gateway-1.4.5/0000755000175000017500000000000013312227714011666 5ustar toljtoljgateway-1.4.5/COPYING0000644000175000017500000000017407755423260012733 0ustar toljtoljSee file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software. gateway-1.4.5/ltmain.sh0000644000175000017500000105203013312227404013503 0ustar toljtolj # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.11 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.2 Debian-2.4.2-1.11" TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 gateway-1.4.5/config.guess0000755000175000017500000012463712502251632014217 0ustar toljtolj#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2015 Free Software Foundation, Inc. timestamp='2015-03-04' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || \ echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "${UNAME_MACHINE_ARCH}" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; e2k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gateway-1.4.5/AUTHORS0000644000175000017500000000012107234326666012744 0ustar toljtoljSee http://www.kannel.org/authors.shtml for a list of the people behind Kannel. gateway-1.4.5/config.sub0000755000175000017500000007247407665505523013702 0ustar toljtolj#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-05-09' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | msp430-* \ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nv1) basic_machine=nv1-cray os=-unicosmp ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic4x | c4x*) basic_machine=tic4x-unknown os=-coff ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gateway-1.4.5/depcomp0000755000175000017500000005601613312227404013247 0ustar toljtolj#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gateway-1.4.5/debian/0000755000175000017500000000000013312227714013110 5ustar toljtoljgateway-1.4.5/debian/kannel-devel.examples0000644000175000017500000000001707644631352017223 0ustar toljtoljdoc/examples/* gateway-1.4.5/debian/changelog.stable0000644000175000017500000000502310105463626016234 0ustar toljtoljkannel (1.4.0-0) unstable; urgency=low * New upstream version. * Bumped standards version -- Bruno Rodrigues Sat, 7 Aug 2004 13:45:02 +0200 kannel (1.2.1-5) unstable; urgency=low * New maintainer (Closes: #185224) * Fix bug in init script -- Bruno Rodrigues Sun, 4 May 2003 18:54:43 +0000 kannel (1.2.1-4) unstable; urgency=low * Updated Standards-Version to 3.5.9 and other cleaning up * Kannel-docs is now architecture independent. Updated control and rules -- Bruno Rodrigues Tue, 8 Apr 2003 20:08:40 +0000 kannel (1.2.1-3) unstable; urgency=low * Moved debian dir from orig to diff * Added debian/compat * Tidy up -- Bruno Rodrigues Mon, 17 Mar 2003 18:42:36 +0000 kannel (1.2.1-2) unstable; urgency=low * Updated Standards-Version to 3.5.8 -- Bruno Rodrigues Sun, 26 Jan 2003 17:05:13 +0100 kkannel (1.2.1-1) unstable; urgency=low * New upstream version -- Bruno Rodrigues Sun, 26 Jan 2003 17:05:13 +0100 kannel (1.2.0-1) unstable; urgency=low * New upstream version -- Bruno Rodrigues Thu, 18 Jul 2002 10:30:39 +0100 kannel (0.11.3.cvs-1) unstable; urgency=low * New upstream version 0.11.3. This Debian package has a few additional changes made in upstream CVS since the release: * SMS timestamps are set by Kannel, if the SMS center did not set them. * Bugfixes in assertions. * Fixes to a couple of WMLScript compilation bugs. * WTP protocol fix in cases when load is heavy and Ack packets are delayed. * WTP state machine fix: if an event can't be handled, it is just ignored, instead of the state machine being killed. * Debian packaging: postinst creates user kannel, init.d/kannel runs the boxes as that user. -- Lars Wirzenius Tue, 10 Oct 2000 15:54:01 +0300 kannel (0.11.2.cvs-1) unstable; urgency=low * Updated version of Debian packaging, for the CVS version. Also added a Debian revision number to the version number: even though the debian/ directory is part of upstream sources, there may be several Debian versions due to packaging etc per upstream release. -- Lars Wirzenius Tue, 3 Oct 2000 13:20:24 +0300 kannel (0.7.9999) unstable; urgency=low * Initial version of Debian package. This is not an upstream release version. It is a CVS snapshot. -- Lars Wirzenius Wed, 29 Mar 2000 22:17:43 +0300 gateway-1.4.5/debian/kannel-cvs-docs.docs0000644000175000017500000000017007643631624016760 0ustar toljtoljdebian/tmp/usr/share/doc/kannel/alligata debian/tmp/usr/share/doc/kannel/userguide debian/tmp/usr/share/doc/kannel/wtls gateway-1.4.5/debian/kannel-devel.install0000644000175000017500000000016207644631352017054 0ustar toljtoljdebian/tmp/usr/bin usr debian/tmp/usr/sbin usr debian/tmp/usr/share/man usr/share debian/kannel.conf /etc/kannel/ gateway-1.4.5/debian/kannel.install0000644000175000017500000000016207644631352015757 0ustar toljtoljdebian/tmp/usr/bin usr debian/tmp/usr/sbin usr debian/tmp/usr/share/man usr/share debian/kannel.conf /etc/kannel/ gateway-1.4.5/debian/kannel.default0000644000175000017500000000003707623266642015741 0ustar toljtoljSTART_WAPBOX=1 #START_SMSBOX=1 gateway-1.4.5/debian/kannel-docs.docs0000644000175000017500000000017007623266642016171 0ustar toljtoljdebian/tmp/usr/share/doc/kannel/alligata debian/tmp/usr/share/doc/kannel/userguide debian/tmp/usr/share/doc/kannel/wtls gateway-1.4.5/debian/copyright0000644000175000017500000000345207617264442015061 0ustar toljtoljThis is Kannel, originally packaged for Debian by Lars Wirzenius and now maintained by Bruno Rodrigues Original author is the Kannel project, see http://www.kannel.org, run by Wapit Ltd, see http://www.wapit.com. Copyright (c) 1998 WAPIT OY LTD. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by WAPIT OY LTD. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. gateway-1.4.5/debian/kannel-devel.links0000644000175000017500000000030307623266642016526 0ustar toljtolj/usr/share/man/man8/kannel.8.gz /usr/share/man/man8/bearerbox.8.gz /usr/share/man/man8/kannel.8.gz /usr/share/man/man8/wapbox.8.gz /usr/share/man/man8/kannel.8.gz /usr/share/man/man8/smsbox.8.gz gateway-1.4.5/debian/kannel-devel.postrm0000644000175000017500000000206407623266642016740 0ustar toljtolj#! /bin/sh # postrm script for kannel # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' overwrit>r> # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in remove|upgrade|failed-upgrade|abort-upgrade|disappear|abort-install) ;; purge) test -d /var/log/kannel && rm -fr /var/log/kannel test -d /var/run/kannel && rm -fr /var/run/kannel test -d /etc/kannel && rmdir /etc/kannel deluser kannel ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 gateway-1.4.5/debian/kannel-devel.default0000644000175000017500000000003707623266642017036 0ustar toljtoljSTART_WAPBOX=1 #START_SMSBOX=1 gateway-1.4.5/debian/kannel-devel.init0000755000175000017500000000572311542220104016341 0ustar toljtolj#!/bin/sh # Start/stop the Kannel boxes: One bearer box and one WAP box. # This is the default init.d script for Kannel. Its configuration is # appropriate for a small site running Kannel on one machine. # Make sure that the Kannel binaries can be found in $BOXPATH or somewhere # else along $PATH. run_kannel_box has to be in $BOXPATH. BOXPATH=/usr/sbin PIDFILES=/var/run/kannel CONFDIR=/etc/kannel CONF=$CONFDIR/kannel.conf PATH=$BOXPATH:$PATH # On Debian, the most likely reason for the bearerbox not being available # is that the package is in the "removed" or "unconfigured" state, and the # init.d script is still around because it's a conffile. This is normal, # so don't generate any output. test -x $BOXPATH/bearerbox || exit 0 test -r /etc/default/kannel-devel && . /etc/default/kannel-devel case "$1" in start) echo -n "Starting WAP gateway:" echo -n " bearerbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_bearerbox.pid \ --chuid kannel \ --exec $BOXPATH/run_kannel_box \ -- \ --pidfile $PIDFILES/kannel_bearerbox.pid \ --no-extra-args \ $BOXPATH/bearerbox -v 4 -- $CONF sleep 1 # Wait for bearerbox test ! -z $START_WAPBOX && ( echo -n " wapbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_wapbox.pid \ --chuid kannel \ --exec $BOXPATH/run_kannel_box \ -- \ --pidfile $PIDFILES/kannel_wapbox.pid \ --no-extra-args \ $BOXPATH/wapbox -v 4 -- $CONF ) test ! -z $START_SMSBOX && ( echo -n " smsbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_smsbox.pid \ --chuid kannel \ --exec $BOXPATH/run_kannel_box \ -- \ --pidfile $PIDFILES/kannel_smsbox.pid \ --no-extra-args \ $BOXPATH/smsbox -v 4 -- $CONF ) echo "." ;; stop) echo -n "Stopping WAP gateway:" test ! -z $START_SMSBOX && ( echo -n " smsbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_smsbox.pid \ --exec $BOXPATH/run_kannel_box ) test ! -z $START_WAPBOX && ( echo -n " wapbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_wapbox.pid \ --exec $BOXPATH/run_kannel_box ) echo -n " bearerbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_bearerbox.pid \ --exec $BOXPATH/run_kannel_box echo "." ;; status) CORE_CONF=$(grep -r 'group[[:space:]]*=[[:space:]]*core' $CONFDIR | cut -d: -f1) ADMIN_PORT=$(grep '^admin-port' $CORE_CONF | sed "s/.*=[[:space:]]*//") ADMIN_PASS=$(grep '^admin-password' $CORE_CONF | sed "s/.*=[[:space:]]*//") STATUS_URL="http://127.0.0.1:${ADMIN_PORT}/status.txt?password=${ADMIN_PASS}" lynx -source $STATUS_URL ;; reload) # We don't have support for this yet. exit 1 ;; restart|force-reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|status|restart|force-reload}" exit 1 esac exit 0 gateway-1.4.5/debian/kannel.links0000644000175000017500000000030307617264442015430 0ustar toljtolj/usr/share/man/man8/kannel.8.gz /usr/share/man/man8/bearerbox.8.gz /usr/share/man/man8/kannel.8.gz /usr/share/man/man8/wapbox.8.gz /usr/share/man/man8/kannel.8.gz /usr/share/man/man8/smsbox.8.gz gateway-1.4.5/debian/kannel-cvs.install0000644000175000017500000000016207644631352016550 0ustar toljtoljdebian/tmp/usr/bin usr debian/tmp/usr/sbin usr debian/tmp/usr/share/man usr/share debian/kannel.conf /etc/kannel/ gateway-1.4.5/debian/kannel-cvs.dirs0000644000175000017500000000003607643631624016044 0ustar toljtoljvar/log/kannel var/run/kannel gateway-1.4.5/debian/kannel-extras.install0000644000175000017500000000014407644631352017263 0ustar toljtoljdebian/tmp/usr/lib/kannel/* usr/lib/kannel debian/tmp/usr/share/doc/kannel/contrib usr/share/kannel gateway-1.4.5/debian/kannel-cvs.examples0000644000175000017500000000001707644631352016717 0ustar toljtoljdoc/examples/* gateway-1.4.5/debian/kannel-cvs.postinst0000644000175000017500000000347307643631624016776 0ustar toljtolj#! /bin/sh # postinst script for kannel # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package # # quoting from the policy: # Any necessary prompting should almost always be confined to the # post-installation script, and should be protected with a conditional # so that unnecessary prompting doesn't happen if a package's # installation fails and the `postinst' is called with `abort-upgrade', # `abort-remove' or `abort-deconfigure'. case "$1" in configure) # Create a "kannel" user. This has modeled after the code in the postfix.deb # postinst. We first try to set the ownership of /var/log/kannel. If that # fails, we create the user and re-try. If that still fails, we abort. if chown -c kannel.root /var/log/kannel /var/run/kannel 2>/dev/null then : #elif adduser --system --group kannel elif adduser --system --home /usr/lib/kannel --no-create-home --gecos "Kannel" kannel then sleep 1 # wait for user creation chown -c kannel.root /var/log/kannel chown -c kannel.root /var/run/kannel fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 gateway-1.4.5/debian/kannel.postrm0000644000175000017500000000206407623266642015643 0ustar toljtolj#! /bin/sh # postrm script for kannel # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' overwrit>r> # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in remove|upgrade|failed-upgrade|abort-upgrade|disappear|abort-install) ;; purge) test -d /var/log/kannel && rm -fr /var/log/kannel test -d /var/run/kannel && rm -fr /var/run/kannel test -d /etc/kannel && rmdir /etc/kannel deluser kannel ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 gateway-1.4.5/debian/rules0000755000175000017500000000751707702407220014200 0ustar toljtolj#!/usr/bin/make -f # Sample debian/rules that uses debhelper. # GNU copyright 1997 to 1999 by Joey Hess. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # This is the debhelper compatibility version to use. #export DH_COMPAT=4 # These are used for cross-compiling and for saving the configure script # from having to guess our platform (since we know it already) DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) INSTALL_PROGRAM += -s endif config.status: configure build: build-stamp build.indep: build-stamp.indep build-stamp: config.status dh_testdir ./configure \ --host=$(DEB_HOST_GNU_TYPE) \ --build=$(DEB_BUILD_GNU_TYPE) \ --prefix=/usr \ --mandir=\$${prefix}/share/man \ --infodir=\$${prefix}/share/info \ --disable-docs --enable-pam \ --enable-ssl --with-ssl=/usr \ --enable-mysql --with-mysql=/usr \ --enable-cookies $(MAKE) touch build-stamp build-stamp.indep: config.status dh_testdir ./configure \ --host=$(DEB_HOST_GNU_TYPE) \ --build=$(DEB_BUILD_GNU_TYPE) \ --prefix=/usr \ --mandir=\$${prefix}/share/man \ --infodir=\$${prefix}/share/info \ --enable-docs --enable-pam \ --enable-ssl --with-ssl=/usr \ --enable-mysql --with-mysql=/usr \ --enable-cookies $(MAKE) docs touch build-stamp.indep clean: dh_testdir dh_testroot rm -f build-stamp build-stamp.indep config.status # Add here commands to clean up after the build process. -$(MAKE) distclean ifneq "$(wildcard /usr/share/misc/config.sub)" "" cp -f /usr/share/misc/config.sub config.sub endif ifneq "$(wildcard /usr/share/misc/config.guess)" "" cp -f /usr/share/misc/config.guess config.guess endif dh_clean install: build dh_testdir -a dh_testroot -a dh_clean -k -a dh_installdirs -a $(MAKE) install prefix=$(CURDIR)/debian/tmp/usr $(MAKE) install-contrib prefix=$(CURDIR)/debian/tmp/usr $(MAKE) install-checks prefix=$(CURDIR)/debian/tmp/usr $(MAKE) install-test prefix=$(CURDIR)/debian/tmp/usr # XXX this is temporary for pre 1.3.1/1.2.2 versions -test -e test/run-http2-tests && mv $(CURDIR)/debian/tmp/usr/lib/kannel/test/run-http2-tests $(CURDIR)/debian/tmp/usr/lib/kannel/test/run-http2-tests.sh dh_install -a dh_movefiles -a install.indep: build.indep dh_testdir -i dh_testroot -i dh_clean -k -i dh_installdirs -i $(MAKE) install-docs prefix=$(CURDIR)/debian/tmp/usr dh_install -i dh_movefiles -i # Build architecture-independent files here. binary-indep: build.indep install.indep dh_testdir -i dh_testroot -i # dh_installdebconf -i dh_installdocs -i # dh_installexamples -i # dh_installmenu -i # dh_installlogrotate -i # dh_installemacsen -i # dh_installpam -i # dh_installmime -i # dh_installinit -i # dh_installcron -i # dh_installman -i # dh_installinfo -i # dh_undocumented -i dh_installchangelogs ChangeLog -i dh_link -i # dh_strip -i dh_compress -i dh_fixperms -i # dh_makeshlibs -i dh_installdeb -i # dh_perl -i # dh_shlibdeps -i dh_gencontrol -i dh_md5sums -i dh_builddeb -i # Build architecture-dependent files here. binary-arch: build install dh_testdir -a dh_testroot -a # dh_installdebconf -a dh_installdocs -a dh_installexamples -a # dh_installmenu -a dh_installlogrotate -a # dh_installemacsen -a # dh_installpam -a # dh_installmime -a dh_installinit -a # dh_installcron -a dh_installman -a # dh_installinfo -a # dh_undocumented -a dh_installchangelogs ChangeLog -a dh_link -a dh_strip -a dh_compress -a dh_fixperms -a # dh_makeshlibs -a dh_installdeb -a # dh_perl -a dh_shlibdeps -a dh_gencontrol -a dh_md5sums -a dh_builddeb -a binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install gateway-1.4.5/debian/kannel.examples0000644000175000017500000000001707644631352016126 0ustar toljtoljdoc/examples/* gateway-1.4.5/debian/kannel.dirs0000644000175000017500000000003607617264442015254 0ustar toljtoljvar/log/kannel var/run/kannel gateway-1.4.5/debian/kannel.docs0000644000175000017500000000004107644631352015235 0ustar toljtoljAUTHORS README NEWS TODO VERSION gateway-1.4.5/debian/kannel-cvs.init0000755000175000017500000000571711542220104016040 0ustar toljtolj#!/bin/sh # Start/stop the Kannel boxes: One bearer box and one WAP box. # This is the default init.d script for Kannel. Its configuration is # appropriate for a small site running Kannel on one machine. # Make sure that the Kannel binaries can be found in $BOXPATH or somewhere # else along $PATH. run_kannel_box has to be in $BOXPATH. BOXPATH=/usr/sbin PIDFILES=/var/run/kannel CONFDIR=/etc/kannel CONF=$CONFDIR/kannel.conf PATH=$BOXPATH:$PATH # On Debian, the most likely reason for the bearerbox not being available # is that the package is in the "removed" or "unconfigured" state, and the # init.d script is still around because it's a conffile. This is normal, # so don't generate any output. test -x $BOXPATH/bearerbox || exit 0 test -r /etc/default/kannel-cvs && . /etc/default/kannel-cvs case "$1" in start) echo -n "Starting WAP gateway:" echo -n " bearerbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_bearerbox.pid \ --chuid kannel \ --exec $BOXPATH/run_kannel_box \ -- \ --pidfile $PIDFILES/kannel_bearerbox.pid \ --no-extra-args \ $BOXPATH/bearerbox -v 4 -- $CONF sleep 1 # Wait for bearerbox test ! -z $START_WAPBOX && ( echo -n " wapbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_wapbox.pid \ --chuid kannel \ --exec $BOXPATH/run_kannel_box \ -- \ --pidfile $PIDFILES/kannel_wapbox.pid \ --no-extra-args \ $BOXPATH/wapbox -v 4 -- $CONF ) test ! -z $START_SMSBOX && ( echo -n " smsbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_smsbox.pid \ --chuid kannel \ --exec $BOXPATH/run_kannel_box \ -- \ --pidfile $PIDFILES/kannel_smsbox.pid \ --no-extra-args \ $BOXPATH/smsbox -v 4 -- $CONF ) echo "." ;; stop) echo -n "Stopping WAP gateway:" test ! -z $START_SMSBOX && ( echo -n " smsbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_smsbox.pid \ --exec $BOXPATH/run_kannel_box ) test ! -z $START_WAPBOX && ( echo -n " wapbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_wapbox.pid \ --exec $BOXPATH/run_kannel_box ) echo -n " bearerbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_bearerbox.pid \ --exec $BOXPATH/run_kannel_box echo "." ;; status) CORE_CONF=$(grep -r 'group[[:space:]]*=[[:space:]]*core' $CONFDIR | cut -d: -f1) ADMIN_PORT=$(grep '^admin-port' $CORE_CONF | sed "s/.*=[[:space:]]*//") ADMIN_PASS=$(grep '^admin-password' $CORE_CONF | sed "s/.*=[[:space:]]*//") STATUS_URL="http://127.0.0.1:${ADMIN_PORT}/status.txt?password=${ADMIN_PASS}" lynx -source $STATUS_URL ;; reload) # We don't have support for this yet. exit 1 ;; restart|force-reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|status|restart|force-reload}" exit 1 esac exit 0 gateway-1.4.5/debian/kannel-cvs.docs0000644000175000017500000000003407702407220016016 0ustar toljtoljAUTHORS README NEWS VERSION gateway-1.4.5/debian/kannel-devel-extras.install0000644000175000017500000000016007644631352020356 0ustar toljtoljdebian/tmp/usr/lib/kannel/* usr/lib/kannel-devel debian/tmp/usr/share/doc/kannel/contrib usr/share/kannel-devel gateway-1.4.5/debian/kannel-cvs-extras.install0000644000175000017500000000015407644631352020055 0ustar toljtoljdebian/tmp/usr/lib/kannel/* usr/lib/kannel-cvs debian/tmp/usr/share/doc/kannel/contrib usr/share/kannel-cvs gateway-1.4.5/debian/control.stable0000644000175000017500000000267110105463626015773 0ustar toljtoljSource: kannel Section: net Priority: optional Maintainer: Bruno Rodrigues Build-Depends: debhelper (>> 4.0.0), libxml2-dev, libssl-dev, openssl, libmysqlclient10-dev, libpam0g-dev Build-Depends-Indep: debhelper (>> 4.0.0), docbook-dsssl, jadetex, transfig, imagemagick, gs Standards-Version: 3.6.1 Package: kannel Architecture: any Section: net Priority: optional Depends: ${shlibs:Depends} Suggests: kannel-extras, kannel-docs Description: WAP and SMS gateway Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Compiled with ssl, mysql and native malloc. Package: kannel-extras Architecture: any Section: net Priority: optional Suggests: kannel, python Depends: ${shlibs:Depends} Description: WAP and SMS gateway extras Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Test utilities and contrib data. Package: kannel-docs Architecture: all Section: net Suggests: kannel Priority: optional Description: WAP and SMS gateway documentation Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Documentation in HTML, RTF and PDF format. gateway-1.4.5/debian/kannel-cvs.postrm0000644000175000017500000000206407643631624016432 0ustar toljtolj#! /bin/sh # postrm script for kannel # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' overwrit>r> # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in remove|upgrade|failed-upgrade|abort-upgrade|disappear|abort-install) ;; purge) test -d /var/log/kannel && rm -fr /var/log/kannel test -d /var/run/kannel && rm -fr /var/run/kannel test -d /etc/kannel && rmdir /etc/kannel deluser kannel ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 gateway-1.4.5/debian/compat0000644000175000017500000000000207644631352014316 0ustar toljtolj4 gateway-1.4.5/debian/kannel-devel.postinst0000644000175000017500000000347307643631624017302 0ustar toljtolj#! /bin/sh # postinst script for kannel # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package # # quoting from the policy: # Any necessary prompting should almost always be confined to the # post-installation script, and should be protected with a conditional # so that unnecessary prompting doesn't happen if a package's # installation fails and the `postinst' is called with `abort-upgrade', # `abort-remove' or `abort-deconfigure'. case "$1" in configure) # Create a "kannel" user. This has modeled after the code in the postfix.deb # postinst. We first try to set the ownership of /var/log/kannel. If that # fails, we create the user and re-try. If that still fails, we abort. if chown -c kannel.root /var/log/kannel /var/run/kannel 2>/dev/null then : #elif adduser --system --group kannel elif adduser --system --home /usr/lib/kannel --no-create-home --gecos "Kannel" kannel then sleep 1 # wait for user creation chown -c kannel.root /var/log/kannel chown -c kannel.root /var/run/kannel fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 gateway-1.4.5/debian/kannel-devel-docs.docs0000644000175000017500000000017007623266642017266 0ustar toljtoljdebian/tmp/usr/share/doc/kannel/alligata debian/tmp/usr/share/doc/kannel/userguide debian/tmp/usr/share/doc/kannel/wtls gateway-1.4.5/debian/control.devel0000644000175000017500000000422107644631352015620 0ustar toljtoljSource: kannel-devel Section: net Priority: optional Maintainer: Bruno Rodrigues Build-Depends: debhelper (>> 4.0.0), libxml2-dev, libssl-dev, openssl, libmysqlclient10-dev, libpam0g-dev Build-Depends-Indep: debhelper (>> 4.0.0), docbook-dsssl, jadetex, transfig, imagemagick, gs Standards-Version: 3.5.9 Package: kannel-devel Architecture: any Section: net Priority: optional Depends: ${shlibs:Depends} Conflicts: kannel, kannel-cvs Replaces: kannel, kannel-cvs Description: WAP and SMS gateway (development) Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Compiled with ssl, mysql and native malloc. . Development and/or CVS versions are stable enough and encouraged to use to enable constant testing. CVS bugs are usually fixed in one or to days and a lot of developers use stable CVS versions in production. Package: kannel-devel-extras Architecture: any Section: net Priority: optional Suggests: kannel-devel, python Depends: ${shlibs:Depends} Description: WAP and SMS gateway extras (development) Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Test utilities and contrib data. . Development and/or CVS versions are stable enough and encouraged to use to enable constant testing. CVS bugs are usually fixed in one or to days and a lot of developers use stable CVS versions in production. Package: kannel-devel-docs Architecture: all Section: net Suggests: kannel-devel Priority: optional Description: WAP and SMS gateway documentation Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Documentation in html, rtf and pdf format. . Development and/or CVS versions are stable enough and encouraged to use to enable constant testing. CVS bugs are usually fixed in one or to days and a lot of developers use stable CVS versions in production. gateway-1.4.5/debian/kannel-cvs.links0000644000175000017500000000030307643631624016220 0ustar toljtolj/usr/share/man/man8/kannel.8.gz /usr/share/man/man8/bearerbox.8.gz /usr/share/man/man8/kannel.8.gz /usr/share/man/man8/wapbox.8.gz /usr/share/man/man8/kannel.8.gz /usr/share/man/man8/smsbox.8.gz gateway-1.4.5/debian/kannel-cvs.default0000644000175000017500000000003707643631624016530 0ustar toljtoljSTART_WAPBOX=1 #START_SMSBOX=1 gateway-1.4.5/debian/kannel-devel.docs0000644000175000017500000000004107644631352016332 0ustar toljtoljAUTHORS README NEWS TODO VERSION gateway-1.4.5/debian/kannel-devel.logrotate0000644000175000017500000000034207623266642017411 0ustar toljtolj/var/log/kannel/*.log { daily missingok rotate 365 compress delaycompress notifempty create 640 kannel adm sharedscripts postrotate killall -HUP bearerbox smsbox wapbox > /dev/null 2> /dev/null || true endscript } gateway-1.4.5/debian/changelog.devel0000644000175000017500000000247507655261404016077 0ustar toljtoljkannel-devel (1.3.1-4) unstable; urgency=low * New package (Closes: #185381) * Fix bug in init script -- Bruno Rodrigues Sun, 4 May 2003 18:55:12 +0000 kannel-devel (1.3.1-3) unstable; urgency=low * Updated Standards-Version to 3.5.9 and other cleaning up * Kannel-devel-docs is now architecture independent. Updated control and rule. -- Bruno Rodrigues Tue, 8 Apr 2003 20:08:50 +0000 kannel-devel (1.3.1-2) unstable; urgency=low * Moved debian dir from orig.tar.gz to diff * Tidy up debian/ files -- Bruno Rodrigues Mon, 17 Mar 2003 21:20:19 +0000 kannel-devel (1.3.1-1) unstable; urgency=low * New upstream version (development) -- Bruno Rodrigues Tue, 18 Feb 2003 05:52:44 +0000 kannel-devel (1.3.0-2) unstable; urgency=low * Updated Standards-Version. -- Bruno Rodrigues Tue, 21 Jan 2003 01:34:48 +0000 kannel-devel (1.3.0-1) unstable; urgency=low * New upstream version (development) -- Bruno Rodrigues Sat, 11 Jan 2003 16:23:39 +0100 kannel-devel (1.1.6-1) unstable; urgency=low * New upstream version * Non-Official Package -- Bruno Rodrigues Thu, 28 Mar 2002 10:30:39 +0100 gateway-1.4.5/debian/control0000644000175000017500000000417707644631352014534 0ustar toljtoljSource: kannel-cvs Section: net Priority: optional Maintainer: Bruno Rodrigues Build-Depends: debhelper (>> 4.0.0), libxml2-dev, libssl-dev, openssl, libmysqlclient10-dev, libpam0g-dev Build-Depends-Indep: debhelper (>> 4.0.0), docbook-dsssl, jadetex, transfig, imagemagick, gs Standards-Version: 3.5.9 Package: kannel-cvs Architecture: any Section: net Priority: optional Depends: ${shlibs:Depends} Conflicts: kannel, kannel-devel Replaces: kannel, kannel-devel Description: WAP and SMS gateway (cvs) Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Compiled with ssl, mysql and native malloc. . Development and/or CVS versions are stable enough and encouraged to use to enable constant testing. CVS bugs are usually fixed in one or to days and a lot of developers use stable CVS versions in production. Package: kannel-cvs-extras Architecture: any Section: net Priority: optional Suggests: kannel-cvs, python Depends: ${shlibs:Depends} Description: WAP and SMS gateway extras (cvs) Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Test utilities and contrib data. . Development and/or CVS versions are stable enough and encouraged to use to enable constant testing. CVS bugs are usually fixed in one or to days and a lot of developers use stable CVS versions in production. Package: kannel-cvs-docs Architecture: all Section: net Suggests: kannel-cvs Priority: optional Description: WAP and SMS gateway documentation (cvs) Kannel is a gateway for connecting WAP (Wireless Application Protocol) phones to the Internet. It also works as an SMS gateway, for providing SMS based services for GSM phones. . Documentation in html, rtf and pdf format. . Development and/or CVS versions are stable enough and encouraged to use to enable constant testing. CVS bugs are usually fixed in one or to days and a lot of developers use stable CVS versions in production. gateway-1.4.5/debian/kannel.conf0000644000175000017500000000103007166363552015234 0ustar toljtolj# # Sample configuration file for Kannel bearerbox on Debian. # See the documentation for explanations of fields. # # HTTP administration is disabled by default. Make sure you set the # password if you enable it. group = core admin-port = 13000 admin-password = bar admin-deny-ip = "*.*.*.*" admin-allow-ip = "" wapbox-port = 13002 wdp-interface-name = "*" log-file = "/var/log/kannel/bearerbox.log" box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" group = wapbox bearerbox-host = localhost log-file = "/var/log/kannel/wapbox.log" gateway-1.4.5/debian/kannel.logrotate0000644000175000017500000000034207623266642016314 0ustar toljtolj/var/log/kannel/*.log { daily missingok rotate 365 compress delaycompress notifempty create 640 kannel adm sharedscripts postrotate killall -HUP bearerbox smsbox wapbox > /dev/null 2> /dev/null || true endscript } gateway-1.4.5/debian/kannel.init0000755000175000017500000000545411542220104015245 0ustar toljtolj#!/bin/sh # Start/stop the Kannel boxes: One bearer box and one WAP box. # This is the default init.d script for Kannel. Its configuration is # appropriate for a small site running Kannel on one machine. # Make sure that the Kannel binaries can be found in $BOXPATH or somewhere # else along $PATH. run_kannel_box has to be in $BOXPATH. BOXPATH=/usr/sbin PIDFILES=/var/run/kannel CONFDIR=/etc/kannel CONF=$CONFDIR/kannel.conf PATH=$BOXPATH:$PATH # On Debian, the most likely reason for the bearerbox not being available # is that the package is in the "removed" or "unconfigured" state, and the # init.d script is still around because it's a conffile. This is normal, # so don't generate any output. test -x $BOXPATH/bearerbox || exit 0 test -r /etc/default/kannel && . /etc/default/kannel case "$1" in start) echo -n "Starting WAP gateway:" echo -n " bearerbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_bearerbox.pid \ --chuid kannel \ --exec $BOXPATH/bearerbox -- -v 4 --parachute --daemonize \ --pid-file $PIDFILES/kannel_bearerbox.pid $CONF sleep 1 # Wait for bearerbox test ! -z $START_WAPBOX && ( echo -n " wapbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_wapbox.pid \ --chuid kannel \ --exec $BOXPATH/wapbox -- -v 4 --parachute --daemonize \ --pid-file $PIDFILES/kannel_wapbox.pid $CONF ) test ! -z $START_SMSBOX && ( echo -n " smsbox" start-stop-daemon --start --quiet \ --pidfile $PIDFILES/kannel_smsbox.pid \ --chuid kannel \ --exec $BOXPATH/smsbox -- -v 4 --parachute --daemonize \ --pid-file $PIDFILES/kannel_smsbox.pid $CONF ) echo "." ;; stop) echo -n "Stopping WAP gateway:" test ! -z $START_SMSBOX && ( echo -n " smsbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_smsbox.pid \ --name smsbox ) test ! -z $START_WAPBOX && ( echo -n " wapbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_wapbox.pid \ --name wapbox ) echo -n " bearerbox" start-stop-daemon --stop --retry 5 --quiet \ --pidfile $PIDFILES/kannel_bearerbox.pid \ --name bearerbox echo "." ;; status) CORE_CONF=$(grep -r 'group[[:space:]]*=[[:space:]]*core' $CONFDIR | cut -d: -f1) ADMIN_PORT=$(grep '^admin-port' $CORE_CONF | sed "s/.*=[[:space:]]*//") ADMIN_PASS=$(grep '^admin-password' $CORE_CONF | sed "s/.*=[[:space:]]*//") STATUS_URL="http://127.0.0.1:${ADMIN_PORT}/status.txt?password=${ADMIN_PASS}" lynx -source $STATUS_URL ;; reload) # We don't have support for this yet. exit 1 ;; restart|force-reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|status|restart|force-reload}" exit 1 esac exit 0 gateway-1.4.5/debian/changelog0000644000175000017500000000023307643631624014771 0ustar toljtoljkannel-cvs (1.3.1-20030404-1) unstable; urgency=low * CVS Daily build -- Bruno Rodrigues Sun, 26 Jan 2003 17:05:13 +0100 gateway-1.4.5/debian/kannel-cvs.logrotate0000644000175000017500000000034207643631624017103 0ustar toljtolj/var/log/kannel/*.log { daily missingok rotate 365 compress delaycompress notifempty create 640 kannel adm sharedscripts postrotate killall -HUP bearerbox smsbox wapbox > /dev/null 2> /dev/null || true endscript } gateway-1.4.5/debian/kannel-devel.dirs0000644000175000017500000000003607623266642016352 0ustar toljtoljvar/log/kannel var/run/kannel gateway-1.4.5/debian/kannel.postinst0000644000175000017500000000347307643631624016205 0ustar toljtolj#! /bin/sh # postinst script for kannel # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package # # quoting from the policy: # Any necessary prompting should almost always be confined to the # post-installation script, and should be protected with a conditional # so that unnecessary prompting doesn't happen if a package's # installation fails and the `postinst' is called with `abort-upgrade', # `abort-remove' or `abort-deconfigure'. case "$1" in configure) # Create a "kannel" user. This has modeled after the code in the postfix.deb # postinst. We first try to set the ownership of /var/log/kannel. If that # fails, we create the user and re-try. If that still fails, we abort. if chown -c kannel.root /var/log/kannel /var/run/kannel 2>/dev/null then : #elif adduser --system --group kannel elif adduser --system --home /usr/lib/kannel --no-create-home --gecos "Kannel" kannel then sleep 1 # wait for user creation chown -c kannel.root /var/log/kannel chown -c kannel.root /var/run/kannel fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 gateway-1.4.5/Makefile.in0000644000175000017500000002701513312221404013726 0ustar toljtolj# # Makefile.in for Kannel, the Open Source WAP and SMS Gateway. # # This file is currently maintained manually. There is currently # no generation out of automake. This will change as soon as we # switch to our new autoconf/configure build process. # SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ oldincludedir = /usr/include docdir = @docdir@ DESTDIR = pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = . ACLOCAL = @ACLOCAL@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ transform = @program_transform_name@ NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : CC = @CC@ MAKEINFO = @MAKEINFO@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ SHELL = @SHELL@ VERSION = @VERSION@ SUFFIX = @SUFFIX@ LEX = @LEX@ PERL = @PERL@ YACC = @YACC@ # -v gives verbose output. YFLAGS = -d -p ws_yy_ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = gw-config.h CONFIG_CLEAN_FILES = LIBOBJS=@LIBOBJS@ LIBSRCS=$(LIBOBJS:.o=.c) LIBS=@LIBS@ @LIBICONV@ CFLAGS=-D_REENTRANT=1 -I. -Igw @CFLAGS@ LDFLAGS=@LDFLAGS@ MKDEPEND=$(CC) $(CFLAGS) -MM JADE=@JADE@ JADETEX=@JADETEX@ PDFJADETEX=@PDFJADETEX@ DVIPS=@DVIPS@ FIG2DEV=@FIG2DEV@ CONVERT=@CONVERT@ HTML_DSL=@HTML_DSL@ TEX_DSL=@TEX_DSL@ XML_DCL=@XML_DCL@ # Set this to something if you want all installed binaries to have a suffix. # Version number is common. suffix = $(SUFFIX) SUBDIRS = utils # # You probably don't need to touch anything below this, if you're just # compiling and installing the software. # binsrcs = \ wmlscript/wmlsc.c \ wmlscript/wmlsdasm.c sbinsrcs = \ gw/bearerbox.c \ gw/smsbox.c \ gw/wapbox.c progsrcs = $(binsrcs) $(sbinsrcs) progobjs = $(progsrcs:.c=.o) progs = $(progsrcs:.c=@EXE_EXT@) binprogs = $(binsrcs:.c=) gw-config sbinprogs = $(sbinsrcs:.c=) gwsrcs = $(wildcard gw/*.c) $(wildcard gw/smsc/*.c) gwobjs = $(filter-out $(progobjs),$(gwsrcs:.c=.o)) libsrcs = $(wildcard gwlib/*.c) $(LIBSRCS) libobjs = $(libsrcs:.c=.o) $(LIBOBJS) wapsrcs = $(wildcard wap/*.c) $(wildcard radius/*.c) wapobjs = $(wapsrcs:.c=.o) wmlscriptsrcs = $(wildcard wmlscript/*.c) wmlscriptobjs = $(wmlscriptsrcs:.c=.o) testsrcs = $(wildcard test/*.c) testobjs = $(testsrcs:.c=.o) testprogs = $(testsrcs:.c=@EXE_EXT@) tests = $(testprogs) $(wildcard test/*.sh) checksrcs = $(wildcard checks/*.c) checkobjs = $(checksrcs:.c=.o) checkprogs = $(checksrcs:.c=@EXE_EXT@) checks = $(checkprogs) $(wildcard checks/*.sh) benchformats = \ benchmarks/report.pdf \ benchmarks/report.ps \ benchmarks/report.html benchscripts = benchmarks/run-benchmarks $(wildcard benchmarks/*.sh) benchoutputs = \ $(benchformats) \ $(wildcard benchmarks/*.ps) \ $(wildcard benchmarks/*.png) \ $(wildcard benchmarks/*.xml) srcs = $(wildcard */*.c) $(wildcard */*/*.c) objs = $(srcs:.c=.o) pres = $(srcs:.c=.i) libs = libgw.a libwmlscript.a libwap.a libgwlib.a srcdirs = gw gw/smsc gwlib test wmlscript checks wap radius man1pages = wmlscript/wmlsc.1 wmlscript/wmlsdasm.1 man8pages = gw/kannel.8 docsrcs = $(wildcard grep -l ' $*.tmp ${JADE} -V nochunks -t sgml -d $(HTML_DSL) $(XML_DCL) $*.tmp > $@ rm -f $*.tmp .xml.rtf: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp cd `dirname $<` && $(JADE) -o `basename $*`.rtf -t rtf -d $(TEX_DSL) $(XML_DCL) `basename $*`.tmp rm -f $*.tmp .xml.ps: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || \ ( echo Check `dirname $<`/`basename $*`.log for errors && false) rm -f $*.log cd `dirname $<` && $(DVIPS) -q -o `basename $*`.ps `basename $*`.dvi rm -f $*.dvi $*.tex $*.aux .xml.pdf: sed "s/#FIGTYPE#/.png/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true rm -f $*.log $*.dvi cd `dirname $<` && $(PDFJADETEX) `basename $*`.tex > /dev/null || true test -r $*.pdf || false rm -f $*.log $*.tex $*.aux $*.out .fig.png: $(FIG2DEV) -Lpng $< $@ .fig.ps: $(FIG2DEV) -Lps $< $@ .png.ps: $(CONVERT) $< $@ .y.c: $(YACC) $(YFLAGS) $< && mv y.tab.c $*.c if test -f y.tab.h; then \ if cmp -s y.tab.h $*.h; then rm y.tab.h; else mv y.tab.h $*.h; fi; \ else :; fi .c.o: $(CC) $(CFLAGS) -o $@ -c $< .c.i: $(CC) $(CFLAGS) -o $@ -E $< all: $(libs) $(SUBDIRS) progs $(testprogs) $(checkprogs) $(DOCSTARGET) gw-config progs: $(progs) tests: $(testprogs) docs: figs ps $(docs) no-docs: figs: $(figs) ps: $(ps) pp: $(pres) check: all $(SUBDIRS) utils/run-checks $(checks) bench: all $(benchformats) $(SUBDIRS) benchmarks/report.xml: dummy benchmarks/run-benchmarks benchmarks/*.sh dummy: install: all $(SUBDIRS) $(INSTALL) -d $(DESTDIR)$(bindir) for prog in $(binprogs); do \ $(INSTALL) $$prog \ $(DESTDIR)$(bindir)/`basename $$prog`$(suffix); \ done test -r $(DESTDIR)$(bindir)/gw-config || \ ln -sf gw-config$(suffix) $(DESTDIR)$(bindir)/gw-config $(INSTALL) -d $(DESTDIR)$(sbindir) for prog in $(sbinprogs); do \ $(INSTALL) $$prog \ $(DESTDIR)$(sbindir)/`basename $$prog`$(suffix); \ done $(INSTALL) -d $(DESTDIR)$(mandir)/man1 $(INSTALL) $(man1pages) $(DESTDIR)$(mandir)/man1 $(INSTALL) -d $(DESTDIR)$(mandir)/man8 $(INSTALL) $(man8pages) $(DESTDIR)$(mandir)/man8 $(INSTALL) -d $(DESTDIR)$(includedir)/kannel/gwlib $(INSTALL_DATA) $(top_srcdir)/gwlib/*.h $(DESTDIR)$(includedir)/kannel/gwlib $(INSTALL_DATA) $(top_srcdir)/gwlib/*.def $(DESTDIR)$(includedir)/kannel/gwlib $(INSTALL) -d $(DESTDIR)$(includedir)/kannel/gw $(INSTALL_DATA) $(top_srcdir)/gw/*.h $(DESTDIR)$(includedir)/kannel/gw $(INSTALL_DATA) $(top_srcdir)/gw/*.def $(DESTDIR)$(includedir)/kannel/gw $(INSTALL) -d $(DESTDIR)$(includedir)/kannel/gw/smsc $(INSTALL_DATA) $(top_srcdir)/gw/smsc/*.h $(DESTDIR)$(includedir)/kannel/gw/smsc $(INSTALL_DATA) $(top_srcdir)/gw/smsc/*.def $(DESTDIR)$(includedir)/kannel/gw/smsc $(INSTALL) -d $(DESTDIR)$(includedir)/kannel/wap $(INSTALL_DATA) $(top_srcdir)/wap/*.h $(DESTDIR)$(includedir)/kannel/wap $(INSTALL_DATA) $(top_srcdir)/wap/*.def $(DESTDIR)$(includedir)/kannel/wap $(INSTALL_DATA) gw-config.h $(DESTDIR)$(includedir)/kannel $(INSTALL) -d $(DESTDIR)$(libdir)/kannel $(INSTALL_DATA) lib*.a $(DESTDIR)$(libdir)/kannel install-test: all $(SUBDIRS) $(INSTALL) -d $(DESTDIR)$(libdir)/kannel $(INSTALL) -d $(DESTDIR)$(libdir)/kannel/test (cd test && find . -type f ! -name "*.c" ! -name "*.o" | grep -v ".cvsignore" | grep -v "/CVS/" | while read a ; do $(INSTALL_DATA) $$a $(DESTDIR)$(libdir)/kannel/test ; done) for prog in $(tests) ; do \ chmod 755 $(DESTDIR)$(libdir)/kannel/$$prog ; \ done install-checks: all $(SUBDIRS) $(INSTALL) -d $(DESTDIR)$(libdir)/kannel/checks (cd checks && find . -type f ! -name "*.c" ! -name "*.o" | grep -v ".cvsignore" | grep -v "/CVS/" | while read a ; do $(INSTALL_DATA) $$a $(DESTDIR)$(libdir)/kannel/checks ; done) for prog in $(checks) ; do \ chmod 755 $(DESTDIR)$(libdir)/kannel/$$prog ; \ done install-contrib: all $(SUBDIRS) $(INSTALL) -d $(DESTDIR)$(docdir)/contrib (cd contrib && find . -type d ! -name "CVS" | while read a ; do $(INSTALL) -d $(DESTDIR)$(docdir)/contrib/$$a ; done ) (cd contrib && find . -type f ! -name ".cvsignore" | grep -v "/CVS/" | while read a ; do $(INSTALL_DATA) $$a $(DESTDIR)$(docdir)/contrib/$$a ; done ) find $(DESTDIR)$(docdir)/contrib/ -name "*.pl" -o -name "*.sh" -o -name "*.cgi" -o -name "sendsms" -o -name "kannel.monitor" | while read a ; do chmod 755 "$$a" ; done install-docs: $(SUBDIRS) $(INSTALL) -d $(DESTDIR)$(docdir)/examples $(INSTALL_DATA) doc/examples/*.conf $(DESTDIR)$(docdir)/examples for docfile in userguide alligata wtls ; do \ $(INSTALL) -d $(DESTDIR)$(docdir)/$$docfile ; \ $(INSTALL_DATA) doc/$$docfile/$$docfile.ps $(DESTDIR)$(docdir)/$$docfile ; \ $(INSTALL_DATA) doc/$$docfile/$$docfile.html $(DESTDIR)$(docdir)/$$docfile ; \ $(INSTALL_DATA) doc/$$docfile/$$docfile.rtf $(DESTDIR)$(docdir)/$$docfile ; \ $(INSTALL_DATA) doc/$$docfile/$$docfile.pdf $(DESTDIR)$(docdir)/$$docfile ; \ $(INSTALL_DATA) doc/$$docfile/*.png $(DESTDIR)$(docdir)/$$docfile ; \ done clean: $(SUBDIRS) find . -name "*.o" -o -name "*.i" -o -name "*.a" | xargs rm -f rm -f core gw-config $(progs) $(testprogs) $(checkprogs) rm -f $(figs) $(ps) $(docs) rm -f $(benchoutputs) distclean: clean $(SUBDIRS) rm -f Makefile gw-config.h config.cache config.log config.status config.nice .depend gwlib/gw_uuid_types.h nag: utils/find-long-lines @SOAP_INCLUDE@ depend .depend: wmlscript/wsgram.h gw-config.h $(soap_depend) for dir in $(srcdirs); do \ for file in $$dir/*.c; do \ $(MKDEPEND) $$file -MT $$dir/`basename $$file .c`.o -MT $$dir/`basename $$file .c`.i; done; done > .depend include .depend libgw.a: $(gwobjs) @OLD_LIBTOOL@ libgw.a $(gwobjs) $(RANLIB) libgw.a libgwlib.a: $(libobjs) @OLD_LIBTOOL@ libgwlib.a $(libobjs) $(RANLIB) libgwlib.a libwmlscript.a: $(wmlscriptobjs) @OLD_LIBTOOL@ libwmlscript.a $(wmlscriptobjs) $(RANLIB) libwmlscript.a libwap.a: $(wapobjs) @OLD_LIBTOOL@ libwap.a $(wapobjs) $(RANLIB) libwap.a wmlscript/wsgram.h: wmlscript/wsgram.c make-op-table: $(srcdir)/wmlscript/make-op-table.in sed 's%@PERLPROG@%@PERL@%g' $(srcdir)/wmlscript/make-op-table.in \ > make-op-table chmod a+x make-op-table opcodes: ./make-op-table $(srcdir)/wmlscript/wsasm.h \ > $(srcdir)/wmlscript/wsopcodes.h $(progs): $(libs) $(progobjs) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(@:@EXE_EXT@=).o $(libs) $(LIBS) $(testprogs): $(testobjs) $(libs) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(@:@EXE_EXT@=).o $(libs) $(LIBS) $(checkprogs): $(checkobjs) $(libs) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(@:@EXE_EXT@=).o $(libs) $(LIBS) pkg: all (cd solaris; mk-solaris-package.sh) echo Package is now in solaris directory gw-config: utils/foobar-config.sh Makefile ./utils/foobar-config.sh "-I$(includedir)/kannel @CFLAGS@" \ "-L$(libdir)/kannel -lgw -lwap -lgwlib $(LIBS)" \ "@VERSION@" > gw-config chmod 0755 gw-config $(SUBDIRS): $(MAKE) -C $@ $(MAKECMDGOALS) am--refresh: @: .PHONY: $(SUBDIRS) am--refresh gateway-1.4.5/bootstrap.sh0000755000175000017500000000050313312221404014226 0ustar toljtolj#!/bin/sh # # verbose # set -x # # set automake version that needed # export WANT_AUTOMAKE=1.8 # # libtool stuff # if `which glibtoolize` then glibtoolize --copy --automake --force else libtoolize --copy --automake --force fi # # and auto-magic stuff # aclocal autoheader automake --add-missing --copy --gnu autoconf gateway-1.4.5/wmlscript/0000755000175000017500000000000013312227714013712 5ustar toljtoljgateway-1.4.5/wmlscript/wsstdlib.c0000644000175000017500000003022013227613126015707 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsstdlib.c - WTA and WTAI standard libraries related implementations * * Authors: * Markku Rossi * Stipe Tolj * * 2005-03-22 - update to latest specs: * WAP-268-WTAI-20010908.pdf * WAP-269-WTAIIS136-20010908-a.pdf * WAP-270-WTAIPDC-20010908-a.pdf * WAP-228-WTAIIS95-20010908-a.pdf * WAP-255-WTAIGSM-20010908-a.pdf */ #include "wsint.h" /* TODO: the function registry could have argument type specifier * strings. These could be used to generate extra warnings when * functions are called with wrong arguments. However, this might not * be fully conformable to the WMLScript specification. I think that * the interpreter might do an automatic type conversion so the * warnings are less useful. But, these warnings could be enabled in * the `-Wpedantic' mode. */ /********************* Types and definitions ****************************/ /* Calculate the number of function registries in the array `f'. */ #define NF(f) (sizeof(f) / sizeof(f[0])) /* Information about a standard library function. */ struct WsStdLibFuncRegRec { char *name; /* The exact number of arguments. */ int num_args; /* The function ID as specified */ WsUInt8 function_id; }; typedef struct WsStdLibFuncRegRec WsStdLibFuncReg; /* Information about a standard library. */ struct WsStdLibRegRec { char *name; WsUInt16 library_id; /* The number of functions in this library. */ WsUInt8 num_functions; /* The functions are given in their index order. */ WsStdLibFuncReg *functions; }; typedef struct WsStdLibRegRec WsStdLibReg; /********************* Static variables *********************************/ static WsStdLibFuncReg lib_lang_functions[] = { {"abs", 1, 0}, {"min", 2, 1}, {"max", 2, 2}, {"parseInt", 1, 3}, {"parseFloat", 1, 4}, {"isInt", 1, 5}, {"isFloat", 1, 6}, {"maxInt", 0, 7}, {"minInt", 0, 8}, {"float", 0, 9}, {"exit", 1, 10}, {"abort", 1, 11}, {"random", 1, 12}, {"seed", 1, 13}, {"characterSet", 0, 14}, }; static WsStdLibFuncReg lib_float_functions[] = { {"int", 1, 0}, {"floor", 1, 1}, {"ceil", 1, 2}, {"pow", 2, 3}, {"round", 1, 4}, {"sqrt", 1, 5}, {"maxFloat", 0, 6}, {"minFloat", 0, 7}, }; static WsStdLibFuncReg lib_string_functions[] = { {"length", 1, 0}, {"isEmpty", 1, 1}, {"charAt", 2, 2}, {"subString", 3, 3}, {"find", 2, 4}, {"replace", 3, 5}, {"elements", 2, 6}, {"elementAt", 3, 7}, {"removeAt", 3, 8}, {"replaceAt", 4, 9}, {"insertAt", 4, 10}, {"squeeze", 1, 11}, {"trim", 1, 12}, {"compare", 2, 13}, {"toString", 1, 14}, {"format", 2, 15}, }; static WsStdLibFuncReg lib_url_functions[] = { {"isValid", 1, 0}, {"getScheme", 1, 1}, {"getHost", 1, 2}, {"getPort", 1, 3}, {"getPath", 1, 4}, {"getParameters", 1, 5}, {"getQuery", 1, 6}, {"getFragment", 1, 7}, {"getBase", 0, 8}, {"getReferer", 0, 9}, {"resolve", 2, 10}, {"escapeString", 1, 11}, {"unescapeString", 1, 12}, {"loadString", 2, 13}, }; static WsStdLibFuncReg lib_wmlbrowser_functions[] = { {"getVar", 1, 0}, {"setVar", 2, 1}, {"go", 1, 2}, {"prev", 0, 3}, {"newContext", 0, 4}, {"getCurrentCard", 0, 5}, {"refresh", 0, 6}, }; static WsStdLibFuncReg lib_dialogs_functions[] = { {"prompt", 2, 0}, {"confirm", 3, 1}, {"alert", 1, 2}, }; static WsStdLibFuncReg lib_crypto_functions[] = { {"signText", 4, 16}, }; static WsStdLibFuncReg lib_efi_functions[] = { {"set", 3, 0}, {"get", 2, 1}, {"getFirstName", 1, 2}, {"getNextName", 2, 3}, {"getAllAttributes", 1, 4}, {"getAttribute", 2, 5}, {"getClassProperty", 2, 6}, {"getUnits", 1, 7}, {"query", 1, 8}, {"invoke", 3, 9}, {"call", 3, 10}, {"status", 1, 11}, {"control", 3, 12}, }; static WsStdLibFuncReg lib_wtapublic_functions[] = { {"makeCall", 1, 0}, {"sendDTMF", 1, 1}, {"addPBEntry", 2, 2}, }; static WsStdLibFuncReg lib_wtavoicecall_functions[] = { {"setup", 2, 0}, {"accept", 2, 1}, {"release", 1, 2}, {"sendDTMF", 2, 3}, {"callStatus", 2, 4}, {"list", 1, 5}, }; static WsStdLibFuncReg lib_wtanettext_functions[] = { {"send", 2, 0}, {"list", 2, 1}, {"remove", 1, 2}, {"getFieldValue", 2, 3}, {"markAsRead", 1, 4}, }; static WsStdLibFuncReg lib_wtaphonebook_functions[] = { {"write", 3, 0}, {"search", 2, 1}, {"remove", 1, 2}, {"getFieldValue", 2, 3}, {"change", 3, 4}, }; static WsStdLibFuncReg lib_wtamisc_functions[] = { {"setIndicator", 2, 0}, {"endContext", 0, 1}, {"getProtection", 0, 2}, {"setProtection", 1, 3}, }; static WsStdLibFuncReg lib_wtaansi136_functions[] = { {"sendFlash", 2, 0}, {"sendAlert", 2, 1}, }; static WsStdLibFuncReg lib_wtagsm_functions[] = { {"hold", 1, 0}, {"retrieve", 1, 1}, {"transfer", 2, 2}, {"deflect", 2, 3}, {"multiparty", 0, 4}, {"seperate", 1, 5}, {"sendUSSD", 4, 6}, {"netinfo", 1, 7}, {"callWaiting", 1, 8}, {"sendBusy", 1, 9}, }; static WsStdLibFuncReg lib_wtacalllog_functions[] = { {"dialled", 1, 0}, {"missed", 1, 1}, {"received", 1, 2}, {"getFieldValue", 2, 3}, }; static WsStdLibFuncReg lib_wtapdc_functions[] = { {"hold", 1, 0}, {"retrieve", 1, 1}, {"transfer", 2, 2}, {"deflect", 2, 3}, {"multiparty", 0, 4}, {"seperate", 1, 5}, }; static WsStdLibFuncReg lib_wtais95_functions[] = { {"sendText", 6, 0}, {"cancelText", 1, 1}, {"sendAck", 1, 2}, }; static WsStdLibReg libraries[] = { {"Lang", 0, NF(lib_lang_functions), lib_lang_functions}, {"Float", 1, NF(lib_float_functions), lib_float_functions}, {"String", 2, NF(lib_string_functions), lib_string_functions}, {"URL", 3, NF(lib_url_functions), lib_url_functions}, {"WMLBrowser", 4, NF(lib_wmlbrowser_functions), lib_wmlbrowser_functions}, {"Dialogs", 5, NF(lib_dialogs_functions), lib_dialogs_functions}, {"Crypto", 6, NF(lib_crypto_functions), lib_crypto_functions}, {"EFI", 7, NF(lib_efi_functions), lib_efi_functions}, {"WTAPublic", 512, NF(lib_wtapublic_functions), lib_wtapublic_functions}, {"WTAVoiceCall", 513, NF(lib_wtavoicecall_functions), lib_wtavoicecall_functions}, {"WTANetText", 514, NF(lib_wtanettext_functions), lib_wtanettext_functions}, {"WTAPhoneBook", 515, NF(lib_wtaphonebook_functions), lib_wtaphonebook_functions}, {"WTAMisc", 516, NF(lib_wtamisc_functions), lib_wtamisc_functions}, {"WTAANSI163", 517, NF(lib_wtaansi136_functions), lib_wtaansi136_functions}, {"WTAGSM", 518, NF(lib_wtagsm_functions), lib_wtagsm_functions}, {"WTACallLog", 519, NF(lib_wtacalllog_functions), lib_wtacalllog_functions}, {"WTAPDC", 520, NF(lib_wtapdc_functions), lib_wtapdc_functions}, {"WTAIS95", 521, NF(lib_wtais95_functions), lib_wtais95_functions}, {NULL, 0, 0, NULL} }; /********************* Global functions *********************************/ WsBool ws_stdlib_function(const char *library, const char *function, WsUInt16 *lindex_return, WsUInt8 *findex_return, WsUInt8 *num_args_return, WsBool *lindex_found_return, WsBool *findex_found_return) { WsUInt16 l; *lindex_found_return = WS_FALSE; *findex_found_return = WS_FALSE; for (l = 0; libraries[l].name != NULL; l++) { if (strcmp(libraries[l].name, library) == 0) { WsUInt8 f; *lindex_return = libraries[l].library_id; *lindex_found_return = WS_TRUE; for (f = 0; f < libraries[l].num_functions; f++) { if (strcmp(libraries[l].functions[f].name, function) == 0) { *findex_return = libraries[l].functions[f].function_id; *findex_found_return = WS_TRUE; *num_args_return = libraries[l].functions[f].num_args; return WS_TRUE; } } } } return WS_FALSE; } WsBool ws_stdlib_function_name(WsUInt16 lindex, WsUInt8 findex, const char **library_return, const char **function_return) { WsUInt16 l; WsUInt8 f; *library_return = NULL; *function_return = NULL; for (l = 0; libraries[l].name != NULL; l++) if (libraries[l].library_id == lindex) for (f = 0; f < libraries[l].num_functions; f++) { if (libraries[l].functions[f].function_id == findex) { *library_return = libraries[l].name; *function_return = libraries[l].functions[f].name; return WS_TRUE; } } return WS_FALSE; } gateway-1.4.5/wmlscript/wsbc.c0000644000175000017500000010367213227613126015026 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsbc.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Byte-code handling functions. * */ #include "wsint.h" #include "wsbc.h" /********************* Prototypes for static functions ******************/ /* Add a new pragma of type `type' to the byte-code `bc'. The * function returns a pointer to an internal pragma structure that * must not be freed by the caller. It is freed when the byte-code * `bc' is freed. The function returns NULL if the pragma structure * could not be allocated. */ static WsBcPragma *add_pragma(WsBc *bc, WsBcPragmaType type); /********************* Manipulating byte-code structure *****************/ WsBc *ws_bc_alloc(WsBcStringEncoding string_encoding) { WsBc *bc = ws_calloc(1, sizeof(WsBc)); if (bc == NULL) return NULL; bc->string_encoding = string_encoding; return bc; } void ws_bc_free(WsBc *bc) { WsUInt16 i; WsUInt8 j; if (bc == NULL) return; /* Free constants. */ for (i = 0; i < bc->num_constants; i++) { WsBcConstant *c = &bc->constants[i]; if (c->type == WS_BC_CONST_TYPE_UTF8_STRING) ws_free(c->u.v_string.data); } ws_free(bc->constants); /* Free pragmas. */ ws_free(bc->pragmas); /* Free function names. */ for (j = 0; j < bc->num_function_names; j++) ws_free(bc->function_names[j].name); ws_free(bc->function_names); /* Free functions. */ for (j = 0; j < bc->num_functions; j++) ws_free(bc->functions[j].code); ws_free(bc->functions); /* Free the byte-code structure. */ ws_free(bc); } WsBool ws_bc_encode(WsBc *bc, unsigned char **data_return, size_t *data_len_return) { WsBuffer buffer; WsUInt32 ui; unsigned char data[64]; unsigned char *p, *mb; size_t len; ws_buffer_init(&buffer); /* Append space for the header. We do not know yet the size of the resulting byte-code. */ if (!ws_buffer_append_space(&buffer, NULL, WS_BC_MAX_HEADER_LEN)) goto error; /* Constants. */ if (!ws_encode_buffer(&buffer, WS_ENC_MB_UINT16, bc->num_constants, WS_ENC_MB_UINT16, (WsUInt16) bc->string_encoding, WS_ENC_END)) goto error; for (ui = 0 ; ui < bc->num_constants; ui++) { switch (bc->constants[ui].type) { case WS_BC_CONST_TYPE_INT: if (WS_INT8_MIN <= bc->constants[ui].u.v_int && bc->constants[ui].u.v_int <= WS_INT8_MAX) { if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT8, WS_ENC_INT8, (WsInt8) bc->constants[ui].u.v_int, WS_ENC_END)) goto error; } else if (WS_INT16_MIN <= bc->constants[ui].u.v_int && bc->constants[ui].u.v_int <= WS_INT16_MAX) { if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT16, WS_ENC_INT16, (WsInt16) bc->constants[ui].u.v_int, WS_ENC_END)) goto error; } else { if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_INT32, WS_ENC_INT32, bc->constants[ui].u.v_int, WS_ENC_END)) goto error; } break; case WS_BC_CONST_TYPE_FLOAT32: case WS_BC_CONST_TYPE_FLOAT32_NAN: case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF: case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF: switch (bc->constants[ui].type) { case WS_BC_CONST_TYPE_FLOAT32: ws_ieee754_encode_single(bc->constants[ui].u.v_float, data); p = data; break; case WS_BC_CONST_TYPE_FLOAT32_NAN: p = ws_ieee754_nan; break; case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF: p = ws_ieee754_positive_inf; break; case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF: p = ws_ieee754_negative_inf; break; default: ws_fatal("ws_bc_encode(): internal inconsistency"); /* NOTREACHED */ p = NULL; /* Initialized to keep compiler quiet. */ break; } if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_FLOAT32, WS_ENC_DATA, p, 4, WS_ENC_END)) goto error; break; break; case WS_BC_CONST_TYPE_UTF8_STRING: /* Encode the strings as requested. */ switch (bc->string_encoding) { case WS_BC_STRING_ENC_ISO_8859_1: { WsUtf8String *string = ws_utf8_alloc(); unsigned char *latin1; size_t latin1_len; WsBool success; if (string == NULL) goto error; /* Create an UTF-8 string. */ if (!ws_utf8_set_data(string, bc->constants[ui].u.v_string.data, bc->constants[ui].u.v_string.len)) { ws_utf8_free(string); goto error; } /* Convert it to latin1. */ latin1 = ws_utf8_to_latin1(string, '?', &latin1_len); /* We'r done with the UTF-8 string. */ ws_utf8_free(string); if (latin1 == NULL) goto error; /* Encode it. */ success = ws_encode_buffer( &buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_EXT_ENC_STRING, WS_ENC_MB_UINT32, (WsUInt32) latin1_len, WS_ENC_DATA, latin1, latin1_len, WS_ENC_END); ws_utf8_free_data(latin1); if (!success) goto error; } break; case WS_BC_STRING_ENC_UTF8: if (!ws_encode_buffer( &buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_UTF8_STRING, WS_ENC_MB_UINT32, (WsUInt32) bc->constants[ui].u.v_string.len, WS_ENC_DATA, bc->constants[ui].u.v_string.data, bc->constants[ui].u.v_string.len, WS_ENC_END)) goto error; break; } break; case WS_BC_CONST_TYPE_EMPTY_STRING: if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_CONST_EMPTY_STRING, WS_ENC_END)) goto error; break; } } /* Pragmas. */ if (!ws_encode_buffer(&buffer, WS_ENC_MB_UINT16, bc->num_pragmas, WS_ENC_END)) goto error; for (ui = 0; ui < bc->num_pragmas; ui++) { switch (bc->pragmas[ui].type) { case WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN: if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_PRAGMA_ACCESS_DOMAIN, WS_ENC_MB_UINT16, bc->pragmas[ui].index_1, WS_ENC_END)) goto error; break; case WS_BC_PRAGMA_TYPE_ACCESS_PATH: if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_PRAGMA_ACCESS_PATH, WS_ENC_MB_UINT16, bc->pragmas[ui].index_1, WS_ENC_END)) goto error; break; case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY: if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY, WS_ENC_MB_UINT16, bc->pragmas[ui].index_1, WS_ENC_MB_UINT16, bc->pragmas[ui].index_2, WS_ENC_END)) goto error; break; case WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME: if (!ws_encode_buffer( &buffer, WS_ENC_UINT8, (WsUInt8) WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME, WS_ENC_MB_UINT16, bc->pragmas[ui].index_1, WS_ENC_MB_UINT16, bc->pragmas[ui].index_2, WS_ENC_MB_UINT16, bc->pragmas[ui].index_3, WS_ENC_END)) goto error; break; } } /* Function pool. */ if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, bc->num_functions, WS_ENC_END)) goto error; /* Function names. */ if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, bc->num_function_names, WS_ENC_END)) goto error; for (ui = 0; ui < bc->num_function_names; ui++) { size_t name_len = strlen(bc->function_names[ui].name); if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, bc->function_names[ui].index, WS_ENC_UINT8, (WsUInt8) name_len, WS_ENC_DATA, bc->function_names[ui].name, name_len, WS_ENC_END)) goto error; } /* Functions. */ for (ui = 0; ui < bc->num_functions; ui++) { if (!ws_encode_buffer(&buffer, WS_ENC_UINT8, bc->functions[ui].num_arguments, WS_ENC_UINT8, bc->functions[ui].num_locals, WS_ENC_MB_UINT32, bc->functions[ui].code_size, WS_ENC_DATA, bc->functions[ui].code, (size_t) bc->functions[ui].code_size, WS_ENC_END)) goto error; } /* Fix the byte-code header. */ p = ws_buffer_ptr(&buffer); /* Encode the size of the byte-code excluding the byte-code header. */ mb = ws_encode_mb_uint32(ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN, data, &len); memcpy(p + WS_BC_MAX_HEADER_LEN - len, mb, len); /* Set the byte-code file version information. */ WS_PUT_UINT8(p + WS_BC_MAX_HEADER_LEN - len - 1, WS_BC_VERSION); /* Calculate the beginning of the bc-array and its size. */ *data_return = p + WS_BC_MAX_HEADER_LEN - len - 1; *data_len_return = ws_buffer_len(&buffer) - WS_BC_MAX_HEADER_LEN + len + 1; /* All done. */ return WS_TRUE; /* * Error handling. */ error: ws_buffer_uninit(&buffer); *data_return = NULL; *data_len_return = 0; return WS_FALSE; } void ws_bc_data_free(unsigned char *data) { size_t len = WS_MB_UINT32_MAX_ENCODED_LEN; if (data == NULL) return; /* Decode the mb-encoded length so we know how much space it uses. */ (void) ws_decode_mb_uint32(data + 1, &len); /* Now we can compute the beginning of the array `data'. */ ws_free(data - (WS_MB_UINT32_MAX_ENCODED_LEN - len)); } /* A helper macro to update the data pointers during the decoding of byte-code data. */ #define WS_UPDATE_DATA \ data += decoded; \ data_len -= decoded /* A helper macro to check the validity of the constant string index `idx'. */ #define WS_CHECK_STRING(idx) \ if ((idx) >= bc->num_constants \ || ((bc->constants[(idx)].type \ != WS_BC_CONST_TYPE_UTF8_STRING) \ && (bc->constants[(idx)].type \ != WS_BC_CONST_TYPE_EMPTY_STRING))) \ goto error; WsBc *ws_bc_decode(const unsigned char *data, size_t data_len) { WsBc *bc = ws_bc_alloc(WS_BC_STRING_ENC_ISO_8859_1); WsByte b; WsUInt32 ui32; WsUInt16 ui16, j; WsUInt16 ui16b; WsUInt8 ui8, num_functions, k, l; WsInt8 i8; WsInt16 i16; WsInt32 i32; WsIeee754Result ieee754; unsigned char *ucp; size_t decoded; /* Decode the byte-code header. */ decoded = ws_decode_buffer(data, data_len, WS_ENC_BYTE, &b, WS_ENC_MB_UINT32, &ui32, WS_ENC_END); if (!decoded || b != WS_BC_VERSION || ui32 != data_len - decoded) /* This is not a valid (or supported) byte-code header. */ goto error; WS_UPDATE_DATA; /* Constant pool. */ decoded = ws_decode_buffer(data, data_len, WS_ENC_MB_UINT16, &ui16, WS_ENC_MB_UINT16, &ui16b, WS_ENC_END); if (!decoded) goto error; bc->string_encoding = ui16b; bc->constants = ws_calloc(ui16, sizeof(WsBcConstant)); if (bc->constants == NULL) goto error; bc->num_constants = ui16; WS_UPDATE_DATA; for (j = 0; j < bc->num_constants; j++) { WsBcConstant *c = &bc->constants[j]; decoded = ws_decode_buffer(data, data_len, WS_ENC_UINT8, &ui8, WS_ENC_END); if (decoded != 1) goto error; WS_UPDATE_DATA; switch (ui8) { case WS_BC_CONST_INT8: decoded = ws_decode_buffer(data, data_len, WS_ENC_INT8, &i8, WS_ENC_END); if (decoded != 1) goto error; WS_UPDATE_DATA; c->type = WS_BC_CONST_TYPE_INT; c->u.v_int = i8; break; case WS_BC_CONST_INT16: decoded = ws_decode_buffer(data, data_len, WS_ENC_INT16, &i16, WS_ENC_END); if (decoded != 2) goto error; WS_UPDATE_DATA; c->type = WS_BC_CONST_TYPE_INT; c->u.v_int = i16; break; case WS_BC_CONST_INT32: decoded = ws_decode_buffer(data, data_len, WS_ENC_INT32, &i32, WS_ENC_END); if (decoded != 4) goto error; WS_UPDATE_DATA; c->type = WS_BC_CONST_TYPE_INT; c->u.v_int = i32; break; case WS_BC_CONST_FLOAT32: decoded = ws_decode_buffer(data, data_len, WS_ENC_DATA, &ucp, (size_t) 4, WS_ENC_END); if (decoded != 4) goto error; WS_UPDATE_DATA; ieee754 = ws_ieee754_decode_single(ucp, &c->u.v_float); switch (ieee754) { case WS_IEEE754_OK: c->type = WS_BC_CONST_TYPE_FLOAT32; break; case WS_IEEE754_NAN: c->type = WS_BC_CONST_TYPE_FLOAT32_NAN; break; case WS_IEEE754_POSITIVE_INF: c->type = WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF; break; case WS_IEEE754_NEGATIVE_INF: c->type = WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF; break; } break; case WS_BC_CONST_UTF8_STRING: decoded = ws_decode_buffer(data, data_len, WS_ENC_MB_UINT32, &ui32, WS_ENC_END); if (decoded == 0) goto error; WS_UPDATE_DATA; c->type = WS_BC_CONST_TYPE_UTF8_STRING; c->u.v_string.len = ui32; decoded = ws_decode_buffer(data, data_len, WS_ENC_DATA, &ucp, c->u.v_string.len, WS_ENC_END); if (decoded != ui32) goto error; WS_UPDATE_DATA; c->u.v_string.data = ws_memdup(ucp, ui32); if (c->u.v_string.data == NULL) goto error; /* Check the validity of the data. */ if (!ws_utf8_verify(c->u.v_string.data, c->u.v_string.len, &c->u.v_string.num_chars)) goto error; break; case WS_BC_CONST_EMPTY_STRING: c->type = WS_BC_CONST_TYPE_EMPTY_STRING; break; case WS_BC_CONST_EXT_ENC_STRING: ws_fatal("external character encoding not implemented yet"); break; default: /* Reserved. */ goto error; break; } } /* Pragma pool. */ decoded = ws_decode_buffer(data, data_len, WS_ENC_MB_UINT16, &ui16, WS_ENC_END); if (!decoded) goto error; bc->pragmas = ws_calloc(ui16, sizeof(WsBcPragma)); if (bc->pragmas == NULL) goto error; bc->num_pragmas = ui16; WS_UPDATE_DATA; for (j = 0; j < bc->num_pragmas; j++) { WsBcPragma *p = &bc->pragmas[j]; decoded = ws_decode_buffer(data, data_len, WS_ENC_UINT8, &ui8, WS_ENC_END); if (decoded != 1) goto error; WS_UPDATE_DATA; p->type = ui8; switch (ui8) { case WS_BC_PRAGMA_ACCESS_DOMAIN: decoded = ws_decode_buffer(data, data_len, WS_ENC_MB_UINT16, &p->index_1, WS_ENC_END); if (!decoded) goto error; WS_CHECK_STRING(p->index_1); break; case WS_BC_PRAGMA_ACCESS_PATH: decoded = ws_decode_buffer(data, data_len, WS_ENC_MB_UINT16, &p->index_1, WS_ENC_END); if (!decoded) goto error; WS_CHECK_STRING(p->index_1); break; case WS_BC_PRAGMA_USER_AGENT_PROPERTY: decoded = ws_decode_buffer(data, data_len, WS_ENC_MB_UINT16, &p->index_1, WS_ENC_MB_UINT16, &p->index_2, WS_ENC_END); if (!decoded) goto error; WS_CHECK_STRING(p->index_1); WS_CHECK_STRING(p->index_2); break; case WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME: decoded = ws_decode_buffer(data, data_len, WS_ENC_MB_UINT16, &p->index_1, WS_ENC_MB_UINT16, &p->index_2, WS_ENC_MB_UINT16, &p->index_3, WS_ENC_END); if (!decoded) goto error; WS_CHECK_STRING(p->index_1); WS_CHECK_STRING(p->index_2); WS_CHECK_STRING(p->index_3); break; default: goto error; break; } WS_UPDATE_DATA; } /* Function pool. */ decoded = ws_decode_buffer(data, data_len, WS_ENC_UINT8, &num_functions, WS_ENC_END); if (decoded != 1) goto error; WS_UPDATE_DATA; /* Function names. */ decoded = ws_decode_buffer(data, data_len, WS_ENC_UINT8, &ui8, WS_ENC_END); if (decoded != 1) goto error; WS_UPDATE_DATA; if (ui8) { /* We have function names. */ bc->function_names = ws_calloc(ui8, sizeof(WsBcFunctionName)); if (bc->function_names == NULL) goto error; bc->num_function_names = ui8; for (k = 0; k < bc->num_function_names; k++) { WsBcFunctionName *n = &bc->function_names[k]; decoded = ws_decode_buffer(data, data_len, WS_ENC_UINT8, &n->index, WS_ENC_UINT8, &ui8, WS_ENC_END); if (decoded != 2) goto error; WS_UPDATE_DATA; decoded = ws_decode_buffer(data, data_len, WS_ENC_DATA, &ucp, (size_t) ui8, WS_ENC_END); if (decoded != ui8) goto error; WS_UPDATE_DATA; n->name = ws_memdup(ucp, ui8); if (n->name == NULL) goto error; /* Check the validity of the name. */ if (!ws_utf8_verify((unsigned char *) n->name, ui8, NULL)) goto error; /* Just check that the data contains only valid characters. */ for (l = 0; l < ui8; l++) { unsigned int ch = (unsigned char) n->name[l]; if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ch == '_' || (l > 0 && ('0' <= ch && ch <= '9'))) /* Ok. */ continue; /* Invalid character in the function name. */ goto error; } /* Is the index valid? */ if (n->index >= num_functions) goto error; } } /* Functions. */ if (num_functions) { /* We have functions. */ bc->functions = ws_calloc(num_functions, sizeof(WsBcFunction)); if (bc->functions == NULL) goto error; bc->num_functions = num_functions; for (k = 0; k < bc->num_functions; k++) { WsBcFunction *f = &bc->functions[k]; decoded = ws_decode_buffer(data, data_len, WS_ENC_UINT8, &f->num_arguments, WS_ENC_UINT8, &f->num_locals, WS_ENC_MB_UINT32, &f->code_size, WS_ENC_END); if (!decoded) goto error; WS_UPDATE_DATA; decoded = ws_decode_buffer(data, data_len, WS_ENC_DATA, &ucp, f->code_size, WS_ENC_END); if (decoded != f->code_size) goto error; WS_UPDATE_DATA; if (f->code_size) { /* It is not an empty function. */ f->code = ws_memdup(ucp, f->code_size); if (f->code == NULL) goto error; } } } /* Did we process it all? */ if (data_len != 0) goto error; /* All done. */ return bc; /* * Error handling. */ error: ws_bc_free(bc); return NULL; } /********************* Adding constant elements *************************/ WsBool ws_bc_add_const_int(WsBc *bc, WsUInt16 *index_return, WsInt32 value) { WsUInt16 i; WsBcConstant *nc; /* Do we already have a suitable integer constant? */ for (i = 0; i < bc->num_constants; i++) { if (bc->constants[i].type == WS_BC_CONST_TYPE_INT && bc->constants[i].u.v_int == value) { *index_return = i; return WS_TRUE; } } /* Must add a new constant. */ nc = ws_realloc(bc->constants, (bc->num_constants + 1) * sizeof(WsBcConstant)); if (nc == NULL) return WS_FALSE; bc->constants = nc; bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_INT; bc->constants[bc->num_constants].u.v_int = value; *index_return = bc->num_constants++; return WS_TRUE; } WsBool ws_bc_add_const_float(WsBc *bc, WsUInt16 *index_return, WsFloat value) { WsUInt16 i; WsBcConstant *nc; /* Do we already have a suitable float32 constant? */ for (i = 0; i < bc->num_constants; i++) { if (bc->constants[i].type == WS_BC_CONST_TYPE_FLOAT32 && bc->constants[i].u.v_float == value) { *index_return = i; return WS_TRUE; } } /* Must add a new constant. */ nc = ws_realloc(bc->constants, (bc->num_constants + 1) * sizeof(WsBcConstant)); if (nc == NULL) return WS_FALSE; bc->constants = nc; bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_FLOAT32; bc->constants[bc->num_constants].u.v_float = value; *index_return = bc->num_constants++; return WS_TRUE; } WsBool ws_bc_add_const_utf8_string(WsBc *bc, WsUInt16 *index_return, const unsigned char *data, size_t len) { WsUInt16 i; WsBcConstant *nc; /* Do we already have a suitable UFT-8 constant? */ for (i = 0; i < bc->num_constants; i++) { if (bc->constants[i].type == WS_BC_CONST_TYPE_UTF8_STRING && bc->constants[i].u.v_string.len == len && memcmp(bc->constants[i].u.v_string.data, data, len) == 0) { *index_return = i; return WS_TRUE; } } /* Must add a new constant. */ nc = ws_realloc(bc->constants, (bc->num_constants + 1) * sizeof(WsBcConstant)); if (nc == NULL) return WS_FALSE; bc->constants = nc; bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_UTF8_STRING; bc->constants[bc->num_constants].u.v_string.len = len; bc->constants[bc->num_constants].u.v_string.data = ws_memdup(data, len); if (bc->constants[bc->num_constants].u.v_string.data == NULL) return WS_FALSE; *index_return = bc->num_constants++; return WS_TRUE; } WsBool ws_bc_add_const_empty_string(WsBc *bc, WsUInt16 *index_return) { WsUInt16 i; WsBcConstant *nc; /* Do we already have a suitable empty string constant? */ for (i = 0; i < bc->num_constants; i++) { if (bc->constants[i].type == WS_BC_CONST_TYPE_EMPTY_STRING) { *index_return = i; return WS_TRUE; } } /* Must add a new constant. */ nc = ws_realloc(bc->constants, (bc->num_constants + 1) * sizeof(WsBcConstant)); if (nc == NULL) return WS_FALSE; bc->constants = nc; bc->constants[bc->num_constants].type = WS_BC_CONST_TYPE_EMPTY_STRING; *index_return = bc->num_constants++; return WS_TRUE; } /********************* Adding pragmas ***********************************/ WsBool ws_bc_add_pragma_access_domain(WsBc *bc, const unsigned char *domain, size_t domain_len) { WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN); if (p == NULL) return WS_FALSE; if (!ws_bc_add_const_utf8_string(bc, &p->index_1, domain, domain_len)) return WS_FALSE; return WS_TRUE; } WsBool ws_bc_add_pragma_access_path(WsBc *bc, const unsigned char *path, size_t path_len) { WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_ACCESS_PATH); if (p == NULL) return WS_FALSE; if (!ws_bc_add_const_utf8_string(bc, &p->index_1, path, path_len)) return WS_FALSE; return WS_TRUE; } WsBool ws_bc_add_pragma_user_agent_property(WsBc *bc, const unsigned char *name, size_t name_len, const unsigned char *property, size_t property_len) { WsBcPragma *p = add_pragma(bc, WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY); if (p == NULL) return WS_FALSE; if (!ws_bc_add_const_utf8_string(bc, &p->index_1, name, name_len) || !ws_bc_add_const_utf8_string(bc, &p->index_2, property, property_len)) return WS_FALSE; return WS_TRUE; } WsBool ws_bc_add_pragma_user_agent_property_and_scheme( WsBc *bc, const unsigned char *name, size_t name_len, const unsigned char *property, size_t property_len, const unsigned char *scheme, size_t scheme_len) { WsBcPragma *p; p = add_pragma(bc, WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME); if (p == NULL) return WS_FALSE; if (!ws_bc_add_const_utf8_string(bc, &p->index_1, name, name_len) || !ws_bc_add_const_utf8_string(bc, &p->index_2, property, property_len) || !ws_bc_add_const_utf8_string(bc, &p->index_3, scheme, scheme_len)) return WS_FALSE; return WS_TRUE; } /********************* Adding functions *********************************/ WsBool ws_bc_add_function(WsBc *bc, WsUInt8 *index_return, char *name, WsUInt8 num_arguments, WsUInt8 num_locals, WsUInt32 code_size, unsigned char *code) { WsBcFunction *nf; /* First, add the function to the function pool. */ nf = ws_realloc(bc->functions, (bc->num_functions + 1) * sizeof(WsBcFunction)); if (nf == NULL) return WS_FALSE; bc->functions = nf; bc->functions[bc->num_functions].num_arguments = num_arguments; bc->functions[bc->num_functions].num_locals = num_locals; bc->functions[bc->num_functions].code_size = code_size; bc->functions[bc->num_functions].code = ws_memdup(code, code_size); if (bc->functions[bc->num_functions].code == NULL) return WS_FALSE; /* Save the index of the function. */ *index_return = bc->num_functions++; /* For external functions (which have name), add a name entry to the function name pool. */ if (name) { WsBcFunctionName *nfn; nfn = ws_realloc(bc->function_names, ((bc->num_function_names + 1) * sizeof(WsBcFunctionName))); if (nfn == NULL) return WS_FALSE; bc->function_names = nfn; bc->function_names[bc->num_function_names].index = *index_return; bc->function_names[bc->num_function_names].name = ws_strdup(name); if (bc->function_names[bc->num_function_names].name == NULL) return WS_FALSE; bc->num_function_names++; } /* All done. */ return WS_TRUE; } /********************* Static functions *********************************/ static WsBcPragma *add_pragma(WsBc *bc, WsBcPragmaType type) { WsBcPragma *np; /* Add a new pragma slot. */ np = ws_realloc(bc->pragmas, (bc->num_pragmas + 1) * sizeof(WsBcPragma)); if (np == NULL) return NULL; bc->pragmas = np; bc->pragmas[bc->num_pragmas].type = type; return &bc->pragmas[bc->num_pragmas++]; } gateway-1.4.5/wmlscript/wsasm.c0000644000175000017500000007240213227613126015216 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsasm.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Byte-code assembler. * */ #include "wsint.h" #include "wsasm.h" #include "wsstdlib.h" /********************* Macros to fetch items from BC operands ***********/ #define WS_OPNAME(op) (operands[(op)].name) #define WS_OPSIZE(op) (operands[(op)].size) /********************* Byte-code operands *******************************/ static struct { char *name; int size; } operands[256] = { #include "wsopcodes.h" }; /********************* Symbolic assembler instructions ******************/ /* General helpers. */ void ws_asm_link(WsCompiler *compiler, WsAsmIns *ins) { if (compiler->asm_tail) { compiler->asm_tail->next = ins; ins->prev = compiler->asm_tail; compiler->asm_tail = ins; } else compiler->asm_tail = compiler->asm_head = ins; } void ws_asm_print(WsCompiler *compiler) { WsAsmIns *ins; for (ins = compiler->asm_head; ins; ins = ins->next) { if (ins->type > 0xff) { /* A symbolic operand. */ switch (ins->type) { case WS_ASM_P_LABEL: ws_fprintf(WS_STDOUT, ".L%d:\t\t\t\t/* refcount=%d */\n", ins->ws_label_idx, ins->ws_label_refcount); break; case WS_ASM_P_JUMP: ws_fprintf(WS_STDOUT, "\tjump*\t\tL%d\n", ins->ws_label->ws_label_idx); break; case WS_ASM_P_TJUMP: ws_fprintf(WS_STDOUT, "\ttjump*\t\tL%d\n", ins->ws_label->ws_label_idx); break; case WS_ASM_P_CALL: ws_fprintf(WS_STDOUT, "\tcall*\t\t%s\n", compiler->functions[ins->ws_findex].name); break; case WS_ASM_P_CALL_LIB: { const char *lib; const char *func; ws_stdlib_function_name(ins->ws_lindex, ins->ws_findex, &lib, &func); ws_fprintf(WS_STDOUT, "\tcall_lib*\t%s.%s\n", lib ? lib : "???", func ? func : "???"); } break; case WS_ASM_P_CALL_URL: ws_fprintf(WS_STDOUT, "\tcall_url*\t%u %u %u\n", ins->ws_lindex, ins->ws_findex, ins->ws_args); break; case WS_ASM_P_LOAD_VAR: ws_fprintf(WS_STDOUT, "\tload_var*\t%u\n", ins->ws_vindex); break; case WS_ASM_P_STORE_VAR: ws_fprintf(WS_STDOUT, "\tstore_var*\t%u\n", ins->ws_vindex); break; case WS_ASM_P_INCR_VAR: ws_fprintf(WS_STDOUT, "\tincr_var*\t%u\n", ins->ws_vindex); break; case WS_ASM_P_LOAD_CONST: ws_fprintf(WS_STDOUT, "\tload_const*\t%u\n", ins->ws_cindex); break; } } else { WsUInt8 op = WS_ASM_OP(ins->type); if (operands[op].name) { /* Operands add_asg and sub_asg are special. */ if (op == WS_ASM_ADD_ASG || op == WS_ASM_SUB_ASG) ws_fprintf(WS_STDOUT, "\t%s\t\t%u\n", operands[ins->type].name, ins->ws_vindex); else ws_fprintf(WS_STDOUT, "\t%s\n", operands[ins->type].name); } else ws_fatal("ws_asm_print(): unknown operand 0x%x", op); } } } void ws_asm_dasm(WsCompilerPtr compiler, const unsigned char *code, size_t len) { size_t i = 0; while (i < len) { WsUInt8 byt = code[i]; WsUInt8 op; WsUInt8 arg; WsUInt8 i8, j8, k8; WsUInt16 i16, j16; op = WS_ASM_OP(byt); arg = WS_ASM_ARG(byt); ws_fprintf(WS_STDOUT, "%4x:\t%-16s", i, WS_OPNAME(op)); switch (op) { /* The `short jumps'. */ case WS_ASM_JUMP_FW_S: case WS_ASM_TJUMP_FW_S: ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + arg); break; case WS_ASM_JUMP_BW_S: ws_fprintf(WS_STDOUT, "%x\n", i - arg); break; /* Jumps with WsUInt8 argument. */ case WS_ASM_JUMP_FW: case WS_ASM_TJUMP_FW: WS_GET_UINT8(code + i + 1, i8); ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + i8); break; case WS_ASM_JUMP_BW: case WS_ASM_TJUMP_BW: WS_GET_UINT8(code + i + 1, i8); ws_fprintf(WS_STDOUT, "%x\n", i - i8); break; /* Jumps with wide argument. */ case WS_ASM_JUMP_FW_W: case WS_ASM_TJUMP_FW_W: WS_GET_UINT16(code + i + 1, i16); ws_fprintf(WS_STDOUT, "%x\n", i + WS_OPSIZE(op) + i16); break; case WS_ASM_JUMP_BW_W: case WS_ASM_TJUMP_BW_W: WS_GET_UINT16(code + i + 1, i16); ws_fprintf(WS_STDOUT, "%x\n", i - i16); break; /* The `short' opcodes. */ case WS_ASM_LOAD_VAR_S: case WS_ASM_STORE_VAR_S: case WS_ASM_INCR_VAR_S: ws_fprintf(WS_STDOUT, "%d\n", arg); break; /* Local script function calls. */ case WS_ASM_CALL_S: ws_fprintf(WS_STDOUT, "%d\n", arg); break; case WS_ASM_CALL: WS_GET_UINT8(code + i + 1, i8); ws_fprintf(WS_STDOUT, "%d\n", i8); break; /* Library calls. */ case WS_ASM_CALL_LIB_S: case WS_ASM_CALL_LIB: case WS_ASM_CALL_LIB_W: { WsUInt8 findex; WsUInt16 lindex; char lnamebuf[64]; char fnamebuf[64]; const char *lname; const char *fname; if (op == WS_ASM_CALL_LIB_S) { WS_GET_UINT8(code + i + 1, lindex); findex = arg; } else if (op == WS_ASM_CALL_LIB) { WS_GET_UINT8(code + i + 1, findex); WS_GET_UINT8(code + i + 2, lindex); } else { WS_GET_UINT8(code + i + 1, findex); WS_GET_UINT16(code + i + 2, lindex); } if (!ws_stdlib_function_name(lindex, findex, &lname, &fname)) { snprintf(lnamebuf, sizeof(lnamebuf), "%d", lindex); snprintf(fnamebuf, sizeof(lnamebuf), "%d", findex); lname = lnamebuf; fname = fnamebuf; } ws_fprintf(WS_STDOUT, "%s.%s\n", lname, fname); } break; /* URL calls. */ case WS_ASM_CALL_URL: WS_GET_UINT8(code + i + 1, i8); WS_GET_UINT8(code + i + 2, j8); WS_GET_UINT8(code + i + 3, k8); ws_fprintf(WS_STDOUT, "%d.%d %d\n", i8, j8, k8); break; case WS_ASM_CALL_URL_W: WS_GET_UINT16(code + i + 1, i16); WS_GET_UINT16(code + i + 3, j16); WS_GET_UINT8(code + i + 5, i8); ws_fprintf(WS_STDOUT, "%d.%d %d\n", i16, j16, i8); break; /* Constant access. */ case WS_ASM_LOAD_CONST_S: case WS_ASM_LOAD_CONST: case WS_ASM_LOAD_CONST_W: if (op == WS_ASM_LOAD_CONST_S) i16 = arg; else if (op == WS_ASM_LOAD_CONST) { WS_GET_UINT8(code + i + 1, i8); i16 = i8; } else WS_GET_UINT16(code + i + 1, i16); ws_fprintf(WS_STDOUT, "%d\n", i16); break; /* Operands with WsUInt8 argument. */ case WS_ASM_LOAD_VAR: case WS_ASM_STORE_VAR: case WS_ASM_INCR_VAR: case WS_ASM_DECR_VAR: case WS_ASM_ADD_ASG: case WS_ASM_SUB_ASG: WS_GET_UINT8(code + i + 1, i8); ws_fprintf(WS_STDOUT, "%d\n", i8); break; /* The trivial cases. */ default: ws_fprintf(WS_STDOUT, "\n"); break; } i += WS_OPSIZE(op); } } void ws_asm_linearize(WsCompiler *compiler) { WsAsmIns *ins; WsBool process_again = WS_TRUE; /* Calculate all offsets and select real assembler instructions for our internal pseudo instructions. This is continued as long as the code changes. */ while (process_again) { WsUInt32 offset = 1; process_again = WS_FALSE; for (ins = compiler->asm_head; ins; ins = ins->next) { ins->offset = offset; switch (ins->type) { case WS_ASM_JUMP_FW_S: ins->ws_offset = (ins->ws_label->offset - (offset + WS_OPSIZE(ins->type))); break; case WS_ASM_JUMP_FW: ins->ws_offset = (ins->ws_label->offset - (offset + WS_OPSIZE(ins->type))); if (ins->ws_offset <= 31) { ins->type = WS_ASM_JUMP_FW_S; process_again = WS_TRUE; } break; case WS_ASM_JUMP_FW_W: ins->ws_offset = (ins->ws_label->offset - (offset + WS_OPSIZE(ins->type))); if (ins->ws_offset <= 31) { ins->type = WS_ASM_JUMP_FW_S; process_again = WS_TRUE; } else if (ins->ws_offset <= 255) { ins->type = WS_ASM_JUMP_FW; process_again = WS_TRUE; } break; case WS_ASM_JUMP_BW_S: ins->ws_offset = offset - ins->ws_label->offset; break; case WS_ASM_JUMP_BW: ins->ws_offset = offset - ins->ws_label->offset; if (ins->ws_offset <= 31) { ins->type = WS_ASM_JUMP_BW_S; process_again = WS_TRUE; } break; case WS_ASM_JUMP_BW_W: ins->ws_offset = offset - ins->ws_label->offset; if (ins->ws_offset <= 31) { ins->type = WS_ASM_JUMP_BW_S; process_again = WS_TRUE; } else if (ins->ws_offset <= 255) { ins->type = WS_ASM_JUMP_BW; process_again = WS_TRUE; } break; case WS_ASM_TJUMP_FW_S: ins->ws_offset = (ins->ws_label->offset - (offset + WS_OPSIZE(ins->type))); break; case WS_ASM_TJUMP_FW: ins->ws_offset = (ins->ws_label->offset - (offset + WS_OPSIZE(ins->type))); if (ins->ws_offset <= 31) { ins->type = WS_ASM_TJUMP_FW_S; process_again = WS_TRUE; } break; case WS_ASM_TJUMP_FW_W: ins->ws_offset = (ins->ws_label->offset - (offset + WS_OPSIZE(ins->type))); if (ins->ws_offset <= 31) { ins->type = WS_ASM_TJUMP_FW_S; process_again = WS_TRUE; } else if (ins->ws_offset <= 255) { ins->type = WS_ASM_TJUMP_FW; process_again = WS_TRUE; } break; case WS_ASM_TJUMP_BW: ins->ws_offset = offset - ins->ws_label->offset; break; case WS_ASM_TJUMP_BW_W: ins->ws_offset = offset - ins->ws_label->offset; if (ins->ws_offset <= 255) { ins->type = WS_ASM_TJUMP_BW; process_again = WS_TRUE; } break; /* * The pseudo instructions. */ case WS_ASM_P_LABEL: /* Nothing here. */ break; case WS_ASM_P_JUMP: if (ins->ws_label->offset == 0) { /* A forward jump. Let's assume the widest form. */ ins->type = WS_ASM_JUMP_FW_W; } else { ins->ws_offset = offset - ins->ws_label->offset; /* Jump backwards. */ if (ins->ws_offset <= 31) { ins->type = WS_ASM_JUMP_BW_S; } else if (ins->ws_offset <= 255) { ins->type = WS_ASM_JUMP_BW; } else { ins->type = WS_ASM_JUMP_BW_W; } } break; case WS_ASM_P_TJUMP: if (ins->ws_label->offset == 0) { /* A forward jump. Let's assume the widest form. */ ins->type = WS_ASM_TJUMP_FW_W; process_again = WS_TRUE; } else { ins->ws_offset = offset - ins->ws_label->offset; /* Jump backwards. */ if (ins->ws_offset <= 255) { ins->type = WS_ASM_TJUMP_BW; } else { ins->type = WS_ASM_TJUMP_BW_W; } } break; case WS_ASM_P_CALL: if (ins->ws_findex <= 7) { /* The most compact form. */ ins->type = WS_ASM_CALL_S; } else { /* The wider form. */ ins->type = WS_ASM_CALL; } break; case WS_ASM_P_CALL_LIB: if (ins->ws_findex <= 7 && ins->ws_lindex <= 255) { /* The most compact form. */ ins->type = WS_ASM_CALL_LIB_S; } else if (ins->ws_findex <= 255 && ins->ws_lindex <= 255) { /* The quite compact form. */ ins->type = WS_ASM_CALL_LIB; } else { /* The most liberal form. */ ins->type = WS_ASM_CALL_LIB_W; } break; case WS_ASM_P_CALL_URL: if (ins->ws_findex <= 255 && ins->ws_lindex <= 255) /* The compact form. */ ins->type = WS_ASM_CALL_URL; else ins->type = WS_ASM_CALL_URL_W; break; case WS_ASM_P_LOAD_VAR: if (ins->ws_vindex <= 31) /* The compact form. */ ins->type = WS_ASM_LOAD_VAR_S; else ins->type = WS_ASM_LOAD_VAR; break; case WS_ASM_P_STORE_VAR: if (ins->ws_vindex <= 15) ins->type = WS_ASM_STORE_VAR_S; else ins->type = WS_ASM_STORE_VAR; break; case WS_ASM_P_INCR_VAR: if (ins->ws_vindex <= 7) ins->type = WS_ASM_INCR_VAR_S; else ins->type = WS_ASM_INCR_VAR; break; case WS_ASM_P_LOAD_CONST: if (ins->ws_cindex <= 15) ins->type = WS_ASM_LOAD_CONST_S; else if (ins->ws_cindex <= 255) ins->type = WS_ASM_LOAD_CONST; else ins->type = WS_ASM_LOAD_CONST_W; break; } gw_assert(ins->type == WS_ASM_P_LABEL || ins->type < 0x100); if (ins->type != WS_ASM_P_LABEL) { gw_assert(operands[ins->type].name != NULL); offset += operands[ins->type].size; } } } /* Ok, ready to linearize the byte-code. */ for (ins = compiler->asm_head; ins; ins = ins->next) { if (ins->type == WS_ASM_P_LABEL) continue; gw_assert(ins->type <= 0xff); switch (ins->type) { case WS_ASM_JUMP_FW_S: case WS_ASM_JUMP_BW_S: case WS_ASM_TJUMP_FW_S: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, WS_ASM_GLUE(ins->type, ins->ws_offset), WS_ENC_END)) goto error; break; case WS_ASM_JUMP_FW: case WS_ASM_JUMP_BW: case WS_ASM_TJUMP_FW: case WS_ASM_TJUMP_BW: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_offset, WS_ENC_END)) goto error; break; case WS_ASM_JUMP_FW_W: case WS_ASM_JUMP_BW_W: case WS_ASM_TJUMP_FW_W: case WS_ASM_TJUMP_BW_W: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, ins->type, WS_ENC_UINT16, (WsUInt16) ins->ws_offset, WS_ENC_END)) goto error; break; case WS_ASM_CALL_S: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, WS_ASM_GLUE(ins->type, ins->ws_findex), WS_ENC_END)) goto error; break; case WS_ASM_CALL: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_findex, WS_ENC_END)) goto error; break; case WS_ASM_CALL_LIB_S: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, WS_ASM_GLUE(ins->type, ins->ws_findex), WS_ENC_UINT8, (WsUInt8) ins->ws_lindex, WS_ENC_END)) goto error; break; case WS_ASM_CALL_LIB: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_findex, WS_ENC_UINT8, (WsUInt8) ins->ws_lindex, WS_ENC_END)) goto error; break; case WS_ASM_CALL_LIB_W: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_findex, WS_ENC_UINT16, (WsUInt16) ins->ws_lindex, WS_ENC_END)) goto error; break; case WS_ASM_CALL_URL: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_lindex, WS_ENC_UINT8, (WsUInt8) ins->ws_findex, WS_ENC_UINT8, (WsUInt8) ins->ws_args, WS_ENC_END)) goto error; break; case WS_ASM_CALL_URL_W: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT16, (WsUInt16) ins->ws_lindex, WS_ENC_UINT16, (WsUInt16) ins->ws_findex, WS_ENC_UINT8, (WsUInt8) ins->ws_args, WS_ENC_END)) goto error; break; case WS_ASM_LOAD_VAR_S: case WS_ASM_STORE_VAR_S: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, WS_ASM_GLUE(ins->type, ins->ws_vindex), WS_ENC_END)) goto error; break; case WS_ASM_LOAD_VAR: case WS_ASM_STORE_VAR: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_vindex, WS_ENC_END)) goto error; break; case WS_ASM_INCR_VAR_S: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, WS_ASM_GLUE(ins->type, ins->ws_vindex), WS_ENC_END)) goto error; break; case WS_ASM_INCR_VAR: case WS_ASM_DECR_VAR: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_vindex, WS_ENC_END)) goto error; break; case WS_ASM_LOAD_CONST_S: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, WS_ASM_GLUE(ins->type, ins->ws_cindex), WS_ENC_END)) goto error; break; case WS_ASM_LOAD_CONST: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_cindex, WS_ENC_END)) goto error; break; case WS_ASM_LOAD_CONST_W: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT16, (WsUInt16) ins->ws_cindex, WS_ENC_END)) goto error; break; case WS_ASM_ADD_ASG: case WS_ASM_SUB_ASG: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_UINT8, (WsUInt8) ins->ws_vindex, WS_ENC_END)) goto error; break; case WS_ASM_CONST_0: case WS_ASM_CONST_1: case WS_ASM_CONST_M1: case WS_ASM_CONST_ES: case WS_ASM_CONST_INVALID: case WS_ASM_CONST_TRUE: case WS_ASM_CONST_FALSE: case WS_ASM_INCR: case WS_ASM_DECR: case WS_ASM_UMINUS: case WS_ASM_ADD: case WS_ASM_SUB: case WS_ASM_MUL: case WS_ASM_DIV: case WS_ASM_IDIV: case WS_ASM_REM: case WS_ASM_B_AND: case WS_ASM_B_OR: case WS_ASM_B_XOR: case WS_ASM_B_NOT: case WS_ASM_B_LSHIFT: case WS_ASM_B_RSSHIFT: case WS_ASM_B_RSZSHIFT: case WS_ASM_EQ: case WS_ASM_LE: case WS_ASM_LT: case WS_ASM_GE: case WS_ASM_GT: case WS_ASM_NE: case WS_ASM_NOT: case WS_ASM_SCAND: case WS_ASM_SCOR: case WS_ASM_TOBOOL: case WS_ASM_POP: case WS_ASM_TYPEOF: case WS_ASM_ISVALID: case WS_ASM_RETURN: case WS_ASM_RETURN_ES: case WS_ASM_DEBUG: if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) ins->type, WS_ENC_END)) goto error; break; default: ws_fatal("ws_asm_linearize(): unknown instruction 0x%02x", ins->type); break; } } /* * Avoid generating 0-length functions, because not all clients * handle them correctly. */ if (ws_buffer_len(&compiler->byte_code) == 0) { if (!ws_encode_buffer(&compiler->byte_code, WS_ENC_BYTE, (WsByte) WS_ASM_RETURN_ES, WS_ENC_END)) goto error; } return; /* * Error handling. */ error: ws_error_memory(compiler); return; } /* Contructors for assembler instructions. */ static WsAsmIns *asm_alloc(WsCompiler *compiler, WsUInt16 type, WsUInt32 line) { WsAsmIns *ins = ws_f_calloc(compiler->pool_asm, 1, sizeof(*ins)); if (ins == NULL) ws_error_memory(compiler); else { ins->type = type; ins->line = line; } return ins; } WsAsmIns *ws_asm_label(WsCompiler *compiler, WsUInt32 line) { WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_LABEL, line); if (ins) ins->ws_label_idx = compiler->next_label++; return ins; } WsAsmIns *ws_asm_branch(WsCompiler *compiler, WsUInt32 line, WsUInt16 inst, WsAsmIns *label) { WsAsmIns *ins = asm_alloc(compiler, inst, line); if (ins) { ins->ws_label = label; label->ws_label_refcount++; } return ins; } WsAsmIns *ws_asm_call(WsCompiler *compiler, WsUInt32 line, WsUInt8 findex) { WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL, line); if (ins) ins->ws_findex = findex; return ins; } WsAsmIns *ws_asm_call_lib(WsCompiler *compiler, WsUInt32 line, WsUInt8 findex, WsUInt16 lindex) { WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL_LIB, line); if (ins) { ins->ws_findex = findex; ins->ws_lindex = lindex; } return ins; } WsAsmIns *ws_asm_call_url(WsCompiler *compiler, WsUInt32 line, WsUInt16 findex, WsUInt16 urlindex, WsUInt8 args) { WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_CALL_URL, line); if (ins) { ins->ws_findex = findex; ins->ws_lindex = urlindex; ins->ws_args = args; } return ins; } WsAsmIns *ws_asm_variable(WsCompiler *compiler, WsUInt32 line, WsUInt16 inst, WsUInt8 vindex) { WsAsmIns *ins = asm_alloc(compiler, inst, line); if (ins) ins->ws_vindex = vindex; return ins; } WsAsmIns *ws_asm_load_const(WsCompiler *compiler, WsUInt32 line, WsUInt16 cindex) { WsAsmIns *ins = asm_alloc(compiler, WS_ASM_P_LOAD_CONST, line); if (ins) ins->ws_cindex = cindex; return ins; } WsAsmIns *ws_asm_ins(WsCompiler *compiler, WsUInt32 line, WsUInt8 opcode) { return asm_alloc(compiler, opcode, line); } gateway-1.4.5/wmlscript/wshash.h0000644000175000017500000001144613227613126015367 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wshash.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * A mapping from null-terminated strings to `void *' pointers. * */ #ifndef WSHASH_H #define WSHASH_H /********************* Types and definitions ****************************/ /* A hash handle. */ typedef struct WsHashRec *WsHashPtr; /* A callback function of this type is called to free the data item `item' when the hash is destroyed, or a new mapping is set for the key of the item `item'. The argument `context' is a user specified context data for the function. */ typedef void (*WsHashItemDestructor)(void *item, void *context); /********************* Prototypes for global functions ******************/ /* Create a new hash table. The argument `destructor' is a destructor function that is called once for each deleted item. The argument `context' is passed as context data to the destructor function. The argument `destructor' can be NULL in which case the mapped items are not freed. The function returns NULL if the creation failed (out of memory). */ WsHashPtr ws_hash_create(WsHashItemDestructor destructor, void *contex); /* Destroy the hash `hash' and free all resources it has allocated. If the hash has a destructor function, it is called once for each mapped item. */ void ws_hash_destroy(WsHashPtr hash); /* Add a mapping from the name `name' to the data `data'. The function takes a copy of the name `name' but the data `data' is stored as-is. The possible old data, stored for the name `name', will be freed with the destructor function. The function returns WS_TRUE if the operatio was successful or WS_FALSE otherwise. */ WsBool ws_hash_put(WsHashPtr hash, const char *name, void *data); /* Get the mapping of the name `name' from the hash `hash'. */ void *ws_hash_get(WsHashPtr hash, const char *name); /* Clear the hash and free all individual items with the destructor function. After this call, the hash `hash' does not contain any mappings. */ void ws_hash_clear(WsHashPtr hash); #endif /* not WSHASH_H */ gateway-1.4.5/wmlscript/ws.h0000644000175000017500000002362313227613126014523 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * ws.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Public header file for the WMLScript compiler library. * * The compiler is written for WMLScript version 1.1. * */ #ifndef WS_H #define WS_H #include "wsutf8.h" /********************* Creating and destroying compiler *****************/ /* A callback function of this type is called to output compiler's diagnostic, error, and warning messages. The argument `data' has `len' bytes of data that should be output somehow to user. The argument `context' is the user-specified context data for the callback function. */ typedef void (*WsIOProc)(const char *data, size_t len, void *context); /* A callback function of this type is called for each `use meta name' and `use meta http equiv' pragma, found from the current compilation unit. The arguments `property_name', `content', and `scheme' are the meta-body arguments of the pragma. They can be manipulated with the functions of the `wsutf8.h' module. The argument `scheme' can have the value NULL if the pragma did not specify it. The string arguments belong to the WMLScript compiler and you should not modify or free them. The argument `context' is the user-specified context data for the callback function. */ typedef void (*WsPragmaMetaProc)(const WsUtf8String *property_name, const WsUtf8String *content, const WsUtf8String *scheme, void *context); /* Parameters for a WMLScript copiler. */ struct WsCompilerParamsRec { /* Features. */ /* Store string constants in ISO-8859/1 (ISO latin1) format. The default format is UTF-8. This option makes a bit smaller byte-code files but it loses information for non-latin1 languages. */ unsigned int use_latin1_strings : 1; /* Warning flags. */ /* Warn if a standard library function is called with mismatching argument types. */ unsigned int warn_stdlib_type_mismatch : 1; /* Optimization flags. */ /* Do not perform constant folding. */ unsigned int no_opt_constant_folding : 1; /* Do not sort byte-code functions by their usage counts. */ unsigned int no_opt_sort_bc_functions : 1; /* Do not perform peephole optimization. */ unsigned int no_opt_peephole : 1; /* Do not optimize jumps to jump instructions to jump directly to the target label of the next instruction. */ unsigned int no_opt_jumps_to_jumps : 1; /* Do not optimize jumps to the next instruction. */ unsigned int no_opt_jumps_to_next_instruction : 1; /* Do not remove unreachable code. */ unsigned int no_opt_dead_code : 1; /* Do not remove useless conversions */ unsigned int no_opt_conv : 1; /* Perform expensive optimizations which require liveness analyzation of the local variables. */ unsigned int opt_analyze_variable_liveness : 1; /* Output flags. */ /* Print verbose progress messages. */ unsigned int verbose : 1; /* Print symbolic assembler to the stdout. */ unsigned int print_symbolic_assembler : 1; /* Disassemble the resulting byte-code instructions. */ unsigned int print_assembler : 1; /* Function pointers to receive standard output and error messages. If these are unset, the outputs are directed to the system's standard output and error streams. */ /* Standard output. */ WsIOProc stdout_cb; void *stdout_cb_context; /* Standard error. */ WsIOProc stderr_cb; void *stderr_cb_context; /* A callback function which is called for each `use meta name' pragma, found from the current compilation unit. */ WsPragmaMetaProc meta_name_cb; void *meta_name_cb_context; /* A callback function which is called for each `use meta http equiv' pragma, found from the current compilation unit. */ WsPragmaMetaProc meta_http_equiv_cb; void *meta_http_equiv_cb_context; }; typedef struct WsCompilerParamsRec WsCompilerParams; /* A compiler handle. */ typedef struct WsCompilerRec *WsCompilerPtr; /* Create a new WMLScript compiler. The argument `params' specifies initialization parameters for the compiler. If the argument `params' is NULL or any of its fiels have value 0 or NULL, the default values will be used for those parameters. The function takes a copy of the value of the `params' argument. You can free it after this call. The function returns NULL if the operation fails (out of memory). */ WsCompilerPtr ws_create(WsCompilerParams *params); /* Destroy the WMLScript compiler `compiler' and free all resources it has allocated. */ void ws_destroy(WsCompilerPtr compiler); /********************* Compiling WMLScript ******************************/ /* Returns codes for the compiler functions. */ typedef enum { /* Successful termination */ WS_OK, /* The compiler ran out of memory. */ WS_ERROR_OUT_OF_MEMORY, /* The input was not syntactically correct. */ WS_ERROR_SYNTAX, /* The input was not semantically correct. */ WS_ERROR_SEMANTIC, /* IO error. */ WS_ERROR_IO, /* A generic `catch-all' error code. This should not be used. More descriptive error messages should be generated instead. */ WS_ERROR } WsResult; /* Compile the WMLScript input file `input' with the compiler `compiler' and save the generated byte-code output to the file `output'. The argument `input_name' is the name of the input file `input'. It is used in error messages. The function returns a success code that describes the result of the compilation. The output file `output' is modified only if the result code is `WS_OK'. */ WsResult ws_compile_file(WsCompilerPtr compiler, const char *input_name, FILE *input, FILE *output); /* Compile the `input_len' bytes of WMLScript data in `input' with the compiler `compiler'. The data is assumed to be in the ISO-8859/1 (ISO latin1) format. The resulting byte-code is returned in `output_return' and its length is returned in `output_len_return'. The argument `input_name' is the name of the input data `input_data'. It is used in error messages. The function returns a success code that describes the result of the compilation. The output in `output_return' is valid only if the result code is `WS_OK'. The byte-code, returned in `output_return', must be freed with the ws_free_byte_code() function after it is not needed anymore. It is a fatal error to free it with any other function, like free(). */ WsResult ws_compile_data(WsCompilerPtr compiler, const char *input_name, const unsigned char *input, size_t input_len, unsigned char **output_return, size_t *output_len_return); /* Free the byte-code buffer `byte_code', returned by ws_compiler_data() function. The byte-code `byte_code' must not be used after this function has been called. */ void ws_free_byte_code(unsigned char *byte_code); /* Convert the result code `result' into human readable 7 bit ASCII string. */ const char *ws_result_to_string(WsResult result); #endif /* not WS_H */ gateway-1.4.5/wmlscript/wsstree.h0000644000175000017500000004663313227613126015574 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsstree.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Syntax tree creation, manipulation and byte-code assembler * generation. * */ #ifndef WSSTREE_H #define WSSTREE_H /********************* Linked list for syntax tree items ****************/ /* A list item. */ struct WsListItemRec { struct WsListItemRec *next; void *data; }; typedef struct WsListItemRec WsListItem; /* The linked list object. */ struct WsListRec { WsListItem *head; WsListItem *tail; WsUInt32 num_items; /* These are used in blocks to record the first and last line information. They might also be used in other grammar constructs. */ WsUInt32 first_line; WsUInt32 last_line; }; typedef struct WsListRec WsList; /* Create a new syntax tree linked list for the compiler `compiler'. The list is allocated from the `compiler->pool_stree' fast malloc pool. */ WsList *ws_list_new(WsCompilerPtr compiler); /* Append the item `value' to the end of the list `list'. The item is allocated from the `compiler->pool_stree' fast malloc pool. */ void ws_list_append(WsCompilerPtr compiler, WsList *list, void *value); /********************* Namespace for arguments and locals ***************/ /* A namespace record. */ struct WsNamespaceRec { /* The line where this argument or local variable is declared. */ WsUInt32 line; /* The index of this variable. */ WsUInt8 vindex; }; typedef struct WsNamespaceRec WsNamespace; /* Create a new variable hash. */ WsHashPtr ws_variable_hash_create(void); /* Define the new local variable or argument `name' to the local variables namespace. The argument `line' specifies the location where the variable `name' is defined. The argument `variablep' is WS_TRUE for local variables and WS_FALSE for arguments. The function performs all necessary initializations and sanity checks needed. It will also report errors, etc. The function returns NULL if there were any errors. */ WsNamespace *ws_variable_define(WsCompilerPtr compiler, WsUInt32 line, WsBool variablep, char *name); /* Lookup the variable `name' from the variables namespace. The function returns NULL if the variable `name' is undefined. The function does not report any errors. */ WsNamespace *ws_variable_lookup(WsCompilerPtr compiler, char *name); /********************* Top-level declarations ***************************/ /* An external compilation unit pragma. */ struct WsPragmaUseRec { /* The line number of the pragma. */ WsUInt32 line; /* The byte-code pool constant index of the external compilation unit URL. */ WsUInt16 urlindex; }; typedef struct WsPragmaUseRec WsPragmaUse; /* Create a hash for the external compilation unit pragmas. */ WsHashPtr ws_pragma_use_hash_create(void); /* Add a new external compilation unit pragma to the compiler `compiler'. The function inserts the URL string `url' to the byte-code structure of the compiler `compiler'. It updates the external compilation unit hash to have mapping from the identifier `identifier' to the URL `url' (or its constant index). The function reports errors if the identifier `identifier' does already have a mapping the external compilation unit namespace. */ void ws_pragma_use(WsCompilerPtr compiler, WsUInt32 line, char *identifier, WsUtf8String *url); /* MetaBody handling of the `use meta' pragmas. */ struct WsPragmaMetaBodyRec { WsUtf8String *property_name; WsUtf8String *content; WsUtf8String *scheme; }; typedef struct WsPragmaMetaBodyRec WsPragmaMetaBody; /* Create a meta body pragma. */ WsPragmaMetaBody *ws_pragma_meta_body(WsCompilerPtr compiler, WsUtf8String *property_name, WsUtf8String *content, WsUtf8String *scheme); /* Free the MetaBody `mb'. */ void ws_pragma_meta_body_free(WsCompilerPtr compiler, WsPragmaMetaBody *mb); /* A top-level function declaration. */ struct WsFunctionRec { WsUInt8 findex; WsBool externp; char *name; WsUInt32 line; WsList *params; WsList *block; /* The usage count of this function. This is used when sorting the functions by their usage count. */ WsUInt32 usage_count; }; typedef struct WsFunctionRec WsFunction; /* Function hash item. The function hash contains mapping from the function names and their usage counts to the actual function declaration. */ struct WsFunctionHashRec { /* Does this mapping have a function declaration. */ WsBool defined; /* If declared, this is the index. */ WsUInt8 findex; WsUInt32 usage_count; }; typedef struct WsFunctionHashRec WsFunctionHash; /* Create a new hash for functions. */ WsHashPtr ws_function_hash_create(void); /* Returns a pointer to the function hash item for the function name `name'. The function creates a new hash slot if the name `name' is currently unknown. The function returns NULL if the memory allocation failed. */ WsFunctionHash *ws_function_hash(WsCompilerPtr compiler, char *name); /* Add a new function definition to the compiler `compiler'. The argument `externp' specifies whether the function is extern or not. The argument `name' is the name of the function. The function name is ws_malloc() allocated and must be freed when it is not needed anymore. The argument `line' specifies the definition location of the function. It is the line where the function name was in the source stream. The argument `params' contains the formal parameters of the function and its body is specified in the argument `block'. */ void ws_function(WsCompilerPtr compiler, WsBool externp, char *name, WsUInt32 line, WsList *params, WsList *block); /********************* Expressions **************************************/ /* Expression types. */ typedef enum { WS_EXPR_COMMA, WS_EXPR_ASSIGN, WS_EXPR_CONDITIONAL, WS_EXPR_LOGICAL, WS_EXPR_BINARY, WS_EXPR_UNARY, WS_EXPR_UNARY_VAR, WS_EXPR_POSTFIX_VAR, WS_EXPR_CALL, WS_EXPR_SYMBOL, WS_EXPR_CONST_INVALID, WS_EXPR_CONST_TRUE, WS_EXPR_CONST_FALSE, WS_EXPR_CONST_INTEGER, WS_EXPR_CONST_FLOAT, WS_EXPR_CONST_STRING } WsExpressionType; /* An expression. */ struct WsExpressionRec { WsExpressionType type; WsUInt32 line; union { struct { struct WsExpressionRec *left; struct WsExpressionRec *right; } comma; struct { /* The identifier that is modified. */ char *identifier; /* The type of the assignment. This is the assignment token value: '=', tMULA, tDA, ... */ int op; /* The expression to assign to the identifier `identifier'. */ struct WsExpressionRec *expr; } assign; struct { struct WsExpressionRec *e_cond; struct WsExpressionRec *e_then; struct WsExpressionRec *e_else; } conditional; struct { /* The type is the opcode of the short-circuit logical byte-code operand. */ int type; struct WsExpressionRec *left; struct WsExpressionRec *right; } logical; struct { /* The type is the opcode of the binary byte-code operand. */ int type; struct WsExpressionRec *left; struct WsExpressionRec *right; } binary; struct { /* The type is the opcode of the unary byte-code operand. */ int type; struct WsExpressionRec *expr; } unary; struct { /* Is this an unary addition or substraction. */ WsBool addp; char *variable; } unary_var; struct { /* Is this a postfix addition or substraction. */ WsBool addp; char *variable; } postfix_var; struct { /* The type of the call: ' ', '#', '.' */ int type; /* The name of the external module or library. */ char *base; /* The name of the function to call. */ char *name; /* The arguments of the call. */ WsList *arguments; } call; struct { /* Separate sign bit, so that we can tell the difference * between -2147483648 and +2147483648. We have to deal * with both, because the former is parsed as "-" "2147483648". * Sign is 1 for positive numbers, -1 for negative numbers, * and can be either 1 or -1 for zero. */ int sign; WsUInt32 ival; } integer; char *symbol; WsUInt16 cindex; WsFloat fval; WsUtf8String string; } u; }; typedef struct WsExpressionRec WsExpression; /* Linearize the expression `expr' into symbolic byte-code assembler. */ void ws_expr_linearize(WsCompilerPtr compiler, WsExpression *expr); /* Constructors for different expression types. */ /* Create a comma expression for `left' and `right'. */ WsExpression *ws_expr_comma(WsCompilerPtr compiler, WsUInt32 line, WsExpression *left, WsExpression *right); /* Create an assignment expression. The argument `type' specifies the type of the expression. It is the assignment token value. */ WsExpression *ws_expr_assign(WsCompilerPtr compiler, WsUInt32 line, char *identifier, int op, WsExpression *expr); /* Create a conditional expression with condition `e_cond' and expressions `e_then' and `e_else'. */ WsExpression *ws_expr_conditional(WsCompilerPtr compiler, WsUInt32 line, WsExpression *e_cond, WsExpression *e_then, WsExpression *e_else); /* Create a logical expression of type `type'. The argument `type' is the opcode of the logical shoft-circuit byte-code operand. */ WsExpression *ws_expr_logical(WsCompilerPtr compiler, WsUInt32 line, int type, WsExpression *left, WsExpression *right); /* Create a binary expression of type `type'. The argument `type' is the opcode of the binary byte-code operand. */ WsExpression *ws_expr_binary(WsCompilerPtr compiler, WsUInt32 line, int type, WsExpression *left, WsExpression *right); /* Create an unary expression of type `type'. The argument `type' is the opcode of the unary byte-code operand. */ WsExpression *ws_expr_unary(WsCompilerPtr compiler, WsUInt32 line, int type, WsExpression *expr); /* Create an unary variable modification expression. The argument `addp' specified whether the expression is an addition (++) or a substraction (--) expression. */ WsExpression *ws_expr_unary_var(WsCompilerPtr compiler, WsUInt32 line, WsBool addp, char *variable); /* Create a postfix variable modification expression. The argument `addp' specified whether the expression is an addition (++) or a substraction (--) expression. */ WsExpression *ws_expr_postfix_var(WsCompilerPtr compiler, WsUInt32 line, WsBool addp, char *variable); /* A generic call expression. The argument `type' must be one of ' ', '#', or '.' for local, extern, or library function call respectively. */ WsExpression *ws_expr_call(WsCompilerPtr compiler, WsUInt32 linenum, int type, char *base, char *name, WsList *arguments); /* A symbol reference expression. */ WsExpression *ws_expr_symbol(WsCompilerPtr compiler, WsUInt32 linenum, char *identifier); /* Constant `invalid'. */ WsExpression *ws_expr_const_invalid(WsCompilerPtr compiler, WsUInt32 linenum); /* Constant `true'. */ WsExpression *ws_expr_const_true(WsCompilerPtr compiler, WsUInt32 linenum); /* Constant `false'. */ WsExpression *ws_expr_const_false(WsCompilerPtr compiler, WsUInt32 linenum); /* An unsigned 32 bit integer. */ WsExpression *ws_expr_const_integer(WsCompilerPtr compiler, WsUInt32 linenum, WsUInt32 ival); /* A floating point number. */ WsExpression *ws_expr_const_float(WsCompilerPtr compiler, WsUInt32 linenum, WsFloat fval); /* An UTF-8 encoded string. */ WsExpression *ws_expr_const_string(WsCompilerPtr compiler, WsUInt32 linenum, WsUtf8String *string); /********************* Misc syntax tree structures **********************/ /* A variable declaration */ struct WsVarDecRec { char *name; WsExpression *expr; }; typedef struct WsVarDecRec WsVarDec; /* Create a new variable declaration */ WsVarDec *ws_variable_declaration(WsCompilerPtr compiler, char *name, WsExpression *expr); /* A function formal parameter */ struct WsFormalParmRec { WsUInt32 line; char *name; }; typedef struct WsFormalParmRec WsFormalParm; /* Create a new formal parameter */ WsFormalParm *ws_formal_parameter(WsCompilerPtr compiler, WsUInt32 line, char *name); /********************* Statements ***************************************/ /* Statement types. */ typedef enum { WS_STMT_BLOCK, WS_STMT_VARIABLE, WS_STMT_EMPTY, WS_STMT_EXPR, WS_STMT_IF, WS_STMT_FOR, WS_STMT_WHILE, WS_STMT_CONTINUE, WS_STMT_BREAK, WS_STMT_RETURN } WsStatementType; /* A statement. */ struct WsStatementRec { WsStatementType type; WsUInt32 first_line; WsUInt32 last_line; union { WsList *block; WsList *var; WsExpression *expr; struct { WsExpression *expr; struct WsStatementRec *s_then; struct WsStatementRec *s_else; } s_if ; struct { WsList *init; WsExpression *e1; WsExpression *e2; WsExpression *e3; struct WsStatementRec *stmt; } s_for ; struct { WsExpression *expr; struct WsStatementRec *stmt; } s_while ; } u; }; typedef struct WsStatementRec WsStatement; /* Linearize the statement `stmt' into symbolic byte-code assembler. */ void ws_stmt_linearize(WsCompilerPtr compiler, WsStatement *stmt); /* Constructors for statements. */ /* Create a new block statement from the statements `block'. The arguments `first_line' and `last_line' specify the first and last line numbers of the block (the line numbers of the '{' and '}' tokens). */ WsStatement *ws_stmt_block(WsCompilerPtr compiler, WsUInt32 first_line, WsUInt32 last_line, WsList *block); /* Create a new variable initialization statement. */ WsStatement *ws_stmt_variable(WsCompilerPtr compiler, WsUInt32 line, WsList *variables); /* Create a new empty statement. */ WsStatement *ws_stmt_empty(WsCompilerPtr compiler, WsUInt32 line); /* Create a new expression statement. */ WsStatement *ws_stmt_expr(WsCompilerPtr compiler, WsUInt32 line, WsExpression *expr); /* Create a new if statement. */ WsStatement *ws_stmt_if (WsCompilerPtr compiler, WsUInt32 line, WsExpression *expr, WsStatement *s_then, WsStatement *s_else); /* Create a new for statement. Only one of the arguments `init' and `e1' can be defined. The init must be given for statements which has a VariableDeclarationList in the initialization block. For the C-like statements, the argument `e1' must be given for the initialization expression. */ WsStatement *ws_stmt_for (WsCompilerPtr compiler, WsUInt32 line, WsList *init, WsExpression *e1, WsExpression *e2, WsExpression *e3, WsStatement *stmt); /* Create a new while statement. */ WsStatement *ws_stmt_while (WsCompilerPtr compiler, WsUInt32 line, WsExpression *expr, WsStatement *stmt); /* Create a new continue statement. */ WsStatement *ws_stmt_continue(WsCompilerPtr compiler, WsUInt32 line); /* Create a new break statement. */ WsStatement *ws_stmt_break(WsCompilerPtr compiler, WsUInt32 line); /* Create a new return statement. The argument `expr' is the expression to return. If it is NULL, the return statement returns an empty string. */ WsStatement *ws_stmt_return(WsCompilerPtr compiler, WsUInt32 line, WsExpression *expr); #endif /* not WSSTREE_H */ gateway-1.4.5/wmlscript/wmlsdasm.10000644000175000017500000000063007166363552015635 0ustar toljtolj.\" Hey, Emacs! This is an -*- nroff -*- source file. .TH WMLSDASM 1 "3rd October 2000" "Kannel Project" "Kannel Project" .SH NAME wmlsdasm \- WMLScript disassembler .SH SYNOPSIS .B wmlsdasm .BR "" [ -cfnh ] .IR file ... .SH DESCRIPTION .B wmlsdasm un-compilers WMLScript bytecode files into a source version. It is useful for debugging the WMLScript compiler. .SH "SEE ALSO" .BR wmlsc (1), .BR kannel (8). gateway-1.4.5/wmlscript/wsbuffer.c0000644000175000017500000001025513227613126015705 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsbuffer.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * A multipurpose buffer. * */ #include "wsint.h" /********************* Global functions *********************************/ void ws_buffer_init(WsBuffer *buffer) { buffer->len = 0; buffer->data = NULL; } void ws_buffer_uninit(WsBuffer *buffer) { ws_free(buffer->data); buffer->len = 0; buffer->data = NULL; } WsBuffer *ws_buffer_alloc() { return ws_calloc(1, sizeof(WsBuffer)); } void ws_buffer_free(WsBuffer *buffer) { ws_free(buffer->data); ws_free(buffer); } WsBool ws_buffer_append(WsBuffer *buffer, unsigned char *data, size_t len) { unsigned char *p; if (!ws_buffer_append_space(buffer, &p, len)) return WS_FALSE; memcpy(p, data, len); return WS_TRUE; } WsBool ws_buffer_append_space(WsBuffer *buffer, unsigned char **p, size_t size) { unsigned char *ndata = ws_realloc(buffer->data, buffer->len + size); if (ndata == NULL) return WS_FALSE; buffer->data = ndata; if (p) *p = buffer->data + buffer->len; buffer->len += size; return WS_TRUE; } unsigned char *ws_buffer_ptr(WsBuffer *buffer) { return buffer->data; } size_t ws_buffer_len(WsBuffer *buffer) { return buffer->len; } unsigned char *ws_buffer_steal(WsBuffer *buffer) { unsigned char *p = buffer->data; buffer->data = NULL; buffer->len = 0; return p; } gateway-1.4.5/wmlscript/lexer.txt0000644000175000017500000000150207040615663015575 0ustar toljtolj Lexer entities ============== * Reserved Words The `div=' is actually puctuation. access agent break case catch class const continue debugger default delete div div= do domain else enum equiv export extends extern false finally for function header http if import in invalid isvalid lib meta name new null path private public return sizeof struct super switch this throw true try typeof url use user var void while with * Punctuation (Plus comment starters) ! != # % %= & && &= ( ) * *= + ++ += , - -- -= . can be followed by [0-9] => DecimalFloatLiteral / /* block comment // single-line comment /= : ; < << <<= <= = == > >= >> >>= >>> >>>= ? ^ ^= { | |= || } ~ * Strings start with ' or " * Numbers: 0xHexDigit 0XHexDigit 0 [1-9][0-9]* 0[0-7]+ floats start with `DecimalIntegerLiteral' or '.'gateway-1.4.5/wmlscript/wmlsdasm.c0000644000175000017500000002412113227613126015706 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wmlsdasm.c * * Author: Markku Rossi * * Copyright (c) 2000 WAPIT OY LTD. * All rights reserved. * * Disassembler for WMLScript byte-code. * */ #include "wsint.h" #include "gwlib/gwlib.h" #include /* TODO: - print pragmas - option to disassemble only a named external function - print constants in assembler => wsasm.c */ /********************* Prototypes for static functions ******************/ /* Print usage message to the stdout. */ static void usage(void); /* Lookup the name of the function `index' from the function names section of the byte-code structure `bc'. The function returns NULL if the function is internal. */ const char *lookup_function(WsBc *bc, WsUInt8 index); /********************* Static variables *********************************/ /* The name of the compiler program. */ static char *program; /********************* Global functions *********************************/ int main(int argc, char *argv[]) { int i; int opt; WsBool print_constants = WS_FALSE; WsBool print_function_names = WS_FALSE; WsBool print_functions = WS_FALSE; WsUInt8 k; WsUInt16 j; program = strrchr(argv[0], '/'); if (program) program++; else program = argv[0]; /* Process command line arguments. */ while ((opt = getopt(argc, argv, "cfnh")) != EOF) { switch (opt) { case 'c': print_constants = WS_TRUE; break; case 'f': print_functions = WS_TRUE; break; case 'n': print_function_names = WS_TRUE; break; case 'h': usage(); exit(0); break; case '?': printf("Try `%s -h' for a complete list of options.\n", program); exit(1); } } for (i = optind; i < argc; i++) { FILE *fp; struct stat stat_st; unsigned char *data; size_t data_len; WsBc *bc; if (stat(argv[i], &stat_st) < 0) { fprintf(stderr, "%s: could not access `%s': %s\n", program, argv[i], strerror(errno)); exit(1); } data_len = stat_st.st_size; data = ws_malloc(data_len); if (data == NULL) { fprintf(stderr, "%s: out of memory: %s\n", program, strerror(errno)); exit(1); } fp = fopen(argv[i], "rb"); if (fp == NULL) { fprintf(stderr, "%s: could not open input file `%s': %s\n", program, argv[i], strerror(errno)); exit(1); } if (fread(data, 1, data_len, fp) != data_len) { fprintf(stderr, "%s: could not read file `%s': %s\n", program, argv[i], strerror(errno)); exit(1); } fclose(fp); /* Decode byte-code. */ bc = ws_bc_decode(data, data_len); if (bc == NULL) { fprintf(stderr, "%s: invalid byte-code file `%s'\n", program, argv[i]); continue; } /* Print all requested data. */ printf("\n%s:\t%lu bytes\n\n", argv[i], (unsigned long) data_len); if (print_constants) { printf("Disassembly of section Constants:\n\n"); for (j = 0; j < bc->num_constants; j++) { printf("%4d:\t", j); switch (bc->constants[j].type) { case WS_BC_CONST_TYPE_INT: printf("%ld\n", (long) bc->constants[j].u.v_int); break; case WS_BC_CONST_TYPE_FLOAT32: printf("%f\n", bc->constants[j].u.v_float); break; case WS_BC_CONST_TYPE_FLOAT32_NAN: printf("NaN\n"); break; case WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF: printf("+infinity\n"); break; case WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF: printf("-infinity\n"); break; case WS_BC_CONST_TYPE_UTF8_STRING: { size_t pos = 0; size_t column = 8; unsigned long ch; printf("\""); while (ws_utf8_get_char(&bc->constants[j].u.v_string, &ch, &pos)) { if (ch < ' ') { printf("\\%02lx", ch); column += 3; } else if (ch <= 0xff) { printf("%c", (unsigned char) ch); column++; } else { printf("\\u%04lx", ch); column += 5; } if (column >= 75) { printf("\"\n\t\""); column = 8; } } printf("\"\n"); } break; case WS_BC_CONST_TYPE_EMPTY_STRING: printf("\"\"\n"); break; } } } if (print_function_names) { printf("Disassembly of section Function names:\n\n"); for (k = 0; k < bc->num_function_names; k++) printf(" %-40.40s%8d\n", bc->function_names[k].name, bc->function_names[k].index); } if (print_functions) { WsCompilerPtr compiler = ws_create(NULL); printf("Disassembly of section Functions:\n"); for (k = 0; k < bc->num_functions; k++) { const char *name = lookup_function(bc, k); printf("\nFunction %u", (unsigned int) k); if (name) printf(" <%s>", name); printf(":\n"); ws_asm_dasm(compiler, bc->functions[k].code, bc->functions[k].code_size); } ws_destroy(compiler); } if (!print_constants && !print_function_names && !print_functions) { printf("Sections:\n\ Name\t\t Items\n\ Constants\t%8d\n\ Pragmas\t%8d\n\ Function names\t%8d\n\ Functions\t%8d\n", bc->num_constants, bc->num_pragmas, bc->num_function_names, bc->num_functions); } ws_bc_free(bc); } return 0; } /********************* Static functions *********************************/ static void usage(void) { printf("Usage: %s OPTION... FILE...\n\ \n\ -c print constants\n\ -f disassemble functions\n\ -n print function names\n\ -h print this help message and exit successfully\n\ \n", program); } const char *lookup_function(WsBc *bc, WsUInt8 index) { WsUInt8 i; for (i = 0; i < bc->num_function_names; i++) if (bc->function_names[i].index == index) return bc->function_names[i].name; return NULL; } gateway-1.4.5/wmlscript/wsasm.h0000644000175000017500000002744513227613126015232 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsasm.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Byte-code assembler definitions. * */ #ifndef WSASM_H #define WSASM_H /********************* Opcodes for the ASM instructions *****************/ /* The instruction classes. */ /* Class 1: 1xxPPPPP */ #define WS_ASM_CLASS1P(op) (((op) & 0x80) == 0x80) #define WS_ASM_CLASS1_OP(op) ((op) & 0xe0) #define WS_ASM_CLASS1_ARG(op) ((op) & 0x1f) /* Class 2: 010xPPPP */ #define WS_ASM_CLASS2P(op) (((op) & 0xe0) == 0x40) #define WS_ASM_CLASS2_OP(op) ((op) & 0xf0) #define WS_ASM_CLASS2_ARG(op) ((op) & 0x0f) /* Class 3: 011xxPPP */ #define WS_ASM_CLASS3P(op) (((op) & 0xe0) == 0x60) #define WS_ASM_CLASS3_OP(op) ((op) & 0x78) #define WS_ASM_CLASS3_ARG(op) ((op) & 0x07) /* Class 4: 00xxxxxx */ #define WS_ASM_CLASS4P(op) (((op) & 0xc0) == 0x00) #define WS_ASM_CLASS4_OP(op) (op) /* Get the opcode of the operand `op'. The operand `op' can belong to any of the classes 1-4. */ #define WS_ASM_OP(op) \ (WS_ASM_CLASS1P(op) \ ? WS_ASM_CLASS1_OP(op) \ : (WS_ASM_CLASS2P(op) \ ? WS_ASM_CLASS2_OP(op) \ : (WS_ASM_CLASS3P(op) \ ? WS_ASM_CLASS3_OP(op) \ : WS_ASM_CLASS4_OP(op)))) /* Get the implicit argument of the operand `op'. The operand `op' can belong to any of the classes 1-4. For the class 4 operands, this returns 0. */ #define WS_ASM_ARG(op) \ (WS_ASM_CLASS1P(op) \ ? WS_ASM_CLASS1_ARG(op) \ : (WS_ASM_CLASS2P(op) \ ? WS_ASM_CLASS2_ARG(op) \ : (WS_ASM_CLASS3P(op) \ ? WS_ASM_CLASS3_ARG(op) \ : 0))) /* Create an operand with implicit argument from the operand `op' and argument `arg'. */ #define WS_ASM_GLUE(op, arg) ((WsByte) (((WsByte) (op)) | ((WsByte) (arg)))) /* The instruction opcodes. Opcode Binary Size */ #define WS_ASM_JUMP_FW_S 0x80 /* 10000000 1 */ #define WS_ASM_JUMP_FW 0x01 /* 00000001 2 */ #define WS_ASM_JUMP_FW_W 0x02 /* 00000010 3 */ #define WS_ASM_JUMP_BW_S 0xa0 /* 10100000 1 */ #define WS_ASM_JUMP_BW 0x03 /* 00000011 2 */ #define WS_ASM_JUMP_BW_W 0x04 /* 00000100 3 */ #define WS_ASM_TJUMP_FW_S 0xc0 /* 11000000 1 */ #define WS_ASM_TJUMP_FW 0x05 /* 00000101 2 */ #define WS_ASM_TJUMP_FW_W 0x06 /* 00000110 3 */ #define WS_ASM_TJUMP_BW 0x07 /* 00000111 2 */ #define WS_ASM_TJUMP_BW_W 0x08 /* 00001000 3 */ #define WS_ASM_CALL_S 0x60 /* 01100000 1 */ #define WS_ASM_CALL 0x09 /* 00001001 2 */ #define WS_ASM_CALL_LIB_S 0x68 /* 01101000 2 */ #define WS_ASM_CALL_LIB 0x0a /* 00001010 3 */ #define WS_ASM_CALL_LIB_W 0x0b /* 00001011 4 */ #define WS_ASM_CALL_URL 0x0c /* 00001100 4 */ #define WS_ASM_CALL_URL_W 0x0d /* 00001101 6 */ #define WS_ASM_LOAD_VAR_S 0xe0 /* 11100000 1 */ #define WS_ASM_LOAD_VAR 0x0e /* 00001110 2 */ #define WS_ASM_STORE_VAR_S 0x40 /* 01000000 1 */ #define WS_ASM_STORE_VAR 0x0f /* 00001111 2 */ #define WS_ASM_INCR_VAR_S 0x70 /* 01110000 1 */ #define WS_ASM_INCR_VAR 0x10 /* 00010000 2 */ #define WS_ASM_DECR_VAR 0x11 /* 00010001 2 */ #define WS_ASM_LOAD_CONST_S 0x50 /* 01010000 1 */ #define WS_ASM_LOAD_CONST 0x12 /* 00010010 2 */ #define WS_ASM_LOAD_CONST_W 0x13 /* 00010011 3 */ #define WS_ASM_CONST_0 0x14 /* 00010100 1 */ #define WS_ASM_CONST_1 0x15 /* 00010101 1 */ #define WS_ASM_CONST_M1 0x16 /* 00010110 1 */ #define WS_ASM_CONST_ES 0x17 /* 00010111 1 */ #define WS_ASM_CONST_INVALID 0x18 /* 00011000 1 */ #define WS_ASM_CONST_TRUE 0x19 /* 00011001 1 */ #define WS_ASM_CONST_FALSE 0x1a /* 00011010 1 */ #define WS_ASM_INCR 0x1b /* 00011011 1 */ #define WS_ASM_DECR 0x1c /* 00011100 1 */ #define WS_ASM_ADD_ASG 0x1d /* 00011101 2 */ #define WS_ASM_SUB_ASG 0x1e /* 00011110 2 */ #define WS_ASM_UMINUS 0x1f /* 00011111 1 */ #define WS_ASM_ADD 0x20 /* 00100000 1 */ #define WS_ASM_SUB 0x21 /* 00100001 1 */ #define WS_ASM_MUL 0x22 /* 00100010 1 */ #define WS_ASM_DIV 0x23 /* 00100011 1 */ #define WS_ASM_IDIV 0x24 /* 00100100 1 */ #define WS_ASM_REM 0x25 /* 00100101 1 */ #define WS_ASM_B_AND 0x26 /* 00100110 1 */ #define WS_ASM_B_OR 0x27 /* 00100111 1 */ #define WS_ASM_B_XOR 0x28 /* 00101000 1 */ #define WS_ASM_B_NOT 0x29 /* 00101001 1 */ #define WS_ASM_B_LSHIFT 0x2a /* 00101010 1 */ #define WS_ASM_B_RSSHIFT 0x2b /* 00101011 1 */ #define WS_ASM_B_RSZSHIFT 0x2c /* 00101100 1 */ #define WS_ASM_EQ 0x2d /* 00101101 1 */ #define WS_ASM_LE 0x2e /* 00101110 1 */ #define WS_ASM_LT 0x2f /* 00101111 1 */ #define WS_ASM_GE 0x30 /* 00110000 1 */ #define WS_ASM_GT 0x31 /* 00110001 1 */ #define WS_ASM_NE 0x32 /* 00110010 1 */ #define WS_ASM_NOT 0x33 /* 00110011 1 */ #define WS_ASM_SCAND 0x34 /* 00110100 1 */ #define WS_ASM_SCOR 0x35 /* 00110101 1 */ #define WS_ASM_TOBOOL 0x36 /* 00110110 1 */ #define WS_ASM_POP 0x37 /* 00110111 1 */ #define WS_ASM_TYPEOF 0x38 /* 00111000 1 */ #define WS_ASM_ISVALID 0x39 /* 00111001 1 */ #define WS_ASM_RETURN 0x3a /* 00111010 1 */ #define WS_ASM_RETURN_ES 0x3b /* 00111011 1 */ #define WS_ASM_DEBUG 0x3c /* 00111100 1 */ /********************* Pseudo opcodes for assembler *********************/ /* These are pseudo opcodes grouping together several real byte-code opcodes. These are used in the symbolic assembler. */ #define WS_ASM_P_LABEL 0x0100 #define WS_ASM_P_JUMP 0x0200 #define WS_ASM_P_TJUMP 0x0300 #define WS_ASM_P_CALL 0x0400 #define WS_ASM_P_CALL_LIB 0x0500 #define WS_ASM_P_CALL_URL 0x0600 #define WS_ASM_P_LOAD_VAR 0x0700 #define WS_ASM_P_STORE_VAR 0x0800 #define WS_ASM_P_INCR_VAR 0x0900 #define WS_ASM_P_LOAD_CONST 0x0a00 /* Check whether the instruction `ins' is a pseudo-branch instruction. */ #define WS_ASM_P_BRANCH(ins) \ ((ins)->type == WS_ASM_P_JUMP || (ins)->type == WS_ASM_P_TJUMP) /********************* Symbolic assembler instructions ******************/ #define ws_label_idx u.ivalues.i1 #define ws_label_refcount u.ivalues.i2 #define ws_findex u.ivalues.i1 #define ws_lindex u.ivalues.i2 #define ws_args u.ivalues.i3 #define ws_vindex u.ivalues.i1 #define ws_cindex u.ivalues.i1 #define ws_label u.branch.label #define ws_offset u.branch.offset struct WsAsmInsRec { struct WsAsmInsRec *next; struct WsAsmInsRec *prev; WsUInt16 type; /* The source stream line number. */ WsUInt32 line; /* The operands offset in the linearized byte-code stream. */ WsUInt32 offset; union { /* The target label for branch instructions. */ struct { struct WsAsmInsRec *label; /* The offset argument of the branch operand. This is the adjustment that must be performed for the pc after this instruction. */ WsUInt32 offset; } branch; struct { WsUInt32 i1; WsUInt16 i2; WsUInt16 i3; } ivalues; } u; }; typedef struct WsAsmInsRec WsAsmIns; /* Link the instruction `ins' to the end of the symbolic assembler chain, currently being constructed in `compiler'. */ void ws_asm_link(WsCompilerPtr compiler, WsAsmIns *ins); /* Print the current assembler instructions of the compiler `compiler'. */ void ws_asm_print(WsCompilerPtr compiler); /* Disassemble the byte-code `code', `len' to the standard output. */ void ws_asm_dasm(WsCompilerPtr compiler, const unsigned char *code, size_t len); /* Linearize the assembler, currently being constructed in `compiler', into `compiler->byte_code'. */ void ws_asm_linearize(WsCompilerPtr compiler); /* Constructors for assembler instructions. */ /* Create a label instruction. */ WsAsmIns *ws_asm_label(WsCompilerPtr compiler, WsUInt32 line); /* Create a branch instruction `ins' to label `label'. */ WsAsmIns *ws_asm_branch(WsCompilerPtr compiler, WsUInt32 line, WsUInt16 ins, WsAsmIns *label); /* Create a local call instruction to function `findex'. */ WsAsmIns *ws_asm_call(WsCompilerPtr compiler, WsUInt32 line, WsUInt8 findex); /* Create a library call instruction to function `findex' from the libary `lindex'. */ WsAsmIns *ws_asm_call_lib(WsCompilerPtr compiler, WsUInt32 line, WsUInt8 findex, WsUInt16 lindex); /* Create an URL call instruction for function `findex' from the URL `urlindex' with `args' arguments. The arguments `urlindex' and `findex' pont to the constant pool. */ WsAsmIns *ws_asm_call_url(WsCompilerPtr compiler, WsUInt32 line, WsUInt16 findex, WsUInt16 urlindex, WsUInt8 args); /* Create a variable modification instruction `ins' for the variable `vindex'. */ WsAsmIns *ws_asm_variable(WsCompilerPtr compiler, WsUInt32 line, WsUInt16 ins, WsUInt8 vindex); /* Create a constant loading instruction for the constant `cindex'. */ WsAsmIns *ws_asm_load_const(WsCompilerPtr compiler, WsUInt32 line, WsUInt16 cindex); /* Create an instruction `ins'. */ WsAsmIns *ws_asm_ins(WsCompilerPtr compiler, WsUInt32 line, WsUInt8 opcode); #endif /* not WSASM_H */ gateway-1.4.5/wmlscript/wsfalloc.h0000644000175000017500000001163713227613126015706 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsfalloc.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Fast memory allocation routines with easy cleanup. * */ #ifndef WSFALLOC_H #define WSFALLOC_H /********************* Types and definitions ****************************/ struct WsFastMallocBlockRec { struct WsFastMallocBlockRec *next; /* The data follows immediately here. */ }; typedef struct WsFastMallocBlockRec WsFastMallocBlock; struct WsFastMallocRec { WsFastMallocBlock *blocks; /* The default block size of this pool. */ size_t block_size; /* The number of bytes allocates for user blocks. */ size_t user_bytes_allocated; /* The next allocation can be done from this position. */ unsigned char *ptr; /* And it has this much space. */ size_t size; }; typedef struct WsFastMallocRec WsFastMalloc; /********************* Prototypes for global functions ******************/ /* Create a new fast memory allocator with internal block size of `block_size' bytes. The function returns NULL if the creation failed. */ WsFastMalloc *ws_f_create(size_t block_size); /* Destroy the fast allocator `pool' and free all resources it has allocated. All memory chunks, allocated from this pool will be invalidated with this call. */ void ws_f_destroy(WsFastMalloc *pool); /* Allocate `size' bytes of memory from the pool `pool'. The function returns NULL if the allocation fails. */ void *ws_f_malloc(WsFastMalloc *pool, size_t size); /* Allocate `num' items of size `size' from the pool `pool'. The returned memory block is initialized with zero. The function returns NULL if the allocation fails. */ void *ws_f_calloc(WsFastMalloc *pool, size_t num, size_t size); /* Take a copy of the memory buffer `ptr' which has `size' bytes of data. The copy is allocated from the pool `pool'. The function returns NULL if the allocation fails. */ void *ws_f_memdup(WsFastMalloc *pool, const void *ptr, size_t size); /* Take a copy of the C-string `str'. The copy is allocated from the pool `pool'. The function returns NULL if the allocation fails. */ void *ws_f_strdup(WsFastMalloc *pool, const char *str); #endif /* not WSFALLOC_H */ gateway-1.4.5/wmlscript/wsalloc.c0000644000175000017500000001763513227613126015537 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsalloc.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Memory allocation routines. These are simple stub functions to fix * some brain damages, found from some system's default allocators. * */ #include "wsint.h" #if !WS_MEM_DEBUG /********************* Global functions *********************************/ void *ws_malloc(size_t size) { return malloc(size); } void *ws_calloc(size_t num, size_t size) { return calloc(num, size); } void *ws_realloc(void *ptr, size_t size) { if (size == 0) { if (ptr) free(ptr); return NULL; } if (ptr == NULL) return malloc(size); return realloc(ptr, size); } void *ws_memdup(const void *ptr, size_t size) { unsigned char *data = ws_malloc(size + 1); if (data == NULL) return NULL; memcpy(data, ptr, size); data[size] = '\0'; return data; } void *ws_strdup(const char *str) { size_t len; void *s; if (str == NULL) return NULL; len = strlen(str); s = ws_malloc(len + 1); if (s == NULL) return NULL; memcpy(s, str, len + 1); return s; } void ws_free(void *ptr) { if (ptr) free(ptr); } #else /* WS_MEM_DEBUG */ /********************* Memory debugging routines ************************/ #define SIZE(_size) (sizeof(WsMemBlockHdr) + (_size)) #define MAGIC 0xfe01fa77 struct WsMemBlockHdrRec { unsigned long magic; struct WsMemBlockHdrRec *next; struct WsMemBlockHdrRec *prev; size_t size; const char *file; int line; }; typedef struct WsMemBlockHdrRec WsMemBlockHdr; /* A linked list of currently allocated blocks. */ WsMemBlockHdr *blocks = NULL; /* How many blocks are currently allocated. */ unsigned int num_blocks = 0; /* The maximum amount of blocks used. */ unsigned int max_num_blocks = 0; /* How many (user) bytes of memory the currently allocated blocks use. */ size_t balance = 0; /* The maximum amount of memory used. */ size_t max_balance = 0; /* The alloc sequence number. */ unsigned int alloc_number = 0; /* How many allocations are successful. */ unsigned int num_successful_allocs = -1; static void add_block(WsMemBlockHdr *b, size_t size, const char *file, int line) { b->magic = MAGIC; b->next = blocks; b->prev = NULL; if (blocks) blocks->prev = b; blocks = b; b->size = size; b->file = file; b->line = line; num_blocks++; balance += size; if (balance > max_balance) max_balance = balance; if (num_blocks > max_num_blocks) max_num_blocks = num_blocks; } static void remove_block(WsMemBlockHdr *b) { if (b->magic != MAGIC) ws_fatal("remove_block(): invalid magic\n"); if (b->next) b->next->prev = b->prev; if (b->prev) b->prev->next = b->next; else blocks = b->next; balance -= b->size; num_blocks--; memset(b, 0xfe, SIZE(b->size)); } void *ws_malloc_i(size_t size, const char *file, int line) { WsMemBlockHdr *b; if (alloc_number++ >= num_successful_allocs) return NULL; b = malloc(SIZE(size)); if (b == NULL) return NULL; add_block(b, size, file, line); return b + 1; } void *ws_calloc_i(size_t num, size_t size, const char *file, int line) { void *p = ws_malloc_i(num * size, file, line); if (p) memset(p, 0, num * size); return p; } void *ws_realloc_i(void *ptr, size_t size, const char *file, int line) { WsMemBlockHdr *b = ((WsMemBlockHdr *) ptr) - 1; void *n; if (ptr == NULL) return ws_malloc_i(size, file, line); if (b->size >= size) /* We can use the old block. */ return ptr; /* Allocate a bigger block. */ n = ws_malloc_i(size, file, line); if (n == NULL) return NULL; memcpy(n, ptr, b->size); /* Free old block. */ remove_block(b); free(b); return n; } void *ws_memdup_i(const void *ptr, size_t size, const char *file, int line) { void *p = ws_malloc_i(size + 1, file, line); if (p) { unsigned char *cp = (unsigned char *) p; memcpy(p, ptr, size); cp[size] = '\0'; } return p; } void *ws_strdup_i(const char *str, const char *file, int line) { return ws_memdup_i(str, strlen(str), file, line); } void ws_free_i(void *ptr) { WsMemBlockHdr *b = ((WsMemBlockHdr *) ptr) - 1; if (ptr == NULL) return; remove_block(b); free(b); } int ws_has_leaks(void) { return num_blocks || balance; } void ws_dump_blocks(void) { WsMemBlockHdr *b; fprintf(stderr, "ws: maximum memory usage: %u blocks, %ld bytes\n", max_num_blocks, (long) max_balance); fprintf(stderr, "ws: number of allocs: %u\n", alloc_number); if (num_blocks || balance) { fprintf(stderr, "ws: memory leaks: %u blocks, %ld bytes:\n", num_blocks, (long) balance); for (b = blocks; b; b = b->next) fprintf(stderr, "%s:%d: %ld\n", b->file, b->line, (long) b->size); } } void ws_clear_leaks(unsigned int num_successful_allocs_) { alloc_number = 0; num_successful_allocs = num_successful_allocs_; blocks = NULL; } #endif /* WS_MEM_DEBUG */ gateway-1.4.5/wmlscript/wsbuffer.h0000644000175000017500000001160013227613126015705 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsbuffer.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * A multipurpose buffer. * */ #ifndef WSBUFFER_H #define WSBUFFER_H /********************* Types and defintions *****************************/ /* A multipurpose buffer. The contents of the buffer handle is visible but its internals should not be modified directly. */ struct WsBufferRec { size_t len; unsigned char *data; }; typedef struct WsBufferRec WsBuffer; /********************* Global functions *********************************/ /* Initialize the buffer `buffer'. The buffer is not allocated; the argument `buffer' must point to allocated buffer. */ void ws_buffer_init(WsBuffer *buffer); /* Uninitialize buffer `buffer'. The actual buffer structure is not freed; only its internally allocated buffer is freed. */ void ws_buffer_uninit(WsBuffer *buffer); /* Allocate and initialize a new buffer. The function returns NULL if the allocation failed. */ WsBuffer *ws_buffer_alloc(void); /* Free the buffer `buffer' and all its resources. */ void ws_buffer_free(WsBuffer *buffer); /* Append `size' bytes of data from `data' to the buffer `buffer'. The function returns WS_TRUE if the operation was successful or WS_FALSE otherwise. */ WsBool ws_buffer_append(WsBuffer *buffer, unsigned char *data, size_t len); /* Append `size' bytes of space to the buffer `buffer'. If the argument `p' is not NULL, it is set to point to the beginning of the appended space. The function returns WS_TRUE if the operation was successful of WS_FALSE otherwise. */ WsBool ws_buffer_append_space(WsBuffer *buffer, unsigned char **p, size_t size); /* Return a pointer to the beginning of the buffer's data. */ unsigned char *ws_buffer_ptr(WsBuffer *buffer); /* Return the length of the buffer `buffer'. */ size_t ws_buffer_len(WsBuffer *buffer); /* Steal the buffer's data. The function returns a pointer to the beginning of the buffer's data and re-initializes the buffer to empty data. The returned data must be with the ws_free() function by the caller. */ unsigned char *ws_buffer_steal(WsBuffer *buffer); #endif /* not WSBUFFER_H */ gateway-1.4.5/wmlscript/make-op-table.in0000644000175000017500000000141107045237220016654 0ustar toljtolj#!@PERLPROG@ -w # -*- perl -*- # # make-op-table.in # # Author: Markku Rossi # # Copyright (c) 1999-2000 WAPIT OY LTD. # All rights reserved. # # A help script to create the `wsopcodes.h' file from the `wsasm.h' # header file. # my(@table) = (); my(@size) = (); while (<>) { if (/^\#define\s(WS_ASM_[A-Z_0-9]+)\s+(\S+)\s+\/\*\s+(\S+)\s+(\S+)/) { my($name) = $1; my($code) = $2; my($size) = $4; if ($name =~ /WS_ASM_P_/) { next; } $table[hex($code)] = $name; $size[hex($code)] = $size; } } for ($i = 0; $i < 256; $i++) { printf(" /* 0x%02x */ ", $i); if (defined($table[$i])) { $name = $table[$i]; $name =~ s/^WS_ASM_//; $name =~ tr/A-Z/a-z/; print "{\"$name\",\t$size[$i]},\n"; } else { print "{NULL,\t0},\n"; } } gateway-1.4.5/wmlscript/wsencode.h0000644000175000017500000001722313227613126015700 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsencode.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Encoding and decoding routines to store different types of data to * the format, specified by the WMLScript specification. * */ #ifndef WSENCODE_H #define WSENCODE_H /********************* Types and defintions *****************************/ /* Macros to store and restore integers from data buffers. */ #define WS_PUT_UINT8(buf, val) \ do { \ unsigned char *_p = (buf); \ _p[0] = ((val) & 0xff); \ } while (0) #define WS_PUT_UINT16(buf, val) \ do { \ unsigned char *_p = (buf); \ _p[0] = (((val) & 0xff00) >> 8); \ _p[1] = ((val) & 0xff); \ } while (0) #define WS_PUT_UINT32(buf, val) \ do { \ unsigned char *_p = (buf); \ _p[0] = (((val) & 0xff000000) >> 24); \ _p[1] = (((val) & 0x00ff0000) >> 16); \ _p[2] = (((val) & 0x0000ff00) >> 8); \ _p[3] = ((val) & 0x000000ff); \ } while (0) #define WS_GET_UINT8(buf, var) \ do { \ const unsigned char *_p = (buf); \ (var) = _p[0]; \ } while (0); #define WS_GET_UINT16(buf, var) \ do { \ const unsigned char *_p = (buf); \ WsUInt16 _val; \ _val = _p[0]; \ _val <<= 8; \ _val |= _p[1]; \ (var) = _val; \ } while (0); #define WS_GET_UINT32(buf, var) \ do { \ const unsigned char *_p = (buf); \ WsUInt32 _val; \ _val = _p[0]; \ _val <<= 8; \ _val |= _p[1]; \ _val <<= 8; \ _val |= _p[2]; \ _val <<= 8; \ _val |= _p[3]; \ (var) = _val; \ } while (0); /* The maximum length of a multi-byte encoded WsUInt32 integer (in bytes). */ #define WS_MB_UINT32_MAX_ENCODED_LEN 5 /* Type specifiers for the ws_{encode,decode}_buffer() functions. */ typedef enum { /* The terminator of the encoding list. This must be the last item in all encoding and decoding function calls. */ WS_ENC_END, /* 8 bits of data. The value must be given as `WsByte'. */ WS_ENC_BYTE, /* A signed 8 bit integer. The value must be given as `WsInt8'. */ WS_ENC_INT8, /* An unsigned 8 bit integer. The value must be given as `WsUInt8'. */ WS_ENC_UINT8, /* A signed 16 bit integer. The value must be given as `WsInt16'. */ WS_ENC_INT16, /* An unsigned 16 bit integer. The value must be given as `WsUInt16'. */ WS_ENC_UINT16, /* A signed 32 bit integer. The value must be given as `WsInt32'. */ WS_ENC_INT32, /* An unsigned 32 bit integer. The value must be given as `WsUInt32'. */ WS_ENC_UINT32, /* An unsigned 16 bit integer in the multi-byte format. The value must be given as `WsUInt16'. */ WS_ENC_MB_UINT16, /* An unsigned 32 bit integer in the multi-byte format. The value must be given as `WsUInt32'. */ WS_ENC_MB_UINT32, /* Binary data specified with two arguments: unsigned char *, size_t */ WS_ENC_DATA } WsEncodingSpec; /********************* Global functions *********************************/ /* Encode the unsigned 32 bit integer `value' to the multi-byte format to the buffer `buffer'. The buffer `buffer' must have at least WS_MB_UINT32_MAX_ENCODED_LEN bytes of data. The function returns a pointer, pointing to the beginning of the encoded data. Note that the returned pointer does not necessarily point to the beginning of the buffer `buffer'. The size of the encoded multi-byte value is returned in `len_return'. */ unsigned char *ws_encode_mb_uint32(WsUInt32 value, unsigned char *buffer, size_t *len_return); /* Decode a multi-byte encoded unsigned integer from the buffer `buffer'. The function returns the decoded value. The argument `len' must contain the length of the buffer `buffer'. It is set to contain the length of the encoded value in the buffer. The value, stored in `len', can be used to skip the multi-byte encoded value from the buffer `buffer'. */ WsUInt32 ws_decode_mb_uint32(const unsigned char *buffer, size_t *len); /* Encode data as specified in the WsEncodingSpec encoded argument list `...' into the buffer `buffer'. The function returns WS_TRUE if the encoding was successful or WS_FALSE otherwise (out of memory). */ WsBool ws_encode_buffer(WsBuffer *buffer, ...); /* Decode data from the buffer `buffer', `buffer_len' according to the WsEncodingSpec encoded argument list `...'. The argument list `...' must be encoded as in ws_encode_buffer() but the values must be replaced with pointers to variables of the type. The function returns the number of bytes decoded from the buffer or 0 if the decoding failed. */ size_t ws_decode_buffer(const unsigned char *buffer, size_t buffer_len, ...); #endif /* not WSENCODE_H */ gateway-1.4.5/wmlscript/wsutf8.c0000644000175000017500000002470513227613126015327 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsutf8.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Functions to manipulate UTF-8 encoded strings. * * Specification: RFC-2279 * */ #include "wsint.h" /********************* Types and definitions ****************************/ /* Masks to determine the UTF-8 encoding of an ISO 10646 character. */ #define WS_UTF8_ENC_1_M 0xffffff80 #define WS_UTF8_ENC_2_M 0xfffff800 #define WS_UTF8_ENC_3_M 0xffff0000 #define WS_UTF8_ENC_4_M 0xffe00000 #define WS_UTF8_ENC_5_M 0xfc000000 #define WS_UTF8_ENC_6_M 0x80000000 /* The high-order bits. This array can be indexed with the number of bytes in the encoding to get the initialization mask for the high-order bits. */ static unsigned char utf8_hibits[7] = { 0x00, /* unused */ 0x00, /* 1 byte */ 0xc0, /* 2 bytes */ 0xe0, /* 3 bytes */ 0xf0, /* 4 bytes */ 0xf8, /* 5 bytes */ 0xfc, /* 6 bytes */ }; /* The high-order bits for continuation bytes (10xxxxxx). */ #define WS_UTF8_ENC_C_BITS 0x80 /* Mask to get the continuation bytes from the character (00111111). */ #define WS_UTF8_CONT_DATA_MASK 0x3f /* Determine the encoding type of the ISO 10646 character `ch'. The argument `ch' must be given as `unsigned long'. The macro returns 0 if the value `ch' can not be encoded as UTF-8 and the number of bytes in the encoded value otherwise. */ #define WS_UTF8_ENC_TYPE(ch) \ (((ch) & WS_UTF8_ENC_1_M) == 0 \ ? 1 \ : (((ch) & WS_UTF8_ENC_2_M) == 0 \ ? 2 \ : (((ch) & WS_UTF8_ENC_3_M) == 0 \ ? 3 \ : (((ch) & WS_UTF8_ENC_4_M) == 0 \ ? 4 \ : (((ch) & WS_UTF8_ENC_5_M) == 0 \ ? 5 \ : (((ch) & WS_UTF8_ENC_6_M) == 0 \ ? 6 \ : 0)))))) /* Masks and values to determine the length of an UTF-8 encoded character. */ #define WS_UTF8_DEC_1_M 0x80 #define WS_UTF8_DEC_2_M 0xe0 #define WS_UTF8_DEC_3_M 0xf0 #define WS_UTF8_DEC_4_M 0xf8 #define WS_UTF8_DEC_5_M 0xfc #define WS_UTF8_DEC_6_M 0xfe #define WS_UTF8_DEC_1_V 0x00 #define WS_UTF8_DEC_2_V 0xc0 #define WS_UTF8_DEC_3_V 0xe0 #define WS_UTF8_DEC_4_V 0xf0 #define WS_UTF8_DEC_5_V 0xf8 #define WS_UTF8_DEC_6_V 0xfc /* Masks to get the data bits from the first byte of an UTF-8 encoded character. This array can be indexed with the number of bytes in the encoding. */ static unsigned char utf8_hidata_masks[7] = { 0x00, /* unused */ 0x7f, /* 1 byte */ 0x1f, /* 2 bytes */ 0x0f, /* 3 bytes */ 0x07, /* 4 bytes */ 0x03, /* 5 bytes */ 0x01, /* 6 bytes */ }; /* The mask and the value of the continuation bytes. */ #define WS_UTF8_DEC_C_M 0xc0 #define WS_UTF8_DEC_C_V 0x80 /* Determine how many bytes the UTF-8 encoding uses by investigating the first byte `b'. The argument `b' must be given as `unsigned char'. The macro returns 0 if the byte `b' is not a valid UTF-8 first byte. */ #define WS_UTF8_DEC_TYPE(b) \ (((b) & WS_UTF8_DEC_1_M) == WS_UTF8_DEC_1_V \ ? 1 \ : (((b) & WS_UTF8_DEC_2_M) == WS_UTF8_DEC_2_V \ ? 2 \ : (((b) & WS_UTF8_DEC_3_M) == WS_UTF8_DEC_3_V \ ? 3 \ : (((b) & WS_UTF8_DEC_4_M) == WS_UTF8_DEC_4_V \ ? 4 \ : (((b) & WS_UTF8_DEC_5_M) == WS_UTF8_DEC_5_V \ ? 5 \ : (((b) & WS_UTF8_DEC_6_M) == WS_UTF8_DEC_6_V \ ? 6 \ : 0)))))) /* Predicate to check whether the `unsigned char' byte `b' is a continuation byte. */ #define WS_UTF8_DEC_C_P(b) (((b) & WS_UTF8_DEC_C_M) == WS_UTF8_DEC_C_V) /********************* Global functions *********************************/ WsUtf8String *ws_utf8_alloc() { return ws_calloc(1, sizeof(WsUtf8String)); } void ws_utf8_free(WsUtf8String *string) { if (string == NULL) return; ws_free(string->data); ws_free(string); } int ws_utf8_append_char(WsUtf8String *string, unsigned long ch) { unsigned char *d; unsigned int num_bytes = WS_UTF8_ENC_TYPE(ch); unsigned int len, i; if (num_bytes == 0) ws_fatal("ws_utf8_append_char(): 0x%lx is not a valid UTF-8 character", ch); d = ws_realloc(string->data, string->len + num_bytes); if (d == NULL) return 0; len = string->len; /* Encode the continuation bytes (n > 1). */ for (i = num_bytes - 1; i > 0; i--) { d[len + i] = WS_UTF8_ENC_C_BITS; d[len + i] |= ch & WS_UTF8_CONT_DATA_MASK; ch >>= 6; } /* And continue the first byte. */ d[len] = utf8_hibits[num_bytes]; d[len] |= ch; string->data = d; string->len += num_bytes; string->num_chars++; return 1; } int ws_utf8_verify(const unsigned char *data, size_t len, size_t *strlen_return) { unsigned int num_bytes, i; size_t strlen = 0; while (len > 0) { num_bytes = WS_UTF8_DEC_TYPE(*data); if (num_bytes == 0) /* Not a valid beginning. */ return 0; if (len < num_bytes) /* The data is truncated. */ return 0; for (i = 1; i < num_bytes; i++) if (!WS_UTF8_DEC_C_P(data[i])) /* Not a valid continuation byte. */ return 0; len -= num_bytes; data += num_bytes; strlen++; } if (strlen_return) *strlen_return = strlen; return 1; } int ws_utf8_set_data(WsUtf8String *string, const unsigned char *data, size_t len) { size_t num_chars; if (!ws_utf8_verify(data, len, &num_chars)) /* Malformed data. */ return 0; /* Init `string' to empty. */ ws_free(string->data); string->data = NULL; string->len = 0; string->num_chars = 0; /* Set the new data. */ string->data = ws_memdup(data, len); if (string->data == NULL) return 0; string->len = len; string->num_chars = num_chars; return 1; } int ws_utf8_get_char(const WsUtf8String *string, unsigned long *ch_return, size_t *posp) { size_t pos = *posp; unsigned int num_bytes, i; unsigned char *data; unsigned long ch; if (pos < 0 || pos >= string->len) /* Index out range. */ return 0; data = string->data + pos; num_bytes = WS_UTF8_DEC_TYPE(*data); if (num_bytes == 0) /* Invalid position. */ return 0; if (pos + num_bytes > string->len) /* Truncated data. */ return 0; /* Get the first byte. */ ch = data[0] & utf8_hidata_masks[num_bytes]; /* Add the continuation bytes. */ for (i = 1; i < num_bytes; i++) { ch <<= 6; ch |= data[i] & WS_UTF8_CONT_DATA_MASK; } *ch_return = ch; *posp = pos + num_bytes; return 1; } unsigned char *ws_utf8_to_latin1(const WsUtf8String *string, unsigned char unknown_char, size_t *len_return) { unsigned char *cstr; size_t i; size_t pos = 0; if (string == NULL) return NULL; cstr = ws_malloc(string->num_chars + 1); if (cstr == NULL) return NULL; for (i = 0; i < string->num_chars; i++) { unsigned long ch; if (!ws_utf8_get_char(string, &ch, &pos)) ws_fatal("ws_utf8_to_latin1_cstr(): internal inconsistency"); if (ch > 0xff) cstr[i] = unknown_char; else cstr[i] = (unsigned char) ch; } cstr[i] = '\0'; if (len_return) *len_return = string->num_chars; return cstr; } void ws_utf8_free_data(unsigned char *data) { if (data) ws_free(data); } gateway-1.4.5/wmlscript/wsstdlib.h0000644000175000017500000001032513227613126015720 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsstdlib.c - WTA and WTAI standard libraries related implementations * * Authors: * Markku Rossi * Stipe Tolj */ #ifndef WSSTDLIB_H #define WSSTDLIB_H /********************* Prototypes for global functions ******************/ /* Returns the library and function indexes and the exact amount of arguments for the function `function' of the library `library'. The function returns WS_TRUE if the operation was successful. If the operation failed the function returns WS_FALSE and it sets the `{l,f}index_found_return' to WS_FALSE to indicate whether the library or the function name was unknown. Note that if the library is unknown, then also the function is unknown. */ WsBool ws_stdlib_function(const char *library, const char *function, WsUInt16 *lindex_return, WsUInt8 *findex_return, WsUInt8 *num_args_return, WsBool *lindex_found_return, WsBool *findex_found_return); /* Returns the library and function names, corresponding to their indexes `lindex' and `findex'. The function returns WS_TRUE if both the library and function name could be resolved. Otherwise the function returns WS_FALSE and sets the failed name pointer(s) to NULL. */ WsBool ws_stdlib_function_name(WsUInt16 lindex, WsUInt8 findex, const char **library_return, const char **function_return); #endif /* not WSSTDLIB_H */ gateway-1.4.5/wmlscript/wslexer.c0000644000175000017500000010722013227613126015552 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wslexer.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Lexical analyzer. * */ #include "wsint.h" #include "wsstree.h" #include "wsgram.h" /********************* Types and definitions ****************************/ /* A predicate to check whether the character `ch' is a decimal digit. */ #define WS_IS_DECIMAL_DIGIT(ch) ('0' <= (ch) && (ch) <= '9') /* Convert the decimal digit `ch' to an integer number. */ #define WS_DECIMAL_TO_INT(ch) ((ch) - '0') /* A predicate to check whether the character `ch' is a non-zero decimal digit. */ #define WS_IS_NON_ZERO_DIGIT(ch) ('1' <= (ch) && (ch) <= '9') /* A predicate to check whether the character `ch' is an octal digit. */ #define WS_IS_OCTAL_DIGIT(ch) ('0' <= (ch) && (ch) <= '7') /* Convert the octal digit `ch' to an integer number. */ #define WS_OCTAL_TO_INT(ch) ((ch) - '0') /* A predicate to check whether the character `ch' is a hex digit. */ #define WS_IS_HEX_DIGIT(ch) (('0' <= (ch) && (ch) <= '9') \ || ('a' <= (ch) && (ch) <= 'f') \ || ('A' <= (ch) && (ch) <= 'F')) /* Convert the hex digit `ch' to an integer number. */ #define WS_HEX_TO_INT(ch) \ ('0' <= (ch) && (ch) <= '9' \ ? ((ch) - '0') \ : ('a' <= (ch) && (ch) <= 'f' \ ? ((ch) - 'a' + 10) \ : (ch) - 'A' + 10)) /* A predicate to check whether the character `ch' is an identifier starter letter. */ #define WS_IS_IDENTIFIER_LETTER(ch) \ (('a' <= (ch) && (ch) <= 'z') \ || ('A' <= (ch) && (ch) <= 'Z') \ || (ch) == '_') /********************* Prototypes for static functions ******************/ /* Check whether the identifier `id', `len' is a keyword. If the identifier is a keyword, the function returns WS_TRUE and sets the keywords token ID to `token_return'. Otherwise the function returns WS_FALSE. */ static WsBool lookup_keyword(char *id, size_t len, int *token_return); /* Convert literal integer number, stored to the buffer `buffer', into a 32 bit integer number. The function will report possible integer overflows to the compiler `compiler'. The function modifies the contents of the buffer `buffer' but it does not free it. */ static WsUInt32 buffer_to_int(WsCompilerPtr compiler, WsBuffer *buffer); /* Read a floating point number from the decimal point to the buffer `buffer'. The buffer `buffer' might already contain some leading digits of the number and it always contains the decimal point. If the operation is successful, the function returns WS_TRUE and it returns the resulting floating point number in `result'. Otherwise the function returns WS_FALSE. The buffer `buffer' must be initialized before this function is called and it must be uninitialized by the caller. */ static WsBool read_float_from_point(WsCompiler *compiler, WsBuffer *buffer, WsFloat *result); /* Read a floating point number from the exponent part to the buffer `buffer'. The buffer might already contain some leading digits and fields of the floating poit number. Otherwise, the function works like read_float_from_point(). */ static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer, WsFloat *result); /********************* Static variables *********************************/ /* A helper macro which expands to a strings and its length excluding the trailing '\0' character. */ #define N(n) n, sizeof(n) - 1 /* They keywords of the WMLScript language. This array must be sorted by the keyword names. */ static struct { char *name; size_t name_len; int token; } keywords[] = { {N("access"), tACCESS}, {N("agent"), tAGENT}, {N("break"), tBREAK}, {N("case"), tCASE}, {N("catch"), tCATCH}, {N("class"), tCLASS}, {N("const"), tCONST}, {N("continue"), tCONTINUE}, {N("debugger"), tDEBUGGER}, {N("default"), tDEFAULT}, {N("delete"), tDELETE}, {N("div"), tIDIV}, {N("do"), tDO}, {N("domain"), tDOMAIN}, {N("else"), tELSE}, {N("enum"), tENUM}, {N("equiv"), tEQUIV}, {N("export"), tEXPORT}, {N("extends"), tEXTENDS}, {N("extern"), tEXTERN}, {N("false"), tFALSE}, {N("finally"), tFINALLY}, {N("for"), tFOR}, {N("function"), tFUNCTION}, {N("header"), tHEADER}, {N("http"), tHTTP}, {N("if"), tIF}, {N("import"), tIMPORT}, {N("in"), tIN}, {N("invalid"), tINVALID}, {N("isvalid"), tISVALID}, {N("lib"), tLIB}, {N("meta"), tMETA}, {N("name"), tNAME}, {N("new"), tNEW}, {N("null"), tNULL}, {N("path"), tPATH}, {N("private"), tPRIVATE}, {N("public"), tPUBLIC}, {N("return"), tRETURN}, {N("sizeof"), tSIZEOF}, {N("struct"), tSTRUCT}, {N("super"), tSUPER}, {N("switch"), tSWITCH}, {N("this"), tTHIS}, {N("throw"), tTHROW}, {N("true"), tTRUE}, {N("try"), tTRY}, {N("typeof"), tTYPEOF}, {N("url"), tURL}, {N("use"), tUSE}, {N("user"), tUSER}, {N("var"), tVAR}, {N("void"), tVOID}, {N("while"), tWHILE}, {N("with"), tWITH}, }; static int num_keywords = sizeof(keywords) / sizeof(keywords[0]); /********************* Global functions *********************************/ int ws_yy_lex(YYSTYPE *yylval, YYLTYPE *yylloc, void *context) { WsCompiler *compiler = (WsCompiler *) context; WsUInt32 ch, ch2; WsBuffer buffer; unsigned char *p; WsBool success; /* Just check that we get the correct amount of arguments. */ gw_assert(compiler->magic == COMPILER_MAGIC); while (ws_stream_getc(compiler->input, &ch)) { /* Save the token's line number. */ yylloc->first_line = compiler->linenum; switch (ch) { case '\t': /* Whitespace characters. */ case '\v': case '\f': case ' ': continue; case '\n': /* Line terminators. */ case '\r': if (ch == '\r' && ws_stream_getc(compiler->input, &ch2)) { if (ch2 != '\n') ws_stream_ungetc(compiler->input, ch2); } compiler->linenum++; continue; case '!': /* !, != */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '=') return tNE; ws_stream_ungetc(compiler->input, ch2); } return '!'; case '%': /* %, %= */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '=') return tREMA; ws_stream_ungetc(compiler->input, ch2); } return '%'; case '&': /* &, &&, &= */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '&') return tAND; if (ch2 == '=') return tANDA; ws_stream_ungetc(compiler->input, ch2); } return '&'; case '*': /* *, *= */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '=') return tMULA; ws_stream_ungetc(compiler->input, ch2); } return '*'; case '+': /* +, ++, += */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '+') return tPLUSPLUS; if (ch2 == '=') return tADDA; ws_stream_ungetc(compiler->input, ch2); } return '+'; case '-': /* -, --, -= */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '-') return tMINUSMINUS; if (ch2 == '=') return tSUBA; ws_stream_ungetc(compiler->input, ch2); } return '-'; case '.': if (ws_stream_getc(compiler->input, &ch2)) { if (WS_IS_DECIMAL_DIGIT(ch2)) { /* DecimalFloatLiteral. */ ws_buffer_init(&buffer); if (!ws_buffer_append_space(&buffer, &p, 2)) { ws_error_memory(compiler); ws_buffer_uninit(&buffer); return EOF; } p[0] = '.'; p[1] = (unsigned char) ch2; success = read_float_from_point(compiler, &buffer, &yylval->vfloat); ws_buffer_uninit(&buffer); if (!success) return EOF; return tFLOAT; } ws_stream_ungetc(compiler->input, ch2); } return '.'; case '/': /* /, /=, block or a single line comment */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '*') { /* Block comment. */ while (1) { if (!ws_stream_getc(compiler->input, &ch)) { ws_src_error(compiler, 0, "EOF in comment"); return EOF; } if (ch == '\n' || ch == '\r') { /* Line terminators. */ if (ch == '\r' && ws_stream_getc(compiler->input, &ch2)) { if (ch2 != '\n') ws_stream_ungetc(compiler->input, ch2); } compiler->linenum++; /* Continue reading the block comment. */ continue; } if (ch == '*' && ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '/') /* The end of the comment found. */ break; ws_stream_ungetc(compiler->input, ch2); } } /* Continue after the comment. */ continue; } if (ch2 == '/') { /* Single line comment. */ while (1) { if (!ws_stream_getc(compiler->input, &ch)) /* The end of input stream reached. We accept this as a valid comment terminator. */ break; if (ch == '\n' || ch == '\r') { /* Line terminators. */ if (ch == '\r' && ws_stream_getc(compiler->input, &ch2)) { if (ch2 != '\n') ws_stream_ungetc(compiler->input, ch2); } /* The end of the line (and the comment) reached. */ compiler->linenum++; break; } } /* Continue after the comment. */ continue; } if (ch2 == '=') return tDIVA; ws_stream_ungetc(compiler->input, ch2); } return '/'; case '<': /* <, <<, <<=, <= */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '<') { if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '=') return tLSHIFTA; ws_stream_ungetc(compiler->input, ch2); } return tLSHIFT; } if (ch2 == '=') return tLE; ws_stream_ungetc(compiler->input, ch2); } return '<'; case '=': /* =, == */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '=') return tEQ; ws_stream_ungetc(compiler->input, ch2); } return '='; case '>': /* >, >=, >>, >>=, >>>, >>>= */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '>') { if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '>') { if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '=') return tRSZSHIFTA; ws_stream_ungetc(compiler->input, ch2); } return tRSZSHIFT; } if (ch2 == '=') return tRSSHIFTA; ws_stream_ungetc(compiler->input, ch2); } return tRSSHIFT; } if (ch2 == '=') return tGE; ws_stream_ungetc(compiler->input, ch2); } return '>'; case '^': /* ^, ^= */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '=') return tXORA; ws_stream_ungetc(compiler->input, ch2); } return '^'; case '|': /* |, |=, || */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == '=') return tORA; if (ch2 == '|') return tOR; ws_stream_ungetc(compiler->input, ch2); } return '|'; case '#': /* The simple cases. */ case '(': case ')': case ',': case ':': case ';': case '?': case '{': case '}': case '~': return (int) ch; case '\'': /* String literals. */ case '"': { WsUInt32 string_end_ch = ch; WsUtf8String *str = ws_utf8_alloc(); if (str == NULL) { ws_error_memory(compiler); return EOF; } while (1) { if (!ws_stream_getc(compiler->input, &ch)) { eof_in_string_literal: ws_src_error(compiler, 0, "EOF in string literal"); ws_utf8_free(str); return EOF; } if (ch == string_end_ch) /* The end of string reached. */ break; if (ch == '\\') { /* An escape sequence. */ if (!ws_stream_getc(compiler->input, &ch)) goto eof_in_string_literal; switch (ch) { case '\'': case '"': case '\\': case '/': /* The character as-is. */ break; case 'b': ch = '\b'; break; case 'f': ch = '\f'; break; case 'n': ch = '\n'; break; case 'r': ch = '\r'; break; case 't': ch = '\t'; break; case 'x': case 'u': { int i, len; int type = ch; if (ch == 'x') len = 2; else len = 4; ch = 0; for (i = 0; i < len; i++) { if (!ws_stream_getc(compiler->input, &ch2)) goto eof_in_string_literal; if (!WS_IS_HEX_DIGIT(ch2)) { ws_src_error(compiler, 0, "malformed `\\%c' escape in " "string literal", (char) type); ch = 0; break; } ch *= 16; ch += WS_HEX_TO_INT(ch2); } } break; default: if (WS_IS_OCTAL_DIGIT(ch)) { int i; int limit = 3; ch = WS_OCTAL_TO_INT(ch); if (ch > 3) limit = 2; for (i = 1; i < limit; i++) { if (!ws_stream_getc(compiler->input, &ch2)) goto eof_in_string_literal; if (!WS_IS_OCTAL_DIGIT(ch2)) { ws_stream_ungetc(compiler->input, ch2); break; } ch *= 8; ch += WS_OCTAL_TO_INT(ch2); } } else { ws_src_error(compiler, 0, "unknown escape sequence `\\%c' in " "string literal", (char) ch); ch = 0; } break; } /* FALLTHROUGH */ } if (!ws_utf8_append_char(str, ch)) { ws_error_memory(compiler); ws_utf8_free(str); return EOF; } } if (!ws_lexer_register_utf8(compiler, str)) { ws_error_memory(compiler); ws_utf8_free(str); return EOF; } gw_assert(str != NULL); yylval->string = str; return tSTRING; } break; default: /* Identifiers, keywords and number constants. */ if (WS_IS_IDENTIFIER_LETTER(ch)) { WsBool got; int token; unsigned char *p; unsigned char *np; size_t len = 0; /* An identifier or a keyword. We start with a 256 * bytes long buffer but it is expanded dynamically if * needed. However, 256 should be enought for most * cases since the byte-code format limits the function * names to 255 characters. */ p = ws_malloc(256); if (p == NULL) { ws_error_memory(compiler); return EOF; } do { /* Add one extra for the possible terminator character. */ np = ws_realloc(p, len + 2); if (np == NULL) { ws_error_memory(compiler); ws_free(p); return EOF; } p = np; /* This is ok since the only valid identifier names * can be written in 7 bit ASCII. */ p[len++] = (unsigned char) ch; } while ((got = ws_stream_getc(compiler->input, &ch)) && (WS_IS_IDENTIFIER_LETTER(ch) || WS_IS_DECIMAL_DIGIT(ch))); if (got) /* Put back the terminator character. */ ws_stream_ungetc(compiler->input, ch); /* Is it a keyword? */ if (lookup_keyword((char *) p, len, &token)) { /* Yes it is... */ ws_free(p); /* ...except one case: `div='. */ if (token == tIDIV) { if (ws_stream_getc(compiler->input, &ch)) { if (ch == '=') return tIDIVA; ws_stream_ungetc(compiler->input, ch); } } /* Return the token value. */ return token; } /* It is a normal identifier. Let's pad the name with a null-character. We have already allocated space for it. */ p[len] = '\0'; if (!ws_lexer_register_block(compiler, p)) { ws_error_memory(compiler); ws_free(p); return EOF; } gw_assert(p != NULL); yylval->identifier = (char *) p; return tIDENTIFIER; } if (WS_IS_NON_ZERO_DIGIT(ch)) { /* A decimal integer literal or a decimal float literal. */ ws_buffer_init(&buffer); if (!ws_buffer_append_space(&buffer, &p, 1)) { number_error_memory: ws_error_memory(compiler); ws_buffer_uninit(&buffer); return EOF; } p[0] = ch; while (ws_stream_getc(compiler->input, &ch)) { if (WS_IS_DECIMAL_DIGIT(ch)) { if (!ws_buffer_append_space(&buffer, &p, 1)) goto number_error_memory; p[0] = ch; } else if (ch == '.' || ch == 'e' || ch == 'E') { /* DecimalFloatLiteral. */ if (ch == '.') { if (!ws_buffer_append_space(&buffer, &p, 1)) goto number_error_memory; p[0] = '.'; success = read_float_from_point(compiler, &buffer, &yylval->vfloat); } else { ws_stream_ungetc(compiler->input, ch); success = read_float_from_exp(compiler, &buffer, &yylval->vfloat); } ws_buffer_uninit(&buffer); if (!success) return EOF; return tFLOAT; } else { ws_stream_ungetc(compiler->input, ch); break; } } /* Now the buffer contains an integer number as a string. Let's convert it to an integer number. */ yylval->integer = buffer_to_int(compiler, &buffer); ws_buffer_uninit(&buffer); /* Read a DecimalIntegerLiteral. */ return tINTEGER; } if (ch == '0') { /* The integer constant 0, an octal number or a HexIntegerLiteral. */ if (ws_stream_getc(compiler->input, &ch2)) { if (ch2 == 'x' || ch2 == 'X') { /* HexIntegerLiteral. */ ws_buffer_init(&buffer); if (!ws_buffer_append_space(&buffer, &p, 2)) goto number_error_memory; p[0] = '0'; p[1] = 'x'; while (ws_stream_getc(compiler->input, &ch)) { if (WS_IS_HEX_DIGIT(ch)) { if (!ws_buffer_append_space(&buffer, &p, 1)) goto number_error_memory; p[0] = ch; } else { ws_stream_ungetc(compiler->input, ch); break; } } if (ws_buffer_len(&buffer) == 2) { ws_buffer_uninit(&buffer); ws_src_error(compiler, 0, "numeric constant with no digits"); yylval->integer = 0; return tINTEGER; } /* Now the buffer contains an integer number as * a string. Let's convert it to an integer * number. */ yylval->integer = buffer_to_int(compiler, &buffer); ws_buffer_uninit(&buffer); /* Read a HexIntegerLiteral. */ return tINTEGER; } if (WS_IS_OCTAL_DIGIT(ch2)) { /* OctalIntegerLiteral. */ ws_buffer_init(&buffer); if (!ws_buffer_append_space(&buffer, &p, 2)) goto number_error_memory; p[0] = '0'; p[1] = ch2; while (ws_stream_getc(compiler->input, &ch)) { if (WS_IS_OCTAL_DIGIT(ch)) { if (!ws_buffer_append_space(&buffer, &p, 1)) goto number_error_memory; p[0] = ch; } else { ws_stream_ungetc(compiler->input, ch); break; } } /* Convert the buffer into an intger number. */ yylval->integer = buffer_to_int(compiler, &buffer); ws_buffer_uninit(&buffer); /* Read an OctalIntegerLiteral. */ return tINTEGER; } if (ch2 == '.' || ch2 == 'e' || ch2 == 'E') { /* DecimalFloatLiteral. */ ws_buffer_init(&buffer); if (ch2 == '.') { if (!ws_buffer_append_space(&buffer, &p, 1)) goto number_error_memory; p[0] = '.'; success = read_float_from_point(compiler, &buffer, &yylval->vfloat); } else { ws_stream_ungetc(compiler->input, ch); success = read_float_from_exp(compiler, &buffer, &yylval->vfloat); } ws_buffer_uninit(&buffer); if (!success) return EOF; return tFLOAT; } ws_stream_ungetc(compiler->input, ch2); } /* Integer literal 0. */ yylval->integer = 0; return tINTEGER; } /* Garbage found from the input stream. */ ws_src_error(compiler, 0, "garbage found from the input stream: character=0x%x", ch); return EOF; break; } } return EOF; } /********************* Static functions *********************************/ static WsBool lookup_keyword(char *id, size_t len, int *token_return) { int left = 0, center, right = num_keywords; while (left < right) { size_t l; int result; center = left + (right - left) / 2; l = keywords[center].name_len; if (len < l) l = len; result = memcmp(id, keywords[center].name, l); if (result < 0 || (result == 0 && len < keywords[center].name_len)) /* The possible match is smaller. */ right = center; else if (result > 0 || (result == 0 && len > keywords[center].name_len)) /* The possible match is bigger. */ left = center + 1; else { /* Found a match. */ *token_return = keywords[center].token; return WS_TRUE; } } /* No match. */ return WS_FALSE; } static WsUInt32 buffer_to_int(WsCompilerPtr compiler, WsBuffer *buffer) { unsigned char *p; unsigned long value; /* Terminate the string. */ if (!ws_buffer_append_space(buffer, &p, 1)) { ws_error_memory(compiler); return 0; } p[0] = '\0'; /* Convert the buffer into an integer number. The base is taken from the bufer. */ errno = 0; value = strtoul((char *) ws_buffer_ptr(buffer), NULL, 0); /* Check for overflow. We accept WS_INT32_MAX + 1 because we might * be parsing the numeric part of '-2147483648'. */ if (errno == ERANGE || value > (WsUInt32) WS_INT32_MAX + 1) ws_src_error(compiler, 0, "integer literal too large"); /* All done. */ return (WsUInt32) value; } static WsBool read_float_from_point(WsCompiler *compiler, WsBuffer *buffer, WsFloat *result) { WsUInt32 ch; unsigned char *p; while (ws_stream_getc(compiler->input, &ch)) { if (WS_IS_DECIMAL_DIGIT(ch)) { if (!ws_buffer_append_space(buffer, &p, 1)) { ws_error_memory(compiler); return WS_FALSE; } p[0] = (unsigned char) ch; } else { ws_stream_ungetc(compiler->input, ch); break; } } return read_float_from_exp(compiler, buffer, result); } static WsBool read_float_from_exp(WsCompiler *compiler, WsBuffer *buffer, WsFloat *result) { WsUInt32 ch; unsigned char *p; int sign = '+'; unsigned char buf[4]; /* Do we have an exponent part. */ if (!ws_stream_getc(compiler->input, &ch)) goto done; if (ch != 'e' && ch != 'E') { /* No exponent part. */ ws_stream_ungetc(compiler->input, ch); goto done; } /* Sign. */ if (!ws_stream_getc(compiler->input, &ch)) { /* This is an error. */ ws_src_error(compiler, 0, "truncated float literal"); return WS_FALSE; } if (ch == '-') sign = '-'; else if (ch == '+') sign = '+'; else ws_stream_ungetc(compiler->input, ch); /* DecimalDigits. */ if (!ws_stream_getc(compiler->input, &ch)) { ws_src_error(compiler, 0, "truncated float literal"); return WS_FALSE; } if (!WS_IS_DECIMAL_DIGIT(ch)) { ws_src_error(compiler, 0, "no decimal digits in exponent part"); return WS_FALSE; } /* Append exponent part read so far. */ if (!ws_buffer_append_space(buffer, &p, 2)) { ws_error_memory(compiler); return WS_FALSE; } p[0] = 'e'; p[1] = sign; /* Read decimal digits. */ while (WS_IS_DECIMAL_DIGIT(ch)) { if (!ws_buffer_append_space(buffer, &p, 1)) { ws_error_memory(compiler); return WS_FALSE; } p[0] = (unsigned char) ch; if (!ws_stream_getc(compiler->input, &ch)) /* EOF. This is ok. */ goto done; } /* Unget the extra character. */ ws_stream_ungetc(compiler->input, ch); /* FALLTHROUGH */ done: if (!ws_buffer_append_space(buffer, &p, 1)) { ws_error_memory(compiler); return WS_FALSE; } p[0] = 0; /* Now the buffer contains a valid floating point number. */ *result = (WsFloat) strtod((char *) ws_buffer_ptr(buffer), NULL); /* Check that the generated floating point number fits to `float32'. */ if (*result == HUGE_VAL || *result == -HUGE_VAL || ws_ieee754_encode_single(*result, buf) != WS_IEEE754_OK) ws_src_error(compiler, 0, "floating point literal too large"); return WS_TRUE; } gateway-1.4.5/wmlscript/wserror.h0000644000175000017500000001251313227613126015571 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wserror.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Error and information reporting functions. * */ #ifndef WSERROR_H #define WSERROR_H /********************* High-level functions *****************************/ /* Report an informative message `message'. */ void ws_info(WsCompilerPtr compiler, char *message, ...); /* Report a fatal (non-recovable) error and terminate the program brutally. This is only used to report internal inconsistencies and bugs. This will never return. */ void ws_fatal(char *fmt, ...) PRINTFLIKE(1,2); /* Report an out-of-memory error. */ void ws_error_memory(WsCompilerPtr compiler); /* Report a syntax error from the line `line' of the current input stream. If the argument `line' is 0, the error line number is the current line number of the input stream. */ void ws_error_syntax(WsCompilerPtr compiler, WsUInt32 line); /* Report a source stream specific (WMLScript language specific) error `message' from the source stream line number `line'. If the argument `line' is 0, the line number information is taken from the input stream's current position. */ void ws_src_error(WsCompilerPtr compiler, WsUInt32 line, char *message, ...); /* Report a source stream specific warning `message' from the source stram line number `line'. If the argument `line' is 0, the line number information is taken from the input stream's current position. */ void ws_src_warning(WsCompilerPtr compiler, WsUInt32 line, char *message, ...); /********************* Low-level functions ******************************/ /* Standard output and error streams. These are handy macros to fetch the I/O function and its context corresponding to the stream from the compiler. */ #define WS_STREAM(_stream) \ compiler->params._stream ## _cb, \ compiler->params._stream ## _cb_context #define WS_STDOUT WS_STREAM(stdout) #define WS_STDERR WS_STREAM(stderr) /* Print the message `fmt', `...' to the stream `io', `context'. Note that not all format and format specifiers of the normal printf() are supported. */ void ws_fprintf(WsIOProc io, void *context, const char *fmt, ...); /* Print the message `fmt', `ap' to the stream `io', `context'. */ void ws_vfprintf(WsIOProc io, void *context, const char *fmt, va_list ap); /* Print the string `str' to the stream `io', `context'. The function will not print newline after the string. */ void ws_puts(WsIOProc io, void *context, const char *str); /* Print the character `ch' to the stream `io', `context'. */ void ws_fputc(int ch, WsIOProc io, void *context); #endif /* not WSERROR_H */ gateway-1.4.5/wmlscript/wsopcodes.h0000644000175000017500000002143613227613126016100 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* 0x00 */ {NULL, 0}, /* 0x01 */ {"jump_fw", 2}, /* 0x02 */ {"jump_fw_w", 3}, /* 0x03 */ {"jump_bw", 2}, /* 0x04 */ {"jump_bw_w", 3}, /* 0x05 */ {"tjump_fw", 2}, /* 0x06 */ {"tjump_fw_w", 3}, /* 0x07 */ {"tjump_bw", 2}, /* 0x08 */ {"tjump_bw_w", 3}, /* 0x09 */ {"call", 2}, /* 0x0a */ {"call_lib", 3}, /* 0x0b */ {"call_lib_w", 4}, /* 0x0c */ {"call_url", 4}, /* 0x0d */ {"call_url_w", 6}, /* 0x0e */ {"load_var", 2}, /* 0x0f */ {"store_var", 2}, /* 0x10 */ {"incr_var", 2}, /* 0x11 */ {"decr_var", 2}, /* 0x12 */ {"load_const", 2}, /* 0x13 */ {"load_const_w", 3}, /* 0x14 */ {"const_0", 1}, /* 0x15 */ {"const_1", 1}, /* 0x16 */ {"const_m1", 1}, /* 0x17 */ {"const_es", 1}, /* 0x18 */ {"const_invalid", 1}, /* 0x19 */ {"const_true", 1}, /* 0x1a */ {"const_false", 1}, /* 0x1b */ {"incr", 1}, /* 0x1c */ {"decr", 1}, /* 0x1d */ {"add_asg", 2}, /* 0x1e */ {"sub_asg", 2}, /* 0x1f */ {"uminus", 1}, /* 0x20 */ {"add", 1}, /* 0x21 */ {"sub", 1}, /* 0x22 */ {"mul", 1}, /* 0x23 */ {"div", 1}, /* 0x24 */ {"idiv", 1}, /* 0x25 */ {"rem", 1}, /* 0x26 */ {"b_and", 1}, /* 0x27 */ {"b_or", 1}, /* 0x28 */ {"b_xor", 1}, /* 0x29 */ {"b_not", 1}, /* 0x2a */ {"b_lshift", 1}, /* 0x2b */ {"b_rsshift", 1}, /* 0x2c */ {"b_rszshift", 1}, /* 0x2d */ {"eq", 1}, /* 0x2e */ {"le", 1}, /* 0x2f */ {"lt", 1}, /* 0x30 */ {"ge", 1}, /* 0x31 */ {"gt", 1}, /* 0x32 */ {"ne", 1}, /* 0x33 */ {"not", 1}, /* 0x34 */ {"scand", 1}, /* 0x35 */ {"scor", 1}, /* 0x36 */ {"tobool", 1}, /* 0x37 */ {"pop", 1}, /* 0x38 */ {"typeof", 1}, /* 0x39 */ {"isvalid", 1}, /* 0x3a */ {"return", 1}, /* 0x3b */ {"return_es", 1}, /* 0x3c */ {"debug", 1}, /* 0x3d */ {NULL, 0}, /* 0x3e */ {NULL, 0}, /* 0x3f */ {NULL, 0}, /* 0x40 */ {"store_var_s", 1}, /* 0x41 */ {NULL, 0}, /* 0x42 */ {NULL, 0}, /* 0x43 */ {NULL, 0}, /* 0x44 */ {NULL, 0}, /* 0x45 */ {NULL, 0}, /* 0x46 */ {NULL, 0}, /* 0x47 */ {NULL, 0}, /* 0x48 */ {NULL, 0}, /* 0x49 */ {NULL, 0}, /* 0x4a */ {NULL, 0}, /* 0x4b */ {NULL, 0}, /* 0x4c */ {NULL, 0}, /* 0x4d */ {NULL, 0}, /* 0x4e */ {NULL, 0}, /* 0x4f */ {NULL, 0}, /* 0x50 */ {"load_const_s", 1}, /* 0x51 */ {NULL, 0}, /* 0x52 */ {NULL, 0}, /* 0x53 */ {NULL, 0}, /* 0x54 */ {NULL, 0}, /* 0x55 */ {NULL, 0}, /* 0x56 */ {NULL, 0}, /* 0x57 */ {NULL, 0}, /* 0x58 */ {NULL, 0}, /* 0x59 */ {NULL, 0}, /* 0x5a */ {NULL, 0}, /* 0x5b */ {NULL, 0}, /* 0x5c */ {NULL, 0}, /* 0x5d */ {NULL, 0}, /* 0x5e */ {NULL, 0}, /* 0x5f */ {NULL, 0}, /* 0x60 */ {"call_s", 1}, /* 0x61 */ {NULL, 0}, /* 0x62 */ {NULL, 0}, /* 0x63 */ {NULL, 0}, /* 0x64 */ {NULL, 0}, /* 0x65 */ {NULL, 0}, /* 0x66 */ {NULL, 0}, /* 0x67 */ {NULL, 0}, /* 0x68 */ {"call_lib_s", 2}, /* 0x69 */ {NULL, 0}, /* 0x6a */ {NULL, 0}, /* 0x6b */ {NULL, 0}, /* 0x6c */ {NULL, 0}, /* 0x6d */ {NULL, 0}, /* 0x6e */ {NULL, 0}, /* 0x6f */ {NULL, 0}, /* 0x70 */ {"incr_var_s", 1}, /* 0x71 */ {NULL, 0}, /* 0x72 */ {NULL, 0}, /* 0x73 */ {NULL, 0}, /* 0x74 */ {NULL, 0}, /* 0x75 */ {NULL, 0}, /* 0x76 */ {NULL, 0}, /* 0x77 */ {NULL, 0}, /* 0x78 */ {NULL, 0}, /* 0x79 */ {NULL, 0}, /* 0x7a */ {NULL, 0}, /* 0x7b */ {NULL, 0}, /* 0x7c */ {NULL, 0}, /* 0x7d */ {NULL, 0}, /* 0x7e */ {NULL, 0}, /* 0x7f */ {NULL, 0}, /* 0x80 */ {"jump_fw_s", 1}, /* 0x81 */ {NULL, 0}, /* 0x82 */ {NULL, 0}, /* 0x83 */ {NULL, 0}, /* 0x84 */ {NULL, 0}, /* 0x85 */ {NULL, 0}, /* 0x86 */ {NULL, 0}, /* 0x87 */ {NULL, 0}, /* 0x88 */ {NULL, 0}, /* 0x89 */ {NULL, 0}, /* 0x8a */ {NULL, 0}, /* 0x8b */ {NULL, 0}, /* 0x8c */ {NULL, 0}, /* 0x8d */ {NULL, 0}, /* 0x8e */ {NULL, 0}, /* 0x8f */ {NULL, 0}, /* 0x90 */ {NULL, 0}, /* 0x91 */ {NULL, 0}, /* 0x92 */ {NULL, 0}, /* 0x93 */ {NULL, 0}, /* 0x94 */ {NULL, 0}, /* 0x95 */ {NULL, 0}, /* 0x96 */ {NULL, 0}, /* 0x97 */ {NULL, 0}, /* 0x98 */ {NULL, 0}, /* 0x99 */ {NULL, 0}, /* 0x9a */ {NULL, 0}, /* 0x9b */ {NULL, 0}, /* 0x9c */ {NULL, 0}, /* 0x9d */ {NULL, 0}, /* 0x9e */ {NULL, 0}, /* 0x9f */ {NULL, 0}, /* 0xa0 */ {"jump_bw_s", 1}, /* 0xa1 */ {NULL, 0}, /* 0xa2 */ {NULL, 0}, /* 0xa3 */ {NULL, 0}, /* 0xa4 */ {NULL, 0}, /* 0xa5 */ {NULL, 0}, /* 0xa6 */ {NULL, 0}, /* 0xa7 */ {NULL, 0}, /* 0xa8 */ {NULL, 0}, /* 0xa9 */ {NULL, 0}, /* 0xaa */ {NULL, 0}, /* 0xab */ {NULL, 0}, /* 0xac */ {NULL, 0}, /* 0xad */ {NULL, 0}, /* 0xae */ {NULL, 0}, /* 0xaf */ {NULL, 0}, /* 0xb0 */ {NULL, 0}, /* 0xb1 */ {NULL, 0}, /* 0xb2 */ {NULL, 0}, /* 0xb3 */ {NULL, 0}, /* 0xb4 */ {NULL, 0}, /* 0xb5 */ {NULL, 0}, /* 0xb6 */ {NULL, 0}, /* 0xb7 */ {NULL, 0}, /* 0xb8 */ {NULL, 0}, /* 0xb9 */ {NULL, 0}, /* 0xba */ {NULL, 0}, /* 0xbb */ {NULL, 0}, /* 0xbc */ {NULL, 0}, /* 0xbd */ {NULL, 0}, /* 0xbe */ {NULL, 0}, /* 0xbf */ {NULL, 0}, /* 0xc0 */ {"tjump_fw_s", 1}, /* 0xc1 */ {NULL, 0}, /* 0xc2 */ {NULL, 0}, /* 0xc3 */ {NULL, 0}, /* 0xc4 */ {NULL, 0}, /* 0xc5 */ {NULL, 0}, /* 0xc6 */ {NULL, 0}, /* 0xc7 */ {NULL, 0}, /* 0xc8 */ {NULL, 0}, /* 0xc9 */ {NULL, 0}, /* 0xca */ {NULL, 0}, /* 0xcb */ {NULL, 0}, /* 0xcc */ {NULL, 0}, /* 0xcd */ {NULL, 0}, /* 0xce */ {NULL, 0}, /* 0xcf */ {NULL, 0}, /* 0xd0 */ {NULL, 0}, /* 0xd1 */ {NULL, 0}, /* 0xd2 */ {NULL, 0}, /* 0xd3 */ {NULL, 0}, /* 0xd4 */ {NULL, 0}, /* 0xd5 */ {NULL, 0}, /* 0xd6 */ {NULL, 0}, /* 0xd7 */ {NULL, 0}, /* 0xd8 */ {NULL, 0}, /* 0xd9 */ {NULL, 0}, /* 0xda */ {NULL, 0}, /* 0xdb */ {NULL, 0}, /* 0xdc */ {NULL, 0}, /* 0xdd */ {NULL, 0}, /* 0xde */ {NULL, 0}, /* 0xdf */ {NULL, 0}, /* 0xe0 */ {"load_var_s", 1}, /* 0xe1 */ {NULL, 0}, /* 0xe2 */ {NULL, 0}, /* 0xe3 */ {NULL, 0}, /* 0xe4 */ {NULL, 0}, /* 0xe5 */ {NULL, 0}, /* 0xe6 */ {NULL, 0}, /* 0xe7 */ {NULL, 0}, /* 0xe8 */ {NULL, 0}, /* 0xe9 */ {NULL, 0}, /* 0xea */ {NULL, 0}, /* 0xeb */ {NULL, 0}, /* 0xec */ {NULL, 0}, /* 0xed */ {NULL, 0}, /* 0xee */ {NULL, 0}, /* 0xef */ {NULL, 0}, /* 0xf0 */ {NULL, 0}, /* 0xf1 */ {NULL, 0}, /* 0xf2 */ {NULL, 0}, /* 0xf3 */ {NULL, 0}, /* 0xf4 */ {NULL, 0}, /* 0xf5 */ {NULL, 0}, /* 0xf6 */ {NULL, 0}, /* 0xf7 */ {NULL, 0}, /* 0xf8 */ {NULL, 0}, /* 0xf9 */ {NULL, 0}, /* 0xfa */ {NULL, 0}, /* 0xfb */ {NULL, 0}, /* 0xfc */ {NULL, 0}, /* 0xfd */ {NULL, 0}, /* 0xfe */ {NULL, 0}, /* 0xff */ {NULL, 0}, gateway-1.4.5/wmlscript/wsstream_file.c0000644000175000017500000001557713227613126016742 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsstream_file.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Implementation of the file stream. * */ #include "wsint.h" /********************* Types and definitions ****************************/ struct WsStreamFileCtxRec { FILE *fp; /* Should the `fp' be closed when the stream is closed. */ WsBool close_fp; /* A temporary buffer for the raw file data. */ unsigned char buf[WS_STREAM_BUFFER_SIZE]; /* For file output streams, this variable holds the number of data in `buf'. */ size_t data_in_buf; /* Other fields (like character set conversion information) might be defined later. */ }; typedef struct WsStreamFileCtxRec WsStreamFileCtx; /********************* Static method functions **************************/ static size_t file_input(void *context, WsUInt32 *buf, size_t buflen) { WsStreamFileCtx *ctx = (WsStreamFileCtx *) context; size_t read = 0; while (buflen > 0) { size_t toread = buflen < sizeof(ctx->buf) ? buflen : sizeof(ctx->buf); size_t got, i; got = fread(ctx->buf, 1, toread, ctx->fp); /* Convert the data to the stream's IO buffer. */ for (i = 0; i < got; i++) buf[i] = ctx->buf[i]; buflen -= got; buf += got; read += got; if (got < toread) /* EOF seen. */ break; } return read; } static size_t file_output(void *context, WsUInt32 *buf, size_t buflen) { WsStreamFileCtx *ctx = (WsStreamFileCtx *) context; size_t wrote = 0; unsigned char ch; while (buflen) { /* Do we have any space in the stream's internal IO buffer? */ if (ctx->data_in_buf >= WS_STREAM_BUFFER_SIZE) { size_t w; /* No, flush something to our file stream. */ w = fwrite(ctx->buf, 1, ctx->data_in_buf, ctx->fp); if (w < ctx->data_in_buf) { /* Write failed. As a result code we return the number of characters written from our current write request. */ ctx->data_in_buf = 0; return wrote; } ctx->data_in_buf = 0; } /* Now we have space in the internal buffer. */ /* Here we could perform some sort of conversions from ISO 10646 to the output character set. Currently we just support ISO-8859/1 and all unknown characters are replaced with '?'. */ if (*buf > 0xff) ch = '?'; else ch = (unsigned char) * buf; ctx->buf[ctx->data_in_buf++] = ch; /* Move forward. */ buf++; buflen--; wrote++; } return wrote; } static WsBool file_flush(void *context) { WsStreamFileCtx *ctx = (WsStreamFileCtx *) context; /* If the internal buffer has any data, then this stream must be an output stream. The variable `data_in_buf' is not updated on input streams. */ if (ctx->data_in_buf) { if (fwrite(ctx->buf, 1, ctx->data_in_buf, ctx->fp) != ctx->data_in_buf) { /* The write failed. */ ctx->data_in_buf = 0; return WS_FALSE; } /* The temporary buffer is not empty. */ ctx->data_in_buf = 0; } /* Flush the underlying file stream. */ return fflush(ctx->fp) == 0; } static void file_close(void *context) { WsStreamFileCtx *ctx = (WsStreamFileCtx *) context; if (ctx->close_fp) fclose(ctx->fp); ws_free(ctx); } /********************* Global functions *********************************/ WsStream *ws_stream_new_file(FILE *fp, WsBool output, WsBool close) { WsStreamFileCtx *ctx = ws_calloc(1, sizeof(*ctx)); WsStream *stream; if (ctx == NULL) return NULL; ctx->fp = fp; ctx->close_fp = close; if (output) stream = ws_stream_new(ctx, file_output, file_flush, file_close); else stream = ws_stream_new(ctx, file_input, file_flush, file_close); if (stream == NULL) /* The stream creation failed. Close the stream context. */ file_close(ctx); return stream; } gateway-1.4.5/wmlscript/wsgram.h0000644000175000017500000001332411443356457015400 0ustar toljtolj/* A Bison parser, made by GNU Bison 2.3. */ /* Skeleton interface for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { tINVALID = 258, tTRUE = 259, tFALSE = 260, tINTEGER = 261, tFLOAT = 262, tSTRING = 263, tIDENTIFIER = 264, tACCESS = 265, tAGENT = 266, tBREAK = 267, tCONTINUE = 268, tIDIV = 269, tIDIVA = 270, tDOMAIN = 271, tELSE = 272, tEQUIV = 273, tEXTERN = 274, tFOR = 275, tFUNCTION = 276, tHEADER = 277, tHTTP = 278, tIF = 279, tISVALID = 280, tMETA = 281, tNAME = 282, tPATH = 283, tRETURN = 284, tTYPEOF = 285, tUSE = 286, tUSER = 287, tVAR = 288, tWHILE = 289, tURL = 290, tDELETE = 291, tIN = 292, tLIB = 293, tNEW = 294, tNULL = 295, tTHIS = 296, tVOID = 297, tWITH = 298, tCASE = 299, tCATCH = 300, tCLASS = 301, tCONST = 302, tDEBUGGER = 303, tDEFAULT = 304, tDO = 305, tENUM = 306, tEXPORT = 307, tEXTENDS = 308, tFINALLY = 309, tIMPORT = 310, tPRIVATE = 311, tPUBLIC = 312, tSIZEOF = 313, tSTRUCT = 314, tSUPER = 315, tSWITCH = 316, tTHROW = 317, tTRY = 318, tEQ = 319, tLE = 320, tGE = 321, tNE = 322, tAND = 323, tOR = 324, tPLUSPLUS = 325, tMINUSMINUS = 326, tLSHIFT = 327, tRSSHIFT = 328, tRSZSHIFT = 329, tADDA = 330, tSUBA = 331, tMULA = 332, tDIVA = 333, tANDA = 334, tORA = 335, tXORA = 336, tREMA = 337, tLSHIFTA = 338, tRSSHIFTA = 339, tRSZSHIFTA = 340 }; #endif /* Tokens. */ #define tINVALID 258 #define tTRUE 259 #define tFALSE 260 #define tINTEGER 261 #define tFLOAT 262 #define tSTRING 263 #define tIDENTIFIER 264 #define tACCESS 265 #define tAGENT 266 #define tBREAK 267 #define tCONTINUE 268 #define tIDIV 269 #define tIDIVA 270 #define tDOMAIN 271 #define tELSE 272 #define tEQUIV 273 #define tEXTERN 274 #define tFOR 275 #define tFUNCTION 276 #define tHEADER 277 #define tHTTP 278 #define tIF 279 #define tISVALID 280 #define tMETA 281 #define tNAME 282 #define tPATH 283 #define tRETURN 284 #define tTYPEOF 285 #define tUSE 286 #define tUSER 287 #define tVAR 288 #define tWHILE 289 #define tURL 290 #define tDELETE 291 #define tIN 292 #define tLIB 293 #define tNEW 294 #define tNULL 295 #define tTHIS 296 #define tVOID 297 #define tWITH 298 #define tCASE 299 #define tCATCH 300 #define tCLASS 301 #define tCONST 302 #define tDEBUGGER 303 #define tDEFAULT 304 #define tDO 305 #define tENUM 306 #define tEXPORT 307 #define tEXTENDS 308 #define tFINALLY 309 #define tIMPORT 310 #define tPRIVATE 311 #define tPUBLIC 312 #define tSIZEOF 313 #define tSTRUCT 314 #define tSUPER 315 #define tSWITCH 316 #define tTHROW 317 #define tTRY 318 #define tEQ 319 #define tLE 320 #define tGE 321 #define tNE 322 #define tAND 323 #define tOR 324 #define tPLUSPLUS 325 #define tMINUSMINUS 326 #define tLSHIFT 327 #define tRSSHIFT 328 #define tRSZSHIFT 329 #define tADDA 330 #define tSUBA 331 #define tMULA 332 #define tDIVA 333 #define tANDA 334 #define tORA 335 #define tXORA 336 #define tREMA 337 #define tLSHIFTA 338 #define tRSSHIFTA 339 #define tRSZSHIFTA 340 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE #line 34 "wmlscript/wsgram.y" { WsUInt32 integer; WsFloat vfloat; char *identifier; WsUtf8String *string; WsBool boolean; WsList *list; WsFormalParm *parm; WsVarDec *vardec; WsPragmaMetaBody *meta_body; WsStatement *stmt; WsExpression *expr; } /* Line 1529 of yacc.c. */ #line 236 "y.tab.h" YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; } YYLTYPE; # define yyltype YYLTYPE /* obsolescent; will be withdrawn */ # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif gateway-1.4.5/wmlscript/wmlsc.10000644000175000017500000000061007166363552015131 0ustar toljtolj.\" Hey, Emacs! This is an -*- nroff -*- source file. .TH WMLSC 1 "3rd October 2000" "Kannel Project" "Kannel Project" .SH NAME wmlsc \- WMLScript compiler .SH SYNOPSIS .B wmlsc .BR "" [ -adlsv ] .IR file ... .SH DESCRIPTION .B wmlsc compiles WMLScript source files into a binary version. It is useful for testing WMLScript file correctness. .SH "SEE ALSO" .BR wmlsdasm (1), .BR kannel (8). gateway-1.4.5/wmlscript/wmlsc.c0000644000175000017500000002361313227613126015211 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wmlsc.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Main for the WMLScript compiler. * */ #include #include #include #include #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include #include #include "gwlib/gwlib.h" #include "ws.h" /* XXX This module, as well, should use the gwmem wrappers. We'll change this later. --liw */ #undef malloc #undef realloc #undef free /********************* Prototypes for static functions ******************/ /* Print usage message to the stdout. */ static void usage(void); /* A callback function to receive the meta-pragmas. */ static void pragma_meta(const WsUtf8String *property_name, const WsUtf8String *content, const WsUtf8String *scheme, void *context); /********************* Static variables *********************************/ /* The name of the compiler program. */ static char *program; /* Use ws_compile_data() instead of ws_compile_file(). */ static int eval_data = 0; /********************* Global functions *********************************/ int main(int argc, char *argv[]) { int i; WsCompilerParams params; WsCompilerPtr compiler; WsResult result; int opt; program = strrchr(argv[0], '/'); if (program) program++; else program = argv[0]; /* Initialize the parameters structure. The command line options modify this directly. */ memset(¶ms, 0, sizeof(params)); /* Process command line arguments. */ while ((opt = getopt(argc, argv, "adhsv")) != EOF) { switch (opt) { case 'a': params.print_assembler = 1; break; case 'd': eval_data = 1; break; case 'h': usage(); exit(0); break; case 'l': params.use_latin1_strings = 1; break; case 'p': params.meta_name_cb = pragma_meta; params.meta_name_cb_context = "meta name"; params.meta_http_equiv_cb = pragma_meta; params.meta_http_equiv_cb_context = "meta http equiv"; break; case 's': params.print_symbolic_assembler = 1; break; case 'v': params.verbose = 1; break; case '?': printf("Try `%s -h' for a complete list of options.\n", program); exit(1); } } /* Create compiler. */ compiler = ws_create(¶ms); if (compiler == NULL) { fprintf(stderr, "wsc: could not create compiler\n"); exit(1); } for (i = optind; i < argc; i++) { FILE *ifp, *ofp; char *outname; ifp = fopen(argv[i], "rb"); if (ifp == NULL) { fprintf(stderr, "wsc: could not open input file `%s': %s'\n", argv[i], strerror(errno)); exit(1); } /* Create the output name. */ outname = malloc(strlen(argv[i]) + 1 + 1); if (outname == NULL) { fprintf(stderr, "wmlsc: could not create output file name: %s\n", strerror(errno)); exit(1); } strcpy(outname, argv[i]); strcat(outname, "c"); ofp = fopen(outname, "wb"); if (ofp == NULL) { fprintf(stderr, "wsc: could not create output file `%s': %s\n", outname, strerror(errno)); exit(1); } if (eval_data) { /* Use the ws_compile_data() interface. */ struct stat stat_st; unsigned char *data; unsigned char *output; size_t output_len; if (stat(argv[i], &stat_st) == -1) { fprintf(stderr, "wsc: could not stat input file `%s': %s\n", argv[i], strerror(errno)); exit(1); } /* Allocate the input buffer. */ data = malloc(stat_st.st_size); if (data == NULL) { fprintf(stderr, "wsc: could not allocate input buffer: %s\n", strerror(errno)); exit(1); } if (fread(data, 1, stat_st.st_size, ifp) < (size_t) stat_st.st_size) { fprintf(stderr, "wsc: could not read data: %s\n", strerror(errno)); exit(1); } result = ws_compile_data(compiler, argv[i], data, stat_st.st_size, &output, &output_len); if (result == WS_OK) { /* Save the output to `ofp'. */ if (fwrite(output, 1, output_len, ofp) != output_len) { fprintf(stderr, "wsc: could not save output to file `%s': %s\n", outname, strerror(errno)); exit(1); } } free(data); ws_free_byte_code(output); } else { /* Use the ws_compile_file() interface. */ result = ws_compile_file(compiler, argv[i], ifp, ofp); } /* Common cleanup. */ fclose(ifp); fclose(ofp); if (result != WS_OK) { remove(outname); fprintf(stderr, "wsc: compilation failed: %s\n", ws_result_to_string(result)); exit(1); } free(outname); } ws_destroy(compiler); return 0; } /********************* Static functions *********************************/ static void usage(void) { printf("Usage: %s OPTION... FILE...\n\ \n\ -a disassemble resulting byte-code and print it to the\n\ standard output\n\ -d use ws_eval_data() function instead of ws_eval_file()\n\ -h print this help message and exit successfully\n\ -l encode strings in ISO-8859/1 (ISO latin1) instead of using\n\ UTF-8\n\ -p print pragmas\n\ -s print symbolic byte-code assembler to the standard output\n\ -v print verbose progress messages\n\ \n", program); } static void pragma_meta(const WsUtf8String *property_name, const WsUtf8String *content, const WsUtf8String *scheme, void *context) { FILE *fp = stdout; char *what = (char *) context; char *property_name_l = (char *) ws_utf8_to_latin1(property_name, '?', NULL); char *content_l = (char *) ws_utf8_to_latin1(content, '?', NULL); char *scheme_l = (char *) ws_utf8_to_latin1(scheme, '?', NULL); fprintf(fp, "%s: name=\"%s\", content=\"%s\",", what, property_name_l ? property_name_l : "", content_l ? content_l : ""); if (scheme) fprintf(fp, ", scheme=\"%s\"", scheme_l ? scheme_l : ""); fprintf(fp, "\n"); ws_utf8_free_data((unsigned char *) property_name_l); ws_utf8_free_data((unsigned char *) content_l); ws_utf8_free_data((unsigned char *) scheme_l); } gateway-1.4.5/wmlscript/wsfalloc.c0000644000175000017500000001237213227613126015676 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsfalloc.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Fast memory allocation routines. * */ #include "wsint.h" /********************* Global functions *********************************/ WsFastMalloc *ws_f_create(size_t block_size) { WsFastMalloc *pool = ws_calloc(1, sizeof(WsFastMalloc)); if (pool == NULL) return NULL; pool->block_size = block_size; return pool; } void ws_f_destroy(WsFastMalloc *pool) { WsFastMallocBlock *b, *bnext; if (pool == NULL) return; for (b = pool->blocks; b; b = bnext) { bnext = b->next; ws_free(b); } ws_free(pool); } void *ws_f_malloc(WsFastMalloc *pool, size_t size) { unsigned char *result; /* Keep the blocks aligned, because this function is used to allocate * space for structures containing longs and such. */ if (size % sizeof(long) != 0) { size += sizeof(long) - (size % sizeof(long)); } if (pool->size < size) { size_t alloc_size; WsFastMallocBlock *b; /* Must allocate a fresh block. */ alloc_size = pool->block_size; if (alloc_size < size) alloc_size = size; /* Allocate the block and remember to add the header size. */ b = ws_malloc(alloc_size + sizeof(WsFastMallocBlock)); if (b == NULL) /* No memory available. */ return NULL; /* Add this block to the memory pool. */ b->next = pool->blocks; pool->blocks = b; pool->ptr = ((unsigned char *) b) + sizeof(WsFastMallocBlock); pool->size = alloc_size; } /* Now we can allocate `size' bytes of data from this pool. */ result = pool->ptr; pool->ptr += size; pool->size -= size; pool->user_bytes_allocated += size; return result; } void *ws_f_calloc(WsFastMalloc *pool, size_t num, size_t size) { void *p = ws_f_malloc(pool, num * size); if (p == NULL) return p; memset(p, 0, num * size); return p; } void *ws_f_memdup(WsFastMalloc *pool, const void *ptr, size_t size) { unsigned char *d = ws_f_malloc(pool, size + 1); if (d == NULL) return NULL; memcpy(d, ptr, size); d[size] = '\0'; return d; } void *ws_f_strdup(WsFastMalloc *pool, const char *str) { size_t len; char *s; if (str == NULL) return NULL; len = strlen(str) + 1; s = ws_f_malloc(pool, len); if (s == NULL) return NULL; memcpy(s, str, len); return s; } gateway-1.4.5/wmlscript/wsstream_data.c0000644000175000017500000001032413227613126016715 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsstream_data.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Implementation of the data streams. * */ #include "wmlscript/wsint.h" /********************* Types and definitions ****************************/ struct WsStreamDataInputCtxRec { const unsigned char *data; size_t data_len; size_t data_pos; }; typedef struct WsStreamDataInputCtxRec WsStreamDataInputCtx; /********************* Static method functions **************************/ static size_t data_input(void *context, WsUInt32 *buf, size_t buflen) { WsStreamDataInputCtx *ctx = (WsStreamDataInputCtx *) context; size_t read; for (read = 0; read < buflen && ctx->data_pos < ctx->data_len; read++, ctx->data_pos++) buf[read] = ctx->data[ctx->data_pos]; return read; } static void data_close(void *context) { WsStreamDataInputCtx *ctx = (WsStreamDataInputCtx *) context; ws_free(ctx); } /********************* Global functions *********************************/ WsStream *ws_stream_new_data_input(const unsigned char *data, size_t data_len) { WsStreamDataInputCtx *ctx = ws_calloc(1, sizeof(*ctx)); WsStream *stream; if (ctx == NULL) return NULL; ctx->data = data; ctx->data_len = data_len; stream = ws_stream_new(ctx, data_input, NULL, data_close); if (stream == NULL) /* The stream creation failed. Close the stream context. */ data_close(ctx); return stream; } gateway-1.4.5/wmlscript/wsopt.c0000644000175000017500000002700413227613126015236 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsopt.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Optimizations for the WMLScript symbolic assembler. * */ #include "wsint.h" #include "wsasm.h" /* TODO: liveness analyzation */ /* TODO: jumps to return or return_es */ /* TODO: remove empty labels (helps peephole opt) */ /* TODO: i++; becomes "load, incr, pop", optimize to just incr. */ /* TODO: { const; tjump } -> { jump or nothing } */ /********************* Optimization functions ***************************/ static WsBool opt_jumps_to_jumps(WsCompilerPtr compiler) { WsAsmIns *i; WsBool change = WS_TRUE; unsigned int count = 0; ws_info(compiler, "optimize: jumps to jumps"); while (change) { count++; change = WS_FALSE; for (i = compiler->asm_head; i; i = i->next) { WsAsmIns * j; if (!WS_ASM_P_BRANCH(i)) continue; /* Find the next instruction following the label. */ for (j = i->ws_label; j && j->type == WS_ASM_P_LABEL; j = j->next) ; if (j == NULL || j->type != WS_ASM_P_JUMP) /* Can't optimize this case. */ continue; /* We can optimize the jump `i' directly to the label of `j'. We must remember to update the reference counts too. */ i->ws_label->ws_label_refcount--; j->ws_label->ws_label_refcount++; i->ws_label = j->ws_label; change = WS_TRUE; } } return count > 1; } static WsBool opt_jumps_to_next_instruction(WsCompilerPtr compiler) { WsAsmIns *i; WsBool change = WS_FALSE; ws_info(compiler, "optimize: jumps to next instruction"); for (i = compiler->asm_head; i; i = i->next) { WsAsmIns * j; if (i->type != WS_ASM_P_JUMP) continue; for (j = i->next; j && j->type == WS_ASM_P_LABEL && i->ws_label != j; j = j->next) ; if (i->ws_label != j) /* Nop. */ continue; /* Remove the jump instruction `i'. */ change = WS_TRUE; i->ws_label->ws_label_refcount--; if (i->next) i->next->prev = i->prev; else compiler->asm_tail = i->prev; if (i->prev) i->prev->next = i->next; else compiler->asm_head = i->next; /* Continue from the label `j'. */ i = j; } return change; } static WsBool opt_dead_code(WsCompilerPtr compiler) { WsBool change = WS_FALSE; WsAsmIns *i; ws_info(compiler, "optimize: dead code"); for (i = compiler->asm_head; i; i = i->next) { WsAsmIns * j; if (!(i->type == WS_ASM_P_JUMP || i->type == WS_ASM_RETURN || i->type == WS_ASM_RETURN_ES)) continue; /* Skip until the next referenced label is found. */ for (j = i->next; j && (j->type != WS_ASM_P_LABEL || j->ws_label_refcount == 0); j = j->next) { /* Update label reference counts in the deleted block. */ if (WS_ASM_P_BRANCH(j)) j->ws_label->ws_label_refcount--; } if (j == i->next) /* Nothing to delete. */ continue; /* Delete everything between `i' and `j'. */ i->next = j; if (j) j->prev = i; else compiler->asm_tail = i; change = WS_TRUE; } return change; } static WsBool opt_peephole(WsCompilerPtr compiler) { WsBool change = WS_FALSE; WsAsmIns *i, *i2, *prev; WsAsmIns *new; ws_info(compiler, "optimize: peephole"); prev = NULL; i = compiler->asm_head; while (i) { /* Two instructions wide peephole. */ if (i->next) { i2 = i->next; /* * {load*,const*} => - * pop */ if (i2->type == WS_ASM_POP && (i->type == WS_ASM_P_LOAD_VAR || i->type == WS_ASM_P_LOAD_CONST || i->type == WS_ASM_CONST_0 || i->type == WS_ASM_CONST_1 || i->type == WS_ASM_CONST_M1 || i->type == WS_ASM_CONST_ES || i->type == WS_ASM_CONST_INVALID || i->type == WS_ASM_CONST_TRUE || i->type == WS_ASM_CONST_FALSE)) { /* Remove both instructions. */ change = WS_TRUE; if (prev) prev->next = i2->next; else compiler->asm_head = i2->next; if (i2->next) i2->next->prev = prev; else compiler->asm_tail = prev; i = i2->next; continue; } /* * const_es => return_es * return */ if (i2->type == WS_ASM_RETURN && i->type == WS_ASM_CONST_ES) { /* Replace with WS_ASM_RETURN_ES */ new = ws_asm_ins(compiler, i->line, WS_ASM_RETURN_ES); if (new) { change = WS_TRUE; if (prev) prev->next = new; else compiler->asm_head = new; new->prev = prev; new->next = i2->next; if (new->next) new->next->prev = new; else compiler->asm_tail = new; i = new; continue; } } } /* Move forward. */ prev = i; i = i->next; } /* The interpreter will by default return the empty string if a * function ends without a return statement, so returning the * empty string at the end of a function is never useful. */ if (compiler->asm_tail && compiler->asm_tail->type == WS_ASM_RETURN_ES) { compiler->asm_tail = compiler->asm_tail->prev; if (compiler->asm_tail == NULL) compiler->asm_head = NULL; else compiler->asm_tail->next = NULL; } return change; } /* * Remove conversions that are followed by an opcode that does * that conversion automatically anyway. */ static WsBool opt_conv(WsCompilerPtr compiler) { WsBool change = WS_FALSE; WsAsmIns *i, *next, *prev; ws_info(compiler, "optimize: peephole"); prev = NULL; i = compiler->asm_head; while (i) { if (i->type == WS_ASM_TOBOOL) { next = i->next; /* Skip labels. They're not going to affect which instruction * gets executed after this TOBOOL. */ while (next != NULL && next->type == WS_ASM_P_LABEL) next = next->next; if (next != NULL && (next->type == WS_ASM_P_TJUMP || next->type == WS_ASM_NOT || next->type == WS_ASM_SCAND || next->type == WS_ASM_SCOR || next->type == WS_ASM_TOBOOL || next->type == WS_ASM_POP)) { /* The next instruction will automatically convert its * operand to boolean, or does not care about its operand * (POP), so the TOBOOL is not necessary. Delete it. */ change = WS_TRUE; /* Use i->next here because next might have been incremented * past a label, which we do not want to delete. */ if (prev) prev->next = i->next; else compiler->asm_head = i->next; if (i->next) i->next->prev = prev; else compiler->asm_tail = prev; } } prev = i; i = i->next; } return change; } /********************* Global entry point *******************************/ void ws_asm_optimize(WsCompilerPtr compiler) { WsBool change = WS_TRUE; /* While we manage to change the assembler, perform the requested optimizations. */ while (change) { change = WS_FALSE; /* Useless conversions */ if (!compiler->params.no_opt_conv && opt_conv(compiler)) change = WS_TRUE; /* Peephole. */ if (!compiler->params.no_opt_peephole && opt_peephole(compiler)) change = WS_TRUE; /* Jumps to jump instructions. */ if (!compiler->params.no_opt_jumps_to_jumps && opt_jumps_to_jumps(compiler)) change = WS_TRUE; /* Jumps to the next instruction. */ if (!compiler->params.no_opt_jumps_to_next_instruction && opt_jumps_to_next_instruction(compiler)) change = WS_TRUE; /* Unreachable code. */ if (!compiler->params.no_opt_dead_code && opt_dead_code(compiler)) change = WS_TRUE; } } gateway-1.4.5/wmlscript/wsieee754.c0000644000175000017500000002556413227613126015614 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsieee754.h * * Author: Markku Rossi * * Copyright (c) 2000 WAPIT OY LTD. * All rights reserved. * * Functions to manipulate ANSI/IEEE Std 754-1985 binary floating-point * numbers. * */ #include "wsint.h" /********************* Types and definitions ****************************/ #define WS_IEEE754_SINGLE_EXP_SIZE 8 #define WS_IEEE754_SINGLE_MANT_SIZE 23 #define WS_IEEE754_SINGLE_BIAS 127 #define WS_IEEE754_SINGLE_EXP_MIN -126 #define WS_IEEE754_SINGLE_EXP_MAX 127 #define WS_IEEE754_POSITIVE_INFINITY 0x7f800000 /********************* Special values ***********************************/ unsigned char ws_ieee754_nan[4] = {0xff, 0xff, 0xff, 0xff}; unsigned char ws_ieee754_positive_inf[4] = {0x7f, 0x80, 0x00, 0x00}; unsigned char ws_ieee754_negative_inf[4] = {0xff, 0x80, 0x00, 0x00}; /********************* Global functions *********************************/ WsIeee754Result ws_ieee754_encode_single(double value, unsigned char *buf) { int sign = 0; WsInt32 exp = 0; WsUInt32 mant = 0; int i; WsIeee754Result result = WS_IEEE754_OK; /* The sign bit. */ if (value < 0.0) { sign = 1; value = -value; } /* Scale the value so that: 1 <= mantissa < 2. */ if (value > 1.0) { /* The exponent is positive. */ while (value >= 2.0 && exp <= WS_IEEE754_SINGLE_EXP_MAX) { value /= 2.0; exp++; } if (exp > WS_IEEE754_SINGLE_EXP_MAX) { /* Overflow => infinity. */ exp = 0xff; if (sign) result = WS_IEEE754_NEGATIVE_INF; else result = WS_IEEE754_POSITIVE_INF; goto done; } /* The 1 is implicit. */ value -= 1; } else { /* The exponent is negative. */ while (value < 1.0 && exp > WS_IEEE754_SINGLE_EXP_MIN) { value *= 2.0; exp--; } if (value >= 1.0) { /* We managed to get the number to the normal form. Let's remote the implicit 1 from the value. */ gw_assert(value >= 1.0); value -= 1.0; } else { /* The number is still smaller than 1. We just try to present the remaining stuff in our mantissa. If that fails, we fall back to 0.0. We mark exp to -127 (after bias it is 0) to mark this unnormalized form. */ exp--; gw_assert(exp == -127); } } for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) { value *= 2.0; mant <<= 1; if (value >= 1.0) { mant |= 1; value -= 1.0; } } /* Handle rounding. Intel seems to round 0.5 down so to be compatible, our check is > instead of >=. */ if (value * 2.0 > 1.0) { mant++; if (mant == 0x800000) { /* This we the really worst case. The rounding rounds the mant up to 2.0. So we must increase the exponent by one. This may then result an overflow in the exponent which converts our number to infinity. */ mant = 0; exp++; if (exp > WS_IEEE754_SINGLE_EXP_MAX) { /* Overflow => infinity. */ exp = 0xff; goto done; } } } /* Handle biased exponent. */ exp += WS_IEEE754_SINGLE_BIAS; done: /* Encode the value to the buffer. */ mant |= exp << 23; mant |= sign << 31; buf[3] = (mant & 0x000000ff); buf[2] = (mant & 0x0000ff00) >> 8; buf[1] = (mant & 0x00ff0000) >> 16; buf[0] = (mant & 0xff000000) >> 24; return result; } WsIeee754Result ws_ieee754_decode_single(unsigned char *buf, double *value_return) { WsUInt32 sign = ws_ieee754_single_get_sign(buf); WsInt32 exp = (WsInt32) ws_ieee754_single_get_exp(buf); WsUInt32 mant = ws_ieee754_single_get_mant(buf); double value; int i; /* Check the special cases where exponent is all 1. */ if (exp == 0xff) { if (mant == 0) return sign ? WS_IEEE754_NEGATIVE_INF : WS_IEEE754_POSITIVE_INF; return WS_IEEE754_NAN; } /* Expand the mantissa. */ value = 0.0; for (i = 0; i < WS_IEEE754_SINGLE_MANT_SIZE; i++) { if (mant & 0x1) value += 1.0; value /= 2.0; mant >>= 1; } /* Check the `unnormalized' vs. `normal form'. */ if (exp == 0) /* This is a `unnormalized' number. */ exp = -126; else { /* This is a standard case. */ value += 1.0; exp -= WS_IEEE754_SINGLE_BIAS; } /* Handle exponents. */ while (exp > 0) { value *= 2; exp--; } while (exp < 0) { value /= 2; exp++; } /* Finally notify sign. */ if (sign) value = -value; *value_return = value; return WS_IEEE754_OK; } WsUInt32 ws_ieee754_single_get_sign(unsigned char *buf) { return (buf[0] & 0x80) >> 7; } WsUInt32 ws_ieee754_single_get_exp(unsigned char *buf) { WsUInt32 value = buf[0] & 0x7f; value <<= 1; value |= (buf[1] & 0x80) >> 7; return value; } WsUInt32 ws_ieee754_single_get_mant(unsigned char *buf) { WsUInt32 value = buf[1] & 0x7f; value <<= 8; value |= buf[2]; value <<= 8; value |= buf[3]; return value; } #if 0 /********************* Tests for IEEE754 functions **********************/ void ws_ieee754_print(unsigned char *buf) { int i, j; for (i = 0; i < 4; i++) { unsigned char mask = 0x80; unsigned char ch = buf[i]; for (j = 0; j < 8; j++) { if (ch & mask) printf("1"); else printf("0"); if ((i == 0 && j == 0) || (i == 1 && j == 0)) printf(" "); mask >>= 1; } } printf("\n"); } #include #include #include void check_value(double num) { float native = num; unsigned char buf[4]; struct ieee_single *s = (struct ieee_single *) & native; unsigned int *uip = (unsigned int *) s; unsigned int n = ntohl(*uip); double d; ws_ieee754_encode_single(num, buf); if (memcmp(buf, &n, 4) != 0) { printf("\n"); printf("%f failed:\n", num); printf("ws: "); ws_ieee754_print(buf); printf("native: "); ws_ieee754_print((unsigned char *) &n); abort(); } if (ws_ieee754_decode_single(buf, &d) != WS_IEEE754_OK || d != native) { printf("\ndecode of %f failed: got %f\n", num, d); abort(); } } int main(int argc, char *argv[]) { unsigned char buf[4]; unsigned int rounds = 0; if (argc > 1) { int i; for (i = 1; i < argc; i++) check_value(strtod(argv[1], NULL)); return 0; } ws_ieee754_encode_single(5.75, buf); ws_ieee754_print(buf); check_value(5.75); ws_ieee754_encode_single(340282346638528859811704183484516925440.0, buf); ws_ieee754_print(buf); check_value(340282346638528859811704183484516925440.0); ws_ieee754_encode_single( -340282346638528859811704183484516925440.0, buf); ws_ieee754_print(buf); check_value( -340282346638528859811704183484516925440.0); ws_ieee754_encode_single(3.0 * pow(2, -129), buf); ws_ieee754_print(buf); check_value(3.0 * pow(2, -129)); ws_ieee754_encode_single(pow(2, -149), buf); ws_ieee754_print(buf); check_value(pow(2, -149)); ws_ieee754_encode_single(pow(2, -149) * .1, buf); ws_ieee754_print(buf); check_value(pow(2, -149) * .1); ws_ieee754_encode_single( -pow(2, -149), buf); ws_ieee754_print(buf); check_value( -pow(2, -149)); ws_ieee754_encode_single( -pow(2, -149) * .1, buf); ws_ieee754_print(buf); while (1) { double a = random(); double b = random(); if (b == 0.0) continue; check_value(a / b); check_value(a * b); if ((++rounds % 100000) == 0) { printf("%d ", rounds); fflush(stdout); } } return 0; } #endif gateway-1.4.5/wmlscript/wsgram.c0000644000175000017500000026417611443356457015410 0ustar toljtolj/* A Bison parser, made by GNU Bison 2.3. */ /* Skeleton implementation for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.3" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Using locations. */ #define YYLSP_NEEDED 1 /* Substitute the variable and function names. */ #define yyparse ws_yy_parse #define yylex ws_yy_lex #define yyerror ws_yy_error #define yylval ws_yy_lval #define yychar ws_yy_char #define yydebug ws_yy_debug #define yynerrs ws_yy_nerrs #define yylloc ws_yy_lloc /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { tINVALID = 258, tTRUE = 259, tFALSE = 260, tINTEGER = 261, tFLOAT = 262, tSTRING = 263, tIDENTIFIER = 264, tACCESS = 265, tAGENT = 266, tBREAK = 267, tCONTINUE = 268, tIDIV = 269, tIDIVA = 270, tDOMAIN = 271, tELSE = 272, tEQUIV = 273, tEXTERN = 274, tFOR = 275, tFUNCTION = 276, tHEADER = 277, tHTTP = 278, tIF = 279, tISVALID = 280, tMETA = 281, tNAME = 282, tPATH = 283, tRETURN = 284, tTYPEOF = 285, tUSE = 286, tUSER = 287, tVAR = 288, tWHILE = 289, tURL = 290, tDELETE = 291, tIN = 292, tLIB = 293, tNEW = 294, tNULL = 295, tTHIS = 296, tVOID = 297, tWITH = 298, tCASE = 299, tCATCH = 300, tCLASS = 301, tCONST = 302, tDEBUGGER = 303, tDEFAULT = 304, tDO = 305, tENUM = 306, tEXPORT = 307, tEXTENDS = 308, tFINALLY = 309, tIMPORT = 310, tPRIVATE = 311, tPUBLIC = 312, tSIZEOF = 313, tSTRUCT = 314, tSUPER = 315, tSWITCH = 316, tTHROW = 317, tTRY = 318, tEQ = 319, tLE = 320, tGE = 321, tNE = 322, tAND = 323, tOR = 324, tPLUSPLUS = 325, tMINUSMINUS = 326, tLSHIFT = 327, tRSSHIFT = 328, tRSZSHIFT = 329, tADDA = 330, tSUBA = 331, tMULA = 332, tDIVA = 333, tANDA = 334, tORA = 335, tXORA = 336, tREMA = 337, tLSHIFTA = 338, tRSSHIFTA = 339, tRSZSHIFTA = 340 }; #endif /* Tokens. */ #define tINVALID 258 #define tTRUE 259 #define tFALSE 260 #define tINTEGER 261 #define tFLOAT 262 #define tSTRING 263 #define tIDENTIFIER 264 #define tACCESS 265 #define tAGENT 266 #define tBREAK 267 #define tCONTINUE 268 #define tIDIV 269 #define tIDIVA 270 #define tDOMAIN 271 #define tELSE 272 #define tEQUIV 273 #define tEXTERN 274 #define tFOR 275 #define tFUNCTION 276 #define tHEADER 277 #define tHTTP 278 #define tIF 279 #define tISVALID 280 #define tMETA 281 #define tNAME 282 #define tPATH 283 #define tRETURN 284 #define tTYPEOF 285 #define tUSE 286 #define tUSER 287 #define tVAR 288 #define tWHILE 289 #define tURL 290 #define tDELETE 291 #define tIN 292 #define tLIB 293 #define tNEW 294 #define tNULL 295 #define tTHIS 296 #define tVOID 297 #define tWITH 298 #define tCASE 299 #define tCATCH 300 #define tCLASS 301 #define tCONST 302 #define tDEBUGGER 303 #define tDEFAULT 304 #define tDO 305 #define tENUM 306 #define tEXPORT 307 #define tEXTENDS 308 #define tFINALLY 309 #define tIMPORT 310 #define tPRIVATE 311 #define tPUBLIC 312 #define tSIZEOF 313 #define tSTRUCT 314 #define tSUPER 315 #define tSWITCH 316 #define tTHROW 317 #define tTRY 318 #define tEQ 319 #define tLE 320 #define tGE 321 #define tNE 322 #define tAND 323 #define tOR 324 #define tPLUSPLUS 325 #define tMINUSMINUS 326 #define tLSHIFT 327 #define tRSSHIFT 328 #define tRSZSHIFT 329 #define tADDA 330 #define tSUBA 331 #define tMULA 332 #define tDIVA 333 #define tANDA 334 #define tORA 335 #define tXORA 336 #define tREMA 337 #define tLSHIFTA 338 #define tRSSHIFTA 339 #define tRSZSHIFTA 340 /* Copy the first part of user declarations. */ #line 1 "wmlscript/wsgram.y" /* * * wsgram.y * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Bison grammar for the WMLScript compiler. * */ #include "wmlscript/wsint.h" #define YYPARSE_PARAM pctx #define YYLEX_PARAM pctx /* The required yyerror() function. This is actually not used but to report the internal parser errors. All other errors are reported by using the `wserror.h' functions. */ extern void yyerror(char *msg); #if WS_DEBUG /* Just for debugging purposes. */ WsCompilerPtr global_compiler = NULL; #endif /* WS_DEBUG */ /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* Enabling the token table. */ #ifndef YYTOKEN_TABLE # define YYTOKEN_TABLE 0 #endif #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE #line 34 "wmlscript/wsgram.y" { WsUInt32 integer; WsFloat vfloat; char *identifier; WsUtf8String *string; WsBool boolean; WsList *list; WsFormalParm *parm; WsVarDec *vardec; WsPragmaMetaBody *meta_body; WsStatement *stmt; WsExpression *expr; } /* Line 193 of yacc.c. */ #line 322 "y.tab.c" YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_TRIVIAL 1 #endif #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; } YYLTYPE; # define yyltype YYLTYPE /* obsolescent; will be withdrawn */ # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif /* Copy the second part of user declarations. */ /* Line 216 of yacc.c. */ #line 347 "y.tab.c" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int i) #else static int YYID (i) int i; #endif { return i; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss; YYSTYPE yyvs; YYLTYPE yyls; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack, Stack, yysize); \ Stack = &yyptr->Stack; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 17 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 448 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 109 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 55 /* YYNRULES -- Number of rules. */ #define YYNRULES 146 /* YYNRULES -- Number of states. */ #define YYNSTATES 257 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 340 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 106, 2, 107, 2, 104, 97, 2, 87, 88, 102, 100, 89, 101, 108, 103, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 94, 86, 98, 92, 99, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 95, 91, 105, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint16 yyprhs[] = { 0, 0, 3, 6, 8, 10, 12, 15, 19, 21, 23, 25, 27, 31, 34, 37, 40, 45, 48, 50, 52, 54, 57, 61, 65, 68, 72, 74, 76, 78, 80, 83, 92, 93, 95, 96, 98, 99, 101, 103, 107, 109, 111, 113, 116, 118, 120, 123, 126, 128, 132, 134, 135, 137, 139, 142, 146, 149, 151, 155, 158, 159, 162, 170, 176, 182, 184, 194, 205, 209, 210, 212, 214, 218, 220, 224, 228, 232, 236, 240, 244, 248, 252, 256, 260, 264, 268, 272, 274, 280, 282, 286, 288, 292, 294, 298, 300, 304, 306, 310, 312, 316, 320, 322, 326, 330, 334, 338, 340, 344, 348, 352, 354, 358, 362, 364, 368, 372, 376, 380, 382, 385, 388, 391, 394, 397, 400, 403, 406, 408, 411, 414, 416, 419, 424, 429, 431, 433, 435, 437, 439, 441, 443, 447, 450, 454, 456 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { 110, 0, -1, 111, 126, -1, 126, -1, 1, -1, 112, -1, 111, 112, -1, 31, 113, 86, -1, 1, -1, 114, -1, 115, -1, 117, -1, 35, 9, 8, -1, 10, 116, -1, 16, 8, -1, 28, 8, -1, 16, 8, 28, 8, -1, 26, 118, -1, 119, -1, 120, -1, 121, -1, 27, 122, -1, 23, 18, 122, -1, 32, 11, 122, -1, 123, 124, -1, 123, 124, 125, -1, 8, -1, 8, -1, 8, -1, 127, -1, 126, 127, -1, 128, 21, 9, 87, 129, 88, 133, 130, -1, -1, 19, -1, -1, 131, -1, -1, 86, -1, 9, -1, 131, 89, 9, -1, 133, -1, 136, -1, 86, -1, 145, 86, -1, 140, -1, 141, -1, 13, 86, -1, 12, 86, -1, 143, -1, 90, 134, 91, -1, 1, -1, -1, 135, -1, 132, -1, 135, 132, -1, 33, 137, 86, -1, 33, 1, -1, 138, -1, 137, 89, 138, -1, 9, 139, -1, -1, 92, 147, -1, 24, 87, 145, 88, 132, 17, 132, -1, 24, 87, 145, 88, 132, -1, 34, 87, 145, 88, 132, -1, 142, -1, 20, 87, 144, 86, 144, 86, 144, 88, 132, -1, 20, 87, 33, 137, 86, 144, 86, 144, 88, 132, -1, 29, 144, 86, -1, -1, 145, -1, 146, -1, 145, 89, 146, -1, 147, -1, 9, 92, 146, -1, 9, 77, 146, -1, 9, 78, 146, -1, 9, 82, 146, -1, 9, 75, 146, -1, 9, 76, 146, -1, 9, 83, 146, -1, 9, 84, 146, -1, 9, 85, 146, -1, 9, 79, 146, -1, 9, 81, 146, -1, 9, 80, 146, -1, 9, 15, 146, -1, 148, -1, 148, 93, 146, 94, 146, -1, 149, -1, 148, 69, 149, -1, 150, -1, 149, 68, 150, -1, 151, -1, 150, 95, 151, -1, 152, -1, 151, 96, 152, -1, 153, -1, 152, 97, 153, -1, 154, -1, 153, 64, 154, -1, 153, 67, 154, -1, 155, -1, 154, 98, 155, -1, 154, 99, 155, -1, 154, 65, 155, -1, 154, 66, 155, -1, 156, -1, 155, 72, 156, -1, 155, 73, 156, -1, 155, 74, 156, -1, 157, -1, 156, 100, 157, -1, 156, 101, 157, -1, 158, -1, 157, 102, 158, -1, 157, 103, 158, -1, 157, 14, 158, -1, 157, 104, 158, -1, 159, -1, 30, 158, -1, 25, 158, -1, 70, 9, -1, 71, 9, -1, 100, 158, -1, 101, 158, -1, 105, 158, -1, 106, 158, -1, 160, -1, 9, 70, -1, 9, 71, -1, 161, -1, 9, 162, -1, 9, 107, 9, 162, -1, 9, 108, 9, 162, -1, 9, -1, 3, -1, 4, -1, 5, -1, 6, -1, 7, -1, 8, -1, 87, 145, 88, -1, 87, 88, -1, 87, 163, 88, -1, 146, -1, 163, 89, 146, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 122, 122, 123, 124, 131, 132, 136, 137, 142, 143, 144, 148, 153, 157, 167, 178, 201, 205, 206, 207, 211, 229, 249, 284, 286, 290, 291, 292, 297, 298, 302, 317, 318, 323, 324, 327, 329, 333, 351, 372, 380, 381, 383, 385, 386, 387, 389, 391, 394, 402, 411, 412, 416, 421, 426, 428, 433, 438, 443, 459, 460, 465, 467, 472, 474, 478, 481, 487, 494, 495, 500, 501, 506, 507, 509, 511, 513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 536, 537, 542, 543, 548, 549, 554, 555, 560, 561, 566, 567, 572, 573, 575, 580, 581, 583, 585, 587, 592, 593, 595, 597, 602, 603, 605, 610, 611, 613, 615, 617, 622, 623, 625, 627, 629, 631, 647, 649, 651, 656, 657, 659, 664, 665, 675, 677, 682, 684, 686, 688, 690, 692, 694, 696, 701, 703, 708, 713 }; #endif #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "tINVALID", "tTRUE", "tFALSE", "tINTEGER", "tFLOAT", "tSTRING", "tIDENTIFIER", "tACCESS", "tAGENT", "tBREAK", "tCONTINUE", "tIDIV", "tIDIVA", "tDOMAIN", "tELSE", "tEQUIV", "tEXTERN", "tFOR", "tFUNCTION", "tHEADER", "tHTTP", "tIF", "tISVALID", "tMETA", "tNAME", "tPATH", "tRETURN", "tTYPEOF", "tUSE", "tUSER", "tVAR", "tWHILE", "tURL", "tDELETE", "tIN", "tLIB", "tNEW", "tNULL", "tTHIS", "tVOID", "tWITH", "tCASE", "tCATCH", "tCLASS", "tCONST", "tDEBUGGER", "tDEFAULT", "tDO", "tENUM", "tEXPORT", "tEXTENDS", "tFINALLY", "tIMPORT", "tPRIVATE", "tPUBLIC", "tSIZEOF", "tSTRUCT", "tSUPER", "tSWITCH", "tTHROW", "tTRY", "tEQ", "tLE", "tGE", "tNE", "tAND", "tOR", "tPLUSPLUS", "tMINUSMINUS", "tLSHIFT", "tRSSHIFT", "tRSZSHIFT", "tADDA", "tSUBA", "tMULA", "tDIVA", "tANDA", "tORA", "tXORA", "tREMA", "tLSHIFTA", "tRSSHIFTA", "tRSZSHIFTA", "';'", "'('", "')'", "','", "'{'", "'}'", "'='", "'?'", "':'", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'", "'-'", "'*'", "'/'", "'%'", "'~'", "'!'", "'#'", "'.'", "$accept", "CompilationUnit", "Pragmas", "Pragma", "PragmaDeclaration", "ExternalCompilationUnitPragma", "AccessControlPragma", "AccessControlSpecifier", "MetaPragma", "MetaSpecifier", "MetaName", "MetaHttpEquiv", "MetaUserAgent", "MetaBody", "MetaPropertyName", "MetaContent", "MetaScheme", "FunctionDeclarations", "FunctionDeclaration", "ExternOpt", "FormalParameterListOpt", "SemicolonOpt", "FormalParameterList", "Statement", "Block", "StatementListOpt", "StatementList", "VariableStatement", "VariableDeclarationList", "VariableDeclaration", "VariableInitializedOpt", "IfStatement", "IterationStatement", "ForStatement", "ReturnStatement", "ExpressionOpt", "Expression", "AssignmentExpression", "ConditionalExpression", "LogicalORExpression", "LogicalANDExpression", "BitwiseORExpression", "BitwiseXORExpression", "BitwiseANDExpression", "EqualityExpression", "RelationalExpression", "ShiftExpression", "AdditiveExpression", "MultiplicativeExpression", "UnaryExpression", "PostfixExpression", "CallExpression", "PrimaryExpression", "Arguments", "ArgumentList", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 59, 40, 41, 44, 123, 125, 61, 63, 58, 124, 94, 38, 60, 62, 43, 45, 42, 47, 37, 126, 33, 35, 46 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 109, 110, 110, 110, 111, 111, 112, 112, 113, 113, 113, 114, 115, 116, 116, 116, 117, 118, 118, 118, 119, 120, 121, 122, 122, 123, 124, 125, 126, 126, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 132, 132, 132, 132, 132, 132, 132, 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 139, 139, 140, 140, 141, 141, 142, 142, 143, 144, 144, 145, 145, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 147, 147, 148, 148, 149, 149, 150, 150, 151, 151, 152, 152, 153, 153, 153, 154, 154, 154, 154, 154, 155, 155, 155, 155, 156, 156, 156, 157, 157, 157, 157, 157, 158, 158, 158, 158, 158, 158, 158, 158, 158, 159, 159, 159, 160, 160, 160, 160, 161, 161, 161, 161, 161, 161, 161, 161, 162, 162, 163, 163 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 2, 1, 1, 1, 2, 3, 1, 1, 1, 1, 3, 2, 2, 2, 4, 2, 1, 1, 1, 2, 3, 3, 2, 3, 1, 1, 1, 1, 2, 8, 0, 1, 0, 1, 0, 1, 1, 3, 1, 1, 1, 2, 1, 1, 2, 2, 1, 3, 1, 0, 1, 1, 2, 3, 2, 1, 3, 2, 0, 2, 7, 5, 5, 1, 9, 10, 3, 0, 1, 1, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 5, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 1, 3, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 1, 3, 3, 3, 3, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 4, 4, 1, 1, 1, 1, 1, 1, 1, 3, 2, 3, 1, 3 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 0, 8, 33, 0, 0, 0, 5, 3, 29, 0, 0, 0, 0, 0, 9, 10, 11, 1, 8, 6, 2, 30, 0, 0, 0, 13, 0, 0, 0, 17, 18, 19, 20, 0, 7, 0, 14, 15, 0, 26, 21, 0, 0, 12, 34, 0, 22, 27, 24, 23, 38, 0, 35, 16, 28, 25, 0, 0, 50, 0, 36, 39, 136, 137, 138, 139, 140, 141, 135, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 53, 40, 0, 0, 41, 44, 45, 65, 48, 0, 71, 73, 87, 89, 91, 93, 95, 97, 99, 102, 107, 111, 114, 119, 128, 131, 37, 31, 0, 129, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 132, 47, 46, 69, 0, 135, 121, 0, 70, 120, 56, 60, 0, 57, 0, 122, 123, 0, 124, 125, 126, 127, 49, 54, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 78, 79, 75, 76, 83, 85, 84, 77, 80, 81, 82, 143, 145, 0, 74, 0, 0, 0, 0, 0, 68, 0, 59, 55, 0, 0, 142, 72, 90, 0, 92, 94, 96, 98, 100, 101, 105, 106, 103, 104, 108, 109, 110, 112, 113, 117, 115, 116, 118, 144, 0, 133, 134, 0, 69, 0, 61, 58, 0, 0, 146, 69, 0, 63, 64, 88, 0, 69, 0, 69, 0, 62, 0, 0, 0, 66, 67 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 4, 5, 6, 13, 14, 15, 25, 16, 29, 30, 31, 32, 40, 41, 48, 55, 7, 8, 9, 51, 113, 52, 86, 87, 88, 89, 90, 144, 145, 202, 91, 92, 93, 94, 139, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 132, 193 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -135 static const yytype_int16 yypact[] = { 59, 39, -135, 28, 68, 63, -135, 38, -135, 62, 37, 54, 13, -43, -135, -135, -135, -135, -135, -135, 38, -135, 57, 67, 87, -135, 92, 108, 109, -135, -135, -135, -135, 121, -135, 47, 123, -135, 108, -135, -135, 141, 108, -135, 155, 164, -135, -135, 166, -135, -135, 89, 107, -135, -135, -135, 1, 188, -135, 132, 112, -135, -135, -135, -135, -135, -135, -135, 340, 115, 120, 124, 125, 296, 308, 296, 35, 126, 198, 201, -135, 308, 296, 296, 296, 296, -135, -135, 129, 175, -135, -135, -135, -135, -135, -83, -135, -135, -48, 146, 122, 119, 127, 12, -25, 45, 5, 44, -135, -135, -135, -135, -135, -135, 308, -135, -135, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 308, 222, 308, 207, 212, -135, -135, -135, 264, 308, -38, -135, 148, 147, -135, -135, 143, -1, -135, 308, -135, -135, 43, -135, -135, -135, -135, -135, -135, -135, 308, 296, 308, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, -135, -135, -135, -135, -135, -135, -135, -135, -135, -135, -135, -135, -135, -135, 66, -135, 152, 152, 231, 156, 70, -135, 296, -135, -135, 231, 82, -135, -135, 146, 149, 122, 119, 127, 12, -25, -25, 45, 45, 45, 45, 5, 5, 5, 44, 44, -135, -135, -135, -135, -135, 308, -135, -135, 25, 308, 22, -135, -135, 22, 308, -135, 308, 158, 224, -135, -135, 162, 308, 22, 308, 161, -135, 163, 22, 22, -135, -135 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -135, -135, -135, 245, -135, -135, -135, -135, -135, -135, -135, -135, -135, 29, -135, -135, -135, 248, 17, -135, -135, -135, -135, -85, 199, -135, -135, -135, 60, 50, -135, -135, -135, -135, -135, -134, -74, -109, 55, -135, 100, 99, 102, 98, 101, -22, -65, -46, 20, 14, -135, -135, -135, -10, -135 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -53 static const yytype_int16 yytable[] = { 140, 198, 58, 156, 155, 179, 157, 149, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 192, 194, 158, 33, 58, 21, 62, 63, 64, 65, 66, 67, 68, 115, 116, 69, 70, 142, 21, 10, -4, 166, 167, 71, 34, 143, 159, 72, 73, 207, 128, 209, 74, 75, 23, 11, 76, 77, 2, 175, -32, 1, 140, 199, 12, 18, 24, 35, 46, 17, 130, 131, 49, 205, 168, 169, 36, 164, 26, 2, 165, -32, 27, 2, 22, -32, 203, 28, 138, 204, 141, 3, 59, 78, 79, 3, 37, 150, 151, 152, 153, 242, 216, 217, 218, 219, 173, 174, 246, 80, 81, 38, 241, 59, 250, 204, 252, 39, 170, 171, 172, 42, 240, 82, 83, 220, 221, 222, 84, 85, 43, 245, 206, 157, 58, 44, 62, 63, 64, 65, 66, 67, 68, 214, 215, 69, 70, 176, 177, 178, 47, 243, 45, 71, 244, 229, 230, 72, 73, 235, 157, 140, 74, 75, 251, 50, 76, 77, 140, 255, 256, 238, 157, 53, 140, 54, 140, 58, 56, 62, 63, 64, 65, 66, 67, 68, 231, 232, 69, 70, 225, 226, 227, 228, 223, 224, 71, 57, 61, 112, 72, 73, 133, 78, 79, 74, 75, 134, 147, 76, 77, 148, 135, 136, 146, 160, 162, 195, 161, 80, 81, 154, 196, 59, -51, 163, 62, 63, 64, 65, 66, 67, 68, 82, 83, 200, 201, 157, 84, 85, 128, 143, 248, 234, 239, 247, 78, 79, 73, 249, 253, 19, 254, 75, 20, 237, 60, 236, 233, 208, 210, 212, 80, 81, 211, 213, 59, -52, 62, 63, 64, 65, 66, 67, 68, 0, 82, 83, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, 0, 0, 73, 0, 0, 78, 79, 75, 0, 0, 197, 0, 62, 63, 64, 65, 66, 67, 137, 0, 0, 0, 81, 191, 62, 63, 64, 65, 66, 67, 68, 0, 0, 0, 73, 82, 83, 0, 0, 75, 84, 85, 0, 0, 0, 0, 73, 78, 79, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 114, 0, 0, 0, 0, 0, 0, 0, 0, 82, 83, 78, 79, 0, 84, 85, 0, 0, 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 82, 83, 0, 0, 0, 84, 85, 0, 0, 0, 0, 0, 82, 83, 115, 116, 0, 84, 85, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 0, 128, 0, 0, 0, 0, 129, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 130, 131 }; static const yytype_int16 yycheck[] = { 74, 135, 1, 86, 89, 114, 89, 81, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 69, 9, 1, 7, 3, 4, 5, 6, 7, 8, 9, 70, 71, 12, 13, 1, 20, 10, 0, 65, 66, 20, 86, 9, 93, 24, 25, 157, 87, 159, 29, 30, 16, 26, 33, 34, 19, 14, 21, 1, 135, 136, 35, 1, 28, 9, 38, 0, 107, 108, 42, 146, 98, 99, 8, 64, 23, 19, 67, 21, 27, 19, 21, 21, 86, 32, 73, 89, 75, 31, 90, 70, 71, 31, 8, 82, 83, 84, 85, 234, 166, 167, 168, 169, 100, 101, 241, 86, 87, 18, 86, 90, 247, 89, 249, 8, 72, 73, 74, 11, 230, 100, 101, 170, 171, 172, 105, 106, 8, 239, 88, 89, 1, 87, 3, 4, 5, 6, 7, 8, 9, 164, 165, 12, 13, 102, 103, 104, 8, 235, 28, 20, 238, 88, 89, 24, 25, 88, 89, 234, 29, 30, 248, 9, 33, 34, 241, 253, 254, 88, 89, 8, 247, 8, 249, 1, 88, 3, 4, 5, 6, 7, 8, 9, 195, 196, 12, 13, 175, 176, 177, 178, 173, 174, 20, 89, 9, 86, 24, 25, 86, 70, 71, 29, 30, 86, 9, 33, 34, 9, 87, 87, 87, 68, 96, 9, 95, 86, 87, 91, 9, 90, 91, 97, 3, 4, 5, 6, 7, 8, 9, 100, 101, 86, 92, 89, 105, 106, 87, 9, 17, 86, 94, 86, 70, 71, 25, 86, 88, 5, 88, 30, 5, 204, 56, 201, 197, 158, 160, 162, 86, 87, 161, 163, 90, 91, 3, 4, 5, 6, 7, 8, 9, -1, 100, 101, -1, -1, -1, 105, 106, -1, -1, -1, -1, -1, -1, -1, 25, -1, -1, 70, 71, 30, -1, -1, 33, -1, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, 87, 88, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, 25, 100, 101, -1, -1, 30, 105, 106, -1, -1, -1, -1, 25, 70, 71, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, -1, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, 100, 101, 70, 71, -1, 105, 106, -1, -1, -1, -1, -1, -1, -1, 70, 71, -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 100, 101, -1, -1, -1, 105, 106, -1, -1, -1, -1, -1, 100, 101, 70, 71, -1, 105, 106, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, -1, 87, -1, -1, -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 107, 108 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 1, 19, 31, 110, 111, 112, 126, 127, 128, 10, 26, 35, 113, 114, 115, 117, 0, 1, 112, 126, 127, 21, 16, 28, 116, 23, 27, 32, 118, 119, 120, 121, 9, 86, 9, 8, 8, 18, 8, 122, 123, 11, 8, 87, 28, 122, 8, 124, 122, 9, 129, 131, 8, 8, 125, 88, 89, 1, 90, 133, 9, 3, 4, 5, 6, 7, 8, 9, 12, 13, 20, 24, 25, 29, 30, 33, 34, 70, 71, 86, 87, 100, 101, 105, 106, 132, 133, 134, 135, 136, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 86, 130, 15, 70, 71, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 87, 92, 107, 108, 162, 86, 86, 87, 87, 9, 158, 144, 145, 158, 1, 9, 137, 138, 87, 9, 9, 145, 158, 158, 158, 158, 91, 132, 86, 89, 69, 93, 68, 95, 96, 97, 64, 67, 65, 66, 98, 99, 72, 73, 74, 100, 101, 14, 102, 103, 104, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 88, 146, 163, 146, 9, 9, 33, 144, 145, 86, 92, 139, 86, 89, 145, 88, 146, 149, 146, 150, 151, 152, 153, 154, 154, 155, 155, 155, 155, 156, 156, 156, 157, 157, 158, 158, 158, 158, 88, 89, 162, 162, 137, 86, 88, 147, 138, 88, 94, 146, 86, 144, 132, 132, 146, 144, 86, 17, 86, 144, 132, 144, 88, 88, 132, 132 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ (Loc).last_line, (Loc).last_column) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) #else # define YYLEX yylex (&yylval, &yylloc) #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value, Location); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; YYLTYPE const * const yylocationp; #endif { if (!yyvaluep) return; YYUSE (yylocationp); # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; YYLTYPE const * const yylocationp; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); YY_LOCATION_PRINT (yyoutput, *yylocationp); YYFPRINTF (yyoutput, ": "); yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) #else static void yy_stack_print (bottom, top) yytype_int16 *bottom; yytype_int16 *top; #endif { YYFPRINTF (stderr, "Stack now"); for (; bottom <= top; ++bottom) YYFPRINTF (stderr, " %d", *bottom); YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule) #else static void yy_reduce_print (yyvsp, yylsp, yyrule) YYSTYPE *yyvsp; YYLTYPE *yylsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { fprintf (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) , &(yylsp[(yyi + 1) - (yynrhs)]) ); fprintf (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, yylsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into YYRESULT an error message about the unexpected token YYCHAR while in state YYSTATE. Return the number of bytes copied, including the terminating null byte. If YYRESULT is null, do not copy anything; just return the number of bytes that would be copied. As a special case, return 0 if an ordinary "syntax error" message will do. Return YYSIZE_MAXIMUM if overflow occurs during size calculation. */ static YYSIZE_T yysyntax_error (char *yyresult, int yystate, int yychar) { int yyn = yypact[yystate]; if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) return 0; else { int yytype = YYTRANSLATE (yychar); YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; int yysize_overflow = 0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; int yyx; # if 0 /* This is so xgettext sees the translatable formats that are constructed on the fly. */ YY_("syntax error, unexpected %s"); YY_("syntax error, unexpected %s, expecting %s"); YY_("syntax error, unexpected %s, expecting %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); # endif char *yyfmt; char const *yyf; static char const yyunexpected[] = "syntax error, unexpected %s"; static char const yyexpecting[] = ", expecting %s"; static char const yyor[] = " or %s"; char yyformat[sizeof yyunexpected + sizeof yyexpecting - 1 + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) * (sizeof yyor - 1))]; char const *yyprefix = yyexpecting; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yycount = 1; yyarg[0] = yytname[yytype]; yyfmt = yystpcpy (yyformat, yyunexpected); for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; yyformat[sizeof yyunexpected - 1] = '\0'; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; yyfmt = yystpcpy (yyfmt, yyprefix); yyprefix = yyor; } yyf = YY_(yyformat); yysize1 = yysize + yystrlen (yyf); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; if (yysize_overflow) return YYSIZE_MAXIMUM; if (yyresult) { /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ char *yyp = yyresult; int yyi = 0; while ((*yyp = *yyf) != '\0') { if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyf += 2; } else { yyp++; yyf++; } } } return yysize; } } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) #else static void yydestruct (yymsg, yytype, yyvaluep, yylocationp) const char *yymsg; int yytype; YYSTYPE *yyvaluep; YYLTYPE *yylocationp; #endif { YYUSE (yyvaluep); YYUSE (yylocationp); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /*----------. | yyparse. | `----------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { /* The look-ahead symbol. */ int yychar; /* The semantic value of the look-ahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /* Location data for the look-ahead symbol. */ YYLTYPE yylloc; int yystate; int yyn; int yyresult; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* Look-ahead token as an internal (translated) token number. */ int yytoken = 0; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif /* Three stacks and their tools: `yyss': related to states, `yyvs': related to semantic values, `yyls': related to locations. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss = yyssa; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp; /* The location stack. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls = yylsa; YYLTYPE *yylsp; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[2]; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) YYSIZE_T yystacksize = YYINITDEPTH; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; yylsp = yyls; #if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL /* Initialize the default location before parsing starts. */ yylloc.first_line = yylloc.last_line = 1; yylloc.first_column = yylloc.last_column = 0; #endif goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); yyls = yyls1; yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss); YYSTACK_RELOCATE (yyvs); YYSTACK_RELOCATE (yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a look-ahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to look-ahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; /* Not known => get a look-ahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } if (yyn == YYFINAL) YYACCEPT; /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the look-ahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token unless it is eof. */ if (yychar != YYEOF) yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; *++yylsp = yylloc; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; /* Default location. */ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); YY_REDUCE_PRINT (yyn); switch (yyn) { case 4: #line 125 "wmlscript/wsgram.y" { ws_error_syntax(pctx, (yylsp[(1) - (1)]).first_line); } break; case 8: #line 138 "wmlscript/wsgram.y" { ws_error_syntax(pctx, (yylsp[(1) - (1)]).first_line); } break; case 12: #line 149 "wmlscript/wsgram.y" { ws_pragma_use(pctx, (yylsp[(2) - (3)]).first_line, (yyvsp[(2) - (3)].identifier), (yyvsp[(3) - (3)].string)); } break; case 14: #line 158 "wmlscript/wsgram.y" { WsCompiler *compiler = (WsCompiler *) pctx; /* Pass this to the byte-code */ if (!ws_bc_add_pragma_access_domain(compiler->bc, (yyvsp[(2) - (2)].string)->data, (yyvsp[(2) - (2)].string)->len)) ws_error_memory(pctx); ws_lexer_free_utf8(compiler, (yyvsp[(2) - (2)].string)); } break; case 15: #line 168 "wmlscript/wsgram.y" { WsCompiler *compiler = (WsCompiler *) pctx; /* Pass this to the byte-code */ if (!ws_bc_add_pragma_access_path(compiler->bc, (yyvsp[(2) - (2)].string)->data, (yyvsp[(2) - (2)].string)->len)) ws_error_memory(pctx); ws_lexer_free_utf8(compiler, (yyvsp[(2) - (2)].string)); } break; case 16: #line 179 "wmlscript/wsgram.y" { WsCompiler *compiler = (WsCompiler *) pctx; WsBool success = WS_TRUE; /* Pass these to the byte-code */ if (!ws_bc_add_pragma_access_domain(compiler->bc, (yyvsp[(2) - (4)].string)->data, (yyvsp[(2) - (4)].string)->len)) success = WS_FALSE; if (!ws_bc_add_pragma_access_path(compiler->bc, (yyvsp[(4) - (4)].string)->data, (yyvsp[(4) - (4)].string)->len)) success = WS_FALSE; if (!success) ws_error_memory(pctx); ws_lexer_free_utf8(compiler, (yyvsp[(2) - (4)].string)); ws_lexer_free_utf8(compiler, (yyvsp[(4) - (4)].string)); } break; case 21: #line 212 "wmlscript/wsgram.y" { WsCompiler *compiler = (WsCompiler *) pctx; /* Meta information for the origin servers. Show it * to the user if requested. */ if (compiler->params.meta_name_cb) (*compiler->params.meta_name_cb)( (yyvsp[(2) - (2)].meta_body)->property_name, (yyvsp[(2) - (2)].meta_body)->content, (yyvsp[(2) - (2)].meta_body)->scheme, compiler->params.meta_name_cb_context); /* We do not need the MetaBody anymore. */ ws_pragma_meta_body_free(compiler, (yyvsp[(2) - (2)].meta_body)); } break; case 22: #line 230 "wmlscript/wsgram.y" { WsCompiler *compiler = (WsCompiler *) pctx; /* Meta information HTTP header that should be * included to an HTTP response header. Show it to * the user if requested. */ if (compiler->params.meta_http_equiv_cb) (*compiler->params.meta_http_equiv_cb)( (yyvsp[(3) - (3)].meta_body)->property_name, (yyvsp[(3) - (3)].meta_body)->content, (yyvsp[(3) - (3)].meta_body)->scheme, compiler->params.meta_http_equiv_cb_context); /* We do not need the MetaBody anymore. */ ws_pragma_meta_body_free(compiler, (yyvsp[(3) - (3)].meta_body)); } break; case 23: #line 250 "wmlscript/wsgram.y" { WsBool success; WsCompiler *compiler = (WsCompiler *) pctx; /* Pass this pragma to the byte-code */ if ((yyvsp[(3) - (3)].meta_body)) { if ((yyvsp[(3) - (3)].meta_body)->scheme) success = ws_bc_add_pragma_user_agent_property_and_scheme( compiler->bc, (yyvsp[(3) - (3)].meta_body)->property_name->data, (yyvsp[(3) - (3)].meta_body)->property_name->len, (yyvsp[(3) - (3)].meta_body)->content->data, (yyvsp[(3) - (3)].meta_body)->content->len, (yyvsp[(3) - (3)].meta_body)->scheme->data, (yyvsp[(3) - (3)].meta_body)->scheme->len); else success = ws_bc_add_pragma_user_agent_property( compiler->bc, (yyvsp[(3) - (3)].meta_body)->property_name->data, (yyvsp[(3) - (3)].meta_body)->property_name->len, (yyvsp[(3) - (3)].meta_body)->content->data, (yyvsp[(3) - (3)].meta_body)->content->len); /* Free the MetaBody. */ ws_pragma_meta_body_free(compiler, (yyvsp[(3) - (3)].meta_body)); if (!success) ws_error_memory(pctx); } } break; case 24: #line 285 "wmlscript/wsgram.y" { (yyval.meta_body) = ws_pragma_meta_body(pctx, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].string), NULL); } break; case 25: #line 287 "wmlscript/wsgram.y" { (yyval.meta_body) = ws_pragma_meta_body(pctx, (yyvsp[(1) - (3)].string), (yyvsp[(2) - (3)].string), (yyvsp[(3) - (3)].string)); } break; case 31: #line 304 "wmlscript/wsgram.y" { char *name = ws_strdup((yyvsp[(3) - (8)].identifier)); ws_lexer_free_block(pctx, (yyvsp[(3) - (8)].identifier)); if (name) ws_function(pctx, (yyvsp[(1) - (8)].boolean), name, (yylsp[(3) - (8)]).first_line, (yyvsp[(5) - (8)].list), (yyvsp[(7) - (8)].list)); else ws_error_memory(pctx); } break; case 32: #line 317 "wmlscript/wsgram.y" { (yyval.boolean) = WS_FALSE; } break; case 33: #line 318 "wmlscript/wsgram.y" { (yyval.boolean) = WS_TRUE; } break; case 34: #line 323 "wmlscript/wsgram.y" { (yyval.list) = ws_list_new(pctx); } break; case 38: #line 334 "wmlscript/wsgram.y" { char *id; WsFormalParm *parm; id = ws_f_strdup(((WsCompiler *) pctx)->pool_stree, (yyvsp[(1) - (1)].identifier)); parm = ws_formal_parameter(pctx, (yylsp[(1) - (1)]).first_line, id); ws_lexer_free_block(pctx, (yyvsp[(1) - (1)].identifier)); if (id == NULL || parm == NULL) { ws_error_memory(pctx); (yyval.list) = NULL; } else { (yyval.list) = ws_list_new(pctx); ws_list_append(pctx, (yyval.list), parm); } } break; case 39: #line 352 "wmlscript/wsgram.y" { char *id; WsFormalParm *parm; id = ws_f_strdup(((WsCompiler *) pctx)->pool_stree, (yyvsp[(3) - (3)].identifier)); parm = ws_formal_parameter(pctx, (yylsp[(1) - (3)]).first_line, id); ws_lexer_free_block(pctx, (yyvsp[(3) - (3)].identifier)); if (id == NULL || parm == NULL) { ws_error_memory(pctx); (yyval.list) = NULL; } else ws_list_append(pctx, (yyvsp[(1) - (3)].list), parm); } break; case 40: #line 373 "wmlscript/wsgram.y" { if ((yyvsp[(1) - (1)].list)) (yyval.stmt) = ws_stmt_block(pctx, (yyvsp[(1) - (1)].list)->first_line, (yyvsp[(1) - (1)].list)->last_line, (yyvsp[(1) - (1)].list)); else (yyval.stmt) = NULL; } break; case 42: #line 382 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_empty(pctx, (yylsp[(1) - (1)]).first_line); } break; case 43: #line 384 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_expr(pctx, (yyvsp[(1) - (2)].expr)->line, (yyvsp[(1) - (2)].expr)); } break; case 46: #line 388 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_continue(pctx, (yylsp[(1) - (2)]).first_line); } break; case 47: #line 390 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_break(pctx, (yylsp[(1) - (2)]).first_line); } break; case 49: #line 395 "wmlscript/wsgram.y" { (yyval.list) = (yyvsp[(2) - (3)].list); if ((yyval.list)) { (yyval.list)->first_line = (yylsp[(1) - (3)]).first_line; (yyval.list)->last_line = (yylsp[(3) - (3)]).first_line; } } break; case 50: #line 403 "wmlscript/wsgram.y" { ws_error_syntax(pctx, (yylsp[(1) - (1)]).first_line); (yyval.list) = NULL; } break; case 51: #line 411 "wmlscript/wsgram.y" { (yyval.list) = ws_list_new(pctx); } break; case 53: #line 417 "wmlscript/wsgram.y" { (yyval.list) = ws_list_new(pctx); ws_list_append(pctx, (yyval.list), (yyvsp[(1) - (1)].stmt)); } break; case 54: #line 422 "wmlscript/wsgram.y" { ws_list_append(pctx, (yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].stmt)); } break; case 55: #line 427 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_variable(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(2) - (3)].list)); } break; case 56: #line 429 "wmlscript/wsgram.y" { ws_error_syntax(pctx, (yylsp[(2) - (2)]).first_line); } break; case 57: #line 434 "wmlscript/wsgram.y" { (yyval.list) = ws_list_new(pctx); ws_list_append(pctx, (yyval.list), (yyvsp[(1) - (1)].vardec)); } break; case 58: #line 439 "wmlscript/wsgram.y" { ws_list_append(pctx, (yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].vardec)); } break; case 59: #line 444 "wmlscript/wsgram.y" { char *id = ws_f_strdup(((WsCompiler *) pctx)->pool_stree, (yyvsp[(1) - (2)].identifier)); ws_lexer_free_block(pctx, (yyvsp[(1) - (2)].identifier)); if (id == NULL) { ws_error_memory(pctx); (yyval.vardec) = NULL; } else (yyval.vardec) = ws_variable_declaration(pctx, id, (yyvsp[(2) - (2)].expr)); } break; case 60: #line 459 "wmlscript/wsgram.y" { (yyval.expr) = NULL; } break; case 61: #line 461 "wmlscript/wsgram.y" { (yyval.expr) = (yyvsp[(2) - (2)].expr); } break; case 62: #line 466 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_if(pctx, (yylsp[(1) - (7)]).first_line, (yyvsp[(3) - (7)].expr), (yyvsp[(5) - (7)].stmt), (yyvsp[(7) - (7)].stmt)); } break; case 63: #line 468 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_if(pctx, (yylsp[(1) - (5)]).first_line, (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].stmt), NULL); } break; case 64: #line 473 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_while(pctx, (yylsp[(1) - (5)]).first_line, (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].stmt)); } break; case 66: #line 480 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_for(pctx, (yylsp[(1) - (9)]).first_line, NULL, (yyvsp[(3) - (9)].expr), (yyvsp[(5) - (9)].expr), (yyvsp[(7) - (9)].expr), (yyvsp[(9) - (9)].stmt)); } break; case 67: #line 483 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_for(pctx, (yylsp[(1) - (10)]).first_line, (yyvsp[(4) - (10)].list), NULL, (yyvsp[(6) - (10)].expr), (yyvsp[(8) - (10)].expr), (yyvsp[(10) - (10)].stmt)); } break; case 68: #line 488 "wmlscript/wsgram.y" { (yyval.stmt) = ws_stmt_return(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(2) - (3)].expr)); } break; case 69: #line 494 "wmlscript/wsgram.y" { (yyval.expr) = NULL; } break; case 72: #line 502 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_comma(pctx, (yylsp[(2) - (3)]).first_line, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 74: #line 508 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), '=', (yyvsp[(3) - (3)].expr)); } break; case 75: #line 510 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tMULA, (yyvsp[(3) - (3)].expr)); } break; case 76: #line 512 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tDIVA, (yyvsp[(3) - (3)].expr)); } break; case 77: #line 514 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tREMA, (yyvsp[(3) - (3)].expr)); } break; case 78: #line 516 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tADDA, (yyvsp[(3) - (3)].expr)); } break; case 79: #line 518 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tSUBA, (yyvsp[(3) - (3)].expr)); } break; case 80: #line 520 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tLSHIFTA, (yyvsp[(3) - (3)].expr)); } break; case 81: #line 522 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tRSSHIFTA, (yyvsp[(3) - (3)].expr)); } break; case 82: #line 524 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tRSZSHIFTA, (yyvsp[(3) - (3)].expr)); } break; case 83: #line 526 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tANDA, (yyvsp[(3) - (3)].expr)); } break; case 84: #line 528 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tXORA, (yyvsp[(3) - (3)].expr)); } break; case 85: #line 530 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tORA, (yyvsp[(3) - (3)].expr)); } break; case 86: #line 532 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_assign(pctx, (yylsp[(1) - (3)]).first_line, (yyvsp[(1) - (3)].identifier), tIDIVA, (yyvsp[(3) - (3)].expr)); } break; case 88: #line 538 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_conditional(pctx, (yylsp[(2) - (5)]).first_line, (yyvsp[(1) - (5)].expr), (yyvsp[(3) - (5)].expr), (yyvsp[(5) - (5)].expr)); } break; case 90: #line 544 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_logical(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_SCOR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 92: #line 550 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_logical(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_SCAND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 94: #line 556 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_B_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 96: #line 562 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_B_XOR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 98: #line 568 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_B_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 100: #line 574 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_EQ, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 101: #line 576 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_NE, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 103: #line 582 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_LT, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 104: #line 584 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_GT, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 105: #line 586 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_LE, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 106: #line 588 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_GE, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 108: #line 594 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_B_LSHIFT, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 109: #line 596 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_B_RSSHIFT, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 110: #line 598 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_B_RSZSHIFT, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 112: #line 604 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_ADD, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 113: #line 606 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_SUB, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 115: #line 612 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_MUL, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 116: #line 614 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_DIV, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 117: #line 616 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_IDIV, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 118: #line 618 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_binary(pctx, (yylsp[(2) - (3)]).first_line, WS_ASM_REM, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } break; case 120: #line 624 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_unary(pctx, (yylsp[(1) - (2)]).first_line, WS_ASM_TYPEOF, (yyvsp[(2) - (2)].expr)); } break; case 121: #line 626 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_unary(pctx, (yylsp[(1) - (2)]).first_line, WS_ASM_ISVALID, (yyvsp[(2) - (2)].expr)); } break; case 122: #line 628 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_unary_var(pctx, (yylsp[(1) - (2)]).first_line, WS_TRUE, (yyvsp[(2) - (2)].identifier)); } break; case 123: #line 630 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_unary_var(pctx, (yylsp[(1) - (2)]).first_line, WS_FALSE, (yyvsp[(2) - (2)].identifier)); } break; case 124: #line 632 "wmlscript/wsgram.y" { /* There is no direct way to compile unary `+'. * It doesn't do anything except require type conversion * (section 7.2, 7.3.2), and we do that by converting * it to a binary expression: `UnaryExpression - 0'. * Using `--UnaryExpression' would not be correct because * it might overflow if UnaryExpression is the smallest * possible integer value (see 6.2.7.1). * Using `UnaryExpression + 0' would not be correct * because binary `+' accepts strings, which makes the * type conversion different. */ (yyval.expr) = ws_expr_binary(pctx, (yylsp[(1) - (2)]).first_line, WS_ASM_SUB, (yyvsp[(2) - (2)].expr), ws_expr_const_integer(pctx, (yylsp[(1) - (2)]).first_line, 0)); } break; case 125: #line 648 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_unary(pctx, (yylsp[(1) - (2)]).first_line, WS_ASM_UMINUS, (yyvsp[(2) - (2)].expr)); } break; case 126: #line 650 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_unary(pctx, (yylsp[(1) - (2)]).first_line, WS_ASM_B_NOT, (yyvsp[(2) - (2)].expr)); } break; case 127: #line 652 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_unary(pctx, (yylsp[(1) - (2)]).first_line, WS_ASM_NOT, (yyvsp[(2) - (2)].expr)); } break; case 129: #line 658 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_postfix_var(pctx, (yylsp[(1) - (2)]).first_line, WS_TRUE, (yyvsp[(1) - (2)].identifier)); } break; case 130: #line 660 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_postfix_var(pctx, (yylsp[(1) - (2)]).first_line, WS_FALSE, (yyvsp[(1) - (2)].identifier)); } break; case 132: #line 666 "wmlscript/wsgram.y" { WsFunctionHash *f = ws_function_hash(pctx, (yyvsp[(1) - (2)].identifier)); /* Add an usage count for the local script function. */ if (f) f->usage_count++; (yyval.expr) = ws_expr_call(pctx, (yylsp[(1) - (2)]).first_line, ' ', NULL, (yyvsp[(1) - (2)].identifier), (yyvsp[(2) - (2)].list)); } break; case 133: #line 676 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_call(pctx, (yylsp[(3) - (4)]).first_line, '#', (yyvsp[(1) - (4)].identifier), (yyvsp[(3) - (4)].identifier), (yyvsp[(4) - (4)].list)); } break; case 134: #line 678 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_call(pctx, (yylsp[(3) - (4)]).first_line, '.', (yyvsp[(1) - (4)].identifier), (yyvsp[(3) - (4)].identifier), (yyvsp[(4) - (4)].list)); } break; case 135: #line 683 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_symbol(pctx, (yylsp[(1) - (1)]).first_line, (yyvsp[(1) - (1)].identifier)); } break; case 136: #line 685 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_const_invalid(pctx, (yylsp[(1) - (1)]).first_line); } break; case 137: #line 687 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_const_true(pctx, (yylsp[(1) - (1)]).first_line); } break; case 138: #line 689 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_const_false(pctx, (yylsp[(1) - (1)]).first_line); } break; case 139: #line 691 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_const_integer(pctx, (yylsp[(1) - (1)]).first_line, (yyvsp[(1) - (1)].integer)); } break; case 140: #line 693 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_const_float(pctx, (yylsp[(1) - (1)]).first_line, (yyvsp[(1) - (1)].vfloat)); } break; case 141: #line 695 "wmlscript/wsgram.y" { (yyval.expr) = ws_expr_const_string(pctx, (yylsp[(1) - (1)]).first_line, (yyvsp[(1) - (1)].string)); } break; case 142: #line 697 "wmlscript/wsgram.y" { (yyval.expr) = (yyvsp[(2) - (3)].expr); } break; case 143: #line 702 "wmlscript/wsgram.y" { (yyval.list) = ws_list_new(pctx); } break; case 144: #line 704 "wmlscript/wsgram.y" { (yyval.list) = (yyvsp[(2) - (3)].list); } break; case 145: #line 709 "wmlscript/wsgram.y" { (yyval.list) = ws_list_new(pctx); ws_list_append(pctx, (yyval.list), (yyvsp[(1) - (1)].expr)); } break; case 146: #line 714 "wmlscript/wsgram.y" { ws_list_append(pctx, (yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].expr)); } break; /* Line 1267 of yacc.c. */ #line 2566 "y.tab.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; *++yylsp = yyloc; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else { YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) { YYSIZE_T yyalloc = 2 * yysize; if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) yyalloc = YYSTACK_ALLOC_MAXIMUM; if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yyalloc); if (yymsg) yymsg_alloc = yyalloc; else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; } } if (0 < yysize && yysize <= yymsg_alloc) { (void) yysyntax_error (yymsg, yystate, yychar); yyerror (yymsg); } else { yyerror (YY_("syntax error")); if (yysize != 0) goto yyexhaustedlab; } } #endif } yyerror_range[0] = yylloc; if (yyerrstatus == 3) { /* If just tried and failed to reuse look-ahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, &yylloc); yychar = YYEMPTY; } } /* Else will try to reuse look-ahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; yyerror_range[0] = yylsp[1-yylen]; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yyerror_range[0] = *yylsp; yydestruct ("Error: popping", yystos[yystate], yyvsp, yylsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } if (yyn == YYFINAL) YYACCEPT; *++yyvsp = yylval; yyerror_range[1] = yylloc; /* Using YYLLOC is tempting, but would change the location of the look-ahead. YYLOC is available though. */ YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); *++yylsp = yyloc; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #ifndef yyoverflow /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEOF && yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp, yylsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } #line 717 "wmlscript/wsgram.y" void yyerror(char *msg) { #if WS_DEBUG fprintf(stderr, "*** %s:%ld: wsc: %s - this msg will be removed ***\n", global_compiler->input_name, global_compiler->linenum, msg); #endif /* WS_DEBUG */ } gateway-1.4.5/wmlscript/wsstree.c0000644000175000017500000013364613227613126015570 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsstree.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Syntax tree creation, manipulation and byte-code assembler * generation. * */ #include "wsint.h" #include "wsgram.h" /* TODO: Constant folding. */ /********************* Misc syntax tree structures **********************/ WsVarDec *ws_variable_declaration(WsCompilerPtr compiler, char *name, WsExpression *expr) { WsVarDec *vardec = ws_f_malloc(compiler->pool_stree, sizeof(*vardec)); if (vardec == NULL) ws_error_memory(compiler); else { vardec->name = name; vardec->expr = expr; } return vardec; } WsFormalParm *ws_formal_parameter(WsCompilerPtr compiler, WsUInt32 line, char *name) { WsFormalParm *parm = ws_f_malloc(compiler->pool_stree, sizeof(*parm)); if (parm == NULL) ws_error_memory(compiler); else { parm->line = line; parm->name = name; } return parm; } /********************* Linked list **************************************/ WsList *ws_list_new(WsCompiler *compiler) { WsList *list = ws_f_calloc(compiler->pool_stree, 1, sizeof(*list)); if (list == NULL) ws_error_memory(compiler); return list; } void ws_list_append(WsCompiler *compiler, WsList *list, void *value) { WsListItem *item; if (list == NULL) /* A recovery code for previous memory allocation problems. */ return; item = ws_f_calloc(compiler->pool_stree, 1, sizeof(*item)); if (item == NULL) { ws_error_memory(compiler); return; } item->data = value; if (list->tail) { list->tail->next = item; list->tail = item; } else list->head = list->tail = item; list->num_items++; } /********************* Namespace for arguments and locals ***************/ static void variable_hash_destructor(void *item, void *context) { ws_free(item); } WsHashPtr ws_variable_hash_create(void) { return ws_hash_create(variable_hash_destructor, NULL); } WsNamespace *ws_variable_define(WsCompilerPtr compiler, WsUInt32 line, WsBool variablep, char *name) { WsNamespace *ns; /* Is the symbol already defined? */ ns = ws_hash_get(compiler->variables_hash, name); if (ns) { ws_src_error(compiler, line, "redeclaration of `%s'", name); ws_src_error(compiler, ns->line, "`%s' previously declared here", name); return NULL; } /* Can we still define more variables? */ if (compiler->next_vindex > 255) { /* No we can't. */ ws_src_error(compiler, line, "too many local variables"); return NULL; } ns = ws_calloc(1, sizeof(*ns)); if (ns == NULL) { ws_error_memory(compiler); return NULL; } ns->line = line; ns->vindex = compiler->next_vindex++; if (!ws_hash_put(compiler->variables_hash, name, ns)) { ws_free(ns); ws_error_memory(compiler); return NULL; } return ns; } WsNamespace *ws_variable_lookup(WsCompilerPtr compiler, char *name) { return ws_hash_get(compiler->variables_hash, name); } /********************* Top-level declarations ***************************/ /* External compilation units. */ static void pragma_use_hash_destructor(void *item, void *context) { ws_free(item); } WsHashPtr ws_pragma_use_hash_create(void) { return ws_hash_create(pragma_use_hash_destructor, NULL); } void ws_pragma_use(WsCompilerPtr compiler, WsUInt32 line, char *identifier, WsUtf8String *url) { WsPragmaUse *u = ws_calloc(1, sizeof(*u)); WsPragmaUse *uold; /* Do we already know this pragma? */ uold = ws_hash_get(compiler->pragma_use_hash, identifier); if (uold) { ws_src_error(compiler, line, "redefinition of pragma `%s'", identifier); ws_src_error(compiler, uold->line, "`%s' previously defined here", identifier); goto error_cleanup; } if (u == NULL) goto error; u->line = line; /* Insert the URL to the byte-code module. */ if (!ws_bc_add_const_utf8_string(compiler->bc, &u->urlindex, url->data, url->len)) goto error; /* Add it to the use pragma hash. */ if (!ws_hash_put(compiler->pragma_use_hash, identifier, u)) goto error; /* Cleanup. */ ws_lexer_free_block(compiler, identifier); ws_lexer_free_utf8(compiler, url); return; /* Error handling. */ error: ws_error_memory(compiler); error_cleanup: ws_free(u); ws_lexer_free_block(compiler, identifier); ws_lexer_free_utf8(compiler, url); } /* MetaBody of the `use meta' pragmas. */ WsPragmaMetaBody *ws_pragma_meta_body(WsCompilerPtr compiler, WsUtf8String *property_name, WsUtf8String *content, WsUtf8String *scheme) { WsPragmaMetaBody *mb = ws_calloc(1, sizeof(*mb)); if (mb == NULL) { ws_error_memory(compiler); return NULL; } mb->property_name = property_name; mb->content = content; mb->scheme = scheme; return mb; } void ws_pragma_meta_body_free(WsCompilerPtr compiler, WsPragmaMetaBody *mb) { if (mb == NULL) return; ws_lexer_free_utf8(compiler, mb->property_name); ws_lexer_free_utf8(compiler, mb->content); ws_lexer_free_utf8(compiler, mb->scheme); ws_free(mb); } /* Functions. */ static void function_hash_destructor(void *item, void *context) { ws_free(item); } WsHashPtr ws_function_hash_create(void) { return ws_hash_create(function_hash_destructor, NULL); } WsFunctionHash *ws_function_hash(WsCompilerPtr compiler, char *name) { WsFunctionHash *i = ws_hash_get(compiler->functions_hash, name); if (i) return i; /* Must create a new mapping. */ i = ws_calloc(1, sizeof(*i)); if (i == NULL) { ws_error_memory(compiler); return NULL; } if (!ws_hash_put(compiler->functions_hash, name, i)) { ws_free(i); ws_error_memory(compiler); return NULL; } return i; } void ws_function(WsCompiler *compiler, WsBool externp, char *name, WsUInt32 line, WsList *params, WsList *block) { WsFunctionHash *hash; WsFunction *f = ws_realloc(compiler->functions, ((compiler->num_functions + 1) * sizeof(WsFunction))); if (f == NULL) { ws_free(name); ws_error_memory(compiler); return; } if (externp) compiler->num_extern_functions++; else compiler->num_local_functions++; compiler->functions = f; f = &compiler->functions[compiler->num_functions]; f->findex = compiler->num_functions++; f->externp = externp; f->name = name; f->line = line; f->params = params; f->block = block; /* Update the function name hash. */ hash = ws_function_hash(compiler, name); if (hash == NULL) { ws_error_memory(compiler); return; } if (hash->defined) { ws_src_error(compiler, line, "redefinition of `%s'", name); ws_src_error(compiler, compiler->functions[hash->findex].line, "`%s' previously defined here", name); return; } hash->defined = WS_TRUE; hash->findex = f->findex; } /********************* Expressions **************************************/ void ws_expr_linearize(WsCompiler *compiler, WsExpression *expr) { WsListItem *li; WsAsmIns *ins; switch (expr->type) { case WS_EXPR_COMMA: /* Linearize left. */ ws_expr_linearize(compiler, expr->u.comma.left); /* Pop its result. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_POP)); /* Linearize right */ ws_expr_linearize(compiler, expr->u.comma.right); break; case WS_EXPR_ASSIGN: { WsNamespace *ns = ws_variable_lookup(compiler, expr->u.assign.identifier); if (ns == NULL) { /* Unknown identifier. */ ws_src_error(compiler, expr->line, "unknown variable `%s'", expr->u.symbol); return; } if (expr->u.assign.op == '=') { /* Evaluate the expression. */ ws_expr_linearize(compiler, expr->u.assign.expr); /* Store the value to the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_STORE_VAR, ns->vindex)); } else if (expr->u.assign.op == tADDA) { /* Linearize the expression. */ ws_expr_linearize(compiler, expr->u.assign.expr); /* Add it to the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_ADD_ASG, ns->vindex)); } else if (expr->u.assign.op == tSUBA) { /* Linearize the expression. */ ws_expr_linearize(compiler, expr->u.assign.expr); /* Substract it from the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_SUB_ASG, ns->vindex)); } else { /* Load the old value from the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); /* Evaluate the expression. */ ws_expr_linearize(compiler, expr->u.assign.expr); /* Perform the operand. */ ins = NULL; switch (expr->u.assign.op) { case tMULA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_MUL); break; case tDIVA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_DIV); break; case tREMA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_REM); break; case tADDA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_ADD); break; case tSUBA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_SUB); break; case tLSHIFTA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_LSHIFT); break; case tRSSHIFTA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSSHIFT); break; case tRSZSHIFTA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_RSZSHIFT); break; case tANDA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_AND); break; case tXORA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_XOR); break; case tORA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_B_OR); break; case tIDIVA: ins = ws_asm_ins(compiler, expr->line, WS_ASM_IDIV); break; default: ws_fatal("ws_expr_linearize(): unknown assignment operand %x", expr->u.assign.op); break; } ws_asm_link(compiler, ins); /* Store the value to the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_STORE_VAR, ns->vindex)); } /* The value of the assignment expression is the value assigned. So, we must load the value from the variable. This would also be a good place for the `dup' operand but we lose since we don't have it. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); } break; case WS_EXPR_CONDITIONAL: { WsAsmIns *l_else = ws_asm_label(compiler, expr->line); WsAsmIns *l_end = ws_asm_label(compiler, expr->line); /* Linearize condition. */ ws_expr_linearize(compiler, expr->u.conditional.e_cond); /* If the result if false, jump to the else-branch. */ ws_asm_link(compiler, ws_asm_branch(compiler, expr->line, WS_ASM_P_TJUMP, l_else)); /* Linearize the then-expression and jump out. */ ws_expr_linearize(compiler, expr->u.conditional.e_then); ws_asm_link(compiler, ws_asm_branch(compiler, expr->line, WS_ASM_P_JUMP, l_end)); /* The else-branch. */ ws_asm_link(compiler, l_else); ws_expr_linearize(compiler, expr->u.conditional.e_else); /* Insert the end label. */ ws_asm_link(compiler, l_end); } break; case WS_EXPR_LOGICAL: { WsAsmIns *l_out = ws_asm_label(compiler, expr->line); /* Linearize the left-hand size expression. */ ws_expr_linearize(compiler, expr->u.logical.left); /* Short-circuit check. The type of the logical expression is the short-circuit byte-code operand. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, expr->u.logical.type)); ws_asm_link(compiler, ws_asm_branch(compiler, expr->line, WS_ASM_P_TJUMP, l_out)); /* Linearize the right-hand size expression. */ ws_expr_linearize(compiler, expr->u.logical.right); /* The result of a logical expression should be boolean. * Control statements do automatic conversion, but typeof() * does not. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_TOBOOL)); /* Insert the end label. */ ws_asm_link(compiler, l_out); } break; case WS_EXPR_BINARY: /* Linearize left and right. */ ws_expr_linearize(compiler, expr->u.binary.left); ws_expr_linearize(compiler, expr->u.binary.right); /* The type of the binary expression is the byte-code opcode. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, expr->u.binary.type)); break; case WS_EXPR_UNARY: /* Linearize the expression. */ ws_expr_linearize(compiler, expr->u.unary.expr); /* The type of the unary expression is the byte-code opcode. */ ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, expr->u.unary.type)); break; case WS_EXPR_UNARY_VAR: { WsNamespace *ns = ws_variable_lookup(compiler, expr->u.unary_var.variable); if (ns == NULL) { /* An unknown identifier. */ ws_src_error(compiler, expr->line, "unknown variable `%s'", expr->u.unary_var.variable); return; } /* First, do the operation. */ if (expr->u.unary_var.addp) ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR, ns->vindex)); else ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR, ns->vindex)); /* Second, load the new value of the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); } break; case WS_EXPR_POSTFIX_VAR: { WsNamespace *ns = ws_variable_lookup(compiler, expr->u.postfix_var.variable); if (ns == NULL) { /* An unknown identifier. */ ws_src_error(compiler, expr->line, "unknown variable `%s'", expr->u.postfix_var.variable); return; } /* First, load the old value of the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); /* Second, do the operation. */ if (expr->u.unary_var.addp) ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_INCR_VAR, ns->vindex)); else ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_DECR_VAR, ns->vindex)); } break; case WS_EXPR_CALL: /* First, evaluate the arguments. */ for (li = expr->u.call.arguments->head; li; li = li->next) ws_expr_linearize(compiler, li->data); /* Second, emit the call instruction. */ switch (expr->u.call.type) { case ' ': /* LocalScriptFunctionCall */ { WsFunctionHash *f = ws_function_hash(compiler, expr->u.call.name); if (f == NULL || !f->defined) { ws_src_error(compiler, expr->line, "unknown local function `%s'", expr->u.call.name); return; } /* Check that the function is called with correct amount of arguments. */ if (expr->u.call.arguments->num_items != compiler->functions[f->findex].params->num_items) { ws_src_error(compiler, expr->line, "invalid amount of arguments for `%s': " "expected %u, got %u", expr->u.call.name, compiler->functions[f->findex].params->num_items, expr->u.call.arguments->num_items); return; } /* Emit assembler. */ ws_asm_link(compiler, ws_asm_call(compiler, expr->line, f->findex)); } break; case '#': /* ExternalScriptFunctionCall */ { WsPragmaUse *use = ws_hash_get(compiler->pragma_use_hash, expr->u.call.base); WsUInt16 findex; if (use == NULL) { ws_src_error(compiler, expr->line, "unknown external compilation unit `%s'", expr->u.call.base); return; } /* Insert the function name to the byte-code pool. */ if (!ws_bc_add_const_utf8_string( compiler->bc, &findex, (unsigned char *) expr->u.call.name, strlen(expr->u.call.name))) { ws_error_memory(compiler); return; } /* Emit assembler. */ ws_asm_link(compiler, ws_asm_call_url(compiler, expr->line, findex, use->urlindex, expr->u.call.arguments->num_items)); } break; case '.': /* LibraryFunctionCall */ { WsUInt16 lindex; WsUInt8 findex; WsUInt8 num_args; WsBool lindex_found; WsBool findex_found; if (!ws_stdlib_function(expr->u.call.base, expr->u.call.name, &lindex, &findex, &num_args, &lindex_found, &findex_found)) { if (!lindex_found) ws_src_error(compiler, expr->line, "unknown system library `%s'", expr->u.call.base); else ws_src_error(compiler, expr->line, "unknown library function `%s.%s'", expr->u.call.base, expr->u.call.name); return; } /* Check the argument count. */ if (expr->u.call.arguments->num_items != num_args) { ws_src_error(compiler, expr->line, "invalid amount of arguments for `%s.%s': " "expected %u, got %u", expr->u.call.base, expr->u.call.name, num_args, expr->u.call.arguments->num_items); return; } /* Emit assembler. */ ws_asm_link(compiler, ws_asm_call_lib(compiler, expr->line, findex, lindex)); } break; default: ws_fatal("ws_expr_linearize(): unknown call expression type %x", expr->u.call.type); break; } break; case WS_EXPR_SYMBOL: { WsNamespace *ns = ws_variable_lookup(compiler, expr->u.symbol); if (ns == NULL) { /* An unknown identifier. */ ws_src_error(compiler, expr->line, "unknown variable `%s'", expr->u.symbol); return; } /* Create a load instruction for the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, expr->line, WS_ASM_P_LOAD_VAR, ns->vindex)); } break; case WS_EXPR_CONST_INVALID: ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_CONST_INVALID)); break; case WS_EXPR_CONST_TRUE: ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_CONST_TRUE)); break; case WS_EXPR_CONST_FALSE: ws_asm_link(compiler, ws_asm_ins(compiler, expr->line, WS_ASM_CONST_FALSE)); break; case WS_EXPR_CONST_INTEGER: if (expr->u.integer.ival == 0) ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_0); else if (expr->u.integer.ival == 1 && expr->u.integer.sign == 1) ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_1); else { WsUInt16 cindex; WsInt32 ival; if (expr->u.integer.sign >= 0) { if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX) ws_src_error(compiler, expr->line, "integer literal too large"); ival = expr->u.integer.ival; } else { if (expr->u.integer.ival > (WsUInt32) WS_INT32_MAX + 1) ws_src_error(compiler, expr->line, "integer too small"); ival = - (WsInt32) expr->u.integer.ival; } if (!ws_bc_add_const_int(compiler->bc, &cindex, ival)) { ws_error_memory(compiler); return; } ins = ws_asm_load_const(compiler, expr->line, cindex); } ws_asm_link(compiler, ins); break; case WS_EXPR_CONST_FLOAT: { WsUInt16 cindex; if (!ws_bc_add_const_float(compiler->bc, &cindex, expr->u.fval)) { ws_error_memory(compiler); return; } ws_asm_link(compiler, ws_asm_load_const(compiler, expr->line, cindex)); } break; case WS_EXPR_CONST_STRING: if (expr->u.string.len == 0) ins = ws_asm_ins(compiler, expr->line, WS_ASM_CONST_ES); else { WsUInt16 cindex; if (!ws_bc_add_const_utf8_string(compiler->bc, &cindex, expr->u.string.data, expr->u.string.len)) { ws_error_memory(compiler); return; } ins = ws_asm_load_const(compiler, expr->line, cindex); } ws_asm_link(compiler, ins); break; } } /* Constructors. */ static WsExpression *expr_alloc(WsCompiler *compiler, WsExpressionType type, WsUInt32 line) { WsExpression *expr = ws_f_calloc(compiler->pool_stree, 1, sizeof(*expr)); if (expr == NULL) ws_error_memory(compiler); else { expr->type = type; expr->line = line; } return expr; } WsExpression *ws_expr_comma(WsCompilerPtr compiler, WsUInt32 line, WsExpression *left, WsExpression *right) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_COMMA, line); if (expr) { expr->u.comma.left = left; expr->u.comma.right = right; } return expr; } WsExpression *ws_expr_assign(WsCompilerPtr compiler, WsUInt32 line, char *identifier, int op, WsExpression *expr) { WsExpression *e = expr_alloc(compiler, WS_EXPR_ASSIGN, line); if (e) { e->u.assign.identifier = ws_f_strdup(compiler->pool_stree, identifier); if (e->u.assign.identifier == NULL) ws_error_memory(compiler); e->u.assign.op = op; e->u.assign.expr = expr; } /* Free the identifier symbol since it allocated from the system heap. */ ws_lexer_free_block(compiler, identifier); return e; } WsExpression *ws_expr_conditional(WsCompilerPtr compiler, WsUInt32 line, WsExpression *e_cond, WsExpression *e_then, WsExpression *e_else) { WsExpression *e = expr_alloc(compiler, WS_EXPR_CONDITIONAL, line); if (e) { e->u.conditional.e_cond = e_cond; e->u.conditional.e_then = e_then; e->u.conditional.e_else = e_else; } return e; } WsExpression *ws_expr_logical(WsCompilerPtr compiler, WsUInt32 line, int type, WsExpression *left, WsExpression *right) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_LOGICAL, line); if (expr) { expr->u.logical.type = type; expr->u.logical.left = left; expr->u.logical.right = right; } return expr; } WsExpression *ws_expr_binary(WsCompilerPtr compiler, WsUInt32 line, int type, WsExpression *left, WsExpression *right) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_BINARY, line); if (expr) { expr->u.binary.type = type; expr->u.binary.left = left; expr->u.binary.right = right; } return expr; } WsExpression *ws_expr_unary(WsCompilerPtr compiler, WsUInt32 line, int type, WsExpression *expression) { WsExpression *expr; /* Handle negative integers here as a special case of constant folding, * in order to get -2147483648 right. */ if (type == WS_ASM_UMINUS && expression->type == WS_EXPR_CONST_INTEGER) { expression->u.integer.sign = - expression->u.integer.sign; return expression; } expr = expr_alloc(compiler, WS_EXPR_UNARY, line); if (expr) { expr->u.unary.type = type; expr->u.unary.expr = expression; } return expr; } WsExpression *ws_expr_unary_var(WsCompilerPtr compiler, WsUInt32 line, WsBool addp, char *variable) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_UNARY_VAR, line); if (expr) { expr->u.unary_var.addp = addp; expr->u.unary_var.variable = ws_f_strdup(compiler->pool_stree, variable); if (expr->u.unary_var.variable == NULL) ws_error_memory(compiler); } ws_lexer_free_block(compiler, variable); return expr; } WsExpression *ws_expr_postfix_var(WsCompilerPtr compiler, WsUInt32 line, WsBool addp, char *variable) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_POSTFIX_VAR, line); if (expr) { expr->u.postfix_var.addp = addp; expr->u.postfix_var.variable = ws_f_strdup(compiler->pool_stree, variable); if (expr->u.postfix_var.variable == NULL) ws_error_memory(compiler); } ws_lexer_free_block(compiler, variable); return expr; } WsExpression *ws_expr_call(WsCompiler *compiler, WsUInt32 line, int type, char *base, char *name, WsList *arguments) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_CALL, line); if (expr) { expr->u.call.type = type; expr->u.call.base = ws_f_strdup(compiler->pool_stree, base); expr->u.call.name = ws_f_strdup(compiler->pool_stree, name); expr->u.call.arguments = arguments; if ((base && expr->u.call.base == NULL) || (name && expr->u.call.name == NULL)) ws_error_memory(compiler); } ws_lexer_free_block(compiler, base); ws_lexer_free_block(compiler, name); return expr; } WsExpression *ws_expr_symbol(WsCompiler *compiler, WsUInt32 line, char *identifier) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_SYMBOL, line); if (expr) { expr->u.symbol = ws_f_strdup(compiler->pool_stree, identifier); if (expr->u.symbol == NULL) ws_error_memory(compiler); } ws_lexer_free_block(compiler, identifier); return expr; } WsExpression *ws_expr_const_invalid(WsCompiler *compiler, WsUInt32 line) { return expr_alloc(compiler, WS_EXPR_CONST_INVALID, line); } WsExpression *ws_expr_const_true(WsCompiler *compiler, WsUInt32 line) { return expr_alloc(compiler, WS_EXPR_CONST_TRUE, line); } WsExpression *ws_expr_const_false(WsCompiler *compiler, WsUInt32 line) { return expr_alloc(compiler, WS_EXPR_CONST_FALSE, line); } WsExpression *ws_expr_const_integer(WsCompiler *compiler, WsUInt32 line, WsUInt32 ival) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_INTEGER, line); if (expr) { expr->u.integer.sign = 1; expr->u.integer.ival = ival; } return expr; } WsExpression *ws_expr_const_float(WsCompiler *compiler, WsUInt32 line, WsFloat fval) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_FLOAT, line); if (expr) expr->u.fval = fval; return expr; } WsExpression *ws_expr_const_string(WsCompiler *compiler, WsUInt32 line, WsUtf8String *string) { WsExpression *expr = expr_alloc(compiler, WS_EXPR_CONST_STRING, line); if (expr) { expr->u.string.len = string->len; expr->u.string.data = ws_f_memdup(compiler->pool_stree, string->data, string->len); if (expr->u.string.data == NULL) ws_error_memory(compiler); } ws_lexer_free_utf8(compiler, string); return expr; } /********************* Statements ***************************************/ /* Linearize the variable declaration list `list'. */ static void linearize_variable_init(WsCompiler *compiler, WsList *list, WsUInt32 line) { WsNamespace *ns; WsListItem *li; /* For each variable, declared with this list. */ for (li = list->head; li; li = li->next) { WsVarDec *vardec = li->data; ns = ws_variable_define(compiler, line, WS_TRUE, vardec->name); if (ns && vardec->expr) { ws_expr_linearize(compiler, vardec->expr); /* Emit an instruction to store the initialization value to the variable. */ ws_asm_link(compiler, ws_asm_variable(compiler, line, WS_ASM_P_STORE_VAR, ns->vindex)); } } } void ws_stmt_linearize(WsCompiler *compiler, WsStatement *stmt) { WsListItem *li; WsAsmIns *ins; switch (stmt->type) { case WS_STMT_BLOCK: for (li = stmt->u.block->head; li; li = li->next) ws_stmt_linearize(compiler, li->data); break; case WS_STMT_VARIABLE: linearize_variable_init(compiler, stmt->u.var, stmt->first_line); break; case WS_STMT_EMPTY: /* Nothing here. */ break; case WS_STMT_EXPR: ws_expr_linearize(compiler, stmt->u.expr); /* Pop the expressions result from the stack. Otherwise loops could eventually cause stack overflows. */ ws_asm_link(compiler, ws_asm_ins(compiler, stmt->last_line, WS_ASM_POP)); break; case WS_STMT_IF: { WsAsmIns *l_else = ws_asm_label(compiler, (stmt->u.s_if.s_else ? stmt->u.s_if.s_else->first_line : stmt->last_line)); WsAsmIns *l_end = ws_asm_label(compiler, stmt->last_line); /* Linearize the expression. */ ws_expr_linearize(compiler, stmt->u.s_if.expr); /* If the result is false, jump to the else-branch. */ ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line, WS_ASM_P_TJUMP, l_else)); /* Else, execute the then-branch and jump to the end. */ ws_stmt_linearize(compiler, stmt->u.s_if.s_then); ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line, WS_ASM_P_JUMP, l_end)); /* Then else-branch. */ ws_asm_link(compiler, l_else); /* Linearize the else-branch if it is present. */ if (stmt->u.s_if.s_else) ws_stmt_linearize(compiler, stmt->u.s_if.s_else); /* Insert the end label. */ ws_asm_link(compiler, l_end); } break; case WS_STMT_FOR: { WsAsmIns *l_loop = ws_asm_label(compiler, stmt->first_line); WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line); WsAsmIns *l_break = ws_asm_label(compiler, stmt->first_line); WsContBreak *cb; /* Store the labels to the compiler. */ cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb)); if (cb == NULL) { ws_error_memory(compiler); return; } cb->next = compiler->cont_break; compiler->cont_break = cb; cb->l_cont = l_cont; cb->l_break = l_break; /* Linearize the possible init code. */ if (stmt->u.s_for.init) linearize_variable_init(compiler, stmt->u.s_for.init, stmt->first_line); else if (stmt->u.s_for.e1) { /* Linearize the init. */ ws_expr_linearize(compiler, stmt->u.s_for.e1); /* Pop the result. */ ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line, WS_ASM_POP)); } /* Insert the loop label. */ ws_asm_link(compiler, l_loop); /* Linearize the condition. */ if (stmt->u.s_for.e2) { ws_expr_linearize(compiler, stmt->u.s_for.e2); /* If false, jump out. */ ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line, WS_ASM_P_TJUMP, l_break)); } /* Linearize the body statement. */ ws_stmt_linearize(compiler, stmt->u.s_for.stmt); /* Link the continue label. */ ws_asm_link(compiler, l_cont); /* Linearize the update expression. */ if (stmt->u.s_for.e3) { ws_expr_linearize(compiler, stmt->u.s_for.e3); /* Pop the result. */ ws_asm_link(compiler, ws_asm_ins(compiler, stmt->first_line, WS_ASM_POP)); } /* Jump to the loop label to check the condition. */ ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line, WS_ASM_P_JUMP, l_loop)); /* Insert the break label. */ ws_asm_link(compiler, l_break); /* Pop the cont-break block. */ compiler->cont_break = compiler->cont_break->next; } break; case WS_STMT_WHILE: { WsAsmIns *l_cont = ws_asm_label(compiler, stmt->first_line); WsAsmIns *l_break = ws_asm_label(compiler, stmt->u.s_while.stmt->last_line); WsContBreak *cb; /* Store the labels to the compiler. */ cb = ws_f_calloc(compiler->pool_stree, 1, sizeof(*cb)); if (cb == NULL) { ws_error_memory(compiler); return; } cb->next = compiler->cont_break; compiler->cont_break = cb; cb->l_cont = l_cont; cb->l_break = l_break; /* Insert the continue label. */ ws_asm_link(compiler, l_cont); /* Linearize the expression. */ ws_expr_linearize(compiler, stmt->u.s_while.expr); /* If false, jump out. */ ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line, WS_ASM_P_TJUMP, l_break)); /* Linearize the body statement. */ ws_stmt_linearize(compiler, stmt->u.s_while.stmt); /* And jump to the continue label to check the expression. */ ws_asm_link(compiler, ws_asm_branch(compiler, stmt->last_line, WS_ASM_P_JUMP, l_cont)); /* Insert the break label. */ ws_asm_link(compiler, l_break); /* Pop the cont-break block. */ compiler->cont_break = compiler->cont_break->next; } break; case WS_STMT_CONTINUE: if (compiler->cont_break == NULL) ws_src_error(compiler, stmt->first_line, "continue statement not within a loop"); ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line, WS_ASM_P_JUMP, compiler->cont_break->l_cont)); break; case WS_STMT_BREAK: if (compiler->cont_break == NULL) ws_src_error(compiler, stmt->first_line, "break statement not within a loop"); ws_asm_link(compiler, ws_asm_branch(compiler, stmt->first_line, WS_ASM_P_JUMP, compiler->cont_break->l_break)); break; case WS_STMT_RETURN: if (stmt->u.expr) { /* Linearize the return value and return it. */ ws_expr_linearize(compiler, stmt->u.expr); ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN); } else /* Return an empty string. */ ins = ws_asm_ins(compiler, stmt->first_line, WS_ASM_RETURN_ES); ws_asm_link(compiler, ins); break; } } /* Constructors. */ static WsStatement *stmt_alloc(WsCompiler *compiler, WsStatementType type, WsUInt32 first_line, WsUInt32 last_line) { WsStatement *stmt = ws_f_calloc(compiler->pool_stree, 1, sizeof(*stmt)); if (stmt == NULL) ws_error_memory(compiler); else { stmt->type = type; stmt->first_line = first_line; stmt->last_line = last_line; } return stmt; } WsStatement *ws_stmt_block(WsCompiler *compiler, WsUInt32 fline, WsUInt32 lline, WsList *block) { WsStatement *stmt = stmt_alloc(compiler, WS_STMT_BLOCK, fline, lline); if (stmt) stmt->u.block = block; return stmt; } WsStatement *ws_stmt_variable(WsCompilerPtr compiler, WsUInt32 line, WsList *variables) { WsStatement *stmt = stmt_alloc(compiler, WS_STMT_VARIABLE, line, line); if (stmt) stmt->u.var = variables; return stmt; } WsStatement *ws_stmt_empty(WsCompiler *compiler, WsUInt32 line) { return stmt_alloc(compiler, WS_STMT_EMPTY, line, line); } WsStatement *ws_stmt_expr(WsCompiler *compiler, WsUInt32 line, WsExpression *expr) { WsStatement *stmt = stmt_alloc(compiler, WS_STMT_EXPR, line, line); if (stmt) stmt->u.expr = expr; return stmt; } WsStatement *ws_stmt_if(WsCompiler *compiler, WsUInt32 line, WsExpression *expr, WsStatement *s_then, WsStatement *s_else) { WsStatement *stmt = stmt_alloc(compiler, WS_STMT_IF, line, line); if (stmt) { stmt->u.s_if.expr = expr; stmt->u.s_if.s_then = s_then; stmt->u.s_if.s_else = s_else; } return stmt; } WsStatement *ws_stmt_for(WsCompilerPtr compiler, WsUInt32 line, WsList *init, WsExpression *e1, WsExpression *e2, WsExpression *e3, WsStatement *stmt_body) { WsStatement *stmt = stmt_alloc(compiler, WS_STMT_FOR, line, line); if (stmt) { stmt->u.s_for.init = init; stmt->u.s_for.e1 = e1; stmt->u.s_for.e2 = e2; stmt->u.s_for.e3 = e3; stmt->u.s_for.stmt = stmt_body; } return stmt; } WsStatement *ws_stmt_while(WsCompiler *compiler, WsUInt32 line, WsExpression *expr, WsStatement *stmt_arg) { WsStatement *stmt = stmt_alloc(compiler, WS_STMT_WHILE, line, line); if (stmt) { stmt->u.s_while.expr = expr; stmt->u.s_while.stmt = stmt_arg; } return stmt; } WsStatement *ws_stmt_continue(WsCompiler *compiler, WsUInt32 line) { return stmt_alloc(compiler, WS_STMT_CONTINUE, line, line); } WsStatement *ws_stmt_break(WsCompiler *compiler, WsUInt32 line) { return stmt_alloc(compiler, WS_STMT_BREAK, line, line); } WsStatement *ws_stmt_return(WsCompilerPtr compiler, WsUInt32 line, WsExpression *expr) { WsStatement *stmt = stmt_alloc(compiler, WS_STMT_RETURN, line, line); if (stmt) stmt->u.expr = expr; return stmt; } gateway-1.4.5/wmlscript/wsstream.c0000644000175000017500000001072013227613126015724 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsstream.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Generic input / output stream. * */ #include "wsint.h" /********************* Global functions *********************************/ WsBool ws_stream_getc(WsStream *stream, WsUInt32 *ch_return) { if (stream->ungetch_valid) { *ch_return = stream->ungetch; stream->ungetch_valid = WS_FALSE; return WS_TRUE; } if (stream->buffer_pos >= stream->data_in_buffer) { /* Read more data to the buffer. */ stream->buffer_pos = 0; stream->data_in_buffer = (*stream->io)(stream->context, stream->buffer, WS_STREAM_BUFFER_SIZE); if (stream->data_in_buffer == 0) /* EOF reached. */ return WS_FALSE; } /* Return the next character. */ *ch_return = stream->buffer[stream->buffer_pos++]; return WS_TRUE; } void ws_stream_ungetc(WsStream *stream, WsUInt32 ch) { stream->ungetch = ch; stream->ungetch_valid = WS_TRUE; } WsBool ws_stream_flush(WsStream *stream) { if (stream->flush) return (*stream->flush)(stream->context); return WS_TRUE; } void ws_stream_close(WsStream *stream) { if (stream->close) (*stream->close)(stream->context); ws_free(stream); } WsStream *ws_stream_new(void *context, WsStreamIOProc io, WsStreamFlushProc flush, WsStreamCloseProc close) { WsStream *stream = ws_calloc(1, sizeof(*stream)); if (stream == NULL) return NULL; stream->io = io; stream->flush = flush; stream->close = close; stream->context = context; return stream; } gateway-1.4.5/wmlscript/ws.c0000644000175000017500000004117013227613126014513 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * ws.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Public entry points to the WMLScript compiler and the main compile * function. * */ #include "wsint.h" #include "ws.h" #include "wsstree.h" #include "wsasm.h" /********************* Types and definitions ****************************/ #define WS_CHECK_COMPILE_ERROR() \ do { \ if (compiler->errors != 0) { \ if (compiler->errors & WS_ERROR_B_MEMORY) \ result = WS_ERROR_OUT_OF_MEMORY; \ else if (compiler->errors & WS_ERROR_B_SYNTAX) \ result = WS_ERROR_SYNTAX; \ else if (compiler->errors & WS_ERROR_B_SEMANTIC) \ result = WS_ERROR_SEMANTIC; \ else \ /* This shouldn't happen. */ \ result = WS_ERROR; \ goto out; \ } \ } while (0); /********************* Static variables *********************************/ /* Human readable names for the result codes. */ static struct { WsResult code; char *description; } result_codes[] = { { WS_OK, "success" }, { WS_ERROR_OUT_OF_MEMORY, "out of memory" }, { WS_ERROR_SYNTAX, "syntax error" }, { WS_ERROR_SEMANTIC, "compile error" }, { WS_ERROR_IO, "IO error" }, { WS_ERROR, "error" }, { 0, NULL }, }; /********************* Prototypes for static functions ******************/ /* Compile the input stream `input' with the compiler `compiler' and return the byte-code in `output_return' and its length in `output_len_return'. The function returns a WsResult error code describing the success of the compilation. */ static WsResult compile_stream(WsCompilerPtr compiler, const char *input_name, WsStream *input, unsigned char **output_return, size_t *output_len_return); /* The default I/O function to send the output to stdout and stderr. The argument `context' must be a `FILE *' file to which the output is written. */ static void std_io(const char *data, size_t len, void *context); /* A comparison function for functions entries when sorting them by their usage counts. The function is stable maintaining their original order if their usage counts are equal. */ static int sort_functions_cmp(const void *a, const void *b); /********************* Global functions *********************************/ WsCompilerPtr ws_create(WsCompilerParams *params) { WsCompilerPtr compiler = ws_calloc(1, sizeof(*compiler)); if (compiler == NULL) return NULL; /* Store user params if specified. */ if (params) compiler->params = *params; /* Basic initialization. */ compiler->magic = COMPILER_MAGIC; if (compiler->params.stdout_cb == NULL) { compiler->params.stdout_cb = std_io; compiler->params.stdout_cb_context = stdout; } if (compiler->params.stderr_cb == NULL) { compiler->params.stderr_cb = std_io; compiler->params.stderr_cb_context = stderr; } return compiler; } void ws_destroy(WsCompilerPtr compiler) { if (compiler == NULL) return; ws_free(compiler); #if WS_MEM_DEBUG if (ws_has_leaks()) ws_dump_blocks(); #endif /* WS_MEM_DEBUG */ } WsResult ws_compile_file(WsCompilerPtr compiler, const char *input_name, FILE *input, FILE *output) { WsResult result; WsStream *stream; unsigned char *bc; size_t bc_len; /* Initialize the input stream. */ stream = ws_stream_new_file(input, WS_FALSE, WS_FALSE); if (stream == NULL) return WS_ERROR_OUT_OF_MEMORY; result = compile_stream(compiler, input_name, stream, &bc, &bc_len); ws_stream_close(stream); if (result == WS_OK) { /* Store the result to the file. */ if (fwrite(bc, 1, bc_len, output) != bc_len) result = WS_ERROR_IO; ws_bc_data_free(bc); } return result; } WsResult ws_compile_data(WsCompilerPtr compiler, const char *input_name, const unsigned char *input, size_t input_len, unsigned char **output_return, size_t *output_len_return) { WsResult result; WsStream *stream; /* Initialize the input stream. */ stream = ws_stream_new_data_input(input, input_len); if (stream == NULL) return WS_ERROR_OUT_OF_MEMORY; result = compile_stream(compiler, input_name, stream, output_return, output_len_return); ws_stream_close(stream); return result; } void ws_free_byte_code(unsigned char *byte_code) { ws_bc_data_free(byte_code); } const char *ws_result_to_string(WsResult result) { int i; for (i = 0; result_codes[i].description; i++) { if (result_codes[i].code == result) return result_codes[i].description; } return "unknown result code"; } /********************* Lexer's memory handling helpers ******************/ WsBool ws_lexer_register_block(WsCompiler *compiler, void *ptr) { void **n; if (ptr == NULL) return WS_TRUE; n = ws_realloc(compiler->lexer_active_list, ((compiler->lexer_active_list_size + 1) * sizeof(void *))); if (n == NULL) return WS_FALSE; compiler->lexer_active_list = n; compiler->lexer_active_list[compiler->lexer_active_list_size++] = ptr; return WS_TRUE; } WsBool ws_lexer_register_utf8(WsCompiler *compiler, WsUtf8String *string) { if (!ws_lexer_register_block(compiler, string)) return WS_FALSE; if (!ws_lexer_register_block(compiler, string->data)) { compiler->lexer_active_list_size--; return WS_FALSE; } return WS_TRUE; } void ws_lexer_free_block(WsCompiler *compiler, void *ptr) { int i; if (ptr == NULL) return; for (i = compiler->lexer_active_list_size - 1; i >= 0; i--) { if (compiler->lexer_active_list[i] == ptr) { memmove(&compiler->lexer_active_list[i], &compiler->lexer_active_list[i + 1], (compiler->lexer_active_list_size - i - 1) * sizeof(void *)); compiler->lexer_active_list_size--; ws_free(ptr); return; } } ws_fatal("ws_lexer_free_block(): unknown block 0x%lx", (unsigned long) ptr); } void ws_lexer_free_utf8(WsCompiler *compiler, WsUtf8String *string) { if (string == NULL) return; ws_lexer_free_block(compiler, string->data); ws_lexer_free_block(compiler, string); } /********************* Static functions *********************************/ static WsResult compile_stream(WsCompilerPtr compiler, const char *input_name, WsStream *input, unsigned char **output_return, size_t *output_len_return) { WsResult result = WS_OK; WsUInt32 i; WsListItem *li; WsUInt8 findex; WsUInt8 num_locals; WsBcStringEncoding string_encoding = WS_BC_STRING_ENC_UTF8; /* Initialize the compiler context. */ compiler->linenum = 1; compiler->input_name = input_name; compiler->num_errors = 0; compiler->num_warnings = 0; compiler->num_extern_functions = 0; compiler->num_local_functions = 0; compiler->errors = 0; compiler->last_syntax_error_line = 0; /* Allocate fast-malloc pool for the syntax tree. */ compiler->pool_stree = ws_f_create(1024 * 1024); if (compiler->pool_stree == NULL) { result = WS_ERROR_OUT_OF_MEMORY; goto out; } /* Allocate hash tables. */ compiler->pragma_use_hash = ws_pragma_use_hash_create(); if (compiler->pragma_use_hash == NULL) { result = WS_ERROR_OUT_OF_MEMORY; goto out; } compiler->functions_hash = ws_function_hash_create(); if (compiler->functions_hash == NULL) { result = WS_ERROR_OUT_OF_MEMORY; goto out; } /* Allocate a byte-code module. */ if (compiler->params.use_latin1_strings) string_encoding = WS_BC_STRING_ENC_ISO_8859_1; compiler->bc = ws_bc_alloc(string_encoding); if (compiler->bc == NULL) { result = WS_ERROR_OUT_OF_MEMORY; goto out; } /* Save the input stream. */ compiler->input = input; /* Parse the input. */ #if WS_DEBUG global_compiler = compiler; #endif /* WS_DEBUG */ ws_yy_parse(compiler); /* Free all lexer's active not freed blocks. If we have any blocks on the used list, our compilation was not successful. */ { size_t j; for (j = 0; j < compiler->lexer_active_list_size; j++) ws_free(compiler->lexer_active_list[j]); ws_free(compiler->lexer_active_list); compiler->lexer_active_list = NULL; } WS_CHECK_COMPILE_ERROR(); /* Sort functions if allowed and it helps. */ if (!compiler->params.no_opt_sort_bc_functions && compiler->num_functions > 7) { WsUInt32 i; ws_info(compiler, "optimize: sorting functions"); /* Fetch the usage counts from the functions hash. */ for (i = 0; i < compiler->num_functions; i++) { WsFunctionHash *fh = ws_function_hash(compiler, compiler->functions[i].name); compiler->functions[i].usage_count = fh->usage_count; } /* Sort functions. */ qsort(compiler->functions, compiler->num_functions, sizeof(compiler->functions[0]), sort_functions_cmp); /* Patch the function indexes. */ for (i = 0; i < compiler->num_functions; i++) { WsFunctionHash *fh = ws_function_hash(compiler, compiler->functions[i].name); compiler->functions[i].findex = i; fh->findex = i; } } /* Linearize functions */ for (i = 0; i < compiler->num_functions; i++) { WsFunction *func = &compiler->functions[i]; ws_info(compiler, "linearizing function `%s'...", func->name); compiler->pool_asm = ws_f_create(100 * 1024); if (compiler->pool_asm == NULL) { result = WS_ERROR_OUT_OF_MEMORY; goto out; } compiler->next_label = 0; compiler->asm_head = compiler->asm_tail = NULL; /* Create variables namespace. */ compiler->next_vindex = 0; compiler->variables_hash = ws_variable_hash_create(); if (compiler->variables_hash == NULL) { result = WS_ERROR_OUT_OF_MEMORY; goto out; } /* Define the formal arguments to the namespace. */ for (li = func->params->head; li; li = li->next) { WsFormalParm *parm = li->data; ws_variable_define(compiler, parm->line, WS_FALSE, parm->name); } WS_CHECK_COMPILE_ERROR(); /* Linearize it. */ for (li = func->block->head; li; li = li->next) ws_stmt_linearize(compiler, li->data); WS_CHECK_COMPILE_ERROR(); /* Optimize symbolic assembler. This function does nothing if no optimizations were requested. */ ws_asm_optimize(compiler); /* Print the resulting symbolic assembler if requested. */ if (compiler->params.print_symbolic_assembler) ws_asm_print(compiler); WS_CHECK_COMPILE_ERROR(); /* Generate byte-code */ ws_buffer_init(&compiler->byte_code); ws_asm_linearize(compiler); WS_CHECK_COMPILE_ERROR(); /* Disassemble the output if requested. */ if (compiler->params.print_assembler) ws_asm_dasm(compiler, ws_buffer_ptr(&compiler->byte_code), ws_buffer_len(&compiler->byte_code)); /* Calculate the number of local variables */ num_locals = compiler->next_vindex - func->params->num_items; /* Add the function to the byte-code module. */ if (!ws_bc_add_function(compiler->bc, &findex, func->externp ? func->name : NULL, func->params->num_items, num_locals, ws_buffer_len(&compiler->byte_code), ws_buffer_ptr(&compiler->byte_code))) { result = WS_ERROR_OUT_OF_MEMORY; goto out; } /* Cleanup and prepare for the next function. */ ws_buffer_uninit(&compiler->byte_code); ws_hash_destroy(compiler->variables_hash); compiler->variables_hash = NULL; ws_f_destroy(compiler->pool_asm); compiler->pool_asm = NULL; } /* Linearize the byte-code structure. */ if (!ws_bc_encode(compiler->bc, output_return, output_len_return)) result = WS_ERROR_OUT_OF_MEMORY; out: /* Cleanup. */ ws_f_destroy(compiler->pool_stree); compiler->pool_stree = NULL; ws_hash_destroy(compiler->pragma_use_hash); compiler->pragma_use_hash = NULL; /* Free functions. */ for (i = 0; i < compiler->num_functions; i++) ws_free(compiler->functions[i].name); ws_free(compiler->functions); ws_hash_destroy(compiler->functions_hash); compiler->functions_hash = NULL; ws_bc_free(compiler->bc); compiler->bc = NULL; compiler->input = NULL; ws_f_destroy(compiler->pool_asm); compiler->pool_asm = NULL; ws_hash_destroy(compiler->variables_hash); compiler->variables_hash = NULL; ws_buffer_uninit(&compiler->byte_code); /* All done. */ return result; } static void std_io(const char *data, size_t len, void *context) { fwrite(data, 1, len, (FILE *) context); } static int sort_functions_cmp(const void *a, const void *b) { WsFunction *fa = (WsFunction *) a; WsFunction *fb = (WsFunction *) b; if (fa->usage_count > fb->usage_count) return -1; if (fa->usage_count < fb->usage_count) return 1; if (fa->findex < fb->findex) return -1; return 1; } gateway-1.4.5/wmlscript/wshash.c0000644000175000017500000001344013227613126015356 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wshash.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * A mapping from null-terminated strings to `void *' pointers. * */ #include "wsint.h" #include "wshash.h" /********************* Types and definitions ****************************/ /* The size of the hash table. */ #define WS_HASH_TABLE_SIZE 256 /* A hash item. */ struct WsHashItemRec { struct WsHashItemRec *next; char *name; void *data; }; typedef struct WsHashItemRec WsHashItem; /* The hash object. */ struct WsHashRec { WsHashItem *items[WS_HASH_TABLE_SIZE]; WsHashItemDestructor destructor; void *destructor_context; }; /********************* Prototypes for static functions ******************/ /* Hash function to count the hash value of string `string'. */ static size_t count_hash(const char *string); /********************* Global functions *********************************/ WsHashPtr ws_hash_create(WsHashItemDestructor destructor, void *context) { WsHashPtr hash = ws_calloc(1, sizeof(*hash)); if (hash) { hash->destructor = destructor; hash->destructor_context = context; } return hash; } void ws_hash_destroy(WsHashPtr hash) { if (hash == NULL) return; ws_hash_clear(hash); ws_free(hash); } WsBool ws_hash_put(WsHashPtr hash, const char *name, void *data) { WsHashItem *i; size_t h = count_hash(name); for (i = hash->items[h]; i; i = i->next) { if (strcmp(i->name, name) == 0) { /* Found it. */ /* Destroy the old item */ if (hash->destructor) (*hash->destructor)(i->data, hash->destructor_context); i->data = data; return WS_FALSE; } } /* Must create a new mapping. */ i = ws_calloc(1, sizeof(*i)); if (i == NULL) return WS_FALSE; i->name = ws_strdup(name); if (i->name == NULL) { ws_free(i); return WS_FALSE; } i->data = data; /* Link it to our hash. */ i->next = hash->items[h]; hash->items[h] = i; return WS_TRUE; } void *ws_hash_get(WsHashPtr hash, const char *name) { WsHashItem *i; size_t h = count_hash(name); for (i = hash->items[h]; i; i = i->next) if (strcmp(i->name, name) == 0) return i->data; return NULL; } void ws_hash_clear(WsHashPtr hash) { WsHashItem *i, *n; size_t j; for (j = 0; j < WS_HASH_TABLE_SIZE; j++) { for (i = hash->items[j]; i; i = n) { n = i->next; if (hash->destructor) (*hash->destructor)(i->data, hash->destructor_context); ws_free(i->name); ws_free(i); } hash->items[j] = NULL; } } /********************* Static functions *********************************/ static size_t count_hash(const char *string) { size_t val = 0; int i; for (i = 0; string[i]; i++) { val <<= 3; val ^= string[i]; val ^= (val & 0xff00) >> 5; val ^= (val & 0xff0000) >> 16; } return val % WS_HASH_TABLE_SIZE; } gateway-1.4.5/wmlscript/wsieee754.h0000644000175000017500000001237113227613126015611 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsieee754.h * * Author: Markku Rossi * * Copyright (c) 2000 WAPIT OY LTD. * All rights reserved. * * Functions to manipulate ANSI/IEEE Std 754-1985 binary floating-point * numbers. * */ #ifndef WSIEEE754_H #define WSIEEE754_H /********************* Types and definitions ****************************/ /* Return codes for encoding and decoding functions. */ typedef enum { /* The operation was successful. */ WS_IEEE754_OK, /* The value is `Not a Number' NaN. */ WS_IEEE754_NAN, /* The valueis positive infinity. */ WS_IEEE754_POSITIVE_INF, /* The value is negative infinity. */ WS_IEEE754_NEGATIVE_INF } WsIeee754Result; /********************* Special values ***********************************/ /* `Not a Number' NaN */ extern unsigned char ws_ieee754_nan[4]; /* Positive infinity. */ extern unsigned char ws_ieee754_positive_inf[4]; /* Positive infinity. */ extern unsigned char ws_ieee754_negative_inf[4]; /********************* Global functions *********************************/ /* Encode the floating point number `value' to the IEEE-754 single precision format. The function stores the encoded value to the buffer `buf'. The buffer `buf' must have 32 bits (4 bytes) of space. The function returns WsIeee754Result return value. It describes the format of the encoded value in `buf'. In all cases, the function generates the corresponding encoded value to the buffer `buf'. */ WsIeee754Result ws_ieee754_encode_single(double value, unsigned char *buf); /* Decode the IEEE-754 encoded number `buf' into a floating point number. The argument `buf' must have 32 bits of data. The function returns a result code which describes the success of the decode operation. If the result is WS_IEEE754_OK, the resulting floating point number is returned in `value_return'. */ WsIeee754Result ws_ieee754_decode_single(unsigned char *buf, double *value_return); /* Get the sign bit from the IEEE-754 single format encoded number `buf'. The buffer `buf' must have 32 bits of data. */ WsUInt32 ws_ieee754_single_get_sign(unsigned char *buf); /* Get the exponent from the IEEE-754 single format encoded number `buf'. The buffer `buf' must have 32 bits of data. The returned value is the biased exponent. */ WsUInt32 ws_ieee754_single_get_exp(unsigned char *buf); /* Get the mantissa from the IEEE-754 single format encoded number `buf'. The buffer `buf' must have 32 bits of data. */ WsUInt32 ws_ieee754_single_get_mant(unsigned char *buf); #endif /* not WSIEEE754_H */ gateway-1.4.5/wmlscript/wserror.c0000644000175000017500000002200713227613126015563 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wserror.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Error and information reporting functions. * */ #include "wsint.h" /********************* High-level functions *****************************/ void ws_info(WsCompilerPtr compiler, char *message, ...) { va_list ap; if (!compiler->params.verbose) return; ws_puts(WS_STDOUT, "wsc: "); va_start(ap, message); ws_vfprintf(WS_STDOUT, message, ap); va_end(ap); ws_puts(WS_STDOUT, WS_LINE_TERMINATOR); } void ws_fatal(char *fmt, ...) { va_list ap; fprintf(stderr, "wsc: fatal: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); abort(); } void ws_error_memory(WsCompilerPtr compiler) { gw_assert(compiler->magic == COMPILER_MAGIC); if (compiler->errors & WS_ERROR_B_MEMORY) /* We have already reported this error. */ return; compiler->errors |= WS_ERROR_B_MEMORY; ws_puts(WS_STDERR, "wsc: error: out of memory" WS_LINE_TERMINATOR); } void ws_error_syntax(WsCompilerPtr compiler, WsUInt32 line) { gw_assert(compiler->magic == COMPILER_MAGIC); if (compiler->errors & WS_ERROR_B_MEMORY) /* It makes no sense to report syntax errors when we have run out of memory. This information is not too valid. */ return; if (line == 0) line = compiler->linenum; if (compiler->last_syntax_error_line == line) /* It makes no sense to report multiple syntax errors from the same line. */ return; compiler->last_syntax_error_line = line; compiler->errors |= WS_ERROR_B_SYNTAX; ws_fprintf(WS_STDERR, "%s:%u: syntax error" WS_LINE_TERMINATOR, compiler->input_name, line); } void ws_src_error(WsCompilerPtr compiler, WsUInt32 line, char *message, ...) { va_list ap; gw_assert(compiler->magic == COMPILER_MAGIC); if (line == 0) line = compiler->linenum; compiler->errors |= WS_ERROR_B_SEMANTIC; ws_fprintf(WS_STDERR, "%s:%u: ", compiler->input_name, line); va_start(ap, message); ws_vfprintf(WS_STDERR, message, ap); va_end(ap); ws_puts(WS_STDERR, WS_LINE_TERMINATOR); compiler->num_errors++; } void ws_src_warning(WsCompilerPtr compiler, WsUInt32 line, char *message, ...) { va_list ap; gw_assert(compiler->magic == COMPILER_MAGIC); if (line == 0) line = compiler->linenum; ws_fprintf(WS_STDERR, "%s:%u: warning: ", compiler->input_name, line); va_start(ap, message); ws_vfprintf(WS_STDERR, message, ap); va_end(ap); ws_puts(WS_STDERR, WS_LINE_TERMINATOR); compiler->num_errors++; } /********************* Low-level functions ******************************/ void ws_fprintf(WsIOProc io, void *context, const char *fmt, ...) { va_list ap; va_start(ap, fmt); ws_vfprintf(io, context, fmt, ap); va_end(ap); } void ws_vfprintf(WsIOProc io, void *context, const char *fmt, va_list ap) { int start, i; for (start = 0, i = 0; fmt[i]; i++) if (fmt[i] == '%' && fmt[i + 1]) { char buf[256]; char *cp; int ival; unsigned int uival; int padder = ' '; int left = 0; unsigned int width = 0; if (fmt[i + 1] == '%') { /* An escaped `%'. Print leading data including the `%' character. */ i++; (*io)(fmt + start, i - start, context); start = i + 1; continue; } /* An escape sequence. */ /* Print leading data if any. */ if (i > start) (*io)(fmt + start, i - start, context); /* We support a minor sub-set of the printf()'s formatting capabilities. Let's see what we got. */ i++; /* Alignment? */ if (fmt[i] == '-') { left = 1; i++; } /* Padding? */ if (fmt[i] == '0') { padder = '0'; i++; } /* Width? */ while ('0' <= fmt[i] && fmt[i] <= '9') { width *= 10; width += fmt[i++] - '0'; } /* Check the format. */ cp = buf; switch (fmt[i]) { case 'c': /* character */ ival = (int) va_arg(ap, int); snprintf(buf, sizeof(buf), "%c", (char) ival); cp = buf; break; case 's': /* string */ cp = va_arg(ap, char *); break; case 'd': /* integer */ ival = va_arg(ap, int); snprintf(buf, sizeof(buf), "%d", ival); cp = buf; break; case 'u': /* unsigned integer */ uival = va_arg(ap, unsigned int); snprintf(buf, sizeof(buf), "%u", uival); cp = buf; break; case 'x': /* unsigned integer in hexadecimal format */ uival = va_arg(ap, unsigned int); snprintf(buf, sizeof(buf), "%x", uival); cp = buf; break; default: ws_fatal("ws_vfprintf(): format %%%c not implemented", fmt[i]); break; } if (left) /* Output the value left-justified. */ (*io)(cp, strlen(cp), context); /* Need padding? */ if (width > strlen(cp)) { /* Yes we need. */ int amount = width - strlen(cp); while (amount-- > 0) ws_fputc(padder, io, context); } if (!left) /* Output the value right-justified. */ (*io)(cp, strlen(cp), context); /* Process more. */ start = i + 1; } /* Print trailing data if any. */ if (i > start) (*io)(fmt + start, i - start, context); } void ws_puts(WsIOProc io, void *context, const char *str) { (*io)(str, strlen(str), context); } void ws_fputc(int ch, WsIOProc io, void *context) { char c = (char) ch; (*io)(&c, 1, context); } gateway-1.4.5/wmlscript/wsencode.c0000644000175000017500000002061613227613126015673 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsencode.c * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Encoding and decoding routines. * */ #include "wsint.h" /********************* Types and definitions ****************************/ #define WS_MB_CONT_BIT 0x80 #define WS_MB_DATA_MASK 0x7f /********************* Global functions *********************************/ unsigned char *ws_encode_mb_uint32(WsUInt32 value, unsigned char *buffer, size_t *len_return) { unsigned char *p = buffer + WS_MB_UINT32_MAX_ENCODED_LEN; size_t len = 1; /* Set the terminator byte. */ *p = value & WS_MB_DATA_MASK; value >>= 7; p--; /* And add the data. */ while (value > 0) { *p = (value & WS_MB_DATA_MASK) | WS_MB_CONT_BIT; value >>= 7; p--; len++; } *len_return = len; return p + 1; } WsUInt32 ws_decode_mb_uint32(const unsigned char *buffer, size_t *len) { WsUInt32 value = 0; size_t i; for (i = 0; i < *len; i++) { value <<= 7; value |= buffer[i] & WS_MB_DATA_MASK; if ((buffer[i] & WS_MB_CONT_BIT) == 0) break; } *len = i + 1; return value; } WsBool ws_encode_buffer(WsBuffer *buffer, ...) { va_list ap; WsEncodingSpec spec; int ival; unsigned char *p; unsigned char *cp; size_t len; WsUInt32 ui32; unsigned char data[64]; va_start(ap, buffer); while ((spec = va_arg(ap, int)) != WS_ENC_END) { switch (spec) { case WS_ENC_BYTE: case WS_ENC_INT8: case WS_ENC_UINT8: ival = va_arg(ap, int); if (!ws_buffer_append_space(buffer, &p, 1)) goto error; WS_PUT_UINT8(p, ival); break; case WS_ENC_INT16: case WS_ENC_UINT16: ival = va_arg(ap, int); if (!ws_buffer_append_space(buffer, &p, 2)) goto error; WS_PUT_UINT16(p, ival); break; case WS_ENC_INT32: case WS_ENC_UINT32: ival = va_arg(ap, long); if (!ws_buffer_append_space(buffer, &p, 4)) goto error; WS_PUT_UINT32(p, ival); break; case WS_ENC_MB_UINT16: case WS_ENC_MB_UINT32: if (spec == WS_ENC_MB_UINT16) ui32 = va_arg(ap, int); else ui32 = va_arg(ap, long); len = sizeof(data); cp = ws_encode_mb_uint32(ui32, data, &len); if (!ws_buffer_append_space(buffer, &p, len)) goto error; memcpy(p, cp, len); break; case WS_ENC_DATA: cp = va_arg(ap, unsigned char *); len = va_arg(ap, unsigned int); if (!ws_buffer_append_space(buffer, &p, len)) goto error; memcpy(p, cp, len); break; default: ws_fatal("ws_encode_buffer(): unknown type %d: probably a missing " "WS_ENC_END", spec); break; } } va_end(ap); return WS_TRUE; /* * Error handling. */ error: va_end(ap); return WS_FALSE; } size_t ws_decode_buffer(const unsigned char *buffer, size_t buffer_len, ...) { va_list ap; WsEncodingSpec spec; WsUInt8 *i8p; WsUInt16 *i16p; WsUInt32 *i32p; unsigned char **cpp; size_t len; size_t orig_buffer_len = buffer_len; va_start(ap, buffer_len); while ((spec = va_arg(ap, int)) != WS_ENC_END) { switch (spec) { case WS_ENC_BYTE: case WS_ENC_INT8: case WS_ENC_UINT8: if (buffer_len < 1) goto too_short_buffer; i8p = va_arg(ap, WsUInt8 *); WS_GET_UINT8(buffer, *i8p); buffer++; buffer_len--; break; case WS_ENC_INT16: case WS_ENC_UINT16: if (buffer_len < 2) goto too_short_buffer; i16p = va_arg(ap, WsUInt16 *); WS_GET_UINT16(buffer, *i16p); buffer += 2; buffer_len -= 2; break; case WS_ENC_INT32: case WS_ENC_UINT32: if (buffer_len < 4) goto too_short_buffer; i32p = va_arg(ap, WsUInt32 *); WS_GET_UINT32(buffer, *i32p); buffer += 4; buffer_len -= 4; break; case WS_ENC_MB_UINT16: case WS_ENC_MB_UINT32: { size_t len = buffer_len; WsUInt32 i32; if (buffer_len < 1) goto too_short_buffer; i32 = ws_decode_mb_uint32(buffer, &len); if (spec == WS_ENC_MB_UINT16) { i16p = va_arg(ap, WsUInt16 *); *i16p = i32; } else { i32p = va_arg(ap, WsUInt32 *); *i32p = i32; } buffer += len; buffer_len -= len; } break; case WS_ENC_DATA: cpp = va_arg(ap, unsigned char **); len = va_arg(ap, size_t); if (buffer_len < len) goto too_short_buffer; *cpp = (unsigned char *) buffer; buffer += len; buffer_len -= len; break; default: ws_fatal("ws_encode_buffer(): unknown type %d: probably a missing " "WS_ENC_END", spec); break; } } va_end(ap); return orig_buffer_len - buffer_len; too_short_buffer: va_end(ap); return 0; } gateway-1.4.5/wmlscript/wsint.h0000644000175000017500000002136213227613126015234 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsint.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Operating system specific environment and general helper utilities * for the WMLScript tools. * */ #ifndef WSINT_H #define WSINT_H #include "gw-config.h" #include #include #include #include #include #include #if HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #include "gwlib/gwassert.h" /********************* Types and definitions ****************************/ /* Platform dependent line terminator. This is used in diagnostic and error messages to terminate output lines. */ #ifdef WIN32 #define WS_LINE_TERMINATOR "\r\n" #else /* not WIN32 */ #define WS_LINE_TERMINATOR "\n" #endif /* not WIN32 */ /* Data types. */ #define WS_INT8_MIN -128 #define WS_INT8_MAX 127 #define WS_INT16_MIN -32768 #define WS_INT16_MAX 32767 #define WS_INT32_MIN -2147483648 #define WS_INT32_MAX 2147483647 /* Integer types. */ typedef unsigned char WsByte; typedef signed char WsInt8; typedef unsigned char WsUInt8; typedef signed short WsInt16; typedef unsigned short WsUInt16; typedef signed long WsInt32; typedef unsigned long WsUInt32; /* Internally we use as good floating point numbers as possible. This way we avoid losing data in constant folding, etc. */ typedef double WsFloat; typedef enum { WS_FALSE, WS_TRUE } WsBool; /* Error flags. */ /* Out of memory. */ #define WS_ERROR_B_MEMORY 0x01 /* The input program was syntactically incorrect. */ #define WS_ERROR_B_SYNTAX 0x02 /* The input program was semantically incorrect. We managed to parse it, but it contained some semantical errors. For example, a local variable was defined twice. */ #define WS_ERROR_B_SEMANTIC 0x04 /********************* Include sub-module headers ***********************/ #include "ws.h" #include "wserror.h" #include "wsutf8.h" #include "wsieee754.h" #include "wsbuffer.h" #include "wsencode.h" #include "wsalloc.h" #include "wsfalloc.h" #include "wsstream.h" #include "wshash.h" #include "wsbc.h" #include "wsstree.h" #include "wsasm.h" #include "wsopt.h" #include "wsstdlib.h" /********************* The compiler handle ******************************/ #if WS_DEBUG /* The currently active compiler. Just for debugging purposes. */ extern WsCompilerPtr global_compiler; #endif /* WS_DEBUG */ /* A structure to register the currently active `continue-break' labels. These are allocated from the syntax-tree pool. */ struct WsContBreakRec { struct WsContBreakRec *next; WsAsmIns *l_cont; WsAsmIns *l_break; }; typedef struct WsContBreakRec WsContBreak; #define COMPILER_MAGIC (0xfefe0101) struct WsCompilerRec { /* A magic number of assure that a correct compiler handle is passed to the parser and lexer functions. */ WsUInt32 magic; /* User-specifiable parameters. */ WsCompilerParams params; /* Current input stream. */ WsStream *input; /* The source file name and line number of the current input stream. */ const char *input_name; WsUInt32 linenum; /* Fast-malloc pool for the syntax tree items. */ WsFastMalloc *pool_stree; /* Fast-malloc pool for the symbolic assembler instructions. */ WsFastMalloc *pool_asm; /* List of active memory blocks, allocated by the lexer. When lexer allocates string or symbol tokens, their dynamically allocated data is registered to this list. The parser removes the items when needed, but if the parsing fails, the items can be freed from this list during the cleanup. */ void **lexer_active_list; size_t lexer_active_list_size; /* The byte-code object. */ WsBc *bc; /* The next label for the assembler generation. */ WsUInt32 next_label; /* The assembler code, currently begin constructed on this compiler. */ WsAsmIns *asm_head; WsAsmIns *asm_tail; /* Buffer holding the linearized byte-code for the current symbolic assembler. */ WsBuffer byte_code; /* The syntax tree items, found from the source stream. */ /* External compilation unit pragmas. */ WsHashPtr pragma_use_hash; /* Functions. */ WsUInt32 num_functions; WsFunction *functions; /* A mapping from function names to their declarations in `functions'. */ WsHashPtr functions_hash; /* A namespace for function arguments and local variables. */ WsUInt32 next_vindex; WsHashPtr variables_hash; /* Registry for the currently active `continue-break' labels. */ WsContBreak *cont_break; /* Statistics about the compilation. */ WsUInt32 num_errors; WsUInt32 num_warnings; WsUInt32 num_extern_functions; WsUInt32 num_local_functions; /* Bitmask to record occurred errors. This is used in error generation and reporting to make sane error messages. */ WsUInt32 errors; /* The latest line where a syntax error occurred. The compiler do not print multiple syntax errors from the same line. */ WsUInt32 last_syntax_error_line; }; typedef struct WsCompilerRec WsCompiler; /********************* Lexer and parser *********************************/ #define YYPARSE_PARAM pctx #define YYLEX_PARAM pctx /* The lexer. */ extern int yylex(); /* Register the lexer allocated block `ptr' to the compiler's list of active blocks. */ WsBool ws_lexer_register_block(WsCompiler *compiler, void *ptr); /* Register the lexer allocated UTF-8 string `string' to the compiler's list of active blocks. */ WsBool ws_lexer_register_utf8(WsCompiler *compiler, WsUtf8String *string); /* Unregister the block `ptr' from the compiler's list of active blocks and free it. It is a fatal error if the block `ptr' does not exist on the list. */ void ws_lexer_free_block(WsCompiler *compiler, void *ptr); /* Unregister an UTF-8 string `string' from the compiler's list of active blocks and free it. */ void ws_lexer_free_utf8(WsCompiler *compiler, WsUtf8String *string); /* The parser. */ int ws_yy_parse(void *context); #endif /* not WSINT_H */ gateway-1.4.5/wmlscript/wsstream.h0000644000175000017500000001425113227613126015734 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsstream.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Generic input / output stream. * */ #ifndef WSSTREAM_H #define WSSTREAM_H /********************* Types and definitions ****************************/ /* The generic input / output stream that is capable of handling ISO/IEC-10646 characters. */ #define WS_STREAM_BUFFER_SIZE 1024 /* Do IO to the stream instance `context'. When reading, the function must read at most `buflen' characters to the buffer `buf' and it must return the number of characters read. When writing, the buffer `buf' has `buflen' characters and the function must return the number of characters written. In both operations, if the function reads or writes less that `buflen' characters, the EOF is assumed to been seen in the stream. */ typedef size_t (*WsStreamIOProc)(void *context, WsUInt32 *buf, size_t buflen); /* Flush all buffered data of the stream instance `context'. The function returns WS_TRUE if the flushing was successful or WS_FALSE otherwise. */ typedef WsBool (*WsStreamFlushProc)(void *context); /* Close the stream instance `context'. */ typedef void (*WsStreamCloseProc)(void *context); /* A stream handle. */ struct WsStreamRec { /* The method functions of this stream. */ WsStreamIOProc io; WsStreamFlushProc flush; WsStreamCloseProc close; /* The stream instance context. */ void *context; /* The current buffered contents of the stream. */ WsUInt32 buffer[WS_STREAM_BUFFER_SIZE]; size_t buffer_pos; size_t data_in_buffer; /* The possible put-back character. */ WsBool ungetch_valid; WsUInt32 ungetch; }; typedef struct WsStreamRec WsStream; /********************* Stream access functions **************************/ /* Get a character from the stream `stream'. The character is returned in `ch_return'. The function returns WS_FALSE if the end of stream has been encountered. */ WsBool ws_stream_getc(WsStream *stream, WsUInt32 *ch_return); /* Put the character `ch' back to the stream `stream'. */ void ws_stream_ungetc(WsStream *stream, WsUInt32 ch); /* Flush all buffered data to the stream back-end. */ WsBool ws_stream_flush(WsStream *stream); /* Close the stream `stream'. */ void ws_stream_close(WsStream *stream); /********************* Constructors for different streams ***************/ /* A generic constructor to create the actual WsStream from the context and from the method functions. The function returns NULL if the stream creation failed. */ WsStream *ws_stream_new(void *context, WsStreamIOProc io, WsStreamFlushProc flush, WsStreamCloseProc close); /* Create a new file stream to the file handle `fp'. The argument `output' specifies whether the stream is an output or an input stream, respectively. The argument `close' specifies whether the file handle `fp' is closed when the stream is closed. It is basicly a good idea to set this argument to WS_FALSE when wrapping the system streams (stdin, stdout, stderr) in a WsStream. The function returns NULL if the stream could not be created. */ WsStream *ws_stream_new_file(FILE *fp, WsBool output, WsBool close); /* Create a new data input stream for `data_len' bytes of ISO-8859/1 data in `data'. The function returns NULL if the stream could not be created. */ WsStream *ws_stream_new_data_input(const unsigned char *data, size_t data_len); #endif /* not WSSTREAM_H */ gateway-1.4.5/wmlscript/wsbc.h0000644000175000017500000002677313227613126015041 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsbc.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Byte-code handling. * */ #ifndef WSBC_H #define WSBC_H #include "wsint.h" /********************* Types and defintions *****************************/ /* The byte-code version numbers. */ #define WS_BC_VERSION_MAJOR 1 #define WS_BC_VERSION_MINOR 1 #define WS_BC_VERSION (((WS_BC_VERSION_MAJOR - 1) << 4) | WS_BC_VERSION_MINOR) /* The maximum length of the byte-code header: the multi-byte encoded length + one byte for the version information. */ #define WS_BC_MAX_HEADER_LEN (WS_MB_UINT32_MAX_ENCODED_LEN + 1) /* The string encoding, used in the byte-code data. These are the MIBEnum values, assigned by IANA. For a complete description of the character sets and values, please see the document `rfc/iana/assignments/character-sets'. */ typedef enum { WS_BC_STRING_ENC_ISO_8859_1 = 4, WS_BC_STRING_ENC_UTF8 = 106 } WsBcStringEncoding; /* Constant types in the BC constants pool. */ #define WS_BC_CONST_INT8 0 #define WS_BC_CONST_INT16 1 #define WS_BC_CONST_INT32 2 #define WS_BC_CONST_FLOAT32 3 #define WS_BC_CONST_UTF8_STRING 4 #define WS_BC_CONST_EMPTY_STRING 5 #define WS_BC_CONST_EXT_ENC_STRING 6 #define WS_BC_CONST_FIRST_RESERVED 7 /* An in-memory byte-code constant. */ typedef enum { WS_BC_CONST_TYPE_INT, WS_BC_CONST_TYPE_FLOAT32, WS_BC_CONST_TYPE_FLOAT32_NAN, WS_BC_CONST_TYPE_FLOAT32_POSITIVE_INF, WS_BC_CONST_TYPE_FLOAT32_NEGATIVE_INF, WS_BC_CONST_TYPE_UTF8_STRING, WS_BC_CONST_TYPE_EMPTY_STRING } WsBcConstantType; struct WsBcConstantRec { WsBcConstantType type; union { WsInt32 v_int; WsFloat v_float; WsUtf8String v_string; } u; }; typedef struct WsBcConstantRec WsBcConstant; /* Pragma types in the BC pragma pool. */ #define WS_BC_PRAGMA_ACCESS_DOMAIN 0 #define WS_BC_PRAGMA_ACCESS_PATH 1 #define WS_BC_PRAGMA_USER_AGENT_PROPERTY 2 #define WS_BC_PRAGMA_USER_AGENT_PROPERTY_AND_SCHEME 3 #define WS_BC_PRAGMA_FIRST_RESERVED 4 /* An in-memory byte-code pragma. */ typedef enum { WS_BC_PRAGMA_TYPE_ACCESS_DOMAIN, WS_BC_PRAGMA_TYPE_ACCESS_PATH, WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY, WS_BC_PRAGMA_TYPE_USER_AGENT_PROPERTY_AND_SCHEME } WsBcPragmaType; struct WsBcPragmaRec { WsBcPragmaType type; WsUInt16 index_1; WsUInt16 index_2; WsUInt16 index_3; }; typedef struct WsBcPragmaRec WsBcPragma; /* An in-memory byte-code function name. */ struct WsBcFunctionNameRec { /* Index to the function pool. */ WsUInt8 index; /* The name of the function as a 7 bit ASCII. This is as-is in the UTF-8 format. */ char *name; }; typedef struct WsBcFunctionNameRec WsBcFunctionName; /* An in-memory byte-code function. */ struct WsBcFunctionRec { WsUInt8 num_arguments; WsUInt8 num_locals; WsUInt32 code_size; unsigned char *code; }; typedef struct WsBcFunctionRec WsBcFunction; /* An in-memory byte-code file. */ struct WsBcRec { /* How the strings are encoded in linearization. */ WsBcStringEncoding string_encoding; /* Constant pool. In this structure, all strings are in UTF-8 format. However, they can be converted to different formats - if requested - when linearizing the byte-code. */ WsUInt16 num_constants; WsBcConstant *constants; /* Pragma pool. */ WsUInt16 num_pragmas; WsBcPragma *pragmas; /* Function pool. */ WsUInt8 num_function_names; WsBcFunctionName *function_names; WsUInt8 num_functions; WsBcFunction *functions; }; typedef struct WsBcRec WsBc; /********************* Manipulating byte-code structure *****************/ /* Allocate a new byte-code structure. The argument `string_encoding' specifies the encoding that is used for strings. The function returns NULL if the allocation failed. */ WsBc *ws_bc_alloc(WsBcStringEncoding string_encoding); /* Free the byte-code structure `bc' and all its internally allocated data structures. The byte-code handle `bc' should not be used after this function. */ void ws_bc_free(WsBc *bc); /* Encode the byte-code structure `bc' into a linearized binary byte-code blob. The function returns WS_TRUE if the encoding was successful of WS_FALSE otherwise. The result blob is returned in `data_return' and its length is returned in `data_len_return'. The returned byte-code block must be freed with the ws_bc_data_free() function. You *must* not free it with ws_free() since it will corrupt the heap. */ WsBool ws_bc_encode(WsBc *bc, unsigned char **data_return, size_t *data_len_return); /* Free a byte-code data `data', returned by the ws_bc_encode() function. */ void ws_bc_data_free(unsigned char *data); /* Decode the byte-code data `data' into an in-memory byte-code structure. The function returns the byte-code structure or NULL if the decoding fails. The argument `data_len' specfies the length of the byte-code data `data'. The returned byte-code structure must be freed with the ws_bc_free() function when it is not needed anymore. */ WsBc *ws_bc_decode(const unsigned char *data, size_t data_len); /********************* Adding constant elements *************************/ /* Add an integer constant `value' to the constant pool of the byte-code structure `bc'. The index of the constant is returned in `index_return'. The function returns WS_TRUE if the operation was successful or WS_FALSE otherwise (out of memory). */ WsBool ws_bc_add_const_int(WsBc *bc, WsUInt16 *index_return, WsInt32 value); /* Add a floating point constant `value' to the constant pool of the byte-code structure `bc'. */ WsBool ws_bc_add_const_float(WsBc *bc, WsUInt16 *index_return, WsFloat value); /* Add an UTF-8 encoded string to the constant pool of the byte-code structure `bc'. */ WsBool ws_bc_add_const_utf8_string(WsBc *bc, WsUInt16 *index_return, const unsigned char *data, size_t len); /* Add an empty string to the constant pool of the byte-code structure `bc'. */ WsBool ws_bc_add_const_empty_string(WsBc *bc, WsUInt16 *index_return); /********************* Adding pragmas ***********************************/ /* Add an access control specifier pragma to the constant and pragma pools of the byte-code structure `bc'. The argument `domain' has `domain_len' bytes of UTF-8 data specifying the access domain. */ WsBool ws_bc_add_pragma_access_domain(WsBc *bc, const unsigned char *domain, size_t domain_len); /* Add an access control specifier pragma to the constant and pragma pools of the byte-code structure `bc'. The argument `path' has `path_len' bytes of UTF-8 data specifying the access path. */ WsBool ws_bc_add_pragma_access_path(WsBc *bc, const unsigned char *path, size_t path_len); /* Add a use agent property pragma to the constant and pragma pools of the byte-code structure `bc'. The arguments `name' and `property' are UTF-8 encoded use agent property. */ WsBool ws_bc_add_pragma_user_agent_property(WsBc *bc, const unsigned char *name, size_t name_len, const unsigned char *property, size_t property_len); /* Add a use agent property pragma to the constant and pragma pools of the byte-code structure `bc'. The arguments `name', `property', and `scheme' are UTF-8 encoded use agent property and scheme. */ WsBool ws_bc_add_pragma_user_agent_property_and_scheme( WsBc *bc, const unsigned char *name, size_t name_len, const unsigned char *property, size_t property_len, const unsigned char *scheme, size_t scheme_len); /********************* Adding functions *********************************/ /* Add a new function to the function pool of the byte-code structure `bc'. The argument `name' specifies the name of the function for external functions. For internal functions, the `name' argument must be NULL. The argument `num_arguments' specifies the number of arguments the function takes. The argument `num_locals' specifies how many local variables the function needs. The byte-code of the function is in `code' and it is `code_size' bytes long. The function takes a copy of the byte-code array `code'. The caller can free / modify the original array, pointed by the argument `code', after the function returns. The function returns WS_TRUE if the adding was successful or WS_FALSE otherwise (out of memory). */ WsBool ws_bc_add_function(WsBc *bc, WsUInt8 *index_return, char *name, WsUInt8 num_arguments, WsUInt8 num_locals, WsUInt32 code_size, unsigned char *code); #endif /* not WSBC_H */ gateway-1.4.5/wmlscript/wsgram.y0000644000175000017500000004542312254026213015407 0ustar toljtolj%{ /* * * wsgram.y * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Bison grammar for the WMLScript compiler. * */ #include "wmlscript/wsint.h" /* The required yyerror() function. This is actually not used but to report the internal parser errors. All other errors are reported by using the `wserror.h' functions. */ extern void yyerror(char *msg); #if WS_DEBUG /* Just for debugging purposes. */ WsCompilerPtr global_compiler = NULL; #endif /* WS_DEBUG */ %} /* The possible semantic values. */ %union { WsUInt32 integer; WsFloat vfloat; char *identifier; WsUtf8String *string; WsBool boolean; WsList *list; WsFormalParm *parm; WsVarDec *vardec; WsPragmaMetaBody *meta_body; WsStatement *stmt; WsExpression *expr; } /* Tokens. */ /* Language literals. */ %token tINVALID tTRUE tFALSE tINTEGER tFLOAT tSTRING /* Identifier. */ %token tIDENTIFIER /* Keywords. */ %token tACCESS tAGENT tBREAK tCONTINUE tIDIV tIDIVA tDOMAIN tELSE tEQUIV %token tEXTERN tFOR tFUNCTION tHEADER tHTTP tIF tISVALID tMETA tNAME tPATH %token tRETURN tTYPEOF tUSE tUSER tVAR tWHILE tURL /* Keywords not used by WMLScript */ %token tDELETE tIN tLIB tNEW tNULL tTHIS tVOID tWITH /* Future reserved keywords. */ %token tCASE tCATCH tCLASS tCONST tDEBUGGER tDEFAULT tDO tENUM tEXPORT %token tEXTENDS tFINALLY tIMPORT tPRIVATE tPUBLIC tSIZEOF tSTRUCT tSUPER %token tSWITCH tTHROW tTRY /* Punctuation. */ %token tEQ tLE tGE tNE tAND tOR tPLUSPLUS tMINUSMINUS %token tLSHIFT tRSSHIFT tRSZSHIFT tADDA tSUBA tMULA tDIVA tANDA tORA tXORA %token tREMA tLSHIFTA tRSSHIFTA tRSZSHIFTA /* Assign semantic values to tokens and non-terminals. */ %type tINTEGER %type tFLOAT %type tSTRING %type tIDENTIFIER %type MetaPropertyName MetaContent MetaScheme %type MetaBody %type ExternOpt %type FormalParameterListOpt FormalParameterList %type StatementListOpt StatementList %type Block Arguments ArgumentList VariableDeclarationList %type VariableDeclaration %type Statement ReturnStatement VariableStatement IfStatement %type IterationStatement ForStatement %type ExpressionOpt Expression AssignmentExpression %type ConditionalExpression LogicalORExpression %type LogicalANDExpression BitwiseORExpression %type BitwiseXORExpression BitwiseANDExpression %type EqualityExpression RelationalExpression ShiftExpression %type AdditiveExpression MultiplicativeExpression UnaryExpression %type PostfixExpression CallExpression PrimaryExpression %type VariableInitializedOpt /* Options for bison. */ /* Generate reentrant parser. */ %pure-parser /* This grammar has one shift-reduce conflict. It comes from the if-else statement. */ %expect 1 %% /* A compilation unit. */ CompilationUnit: Pragmas FunctionDeclarations | FunctionDeclarations | error { ws_error_syntax(pctx, @1.first_line); } ; /* Pragmas. */ Pragmas: Pragma | Pragmas Pragma ; Pragma: tUSE PragmaDeclaration ';' | error { ws_error_syntax(pctx, @1.first_line); } ; PragmaDeclaration: ExternalCompilationUnitPragma | AccessControlPragma | MetaPragma ; ExternalCompilationUnitPragma: tURL tIDENTIFIER tSTRING { ws_pragma_use(pctx, @2.first_line, $2, $3); } ; AccessControlPragma: tACCESS AccessControlSpecifier ; AccessControlSpecifier: tDOMAIN tSTRING { WsCompiler *compiler = (WsCompiler *) pctx; /* Pass this to the byte-code */ if (!ws_bc_add_pragma_access_domain(compiler->bc, $2->data, $2->len)) ws_error_memory(pctx); ws_lexer_free_utf8(compiler, $2); } | tPATH tSTRING { WsCompiler *compiler = (WsCompiler *) pctx; /* Pass this to the byte-code */ if (!ws_bc_add_pragma_access_path(compiler->bc, $2->data, $2->len)) ws_error_memory(pctx); ws_lexer_free_utf8(compiler, $2); } | tDOMAIN tSTRING tPATH tSTRING { WsCompiler *compiler = (WsCompiler *) pctx; WsBool success = WS_TRUE; /* Pass these to the byte-code */ if (!ws_bc_add_pragma_access_domain(compiler->bc, $2->data, $2->len)) success = WS_FALSE; if (!ws_bc_add_pragma_access_path(compiler->bc, $4->data, $4->len)) success = WS_FALSE; if (!success) ws_error_memory(pctx); ws_lexer_free_utf8(compiler, $2); ws_lexer_free_utf8(compiler, $4); } ; MetaPragma: tMETA MetaSpecifier ; MetaSpecifier: MetaName | MetaHttpEquiv | MetaUserAgent ; MetaName: tNAME MetaBody { WsCompiler *compiler = (WsCompiler *) pctx; /* Meta information for the origin servers. Show it * to the user if requested. */ if (compiler->params.meta_name_cb) (*compiler->params.meta_name_cb)( $2->property_name, $2->content, $2->scheme, compiler->params.meta_name_cb_context); /* We do not need the MetaBody anymore. */ ws_pragma_meta_body_free(compiler, $2); } ; MetaHttpEquiv: tHTTP tEQUIV MetaBody { WsCompiler *compiler = (WsCompiler *) pctx; /* Meta information HTTP header that should be * included to an HTTP response header. Show it to * the user if requested. */ if (compiler->params.meta_http_equiv_cb) (*compiler->params.meta_http_equiv_cb)( $3->property_name, $3->content, $3->scheme, compiler->params.meta_http_equiv_cb_context); /* We do not need the MetaBody anymore. */ ws_pragma_meta_body_free(compiler, $3); } ; MetaUserAgent: tUSER tAGENT MetaBody { WsBool success; WsCompiler *compiler = (WsCompiler *) pctx; /* Pass this pragma to the byte-code */ if ($3) { if ($3->scheme) success = ws_bc_add_pragma_user_agent_property_and_scheme( compiler->bc, $3->property_name->data, $3->property_name->len, $3->content->data, $3->content->len, $3->scheme->data, $3->scheme->len); else success = ws_bc_add_pragma_user_agent_property( compiler->bc, $3->property_name->data, $3->property_name->len, $3->content->data, $3->content->len); /* Free the MetaBody. */ ws_pragma_meta_body_free(compiler, $3); if (!success) ws_error_memory(pctx); } } ; MetaBody: MetaPropertyName MetaContent { $$ = ws_pragma_meta_body(pctx, $1, $2, NULL); } | MetaPropertyName MetaContent MetaScheme { $$ = ws_pragma_meta_body(pctx, $1, $2, $3); } ; MetaPropertyName: tSTRING; MetaContent: tSTRING; MetaScheme: tSTRING; /* Function declarations. */ FunctionDeclarations: FunctionDeclaration | FunctionDeclarations FunctionDeclaration ; FunctionDeclaration: ExternOpt tFUNCTION tIDENTIFIER '(' FormalParameterListOpt ')' Block SemicolonOpt { char *name = ws_strdup($3); ws_lexer_free_block(pctx, $3); if (name) ws_function(pctx, $1, name, @3.first_line, $5, $7); else ws_error_memory(pctx); } ; ExternOpt: /* empty */ { $$ = WS_FALSE; } | tEXTERN { $$ = WS_TRUE; } ; FormalParameterListOpt: /* empty */ { $$ = ws_list_new(pctx); } | FormalParameterList ; SemicolonOpt: /* empty */ | ';' ; FormalParameterList: tIDENTIFIER { char *id; WsFormalParm *parm; id = ws_f_strdup(((WsCompiler *) pctx)->pool_stree, $1); parm = ws_formal_parameter(pctx, @1.first_line, id); ws_lexer_free_block(pctx, $1); if (id == NULL || parm == NULL) { ws_error_memory(pctx); $$ = NULL; } else { $$ = ws_list_new(pctx); ws_list_append(pctx, $$, parm); } } | FormalParameterList ',' tIDENTIFIER { char *id; WsFormalParm *parm; id = ws_f_strdup(((WsCompiler *) pctx)->pool_stree, $3); parm = ws_formal_parameter(pctx, @1.first_line, id); ws_lexer_free_block(pctx, $3); if (id == NULL || parm == NULL) { ws_error_memory(pctx); $$ = NULL; } else ws_list_append(pctx, $1, parm); } ; /* Statements. */ Statement: Block { if ($1) $$ = ws_stmt_block(pctx, $1->first_line, $1->last_line, $1); else $$ = NULL; } | VariableStatement | ';' /* EmptyStatement */ { $$ = ws_stmt_empty(pctx, @1.first_line); } | Expression ';' /* ExpressionStatement */ { $$ = ws_stmt_expr(pctx, $1->line, $1); } | IfStatement | IterationStatement | tCONTINUE ';' /* ContinueStatement */ { $$ = ws_stmt_continue(pctx, @1.first_line); } | tBREAK ';' /* BreakStatement */ { $$ = ws_stmt_break(pctx, @1.first_line); } | ReturnStatement ; Block: '{' StatementListOpt '}' { $$ = $2; if ($$) { $$->first_line = @1.first_line; $$->last_line = @3.first_line; } } | error { ws_error_syntax(pctx, @1.first_line); $$ = NULL; } ; StatementListOpt: /* empty */ { $$ = ws_list_new(pctx); } | StatementList ; StatementList: Statement { $$ = ws_list_new(pctx); ws_list_append(pctx, $$, $1); } | StatementList Statement { ws_list_append(pctx, $1, $2); } ; VariableStatement: tVAR VariableDeclarationList ';' { $$ = ws_stmt_variable(pctx, @1.first_line, $2); } | tVAR error { ws_error_syntax(pctx, @2.first_line); } ; VariableDeclarationList: VariableDeclaration { $$ = ws_list_new(pctx); ws_list_append(pctx, $$, $1); } | VariableDeclarationList ',' VariableDeclaration { ws_list_append(pctx, $1, $3); } ; VariableDeclaration: tIDENTIFIER VariableInitializedOpt { char *id = ws_f_strdup(((WsCompiler *) pctx)->pool_stree, $1); ws_lexer_free_block(pctx, $1); if (id == NULL) { ws_error_memory(pctx); $$ = NULL; } else $$ = ws_variable_declaration(pctx, id, $2); } ; VariableInitializedOpt: /* empty */ { $$ = NULL; } | '=' ConditionalExpression { $$ = $2; } ; IfStatement: tIF '(' Expression ')' Statement tELSE Statement { $$ = ws_stmt_if(pctx, @1.first_line, $3, $5, $7); } | tIF '(' Expression ')' Statement { $$ = ws_stmt_if(pctx, @1.first_line, $3, $5, NULL); } ; IterationStatement: tWHILE '(' Expression ')' Statement { $$ = ws_stmt_while(pctx, @1.first_line, $3, $5); } | ForStatement ; ForStatement: tFOR '(' ExpressionOpt ';' ExpressionOpt ';' ExpressionOpt ')' Statement { $$ = ws_stmt_for(pctx, @1.first_line, NULL, $3, $5, $7, $9); } | tFOR '(' tVAR VariableDeclarationList ';' ExpressionOpt ';' ExpressionOpt ')' Statement { $$ = ws_stmt_for(pctx, @1.first_line, $4, NULL, $6, $8, $10); } ; ReturnStatement: tRETURN ExpressionOpt ';' { $$ = ws_stmt_return(pctx, @1.first_line, $2); } ; /* Expressions. */ ExpressionOpt: /* empty */ { $$ = NULL; } | Expression ; Expression: AssignmentExpression | Expression ',' AssignmentExpression { $$ = ws_expr_comma(pctx, @2.first_line, $1, $3); } ; AssignmentExpression: ConditionalExpression | tIDENTIFIER '=' AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, '=', $3); } | tIDENTIFIER tMULA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tMULA, $3); } | tIDENTIFIER tDIVA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tDIVA, $3); } | tIDENTIFIER tREMA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tREMA, $3); } | tIDENTIFIER tADDA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tADDA, $3); } | tIDENTIFIER tSUBA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tSUBA, $3); } | tIDENTIFIER tLSHIFTA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tLSHIFTA, $3); } | tIDENTIFIER tRSSHIFTA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tRSSHIFTA, $3); } | tIDENTIFIER tRSZSHIFTA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tRSZSHIFTA, $3); } | tIDENTIFIER tANDA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tANDA, $3); } | tIDENTIFIER tXORA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tXORA, $3); } | tIDENTIFIER tORA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tORA, $3); } | tIDENTIFIER tIDIVA AssignmentExpression { $$ = ws_expr_assign(pctx, @1.first_line, $1, tIDIVA, $3); } ; ConditionalExpression: LogicalORExpression | LogicalORExpression '?' AssignmentExpression ':' AssignmentExpression { $$ = ws_expr_conditional(pctx, @2.first_line, $1, $3, $5); } ; LogicalORExpression: LogicalANDExpression | LogicalORExpression tOR LogicalANDExpression { $$ = ws_expr_logical(pctx, @2.first_line, WS_ASM_SCOR, $1, $3); } ; LogicalANDExpression: BitwiseORExpression | LogicalANDExpression tAND BitwiseORExpression { $$ = ws_expr_logical(pctx, @2.first_line, WS_ASM_SCAND, $1, $3); } ; BitwiseORExpression: BitwiseXORExpression | BitwiseORExpression '|' BitwiseXORExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_B_OR, $1, $3); } ; BitwiseXORExpression: BitwiseANDExpression | BitwiseXORExpression '^' BitwiseANDExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_B_XOR, $1, $3); } ; BitwiseANDExpression: EqualityExpression | BitwiseANDExpression '&' EqualityExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_B_AND, $1, $3); } ; EqualityExpression: RelationalExpression | EqualityExpression tEQ RelationalExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_EQ, $1, $3); } | EqualityExpression tNE RelationalExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_NE, $1, $3); } ; RelationalExpression: ShiftExpression | RelationalExpression '<' ShiftExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_LT, $1, $3); } | RelationalExpression '>' ShiftExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_GT, $1, $3); } | RelationalExpression tLE ShiftExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_LE, $1, $3); } | RelationalExpression tGE ShiftExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_GE, $1, $3); } ; ShiftExpression: AdditiveExpression | ShiftExpression tLSHIFT AdditiveExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_B_LSHIFT, $1, $3); } | ShiftExpression tRSSHIFT AdditiveExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_B_RSSHIFT, $1, $3); } | ShiftExpression tRSZSHIFT AdditiveExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_B_RSZSHIFT, $1, $3); } ; AdditiveExpression: MultiplicativeExpression | AdditiveExpression '+' MultiplicativeExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_ADD, $1, $3); } | AdditiveExpression '-' MultiplicativeExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_SUB, $1, $3); } ; MultiplicativeExpression: UnaryExpression | MultiplicativeExpression '*' UnaryExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_MUL, $1, $3); } | MultiplicativeExpression '/' UnaryExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_DIV, $1, $3); } | MultiplicativeExpression tIDIV UnaryExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_IDIV, $1, $3); } | MultiplicativeExpression '%' UnaryExpression { $$ = ws_expr_binary(pctx, @2.first_line, WS_ASM_REM, $1, $3); } ; UnaryExpression: PostfixExpression | tTYPEOF UnaryExpression { $$ = ws_expr_unary(pctx, @1.first_line, WS_ASM_TYPEOF, $2); } | tISVALID UnaryExpression { $$ = ws_expr_unary(pctx, @1.first_line, WS_ASM_ISVALID, $2); } | tPLUSPLUS tIDENTIFIER { $$ = ws_expr_unary_var(pctx, @1.first_line, WS_TRUE, $2); } | tMINUSMINUS tIDENTIFIER { $$ = ws_expr_unary_var(pctx, @1.first_line, WS_FALSE, $2); } | '+' UnaryExpression { /* There is no direct way to compile unary `+'. * It doesn't do anything except require type conversion * (section 7.2, 7.3.2), and we do that by converting * it to a binary expression: `UnaryExpression - 0'. * Using `--UnaryExpression' would not be correct because * it might overflow if UnaryExpression is the smallest * possible integer value (see 6.2.7.1). * Using `UnaryExpression + 0' would not be correct * because binary `+' accepts strings, which makes the * type conversion different. */ $$ = ws_expr_binary(pctx, @1.first_line, WS_ASM_SUB, $2, ws_expr_const_integer(pctx, @1.first_line, 0)); } | '-' UnaryExpression { $$ = ws_expr_unary(pctx, @1.first_line, WS_ASM_UMINUS, $2); } | '~' UnaryExpression { $$ = ws_expr_unary(pctx, @1.first_line, WS_ASM_B_NOT, $2); } | '!' UnaryExpression { $$ = ws_expr_unary(pctx, @1.first_line, WS_ASM_NOT, $2); } ; PostfixExpression: CallExpression | tIDENTIFIER tPLUSPLUS { $$ = ws_expr_postfix_var(pctx, @1.first_line, WS_TRUE, $1); } | tIDENTIFIER tMINUSMINUS { $$ = ws_expr_postfix_var(pctx, @1.first_line, WS_FALSE, $1); } ; CallExpression: PrimaryExpression | tIDENTIFIER Arguments /* LocalScriptFunctionCall */ { WsFunctionHash *f = ws_function_hash(pctx, $1); /* Add an usage count for the local script function. */ if (f) f->usage_count++; $$ = ws_expr_call(pctx, @1.first_line, ' ', NULL, $1, $2); } | tIDENTIFIER '#' tIDENTIFIER Arguments /* ExternalScriptFunctionCall*/ { $$ = ws_expr_call(pctx, @3.first_line, '#', $1, $3, $4); } | tIDENTIFIER '.' tIDENTIFIER Arguments /* LibraryFunctionCall */ { $$ = ws_expr_call(pctx, @3.first_line, '.', $1, $3, $4); } ; PrimaryExpression: tIDENTIFIER { $$ = ws_expr_symbol(pctx, @1.first_line, $1); } | tINVALID { $$ = ws_expr_const_invalid(pctx, @1.first_line); } | tTRUE { $$ = ws_expr_const_true(pctx, @1.first_line); } | tFALSE { $$ = ws_expr_const_false(pctx, @1.first_line); } | tINTEGER { $$ = ws_expr_const_integer(pctx, @1.first_line, $1); } | tFLOAT { $$ = ws_expr_const_float(pctx, @1.first_line, $1); } | tSTRING { $$ = ws_expr_const_string(pctx, @1.first_line, $1); } | '(' Expression ')' { $$ = $2; } ; Arguments: '(' ')' { $$ = ws_list_new(pctx); } | '(' ArgumentList ')' { $$ = $2; } ; ArgumentList: AssignmentExpression { $$ = ws_list_new(pctx); ws_list_append(pctx, $$, $1); } | ArgumentList ',' AssignmentExpression { ws_list_append(pctx, $1, $3); } ; %% void yyerror(char *msg) { #if WS_DEBUG fprintf(stderr, "*** %s:%ld: wsc: %s - this msg will be removed ***\n", global_compiler->input_name, global_compiler->linenum, msg); #endif /* WS_DEBUG */ } gateway-1.4.5/wmlscript/wsopt.h0000644000175000017500000000644113227613126015245 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsopt.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Optimizations for the WMLScript symbolic assembler. * */ #ifndef WSOPT_H #define WSOPT_H /********************* Optimizations ************************************/ /* Optimize the symbolic assembler in the compiler `compiler'. The enabled optimizations can be found from the compiler's options. The possible errors are reported through the error variables of the `compiler'. */ void ws_asm_optimize(WsCompilerPtr compiler); #endif /* WSOPT_H */ gateway-1.4.5/wmlscript/wsalloc.h0000644000175000017500000001654313227613126015541 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsalloc.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Memory allocation routines. * */ #ifndef WSALLOC_H #define WSALLOC_H #if WS_DEBUG #define WS_MEM_DEBUG 1 #endif /* WS_DEBUG */ #if !WS_MEM_DEBUG /********************* Prototypes for global functions ******************/ /* Allocate `size' bytes of memory. The function returns NULL if the * allocation fails. */ void *ws_malloc(size_t size); /* Allocate `num' items of size `size'. The returned memory block is * initialied with zero. The function returns NULL if the allocation * fails .*/ void *ws_calloc(size_t num, size_t size); /* Reallocate the memory block `ptr' to size `size'. The old data is * preserved in the new memory block. The function returns NULL if * the allocation fails. It is permissible to call the function with * NULL as the `ptr' argument of 0 as the `size' argument. In these * cases, the function acts the "Right Way". If the `ptr' is NULL, * the function allocates a fresh block of size `size'. If the `size' * is NULL, the memory block `ptr' is freed. */ void *ws_realloc(void *ptr, size_t size); /* Take a copy of the memory buffer `ptr' which has `size' bytes of * data. The function returns NULL if the allocation fails. The * returned buffer is null-terminated. */ void *ws_memdup(const void *ptr, size_t size); /* Take a copy of the C-string `str'. The function returns NULL if * the allocation fails. */ void *ws_strdup(const char *str); /* Free the memory block `ptr' that was previously allocated with one * of the ws_{m,c,re}alloc() functions. It is allowed to call the * function with NULL as the `ptr' argument. */ void ws_free(void *ptr); #else /* WS_MEM_DEBUG */ /********************* Memory debugging routines ************************/ /* These macros and functions are used in debugging memory usage of * the compiler and to find out memory leaks. When these functions * are used, each dynamically allocated block is recorded in a list of * active blocks, and allocated blocks are tagged with information * about their allocation location. When the block is freed, it is * removed from the list and its contents is marked freed. Typically * these functions detect memory leaks and freeing same memory block * multiple times. * * These functions can also be used to test error recovery code of * memory allocation failures. The function ws_clear_leaks() clears * the current information about used blocks and it sets the limit of * successful memory allocations. When more than the limit number of * memory allocations have been performed, all memory allocations * fail. When the tested function has returned, you can see if you * cleanup code did not free all blocks by using the functions * ws_hash_leaks() and ws_dump_blocks(). * * These functions are not thread safe. They use shared static list * to record the active blocks and they do not use any sorts of * locking. */ /* Macros to tag the allocation source file location to the allocated memory block. */ #define ws_malloc(_s) ws_malloc_i((_s), __FILE__, __LINE__) #define ws_calloc(_n, _s) ws_calloc_i((_n), (_s), __FILE__, __LINE__) #define ws_realloc(_p, _s) ws_realloc_i((_p), (_s), __FILE__, __LINE__) #define ws_memdup(_p, _s) ws_memdup_i((_p), (_s), __FILE__, __LINE__) #define ws_strdup(_s) ws_strdup_i((_s), __FILE__, __LINE__) #define ws_free(_p) ws_free_i((_p)) /* The allocation and freeing functions. */ void *ws_malloc_i(size_t size, const char *file, int line); void *ws_calloc_i(size_t num, size_t size, const char *file, int line); void *ws_realloc_i(void *ptr, size_t size, const char *file, int line); void *ws_memdup_i(const void *ptr, size_t size, const char *file, int line); void *ws_strdup_i(const char *str, const char *file, int line); void ws_free_i(void *ptr); /* A predicate to check if the system currently has any allocated * blocks. The function returns 1 if it has any blocks and 0 * otherwise. */ int ws_has_leaks(void); /* Dumps all currently allocated blocks, including their allocation * location, to standard error (stderr). The function also prints * statistics about maximum memory usage. */ void ws_dump_blocks(void); /* Clear all statistics and the list containing the currently * allocated leaks. The argument `num_successful_allocs' sets the * limit how many memory allocations (assuming that the system has * enought memory) are successful. If more than * `num_successful_allocs' are performed, the allocations routines * will fail and return the value NULL. */ void ws_clear_leaks(unsigned int num_successful_allocs); #endif /* WS_MEM_DEBUG */ #endif /* not WSALLOC_H */ gateway-1.4.5/wmlscript/wsutf8.h0000644000175000017500000001401313227613126015323 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * * wsutf8.h * * Author: Markku Rossi * * Copyright (c) 1999-2000 WAPIT OY LTD. * All rights reserved. * * Functions to manipulate UTF-8 encoded strings. * * Specification: RFC-2279 * */ #ifndef WSUTF8_H #define WSUTF8_H /********************* Types and defintions *****************************/ /* UTF-8 string handle. */ struct WsUtf8StringRec { /* The length of the UTF-8 encoded `data'. */ size_t len; /* The UTF-8 encoded data. */ unsigned char *data; /* The number of characters in the string. */ size_t num_chars; }; typedef struct WsUtf8StringRec WsUtf8String; /********************* Global functions *********************************/ /* Allocate an empty UTF-8 string. The function returns NULL if the allocation failed (out of memory). */ WsUtf8String *ws_utf8_alloc(void); /* Free an UTF-8 encoded string. */ void ws_utf8_free(WsUtf8String *string); /* Append the character `ch' to the string `string'. The function returns 1 if the operation was successful or 0 otherwise (out of memory). */ int ws_utf8_append_char(WsUtf8String *string, unsigned long ch); /* Verify the UTF-8 encoded string `data' containing `len' bytes of data. The function returns 1 if the `data' is correctly encoded and 0 otherwise. If the argument `strlen_return' is not NULL, it is set to the number of characters in the string. */ int ws_utf8_verify(const unsigned char *data, size_t len, size_t *strlen_return); /* Set UTF-8 encoded data `data', `len' to the string `string'. The function returns 1 if the data was UTF-8 encoded and 0 otherwise (malformed data or out of memory). The function frees the possible old data from `string'. */ int ws_utf8_set_data(WsUtf8String *string, const unsigned char *data, size_t len); /* Get a character from the UTF-8 string `string'. The argument `posp' gives the index of the character in the UTF-8 encoded data. It is not the sequence number of the character. It is its starting position within the UTF-8 encoded data. The argument `posp' is updated to point to the beginning of the next character within the data. The character is returned in `ch_return'. The function returns 1 if the operation was successful or 0 otherwise (index `posp' was invalid or there were no more characters in the string). */ int ws_utf8_get_char(const WsUtf8String *string, unsigned long *ch_return, size_t *posp); /* Convert the UTF-8 encoded string `string' to null-terminated ISO 8859/1 (ISO latin1) string. Those characters of `string' which can not be presented in latin1 are replaced with the character `unknown_char'. If the argument `len_return' is not NULL, it is set to contain the length of the returned string (excluding the trailing null-character). The function returns a pointer to the string or NULL if the operation failed (out of memory). The returned string must be freed with the ws_utf8_free_data() function. */ unsigned char *ws_utf8_to_latin1(const WsUtf8String *string, unsigned char unknown_char, size_t *len_return); /* Free a string, returned by the ws_utf8_to_latin1_cstr() function. */ void ws_utf8_free_data(unsigned char *data); #endif /* not WSUTF8_H */ gateway-1.4.5/aclocal.m40000644000175000017500000142754613312227404013545 0ustar toljtolj# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # iconv.m4 serial 18 (gettext-0.18.2) dnl Copyright (C) 2000-2002, 2007-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. AC_DEFUN([AM_ICONV_LINKFLAGS_BODY], [ dnl Prerequisites of AC_LIB_LINKFLAGS_BODY. AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) AC_REQUIRE([AC_LIB_RPATH]) dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_LIB_LINKFLAGS_BODY([iconv]) ]) AC_DEFUN([AM_ICONV_LINK], [ dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and dnl those with the standalone portable GNU libiconv installed). AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV dnl accordingly. AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY]) dnl Add $INCICONV to CPPFLAGS before performing the following checks, dnl because if the user has installed libiconv and not disabled its use dnl via --without-libiconv-prefix, he wants to use it. The first dnl AC_LINK_IFELSE will then fail, the second AC_LINK_IFELSE will succeed. am_save_CPPFLAGS="$CPPFLAGS" AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV]) AC_CACHE_CHECK([for iconv], [am_cv_func_iconv], [ am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);]])], [am_cv_func_iconv=yes]) if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" AC_LINK_IFELSE( [AC_LANG_PROGRAM( [[ #include #include ]], [[iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd);]])], [am_cv_lib_iconv=yes] [am_cv_func_iconv=yes]) LIBS="$am_save_LIBS" fi ]) if test "$am_cv_func_iconv" = yes; then AC_CACHE_CHECK([for working iconv], [am_cv_func_iconv_works], [ dnl This tests against bugs in AIX 5.1, AIX 6.1..7.1, HP-UX 11.11, dnl Solaris 10. am_save_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi AC_RUN_IFELSE( [AC_LANG_SOURCE([[ #include #include int main () { int result = 0; /* Test against AIX 5.1 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { static const char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 1; iconv_close (cd_utf8_to_88591); } } /* Test against Solaris 10 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); if (cd_ascii_to_88591 != (iconv_t)(-1)) { static const char input[] = "\263"; char buf[10]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_ascii_to_88591, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 2; iconv_close (cd_ascii_to_88591); } } /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ { iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static const char input[] = "\304"; static char buf[2] = { (char)0xDE, (char)0xAD }; const char *inptr = input; size_t inbytesleft = 1; char *outptr = buf; size_t outbytesleft = 1; size_t res = iconv (cd_88591_to_utf8, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) result |= 4; iconv_close (cd_88591_to_utf8); } } #if 0 /* This bug could be worked around by the caller. */ /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ { iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if ((int)res > 0) result |= 8; iconv_close (cd_88591_to_utf8); } } #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ if (/* Try standardized names. */ iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) /* Try IRIX, OSF/1 names. */ && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) /* Try AIX names. */ && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) /* Try HP-UX names. */ && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) result |= 16; return result; }]])], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no], [ changequote(,)dnl case "$host_os" in aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; *) am_cv_func_iconv_works="guessing yes" ;; esac changequote([,])dnl ]) LIBS="$am_save_LIBS" ]) case "$am_cv_func_iconv_works" in *no) am_func_iconv=no am_cv_lib_iconv=no ;; *) am_func_iconv=yes ;; esac else am_func_iconv=no am_cv_lib_iconv=no fi if test "$am_func_iconv" = yes; then AC_DEFINE([HAVE_ICONV], [1], [Define if you have the iconv() function and it works.]) fi if test "$am_cv_lib_iconv" = yes; then AC_MSG_CHECKING([how to link with libiconv]) AC_MSG_RESULT([$LIBICONV]) else dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV dnl either. CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi AC_SUBST([LIBICONV]) AC_SUBST([LTLIBICONV]) ]) dnl Define AM_ICONV using AC_DEFUN_ONCE for Autoconf >= 2.64, in order to dnl avoid warnings like dnl "warning: AC_REQUIRE: `AM_ICONV' was expanded before it was required". dnl This is tricky because of the way 'aclocal' is implemented: dnl - It requires defining an auxiliary macro whose name ends in AC_DEFUN. dnl Otherwise aclocal's initial scan pass would miss the macro definition. dnl - It requires a line break inside the AC_DEFUN_ONCE and AC_DEFUN expansions. dnl Otherwise aclocal would emit many "Use of uninitialized value $1" dnl warnings. m4_define([gl_iconv_AC_DEFUN], m4_version_prereq([2.64], [[AC_DEFUN_ONCE( [$1], [$2])]], [m4_ifdef([gl_00GNULIB], [[AC_DEFUN_ONCE( [$1], [$2])]], [[AC_DEFUN( [$1], [$2])]])])) gl_iconv_AC_DEFUN([AM_ICONV], [ AM_ICONV_LINK if test "$am_cv_func_iconv" = yes; then AC_MSG_CHECKING([for iconv declaration]) AC_CACHE_VAL([am_cv_proto_iconv], [ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif ]], [[]])], [am_cv_proto_iconv_arg1=""], [am_cv_proto_iconv_arg1="const"]) am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"]) am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` AC_MSG_RESULT([ $am_cv_proto_iconv]) AC_DEFINE_UNQUOTED([ICONV_CONST], [$am_cv_proto_iconv_arg1], [Define as const if the declaration of iconv() needs const.]) dnl Also substitute ICONV_CONST in the gnulib generated . m4_ifdef([gl_ICONV_H_DEFAULTS], [AC_REQUIRE([gl_ICONV_H_DEFAULTS]) if test -n "$am_cv_proto_iconv_arg1"; then ICONV_CONST="const" fi ]) fi ]) # lib-ld.m4 serial 6 dnl Copyright (C) 1996-2003, 2009-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl Subroutines of libtool.m4, dnl with replacements s/_*LT_PATH/AC_LIB_PROG/ and s/lt_/acl_/ to avoid dnl collision with libtool.m4. dnl From libtool-2.4. Sets the variable with_gnu_ld to yes or no. AC_DEFUN([AC_LIB_PROG_LD_GNU], [AC_CACHE_CHECK([if the linker ($LD) is GNU ld], [acl_cv_prog_gnu_ld], [# I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 /dev/null 2>&1 \ && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ || PATH_SEPARATOR=';' } fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL([acl_cv_path_LD], [if test -z "$LD"; then acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$acl_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 = 1.10 to complain if config.rpath is missing. m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])]) AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir AC_CACHE_CHECK([for shared library run path origin], [acl_cv_rpath], [ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done ]) wl="$acl_cv_wl" acl_libext="$acl_cv_libext" acl_shlibext="$acl_cv_shlibext" acl_libname_spec="$acl_cv_libname_spec" acl_library_names_spec="$acl_cv_library_names_spec" acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" acl_hardcode_direct="$acl_cv_hardcode_direct" acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" dnl Determine whether the user wants rpath handling at all. AC_ARG_ENABLE([rpath], [ --disable-rpath do not hardcode runtime library paths], :, enable_rpath=yes) ]) dnl AC_LIB_FROMPACKAGE(name, package) dnl declares that libname comes from the given package. The configure file dnl will then not have a --with-libname-prefix option but a dnl --with-package-prefix option. Several libraries can come from the same dnl package. This declaration must occur before an AC_LIB_LINKFLAGS or similar dnl macro call that searches for libname. AC_DEFUN([AC_LIB_FROMPACKAGE], [ pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) define([acl_frompackage_]NAME, [$2]) popdef([NAME]) pushdef([PACK],[$2]) pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) define([acl_libsinpackage_]PACKUP, m4_ifdef([acl_libsinpackage_]PACKUP, [m4_defn([acl_libsinpackage_]PACKUP)[, ]],)[lib$1]) popdef([PACKUP]) popdef([PACK]) ]) dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and dnl the libraries corresponding to explicit and implicit dependencies. dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem. AC_DEFUN([AC_LIB_LINKFLAGS_BODY], [ AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) pushdef([NAME],[m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) pushdef([PACK],[m4_ifdef([acl_frompackage_]NAME, [acl_frompackage_]NAME, lib[$1])]) pushdef([PACKUP],[m4_translit(PACK,[abcdefghijklmnopqrstuvwxyz./+-], [ABCDEFGHIJKLMNOPQRSTUVWXYZ____])]) pushdef([PACKLIBS],[m4_ifdef([acl_frompackage_]NAME, [acl_libsinpackage_]PACKUP, lib[$1])]) dnl Autoconf >= 2.61 supports dots in --with options. pushdef([P_A_C_K],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[m4_translit(PACK,[.],[_])],PACK)]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_ARG_WITH(P_A_C_K[-prefix], [[ --with-]]P_A_C_K[[-prefix[=DIR] search for ]PACKLIBS[ in DIR/include and DIR/lib --without-]]P_A_C_K[[-prefix don't search for ]PACKLIBS[ in includedir and libdir]], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" if test "$acl_libdirstem2" != "$acl_libdirstem" \ && ! test -d "$withval/$acl_libdirstem"; then additional_libdir="$withval/$acl_libdirstem2" fi fi fi ]) dnl Search the library and its dependencies in $additional_libdir and dnl $LDFLAGS. Using breadth-first-seach. LIB[]NAME= LTLIB[]NAME= INC[]NAME= LIB[]NAME[]_PREFIX= dnl HAVE_LIB${NAME} is an indicator that LIB${NAME}, LTLIB${NAME} have been dnl computed. So it has to be reset here. HAVE_LIB[]NAME= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='$1 $2' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" dnl See if it was already located by an earlier AC_LIB_LINKFLAGS dnl or AC_LIB_HAVE_LINKFLAGS call. uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" else dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined dnl that this library doesn't exist. So just drop it. : fi else dnl Search the library lib$name in $additional_libdir and $LDFLAGS dnl and the already constructed $LIBNAME/$LTLIBNAME. found_dir= found_la= found_so= found_a= eval libname=\"$acl_libname_spec\" # typically: libname=lib$name if test -n "$acl_shlibext"; then shrext=".$acl_shlibext" # typically: shrext=.so else shrext= fi if test $use_additional = yes; then dir="$additional_libdir" dnl The same code as in the loop below: dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` dnl First look for a shared library. if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi dnl Then look for a static library. if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then dnl Found the library. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then dnl Linking with a shared library. We attempt to hardcode its dnl directory into the executable's runpath, unless it's the dnl standard /usr/lib. if test "$enable_rpath" = no \ || test "X$found_dir" = "X/usr/$acl_libdirstem" \ || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then dnl No hardcoding is needed. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl Use an explicit option to hardcode DIR into the resulting dnl binary. dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi dnl The hardcoding into $LIBNAME is system dependent. if test "$acl_hardcode_direct" = yes; then dnl Using DIR/libNAME.so during linking hardcodes DIR into the dnl resulting binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode DIR into the resulting dnl binary. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else dnl Rely on "-L$found_dir". dnl But don't add it if it's already contained in the LDFLAGS dnl or the already constructed $LIBNAME haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" fi if test "$acl_hardcode_minus_L" != no; then dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" else dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH dnl here, because this doesn't fit in flags passed to the dnl compiler. So give up. No hardcoding. This affects only dnl very old systems. dnl FIXME: Not sure whether we should use dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" dnl here. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then dnl Linking with a static library. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" else dnl We shouldn't come here, but anyway it's good to have a dnl fallback. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" fi fi dnl Assume the include files are nearby. additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` if test "$name" = '$1'; then LIB[]NAME[]_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; */$acl_libdirstem2 | */$acl_libdirstem2/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` if test "$name" = '$1'; then LIB[]NAME[]_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then dnl Potentially add $additional_includedir to $INCNAME. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's /usr/local/include and we are using GCC on Linux, dnl 3. if it's already present in $CPPFLAGS or the already dnl constructed $INCNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INC[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $INCNAME. INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" fi fi fi fi fi dnl Look for dependencies. if test -n "$found_la"; then dnl Read the .la file. It defines the variables dnl dlname, library_names, old_library, dependency_libs, current, dnl age, revision, installed, dlopen, dlpreopen, libdir. save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" dnl We use only dependency_libs. for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's /usr/local/lib and we are using GCC on Linux, dnl 3. if it's already present in $LDFLAGS or the already dnl constructed $LIBNAME, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LIBNAME. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIB[]NAME; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LTLIBNAME. LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then dnl Potentially add DIR to rpathdirs. dnl The rpathdirs will be appended to $LIBNAME at the end. haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi dnl Potentially add DIR to ltrpathdirs. dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) dnl Handle this in the next round. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) dnl Handle this in the next round. Throw away the .la's dnl directory; it is already contained in a preceding -L dnl option. names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) dnl Most likely an immediate library name. LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" ;; esac done fi else dnl Didn't find the library; assume it is in the system directories dnl known to the linker and runtime loader. (All the system dnl directories known to the linker should also be known to the dnl runtime loader, otherwise the system is severely misconfigured.) LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user must dnl pass all path elements in one option. We can arrange that for a dnl single library, but not when more than one $LIBNAMEs are used. alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" done dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl. acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" else dnl The -rpath options are cumulative. for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then dnl When using libtool, the option that works for both libraries and dnl executables is -R. The -R options are cumulative. for found_dir in $ltrpathdirs; do LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" done fi popdef([P_A_C_K]) popdef([PACKLIBS]) popdef([PACKUP]) popdef([PACK]) popdef([NAME]) ]) dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, dnl unless already present in VAR. dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes dnl contains two or three consecutive elements that belong together. AC_DEFUN([AC_LIB_APPENDTOVAR], [ for element in [$2]; do haveit= for x in $[$1]; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then [$1]="${[$1]}${[$1]:+ }$element" fi done ]) dnl For those cases where a variable contains several -L and -l options dnl referring to unknown libraries and directories, this macro determines the dnl necessary additional linker options for the runtime path. dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL]) dnl sets LDADDVAR to linker options needed together with LIBSVALUE. dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed, dnl otherwise linking without libtool is assumed. AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS], [ AC_REQUIRE([AC_LIB_RPATH]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) $1= if test "$enable_rpath" != no; then if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then dnl Use an explicit option to hardcode directories into the resulting dnl binary. rpathdirs= next= for opt in $2; do if test -n "$next"; then dir="$next" dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem" \ && test "X$dir" != "X/usr/$acl_libdirstem2"; then rpathdirs="$rpathdirs $dir" fi next= else case $opt in -L) next=yes ;; -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'` dnl No need to hardcode the standard /usr/lib. if test "X$dir" != "X/usr/$acl_libdirstem" \ && test "X$dir" != "X/usr/$acl_libdirstem2"; then rpathdirs="$rpathdirs $dir" fi next= ;; *) next= ;; esac fi done if test "X$rpathdirs" != "X"; then if test -n ""$3""; then dnl libtool is used for linking. Use -R options. for dir in $rpathdirs; do $1="${$1}${$1:+ }-R$dir" done else dnl The linker is used for linking directly. if test -n "$acl_hardcode_libdir_separator"; then dnl Weird platform: only the last -rpath option counts, the user dnl must pass all path elements in one option. alldirs= for dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="$flag" else dnl The -rpath options are cumulative. for dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" $1="${$1}${$1:+ }$flag" done fi fi fi fi fi AC_SUBST([$1]) ]) # lib-prefix.m4 serial 7 (gettext-0.18) dnl Copyright (C) 2001-2005, 2008-2014 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. dnl From Bruno Haible. dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't dnl require excessive bracketing. ifdef([AC_HELP_STRING], [AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], [AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed dnl to access previously installed libraries. The basic assumption is that dnl a user will want packages to use other packages he previously installed dnl with the same --prefix option. dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate dnl libraries, but is otherwise very convenient. AC_DEFUN([AC_LIB_PREFIX], [ AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_LIB_PREPARE_MULTILIB]) AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) dnl By default, look in $includedir and $libdir. use_additional=yes AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) AC_LIB_ARG_WITH([lib-prefix], [ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib --without-lib-prefix don't search for libraries in includedir and libdir], [ if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then AC_LIB_WITH_FINAL_PREFIX([ eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" ]) else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" fi fi ]) if test $use_additional = yes; then dnl Potentially add $additional_includedir to $CPPFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/include, dnl 2. if it's already present in $CPPFLAGS, dnl 3. if it's /usr/local/include and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_includedir" != "X/usr/include"; then haveit= for x in $CPPFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_includedir"; then dnl Really add $additional_includedir to $CPPFLAGS. CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" fi fi fi fi dnl Potentially add $additional_libdir to $LDFLAGS. dnl But don't add it dnl 1. if it's the standard /usr/lib, dnl 2. if it's already present in $LDFLAGS, dnl 3. if it's /usr/local/lib and we are using GCC on Linux, dnl 4. if it doesn't exist as a directory. if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then haveit= for x in $LDFLAGS; do AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then if test -n "$GCC"; then case $host_os in linux*) haveit=yes;; esac fi fi if test -z "$haveit"; then if test -d "$additional_libdir"; then dnl Really add $additional_libdir to $LDFLAGS. LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" fi fi fi fi fi ]) dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, dnl acl_final_exec_prefix, containing the values to which $prefix and dnl $exec_prefix will expand at the end of the configure script. AC_DEFUN([AC_LIB_PREPARE_PREFIX], [ dnl Unfortunately, prefix and exec_prefix get only finally determined dnl at the end of configure. if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" ]) dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the dnl variables prefix and exec_prefix bound to the values they will have dnl at the end of the configure script. AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], [ acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" $1 exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" ]) dnl AC_LIB_PREPARE_MULTILIB creates dnl - a variable acl_libdirstem, containing the basename of the libdir, either dnl "lib" or "lib64" or "lib/64", dnl - a variable acl_libdirstem2, as a secondary possible value for dnl acl_libdirstem, either the same as acl_libdirstem or "lib/sparcv9" or dnl "lib/amd64". AC_DEFUN([AC_LIB_PREPARE_MULTILIB], [ dnl There is no formal standard regarding lib and lib64. dnl On glibc systems, the current practice is that on a system supporting dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under dnl $prefix/lib64 and 32-bit libraries go under $prefix/lib. We determine dnl the compiler's default mode by looking at the compiler's library search dnl path. If at least one of its elements ends in /lib64 or points to a dnl directory whose absolute pathname ends in /lib64, we assume a 64-bit ABI. dnl Otherwise we use the default, namely "lib". dnl On Solaris systems, the current practice is that on a system supporting dnl 32-bit and 64-bit instruction sets or ABIs, 64-bit libraries go under dnl $prefix/lib/64 (which is a symlink to either $prefix/lib/sparcv9 or dnl $prefix/lib/amd64) and 32-bit libraries go under $prefix/lib. AC_REQUIRE([AC_CANONICAL_HOST]) acl_libdirstem=lib acl_libdirstem2= case "$host_os" in solaris*) dnl See Solaris 10 Software Developer Collection > Solaris 64-bit Developer's Guide > The Development Environment dnl . dnl "Portable Makefiles should refer to any library directories using the 64 symbolic link." dnl But we want to recognize the sparcv9 or amd64 subdirectory also if the dnl symlink is missing, so we set acl_libdirstem2 too. AC_CACHE_CHECK([for 64-bit host], [gl_cv_solaris_64bit], [AC_EGREP_CPP([sixtyfour bits], [ #ifdef _LP64 sixtyfour bits #endif ], [gl_cv_solaris_64bit=yes], [gl_cv_solaris_64bit=no]) ]) if test $gl_cv_solaris_64bit = yes; then acl_libdirstem=lib/64 case "$host_cpu" in sparc*) acl_libdirstem2=lib/sparcv9 ;; i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; esac fi ;; *) searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; */../ | */.. ) # Better ignore directories of this form. They are misleading. ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi ;; esac test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" ]) # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS # Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) # ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.14' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.14.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.14.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([acinclude.m4]) gateway-1.4.5/config.rpath0000644000175000017500000000000011156776565014202 0ustar toljtoljgateway-1.4.5/configure0000755000175000017500000232331413312227404013601 0ustar toljtolj#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="gw/alt_charsets.h" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS GSOAP_SHARE SOAP_INCLUDE SOAPCPP WSDL2H REDIS_CONFIG PGSQL_CONFIG SQLITE3 SQLITE SDB_CONFIG MYSQL_CONFIG OPENSSL BUILD_STARTSTOPDAEMON_FALSE BUILD_STARTSTOPDAEMON_TRUE SUFFIX DOCDRAFTS DOCSTARGET XML_DCL TEX_DSL HTML_DSL FIG2DEV DVIPS PDFJADETEX JADETEX JADE PCRE_CONFIG XML_CONFIG LIBOBJS LTLIBICONV LIBICONV SIZEOF_LONG_LONG SIZEOF_LONG SIZEOF_INT SIZEOF_SHORT OLD_LIBTOOL EXE_EXT PERL CONVERT LEXLIB LEX_OUTPUT_ROOT LEX YFLAGS YACC PKGADD_VENDOR PKGADD_NAME PKGADD_PKG CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM VERSION GW_VERSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_static enable_shared with_pic enable_fast_install enable_dependency_tracking with_gnu_ld with_sysroot enable_libtool_lock with_cflags with_libs enable_largefile enable_rpath with_libiconv_prefix enable_pcre enable_warnings enable_docs enable_drafts with_suffix enable_suffix with_defaults with_malloc enable_assertions enable_pam enable_debug enable_localtime enable_mutex_stats enable_cookies enable_keepalive enable_start_stop_daemon enable_wap enable_sms with_ssl enable_ssl enable_ssl_thread_test with_mysql with_mysql_dir with_sdb with_sqlite2 with_sqlite3 with_oracle with_oracle_includes with_oracle_libs with_pgsql with_pgsql_dir with_redis with_redis_dir with_mssql with_cassandra with_cassandra_dir with_wtls with_gsoap ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP YACC YFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-static[=PKGS] build static libraries [default=no] --enable-shared[=PKGS] build shared libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --disable-libtool-lock avoid locking (might break parallel builds) --disable-largefile omit support for large files --disable-rpath do not hardcode runtime library paths --enable-pcre enable PCRE regex support [disabled] --enable-warnings enable compilation warnings [disabled] --enable-docs enable building of documentation [enabled] --enable-drafts enable building of documentation drafts [disabled] --enable-suffix enable suffix for binaries [disabled] --disable-assertions turn off assertion checking --enable-pam enable PAM authentication [disabled] --enable-debug enable non-reentrant debugging for wmls compiler [disabled] --enable-localtime log file time stamps in local time, not GMT [enabled] --enable-mutex-stats produce information about lock contention --disable-cookies disable cookie support for WSP [enabled] --disable-keepalive disable HTTP/1.1 keep-alive support [enabled] --enable-start-stop-daemon compile/install the start-stop-daemon program [disabled] --disable-wap disables WAP gateway parts in bearerbox --disable-sms disables SMS gateway parts in bearerbox --enable-ssl enable SSL client and server support [enabled] --disable-ssl-thread-test disable the multithread test for the OpenSSL library this will force to continue even if the test fails Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-cflags=FLAGS use FLAGS for CFLAGS --with-libs=FLAGS use FLAGS for extra libraries --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib --without-libiconv-prefix don't search for libiconv in includedir and libdir --with-suffix=VERSION set suffix for binaries [foobox-VERSION] --with-defaults=OPTION set default configure options: speed/debug [speed] this will set assertion checking and malloc wrapper accordingly speed = native malloc + no assertions debug = checking malloc + assertions --with-malloc=OPTION select malloc wrapper to use: native/check/slow [native] --with-ssl=DIR where to look for OpenSSL libs and header files DIR points to the installation [/usr/local/ssl] --with-mysql enable MySQL storage [disabled] --with-mysql-dir=DIR where to look for MySQL libs and header files DIR points to the installation [/usr/local/mysql] --with-sdb enable LibSDB storage [disabled] --with-sqlite2 enable SQLite2 storage [disabled] --with-sqlite3 enable SQLite3 storage [disabled] --with-oracle enable ORACLE storage [disabled] --with-oracle-includes=DIR adds oracle include paths --with-oracle-libs=DIR adds oracle library path --with-pgsql enable PostgreSQL storage [disabled] --with-pgsql-dir=DIR where to look for PostgreSQL libs and header files DIR points to the installation [/usr/local/pgsql] --with-redis enable Redis storage [disabled] --with-redis-dir=DIR where to look for Redis libs and header files DIR points to the installation [/usr/local/redis] --with-mssql=DIR enable FreeTDS Ct-Lib storage support [disabled] DIR points to the installation [/usr/local] --with-cassandra enable Cassandra storage [disabled] --with-cassandra-dir=DIR where to look for Cassandra libs and header files DIR points to the installation [/usr/local] --with-wtls[=TYPE] select WTLS version to use: [openssl|baltimore] --with-gsoap[=DIR] enable gSOAP web services SMSC module support [disabled] DIR points to the gSOAP share directory [/usr/share/gsoap] Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor YACC The `Yet Another Compiler Compiler' implementation to use. Defaults to the first program found out of: `bison -y', `byacc', `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of `-d' given by some make applications. Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 &5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers gw-config.h" ac_aux_dir= for ac_dir in . "$srcdir"/.; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. case $TERM in xterm|xterm*|vt220|vt220*|cygwin) T_MD=`echo dummy | awk '{ printf("%c%c%c%c", 27, 91, 49, 109); }'` T_ME=`echo dummy | awk '{ printf("%c%c%c", 27, 91, 109); }'` ;; vt100|vt100*) T_MD=`echo dummy | awk '{ printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }'` T_ME=`echo dummy | awk '{ printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }'` ;; default) T_MD='' T_ME='' ;; esac test -f config.nice && mv config.nice config.nice.old rm -f config.nice.old cat >config.nice<> config.nice fi done for arg in $0 "$@"; do echo "'$arg' \\" >> config.nice done echo '"$@"' >> config.nice chmod +x config.nice VERSION=`head -n 1 VERSION` if test "x$VERSION" = "xsvn"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking svn checkout revision" >&5 $as_echo_n "checking svn checkout revision... " >&6; } if test -d ".svn" then revision=`svnversion .` test -z "$revision" && revision="unknown" SVN_REVISION="$revision" elif test -d ".git" then sha1=$(git rev-parse --short HEAD) mod=$(git status | grep "modified:\|added:\|deleted:" -q && echo "M") SVN_REVISION="$sha1$mod" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SVN_REVISION" >&5 $as_echo "$SVN_REVISION" >&6; } VERSION="$VERSION-r$SVN_REVISION" fi cat >>confdefs.h <<_ACEOF #define GW_NAME "Kannel" _ACEOF cat >>confdefs.h <<_ACEOF #define GW_VERSION "$VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF nl=' ' echo "${nl}${T_MD}Configuring for Kannel gateway version $VERSION ...${T_ME}" am__api_version='1.14' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE=Kannel VERSION=$VERSION cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=no fi case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: PKGADD_PKG="KANNELgateway" PKGADD_NAME="Kannel - WAP and SMS gateway" PKGADD_VENDOR="www.kannel.org" docdir='${prefix}/share/doc/kannel' nl=' ' echo "${nl}${T_MD}Running system checks ...${T_ME}" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; } if ${ac_cv_prog_cc_c99+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy. static void test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str; int number; float fnumber; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. test_varargs ("s, d' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c99" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 $as_echo "$ac_cv_prog_cc_c99" >&6; } ;; esac if test "x$ac_cv_prog_cc_c99" != xno; then : fi if test "$ac_cv_prog_cc_c99" = "no"; then as_fn_error $? "\"Kannel requires a C compiler that supports ISO C99.\"" "$LINENO" 5 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_YACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 $as_echo "$YACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 $as_echo "$LEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then cat >conftest.l <<_ACEOF %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ yyless ((input () != 0)); } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% #ifdef YYTEXT_POINTER extern char *yytext; #endif int main (void) { return ! yylex () + ! yywrap (); } _ACEOF { { ac_try="$LEX conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 $as_echo_n "checking lex output file root... " >&6; } if ${ac_cv_prog_lex_root+:} false; then : $as_echo_n "(cached) " >&6 else if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 $as_echo "$ac_cv_prog_lex_root" >&6; } LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test -z "${LEXLIB+set}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 $as_echo_n "checking lex library... " >&6; } if ${ac_cv_lib_lex+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS=$LIBS ac_cv_lib_lex='none needed' for ac_lib in '' -lfl -ll; do LIBS="$ac_lib $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_lex=$ac_lib fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext test "$ac_cv_lib_lex" != 'none needed' && break done LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 $as_echo "$ac_cv_lib_lex" >&6; } test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 $as_echo_n "checking whether yytext is a pointer... " >&6; } if ${ac_cv_prog_lex_yytext_pointer+:} false; then : $as_echo_n "(cached) " >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no ac_save_LIBS=$LIBS LIBS="$LEXLIB $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 $as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then $as_echo "#define YYTEXT_POINTER 1" >>confdefs.h fi rm -f conftest.l $LEX_OUTPUT_ROOT.c fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi # Extract the first word of "convert", so it can be a program name with args. set dummy convert; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_CONVERT+:} false; then : $as_echo_n "(cached) " >&6 else case $CONVERT in [\\/]* | ?:[\\/]*) ac_cv_path_CONVERT="$CONVERT" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_CONVERT="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CONVERT=$ac_cv_path_CONVERT if test -n "$CONVERT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CONVERT" >&5 $as_echo "$CONVERT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PERL+:} false; then : $as_echo_n "(cached) " >&6 else case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 $as_echo "$PERL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi EXE_EXT="" OLD_LIBTOOL="$AR rc" case "$host" in *-sun-solaris*) CFLAGS="$CFLAGS -DSunOS=1" ;; *-cygwin*) EXE_EXT=".exe" LDFLAGS="$LDFLAGS -Wl,--enable-auto-import" ;; *apple-darwin*) # MacOS X # Lets try to find the newest installed SDK for compilation # so we know how to link against it. # If we find a SDK, we use that rather then the standard /usr # location libs and includes. found=0 SDK="" for loc in "MacOSX10.7.sdk" "MacOSX10.6.sdk" "MacOSX10.5.sdk" "MacOSX10.4u.sdk" "MacOSX10.4.0.sdk" "MacOSX10.3.9.sdk" \ "MacOSX10.3.0.sdk" "MacOSX10.2.8.sdk" "MacOSX10.1.5.sdk" do if test "$found" = "0" ; then if test -d "/Developer/SDKs/${E}" ; then found="1" SDK="${loc}" fi fi done if test "$SDK" != "" ; then CFLAGS="$CFLAGS -DDARWIN=1 -L/Developer/SDKs/${SDK}/usr/lib -I/Developer/SDKs/${SDK}/usr/include" else CFLAGS="$CFLAGS -DDARWIN=1" fi OLD_LIBTOOL="libtool -static -o" ;; *-linux-*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE" LDFLAGS="$LDFLAGS -rdynamic" ;; *-*-openbsd* | *-*-freebsd*) CFLAGS="$CFLAGS -pthread" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_exit in -lpthread" >&5 $as_echo_n "checking for pthread_exit in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_exit+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_exit (); int main () { return pthread_exit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_exit=yes else ac_cv_lib_pthread_pthread_exit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_exit" >&5 $as_echo "$ac_cv_lib_pthread_pthread_exit" >&6; } if test "x$ac_cv_lib_pthread_pthread_exit" = xyes; then : LIBS="$LIBS -lpthread"; pthread="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_exit in -lc_r" >&5 $as_echo_n "checking for pthread_exit in -lc_r... " >&6; } if ${ac_cv_lib_c_r_pthread_exit+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_exit (); int main () { return pthread_exit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_r_pthread_exit=yes else ac_cv_lib_c_r_pthread_exit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_exit" >&5 $as_echo "$ac_cv_lib_c_r_pthread_exit" >&6; } if test "x$ac_cv_lib_c_r_pthread_exit" = xyes; then : LIBS="$LIBS -lc_r"; pthread="yes" fi fi ;; *-interix3*) INSTALL="./install-sh" ;; esac # Check whether --with-cflags was given. if test "${with_cflags+set}" = set; then : withval=$with_cflags; CFLAGS="$CFLAGS $withval" fi # Check whether --with-libs was given. if test "${with_libs+set}" = set; then : withval=$with_libs; LIBS="$LIBS $withval" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi if test "${ac_cv_sys_file_offset_bits}" != no ; then CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=${ac_cv_sys_file_offset_bits}" fi if test "${ac_cv_sys_large_files}" != no ; then CFLAGS="$CFLAGS -D_LARGE_FILES=${ac_cv_sys_large_files}" fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 $as_echo_n "checking size of short... " >&6; } if ${ac_cv_sizeof_short+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : else if test "$ac_cv_type_short" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (short) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_short=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 $as_echo "$ac_cv_sizeof_short" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_SHORT $ac_cv_sizeof_short _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 $as_echo_n "checking size of int... " >&6; } if ${ac_cv_sizeof_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : else if test "$ac_cv_type_int" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 $as_echo "$ac_cv_sizeof_int" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT $ac_cv_sizeof_int _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 $as_echo_n "checking size of long... " >&6; } if ${ac_cv_sizeof_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : else if test "$ac_cv_type_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 $as_echo "$ac_cv_sizeof_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG $ac_cv_sizeof_long _ACEOF # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 $as_echo_n "checking size of long long... " >&6; } if ${ac_cv_sizeof_long_long+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : else if test "$ac_cv_type_long_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (long long) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_long=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 $as_echo "$ac_cv_sizeof_long_long" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long _ACEOF SIZEOF_SHORT=$ac_cv_sizeof_short SIZEOF_INT=$ac_cv_sizeof_int SIZEOF_LONG=$ac_cv_sizeof_long SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log in -lm" >&5 $as_echo_n "checking for log in -lm... " >&6; } if ${ac_cv_lib_m_log+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char log (); int main () { return log (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_m_log=yes else ac_cv_lib_m_log=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_log" >&5 $as_echo "$ac_cv_lib_m_log" >&6; } if test "x$ac_cv_lib_m_log" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for accept in -lsocket" >&5 $as_echo_n "checking for accept in -lsocket... " >&6; } if ${ac_cv_lib_socket_accept+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char accept (); int main () { return accept (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_accept=yes else ac_cv_lib_socket_accept=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_accept" >&5 $as_echo "$ac_cv_lib_socket_accept" >&6; } if test "x$ac_cv_lib_socket_accept" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnsl" >&5 $as_echo_n "checking for inet_ntoa in -lnsl... " >&6; } if ${ac_cv_lib_nsl_inet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntoa (); int main () { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_inet_ntoa=yes else ac_cv_lib_nsl_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_inet_ntoa" >&5 $as_echo "$ac_cv_lib_nsl_inet_ntoa" >&6; } if test "x$ac_cv_lib_nsl_inet_ntoa" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntop in -lresolv" >&5 $as_echo_n "checking for inet_ntop in -lresolv... " >&6; } if ${ac_cv_lib_resolv_inet_ntop+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lresolv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntop (); int main () { return inet_ntop (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_resolv_inet_ntop=yes else ac_cv_lib_resolv_inet_ntop=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_inet_ntop" >&5 $as_echo "$ac_cv_lib_resolv_inet_ntop" >&6; } if test "x$ac_cv_lib_resolv_inet_ntop" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF LIBS="-lresolv $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntop in -lbind" >&5 $as_echo_n "checking for inet_ntop in -lbind... " >&6; } if ${ac_cv_lib_bind_inet_ntop+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbind $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_ntop (); int main () { return inet_ntop (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bind_inet_ntop=yes else ac_cv_lib_bind_inet_ntop=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bind_inet_ntop" >&5 $as_echo "$ac_cv_lib_bind_inet_ntop" >&6; } if test "x$ac_cv_lib_bind_inet_ntop" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBBIND 1 _ACEOF LIBS="-lbind $LIBS" fi if test -z "$pthread"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_exit in -lpthread" >&5 $as_echo_n "checking for pthread_exit in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_exit+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_exit (); int main () { return pthread_exit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_exit=yes else ac_cv_lib_pthread_pthread_exit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_exit" >&5 $as_echo "$ac_cv_lib_pthread_pthread_exit" >&6; } if test "x$ac_cv_lib_pthread_pthread_exit" = xyes; then : LIBS="$LIBS -lpthread" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libiconv in -liconv" >&5 $as_echo_n "checking for libiconv in -liconv... " >&6; } if ${ac_cv_lib_iconv_libiconv+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-liconv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char libiconv (); int main () { return libiconv (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_iconv_libiconv=yes else ac_cv_lib_iconv_libiconv=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iconv_libiconv" >&5 $as_echo "$ac_cv_lib_iconv_libiconv" >&6; } if test "x$ac_cv_lib_iconv_libiconv" = xyes; then : LIBS="$LIBS -liconv" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi for ac_header in sys/ioctl.h sys/time.h sys/types.h unistd.h sys/poll.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in pthread.h getopt.h syslog.h zlib.h execinfo.h stdlib.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in sys/socket.h sys/sockio.h netinet/in.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in net/if.h do : ac_fn_c_check_header_compile "$LINENO" "net/if.h" "ac_cv_header_net_if_h" "#include #if STDC_HEADERS # include # include #else #if HAVE_STDLIB_H # include # endif #endif #if HAVE_SYS_SOCKET_H # include #endif " if test "x$ac_cv_header_net_if_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NET_IF_H 1 _ACEOF fi done for ac_header in sys/ucontext.h do : ac_fn_c_check_header_mongrel "$LINENO" "sys/ucontext.h" "ac_cv_header_sys_ucontext_h" "$ac_includes_default" if test "x$ac_cv_header_sys_ucontext_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYS_UCONTEXT_H 1 _ACEOF $as_echo "#define HAVE_UCONTEXT 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: System lacks ucontext.h - user context support" >&5 $as_echo "$as_me: WARNING: System lacks ucontext.h - user context support" >&2;} fi done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { char *func = __FUNCTION__; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE___FUNCTION__ 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { char *func = __func__; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE___FUNC__ 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "X$prefix" = "XNONE"; then acl_final_prefix="$ac_default_prefix" else acl_final_prefix="$prefix" fi if test "X$exec_prefix" = "XNONE"; then acl_final_exec_prefix='${prefix}' else acl_final_exec_prefix="$exec_prefix" fi acl_save_prefix="$prefix" prefix="$acl_final_prefix" eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" prefix="$acl_save_prefix" # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi # Prepare PATH_SEPARATOR. # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then # Determine PATH_SEPARATOR by trying to find /bin/sh in a PATH which # contains only /bin. Note that ksh looks also at the FPATH variable, # so we have to set that as well for the test. PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 \ || PATH_SEPARATOR=';' } fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo "$ac_prog"| sed 's%\\\\%/%g'` while echo "$ac_prog" | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${acl_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then acl_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$acl_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then acl_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$acl_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${acl_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$acl_cv_prog_gnu_ld" >&6; } with_gnu_ld=$acl_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 $as_echo_n "checking for shared library run path origin... " >&6; } if ${acl_cv_rpath+:} false; then : $as_echo_n "(cached) " >&6 else CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 $as_echo "$acl_cv_rpath" >&6; } wl="$acl_cv_wl" acl_libext="$acl_cv_libext" acl_shlibext="$acl_cv_shlibext" acl_libname_spec="$acl_cv_libname_spec" acl_library_names_spec="$acl_cv_library_names_spec" acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" acl_hardcode_direct="$acl_cv_hardcode_direct" acl_hardcode_minus_L="$acl_cv_hardcode_minus_L" # Check whether --enable-rpath was given. if test "${enable_rpath+set}" = set; then : enableval=$enable_rpath; : else enable_rpath=yes fi acl_libdirstem=lib acl_libdirstem2= case "$host_os" in solaris*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit host" >&5 $as_echo_n "checking for 64-bit host... " >&6; } if ${gl_cv_solaris_64bit+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef _LP64 sixtyfour bits #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "sixtyfour bits" >/dev/null 2>&1; then : gl_cv_solaris_64bit=yes else gl_cv_solaris_64bit=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_solaris_64bit" >&5 $as_echo "$gl_cv_solaris_64bit" >&6; } if test $gl_cv_solaris_64bit = yes; then acl_libdirstem=lib/64 case "$host_cpu" in sparc*) acl_libdirstem2=lib/sparcv9 ;; i*86 | x86_64) acl_libdirstem2=lib/amd64 ;; esac fi ;; *) searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'` if test -n "$searchpath"; then acl_save_IFS="${IFS= }"; IFS=":" for searchdir in $searchpath; do if test -d "$searchdir"; then case "$searchdir" in */lib64/ | */lib64 ) acl_libdirstem=lib64 ;; */../ | */.. ) # Better ignore directories of this form. They are misleading. ;; *) searchdir=`cd "$searchdir" && pwd` case "$searchdir" in */lib64 ) acl_libdirstem=lib64 ;; esac ;; esac fi done IFS="$acl_save_IFS" fi ;; esac test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" use_additional=yes acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" # Check whether --with-libiconv-prefix was given. if test "${with_libiconv_prefix+set}" = set; then : withval=$with_libiconv_prefix; if test "X$withval" = "Xno"; then use_additional=no else if test "X$withval" = "X"; then acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval additional_includedir=\"$includedir\" eval additional_libdir=\"$libdir\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" else additional_includedir="$withval/include" additional_libdir="$withval/$acl_libdirstem" if test "$acl_libdirstem2" != "$acl_libdirstem" \ && ! test -d "$withval/$acl_libdirstem"; then additional_libdir="$withval/$acl_libdirstem2" fi fi fi fi LIBICONV= LTLIBICONV= INCICONV= LIBICONV_PREFIX= HAVE_LIBICONV= rpathdirs= ltrpathdirs= names_already_handled= names_next_round='iconv ' while test -n "$names_next_round"; do names_this_round="$names_next_round" names_next_round= for name in $names_this_round; do already_handled= for n in $names_already_handled; do if test "$n" = "$name"; then already_handled=yes break fi done if test -z "$already_handled"; then names_already_handled="$names_already_handled $name" uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./+-|ABCDEFGHIJKLMNOPQRSTUVWXYZ____|'` eval value=\"\$HAVE_LIB$uppername\" if test -n "$value"; then if test "$value" = yes; then eval value=\"\$LIB$uppername\" test -z "$value" || LIBICONV="${LIBICONV}${LIBICONV:+ }$value" eval value=\"\$LTLIB$uppername\" test -z "$value" || LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$value" else : fi else found_dir= found_la= found_so= found_a= eval libname=\"$acl_libname_spec\" # typically: libname=lib$name if test -n "$acl_shlibext"; then shrext=".$acl_shlibext" # typically: shrext=.so else shrext= fi if test $use_additional = yes; then dir="$additional_libdir" if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi fi if test "X$found_dir" = "X"; then for x in $LDFLAGS $LTLIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" case "$x" in -L*) dir=`echo "X$x" | sed -e 's/^X-L//'` if test -n "$acl_shlibext"; then if test -f "$dir/$libname$shrext"; then found_dir="$dir" found_so="$dir/$libname$shrext" else if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then ver=`(cd "$dir" && \ for f in "$libname$shrext".*; do echo "$f"; done \ | sed -e "s,^$libname$shrext\\\\.,," \ | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \ | sed 1q ) 2>/dev/null` if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then found_dir="$dir" found_so="$dir/$libname$shrext.$ver" fi else eval library_names=\"$acl_library_names_spec\" for f in $library_names; do if test -f "$dir/$f"; then found_dir="$dir" found_so="$dir/$f" break fi done fi fi fi if test "X$found_dir" = "X"; then if test -f "$dir/$libname.$acl_libext"; then found_dir="$dir" found_a="$dir/$libname.$acl_libext" fi fi if test "X$found_dir" != "X"; then if test -f "$dir/$libname.la"; then found_la="$dir/$libname.la" fi fi ;; esac if test "X$found_dir" != "X"; then break fi done fi if test "X$found_dir" != "X"; then LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$found_dir -l$name" if test "X$found_so" != "X"; then if test "$enable_rpath" = no \ || test "X$found_dir" = "X/usr/$acl_libdirstem" \ || test "X$found_dir" = "X/usr/$acl_libdirstem2"; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else haveit= for x in $ltrpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $found_dir" fi if test "$acl_hardcode_direct" = yes; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" haveit= for x in $rpathdirs; do if test "X$x" = "X$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $found_dir" fi else haveit= for x in $LDFLAGS $LIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$found_dir"; then haveit=yes break fi done if test -z "$haveit"; then LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir" fi if test "$acl_hardcode_minus_L" != no; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_so" else LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" fi fi fi fi else if test "X$found_a" != "X"; then LIBICONV="${LIBICONV}${LIBICONV:+ }$found_a" else LIBICONV="${LIBICONV}${LIBICONV:+ }-L$found_dir -l$name" fi fi additional_includedir= case "$found_dir" in */$acl_libdirstem | */$acl_libdirstem/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'` if test "$name" = 'iconv'; then LIBICONV_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; */$acl_libdirstem2 | */$acl_libdirstem2/) basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem2/"'*$,,'` if test "$name" = 'iconv'; then LIBICONV_PREFIX="$basedir" fi additional_includedir="$basedir/include" ;; esac if test "X$additional_includedir" != "X"; then if test "X$additional_includedir" != "X/usr/include"; then haveit= if test "X$additional_includedir" = "X/usr/local/include"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then for x in $CPPFLAGS $INCICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-I$additional_includedir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_includedir"; then INCICONV="${INCICONV}${INCICONV:+ }-I$additional_includedir" fi fi fi fi fi if test -n "$found_la"; then save_libdir="$libdir" case "$found_la" in */* | *\\*) . "$found_la" ;; *) . "./$found_la" ;; esac libdir="$save_libdir" for dep in $dependency_libs; do case "$dep" in -L*) additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` if test "X$additional_libdir" != "X/usr/$acl_libdirstem" \ && test "X$additional_libdir" != "X/usr/$acl_libdirstem2"; then haveit= if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem" \ || test "X$additional_libdir" = "X/usr/local/$acl_libdirstem2"; then if test -n "$GCC"; then case $host_os in linux* | gnu* | k*bsd*-gnu) haveit=yes;; esac fi fi if test -z "$haveit"; then haveit= for x in $LDFLAGS $LIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LIBICONV="${LIBICONV}${LIBICONV:+ }-L$additional_libdir" fi fi haveit= for x in $LDFLAGS $LTLIBICONV; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X-L$additional_libdir"; then haveit=yes break fi done if test -z "$haveit"; then if test -d "$additional_libdir"; then LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-L$additional_libdir" fi fi fi fi ;; -R*) dir=`echo "X$dep" | sed -e 's/^X-R//'` if test "$enable_rpath" != no; then haveit= for x in $rpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then rpathdirs="$rpathdirs $dir" fi haveit= for x in $ltrpathdirs; do if test "X$x" = "X$dir"; then haveit=yes break fi done if test -z "$haveit"; then ltrpathdirs="$ltrpathdirs $dir" fi fi ;; -l*) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` ;; *.la) names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` ;; *) LIBICONV="${LIBICONV}${LIBICONV:+ }$dep" LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }$dep" ;; esac done fi else LIBICONV="${LIBICONV}${LIBICONV:+ }-l$name" LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-l$name" fi fi fi done done if test "X$rpathdirs" != "X"; then if test -n "$acl_hardcode_libdir_separator"; then alldirs= for found_dir in $rpathdirs; do alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir" done acl_save_libdir="$libdir" libdir="$alldirs" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" else for found_dir in $rpathdirs; do acl_save_libdir="$libdir" libdir="$found_dir" eval flag=\"$acl_hardcode_libdir_flag_spec\" libdir="$acl_save_libdir" LIBICONV="${LIBICONV}${LIBICONV:+ }$flag" done fi fi if test "X$ltrpathdirs" != "X"; then for found_dir in $ltrpathdirs; do LTLIBICONV="${LTLIBICONV}${LTLIBICONV:+ }-R$found_dir" done fi am_save_CPPFLAGS="$CPPFLAGS" for element in $INCICONV; do haveit= for x in $CPPFLAGS; do acl_save_prefix="$prefix" prefix="$acl_final_prefix" acl_save_exec_prefix="$exec_prefix" exec_prefix="$acl_final_exec_prefix" eval x=\"$x\" exec_prefix="$acl_save_exec_prefix" prefix="$acl_save_prefix" if test "X$x" = "X$element"; then haveit=yes break fi done if test -z "$haveit"; then CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element" fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 $as_echo_n "checking for iconv... " >&6; } if ${am_cv_func_iconv+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$am_cv_func_iconv" != yes; then am_save_LIBS="$LIBS" LIBS="$LIBS $LIBICONV" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { iconv_t cd = iconv_open("",""); iconv(cd,NULL,NULL,NULL,NULL); iconv_close(cd); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : am_cv_lib_iconv=yes am_cv_func_iconv=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$am_save_LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 $as_echo "$am_cv_func_iconv" >&6; } if test "$am_cv_func_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working iconv" >&5 $as_echo_n "checking for working iconv... " >&6; } if ${am_cv_func_iconv_works+:} false; then : $as_echo_n "(cached) " >&6 else am_save_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" fi if test "$cross_compiling" = yes; then : case "$host_os" in aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; *) am_cv_func_iconv_works="guessing yes" ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { int result = 0; /* Test against AIX 5.1 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8"); if (cd_utf8_to_88591 != (iconv_t)(-1)) { static const char input[] = "\342\202\254"; /* EURO SIGN */ char buf[10]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_utf8_to_88591, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 1; iconv_close (cd_utf8_to_88591); } } /* Test against Solaris 10 bug: Failures are not distinguishable from successful returns. */ { iconv_t cd_ascii_to_88591 = iconv_open ("ISO8859-1", "646"); if (cd_ascii_to_88591 != (iconv_t)(-1)) { static const char input[] = "\263"; char buf[10]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_ascii_to_88591, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res == 0) result |= 2; iconv_close (cd_ascii_to_88591); } } /* Test against AIX 6.1..7.1 bug: Buffer overrun. */ { iconv_t cd_88591_to_utf8 = iconv_open ("UTF-8", "ISO-8859-1"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static const char input[] = "\304"; static char buf[2] = { (char)0xDE, (char)0xAD }; const char *inptr = input; size_t inbytesleft = 1; char *outptr = buf; size_t outbytesleft = 1; size_t res = iconv (cd_88591_to_utf8, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if (res != (size_t)(-1) || outptr - buf > 1 || buf[1] != (char)0xAD) result |= 4; iconv_close (cd_88591_to_utf8); } } #if 0 /* This bug could be worked around by the caller. */ /* Test against HP-UX 11.11 bug: Positive return value instead of 0. */ { iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591"); if (cd_88591_to_utf8 != (iconv_t)(-1)) { static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337"; char buf[50]; const char *inptr = input; size_t inbytesleft = strlen (input); char *outptr = buf; size_t outbytesleft = sizeof (buf); size_t res = iconv (cd_88591_to_utf8, (char **) &inptr, &inbytesleft, &outptr, &outbytesleft); if ((int)res > 0) result |= 8; iconv_close (cd_88591_to_utf8); } } #endif /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is provided. */ if (/* Try standardized names. */ iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1) /* Try IRIX, OSF/1 names. */ && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1) /* Try AIX names. */ && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1) /* Try HP-UX names. */ && iconv_open ("utf8", "eucJP") == (iconv_t)(-1)) result |= 16; return result; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : am_cv_func_iconv_works=yes else am_cv_func_iconv_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi LIBS="$am_save_LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv_works" >&5 $as_echo "$am_cv_func_iconv_works" >&6; } case "$am_cv_func_iconv_works" in *no) am_func_iconv=no am_cv_lib_iconv=no ;; *) am_func_iconv=yes ;; esac else am_func_iconv=no am_cv_lib_iconv=no fi if test "$am_func_iconv" = yes; then $as_echo "#define HAVE_ICONV 1" >>confdefs.h fi if test "$am_cv_lib_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 $as_echo_n "checking how to link with libiconv... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 $as_echo "$LIBICONV" >&6; } else CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= LTLIBICONV= fi if test "$am_cv_func_iconv" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv declaration" >&5 $as_echo_n "checking for iconv declaration... " >&6; } if ${am_cv_proto_iconv+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include extern #ifdef __cplusplus "C" #endif #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft); #else size_t iconv(); #endif int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : am_cv_proto_iconv_arg1="" else am_cv_proto_iconv_arg1="const" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);" fi am_cv_proto_iconv=`echo "$am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_proto_iconv" >&5 $as_echo " $am_cv_proto_iconv" >&6; } cat >>confdefs.h <<_ACEOF #define ICONV_CONST $am_cv_proto_iconv_arg1 _ACEOF fi for ac_func in gettimeofday select socket strdup getopt_long localtime_r gmtime_r backtrace srandom initgroups strtoll strtoq do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_func "$LINENO" "getopt" "ac_cv_func_getopt" if test "x$ac_cv_func_getopt" = xyes; then : else case " $LIBOBJS " in *" utils/attgetopt.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS utils/attgetopt.$ac_objext" ;; esac fi ac_fn_c_check_func "$LINENO" "gethostbyname_r" "ac_cv_func_gethostbyname_r" if test "x$ac_cv_func_gethostbyname_r" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for which type of gethostbyname_r" >&5 $as_echo_n "checking for which type of gethostbyname_r... " >&6; } if ${ac_cv_func_which_gethostname_r+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *name; struct hostent *he; struct hostent_data data; (void) gethostbyname_r(name, he, &data); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_which_gethostname_r=3 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *name; struct hostent *he, *res; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_which_gethostname_r=6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *name; struct hostent *he; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &h_errnop); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_func_which_gethostname_r=5 else ac_cv_func_which_gethostname_r=0 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_which_gethostname_r" >&5 $as_echo "$ac_cv_func_which_gethostname_r" >&6; } if test $ac_cv_func_which_gethostname_r -eq 6; then $as_echo "#define HAVE_FUNC_GETHOSTBYNAME_R_6 1" >>confdefs.h elif test $ac_cv_func_which_gethostname_r -eq 5; then $as_echo "#define HAVE_FUNC_GETHOSTBYNAME_R_5 1" >>confdefs.h elif test $ac_cv_func_which_gethostname_r -eq 3; then $as_echo "#define HAVE_FUNC_GETHOSTBYNAME_R_3 1" >>confdefs.h elif test $ac_cv_func_which_gethostname_r -eq 0; then ac_cv_func_which_gethostname_r = no fi else ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = xyes; then : else as_fn_error $? "Couldnot find gethostbyname_r nor gethostbyname functions" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socklen_t in " >&5 $as_echo_n "checking for socklen_t in ... " >&6; } if ${gw_cv_type_HAVE_SOCKLEN_T+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef HAVE_SYS_TYPES_H #include #endif #include int main () { socklen_t foo; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : gw_cv_type_HAVE_SOCKLEN_T=yes else gw_cv_type_HAVE_SOCKLEN_T=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_cv_type_HAVE_SOCKLEN_T" >&5 $as_echo "$gw_cv_type_HAVE_SOCKLEN_T" >&6; } if test $gw_cv_type_HAVE_SOCKLEN_T = yes; then $as_echo "#define HAVE_SOCKLEN_T 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getopt in " >&5 $as_echo_n "checking for getopt in ... " >&6; } if ${gw_cv_func_HAVE_GETOPT_IN_STDIO_H+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { void *foo = getopt; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : gw_cv_func_HAVE_GETOPT_IN_STDIO_H=yes else gw_cv_func_HAVE_GETOPT_IN_STDIO_H=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_cv_func_HAVE_GETOPT_IN_STDIO_H" >&5 $as_echo "$gw_cv_func_HAVE_GETOPT_IN_STDIO_H" >&6; } if test $gw_cv_func_HAVE_GETOPT_IN_STDIO_H = yes; then $as_echo "#define HAVE_GETOPT_IN_STDIO_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getopt in " >&5 $as_echo_n "checking for getopt in ... " >&6; } if ${gw_cv_func_HAVE_GETOPT_IN_UNISTD_H+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { void *foo = getopt; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : gw_cv_func_HAVE_GETOPT_IN_UNISTD_H=yes else gw_cv_func_HAVE_GETOPT_IN_UNISTD_H=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_cv_func_HAVE_GETOPT_IN_UNISTD_H" >&5 $as_echo "$gw_cv_func_HAVE_GETOPT_IN_UNISTD_H" >&6; } if test $gw_cv_func_HAVE_GETOPT_IN_UNISTD_H = yes; then $as_echo "#define HAVE_GETOPT_IN_UNISTD_H 1" >>confdefs.h fi for ac_header in ftw.h do : ac_fn_c_check_header_mongrel "$LINENO" "ftw.h" "ac_cv_header_ftw_h" "$ac_includes_default" if test "x$ac_cv_header_ftw_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FTW_H 1 _ACEOF ac_fn_c_check_func "$LINENO" "nftw" "ac_cv_func_nftw" if test "x$ac_cv_func_nftw" = xyes; then : $as_echo "#define HAVE_NFTW 1" >>confdefs.h fi fi done for ac_header in regex.h do : ac_fn_c_check_header_mongrel "$LINENO" "regex.h" "ac_cv_header_regex_h" "$ac_includes_default" if test "x$ac_cv_header_regex_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_REGEX_H 1 _ACEOF ac_fn_c_check_func "$LINENO" "regcomp" "ac_cv_func_regcomp" if test "x$ac_cv_func_regcomp" = xyes; then : $as_echo "#define HAVE_REGEX 1" >>confdefs.h has_posix_regex=1 fi fi done nl=' ' echo "${nl}${T_MD}Checking for POSIX threads support ...${T_ME}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working pthreads" >&5 $as_echo_n "checking for working pthreads... " >&6; } if test "$cross_compiling" = yes; then : echo Cross compiling - assuming they work else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int pid; void testpid(void* foo); int main(void){ pthread_t child; pid=getpid(); pthread_create(&child,NULL,(void*)testpid,NULL); pthread_join(child,NULL); return 0; } void testpid(void* foo){ int mypid=getpid(); if(mypid!=pid){ /* Pthreads states that all threads should have the same PID * we dont! */ exit(1); }else{ exit(0); } } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo yes else echo no ;CFLAGS="$CFLAGS -DBROKEN_PTHREADS=1" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_spinlock support" >&5 $as_echo_n "checking for pthread_spinlock support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifdef __INTERIX /* * interix has experimental spinlock support and this doesn't work very well * therefore disable it for now */ pthread_spinlock_t_failed lock; #else pthread_spinlock_t lock; #endif pthread_spin_init(&lock, 0); pthread_spin_lock(&lock); pthread_spin_unlock(&lock); pthread_spin_destroy(&lock); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; $as_echo "#define HAVE_PTHREAD_SPINLOCK_T 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_rwlock support" >&5 $as_echo_n "checking for pthread_rwlock support... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { pthread_rwlock_t lock; pthread_rwlock_init(&lock, NULL); pthread_rwlock_rdlock(&lock); pthread_rwlock_unlock(&lock); pthread_rwlock_wrlock(&lock); pthread_rwlock_unlock(&lock); pthread_rwlock_destroy(&lock); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; $as_echo "#define HAVE_PTHREAD_RWLOCK 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sem_init in -lrt" >&5 $as_echo_n "checking for sem_init in -lrt... " >&6; } if ${ac_cv_lib_rt_sem_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sem_init (); int main () { return sem_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_rt_sem_init=yes else ac_cv_lib_rt_sem_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sem_init" >&5 $as_echo "$ac_cv_lib_rt_sem_init" >&6; } if test "x$ac_cv_lib_rt_sem_init" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRT 1 _ACEOF LIBS="-lrt $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for semaphore support" >&5 $as_echo_n "checking for semaphore support... " >&6; } if test "$cross_compiling" = yes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: Cross compiling - assuming suuported" >&5 $as_echo "Cross compiling - assuming suuported" >&6; } ; $as_echo "#define HAVE_SEMAPHORE 1" >>confdefs.h else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main(void) { sem_t s; int val; /* DARWNIN doesn't implement native sem_init */ if (sem_init(&s, 0, 1) != 0) return 1; sem_wait(&s); sem_post(&s); sem_getvalue(&s, &val); sem_destroy(&s); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; $as_echo "#define HAVE_SEMAPHORE 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi nl=' ' echo "${nl}${T_MD}Checking for libxml2 support ...${T_ME}" xml_ver_required="2.6.0" for ac_prog in xml2-config xml-config do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_XML_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $XML_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_XML_CONFIG="$XML_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_XML_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi XML_CONFIG=$ac_cv_path_XML_CONFIG if test -n "$XML_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XML_CONFIG" >&5 $as_echo "$XML_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$XML_CONFIG" && break done test -n "$XML_CONFIG" || XML_CONFIG="no" if test "$XML_CONFIG" = "no"; then as_fn_error $? "You MUST have the libxml2 (aka gnome-xml) library installed" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: checking libxml version" >&5 $as_echo_n "checking libxml version... " >&6; } xml_version=`$XML_CONFIG --version` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xml_version" >&5 $as_echo "$xml_version" >&6; } ac_inst_ver_maj=`echo $xml_version | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_inst_ver_mid=`echo $xml_version | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_inst_ver_min=`echo $xml_version | sed -e 's/^.*\..*\.\(.*\)$/\1/'` ac_req_ver_maj=`echo $xml_ver_required | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_req_ver_mid=`echo $xml_ver_required | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_req_ver_min=`echo $xml_ver_required | sed -e 's/^.*\..*\.\(.*\)$/\1/'` if test "$ac_inst_ver_maj" -lt "$ac_req_ver_maj" || \ ( test "$ac_inst_ver_maj" -eq "$ac_req_ver_maj" && \ test "$ac_inst_ver_mid" -lt "$ac_req_ver_mid" ) || \ ( test "$ac_inst_ver_mid" -eq "$ac_req_ver_mid" && \ test "$ac_inst_ver_min" -lt "$ac_req_ver_min" ) then ac_ver_fail=yes else ac_ver_fail=no fi if test $ac_ver_fail = no; then LIBS="$LIBS `$XML_CONFIG --libs`" CFLAGS="$CFLAGS `$XML_CONFIG --cflags`" fi if test $ac_ver_fail = yes; then as_fn_error $? "libxml2 version $xml_version is too old. You need at least $xml_ver_required" "$LINENO" 5 fi fi nl=' ' echo "${nl}${T_MD}Configuring for PCRE support ...${T_ME}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with PCRE support" >&5 $as_echo_n "checking whether to compile with PCRE support... " >&6; } # Check whether --enable-pcre was given. if test "${enable_pcre+set}" = set; then : enableval=$enable_pcre; if test "$enableval" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } for ac_prog in pcre-config do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PCRE_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PCRE_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PCRE_CONFIG="$PCRE_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PCRE_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PCRE_CONFIG=$ac_cv_path_PCRE_CONFIG if test -n "$PCRE_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PCRE_CONFIG" >&5 $as_echo "$PCRE_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$PCRE_CONFIG" && break done test -n "$PCRE_CONFIG" || PCRE_CONFIG="no" if test "$PCRE_CONFIG" = "no"; then as_fn_error $? "Unable to find pcre-config in path for PCRE support" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: checking PCRE version" >&5 $as_echo_n "checking PCRE version... " >&6; } pcre_version=`$PCRE_CONFIG --version` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pcre_version" >&5 $as_echo "$pcre_version" >&6; } LIBS="$LIBS `$PCRE_CONFIG --libs-posix`" CFLAGS="$CFLAGS `$PCRE_CONFIG --cflags-posix`" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for POSIX regex provider" >&5 $as_echo_n "checking for POSIX regex provider... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: PCRE library" >&5 $as_echo "PCRE library" >&6; } for ac_header in pcreposix.h do : ac_fn_c_check_header_mongrel "$LINENO" "pcreposix.h" "ac_cv_header_pcreposix_h" "$ac_includes_default" if test "x$ac_cv_header_pcreposix_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PCREPOSIX_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for regcomp in -lpcreposix" >&5 $as_echo_n "checking for regcomp in -lpcreposix... " >&6; } if ${ac_cv_lib_pcreposix_regcomp+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpcreposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char regcomp (); int main () { return regcomp (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pcreposix_regcomp=yes else ac_cv_lib_pcreposix_regcomp=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcreposix_regcomp" >&5 $as_echo "$ac_cv_lib_pcreposix_regcomp" >&6; } if test "x$ac_cv_lib_pcreposix_regcomp" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPCREPOSIX 1 _ACEOF LIBS="-lpcreposix $LIBS" fi for ac_header in pcre.h do : ac_fn_c_check_header_mongrel "$LINENO" "pcre.h" "ac_cv_header_pcre_h" "$ac_includes_default" if test "x$ac_cv_header_pcre_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PCRE_H 1 _ACEOF fi done for ac_func in pcre_compile do : ac_fn_c_check_func "$LINENO" "pcre_compile" "ac_cv_func_pcre_compile" if test "x$ac_cv_func_pcre_compile" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PCRE_COMPILE 1 _ACEOF fi done $as_echo "#define HAVE_PCRE 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define LIBPCRE_VERSION "$pcre_version" _ACEOF PCRE="yes" fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi nl=' ' echo "${nl}${T_MD}Configuring DocBook support ...${T_ME}" for ac_prog in jade openjade do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JADE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JADE"; then ac_cv_prog_JADE="$JADE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JADE="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi JADE=$ac_cv_prog_JADE if test -n "$JADE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JADE" >&5 $as_echo "$JADE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$JADE" && break done test -n "$JADE" || JADE="no" # Extract the first word of "jadetex", so it can be a program name with args. set dummy jadetex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JADETEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JADETEX"; then ac_cv_prog_JADETEX="$JADETEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JADETEX="jadetex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_JADETEX" && ac_cv_prog_JADETEX="no" fi fi JADETEX=$ac_cv_prog_JADETEX if test -n "$JADETEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JADETEX" >&5 $as_echo "$JADETEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "pdfjadetex", so it can be a program name with args. set dummy pdfjadetex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PDFJADETEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PDFJADETEX"; then ac_cv_prog_PDFJADETEX="$PDFJADETEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PDFJADETEX="pdfjadetex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_PDFJADETEX" && ac_cv_prog_PDFJADETEX="no" fi fi PDFJADETEX=$ac_cv_prog_PDFJADETEX if test -n "$PDFJADETEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFJADETEX" >&5 $as_echo "$PDFJADETEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "dvips", so it can be a program name with args. set dummy dvips; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DVIPS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DVIPS"; then ac_cv_prog_DVIPS="$DVIPS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DVIPS="dvips" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_DVIPS" && ac_cv_prog_DVIPS="no" fi fi DVIPS=$ac_cv_prog_DVIPS if test -n "$DVIPS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DVIPS" >&5 $as_echo "$DVIPS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "fig2dev", so it can be a program name with args. set dummy fig2dev; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_FIG2DEV+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$FIG2DEV"; then ac_cv_prog_FIG2DEV="$FIG2DEV" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_FIG2DEV="fig2dev" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_FIG2DEV" && ac_cv_prog_FIG2DEV="no" fi fi FIG2DEV=$ac_cv_prog_FIG2DEV if test -n "$FIG2DEV"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FIG2DEV" >&5 $as_echo "$FIG2DEV" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "convert", so it can be a program name with args. set dummy convert; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CONVERT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CONVERT"; then ac_cv_prog_CONVERT="$CONVERT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CONVERT="convert" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CONVERT" && ac_cv_prog_CONVERT="no" fi fi CONVERT=$ac_cv_prog_CONVERT if test -n "$CONVERT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CONVERT" >&5 $as_echo "$CONVERT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/html/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/html/docbook.dsl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/html/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/html/docbook.dsl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : HTML_DSL=$file; found=1 fi fi done fi done found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/print/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/print/docbook.dsl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/print/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/print/docbook.dsl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : TEX_DSL=$file; found=1 fi fi done fi done found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/dtds/decls/xml.dcl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/declaration/xml.dcl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/dtds/decls/xml.dcl \ ${loc}/share/dsssl/docbook-dsssl/dtds/decls/xml.dcl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : XML_DCL=$file; found=1 fi fi done fi done # Check whether --enable-warnings was given. if test "${enable_warnings+set}" = set; then : enableval=$enable_warnings; echo enabling compilation warnings if test -n "$GCC"; then CFLAGS="$CFLAGS -Wall" CFLAGS="$CFLAGS -Wmissing-prototypes" CFLAGS="$CFLAGS -Wmissing-declarations" CFLAGS="$CFLAGS -Wnested-externs" CFLAGS="$CFLAGS -Winline" CFLAGS="$CFLAGS -Wformat -Wformat-security -Wmissing-format-attribute" #CFLAGS="$CFLAGS -Wstrict-prototypes" #CFLAGS="$CFLAGS -Wredundant-decls" #CFLAGS="$CFLAGS -Wconversion" fi fi # Check whether --enable-docs was given. if test "${enable_docs+set}" = set; then : enableval=$enable_docs; if test "$enableval" = "yes" then DOCSTARGET="docs" else DOCSTARGET="no-docs" fi fi if test "x$HTML_DSL" = "x" -o "x$TEX_DSL" = "x" \ || test "$JADE" = "no" \ || test "$JADETEX" = "no" \ || test "$PDFJADETEX" = "no" \ || test "$DVIPS" = "no" \ || test "$FIG2DEV" = "no" \ || test "$CONVERT" = "no" \ || test "$DOCSTARGET" = "no-docs" then DOCSTARGET="no-docs" else DOCSTARGET="docs" fi case "$DOCSTARGET" in no-docs) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not building documentation." >&5 $as_echo "Not building documentation." >&6; } ;; docs) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Documentation will be built as well." >&5 $as_echo "Documentation will be built as well." >&6; } ;; esac DOCDRAFTS="IGNORE" # Check whether --enable-drafts was given. if test "${enable_drafts+set}" = set; then : enableval=$enable_drafts; if test "$enableval" = "yes" then DOCDRAFTS="INCLUDE" else DOCDRAFTS="IGNORE" fi fi if test "x$DOCSTARGET" = "xdocs" then case "$DOCDRAFTS" in INCLUDE) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Documentation will include drafts." >&5 $as_echo "Documentation will include drafts." >&6; } ;; esac fi nl=' ' echo "${nl}${T_MD}Configuring parameters ...${T_ME}" SUFFIX="" # Check whether --with-suffix was given. if test "${with_suffix+set}" = set; then : withval=$with_suffix; if test "x$withval" != "x" ; then SUFFIX=$withval fi fi # Check whether --enable-suffix was given. if test "${enable_suffix+set}" = set; then : enableval=$enable_suffix; if test "$enableval" = "yes" ; then SUFFIX="-$VERSION" else SUFFIX="" fi fi if test "x$SUFFIX" != "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to append suffix to binary" >&5 $as_echo_n "checking whether to append suffix to binary... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SUFFIX" >&5 $as_echo "$SUFFIX" >&6; } fi cat >>confdefs.h <<_ACEOF #define SUFFIX "$SUFFIX" _ACEOF # Check whether --with-defaults was given. if test "${with_defaults+set}" = set; then : withval=$with_defaults; case "$withval" in speed) assertiondefault=no mallocdefault=native ;; debug) assertiondefault=yes mallocdefault=check ;; *) echo "unknown --with-defaults parameter $withval" exit 1 ;; esac else assertiondefault=yes mallocdefault=native fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking which malloc to use" >&5 $as_echo_n "checking which malloc to use... " >&6; } # Check whether --with-malloc was given. if test "${with_malloc+set}" = set; then : withval=$with_malloc; case "$withval" in native) $as_echo "#define USE_GWMEM_NATIVE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: native malloc" >&5 $as_echo "native malloc" >&6; } ;; check) $as_echo "#define USE_GWMEM_CHECK 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking malloc" >&5 $as_echo "checking malloc" >&6; } ;; slow) $as_echo "#define USE_GWMEM_SLOW 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: slow malloc" >&5 $as_echo "slow malloc" >&6; } ;; *) echo "Unknown malloc wrapper $withval. Oops."; exit 1 ;; esac else case "$mallocdefault" in check) $as_echo "#define USE_GWMEM_CHECK 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking malloc" >&5 $as_echo "checking malloc" >&6; } ;; slow) $as_echo "#define USE_GWMEM_SLOW 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: slow malloc" >&5 $as_echo "slow malloc" >&6; } ;; *) $as_echo "#define USE_GWMEM_NATIVE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: native malloc" >&5 $as_echo "native malloc" >&6; } ;; esac fi # Check whether --enable-assertions was given. if test "${enable_assertions+set}" = set; then : enableval=$enable_assertions; if test "$enableval" = "no" then echo disabling assertion checking $as_echo "#define NO_GWASSERT 1" >>confdefs.h fi else if test "$assertiondefault" = "no" then echo disabling assertion checking $as_echo "#define NO_GWASSERT 1" >>confdefs.h fi fi # Check whether --enable-pam was given. if test "${enable_pam+set}" = set; then : enableval=$enable_pam; if test "$enableval" = "yes" then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_end in -lpam" >&5 $as_echo_n "checking for pam_end in -lpam... " >&6; } if ${ac_cv_lib_pam_pam_end+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pam_end (); int main () { return pam_end (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pam_pam_end=yes else ac_cv_lib_pam_pam_end=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_end" >&5 $as_echo "$ac_cv_lib_pam_pam_end" >&6; } if test "x$ac_cv_lib_pam_pam_end" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPAM 1 _ACEOF LIBS="-lpam $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5 $as_echo_n "checking for main in -ldl... " >&6; } if ${ac_cv_lib_dl_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_main=yes else ac_cv_lib_dl_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5 $as_echo "$ac_cv_lib_dl_main" >&6; } if test "x$ac_cv_lib_dl_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF LIBS="-ldl $LIBS" fi for ac_header in security/pam_appl.h do : ac_fn_c_check_header_mongrel "$LINENO" "security/pam_appl.h" "ac_cv_header_security_pam_appl_h" "$ac_includes_default" if test "x$ac_cv_header_security_pam_appl_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SECURITY_PAM_APPL_H 1 _ACEOF fi done PAMTARGET="pam" else PAMTARGET="no-pam" fi fi case "$PAMTARGET" in no-pam) echo PAM authentication is disabled. ;; pam) echo PAM authentication is enabled. ;; esac # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; echo enabling WMLScript compiler debugging if test -n "$GCC"; then CFLAGS="$CFLAGS -Wall" fi $as_echo "#define WS_DEBUG 1" >>confdefs.h fi # Check whether --enable-localtime was given. if test "${enable_localtime+set}" = set; then : enableval=$enable_localtime; if test "$enableval" = yes; then echo enabling local time $as_echo "#define LOG_TIMESTAMP_LOCALTIME 1" >>confdefs.h fi else echo enabling local time $as_echo "#define LOG_TIMESTAMP_LOCALTIME 1" >>confdefs.h fi # Check whether --enable-mutex-stats was given. if test "${enable_mutex_stats+set}" = set; then : enableval=$enable_mutex_stats; if test "$enableval" = yes; then $as_echo "#define MUTEX_STATS 1" >>confdefs.h fi fi # Check whether --enable-cookies was given. if test "${enable_cookies+set}" = set; then : enableval=$enable_cookies; if test "$enableval" = yes; then echo enabling cookies $as_echo "#define ENABLE_COOKIES 1" >>confdefs.h else echo disabling cookies fi else echo enabling cookies $as_echo "#define ENABLE_COOKIES 1" >>confdefs.h fi # Check whether --enable-keepalive was given. if test "${enable_keepalive+set}" = set; then : enableval=$enable_keepalive; if test "$enableval" = yes; then echo enabling HTTP/1.1 keep-alive $as_echo "#define USE_KEEPALIVE 1" >>confdefs.h else echo disabling HTTP/1.1 keep-alive fi else echo enabling HTTP/1.1 keep-alive $as_echo "#define USE_KEEPALIVE 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile start-stop-daemon" >&5 $as_echo_n "checking whether to compile start-stop-daemon... " >&6; } # Check whether --enable-start-stop-daemon was given. if test "${enable_start_stop_daemon+set}" = set; then : enableval=$enable_start_stop_daemon; case "${enableval}" in yes) buildbin=true { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5 $as_echo "enabled" >&6; } ;; no) buildbin=false { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } ;; *) as_fn_error $? "bad value ${enableval} for --enable-start-stop-daemon" "$LINENO" 5 ;; esac else buildbin=false ; { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi if test x$buildbin = xtrue; then BUILD_STARTSTOPDAEMON_TRUE= BUILD_STARTSTOPDAEMON_FALSE='#' else BUILD_STARTSTOPDAEMON_TRUE='#' BUILD_STARTSTOPDAEMON_FALSE= fi # Check whether --enable-wap was given. if test "${enable_wap+set}" = set; then : enableval=$enable_wap; if test "$enableval" = "no" then echo disabling WAP gateway parts in bearerbox $as_echo "#define NO_WAP 1" >>confdefs.h fi fi # Check whether --enable-sms was given. if test "${enable_sms+set}" = set; then : enableval=$enable_sms; if test "$enableval" = "no" then echo disabling SMS gateway parts in bearerbox $as_echo "#define NO_SMS 1" >>confdefs.h fi fi nl=' ' echo "${nl}${T_MD}Configuring OpenSSL support ...${T_ME}" # Check whether --with-ssl was given. if test "${with_ssl+set}" = set; then : withval=$with_ssl; if test -d "$withval"; then ssllib="$withval/lib"; sslinc="$withval/include" else as_fn_error $? "Unable to find OpenSSL libs and/or directories at $withval" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SSL support" >&5 $as_echo_n "checking whether to compile with SSL support... " >&6; } # Check whether --enable-ssl was given. if test "${enable_ssl+set}" = set; then : enableval=$enable_ssl; if test "$enableval" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } ssl=no else ssl=yes fi else ssl=yes fi if test "$ssl" = "yes" ; then if test "x$ssllib" = "x" && test "x$sslinc" = "x"; then for loc in /usr/lib /usr/lib64 /usr/local/ssl/lib /usr/local/openssl/lib; do if test -f "$loc/libssl.a" -o -f "$loc/libssl.so" -o -f "$loc/libssl.dylib" ; then ssllib="$loc" fi done if test "x$sslib" = "x" && test -n "$GCC"; then for lib in libssl.a libssl.so libssl.dylib; do name=`$CC -print-file-name=$lib` if test -f "$name"; then ssllib=`dirname $name` fi done fi for loc in /usr/include/ssl /usr/include/openssl /usr/local/ssl/include \ /usr/local/openssl/include; do if test -d "$loc"; then sslinc="$loc" fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: trying $ssllib $sslinc" >&5 $as_echo "trying $ssllib $sslinc" >&6; } fi if test "x$ssllib" != "x" && test "x$sslinc" != "x"; then CFLAGS="$CFLAGS -I$sslinc" LIBS="$LIBS -L$ssllib" # Extract the first word of "openssl", so it can be a program name with args. set dummy openssl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_OPENSSL+:} false; then : $as_echo_n "(cached) " >&6 else case $OPENSSL in [\\/]* | ?:[\\/]*) ac_cv_path_OPENSSL="$OPENSSL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_OPENSSL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_OPENSSL" && ac_cv_path_OPENSSL="no" ;; esac fi OPENSSL=$ac_cv_path_OPENSSL if test -n "$OPENSSL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENSSL" >&5 $as_echo "$OPENSSL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$OPENSSL" != "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking openssl version" >&5 $as_echo_n "checking openssl version... " >&6; } openssl_version=`$OPENSSL version | awk '{print $2}'` openssl_ver=`echo $openssl_version | sed 's/[a-zA-Z]//g'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $openssl_version" >&5 $as_echo "$openssl_version" >&6; } fi ac_inst_ver_maj=`echo $openssl_ver | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_inst_ver_mid=`echo $openssl_ver | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_inst_ver_min=`echo $openssl_ver | sed -e 's/^.*\..*\.\(.*\)$/\1/'` ac_req_ver_maj=`echo "1.1.0" | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_req_ver_mid=`echo "1.1.0" | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_req_ver_min=`echo "1.1.0" | sed -e 's/^.*\..*\.\(.*\)$/\1/'` if test "$ac_inst_ver_maj" -lt "$ac_req_ver_maj" || \ ( test "$ac_inst_ver_maj" -eq "$ac_req_ver_maj" && \ test "$ac_inst_ver_mid" -lt "$ac_req_ver_mid" ) || \ ( test "$ac_inst_ver_mid" -eq "$ac_req_ver_mid" && \ test "$ac_inst_ver_min" -lt "$ac_req_ver_min" ) then ac_ver_fail=yes else ac_ver_fail=no fi if test $ac_ver_fail = no; then CRYPTO_CHECK=HMAC_Update SSL_CHECK=OPENSSL_init_ssl fi if test $ac_ver_fail = yes; then CRYPTO_CHECK=CRYPTO_lock SSL_CHECK=SSL_library_init fi as_ac_Lib=`$as_echo "ac_cv_lib_crypto_$CRYPTO_CHECK" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CRYPTO_CHECK in -lcrypto" >&5 $as_echo_n "checking for $CRYPTO_CHECK in -lcrypto... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $CRYPTO_CHECK (); int main () { return $CRYPTO_CHECK (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : LIBS="$LIBS -lcrypto" as_ac_Lib=`$as_echo "ac_cv_lib_ssl_$SSL_CHECK" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $SSL_CHECK in -lssl" >&5 $as_echo_n "checking for $SSL_CHECK in -lssl... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $SSL_CHECK (); int main () { return $SSL_CHECK (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_connect in -lssl" >&5 $as_echo_n "checking for SSL_connect in -lssl... " >&6; } if ${ac_cv_lib_ssl_SSL_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SSL_connect (); int main () { return SSL_connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ssl_SSL_connect=yes else ac_cv_lib_ssl_SSL_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_connect" >&5 $as_echo "$ac_cv_lib_ssl_SSL_connect" >&6; } if test "x$ac_cv_lib_ssl_SSL_connect" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSSL 1 _ACEOF LIBS="-lssl $LIBS" fi for ac_header in openssl/x509.h openssl/rsa.h openssl/crypto.h \ openssl/pem.h openssl/ssl.h openssl/err.h \ openssl/hmac.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the OpenSSL library is multithread-enabled" >&5 $as_echo_n "checking whether the OpenSSL library is multithread-enabled... " >&6; } if test "$cross_compiling" = yes; then : echo "Cross-compiling; make sure your SSL library is multithread-enabled" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define OPENSSL_THREAD_DEFINES #include int main(void) { #if defined(THREADS) exit(0); #elif defined(OPENSSL_THREADS) exit(0); #else exit(1); #endif } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LIBSSL 1" >>confdefs.h LIBS="$LIBS -lssl" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SSL support" >&5 $as_echo_n "checking whether to compile with SSL support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # Check whether --enable-ssl-thread-test was given. if test "${enable_ssl_thread_test+set}" = set; then : enableval=$enable_ssl_thread_test; if test "$enableval" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, continue forced" >&5 $as_echo "no, continue forced" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Either get a multithread-enabled SSL or configure with --disable-ssl" "$LINENO" 5 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi fi nl=' ' echo "${nl}${T_MD}Configuring DB support ...${T_ME}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with MySQL support" >&5 $as_echo_n "checking whether to compile with MySQL support... " >&6; } # Check whether --with-mysql was given. if test "${with_mysql+set}" = set; then : withval=$with_mysql; if test "$withval" != yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else # Check whether --with-mysql-dir was given. if test "${with_mysql_dir+set}" = set; then : withval=$with_mysql_dir; mysqlloc="" if test -d "$withval" ; then mysqlloc="$withval" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } # Extract the first word of "mysql_config", so it can be a program name with args. set dummy mysql_config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_MYSQL_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $MYSQL_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_MYSQL_CONFIG="$MYSQL_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$PATH:$mysqlloc/bin:$mysqlloc" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_MYSQL_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_MYSQL_CONFIG" && ac_cv_path_MYSQL_CONFIG="no" ;; esac fi MYSQL_CONFIG=$ac_cv_path_MYSQL_CONFIG if test -n "$MYSQL_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_CONFIG" >&5 $as_echo "$MYSQL_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$MYSQL_CONFIG" = "no"; then found="" for loc in $mysqlloc /usr /usr/local ; do if test "x$found" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MySQL client support in" >&5 $as_echo_n "checking for MySQL client support in... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $loc" >&5 $as_echo "$loc" >&6; } as_ac_File=`$as_echo "ac_cv_file_"$loc/include/mysql/mysql.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/include/mysql/mysql.h\"" >&5 $as_echo_n "checking for \"$loc/include/mysql/mysql.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/include/mysql/mysql.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/include/mysql"; LIBS="$LIBS -L$loc/lib/mysql -lmysqlclient"; found=1 else as_ac_File=`$as_echo "ac_cv_file_"$loc/include/mysql.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/include/mysql.h\"" >&5 $as_echo_n "checking for \"$loc/include/mysql.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/include/mysql.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/include"; LIBS="$LIBS -L$loc/lib -lmysqlclient"; found=1 fi fi fi done if test "x$found" != "x1" ; then as_fn_error $? "Unable to find mysql.h, please provide a --with-mysql-dir= location" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking mysql version" >&5 $as_echo_n "checking mysql version... " >&6; } mysql_version=`$MYSQL_CONFIG --version` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $mysql_version" >&5 $as_echo "$mysql_version" >&6; } MYSQL_LIBS="" if $MYSQL_CONFIG --libs_r &>/dev/null ; then MYSQL_LIBS=`$MYSQL_CONFIG --libs_r` { $as_echo "$as_me:${as_lineno-$LINENO}: checking mysql reentrant libs" >&5 $as_echo_n "checking mysql reentrant libs... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_LIBS" >&5 $as_echo "$MYSQL_LIBS" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient_r" >&5 $as_echo_n "checking for mysql_init in -lmysqlclient_r... " >&6; } if ${ac_cv_lib_mysqlclient_r_mysql_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmysqlclient_r $MYSQL_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char mysql_init (); int main () { return mysql_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_mysqlclient_r_mysql_init=yes else ac_cv_lib_mysqlclient_r_mysql_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_r_mysql_init" >&5 $as_echo "$ac_cv_lib_mysqlclient_r_mysql_init" >&6; } if test "x$ac_cv_lib_mysqlclient_r_mysql_init" = xyes; then : LIBS="$LIBS $MYSQL_LIBS" else MYSQL_LIBS="" fi fi if test -z "$MYSQL_LIBS" ; then MYSQL_LIBS=`$MYSQL_CONFIG --libs` { $as_echo "$as_me:${as_lineno-$LINENO}: checking mysql libs" >&5 $as_echo_n "checking mysql libs... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_LIBS" >&5 $as_echo "$MYSQL_LIBS" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_init in -lmysqlclient" >&5 $as_echo_n "checking for mysql_init in -lmysqlclient... " >&6; } if ${ac_cv_lib_mysqlclient_mysql_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmysqlclient $MYSQL_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char mysql_init (); int main () { return mysql_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_mysqlclient_mysql_init=yes else ac_cv_lib_mysqlclient_mysql_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_mysql_init" >&5 $as_echo "$ac_cv_lib_mysqlclient_mysql_init" >&6; } if test "x$ac_cv_lib_mysqlclient_mysql_init" = xyes; then : LIBS="$LIBS $MYSQL_LIBS" else as_fn_error $? "Unable to find MySQL client libraries" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking mysql includes" >&5 $as_echo_n "checking mysql includes... " >&6; } if $MYSQL_CONFIG --include &>/dev/null ; then MYSQL_CFLAGS=`$MYSQL_CONFIG --include` else MYSQL_CFLAGS=`$MYSQL_CONFIG --cflags` fi CFLAGS="$CFLAGS $MYSQL_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_CFLAGS" >&5 $as_echo "$MYSQL_CFLAGS" >&6; } fi for ac_header in mysql/mysql.h mysql/mysql_version.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_stmt_init in -lmysqlclient_r" >&5 $as_echo_n "checking for mysql_stmt_init in -lmysqlclient_r... " >&6; } if ${ac_cv_lib_mysqlclient_r_mysql_stmt_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmysqlclient_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char mysql_stmt_init (); int main () { return mysql_stmt_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_mysqlclient_r_mysql_stmt_init=yes else ac_cv_lib_mysqlclient_r_mysql_stmt_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_r_mysql_stmt_init" >&5 $as_echo "$ac_cv_lib_mysqlclient_r_mysql_stmt_init" >&6; } if test "x$ac_cv_lib_mysqlclient_r_mysql_stmt_init" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBMYSQLCLIENT_R 1 _ACEOF LIBS="-lmysqlclient_r $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mysql_stmt_init in -lmysqlclient" >&5 $as_echo_n "checking for mysql_stmt_init in -lmysqlclient... " >&6; } if ${ac_cv_lib_mysqlclient_mysql_stmt_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lmysqlclient $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char mysql_stmt_init (); int main () { return mysql_stmt_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_mysqlclient_mysql_stmt_init=yes else ac_cv_lib_mysqlclient_mysql_stmt_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mysqlclient_mysql_stmt_init" >&5 $as_echo "$ac_cv_lib_mysqlclient_mysql_stmt_init" >&6; } if test "x$ac_cv_lib_mysqlclient_mysql_stmt_init" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBMYSQLCLIENT 1 _ACEOF LIBS="-lmysqlclient $LIBS" else as_fn_error $? "Unable to find MySQL client libraries version >= 4.1" "$LINENO" 5 fi fi $as_echo "#define HAVE_MYSQL 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with MySQL support" >&5 $as_echo_n "checking whether to compile with MySQL support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } MYSQL="yes" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with LibSDB support" >&5 $as_echo_n "checking whether to compile with LibSDB support... " >&6; } # Check whether --with-sdb was given. if test "${with_sdb+set}" = set; then : withval=$with_sdb; if test "$withval" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } for ac_prog in sdb-config do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SDB_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $SDB_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_SDB_CONFIG="$SDB_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SDB_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SDB_CONFIG=$ac_cv_path_SDB_CONFIG if test -n "$SDB_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SDB_CONFIG" >&5 $as_echo "$SDB_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$SDB_CONFIG" && break done test -n "$SDB_CONFIG" || SDB_CONFIG="no" if test "$SDB_CONFIG" = "no"; then as_fn_error $? "Unable to find sdb-config in path for SDB support" "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: checking sdb version" >&5 $as_echo_n "checking sdb version... " >&6; } sdb_version=`$SDB_CONFIG --version` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sdb_version" >&5 $as_echo "$sdb_version" >&6; } CFLAGS="$CFLAGS `$SDB_CONFIG --cflags`" for ac_header in sdb.h do : ac_fn_c_check_header_mongrel "$LINENO" "sdb.h" "ac_cv_header_sdb_h" "$ac_includes_default" if test "x$ac_cv_header_sdb_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SDB_H 1 _ACEOF fi done LIBS="$LIBS `$SDB_CONFIG --libs`" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sdb_init in -lsdb" >&5 $as_echo_n "checking for sdb_init in -lsdb... " >&6; } if ${ac_cv_lib_sdb_sdb_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsdb $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sdb_init (); int main () { return sdb_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_sdb_sdb_init=yes else ac_cv_lib_sdb_sdb_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sdb_sdb_init" >&5 $as_echo "$ac_cv_lib_sdb_sdb_init" >&6; } if test "x$ac_cv_lib_sdb_sdb_init" = xyes; then : LIBS="$LIBS -lsdb" $as_echo "#define HAVE_SDB 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define LIBSDB_VERSION "$sdb_version" _ACEOF SDB="yes" else as_fn_error $? "Unable to find libSDB client libraries" "$LINENO" 5 fi fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SQLite2 support" >&5 $as_echo_n "checking whether to compile with SQLite2 support... " >&6; } # Check whether --with-sqlite2 was given. if test "${with_sqlite2+set}" = set; then : withval=$with_sqlite2; if test "$withval" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } for ac_header in sqlite.h do : ac_fn_c_check_header_mongrel "$LINENO" "sqlite.h" "ac_cv_header_sqlite_h" "$ac_includes_default" if test "x$ac_cv_header_sqlite_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SQLITE_H 1 _ACEOF fi done LIBS="$LIBS -L/usr/local/lib" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite_open in -lsqlite" >&5 $as_echo_n "checking for sqlite_open in -lsqlite... " >&6; } if ${ac_cv_lib_sqlite_sqlite_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sqlite_open (); int main () { return sqlite_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_sqlite_sqlite_open=yes else ac_cv_lib_sqlite_sqlite_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite_sqlite_open" >&5 $as_echo "$ac_cv_lib_sqlite_sqlite_open" >&6; } if test "x$ac_cv_lib_sqlite_sqlite_open" = xyes; then : LIBS="$LIBS -lsqlite" $as_echo "#define HAVE_SQLITE 1" >>confdefs.h SQLITE="yes" else as_fn_error $? "Unable to find SQLite2 client libraries" "$LINENO" 5 fi for ac_prog in sqlite do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SQLITE+:} false; then : $as_echo_n "(cached) " >&6 else case $SQLITE in [\\/]* | ?:[\\/]*) ac_cv_path_SQLITE="$SQLITE" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SQLITE="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SQLITE=$ac_cv_path_SQLITE if test -n "$SQLITE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SQLITE" >&5 $as_echo "$SQLITE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$SQLITE" && break done test -n "$SQLITE" || SQLITE="no" if test "$SQLITE" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to find sqlite in path for SQLite2 support" >&5 $as_echo "$as_me: WARNING: Unable to find sqlite in path for SQLite2 support" >&2;} else { $as_echo "$as_me:${as_lineno-$LINENO}: checking sqlite version" >&5 $as_echo_n "checking sqlite version... " >&6; } sqlite_version=`$SQLITE -version` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sqlite_version" >&5 $as_echo "$sqlite_version" >&6; } fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SQLite3 support" >&5 $as_echo_n "checking whether to compile with SQLite3 support... " >&6; } # Check whether --with-sqlite3 was given. if test "${with_sqlite3+set}" = set; then : withval=$with_sqlite3; if test "$withval" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } for ac_header in sqlite3.h do : ac_fn_c_check_header_mongrel "$LINENO" "sqlite3.h" "ac_cv_header_sqlite3_h" "$ac_includes_default" if test "x$ac_cv_header_sqlite3_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SQLITE3_H 1 _ACEOF fi done LIBS="$LIBS -L/usr/local/lib" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3_open in -lsqlite3" >&5 $as_echo_n "checking for sqlite3_open in -lsqlite3... " >&6; } if ${ac_cv_lib_sqlite3_sqlite3_open+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsqlite3 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char sqlite3_open (); int main () { return sqlite3_open (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_sqlite3_sqlite3_open=yes else ac_cv_lib_sqlite3_sqlite3_open=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sqlite3_sqlite3_open" >&5 $as_echo "$ac_cv_lib_sqlite3_sqlite3_open" >&6; } if test "x$ac_cv_lib_sqlite3_sqlite3_open" = xyes; then : LIBS="$LIBS -lsqlite3" $as_echo "#define HAVE_SQLITE3 1" >>confdefs.h SQLITE3="yes" else as_fn_error $? "Unable to find SQLite3 client libraries" "$LINENO" 5 fi for ac_prog in sqlite3 do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SQLITE3+:} false; then : $as_echo_n "(cached) " >&6 else case $SQLITE3 in [\\/]* | ?:[\\/]*) ac_cv_path_SQLITE3="$SQLITE3" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SQLITE3="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SQLITE3=$ac_cv_path_SQLITE3 if test -n "$SQLITE3"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SQLITE3" >&5 $as_echo "$SQLITE3" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$SQLITE3" && break done test -n "$SQLITE3" || SQLITE3="no" if test "$SQLITE3" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to find sqlite3 in path for SQLite3 support" >&5 $as_echo "$as_me: WARNING: Unable to find sqlite3 in path for SQLite3 support" >&2;} else { $as_echo "$as_me:${as_lineno-$LINENO}: checking sqlite3 version" >&5 $as_echo_n "checking sqlite3 version... " >&6; } sqlite3_version=`$SQLITE3 -version | awk '{print $1}'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sqlite3_version" >&5 $as_echo "$sqlite3_version" >&6; } fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with Oracle support" >&5 $as_echo_n "checking whether to compile with Oracle support... " >&6; } # Check whether --with-oracle was given. if test "${with_oracle+set}" = set; then : withval=$with_oracle; if test "$withval" != yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } # Check whether --with-oracle-includes was given. if test "${with_oracle_includes+set}" = set; then : withval=$with_oracle_includes; ORACLE_INCLUDE_PATH="$withval" else ORACLE_INCLUDE_PATH="$ORACLE_HOME/rdbms/demo $ORACLE_HOME/rdbms/public" fi for a in $ORACLE_INCLUDE_PATH do CPPFLAGS="$CPPFLAGS -I$a" done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for oci.h " >&5 $as_echo_n "checking for oci.h ... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else as_fn_error $? "oci.h not found" "$LINENO" 5 fi rm -f conftest.err conftest.i conftest.$ac_ext CFLAGS="$CFLAGS $CPPFLAGS" # Check whether --with-oracle-libs was given. if test "${with_oracle_libs+set}" = set; then : withval=$with_oracle_libs; ORACLE_LIB_PATH="$withval" else ORACLE_LIB_PATH="$ORACLE_HOME/lib" fi for a in $ORACLE_LIB_PATH do LIBS="$LIBS -L$a" done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIEnvCreate in -lclntsh" >&5 $as_echo_n "checking for OCIEnvCreate in -lclntsh... " >&6; } if ${ac_cv_lib_clntsh_OCIEnvCreate+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lclntsh $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char OCIEnvCreate (); int main () { return OCIEnvCreate (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_clntsh_OCIEnvCreate=yes else ac_cv_lib_clntsh_OCIEnvCreate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_clntsh_OCIEnvCreate" >&5 $as_echo "$ac_cv_lib_clntsh_OCIEnvCreate" >&6; } if test "x$ac_cv_lib_clntsh_OCIEnvCreate" = xyes; then : LIBS="$LIBS -lclntsh" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIEnvCreate in -lclntsh" >&5 $as_echo_n "checking for OCIEnvCreate in -lclntsh... " >&6; } if ${ac_cv_lib_clntsh_OCIEnvCreate+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lclntsh $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char OCIEnvCreate (); int main () { return OCIEnvCreate (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_clntsh_OCIEnvCreate=yes else ac_cv_lib_clntsh_OCIEnvCreate=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_clntsh_OCIEnvCreate" >&5 $as_echo "$ac_cv_lib_clntsh_OCIEnvCreate" >&6; } if test "x$ac_cv_lib_clntsh_OCIEnvCreate" = xyes; then : LIBS="$LIBS -lclntsh -lnnz10" else exit fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wtcstu in -lwtc8" >&5 $as_echo_n "checking for wtcstu in -lwtc8... " >&6; } if ${ac_cv_lib_wtc8_wtcstu+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lwtc8 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char wtcstu (); int main () { return wtcstu (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_wtc8_wtcstu=yes else ac_cv_lib_wtc8_wtcstu=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wtc8_wtcstu" >&5 $as_echo "$ac_cv_lib_wtc8_wtcstu" >&6; } if test "x$ac_cv_lib_wtc8_wtcstu" = xyes; then : LIBS="$LIBS -lwtc8" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wtcstu in -lwtc9" >&5 $as_echo_n "checking for wtcstu in -lwtc9... " >&6; } if ${ac_cv_lib_wtc9_wtcstu+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lwtc9 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char wtcstu (); int main () { return wtcstu (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_wtc9_wtcstu=yes else ac_cv_lib_wtc9_wtcstu=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wtc9_wtcstu" >&5 $as_echo "$ac_cv_lib_wtc9_wtcstu" >&6; } if test "x$ac_cv_lib_wtc9_wtcstu" = xyes; then : LIBS="$LIBS -lwtc9" else true fi fi ac_fn_c_check_func "$LINENO" "OCIPing" "ac_cv_func_OCIPing" if test "x$ac_cv_func_OCIPing" = xyes; then : $as_echo "#define HAVE_OCIPING 1" >>confdefs.h fi $as_echo "#define HAVE_ORACLE 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with Oracle support" >&5 $as_echo_n "checking whether to compile with Oracle support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with PostgresSQL support" >&5 $as_echo_n "checking whether to compile with PostgresSQL support... " >&6; } # Check whether --with-pgsql was given. if test "${with_pgsql+set}" = set; then : withval=$with_pgsql; if test "$withval" != yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else # Check whether --with-pgsql-dir was given. if test "${with_pgsql_dir+set}" = set; then : withval=$with_pgsql_dir; pgsqlloc="" if test -d "$withval" ; then pgsqlloc="$withval" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } # Extract the first word of "pg_config", so it can be a program name with args. set dummy pg_config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PGSQL_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PGSQL_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PGSQL_CONFIG="$PGSQL_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$PATH:$pgsqlloc/bin:$pgsqlloc:/usr/lib/postgresql/bin" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PGSQL_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_PGSQL_CONFIG" && ac_cv_path_PGSQL_CONFIG="no" ;; esac fi PGSQL_CONFIG=$ac_cv_path_PGSQL_CONFIG if test -n "$PGSQL_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PGSQL_CONFIG" >&5 $as_echo "$PGSQL_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$PGSQL_CONFIG" = "no"; then found="" for loc in $pgsqlloc /usr /usr/local ; do if test "x$found" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PostgresSQL include files in" >&5 $as_echo_n "checking for PostgresSQL include files in... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $loc" >&5 $as_echo "$loc" >&6; } as_ac_File=`$as_echo "ac_cv_file_"$loc/include/postgresql/libpq-fe.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/include/postgresql/libpq-fe.h\"" >&5 $as_echo_n "checking for \"$loc/include/postgresql/libpq-fe.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/include/postgresql/libpq-fe.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/include/postgresql"; LIBS="$LIBS -L$loc/lib/postgresql -lpq"; found=1 else as_ac_File=`$as_echo "ac_cv_file_"$loc/include/pgsql/libpq-fe.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/include/pgsql/libpq-fe.h\"" >&5 $as_echo_n "checking for \"$loc/include/pgsql/libpq-fe.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/include/pgsql/libpq-fe.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/include/pgsql"; LIBS="$LIBS -L$loc/lib/pgsql -lpq"; found=1 else as_ac_File=`$as_echo "ac_cv_file_"$loc/pgsql/include/libpq-fe.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/pgsql/include/libpq-fe.h\"" >&5 $as_echo_n "checking for \"$loc/pgsql/include/libpq-fe.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/pgsql/include/libpq-fe.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/pgsql/include"; LIBS="$LIBS -L$loc/pgsql/lib -lpq"; found=1 fi fi fi fi done if test "x$found" != "x1" ; then as_fn_error $? "Unable to find libpq-fe.h, please provide a --with-pgsql-dir= location" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking PostgreSQL version" >&5 $as_echo_n "checking PostgreSQL version... " >&6; } pgsql_version=`$PGSQL_CONFIG --version | awk '{print $2}'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgsql_version" >&5 $as_echo "$pgsql_version" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking PostgreSQL libdir" >&5 $as_echo_n "checking PostgreSQL libdir... " >&6; } if $PGSQL_CONFIG --libdir &>/dev/null ; then LIBS="$LIBS -L`$PGSQL_CONFIG --libdir`" pg_libdir=`$PGSQL_CONFIG --libdir` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pg_libdir" >&5 $as_echo "$pg_libdir" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking PostgreSQL includes" >&5 $as_echo_n "checking PostgreSQL includes... " >&6; } if $PGSQL_CONFIG --includedir &>/dev/null ; then CFLAGS="$CFLAGS -I`$PGSQL_CONFIG --includedir`" CPPFLAGS="$CPPFLAGS -I`$PGSQL_CONFIG --includedir`" pg_incdir=`$PGSQL_CONFIG --includedir` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pg_incdir" >&5 $as_echo "$pg_incdir" >&6; } fi fi for ac_header in libpq-fe.h do : ac_fn_c_check_header_mongrel "$LINENO" "libpq-fe.h" "ac_cv_header_libpq_fe_h" "$ac_includes_default" if test "x$ac_cv_header_libpq_fe_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPQ_FE_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PQconnectdb in -lpq" >&5 $as_echo_n "checking for PQconnectdb in -lpq... " >&6; } if ${ac_cv_lib_pq_PQconnectdb+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpq $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char PQconnectdb (); int main () { return PQconnectdb (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pq_PQconnectdb=yes else ac_cv_lib_pq_PQconnectdb=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pq_PQconnectdb" >&5 $as_echo "$ac_cv_lib_pq_PQconnectdb" >&6; } if test "x$ac_cv_lib_pq_PQconnectdb" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPQ 1 _ACEOF LIBS="-lpq $LIBS" fi $as_echo "#define HAVE_PGSQL 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with PostgreSQL support" >&5 $as_echo_n "checking whether to compile with PostgreSQL support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } PGSQL="yes" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with Redis support" >&5 $as_echo_n "checking whether to compile with Redis support... " >&6; } # Check whether --with-redis was given. if test "${with_redis+set}" = set; then : withval=$with_redis; if test "$withval" != yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else # Check whether --with-redis-dir was given. if test "${with_redis_dir+set}" = set; then : withval=$with_redis_dir; redisloc="" if test -d "$withval" ; then redisloc="$withval" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } # Extract the first word of "redis_config", so it can be a program name with args. set dummy redis_config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_REDIS_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $REDIS_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_REDIS_CONFIG="$REDIS_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$PATH:$redisloc/bin:$redisloc" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_REDIS_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_REDIS_CONFIG" && ac_cv_path_REDIS_CONFIG="no" ;; esac fi REDIS_CONFIG=$ac_cv_path_REDIS_CONFIG if test -n "$REDIS_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $REDIS_CONFIG" >&5 $as_echo "$REDIS_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$REDIS_CONFIG" = "no"; then found="" for loc in $redisloc /usr /usr/local ; do if test "x$found" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Redis include files in" >&5 $as_echo_n "checking for Redis include files in... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $loc" >&5 $as_echo "$loc" >&6; } as_ac_File=`$as_echo "ac_cv_file_"$loc/hiredis.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/hiredis.h\"" >&5 $as_echo_n "checking for \"$loc/hiredis.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/hiredis.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc"; LIBS="$LIBS -L$loc -lhiredis"; found=1 else as_ac_File=`$as_echo "ac_cv_file_"$loc/include/hiredis/hiredis.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/include/hiredis/hiredis.h\"" >&5 $as_echo_n "checking for \"$loc/include/hiredis/hiredis.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/include/hiredis/hiredis.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/include/hiredis"; LIBS="$LIBS -L$loc/lib -lhiredis"; found=1 fi fi fi done if test "x$found" != "x1" ; then as_fn_error $? "Unable to find hiredis.h, please provide a --with-redis-dir= location" "$LINENO" 5 fi else REDIS_LIBS="" if test -z "$REDIS_LIBS" ; then REDIS_LIBS=`$REDIS_CONFIG --libs` { $as_echo "$as_me:${as_lineno-$LINENO}: checking redis libs" >&5 $as_echo_n "checking redis libs... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $REDIS_LIBS" >&5 $as_echo "$REDIS_LIBS" >&6; } as_ac_Lib=`$as_echo "ac_cv_lib_hiredis_ LIBS="$LIBS $REDIS_LIBS" " | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBS=\"$LIBS $REDIS_LIBS\" in -lhiredis" >&5 $as_echo_n "checking for LIBS=\"$LIBS $REDIS_LIBS\" in -lhiredis... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lhiredis $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char LIBS="$LIBS $REDIS_LIBS" (); int main () { return LIBS="$LIBS $REDIS_LIBS" (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : as_fn_error $? "Unable to find Redis client libraries" "$LINENO" 5 else $REDIS_LIBS fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking redis includes" >&5 $as_echo_n "checking redis includes... " >&6; } if $REDIS_CONFIG --include &>/dev/null ; then REDIS_CFLAGS=`$REDIS_CONFIG --include` else REDIS_CFLAGS=`$REDIS_CONFIG --cflags` fi CFLAGS="$CFLAGS $REDIS_CFLAGS" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $REDIS_CFLAGS" >&5 $as_echo "$REDIS_CFLAGS" >&6; } fi for ac_header in hiredis/hiredis.h do : ac_fn_c_check_header_mongrel "$LINENO" "hiredis/hiredis.h" "ac_cv_header_hiredis_hiredis_h" "$ac_includes_default" if test "x$ac_cv_header_hiredis_hiredis_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_HIREDIS_HIREDIS_H 1 _ACEOF fi done $as_echo "#define HAVE_REDIS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with Redis support" >&5 $as_echo_n "checking whether to compile with Redis support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } REDIS="yes" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with FreeTDS Ct-Lib support" >&5 $as_echo_n "checking whether to compile with FreeTDS Ct-Lib support... " >&6; } # Check whether --with-mssql was given. if test "${with_mssql+set}" = set; then : withval=$with_mssql; if test "$withval" = "yes"; then withval=/usr/local fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then MSSQL_INCDIR=$withval/include MSSQL_LIBDIR=$withval/lib else if test -f $withval/include/freetds/ctpublic.h; then MSSQL_INCDIR=$withval/include/freetds MSSQL_LIBDIR=$withval/lib else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Invalid FreeTDS directory - unable to find ctpublic.h" "$LINENO" 5 fi fi LIBS="$LIBS -L$MSSQL_LIBDIR -lct" CFLAGS="$CFLAGS -I$MSSQL_INCDIR" $as_echo "#define HAVE_MSSQL 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } MSSQL="yes" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with Cassandra support" >&5 $as_echo_n "checking whether to compile with Cassandra support... " >&6; } # Check whether --with-cassandra was given. if test "${with_cassandra+set}" = set; then : withval=$with_cassandra; if test "$withval" != yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } else # Check whether --with-cassandra-dir was given. if test "${with_cassandra_dir+set}" = set; then : withval=$with_cassandra_dir; cassloc="" if test -d "$withval" ; then cassloc="$withval" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: searching" >&5 $as_echo "searching" >&6; } found="" for loc in $cassloc /usr /usr/local ; do if test "x$found" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Cassandra include files in" >&5 $as_echo_n "checking for Cassandra include files in... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $loc" >&5 $as_echo "$loc" >&6; } as_ac_File=`$as_echo "ac_cv_file_"$loc/include/cassandra.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/include/cassandra.h\"" >&5 $as_echo_n "checking for \"$loc/include/cassandra.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/include/cassandra.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/include"; LIBS="$LIBS -L$loc/lib -lcassandra"; found=1 fi fi done if test "x$found" != "x1" ; then as_fn_error $? "Unable to find cassandra.h, please provide a --with-cassandra-dir= location" "$LINENO" 5 fi for ac_header in cassandra.h do : ac_fn_c_check_header_mongrel "$LINENO" "cassandra.h" "ac_cv_header_cassandra_h" "$ac_includes_default" if test "x$ac_cv_header_cassandra_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_CASSANDRA_H 1 _ACEOF fi done $as_echo "#define HAVE_CASS 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with Cassandra support" >&5 $as_echo_n "checking whether to compile with Cassandra support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } CASS="yes" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi # Check whether --with-wtls was given. if test "${with_wtls+set}" = set; then : withval=$with_wtls; nl=' ' echo "${nl}${T_MD}Configuring WTLS support ...${T_ME}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for WTLS library" >&5 $as_echo_n "checking for WTLS library... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 $as_echo "$withval" >&6; } case "$withval" in openssl) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RSA_new in -lcrypto" >&5 $as_echo_n "checking for RSA_new in -lcrypto... " >&6; } if ${ac_cv_lib_crypto_RSA_new+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char RSA_new (); int main () { return RSA_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypto_RSA_new=yes else ac_cv_lib_crypto_RSA_new=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_RSA_new" >&5 $as_echo "$ac_cv_lib_crypto_RSA_new" >&6; } if test "x$ac_cv_lib_crypto_RSA_new" = xyes; then : for ac_header in openssl/objects.h openssl/rc5.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF $as_echo "#define HAVE_WTLS_OPENSSL 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: OpenSSL installation seems to lack RC5 algorithm!" >&5 $as_echo "$as_me: WARNING: OpenSSL installation seems to lack RC5 algorithm!" >&2;} fi done fi ;; baltimore) as_fn_error $? "This WTLS library is yet not supported!" "$LINENO" 5 ;; *) as_fn_error $? "Unknown WTLS libary support!" "$LINENO" 5 exit 1 ;; esac fi nl=' ' echo "${nl}${T_MD}Configuring for gSOAP support ...${T_ME}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SOAP support" >&5 $as_echo_n "checking whether to compile with SOAP support... " >&6; } # Check whether --with-gsoap was given. if test "${with_gsoap+set}" = set; then : withval=$with_gsoap; if test "x$withval" = "xyes"; then for loc in /usr/share/gsoap /usr/local/share/gsoap; do if test -d "$loc/import" && test -d "$loc/plugin"; then GSOAP_SHARE=$loc { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GSOAP_SHARE" >&5 $as_echo "$GSOAP_SHARE" >&6; } fi done if test "x$GSOAP_SHARE" = "x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } as_fn_error $? "Unable to find gSOAP's import and/or plugin directory" "$LINENO" 5 fi else if test -d "$withval/import" && test -d "$withval/plugin"; then GSOAP_SHARE="$withval" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $withval" >&5 $as_echo "$withval" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } as_fn_error $? "Unable to find gSOAP's import at $withval/import and/or plugin at $withval/plugin" "$LINENO" 5 fi fi gsoap_ver_required="2.8.4" for ac_prog in wsdl2h do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_WSDL2H+:} false; then : $as_echo_n "(cached) " >&6 else case $WSDL2H in [\\/]* | ?:[\\/]*) ac_cv_path_WSDL2H="$WSDL2H" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_WSDL2H="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi WSDL2H=$ac_cv_path_WSDL2H if test -n "$WSDL2H"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WSDL2H" >&5 $as_echo "$WSDL2H" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$WSDL2H" && break done test -n "$WSDL2H" || WSDL2H="no" if test "$WSDL2H" = "no"; then as_fn_error $? "Unable to find gSOAP's wsdl2h in path for SOAP support" "$LINENO" 5 fi for ac_prog in soapcpp2 do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_SOAPCPP+:} false; then : $as_echo_n "(cached) " >&6 else case $SOAPCPP in [\\/]* | ?:[\\/]*) ac_cv_path_SOAPCPP="$SOAPCPP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_SOAPCPP="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SOAPCPP=$ac_cv_path_SOAPCPP if test -n "$SOAPCPP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SOAPCPP" >&5 $as_echo "$SOAPCPP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$SOAPCPP" && break done test -n "$SOAPCPP" || SOAPCPP="no" if test "$SOAPCPP" = "no"; then as_fn_error $? "Unable to find gSOAP's soapcpp2 in path for SOAP support" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking gSOAP version" >&5 $as_echo_n "checking gSOAP version... " >&6; } gsoap_version=`$SOAPCPP -v &> /tmp/gsoap.tmp && cat /tmp/gsoap.tmp | grep "C and C++" | awk '{print $NF}'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gsoap_version" >&5 $as_echo "$gsoap_version" >&6; } gsoap_version_str=`echo $gsoap_version | grep -e "^[0-9]*\.[0-9]*\.[0-9]*$"` if test "$gsoap_version_str" = ""; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: gSOAP version $gsoap_version contains alphanumeric characters. Version MAYBE too old!" >&5 $as_echo "$as_me: WARNING: gSOAP version $gsoap_version contains alphanumeric characters. Version MAYBE too old!" >&2;} else ac_inst_ver_maj=`echo $gsoap_version | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_inst_ver_mid=`echo $gsoap_version | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_inst_ver_min=`echo $gsoap_version | sed -e 's/^.*\..*\.\(.*\)$/\1/'` ac_req_ver_maj=`echo $gsoap_ver_required | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_req_ver_mid=`echo $gsoap_ver_required | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_req_ver_min=`echo $gsoap_ver_required | sed -e 's/^.*\..*\.\(.*\)$/\1/'` if test "$ac_inst_ver_maj" -lt "$ac_req_ver_maj" || \ ( test "$ac_inst_ver_maj" -eq "$ac_req_ver_maj" && \ test "$ac_inst_ver_mid" -lt "$ac_req_ver_mid" ) || \ ( test "$ac_inst_ver_mid" -eq "$ac_req_ver_mid" && \ test "$ac_inst_ver_min" -lt "$ac_req_ver_min" ) then ac_ver_fail=yes else ac_ver_fail=no fi if test $ac_ver_fail = yes; then as_fn_error $? "gSOAP version $gsoap_version is too old. You MUST have at least $gsoap_ver_required" "$LINENO" 5 fi fi SOAP_INCLUDE="include soap/Makefile" $as_echo "#define HAVE_GSOAP 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi nl=' ' echo "${nl}${T_MD}Generating output files ...${T_ME}" ac_config_files="$ac_config_files gwlib/gw_uuid_types.h Makefile soap/Makefile utils/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BUILD_STARTSTOPDAEMON_TRUE}" && test -z "${BUILD_STARTSTOPDAEMON_FALSE}"; then as_fn_error $? "conditional \"BUILD_STARTSTOPDAEMON\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "gw-config.h") CONFIG_HEADERS="$CONFIG_HEADERS gw-config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "gwlib/gw_uuid_types.h") CONFIG_FILES="$CONFIG_FILES gwlib/gw_uuid_types.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "soap/Makefile") CONFIG_FILES="$CONFIG_FILES soap/Makefile" ;; "utils/Makefile") CONFIG_FILES="$CONFIG_FILES utils/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### BEGIN LIBTOOL CONFIG # Whether or not to build static libraries. build_old_libs=$enable_static # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi nl=' ' echo "${nl}${T_MD}License information ...${T_ME}" cat < | +--------------------------------------------------------------------+ Thank you for using Kannel. X gateway-1.4.5/utils/0000755000175000017500000000000013312227707013030 5ustar toljtoljgateway-1.4.5/utils/kannel-redhat.init.d0000755000175000017500000000346107201566234016664 0ustar toljtolj#!/bin/sh # # gateway This shell script takes care of starting and stopping # the Kannel WAP gateway (bearer/wapbox) # Fabrice Gatille # chkconfig: 2345 97 03 # description: Start and stop the Kannel WAP gateway used to fetch \ # some WML content from a Web server & compile it \ # into WMLC mobile phone bytecode. # probe: true # Use start-stop-daemon ver=0.12.1 START="start-stop-daemon-$ver -S --quiet -b -c web:web -x " CONF=/etc/wapkannel.conf [ $# -eq 2 ] && ver=$2 # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ ${NETWORKING} = "no" ] && exit 0 [ -x /usr/local/bin/bearerbox-$ver ] || exit 0 [ -x /usr/local/bin/wapbox-$ver ] || exit 0 [ -f $CONF ] || exit 0 RETVAL=0 # See how we were called. case "$1" in start) # Start daemons. echo -n "Starting bearer service (gateway kannel $ver): " daemon --forcedaemon "$START" /usr/local/bin/bearerbox-$ver -- $CONF RETVAL1=$? echo echo -n "Starting wapbox service (gateway kannel $ver): " daemon --forcedaemon "$START" /usr/local/bin/wapbox-$ver -- $CONF RETVAL2=$? echo [ $RETVAL1 -eq 0 -a $RETVAL2 -eq 0 ] && touch /var/lock/subsys/gateway ||\ RETVAL=1 ;; stop) # Stop daemons. echo -n "Shutting down wapbox (kannel $ver): " killproc wapbox-$ver quiet RETVAL2=$? echo echo -n "Shutting down bearerbox (kannel $ver): " killproc bearerbox-$ver quiet RETVAL1=$? echo [ $RETVAL1 -eq 0 -a $RETVAL2 -eq 0 ] && rm -f /var/lock/subsys/gateway echo "" ;; status) status bearerbox-$ver status wapbox-$ver exit $? ;; restart) $0 stop sleep 1 $0 start ;; *) echo "Usage: named {start|stop|status|restart}" exit 1 esac exit $RETVAL gateway-1.4.5/utils/source-stats0000755000175000017500000000170707220443374015420 0ustar toljtolj#!/bin/sh # # Simple program to calculate source code statistics for Kannel. # # Run with current working directory being the Kannel source root. # # Output: # # - number of source files # - number of lines total # - number of non-empty files # - number of lines with semicolons DIRS="gw gwlib wmlscript wap" find $DIRS -type f ! -name .cvsignore ! -name control.html \ ! -name '*kannel.conf' ! -name 'wsgram.[ch]' ! -name '*.txt' \ ! -name '*.[ao]' ! -name '*box' ! -name wmlsc ! -name wmlsdasm | grep -v /CVS/ > files.txt cat < Source line statistics `date +%Y-%m-%d` Number of files `wc -l < files.txt` Lines total `xargs cat < files.txt | wc -l` Non-empty lines `xargs grep -v '^[ ]*$' < files.txt | wc -l` Lines with semicolons`xargs grep ';' < files.txt | wc -l` EOF rm -f files.txt gateway-1.4.5/utils/utf8map.pl0000644000175000017500000000357407117206527014765 0ustar toljtolj#!/usr/bin/perl -wn # # utf8map.pl - remap ascii to utf8 # # Program was created to build conversion table from ascii into utf8. # Ascii table's first half does not require any changes (because utf8 # [0-127] encoding is the same as in ascii). To control second half's # encoding we have to specify all unicode codes for characters in # [128-255] interval. Program takes unicode codes for 128 characters # on input (in hex format with leading 0x) and generates conversion table . # Every utf8 code is padded by '0' and occupies 4 bytes. # It is suitable for use in 'C' programs. # # For example, # in windows-1257 table character 169 '(c)' has code 0x00A9 in unicode. # Program will generate folowing string: # # 0xC2, 0xA9, 0x00, 0x00, /* 169 0x00a9 */ # \______________________/ \___/ \______/ # utf8 code (2 bytes ascii unicode # with padding) # # USAGE: # perl utf8map.pl asci_128-255_unicode_table.txt # # Andrejs Dubovskis # use strict ; use vars qw/$N/ ; BEGIN { # we going to prepare table for characters in 128-255 interval $N = 128 ; } # look for hex number (unicode) for my $hex (/0x[\da-f]+/ig) { my $num = hex($hex) ; my @out = () ; if ($num > 0xffff) { die "too large number: $hex" ; } elsif ($num > 0x07ff) { # result is three bytes long @out = ( (($num >> 12) & 0xf) | 0xe0, (($num >> 6) & 0x3f) | 0x80, ($num & 0x3f) | 0x80 ) ; } elsif ($num > 0x7f) { # result is two bytes long @out = ( (($num >> 6) & 0x1f) | 0xc0, ($num & 0x3f) | 0x80 ) ; } else { # only zero is legal here die "wrong input data: $hex" if $num ; } # pad by '0' push(@out, 0) while @out < 4 ; # output utf8 code printf("0x%02X,\t0x%02X,\t0x%02X,\t0x%02X,\t", @out) ; # output comments print "/*\t$N\t$hex\t*/\n" ; # characters in [128-255] interval only exit if ++$N > 255 ; } gateway-1.4.5/utils/kannel-stable-rh7.spec0000644000175000017500000000726507462343074017141 0ustar toljtoljSummary: Kannel SMS/WAP gateway Name: kannel Version: 1.0.3 Release: 1 Copyright: Open source, FreeBSD-style license; see COPYING Group: Applications/Communications Source: gateway-%{version}.tar.gz BuildRoot: /var/tmp/%{name}-buildroot Packager: Peter Gronholm. Requires: libxml2 >= 2.3.0 %description Kannel is an Open Source SMS/WAP gateway. WAP is short for Wireless Application Protocol. It lets the phone act as a simple hypertext browser, but optimizes the markup language, scripting language, and the transmission protocols for wireless use. The optimized protocols are translated to normal Internet protocols by a WAP gateway. Kannel also works as a SMS gateway for GSM networks. Almost all GSM phones can send and receive SMS messages, so this is a way to serve many more clients than just those using WAP phones. %prep rm -rf $RPM_BUILD_ROOT %setup -n gateway-%{version} %build ./configure --with-malloc-native --enable-docs --enable-ssl --enable-mysql\ --with-ssl=/usr/lib --with-mysql=/usr/lib make %install make bindir=$RPM_BUILD_ROOT/usr/local/bin suffix= install mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d mkdir -p $RPM_BUILD_ROOT/etc/kannel mkdir -p $RPM_BUILD_ROOT/usr/share/man/man8 install -m 644 gw/wapkannel.conf $RPM_BUILD_ROOT/etc/kannel/kannel.conf install -m 644 gw/smskannel.conf $RPM_BUILD_ROOT/etc/kannel install -m 644 gw/kannel.8 $RPM_BUILD_ROOT/usr/share/man/man8 install -m 644 test/fakesmsc $RPM_BUILD_ROOT/usr/local/bin install -m 644 test/fakewap $RPM_BUILD_ROOT/usr/local/bin install -m 755 utils/kannel-init.d $RPM_BUILD_ROOT/etc/rc.d/init.d/kannel install -m 644 utils/run_kannel_box.8 $RPM_BUILD_ROOT/usr/share/man/man8 install -m 644 utils/start-stop-daemon.8 $RPM_BUILD_ROOT/usr/share/man/man8 strip $RPM_BUILD_ROOT/usr/local/bin/bearerbox strip $RPM_BUILD_ROOT/usr/local/bin/wapbox strip $RPM_BUILD_ROOT/usr/local/bin/smsbox strip $RPM_BUILD_ROOT/usr/local/bin/fakesmsc strip $RPM_BUILD_ROOT/usr/local/bin/fakewap strip $RPM_BUILD_ROOT/usr/local/bin/run_kannel_box strip $RPM_BUILD_ROOT/usr/local/bin/start-stop-daemon strip $RPM_BUILD_ROOT/usr/local/bin/wmlsc strip $RPM_BUILD_ROOT/usr/local/bin/wmlsdasm strip $RPM_BUILD_ROOT/usr/local/bin/seewbmp %files %defattr(-,root,root) %doc README README.docbook README.src README.wmlscript INSTALL AUTHORS COPYING VERSION NEWS ChangeLog doc/ gw/control.html contrib/ /usr/local/bin/ /etc/rc.d/init.d/kannel /usr/share/man/man8 %config(noreplace) /etc/kannel/kannel.conf %config(noreplace) /etc/kannel/smskannel.conf %post ln -sf /usr/local/bin/bearerbox /usr/bin/bearerbox ln -sf /usr/local/bin/wapbox /usr/bin/wapbox ln -sf /usr/local/bin/smsbox /usr/bin/smsbox ln -sf /usr/local/bin/start-stop-daemon /usr/bin/start-stop-daemon ln -sf /usr/local/bin/run_kannel_box /usr/bin/run_kannel_box %postun rm -f /usr/bin/bearerbox rm -f /usr/bin/wapbox rm -f /usr/bin/smsbox rm -f /usr/bin/start-stop-daemon rm -f /usr/bin/run_kannel_box %clean rm -rf $RPM_BUILD_ROOT %changelog * Fri Mar 30 2001 Peter Gronholm - added that Kannel requires libxml2 >= 2.3.0 * Fri Mar 30 2001 Peter Gronholm - removed that Kannel requires libxml2 < 2.3.0 * Tue Feb 27 2001 Peter Gronholm - moved rm -rf $RPM_BUILD_ROOT from %install to %prep - added that Kannel requires libxml2 < 2.3.0 * Tue Feb 06 2001 Peter Gronholm - install configuration files with %config macro. - clean $RPM_BUILD_ROOT before and after building the rpm package. - %postun macro: remove links to Kannel binaries from /usr/bin when uninstalling rpm package. - removed -b option from install command in %install macro. * Tue Jan 02 2001 Peter Gronholm - initial release of Kannel rpm package. gateway-1.4.5/utils/start-stop-daemon.80000644000175000017500000001063607065656643016525 0ustar toljtolj.\" Hey, Emacs! This is an -*- nroff -*- source file. .TH START\-STOP\-DAEMON 8 "15th March 1997" "Debian Project" "Debian GNU/Linux" .SH NAME start\-stop\-daemon \- start and stop system daemon programs .SH SYNOPSIS .B start-stop-daemon .BR -S|--start .IR "options ... -- arguments ..." .HP .B start-stop-daemon .BR -K|--stop .IR "options ..." .HP .B start-stop-daemon .BR -H|--help .HP .B start-stop-daemon .BR -V|--version .SH DESCRIPTION .B start\-stop\-daemon is used to control the creation and termination of system-level processes. Using the .BR --exec , .BR --pidfile , .BR --user , and .BR --name options, .B start\-stop\-daemon can be configured to find existing instances of a running process. With .BR --start , .B start\-stop\-daemon checks for the existence of a specified process. If such a process exists, .B start\-stop\-daemon does nothing, and exits with error status 1 (0 if .BR --oknodo is specified). If such a process does not exist, it starts an instance, using either the executable specified by .BR --exec , (or, if specified, by .BR --startas ). Any arguments given after .BR -- on the command line are passed unmodified to the program being started. With .BR --stop , .B start\-stop\-daemon also checks for the existence of a specified process. If such a process exists, .B start\-stop\-daemon sends it the signal specified by .BR --signal , and exits with error status 0. If such a process does not exist, .B start\-stop\-daemon exits with error status 1 (0 if .BR --oknodo is specified). .SH OPTIONS .TP .I -x|--exec executable Check for processes that are instances of this executable (according to .B /proc/ .I pid .B /exe ). .TP .I -p|--pidfile pid-file Check for processes whose process-id is specified in .I pid-file. .TP .I -u|--user username|uid Check for processes owned by the user specified by .I username or .I uid. .TP .I -n|--name process-name Check for processes with the name .I process-name (according to .B /proc/ .I pid .B /stat ). .TP .I -s|--signal signal With .BR --stop , specifies the signal to send to processes being stopped (default 15). .TP .I -a|--startas pathname With .B --start , start the process specified by .I pathname. If not specified, defaults to the argument given to .B --exec. .TP .I -t|--test Print actions that would be taken and set appropriate return value, but take no action. .TP .I -o|--oknodo Return exit status 0 instead of 1 if no actions are (would be) taken. .TP .I -q|--quiet Do not print informational messages; only display error messages. .TP .I -c|--chuid Change to this username/uid before starting the process. You can also specify a group by appending a ':', then the group or gid in the same way as you would for the `chown' command (user:group). When using this option you must realize that the primary and suplimental groups are set as well, even if the `group' options is not specified. The group option is only for groups that the user isn't normally a member of (like adding per/process group membership for generic users like `nobody'). .TP .I -r|--chroot root Chdir and chroot to .B root before starting the process. Please note that the pidfile is also written after the chroot. .TP .I -b|--background Typically used with programs that don't detach on their own. This option will force .B start-stop-daemon to fork before starting the process, and force it into the background. .B WARNING: start-stop-daemon cannot check the exit status if the process fails to execute for .B any reason. This is a last resort, and is only meant for programs that either make no sense forking on their own, or where it's not feasible to add the code for it to do this itself. .TP .I -m|--make-pidfile Used when starting a program that does not create its own pid file. This option will make .B start-stop-daemon create the file referenced with .B --pidfile and place the pid into it just before executing the process. Note, it will not be removed when stopping the program. .B NOTE: This feature may not work in all cases. Most notably when the program being executed forks from it's main process. Because of this it is usually only useful when combined with the .B --background option. .TP .I -v|--verbose Print verbose informational messages. .TP .I -H|--help Print help information; then exit. .TP .I -V|--version Print version information; then exit. .SH AUTHORS Ian Jackson Marek Michalkiewicz Manual page by Klee Dienes . gateway-1.4.5/utils/run_kannel_box.80000644000175000017500000000153407166363552016141 0ustar toljtolj.\" Hey, Emacs! This is an -*- nroff -*- source file. .TH RUN_KANNEL_BOX 8 "3rd October 2000" "Kannel Project" "Kannel Project" .SH NAME run_kannel_box \- Run a Kannel box .SH SYNOPSIS .B run_kannel_box .BR "" [ --pidfile .IR PIDFILE ] .BR "" [ --min-delay .IR SECONDS ] .I BOXPATH .IR "" [ boxoptions ...] .SH DESCRIPTION .B run_kannel_box runs a .BR kannel (8) box, i.e., one of the daemon programs of Kannel. is an WAP and SMS gateway. WAP is short for Wireless Application Protocol, and is used to implement hypertext based services on mobile phones. SMS is short for Short Message Service, and is used to send and recive short (up to 160 characters) text messages with mobile phones. SMS can also be used to implement simple text based services on mobile phones. .PP For more information, see .B http://www.kannel.org or .BR file://usr/doc/kannel/ . gateway-1.4.5/utils/OTAbitmap.h0000644000175000017500000001101513227613126015016 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef OTABITMAP_H #define OTABITMAP_H /* OTA Bitmap - used for CLI Icon and Operator logo messages * * Kalle Marjola 1999 for WapIT Ltd. * * functions to store OTA Bitmaps and and create Octet strings from them */ #include "gwlib/gwlib.h" /* OTA Bitmap */ typedef struct OTA_bitmap { Octet infofield; Octet *ext_fields; int extfield_count; int width; /* 8 or 16 bits, defined by infofield */ int height; /* ditto */ int depth; Octet *main_image; Octet **animated_image; int animimg_count; /* total # of animated images */ /* Octet *palette; */ } OTAbitmap; /* create a new empty OTAbitmap struct. Return a pointer to it or NULL if * operation fails */ OTAbitmap *OTAbitmap_create_empty(void); /* delete given OTAbitmap, including freeing the pixmap */ void OTAbitmap_delete(OTAbitmap *pic); #define NEGATIVE 1 /* source has white=0, black=1 */ #define REVERSE 2 /* source has righmost as most significant */ /* create a new bitmap * * width and height are size of the bitmap, * data is the entire bitmap; from left-top corner to righ-bottom; * if the width is not dividable by 8, the rest of the row is NOT padded * with zeros. bytes are ordered big-endian * * target: black=0, white=1, most significant leftmost * * You can generate raw bitmap in Linux (RH 6.0) with following line: * %> convert -monochrome input_file target.mono * * ..which then requires flags REVERSE and NEGATIVE * * return pointer to created OTAbitmap, or NULL if fails */ OTAbitmap *OTAbitmap_create(int width, int height, int depth, Octet *data, int flags); /* create Octet stream out of given OTAbitmap * return the length of stream, *stream is set to new stream which must * be freed by the caller */ int OTAbitmap_create_stream(OTAbitmap *pic, Octet **stream); #endif gateway-1.4.5/utils/daily-patch0000755000175000017500000000207507076116557015173 0ustar toljtolj#!/bin/sh # # daily-patch - generate and e-mail the daily patch for Kannel # # DO NOT RUN THIS SCRIPT, unless you know the recipient and the CVS maintainer # want you to. # # Make a "daily patch", or actually just a patch from the previous time # this script was run. # # Lars Wirzenius # set -e addr="" CVSROOT=":pserver:anonymoua@cvs.kannel.org:/home/cvs" tagsuffix="debug" newtag="new_daily_patch_tag$tagsuffix" tag="daily_patch_tag$tagsuffix" temp=/tmp/daily-patch.$$ for module in "$@" do cvs -Q -d$CVSROOT rtag -F -a -D now $newtag $module rm -f $temp cvs -Q -d$CVSROOT rdiff -s -r $tag -r $newtag -u $module >> $temp if [ -s "$temp" ] then echo "" >> $temp echo "" >> $temp echo "" >> $temp cvs -Q -d$CVSROOT rdiff -r $tag -r $newtag -u $module | awk '/^Index: / { if ($2 == "gateway/configure") hide = 1 else hide = 0 } !hide { print $0 }' >> $temp cat $temp else echo "No changes in $module since yesterday." fi | mail -s "Daily patch: $module" $addr rm -f $temp cvs -Q -d$CVSROOT rtag -F -a -r $newtag $tag $module done gateway-1.4.5/utils/find-long-lines0000755000175000017500000000123507501671431015744 0ustar toljtolj#!/bin/sh # # This script looks for long lines in source files in Kannel. # # Lars Wirzenius if [ ! -e /usr/bin/expand ] then # No expand -> we can't expand tabs -> let's just fail silently exit 0 fi if [ -z "$1" ] then dirs="." else dirs="$@" fi find $dirs -type f ! -name '*.[oa]' ! -name '.*' ! -name '*.ps' ! \ -name '*.html' ! -name '*.pdf' ! -name '*.rtf' ! \ -name '*.png' ! -name core ! -name configure ! -name config.status \ ! -name '*.log' ! -name '*.fig' | grep -v '/CVS/' | while read file do if file "$file" | grep executable >/dev/null then : else expand $file | awk -vfile="$file" 'length > 78 { print file ":" NR ":" $0 }' fi done gateway-1.4.5/utils/Makefile.in0000644000175000017500000007257213312227404015104 0ustar toljtolj# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = seewbmp$(EXEEXT) mtbatch$(EXEEXT) \ decode_emimsg$(EXEEXT) sbin_PROGRAMS = run_kannel_box$(EXEEXT) $(am__EXEEXT_1) @BUILD_STARTSTOPDAEMON_TRUE@am__append_1 = start-stop-daemon subdir = utils DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/gw-config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" @BUILD_STARTSTOPDAEMON_TRUE@am__EXEEXT_1 = start-stop-daemon$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS) am_decode_emimsg_OBJECTS = decode_emimsg.$(OBJEXT) decode_emimsg_OBJECTS = $(am_decode_emimsg_OBJECTS) decode_emimsg_DEPENDENCIES = $(top_builddir)/libgwlib.a \ $(top_builddir)/libgw.a AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_mtbatch_OBJECTS = mtbatch.$(OBJEXT) mtbatch_OBJECTS = $(am_mtbatch_OBJECTS) mtbatch_DEPENDENCIES = $(top_builddir)/libgwlib.a \ $(top_builddir)/libgw.a am_run_kannel_box_OBJECTS = run_kannel_box.$(OBJEXT) run_kannel_box_OBJECTS = $(am_run_kannel_box_OBJECTS) run_kannel_box_DEPENDENCIES = $(top_builddir)/libgwlib.a \ $(top_builddir)/libgw.a am_seewbmp_OBJECTS = seewbmp.$(OBJEXT) seewbmp_OBJECTS = $(am_seewbmp_OBJECTS) seewbmp_DEPENDENCIES = $(top_builddir)/libgwlib.a \ $(top_builddir)/libgw.a am__start_stop_daemon_SOURCES_DIST = start-stop-daemon.c @BUILD_STARTSTOPDAEMON_TRUE@am_start_stop_daemon_OBJECTS = \ @BUILD_STARTSTOPDAEMON_TRUE@ start-stop-daemon.$(OBJEXT) start_stop_daemon_OBJECTS = $(am_start_stop_daemon_OBJECTS) @BUILD_STARTSTOPDAEMON_TRUE@start_stop_daemon_DEPENDENCIES = \ @BUILD_STARTSTOPDAEMON_TRUE@ $(top_builddir)/libgwlib.a \ @BUILD_STARTSTOPDAEMON_TRUE@ $(top_builddir)/libgw.a AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(decode_emimsg_SOURCES) $(mtbatch_SOURCES) \ $(run_kannel_box_SOURCES) $(seewbmp_SOURCES) \ $(start_stop_daemon_SOURCES) DIST_SOURCES = $(decode_emimsg_SOURCES) $(mtbatch_SOURCES) \ $(run_kannel_box_SOURCES) $(seewbmp_SOURCES) \ $(am__start_stop_daemon_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man1_MANS) $(man8_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONVERT = @CONVERT@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOCDRAFTS = @DOCDRAFTS@ DOCSTARGET = @DOCSTARGET@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ DVIPS = @DVIPS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ EXE_EXT = @EXE_EXT@ FGREP = @FGREP@ FIG2DEV = @FIG2DEV@ GREP = @GREP@ GSOAP_SHARE = @GSOAP_SHARE@ GW_VERSION = @GW_VERSION@ HTML_DSL = @HTML_DSL@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ JADE = @JADE@ JADETEX = @JADETEX@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBICONV = @LIBICONV@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBICONV = @LTLIBICONV@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ MYSQL_CONFIG = @MYSQL_CONFIG@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OLD_LIBTOOL = @OLD_LIBTOOL@ OPENSSL = @OPENSSL@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PCRE_CONFIG = @PCRE_CONFIG@ PDFJADETEX = @PDFJADETEX@ PERL = @PERL@ PGSQL_CONFIG = @PGSQL_CONFIG@ PKGADD_NAME = @PKGADD_NAME@ PKGADD_PKG = @PKGADD_PKG@ PKGADD_VENDOR = @PKGADD_VENDOR@ RANLIB = @RANLIB@ REDIS_CONFIG = @REDIS_CONFIG@ SDB_CONFIG = @SDB_CONFIG@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SIZEOF_INT = @SIZEOF_INT@ SIZEOF_LONG = @SIZEOF_LONG@ SIZEOF_LONG_LONG = @SIZEOF_LONG_LONG@ SIZEOF_SHORT = @SIZEOF_SHORT@ SOAPCPP = @SOAPCPP@ SOAP_INCLUDE = @SOAP_INCLUDE@ SQLITE = @SQLITE@ SQLITE3 = @SQLITE3@ STRIP = @STRIP@ SUFFIX = @SUFFIX@ TEX_DSL = @TEX_DSL@ VERSION = @VERSION@ WSDL2H = @WSDL2H@ XML_CONFIG = @XML_CONFIG@ XML_DCL = @XML_DCL@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_CFLAGS = -I. -I$(top_builddir)/gw -I$(top_builddir)/gwlib -I$(top_builddir) man1_MANS = seewbmp.1 mtbatch.1 man8_MANS = run_kannel_box.8 seewbmp_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a seewbmp_SOURCES = \ seewbmp.c mtbatch_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a mtbatch_SOURCES = \ mtbatch.c decode_emimsg_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a decode_emimsg_SOURCES = \ decode_emimsg.c run_kannel_box_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a run_kannel_box_SOURCES = \ run_kannel_box.c @BUILD_STARTSTOPDAEMON_TRUE@start_stop_daemon_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a @BUILD_STARTSTOPDAEMON_TRUE@start_stop_daemon_SOURCES = \ @BUILD_STARTSTOPDAEMON_TRUE@ start-stop-daemon.c all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu utils/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu utils/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list decode_emimsg$(EXEEXT): $(decode_emimsg_OBJECTS) $(decode_emimsg_DEPENDENCIES) $(EXTRA_decode_emimsg_DEPENDENCIES) @rm -f decode_emimsg$(EXEEXT) $(AM_V_CCLD)$(LINK) $(decode_emimsg_OBJECTS) $(decode_emimsg_LDADD) $(LIBS) mtbatch$(EXEEXT): $(mtbatch_OBJECTS) $(mtbatch_DEPENDENCIES) $(EXTRA_mtbatch_DEPENDENCIES) @rm -f mtbatch$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mtbatch_OBJECTS) $(mtbatch_LDADD) $(LIBS) run_kannel_box$(EXEEXT): $(run_kannel_box_OBJECTS) $(run_kannel_box_DEPENDENCIES) $(EXTRA_run_kannel_box_DEPENDENCIES) @rm -f run_kannel_box$(EXEEXT) $(AM_V_CCLD)$(LINK) $(run_kannel_box_OBJECTS) $(run_kannel_box_LDADD) $(LIBS) seewbmp$(EXEEXT): $(seewbmp_OBJECTS) $(seewbmp_DEPENDENCIES) $(EXTRA_seewbmp_DEPENDENCIES) @rm -f seewbmp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(seewbmp_OBJECTS) $(seewbmp_LDADD) $(LIBS) start-stop-daemon$(EXEEXT): $(start_stop_daemon_OBJECTS) $(start_stop_daemon_DEPENDENCIES) $(EXTRA_start_stop_daemon_DEPENDENCIES) @rm -f start-stop-daemon$(EXEEXT) $(AM_V_CCLD)$(LINK) $(start_stop_daemon_OBJECTS) $(start_stop_daemon_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode_emimsg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mtbatch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/run_kannel_box.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/seewbmp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/start-stop-daemon.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-man8: $(man8_MANS) @$(NORMAL_INSTALL) @list1='$(man8_MANS)'; \ list2=''; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) $(MANS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-man \ uninstall-sbinPROGRAMS uninstall-man: uninstall-man1 uninstall-man8 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool \ clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man1 install-man8 \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-man uninstall-man1 uninstall-man8 \ uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gateway-1.4.5/utils/foobar-config.sh0000755000175000017500000000160410203150325016066 0ustar toljtolj#!/bin/sh # # foobar-config.sh -- a generic foobar-config shell script generator # # This generator takes 3 arguments and creates a foobar-config shell # scirpt that is used to determine the common CFLAGS for compiling # again this foobar package, LIBS for linking against dependency libs # and VERSION for displaying which version is used/installed. # # Derived from Ulric Eriksson from the libsdb project. # # Stipe Tolj # cat << EOF #!/bin/sh usage() { echo "usage: \$0 [--cflags] [--libs] [--version]" exit 0 } cflags=no libs=no version=no test "\$1" || usage while test "\$1"; do case "\$1" in --cflags ) cflags=yes ;; --libs ) libs=yes ;; --version ) version=yes ;; * ) usage ;; esac shift done test "\$cflags" = yes && cat << FOO $1 FOO test "\$libs" = yes && cat << FOO $2 FOO test "\$version" = yes && cat << FOO $3 FOO EOF gateway-1.4.5/utils/mtbatch.c0000644000175000017500000003515513227613126014626 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * mtbatch.c - an MT batch run utility for bearerbox * * This utility reads in a content file which has the SMS text message and * a receivers file, which has receiver numbers in each line. It connects * to bearerbox as if it would be a smsbox and issues the SMS sequentially * to bearerbox. * * Stipe Tolj * Vincent Chavanis * * XXX Add UDH capabilities. * XXX Support more charsets than 7-bit. */ #include #include #include #include "gwlib/gwlib.h" #include "msg.h" #include "sms.h" #include "dlr.h" #include "bb.h" #include "shared.h" #include "heartbeat.h" static char *pid_file; static Octstr *smsbox_id = NULL; static Octstr *content = NULL; static List *lines = NULL; static Octstr *bb_host; static long bb_port; static int bb_ssl; static Counter *counter; static Octstr *service = NULL; static Octstr *account = NULL; static Octstr *from = NULL; static int dlr_mask = 0; static Octstr *dlr_url = NULL; static Octstr *smsc_id = NULL; static double delay = 0; static int no_smsbox_id = 0; static void write_pid_file(void) { FILE *f; if (pid_file != NULL) { f = fopen(pid_file, "w"); fprintf(f, "%d\n", (int)getpid()); fclose(f); } } /*********************************************************************** * Communication with the bearerbox. */ /* * Identify ourself to bearerbox for smsbox-specific routing inside bearerbox. * Do this even while no smsbox-id is given to unlock the sender thread in * bearerbox. */ static void identify_to_bearerbox(void) { Msg *msg; msg = msg_create(admin); msg->admin.command = cmd_identify; msg->admin.boxc_id = octstr_duplicate(smsbox_id); write_to_bearerbox(msg); } /* * Read an Msg from the bearerbox and send it to the proper receiver * via a List. At the moment all messages are sent to the smsbox_requests * List. */ static void read_messages_from_bearerbox(void *arg) { time_t start, t; unsigned long secs; unsigned long total_s, total_f, total_ft, total_b, total_o; Msg *msg; total_s = total_f = total_ft = total_b = total_o = 0; start = t = time(NULL); while (program_status != shutting_down) { int ret; /* block infinite for reading messages */ ret = read_from_bearerbox(&msg, 0.5); if (ret == -1) break; else if (ret == 1) /* timeout */ continue; else if (msg == NULL) /* just to be sure, may not happens */ break; if (msg_type(msg) == admin) { if (msg->admin.command == cmd_shutdown || msg->admin.command == cmd_restart) { info(0, "Bearerbox told us to die"); program_status = shutting_down; } /* * XXXX here should be suspend/resume, add RSN */ msg_destroy(msg); } else if (msg_type(msg) == ack) { counter_increase(counter); switch (msg->ack.nack) { case ack_success: total_s++; break; case ack_failed: total_f++; break; case ack_failed_tmp: total_ft++; break; case ack_buffered: total_b++; break; } msg_destroy(msg); } else { warning(0, "Received other message than ack/admin, ignoring!"); msg_destroy(msg); total_o++; } } secs = difftime(time(NULL), start); info(0, "Received acks: %ld success, %ld failed, %ld failed temporarly, %ld queued, %ld other in %ld seconds " "(%.2f per second)", total_s, total_f, total_ft, total_b, total_o, secs, (float)(total_s+total_f+total_ft+total_b) / secs); } /* * Send a message to the bearerbox for delivery to a phone. * Return >= 0 for success & count of splitted sms messages, * -1 for failure. Does not destroy the msg. */ static int send_message(Msg *msg) { unsigned long msg_count; List *list; gw_assert(msg != NULL); gw_assert(msg_type(msg) == sms); /* * Encode our smsbox-id to the msg structure. * This will allow bearerbox to return specific answers to the * same smsbox, mainly for DLRs and SMS proxy modes. * * In addition the -x flag can be used to identify the mtbatch * instance with an own smsbox-id, but let the normal smsbox * daemons handle the DLRs coming back, as the mtbatch shuts down * after all MTs have been injected. It's not meant to process * the DLR messages. */ if (no_smsbox_id == 0 && smsbox_id != NULL) { msg->sms.boxc_id = octstr_duplicate(smsbox_id); } list = sms_split(msg, NULL, NULL, NULL, NULL, 1, 0, 100, MAX_SMS_OCTETS); msg_count = gwlist_len(list); gwlist_destroy(list, msg_destroy_item); debug("sms", 0, "message length %ld, sending %ld messages", octstr_len(msg->sms.msgdata), msg_count); if (delay > 0) gwthread_sleep(delay); /* pass message to bearerbox */ if (deliver_to_bearerbox(msg) != 0) return -1; return msg_count; } static void help(void) { info(0, "Usage: mtbatch [options] content-file receivers-file ..."); info(0, "where options are:"); info(0, "-v number"); info(0, " set log level for stderr logging"); info(0, "-b host"); info(0, " defines the host of bearerbox (default: localhost)"); info(0, "-p port"); info(0, " the smsbox port to connect to (default: 13001)"); info(0, "-s"); info(0, " inidicatr to use SSL for bearerbox connection (default: no)"); info(0, "-i smsbox-id"); info(0, " defines the smsbox-id to be used for bearerbox connection (default: none)"); info(0, "-x"); info(0, " indicator to not use smsbox-id in messages send to bearerbox (default: yes)"); info(0, "-f sender"); info(0, " which sender address should be used"); info(0, "-D dlr-mask"); info(0, " defines the dlr-mask"); info(0, "-u dlr-url"); info(0, " defines the dlr-url"); info(0, "-n service"); info(0, " defines which service name should be logged (default: none)"); info(0, "-a account"); info(0, " defines which account name should be logged (default: none)"); info(0, "-d seconds"); info(0, " delay between message sending to bearerbox (default: 0)"); info(0, "-r smsc-id"); info(0, " use a specific route for the MT traffic"); } static void init_batch(Octstr *cfilename, Octstr *rfilename) { Octstr *receivers; long lineno = 0; content = octstr_read_file(octstr_get_cstr(cfilename)); octstr_strip_crlfs(content); if (content == NULL) panic(0,"Can not read content file `%s'.", octstr_get_cstr(cfilename)); info(0,"SMS-Text: <%s>", octstr_get_cstr(content)); info(0,"Loading receiver list. This may take a while..."); receivers = octstr_read_file(octstr_get_cstr(rfilename)); if (receivers == NULL) panic(0,"Can not read receivers file `%s'.", octstr_get_cstr(rfilename)); lines = octstr_split(receivers, octstr_imm("\n")); lineno = gwlist_len(lines); if (lineno <= 0) panic(0,"Receiver file seems empty!"); info(0,"Receivers file `%s' contains %ld destination numbers.", octstr_get_cstr(rfilename), lineno); counter = counter_create(); } static unsigned long run_batch(void) { Octstr *no; unsigned long linerr = 0; unsigned long lineno = 0; while ((no = gwlist_consume(lines)) != NULL) { if (octstr_check_range(no, 0, 256, gw_isdigit)) { Msg *msg; lineno++; msg = msg_create(sms); msg->sms.smsc_id = smsc_id ? octstr_duplicate(smsc_id) : NULL; msg->sms.service = service ? octstr_duplicate(service) : NULL; msg->sms.sms_type = mt_push; msg->sms.sender = octstr_duplicate(from); msg->sms.receiver = octstr_duplicate(no); msg->sms.account = account ? octstr_duplicate(account) : NULL; msg->sms.msgdata = content ? octstr_duplicate(content) : octstr_create(""); msg->sms.dlr_mask = dlr_mask; msg->sms.dlr_url = octstr_duplicate(dlr_url); msg->sms.udhdata = octstr_create(""); msg->sms.coding = DC_7BIT; if (send_message(msg) < 0) { linerr++; info(0,"Failed to send message at line <%ld> for receiver `%s' to bearerbox.", lineno, octstr_get_cstr(no)); msg_destroy(msg); } } else { linerr++; error(0, "Receiver `%s' at line <%ld> contains non-digit characters, discarded!", octstr_get_cstr(no), lineno); } octstr_destroy(no); } info(0,"mtbatch has processed %ld messages with %ld errors.", lineno, linerr); return lineno; } int main(int argc, char **argv) { int opt; unsigned long sended = 0; Octstr *cf, *rf; gwlib_init(); bb_host = octstr_create("localhost"); bb_port = 13001; bb_ssl = 0; while ((opt = getopt(argc, argv, "hv:b:p:si:xn:a:f:D:u:d:r:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'b': octstr_destroy(bb_host); bb_host = octstr_create(optarg); break; case 'p': bb_port = atoi(optarg); break; case 's': bb_ssl = 1; break; case 'i': smsbox_id = octstr_create(optarg); break; case 'x': no_smsbox_id = 1; break; case 'n': service = octstr_create(optarg); break; case 'a': account = octstr_create(optarg); break; case 'f': from = octstr_create(optarg); break; case 'D': dlr_mask = atoi(optarg); break; case 'u': dlr_url = octstr_create(optarg); break; case 'd': delay = atof(optarg); break; case 'r': smsc_id = octstr_create(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (optind == argc || argc-optind < 2) { help(); exit(1); } /* check some mandatory elements */ if (from == NULL) panic(0,"Sender address not specified. Use option -f to specify sender address."); if ((DLR_IS_ENABLED(dlr_mask) && dlr_url == NULL) || (!DLR_IS_ENABLED(dlr_mask) && dlr_url != NULL)) panic(0,"dlr-url address OR dlr-mask not specified. Use option -D or -u to specify dlr values"); rf = octstr_create(argv[argc-1]); cf = octstr_create(argv[argc-2]); report_versions("mtbatch"); write_pid_file(); init_batch(cf, rf); connect_to_bearerbox(bb_host, bb_port, bb_ssl, NULL /* bb_our_host */); identify_to_bearerbox(); gwthread_create(read_messages_from_bearerbox, NULL); sended = run_batch(); /* avoid exiting before sending all msgs */ while (sended > counter_value(counter)) { gwthread_sleep(0.1); } program_status = shutting_down; gwthread_join_all(); octstr_destroy(bb_host); octstr_destroy(smsbox_id); octstr_destroy(content); octstr_destroy(service); octstr_destroy(account); octstr_destroy(dlr_url); octstr_destroy(smsc_id); counter_destroy(counter); gwlist_destroy(lines, octstr_destroy_item); gwlib_shutdown(); return 0; } gateway-1.4.5/utils/vimrc0000644000175000017500000000005507714723306014100 0ustar toljtoljset expandtab set sw=4 set ts=4 set sts=4 gateway-1.4.5/utils/run-checks0000755000175000017500000000077510361342026015022 0ustar toljtolj#!/bin/sh # # This script runs all the checks given in the command line. See the # README for more info. # rm -f check.log check.log.new for prog in "$@" do echo -n "Check: $prog..." $prog 2> check.log.new if test ! -s check.log.new then echo " OK." else echo " FAILURE!" echo "Check: $prog" >> check.log cat check.log.new >> check.log fi rm check.log.new done if test -s check.log then echo At least one check failed, see \`check.log\'. else echo All checks OK. rm -f check.log fi gateway-1.4.5/utils/wbmp.c0000644000175000017500000001126713227613126014147 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include #include #include #include #include "gwlib/gwlib.h" #include "wbmp.h" /* create empty WBMP */ WBMP *wbmp_create_empty(void) { WBMP *new; new = gw_malloc(sizeof(WBMP)); memset(new, 0, sizeof(WBMP)); return new; } /* delete a WBMP, freeing everything */ void wbmp_delete(WBMP *pic) { gw_free(pic->ext_header_field); gw_free(pic->main_image); if (pic->animated_image) { int i; for(i=0; i < pic->animimg_count; i++) gw_free(pic->animated_image[i]); gw_free(pic->animated_image); } gw_free(pic); } WBMP *wbmp_create(int type, int width, int height, Octet *data, int flags) { WBMP *new; int i, siz; Octet val; new = wbmp_create_empty(); new->type_field = type; if (type == 0) { new->fix_header_field = 0x00; } else { error(0, "WBMP type %d not supported", type); return NULL; } new->width = width; new->height = height; siz = (width+7)/8 * height; new->main_image = gw_malloc(siz); for(i=0; i < siz; i++) { if (flags & REVERSE) val = reverse_octet(data[i]); else val = data[i]; if (flags & NEGATIVE) val = ~val; new->main_image[i] = val; } return new; } /* create Octet stream from given WBMP */ int wbmp_create_stream(WBMP *pic, Octet **stream) { Octet tmp_w[30], tmp_h[30]; int wl, hl, pic_size; wl = write_variable_value(pic->width, tmp_w); hl = write_variable_value(pic->height, tmp_h); pic_size = ((pic->width+7)/8) * pic->height; if (pic->type_field != 0) { error(0, "Unknown WBMP type %d, cannot convert", pic->type_field); return -1; } *stream = gw_malloc(2+wl+hl+pic_size); sprintf(*stream, "%c%c", 0x00, 0x00); memcpy(*stream+2, tmp_w, wl); memcpy(*stream+2+wl, tmp_h, hl); memcpy(*stream+2+wl+hl, pic->main_image, pic_size); debug("util", 0, "picture %d x %d, stream length %d", pic->width, pic->height, 2+wl+hl+pic_size); return (2+wl+hl+pic_size); } gateway-1.4.5/utils/seewbmp.10000644000175000017500000000072107166363552014565 0ustar toljtolj.\" Hey, Emacs! This is an -*- nroff -*- source file. .TH SEEWBMP 1 "3rd October 2000" "Kannel Project" "Kannel Project" .SH NAME seewbmp \- Convert a WBMP wireless bitmap to textual format .SH SYNOPSIS .B seewbmp .IR "" [ inputfile ... ] .SH DESCRIPTION .B seewbmp reads one or more wireless bitmap images (WBMP files) and prints them to the standard output in a textual format. Each pixel is shown as either a space or an asterisk. .SH "SEE ALSO" .BR kannel (8) gateway-1.4.5/utils/accesslog_parser.pl0000755000175000017500000000610407240263136016707 0ustar toljtolj#!/usr/bin/perl # # accesslog_parser.pl # # Kalle Marjola for project Kannel, based on stat.pl by # 2000-05-12 jarkko@iki.fi use strict; my (%stat_in, %stat_out); my (%userstat_in, %userstat_out); my (%dailystat_in, %dailystat_out); my (%keywordstat_in); my $failed_send = 0; my $failed_rout = 0; my $rejected = 0; my $start = 0; my $ends = 0; my $line; while ($line = ) { chomp($line); # does string begin with date if ($line =~ /^(\d\d\d\d)-(\d\d)-(\d\d)\s+(\d\d)\:\d\d\:\d\d\s+(.*)$/) { my ($year, $month, $day, $hour, $msg) = ($1, $2, $3, $4, $5); my ($sender, $receiver, $keyword) = ($msg =~ /\[SMSC\:[^\]]*\] \[[^:]*\:([^\]]*)\] \[[^:]*:([^\]]*)\] \[[^:]*:(\w*)/i); if ($msg =~ /receive sms/i) { $stat_in{$sender}{"$year-$month-$day $hour"}++; $userstat_in{$sender}++; $dailystat_in{"$year-$month-$day $hour"}++; $keywordstat_in{lc($keyword)}{"$year-$month-$day $hour"}++; } elsif ($msg =~ /sent sms/i) { $stat_out{$receiver}{"$year-$month-$day $hour"}++; $userstat_out{$receiver}++; $dailystat_out{"$year-$month-$day $hour"}++; } elsif ($msg =~ /failed send sms/i) { $failed_send++; } elsif ($msg =~ /failed routing sms/i) { $failed_rout++; } elsif ($msg =~ /rejected/i) { $rejected++; } elsif ($msg =~ /log begins/i) { $start++; } elsif ($msg =~ /log ends/i) { $ends++; } } } my $key; my $key2; # daily/hourly user (phone-number) specific statistics print "By phone number\n===============\n"; print "Mobile Originated (from user):\n"; foreach $key (sort keys %stat_in) { print "$key:\n"; foreach $key2 (sort keys %{ $stat_in{$key} } ) { print "\t$key2 = $stat_in{$key}{$key2}\n"; } print "\t\t\t\tTotal: $userstat_in{$key}\n\n"; } print "Mobile Terminated (to user):\n"; foreach $key (sort keys %stat_out) { print "$key:\n"; foreach $key2 (sort keys %{ $stat_out{$key} } ) { print "\t$key2 = $stat_out{$key}{$key2}\n"; } print "\t\t\t\tTotal: $userstat_out{$key}\n\n"; } # statistics by keyword my $total; print "By keyword\n==========\n"; print "Mobile Originated (from user):\n"; foreach $key (sort keys %keywordstat_in) { print "$key:\n"; $total = 0; foreach $key2 (sort keys %{ $keywordstat_in{$key} } ) { print "\t$key2 = $keywordstat_in{$key}{$key2}\n"; $total += $keywordstat_in{$key}{$key2}; } print "\t\t\t\tTotal: $total\n\n"; } # statistics by hour basic my ($total_in, $total_out); print "Total usage\n===========\n"; print "Mobile Originated (from user):\n"; foreach $key (sort keys %dailystat_in) { $total_in += $dailystat_in{$key}; print "$key = $dailystat_in{$key}\n"; } print "\t\t\t\tTotal: $total_in\n\n"; print "Mobile Terminated (to user):\n"; foreach $key (sort keys %dailystat_out) { $total_out += $dailystat_out{$key}; print "$key = $dailystat_out{$key}\n"; } print "\t\t\t\tTotal: $total_out\n\n"; print "$failed_send failed sendings, $failed_rout failed routing, $rejected rejected messages\n"; my $ugly = $start - $ends; print "$start Kannel start-ups, $ugly crashes/ugly shutdowns\n"; gateway-1.4.5/utils/makedist0000755000175000017500000000237211453346234014564 0ustar toljtolj#!/bin/sh # # Create distribution files. # # Lars Wirzenius set -e version="$1" tag=version_`echo $version | tr .- __` base=gateway-$version repo="https://svn.kannel.org/gateway/tags/" rm -rf $base svn --quiet export ${repo}$tag $base if [ "`head -1 $base/VERSION`" != "$version" ] then echo "Oops, VERSION does not match." exit 1 fi tar -c -z -f $base.tar.gz $base md5sum $base.tar.gz > $base.tar.gz.md5 sha1sum $base.tar.gz > $base.tar.gz.sha1 tar -c -j -f $base.tar.bz2 $base md5sum $base.tar.bz2 > $base.tar.bz2.md5 sha1sum $base.tar.bz2 > $base.tar.bz2.sha1 zip -9qr $base.zip $base/* md5sum $base.zip > $base.zip.md5 sha1sum $base.zip > $base.zip.sha1 ( set -e cd $base ./configure --enable-docs >/dev/null touch .depend make -s depend make -s docs ) cp -a $base/doc/arch arch-$version cp $base/doc/arch/arch.ps arch-$version.ps tar -c -z -f arch-$version.tar.gz arch-$version/* zip -9qr arch-$version.zip arch-$version/* cp -a $base/doc/userguide userguide-$version cp $base/doc/userguide/userguide.ps userguide-$version.ps tar -c -z -f userguide-$version.tar.gz userguide-$version/* zip -9qr userguide-$version.zip userguide-$version/* cp $base/NEWS NEWS-$version cp $base/README README-$version cp $base/ChangeLog ChangeLog-$version gateway-1.4.5/utils/run_kannel_box.c0000644000175000017500000002574413227613126016213 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include #include #include #include #include #include #include #include #include #include #include #include #include static char *progname; /* The name of this program (for error messages) */ static char **box_arglist; static int min_restart_delay = 60; /* in seconds */ static pid_t child_box; /* used in main_loop, available to signal handlers */ static char *pidfile; /* The name of the pidfile to use. NULL if no pidfile */ static int use_extra_args = 1; /* Add "extra_arguments" list to argv? */ /* Extra arguments to pass to the box */ static char *extra_arguments[] = { "-v", "4", /* Minimal output on stderr, goes to /dev/null anyway */ }; #define NUM_EXTRA ((int) (sizeof(extra_arguments) / sizeof(*extra_arguments))) static void print_usage(FILE *stream) { fprintf(stream, "Usage: %s [--pidfile PIDFILE] [--min-delay SECONDS] BOXPATH [boxoptions...]\n", progname); } /* Create the argument list to pass to the box process, and put it * in the box_arglist global variable. This is also the right place * to add any standard arguments that we want to pass. */ static void build_box_arglist(char *boxfile, int argc, char **argv) { int i; char **argp; if (box_arglist) { free(box_arglist); } /* one for the boxfile name itself, one for each extra argument, * one for each normal argument, and one for the terminating NULL */ box_arglist = malloc((1 + NUM_EXTRA + argc + 1) * sizeof(*box_arglist)); if (!box_arglist) { fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno)); exit(1); } /* Have argp walk down box_arglist and set each argument. */ argp = box_arglist; *argp++ = boxfile; if (use_extra_args) { for (i = 0; i < NUM_EXTRA; i++) { *argp++ = extra_arguments[i]; } } for (i = 0; i < argc; i++) { *argp++ = argv[i]; } *argp++ = (char *)NULL; } static void write_pidfile(void) { int fd; FILE *f; if (!pidfile) return; fd = open(pidfile, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT, 0644); if (fd < 0) { fprintf(stderr, "%s: open: %s: %s\n", progname, pidfile, strerror(errno)); exit(1); } f = fdopen(fd, "w"); if (!f) { fprintf(stderr, "%s: fdopen: %s\n", progname, strerror(errno)); exit(1); } fprintf(f, "%ld\n", (long)getpid()); if (fclose(f) < 0) { fprintf(stderr, "%s: writing %s: %s\n", progname, pidfile, strerror(errno)); exit(1); } } static void remove_pidfile(void) { if (!pidfile) return; unlink(pidfile); } /* Set 0 (stdin) to /dev/null, and 1 and 2 (stdout and stderr) to /dev/full * if it's available and /dev/null otherwise. */ static void rebind_standard_streams(void) { int devnullfd; int devfullfd; devnullfd = open("/dev/null", O_RDONLY); if (devnullfd < 0) { fprintf(stderr, "%s: cannot open /dev/null: %s\n", progname, strerror(errno)); exit(2); } devfullfd = open("/dev/full", O_WRONLY); if (devfullfd < 0) { devfullfd = devnullfd; } /* Alert: The dup on stderr is done last, so that the error message * works regardless of which dup fails. */ if (dup2(devnullfd, 0) < 0 || dup2(devfullfd, 1) < 0 || dup2(devfullfd, 2) < 0) { fprintf(stderr, "%s: dup2: %s\n", progname, strerror(errno)); exit(1); } } /* Some code to determine the highest possible file descriptor number, * so that we can close them all. */ static int open_max(void) { #ifdef OPEN_MAX return OPEN_MAX; #else int max; max = sysconf(_SC_OPEN_MAX); if (max <= 0) { return 1024; /* guess */ } return max; #endif } /* Close all file descriptors other than 0, 1, and 2. */ static void close_extra_files(void) { int max = open_max(); int fd; for (fd = 3; fd < max; fd++) { close(fd); } } /* We received a signal that we should pass on to the child box. * We ignore it ourselves. */ static void signal_transfer(int signum) { if (child_box > 0) { kill(child_box, signum); } } /* We received a signal that we should pass on to the child box, * and then die from ourselves. It has to be a signal that * terminates the process as its default action! */ static void signal_transfer_and_die(int signum) { /* First send it to the child process */ if (child_box > 0) { kill(child_box, signum); } /* Prepare to die. Normally the atexit handler would take care * of this when we exit(), but we're going to die from a signal. */ remove_pidfile(); /* Then send it to self. First set the default handler, to * avoid catching the signal with this handler again. This * is not a race, because it doesn't matter if we die from * the signal we're going to send or from a different one. */ signal(signum, SIG_DFL); kill(getpid(), signum); } static void setup_signals(void) { signal(SIGHUP, &signal_transfer); signal(SIGINT, &signal_transfer_and_die); signal(SIGQUIT, &signal_transfer_and_die); signal(SIGTERM, &signal_transfer_and_die); signal(SIGUSR1, &signal_transfer); signal(SIGUSR2, &signal_transfer); } /* Fork off a box process and loop indefinitely, forking a new one * every time it dies. */ static int main_loop(char *boxfile) { time_t next_fork = 0; /* We can't report any errors here, because we are running * as a daemon and we have no logfile of our own. So we * exit with errno as the exit code, to offer a minimal clue. */ for (;;) { /* Make sure we don't fork in an endless loop if something * is drastically wrong. This code limits it to one * per minute (or whatever min_restart_delay is set to). */ time_t this_time = time(NULL); if (this_time <= next_fork) { sleep(next_fork - this_time); } next_fork = this_time + min_restart_delay; child_box = fork(); if (child_box < 0) { return errno; } if (child_box == 0) { /* child. exec the box */ execvp(boxfile, box_arglist); exit(127); } while (waitpid(child_box, (int *)NULL, 0) != child_box) { if (errno == ECHILD) { /* Something went wrong... we don't know what, * but we do know that our child does not * exist. So restart it. */ break; } if (errno == EINTR) { continue; } /* Something weird happened. */ return errno; } } } int main(int argc, char *argv[]) { int i; char *boxfile = NULL; pid_t childpid; progname = argv[0]; if (argc == 1) { print_usage(stderr); exit(2); } /* Parse the options meant for the wrapper, and get the name of * the box to wrap. */ for (i = 1; i < argc && !boxfile; i++) { if (strcmp(argv[i], "--pidfile") == 0) { if (i+1 >= argc) { fprintf(stderr, "Missing argument for option %s\n", argv[i]); exit(2); } pidfile = argv[i+1]; i++; } else if (strcmp(argv[i], "--min-delay") == 0) { if (i+1 >= argc) { fprintf(stderr, "Missing argument for option %s", argv[i]); exit(2); } min_restart_delay = atoi(argv[i+1]); i++; } else if (strcmp(argv[i], "--no-extra-args") == 0) { use_extra_args = 0; } else if (argv[i][0] == '-') { fprintf(stderr, "Unknown option %s\n", argv[i]); exit(2); } else { boxfile = argv[i]; } } /* Check if we have everything */ if (!boxfile) { print_usage(stderr); exit(2); } /* The remaining arguments should be passed to the box */ build_box_arglist(boxfile, argc - i, argv + i); /* Ready to rock. Begin daemonization. */ /* Fork a child process and have the parent exit. * This makes us run in the background. */ childpid = fork(); if (childpid < 0) { fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno)); exit(1); } if (childpid != 0) { exit(0); /* parent exits immediately */ } /* The child continues here. Now call setsid() to disconnect * from our terminal and from the parent's session and process * group. */ if (setsid() < 0) { fprintf(stderr, "%s: setsid: %s\n", progname, strerror(errno)); exit(1); } /* Change to the root directory, so that we don't keep a * file descriptor open on an unknown directory. */ if (chdir("/") < 0) { fprintf(stderr, "%s: chdir to root: %s\n", progname, strerror(errno)); exit(1); } atexit(remove_pidfile); write_pidfile(); /* Set the umask to a known value, rather than inheriting * an unknown one. */ umask(077); /* Leave file descriptors 0, 1, and 2 pointing to harmless * places, and close all other file descriptors. */ rebind_standard_streams(); close_extra_files(); setup_signals(); return main_loop(boxfile); } gateway-1.4.5/utils/attgetopt.c0000644000175000017500000001123113227613126015204 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * attgetopt.c - AT&T's public domain implementation of getopt. * * From the mod.sources newsgroup, volume 3, issue 58, with modifications * to bring it up to 21st century C. */ #include #include #include "gw-config.h" /* * If the systm has getopt() defined within stdio.h (like on Solaris 2.6) * then we will not implement our own here. */ #ifndef HAVE_GETOPT_IN_STDIO_H #define ERR(s, c) \ if (opterr) \ (void) fprintf(stderr, "%s: %s\n", argv[0], s) int opterr = 1; int optind = 1; int optopt; char *optarg; int getopt(int argc, char **argv, char *opts) { static int sp = 1; register int c; register char *cp; if(sp == 1) { if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') return(EOF); else if(strcmp(argv[optind], "--") == 0) { optind++; return(EOF); } } optopt = c = argv[optind][sp]; if(c == ':' || (cp=strchr(opts, c)) == NULL) { ERR(": illegal option -- ", c); if(argv[optind][++sp] == '\0') { optind++; sp = 1; } return('?'); } if(*++cp == ':') { if(argv[optind][sp+1] != '\0') optarg = &argv[optind++][sp+1]; else if(++optind >= argc) { ERR(": option requires an argument -- ", c); sp = 1; return('?'); } else optarg = argv[optind++]; sp = 1; } else { if(argv[optind][++sp] == '\0') { sp = 1; optind++; } optarg = NULL; } return(c); } #endif /* HAVE_GETOPT_IN_STDIO_H */ gateway-1.4.5/utils/chlog-stats0000755000175000017500000000112407227322205015201 0ustar toljtolj#!/usr/bin/awk -f # # Compute some simple statistics from a ChangeLog file. Output has several # columns: # # 1) number of changelog entries # 2) total lines in changelog entries # 3) average lines per entry # 4) username # # Output is not sorted. Use "sort -n" to sort. # # Lars Wirzenius /^[a-zA-Z0-9]/ { match($NF, /<.*@/) who = substr($NF, RSTART+1, RLENGTH-2) if (who == "") who = $NF entries[who]++ next } /[^ ]/ { lines[who]++ } END { for (who in entries) printf "%4d %4d %.1f %s\n", entries[who], lines[who], lines[who]/entries[who], who } gateway-1.4.5/utils/changelog-report0000755000175000017500000000120407065670456016226 0ustar toljtolj#!/bin/sh # # changelog-report - Report changes to ChangeLog # # DO NOT RUN THIS SCRIPT unless you make damn sure the e-mail address points # at somewhere who wants to receive it. # # This script reports changes to the ChangeLog file in the Kannel CVS # repository. # # Lars Wirzenius # set -e addr="" workdir="$HOME/gateway" tmp=ChangeLog.temp cd $workdir cvs -Q update ChangeLog diff -w -b -B -t ChangeLog.old ChangeLog | sed -n '/^> /s///p' >> $tmp || true if test -s $tmp then ( echo 'Changes to gateway ChangeLog.' echo '' cat $tmp ) | mail -s 'ChangeLog update' $addr fi cp ChangeLog ChangeLog.old rm -f $tmp gateway-1.4.5/utils/OTAbitmap.c0000644000175000017500000001200413227613126015010 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include #include #include #include #include "gwlib/gwlib.h" #include "OTAbitmap.h" /* create empty OTAbitmap */ OTAbitmap *OTAbitmap_create_empty(void) { OTAbitmap *new; new = gw_malloc(sizeof(OTAbitmap)); memset(new, 0, sizeof(OTAbitmap)); return new; } void OTAbitmap_delete(OTAbitmap *pic) { gw_free(pic->ext_fields); gw_free(pic->main_image); if (pic->animated_image) { int i; for(i=0; i < pic->animimg_count; i++) gw_free(pic->animated_image[i]); gw_free(pic->animated_image); } gw_free(pic); } OTAbitmap *OTAbitmap_create(int width, int height, int depth, Octet *data, int flags) { OTAbitmap *new; int i, j, siz, osiz; Octet val; new = OTAbitmap_create_empty(); if (width > 255 || height > 255) new->infofield = 0x10; /* set bit */ else new->infofield = 0x00; new->width = width; new->height = height; siz = (width * height + 7)/8; new->main_image = gw_malloc(siz); osiz = (width+7)/8 * height; for(i=j=0; i 0 && i % ((width+7)/8) == 0 && width % 8 > 0) j -= 8 + width % 8; if (j % 8 == 0) { new->main_image[j/8] = val; } else { new->main_image[j/8] |= val >> (j % 8); new->main_image[j/8 + 1] = val << (8 - j % 8); } } /* no palette nor animated images, yet */ return new; } /* create Octet stream from given OTAbitmap */ int OTAbitmap_create_stream(OTAbitmap *pic, Octet **stream) { Octet tmp_header[10]; int hdr_len; int pic_size; if (pic->infofield & 0x10) { sprintf(tmp_header, "%c%c%c%c%c%c", pic->infofield, pic->width/256, pic->width%256, pic->height/256, pic->height%256, pic->depth); hdr_len = 6; } else { sprintf(tmp_header, "%c%c%c%c", pic->infofield, pic->width, pic->height, pic->depth); hdr_len = 4; } pic_size = (pic->width * pic->height + 7)/8; *stream = gw_malloc(pic_size+pic_size); memcpy(*stream, tmp_header, hdr_len); memcpy(*stream + hdr_len, pic->main_image, pic_size); debug("util", 0, "picture %d x %d, stream length %d", pic->width, pic->height, hdr_len + pic_size); return (hdr_len + pic_size); } gateway-1.4.5/utils/Makefile.am0000644000175000017500000000152613207544475015077 0ustar toljtoljAM_CFLAGS = -I. -I$(top_builddir)/gw -I$(top_builddir)/gwlib -I$(top_builddir) bin_PROGRAMS = seewbmp mtbatch decode_emimsg sbin_PROGRAMS = run_kannel_box man1_MANS = seewbmp.1 mtbatch.1 man8_MANS = run_kannel_box.8 seewbmp_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a seewbmp_SOURCES = \ seewbmp.c mtbatch_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a mtbatch_SOURCES = \ mtbatch.c decode_emimsg_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a decode_emimsg_SOURCES = \ decode_emimsg.c run_kannel_box_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a run_kannel_box_SOURCES = \ run_kannel_box.c if BUILD_STARTSTOPDAEMON sbin_PROGRAMS += start-stop-daemon start_stop_daemon_LDADD = $(top_builddir)/libgwlib.a $(top_builddir)/libgw.a start_stop_daemon_SOURCES = \ start-stop-daemon.c endifgateway-1.4.5/utils/kannel-init.d0000755000175000017500000000447611542220113015407 0ustar toljtolj#!/bin/sh # Start/stop the Kannel boxes: One bearer box and one WAP box. # This is the default init.d script for Kannel. Its configuration is # appropriate for a small site running Kannel on one machine. # Make sure that the Kannel binaries can be found in $BOXPATH or somewhere # else along $PATH. run_kannel_box has to be in $BOXPATH. BOXPATH=/usr/bin PIDFILES=/var/run CONFDIR=/etc/kannel CONF=$CONFDIR/kannel.conf USER=kannel VERSION="" #VERSION="-0.12.4" RB=run_kannel_box$VERSION BB=bearerbox$VERSION WB=wapbox$VERSION SB=smsbox$VERSION SSD=start-stop-daemon$VERSION PATH=$BOXPATH:$PATH # On Debian, the most likely reason for the bearerbox not being available # is that the package is in the "removed" or "unconfigured" state, and the # init.d script is still around because it's a conffile. This is normal, # so don't generate any output. test -x $BOXPATH/$BB || exit 0 case "$1" in start) echo -n "Starting WAP gateway: bearerbox" $SSD --start --quiet --pidfile $PIDFILES/kannel_bearerbox.pid --exec $RB -- --pidfile $PIDFILES/kannel_bearerbox.pid $BB -- $CONF echo -n " wapbox" $SSD --start --quiet --pidfile $PIDFILES/kannel_wapbox.pid --exec $RB -- --pidfile $PIDFILES/kannel_wapbox.pid $WB -- $CONF # echo -n " smsbox" # $SSD --start --quiet --pidfile $PIDFILES/kannel_smsbox.pid --exec $RB -- --pidfile $PIDFILES/kannel_smsbox.pid $SB -- $CONF echo "." ;; stop) echo -n "Stopping WAP gateway: wapbox" $SSD --stop --quiet --pidfile $PIDFILES/kannel_wapbox.pid --exec $RB # echo -n " smsbox" # $SSD --stop --quiet --pidfile $PIDFILES/kannel_smsbox.pid --exec $RB echo -n " bearerbox" $SSD --stop --quiet --pidfile $PIDFILES/kannel_bearerbox.pid --exec $RB echo "." ;; status) CORE_CONF=$(grep -r 'group[[:space:]]*=[[:space:]]*core' $CONFDIR | cut -d: -f1) ADMIN_PORT=$(grep '^admin-port' $CORE_CONF | sed "s/.*=[[:space:]]*//") ADMIN_PASS=$(grep '^admin-password' $CORE_CONF | sed "s/.*=[[:space:]]*//") STATUS_URL="http://127.0.0.1:${ADMIN_PORT}/status.txt?password=${ADMIN_PASS}" lynx -source $STATUS_URL ;; reload) # We don't have support for this yet. exit 1 ;; restart|force-reload) $0 stop sleep 1 $0 start ;; *) echo "Usage: $0 {start|stop|status|reload|restart|force-reload}" exit 1 esac exit 0 gateway-1.4.5/utils/update-license-text.sh0000644000175000017500000000105513227613126017250 0ustar toljtolj#!/bin/sh # # update-license -- update prefix blocks with LICENSE text # # Run this script in gateway root directory to update the # current LICENSE text file to all source code files. # # to avoid sed errors like: # RE error: illegal byte sequence export LC_ALL=C old="2001-2017 Kannel Group" new="2001-2018 Kannel Group" prog=`basename $0` files=`find . -type f ! -name "${prog}" ! -path "*/.svn/*" ! -path "./addons/*" | xargs fgrep -lr "${old}"` for i in $files; do echo ${i} cat ${i} | sed "s/${old}/${new}/" > ${i}.new mv ${i}.new ${i} done gateway-1.4.5/utils/mtbatch.10000644000175000017500000000176112542461063014540 0ustar toljtolj.\" Hey, Emacs! This is an -*- nroff -*- source file. .TH MTBATCH 1 "22th January 2004" "Kannel Project" "Kannel Project" .SH NAME mtbatch \- Sends SMS in batch mode .SH SYNOPSIS .B mtbatch .IR "" [ options ] .I content-file receivers-file \&... .SH OPTIONS .TP .BI \-v\ number set log level for stderr logging .TP .BI \-b\ host defines the host of bearerbox (default: localhost) .TP .BI \-p\ port the smsbox port to connect to (default: 13002) .TP .B \-s inidicatr to use SSL for bearerbox connection (default: no) .TP .BI \-i\ smsbox-id defines the smsbox-id to be used for bearerbox connection (default: none) .TP .BI \-f\ sender which sender address should be used .TP .BI \-n\ service defines which service name should be logged (default: none) .TP .BI \-a\ account defines which account name should be logged (default: none) .TP .BI \-d\ seconds delay between message sending to bearerbox (default: 0) .TP .BI \-r\ smsc-id use a specific route for the MT traffic .SH "SEE ALSO" .BR kannel (8) gateway-1.4.5/utils/pixmapgen.pl0000755000175000017500000000110007014252375015351 0ustar toljtolj#!/usr/bin/perl use strict; # # a short perl script to convert (almost) any pictures into WBMP pictures # # Kalle Marjola for WapIT Ltd. 1999 # # USAGE: ./pixmapgen.pl SOURCE >TARGET # # # note: change following strings if needed to # my $temp_target = "/tmp/pmgen_tmp.mono"; # the program for mono->WBMP my $converter = "./test_wbmp"; # temporary file my $source = $ARGV[0]; my $retval = `convert -verbose -monochrome $source $temp_target`; my ($width, $height) = ($retval =~ /$temp_target (\d+)x(\d+)/s); print `$converter $temp_target $width $height`; gateway-1.4.5/utils/start-stop-daemon.c0000644000175000017500000005701413227613126016563 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* This utility was added to the Kannel source tree for the benefit of * those distributions that aren't Debian. It is used by kannel-init.d * to start and stop the run_kannel_box daemon. * It was copied from the dpkg 1.6.11 source tree on 21 March 2000. * If that was very long ago, refreshing the copy would be a good idea, * in case bugs were fixed. * Richard Braakman */ /* * A rewrite of the original Debian's start-stop-daemon Perl script * in C (faster - it is executed many times during system startup). * * Written by Marek Michalkiewicz , * public domain. Based conceptually on start-stop-daemon.pl, by Ian * Jackson . May be used and distributed * freely for any purpose. Changes by Christian Schwarz * , to make output conform to the Debian * Console Message Standard, also placed in public domain. Minor * changes by Klee Dienes , also placed in the Public * Domain. * * Changes by Ben Collins , added --chuid, --background * and --make-pidfile options, placed in public domain aswell. */ #include "gw-config.h" #if defined(linux) #define OSLinux #elif defined(__GNU__) #define OSHURD #elif defined(SunOS) #elif defined(__CYGWIN__) #elif defined(__FreeBSD__) || defined(__APPLE__) #define FreeBSD #else #error Unknown architecture - cannot build start-stop-daemon #endif #ifdef HAVE_HURH_H #include #endif #ifdef HAVE_PS_H #include #endif #include #include #include #include #include #include #include #include #include #if HAVE_GETOPT_H #include #endif #include #include #include #include #include #include #include /*Solaris needs to be told how to talk to it's proc filesystem*/ #define _STRUCTURED_PROC 1 #ifdef SunOS #include #endif #ifdef HAVE_ERROR_H #include #endif #ifdef HURD_IHASH_H #include #endif static int testmode = 0; static int quietmode = 0; static int exitnodo = 1; static int start = 0; static int stop = 0; static int background = 0; static int mpidfile = 0; static int signal_nr = 15; static const char *signal_str = NULL; static int user_id = -1; static int runas_uid = -1; static int runas_gid = -1; static const char *userspec = NULL; static char *changeuser = NULL; static char *changegroup = NULL; static char *changeroot = NULL; static const char *cmdname = NULL; static char *execname = NULL; static char *startas = NULL; static const char *pidfile = NULL; static const char *progname = ""; static struct stat exec_stat; #if defined(OSHURD) static struct ps_context *context; static struct proc_stat_list *procset; #endif struct pid_list { struct pid_list *next; int pid; }; static struct pid_list *found = NULL; static struct pid_list *killed = NULL; static void *xmalloc(int size); static void push(struct pid_list **list, int pid); static void do_help(void); static void parse_options(int argc, char * const *argv); #if defined(OSLinux) || defined(OSHURD) || defined(SunOS) || defined(FreeBSD) static int pid_is_user(int pid, int uid); static int pid_is_cmd(int pid, const char *name); #endif static void check(int pid); static void do_pidfile(const char *name); static int do_stop(void); #if defined(OSLinux) static int pid_is_exec(int pid, const struct stat *esb); #endif #if defined(OSHURD) static void do_psinit(void); #endif #ifdef __GNUC__ static void fatal(const char *format, ...) __attribute__((noreturn, format(printf, 1, 2))); static void badusage(const char *msg) __attribute__((noreturn)); #else static void fatal(const char *format, ...); static void badusage(const char *msg); #endif static void fatal(const char *format, ...) { va_list arglist; fprintf(stderr, "%s: ", progname); va_start(arglist, format); vfprintf(stderr, format, arglist); va_end(arglist); putc('\n', stderr); exit(2); } static void * xmalloc(int size) { void *ptr; ptr = malloc(size); if (ptr) return ptr; fatal("malloc(%d) failed", size); } static void push(struct pid_list **list, int pid) { struct pid_list *p; p = xmalloc(sizeof(*p)); p->next = *list; p->pid = pid; *list = p; } static void do_help(void) { /*Print the help for systems that have getopt long*/ #ifndef SunOS /*Solaris doesn't*/ printf("\ start-stop-daemon for Debian GNU/Linux - small and fast C version written by\n\ Marek Michalkiewicz , public domain.\n" GW_VERSION "\n\ \n\ Usage:\n\ start-stop-daemon -S|--start options ... -- arguments ...\n\ start-stop-daemon -K|--stop options ...\n\ start-stop-daemon -H|--help\n\ start-stop-daemon -V|--version\n\ \n\ Options (at least one of --exec|--pidfile|--user is required):\n\ -x|--exec program to start/check if it is running\n\ -p|--pidfile pid file to check\n\ -c|--chuid \n\ change to this user/group before starting process\n\ -u|--user | stop processes owned by this user\n\ -n|--name stop processes with this name\n\ -s|--signal signal to send (default TERM)\n\ -a|--startas program to start (default is )\n\ -b|--background force the process to detach\n\ -m|--make-pidfile create the pidfile before starting\n\ -t|--test test mode, don't do anything\n\ -o|--oknodo exit status 0 (not 1) if nothing done\n\ -q|--quiet be more quiet\n\ -v|--verbose be more verbose\n\ \n\ Exit status: 0 = done 1 = nothing done (=> 0 if --oknodo) 2 = trouble\n"); #else /* Deal with systems that don't have getopt long, like Solaris*/ printf("\ start-stop-daemon for Debian GNU/Linux - small and fast C version written by\n\ Marek Michalkiewicz , public domain.\n" GW_VERSION "\n\ \n\ Usage:\n\ start-stop-daemon -S options ... -- arguments ...\n\ start-stop-daemon -K options ...\n\ start-stop-daemon -H\n\ start-stop-daemon -V\n\ \n\ Options (at least one of --exec|--pidfile|--user is required):\n\ -x program to start/check if it is running\n\ -p pid file to check\n\ -c change to this user/group before starting process\n\ -u | stop processes owned by this user\n\ -n stop processes with this name\n\ -s signal to send (default TERM)\n\ -a program to start (default is )\n\ -b force the process to detach\n\ -m create the pidfile before starting\n\ -t test mode, don't do anything\n\ -o exit status 0 (not 1) if nothing done\n\ -q be more quiet\n\ -v be more verbose\n\ \n\ Exit status: 0 = done 1 = nothing done (=> 0 if -o) 2 = trouble\n"); #endif /*No more OS ( getopt ) specific stuff this function... */ } static void badusage(const char *msg) { if (msg) fprintf(stderr, "%s: %s\n", progname, msg); #ifndef SunOS fprintf(stderr, "Try `%s --help' for more information.\n", progname); #else fprintf(stderr, "Try `%s -H' for more information.\n", progname); #endif exit(2); } struct sigpair { const char *name; int signal; }; static const struct sigpair siglist[] = { { "ABRT", SIGABRT }, { "ALRM", SIGALRM }, { "FPE", SIGFPE }, { "HUP", SIGHUP }, { "ILL", SIGILL }, { "INT", SIGINT }, { "KILL", SIGKILL }, { "PIPE", SIGPIPE }, { "QUIT", SIGQUIT }, { "SEGV", SIGSEGV }, { "TERM", SIGTERM }, { "USR1", SIGUSR1 }, { "USR2", SIGUSR2 }, { "CHLD", SIGCHLD }, { "CONT", SIGCONT }, { "STOP", SIGSTOP }, { "TSTP", SIGTSTP }, { "TTIN", SIGTTIN }, { "TTOU", SIGTTOU } }; static int sigcount = sizeof (siglist) / sizeof (siglist[0]); static int parse_signal (const char *signal_str, int *signal_nr) { int i; for (i = 0; i < sigcount; i++) { if (strcmp (signal_str, siglist[i].name) == 0) { *signal_nr = siglist[i].signal; return 0; } } return -1; } static void parse_options(int argc, char * const *argv) { #if HAVE_GETOPT_LONG static struct option longopts[] = { { "help", 0, NULL, 'H'}, { "stop", 0, NULL, 'K'}, { "start", 0, NULL, 'S'}, { "version", 0, NULL, 'V'}, { "startas", 1, NULL, 'a'}, { "name", 1, NULL, 'n'}, { "oknodo", 0, NULL, 'o'}, { "pidfile", 1, NULL, 'p'}, { "quiet", 0, NULL, 'q'}, { "signal", 1, NULL, 's'}, { "test", 0, NULL, 't'}, { "user", 1, NULL, 'u'}, { "chroot", 1, NULL, 'r'}, { "verbose", 0, NULL, 'v'}, { "exec", 1, NULL, 'x'}, { "chuid", 1, NULL, 'c'}, { "background", 0, NULL, 'b'}, { "make-pidfile", 0, NULL, 'm'}, { NULL, 0, NULL, 0} }; #endif int c; for (;;) { #if HAVE_GETOPT_LONG c = getopt_long(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm", longopts, (int *) 0); #else c = getopt(argc, argv, "HKSVa:n:op:qr:s:tu:vx:c:bm"); #endif if (c == -1) break; switch (c) { case 'H': /* --help */ do_help(); exit(0); case 'K': /* --stop */ stop = 1; break; case 'S': /* --start */ start = 1; break; case 'V': /* --version */ printf("start-stop-daemon " GW_VERSION "\n"); exit(0); case 'a': /* --startas */ startas = optarg; break; case 'n': /* --name */ cmdname = optarg; break; case 'o': /* --oknodo */ exitnodo = 0; break; case 'p': /* --pidfile */ pidfile = optarg; break; case 'q': /* --quiet */ quietmode = 1; break; case 's': /* --signal */ signal_str = optarg; break; case 't': /* --test */ testmode = 1; break; case 'u': /* --user | */ userspec = optarg; break; case 'v': /* --verbose */ quietmode = -1; break; case 'x': /* --exec */ execname = optarg; break; case 'c': /* --chuid | */ /* we copy the string just in case we need the * argument later. */ changeuser = strdup(optarg); changeuser = strtok(changeuser, ":"); changegroup = strtok(NULL, ":"); break; case 'r': /* --chroot /new/root */ changeroot = optarg; break; case 'b': /* --background */ background = 1; break; case 'm': /* --make-pidfile */ mpidfile = 1; break; default: badusage(NULL); /* message printed by getopt */ } } if (signal_str != NULL) { if (sscanf (signal_str, "%d", &signal_nr) != 1) { if (parse_signal (signal_str, &signal_nr) != 0) { badusage ("--signal takes a numeric argument or name of signal (KILL, INTR, ...)"); } } } if (start == stop) #ifndef SunOS badusage("need one of --start or --stop"); #else badusage("need one of -S (start) or -K (stop)"); #endif if (!execname && !pidfile && !userspec) badusage("need at least one of --exec, --pidfile or --user"); if (!startas) startas = execname; if (start && !startas) badusage("--start needs --exec or --startas"); if (mpidfile && pidfile == NULL) badusage("--make-pidfile is only relevant with --pidfile"); if (background && !start) badusage("--background is only relevant with --start"); } #if defined(OSLinux) static int pid_is_exec(int pid, const struct stat *esb) { struct stat sb; char buf[32]; sprintf(buf, "/proc/%d/exe", pid); if (stat(buf, &sb) != 0) return 0; return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino); } static int pid_is_user(int pid, int uid) { struct stat sb; char buf[32]; sprintf(buf, "/proc/%d", pid); if (stat(buf, &sb) != 0) return 0; return ((int) sb.st_uid == uid); } static int pid_is_cmd(int pid, const char *name) { char buf[32]; FILE *f; int c; sprintf(buf, "/proc/%d/stat", pid); f = fopen(buf, "r"); if (!f) return 0; while ((c = getc(f)) != EOF && c != '(') ; if (c != '(') { fclose(f); return 0; } /* this hopefully handles command names containing ')' */ while ((c = getc(f)) != EOF && c == *name) name++; fclose(f); return (c == ')' && *name == '\0'); } #endif /* OSLinux */ #if defined(OSHURD) static int pid_is_user(int pid, int uid) { struct stat sb; char buf[32]; struct proc_stat *pstat; sprintf(buf, "/proc/%d", pid); if (stat(buf, &sb) != 0) return 0; return (sb.st_uid == uid); pstat = proc_stat_list_pid_proc_stat (procset, pid); if (pstat == NULL) fatal ("Error getting process information: NULL proc_stat struct"); proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_OWNER_UID); return (pstat->owner_uid == uid); } static int pid_is_cmd(int pid, const char *name) { struct proc_stat *pstat; pstat = proc_stat_list_pid_proc_stat (procset, pid); if (pstat == NULL) fatal ("Error getting process information: NULL proc_stat struct"); proc_stat_set_flags (pstat, PSTAT_PID | PSTAT_ARGS); return (!strcmp (name, pstat->args)); } #endif /* OSHURD */ #if defined(SunOS) /* Lots of lovely system dependant functions for Solaris. I used to like the idea of proc, but now I'm not so sure. It feels to much like a kludge. */ /* pid_is_user, takes the pid and a uid, normally ours, but can be someone elses, to allow you to identify the process' owner. returns zero on success, and either true or the uid of the owner on failure (this may be undefined, or I may be misremembering. */ static int pid_is_user(int pid, int uid) { struct stat sb; char buf[32]; sprintf(buf, "/proc/%d", pid); if (stat(buf, &sb) != 0) return 0; /*I can stat it so it seems to be mine...*/ return ((int) sb.st_uid == uid); } /* pid_is_cmd, takes a pid, and a string representing the process' (supposed) name. Compares the process' supposed name with the name reported by the system. Returns zero on failure, and nonzero on success. */ static int pid_is_cmd(int pid, const char *name) { char buf[32]; FILE *f; psinfo_t pid_info; sprintf(buf, "/proc/%d/psinfo", pid); f = fopen(buf, "r"); if (!f) return 0; fread(&pid_info,sizeof(psinfo_t),1,f); return (!strcmp(name,pid_info.pr_fname)); } #endif /*SunOS*/ #ifdef FreeBSD static int pid_is_user(int pid, int uid) { struct stat sb; char buf[32]; sprintf(buf, "/proc/%d", pid); if (stat(buf, &sb) != 0) return 0; return ((int) sb.st_uid == uid); } static int pid_is_cmd(int pid, const char *name) { char buf[32]; FILE *f; int c; sprintf(buf, "/proc/%d/stat", pid); f = fopen(buf, "r"); if (!f) return 0; while ((c = getc(f)) != EOF && c != '(') ; if (c != '(') { fclose(f); return 0; } /* this hopefully handles command names containing ')' */ while ((c = getc(f)) != EOF && c == *name) name++; fclose(f); return (c == ')' && *name == '\0'); } #endif /*FreeBSD*/ static void check(int pid) { #if defined(OSLinux) if (execname && !pid_is_exec(pid, &exec_stat)) return; #elif defined(OSHURD) /* I will try this to see if it works */ if (execname && !pid_is_cmd(pid, execname)) return; #endif if (userspec && !pid_is_user(pid, user_id)) return; if (cmdname && !pid_is_cmd(pid, cmdname)) return; push(&found, pid); } static void do_pidfile(const char *name) { FILE *f; int pid; f = fopen(name, "r"); if (f) { if (fscanf(f, "%d", &pid) == 1) check(pid); fclose(f); } } /* WTA: this needs to be an autoconf check for /proc/pid existance. */ #if defined(OSLinux) || defined (SunOS) || defined(FreeBSD) static void do_procinit(void) { DIR *procdir; struct dirent *entry; int foundany, pid; procdir = opendir("/proc"); if (!procdir) fatal("opendir /proc: %s", strerror(errno)); foundany = 0; while ((entry = readdir(procdir)) != NULL) { if (sscanf(entry->d_name, "%d", &pid) != 1) continue; foundany++; check(pid); } closedir(procdir); if (!foundany) fatal("nothing in /proc - not mounted?"); } #endif /* OSLinux */ #if defined(OSHURD) error_t check_all (void *ptr) { struct proc_stat *pstat = ptr; check (pstat->pid); return (0); } static void do_psinit(void) error_t err; err = ps_context_create (getproc (), &context); if (err) error (1, err, "ps_context_create"); err = proc_stat_list_create (context, &procset); if (err) error (1, err, "proc_stat_list_create"); err = proc_stat_list_add_all (procset, 0, 0); if (err) error (1, err, "proc_stat_list_add_all"); /* Check all pids */ ihash_iterate (context->procs, check_all); } #endif /* OSHURD */ /* return 1 on failure */ static int do_stop(void) { char what[1024]; struct pid_list *p; int retval = 0; if (cmdname) strcpy(what, cmdname); else if (execname) strcpy(what, execname); else if (pidfile) sprintf(what, "process in pidfile `%s'", pidfile); else if (userspec) sprintf(what, "process(es) owned by `%s'", userspec); else fatal("internal error, please report"); if (!found) { if (quietmode <= 0) printf("No %s found running; none killed.\n", what); exit(exitnodo); } for (p = found; p; p = p->next) { if (testmode) printf("Would send signal %d to %d.\n", signal_nr, p->pid); else if (kill(p->pid, signal_nr) == 0) push(&killed, p->pid); else { printf("%s: warning: failed to kill %d: %s\n", progname, p->pid, strerror(errno)); retval += exitnodo; } } if (quietmode < 0 && killed) { printf("Stopped %s (pid", what); for (p = killed; p; p = p->next) printf(" %d", p->pid); printf(").\n"); } return retval; } int main(int argc, char **argv) { progname = argv[0]; parse_options(argc, argv); argc -= optind; argv += optind; if (execname && stat(execname, &exec_stat)) fatal("stat %s: %s", execname, strerror(errno)); if (userspec && sscanf(userspec, "%d", &user_id) != 1) { struct passwd *pw; pw = getpwnam(userspec); if (!pw) fatal("user `%s' not found\n", userspec); user_id = pw->pw_uid; } if (changegroup && sscanf(changegroup, "%d", &runas_gid) != 1) { struct group *gr = getgrnam(changegroup); if (!gr) fatal("group `%s' not found\n", changegroup); runas_gid = gr->gr_gid; } if (changeuser && sscanf(changeuser, "%d", &runas_uid) != 1) { struct passwd *pw = getpwnam(changeuser); if (!pw) fatal("user `%s' not found\n", changeuser); runas_uid = pw->pw_uid; if (changegroup == NULL) { /* pass the default group of this user */ changegroup = ""; /* just empty */ runas_gid = pw->pw_gid; } } if (pidfile) do_pidfile(pidfile); else do_procinit(); if (stop) { int i = do_stop(); if (i) { if (quietmode <= 0) printf("%d pids were not killed\n", i); exit(1); } exit(0); } if (found) { if (quietmode <= 0) printf("%s already running.\n", execname); exit(exitnodo); } if (testmode) { printf("Would start %s ", startas); while (argc-- > 0) printf("%s ", *argv++); if (changeuser != NULL) { printf(" (as user %s[%d]", changeuser, runas_uid); if (changegroup != NULL) printf(", and group %s[%d])", changegroup, runas_gid); else printf(")"); } if (changeroot != NULL) printf(" in directory %s", changeroot); printf(".\n"); exit(0); } if (quietmode < 0) printf("Starting %s...\n", startas); *--argv = startas; if (changeroot != NULL) { if (chdir(changeroot) < 0) fatal("Unable to chdir() to %s", changeroot); if (chroot(changeroot) < 0) fatal("Unable to chroot() to %s", changeroot); } if (changeuser != NULL) { if (setgid(runas_gid)) fatal("Unable to set gid to %d", runas_gid); if (initgroups(changeuser, runas_gid)) fatal("Unable to set initgroups() with gid %d", runas_gid); if (setuid(runas_uid)) fatal("Unable to set uid to %s", changeuser); } if (background) { /* ok, we need to detach this process */ int i, fd; if (quietmode < 0) printf("Detatching to start %s...", startas); i = fork(); if (i<0) { fatal("Unable to fork.\n"); } if (i) { /* parent */ if (quietmode < 0) printf("done.\n"); exit(0); } /* child continues here */ /* now close all extra fds */ for (i=getdtablesize()-1; i>=0; --i) close(i); /* change tty */ fd = open("/dev/tty", O_RDWR); ioctl(fd, TIOCNOTTY, 0); close(fd); chdir("/"); umask(022); /* set a default for dumb programs */ #ifdef DARWIN setpgrp(); /* set the process group */ #else #ifndef FreeBSD setpgrp(); /* set the process group */ #else setpgrp(0, runas_gid); /* set the process group */ #endif #endif fd=open("/dev/null", O_RDWR); /* stdin */ dup(fd); /* stdout */ dup(fd); /* stderr */ } if (mpidfile && pidfile != NULL) { /* user wants _us_ to make the pidfile :) */ FILE *pidf = fopen(pidfile, "w"); pid_t pidt = getpid(); if (pidf == NULL) fatal("Unable to open pidfile `%s' for writing: %s", pidfile, strerror(errno)); fprintf(pidf, "%d\n", (int)pidt); fclose(pidf); } execv(startas, argv); fatal("Unable to start %s: %s", startas, strerror(errno)); } gateway-1.4.5/utils/kannel-stable-rh6x.spec0000644000175000017500000000711707261074053017317 0ustar toljtoljSummary: Kannel SMS/WAP gateway Name: kannel Version: 1.0.3 Release: 1 Copyright: Open source, FreeBSD-style license; see COPYING Group: Applications/Communications Source: gateway-%{version}.tar.gz BuildRoot: /var/tmp/%{name}-buildroot Packager: Peter Gronholm. Requires: libxml2 >= 2.3.0 %description Kannel is an Open Source SMS/WAP gateway. WAP is short for Wireless Application Protocol. It lets the phone act as a simple hypertext browser, but optimizes the markup language, scripting language, and the transmission protocols for wireless use. The optimized protocols are translated to normal Internet protocols by a WAP gateway. Kannel also works as a SMS gateway for GSM networks. Almost all GSM phones can send and receive SMS messages, so this is a way to serve many more clients than just those using WAP phones. %prep rm -rf $RPM_BUILD_ROOT %setup -n gateway-%{version} %build ./configure --with-malloc-native --enable-docs make %install make bindir=$RPM_BUILD_ROOT/usr/local/bin suffix= install mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d mkdir -p $RPM_BUILD_ROOT/etc/kannel mkdir -p $RPM_BUILD_ROOT/usr/man/man8 install -m 644 gw/wapkannel.conf $RPM_BUILD_ROOT/etc/kannel/kannel.conf install -m 644 gw/smskannel.conf $RPM_BUILD_ROOT/etc/kannel install -m 644 gw/kannel.8 $RPM_BUILD_ROOT/usr/man/man8 install -m 644 test/fakesmsc $RPM_BUILD_ROOT/usr/local/bin install -m 644 test/fakewap $RPM_BUILD_ROOT/usr/local/bin install -m 755 utils/kannel-init.d $RPM_BUILD_ROOT/etc/rc.d/init.d/kannel install -m 644 utils/run_kannel_box.8 $RPM_BUILD_ROOT/usr/man/man8 install -m 644 utils/start-stop-daemon.8 $RPM_BUILD_ROOT/usr/man/man8 strip $RPM_BUILD_ROOT/usr/local/bin/bearerbox strip $RPM_BUILD_ROOT/usr/local/bin/wapbox strip $RPM_BUILD_ROOT/usr/local/bin/smsbox strip $RPM_BUILD_ROOT/usr/local/bin/fakesmsc strip $RPM_BUILD_ROOT/usr/local/bin/fakewap strip $RPM_BUILD_ROOT/usr/local/bin/run_kannel_box strip $RPM_BUILD_ROOT/usr/local/bin/start-stop-daemon strip $RPM_BUILD_ROOT/usr/local/bin/wmlsc strip $RPM_BUILD_ROOT/usr/local/bin/wmlsdasm strip $RPM_BUILD_ROOT/usr/local/bin/seewbmp %files %defattr(-,root,root) %doc README README.docbook README.src README.wmlscript INSTALL AUTHORS COPYING VERSION NEWS ChangeLog doc/ gw/control.html contrib/ /usr/local/bin/ /etc/rc.d/init.d/kannel /usr/man/man8 %config(noreplace) /etc/kannel/kannel.conf %config(noreplace) /etc/kannel/smskannel.conf %post ln -sf /usr/local/bin/bearerbox /usr/bin/bearerbox ln -sf /usr/local/bin/wapbox /usr/bin/wapbox ln -sf /usr/local/bin/smsbox /usr/bin/smsbox ln -sf /usr/local/bin/start-stop-daemon /usr/bin/start-stop-daemon ln -sf /usr/local/bin/run_kannel_box /usr/bin/run_kannel_box %postun rm -f /usr/bin/bearerbox rm -f /usr/bin/wapbox rm -f /usr/bin/smsbox rm -f /usr/bin/start-stop-daemon rm -f /usr/bin/run_kannel_box %clean rm -rf $RPM_BUILD_ROOT %changelog * Fri Mar 30 2001 Peter Gronholm - added that Kannel requires libxml2 >= 2.3.0 * Fri Mar 30 2001 Peter Gronholm - removed that Kannel requires libxml2 < 2.3.0 * Tue Feb 27 2001 Peter Gronholm - moved rm -rf $RPM_BUILD_ROOT from %install to %prep - added that Kannel requires libxml2 < 2.3.0 * Tue Feb 06 2001 Peter Gronholm - install configuration files with %config macro. - clean $RPM_BUILD_ROOT before and after building the rpm package. - %postun macro: remove links to Kannel binaries from /usr/bin when uninstalling rpm package. - removed -b option from install command in %install macro. * Tue Jan 02 2001 Peter Gronholm - initial release of Kannel rpm package. gateway-1.4.5/utils/update-license.sh0000644000175000017500000000062210203150325016251 0ustar toljtolj#!/bin/sh # # update-license -- update prefix blocks with LICENSE text # # Run this script in gateway root directory to update the # current LICENSE text file to all source code files. # types="\.h \.c \.def" for t in $types; do echo "Updating LICENSE in '${t}' files." files=`find -type f | grep "${t}\$"` for i in $files; do cat LICENSE ${i} >> ${i}.new mv ${i}.new ${i} done done gateway-1.4.5/utils/decode_emimsg.c0000644000175000017500000002661313227613126015767 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * decode_emimsg.c - This tool can decode an UCP/EMI packet. * */ #include #include #include #include "gwlib/gwlib.h" #include "gw/smsc/emimsg.c" #include "gw/alt_charsets.h" static char *emi_typeop(int typeop) { switch (typeop) { case 31: return "Alert Operation"; case 51: return "Submit Short Message operation"; case 52: return "Delivery Short Message operation"; case 53: return "Delivery notification operation"; case 54: return "Modify Short Message operation"; case 55: return "Inquiry message operation"; case 56: return "Delete message operation"; case 57: return "Response Inquiry message operation"; case 58: return "Response delete message operation"; case 60: return "Session management operation"; case 61: return "Provisioning actions operation"; default: return "!UNRECOGNIZED CODE!"; } } int main (int argc, char **argv) { Octstr *message, *whoami; struct emimsg *emimsg; printf("/* This tool can decode an UCP/EMI packet. */\n\n"); gwlib_init(); if (argc < 2) panic(0, "Syntax: %s \n", argv[0]); message = octstr_format("\02%s\03", argv[1]); // fit the UCP specs. whoami = octstr_create("DECODE"); emimsg = get_fields(message, whoami); if (emimsg != NULL) { printf("\n"); printf("TRN \t%d\n", emimsg->trn); printf("TYPE \t%c (%s)\n", emimsg->or, emimsg->or == 'R' ? "Result" : "Operation"); printf("OPERATION\t%d (%s)\n", emimsg->ot, emi_typeop (emimsg->ot)); if (emimsg->ot == 01) { printf("E01_ADC \t%s\n", octstr_get_cstr(emimsg->fields[E01_ADC])); printf("E01_OADC \t%s\n", octstr_get_cstr(emimsg->fields[E01_OADC])); printf("E01_AC \t%s\n", octstr_get_cstr(emimsg->fields[E01_AC])); printf("E01_ADC \t%s\n", octstr_get_cstr(emimsg->fields[E01_ADC])); printf("E01_MT \t%s\n", octstr_get_cstr(emimsg->fields[E01_MT])); if (octstr_get_char(emimsg->fields[E01_MT], 0) == '3') { charset_gsm_to_latin1(emimsg->fields[E01_AMSG]); } printf("E01_AMSG \t%s\n", octstr_get_cstr(emimsg->fields[E01_AMSG])); } if ((emimsg->ot == 31 || (emimsg->ot >= 50 && emimsg->ot <= 60)) && emimsg->or == 'R' && (octstr_get_char(emimsg->fields[E50_ADC], 0) == 'A' || octstr_get_char(emimsg->fields[E50_ADC], 0) == 'N')) { printf("E%d_ACK \t%s\n", emimsg->ot, octstr_get_cstr(emimsg->fields[E50_ADC])); printf("E%d_SM \t%s\n", emimsg->ot, octstr_get_cstr(emimsg->fields[E50_OADC])); } if (emimsg->ot == 31 && emimsg->or == 'O') { printf("E50_ADC \t%s\n", octstr_get_cstr(emimsg->fields[E50_ADC])); printf("E50_PID \t%s\n", octstr_get_cstr(emimsg->fields[E50_OADC])); } if (emimsg->ot >= 50 && emimsg->ot <= 59 && octstr_get_char(emimsg->fields[E50_ADC], 0) != 'A' && octstr_get_char(emimsg->fields[E50_ADC], 0) != 'N') { printf("E50_ADC \t%s\n", octstr_get_cstr(emimsg->fields[E50_ADC])); printf("E50_OADC \t%s\n", octstr_get_cstr(emimsg->fields[E50_OADC])); printf("E50_AC \t%s\n", octstr_get_cstr(emimsg->fields[E50_AC])); printf("E50_NRQ \t%s\n", octstr_get_cstr(emimsg->fields[E50_NRQ])); printf("E50_NADC \t%s\n", octstr_get_cstr(emimsg->fields[E50_NADC])); printf("E50_NT \t%s\n", octstr_get_cstr(emimsg->fields[E50_NT])); printf("E50_NPID \t%s\n", octstr_get_cstr(emimsg->fields[E50_NPID])); printf("E50_LRQ \t%s\n", octstr_get_cstr(emimsg->fields[E50_LRQ])); printf("E50_LRAD \t%s\n", octstr_get_cstr(emimsg->fields[E50_LRAD])); printf("E50_LPID \t%s\n", octstr_get_cstr(emimsg->fields[E50_LPID])); printf("E50_DD \t%s\n", octstr_get_cstr(emimsg->fields[E50_DD])); printf("E50_DDT \t%s\n", octstr_get_cstr(emimsg->fields[E50_DDT])); printf("E50_VP \t%s\n", octstr_get_cstr(emimsg->fields[E50_VP])); printf("E50_RPID \t%s\n", octstr_get_cstr(emimsg->fields[E50_RPID])); printf("E50_SCTS \t%s\n", octstr_get_cstr(emimsg->fields[E50_SCTS])); printf("E50_DST \t%s\n", octstr_get_cstr(emimsg->fields[E50_DST])); printf("E50_RSN \t%s\n", octstr_get_cstr(emimsg->fields[E50_RSN])); printf("E50_DSCTS\t%s\n", octstr_get_cstr(emimsg->fields[E50_DSCTS])); printf("E50_MT \t%s\n", octstr_get_cstr(emimsg->fields[E50_MT])); printf("E50_NB \t%s\n", octstr_get_cstr(emimsg->fields[E50_NB])); printf("E50_NMSG \t%s\n", octstr_get_cstr(emimsg->fields[E50_NMSG])); if (emimsg->fields[E50_AMSG]) octstr_hex_to_binary (emimsg->fields[E50_AMSG]); if (octstr_get_char(emimsg->fields[E50_MT], 0) == '3') { charset_gsm_to_latin1(emimsg->fields[E50_AMSG]); } printf("E50_AMSG \t%s\n", octstr_get_cstr(emimsg->fields[E50_AMSG])); printf("E50_TMSG \t%s\n", octstr_get_cstr(emimsg->fields[E50_TMSG])); printf("E50_MMS \t%s\n", octstr_get_cstr(emimsg->fields[E50_MMS])); printf("E50_PR \t%s\n", octstr_get_cstr(emimsg->fields[E50_PR])); printf("E50_DCS \t%s\n", octstr_get_cstr(emimsg->fields[E50_DCS])); printf("E50_MCLS \t%s\n", octstr_get_cstr(emimsg->fields[E50_MCLS])); printf("E50_RPI \t%s\n", octstr_get_cstr(emimsg->fields[E50_RPI])); printf("E50_CPG \t%s\n", octstr_get_cstr(emimsg->fields[E50_CPG])); printf("E50_RPLY \t%s\n", octstr_get_cstr(emimsg->fields[E50_RPLY])); printf("E50_OTOA \t%s\n", octstr_get_cstr(emimsg->fields[E50_OTOA])); printf("E50_HPLMN\t%s\n", octstr_get_cstr(emimsg->fields[E50_HPLMN])); printf("E50_XSER \t%s\n", octstr_get_cstr(emimsg->fields[E50_XSER])); printf("E50_RES4 \t%s\n", octstr_get_cstr(emimsg->fields[E50_RES4])); printf("E50_RES5 \t%s\n", octstr_get_cstr(emimsg->fields[E50_RES5])); } if ((emimsg->ot == 60 || emimsg->ot == 61) && (octstr_get_char(emimsg->fields[E50_ADC], 0) != 'A' && octstr_get_char(emimsg->fields[E50_ADC], 0) != 'N')) { printf("E60_OADC \t%s\n", octstr_get_cstr(emimsg->fields[E60_OADC])); printf("E60_OTON \t%s\n", octstr_get_cstr(emimsg->fields[E60_OTON])); printf("E60_ONPI \t%s\n", octstr_get_cstr(emimsg->fields[E60_ONPI])); printf("E60_STYP \t%s\n", octstr_get_cstr(emimsg->fields[E60_STYP])); if (emimsg->fields[E60_PWD]) octstr_hex_to_binary (emimsg->fields[E60_PWD]); printf("E60_PWD \t%s\n", octstr_get_cstr(emimsg->fields[E60_PWD])); printf("E60_NPWD \t%s\n", octstr_get_cstr(emimsg->fields[E60_NPWD])); printf("E60_VERS \t%s\n", octstr_get_cstr(emimsg->fields[E60_VERS])); printf("E60_LADC \t%s\n", octstr_get_cstr(emimsg->fields[E60_LADC])); printf("E60_LTON \t%s\n", octstr_get_cstr(emimsg->fields[E60_LTON])); printf("E60_LNPI \t%s\n", octstr_get_cstr(emimsg->fields[E60_LNPI])); printf("E60_OPID \t%s\n", octstr_get_cstr(emimsg->fields[E60_OPID])); printf("E60_RES1 \t%s\n", octstr_get_cstr(emimsg->fields[E60_RES1])); } } octstr_destroy(message); octstr_destroy(whoami); gwlib_shutdown(); return 0; } gateway-1.4.5/utils/win1257unicode.txt0000644000175000017500000000177707117206527016273 0ustar toljtolj0x20ac, 0x0000, 0x201a, 0x0000, 0x201e, 0x2026, 0x2020, 0x2021, 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00a8, 0x02c7, 0x00b8, 0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x0000, 0x2122, 0x0000, 0x203a, 0x0000, 0x00af, 0x02db, 0x0000, 0x00a0, 0x0000, 0x00a2, 0x00a3, 0x00a4, 0x0000, 0x00a6, 0x00a7, 0x00d8, 0x00a9, 0x0156, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00c6, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00f8, 0x00b9, 0x0157, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00e6, 0x0104, 0x012e, 0x0100, 0x0106, 0x00c4, 0x00c5, 0x0118, 0x0112, 0x010c, 0x00c9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012a, 0x013b, 0x0160, 0x0143, 0x0145, 0x00d3, 0x014c, 0x00d5, 0x00d6, 0x00d7, 0x0172, 0x0141, 0x015a, 0x016a, 0x00dc, 0x017b, 0x017d, 0x00df, 0x0105, 0x012f, 0x0101, 0x0107, 0x00e4, 0x00e5, 0x0119, 0x0113, 0x010d, 0x00e9, 0x017a, 0x0117, 0x0123, 0x0137, 0x012b, 0x013c, 0x0161, 0x0144, 0x0146, 0x00f3, 0x014d, 0x00f5, 0x00f6, 0x00f7, 0x0173, 0x0142, 0x015b, 0x016b, 0x00fc, 0x017c, 0x017e, 0x02d9 gateway-1.4.5/utils/build-cygwin-package0000644000175000017500000000160107536234065016745 0ustar toljtolj#!/bin/bash if [ ! -d "gw" ] ; then echo "Must be ran in gateway dir" exit 1 fi BUILDDIR=/tmp/kannel if [ -d "$BUILDDIR" ] ; then rm -fr "$BUILDDIR" fi mkdir "$BUILDDIR" mkdir "$BUILDDIR/bin" cp gw/*.exe "$BUILDDIR/bin" -v mkdir "$BUILDDIR/conf" for i in doc/examples/*.conf ; do cp $i "$BUILDDIR/conf" -v done mkdir "$BUILDDIR/tools" for i in test utils wmlscript ; do mkdir "$BUILDDIR/tools/$i" cp $i/*.exe "$BUILDDIR/tools/$i" -v done if [ -e doc/userguide/userguide.pdf ] ; then mkdir "$BUILDDIR/docs" for i in userguide alligata arch wtls ; do mkdir "$BUILDDIR/docs/$i" cp doc/$i/*.pdf \ doc/$i/*.rtf \ doc/$i/*.png \ "$BUILDDIR/docs/$i" done fi (cd "$BUILDDIR" ; zip -r kannel.zip *) echo "kannel.zip is on $BUILDDIR" gateway-1.4.5/utils/kannel-nag0000755000175000017500000000302107411425412014761 0ustar toljtolj#!/bin/bash # # kannel-nag - do a test compile of Kannel and mail results to devel list # # This script is meant to compile Kannel and mail all warnings and errors # to the development list. It is meant to be run on a few carefully chosen # machines, not by everyone on the Internet. The goal is to make sure Kannel # at least compiles on many platforms. It is quite uninteresting to have # fiftyseven thousand people running this script on identical Linux machines. # # I repeat: DO NOT RUN THIS SCRIPT without asking for permission of the # receiver first. # # TODO: # - CFLAGS now set for GCC, should be more portable # # Lars Wirzenius # set -e addr="" CVSROOT=":pserver:anonymous@cvs.kannel.3glab.org:/home/cvs" dir="kannel-nag-dir" cd /var/tmp rm -rf $dir mkdir $dir cd $dir cvs -Q -d$CVSROOT co gateway cd gateway if CFLAGS='-Wall -O2 -g' ./configure >config.output 2>&1 then configure=ok touch .depend || true make -s depend || true make -s >make.output 2>&1 || true else configure=failed fi if test -s make.output || [ "$configure" = failed ] then ( echo "Kannel compilation test." echo "" echo "Host: `uname -a`" echo "" echo "Kannel compilation had warnings or failed." echo "" if test -e make.output then echo "Output of 'make -s':" cat make.output echo "-------------------------------------------------------" echo "" fi echo "Output of 'CFLAGS='-Wall -O2 -g' ./configure':" cat config.output ) | mail -s "Kannel automatic compilation test for `uname -s`" $addr fi cd /var/tmp rm -rf $dir gateway-1.4.5/utils/kannel-log-summary0000755000175000017500000000623107072401162016475 0ustar toljtolj#!/usr/bin/awk -f # # Summarize Kannel log files. # # - total number of lines # - start and end times # - smsbox/wapbox requests: total, within the last hour (total and avg/s) # - number of restarts # # Lars Wirzenius # BEGIN { days_in_month[1] = 31 days_in_month[2] = 28 days_in_month[3] = 31 days_in_month[4] = 30 days_in_month[5] = 31 days_in_month[6] = 30 days_in_month[7] = 31 days_in_month[8] = 31 days_in_month[9] = 30 days_in_month[10] = 31 days_in_month[11] = 30 days_in_month[12] = 31 "date -u '+%Y-%m-%d %H:%M:%S'" | getline nowstr now = secs(nowstr) new_request_age = 3600 * 4 new_restart_age = 3600 * 24 } FILENAME != prev_filename { if (prev_filename) { lines = NR - prev_nr report(prev_filename, lines, starts, ends, requests, new_requests, restarts, new_restarts) } prev_filename = FILENAME prev_nr = NR starts = substr($0, 0, 20) requests = 0 new_requests = 0 restarts = 0 new_restarts = 0 } /INFO: Added logfile `.*' with level/ { ++restarts if (now - secs($0) <= new_restart_age) ++new_restarts } /INFO: Starting to service <.*> from <.*> to <.*>$/ || /INFO: WSP: Fetched <.*>$/ { ++requests if (now - secs($0) <= new_request_age) ++new_requests } /^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]/ { ends = substr($0, 0, 20) } END { if (prev_filename) report(prev_filename, NR - prev_nr, starts, ends, requests, new_requests, restarts, new_restarts) } function report(filename, lines, starts, ends, requests, new_requests, \ restarts, new_restarts) { duration = secs(ends) - secs(starts) avgperday = requests / (duration / 86400) persec = new_requests / new_request_age print "File:", filename print "Lines:", lines print "Starts:", starts print "Ends:", ends print "Duration:", secs2str(duration) print "Restarts:", restarts print "Recent restarts:", new_restarts, "(in the last", \ new_restart_age/3600, "hours)" if (requests > 0) { print "Requests:", requests, "total", \ avgperday, "average per day" print "Recent requests (last", new_request_age/3600, \ "hours):", new_requests print "Recent average per second:", persec } print "" } function secs2str(s) { days = idiv(s, 86400) s -= days * 86400 hours = idiv(s, 3600) s -= hours * 3600 mins = idiv(s, 60) s -= mins * 60 return days "d " hours "h " mins "m " s "s" } function secs(timestamp) { year = substr(timestamp, 1, 4) mon = substr(timestamp, 6, 2) day = substr(timestamp, 9, 2) hour = substr(timestamp, 12, 2) min = substr(timestamp, 15, 2) sec = substr(timestamp, 18, 2) return sec + min*60 + hour*3600 + (day-1)*86400 + \ mon2secs(mon, year) + year2secs(year) } function mon2secs(mon, year) { days = 0 mon = mon + 0 # make sure it is a number for (m = 1; m < mon; ++m) days += days_in_month[mon] if (mon > 2 && isleap(year)) ++days return days * 86400 } function year2secs(year) { s = 0 for (y = 1970; y < year; ++y) { if (isleap(year)) s += 366 * 86400 else s += 365 * 86400 } return s } function isleap(year) { return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) } function idiv(a, b) { # assume a >= 0, b > 0 for (i = 0; a > b; ++i) a -= b; return i } gateway-1.4.5/utils/seewbmp.c0000644000175000017500000002256113227613126014643 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* seebmp -- simple viewer for WBMP images (image/vnd.wap.wbmp) */ /* * * Copyright (c) Richard Braakman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include /* The spec includes a multi-byte integer format. For reasons of simplicity, we * only handle integers that end up fitting in 31 bits. This limits picture * sizes to about 2 billion pixels width or height, which I think we can live * with. */ /* The function returns -1 in case of an error. */ static long get_mbi(FILE *infile) { int c; long result = 0; do { c = getc(infile); if (c < 0) return -1; result = (result << 7) | (c & 0x7f); } while (c & 0x80); return result; } /* This function is like get_mbi, but it ignores the value of the result. * So it's not limited to 31 bits, and it ends up skipping all bytes that * have their high bit set. */ /* The function returns 0 for success, or -1 in case of an error. */ static int skip_mbi(FILE *infile) { int c; do { c = getc(infile); if (c < 0) return -1; } while (c & 0x80); return 0; } static int show_image_from_file(char *bmpname, FILE *bmpfile, long width, long height) { long w, h; for (h = 0; h < height; h++) { /* w is incremented in its inner loop */ for (w = 0; w < width; ) { int c; unsigned int bit; c = getc(bmpfile); if (c < 0) { perror(bmpname); return -1; } for (bit = 0x80; bit > 0 && w < width; bit >>= 1, w++) { putc((c & bit) ? '*' : ' ', stdout); } } putc('\n', stdout); } return 0; } /* These are global because that's easier. In a real parser they would * be part of an image descriptor structure */ struct parm { struct parm *next; char *name; char *value; }; struct parm *extparms = NULL; static void clear_extparms(void) { while (extparms) { struct parm *tmp = extparms; extparms = extparms->next; free(tmp->name); free(tmp->value); free(tmp); } } /* Record a new parameter. The name and value will be used directly, * not copied. */ static int new_extparm(char *name, char *value) { struct parm *new; struct parm *p; /* Construct a new node */ new = (struct parm *)malloc(sizeof(struct parm)); if (!new) return -1; new->name = name; new->value = value; new->next = NULL; /* Add it to the end of the list. */ if (!extparms) { extparms = new; } else { p = extparms; while (p->next) { p = p->next; } p->next = new; } return 0; } static void print_extparms(FILE *outfile) { struct parm *p; for (p = extparms; p; p = p->next) { fprintf(outfile, "%s=%s\n", p->name, p->value); } } static int parse_headers(FILE *bmpfile) { int c; int exttype; clear_extparms(); c = getc(bmpfile); if (c < 0) return -1; if (!(c & 0x80)) { /* No extension headers follow */ return 0; } exttype = (c >> 5) & 0x03; /* None of these headers do much at this time, but they * might be meaningful with later specifications */ switch (exttype) { case 0: /* All we know of type 0 headers is that * the high bit is a continuation bit. * That makes them exactly like an MBI. */ if (skip_mbi(bmpfile) < 0) return -1; break; case 1: case 2: /* We don't know what to do with these */ return -1; case 3: /* A sequence of parameter/value combinations */ do { int namelen, valuelen; char *name, *value; c = getc(bmpfile); if (c < 0) return -1; namelen = (c >> 4) & 0x07; name = malloc(namelen + 1); if (!name) return -1; if (fread(name, namelen, 1, bmpfile) < (size_t) namelen) return -1; valuelen = c & 0x0f; value = malloc(valuelen + 1); if (!value) { free(name); return -1; } if (fread(value, valuelen, 1, bmpfile) < (size_t) valuelen) return -1; new_extparm(name, value); } while (c & 0x80); break; } return 0; } /* Return 0 for success, < 0 for failure */ static int show_wbmp_from_file(char *bmpname, FILE *bmpfile) { long typefield; long width, height; typefield = get_mbi(bmpfile); if (typefield < 0) { perror(bmpname); return -1; } if (parse_headers(bmpfile) < 0) { fprintf(stderr, "%s: format error in headers\n", bmpname); return -1; } width = get_mbi(bmpfile); height = get_mbi(bmpfile); if (width < 0 || height < 0) { fprintf(stderr, "%s: error reading height and width\n", bmpname); return -1; } switch (typefield) { case 0: printf("%s, %ldx%ld B/W bitmap, no compression\n", bmpname, width, height); print_extparms(stdout); if (show_image_from_file(bmpname, bmpfile, width, height) < 0) { return -1; } break; default: fprintf(stderr, "%s: cannot handle level %ld wbmp\n", bmpname, typefield); return -1; } return 0; } int main(int argc, char *argv[]) { int i; /* 1 means an I/O error. No other error values are used yet. */ int exitvalue = 0; if (argc > 1) { for (i = 1; i < argc; i++) { FILE *bmpfile; bmpfile = fopen(argv[i], "r"); if (bmpfile) { if (show_wbmp_from_file(argv[i], bmpfile) < 0) { /* We've already reported the error */ exitvalue = 1; } if (fclose(bmpfile) < 0) { perror(argv[i]); exitvalue = 1; } } else { perror(argv[i]); exitvalue = 1; } if (i < argc - 1) { /* more files follow -- separate them */ printf("\n"); } } } else { /* No files specified -- read from standard input */ if (show_wbmp_from_file("stdin", stdin)) { exitvalue = 1; } } return exitvalue; } gateway-1.4.5/utils/wbmp.h0000644000175000017500000001216113227613126014146 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef WBMP_H #define WBMP_H /* WBMP - Wireless Bitmap * * Kalle Marjola 1999 for WapIT Ltd. * * functions to store WBMPs and and create Octet strings from them */ #include "gwlib/gwlib.h" /* extension header parameters... not implemented/supported in any WBMP * yet... but for future reference, although I'm quite sure there is * something wrong in these... */ typedef struct extparam { Octet bitfield; /* if bitfield additional data */ /* or */ char param[9]; /* parameter */ char value[17]; /* and associated value */ } ExtParam; /* WBMP - wireless bitmap format * * structure to define wireless bitmap - not complete! */ typedef struct wbmp { MultibyteInt type_field; Octet fix_header_field; /* extension header is a bit more complicated thing that what is * represented here but the spesification is a bit obfuscated one * and they are not yet used to anything, so it is left undefined */ ExtParam *ext_header_field; int exthdr_count; /* total # of ext headers */ MultibyteInt width; MultibyteInt height; Octet *main_image; Octet **animated_image; int animimg_count; /* total # of animated images */ } WBMP; /* create a new empty WBMP struct. Return a pointer to it or NULL if * operation fails */ WBMP *wbmp_create_empty(void); /* delete given WBMP, including freeing the pixmap */ void wbmp_delete(WBMP *pic); #define NEGATIVE 1 /* source has white=0, black=1 */ #define REVERSE 2 /* source has righmost as most significant */ /* create a new bitmap * * type: 0 (B/W, Uncompressed bitmap) WBMP - the only type currently * specificated. * * width and height are size of the bitmap, * data is the entire bitmap; from left-top corner to righ-bottom; * if the width is not dividable by 8, the rest of the row is padded with * zeros. bytes are ordered big-endian * * target: black=0, white=1, most significant leftmost * * You can generate raw bitmap in Linux (RH 6.0) with following line: * %> convert -monochrome input_file target.mono * * ..which then requires flags REVERSE and NEGATIVE * * return pointer to created WBMP, or NULL if fails */ WBMP *wbmp_create(int type, int width, int height, Octet *data, int flags); /* create Octet stream out of given WBMP * return the length of stream, *stream is set to new stream which must * be freed by the caller */ int wbmp_create_stream(WBMP *pic, Octet **stream); #endif gateway-1.4.5/wap/0000755000175000017500000000000013312227713012454 5ustar toljtoljgateway-1.4.5/wap/wtls_machine-decl.h0000644000175000017500000001611313227613126016213 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtls_machine-decl.h - macro call for generating WTLS server state machine. See * the architecture document for guidance how to use and update it. * * By Nick Clarey (c) 3GLab Ltd. * Nikos Balkanas, Inaccess Networks (2009) * * The WTLSMachine data structure preserves the state of the existing WTLS * transaction. The fields which are included; * * Machine identification: address four-tuple * Connection End : Server (1) or Client (2) This is always "server" * (at least at the moment) * Bulk Cipher Algorithm : The algorithm to be used for stream or block encryption * Key Size : ????? * IV Size : The base IV used to calculate a record level IV for block ciphers running * in CBC mode for records sent by the server * MAC Algorithm : The algorithm identifier used for message authentication. * Master Secret : A shared secret between the two peers * Client Random : A random value supplied by the client * Server Random : A random value supplied by the server * Sequence Number Mode : Off (0), Implicit (1) or Explicit (2) * Key Refresh rate : New keys for MAC secret, IV and Encryption are calculated * every "n", where n = 2^(RefreshRate) * Compression Method : The algorithm to compress data prior to encryption * */ #if !defined(MACHINE) #error "wtls_machine-decl.h: Macro MACHINE is missing." #elif !defined(ENUM) #error "wtls_machine-decl.h: Macro ENUM is missing." #elif !defined(ADDRTUPLE) #error "wtls_machine-decl.h: Macro ADDRTUPLE is missing." #elif !defined(INTEGER) #error "wtls_machine-decl.h: Macro INTEGER is missing." #elif !defined(OCTSTR) #error "wtls_machine-decl.h: Macro OCTSTR is missing." #elif !defined(PDULIST) #error "wtls_machine-decl.h: Macro PDULIST is missing." #endif /* Need to add server sent and client received packets for sequence numbering */ /* Last received packet maybe needs to be hashed according to Alert message in case we need to send an alert. */ MACHINE(ENUM(state) ADDRTUPLE(addr_tuple) /* The source address/port and dest address/port */ INTEGER(bulk_cipher_algorithm) /* Bulk Cipher Algorithm identifier */ INTEGER(cipher_type) /* Cipher type */ INTEGER(mac_algorithm) /* MAC Algorithm identifier */ OCTSTR(client_random) /* The client's random number */ OCTSTR(server_random) /* The server's random number */ OCTSTR(master_secret) /* The master secret */ INTEGER (key_algorithm) /* Exchange key algorithm chosen */ INTEGER (key_size) /* The "key size". Which key size, I have no idea */ INTEGER (key_material_length) /* and what might that be ? */ INTEGER (is_exportable) /* exportable flag (?) */ INTEGER(iv_size) /* The IV size */ INTEGER(mac_size) /* MAC size */ INTEGER(mac_key_size) /* MAC key size */ INTEGER(sequence_number_mode) /* The sequence number mode */ INTEGER(key_refresh) /* How often we should refresh our keys */ INTEGER(last_refresh) /* Last client seqnum when keys were refreshed */ OCTSTR(compression_method) /* The compression algorithm */ INTEGER(encrypted) /* set if packets are encrypted */ OCTSTR(client_write_MAC_secret) /* */ OCTSTR(client_write_enc_key) /* */ OCTSTR(client_write_IV) /* */ OCTSTR(server_write_MAC_secret) /* */ OCTSTR(server_write_enc_key) /* */ OCTSTR(server_write_IV) /* */ INTEGER(client_seq_num) /* incremented for each client msg */ INTEGER(server_seq_num) /* incremented for each server msg */ OCTSTR(last_packet_checksum) /* The last received packet checksum */ PDULIST(last_received_packet) /* The last received packet checksum */ OCTSTR(handshake_data) /* All the handshake payloads, received or sent, concatenated in order */ OCTSTR(packet_to_send) /* A packet we're preparing to send */ ) #undef MACHINE #undef ENUM #undef ADDRTUPLE #undef INTEGER #undef OCTSTR #undef PDULIST gateway-1.4.5/wap/wtls_state-decl.h0000644000175000017500000004347713227613126015744 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Macro calls to generate rows of the state table. See the documentation for * guidance how to use and update these. * * by Nick Clarey * Nikos Balkanas, Inaccess Networks (2009) */ STATE_NAME(NULL_STATE) STATE_NAME(CREATING) STATE_NAME(CREATED) STATE_NAME(EXCHANGE) STATE_NAME(COMMIT) STATE_NAME(OPENING) STATE_NAME(OPEN) /* If the packet is a ClientHello */ /* We only include this case in state NULL; the others are handled by the wtls_find_or_create function */ ROW(NULL_STATE, T_Unitdata_Ind, packet_contains_clienthello (event->u.T_Unitdata_Ind.pdu_list), { clientHello(event, wtls_machine); }, CREATING) ROW(NULL_STATE, T_Unitdata_Ind, 1, { WAPEvent *alert; error(0, "send_alert ~> Critical alert (unexpected_message), while waiting for client hello."); alert = wap_event_create(SEC_Terminate_Req); alert->u.SEC_Terminate_Req.addr_tuple = wap_addr_tuple_duplicate(event->u.T_Unitdata_Ind.addr_tuple); alert->u.SEC_Terminate_Req.alert_desc = unexpected_message; alert->u.SEC_Terminate_Req.alert_level = critical_alert; wtls_dispatch_event(alert); }, CREATING) /* Creating State */ /* Termination */ ROW(CREATING, SEC_Terminate_Req, 1, { /* Send off a T_Unitdata_Req containing an alert as specified */ send_alert(event, wtls_machine); }, NULL_STATE) /* Exception */ ROW(CREATING, SEC_Exception_Req, 1, { /* Send off a T_Unitdata_Req containing an exception as specified */ send_alert(event, wtls_machine); }, CREATING) /* Create Response - create a buffer with a "ServerHello" and possibly a Certificate or something else */ ROW(CREATING, SEC_Create_Res, 1, { serverHello(event, wtls_machine); }, CREATED) /* Created State */ /* Exchange Request - Full Handshake will be performed */ ROW(CREATED, SEC_Exchange_Req, 1, { wtls_PDU* serverKeyXchgPDU; wtls_PDU* serverHelloDonePDU; /* Assert that the PDU list is valid */ gw_assert(wtls_machine->packet_to_send != NULL); /* We'll also need a Server Key Exchange message */ serverKeyXchgPDU = wtls_pdu_create(Handshake_PDU); serverKeyXchgPDU->rlen = 1; serverKeyXchgPDU->snMode = wtls_machine->sequence_number_mode? 1: 0; serverKeyXchgPDU->u.handshake.msg_type = server_key_exchange; serverKeyXchgPDU->u.handshake.server_key_exchange = (ServerKeyExchange*) gw_malloc(sizeof(ServerKeyExchange)); serverKeyXchgPDU->u.handshake.server_key_exchange->param_spec = NULL; /* Allocate memory for the RSA component */ debug("wtls: ", 0,"Going to get the RSA public key..."); serverKeyXchgPDU->u.handshake.server_key_exchange->rsa_params = wtls_get_rsapublickey(); debug("wtls: ", 0,"...got it."); add_pdu(wtls_machine, serverKeyXchgPDU); wtls_pdu_destroy(serverKeyXchgPDU); debug("wtls: ", 0,"in CREATED - just added pdu..."); /* Add some more PDUs to the List - potentially a ServerKeyExchange, a CertificateRequest and a ServerHelloDone */ /* Just a ServerHelloDone for now */ serverHelloDonePDU = wtls_pdu_create(Handshake_PDU); serverHelloDonePDU->rlen = 1; serverHelloDonePDU->snMode = wtls_machine->sequence_number_mode? 1: 0; serverHelloDonePDU->u.handshake.msg_type = server_hello_done; add_pdu(wtls_machine, serverHelloDonePDU); wtls_pdu_destroy(serverHelloDonePDU); /* Translate the buffer and address details into a T_Unitdata_Req * and send it winging it's way across the network */ send_queuedpdus(wtls_machine); }, EXCHANGE) /* Commit Request - Abbreviated Handshake will be performed */ ROW(CREATED, SEC_Commit_Req, 1, { /* Assert that the PDU list is valid */ /* Add some more PDUs to the List - a ChangeCipherSpec and a Finished */ /* Translate the buffer and address details into a T_Unitdata_Req */ /* And send it winging it's way across the network */ }, COMMIT) /* Terminate Request */ ROW(CREATED, SEC_Terminate_Req, 1, { /* Send off a T_Unitdata_Req containing an alert as specified */ send_alert(event, wtls_machine); }, NULL_STATE) /* Exception Request */ ROW(CREATED, SEC_Exception_Req, 1, { /* Send off a T_Unitdata_Req containing an exception as specified */ send_alert(event, wtls_machine); }, CREATED) /* Exchange State */ /* Unitdata arrival - identical ClientHello record */ ROW(EXCHANGE, T_Unitdata_Ind, clienthellos_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1, { /* It appears as though someone has sent us an identical ClientHello to the last one */ /* Make ourselves a T_Unitdata_Req with the last_transmitted_packet */ /* And send it on it's merry */ }, EXCHANGE) /* Unitdata arrival - non-identical ClientHello record */ //ROW(EXCHANGE, // T_Unitdata_Ind, // clienthellos_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) != 1, // { /* So, this one's different. They must have changed their mind about something, so try a CREATING again */ /* Do the necessary SEC_Create_Ind stuff */ // }, // CREATING) /* Unitdata arrival - warning alert */ ROW(EXCHANGE, T_Unitdata_Ind, is_warning_alert(event->u.T_Unitdata_Ind.pdu_list, wtls_machine), { /* Do the necessary SEC_Exception_Ind stuff */ }, EXCHANGE) /* Unitdata arrival - critical/fatal alert */ ROW(EXCHANGE, T_Unitdata_Ind, is_critical_alert(event->u.T_Unitdata_Ind.pdu_list, wtls_machine), { /* Do the necessary SEC_Terminate_Ind stuff */ /* And we're dead :-< */ }, NULL_STATE) /* Terminate */ ROW(EXCHANGE, SEC_Terminate_Req, 1, { /* Send off a T_Unitdata_Req containing an alert as specified */ send_alert(event, wtls_machine); }, NULL_STATE) /* Unitdata arrival - good packet */ ROW(EXCHANGE, T_Unitdata_Ind, 1, { exchange_keys(event, wtls_machine); }, OPENING) /* Exception */ ROW(EXCHANGE, SEC_Exception_Req, 1, { /* Send off a T_Unitdata_Req containing an exception as specified */ send_alert(event, wtls_machine); }, EXCHANGE) /* Commit State */ /* Unitdata arrival - identical ClientHello record */ ROW(COMMIT, T_Unitdata_Ind, clienthellos_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet), { /* It appears as though someone has sent us an identical ClientHello to the last one */ /* Make ourselves a T_Unitdata_Req with the last_transmitted_packet */ /* And send it on it's merry way */ }, COMMIT) /* Unitdata arrival - non-identical ClientHello record */ ROW(COMMIT, T_Unitdata_Ind, clienthellos_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) != 1, { /* So, this one's different. They must have changed their mind about something, so try a CREATING again */ /* Do the necessary SEC_Create_Ind stuff */ }, CREATING) /* Unitdata arrival - good packet with ChangeCipherSpec and Finished */ ROW(COMMIT, T_Unitdata_Ind, packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) && packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) && packet_contains_userdata (event->u.T_Unitdata_Ind.pdu_list), { /* Create ourselves a SEC_Commit_Cnf packet to send off */ /* Send it off */ }, OPEN) /* Unitdata arrival - good packet with ChangeCipherSpec, Finished and UD */ ROW(COMMIT, T_Unitdata_Ind, packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) && packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) && packet_contains_userdata (event->u.T_Unitdata_Ind.pdu_list), { /* Create a SEC_Commit_Cnf packet to send off */ /* Send it off */ /* Relay the contents of the packets up to the WTP or WSP layers, depending on the destination port */ }, OPEN) /* Unitdata arrival - critical/fatal alert */ ROW(COMMIT, T_Unitdata_Ind, is_critical_alert(event->u.T_Unitdata_Ind.pdu_list, wtls_machine), { /* Do the necessary SEC_Terminate_Ind stuff */ /* And we're dead :-< */ }, NULL_STATE) /* Unitdata arrival - warning alert */ ROW(COMMIT, T_Unitdata_Ind, is_warning_alert(event->u.T_Unitdata_Ind.pdu_list, wtls_machine), { /* Do the necessary SEC_Exception_Ind stuff */ }, COMMIT) /* Terminate */ ROW(COMMIT, SEC_Terminate_Req, 1, { /* Send off a T_Unitdata_Req containing an alert as specified */ send_alert(event, wtls_machine); }, NULL_STATE) /* Exception */ ROW(COMMIT, SEC_Exception_Req, 1, { /* Send off a T_Unitdata_Req containing an exception as specified */ send_alert(event, wtls_machine); }, COMMIT) /* Opening State */ /* Create Request */ ROW(OPENING, SEC_Create_Request_Req, 1, { /* Send off a T_Unitdata_Req containing a HelloRequest */ }, OPENING) /* Send out UnitData */ ROW(OPENING, SEC_Unitdata_Req, 1, { /* Apply the negotiated security "stuff" to the received packet */ /* Send out the packet to the destination port/address requested */ }, OPENING) /* Unitdata received - ClientHello */ //ROW(OPENING, // T_Unitdata_Ind, // packet_contains_clienthello (event->u.T_Unitdata_Ind.pdu_list) == 0, // { ///* Hmm, they're obviously not happy with something we discussed, so let's head back to creating */ ///* Do the necessary SEC_Create_Ind stuff */ //}, // CREATING) /* Unitdata received */ ROW(OPENING, T_Unitdata_Ind, packet_is_application_data(event->u.T_Unitdata_Ind.pdu_list), { wtls_application(event, wtls_machine); }, OPEN) /* Unitdata arrival - Certificate, ClientKeyExchange ... Finished */ ROW(OPENING, T_Unitdata_Ind, certificates_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1 && clientkeyexchanges_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1 && certifcateverifys_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1 && changecipherspecs_are_identical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1 && finishes_are_indentical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1, { /* It appears as though someone has sent us an identical ClientHello to the last one */ /* Make ourselves a T_Unitdata_Req with the last_transmitted_packet */ /* And send it on it's merry way */ }, OPENING) /* Unitdata arrival - critical/fatal alert */ ROW(OPENING, T_Unitdata_Ind, is_critical_alert(event->u.T_Unitdata_Ind.pdu_list, wtls_machine), { /* Do the necessary SEC_Terminate_Ind stuff */ /* And we're dead :-< */ }, NULL_STATE) /* Unitdata arrival - warning alert */ ROW(OPENING, T_Unitdata_Ind, is_warning_alert(event->u.T_Unitdata_Ind.pdu_list, wtls_machine), { /* Do the necessary SEC_Exception_Ind stuff */ }, OPENING) /* Terminate */ ROW(OPENING, SEC_Terminate_Req, 1, { /* Send off a T_Unitdata_Req containing an alert as specified */ send_alert(event, wtls_machine); }, NULL_STATE) /* Exception */ ROW(OPENING, SEC_Exception_Req, 1, { /* Send off a T_Unitdata_Req containing an exception as specified */ send_alert(event, wtls_machine); }, OPENING) /* Open State */ /* Create Request */ ROW(OPEN, SEC_Create_Request_Req, 1, { /* Send off a T_Unitdata_Req with a HelloRequest */ }, OPEN) /* Send out UnitData */ ROW(OPEN, SEC_Unitdata_Req, 1, { /* Apply the negotiated security "stuff" to the received packet */ /* Send out the packet to the destination port/address requested */ }, OPEN) /* Unitdata received - ClientHello */ ROW(OPEN, T_Unitdata_Ind, packet_contains_clienthello (event->u.T_Unitdata_Ind.pdu_list), { /* Hmm, they're obviously not happy with something we discussed, so let's head back to creating */ /* Do the necessary SEC_Create_Ind stuff */ wtls_machine->encrypted = 0; wtls_machine->last_refresh = -1; clientHello(event, wtls_machine); }, CREATING) /* Unitdata received */ ROW(OPEN, T_Unitdata_Ind, packet_is_application_data(event->u.T_Unitdata_Ind.pdu_list), { wtls_application(event, wtls_machine); }, OPEN) /* Unitdata arrival - ChangeCipherSpec, Finished */ ROW(OPEN, T_Unitdata_Ind, packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) == 1 && packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) == 1 && packet_contains_userdata(event->u.T_Unitdata_Ind.pdu_list) != 1 && finishes_are_indentical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1, { /* Just send out a T_Unitdata_Req with an Alert(duplicate_finished_received) */ }, OPEN) /* Unitdata arrival - ChangeCipherSpec, Finished and UD */ ROW(OPEN, T_Unitdata_Ind, packet_contains_changecipherspec (event->u.T_Unitdata_Ind.pdu_list) == 1 && packet_contains_finished (event->u.T_Unitdata_Ind.pdu_list) == 1 && packet_contains_userdata(event->u.T_Unitdata_Ind.pdu_list) == 1 && finishes_are_indentical(event->u.T_Unitdata_Ind.pdu_list, wtls_machine->last_received_packet) == 1, { /* Apply the negotiated decryption/decoding/MAC check to the received data */ /* Take the userdata and pass it on up to the WTP/WSP, depending on the destination port */ /* Send out a T_Unitdata_Req with an Alert(duplicate_finished_received) */ }, OPEN) /* Unitdata arrival - critical/fatal alert */ ROW(OPEN, T_Unitdata_Ind, is_critical_alert(event->u.T_Unitdata_Ind.pdu_list, wtls_machine), { /* Do the necessary SEC_Terminate_Ind stuff */ /* And we're dead :-< */ }, NULL_STATE) /* Unitdata arrival - warning alert */ ROW(OPEN, T_Unitdata_Ind, is_warning_alert(event->u.T_Unitdata_Ind.pdu_list, wtls_machine), { /* Do the necessary SEC_Terminate_Ind stuff */ }, OPEN) /* Terminate */ ROW(OPEN, SEC_Terminate_Req, 1, { /* Send off a T_Unitdata_Req containing an alert as specified */ send_alert(event, wtls_machine); }, NULL_STATE) /* Exception */ ROW(OPEN, SEC_Exception_Req, 1, { /* Send off a T_Unitdata_Req containing an exception as specified */ send_alert(event, wtls_machine); }, OPEN) #undef ROW #undef STATE_NAME gateway-1.4.5/wap/wsp_headers.h0000644000175000017500000001624613227613126015144 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_headers.h - WSP PDU headers implementation header * * Kalle Marjola */ #ifndef WSP_HEADERS_H #define WSP_HEADERS_H #include "gwlib/gwlib.h" #define WSP_FIELD_VALUE_NUL_STRING 1 #define WSP_FIELD_VALUE_ENCODED 2 #define WSP_FIELD_VALUE_DATA 3 #define WSP_FIELD_VALUE_NONE 4 /* secondary_field_value only */ /* The value defined as Quote in 8.4.2.1 */ #define WSP_QUOTE 127 /* Largest value that will fit in a Short-integer encoding */ #define MAX_SHORT_INTEGER 127 /* Marker values used in the encoding */ #define BASIC_AUTHENTICATION 128 #define ABSOLUTE_TIME 128 #define RELATIVE_TIME 129 #define BYTE_RANGE 128 #define SUFFIX_BYTE_RANGE 129 /* Use this value for Expires headers if we can't parse the expiration * date. It's about one day after the start of the epoch. We don't * use the exact start of the epoch because some clients have trouble * with that. */ #define LONG_AGO_VALUE 100000 /* LIST is a comma-separated list such as is described in the "#rule" * entry of RFC2616 section 2.1. */ #define LIST 1 /* BROKEN_LIST is a list of "challenge" or "credentials" elements * such as described in RFC2617. I call it broken because the * parameters are separated with commas, instead of with semicolons * like everywhere else in HTTP. Parsing is more difficult because * commas are also used to separate list elements. */ #define BROKEN_LIST 2 #define TABLE_SIZE(table) ((long)(sizeof(table) / sizeof(table[0]))) struct parameter { Octstr *key; Octstr *value; }; typedef struct parameter Parameter; typedef int header_pack_func_t(Octstr *packed, Octstr *value); struct headerinfo { /* The WSP_HEADER_* enumeration value for this header */ int header; header_pack_func_t *func; /* True if this header type allows multiple elements per * header on the HTTP side. */ int allows_list; }; /* All WSP packing/unpacking routines that are exported for use within * external modules, ie. MMS encoding/decoding. */ int wsp_field_value(ParseContext *context, int *well_known_value); void wsp_skip_field_value(ParseContext *context); int wsp_secondary_field_value(ParseContext *context, long *result); void parm_destroy_item(void *parm); List *wsp_strip_parameters(Octstr *value); /* unpacking */ Octstr *wsp_unpack_integer_value(ParseContext *context); Octstr *wsp_unpack_version_value(long value); void wsp_unpack_all_parameters(ParseContext *context, Octstr *decoded); Octstr *wsp_unpack_date_value(ParseContext *context); void wsp_unpack_well_known_field(List *unpacked, int field_type, ParseContext *context); void wsp_unpack_app_header(List *unpacked, ParseContext *context); /* packing */ void wsp_pack_integer_value(Octstr *packed, unsigned long integer); int wsp_pack_date(Octstr *packet, Octstr *value); int wsp_pack_retry_after(Octstr *packet, Octstr *value); int wsp_pack_text(Octstr *packet, Octstr *value); int wsp_pack_quoted_text(Octstr *packed, Octstr *text); int wsp_pack_integer_string(Octstr *packet, Octstr *value); int wsp_pack_version_value(Octstr *packet, Octstr *value); int wsp_pack_constrained_value(Octstr *packed, Octstr *text, long value); void wsp_pack_value(Octstr *packed, Octstr *encoded); void wsp_pack_parameters(Octstr *packed, List *parms); int wsp_pack_list(Octstr *packed, long fieldnum, List *elements, int i); void wsp_pack_short_integer(Octstr *packed, unsigned long integer); void wsp_pack_separate_content_type(Octstr *packed, List *headers); Octstr *wsp_unpack_accept_general_form(ParseContext *context); Octstr *wsp_unpack_accept_charset_general_form(ParseContext *context); int wsp_pack_content_type(Octstr *packet, Octstr *value); int wsp_pack_application_header(Octstr *packed, Octstr *fieldname, Octstr *value); void wsp_pack_long_integer(Octstr *packed, unsigned long integer); /* Return an HTTPHeader linked list which must be freed by the caller * (see http.h for details of HTTPHeaders). Cannot fail. * The second argument is true if the headers will have a leading * Content-Type field. Some WSP PDUs encode Content-Type separately * this way for historical reasons. */ List *wsp_headers_unpack(Octstr *headers, int content_type); /* Take a List of headers, encode them according to the WSP spec, * and return the encoded headers as an Octstr. * The second argument is true if the encoded headers should have * a leading content-type field. See the note for wsp_headers_unpack. */ Octstr *wsp_headers_pack(List *headers, int separate_content_type, int wsp_version); #endif gateway-1.4.5/wap/cookies.c0000644000175000017500000004205613227613126014265 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Module: cookies.c * * Description: Implements a minimal cookie handler for session persistence. * * References: RFC 2109 * * Author: Paul Keogh, ANAM Wireless Internet Solutions * * Date: May 2000 */ #include #include #include "gwlib/gwlib.h" #include "wsp.h" #include "cookies.h" /* Statics */ static Octstr *get_header_value(Octstr*); static Cookie *parse_cookie(Octstr*); static void add_cookie_to_cache(const WSPMachine*, Cookie*); static void expire_cookies(List*); static void cookie_destroy(void*); static int have_cookie(List*, Cookie*); static int parse_http_date(const char*); static Cookie emptyCookie; Cookie *cookie_create(void) { Cookie *p; p = gw_malloc(sizeof(Cookie)); /* Never returns NULL */ *p = emptyCookie; p -> max_age = -1; time (&p -> birth); return p; } void cookies_destroy(List *cookies) { gwlib_assert_init(); if (cookies == NULL) return; gwlist_destroy(cookies, cookie_destroy); } int get_cookies(List *headers, const WSPMachine *sm) { Octstr *header = NULL; Octstr *value = NULL; Cookie *cookie = NULL; long pos = 0; /* * This can happen if the user aborts while the HTTP request is pending from the server. * In that case, the session machine is destroyed and is not available to this function * for cookie caching. */ if (sm == NULL) { info (0, "No session machine for cookie retrieval"); return 0; } for (pos = 0; pos < gwlist_len(headers); pos++) { header = gwlist_get(headers, pos); /* debug ("wap.wsp.http", 0, "get_cookies: Examining header (%s)", octstr_get_cstr (header)); */ if (strncasecmp ("set-cookie", octstr_get_cstr (header),10) == 0) { debug ("wap.wsp.http", 0, "Caching cookie (%s)", octstr_get_cstr (header)); if ((value = get_header_value (header)) == NULL) { error (0, "get_cookies: No value in (%s)", octstr_get_cstr(header)); continue; } /* Parse the received cookie */ if ((cookie = parse_cookie(value)) != NULL) { /* Check to see if this cookie is already present */ if (have_cookie(sm->cookies, cookie) == 1) { debug("wap.wsp.http", 0, "parse_cookie: Cookie present"); cookie_destroy(cookie); continue; } else { add_cookie_to_cache(sm, cookie); debug("wap.wsp.http", 0, "get_cookies: Added (%s)", octstr_get_cstr(cookie -> name)); } } } } debug("wap.wsp.http", 0, "get_cookies: End"); return 0; } int set_cookies(List *headers, WSPMachine *sm) { Cookie *value = NULL; Octstr *cookie = NULL; long pos = 0; if (headers == NULL || sm == NULL) { error (0, "set_cookies: Null argument(s) - no headers, WSPMachine or both"); return -1; } /* Expire cookies that have timed out */ expire_cookies(sm->cookies); /* Walk through the cookie cache, adding the cookie to the request headers */ if (gwlist_len(sm->cookies) > 0) { debug("wap.wsp.http", 0, "set_cookies: Cookies in cache"); for (pos = 0; pos < gwlist_len(sm->cookies); pos++) { value = gwlist_get(sm->cookies, pos); cookie = octstr_create("Cookie: "); if (value->version) octstr_append(cookie, value->version); octstr_append(cookie, value->name); octstr_append_char(cookie, '='); octstr_append(cookie, value->value); if (value->path) { octstr_append_char(cookie, ';'); octstr_append(cookie, value->path); } if (value->domain) { octstr_append_char(cookie, ';'); octstr_append(cookie, value->domain); } gwlist_append(headers, cookie); debug("wap.wsp.http", 0, "set_cookies: Added (%s)", octstr_get_cstr (cookie)); } } else debug("wap.wsp.http", 0, "set_cookies: No cookies in cache"); return 0; } /* * Private interface functions */ /* * Function: get_header_value * * Description: Gets the header value as an Octstr. */ static Octstr *get_header_value(Octstr *header) { Octstr *h = NULL; long colon = -1; if (header == NULL) { error(0, "get_header_value: NULL argument"); return NULL; } octstr_strip_blanks(header); colon = octstr_search_char(header, ':', 0); if (colon == -1) { error(0, "get_header_value: Malformed header (%s)", octstr_get_cstr (header)); return NULL; } else { h = octstr_copy(header, colon + 1, octstr_len(header)); octstr_strip_blanks(h); } debug("wap.wsp.http", 0, "get_header_value: Value (%s)", octstr_get_cstr (h)); return h; } /* * Function: parse_cookie * * Description: Parses the received cookie and rewrites it for sending. */ static Cookie *parse_cookie(Octstr *cookiestr) { char *v = NULL; char *p = NULL; int delta = 0; Cookie *c = NULL; Octstr **f = NULL; if (cookiestr == NULL) { error(0, "parse_cookie: NULL argument"); return NULL; } v = gw_strdup(octstr_get_cstr (cookiestr)); p = strtok(v, ";"); c = cookie_create(); /* Never returns NULL */ while (p != NULL) { while (isspace((int)*p)) p++; /* Skip leading whitespace */ if (strncasecmp("version", p, 7) == 0) f = &c -> version; else if (strncasecmp("path", p, 4) == 0) f = &c -> path; else if (strncasecmp("domain", p, 6) == 0) f = &c -> domain; /* XXX DAVI: Shouldn't we check if domain is similar * to real domain, and to set domain to * real domain if not set by header ??? */ else if (strncasecmp("max-age", p, 7) == 0) { c -> max_age = atol(strrchr (p, '=') + 1); p = strtok(NULL, ";"); continue; } else if (strncasecmp("expires", p, 7) == 0) { delta = parse_http_date(p); if (delta != -1) c->max_age = delta; p = strtok(NULL, ";"); continue; } else if (strncasecmp("comment", p, 7) == 0 ) { /* Ignore comments */ p = strtok(NULL, ";"); continue; } else if (strncasecmp("secure", p, 6) == 0 ) { /* XXX DAVI: this should processed */ p = strtok(NULL, ";"); continue; } else { /* Name value pair - this should be first */ char *equals = NULL; if ((equals = strchr(p, '=')) != NULL) { *equals = '\0'; c->name = octstr_create(p); c->value = octstr_create(equals + 1); } else { error(0, "parse_cookie: Bad name=value cookie component (%s)", p); cookie_destroy(c); return NULL; } p = strtok(NULL, ";"); continue; } if (*f != NULL) { /* Undefined behaviour - 4.2.2 */ error(0, "parse_cookie: Duplicate cookie field (%s), discarding", p); p = strtok(NULL, ";"); continue; } *f = octstr_create("$"); octstr_append_cstr(*f, p); p = strtok(NULL, ";"); } /* Process version - 4.3.4 * XXX DAVI: Altough it seems to be "MUST" in RFC, no one sends a Version * tag when it's value is "0" if (c->version == NULL) { c->version = octstr_create(""); octstr_append_cstr(c->version, "$Version=\"0\";"); } */ gw_free (v); return c; } /* * Function: add_cookie_to_cache * * Description: Adds the cookie to the WSPMachine cookie cache. */ static void add_cookie_to_cache(const WSPMachine *sm, Cookie *value) { gw_assert(sm != NULL); gw_assert(sm->cookies != NULL); gw_assert(value != NULL); gwlist_append(sm->cookies, value); return; } /* * Function: have_cookie * * Description: Checks to see if the cookie is present in the list. */ static int have_cookie(List *cookies, Cookie *cookie) { Cookie *value = NULL; long pos = 0; if (cookies == NULL || cookie == NULL) { error(0, "have_cookie: Null argument(s) - no Cookie list, Cookie or both"); return 0; } /* Walk through the cookie cache, comparing cookie */ while (pos < gwlist_len(cookies)) { value = gwlist_get(cookies, pos); /* octstr_compare() now only returns 0 on an exact match or if both args are 0 */ debug ("wap.wsp.http", 0, "have_cookie: Comparing name (%s:%s), path (%s:%s), domain (%s:%s)", octstr_get_cstr(cookie->name), octstr_get_cstr(value->name), octstr_get_cstr(cookie->path), octstr_get_cstr(value->path), octstr_get_cstr(cookie->domain), octstr_get_cstr(value->domain)); /* Match on no value or value and value equality for name, path and domain */ if ( (value->name == NULL || ((value->name != NULL && cookie->name != NULL) && octstr_compare(value->name, cookie->name) == 0)) && (value->path == NULL || ((value->path != NULL && cookie->path != NULL) && octstr_compare(value->path, cookie->path) == 0)) && (value->domain == NULL || ((value->domain != NULL && cookie->domain != NULL) && octstr_compare(value->domain, cookie->domain) == 0)) ) { /* We have a match according to 4.3.3 - discard the old one */ cookie_destroy(value); gwlist_delete(cookies, pos, 1); /* Discard the new cookie also if max-age is 0 - set if expiry date is up */ if (cookie->max_age == 0) { debug("wap.wsp.http", 0, "have_cookie: Discarding expired cookie (%s)", octstr_get_cstr(cookie->name)); return 1; } debug("wap.wsp.http", 0, "have_cookie: Updating cached cookie (%s)", octstr_get_cstr (cookie->name)); break; } else { pos++; } } return 0; } /* * Function: expire_cookies * * Description: Walks thru the cookie list and checking for expired cookies. */ static void expire_cookies(List *cookies) { Cookie *value = NULL; time_t now = 0; long pos = 0; if (cookies == NULL) { error(0, "expire_cookies: Null argument(s) - no Cookie list"); return; } /* Walk through the cookie cache */ time(&now); if (gwlist_len(cookies) > 0) { debug("wap.wsp.http", 0, "expire_cookies: Cookies in cache"); for (pos = 0; pos < gwlist_len(cookies); pos++) { value = gwlist_get(cookies, pos); gw_assert(value != NULL); if (value->max_age != -1) { /* Interesting value */ if (value->max_age + value->birth < now) { debug("wap.wsp.http", 0, "expire_cookies: Expired cookie (%s)", octstr_get_cstr(value->name)); cookie_destroy(value); gwlist_delete(cookies, pos, 1); } } } } else debug("wap.wsp.http", 0, "expire_cookies: No cookies in cache"); return; } static void cookie_destroy(void *p) { Cookie *cookie; if (p == NULL) return; cookie = p; octstr_destroy(cookie->name); octstr_destroy(cookie->value); octstr_destroy(cookie->version); octstr_destroy(cookie->domain); octstr_destroy(cookie->path); gw_free(cookie); debug("wap.wsp.http", 0, "cookie_destroy: Destroyed cookie"); return; } /* * Function: parse_http_date * * Description: Parses an HTTP date format as used by the Expires: header. See RFC 2616 * section 3.3.1 for more information. * HTTP applications have historically allowed three different formats * for the representation of date/time stamps: * * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format * * The first format is preferred as an Internet standard and represents * a fixed-length subset of that defined by RFC 1123 [8] (an update to * RFC 822 [9]). The second format is in common use, but is based on the * obsolete RFC 850 [12] date format and lacks a four-digit year. * HTTP/1.1 clients and servers that parse the date value MUST accept * all three formats (for compatibility with HTTP/1.0), though they MUST * only generate the RFC 1123 format for representing HTTP-date values * in header fields. * * Returns: -1 on success, max-age sematic value on success. */ /* * TODO: This is obviously the same as gwlib/date.c:date_http_parse(). * Need to unify this to one pulic function. */ static const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; static int month_index(const char *s) { const char **p = &months[0]; int i = 0; while (*p != NULL) { if (strcmp(s, *p) == 0) return i; p++, i++; } return -1; } static int parse_http_date(const char *expires) { struct tm ti; char *p = NULL; char *date = NULL; char month[MAX_HTTP_DATE_LENGTH]; time_t rv; time_t now; memset(&ti, 0, sizeof(struct tm)); /* Break up the Expires: header */ if (!(date = strchr(expires, '='))) { error(0, "parse_http_date: Bogus expires type=value header (%s)", expires); return -1; } else { date++; while (isspace((int)*date)) ++date; } /* Onto the date value */ if (!(p = strchr (date,' '))) { error(0, "parse_http_date: Bogus date string (%s)", date); return -1; } else while (isspace((int)*p)) ++p; if (MAX_HTTP_DATE_LENGTH < strlen(p)) { error(0, "parse_http_date: %s blows length limit (%d)", date, MAX_HTTP_DATE_LENGTH); return -1; } if (isalpha((int)*p)) { /* ctime */ sscanf(p, (strstr(p, "DST") ? "%s %d %d:%d:%d %*s %d" : "%s %d %d:%d:%d %d"), month, &ti.tm_mday, &ti.tm_hour, &ti.tm_min, &ti.tm_sec, &ti.tm_year); ti.tm_year -= 1900; } else if (p[2] == '-') { /* RFC 850 (normal HTTP) */ char buf[MAX_HTTP_DATE_LENGTH]; sscanf(p, "%s %d:%d:%d", buf, &ti.tm_hour, &ti.tm_min, &ti.tm_sec); buf[2] = '\0'; ti.tm_mday = atoi(buf); buf[6] = '\0'; strcpy(month, &buf[3]); ti.tm_year = atoi(&buf[7]); /* Prevent wraparound from ambiguity */ if (ti.tm_year < 70) { ti.tm_year += 100; } else if (ti.tm_year > 1900) { ti.tm_year -= 1900; } } else { /* RFC 822 */ sscanf(p,"%d %s %d %d:%d:%d",&ti.tm_mday, month, &ti.tm_year, &ti.tm_hour, &ti.tm_min, &ti.tm_sec); /* * since tm_year is years since 1900 and the year we parsed * is absolute, we need to subtract 1900 years from it */ ti.tm_year -= 1900; } ti.tm_mon = month_index(month); if (ti.tm_mon == -1) { error(0, "parse_http_date () failed on bad month value (%s)", month); return -1; } ti.tm_isdst = -1; rv = gw_mktime(&ti); if (ti.tm_isdst) rv -= 3600; if (rv == -1) { error(0, "parse_http_date(): mktime() was unable to resolve date/time: %s", asctime(&ti)); return -1; } debug("parse_http_date", 0, "Parsed date (%s) as: %s", date, asctime(&ti)); /* * If rv is valid, it should be some time in the (near) future. Normalise this to * a max-age semantic so we can use the same expiry mechanism */ now = time(NULL); if (rv - now < 0) { /* This is bad - set the delta to 0 so we expire next time around */ error(0, "parse_http_date () Expiry time (%s) (delta=%ld) is in the past !", asctime(&ti), rv-now); return 0; } return rv - now; } gateway-1.4.5/wap/wtls.c0000644000175000017500000011102313227613126013611 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtls.c: WTLS server-side implementation * * Nick Clarey * Nikos Balkanas, InAccess Networks (2009) */ #include "gwlib/gwlib.h" #ifdef HAVE_WTLS_OPENSSL #include "wtls.h" #include "timers.h" #include "wap_events.h" #include "wtls_pdu.h" #include "wtls_statesupport.h" #include "wtls_pdusupport.h" #include "gw/msg.h" #include "wap.h" #include "wtp.h" #define WTLS_CONNECTIONLESS_PORT 9202 /*********************************************************************** * Internal data structures. * * List of WTLS Server machines. */ static List *wtls_machines = NULL; /* * Counter for WTLS Server machine id numbers, to make sure they are unique. */ static Counter *wtls_machine_id_counter = NULL; /* * Give the status of wtls server layer: * limbo - not running at all * running - operating normally * terminating - waiting for operations to terminate, returning to limbo */ static enum { limbo, running, terminating } wtls_run_status = limbo; /* * Queue of events to be handled by WTLS Server machines. */ static List *wtls_queue = NULL; /***************************************************************************** * * Prototypes of internal functions: */ static wtls_dispatch_func_t *dispatch_resp_to_bb; /* * Create and destroy an uninitialized wtls server state machine. */ static WTLSMachine *wtls_machine_create(WAPAddrTuple * tuple); static void wtls_machine_destroy(void *p); /* * Checks whether the list of wlts server machines includes a specific machine. * * The machine in question is identified with with source and destination * address and port. If the machine does not exist and the event is either; * - A SEC-Create-Request.req or * - A T-Unitdata.ind containing a ClientHello packet or * - A T-Unitdata.ind containing an Alert(no_renegotiation) packet * a new machine is created and added in the machines data structure. * * See WTLS 7.2 for details of this check. */ static WTLSMachine *wtls_machine_find_or_create(WAPEvent * event); /* * Feed an event to a WTLS Server state machine. Handle all errors by * itself, do not report them to the caller. */ static void wtls_event_handle(WTLSMachine * machine, WAPEvent * event); /* * Find a WTLS Server machine from the global list of wtls server * structures that corresponds to the four-tuple of source and destination * addresses and ports. Return a pointer to the machine, or NULL if not found. */ static WTLSMachine *wtls_machine_find(WAPAddrTuple * tuple, long mid); /* Function prototypes */ static void main_thread(void *); static WTLSMachine *find_wtls_machine_using_mid(long mid); static void add_wtls_address(Msg * msg, WTLSMachine * wtls_machine); static void add_pdu(WTLSMachine * wtls_machine, wtls_PDU * pduToAdd); static void send_queuedpdus(WTLSMachine * wtls_machine); void send_alert(WAPEvent * event, WTLSMachine * wtls_machine); char *stateName(int s); /* The match* functions are used for searches through lists */ static int match_handshake_type(void *item, void *pattern); static int match_pdu_type(void *item, void *pattern); extern void write_to_bearerbox(Msg * pmsg); extern Octstr *wtls_get_certificate(void); /*static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data); static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason); static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm); */ /****************************************************************************** * * EXTERNAL FUNCTIONS: * */ WAPEvent *wtls_unpack_wdp_datagram(Msg * msg) { WAPEvent *unitdataIndEvent; List *wtlsPayloadList; /* Dump the Msg */ msg_dump(msg, 0); /* Then, stuff it into a T_Unitdata_Ind Event */ unitdataIndEvent = wap_event_create(T_Unitdata_Ind); info(0, "Event created"); /* Firstly, the address */ unitdataIndEvent->u.T_Unitdata_Ind.addr_tuple = wap_addr_tuple_create(msg->wdp_datagram.source_address, msg->wdp_datagram.source_port, msg->wdp_datagram.destination_address, msg->wdp_datagram.destination_port); info(0, "Set address and stuff"); /* Attempt to stuff this baby into a list-of-WTLS-PDUs */ wtlsPayloadList = wtls_unpack_payloadlist(msg->wdp_datagram.user_data); info(0, "Datagram unpacked!"); /* Then, the pdu material */ unitdataIndEvent->u.T_Unitdata_Ind.pdu_list = wtlsPayloadList; /* And return the event */ return unitdataIndEvent; } void wtls_init(wtls_dispatch_func_t *responder_dispatch) { /* Initialise our various lists and counters */ wtls_machines = gwlist_create(); wtls_machine_id_counter = counter_create(); wtls_queue = gwlist_create(); gwlist_add_producer(wtls_queue); dispatch_resp_to_bb = responder_dispatch; /* Idiot check - ensure that we are able to start running */ gw_assert(wtls_run_status == limbo); wtls_run_status = running; gwthread_create(main_thread, NULL); } void wtls_shutdown(void) { /* Make sure that we're actually running; if so, then prepare for termination */ gw_assert(wtls_run_status == running); wtls_run_status = terminating; gwlist_remove_producer(wtls_queue); gwthread_join_every(main_thread); /* Print out a friendly message stating that we're going to die */ debug("wap.wtls", 0, "wtls_shutdown: %ld wtls machines left", gwlist_len(wtls_machines)); /* And clean up nicely after ourselves */ gwlist_destroy(wtls_machines, wtls_machine_destroy); gwlist_destroy(wtls_queue, wap_event_destroy_item); counter_destroy(wtls_machine_id_counter); } void wtls_dispatch_event(WAPEvent * event) { /* Stick the event on the incoming events queue */ gwlist_produce(wtls_queue, event); } void wtls_dispatch_resp(WAPEvent * dgram) { WAPAddrTuple *tuple; WTLSMachine *wtls_machine; tuple = dgram->u.T_DUnitdata_Req.addr_tuple; if ((wtls_machine = wtls_machine_find(tuple, -1))) { wtls_PDU *respPDU; debug("wtls", 0, "wtls_dispatch_resp ~> Dispatching datagram to bearerbox"); respPDU = wtls_pdu_create(Application_PDU); respPDU->cipher = 1; respPDU->snMode = wtls_machine->sequence_number_mode ? 1 : 0; respPDU->rlen = 1; respPDU->u.application.data = dgram->u.T_DUnitdata_Req.user_data; debug("wtls", 0, "Sending Response PDU:"); wtls_pdu_dump(respPDU, 0); add_pdu(wtls_machine, respPDU); wtls_pdu_destroy(respPDU); send_queuedpdus(wtls_machine); dgram->u.T_DUnitdata_Req.user_data = NULL; } else error(0, "wtls_dispatch_event: Unable to find state machine. " "Dropping datagram."); } int wtls_get_address_tuple(long mid, WAPAddrTuple ** tuple) { WTLSMachine *sm; sm = find_wtls_machine_using_mid(mid); if (sm == NULL) return -1; *tuple = wap_addr_tuple_duplicate(sm->addr_tuple); return 0; } void send_alert(WAPEvent * event, WTLSMachine * wtls_machine) { wtls_PDU *alertPDU; alertPDU = (wtls_PDU *) wtls_pdu_create(Alert_PDU); alertPDU->rlen = 1; alertPDU->snMode = wtls_machine->sequence_number_mode ? 1 : 0; alertPDU->u.alert.level = event->u.SEC_Terminate_Req.alert_level; alertPDU->u.alert.desc = event->u.SEC_Terminate_Req.alert_desc; /* Here's where we should get the current checksum from the wtls_machine */ alertPDU->u.alert.chksum = octstr_create("0000"); add_pdu(wtls_machine, alertPDU); wtls_pdu_destroy(alertPDU); send_queuedpdus(wtls_machine); } static void add_pdu(WTLSMachine * wtls_machine, wtls_PDU * pduToAdd) { int currentLength; wtls_Payload *payloadToAdd; Octstr *packedPDU; /* Update sequence number before encryption */ wtls_machine->server_seq_num++; /* Pack and encrypt the pdu */ if (!(payloadToAdd = wtls_pdu_pack(pduToAdd, wtls_machine))) { wtls_machine->server_seq_num--; return; } if (!payloadToAdd->data) { wtls_machine->server_seq_num--; wtls_payload_destroy(payloadToAdd); return; } /* Check to see if we've already allocated some memory for the list */ if (!wtls_machine->packet_to_send) wtls_machine->packet_to_send = octstr_create(""); /* If the pdu is a Handshake pdu, append the Octstr to our wtls_machine's exchanged_handshakes Octstr */ packedPDU = wtls_payload_pack(payloadToAdd, wtls_machine->server_seq_num); if (pduToAdd->type == ChangeCipher_PDU) wtls_machine->server_seq_num = -1; /* Add it to our list */ currentLength = octstr_len(wtls_machine->packet_to_send); octstr_insert(wtls_machine->packet_to_send, packedPDU, currentLength); wtls_payload_destroy(payloadToAdd); octstr_destroy(packedPDU); } /* * Send the pdu_to_send list to the destination specified by the address in the machine * structure. Don't return anything, handle all errors internally. */ static void send_queuedpdus(WTLSMachine * wtls_machine) { Msg *msg = NULL; gw_assert(wtls_machine->packet_to_send != NULL); if (!wtls_machine->packet_to_send) return; /* Pack the PDU */ msg = msg_create(wdp_datagram); add_wtls_address(msg, wtls_machine); msg->wdp_datagram.user_data = octstr_duplicate(wtls_machine->packet_to_send); /* Send it off */ dispatch_resp_to_bb(msg); /* Destroy our copy of the sent string */ octstr_destroy(wtls_machine->packet_to_send); wtls_machine->packet_to_send = NULL; } /* * Add address from state machine. */ void add_wtls_address(Msg * msg, WTLSMachine * wtls_machine) { debug("wap.wtls", 0, "adding address"); msg->wdp_datagram.source_address = octstr_duplicate(wtls_machine->addr_tuple->local->address); msg->wdp_datagram.source_port = wtls_machine->addr_tuple->local->port; msg->wdp_datagram.destination_address = octstr_duplicate(wtls_machine->addr_tuple->remote->address); msg->wdp_datagram.destination_port = wtls_machine->addr_tuple->remote->port; } /***************************************************************************** * * INTERNAL FUNCTIONS: * */ static void main_thread(void *arg) { WTLSMachine *sm; WAPEvent *e; while (wtls_run_status == running && (e = gwlist_consume(wtls_queue))) { sm = wtls_machine_find_or_create(e); if (sm == NULL) wap_event_destroy(e); else wtls_event_handle(sm, e); } } /* * Give the name of a WTLS Server state in a readable form. */ char *stateName(int s) { switch (s) { #define STATE_NAME(state) case state: return #state; #define ROW(state, event, condition, action, new_state) #include "wtls_state-decl.h" default: return "unknown state"; } } static void fatalAlert(WAPEvent * event, int description) { WAPEvent *abort; abort = wap_event_create(SEC_Terminate_Req); abort->u.SEC_Terminate_Req.addr_tuple = wap_addr_tuple_duplicate (event->u.T_Unitdata_Ind.addr_tuple); abort->u.SEC_Terminate_Req.alert_level = fatal_alert; abort->u.SEC_Terminate_Req.alert_desc = description; wtls_dispatch_event(abort); } static void clientHello(WAPEvent * event, WTLSMachine * wtls_machine) { /* The Wap event we have to dispatch */ WAPEvent *res; wtls_Payload *tempPayload; wtls_PDU *clientHelloPDU; CipherSuite *ciphersuite; int randomCounter, algo; tempPayload = (wtls_Payload *) gwlist_search(event->u.T_Unitdata_Ind.pdu_list, (void *)client_hello, match_handshake_type); if (!tempPayload) { error(0, "Illegal PDU while waiting for a ClientHello"); fatalAlert(event, unexpected_message); return; } clientHelloPDU = wtls_pdu_unpack(tempPayload, wtls_machine); /* Store the client's random value - use pack for simplicity */ wtls_machine->client_random = octstr_create(""); randomCounter = pack_int32(wtls_machine->client_random, 0, clientHelloPDU->u.handshake.client_hello-> random->gmt_unix_time); octstr_insert(wtls_machine->client_random, clientHelloPDU->u.handshake.client_hello->random-> random_bytes, randomCounter); /* Select the ciphersuite from the supplied list */ ciphersuite = wtls_choose_ciphersuite(clientHelloPDU->u.handshake.client_hello-> ciphersuites); if (!ciphersuite) { error(0, "Couldn't agree on encryption cipher. Aborting"); wtls_pdu_destroy(clientHelloPDU); fatalAlert(event, handshake_failure); return; } /* Set the relevant values in the wtls_machine and PDU structure */ wtls_machine->bulk_cipher_algorithm = ciphersuite->bulk_cipher_algo; wtls_machine->mac_algorithm = ciphersuite->mac_algo; /* Generate a SEC_Create_Res event, and pass it back into the queue */ res = wap_event_create(SEC_Create_Res); res->u.SEC_Create_Res.addr_tuple = wap_addr_tuple_duplicate(event->u.T_Unitdata_Ind.addr_tuple); res->u.SEC_Create_Res.bulk_cipher_algo = ciphersuite->bulk_cipher_algo; res->u.SEC_Create_Res.mac_algo = ciphersuite->mac_algo; res->u.SEC_Create_Res.client_key_id = wtls_choose_clientkeyid (clientHelloPDU->u.handshake.client_hello->client_key_ids, &algo); if (!res->u.SEC_Create_Res.client_key_id) { error(0, "Couldn't agree on key exchange protocol. Aborting"); wtls_pdu_destroy(clientHelloPDU); wap_event_destroy(res); fatalAlert(event, unknown_key_id); return; } wtls_machine->key_algorithm = algo; /* Set the sequence number mode in both the machine and the outgoing packet */ res->u.SEC_Create_Res.snmode = wtls_choose_snmode(clientHelloPDU->u.handshake.client_hello-> snmode); wtls_machine->sequence_number_mode = res->u.SEC_Create_Res.snmode; /* Set the key refresh mode in both the machine and the outgoing packet */ res->u.SEC_Create_Res.krefresh = clientHelloPDU->u.handshake.client_hello->krefresh; wtls_machine->key_refresh = res->u.SEC_Create_Res.krefresh; /* Global refresh variable */ debug("wtls", 0, "clientHello ~> Accepted refresh = %d, refresh_rate = " "%d", wtls_machine->key_refresh, 1 << wtls_machine->key_refresh); /* Keep the data so we can send it back in EXCHANGE * temporary - needs to delete old one if exists ! * wtls_machine->handshake_data = octstr_create(""); */ if (wtls_machine->handshake_data) octstr_destroy(wtls_machine->handshake_data); wtls_machine->handshake_data = octstr_create(""); octstr_append(wtls_machine->handshake_data, tempPayload->data); debug("wtls", 0, "clientHello ~> Dispatching SEC_Create_Res event"); wtls_pdu_destroy(clientHelloPDU); wtls_dispatch_event(res); } static void serverHello(WAPEvent * event, WTLSMachine * wtls_machine) { WAPEvent *req; wtls_PDU *serverHelloPDU; // wtls_PDU* certificatePDU; Random *tempRandom; /* List *certList; Certificate *cert; */ int randomCounter = 0; /* Our serverHello */ serverHelloPDU = wtls_pdu_create(Handshake_PDU); serverHelloPDU->rlen = 1; serverHelloPDU->snMode = wtls_machine->sequence_number_mode ? 1 : 0; serverHelloPDU->u.handshake.msg_type = server_hello; serverHelloPDU->u.handshake.server_hello = (ServerHello *) gw_malloc(sizeof(ServerHello)); /* Set our server version */ serverHelloPDU->u.handshake.server_hello->serverversion = 1; /* Get a suitably random number - store it in both the machine structure and outgoing PDU */ tempRandom = wtls_get_random(); wtls_machine->server_random = octstr_create(""); randomCounter = pack_int32(wtls_machine->server_random, 0, tempRandom->gmt_unix_time); octstr_insert(wtls_machine->server_random, tempRandom->random_bytes, octstr_len(wtls_machine->server_random)); serverHelloPDU->u.handshake.server_hello->random = tempRandom; /* At the moment, we don't support session caching, so tell them to forget about caching us */ serverHelloPDU->u.handshake.server_hello->session_id = octstr_format("%llu", wtls_machine->mid); /* We need to select an appropriate mechanism here from the ones listed */ serverHelloPDU->u.handshake.server_hello->client_key_id = event->u.SEC_Create_Res.client_key_id; /* Get our ciphersuite details */ serverHelloPDU->u.handshake.server_hello->ciphersuite = (CipherSuite *) gw_malloc(sizeof(CipherSuite)); serverHelloPDU->u.handshake.server_hello->ciphersuite->bulk_cipher_algo = event->u.SEC_Create_Res.bulk_cipher_algo; serverHelloPDU->u.handshake.server_hello->ciphersuite->mac_algo = event->u.SEC_Create_Res.mac_algo; serverHelloPDU->u.handshake.server_hello->comp_method = null_comp; /* We need to confirm the client's choice, or if they haven't * specified one, select one ourselves */ serverHelloPDU->u.handshake.server_hello->snmode = event->u.SEC_Create_Res.snmode; /* We need to either confirm the client's choice of key refresh rate, or choose a lower rate */ serverHelloPDU->u.handshake.server_hello->krefresh = event->u.SEC_Create_Res.krefresh; /* Add the PDUsto the server's outgoing list */ add_pdu(wtls_machine, serverHelloPDU); wtls_pdu_destroy(serverHelloPDU); /* Generate and dispatch a SEC_Exchange_Req or maybe a SEC_Commit_Req */ req = wap_event_create(SEC_Exchange_Req); req->u.SEC_Exchange_Req.addr_tuple = wap_addr_tuple_duplicate(event->u.T_Unitdata_Ind.addr_tuple); wtls_dispatch_event(req); debug("wtls", 0, "serverHello ~> Dispatching SEC_Exchange_Req event"); } static void exchange_keys(WAPEvent * event, WTLSMachine * wtls_machine) { RSAPublicKey *public_key = NULL; Octstr *checking_data = NULL; /* The Wap PDUs we have to dispatch */ wtls_PDU *changeCipherSpecPDU; wtls_PDU *finishedPDU; /* The PDUs we have to process */ wtls_Payload *tempPayload; wtls_PDU *clientKeyXchgPDU; wtls_PDU *changeCipherSpec_incoming_PDU; wtls_PDU *finished_incoming_PDU; /* For decrypting/encrypting data */ Octstr *concatenatedRandoms = NULL; Octstr *encryptedData = NULL; Octstr *decryptedData = NULL; Octstr *labelVerify = NULL; Octstr *labelMaster = NULL; /* Process the incoming event : ClientKeyExchange */ tempPayload = (wtls_Payload *) gwlist_search(event->u.T_Unitdata_Ind.pdu_list, (void *)client_key_exchange, match_handshake_type); if (!tempPayload) { error(0, "Missing client_key_exchange. Aborting..."); fatalAlert(event, unexpected_message); return; } /* Keep the data so we can send it back */ octstr_insert(wtls_machine->handshake_data, tempPayload->data, octstr_len(wtls_machine->handshake_data)); clientKeyXchgPDU = wtls_pdu_unpack(tempPayload, wtls_machine); wtls_pdu_dump(clientKeyXchgPDU, 0); /* Decrypt the client key exchange PDU */ encryptedData = clientKeyXchgPDU->u.handshake.client_key_exchange->rsa_params-> encrypted_secret; decryptedData = wtls_decrypt_key(wtls_machine->key_algorithm, encryptedData); if (!decryptedData) { error(0, "Key Exchange failed. Couldn't decrypt client's secret (%d)." " Aborting...", wtls_machine->key_algorithm); wtls_pdu_destroy(clientKeyXchgPDU); fatalAlert(event, decryption_failed); return; } public_key = wtls_get_rsapublickey(); pack_int16(decryptedData, octstr_len(decryptedData), octstr_len(public_key->rsa_exponent)); octstr_insert(decryptedData, public_key->rsa_exponent, octstr_len(decryptedData)); pack_int16(decryptedData, octstr_len(decryptedData), octstr_len(public_key->rsa_modulus)); octstr_insert(decryptedData, public_key->rsa_modulus, octstr_len(decryptedData)); /* Concatenate our random data */ concatenatedRandoms = octstr_cat(wtls_machine->client_random, wtls_machine->server_random); /* Generate our master secret */ labelMaster = octstr_create("master secret"); wtls_machine->master_secret = wtls_calculate_prf(decryptedData, labelMaster, concatenatedRandoms, 20, wtls_machine); /* Process the incoming event : ChangeCipherSpec */ tempPayload = (wtls_Payload *) gwlist_search(event->u.T_Unitdata_Ind.pdu_list, (void *)ChangeCipher_PDU, match_pdu_type); if (!tempPayload) { error(0, "Missing change_cipher. Aborting..."); octstr_destroy(labelMaster); octstr_destroy(concatenatedRandoms); destroy_rsa_pubkey(public_key); octstr_destroy(decryptedData); octstr_destroy(encryptedData); fatalAlert(event, unexpected_message); return; } changeCipherSpec_incoming_PDU = wtls_pdu_unpack(tempPayload, wtls_machine); octstr_dump(wtls_machine->client_write_MAC_secret, 0); wtls_pdu_dump(changeCipherSpec_incoming_PDU, 0); if (changeCipherSpec_incoming_PDU->u.cc.change == 1) { debug("wtls", 0, "Need to decrypt the PDUs from now on..."); wtls_decrypt_pdu_list(wtls_machine, event->u.T_Unitdata_Ind.pdu_list); } /* Process the incoming event : Finished */ tempPayload = (wtls_Payload *) gwlist_search(event->u.T_Unitdata_Ind.pdu_list, (void *)finished, match_handshake_type); if (!tempPayload) { error(0, "Failed to decrypt finished PDU. Aborting..."); wtls_pdu_destroy(changeCipherSpec_incoming_PDU); octstr_destroy(labelMaster); octstr_destroy(concatenatedRandoms); destroy_rsa_pubkey(public_key); octstr_destroy(decryptedData); octstr_destroy(encryptedData); fatalAlert(event, decrypt_error); return; } finished_incoming_PDU = wtls_pdu_unpack(tempPayload, wtls_machine); debug("wtls", 0, "Client Finished PDU:"); wtls_pdu_dump(finished_incoming_PDU, 0); /* Check the verify_data */ labelVerify = octstr_create("client finished"); checking_data = wtls_calculate_prf(wtls_machine->master_secret, labelVerify, (Octstr *) wtls_hash(wtls_machine-> handshake_data, wtls_machine), 12, wtls_machine); if (octstr_compare (finished_incoming_PDU->u.handshake.finished->verify_data, checking_data) == 0) { wtls_machine->encrypted = 1; debug("wtls", 0, "DATA VERIFICATION OK"); } /* Keep the data so we can send it back in the next message * octstr_insert(wtls_machine->handshake_data, tempPayload->data, * octstr_len(wtls_machine->handshake_data)); */ // temporary fix octstr_truncate(tempPayload->data, 15); octstr_insert(wtls_machine->handshake_data, tempPayload->data, octstr_len(wtls_machine->handshake_data)); /* Create a new PDU List containing a ChangeCipherSpec and a Finished */ changeCipherSpecPDU = wtls_pdu_create(ChangeCipher_PDU); changeCipherSpecPDU->u.cc.change = 1; changeCipherSpecPDU->rlen = 1; changeCipherSpecPDU->snMode = wtls_machine->sequence_number_mode ? 1 : 0; /* Generate our verify data */ finishedPDU = wtls_pdu_create(Handshake_PDU); finishedPDU->u.handshake.msg_type = finished; finishedPDU->cipher = 1; finishedPDU->rlen = 1; finishedPDU->snMode = wtls_machine->sequence_number_mode ? 1 : 0;; finishedPDU->u.handshake.finished = gw_malloc(sizeof(Finished)); octstr_destroy(labelVerify); labelVerify = octstr_create("server finished"); finishedPDU->u.handshake.finished->verify_data = wtls_calculate_prf (wtls_machine->master_secret, labelVerify, (Octstr *) wtls_hash (wtls_machine->handshake_data, wtls_machine), 12, wtls_machine); /* Reset the accumulated Handshake data */ octstr_destroy(wtls_machine->handshake_data); wtls_machine->handshake_data = octstr_create(""); /* Add the pdus to our list */ add_pdu(wtls_machine, changeCipherSpecPDU); add_pdu(wtls_machine, finishedPDU); /* Send it off */ send_queuedpdus(wtls_machine); octstr_destroy(labelMaster); octstr_destroy(labelVerify); octstr_destroy(decryptedData); octstr_destroy(encryptedData); octstr_destroy(concatenatedRandoms); wtls_pdu_destroy(finished_incoming_PDU); wtls_pdu_destroy(changeCipherSpec_incoming_PDU); wtls_pdu_destroy(finishedPDU); wtls_pdu_destroy(changeCipherSpecPDU); octstr_destroy(checking_data); destroy_rsa_pubkey(public_key); } static void wtls_application(WAPEvent * event, WTLSMachine * wtls_machine) { int listLen, i = 0; WAPEvent *dgram; wtls_Payload *payLoad; /* Apply the negotiated decryption/decoding/MAC check to the received data */ /* Take the userdata and pass it on up to the WTP/WSP, depending on the destination port */ listLen = gwlist_len(event->u.T_Unitdata_Ind.pdu_list); for (; i < listLen; i++) { payLoad = gwlist_consume(event->u.T_Unitdata_Ind.pdu_list); dgram = wap_event_create(T_DUnitdata_Ind); dgram->u.T_DUnitdata_Ind.addr_tuple = wap_addr_tuple_create(event->u.T_Unitdata_Ind.addr_tuple-> remote->address, event->u.T_Unitdata_Ind.addr_tuple-> remote->port, event->u.T_Unitdata_Ind.addr_tuple-> local->address, event->u.T_Unitdata_Ind.addr_tuple-> local->port); dgram->u.T_DUnitdata_Ind.user_data = payLoad->data; wap_dispatch_datagram(dgram); payLoad->data = NULL; wtls_payload_destroy(payLoad); } } /* * Feed an event to a WTP responder state machine. Handle all errors yourself, * do not report them to the caller. Note: Do not put {}s of the else block * inside the macro definition. */ static void wtls_event_handle(WTLSMachine * wtls_machine, WAPEvent * event) { debug("wap.wtls", 0, "WTLS: wtls_machine %ld, state %s, event %s.", wtls_machine->mid, stateName(wtls_machine->state), wap_event_name(event->type)); /* for T_Unitdata_Ind PDUs */ if (event->type == T_Unitdata_Ind) { /* if encryption: decrypt all pdus in the list */ if (wtls_machine->encrypted) wtls_decrypt_pdu_list(wtls_machine, event->u.T_Unitdata_Ind.pdu_list); /* add all handshake data to wtls_machine->handshake_data */ //add_all_handshake_data(wtls_machine, event->u.T_Unitdata_Ind.pdu_list); } #define STATE_NAME(state) #define ROW(wtls_state, event_type, condition, action, next_state) \ if (wtls_machine->state == wtls_state && \ event->type == event_type && \ (condition)) { \ action \ wtls_machine->state = next_state; \ debug("wap.wtls", 0, "WTLS %ld: New state %s", wtls_machine->mid, #next_state); \ } else #include "wtls_state-decl.h" { error(0, "WTLS: handle_event: unhandled event!"); debug("wap.wtls", 0, "WTLS: handle_event: Unhandled event was:"); wap_event_destroy(event); return; } if (event) wap_event_destroy(event); if (wtls_machine->state == NULL_STATE) { wtls_machine_destroy(wtls_machine); wtls_machine = NULL; } } /* * Checks whether wtls machines data structure includes a specific machine. * The machine in question is identified with with source and destination * address and port. */ static WTLSMachine *wtls_machine_find_or_create(WAPEvent * event) { WTLSMachine *wtls_machine = NULL; long mid; WAPAddrTuple *tuple; tuple = NULL; mid = -1; debug("wap.wtls", 0, "event->type = %d", event->type); /* Get the address that this PDU came in from */ switch (event->type) { case T_Unitdata_Ind: case T_DUnitdata_Ind: tuple = event->u.T_Unitdata_Ind.addr_tuple; break; case SEC_Create_Request_Req: case SEC_Terminate_Req: case SEC_Exception_Req: case SEC_Create_Res: case SEC_Exchange_Req: case SEC_Commit_Req: case SEC_Unitdata_Req: tuple = event->u.T_Unitdata_Ind.addr_tuple; break; default: debug("wap.wtls", 0, "WTLS: wtls_machine_find_or_create:" "unhandled event (1)"); wap_event_dump(event); return NULL; } /* Either the address or the machine id must be available at this point */ gw_assert(tuple != NULL || mid != -1); /* Look for the machine owning this address */ wtls_machine = wtls_machine_find(tuple, mid); /* Oh well, we didn't find one. We'll create one instead, provided it meets certain criteria */ if (wtls_machine == NULL) { switch (event->type) { case SEC_Create_Request_Req: /* State NULL, case 1 */ debug("wap.wtls", 0, "WTLS: received a SEC_Create_Request_Req, and don't know what to do with it..."); /* Create and dispatch a T_Unitdata_Req containing a HelloRequest */ /* And there's no need to do anything else, 'cause we return to state NULL */ break; case T_Unitdata_Ind: case T_DUnitdata_Ind: /* State NULL, case 3 */ /* if (wtls_event_type(event) == Alert_No_Renegotiation) { */ /* Create and dispatch a SEC_Exception_Ind event */ /* debug("wap.wtls",0,"WTLS: received an Alert_no_Renegotiation; just dropped it."); */ /* And there's no need to do anything else, 'cause we return to state NULL */ /* break; */ /* } else */ /* if (event->u.T_Unitdata_Ind == ClientHello) { */ /* State NULL, case 2 */ wtls_machine = wtls_machine_create(tuple); /* And stick said event into machine, which should push us into state CREATING after a SEC_Create_Ind */ /* } */ break; default: error(0, "WTLS: wtls_machine_find_or_create:" " unhandled event (2)"); wap_event_dump(event); break; } } return wtls_machine; } static int is_wanted_wtls_machine(void *a, void *b) { machine_pattern *pat; WTLSMachine *m; m = a; pat = b; if (m->mid == pat->mid) return 1; if (pat->mid != -1) return 0; return wap_addr_tuple_same(m->addr_tuple, pat->tuple); } static WTLSMachine *wtls_machine_find(WAPAddrTuple * tuple, long mid) { machine_pattern pat; WTLSMachine *m; pat.tuple = tuple; pat.mid = mid; m = gwlist_search(wtls_machines, &pat, is_wanted_wtls_machine); return m; } static WTLSMachine *wtls_machine_create(WAPAddrTuple * tuple) { WTLSMachine *wtls_machine; wtls_machine = gw_malloc(sizeof(WTLSMachine)); #define MACHINE(field) field #define ENUM(name) wtls_machine->name = NULL_STATE; #define ADDRTUPLE(name) wtls_machine->name = NULL; #define INTEGER(name) wtls_machine->name = 0; #define OCTSTR(name) wtls_machine->name = NULL; #define PDULIST(name) wtls_machine->name = NULL; #include "wtls_machine-decl.h" gwlist_append(wtls_machines, wtls_machine); wtls_machine->mid = counter_increase(wtls_machine_id_counter); wtls_machine->addr_tuple = wap_addr_tuple_duplicate(tuple); wtls_machine->server_seq_num = wtls_machine->client_seq_num = -1; wtls_machine->last_refresh = -1; wtls_machine->handshake_data = octstr_create(""); debug("wap.wtls", 0, "WTLS: Created WTLSMachine %ld (0x%p)", wtls_machine->mid, (void *)wtls_machine); return wtls_machine; } /* * Destroys a WTLSMachine. Assumes it is safe to do so. Assumes it has * already been deleted from the machines list. */ static void wtls_machine_destroy(void *p) { WTLSMachine *wtls_machine; wtls_machine = p; debug("wap.wtls", 0, "WTLS: Destroying WTLSMachine %ld (0x%p)", wtls_machine->mid, (void *)wtls_machine); gwlist_delete_equal(wtls_machines, wtls_machine); #define MACHINE(field) field #define ENUM(name) wtls_machine->name = NULL_STATE; #define ADDRTUPLE(name) wap_addr_tuple_destroy(wtls_machine->name); #define INTEGER(name) wtls_machine->name = 0; #define OCTSTR(name) octstr_destroy(wtls_machine->name); #define PDULIST(name) wtls_machine->name = NULL; #include "wtls_machine-decl.h" gw_free(wtls_machine); } static int wtls_machine_has_mid(void *a, void *b) { WTLSMachine *sm; long mid; sm = a; mid = *(long *)b; return sm->mid == mid; } static WTLSMachine *find_wtls_machine_using_mid(long mid) { return gwlist_search(wtls_machines, &mid, wtls_machine_has_mid); } /* Used for list searches */ static int match_handshake_type(void *item, void *pattern) { wtls_Payload *matchingPayload; int type; int retrievedType; matchingPayload = (wtls_Payload *) item; type = (long)pattern; if (!matchingPayload->data) return (0); retrievedType = octstr_get_char(matchingPayload->data, 0); if (matchingPayload->type == Handshake_PDU && retrievedType == type) { return 1; } else { return 0; } } static int match_pdu_type(void *item, void *pattern) { wtls_Payload *matchingPayload; int type; matchingPayload = (wtls_Payload *) item; type = (long)pattern; if (matchingPayload->type == type) { return 1; } else { return 0; } } #endif /* HAVE_WTLS_OPENSSL */ gateway-1.4.5/wap/wtp_resp.c0000644000175000017500000007233113227613126014473 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_resp.c - WTP responder implementation * * Aarno Syvänen * Lars Wirzenius */ #include "gwlib/gwlib.h" #include "wtp_resp.h" #include "wtp_pack.h" #include "wtp_tid.h" #include "wtp.h" #include "timers.h" #include "wap.h" /*********************************************************************** * Internal data structures. * * List of responder WTP machines. */ static List *resp_machines = NULL; /* * Counter for responder WTP machine id numbers, to make sure they are unique. */ static Counter *resp_machine_id_counter = NULL; /* * Give the status of wtp responder: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum { limbo, running, terminating } resp_run_status = limbo; wap_dispatch_func_t *dispatch_to_wdp; wap_dispatch_func_t *dispatch_to_wsp; wap_dispatch_func_t *dispatch_to_push; /* * Queue of events to be handled by WTP responder. */ static List *resp_queue = NULL; /* * Timer 'tick'. All wtp responder timer values are multiplies of this one */ static long resp_timer_freq = -1; /***************************************************************************** * * Prototypes of internal functions: * * Create and destroy an uniniatilized wtp responder state machine. */ static WTPRespMachine *resp_machine_create(WAPAddrTuple *tuple, long tid, long tcl); static void resp_machine_destroy(void *sm); /* * Checks whether wtp responser machines data structure includes a specific * machine. * The machine in question is identified with with source and destination * address and port and tid. If the machine does not exist and the event is * RcvInvoke, a new machine is created and added in the machines data * structure. * First test incoming events (WTP 10.2) (Exception is tests nro 4 and 5: if * we have a memory error, we panic. Nro 4 is already checked) If event was * validated and If the event was RcvAck or RcvAbort, the event is ignored. * If the event is RcvErrorPDU, new machine is created. */ static WTPRespMachine *resp_machine_find_or_create(WAPEvent *event); /* * Feed an event to a WTP responder state machine. Handle all errors by * itself, do not report them to the caller. WSP indication or confirmation * is handled by an included state table. */ static void resp_event_handle(WTPRespMachine *machine, WAPEvent *event); /* * Print a wtp responder machine state as a string. */ static char *name_resp_state(int name); /* * Find the wtp responder machine from the global list of wtp responder * structures that corresponds to the five-tuple of source and destination * addresses and ports and the transaction identifier. Return a pointer to * the machine, or NULL if not found. */ static WTPRespMachine *resp_machine_find(WAPAddrTuple *tuple, long tid, long mid); static void main_thread(void *); /* * Start acknowledgement interval timer */ static void start_timer_A(WTPRespMachine *machine); /* * Start retry interval timer */ static void start_timer_R(WTPRespMachine *machine); /* * Start timeout interval timer. */ static void start_timer_W(WTPRespMachine *machine); static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data); static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason); static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm); static int erroneous_field_in(WAPEvent *event); static void handle_wrong_version(WAPEvent *event); /* * SAR related functions. */ static WAPEvent *assembly_sar_event (WTPRespMachine *machine, int last_psn); static int add_sar_transaction (WTPRespMachine *machine, Octstr *data, int psn); /* static int is_wanted_sar_data (void *a, void *b); */ static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event); static void begin_sar_result(WTPRespMachine *machine, WAPEvent *event); static void continue_sar_result(WTPRespMachine *machine, WAPEvent *event); static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event); static void sar_info_destroy(void *sar_info); static void sardata_destroy(void *sardata); /* * Create a datagram with an Abort PDU and send it to the WDP layer. */ static void send_abort(WTPRespMachine *machine, long type, long reason); /* * Create a datagram with an Ack PDU and send it to the WDP layer. */ static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag); /****************************************************************************** * * EXTERNAL FUNCTIONS: * */ void wtp_resp_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *session_dispatch, wap_dispatch_func_t *push_dispatch, long timer_freq) { resp_machines = gwlist_create(); resp_machine_id_counter = counter_create(); resp_queue = gwlist_create(); gwlist_add_producer(resp_queue); dispatch_to_wdp = datagram_dispatch; dispatch_to_wsp = session_dispatch; dispatch_to_push = push_dispatch; timers_init(); resp_timer_freq = timer_freq; wtp_tid_cache_init(); gw_assert(resp_run_status == limbo); resp_run_status = running; gwthread_create(main_thread, NULL); } void wtp_resp_shutdown(void) { gw_assert(resp_run_status == running); resp_run_status = terminating; gwlist_remove_producer(resp_queue); gwthread_join_every(main_thread); debug("wap.wtp", 0, "wtp_resp_shutdown: %ld resp_machines left", gwlist_len(resp_machines)); gwlist_destroy(resp_machines, resp_machine_destroy); gwlist_destroy(resp_queue, wap_event_destroy_item); counter_destroy(resp_machine_id_counter); wtp_tid_cache_shutdown(); timers_shutdown(); } void wtp_resp_dispatch_event(WAPEvent *event) { gwlist_produce(resp_queue, event); } /***************************************************************************** * * INTERNAL FUNCTIONS: * */ static void main_thread(void *arg) { WTPRespMachine *sm; WAPEvent *e; while (resp_run_status == running && (e = gwlist_consume(resp_queue)) != NULL) { sm = resp_machine_find_or_create(e); if (sm == NULL) { wap_event_destroy(e); } else { resp_event_handle(sm, e); } } } /* * Give the name of a responder state in a readable form. */ static char *name_resp_state(int s) { switch (s) { #define STATE_NAME(state) case state: return #state; #define ROW(state, event, condition, action, new_state) #include "wtp_resp_states.def" default: return "unknown state"; } } /* * Feed an event to a WTP responder state machine. Handle all errors yourself, * do not report them to the caller. Note: Do not put {}s of the else block * inside the macro definition. */ static void resp_event_handle(WTPRespMachine *resp_machine, WAPEvent *event) { WAPEvent *wsp_event = NULL; /* * We don't feed sar packets into state machine * until we got the whole message */ if (process_sar_transaction(resp_machine,&event) == 0) { debug("wap.wtp", 0, "SAR event received, wait for continue"); /* For removing state machine in case of incomplete sar */ start_timer_W(resp_machine); if (event != NULL) { wap_event_destroy(event); } return; } debug("wap.wtp", 0, "WTP: resp_machine %ld, state %s, event %s.", resp_machine->mid, name_resp_state(resp_machine->state), wap_event_name(event->type)); #define STATE_NAME(state) #define ROW(wtp_state, event_type, condition, action, next_state) \ if (resp_machine->state == wtp_state && \ event->type == event_type && \ (condition)) { \ action \ resp_machine->state = next_state; \ debug("wap.wtp", 0, "WTP %ld: New state %s", resp_machine->mid, #next_state); \ } else #include "wtp_resp_states.def" { error(0, "WTP: handle_event: unhandled event!"); debug("wap.wtp", 0, "WTP: handle_event: Unhandled event was:"); wap_event_dump(event); wap_event_destroy(event); return; } if (event != NULL) { wap_event_destroy(event); } if (resp_machine->state == LISTEN) resp_machine_destroy(resp_machine); } static void handle_wrong_version(WAPEvent *event) { WAPEvent *ab; if (event->type == RcvInvoke) { ab = wtp_pack_abort(PROVIDER, WTPVERSIONZERO, event->u.RcvInvoke.tid, event->u.RcvInvoke.addr_tuple); dispatch_to_wdp(ab); } } /* * Check for features 7 and 9 in WTP 10.2. */ static int erroneous_field_in(WAPEvent *event) { return event->type == RcvInvoke && event->u.RcvInvoke.version != 0; } /* * React features 7 and 9 in WTP 10.2, by aborting with an appropiate error * message. */ static void handle_erroneous_field_in(WAPEvent *event) { if (event->type == RcvInvoke) { if (event->u.RcvInvoke.version != 0) { debug("wap.wtp_resp", 0, "WTP_RESP: wrong version, aborting" "transaction"); handle_wrong_version(event); } } } /* * Checks whether wtp machines data structure includes a specific machine. * The machine in question is identified with with source and destination * address and port and tid. First test incoming events (WTP 10.2) * (Exception is tests nro 4 and 5: if we have a memory error, we panic. Nro 5 * is already checked) If event was validated and if the machine does not * exist and the event is RcvInvoke, a new machine is created and added in * the machines data structure. If the event was RcvAck or RcvAbort, the * event is ignored (test nro 3). If the event is RcvErrorPDU (test nro 4) * new machine is created for handling this event. If the event is one of WSP * primitives, we have an error. */ static WTPRespMachine *resp_machine_find_or_create(WAPEvent *event) { WTPRespMachine *resp_machine = NULL; long tid, mid; WAPAddrTuple *tuple; tid = -1; tuple = NULL; mid = -1; switch (event->type) { case RcvInvoke: /* check if erroneous fields are given */ if (erroneous_field_in(event)) { handle_erroneous_field_in(event); return NULL; } else { tid = event->u.RcvInvoke.tid; tuple = event->u.RcvInvoke.addr_tuple; } break; case RcvSegInvoke: tid = event->u.RcvSegInvoke.tid; tuple = event->u.RcvSegInvoke.addr_tuple; break; case RcvAck: tid = event->u.RcvAck.tid; tuple = event->u.RcvAck.addr_tuple; break; case RcvNegativeAck: tid = event->u.RcvAck.tid; tuple = event->u.RcvAck.addr_tuple; break; case RcvAbort: tid = event->u.RcvAbort.tid; tuple = event->u.RcvAbort.addr_tuple; break; case RcvErrorPDU: tid = event->u.RcvErrorPDU.tid; tuple = event->u.RcvErrorPDU.addr_tuple; break; case TR_Invoke_Res: mid = event->u.TR_Invoke_Res.handle; break; case TR_Result_Req: mid = event->u.TR_Result_Req.handle; break; case TR_Abort_Req: mid = event->u.TR_Abort_Req.handle; break; case TimerTO_A: mid = event->u.TimerTO_A.handle; break; case TimerTO_R: mid = event->u.TimerTO_R.handle; break; case TimerTO_W: mid = event->u.TimerTO_W.handle; break; default: debug("wap.wtp", 0, "WTP: resp_machine_find_or_create:" "unhandled event"); wap_event_dump(event); return NULL; } gw_assert(tuple != NULL || mid != -1); resp_machine = resp_machine_find(tuple, tid, mid); if (resp_machine == NULL){ switch (event->type) { /* * When PDU with an illegal header is received, its tcl-field is * irrelevant and possibly meaningless). In this case we must create * a new machine, if there is any. There is a machine for all events * handled stateful manner. */ case RcvErrorPDU: debug("wap.wtp_resp", 0, "an erronous pdu received"); wap_event_dump(event); resp_machine = resp_machine_create(tuple, tid, event->u.RcvInvoke.tcl); break; case RcvInvoke: resp_machine = resp_machine_create(tuple, tid, event->u.RcvInvoke.tcl); /* if SAR requested */ if (!event->u.RcvInvoke.gtr || !event->u.RcvInvoke.ttr) { resp_machine->sar = gw_malloc(sizeof(WTPSARData)); resp_machine->sar->nsegm = 0; resp_machine->sar->csegm = 0; resp_machine->sar->lsegm = 0; resp_machine->sar->data = NULL; } break; case RcvSegInvoke: info(0, "WTP_RESP: resp_machine_find_or_create:" " segmented invoke received, yet having no machine"); break; /* * This and the following branch implement test nro 3 in WTP 10.2. */ case RcvAck: info(0, "WTP_RESP: resp_machine_find_or_create:" " ack received, yet having no machine"); break; case RcvNegativeAck: info(0, "WTP_RESP: resp_machine_find_or_create:" " negative ack received, yet having no machine"); break; case RcvAbort: info(0, "WTP_RESP: resp_machine_find_or_create:" " abort received, yet having no machine"); break; case TR_Invoke_Res: case TR_Result_Req: case TR_Abort_Req: error(0, "WTP_RESP: resp_machine_find_or_create: WSP primitive to" " a wrong WTP machine"); break; case TimerTO_A: case TimerTO_R: case TimerTO_W: error(0, "WTP_RESP: resp_machine_find_or_create: timer event" " without a corresponding machine"); break; default: error(0, "WTP_RESP: resp_machine_find_or_create: unhandled event"); wap_event_dump(event); break; } } /* if machine == NULL */ return resp_machine; } static int is_wanted_resp_machine(void *a, void *b) { machine_pattern *pat; WTPRespMachine *m; m = a; pat = b; if (m->mid == pat->mid) return 1; if (pat->mid != -1) return 0; return m->tid == pat->tid && wap_addr_tuple_same(m->addr_tuple, pat->tuple); } static WTPRespMachine *resp_machine_find(WAPAddrTuple *tuple, long tid, long mid) { machine_pattern pat; WTPRespMachine *m; pat.tuple = tuple; pat.tid = tid; pat.mid = mid; m = gwlist_search(resp_machines, &pat, is_wanted_resp_machine); return m; } static WTPRespMachine *resp_machine_create(WAPAddrTuple *tuple, long tid, long tcl) { WTPRespMachine *resp_machine; resp_machine = gw_malloc(sizeof(WTPRespMachine)); #define ENUM(name) resp_machine->name = LISTEN; #define EVENT(name) resp_machine->name = NULL; #define INTEGER(name) resp_machine->name = 0; #define TIMER(name) resp_machine->name = gwtimer_create(resp_queue); #define ADDRTUPLE(name) resp_machine->name = NULL; #define LIST(name) resp_machine->name = NULL; #define SARDATA(name) resp_machine->name = NULL; #define MACHINE(field) field #include "wtp_resp_machine.def" gwlist_append(resp_machines, resp_machine); resp_machine->mid = counter_increase(resp_machine_id_counter); resp_machine->addr_tuple = wap_addr_tuple_duplicate(tuple); resp_machine->tid = tid; resp_machine->tcl = tcl; debug("wap.wtp", 0, "WTP: Created WTPRespMachine %p (%ld)", (void *) resp_machine, resp_machine->mid); return resp_machine; } /* * Destroys a WTPRespMachine. Assumes it is safe to do so. Assumes it has * already been deleted from the machines list. */ static void resp_machine_destroy(void * p) { WTPRespMachine *resp_machine; resp_machine = p; debug("wap.wtp", 0, "WTP: Destroying WTPRespMachine %p (%ld)", (void *) resp_machine, resp_machine->mid); gwlist_delete_equal(resp_machines, resp_machine); #define ENUM(name) resp_machine->name = LISTEN; #define EVENT(name) wap_event_destroy(resp_machine->name); #define INTEGER(name) resp_machine->name = 0; #define TIMER(name) gwtimer_destroy(resp_machine->name); #define ADDRTUPLE(name) wap_addr_tuple_destroy(resp_machine->name); #define LIST(name) gwlist_destroy(resp_machine->name,sar_info_destroy); #define SARDATA(name) sardata_destroy(resp_machine->name); #define MACHINE(field) field #include "wtp_resp_machine.def" gw_free(resp_machine); } /* * Create a TR-Invoke.ind event. */ static WAPEvent *create_tr_invoke_ind(WTPRespMachine *sm, Octstr *user_data) { WAPEvent *event; event = wap_event_create(TR_Invoke_Ind); event->u.TR_Invoke_Ind.ack_type = sm->u_ack; event->u.TR_Invoke_Ind.user_data = octstr_duplicate(user_data); event->u.TR_Invoke_Ind.tcl = sm->tcl; event->u.TR_Invoke_Ind.addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple); event->u.TR_Invoke_Ind.handle = sm->mid; return event; } /* * Create a TR-Result.cnf event. */ static WAPEvent *create_tr_result_cnf(WTPRespMachine *sm) { WAPEvent *event; event = wap_event_create(TR_Result_Cnf); event->u.TR_Result_Cnf.addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple); event->u.TR_Result_Cnf.handle = sm->mid; return event; } /* * Creates TR-Abort.ind event from a responder state machine. In addition, set * the responder indication flag. */ static WAPEvent *create_tr_abort_ind(WTPRespMachine *sm, long abort_reason) { WAPEvent *event; event = wap_event_create(TR_Abort_Ind); event->u.TR_Abort_Ind.abort_code = abort_reason; event->u.TR_Abort_Ind.addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple); event->u.TR_Abort_Ind.handle = sm->mid; event->u.TR_Abort_Ind.ir_flag = RESPONDER_INDICATION; return event; } /* * Start acknowledgement interval timer. Multiply time with * resp_timer_freq. */ static void start_timer_A(WTPRespMachine *machine) { WAPEvent *timer_event; timer_event = wap_event_create(TimerTO_A); timer_event->u.TimerTO_A.handle = machine->mid; gwtimer_start(machine->timer, L_A_WITH_USER_ACK * resp_timer_freq, timer_event); } /* * Start retry interval timer. Multiply time with resp_timer_freq. */ static void start_timer_R(WTPRespMachine *machine) { WAPEvent *timer_event; timer_event = wap_event_create(TimerTO_R); timer_event->u.TimerTO_R.handle = machine->mid; gwtimer_start(machine->timer, L_R_WITH_USER_ACK * resp_timer_freq, timer_event); } /* * Start segmentation timeout interval timer. Multiply time with * resp_timer_freq. */ static void start_timer_W(WTPRespMachine *machine) { WAPEvent *timer_event; timer_event = wap_event_create(TimerTO_W); timer_event->u.TimerTO_W.handle = machine->mid; gwtimer_start(machine->timer, W_WITH_USER_ACK * resp_timer_freq, timer_event); } static void send_abort(WTPRespMachine *machine, long type, long reason) { WAPEvent *e; e = wtp_pack_abort(type, reason, machine->tid, machine->addr_tuple); dispatch_to_wdp(e); } static void send_ack(WTPRespMachine *machine, long ack_type, int rid_flag) { WAPEvent *e; e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple); dispatch_to_wdp(e); } /* * Process incoming event, checking for WTP SAR */ static int process_sar_transaction(WTPRespMachine *machine, WAPEvent **event) { WAPEvent *e, *orig_event; int psn; orig_event = *event; if (orig_event->type == RcvInvoke) { if (!orig_event->u.RcvInvoke.ttr || !orig_event->u.RcvInvoke.gtr) { /* SAR */ /* Ericcson set TTR flag even if we have the only part */ if (orig_event->u.RcvInvoke.ttr == 1) { return 1; /* Not SAR although TTR flag was set */ } else { /* save initial event */ machine->sar_invoke = wap_event_duplicate(orig_event); /* save data into list with psn = 0 */ add_sar_transaction(machine, orig_event->u.RcvInvoke.user_data, 0); if (orig_event->u.RcvInvoke.gtr == 1) { /* Need to acknowledge */ e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid, machine->addr_tuple, 0); dispatch_to_wdp(e); } return 0; } } else { return 1; /* Not SAR */ } } if (orig_event->type == RcvSegInvoke) { add_sar_transaction(machine, orig_event->u.RcvSegInvoke.user_data, orig_event->u.RcvSegInvoke.psn); if (orig_event->u.RcvSegInvoke.gtr == 1) { /* Need to acknowledge */ e = wtp_pack_sar_ack(ACKNOWLEDGEMENT, machine->tid, machine->addr_tuple, orig_event->u.RcvSegInvoke.psn); dispatch_to_wdp(e); } if (orig_event->u.RcvSegInvoke.ttr == 1) { /* Need to feed to WSP */ /* Create assembled event */ psn = orig_event->u.RcvSegInvoke.psn; wap_event_destroy(orig_event); *event = assembly_sar_event(machine,psn); gw_assert(event != NULL); return 1; } return 0; } /* Not SAR message */ return 1; } static int is_wanted_sar_data(void *a, void *b) { sar_info_t *s; int *i; s = a; i = b; if (*i == s->sar_psn) { return 1; } else { return 0; } } /* * Return 0 if transaction added suscessufully, 1 otherwise. */ static int add_sar_transaction(WTPRespMachine *machine, Octstr *data, int psn) { sar_info_t *sar_info; if (machine->sar_info == NULL) { machine->sar_info = gwlist_create(); } if (gwlist_search(machine->sar_info, &psn, is_wanted_sar_data) == NULL) { sar_info = gw_malloc(sizeof(sar_info_t)); sar_info->sar_psn = psn; sar_info->sar_data = octstr_duplicate(data); gwlist_append(machine->sar_info, sar_info); return 0; } else { debug("wap.wtp", 0, "Duplicated psn found, ignore packet"); return 1; } } static WAPEvent *assembly_sar_event(WTPRespMachine *machine, int last_psn) { WAPEvent *e; int i; sar_info_t *sar_info; e = wap_event_duplicate(machine->sar_invoke); for (i = 1; i <= last_psn; i++) { if ((sar_info = gwlist_search(machine->sar_info, &i, is_wanted_sar_data)) != NULL) { octstr_append(e->u.RcvInvoke.user_data,sar_info->sar_data); } else { debug("wap.wtp", 0, "Packet with psn %d not found", i); return e; } } return e; } static void sar_info_destroy(void *p) { sar_info_t *sar_info; sar_info = p; octstr_destroy(sar_info->sar_data); gw_free(sar_info); } static void sardata_destroy(void *p) { WTPSARData * sardata; if (p) { sardata = p; octstr_destroy(sardata->data); gw_free(sardata); } } static void begin_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) { WAPEvent *result; WTPSARData *sar; int psn; gw_assert(resp_machine->sar != NULL); sar = resp_machine->sar; sar->data = octstr_duplicate(event->u.TR_Result_Req.user_data); sar->nsegm = (octstr_len(sar->data)-1)/SAR_SEGM_SIZE; sar->tr = sar->lsegm = 0; sar->csegm = -1; debug("wap.wtp", 0, "WTP: begin_sar_result(): data len = %lu", octstr_len(sar->data)); for (psn = 0; !sar->tr; psn++) { result = wtp_pack_sar_result(resp_machine, psn); if (sar->tr) resp_machine->result = wap_event_duplicate(result); debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn); dispatch_to_wdp(result); sar->lsegm = psn; } resp_machine->rid = 1; } static void continue_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) { WAPEvent *result; WTPSARData *sar; int psn; gw_assert(resp_machine->sar != NULL && event->type == RcvAck); sar = resp_machine->sar; debug("wap.wtp", 0, "WTP: continue_sar_result(): lsegm=%d, nsegm=%d, csegm=%d", sar->lsegm, sar->nsegm, sar->csegm); start_timer_R(resp_machine); if (event->u.RcvAck.psn>sar->csegm) { sar->csegm = event->u.RcvAck.psn; } sar->tr = 0; wap_event_destroy(resp_machine->result); resp_machine->result = NULL; for (psn = sar->csegm + 1; !sar->tr; psn++) { result = wtp_pack_sar_result(resp_machine, psn); if (sar->tr) resp_machine->result = wap_event_duplicate(result); debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u",psn); dispatch_to_wdp(result); sar->lsegm = psn; } } static void resend_sar_result(WTPRespMachine *resp_machine, WAPEvent *event) { WAPEvent *result; WTPSARData *sar; int psn, i; gw_assert(resp_machine->sar != NULL && event->type == RcvNegativeAck); sar = resp_machine->sar; debug("wap.wtp", 0, "WTP: resend_sar_result(): lsegm=%d, nsegm=%d, csegm=%d", sar->lsegm, sar->nsegm, sar->csegm); start_timer_R(resp_machine); if (event->u.RcvNegativeAck.nmissing) { /* if we have a list of missed packets */ for(i = 0; i < event->u.RcvNegativeAck.nmissing; i++) { if ((psn = octstr_get_char(event->u.RcvNegativeAck.missing, i)) >= 0) { result = wtp_pack_sar_result(resp_machine, psn); wtp_pack_set_rid(result, 1); debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn); dispatch_to_wdp(result); } } } else { /* if we have to resend a whole group */ sar->tr = 0; for (psn = sar->csegm+1; !sar->tr; psn++) { result = wtp_pack_sar_result(resp_machine, psn); wtp_pack_set_rid(result, 1); debug("wap.wtp", 0, "WTP: dispath_to_wdp(): psn = %u", psn); dispatch_to_wdp(result); } } } gateway-1.4.5/wap/wsp_unit.c0000644000175000017500000002517313227613126014502 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_unit.c - Implement WSP Connectionless mode * * Lars Wirzenius */ #include #include "gwlib/gwlib.h" #include "wsp.h" #include "wsp_pdu.h" #include "wsp_headers.h" #include "wap_events.h" #include "wsp_strings.h" #include "wap.h" /* * Give the status the module: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum { limbo, running, terminating } run_status = limbo; static wap_dispatch_func_t *dispatch_to_wdp; static wap_dispatch_func_t *dispatch_to_appl; static List *queue = NULL; static void main_thread(void *); static WAPEvent *pack_into_result_datagram(WAPEvent *event); static WAPEvent *pack_into_push_datagram(WAPEvent *event); /*********************************************************************** * Public functions */ void wsp_unit_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *application_dispatch) { queue = gwlist_create(); gwlist_add_producer(queue); dispatch_to_wdp = datagram_dispatch; dispatch_to_appl = application_dispatch; wsp_strings_init(); run_status = running; gwthread_create(main_thread, NULL); } void wsp_unit_shutdown(void) { gw_assert(run_status == running); run_status = terminating; gwlist_remove_producer(queue); gwthread_join_every(main_thread); gwlist_destroy(queue, wap_event_destroy_item); wsp_strings_shutdown(); } void wsp_unit_dispatch_event(WAPEvent *event) { wap_event_assert(event); gwlist_produce(queue, event); } static WAPEvent *unpack_datagram(WAPEvent *datagram) { WAPEvent *event; Octstr *os; WSP_PDU *pdu; long tid_byte; int method; Octstr *method_name; gw_assert(datagram->type == T_DUnitdata_Ind); os = NULL; pdu = NULL; event = NULL; os = octstr_duplicate(datagram->u.T_DUnitdata_Ind.user_data); if (os && octstr_len(os) == 0) { warning(0, "WSP UNIT: Empty datagram."); goto error; } tid_byte = octstr_get_char(os, 0); octstr_delete(os, 0, 1); pdu = wsp_pdu_unpack(os); if (pdu == NULL) goto error; if (pdu->type != Get && pdu->type != Post) { warning(0, "WSP UNIT: Unsupported PDU type %d", pdu->type); goto error; } event = wap_event_create(S_Unit_MethodInvoke_Ind); event->u.S_Unit_MethodInvoke_Ind.addr_tuple = wap_addr_tuple_duplicate( datagram->u.T_DUnitdata_Ind.addr_tuple); event->u.S_Unit_MethodInvoke_Ind.transaction_id = tid_byte; switch (pdu->type) { case Get: debug("wap.wsp", 0, "Connectionless Get request received."); method = GET_METHODS + pdu->u.Get.subtype; event->u.S_Unit_MethodInvoke_Ind.request_uri = octstr_duplicate(pdu->u.Get.uri); event->u.S_Unit_MethodInvoke_Ind.request_headers = wsp_headers_unpack(pdu->u.Get.headers, 0); event->u.S_Unit_MethodInvoke_Ind.request_body = NULL; break; case Post: debug("wap.wsp", 0, "Connectionless Post request received."); method = POST_METHODS + pdu->u.Post.subtype; event->u.S_Unit_MethodInvoke_Ind.request_uri = octstr_duplicate(pdu->u.Post.uri); event->u.S_Unit_MethodInvoke_Ind.request_headers = wsp_headers_unpack(pdu->u.Post.headers, 1); event->u.S_Unit_MethodInvoke_Ind.request_body = octstr_duplicate(pdu->u.Post.data); break; default: warning(0, "WSP UNIT: Unsupported PDU type %d", pdu->type); goto error; } method_name = wsp_method_to_string(method); if (method_name == NULL) method_name = octstr_format("UNKNOWN%02X", method); event->u.S_Unit_MethodInvoke_Ind.method = method_name; octstr_destroy(os); wsp_pdu_destroy(pdu); return event; error: octstr_destroy(os); wsp_pdu_destroy(pdu); wap_event_destroy(event); return NULL; } /*********************************************************************** * Local functions */ static void main_thread(void *arg) { WAPEvent *e; WAPEvent *newevent; while (run_status == running && (e = gwlist_consume(queue)) != NULL) { debug("wap.wsp.unit", 0, "WSP (UNIT): event arrived"); wap_event_assert(e); switch (e->type) { case T_DUnitdata_Ind: newevent = unpack_datagram(e); if (newevent != NULL) dispatch_to_appl(newevent); break; case S_Unit_MethodResult_Req: newevent = pack_into_result_datagram(e); if (newevent != NULL) dispatch_to_wdp(newevent); break; case S_Unit_Push_Req: newevent = pack_into_push_datagram(e); if (newevent != NULL) dispatch_to_wdp(newevent); debug("wsp.unit", 0, "WSP (UNIT): delivering to wdp"); break; default: warning(0, "WSP UNIT: Unknown event type %d", e->type); break; } wap_event_destroy(e); } } /* * We do not set TUnitData.ind's SMS-specific fields here, because we do not * support sending results to the phone over SMS. Wsp, chapter 8.4.1 states * that "that each peer entity is always associated with an encoding version.". * So we add Encoding-Version when we are sending something to the client. * (This includes push, which is not directly mentioned in chapter 8.4.2.70). */ static WAPEvent *pack_into_result_datagram(WAPEvent *event) { WAPEvent *datagram; struct S_Unit_MethodResult_Req *p; WSP_PDU *pdu; Octstr *ospdu; unsigned char tid; gw_assert(event->type == S_Unit_MethodResult_Req); p = &event->u.S_Unit_MethodResult_Req; http_header_add(p->response_headers, "Encoding-Version", "1.3"); pdu = wsp_pdu_create(Reply); pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(p->status); pdu->u.Reply.headers = wsp_headers_pack(p->response_headers, 1, WSP_1_3); pdu->u.Reply.data = octstr_duplicate(p->response_body); ospdu = wsp_pdu_pack(pdu); wsp_pdu_destroy(pdu); if (ospdu == NULL) return NULL; tid = p->transaction_id; octstr_insert_data(ospdu, 0, (char *)&tid, 1); datagram = wap_event_create(T_DUnitdata_Req); datagram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(p->addr_tuple); datagram->u.T_DUnitdata_Req.user_data = ospdu; return datagram; } /* * According to WSP table 12, p. 63, push id and transaction id are stored * into same field. T-UnitData.ind is different for IP and SMS bearer. */ static WAPEvent *pack_into_push_datagram(WAPEvent *event) { WAPEvent *datagram; WSP_PDU *pdu; Octstr *ospdu; unsigned char push_id; gw_assert(event->type == S_Unit_Push_Req); debug("wap.wsp.unit", 0, "WSP_UNIT: Connectionless push accepted"); http_header_add(event->u.S_Unit_Push_Req.push_headers, "Encoding-Version", "1.3"); pdu = wsp_pdu_create(Push); pdu->u.Push.headers = wsp_headers_pack( event->u.S_Unit_Push_Req.push_headers, 1, WSP_1_3); pdu->u.Push.data = octstr_duplicate( event->u.S_Unit_Push_Req.push_body); wsp_pdu_dump(pdu, 0); ospdu = wsp_pdu_pack(pdu); wsp_pdu_destroy(pdu); if (ospdu == NULL) return NULL; push_id = event->u.S_Unit_Push_Req.push_id; octstr_insert_data(ospdu, 0, (char *)&push_id, 1); datagram = wap_event_create(T_DUnitdata_Req); datagram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(event->u.S_Unit_Push_Req.addr_tuple); datagram->u.T_DUnitdata_Req.address_type = event->u.S_Unit_Push_Req.address_type; if (event->u.S_Unit_Push_Req.smsc_id != NULL) datagram->u.T_DUnitdata_Req.smsc_id = octstr_duplicate(event->u.S_Unit_Push_Req.smsc_id); else datagram->u.T_DUnitdata_Req.smsc_id = NULL; if (event->u.S_Unit_Push_Req.dlr_url != NULL) datagram->u.T_DUnitdata_Req.dlr_url = octstr_duplicate(event->u.S_Unit_Push_Req.dlr_url); else datagram->u.T_DUnitdata_Req.dlr_url = NULL; datagram->u.T_DUnitdata_Req.dlr_mask = event->u.S_Unit_Push_Req.dlr_mask; if (event->u.S_Unit_Push_Req.smsbox_id != NULL) datagram->u.T_DUnitdata_Req.smsbox_id = octstr_duplicate(event->u.S_Unit_Push_Req.smsbox_id); else datagram->u.T_DUnitdata_Req.smsbox_id = NULL; datagram->u.T_DUnitdata_Req.service_name = octstr_duplicate(event->u.S_Unit_Push_Req.service_name); datagram->u.T_DUnitdata_Req.user_data = ospdu; return datagram; } gateway-1.4.5/wap/wap_addr.h0000644000175000017500000000667313227613126014424 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_addr.h - interface to WAPAddr and WAPAddrTuple types. */ #ifndef WAP_ADDR_H #define WAP_ADDR_H #include "gwlib/gwlib.h" typedef struct { Octstr *address; in_addr_t iaddr; long port; } WAPAddr; typedef struct { WAPAddr *remote, *local; } WAPAddrTuple; WAPAddr *wap_addr_create(Octstr *address, long port); void wap_addr_destroy(WAPAddr *addr); int wap_addr_same(WAPAddr *a, WAPAddr *b); WAPAddrTuple *wap_addr_tuple_create(Octstr *rmt_addr, long rmt_port, Octstr *lcl_addr, long lcl_port); void wap_addr_tuple_destroy(WAPAddrTuple *tuple); int wap_addr_tuple_same(WAPAddrTuple *a, WAPAddrTuple *b); WAPAddrTuple *wap_addr_tuple_duplicate(WAPAddrTuple *tuple); void wap_addr_tuple_dump(WAPAddrTuple *tuple); #endif gateway-1.4.5/wap/wap_events.h0000644000175000017500000001005413227613126015002 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_events.h - definitions for wapbox events * * Aarno Syvänen * Lars Wirzenius */ #ifndef WAP_EVENTS_H #define WAP_EVENTS_H #include "gwlib/gwlib.h" #include "wap_addr.h" typedef struct WAPEvent WAPEvent; /* * Names of WAPEvents. */ typedef enum { #define WAPEVENT(name, prettyname, fields) name, #include "wap_events.def" WAPEventNameCount } WAPEventName; /* * The actual WAPEvent. */ struct WAPEvent { WAPEventName type; union { #define WAPEVENT(name, prettyname, fields) struct name { fields } name; #define OCTSTR(name) Octstr *name; #define OPTIONAL_OCTSTR(name) Octstr *name; /* May be NULL */ #define INTEGER(name) long name; #define HTTPHEADER(name) List *name; #define WTLSPDUS(name) List *name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define CAPABILITIES(name) List *name; #include "wap_events.def" } u; }; WAPEvent *wap_event_create_real(WAPEventName type, const char *file, long line, const char *func); #define wap_event_create(type) \ gw_claim_area(wap_event_create_real((type), __FILE__, __LINE__, __func__)) void wap_event_destroy(WAPEvent *event); void wap_event_destroy_item(void *event); WAPEvent *wap_event_duplicate(WAPEvent *event); const char *wap_event_name(WAPEventName type); void wap_event_dump(WAPEvent *event); void wap_event_assert(WAPEvent *event); #endif gateway-1.4.5/wap/wtls_pdu.c0000644000175000017500000013762113227613126014475 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtls_pdu.c: pack and unpack WTLS packets * * Generates packing and unpacking code from wtls_pdu.def. * * Nikos Balkanas, Inaccess Networks (2009) * */ #include "gwlib/gwlib.h" #ifdef HAVE_WTLS_OPENSSL #include "gwlib/octstr.h" #include "wtls_pdu.h" #include "wtls_pdusupport.h" #include "wtls_statesupport.h" KeyExchangeSuite client_key_exchange_algo = rsa_anon; PublicKeyAlgorithm public_key_algo; SignatureAlgorithm signature_algo; /* Function prototypes */ wtls_Payload *wtls_payload_unpack_from_offset(Octstr * data, int *offset); int wtls_payload_guess_length(Octstr * data); wtls_PDU *wtls_pdu_create(int type) { wtls_PDU *pdu; pdu = gw_malloc(sizeof(*pdu)); pdu->type = type; pdu->reserved = 0; pdu->cipher = 0; pdu->snMode = 0; pdu->seqNum = -1; pdu->rlen = 0; switch (pdu->type) { case ChangeCipher_PDU: pdu->u.cc.change = 1; break; case Alert_PDU: pdu->u.alert.level = 0; pdu->u.alert.desc = 0; pdu->u.alert.chksum = 0; break; case Handshake_PDU: pdu->u.handshake.msg_type = 0; pdu->u.handshake.length = 0; break; case Application_PDU: pdu->u.application.data = NULL; break; default: warning(0, "Cannot create unknown WTLS PDU type %d", pdu->type); break; } return pdu; } void wtls_payload_destroy(wtls_Payload * payload) { octstr_destroy(payload->data); gw_free(payload); } void wtls_pldList_destroy(List * pld_list) { gwlist_destroy(pld_list, (void *)wtls_payload_destroy); } void wtls_pdu_destroy(wtls_PDU * pdu) { if (pdu == NULL) return; switch (pdu->type) { case ChangeCipher_PDU: /* no memory was allocated for ChangeCipher_PDU */ break; case Alert_PDU: octstr_destroy(pdu->u.alert.chksum); break; case Handshake_PDU: switch (pdu->u.handshake.msg_type) { case hello_request: break; case client_hello: destroy_random(pdu->u.handshake.client_hello->random); octstr_destroy(pdu->u.handshake.client_hello-> session_id); destroy_key_list(pdu->u.handshake.client_hello-> client_key_ids); destroy_key_list(pdu->u.handshake.client_hello-> trusted_key_ids); destroy_ciphersuite_list(pdu->u.handshake.client_hello-> ciphersuites); destroy_compression_method_list(pdu->u.handshake. client_hello-> comp_methods); /* destroy the client_hello struct */ gw_free(pdu->u.handshake.client_hello); break; case server_hello: destroy_random(pdu->u.handshake.server_hello->random); octstr_destroy(pdu->u.handshake.server_hello-> session_id); /* destroy the server_hello struct */ gw_free(pdu->u.handshake.server_hello); break; case certificate: { Certificate *cert; List *certList = pdu->u.handshake.certificates->certList; for (;;) { cert = gwlist_consume(certList); if (!cert) break; switch (cert->certificateformat) { case WTLSCert: destroy_wtls_certificate(cert-> wtls_certificate); break; case X509Cert: octstr_destroy(cert-> x509_certificate); break; case X968Cert: octstr_destroy(cert-> x968_certificate); break; } gw_free(cert); } gwlist_destroy(pdu->u.handshake.certificates-> certList, NULL); } break; case server_key_exchange: destroy_param_spec(pdu->u.handshake. server_key_exchange->param_spec); switch (client_key_exchange_algo) { case rsa_anon: destroy_rsa_pubkey(pdu->u.handshake. server_key_exchange-> rsa_params); break; case dh_anon: destroy_dh_pubkey(pdu->u.handshake. server_key_exchange-> dh_params); break; case ecdh_anon: destroy_ec_pubkey(pdu->u.handshake. server_key_exchange-> ecdh_params); break; default: break; } gw_free(pdu->u.handshake.server_key_exchange); break; case client_key_exchange: switch (client_key_exchange_algo) { case rsa: case rsa_anon: destroy_rsa_encrypted_secret(pdu->u.handshake. client_key_exchange-> rsa_params); break; case dh_anon: destroy_dh_pubkey(pdu->u.handshake. client_key_exchange-> dh_anon_params); break; case ecdh_anon: case ecdh_ecdsa: destroy_ec_pubkey(pdu->u.handshake. client_key_exchange-> ecdh_params); break; default: break; } gw_free(pdu->u.handshake.client_key_exchange); break; case server_hello_done: /* nothing to do here */ default: break; } break; case Application_PDU: octstr_destroy(pdu->u.application.data); break; } gw_free(pdu); } /* This function will pack a list of WTLS PDUs into a single Octstr, and return that Octstr. */ Octstr *wtls_pack_payloadlist(List * payloadlist, int seqnum) { Octstr *returnData = 0, *tempData1 = 0, *tempData2 = 0; wtls_Payload *retrievedPDU; /* Assert that our payloadlist is not NULL */ gw_assert(payloadlist != NULL); /* Initialise our return Octstr */ returnData = octstr_create(""); /* While there are PDUs remaining in our list */ while (gwlist_len(payloadlist) > 0) { /* Retrieve the next payload from the payloadlist */ retrievedPDU = (wtls_Payload *) gwlist_extract_first(payloadlist); /* Pack the PDU */ tempData2 = wtls_payload_pack(retrievedPDU, seqnum++); /* Shift the current stuff in returnData to a temporary pointer */ tempData1 = returnData; /* Tack it onto our Octstr */ returnData = octstr_cat(tempData1, tempData2); /* And now, we can get rid of both tempData1 and tempData2 */ octstr_destroy(tempData1); octstr_destroy(tempData2); } /* Is the Octstr we finish with of length > 0? */ if (octstr_len(returnData) > 0) { /* Return the Octstr */ return returnData; } /* Otherwise, return NULL */ return NULL; } /* This function will unpack an Octstr and return a list of all PDUs contained within that Octstr. If the contents of the packet are garbled in some fashion, and one packet fails to be decoded correctly, we will continue regardless, and a partial list will be returned. NULL is returned if no PDUs can be successfully decoded from the supplied data */ List *wtls_unpack_payloadlist(Octstr * data) { List *payloadlist = NULL; int offset = 0; int dataLength = 0; wtls_Payload *tempPayload; /* Has somebody passed in an unpack of a null pointer ? */ gw_assert(data != NULL); /* Initialise our list */ payloadlist = gwlist_create(); dataLength = octstr_len(data); /* While offset is less than the size of the data */ while (offset < dataLength) { debug("wtls:wtls_unpack_payloadlist", 0, "Offset is now : %d", offset); /* Unpack from the supplied offset. This will bump up the value of offset */ tempPayload = wtls_payload_unpack_from_offset(data, &offset); /* If the packet returned is not NULL */ if (tempPayload != NULL) { /* Add the returned packet to the current list of packets */ gwlist_append(payloadlist, (void *)tempPayload); } } debug("wtls:wtls_unpack_payloadlist", 0, "Finished, found %ld PDUs", gwlist_len(payloadlist)); /* If the length of the list is greater than 0 */ if (gwlist_len(payloadlist) > 0) { /* Return the List */ return payloadlist; } /* Otherwise return NULL */ return NULL; } /* This function tries to determine the length of the PDU at the start of the supplied Octstr using (somewhat) intelligent means. If the packet is screwed up in some fashion, returns length -1. Returns an int. */ int wtls_payload_guess_length(Octstr * data) { int type = 0, lengthFlag = 0, lengthSize = 0, pdu_length = 0; long lengthOffset = 1; /* Is the fragment length indicator on? */ lengthFlag = octstr_get_bits(data, 0, 1); if (lengthFlag) { lengthSize = 2; } /* Is the sequence number indicator on? */ if (octstr_get_bits(data, 1, 1)) { /* Yes, so hop over two extra bytes when reading the length */ lengthOffset += 2; } /* the message type */ type = octstr_get_bits(data, 4, 4); /* If fragment length is turned on, jump to the necessary spot */ if (lengthFlag == 1) { /* After this, lengthOffset + pdu_length == the total length of the PDU */ pdu_length = unpack_int16(data, &lengthOffset); } /* Oh great, so it's not switched on. How considerate. We'll have to make a reasonable guess as to what it might be. */ else { switch (type) { case ChangeCipher_PDU: /* They're really short */ pdu_length = 1; break; case Alert_PDU: /* They're a bit longer */ pdu_length = 6; break; default: /* Otherwise just give up and play dead */ pdu_length = -1; break; } } /* And that's the length of the contents, now just add the other doodads on */ if (pdu_length == -1) { return -1; } else { /* The pdu length, plus the sequence number, plus the length of the length value, plus the actual header byte */ return (pdu_length + lengthOffset); } } /* This function will unpack an Octstr, starting at the specified offset, and return the corresponding wtls_PDU* which was generated from that offset. Offset is changed during the running of this function, and ends up as the octet at the start of the next pdu */ wtls_Payload *wtls_payload_unpack_from_offset(Octstr * data, int *offset) { int guessedPayloadLength = 0; int dataLength = 0; Octstr *dataFromOffset = 0; Octstr *dataFromOffsetToLength = 0; wtls_Payload *returnPayload = 0; /* This would be a sure sign of trouble */ gw_assert(offset != NULL); gw_assert(data != NULL); gw_assert(octstr_len(data) >= *offset); dataLength = octstr_len(data); /* First, we need to figure out how long a PDU starting from the specified offset is going to be. We need to peek quickly into the PDU to check this */ dataFromOffset = octstr_copy(data, *offset, dataLength); guessedPayloadLength = wtls_payload_guess_length(dataFromOffset); /* Ooops. Something's wrong. This requested PDU is screwed up. */ if (guessedPayloadLength == -1) { octstr_destroy(dataFromOffset); *offset = dataLength; return NULL; } /* Quit if we discover that the PDU length plus the requested offset is larger than the length of the data supplied - this would mean that we would overrun our data, and therefore something is corrupt in this PDU. Set the offset as the data length, which will indicate we've gone as far as we can */ if ((*offset + guessedPayloadLength) > dataLength) { octstr_destroy(dataFromOffset); *offset = dataLength; return NULL; } /* If we pass that test, set offset to the correct return value */ *offset += guessedPayloadLength; /* Copy the octstr again, so that we end up with an octstr containing just the PDU we want */ dataFromOffsetToLength = octstr_copy(dataFromOffset, 0, guessedPayloadLength); /* Submit that octstr to the wtls_message_unpack function */ returnPayload = wtls_payload_unpack(dataFromOffsetToLength); octstr_destroy(dataFromOffset); return returnPayload; } wtls_Payload *wtls_payload_unpack(Octstr * data) { wtls_Payload *payload = NULL; long bitpos = 0, charpos = 0; gw_assert(data != NULL); payload = gw_malloc(sizeof(wtls_Payload)); /* the record field length flag */ payload->rlen = octstr_get_bits(data, bitpos, 1); bitpos += 1; /* the sequence number flag */ payload->snMode = octstr_get_bits(data, bitpos, 1); bitpos += 1; /* the cipher usage flag */ payload->cipher = octstr_get_bits(data, bitpos, 1); bitpos += 1; /* the reserved bit */ payload->reserved = octstr_get_bits(data, bitpos, 1); bitpos += 1; /* the message type */ payload->type = octstr_get_bits(data, bitpos, 4); bitpos += 4; charpos += 1; /* Get the sequence number if present */ if (payload->snMode) payload->seqNum = unpack_int16(data, &charpos); /* consume the WTLS plaintext length if present */ if (payload->rlen) charpos += 2; /* the part of data that has just been processed is not * needed anymore. We delete it. What is left of data is * the payload. */ octstr_delete(data, 0, charpos); payload->data = data; return payload; } // Doesn't destroy input payload wtls_PDU *wtls_pdu_unpack(wtls_Payload * payload, WTLSMachine * wtls_machine) { wtls_PDU *pdu = NULL; Octstr *buffer; long charpos = 0; gw_assert(payload->data != NULL); pdu = gw_malloc(sizeof(wtls_PDU)); pdu->type = payload->type; pdu->reserved = payload->reserved; pdu->cipher = payload->cipher; pdu->snMode = payload->snMode; pdu->seqNum = payload->seqNum; pdu->rlen = payload->rlen; /* is the PDU encrypted ? */ /* if(pdu->cipher) { buffer = wtls_decrypt(payload->data, wtls_machine); } else { */ buffer = payload->data; /* } */ switch (pdu->type) { case ChangeCipher_PDU: pdu->u.cc.change = octstr_get_char(buffer, charpos); charpos += 1; break; case Alert_PDU: pdu->u.alert.level = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.alert.desc = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.alert.chksum = unpack_octstr_fixed(buffer, &charpos, 4); break; case Handshake_PDU: pdu->u.handshake.msg_type = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.handshake.length = unpack_int16(buffer, &charpos); switch (pdu->u.handshake.msg_type) { case hello_request: break; case client_hello: pdu->u.handshake.client_hello = (ClientHello *) gw_malloc(sizeof(ClientHello)); pdu->u.handshake.client_hello->clientversion = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.handshake.client_hello->random = unpack_random(buffer, &charpos); pdu->u.handshake.client_hello->session_id = unpack_octstr(buffer, &charpos); /* Unpack the list of keys */ pdu->u.handshake.client_hello->client_key_ids = unpack_key_list(buffer, &charpos); pdu->u.handshake.client_hello->trusted_key_ids = unpack_key_list(buffer, &charpos); /* Unpack the list of CipherSuites */ pdu->u.handshake.client_hello->ciphersuites = unpack_ciphersuite_list(buffer, &charpos); /* CompressionMethods */ pdu->u.handshake.client_hello->comp_methods = unpack_compression_method_list(buffer, &charpos); pdu->u.handshake.client_hello->snmode = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.handshake.client_hello->krefresh = octstr_get_char(buffer, charpos); charpos += 1; break; case server_hello: pdu->u.handshake.server_hello = (ServerHello *) gw_malloc(sizeof(ServerHello)); pdu->u.handshake.server_hello->serverversion = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.handshake.server_hello->random = unpack_random(buffer, &charpos); pdu->u.handshake.server_hello->session_id = unpack_octstr(buffer, &charpos); pdu->u.handshake.server_hello->client_key_id = octstr_get_char(buffer, charpos); charpos += 1; /* CypherSuite */ pdu->u.handshake.server_hello->ciphersuite-> bulk_cipher_algo = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.handshake.server_hello->ciphersuite->mac_algo = octstr_get_char(buffer, charpos); charpos += 1; /* CompressionMethod */ pdu->u.handshake.server_hello->comp_method = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.handshake.server_hello->snmode = octstr_get_char(buffer, charpos); charpos += 1; pdu->u.handshake.server_hello->krefresh = octstr_get_char(buffer, charpos); charpos += 1; break; case certificate: { List *certList = gwlist_create(); Certificate *cert; int len = unpack_int16(buffer, &charpos); while (charpos <= len) { cert = (Certificate *) gw_malloc(sizeof(Certificate)); cert->certificateformat = octstr_get_char(buffer, charpos); charpos += 1; switch (cert->certificateformat) { case WTLSCert: cert->wtls_certificate = unpack_wtls_certificate (buffer, &charpos); break; case X509Cert: cert->x509_certificate = unpack_octstr16(buffer, &charpos); break; case X968Cert: cert->x968_certificate = unpack_octstr16(buffer, &charpos); break; } gwlist_append(certList, cert); } pdu->u.handshake.certificates->certList = certList; } break; case server_key_exchange: pdu->u.handshake.server_key_exchange = (ServerKeyExchange *) gw_malloc(sizeof(ServerKeyExchange)); /* unpack the ParameterSpecifier and ParameterSet */ pdu->u.handshake.server_key_exchange->param_spec = unpack_param_spec(buffer, &charpos); switch (client_key_exchange_algo) { case rsa_anon: pdu->u.handshake.server_key_exchange-> rsa_params = unpack_rsa_pubkey(buffer, &charpos); break; case dh_anon: pdu->u.handshake.server_key_exchange-> dh_params = unpack_dh_pubkey(buffer, &charpos); break; case ecdh_anon: pdu->u.handshake.server_key_exchange-> ecdh_params = unpack_ec_pubkey(buffer, &charpos); break; default: break; } break; case client_key_exchange: pdu->u.handshake.client_key_exchange = (ClientKeyExchange *) gw_malloc(sizeof(ClientKeyExchange)); switch (client_key_exchange_algo) { case rsa: case rsa_anon: pdu->u.handshake.client_key_exchange-> rsa_params = unpack_rsa_encrypted_secret(buffer, &charpos); break; case dh_anon: pdu->u.handshake.client_key_exchange-> dh_anon_params = unpack_dh_pubkey(buffer, &charpos); break; case ecdh_anon: case ecdh_ecdsa: pdu->u.handshake.client_key_exchange-> ecdh_params = unpack_ec_pubkey(buffer, &charpos); break; default: break; } break; case server_hello_done: /* empty */ break; case finished: pdu->u.handshake.finished = (Finished *) gw_malloc(sizeof(Finished)); pdu->u.handshake.finished->verify_data = unpack_octstr_fixed(buffer, &charpos, 12); octstr_dump(pdu->u.handshake.finished->verify_data, 0); break; default: break; } break; case Application_PDU: /* application message */ pdu->u.application.data = octstr_duplicate(buffer); break; default: debug("wap.wtls", 0, "%*sPDU: ", 0, ""); octstr_dump(buffer, 0); panic(0, "Unpacking unknown WTLS PDU type %ld", (long)pdu->type); break; } return (pdu); } Octstr *wtls_payload_pack(wtls_Payload * payload, int seqnum) { Octstr *data; long bitpos, charpos; long sizepos; /* We rely on octstr_set_bits to lengthen our octstr as needed. */ data = octstr_create(""); bitpos = 0; charpos = 0; sizepos = 0; /* the record field length flag - always present */ octstr_set_bits(data, bitpos, 1, 1); bitpos += 1; /* the sequence number flag */ octstr_set_bits(data, bitpos, 1, payload->snMode); bitpos += 1; /* the cipher usage flag */ octstr_set_bits(data, bitpos, 1, payload->cipher); bitpos += 1; /* the reserved bit */ octstr_set_bits(data, bitpos, 1, payload->reserved); bitpos += 1; /* set the message type */ octstr_set_bits(data, bitpos, 4, payload->type); bitpos += 4; charpos += 1; /* set the sequence number */ if (payload->snMode) charpos = pack_int16(data, charpos, seqnum); /* set the WTLS length */ charpos = pack_int16(data, charpos, payload->rlen); /* append the data from the wtls_PDU */ octstr_insert(data, payload->data, octstr_len(data)); return data; } wtls_Payload *wtls_pdu_pack(wtls_PDU * pdu, WTLSMachine * wtls_machine) { Octstr *buffer, *encryptedbuffer; wtls_Payload *payload; long bitpos, charpos; long messageSizePos, sizepos; /* Used for length calculations */ int size, recordType; /* create the wtls_PDU */ payload = (wtls_Payload *) gw_malloc(sizeof(wtls_Payload)); payload->type = pdu->type; payload->reserved = pdu->reserved; payload->cipher = pdu->cipher; payload->snMode = pdu->snMode; payload->seqNum = pdu->seqNum; /* We rely on octstr_set_bits to lengthen our octstr as needed. */ buffer = octstr_create(""); bitpos = 0; charpos = 0; sizepos = 0; switch (pdu->type) { case ChangeCipher_PDU: octstr_append_char(buffer, pdu->u.cc.change); charpos += 1; break; case Alert_PDU: octstr_append_char(buffer, pdu->u.alert.level); charpos += 1; octstr_append_char(buffer, pdu->u.alert.desc); charpos += 1; charpos = pack_octstr_fixed(buffer, charpos, pdu->u.alert.chksum); break; case Handshake_PDU: octstr_append_char(buffer, pdu->u.handshake.msg_type); charpos += 1; /* Save the location of the message size */ messageSizePos = charpos; charpos = pack_int16(buffer, charpos, pdu->u.handshake.length); switch (pdu->u.handshake.msg_type) { case hello_request: break; case client_hello: octstr_append_char(buffer, pdu->u.handshake.client_hello-> clientversion); charpos += 1; charpos = pack_random(buffer, charpos, pdu->u.handshake.client_hello->random); charpos = pack_octstr(buffer, charpos, pdu->u.handshake.client_hello-> session_id); /* pack the list of keys */ charpos = pack_key_list(buffer, charpos, pdu->u.handshake.client_hello-> client_key_ids); charpos = pack_key_list(buffer, charpos, pdu->u.handshake.client_hello-> trusted_key_ids); /* pack the list of CipherSuites */ charpos = pack_ciphersuite_list(buffer, charpos, pdu->u.handshake. client_hello-> ciphersuites); /* CompressionMethods */ charpos = pack_compression_method_list(buffer, charpos, pdu->u.handshake. client_hello-> comp_methods); octstr_append_char(buffer, pdu->u.handshake.client_hello-> snmode); charpos += 1; octstr_append_char(buffer, pdu->u.handshake.client_hello-> krefresh); charpos += 1; break; case server_hello: octstr_append_char(buffer, pdu->u.handshake.server_hello-> serverversion); charpos += 1; charpos = pack_random(buffer, charpos, pdu->u.handshake.server_hello->random); charpos = pack_octstr(buffer, charpos, pdu->u.handshake.server_hello-> session_id); octstr_append_char(buffer, pdu->u.handshake. server_hello->client_key_id); charpos += 1; /* CypherSuite */ octstr_append_char(buffer, pdu->u.handshake. server_hello->ciphersuite-> bulk_cipher_algo); charpos += 1; octstr_append_char(buffer, pdu->u.handshake. server_hello->ciphersuite->mac_algo); charpos += 1; /* CompressionMethod */ octstr_append_char(buffer, pdu->u.handshake.server_hello-> comp_method); charpos += 1; octstr_append_char(buffer, pdu->u.handshake.server_hello-> snmode); charpos += 1; octstr_append_char(buffer, pdu->u.handshake.server_hello-> krefresh); charpos += 1; break; case certificate: { Certificate *cert; int pos = charpos, len; charpos = pack_int16(buffer, charpos, 0); for (;;) { cert = gwlist_consume(pdu->u.handshake. certificates-> certList); if (!cert) break; octstr_append_char(buffer, cert-> certificateformat); charpos += 1; switch (cert->certificateformat) { case WTLSCert: charpos = pack_wtls_certificate (buffer, charpos, cert->wtls_certificate); destroy_wtls_certificate(cert-> wtls_certificate); break; case X509Cert: charpos = pack_octstr16(buffer, charpos, cert-> x509_certificate); octstr_destroy(cert-> x509_certificate); break; case X968Cert: charpos = pack_octstr16(buffer, charpos, cert-> x968_certificate); octstr_destroy(cert-> x968_certificate); break; } gw_free(cert); } len = charpos - pos - 2; octstr_set_char(buffer, pos, (len & 0xFF00) >> 8); octstr_set_char(buffer, pos + 1, len & 0xFF); } break; case server_key_exchange: debug("wtls: ", 0, "Packing ServerKeyExchange"); /* pack the ParameterSpecifier */ charpos = pack_param_spec(buffer, charpos, pdu->u.handshake. server_key_exchange->param_spec); switch (client_key_exchange_algo) { case rsa_anon: charpos = pack_rsa_pubkey(buffer, charpos, pdu->u.handshake. server_key_exchange-> rsa_params); break; case dh_anon: charpos = pack_dh_pubkey(buffer, charpos, pdu->u.handshake. server_key_exchange-> dh_params); break; case ecdh_anon: charpos = pack_ec_pubkey(buffer, charpos, pdu->u.handshake. server_key_exchange-> ecdh_params); break; default: break; } break; case client_key_exchange: switch (client_key_exchange_algo) { case rsa: case rsa_anon: charpos = pack_rsa_encrypted_secret(buffer, charpos, pdu->u.handshake. client_key_exchange-> rsa_params); break; case dh_anon: charpos = pack_dh_pubkey(buffer, charpos, pdu->u.handshake. client_key_exchange-> dh_anon_params); break; case ecdh_anon: case ecdh_ecdsa: charpos = pack_ec_pubkey(buffer, charpos, pdu->u.handshake. client_key_exchange-> ecdh_params); break; default: break; } break; case server_hello_done: /* empty */ default: break; case finished: charpos = pack_octstr_fixed(buffer, charpos, pdu->u.handshake.finished-> verify_data); debug("wtls", 0, "verify_data (in pack)"); octstr_dump(pdu->u.handshake.finished->verify_data, 0); break; } /* Change the length */ size = octstr_len(buffer) - messageSizePos - 2; debug("wtls_msg.c:length", 0, "Setting msg size to : %d", size); octstr_set_char(buffer, messageSizePos, (size & 0xFF00) >> 8); messageSizePos += 1; octstr_set_char(buffer, messageSizePos, (size & 0x00FF)); /* we keep the handshake data to create the Finished PDU */ octstr_append(wtls_machine->handshake_data, buffer); break; case Application_PDU: /* application message */ octstr_destroy(buffer); buffer = pdu->u.application.data; pdu->u.application.data = NULL; break; default: panic(0, "Packing unknown WTLS PDU type %ld", (long)pdu->type); } /* encrypt the buffer if needed */ if (pdu->cipher) { /* the MAC is calculated with the record type so we need it now */ recordType = 1 << 7; /* length, always present */ recordType |= pdu->snMode << 6; recordType |= pdu->cipher << 5; recordType |= pdu->reserved << 4; recordType |= pdu->type; if (!(encryptedbuffer = wtls_encrypt(buffer, wtls_machine, recordType))) return (NULL); payload->data = encryptedbuffer; } else payload->data = buffer; payload->rlen = octstr_len(payload->data); debug("wtls", 0, "Packed PDU Length: %d", payload->rlen); return (payload); } void wtls_payload_dump(wtls_Payload * payload, int level) { char *dbg = "wap.wtls", type[20], *data; if (!payload) return; data = octstr_get_cstr(payload->data); /* the message type */ pduName(type, payload->type); debug(dbg, 0, "%*sPayload type: %s", level, "", type); if (payload->type == Handshake_PDU) { hsName(type, *data); debug(dbg, 0, "%*sHandshake type: %s", level + 1, "", type); } else if (payload->type == Alert_PDU) { alertName(type, *(data + 1)); debug(dbg, 0, "%*sAlert type: %s", level + 1, "", type); } /* the reserved bit */ debug(dbg, 0, "%*sReserved bit: %d", level, "", payload->reserved); /* cipher usage flag */ debug(dbg, 0, "%*sCipher in use: %d", level, "", payload->cipher); /* the sequence number flag */ debug(dbg, 0, "%*sSequence number in use: %d", level, "", payload->seqNum); /* the record field length flag */ debug(dbg, 0, "%*sRecord field length present: %d", level, "", payload->rlen); octstr_dump(payload->data, level + 1); } void wtls_pdu_dump(wtls_PDU * pdu, int level) { char *dbg = "wap.wtls", type[20]; /* the message type */ pduName(type, pdu->type); debug(dbg, 0, "%*sPDU type: %s", level, "", type); if (pdu->type == Handshake_PDU) { hsName(type, pdu->u.handshake.msg_type); debug(dbg, 0, "%*sHandshake type: %s", level + 1, "", type); } /* the reserved bit */ debug(dbg, 0, "%*sReserved bit: %d", level, "", pdu->reserved); /* cipher usage flag */ debug(dbg, 0, "%*sCipher in use: %d", level, "", pdu->cipher); /* the sequence number flag */ debug(dbg, 0, "%*sSequence number in use: %d", level, "", pdu->seqNum); /* the record field length flag */ debug(dbg, 0, "%*sRecord field length present: %d", level, "", pdu->rlen); switch (pdu->type) { case ChangeCipher_PDU: debug(dbg, 0, "%*sChangeCipher:", level, ""); debug(dbg, 0, "%*sChange: %d", level + 1, "", pdu->u.cc.change); break; case Alert_PDU: debug(dbg, 0, "%*sAlert:", level, ""); debug(dbg, 0, "%*sLevel: %d", level + 1, "", pdu->u.alert.level); debug(dbg, 0, "%*sDescription: %d", level + 1, "", pdu->u.alert.desc); debug(dbg, 0, "%*sChecksum: %s", level + 1, "", octstr_get_cstr(pdu->u.alert.chksum)); break; case Handshake_PDU: debug(dbg, 0, "%*sHandshake:", level, ""); debug(dbg, 0, "%*sMessage Type: %d", level + 1, "", pdu->u.handshake.msg_type); debug(dbg, 0, "%*sLength: %d", level + 1, "", pdu->u.handshake.length); switch (pdu->u.handshake.msg_type) { case hello_request: debug(dbg, 0, "%*sHelloRequest.", level, ""); break; case client_hello: debug(dbg, 0, "%*sClientHello:", level, ""); debug(dbg, 0, "%*sClient version: %d", level + 1, "", pdu->u.handshake.client_hello->clientversion); debug(dbg, 0, "%*sRandom:", level + 1, ""); dump_random(dbg, level + 2, pdu->u.handshake.client_hello->random); debug(dbg, 0, "%*sSessionId: ", level, ""); octstr_dump(pdu->u.handshake.client_hello->session_id, level + 2); /* pack the list of keys */ debug(dbg, 0, "%*sClient Key IDs: ", level + 1, ""); dump_key_list(dbg, level + 2, pdu->u.handshake.client_hello-> client_key_ids); debug(dbg, 0, "%*sTrusted Key IDs: ", level + 1, ""); dump_key_list(dbg, level + 2, pdu->u.handshake.client_hello-> trusted_key_ids); /* pack the list of CipherSuites */ debug(dbg, 0, "%*sCipherSuite List: ", level + 1, ""); dump_ciphersuite_list(dbg, level + 2, pdu->u.handshake.client_hello-> ciphersuites); /* CompressionMethods */ debug(dbg, 0, "%*sCompression Method List: ", level + 1, ""); dump_compression_method_list(dbg, level + 2, pdu->u.handshake. client_hello-> comp_methods); debug(dbg, 0, "%*sSeq Number Mode: %d", level + 1, "", pdu->u.handshake.client_hello->snmode); debug(dbg, 0, "%*sKey Refresh: %d", level + 1, "", pdu->u.handshake.client_hello->krefresh); break; case server_hello: debug(dbg, 0, "%*sServerHello:", level, ""); debug(dbg, 0, "%*sServer version: %d", level + 1, "", pdu->u.handshake.server_hello->serverversion); debug(dbg, 0, "%*sRandom:", level + 1, ""); dump_random(dbg, level + 2, pdu->u.handshake.server_hello->random); debug(dbg, 0, "%*sSession ID: %s", level + 1, "", octstr_get_cstr(pdu->u.handshake. server_hello->session_id)); debug(dbg, 0, "%*sClient Key ID: %d", level + 1, "", pdu->u.handshake.server_hello->client_key_id); /* CypherSuite */ debug(dbg, 0, "%*sBulk Cipher Algo: %d", level + 1, "", pdu->u.handshake.server_hello-> ciphersuite->bulk_cipher_algo); debug(dbg, 0, "%*sMAC Algo: %d", level + 1, "", pdu->u.handshake.server_hello->ciphersuite-> mac_algo); /* CompressionMethod */ debug(dbg, 0, "%*sCompression Method: %d", level + 1, "", pdu->u.handshake.server_hello->comp_method); debug(dbg, 0, "%*sSeq Number Mode: %d", level + 1, "", pdu->u.handshake.server_hello->snmode); debug(dbg, 0, "%*sKey Refresh: %d", level + 1, "", pdu->u.handshake.server_hello->krefresh); break; case certificate: debug(dbg, 0, "%*sCertificate:", level, ""); { Certificate *cert; List *certList = pdu->u.handshake.certificates->certList; int i = 0, len = gwlist_len(certList); for (; i < len; i++) { cert = gwlist_get(certList, i); debug(dbg, 0, "%*sCertificate Format: %d", level + 1, "", cert->certificateformat); switch (cert->certificateformat) { case WTLSCert: debug(dbg, 0, "%*sWTLS Certificate:", level + 1, ""); dump_wtls_certificate(dbg, level + 2, cert-> wtls_certificate); break; case X509Cert: debug(dbg, 0, "%*sX509 Certificate:", level + 1, ""); octstr_dump(cert-> x509_certificate, level + 2); break; case X968Cert: debug(dbg, 0, "%*sX968 Certificate:", level + 1, ""); octstr_dump(cert-> x968_certificate, level + 2); break; } } } break; case server_key_exchange: debug(dbg, 0, "%*sServerKeyExchange: ", level, ""); /* ParameterSpecifier */ debug(dbg, 0, "%*sParameter Index: %d", level + 1, "", pdu->u.handshake.server_key_exchange-> param_spec->param_index); if (pdu->u.handshake.server_key_exchange-> param_spec->param_index == 255) { /* ParameterSet */ debug(dbg, 0, "%*sParameter Set: %p", level + 1, "", pdu->u.handshake.server_key_exchange-> param_spec->param_set); } switch (client_key_exchange_algo) { case rsa_anon: dump_rsa_pubkey(dbg, level + 1, pdu->u.handshake. server_key_exchange-> rsa_params); break; case dh_anon: dump_dh_pubkey(dbg, level + 1, pdu->u.handshake. server_key_exchange->dh_params); break; case ecdh_anon: dump_ec_pubkey(dbg, level + 1, pdu->u.handshake. server_key_exchange-> ecdh_params); break; default: break; } break; case client_key_exchange: debug(dbg, 0, "%*sClientKeyExchange:", level, ""); switch (client_key_exchange_algo) { case rsa: case rsa_anon: dump_rsa_encrypted_secret(dbg, level + 1, pdu->u.handshake. client_key_exchange-> rsa_params); break; case dh_anon: dump_dh_pubkey(dbg, level + 1, pdu->u.handshake. client_key_exchange-> dh_anon_params); break; case ecdh_anon: case ecdh_ecdsa: dump_ec_pubkey(dbg, level + 1, pdu->u.handshake. client_key_exchange-> ecdh_params); break; default: break; } break; case server_hello_done: debug(dbg, 0, "%*sClientHelloDone.", level, ""); /* empty */ break; case finished: debug(dbg, 0, "%*sFinished:", level, ""); debug(dbg, 0, "%*sverify_data :", level + 1, ""); octstr_dump(pdu->u.handshake.finished->verify_data, level + 2); break; default: break; } break; case Application_PDU: debug(dbg, 0, "%*sApplication:", level, ""); /* application message */ octstr_dump(pdu->u.application.data, level + 1); break; default: debug(dbg, 0, "%*sWTLS PDU at %p:", level, "", (void *)pdu); debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type); } } #endif /* HAVE_WTLS_OPENSSL */ gateway-1.4.5/wap/wtls_statesupport.c0000644000175000017500000013440113227613126016453 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtls_statesupport.c * * 2001 Nick Clarey, Yann Muller for 3G LAB * Nikos Balkanas, InAccess Networks (2009) */ #include "gwlib/gwlib.h" #ifdef HAVE_WTLS_OPENSSL #include #include #ifndef NO_RC5 #include #else #error "your OpenSSL installation lacks RC5 algorithm support" #endif /* NO_RC5 */ #include "wtls_statesupport.h" #include "wtls_pdusupport.h" #define BLOCKLENGTH 64 #define INNERPAD 0x36 #define OUTERPAD 0x5C /*static keyxchg_table_t keyxchg_table[] = { {"NULL",0}, {"Shared Secret", KEYSIZE_MAX}, {"DH-anon",KEYSIZE_MAX}, {"DH-anon-512",512}, {"DH-anon-768",768}, {"RSA-anon", KEYSIZE_MAX}, {"RSA-anon-512",512}, {"RSA-anon-768",768}, {"RSA",KEYSIZE_MAX}, {"RSA-512", 512}, {"RSA-768",768}, {"ECDH-anon",KEYSIZE_MAX}, {"ECDH-anon-113",113}, {"ECDH-anon-131",131}, {"ECDH-ECDSA",KEYSIZE_MAX} }; */ static bulk_table_t bulk_table[] = { {"NULL Encryption", EXPORTABLE, STREAM, 0, 0, 0, 0, 0}, {"RC5-CBC-40", EXPORTABLE, BLOCK, 5, 16, 40, 8, 8}, {"RC5-CBC-56", EXPORTABLE, BLOCK, 7, 16, 56, 8, 8}, {"RC5-CBC", NOT_EXPORTABLE, BLOCK, 16, 16, 128, 8, 8}, {"DES-CBC-40", EXPORTABLE, BLOCK, 5, 8, 40, 8, 8}, {"DES-CBC", NOT_EXPORTABLE, BLOCK, 8, 8, 56, 8, 8}, {"3DES-CBC-EDE", NOT_EXPORTABLE, BLOCK, 24, 24, 168, 8, 8}, {"IDEA-CBC-40", EXPORTABLE, BLOCK, 5, 16, 40, 8, 8}, {"IDEA-CBC-56", EXPORTABLE, BLOCK, 7, 16, 56, 8, 8}, {"IDEA-CBC", NOT_EXPORTABLE, BLOCK, 16, 16, 128, 8, 8} }; static hash_table_t hash_table[] = { {"SHA-0", 0, 0}, {"SHA1-40", 20, 5}, {"SHA1-80", 20, 10}, {"SHA1", 20, 20}, {"SHA-XOR-40", 0, 5}, {"MD5-40", 16, 5}, {"MD5-80", 16, 10}, {"MD5", 16, 16} }; X509 *x509_cert = NULL; RSA *private_key = NULL; int refresh = 2; extern KeyExchangeSuite client_key_exchange_algo; extern PublicKeyAlgorithm public_key_algo; extern SignatureAlgorithm signature_algo; extern unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md); extern unsigned char *stateName(int state); /* * Function Prototypes. */ Octstr *wtls_hmac_hash(Octstr * key, Octstr * data, int algo); Octstr *wtls_hash(Octstr * inputData, WTLSMachine * wtls_machine); Octstr *wtls_rc5(Octstr * data, WTLSMachine * wtls_machine, int crypt); Octstr *wtls_des(Octstr * data, WTLSMachine * wtls_machine, int crypt); Octstr *wtls_P_hash(Octstr * secret, Octstr * seed, int byteLength, WTLSMachine * wtls_machine); Octstr *wtls_get_certificate(void); int isSupportedKeyEx(int keyExId); void add_all_handshake_data(WTLSMachine * wtls_machine, List * pdu_list); /* Add here the supported KeyExchangeSuites used by wtls_choose_clientkeyid */ KeyExchangeSuite supportedKeyExSuite[] = { rsa_anon }; Octstr *wtls_decrypt(wtls_Payload * payload, WTLSMachine * wtls_machine) { int len, padLen = 0, macSize, recordType, block, refresh; Octstr *openText, *MAContent, *tempData, *result; char cipher[20], *p; if (payload->seqNum && wtls_machine->client_seq_num > payload->seqNum) { error(0, "Out of sequence packet received (p: %d < %d :w). Dropping datagram.", payload->seqNum, wtls_machine->client_seq_num); return (NULL); } else wtls_machine->client_seq_num = payload->seqNum; refresh = 1 << wtls_machine->key_refresh; if (wtls_machine->last_refresh < 0 || (wtls_machine->last_refresh + refresh <= wtls_machine->client_seq_num)) calculate_client_key_block(wtls_machine); switch (wtls_machine->bulk_cipher_algorithm) { case NULL_bulk: openText = octstr_duplicate(payload->data); break; case RC5_CBC: case RC5_CBC_40: case RC5_CBC_56: openText = wtls_rc5(payload->data, wtls_machine, RC5_DECRYPT); break; case DES_CBC: case DES_CBC_40: openText = wtls_des(payload->data, wtls_machine, DES_DECRYPT); break; default: cipherName(cipher, wtls_machine->bulk_cipher_algorithm); error(0, "wtls_decrypt: Unsupported bulk cipher algorithm (%s).", cipher); return (NULL); break; } /* Verify MAC */ recordType = 1 << 7; recordType |= payload->snMode << 6; recordType |= payload->cipher << 5; recordType |= payload->reserved << 4; recordType |= payload->type; len = octstr_len(openText); p = octstr_get_cstr(openText); block = bulk_table[wtls_machine->bulk_cipher_algorithm].block_size; padLen = *(p + len - 1); if (padLen >= block || padLen != *(p + len - 2)) padLen = 0; padLen++; macSize = hash_table[wtls_machine->mac_algorithm].mac_size; tempData = octstr_create(""); pack_int16(tempData, 0, wtls_machine->client_seq_num); octstr_append_char(tempData, recordType); pack_int16(tempData, 3, len - macSize - padLen); octstr_append_data(tempData, p, len - macSize - padLen); MAContent = wtls_hmac_hash(wtls_machine->client_write_MAC_secret, tempData, wtls_machine->mac_algorithm); if (memcmp(octstr_get_cstr(MAContent), p + len - padLen - macSize, macSize)) { octstr_destroy(MAContent); octstr_destroy(tempData); octstr_destroy(openText); error(0, "wtls_decrypt: Rejected packet due to bad MAC"); return (NULL); } octstr_destroy(MAContent); octstr_destroy(tempData); result = octstr_create_from_data((char *)p, len - padLen - macSize); octstr_destroy(openText); return (result); } /* This function will convert our buffer into a completed GenericBlockCipher */ Octstr *wtls_encrypt(Octstr * buffer, WTLSMachine * wtls_machine, int recordType) { Octstr *bufferCopy; Octstr *encryptedContent; Octstr *contentMac; Octstr *tempData; char *tempPadding = NULL; int paddingLength, macSize, blockLength, bufferLength, refresh; int i; refresh = 1 << wtls_machine->key_refresh; if (!(wtls_machine->server_seq_num % refresh)) calculate_server_key_block(wtls_machine); /* Copy our buffer */ bufferCopy = octstr_duplicate(buffer); /* Get the MAC of the content */ bufferLength = octstr_len(buffer); /* Copy the buffer in preparation for MAC calculation */ tempData = octstr_create(""); pack_int16(tempData, 0, wtls_machine->server_seq_num); octstr_append_char(tempData, recordType); pack_int16(tempData, octstr_len(tempData), bufferLength); octstr_append(tempData, buffer); /* Calculate the MAC */ contentMac = wtls_hmac_hash(wtls_machine->server_write_MAC_secret, tempData, wtls_machine->mac_algorithm); /* Calculate the padding length */ macSize = hash_table[wtls_machine->mac_algorithm].mac_size; blockLength = bulk_table[wtls_machine->bulk_cipher_algorithm].block_size; paddingLength = blockLength - ((bufferLength + macSize + 1) % blockLength); /* Append the MAC to the bufferCopy */ octstr_append(bufferCopy, contentMac); if (paddingLength > 0) { /* Pad with the paddingLength itself paddingLength times. Confused yet? */ tempPadding = gw_malloc(paddingLength); for (i = 0; i < paddingLength; i++) { /* You're probably really spaced out around now... see section 9.2.3.3 for more details... */ tempPadding[i] = paddingLength; } octstr_append_data(bufferCopy, tempPadding, paddingLength); gw_free(tempPadding); } /* Add the length byte */ octstr_append_char(bufferCopy, paddingLength); /* Encrypt the content */ switch (wtls_machine->bulk_cipher_algorithm) { case NULL_bulk: encryptedContent = octstr_duplicate(bufferCopy); break; case RC5_CBC: case RC5_CBC_40: case RC5_CBC_56: encryptedContent = wtls_rc5(bufferCopy, wtls_machine, RC5_ENCRYPT); break; case DES_CBC: case DES_CBC_40: encryptedContent = wtls_des(bufferCopy, wtls_machine, DES_ENCRYPT); break; default: error(0, "wtls_encrypt: Unsupported bulk cipher algorithm (%d).", wtls_machine->bulk_cipher_algorithm); encryptedContent = NULL; break; } octstr_destroy(bufferCopy); octstr_destroy(contentMac); octstr_destroy(tempData); octstr_destroy(buffer); return (encryptedContent); } /* * Naming utilities used in printing */ void keyName(char *name, int key) { switch (key) { case null_k: strcpy(name, "null_k"); break; case shared_secret: strcpy(name, "shared_secret"); break; case dh_anon: strcpy(name, "dh_anon"); break; case dh_anon_512: strcpy(name, "dh_anon_512"); break; case dh_anon_768: strcpy(name, "dh_anon_768"); break; case rsa_anon: strcpy(name, "rsa_anon"); break; case rsa_anon_512: strcpy(name, "rsa_anon_512"); break; case rsa_anon_768: strcpy(name, "rsa_anon_768"); break; case rsa: strcpy(name, "rsa"); break; case rsa_512: strcpy(name, "rsa_512"); break; case rsa_768: strcpy(name, "rsa_768"); break; case ecdh_anon: strcpy(name, "ecdh_anon"); break; case ecdh_anon_113: strcpy(name, "ecdh_anon_113"); break; case ecdh_anon_131: strcpy(name, "ecdh_anon_131"); break; case ecdh_ecdsa: strcpy(name, "ecdh_ecdsa"); break; } } void cipherName(char *name, int cipher) { switch (cipher) { case NULL_bulk: strcpy(name, "NULL_bulk"); break; case RC5_CBC_40: strcpy(name, "RC5_CBC_40"); break; case RC5_CBC_56: strcpy(name, "RC5_CBC_56"); break; case RC5_CBC: strcpy(name, "RC5_CBC"); break; case DES_CBC_40: strcpy(name, "DES_CBC_40"); break; case DES_CBC: strcpy(name, "DES_CBC"); break; case TRIPLE_DES_CBC_EDE: strcpy(name, "TRIPLE_DES_CBC_EDE"); break; case IDEA_CBC_40: strcpy(name, "IDEA_CBC_40"); break; case IDEA_CBC_56: strcpy(name, "IDEA_CBC_56"); break; case IDEA_CBC: strcpy(name, "IDEA_CBC"); break; } } void macName(char *name, int mac) { switch (mac) { case SHA_0: strcpy(name, "SHA_0"); break; case SHA_40: strcpy(name, "SHA_40"); break; case SHA_80: strcpy(name, "SHA_80"); break; case SHA_NOLIMIT: strcpy(name, "SHA_NOLIMIT"); break; case SHA_XOR_40: strcpy(name, "SHA_XOR_40"); break; case MD5_40: strcpy(name, "MD5_80"); break; case MD5_80: strcpy(name, "MD5_80"); break; case MD5_NOLIMIT: strcpy(name, "MD5_NOLIMIT"); break; } } void alertName(char *name, int alert) { switch (alert) { case connection_close_notify: strcpy(name, "connection_close_notify"); break; case session_close_notify: strcpy(name, "session_close_notify"); break; case no_connection: strcpy(name, "no_connection"); break; case unexpected_message: strcpy(name, "unexpected_message"); break; case time_required: strcpy(name, "time_required"); break; case bad_record_mac: strcpy(name, "bad_record_mac"); break; case decryption_failed: strcpy(name, "decryption_failed"); break; case record_overflow: strcpy(name, "record_overflow"); break; case decompression_failure: strcpy(name, "decompression_failure"); break; case handshake_failure: strcpy(name, "handshake_failure"); break; case bad_certificate: strcpy(name, "unsupported_certificate"); break; case certificate_revoked: strcpy(name, "certificate_revoked"); break; case certificate_expired: strcpy(name, "certificate_expired"); break; case certificate_unknown: strcpy(name, "certificate_unknown"); break; case illegal_parameter: strcpy(name, "illegal_parameter"); break; case unknown_ca: strcpy(name, "unknown_ca"); break; case access_denied: strcpy(name, "access_denied"); break; case decode_error: strcpy(name, "decode_error"); break; case decrypt_error: strcpy(name, "decrypt_error"); break; case unknown_key_id: strcpy(name, "unknown_key_id"); break; case disabled_key_id: strcpy(name, "disabled_key_id"); break; case key_exchange_disabled: strcpy(name, "key_exchange_disabled"); break; case session_not_ready: strcpy(name, "session_not_ready"); break; case unknown_parameter_index: strcpy(name, "unknown_parameter_index"); break; case duplicate_finished_received: strcpy(name, "duplicate_finished_received"); break; case export_restriction: strcpy(name, "export_restriction"); break; case protocol_version: strcpy(name, "protocol_version"); break; case insufficient_security: strcpy(name, "insufficient_security"); break; case internal_error: strcpy(name, "internal_error"); break; case user_canceled: strcpy(name, "user_canceled"); break; case no_renegotiation: strcpy(name, "no_renegotiation"); break; } } void pduName(char *name, int pdu) { switch (pdu) { case ChangeCipher_PDU: strcpy(name, "Change Cipher"); break; case Alert_PDU: strcpy(name, "Alert"); break; case Handshake_PDU: strcpy(name, "Handshake"); break; case Application_PDU: strcpy(name, "Application"); break; } } void hsName(char *name, int handshake) { switch (handshake) { case hello_request: strcpy(name, "Hello Request"); break; case client_hello: strcpy(name, "Client Hello"); break; case server_hello: strcpy(name, "Server Hello"); break; case certificate: strcpy(name, "Certificate"); break; case server_key_exchange: strcpy(name, "Server Key Exchange"); break; case certificate_request: strcpy(name, "Certificate Request"); break; case server_hello_done: strcpy(name, "Server Hello Done"); break; case certificate_verify: strcpy(name, "Certificate Vaerify"); break; case client_key_exchange: strcpy(name, "Client Key Exchange"); break; case finished: strcpy(name, "Finished"); break; } } /* P_hash as described in WAP WTLS section 11.3.2 */ Octstr *wtls_P_hash(Octstr * secret, Octstr * seed, int byteLength, WTLSMachine * wtls_machine) { Octstr *a; Octstr *aPrev; Octstr *aPlusSeed; Octstr *hashTemp; Octstr *hashedData; hashedData = octstr_create(""); /* start with A(1) = HMAC_hash(secret, seed) */ aPrev = octstr_duplicate(seed); do { /* A(i) */ a = wtls_hmac_hash(secret, aPrev, SHA_80); aPlusSeed = octstr_cat(a, seed); /* HMAC */ hashTemp = wtls_hmac_hash(secret, aPlusSeed, SHA_80); octstr_destroy(aPlusSeed); octstr_append(hashedData, hashTemp); octstr_destroy(hashTemp); /* Update a(i-1) */ octstr_destroy(aPrev); aPrev = a; } while (octstr_len(hashedData) < byteLength); octstr_destroy(aPrev); return (hashedData); } /* Pseudo Random Function (PRF) as described in WAP WTLS section 11.3.2 */ Octstr *wtls_calculate_prf(Octstr * secret, Octstr * label, Octstr * seed, int byteLength, WTLSMachine * wtls_machine) { Octstr *returnOctstr; Octstr *labelPlusSeed; /* Create label + seed */ labelPlusSeed = octstr_cat(label, seed); /* PRF(secret, label, seed) = P_hash(secret, label + seed) */ returnOctstr = wtls_P_hash(secret, labelPlusSeed, byteLength, wtls_machine); /* Return the first nbytes of the hashed data */ octstr_truncate(returnOctstr, byteLength); octstr_destroy(labelPlusSeed); return (returnOctstr); } /* MAC calculation */ Octstr *wtls_hmac_hash(Octstr * key, Octstr * data, int algo) { static unsigned char final_mac[1024]; unsigned char *mac, *buffer, *keyString; int bufferlen, keylen; uint mac_len = 0; Octstr *returnOctstr = NULL; buffer = (unsigned char *)octstr_get_cstr(data); bufferlen = octstr_len(data); keyString = (unsigned char *)octstr_get_cstr(key); keylen = octstr_len(key); mac = final_mac; switch (algo) { case SHA_0: /* Do nothing */ break; case SHA_40: case SHA_80: case SHA_NOLIMIT: HMAC(EVP_sha1(), keyString, keylen, buffer, bufferlen, mac, &mac_len); break; case SHA_XOR_40: error(0, "wtls_hmac_hash: SHA_XOR_40 Mac not supported"); // dunno yet *mac = '\0'; break; case MD5_40: case MD5_80: case MD5_NOLIMIT: HMAC(EVP_md5(), keyString, keylen, buffer, bufferlen, mac, &mac_len); break; } returnOctstr = octstr_create_from_data((char *)mac, mac_len); return (returnOctstr); } /* Not to be confused with octstr_hash, this applies the currently set hashing algorithm from wtls_machine to the supplied input data, returning a hashed Octstr. If it fails, it will return a NULL pointer */ Octstr *wtls_hash(Octstr * inputData, WTLSMachine * wtls_machine) { int inputDataLength; int outputDataLength; unsigned char *outputDataTemp; unsigned char *inputDataTemp; unsigned char *tempPointer = NULL; Octstr *outputData; inputDataLength = octstr_len(inputData); outputDataLength = hash_table[wtls_machine->mac_algorithm].key_size; inputDataTemp = gw_malloc(inputDataLength); outputDataTemp = gw_malloc(outputDataLength); /* Copy the contents of inputData into inputDataTemp, ready for hashing */ tempPointer = (unsigned char *)octstr_get_cstr(inputData); memcpy((void *)inputDataTemp, (void *)tempPointer, inputDataLength); /* Hash away! */ // Here's where we need to hash on the selected algorithm, not just the SHA-1 algorithm //debug("wtls", 0, "mac algo %d", wtls_machine->mac_algorithm); switch (wtls_machine->mac_algorithm) { case SHA_0: /* Do nothing */ break; case SHA_40: case SHA_80: case SHA_NOLIMIT: tempPointer = SHA1(inputDataTemp, inputDataLength, outputDataTemp); break; case SHA_XOR_40: // dunno yet break; case MD5_40: case MD5_80: case MD5_NOLIMIT: tempPointer = MD5(inputDataTemp, inputDataLength, outputDataTemp); break; } if (!tempPointer) { if (wtls_machine->mac_algorithm != SHA_0) error(0, "wtls_hash: Failed to hash input"); gw_free(outputDataTemp); gw_free(inputDataTemp); return (NULL); } /* Get our output data setup */ outputData = octstr_create_from_data((char *)outputDataTemp, outputDataLength); /* some algorithms don't use the full length of H */ octstr_truncate(outputData, hash_table[wtls_machine->mac_algorithm].mac_size); /* Delete our allocated memory */ gw_free(outputDataTemp); gw_free(inputDataTemp); /* Return the outputData */ return (outputData); } Octstr *wtls_des(Octstr * data, WTLSMachine * wtls_machine, int crypt) { Octstr *result; unsigned char *output, iv[20], c[2]; des_key_schedule des_ks; des_cblock des_key, des_iv; int i, len = octstr_len(data); if (!data) return (NULL); if (crypt == DES_ENCRYPT) { memcpy(iv, octstr_get_cstr(wtls_machine->server_write_IV), octstr_len(wtls_machine->server_write_IV)); c[0] = (wtls_machine->server_seq_num & 0xFF00) >> 8; c[1] = wtls_machine->server_seq_num & 0xFF; for (i = 0; i < bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size; i++) iv[i] = iv[i] ^ c[i % 2]; memcpy(des_iv, iv, sizeof(des_iv)); memcpy(des_key, octstr_get_cstr(wtls_machine->server_write_enc_key), sizeof(des_key)); } else { memcpy(iv, octstr_get_cstr(wtls_machine->client_write_IV), octstr_len(wtls_machine->client_write_IV)); c[0] = (wtls_machine->client_seq_num & 0xFF00) >> 8; c[1] = wtls_machine->client_seq_num & 0xFF; for (i = 0; i < bulk_table[wtls_machine->bulk_cipher_algorithm].iv_size; i++) iv[i] = iv[i] ^ c[i % 2]; memcpy(des_iv, iv, sizeof(des_iv)); memcpy(des_key, octstr_get_cstr(wtls_machine->client_write_enc_key), sizeof(des_key)); } des_set_odd_parity(&des_key); if (des_set_key_checked(&des_key, des_ks)) { error(0, "wtls_des ~> Unable to set key schedule"); return (NULL); } output = (unsigned char *)gw_malloc((len + 1) * sizeof(unsigned char)); des_ncbc_encrypt((unsigned char *)octstr_get_cstr(data), output, len, des_ks, &des_iv, crypt); result = octstr_create_from_data((char *)output, len); gw_free(output); return (result); } Octstr *wtls_rc5(Octstr * data, WTLSMachine * wtls_machine, int crypt) { Octstr *result; EVP_CIPHER_CTX ectx; unsigned char ebuf[20], *output, *input, iv[20], c[2]; int i = 0, len = octstr_len(data); if (!data) return (NULL); EVP_CipherInit(&ectx, ALG, NULL, NULL, crypt); switch (wtls_machine->bulk_cipher_algorithm) { case RC5_CBC_40: case RC5_CBC_56: i = 12; break; default: i = 16; break; } EVP_CIPHER_CTX_ctrl(&ectx, EVP_CTRL_SET_RC5_ROUNDS, i, NULL); if (crypt == RC5_ENCRYPT) { memcpy(iv, octstr_get_cstr(wtls_machine->server_write_IV), octstr_len(wtls_machine->server_write_IV)); c[0] = (wtls_machine->server_seq_num & 0xFF00) >> 8; c[1] = wtls_machine->server_seq_num & 0xFF; for (i = 0; i < bulk_table[wtls_machine->bulk_cipher_algorithm]. iv_size; i++) iv[i] = iv[i] ^ c[i % 2]; EVP_CipherInit(&ectx, NULL, (unsigned char *)octstr_get_cstr( wtls_machine->server_write_enc_key), iv, RC5_ENCRYPT); } else { memcpy(iv, octstr_get_cstr(wtls_machine->client_write_IV), octstr_len(wtls_machine->client_write_IV)); c[0] = (wtls_machine->client_seq_num & 0xFF00) >> 8; c[1] = wtls_machine->client_seq_num & 0xFF; for (i = 0; i < bulk_table[wtls_machine->bulk_cipher_algorithm]. iv_size; i++) iv[i] = iv[i] ^ c[i % 2]; EVP_CipherInit(&ectx, NULL, (unsigned char *)octstr_get_cstr( wtls_machine->client_write_enc_key), iv, RC5_DECRYPT); } output = gw_malloc(len + 1); input = (unsigned char *)octstr_get_cstr(data); i = 0; for (i = 0; i <= len - 8; i += 8) { EVP_Cipher(&ectx, ebuf, input + i, 8); memmove(output + i, ebuf, 8); } // Leftovers... if (i < len) { EVP_Cipher(&ectx, ebuf, input + i, len - i); memmove(output + i, ebuf, len - i); } result = octstr_create_from_data((char *)output, len); gw_free(output); return (result); } static Octstr *wtls_decrypt_rsa(Octstr * encryptedData) { int numBytesWritten = 0, numBytesToRead = 0; Octstr *decryptedData = NULL; unsigned char *tempDecryptionBuffer = NULL, *tempEncryptionPointer = NULL; /* Allocate some memory for our decryption buffer */ tempDecryptionBuffer = gw_malloc(RSA_size(private_key)); /* Calculate the number of bytes to read from encryptedData * when decrypting * */ numBytesToRead = octstr_len(encryptedData); /* Don't write to this pointer. Ever ever ever. */ tempEncryptionPointer = (unsigned char *)octstr_get_cstr(encryptedData); /* Decrypt the data in encryptedData */ debug("wtls", 0, "RSA_private_decrypt: Private_key: 0x%p", private_key); numBytesWritten = RSA_private_decrypt(numBytesToRead, tempEncryptionPointer, tempDecryptionBuffer, private_key, RSA_PKCS1_PADDING); if (numBytesWritten == -1) { tempEncryptionPointer += 2; numBytesToRead -= 2; numBytesWritten = RSA_private_decrypt(numBytesToRead, tempEncryptionPointer, tempDecryptionBuffer, private_key, RSA_PKCS1_PADDING); } if (numBytesWritten > 0) { /* Move the tempDecryptionBuffer to an Octstr */ decryptedData = octstr_create_from_data((char *)tempDecryptionBuffer, numBytesWritten); debug("wtls", 0, "Client's secret decrypted succesfully"); } /* Deallocate the tempDecryptionBuffer */ gw_free(tempDecryptionBuffer); /* Return the decrypted data */ return decryptedData; } Octstr *wtls_decrypt_key(int type, Octstr * encryptedData) { switch (type) { case rsa_anon: case rsa: return (wtls_decrypt_rsa(encryptedData)); break; default: break; } return (NULL); } void wtls_decrypt_pdu_list(WTLSMachine * wtls_machine, List * pdu_list) { int i, listlen; Octstr *decryptedData = NULL; wtls_Payload *payload; listlen = gwlist_len(pdu_list); for (i = 0; i < listlen; i++) { payload = (wtls_Payload *) gwlist_get(pdu_list, i); wtls_machine->client_seq_num++; if (payload->cipher) { debug("wtls", 0, "Decrypting PDU %d", i); if ((decryptedData = wtls_decrypt(payload, wtls_machine))) { /* replace the data */ octstr_destroy(payload->data); /* get rid of MAC leftovers and wtls headers */ payload->data = decryptedData; } else { gwlist_delete(pdu_list, i, 1); wtls_payload_destroy(payload); payload = NULL; i--; listlen--; } } else debug("wtls", 0, "PDU %d is not encrypted.", i); if (payload && octstr_get_char(payload->data, 0) == '\1') wtls_machine->client_seq_num = -1; // Change Cipher debug("wtls", 0, "Received Incoming Payload:"); wtls_payload_dump(payload, 1); } } RSAPublicKey *wtls_get_rsapublickey(void) { RSA *rsaStructure = NULL; EVP_PKEY *publicKey = NULL; BIGNUM *modulus = 0, *exponent = NULL; unsigned char *tempModulusStorage = 0, *tempExponentStorage = NULL; int numbytes = 0; RSAPublicKey *returnStructure = NULL; Octstr *Modulus = NULL, *Exponent = NULL; /* First, we need to extract the RSA structure from the X509 Cert */ /* Get the EVP_PKEY structure from the X509 cert */ publicKey = X509_PUBKEY_get(x509_cert->cert_info->key); /* Take said EVP_PKEY structure and get the RSA component */ if (EVP_PKEY_type(publicKey->type) != EVP_PKEY_RSA) { return NULL; } else { rsaStructure = publicKey->pkey.rsa; } /* Then we need to grab the exponent component from the cert */ exponent = rsaStructure->e; /* We need to allocate sufficient memory to hold the exponent */ numbytes = BN_num_bytes(exponent); tempExponentStorage = gw_malloc(numbytes); /* Then we get the exponent */ numbytes = BN_bn2bin(exponent, tempExponentStorage); /* And finally we convert the exponent to an Octstr */ Exponent = octstr_create_from_data((char *)tempExponentStorage, numbytes); /* Then we need to grab the modulus component from the cert */ modulus = rsaStructure->n; /* We need to allocate sufficient memory to hold the modulus */ numbytes = BN_num_bytes(modulus); tempModulusStorage = gw_malloc(numbytes); /* Then we get the modulus */ numbytes = BN_bn2bin(modulus, tempModulusStorage); /* And finally we convert the modulus to an Octstr */ Modulus = octstr_create_from_data((char *)tempModulusStorage, numbytes); /* Put the components into our return structure */ returnStructure = gw_malloc(sizeof(RSAPublicKey)); returnStructure->rsa_exponent = Exponent; returnStructure->rsa_modulus = Modulus; /* And deallocate the memory allocated for holding the modulus */ gw_free(tempModulusStorage); gw_free(tempExponentStorage); return (returnStructure); } Octstr *wtls_get_certificate(void) { unsigned char **pp; unsigned char *ppStart; int amountWritten = 1260; Octstr *returnOctstr; debug("wtls_get_certificate", 0, "x509_cert : 0x%p", x509_cert); /* Convert the x509 certificate to DER-encoding */ amountWritten = i2d_X509(x509_cert, NULL); debug("wtls_get_certificate", 0, "amountWritten : %d", amountWritten); /* Allocate some memory for *pp */ pp = (unsigned char **)gw_malloc(sizeof(unsigned char **)); /* Allocate the memory and call the same function again?!!? What an original idea :-/ */ ppStart = (unsigned char *)gw_malloc(sizeof(unsigned char) * amountWritten); debug("wtls_get_certificate", 0, "x509_cert_DER_pre : 0x%p", *pp); *pp = ppStart; amountWritten = i2d_X509(x509_cert, pp); /* And we do this, because otherwise *pp is pointing to the end of the buffer. Yay */ *pp = ppStart; debug("wtls_get_certificate", 0, "x509_cert_DER_post : 0x%p", *pp); /* Convert the DER-encoded char string to an octstr */ returnOctstr = octstr_create_from_data((char *)*pp, amountWritten); /* Destroy the memory allocated temporarily above */ gw_free(*pp); /* Destroy the memory allocated for pp as well */ gw_free(pp); /* Return the octstr */ return returnOctstr; } /* Chooses a CipherSuite from the list provided by the client. Returns NULL if none is acceptable. */ CipherSuite *wtls_choose_ciphersuite(List * ciphersuites) { CipherSuite *currentCS; int i = 0, listLen; listLen = gwlist_len(ciphersuites); /* the first CS in the list */ for (; i < listLen; i++) { /* the next CS in the list */ currentCS = gwlist_get(ciphersuites, i); /* Check if we support this BulkCipher */ if (currentCS->bulk_cipher_algo == DES_CBC || (currentCS->bulk_cipher_algo <= RC5_CBC && currentCS->bulk_cipher_algo >= RC5_CBC_40)) /* if(currentCS->bulk_cipher_algo >= NULL_bulk && currentCS->bulk_cipher_algo <= IDEA_CBC) */ { /* Check if we support this MAC algsorithm */ if (currentCS->mac_algo >= SHA_0 && currentCS->mac_algo <= MD5_NOLIMIT) { char cipher[20], mac[15]; /* We can use this CipherSuite then */ cipherName(cipher, currentCS->bulk_cipher_algo); macName(mac, currentCS->mac_algo); debug("wtls", 0, "wtls_choose_ciphersuite ~> Accepted cipher: %s, mac: %s (#%d/%d)", cipher, mac, i + 1, listLen); break; } } } if (i < listLen) return (currentCS); else return (NULL); } int isSupportedKeyEx(int keyExId) { int maxSupported; int i = 0, retCode = 0; maxSupported = sizeof(supportedKeyExSuite) / sizeof(KeyExchangeSuite); for (; i < maxSupported; i++) { if (keyExId == supportedKeyExSuite[i]) { retCode = 1; break; } } return retCode; } int wtls_choose_clientkeyid(List * clientKeyIds, int *algo) { int returnKey = 0; KeyExchangeId *currentKeyId = NULL; int i = 0, listLen; listLen = gwlist_len(clientKeyIds); for (; i < listLen; i++) { currentKeyId = gwlist_get(clientKeyIds, i); /* check if the current key suite is supported */ if (isSupportedKeyEx(currentKeyId->key_exchange_suite)) { char key[20]; *algo = currentKeyId->key_exchange_suite; returnKey = i + 1; keyName(key, *algo); debug("wtls", 0, "wtls_choose_clientkeyid ~> Accepted key algorithm: %s (#%d/%d)", key, returnKey, listLen); dump_key_exchange_id("wtls", 0, currentKeyId); break; } } return returnKey; } int wtls_choose_snmode(int snmode) { return 2; } Random *wtls_get_random(void) { Random *randomData; unsigned char bytes[13], *p; struct timeval tp; randomData = gw_malloc(sizeof(Random)); gettimeofday(&tp, NULL); randomData->gmt_unix_time = tp.tv_sec; p = bytes; while (p - bytes < 12) { while (!(*p = rand_r((uint *) & tp.tv_usec))) ; p++; } bytes[12] = '\0'; randomData->random_bytes = octstr_create((char *)bytes); return (randomData); } int clienthellos_are_identical(List * pdu_list, List * last_received_packet) { return 0; } int certifcateverifys_are_identical(List * pdu_list, List * last_received_packet) { return 0; } int certificates_are_identical(List * pdu_list, List * last_received_packet) { return 0; } int clientkeyexchanges_are_identical(List * pdu_list, List * last_received_packet) { return 0; } int changecipherspecs_are_identical(List * pdu_list, List * last_received_packet) { return 0; } int finishes_are_indentical(List * pdu_list, List * last_received_packet) { return 0; } int packet_contains_changecipherspec(List * pdu_list) { return 0; } int packet_contains_finished(List * pdu_list) { return 0; } int packet_contains_optional_stuff(List * pdu_list) { return 0; } int packet_is_application_data(List * pdu_list) { int i, len = gwlist_len(pdu_list); wtls_Payload *tempPayload; for (i = 0; i < len; i++) { tempPayload = gwlist_get(pdu_list, i); if (tempPayload->type != Application_PDU) return (0); } return 1; } int packet_contains_userdata(List * pdu_list) { return 1; } int packet_contains_clienthello(List * pdu_list) { int i, len = gwlist_len(pdu_list); wtls_Payload *tempPayload; for (i = 0; i < len; i++) { tempPayload = gwlist_get(pdu_list, i); if (tempPayload->type == Handshake_PDU) { if (octstr_get_char(tempPayload->data, 0) == client_hello) return (1); } } return (0); } int is_critical_alert(List * pdu_list, WTLSMachine * wtls_machine) { int i, listlen; wtls_Payload *payload; listlen = gwlist_len(pdu_list); for (i = 0; i < listlen; i++) { payload = gwlist_get(pdu_list, i); if (payload->type == Alert_PDU && octstr_get_char(payload->data, 0) >= critical_alert) { char alert[40]; alertName(alert, octstr_get_char(payload->data, 1)); error(0, "Received critical alert (%s) in %s. Aborting", alert, stateName(wtls_machine->state)); return (1); } } return 0; } int is_warning_alert(List * pdu_list, WTLSMachine * wtls_machine) { int i, listlen; wtls_Payload *payload; listlen = gwlist_len(pdu_list); for (i = 0; i < listlen; i++) { payload = gwlist_get(pdu_list, i); if (payload->type == Alert_PDU && octstr_get_char(payload->data, 0) == warning_alert) { char alert[40]; alertName(alert, octstr_get_char(payload->data, 1)); warning(0, "Received warning (%s) in %s.", alert, stateName(wtls_machine->state)); return (1); } } return 0; } /* go through the list of wtls_Payloads and add the data of any handshake message to wtls_machine->handshake_data */ void add_all_handshake_data(WTLSMachine * wtls_machine, List * pdu_list) { long i, listlen; wtls_Payload *payload; gw_assert(pdu_list != NULL); listlen = gwlist_len(pdu_list); debug("wtls", 0, "adding handshake data from %ld PDU(s)", listlen); for (i = 0; i < listlen; i++) { payload = (wtls_Payload *) gwlist_get(pdu_list, i); if (payload->type == Handshake_PDU) { octstr_insert(wtls_machine->handshake_data, payload->data, octstr_len(wtls_machine->handshake_data)); debug("wtls", 0, "Data from PDU %ld:", i); octstr_dump(payload->data, 2); } } } void calculate_server_key_block(WTLSMachine * wtls_machine) { Octstr *concatenatedRandoms = NULL; Octstr *labelMaster = NULL; Octstr *key_block; int seqNum, refresh; refresh = 1 << wtls_machine->key_refresh; /* Concatenate our random data */ concatenatedRandoms = octstr_create(""); seqNum = wtls_machine->server_seq_num; seqNum -= wtls_machine->server_seq_num % refresh; pack_int16(concatenatedRandoms, 0, seqNum); octstr_append(concatenatedRandoms, wtls_machine->server_random); octstr_append(concatenatedRandoms, wtls_machine->client_random); /* Calculate the key_block */ labelMaster = octstr_create("server expansion"); key_block = wtls_calculate_prf(wtls_machine->master_secret, labelMaster, concatenatedRandoms, hash_table[wtls_machine->mac_algorithm]. key_size + bulk_table[wtls_machine-> bulk_cipher_algorithm]. key_material + bulk_table[wtls_machine-> bulk_cipher_algorithm]. iv_size, wtls_machine); octstr_destroy(labelMaster); octstr_destroy(concatenatedRandoms); labelMaster = NULL; /* Break the key_block in its 3 parts */ wtls_machine->server_write_MAC_secret = octstr_copy(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size); octstr_delete(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size); wtls_machine->server_write_enc_key = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm]. key_material); octstr_delete(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm]. key_material); wtls_machine->server_write_IV = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm]. iv_size); octstr_destroy(key_block); /* Additional calculations for exportable encryption algos */ if (bulk_table[wtls_machine->bulk_cipher_algorithm].is_exportable == EXPORTABLE) { Octstr *final_server_write_enc_key = NULL; Octstr *final_server_write_IV = NULL; Octstr *emptySecret = NULL; concatenatedRandoms = octstr_cat(wtls_machine->client_random, wtls_machine->server_random); labelMaster = octstr_create("server write key"); final_server_write_enc_key = wtls_calculate_prf(wtls_machine->server_write_enc_key, labelMaster, concatenatedRandoms, bulk_table[wtls_machine-> bulk_cipher_algorithm]. expanded_key_material, wtls_machine); octstr_destroy(labelMaster); octstr_destroy(wtls_machine->server_write_enc_key); wtls_machine->server_write_enc_key = final_server_write_enc_key; final_server_write_enc_key = NULL; concatenatedRandoms = octstr_create(""); pack_int16(concatenatedRandoms, 0, seqNum); octstr_append(concatenatedRandoms, wtls_machine->client_random); octstr_append(concatenatedRandoms, wtls_machine->server_random); labelMaster = octstr_create("server write IV"); emptySecret = octstr_create(""); final_server_write_IV = wtls_calculate_prf(emptySecret, labelMaster, concatenatedRandoms, bulk_table[wtls_machine-> bulk_cipher_algorithm]. iv_size, wtls_machine); octstr_destroy(wtls_machine->server_write_IV); wtls_machine->server_write_IV = final_server_write_IV; octstr_destroy(emptySecret); octstr_destroy(labelMaster); octstr_destroy(concatenatedRandoms); } } void calculate_client_key_block(WTLSMachine * wtls_machine) { Octstr *concatenatedRandoms = NULL; Octstr *key_block; Octstr *labelMaster = NULL; int seqNum, refresh; refresh = 1 << wtls_machine->key_refresh; /* Concatenate our random data */ concatenatedRandoms = octstr_create(""); seqNum = wtls_machine->client_seq_num; seqNum -= wtls_machine->client_seq_num % refresh; wtls_machine->last_refresh = seqNum; pack_int16(concatenatedRandoms, 0, seqNum); octstr_append(concatenatedRandoms, wtls_machine->server_random); octstr_append(concatenatedRandoms, wtls_machine->client_random); /* Calculate the key_block */ labelMaster = octstr_create("client expansion"); key_block = wtls_calculate_prf(wtls_machine->master_secret, labelMaster, concatenatedRandoms, hash_table[wtls_machine->mac_algorithm]. key_size + bulk_table [wtls_machine->bulk_cipher_algorithm]. key_material + bulk_table[wtls_machine-> bulk_cipher_algorithm]. iv_size, wtls_machine); octstr_destroy(labelMaster); octstr_destroy(concatenatedRandoms); labelMaster = NULL; /* Break the key_block in its 3 parts */ wtls_machine->client_write_MAC_secret = octstr_copy(key_block, 0, hash_table [wtls_machine-> mac_algorithm]. key_size); octstr_delete(key_block, 0, hash_table[wtls_machine->mac_algorithm].key_size); wtls_machine->client_write_enc_key = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm]. key_material); octstr_delete(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm]. key_material); wtls_machine->client_write_IV = octstr_copy(key_block, 0, bulk_table[wtls_machine->bulk_cipher_algorithm]. iv_size); octstr_destroy(key_block); /* Additional calculations for exportable encryption algos */ if (bulk_table[wtls_machine->bulk_cipher_algorithm].is_exportable == EXPORTABLE) { Octstr *final_client_write_enc_key = NULL; Octstr *final_client_write_IV = NULL; Octstr *emptySecret = NULL; concatenatedRandoms = octstr_cat(wtls_machine->client_random, wtls_machine->server_random); labelMaster = octstr_create("client write key"); final_client_write_enc_key = wtls_calculate_prf(wtls_machine->client_write_enc_key, labelMaster, concatenatedRandoms, bulk_table [wtls_machine->bulk_cipher_algorithm]. expanded_key_material, wtls_machine); octstr_destroy(wtls_machine->client_write_enc_key); octstr_destroy(labelMaster); wtls_machine->client_write_enc_key = final_client_write_enc_key; final_client_write_enc_key = NULL; octstr_destroy(concatenatedRandoms); concatenatedRandoms = octstr_create(""); pack_int16(concatenatedRandoms, 0, seqNum); octstr_append(concatenatedRandoms, wtls_machine->client_random); octstr_append(concatenatedRandoms, wtls_machine->server_random); labelMaster = octstr_create("client write IV"); emptySecret = octstr_create(""); final_client_write_IV = wtls_calculate_prf(emptySecret, labelMaster, concatenatedRandoms, bulk_table [wtls_machine->bulk_cipher_algorithm]. iv_size, wtls_machine); octstr_destroy(wtls_machine->client_write_IV); wtls_machine->client_write_IV = final_client_write_IV; final_client_write_IV = NULL; octstr_destroy(emptySecret); octstr_destroy(labelMaster); octstr_destroy(concatenatedRandoms); } } #endif /* HAVE_WTLS_OPENSSL */ gateway-1.4.5/wap/wsp_push_client.c0000644000175000017500000003357713227613126016047 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_push_client.c: Client WSP Push implementation, for testing purposes * * Aarno Syvänen for Wapit Ltd */ #include "wsp_push_client.h" #include "wsp.h" #include "wtp.h" #include "wsp_pdu.h" #include "wsp_headers.h" #include "wap.h" /************************************************************************** * * Internal data structures: * * List of client WSP push machines. */ static List *push_client_machines = NULL; /* * Counter for client push machine id numbers, to make sure that they are * unique. */ static Counter *push_client_machine_id_counter = NULL; /* * Give the status of push client: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum {limbo, running, terminating } push_client_run_status = limbo; /* * Queue of events to be handled by the push client. */ static List *push_client_queue = NULL; wap_dispatch_func_t *dispatch_to_self; wap_dispatch_func_t *dispatch_to_wtp_resp; /***************************************************************************** * * Prototypes of internal functions: * * Create and destroy an uniniatilised push client state machine. */ static WSPPushClientMachine *push_client_machine_create(long cpid); static void push_client_machine_destroy(void *a); /* * Checks whether the client push machines list includes a specific machine. * Creates it, if the event is TR-Invoke.ind */ static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e); /* * Feed an event to the client push state machine. Do not report errors to * caller. */ static void push_client_event_handle(WSPPushClientMachine *cpm, WAPEvent *e); /* * Print WSP client push machine state as a string. */ static unsigned char *name_push_client_state(int name); static void main_thread(void *); static WAPEvent *indicate_confirmedpush(WSPPushClientMachine *cpm, Octstr *push_body); static WAPEvent *indicate_pushabort(WSPPushClientMachine *cpm, long abort_reason); static WAPEvent *response_confirmedpush(WSPPushClientMachine *cpm); static WAPEvent *send_abort_to_responder(WSPPushClientMachine *cpm, long reason); static WAPEvent *response_responder_invoke(WSPPushClientMachine *cpm); /************************************************************************** * * EXTERNAL FUNCTIONS: * */ void wsp_push_client_init(wap_dispatch_func_t *dispatch_self, wap_dispatch_func_t *dispatch_wtp_resp) { push_client_machines = gwlist_create(); push_client_machine_id_counter = counter_create(); push_client_queue = gwlist_create(); gwlist_add_producer(push_client_queue); dispatch_to_self = dispatch_self; dispatch_to_wtp_resp = dispatch_wtp_resp; gw_assert(push_client_run_status == limbo); push_client_run_status = running; gwthread_create(main_thread, NULL); } void wsp_push_client_shutdown(void) { gw_assert(push_client_run_status == running); push_client_run_status = terminating; gwlist_remove_producer(push_client_queue); gwthread_join_every(main_thread); debug("wap.wsp", 0, "wsp_push_client_shutdown: %ld push client machines" "left", gwlist_len(push_client_machines)); gwlist_destroy(push_client_machines, push_client_machine_destroy); gwlist_destroy(push_client_queue, wap_event_destroy_item); counter_destroy(push_client_machine_id_counter); } void wsp_push_client_dispatch_event(WAPEvent *e) { gwlist_produce(push_client_queue, e); } /*************************************************************************** * * INTERNAL FUNCTIONS: * */ static void main_thread(void *arg) { WSPPushClientMachine *cpm; WAPEvent *e; while (push_client_run_status == running && (e = gwlist_consume(push_client_queue)) != NULL) { cpm = push_client_machine_find_or_create(e); if (cpm == NULL) wap_event_destroy(e); else push_client_event_handle(cpm, e); } } /* * Give the name of a push client machine state in a readable form */ static unsigned char *name_push_client_state(int n) { switch (n) { #define PUSH_CLIENT_STATE_NAME(state) case state : return (unsigned char *)#state; #define ROW(state, event, condition, action, new_state) #include "wsp_push_client_states.def" default: return (unsigned char *)"unknown state"; } } /* * Feed an event to a WSP push client state machine. Do not report errors to * the caller. */ static void push_client_event_handle(WSPPushClientMachine *cpm, WAPEvent *e) { WAPEvent *wtp_event; WSP_PDU *pdu = NULL; wap_event_assert(e); gw_assert(cpm); if (e->type == TR_Invoke_Ind) { pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data); /* * Class 1 tests here * Case 4, no session matching address quadruplet, handled by the session mach- * ine. * Tests from table WSP, page 45. Case 5, a PDU state tables cannot handle. */ if (pdu == NULL || pdu->type != ConfirmedPush) { wap_event_destroy(e); wtp_event = send_abort_to_responder(cpm, PROTOERR); wtp_resp_dispatch_event(wtp_event); return; } } debug("wap.wsp", 0, "WSP_PUSH: WSPPushClientMachine %ld, state %s," " event %s", cpm->client_push_id, name_push_client_state(cpm->state), wap_event_name(e->type)); #define PUSH_CLIENT_STATE_NAME(state) #define ROW(push_state, event_type, condition, action, next_state) \ if (cpm->state == push_state && \ e->type == event_type && \ (condition)) { \ action \ cpm->state = next_state; \ debug("wap.wsp", 0, "WSP_PUSH %ld: new state %s", \ cpm->client_push_id, #next_state); \ } else #include "wsp_push_client_states.def" { error(0, "WSP_PUSH: handle_event: unhandled event!"); debug("wap.wsp", 0, "Unhandled event was:"); wap_event_dump(e); wap_event_destroy(e); return; } wsp_pdu_destroy(pdu); wap_event_destroy(e); if (cpm->state == PUSH_CLIENT_NULL_STATE) push_client_machine_destroy(cpm); } static int push_client_machine_has_transid(void *a, void *b) { long transid; WSPPushClientMachine *m; m = a; transid = *(long *)b; return m->transaction_id == transid; } static WSPPushClientMachine *push_client_machine_find_using_transid( long transid) { WSPPushClientMachine *m; m = gwlist_search(push_client_machines, &transid, push_client_machine_has_transid); return m; } /* * Checks client push machines list for a specific machine. Creates it, if the * event is TR-Invoke.ind. * Client push machine is identified (when searching) by transcation identifi- * er. * Note that only WTP responder send its class 1 messages to client push state * machine. So, it is no need to specify WTP machine type. */ static WSPPushClientMachine *push_client_machine_find_or_create(WAPEvent *e) { WSPPushClientMachine *cpm; long transid; cpm = NULL; transid = -1; switch (e->type) { case TR_Invoke_Ind: transid = e->u.TR_Invoke_Ind.handle; break; case S_ConfirmedPush_Res: transid = e->u.S_ConfirmedPush_Res.client_push_id; break; case S_PushAbort_Req: transid = e->u.S_PushAbort_Req.push_id; break; case Abort_Event: break; case TR_Abort_Ind: transid = e->u.TR_Abort_Ind.handle; break; default: debug("wap.wsp", 0, "WSP PUSH: push_client_find_or_create: unhandled" " event"); wap_event_dump(e); wap_event_destroy(e); return NULL; } gw_assert(transid != -1); cpm = push_client_machine_find_using_transid(transid); if (cpm == NULL) { switch (e->type) { case TR_Invoke_Ind: cpm = push_client_machine_create(transid); break; case S_ConfirmedPush_Res: case S_PushAbort_Req: error(0, "WSP_PUSH_CLIENT: POT primitive to a nonexisting" " push client machine"); break; case Abort_Event: error(0, "WSP_PUSH_CLIENT: internal abort to a nonexisting" " push client machine"); break; case TR_Abort_Ind: error(0, "WSP_PUSH_CLIENT: WTP abort to a nonexisting push client" " machine"); break; default: error(0, "WSP_PUSH_CLIENT: Cannot handle event type %s", wap_event_name(e->type)); break; } } return cpm; } static WSPPushClientMachine *push_client_machine_create(long transid) { WSPPushClientMachine *m; m = gw_malloc(sizeof(WSPPushClientMachine)); debug("wap.wsp", 0, "WSP_PUSH_CLIENT: Created WSPPushClientMachine %p", (void *) m); #define INTEGER(name) m->name = 0; #define HTTPHEADERS(name) m->name = NULL; #define MACHINE(fields) fields #include "wsp_push_client_machine.def" m->state = PUSH_CLIENT_NULL_STATE; m->transaction_id = transid; m->client_push_id = counter_increase(push_client_machine_id_counter); gwlist_append(push_client_machines, m); return m; } static void push_client_machine_destroy(void *a) { WSPPushClientMachine *m; m = a; debug("wap.wsp", 0, "Destroying WSPPushClientMachine %p", (void *) m); gwlist_delete_equal(push_client_machines, m); #define INTEGER(name) m->name = 0; #define HTTPHEADERS(name) http_destroy_headers(m->name); #define MACHINE(fields) fields; #include "wsp_push_client_machine.def" gw_free(m); } static WAPEvent *indicate_confirmedpush(WSPPushClientMachine *cpm, Octstr *push_body) { WAPEvent *e; e = wap_event_create(S_ConfirmedPush_Ind); e->u.S_ConfirmedPush_Ind.client_push_id = cpm->client_push_id; e->u.S_ConfirmedPush_Ind.push_headers = http_header_duplicate(cpm->push_headers); e->u.S_ConfirmedPush_Ind.push_body = octstr_duplicate(push_body); return e; } static WAPEvent *indicate_pushabort(WSPPushClientMachine *cpm, long abort_reason) { WAPEvent *e; e = wap_event_create(S_PushAbort_Ind); e->u.S_PushAbort_Ind.push_id = cpm->client_push_id; e->u.S_PushAbort_Ind.reason = abort_reason; return e; } /* * For debugging: create S-ConfirmedPush.res by ourselves. */ static WAPEvent *response_confirmedpush(WSPPushClientMachine *cpm) { WAPEvent *e; e = wap_event_create(S_ConfirmedPush_Res); e->u.S_ConfirmedPush_Res.client_push_id = cpm->client_push_id; return e; } static WAPEvent *send_abort_to_responder(WSPPushClientMachine *cpm, long reason) { WAPEvent *e; e = wap_event_create(TR_Abort_Req); e->u.TR_Abort_Req.abort_type = USER; e->u.TR_Abort_Req.abort_reason = reason; e->u.TR_Abort_Req.handle = cpm->client_push_id; return e; } static WAPEvent *response_responder_invoke(WSPPushClientMachine *cpm) { WAPEvent *e; e = wap_event_create(TR_Invoke_Res); e->u.TR_Invoke_Res.handle = cpm->transaction_id; return e; } gateway-1.4.5/wap/wtls_pdu.h0000644000175000017500000002600213227613126014470 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wtls_pdu.h - definitions for unpacked WTLS protocol data units * * Nikos Balkanas, Inaccess Networks (2009) */ #ifndef PDU_H #define PDU_H #include "gwlib/list.h" #include "gwlib/octstr.h" #include "wtls.h" typedef enum wtls_pdu_modes { ChangeCipher_PDU = 1, Alert_PDU, Handshake_PDU, Application_PDU } wtls_pdu_modes; typedef enum handshake_type { hello_request = 0, client_hello = 1, server_hello = 2, certificate = 11, server_key_exchange = 12, certificate_request = 13, server_hello_done = 14, certificate_verify = 15, client_key_exchange = 16, finished = 20 } HandshakeType; typedef enum compmethod { null_comp = 0 } CompressionMethod; typedef enum certificateformat { WTLSCert = 1, X509Cert, X968Cert } CertificateFormat; typedef enum sig_algo { anonymous, ecdsa_sha, rsa_sha, } SignatureAlgorithm; typedef enum keyex_suite { null_k, shared_secret, dh_anon, dh_anon_512, dh_anon_768, rsa_anon, rsa_anon_512, rsa_anon_768, rsa, rsa_512, rsa_768, ecdh_anon, ecdh_anon_113, ecdh_anon_131, ecdh_ecdsa, } KeyExchangeSuite; typedef enum pubkey_algo { rsa_pubkey, diffie_hellman_pubkey, elliptic_curve_pubkey, } PublicKeyAlgorithm; typedef enum identifier_type { null = 0, text, binary, key_hash_sha = 254, x509_name = 255 } IdentifierType; typedef enum public_key_type { rsa_key = 2, ecdh_key = 3, ecdsa_key = 4 } PublicKeyType; typedef enum ecbasistype { ec_basis_onb = 1, ec_basis_trinomial, ec_basis_pentanomial, ec_basis_polynomial } ECBasisType; typedef enum ecfield { ec_prime_p, ec_characteristic_two } ECField; typedef struct random { long gmt_unix_time; Octstr *random_bytes; } Random; typedef struct ecpoint { Octstr *point; } ECPoint; typedef ECPoint ECPublicKey; typedef struct dhpublickey { Octstr *dh_Y; } DHPublicKey; typedef struct rsa_public_key { Octstr *rsa_exponent; Octstr *rsa_modulus; } RSAPublicKey; typedef struct public_key { /* ecdh */ ECPublicKey *ecdh_pubkey; /* ecdsa */ ECPublicKey *ecdsa_pubkey; /* rsa */ RSAPublicKey *rsa_pubkey; } PublicKey; typedef struct identifier { IdentifierType id_type; /* text */ int charset; Octstr *name; /* binary */ Octstr *identifier; /* key_hash_sha */ Octstr *key_hash; /* x509 */ Octstr *distinguished_name; } Identifier; typedef struct eccurve { Octstr *a; Octstr *b; Octstr *seed; } ECCurve; typedef struct dh_parameters { int dh_e; Octstr *dh_p; Octstr *dh_g; } DHParameters; typedef struct ec_parameters { ECField field; /* case ec_prime_p */ Octstr *prime_p; /* case ec_characteristic_two */ int m; ECBasisType basis; /* case ec_basis_onb : nothing */ /* case ec_trinomial */ int k; /* case ec_pentanomial */ int k1; int k2; int k3; /* case ec_basis_polynomial */ Octstr *irreducible; ECCurve *curve; ECPoint *base; Octstr *order; Octstr *cofactor; } ECParameters; typedef struct parameter_set { long length; /* rsa: empty */ /* diffie-hellman */ DHParameters *dhparams; /* eliptic curve */ ECParameters *ecparams; } ParameterSet; typedef struct parameter_specifier { int param_index; ParameterSet *param_set; } ParameterSpecifier; typedef struct key_exchange_id { int key_exchange_suite; ParameterSpecifier *param_specif; Identifier *identifier; } KeyExchangeId; typedef struct signature { /* case anonymous */ /* nothing */ /* case ecdsa_sha and rsa_sha */ List *sha_hash; } Signature; typedef struct to_be_signed_cert { int certificate_version; SignatureAlgorithm signature_algo; Identifier *issuer; long valid_not_before; long valid_not_after; Identifier *subject; PublicKeyType pubkey_type; ParameterSpecifier *param_spec; PublicKey *pubkey; } ToBeSignedCertificate; typedef struct wtls_cert { ToBeSignedCertificate *tobesigned_cert; Signature *signature; } WTLSCertificate; typedef struct rsa_secret { int client_version; List *random; } RSASecret; typedef struct rsa_encrypted_secret { Octstr *encrypted_secret; } RSAEncryptedSecret; typedef struct cipher_suite { int bulk_cipher_algo; int mac_algo; } CipherSuite; typedef struct cert_request { List *trusted_authorities; // List of KeyExchangeIds } CertificateRequest; typedef struct cert_verify { Signature *signature; } CertificateVerify; typedef struct hello_request { int dummy; /* nothing here */ } HelloRequest; typedef struct client_hello { int clientversion; Random *random; Octstr *session_id; List *client_key_ids; List *trusted_key_ids; List *ciphersuites; // list of CipherSuites List *comp_methods; int snmode; int krefresh; } ClientHello; typedef struct server_hello { int serverversion; Random *random; Octstr *session_id; int client_key_id; CipherSuite *ciphersuite; CompressionMethod comp_method; int snmode; int krefresh; } ServerHello; typedef struct certificate { CertificateFormat certificateformat; /* case WTLS */ WTLSCertificate *wtls_certificate; /* case X509 */ Octstr *x509_certificate; /* X968 */ Octstr *x968_certificate; } Certificate; typedef struct server_key_exchange { ParameterSpecifier *param_spec; /* case rsa_anon */ RSAPublicKey *rsa_params; /* case dh_anon */ DHPublicKey *dh_params; /* case ecdh_anon */ ECPublicKey *ecdh_params; } ServerKeyExchange; typedef struct client_key_exchange { /* case rsa and rsa_anon */ RSAEncryptedSecret *rsa_params; /* case dh_anon */ DHPublicKey *dh_anon_params; /* case ecdh_anon and ecdh_ecdsa */ ECPublicKey *ecdh_params; } ClientKeyExchange; typedef struct finished { Octstr *verify_data; } Finished; typedef struct server_hello_done { int dummy; /* nothing here */ } ServerHelloDone; typedef struct cc { int change; } ChangeCipher; typedef enum { warning_alert = 1, critical_alert, fatal_alert } AlertLevel; typedef enum { connection_close_notify = 0, session_close_notify, no_connection = 5, unexpected_message = 10, time_required, bad_record_mac = 20, decryption_failed, record_overflow, decompression_failure = 30, handshake_failure = 40, bad_certificate = 42, unsupported_certificate, certificate_revoked, certificate_expired, certificate_unknown, illegal_parameter, unknown_ca, access_denied, decode_error, decrypt_error, unknown_key_id, disabled_key_id, key_exchange_disabled, session_not_ready, unknown_parameter_index, duplicate_finished_received, export_restriction = 60, protocol_version = 70, insufficient_security, internal_error = 80, user_canceled = 90, no_renegotiation = 100 } AlertDescription; typedef struct alert { int level; AlertDescription desc; Octstr *chksum; } Alert; typedef struct certificates { List *certList; } Certificates; typedef struct handshake { HandshakeType msg_type; int length; /* case hello_request */ /* case client_hello */ ClientHello *client_hello; /* case server_hello */ ServerHello *server_hello; /* case certificate */ Certificates *certificates; /* case server_key_exchange */ ServerKeyExchange *server_key_exchange; /* case certificate_request */ CertificateRequest *certificate_request; /* case server_hello_done */ ServerHelloDone *server_hello_done; /* case certificate_verify */ CertificateVerify *cert_verify; /* case client_key_exchange */ ClientKeyExchange *client_key_exchange; /* case finished */ Finished *finished; } Handshake; typedef struct application { Octstr *data; } Application; typedef struct wtls_pdu { int type; int reserved; int cipher; int snMode; int seqNum; int rlen; union { ChangeCipher cc; Alert alert; Handshake handshake; Application application; } u; } wtls_PDU; typedef struct wtls_payload { int type; int reserved; int cipher; int snMode; int seqNum; int rlen; Octstr *data; } wtls_Payload; /* Prototypes */ wtls_PDU *wtls_pdu_create(int type); void wtls_pdu_destroy(wtls_PDU * msg); void wtls_pdu_dump(wtls_PDU * msg, int level); wtls_PDU *wtls_pdu_unpack(wtls_Payload * payload, WTLSMachine * wtls_machine); wtls_Payload *wtls_pdu_pack(wtls_PDU * pdu, WTLSMachine * wtls_machine); wtls_Payload *wtls_payload_unpack(Octstr * data); Octstr *wtls_payload_pack(wtls_Payload * payload, int seqnum); void wtls_payload_dump(wtls_Payload * msg, int level); void wtls_pldList_destroy(List * pldList); void wtls_payload_destroy(wtls_Payload * payload); List *wtls_unpack_payloadlist(Octstr * data); Octstr *wtls_pack_payloadlist(List * payloadlist, int seqnum); #endif /* PDU_H */ gateway-1.4.5/wap/wtp_pdu.c0000644000175000017500000003124413227613126014310 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wtp_pdu.c - pack and unpack WTP packets * * Generates packing and unpacking code from wtp_pdu.def. * * Richard Braakman */ #include "gwlib/gwlib.h" #include "wtp_pdu.h" WTP_PDU *wtp_pdu_create(int type) { WTP_PDU *pdu; pdu = gw_malloc(sizeof(*pdu)); pdu->type = type; pdu->options = NULL; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: {\ struct name *p; p = &pdu->u.name; \ fields \ } break; #define UINT(field, docstring, bits) p->field = 0; #define UINTVAR(field, docstring) p->field = 0; #define OCTSTR(field, docstring, lengthfield) p->field = NULL; #define REST(field, docstring) p->field = NULL; #define TYPE(bits, value) #define RESERVED(bits) #define TPI(confield) #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: warning(0, "Cannot create unknown WTP PDU type %d", pdu->type); break; } return pdu; } void wtp_pdu_destroy(WTP_PDU *pdu) { if (pdu == NULL) return; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: {\ struct name *p; p = &pdu->u.name; \ fields \ } break; #define UINT(field, docstring, bits) #define UINTVAR(field, docstring) #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field); #define REST(field, docstring) octstr_destroy(p->field); #define TYPE(bits, value) #define RESERVED(bits) #define TPI(confield) #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: warning(0, "Cannot destroy unknown WTP PDU type %d", pdu->type); break; } if (pdu->options) { while (gwlist_len(pdu->options)) { wtp_tpi_destroy(gwlist_consume(pdu->options)); } gwlist_destroy(pdu->options, NULL); } gw_free(pdu); } void wtp_tpi_destroy(WTP_TPI *p) { if (p == NULL) return; octstr_destroy(p->data); gw_free(p); } void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data) { WTP_TPI *tpi; tpi = gw_malloc(sizeof(*tpi)); tpi->type = type; tpi->data = data; if (pdu->options == NULL) pdu->options = gwlist_create(); gwlist_append(pdu->options, tpi); } static long unpack_tpis(Octstr *data, long bitpos, WTP_PDU *pdu) { long length; int type; Octstr *tpidata; int another; do { another = octstr_get_bits(data, bitpos, 1); type = octstr_get_bits(data, bitpos + 1, 4); if (octstr_get_bits(data, bitpos + 5, 1)) { /* Long TPI */ length = octstr_get_bits(data, bitpos + 8, 8); bitpos += 16; } else { /* Short TPI */ length = octstr_get_bits(data, bitpos + 6, 2); bitpos += 8; } gw_assert(bitpos % 8 == 0); tpidata = octstr_copy(data, bitpos / 8, length); bitpos += 8 * length; wtp_pdu_append_tpi(pdu, type, tpidata); } while (another); return bitpos; } static long pack_tpis(Octstr *data, long bitpos, List *tpis) { long length; WTP_TPI *tpi; int i; int num_tpis; num_tpis = gwlist_len(tpis); for (i = 0; i < num_tpis; i++) { tpi = gwlist_get(tpis, i); length = octstr_len(tpi->data); octstr_set_bits(data, bitpos, 1, i + 1 < num_tpis); octstr_set_bits(data, bitpos + 1, 4, tpi->type); if (length >= 4) { /* Long TPI */ octstr_set_bits(data, bitpos + 5, 1, 1); octstr_set_bits(data, bitpos + 8, 8, length); bitpos += 16; } else { /* Short TPI */ octstr_set_bits(data, bitpos + 5, 1, 0); octstr_set_bits(data, bitpos + 6, 2, length); bitpos += 8; } gw_assert(bitpos % 8 == 0); octstr_append(data, tpi->data); bitpos += 8 * length; } return bitpos; } static void dump_tpis(List *tpis, int level) { int i; int num_tpis; WTP_TPI *tpi; if (tpis == NULL) return; num_tpis = gwlist_len(tpis); for (i = 0; i < num_tpis; i++) { tpi = gwlist_get(tpis, i); debug("wap.wtp", 0, "%*s TPI type %u:", level, "", tpi->type); octstr_dump(tpi->data, level + 1); } } /* Determine which type of PDU this is, using the TYPE macros in * the definition file. */ static int wtp_pdu_type(Octstr *data) { long bitpos; long lastpos = -1; long lastnumbits = -1; long lastval = -1; int thistype; /* This code looks slow, but an optimizing compiler will * reduce it considerably. gcc -O2 will produce a single * call to octstr_get_bits, folllowed by a sequence of * tests on lastval. */ /* Only UINT and RESERVED fields may precede the TYPE */ #define PDU(name, docstring, fields, is_valid) \ bitpos = 0; \ thistype = name; \ fields #define UINT(field, docstring, bits) bitpos += (bits); #define UINTVAR(field, docstring) #define OCTSTR(field, docstring, lengthfield) #define REST(field, docstring) #define TYPE(bits, value) \ if ((bits) != lastnumbits || bitpos != lastpos) { \ lastval = octstr_get_bits(data, bitpos, (bits)); \ } \ if (lastval == (value)) \ return thistype; \ lastnumbits = (bits); \ lastpos = bitpos; #define RESERVED(bits) bitpos += (bits); #define TPI(confield) #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU return -1; } WTP_PDU *wtp_pdu_unpack(Octstr *data) { WTP_PDU *pdu = NULL; long bitpos = 0; gw_assert(data != NULL); pdu = gw_malloc(sizeof(*pdu)); pdu->type = wtp_pdu_type(data); pdu->options = NULL; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: { \ struct name *p = &pdu->u.name; \ fields \ gw_assert(bitpos % 8 == 0); \ if (bitpos / 8 != octstr_len(data)) { \ warning(0, "Bad length for " #name " PDU, " \ "expected %ld", bitpos / 8); \ } \ if (!(is_valid)) { \ warning(0, #name " PDU failed %s", #is_valid); \ return NULL; \ } \ } break; #define UINT(field, docstring, bits) \ p->field = octstr_get_bits(data, bitpos, (bits)); \ bitpos += (bits); #define UINTVAR(field, docstring) \ gw_assert(bitpos % 8 == 0); \ p->field = octstr_get_bits(data, bitpos + 1, 7); \ while (octstr_get_bits(data, bitpos, 1)) { \ bitpos += 8; \ p->field <<= 7; \ p->field |= octstr_get_bits(data, bitpos + 1, 7); \ } \ bitpos += 8; #define OCTSTR(field, docstring, lengthfield) \ gw_assert(bitpos % 8 == 0); \ p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \ bitpos += 8 * p->lengthfield; #define REST(field, docstring) \ gw_assert(bitpos % 8 == 0); \ if (bitpos / 8 <= octstr_len(data)) { \ p->field = octstr_copy(data, bitpos / 8, \ octstr_len(data) - bitpos / 8); \ bitpos = octstr_len(data) * 8; \ } else { \ p->field = octstr_create(""); \ } #define TYPE(bits, value) bitpos += (bits); #define RESERVED(bits) bitpos += (bits); #define TPI(confield) \ if (p->confield) { \ pdu->options = gwlist_create(); \ bitpos = unpack_tpis(data, bitpos, pdu); \ } #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: warning(0, "WTP PDU with unknown type %d", pdu->type); gw_free(pdu); return NULL; } return pdu; } static void fixup_length_fields(WTP_PDU *pdu) { switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: { \ struct name *p = &pdu->u.name; \ fields \ } break; #define UINT(field, docstring, bits) #define UINTVAR(field, docstring) #define OCTSTR(field, docstring, lengthfield) \ p->lengthfield = octstr_len(p->field); #define REST(field, docstring) #define TYPE(bits, value) #define RESERVED(bits) #define TPI(confield) \ p->confield = pdu->options != NULL && gwlist_len(pdu->options) > 0; #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU } } Octstr *wtp_pdu_pack(WTP_PDU *pdu) { Octstr *data; long bitpos; /* We rely on octstr_set_bits to lengthen our octstr as needed. */ data = octstr_create(""); fixup_length_fields(pdu); bitpos = 0; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: { \ struct name *p = &pdu->u.name; \ fields \ gw_assert(bitpos % 8 == 0); \ } break; #define UINT(field, docstring, bits) \ octstr_set_bits(data, bitpos, (bits), p->field); \ bitpos += (bits); #define UINTVAR(field, docstring) \ gw_assert(bitpos % 8 == 0); \ octstr_append_uintvar(data, p->field); \ bitpos = 8 * octstr_len(data); #define OCTSTR(field, docstring, lengthfield) \ gw_assert(bitpos % 8 == 0); \ if (p->field != NULL) \ octstr_append(data, p->field); \ bitpos += 8 * octstr_len(p->field); #define REST(field, docstring) \ gw_assert(bitpos % 8 == 0); \ if (p->field != NULL) \ octstr_append(data, p->field); \ bitpos += 8 * octstr_len(p->field); #define TYPE(bits, value) \ octstr_set_bits(data, bitpos, (bits), (value)); \ bitpos += (bits); #define RESERVED(bits) bitpos += (bits); #define TPI(confield) \ if (p->confield) { \ bitpos = pack_tpis(data, bitpos, pdu->options); \ } #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: panic(0, "Packing unknown WTP PDU type %ld", (long) pdu->type); } return data; } void wtp_pdu_dump(WTP_PDU *pdu, int level) { char *dbg = "wap.wtp"; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: { \ struct name *p = &pdu->u.name; \ debug(dbg, 0, "%*sWTP %s PDU at %p:", \ level, "", #name, (void *)pdu); \ fields \ } break; #define UINT(field, docstring, bits) \ debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field); #define UINTVAR(field, docstring) \ debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field); #define OCTSTR(field, docstring, lengthfield) \ debug(dbg, 0, "%*s %s:", level, "", docstring); \ octstr_dump(p->field, level + 1); #define REST(field, docstring) \ debug(dbg, 0, "%*s %s:", level, "", docstring); \ octstr_dump(p->field, level + 1); #define TYPE(bits, value) #define RESERVED(bits) #define TPI(confield) dump_tpis(pdu->options, level); #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: debug(dbg, 0, "%*sWTP PDU at %p:", level, "", (void *)pdu); debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type); break; } } gateway-1.4.5/wap/wap_events.c0000644000175000017500000001743611443121512014777 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2008 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_events.c - functions for manipulating wapbox events * * Aarno Syvänen * Lars Wirzenius * Nikos Balkanas, Inaccess Networks (2009) */ #include "gwlib/gwlib.h" #include "wsp_caps.h" #include "wap_events.h" #include "wtls_pdu.h" WAPEvent *wap_event_create_real(WAPEventName type, const char *file, long line, const char *func) { WAPEvent *event; gw_assert(type >= 0); gw_assert(type < WAPEventNameCount); event = gw_malloc_trace(sizeof(WAPEvent), file, line, func); event->type = type; switch (event->type) { #define WAPEVENT(name, prettyname, fields) \ case name: \ { struct name *p = &event->u.name; fields } \ break; #define OCTSTR(name) p->name = NULL; #define OPTIONAL_OCTSTR(name) p->name = NULL; #define INTEGER(name) p->name = 0; #define WTLSPDUS(name) p->name = NULL; #define HTTPHEADER(name) p->name = NULL; #define ADDRTUPLE(name) p->name = NULL; #define CAPABILITIES(name) p->name = NULL; #include "wap_events.def" default: panic(0, "Unknown WAP event type %d", event->type); } return event; } void wap_event_destroy(WAPEvent *event) { if (event == NULL) return; wap_event_assert(event); switch (event->type) { #define WAPEVENT(name, prettyname, fields) \ case name: \ { struct name *p = &event->u.name; fields; } \ break; #define OCTSTR(name) octstr_destroy(p->name); #define OPTIONAL_OCTSTR(name) octstr_destroy(p->name); #define INTEGER(name) p->name = 0; #ifdef HAVE_WTLS_OPENSSL #define WTLSPDUS(name) wtls_pldList_destroy(p->name); #endif /* HAVE_WTLS_OPENSSL */ #define HTTPHEADER(name) http_destroy_headers(p->name); #define ADDRTUPLE(name) wap_addr_tuple_destroy(p->name); #define CAPABILITIES(name) wsp_cap_destroy_list(p->name); #include "wap_events.def" default: panic(0, "Unknown WAPEvent type %d", (int) event->type); } gw_free(event); } void wap_event_destroy_item(void *event) { wap_event_destroy(event); } WAPEvent *wap_event_duplicate(WAPEvent *event) { WAPEvent *new; if (event == NULL) return NULL; wap_event_assert(event); new = gw_malloc(sizeof(WAPEvent)); new->type = event->type; switch (event->type) { #define WAPEVENT(name, prettyname, fields) \ case name: \ { struct name *p = &new->u.name; \ struct name *q = &event->u.name; \ fields } \ break; #define OCTSTR(name) p->name = octstr_duplicate(q->name); #define OPTIONAL_OCTSTR(name) p->name = octstr_duplicate(q->name); #define INTEGER(name) p->name = q->name; #define WTLSPDUS(name) debug("wap.events",0,"You need to implement wtls_pdulist_duplicate!"); #define HTTPHEADER(name) p->name = http_header_duplicate(q->name); #define ADDRTUPLE(name) p->name = wap_addr_tuple_duplicate(q->name); #define CAPABILITIES(name) p->name = wsp_cap_duplicate_list(q->name); #include "wap_events.def" default: panic(0, "Unknown WAP event type %d", event->type); } return new; } const char *wap_event_name(WAPEventName type) { switch (type) { #define WAPEVENT(name, prettyname, fields) \ case name: return prettyname; #include "wap_events.def" default: panic(0, "Unknown WAPEvent type %d", (int) type); return "unknown WAPEventName"; } } void wap_event_dump(WAPEvent *event) { debug("wap.event", 0, "Dumping WAPEvent %p", (void *) event); if (event != NULL) { debug("wap.event", 0, " type = %s", wap_event_name(event->type)); switch (event->type) { #define WAPEVENT(name, prettyname, fields) \ case name: \ { struct name *p = &event->u.name; fields; break; } #define OCTSTR(name) \ debug("wap.event", 0, "%s =", #name); \ octstr_dump(p->name, 1); #define OPTIONAL_OCTSTR(name) \ if (p->name == NULL) \ debug("wap.event", 0, "%s = NULL", #name); \ else { \ debug("wap.event", 0, "%s =", #name); \ octstr_dump(p->name, 1); \ } #define INTEGER(name) \ debug("wap.event", 0, " %s = %ld", #name, p->name); #define WTLSPDUS(name) \ debug("wap.event",0,"You need to implement wtls_payloadlist_dump!"); #define HTTPHEADER(name) \ if (p->name == NULL) \ debug("wap.event", 0, "%s = NULL", #name); \ else \ http_header_dump(p->name); #define ADDRTUPLE(name) wap_addr_tuple_dump(p->name); #define CAPABILITIES(name) wsp_cap_dump_list(p->name); #include "wap_events.def" default: debug("wap.event", 0, "Unknown type"); } } debug("wap.event", 0, "WAPEvent dump ends."); } void wap_event_assert(WAPEvent *event) { gw_assert(event != NULL), gw_assert(event->type >= 0); gw_assert(event->type < WAPEventNameCount); switch (event->type) { #define WAPEVENT(name, prettyname, fields) \ case name: \ { struct name *p = &event->u.name; fields; p = NULL; break; } #define OCTSTR(name) \ gw_assert(p->name != NULL); \ /* This is a trick to make the Octstr module run its assertions */ \ gw_assert(octstr_len(p->name) >= 0); #define OPTIONAL_OCTSTR(name) \ gw_assert(p->name == NULL || octstr_len(p->name) >= 0); #define INTEGER(name) #define WTLSPDUS(name) #define HTTPHEADER(name) #define ADDRTUPLE(name) \ gw_assert(p->name != NULL); #define CAPABILITIES(name) #include "wap_events.def" default: debug("wap.event", 0, "Unknown type"); } } gateway-1.4.5/wap/wap.h0000644000175000017500000002217313227613126013423 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap.h - public interface to WAP protocol library * * The WAP protocol library consists of separate layers, which each run * in their own thread. The layers are normally used together and will * communicate with each other, but they can be used separately by * specialized applications. * * Communication between layers is done by sending WAPEvent structures. * These events are passed to dispatch functions. Each layer has its * own dispatch function which is responsible for queueing the event * for that layer. * * The application using this library has to provide an application layer * and a datagram layer. These layers do not have to be implemented in * any particular way and do not have to run in their own threads, but * they do have to provide dispatch functions. * * In general, if a layer receives an event that it does not know how * to handle, it will report this and ignore the event. */ #ifndef WAP_H #define WAP_H #include "wap_events.h" #include "wap_addr.h" typedef void wap_dispatch_func_t(WAPEvent *event); /* * Generic dispatch function that takes T_DUnitdata_Ind events and * figures out to which layer they should be sent, by recognizing * well-known port numbers and by inspecting the datagram contents. * It also unpacks WTP events before dispatching, so that the WTP * thread is not burdened by this. */ void wap_dispatch_datagram(WAPEvent *event); /* * Generic startup function that initializes all the layers and * chains their dispatch functions together. */ void wap_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *application_dispatch); /* * Undoes what wap_init did. */ void wap_shutdown(void); /* * Datagram layer * * This layer is not provided by libwap itself. The application is * expected to create one, by: * - providing a dispatch function that takes T_DUnitdata_Req * events (outgoing datagrams) * - passing incoming datagrams to the right layer, either by * calling the layer's dispatch function directly or by calling * wap_dispatch_datagram(). */ /* * Transaction layer, responder * * This layer implements the Responder side of WTP. * Its dispatch function takes events of these types: * * RcvInvoke, RcvAck, RcvAbort, RcvErrorPDU, * TR_Invoke_Res, TR_Result_Req, TR_Abort_Req, * TimerTO_A, TimerTO_R, TimerTO_W * * FIXME It also takes T_DUnitdata_Ind events, which it will unpack into one * of the Rcv* events and then process. * * This layer will dispatch T_DUnitdata_Req events to the datagram layer, * and these event types to the session layer: * * TR_Invoke_Ind, TR_Result_Cnf, TR_Abort_Ind * * Timer_freq is the timer 'tick' used. All wtp responder timers are * multiplies of this value. */ void wtp_resp_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *session_dispatch, wap_dispatch_func_t *push_dispatch, long timer_freq); void wtp_resp_dispatch_event(WAPEvent *event); void wtp_resp_shutdown(void); /* * Transaction layer, initiator * * This layer implements the Initiator side of WTP. * FIXME Currently only class 0 and 1 are implemented. * Its dispatch function takes events of these types: * * RcvAck, RcvAbort, RcvErrorPDU * TR_Invoke_Req, TR_Abort_Req * TimerTO_R * * FIXME It also takes T_DUnitdata_Ind events, which it will unpack into one * of the Rcv* events and then process. * * This layer will dispatch T_DUnitdata_Req events to the datagram layer, * and these event types to the session layer: * * TR_Invoke_Cnf, TR_Abort_Ind * * Timer_freq is a timer 'tick'. All initiator timer values are multiplies * of it. */ void wtp_initiator_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *session_dispatch, long timer_freq); void wtp_initiator_dispatch_event(WAPEvent *event); void wtp_initiator_shutdown(void); /* * Session layer, connectionless mode * * This layer implements Connectionless WSP. * FIXME Currently only the server side is implemented. * Its dispatch function takes events of these types: * * T_DUnitdata_Ind * S_Unit_MethodResult_Req * * This layer will dispatch T_DUnitdata_Req events to the datagram layer, * and S_Unit_MethodInvoke_Ind events to the application layer. */ void wsp_unit_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *application_dispatch); void wsp_unit_dispatch_event(WAPEvent *event); void wsp_unit_shutdown(void); /* * Session layer, connection-oriented mode, server side * * This layer implements the server side of connection-oriented WSP. * FIXME Not all defined service primitives are supported yet. * Its dispatch function takes events of these types: * * TR_Invoke_Ind, TR_Result_Cnf, TR_Abort_Ind * S_Connect_Res, S_Resume_Res * S_MethodInvoke_Res, S_MethodResult_Res * Disconnect_Event, Suspend_Event (internal) * * This layer will dispatch events of these types to the application layer: * * S_Connect_Ind, S_Disconnect_Ind, * S_Suspend_Ind, S_Resume_Ind, * S_MethodInvoke_Ind, S_MethodResult_Cnf, S_MethodAbort_Ind * * and events of these types to the WTP Responder layer: * * TR_Invoke_Res, TR_Result_Req, TR_Abort_Req * * and events of these types to the WTP Initiator layer: * * (none yet) */ void wsp_session_init(wap_dispatch_func_t *responder_dispatch, wap_dispatch_func_t *initiator_dispatch, wap_dispatch_func_t *application_dispatch, wap_dispatch_func_t *ota_dispatch); void wsp_session_dispatch_event(WAPEvent *event); void wsp_session_shutdown(void); /* * Session layer, connection-oriented mode, client side * * FIXME Not implemented yet. */ void wsp_push_client_init(wap_dispatch_func_t *dispatch_self, wap_dispatch_func_t *dispatch_wtp_resp); void wsp_push_client_shutdown(void); void wsp_push_client_dispatch_event(WAPEvent *e); /* * Application layer * * This layer is not provided by libwap itself. The application is * expected to create one, by providing a dispatch function to the * session layer that takes events of these types: * * S_Connect_Ind, S_Disconnect_Ind, * S_Suspend_Ind, S_Resume_Ind, * S_MethodInvoke_Ind, S_MethodResult_Cnf, S_MethodAbort_Ind * S_Unit_MethodInvoke_Ind (from wsp_unit) * * For most of these events the application layer is expected to send * a response back to the session layer. */ #endif gateway-1.4.5/wap/wtp_pack.h0000644000175000017500000001153513227613126014444 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_pack.h - WTP implementation, message module header * * By Aarno Syvänen for WapIT Ltd. */ #ifndef WTP_SEND_H #define WTP_SEND_H #include "gwlib/gwlib.h" #include "wap_events.h" #include "wtp_init.h" #include "wtp_resp.h" #include "wtp.h" #include "wap.h" /* * Create a datagram event, having invoke PDU as user data. Fetches address, * tid and tid_new from the initiator state machine, other fields from event. * Only for the wtp initiator. * * Return message to be sent. */ WAPEvent *wtp_pack_invoke(WTPInitMachine *init_machine, WAPEvent *event); /* * Create a datagram event, having result PDU as user data. Fetches SDU * from WTP event, address four-tuple and machine state information * (are we resending the packet) from WTP machine. Handles all * errors by itself. Returns message, if OK, else NULL. Only for wtp * responder. */ WAPEvent *wtp_pack_result(WTPRespMachine *resp_machine, WAPEvent *event); /* * Same as above but for a segmented result. */ WAPEvent *wtp_pack_sar_result(WTPRespMachine *resp_machine, int psn); /* * Create a datagram event, having abort PDU as user data. Fetches SDU * from WTP event, address four-tuple from WTP machine. * Handles all errors by itself. Both for wtp initiator and responder. */ WAPEvent *wtp_pack_abort(long abort_type, long abort_reason, long tid, WAPAddrTuple *address); /* * Create a datagram event, having ack PDU as user data. Creates SDU by * itself, fetches address four-tuple and machine state from WTP machine. * Ack_type is a flag telling whether we are doing tid verification or not, * rid_flag tells are we retransmitting. Handles all errors by itself. * Both for wtp initiator and responder. */ WAPEvent *wtp_pack_ack(long ack_type, int rid_flag, long tid, WAPAddrTuple *address); /* * Same as above but for a segmented ack */ WAPEvent *wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn); /* * Set or unset the retransmission indicator on a PDU that has already * been packed as a datagram. dgram must be of type T_DUnitdata_Req. */ void wtp_pack_set_rid(WAPEvent *dgram, long rid); #endif gateway-1.4.5/wap/wap_events.def0000644000175000017500000004565513227613126015330 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_events.def - definitions for wapbox events * * This file uses a pre-processor trick to define the structure of * structures. See the documentation. * * Fields of type HTTPHEADER, CAPABILITIES, and OPTIONAL_OCTSTR may * be NULL. All other fields must be filled in, unless they are * otherwise marked. * * Fields described in the appropriate spec are listed first. Fields * specific to Kannel are introduced with an empty line. In some events, * we have combined fields to form an "address tuple" (see wap_addr.h). * * Aarno Syvänen * Lars Wirzenius */ /* WTLS material - make sure the addr_tuple comes first! */ #ifdef HAVE_WTLS_OPENSSL WAPEVENT(T_Unitdata_Ind, "T-Unitdata.ind", ADDRTUPLE(addr_tuple) WTLSPDUS(pdu_list) ) WAPEVENT(SEC_Create_Ind, "SEC-Create.ind", ADDRTUPLE(addr_tuple) ) WAPEVENT(SEC_Create_Request_Req, "SEC-Create.req", ADDRTUPLE(addr_tuple) ) WAPEVENT(SEC_Terminate_Req, "SEC-Terminate.req", ADDRTUPLE(addr_tuple) INTEGER(alert_level) INTEGER(alert_desc) ) WAPEVENT(SEC_Exception_Req, "SEC-Exception.req", ADDRTUPLE(addr_tuple) INTEGER(alert_level) INTEGER(alert_desc) ) WAPEVENT(SEC_Create_Res, "SEC-Create.res", ADDRTUPLE(addr_tuple) INTEGER(client_key_id) INTEGER(bulk_cipher_algo) INTEGER(mac_algo) INTEGER(snmode) INTEGER(krefresh) ) WAPEVENT(SEC_Exchange_Req, "SEC-Exchange.req", ADDRTUPLE(addr_tuple) ) WAPEVENT(SEC_Commit_Req, "SEC-Commit.req", ADDRTUPLE(addr_tuple) ) WAPEVENT(SEC_Unitdata_Req, "SEC-Unidata.req", ADDRTUPLE(addr_tuple) OCTSTR(user_data) ) #endif /* HAVE_WTLS_OPENSSL */ /* * Transport layer (WDP) */ WAPEVENT(T_DUnitdata_Req, "T-DUnitdata.req", ADDRTUPLE(addr_tuple) OCTSTR(user_data) INTEGER(address_type) OPTIONAL_OCTSTR(smsc_id) INTEGER(dlr_mask) OPTIONAL_OCTSTR(dlr_url) OPTIONAL_OCTSTR(smsbox_id) OPTIONAL_OCTSTR(service_name) ) WAPEVENT(T_DUnitdata_Ind, "T-DUnitdata.ind", ADDRTUPLE(addr_tuple) OCTSTR(user_data) ) /* * Transaction layer (WTP) */ WAPEVENT(TR_Invoke_Req, "TR-Invoke.req", ADDRTUPLE(addr_tuple) INTEGER(up_flag) OCTSTR(user_data) INTEGER(tcl) INTEGER(handle) ) WAPEVENT(TR_Invoke_Ind, "TR-Invoke.ind", INTEGER(ack_type) OCTSTR(user_data) INTEGER(tcl) ADDRTUPLE(addr_tuple) INTEGER(handle) ) WAPEVENT(TR_Invoke_Res, "TR-Invoke.res", INTEGER(handle) ) WAPEVENT(TR_Invoke_Cnf, "TR-Invoke.cnf", INTEGER(handle) ADDRTUPLE(addr_tuple) ) WAPEVENT(TR_Result_Req, "TR-Result.req", OCTSTR(user_data) INTEGER(handle) ) WAPEVENT(TR_Result_Cnf, "TR-Result.cnf", INTEGER(handle) ADDRTUPLE(addr_tuple) ) WAPEVENT(TR_Abort_Req, "TR-Abort.req", INTEGER(abort_type) INTEGER(abort_reason) INTEGER(handle) ) WAPEVENT(TR_Abort_Ind, "TR-Abort.ind", INTEGER(abort_code) INTEGER(handle) ADDRTUPLE(addr_tuple) INTEGER(ir_flag) /* Are we an initiator or a responder */ ) /* * Session layer (WSP), server side * These events use the session id as a handle. */ WAPEVENT(S_Connect_Ind, "S-Connect.ind", ADDRTUPLE(addr_tuple) HTTPHEADER(client_headers) CAPABILITIES(requested_capabilities) INTEGER(session_id) ) WAPEVENT(S_Connect_Res, "S-Connect.res", HTTPHEADER(server_headers) CAPABILITIES(negotiated_capabilities) INTEGER(session_id) ) WAPEVENT(S_Suspend_Ind, "S-Suspend.ind", INTEGER(reason) INTEGER(session_id) ) WAPEVENT(S_Resume_Ind, "S-Resume.ind", ADDRTUPLE(addr_tuple) HTTPHEADER(client_headers) INTEGER(session_id) ) WAPEVENT(S_Resume_Res, "S-Resume.res", HTTPHEADER(server_headers) INTEGER(session_id) ) /* * Session layer (WSP), client side */ WAPEVENT(S_Connect_Req, "S-Connect.req", ADDRTUPLE(addr_tuple) HTTPHEADER(client_headers) CAPABILITIES(requested_capabilities) INTEGER(session_handle) ) WAPEVENT(S_Suspend_Req, "S-Suspend.req", INTEGER(session_handle) ) WAPEVENT(S_Resume_Req, "S-Resume.req", ADDRTUPLE(addr_tuple) HTTPHEADER(client_headers) INTEGER(session_handle) ) WAPEVENT(S_Resume_Cnf, "S-Resume.cnf", HTTPHEADER(server_headers) INTEGER(session_handle) ) /* * Session layer (WSP), events shared between server and client side * On the server side, the "handle" field is always the session id. */ WAPEVENT(S_Disconnect_Req, "S-Disconnect.req", INTEGER(reason_code) INTEGER(redirect_security) /* Only meaningful if redirecting */ INTEGER(redirect_addresses) /* FIXME: Wrong type, not used */ OPTIONAL_OCTSTR(error_headers) OPTIONAL_OCTSTR(error_body) INTEGER(session_handle) ) WAPEVENT(S_Disconnect_Ind, "S-Disconnect.ind", INTEGER(reason_code) INTEGER(redirect_security) /* Only meaningful if redirecting */ INTEGER(redirect_addresses) /* FIXME: Wrong type, not used */ OPTIONAL_OCTSTR(error_headers) OPTIONAL_OCTSTR(error_body) INTEGER(session_handle) ) /* * Pseudo-events used by session layer */ WAPEVENT(Disconnect_Event, "Disconnect", INTEGER(session_handle) ) WAPEVENT(Suspend_Event, "Suspend", INTEGER(session_handle) ) WAPEVENT(Release_Event, "Release", INTEGER(dummy) ) WAPEVENT(Abort_Event, "Abort", INTEGER(reason) ) /* * Per-method events for session layer, server side */ WAPEVENT(S_MethodInvoke_Ind, "S-MethodInvoke.ind", INTEGER(server_transaction_id) OCTSTR(method) /* All caps */ OCTSTR(request_uri) HTTPHEADER(request_headers) OPTIONAL_OCTSTR(request_body) HTTPHEADER(session_headers) ADDRTUPLE(addr_tuple) INTEGER(client_SDU_size) INTEGER(session_id) ) WAPEVENT(S_MethodInvoke_Res, "S-MethodInvoke.res", INTEGER(server_transaction_id) INTEGER(session_id) ) WAPEVENT(S_MethodResult_Req, "S-MethodResult.req", INTEGER(server_transaction_id) INTEGER(status) HTTPHEADER(response_headers) OPTIONAL_OCTSTR(response_body) INTEGER(session_id) ) WAPEVENT(S_MethodResult_Cnf, "S-MethodResult.cnf", INTEGER(server_transaction_id) INTEGER(session_id) ) /* * Per-method events for session layer, client side */ WAPEVENT(S_MethodInvoke_Req, "S-MethodInvoke.req", INTEGER(client_transaction_id) OCTSTR(method) OCTSTR(request_uri) HTTPHEADER(request_headers) OPTIONAL_OCTSTR(request_body) INTEGER(session_handle) ) WAPEVENT(S_MethodInvoke_Cnf, "S-MethodInvoke.cnf", INTEGER(client_transaction_id) INTEGER(session_handle) ) WAPEVENT(S_MethodResult_Ind, "S-MethodResult.ind", INTEGER(client_transaction_id) INTEGER(status) HTTPHEADER(response_headers) OPTIONAL_OCTSTR(response_body) INTEGER(session_handle) ) WAPEVENT(S_MethodResult_Res, "S-MethodResult.res", INTEGER(client_transaction_id) INTEGER(session_handle) ) /* * Per-method events used by the session layer * These events are used by both client and server side. */ WAPEVENT(S_MethodAbort_Req, "S-MethodAbort.req", INTEGER(transaction_id) INTEGER(session_handle) ) WAPEVENT(S_MethodAbort_Ind, "S-MethodAbort.ind", INTEGER(transaction_id) INTEGER(reason) INTEGER(session_handle) ) /* * Per-push events used by the session layer */ WAPEVENT(S_Push_Req, "S-Push.req", HTTPHEADER(push_headers) OPTIONAL_OCTSTR(push_body) INTEGER(session_id) ) WAPEVENT(S_Push_Ind, "S-Push.ind", HTTPHEADER(push_headers) OPTIONAL_OCTSTR(push_body) INTEGER(session_handle) HTTPHEADER(session_headers) ) WAPEVENT(S_ConfirmedPush_Req, "S-ConfirmedPush.req", INTEGER(server_push_id) HTTPHEADER(push_headers) OPTIONAL_OCTSTR(push_body) INTEGER(session_id) ) WAPEVENT(S_ConfirmedPush_Ind, "S-ConfirmedPush.ind", INTEGER(client_push_id) HTTPHEADER(push_headers) OPTIONAL_OCTSTR(push_body) INTEGER(session_handle) ) WAPEVENT(S_ConfirmedPush_Res, "S-ConfirmedPush.res", INTEGER(client_push_id) INTEGER(session_handle) ) WAPEVENT(S_ConfirmedPush_Cnf, "S-ConfirmedPush.cnf", INTEGER(server_push_id) INTEGER(session_id) ) WAPEVENT(S_PushAbort_Ind, "S-PushAbort.ind", INTEGER(push_id) INTEGER(reason) INTEGER(session_id) ) /* * The specification of S-PushAbort seems to assume that only the * client can issue an S-PushAbort.req, and only the server can get * an S-PushAbort.ind. This is contradicted by the state tables. * That's why the definitions here use just "push_id" instead of * server_push_id and client_push_id. */ WAPEVENT(S_PushAbort_Req, "S-PushAbort.req", INTEGER(push_id) INTEGER(reason) INTEGER(session_handle) ) WAPEVENT(Push_Abort, "Internal abort", INTEGER(reason) ) /* * Events created by unpacking T-DUnitdata.ind events. * Used by WTP layer. */ WAPEVENT(RcvInvoke, "RcvInvoke", OCTSTR(user_data) INTEGER(tcl) INTEGER(tid) INTEGER(tid_new) INTEGER(rid) INTEGER(up_flag) INTEGER(no_cache_supported) INTEGER(version) INTEGER(gtr) INTEGER(ttr) ADDRTUPLE(addr_tuple) ) WAPEVENT(RcvSegInvoke, "RcvSegInvoke", OCTSTR(user_data) INTEGER(tid) INTEGER(rid) INTEGER(no_cache_supported) INTEGER(gtr) INTEGER(ttr) INTEGER(psn) ADDRTUPLE(addr_tuple) ) WAPEVENT(RcvResult, "RcvResult", OCTSTR(user_data) INTEGER(tid) INTEGER(rid) INTEGER(gtr) INTEGER(ttr) ADDRTUPLE(addr_tuple) ) WAPEVENT(RcvAbort, "RcvAbort", INTEGER(tid) INTEGER(abort_type) INTEGER(abort_reason) ADDRTUPLE(addr_tuple) ) WAPEVENT(RcvAck, "RcvAck", INTEGER(tid) INTEGER(tid_ok) INTEGER(rid) INTEGER(psn) ADDRTUPLE(addr_tuple) ) WAPEVENT(RcvNegativeAck, "RcvNack", INTEGER(tid) INTEGER(rid) INTEGER(nmissing) OPTIONAL_OCTSTR(missing) ADDRTUPLE(addr_tuple) ) /* * Other events used by WTP layer. */ WAPEVENT(TimerTO_A, "Timeout-A", INTEGER(handle) ) WAPEVENT(TimerTO_R, "Timeout-R", INTEGER(handle) ) WAPEVENT(TimerTO_W, "Timeout-W", INTEGER(handle) ) WAPEVENT(RcvErrorPDU, "RcvErrorPDU", INTEGER(tid) ADDRTUPLE(addr_tuple) ) /* * Events used by connectionless session protocol (WSP) */ WAPEVENT(S_Unit_MethodInvoke_Req, "S-Unit-MethodInvoke.req", ADDRTUPLE(addr_tuple) INTEGER(transaction_id) OCTSTR(method) OCTSTR(request_uri) HTTPHEADER(request_headers) OPTIONAL_OCTSTR(request_body) ) WAPEVENT(S_Unit_MethodInvoke_Ind, "S-Unit_MethodInvoke.ind", ADDRTUPLE(addr_tuple) INTEGER(transaction_id) OCTSTR(method) /* All caps */ OCTSTR(request_uri) HTTPHEADER(request_headers) OPTIONAL_OCTSTR(request_body) ) WAPEVENT(S_Unit_MethodResult_Req, "S-Unit-MethodResult.req", ADDRTUPLE(addr_tuple) INTEGER(transaction_id) INTEGER(status) HTTPHEADER(response_headers) OPTIONAL_OCTSTR(response_body) ) WAPEVENT(S_Unit_MethodResult_Ind, "S-Unit-MethodResult.ind", ADDRTUPLE(addr_tuple) INTEGER(transaction_id) INTEGER(status) HTTPHEADER(response_headers) OPTIONAL_OCTSTR(response_body) ) WAPEVENT(S_Unit_Push_Req, "S-Unit-Push.req", ADDRTUPLE(addr_tuple) INTEGER(push_id) HTTPHEADER(push_headers) OPTIONAL_OCTSTR(push_body) INTEGER(address_type) OPTIONAL_OCTSTR(smsc_id) INTEGER(dlr_mask) OPTIONAL_OCTSTR(dlr_url) OPTIONAL_OCTSTR(smsbox_id) OPTIONAL_OCTSTR(service_name) ) WAPEVENT(S_Unit_Push_Ind, "S-Unit-Push.ind", ADDRTUPLE(addr_tuple) INTEGER(push_id) HTTPHEADER(push_headers) OPTIONAL_OCTSTR(push_body) ) /* * Events used by push OTA protocol, server side */ WAPEVENT(Pom_SessionRequest_Req, "Pom-SessionRequest.req", ADDRTUPLE(addr_tuple) HTTPHEADER(push_headers) INTEGER(push_id) INTEGER(address_type) OPTIONAL_OCTSTR(smsc_id) INTEGER(dlr_mask) OPTIONAL_OCTSTR(dlr_url) OPTIONAL_OCTSTR(smsbox_id) OPTIONAL_OCTSTR(service_name) ) WAPEVENT(Pom_Connect_Ind, "Pom-Connect.ind", ADDRTUPLE(addr_tuple) HTTPHEADER(push_headers) CAPABILITIES(requested_capabilities) HTTPHEADER(accept_application) HTTPHEADER(bearer_indication) INTEGER(session_id) INTEGER(push_id) ) WAPEVENT(Pom_Connect_Res, "Pom-Connect.res", CAPABILITIES(negotiated_capabilities) INTEGER(session_id) ) WAPEVENT(Pom_Disconnect_Ind, "Pom-Disconnect.ind", INTEGER(reason_code) INTEGER(redirect_security) /* Only meaningful if redirecting*/ INTEGER(redirect_addresses) /* FIXME: Wrong type, not used */ OPTIONAL_OCTSTR(error_headers) OPTIONAL_OCTSTR(error_body) INTEGER(session_handle) ) WAPEVENT(Pom_Suspend_Ind, "Pom-Suspend.ind", INTEGER(reason) INTEGER(session_id) ) WAPEVENT(Pom_Resume_Ind, "Pom-Resume.ind", ADDRTUPLE(addr_tuple) HTTPHEADER(client_headers) HTTPHEADER(bearer_indication) INTEGER(session_id) ) WAPEVENT(Po_Push_Req, "Po-Push.req", HTTPHEADER(push_headers) INTEGER(authenticated) INTEGER(trusted) INTEGER(last) OPTIONAL_OCTSTR(push_body) INTEGER(session_handle) ) WAPEVENT(Po_ConfirmedPush_Req, "Po-ConfirmedPush.req", INTEGER(server_push_id) HTTPHEADER(push_headers) INTEGER(authenticated) INTEGER(trusted) INTEGER(last) OPTIONAL_OCTSTR(push_body) INTEGER(session_handle) ) WAPEVENT(Po_ConfirmedPush_Cnf, "Po-ConfirmedPush.Cnf", INTEGER(server_push_id) INTEGER(session_handle) ) WAPEVENT(Po_Unit_Push_Req, "Po-Unit-Push.req", ADDRTUPLE(addr_tuple) INTEGER(push_id) HTTPHEADER(push_headers) INTEGER(authenticated) INTEGER(trusted) INTEGER(last) OPTIONAL_OCTSTR(push_body) INTEGER(address_type) OPTIONAL_OCTSTR(smsc_id) INTEGER(dlr_mask) OPTIONAL_OCTSTR(dlr_url) OPTIONAL_OCTSTR(smsbox_id) OPTIONAL_OCTSTR(service_name) ) WAPEVENT(Po_PushAbort_Req, "Po-PushAbort.req", INTEGER(push_id) INTEGER(reason) INTEGER(session_id) ) WAPEVENT(Po_PushAbort_Ind, "Po-PushAbort.ind", INTEGER(push_id) INTEGER(reason) INTEGER(session_handle) ) /* * Following events are used communicating between PPG main module (implement- * ing main logic of PPG) and PAP module. These are defined in Push Access * Protocol, chapter 9. * Note here is one address, one group of push headers, one push body and one * group of capabilities. We should use list of address_values for multiple * addresses (optional) and Lists of push headers, push data and capabilities * for multipart (non-nested mandatory). * Note, too, that we do not yet support multiple addresses. * Optional fields, if PAP control message originally does not contain one, * should be set NULL, and mandatory fields non-NULL. */ WAPEVENT(Push_Message, "push-message", OCTSTR(pi_push_id) OPTIONAL_OCTSTR(deliver_before_timestamp) /* using PAP format */ OPTIONAL_OCTSTR(deliver_after_timestamp) /* ditto */ OPTIONAL_OCTSTR(source_reference) OPTIONAL_OCTSTR(ppg_notify_requested_to) INTEGER(progress_notes_requested) OCTSTR(address_value) /* as parsed PAP */ INTEGER(address_type) INTEGER(priority) INTEGER(delivery_method) OPTIONAL_OCTSTR(network) INTEGER(network_required) OPTIONAL_OCTSTR(bearer) INTEGER(bearer_required) HTTPHEADER(push_headers) OPTIONAL_OCTSTR(push_data) CAPABILITIES(pi_capabilities) OPTIONAL_OCTSTR(smsc_id) INTEGER(dlr_mask) OPTIONAL_OCTSTR(dlr_url) OPTIONAL_OCTSTR(smsbox_id) OPTIONAL_OCTSTR(service_name) OPTIONAL_OCTSTR(product_name) ) /* * Push response element indicates that there will be no more progress notes, * see Push Access Protocol, 9.3.2. */ WAPEVENT(Push_Response, "push-response", OCTSTR(pi_push_id) OPTIONAL_OCTSTR(sender_name) OPTIONAL_OCTSTR(reply_time) OPTIONAL_OCTSTR(sender_address) INTEGER(code) OPTIONAL_OCTSTR(desc) OPTIONAL_OCTSTR(product_name) ) /* * This is for debugging PIs. One note per stage. See Push Access Protocol, * 9.3.1.PPG main module sends these separately to PAP. */ WAPEVENT(Progress_Note, "progress-note", INTEGER(stage) OPTIONAL_OCTSTR(note) OPTIONAL_OCTSTR(time) ) /* * Element bad-message-response is defined in PAP, Implementation Note, * chapter 5. */ WAPEVENT(Bad_Message_Response, "badmessage-response", INTEGER(code) OPTIONAL_OCTSTR(desc) OPTIONAL_OCTSTR(bad_message_fragment) ) #undef WAPEVENT #undef OCTSTR #undef OPTIONAL_OCTSTR #undef INTEGER #undef WTLSPDUS #undef HTTPHEADER #undef ADDRTUPLE #undef CAPABILITIES gateway-1.4.5/wap/wtls.h0000644000175000017500000001067313227613126013627 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * WTLS Server Header * * Nick Clarey * Nikos Balkanas, InAccess Networks (2009) */ #ifndef WTLS_H #define WTLS_H typedef struct WTLSMachine WTLSMachine; #include "gw/msg.h" #include "wap/wap_events.h" #include "wap/wtls_pdu.h" typedef void wtls_dispatch_func_t(Msg *msg); /* * WTLS Server machine states and WTLS machine. * See file wtls_state-decl.h for comments. Note that we must define macro * ROW to produce an empty string. */ enum serv_states { #define STATE_NAME(state) state, #define ROW(state, event, condition, action, next_state) #include "wtls_state-decl.h" serv_states_count }; typedef enum serv_states serv_states; /* * See files wtls_machine-decl.h for comments. We define one macro for * every separate type. */ struct WTLSMachine { unsigned long mid; #define ENUM(name) serv_states name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define INTEGER(name) int name; #define OCTSTR(name) Octstr *name; #define MACHINE(field) field #define PDULIST(name) List *name; #include "wtls_machine-decl.h" }; /* * Initialize the WTLS server. */ void wtls_init(wtls_dispatch_func_t *responder_dispatch); /* * Shut down the WTLS server machines. MUST be called after the subsystem isn't * used anymore. */ void wtls_shutdown(void); /* * Transfers control of an event to the WTLS server machine subsystem. */ void wtls_dispatch_event(WAPEvent * event); /* * Return control to WTLS server machine subsystem */ void wtls_dispatch_resp(WAPEvent * event); /* * Handles possible concatenated messages. Returns a list of wap events. * Real unpacking is done by an internal function. */ WAPEvent *wtls_unpack_wdp_datagram(Msg * msg); int wtls_get_address_tuple(long mid, WAPAddrTuple ** tuple); #endif gateway-1.4.5/wap/wsp_strings.h0000644000175000017500000001102313227613126015206 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wsp-strings.h: interface to tables defined by WSP standard * * This file defines an interface to the Assigned Numbers tables * in appendix A of the WSP specification. For each supported * table there is a function to convert from number to string and * a function to convert from string to number. * * The tables are in wsp-strings.def, in a special format suitable for * use with the C preprocessor, which we abuse liberally to get the * interface we want. * * For a table named foo, these functions will be declared: * * Octstr *wsp_foo_to_string(long number); * - return NULL if the number has no assigned string. * * unsigned char *wsp_foo_to_cstr(long number); * - return NULL if the number has no assigned string. * * long wsp_string_to_foo(Octstr *ostr); * - case-insensitive lookup. * - Return -1 if the string has no assigned number. * * Richard Braakman */ #ifndef WSP_STRINGS_H #define WSP_STRINGS_H #include "gwlib/gwlib.h" #include "wap/wsp.h" /* Must be called before any of the other functions in this file. * Can be called more than once, in which case multiple shutdowns * are also required. */ void wsp_strings_init(void); /* Call this to clean up memory allocations */ void wsp_strings_shutdown(void); /* Declare the functions */ #define LINEAR(name, strings) \ Octstr *wsp_##name##_to_string(long number); \ unsigned char *wsp_##name##_to_cstr(long number); \ long wsp_string_to_##name(Octstr *ostr); \ long wsp_string_to_versioned_##name(Octstr *ostr, int version); #define STRING(string) #include "wsp_strings.def" /* Define the enumerated types */ #define LINEAR(name, strings) #define STRING(string) #define NAMED(name, strings) enum name##_enum { strings name##_dummy }; #define NSTRING(string, name) name, #define VNSTRING(version, string, name) name, #include "wsp_strings.def" #endif gateway-1.4.5/wap/wsp.c0000644000175000017500000001007513227613126013436 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp.c - Parts of WSP shared between session oriented and connectionless mode */ #include #include "gwlib/gwlib.h" #include "wsp.h" #include "wsp_pdu.h" #include "wsp_headers.h" #include "wsp_strings.h" /*********************************************************************** * Public functions */ /* Convert HTTP status codes to WSP status codes according * to WSP Table 36, Status Code Assignments. */ long wsp_convert_http_status_to_wsp_status(long http_status) { long hundreds, singles; /* * The table is regular, and can be expected to stay regular in * future versions of WSP. The status value is read as XYY, * so that X is the first digit and Y is the value of the * second two digits. This is encoded as a hex value 0xAB, * where A == X and B == YY. * This limits YY to the range 0-15, so an exception is made * to allow larger YY values when X is 4. X value 5 is moved up * to A value 6 to allow more room for YY when X is 4. */ hundreds = http_status / 100; singles = http_status % 100; if ((hundreds == 4 && singles > 31) || (hundreds != 4 && singles > 15) || hundreds < 1 || hundreds > 5) goto bad_status; if (hundreds > 4) hundreds++; return hundreds * 16 + singles; bad_status: error(0, "WSP: Unknown status code used internally. Oops."); return 0x60; /* Status 500, or "Internal Server Error" */ } gateway-1.4.5/wap/wtp_pack.c0000644000175000017500000002221513227613126014434 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation includPd with the redistribution, * if any, must include the following acknowledgment: * "This product includes software eveloped by the * Kann†l Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_pack.c - WTP message packing module implementation * * By Aarno Syvänen for WapIT Ltd. */ #include "gwlib/gwlib.h" #include "wtp_pack.h" #include "wtp_pdu.h" /* * Readable names for octets */ enum { first_byte, second_byte, third_byte, fourth_byte }; /* * Types of header information added by the user (TPIs, or transportation * information items). */ enum { ERROR_DATA = 0x00, INFO_DATA = 0x01, OPTION = 0x02, PACKET_SEQUENCE_NUMBER = 0x03, SDU_BOUNDARY = 0x04, FRAME_BOUNDARY = 0x05 }; /***************************************************************************** * * Prototypes of internal functions */ /* * WTP defines SendTID and RcvTID. We should use SendTID in all PDUs * we send. The RcvTID is the one we got from the initial Invoke and * is the one we expect on all future PDUs for this machine. * SendTID is always RcvTID xor 0x8000. * * Note that when we are the Initiator, for example with WSP PUSH, * we must still store the RcvTID in machine->tid, to be consistent * with the current code. So we'll choose the SendTID and then calculate * the RcvTID. */ static unsigned short send_tid(unsigned short tid); /***************************************************************************** * * EXTERNAL FUNCTIONS: * */ WAPEvent *wtp_pack_invoke(WTPInitMachine *machine, WAPEvent *event) { WAPEvent *dgram = NULL; WTP_PDU *pdu = NULL; gw_assert(event->type == TR_Invoke_Req); pdu = wtp_pdu_create(Invoke); pdu->u.Invoke.con = 0; pdu->u.Invoke.gtr = 1; pdu->u.Invoke.ttr = 1; pdu->u.Invoke.rid = 0; pdu->u.Invoke.version = 0; pdu->u.Invoke.tid = send_tid(machine->tid); pdu->u.Invoke.tidnew = machine->tidnew; pdu->u.Invoke.user_data = octstr_duplicate(event->u.TR_Invoke_Req.user_data); pdu->u.Invoke.class = event->u.TR_Invoke_Req.tcl; pdu->u.Invoke.uack = event->u.TR_Invoke_Req.up_flag; dgram = wap_event_create(T_DUnitdata_Req); dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(machine->addr_tuple); dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu); wtp_pdu_destroy(pdu); return dgram; } WAPEvent *wtp_pack_result(WTPRespMachine *machine, WAPEvent *event) { WAPEvent *dgram = NULL; WTP_PDU *pdu = NULL; gw_assert(event->type == TR_Result_Req); pdu = wtp_pdu_create(Result); pdu->u.Result.con = 0; pdu->u.Result.gtr = 1; pdu->u.Result.ttr = 1; pdu->u.Result.rid = 0; pdu->u.Result.tid = send_tid(machine->tid); pdu->u.Result.user_data = octstr_duplicate(event->u.TR_Result_Req.user_data); dgram = wap_event_create(T_DUnitdata_Req); dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(machine->addr_tuple); dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu); wtp_pdu_destroy(pdu); return dgram; } WAPEvent *wtp_pack_sar_result(WTPRespMachine *machine, int psn) { WAPEvent *dgram = NULL; WTP_PDU *pdu = NULL; Octstr *data = NULL; int gtr, ttr; gw_assert(machine->sar && machine->sar->data); if (psn > machine->sar->nsegm) return dgram; ttr = psn == machine->sar->nsegm ? 1 : 0; gtr = ttr ? 0 : (psn+1)%SAR_GROUP_LEN ? 0 : 1; if (gtr || ttr) machine->sar->tr = 1; data = octstr_copy(machine->sar->data,psn*SAR_SEGM_SIZE,SAR_SEGM_SIZE); if (!psn) { pdu = wtp_pdu_create(Result); pdu->u.Result.con = 0; pdu->u.Result.gtr = gtr; pdu->u.Result.ttr = ttr; pdu->u.Result.rid = 0; pdu->u.Result.tid = send_tid(machine->tid); pdu->u.Result.user_data = data; } else { pdu = wtp_pdu_create(Segmented_result); pdu->u.Segmented_result.con = 0; pdu->u.Segmented_result.gtr = gtr; pdu->u.Segmented_result.ttr = ttr; pdu->u.Segmented_result.rid = 0; pdu->u.Segmented_result.tid = send_tid(machine->tid); pdu->u.Segmented_result.psn = psn; pdu->u.Segmented_result.user_data = data; } dgram = wap_event_create(T_DUnitdata_Req); dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(machine->addr_tuple); dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu); wtp_pdu_destroy(pdu); return dgram; } void wtp_pack_set_rid(WAPEvent *dgram, long rid) { gw_assert(dgram != NULL); gw_assert(dgram->type == T_DUnitdata_Req); octstr_set_bits(dgram->u.T_DUnitdata_Req.user_data, 7, 1, rid); } WAPEvent *wtp_pack_abort(long abort_type, long abort_reason, long tid, WAPAddrTuple *address) { WAPEvent *dgram; WTP_PDU *pdu; pdu = wtp_pdu_create(Abort); pdu->u.Abort.con = 0; pdu->u.Abort.abort_type = abort_type; pdu->u.Abort.tid = send_tid(tid); pdu->u.Abort.abort_reason = abort_reason; dgram = wap_event_create(T_DUnitdata_Req); dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address); dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu); wtp_pdu_destroy(pdu); return dgram; } WAPEvent *wtp_pack_ack(long ack_type, int rid_flag, long tid, WAPAddrTuple *address) { WAPEvent *dgram = NULL; WTP_PDU *pdu; pdu = wtp_pdu_create(Ack); pdu->u.Ack.con = 0; pdu->u.Ack.tidverify = ack_type; pdu->u.Ack.rid = rid_flag; pdu->u.Ack.tid = send_tid(tid); dgram = wap_event_create(T_DUnitdata_Req); dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address); dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu); wtp_pdu_destroy(pdu); return dgram; } WAPEvent *wtp_pack_sar_ack(long ack_type, long tid, WAPAddrTuple *address, int psn) { WAPEvent *dgram = NULL; WTP_PDU *pdu; unsigned char cpsn = psn; pdu = wtp_pdu_create(Ack); pdu->u.Ack.con = 1; pdu->u.Ack.tidverify = ack_type; pdu->u.Ack.rid = 0; pdu->u.Ack.tid = send_tid(tid); wtp_pdu_append_tpi(pdu, 3, octstr_create_from_data((char*) &cpsn, 1)); dgram = wap_event_create(T_DUnitdata_Req); dgram->u.T_DUnitdata_Req.addr_tuple = wap_addr_tuple_duplicate(address); dgram->u.T_DUnitdata_Req.user_data = wtp_pdu_pack(pdu); wtp_pdu_destroy(pdu); return dgram; } /**************************************************************************** * * INTERNAL FUNCTIONS: * */ static unsigned short send_tid(unsigned short tid) { return tid ^ 0x8000; } /****************************************************************************/ gateway-1.4.5/wap/wsp_push_client.h0000644000175000017500000000720613227613126016042 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_push_client.h: push client (for testing) interface * * By Aarno Syvänen for Wapit Ltd. */ #ifndef WSP_PUSH_CLIENT_H #define WSP_PUSH_CLIENT_H typedef struct WSPPushClientMachine WSPPushClientMachine; #include "gwlib/gwlib.h" #include "wap_addr.h" #include "wap_events.h" #include "wap.h" /* * Push client states */ enum push_client_states { #define PUSH_CLIENT_STATE_NAME(state) state, #define ROW(state, event, condition, action, next_state) #include "wsp_push_client_states.def" push_client_states_count }; typedef enum push_client_states push_client_states; /* * Declaration of push client state machine. We define one macro for every * separate type. */ struct WSPPushClientMachine { long cpid; #define INTEGER(name) long name; #define HTTPHEADERS(name) List *name; #define OCTSTR(name) Octstr *name; #define MACHINE(fields) fields #include "wsp_push_client_machine.def" }; #endif gateway-1.4.5/wap/wsp_headers.c0000644000175000017500000026425613227613126015145 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_headers.c - Implement WSP PDU headers * * References: * WSP specification version 1.1 * RFC 2068, Hypertext Transfer Protocol HTTP/1.1 * RFC 2616, Hypertext Transfer Protocol HTTP/1.1 * * For push headers, WSP specification, June 2000 conformance release * * This file has two parts. The first part decodes the request's headers * from WSP to HTTP. The second part encodes the response's headers from * HTTP to WSP. * * Note that push header encoding and decoding are divided two parts: * first decoding and encoding numeric values and then packing these values * into WSP format and unpacking them from WSP format. This module contains * only packing and unpacking parts. * * Some functions are declared non-static to provide them for external use, * ie. the MMS encapsulation encoding and decoding routines implemented in * other files. * * Richard Braakman * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" #include "wsp.h" #include "wsp_headers.h" #include "wsp_strings.h" /* * get field value and return its type as predefined data types * There are three kinds of field encodings: * WSP_FIELD_VALUE_NUL_STRING: 0-terminated string * WSP_FIELD_VALUE_ENCODED: short integer, range 0-127 * WSP_FIELD_VALUE_DATA: octet string defined by length * The function will return one of those values, and modify the parse context * to make it easy to get the field data. * WSP_FIELD_VALUE_NUL_STRING: Leave parsing position at start of string * WSP_FIELD_VALUE_ENCODED: Put value in *well_known_value, leave * parsing position after field value. * WSP_FIELD_VALUE_DATA: Leave parsing position at start of data, and set * a parse limit at the end of data. */ int wsp_field_value(ParseContext *context, int *well_known_value) { int val; unsigned long len; val = parse_get_char(context); if (val > 0 && val < 31) { *well_known_value = -1; parse_limit(context, val); return WSP_FIELD_VALUE_DATA; } else if (val == 31) { *well_known_value = -1; len = parse_get_uintvar(context); parse_limit(context, len); return WSP_FIELD_VALUE_DATA; } else if (val > 127) { *well_known_value = val - 128; return WSP_FIELD_VALUE_ENCODED; } else if (val == WSP_QUOTE || val == '"') { /* 127 */ *well_known_value = -1; /* We already consumed the Quote */ return WSP_FIELD_VALUE_NUL_STRING; } else { /* implicite val == 0 */ *well_known_value = -1; /* Un-parse the character we just read */ parse_skip(context, -1); return WSP_FIELD_VALUE_NUL_STRING; } } /* Skip over a field_value as defined above. */ void wsp_skip_field_value(ParseContext *context) { int val; int ret; ret = wsp_field_value(context, &val); if (ret == WSP_FIELD_VALUE_DATA) { parse_skip_to_limit(context); parse_pop_limit(context); } } /* Multi-octet-integer is defined in 8.4.2.1 */ static long unpack_multi_octet_integer(ParseContext *context, long len) { long val = 0; if (len > (long) sizeof(val) || len < 0) return -1; while (len > 0) { val = val * 256 + parse_get_char(context); len--; } if (parse_error(context)) return -1; return val; } /* This function is similar to field_value, but it is used at various * places in the grammar where we expect either an Integer-value * or some kind of NUL-terminated text. * * Return values are just like field_value except that WSP_FIELD_VALUE_DATA * will not be returned. * * As a special case, we parse a 0-length Long-integer as an * WSP_FIELD_VALUE_NONE, so that we can distinguish between No-value * and an Integer-value of 0. (A real integer 0 would be encoded as * a Short-integer; the definition of Long-integer seems to allow * 0-length integers, but the definition of Multi-octet-integer does * not, so this is an unclear area of the specification.) */ int wsp_secondary_field_value(ParseContext *context, long *result) { int val; long length; val = parse_get_char(context); if (val == 0) { *result = 0; return WSP_FIELD_VALUE_NONE; } else if (val > 0 && val < 31) { *result = unpack_multi_octet_integer(context, val); return WSP_FIELD_VALUE_ENCODED; } else if (val == 31) { length = parse_get_uintvar(context); *result = unpack_multi_octet_integer(context, length); return WSP_FIELD_VALUE_ENCODED; } else if (val > 127) { *result = val - 128; return WSP_FIELD_VALUE_ENCODED; } else if (val == WSP_QUOTE) { /* 127 */ *result = -1; return WSP_FIELD_VALUE_NUL_STRING; } else { *result = -1; /* Un-parse the character we just read */ parse_skip(context, -1); return WSP_FIELD_VALUE_NUL_STRING; } } /* Integer-value is defined in 8.4.2.3 */ Octstr *wsp_unpack_integer_value(ParseContext *context) { Octstr *decoded; unsigned long value; int val; val = parse_get_char(context); if (val < 31) { value = unpack_multi_octet_integer(context, val); } else if (val > 127) { value = val - 128; } else { warning(0, "WSP headers: bad integer-value."); return NULL; } decoded = octstr_create(""); octstr_append_decimal(decoded, value); return decoded; } /* Q-value is defined in 8.4.2.3 */ static Octstr *convert_q_value(int q) { Octstr *result = NULL; /* When quality factor 0 and quality factors with one or two * decimal digits are encoded, they shall be multiplied by 100 * and incremented by one, so that they encode as a one-octet * value in range 1-100. */ if (q >= 1 && q <= 100) { q = q - 1; result = octstr_create("0."); octstr_append_char(result, (q / 10) + '0'); if (q % 10 > 0) octstr_append_char(result, (q % 10) + '0'); return result; } /* Three decimal quality factors shall be multiplied with 1000 * and incremented by 100. */ if (q > 100 && q <= 1000) { q = q - 100; result = octstr_create("0."); octstr_append_char(result, (q / 100) + '0'); if (q % 100 > 0) octstr_append_char(result, (q / 10 % 10) + '0'); if (q % 10 > 0) octstr_append_char(result, (q % 10) + '0'); return result; } return NULL; } /* Q-value is defined in 8.4.2.3 */ static Octstr *unpack_q_value(ParseContext *context) { int c, c2; c = parse_get_char(context); if (c < 0) return NULL; if (c & 0x80) { c2 = parse_get_char(context); if (c2 < 0 || (c2 & 0x80)) return NULL; c = ((c & 0x7f) << 8) + c2; } return convert_q_value(c); } /* Version-value is defined in 8.4.2.3. Encoding-Version uses coding * defined in this chapter, see 8.4.2.70. */ Octstr *wsp_unpack_version_value(long value) { Octstr *result; int major, minor; major = ((value >> 4) & 0x7); minor = (value & 0xf); result = octstr_create(""); octstr_append_char(result, major + '0'); if (minor != 15) { octstr_append_char(result, '.'); octstr_append_decimal(result, minor); } return result; } static Octstr *unpack_encoding_version(ParseContext *context) { int ch; ch = parse_get_char(context); if (ch < 128) { warning(0, "WSP: bad Encoding-Version value"); return NULL; } return wsp_unpack_version_value(((long) ch) - 128); } /* Called with the parse limit set to the end of the parameter data, * and decoded containing the unpacked header line so far. * Parameter is defined in 8.4.2.4. */ static int unpack_parameter(ParseContext *context, Octstr *decoded) { Octstr *parm = NULL; Octstr *value = NULL; int ret; long type; long val; ret = wsp_secondary_field_value(context, &type); if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) { warning(0, "bad parameter"); goto error; } if (ret == WSP_FIELD_VALUE_ENCODED) { /* Typed-parameter */ parm = wsp_parameter_to_string(type); if (!parm) warning(0, "Unknown parameter %02lx.", type); } else if (ret == WSP_FIELD_VALUE_NUL_STRING) { /* Untyped-parameter */ parm = parse_get_nul_string(context); if (!parm) warning(0, "Format error in parameter."); type = -1; /* We treat Untyped-value as a special type. Its format * Integer-value | Text-value is pretty similar to most * typed formats. */ } else { panic(0, "Unknown secondary field value type %d.", ret); } if (type == 0x00) /* q */ value = unpack_q_value(context); else { ret = wsp_secondary_field_value(context, &val); if (parse_error(context)) { warning(0, "bad parameter value"); goto error; } if (ret == WSP_FIELD_VALUE_ENCODED) { switch (type) { case -1: /* untyped: Integer-value */ case 3: /* type: Integer-value */ case 8: /* padding: Short-integer */ value = octstr_create(""); octstr_append_decimal(value, val); break; case 0: /* q, already handled above */ gw_assert(0); break; case 1: /* charset: Well-known-charset */ value = wsp_charset_to_string(val); if (!value) warning(0, "Unknown charset %04lx.", val); break; case 2: /* level: Version-value */ value = wsp_unpack_version_value(val); break; case 5: /* name: Text-string */ case 6: /* filename: Text-string */ warning(0, "Text-string parameter with integer encoding"); break; case 7: /* differences: Field-name */ value = wsp_header_to_string(val); if (!value) warning(0, "Unknown differences header %02lx.", val); break; default: warning(0, "Unknown parameter encoding %02lx.", type); break; } } else if (ret == WSP_FIELD_VALUE_NONE) { value = octstr_create(""); } else { gw_assert(ret == WSP_FIELD_VALUE_NUL_STRING); /* Text-value = No-value | Token-text | Quoted-string */ value = parse_get_nul_string(context); if (!value) warning(0, "Format error in parameter value."); else { if (octstr_get_char(value, 0) == '"') { /* Quoted-string */ octstr_append_char(value, '"'); } else { /* DAVI! */ octstr_insert(value, octstr_imm("\""), 0); octstr_append_char(value, '"'); } } } } if (!parm || !value) { warning(0, "Skipping parameters"); goto error; } octstr_append(decoded, octstr_imm("; ")); octstr_append(decoded, parm); if (octstr_len(value) > 0) { octstr_append_char(decoded, '='); octstr_append(decoded, value); } octstr_destroy(parm); octstr_destroy(value); return 0; error: parse_skip_to_limit(context); octstr_destroy(parm); octstr_destroy(value); parse_set_error(context); return -1; } void wsp_unpack_all_parameters(ParseContext *context, Octstr *decoded) { int ret = 0; while (ret >= 0 && !parse_error(context) && parse_octets_left(context) > 0) { ret = unpack_parameter(context, decoded); } } /* Unpack parameters in the format used by credentials and challenge, * which differs from the format used by all other HTTP headers. */ static void unpack_broken_parameters(ParseContext *context, Octstr *decoded) { int ret = 0; int first = 1; long pos; while (ret >= 0 && !parse_error(context) && parse_octets_left(context) > 0) { pos = octstr_len(decoded); ret = unpack_parameter(context, decoded); if (ret >= 0) { if (first) { /* Zap ';' */ octstr_delete(decoded, pos, 1); first = 0; } else { /* Replace ';' with ',' */ octstr_set_char(decoded, pos, first ? ' ' : ','); } } } } static void unpack_optional_q_value(ParseContext *context, Octstr *decoded) { if (parse_octets_left(context) > 0) { Octstr *qval = unpack_q_value(context); if (qval) { octstr_append(decoded, octstr_imm("; q=")); octstr_append(decoded, qval); octstr_destroy(qval); } else warning(0, "Bad q-value"); } } /* Date-value is defined in 8.4.2.3. */ Octstr *wsp_unpack_date_value(ParseContext *context) { unsigned long timeval; int length; length = parse_get_char(context); if (length > 30) { warning(0, "WSP headers: bad date-value."); return NULL; } timeval = unpack_multi_octet_integer(context, length); if (timeval < 0) { warning(0, "WSP headers: cannot unpack date-value."); return NULL; } return date_format_http(timeval); } /* Accept-general-form is defined in 8.4.2.7 */ Octstr *wsp_unpack_accept_general_form(ParseContext *context) { Octstr *decoded = NULL; int ret; long val; /* The definition for Accept-general-form looks quite complicated, * but the "Q-token Q-value" part fits the normal expansion of * Parameter, so it simplifies to: * Value-length Media-range *(Parameter) * and we've already parsed Value-length. */ /* We use this function to parse content-general-form too, * because its definition of Media-type is identical to Media-range. */ ret = wsp_secondary_field_value(context, &val); if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) { warning(0, "bad media-range or media-type"); return NULL; } if (ret == WSP_FIELD_VALUE_ENCODED) { decoded = wsp_content_type_to_string(val); if (!decoded) { warning(0, "Unknown content type 0x%02lx.", val); return NULL; } } else if (ret == WSP_FIELD_VALUE_NUL_STRING) { decoded = parse_get_nul_string(context); if (!decoded) { warning(0, "Format error in content type"); return NULL; } } else { panic(0, "Unknown secondary field value type %d.", ret); } wsp_unpack_all_parameters(context, decoded); return decoded; } /* Accept-charset-general-form is defined in 8.4.2.8 */ Octstr *wsp_unpack_accept_charset_general_form(ParseContext *context) { Octstr *decoded = NULL; int ret; long val; ret = wsp_secondary_field_value(context, &val); if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) { warning(0, "Bad accept-charset-general-form"); return NULL; } if (ret == WSP_FIELD_VALUE_ENCODED) { decoded = wsp_charset_to_string(val); if (!decoded) { warning(0, "Unknown character set %04lx.", val); return NULL; } } else if (ret == WSP_FIELD_VALUE_NUL_STRING) { decoded = parse_get_nul_string(context); if (!decoded) { warning(0, "Format error in accept-charset"); return NULL; } } else { panic(0, "Unknown secondary field value type %d.", ret); } unpack_optional_q_value(context, decoded); return decoded; } /* Accept-language-general-form is defined in 8.4.2.10 */ static Octstr *unpack_accept_language_general_form(ParseContext *context) { Octstr *decoded = NULL; int ret; long val; ret = wsp_secondary_field_value(context, &val); if (parse_error(context) || ret == WSP_FIELD_VALUE_NONE) { warning(0, "Bad accept-language-general-form"); return NULL; } if (ret == WSP_FIELD_VALUE_ENCODED) { /* Any-language is handled by a special entry in the * language table. */ decoded = wsp_language_to_string(val); if (!decoded) { warning(0, "Unknown language %02lx.", val); return NULL; } } else if (ret == WSP_FIELD_VALUE_NUL_STRING) { decoded = parse_get_nul_string(context); if (!decoded) { warning(0, "Format error in accept-language"); return NULL; } } else { panic(0, "Unknown secondary field value type %d.", ret); } unpack_optional_q_value(context, decoded); return decoded; } /* Credentials is defined in 8.4.2.5 */ static Octstr *unpack_credentials(ParseContext *context) { Octstr *decoded = NULL; int val; val = parse_peek_char(context); if (val == BASIC_AUTHENTICATION) { Octstr *userid, *password; parse_skip(context, 1); userid = parse_get_nul_string(context); password = parse_get_nul_string(context); if (parse_error(context)) { octstr_destroy(userid); octstr_destroy(password); } else { /* Create the user-pass cookie */ decoded = octstr_duplicate(userid); octstr_append_char(decoded, ':'); octstr_append(decoded, password); /* XXX Deal with cookies that overflow the 76-per-line * limit of base64. Either go through and zap all * CR LF sequences, or give the conversion function * a flag or something to leave them out. */ octstr_binary_to_base64(decoded); /* Zap the CR LF at the end */ octstr_delete(decoded, octstr_len(decoded) - 2, 2); octstr_insert_data(decoded, 0, "Basic ", 6); octstr_destroy(userid); octstr_destroy(password); } } else if (val >= 32 && val < 128) { /* Generic authentication scheme */ decoded = parse_get_nul_string(context); if (decoded) unpack_broken_parameters(context, decoded); } if (!decoded) warning(0, "Cannot parse credentials."); return decoded; } /* Credentials is defined in 8.4.2.5 * but as Proxy-Authentication is to be used by kannel, * a simplier to parse version is used here */ static Octstr *proxy_unpack_credentials(ParseContext *context) { Octstr *decoded = NULL; int val; val = parse_peek_char(context); if (val == BASIC_AUTHENTICATION) { Octstr *userid, *password; parse_skip(context, 1); userid = parse_get_nul_string(context); password = parse_get_nul_string(context); if (parse_error(context)) { octstr_destroy(userid); octstr_destroy(password); } else { /* Create the user-pass cookie */ decoded = octstr_duplicate(userid); octstr_append_char(decoded, ':'); octstr_append(decoded, password); octstr_destroy(userid); octstr_destroy(password); } } else if (val >= 32 && val < 128) { /* Generic authentication scheme */ decoded = parse_get_nul_string(context); if (decoded) unpack_broken_parameters(context, decoded); } if (!decoded) warning(0, "Cannot parse credentials."); return decoded; } /* Challenge is defined in 8.4.2.5 */ static Octstr *unpack_challenge(ParseContext *context) { Octstr *decoded = NULL; Octstr *realm_value = NULL; int val; val = parse_peek_char(context); if (val == BASIC_AUTHENTICATION) { parse_skip(context, 1); realm_value = parse_get_nul_string(context); if (realm_value) { decoded = octstr_create("Basic realm=\""); octstr_append(decoded, realm_value); octstr_append_char(decoded, '"'); } } else if (val >= 32 && val < 128) { /* Generic authentication scheme */ decoded = parse_get_nul_string(context); realm_value = parse_get_nul_string(context); if (decoded && realm_value) { octstr_append(decoded, octstr_imm(" realm=\"")); octstr_append(decoded, realm_value); octstr_append_char(decoded, '"'); if (parse_octets_left(context) > 0) { /* Prepare for following parameter list */ octstr_append_char(decoded, ','); } unpack_broken_parameters(context, decoded); } } if (!decoded) warning(0, "Cannot parse challenge."); octstr_destroy(realm_value); return decoded; } /* Content-range is defined in 8.4.2.23 */ static Octstr *unpack_content_range(ParseContext *context) { /* We'd have to figure out how to access the content range * length (i.e. user_data size) from here to parse this, * and I don't see why the _client_ would send this in any case. */ warning(0, "Decoding of content-range not supported"); return NULL; /* Octstr *decoded = NULL; unsigned long first_byte_pos, entity_length; unsigned long last_byte_pos; first_byte_pos = parse_get_uintvar(context); entity_length = parse_get_uintvar(context); if (parse_error(context)) { warning(0, "Cannot parse content-range header"); return NULL; } decoded = octstr_create("bytes "); octstr_append_decimal(decoded, first_byte_pos); octstr_append_char(decoded, '-'); octstr_append_decimal(decoded, last_byte_pos); octstr_append_char(decoded, '/'); octstr_append_decimal(decoded, entity_length); return decoded; */ } /* Field-name is defined in 8.4.2.6 */ static Octstr *unpack_field_name(ParseContext *context) { Octstr *decoded = NULL; int ret; int val; ret = wsp_field_value(context, &val); if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) { warning(0, "Bad field-name encoding"); return NULL; } if (ret == WSP_FIELD_VALUE_ENCODED) { decoded = wsp_header_to_string(val); if (!decoded) { warning(0, "Unknown field-name 0x%02x.", val); return NULL; } } else if (ret == WSP_FIELD_VALUE_NUL_STRING) { decoded = parse_get_nul_string(context); if (!decoded) { warning(0, "Bad field-name encoding"); return NULL; } } else { panic(0, "Unknown field value type %d.", ret); } return decoded; } /* Cache-directive is defined in 8.4.2.15 */ static Octstr *unpack_cache_directive(ParseContext *context) { Octstr *decoded = NULL; int ret; int val; ret = wsp_field_value(context, &val); if (parse_error(context) || ret == WSP_FIELD_VALUE_DATA) { warning(0, "Bad cache-directive"); goto error; } if (ret == WSP_FIELD_VALUE_ENCODED) { decoded = wsp_cache_control_to_string(val); if (!decoded) { warning(0, "Bad cache-directive 0x%02x.", val); goto error; } octstr_append_char(decoded, '='); switch (val) { case WSP_CACHE_CONTROL_NO_CACHE: case WSP_CACHE_CONTROL_PRIVATE: if (parse_octets_left(context) == 0) { warning(0, "Too short cache-directive"); goto error; } octstr_append_char(decoded, '"'); do { Octstr *fieldname = unpack_field_name(context); if (!fieldname) { warning(0, "Bad field name in cache directive"); goto error; } octstr_append(decoded, fieldname); octstr_destroy(fieldname); if (parse_octets_left(context) > 0) { octstr_append_char(decoded, ','); octstr_append_char(decoded, ' '); } } while (parse_octets_left(context) > 0 && !parse_error(context)); octstr_append_char(decoded, '"'); break; case WSP_CACHE_CONTROL_MAX_AGE: case WSP_CACHE_CONTROL_MAX_STALE: case WSP_CACHE_CONTROL_MIN_FRESH: { Octstr *seconds; seconds = wsp_unpack_integer_value(context); if (!seconds) { warning(0, "Bad integer value in cache directive"); goto error; } octstr_append(decoded, seconds); octstr_destroy(seconds); } break; default: warning(0, "Unexpected value 0x%02x in cache directive.", val); break; } } else if (ret == WSP_FIELD_VALUE_NUL_STRING) { /* XXX: WSP grammar seems wrong here. It works out * to Token-text followed by Parameter. But the * grammar in RFC2616 works out to a key = value * pair, i.e. only a Parameter. */ decoded = parse_get_nul_string(context); if (!decoded) { warning(0, "Format error in cache-control."); return NULL; } /* Yes, the grammar allows only one */ unpack_parameter(context, decoded); } else { panic(0, "Unknown field value type %d.", ret); } return decoded; error: octstr_destroy(decoded); return NULL; } /* Retry-after is defined in 8.4.2.44 */ static Octstr *unpack_retry_after(ParseContext *context) { int selector; selector = parse_get_char(context); if (selector == ABSOLUTE_TIME) { return wsp_unpack_date_value(context); } else if (selector == RELATIVE_TIME) { return wsp_unpack_integer_value(context); } else { warning(0, "Cannot parse retry-after value."); return NULL; } } /* Disposition is defined in 8.4.2.53 */ static Octstr *unpack_disposition(ParseContext *context) { Octstr *decoded = NULL; int selector; selector = parse_get_char(context) - 128; decoded = wsp_disposition_to_string(selector); if (!decoded) { warning(0, "Cannot parse content-disposition value."); return NULL; } wsp_unpack_all_parameters(context, decoded); return decoded; } /* Range-value is defined in 8.4.2.42 */ static Octstr *unpack_range_value(ParseContext *context) { Octstr *decoded = NULL; int selector; unsigned long first_byte_pos, last_byte_pos, suffix_length; selector = parse_get_char(context); if (selector == BYTE_RANGE) { first_byte_pos = parse_get_uintvar(context); if (parse_error(context)) goto error; decoded = octstr_create("bytes = "); octstr_append_decimal(decoded, first_byte_pos); octstr_append_char(decoded, '-'); last_byte_pos = parse_get_uintvar(context); if (parse_error(context)) { /* last_byte_pos is optional */ parse_clear_error(context); } else { octstr_append_decimal(decoded, last_byte_pos); } } else if (selector == SUFFIX_BYTE_RANGE) { suffix_length = parse_get_uintvar(context); if (parse_error(context)) goto error; decoded = octstr_create("bytes = -"); octstr_append_decimal(decoded, suffix_length); } else { goto error; } return decoded; error: warning(0, "Bad format for range-value."); octstr_destroy(decoded); return NULL; } /* Warning-value is defined in 8.4.2.51 */ static Octstr *unpack_warning_value(ParseContext *context) { Octstr *decoded = NULL; Octstr *warn_code = NULL; Octstr *warn_agent = NULL; Octstr *warn_text = NULL; unsigned char quote = '"'; warn_code = wsp_unpack_integer_value(context); warn_agent = parse_get_nul_string(context); if (warn_agent && octstr_get_char(warn_agent, 0) == WSP_QUOTE) octstr_delete(warn_agent, 0, 1); warn_text = parse_get_nul_string(context); if (warn_text && octstr_get_char(warn_text, 0) == WSP_QUOTE) octstr_delete(warn_text, 0, 1); if (octstr_get_char(warn_text, 0) != quote) octstr_insert_data(warn_text, 0, (char *)"e, 1); if (octstr_get_char(warn_text, octstr_len(warn_text) - 1) != quote) octstr_append_char(warn_text, quote); if (parse_error(context) || !warn_agent || !warn_text) goto error; decoded = octstr_create(""); octstr_append(decoded, warn_code); octstr_append_char(decoded, ' '); octstr_append(decoded, warn_agent); octstr_append_char(decoded, ' '); octstr_append(decoded, warn_text); octstr_destroy(warn_agent); octstr_destroy(warn_code); octstr_destroy(warn_text); return decoded; error: warning(0, "Bad format for warning-value."); octstr_destroy(warn_agent); octstr_destroy(warn_code); octstr_destroy(warn_text); octstr_destroy(decoded); return NULL; } void wsp_unpack_well_known_field(List *unpacked, int field_type, ParseContext *context) { int val, ret; unsigned char *headername = NULL; unsigned char *ch = NULL; Octstr *decoded = NULL; ret = wsp_field_value(context, &val); if (parse_error(context)) { warning(0, "Faulty header, skipping remaining headers."); parse_skip_to_limit(context); return; } headername = wsp_header_to_cstr(field_type); /* headername can still be NULL. This is checked after parsing * the field value. We want to parse the value before exiting, * so that we are ready for the next header. */ /* The following code must set "ch" or "decoded" to a non-NULL * value if the header is valid. */ if (ret == WSP_FIELD_VALUE_NUL_STRING) { /* We allow any header to have a text value, even if that * is not defined in the grammar. Be generous in what * you accept, etc. */ /* This covers Text-string, Token-Text, and Uri-value rules */ decoded = parse_get_nul_string(context); } else if (ret == WSP_FIELD_VALUE_ENCODED) { switch (field_type) { case WSP_HEADER_ACCEPT: case WSP_HEADER_CONTENT_TYPE: ch = wsp_content_type_to_cstr(val); if (!ch) warning(0, "Unknown content type 0x%02x.", val); break; case WSP_HEADER_ACCEPT_CHARSET: ch = wsp_charset_to_cstr(val); if (!ch) warning(0, "Unknown charset 0x%02x.", val); break; case WSP_HEADER_ACCEPT_ENCODING: case WSP_HEADER_CONTENT_ENCODING: ch = wsp_encoding_to_cstr(val); if (!ch) warning(0, "Unknown encoding 0x%02x.", val); break; case WSP_HEADER_ACCEPT_LANGUAGE: case WSP_HEADER_CONTENT_LANGUAGE: ch = wsp_language_to_cstr(val); if (!ch) warning(0, "Unknown language 0x%02x.", val); break; case WSP_HEADER_ACCEPT_RANGES: ch = wsp_ranges_to_cstr(val); if (!ch) warning(0, "Unknown ranges value 0x%02x.", val); break; case WSP_HEADER_AGE: case WSP_HEADER_CONTENT_LENGTH: case WSP_HEADER_MAX_FORWARDS: /* Short-integer version of Integer-value */ decoded = octstr_create(""); octstr_append_decimal(decoded, val); break; case WSP_HEADER_ALLOW: case WSP_HEADER_PUBLIC: ch = wsp_method_to_cstr(val); if (!ch) { /* FIXME Support extended methods */ warning(0, "Unknown method 0x%02x.", val); } break; case WSP_HEADER_CACHE_CONTROL: case WSP_HEADER_CACHE_CONTROL_V13: case WSP_HEADER_CACHE_CONTROL_V14: ch = wsp_cache_control_to_cstr(val); if (!ch) warning(0, "Unknown cache-control value 0x%02x.", val); break; case WSP_HEADER_CONNECTION: ch = wsp_connection_to_cstr(val); if (!ch) warning(0, "Unknown connection value 0x%02x.", val); break; case WSP_HEADER_PRAGMA: if (val == 0) ch = (unsigned char *)"no-cache"; else warning(0, "Unknown pragma value 0x%02x.", val); break; case WSP_HEADER_TRANSFER_ENCODING: ch = wsp_transfer_encoding_to_cstr(val); if (!ch) warning(0, "Unknown transfer encoding value 0x%02x.", val); break; case WSP_HEADER_VARY: ch = wsp_header_to_cstr(val); if (!ch) warning(0, "Unknown Vary field name 0x%02x.", val); break; case WSP_HEADER_WARNING: decoded = octstr_create(""); octstr_append_decimal(decoded, val); break; case WSP_HEADER_BEARER_INDICATION: ch = wsp_bearer_indication_to_cstr(val); if (!ch) warning(0, "Unknown Bearer-Indication field name 0x%02x.", val); break; case WSP_HEADER_ACCEPT_APPLICATION: ch = wsp_application_id_to_cstr(val); if (!ch) warning(0, "Unknown Accept-Application field name 0x%02x.", val); break; default: if (headername) { warning(0, "Did not expect short-integer with " "'%s' header, skipping.", headername); } break; } } else if (ret == WSP_FIELD_VALUE_DATA) { switch (field_type) { case WSP_HEADER_ACCEPT: case WSP_HEADER_CONTENT_TYPE: /* Content-general-form and Accept-general-form * are defined separately in WSP, but their * definitions are equivalent. */ decoded = wsp_unpack_accept_general_form(context); break; case WSP_HEADER_ACCEPT_CHARSET: decoded = wsp_unpack_accept_charset_general_form(context); break; case WSP_HEADER_ACCEPT_LANGUAGE: decoded = unpack_accept_language_general_form(context); break; case WSP_HEADER_AGE: case WSP_HEADER_CONTENT_LENGTH: case WSP_HEADER_MAX_FORWARDS: case WSP_HEADER_BEARER_INDICATION: case WSP_HEADER_ACCEPT_APPLICATION: /* Long-integer version of Integer-value */ { long l = unpack_multi_octet_integer(context, parse_octets_left(context)); decoded = octstr_create(""); octstr_append_decimal(decoded, l); } break; case WSP_HEADER_AUTHORIZATION: decoded = unpack_credentials(context); break; case WSP_HEADER_PROXY_AUTHORIZATION: decoded = proxy_unpack_credentials(context); break; case WSP_HEADER_CACHE_CONTROL: decoded = unpack_cache_directive(context); break; case WSP_HEADER_CONTENT_MD5: decoded = parse_get_octets(context, parse_octets_left(context)); octstr_binary_to_base64(decoded); /* Zap the CR LF sequence at the end */ octstr_delete(decoded, octstr_len(decoded) - 2, 2); break; case WSP_HEADER_CONTENT_RANGE: decoded = unpack_content_range(context); break; case WSP_HEADER_DATE: case WSP_HEADER_EXPIRES: case WSP_HEADER_IF_MODIFIED_SINCE: case WSP_HEADER_IF_RANGE: case WSP_HEADER_IF_UNMODIFIED_SINCE: case WSP_HEADER_LAST_MODIFIED: /* Back up to get the length byte again */ parse_skip(context, -1); decoded = wsp_unpack_date_value(context); break; case WSP_HEADER_PRAGMA: /* The value is a bare Parameter, without a preceding * header body. unpack_parameter wasn't really * designed for this. We work around it here. */ decoded = octstr_create(""); if (unpack_parameter(context, decoded) < 0) { octstr_destroy(decoded); decoded = NULL; } else { /* Remove the leading "; " */ octstr_delete(decoded, 0, 2); } break; case WSP_HEADER_PROXY_AUTHENTICATE: case WSP_HEADER_WWW_AUTHENTICATE: decoded = unpack_challenge(context); break; case WSP_HEADER_RANGE: decoded = unpack_range_value(context); break; case WSP_HEADER_RETRY_AFTER: decoded = unpack_retry_after(context); break; case WSP_HEADER_WARNING: decoded = unpack_warning_value(context); break; case WSP_HEADER_CONTENT_DISPOSITION: decoded = unpack_disposition(context); break; case WSP_HEADER_ENCODING_VERSION: decoded = unpack_encoding_version(context); break; default: if (headername) { warning(0, "Did not expect value-length with " "'%s' header, skipping.", headername); } break; } if (headername && parse_octets_left(context) > 0) { warning(0, "WSP: %s: skipping %ld trailing octets.", headername, parse_octets_left(context)); } parse_skip_to_limit(context); parse_pop_limit(context); } else { panic(0, "Unknown field-value type %d.", ret); } if (ch == NULL && decoded != NULL) ch = (unsigned char *)octstr_get_cstr(decoded); if (ch == NULL) goto value_error; if (!headername) { warning(0, "Unknown header number 0x%02x.", field_type); goto value_error; } http_header_add(unpacked, (char *)headername,(char *) ch); octstr_destroy(decoded); return; value_error: warning(0, "Skipping faulty header."); octstr_destroy(decoded); } void wsp_unpack_app_header(List *unpacked, ParseContext *context) { Octstr *header = NULL; Octstr *value = NULL; header = parse_get_nul_string(context); value = parse_get_nul_string(context); if (header && value) { http_header_add(unpacked, octstr_get_cstr(header), octstr_get_cstr(value)); } if (parse_error(context)) warning(0, "Error parsing application-header."); octstr_destroy(header); octstr_destroy(value); } List *wsp_headers_unpack(Octstr *headers, int content_type_present) { ParseContext *context; int byte; List *unpacked; int code_page; unpacked = http_create_empty_headers(); context = parse_context_create(headers); if (octstr_len(headers) > 0) { debug("wsp", 0, "WSP: decoding headers:"); octstr_dump(headers, 0); } if (content_type_present) wsp_unpack_well_known_field(unpacked, WSP_HEADER_CONTENT_TYPE, context); code_page = 1; /* default */ while (parse_octets_left(context) > 0 && !parse_error(context)) { byte = parse_get_char(context); if (byte == 127 || (byte >= 1 && byte <= 31)) { if (byte == 127) code_page = parse_get_char(context); else code_page = byte; if (code_page == 1) info(0, "Returning to code page 1 (default)."); else { warning(0, "Shift to unknown code page %d.", code_page); warning(0, "Will try to skip headers until " "next known code page."); } } else if (byte >= 128) { /* well-known-header */ if (code_page == 1) wsp_unpack_well_known_field(unpacked, byte - 128, context); else { debug("wsp", 0, "Skipping field 0x%02x.", byte); wsp_skip_field_value(context); } } else if (byte > 31 && byte < 127) { /* Un-parse the character we just read */ parse_skip(context, -1); wsp_unpack_app_header(unpacked, context); } else { warning(0, "Unsupported token or header (start 0x%x)", byte); break; } } if (gwlist_len(unpacked) > 0) { long i; debug("wsp", 0, "WSP: decoded headers:"); for (i = 0; i < gwlist_len(unpacked); i++) { Octstr *header = gwlist_get(unpacked, i); debug("wsp", 0, "%s", octstr_get_cstr(header)); } debug("wsp", 0, "WSP: End of decoded headers."); } parse_context_destroy(context); return unpacked; } /**********************************************************************/ /* Start of header packing code (HTTP to WSP) */ /**********************************************************************/ static int pack_accept(Octstr *packet, Octstr *value); static int pack_accept_charset(Octstr *packet, Octstr *value); static int pack_accept_encoding(Octstr *packet, Octstr *value); static int pack_accept_language(Octstr *packet, Octstr *value); static int pack_cache_control(Octstr *packet, Octstr *value); static int pack_challenge(Octstr *packet, Octstr *value); static int pack_connection(Octstr *packet, Octstr *value); static int pack_content_disposition(Octstr *packet, Octstr *value); static int pack_content_range(Octstr *packet, Octstr *value); static int pack_credentials(Octstr *packet, Octstr *value); static int pack_encoding(Octstr *packet, Octstr *value); static int pack_expires(Octstr *packet, Octstr *value); static int pack_field_name(Octstr *packet, Octstr *value); static int pack_if_range(Octstr *packet, Octstr *value); static int pack_language(Octstr *packet, Octstr *value); static int pack_md5(Octstr *packet, Octstr *value); static int pack_method(Octstr *packet, Octstr *value); static int pack_pragma(Octstr *packet, Octstr *value); static int pack_range(Octstr *packet, Octstr *value); static int pack_range_unit(Octstr *packet, Octstr *value); static int pack_transfer_encoding(Octstr *packet, Octstr *value); static int pack_uri(Octstr *packet, Octstr *value); static int pack_warning(Octstr *packet, Octstr *value); /* these are used in MMS encapsulation code too */ struct headerinfo headerinfo[] = { { WSP_HEADER_ACCEPT, pack_accept, LIST }, { WSP_HEADER_ACCEPT_CHARSET, pack_accept_charset, LIST }, { WSP_HEADER_ACCEPT_ENCODING, pack_accept_encoding, LIST }, { WSP_HEADER_ACCEPT_LANGUAGE, pack_accept_language, LIST }, { WSP_HEADER_ACCEPT_RANGES, pack_range_unit, LIST }, { WSP_HEADER_AGE, wsp_pack_integer_string, 0 }, /* pack_method is slightly too general because Allow is only * supposed to encode well-known-methods. */ { WSP_HEADER_ALLOW, pack_method, LIST }, { WSP_HEADER_AUTHORIZATION, pack_credentials, BROKEN_LIST }, { WSP_HEADER_CACHE_CONTROL, pack_cache_control, LIST }, { WSP_HEADER_CACHE_CONTROL_V13, pack_cache_control, LIST }, { WSP_HEADER_CACHE_CONTROL_V14, pack_cache_control, LIST }, { WSP_HEADER_CONNECTION, pack_connection, LIST }, { WSP_HEADER_CONTENT_BASE, pack_uri, 0 }, { WSP_HEADER_CONTENT_ENCODING, pack_encoding, LIST }, { WSP_HEADER_CONTENT_LANGUAGE, pack_language, LIST }, { WSP_HEADER_CONTENT_LENGTH, wsp_pack_integer_string, 0 }, { WSP_HEADER_CONTENT_LOCATION, pack_uri, 0 }, { WSP_HEADER_CONTENT_MD5, pack_md5, 0 }, { WSP_HEADER_CONTENT_RANGE, pack_content_range, 0 }, { WSP_HEADER_CONTENT_TYPE, wsp_pack_content_type, 0 }, { WSP_HEADER_DATE, wsp_pack_date, 0 }, { WSP_HEADER_ETAG, wsp_pack_quoted_text, 0 }, { WSP_HEADER_EXPIRES, pack_expires, 0 }, { WSP_HEADER_FROM, wsp_pack_text, 0 }, { WSP_HEADER_HOST, wsp_pack_text, 0 }, { WSP_HEADER_IF_MODIFIED_SINCE, wsp_pack_date, 0 }, { WSP_HEADER_IF_MATCH, wsp_pack_quoted_text, 0 }, { WSP_HEADER_IF_NONE_MATCH, wsp_pack_quoted_text, 0 }, { WSP_HEADER_IF_RANGE, pack_if_range, 0 }, { WSP_HEADER_IF_UNMODIFIED_SINCE, wsp_pack_date, 0 }, { WSP_HEADER_LAST_MODIFIED, wsp_pack_date, 0 }, { WSP_HEADER_LOCATION, pack_uri, 0 }, { WSP_HEADER_MAX_FORWARDS, wsp_pack_integer_string, 0 }, { WSP_HEADER_PRAGMA, pack_pragma, LIST }, { WSP_HEADER_PROXY_AUTHENTICATE, pack_challenge, BROKEN_LIST }, { WSP_HEADER_PROXY_AUTHORIZATION, pack_credentials, BROKEN_LIST }, { WSP_HEADER_PUBLIC, pack_method, LIST }, { WSP_HEADER_RANGE, pack_range, 0 }, { WSP_HEADER_REFERER, pack_uri, 0 }, { WSP_HEADER_RETRY_AFTER, wsp_pack_retry_after, 0 }, { WSP_HEADER_SERVER, wsp_pack_text, 0 }, { WSP_HEADER_TRANSFER_ENCODING, pack_transfer_encoding, LIST }, { WSP_HEADER_UPGRADE, wsp_pack_text, LIST }, { WSP_HEADER_USER_AGENT, wsp_pack_text, 0 }, { WSP_HEADER_VARY, pack_field_name, LIST }, { WSP_HEADER_VIA, wsp_pack_text, LIST }, { WSP_HEADER_WARNING, pack_warning, LIST }, { WSP_HEADER_WWW_AUTHENTICATE, pack_challenge, BROKEN_LIST }, { WSP_HEADER_CONTENT_DISPOSITION, pack_content_disposition, 0 }, { WSP_HEADER_PUSH_FLAG, wsp_pack_integer_string, 0}, { WSP_HEADER_X_WAP_CONTENT_URI, pack_uri, 0}, { WSP_HEADER_X_WAP_INITIATOR_URI, pack_uri, 0}, { WSP_HEADER_X_WAP_APPLICATION_ID, wsp_pack_integer_string, 0}, { WSP_HEADER_CONTENT_ID, wsp_pack_quoted_text, 0}, { WSP_HEADER_ENCODING_VERSION, wsp_pack_version_value, 0 } // DAVI { WSP_HEADER_SET_COOKIE, pack_version_value, 0 } }; static Parameter *parm_create(Octstr *key, Octstr *value) { Parameter *parm; parm = gw_malloc(sizeof(*parm)); parm->key = key; parm->value = value; return parm; } static void parm_destroy(Parameter *parm) { if (parm == NULL) return; octstr_destroy(parm->key); octstr_destroy(parm->value); gw_free(parm); } void parm_destroy_item(void *parm) { parm_destroy(parm); } static Parameter *parm_parse(Octstr *value) { long pos; Octstr *key, *val; pos = octstr_search_char(value, '=', 0); if (pos > 0) { key = octstr_copy(value, 0, pos); val = octstr_copy(value, pos + 1, octstr_len(value) - pos); octstr_strip_blanks(key); octstr_strip_blanks(val); } else { key = octstr_duplicate(value); val = NULL; } return parm_create(key, val); } /* Many HTTP field elements can take parameters in a standardized * form: parameters appear after the main value, each is introduced * by a semicolon (;), and consists of a key=value pair or just * a key, where the key is a token and the value is either a token * or a quoted-string. * The main value itself is a series of tokens, separators, and * quoted-strings. * * This function will take such a field element, and remove all * parameters from it. The parameters are returned as a List * of Parameter, where the value field is left NULL * if the parameter was just a key. * It returns NULL if there were no parameters. */ List *wsp_strip_parameters(Octstr *value) { long pos; long len; int c; long end; List *parms; long firstparm; len = octstr_len(value); /* Find the start of the first parameter. */ for (pos = 0; pos < len; pos++) { c = octstr_get_char(value, pos); if (c == ';') break; else if (c == '"') pos += http_header_quoted_string_len(value, pos) - 1; } if (pos >= len) return NULL; /* no parameters */ parms = gwlist_create(); firstparm = pos; for (pos++; pos > 0 && pos < len; pos++) { Octstr *key = NULL; Octstr *val = NULL; end = octstr_search_char(value, '=', pos); if (end < 0) end = octstr_search_char(value, ';', pos); if (end < 0) end = octstr_len(value); key = octstr_copy(value, pos, end - pos); octstr_strip_blanks(key); pos = end; if (octstr_get_char(value, pos) == '=') { pos++; while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos) == '"') end = pos + http_header_quoted_string_len(value, pos); else end = octstr_search_char(value, ';', pos); if (end < 0) end = octstr_len(value); val = octstr_copy(value, pos, end - pos); octstr_strip_blanks(val); pos = end; pos = octstr_search_char(value, ';', pos); } gwlist_append(parms, parm_create(key, val)); } octstr_delete(value, firstparm, octstr_len(value) - firstparm); octstr_strip_blanks(value); return parms; } int wsp_pack_text(Octstr *packed, Octstr *text) { /* This check catches 0-length strings as well, because * octstr_get_char will return -1. */ if (octstr_get_char(text, 0) >= 128 || octstr_get_char(text, 0) < 32) octstr_append_char(packed, WSP_QUOTE); octstr_append(packed, text); octstr_append_char(packed, 0); return 0; } /* Pack a string as quoted-text WAP WSP 203, Section 8.4.2.1 */ int wsp_pack_quoted_text(Octstr *packed, Octstr *text) { octstr_append_char(packed, '"'); octstr_append(packed,text); octstr_append_char(packed,0); return 0; } /* Pack text as Quoted-string if it starts with a " character. * Pack it as Text-string otherwise. */ static void pack_quoted_string(Octstr *packed, Octstr *text) { octstr_append(packed, text); if (octstr_get_char(text, octstr_len(text) - 1) == '"' && octstr_get_char(text, 0) == '"') octstr_delete(packed, octstr_len(packed) - 1, 1); octstr_append_char(packed, 0); } /* Is this char in the 'separators' set defined by HTTP? */ 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; } } /* 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); } /* Is this string a 'token' as defined by HTTP? */ static int is_token(Octstr *token) { return octstr_len(token) > 0 && octstr_check_range(token, 0, octstr_len(token), is_token_char); } /* We represent qvalues as integers from 0 through 1000, rather than * as floating values. */ static int parse_qvalue(Octstr *value) { int qvalue; if (value == NULL) return -1; if (!isdigit(octstr_get_char(value, 0))) return -1; qvalue = (octstr_get_char(value, 0) - '0') * 1000; if (octstr_get_char(value, 1) != '.') goto gotvalue; if (!isdigit(octstr_get_char(value, 2))) goto gotvalue; qvalue += (octstr_get_char(value, 2) - '0') * 100; if (!isdigit(octstr_get_char(value, 3))) goto gotvalue; qvalue += (octstr_get_char(value, 3) - '0') * 10; if (!isdigit(octstr_get_char(value, 4))) goto gotvalue; qvalue += (octstr_get_char(value, 4) - '0'); gotvalue: if (qvalue < 0 || qvalue > 1000) return -1; return qvalue; } static int get_qvalue(List *parms, int default_qvalue) { long i; Parameter *parm; int qvalue; for (i = 0; i < gwlist_len(parms); i++) { parm = gwlist_get(parms, i); if (octstr_str_compare(parm->key, "q") == 0 || octstr_str_compare(parm->key, "Q") == 0) { qvalue = parse_qvalue(parm->value); if (qvalue >= 0) return qvalue; } } return default_qvalue; } static int pack_qvalue(Octstr *packed, int qvalue) { /* "Quality factor 1 is the default value and shall never * be sent." */ if (qvalue == 1000) return -1; /* Remember that our qvalues are already multiplied by 1000. */ if (qvalue % 10 == 0) qvalue = qvalue / 10 + 1; else qvalue = qvalue + 100; octstr_append_uintvar(packed, qvalue); return 0; } /* Pack value as a Value-length followed by the encoded value. */ void wsp_pack_value(Octstr *packed, Octstr *encoded) { long len; len = octstr_len(encoded); if (len <= 30) octstr_append_char(packed, len); else { octstr_append_char(packed, 31); octstr_append_uintvar(packed, len); } octstr_append(packed, encoded); } void wsp_pack_long_integer(Octstr *packed, unsigned long integer) { long oldlen = octstr_len(packed); unsigned char octet; long len; if (integer == 0) { /* The Multi-octet-integer has to be at least 1 octet long. */ octstr_append_char(packed, 1); /* length */ octstr_append_char(packed, 0); /* value */ return; } /* Encode it back-to-front, by repeatedly inserting * at the same position, because that's easier. */ for (len = 0; integer != 0; integer >>= 8, len++) { octet = integer & 0xff; octstr_insert_data(packed, oldlen, (char *)&octet, 1); } octet = len; octstr_insert_data(packed, oldlen, (char *)&octet, 1); } void wsp_pack_short_integer(Octstr *packed, unsigned long integer) { gw_assert(integer <= MAX_SHORT_INTEGER); octstr_append_char(packed, integer + 0x80); } void wsp_pack_integer_value(Octstr *packed, unsigned long integer) { if (integer <= MAX_SHORT_INTEGER) wsp_pack_short_integer(packed, integer); else wsp_pack_long_integer(packed, integer); } int wsp_pack_integer_string(Octstr *packed, Octstr *value) { unsigned long integer; long pos; int c; int digit; integer = 0; for (pos = 0; pos < octstr_len(value); pos++) { c = octstr_get_char(value, pos); if (!isdigit(c)) break; digit = c - '0'; if (integer > ULONG_MAX / 10) goto overflow; integer *= 10; if (integer > ULONG_MAX - digit) goto overflow; integer += digit; } debug("wsp",0,"WSP: %s: value `%s', integer 0x%04lx", __func__, octstr_get_cstr(value), integer); wsp_pack_integer_value(packed, integer); return 0; overflow: warning(0, "WSP: Number too large to handle: '%s'.", octstr_get_cstr(value)); return -1; } int wsp_pack_version_value(Octstr *packed, Octstr *version) { unsigned long integer; long major, minor; long pos; pos = octstr_parse_long(&major, version, 0, 10); if (pos < 0 || major < 1 || major > 7) goto usetext; if (pos == octstr_len(version)) minor = 15; else { if (octstr_get_char(version, pos) != '.') goto usetext; pos = octstr_parse_long(&minor, version, pos + 1, 10); if (pos != octstr_len(version) || minor < 0 || minor > 14) goto usetext; } integer = major << 4 | minor; debug("wsp",0,"WSP: %s: value `%s', integer 0x%04lx", __func__, octstr_get_cstr(version), integer); wsp_pack_short_integer(packed, integer); return 0; usetext: wsp_pack_text(packed, version); return 0; } int wsp_pack_constrained_value(Octstr *packed, Octstr *text, long value) { if (value >= 0) wsp_pack_short_integer(packed, value); else wsp_pack_text(packed, text); return 0; } static void pack_parameter(Octstr *packed, Parameter *parm) { long keytoken; long tmp; long start; start = octstr_len(packed); /* Parameter = Typed-parameter | Untyped-parameter */ /* keytoken = wsp_string_to_parameter(parm->key); */ /* XXX this should obey what kind of WSP Encoding-Version the client is using */ keytoken = wsp_string_to_versioned_parameter(parm->key, WSP_1_2); if (keytoken >= 0) { /* Typed-parameter = Well-known-parameter-token Typed-value */ /* Well-known-parameter-token = Integer-value */ wsp_pack_integer_value(packed, keytoken); /* Typed-value = Compact-value | Text-value */ /* First try to pack as Compact-value or No-value. * If that fails, pack as Text-value. */ if (parm->value == NULL) { octstr_append_char(packed, 0); /* No-value */ return; } else switch (keytoken) { case 0: /* q */ tmp = parse_qvalue(parm->value); if (tmp >= 0) { if (pack_qvalue(packed, tmp) < 0) octstr_delete(packed, start, octstr_len(packed) - start); return; } break; case 1: /* charset */ tmp = wsp_string_to_charset(parm->value); if (tmp >= 0) { wsp_pack_integer_value(packed, tmp); return; } break; case 2: /* level */ wsp_pack_version_value(packed, parm->value); return; case 3: /* type */ if (octstr_check_range(parm->value, 0, octstr_len(parm->value), gw_isdigit) && wsp_pack_integer_string(packed, parm->value) >= 0) return; break; case 5: /* name */ case 6: /* filename */ break; case 7: /* differences */ if (pack_field_name(packed, parm->value) >= 0) return; break; case 8: /* padding */ if (octstr_parse_long(&tmp, parm->value, 0, 10) == octstr_len(parm->value) && tmp >= 0 && tmp <= MAX_SHORT_INTEGER) { wsp_pack_short_integer(packed, tmp); return; } break; } pack_quoted_string(packed, parm->value); } else { /* Untyped-parameter = Token-text Untyped-value */ wsp_pack_text(packed, parm->key); /* Untyped-value = Integer-value | Text-value */ if (parm->value == NULL) { octstr_append_char(packed, 0); /* No-value */ return; } /* If we can pack as integer, do so. */ if (octstr_parse_long(&tmp, parm->value, 0, 10) == octstr_len(parm->value)) { wsp_pack_integer_value(packed, tmp); } else { pack_quoted_string(packed, parm->value); } } } void wsp_pack_parameters(Octstr *packed, List *parms) { long i; Parameter *parm; for (i = 0; i < gwlist_len(parms); i++) { parm = gwlist_get(parms, i); pack_parameter(packed, parm); } } static int pack_uri(Octstr *packed, Octstr *value) { wsp_pack_text(packed, value); return 0; } static int pack_md5(Octstr *packed, Octstr *value) { Octstr *binary; binary = octstr_duplicate(value); octstr_base64_to_binary(binary); if (octstr_len(binary) != 16) { error(0, "WSP: MD5 value not 128 bits."); return -1; } octstr_append_char(packed, 16); octstr_append(packed, binary); octstr_destroy(binary); return 0; } /* Actually packs a "Value-length Challenge" */ /* Relies on http_split_auth_value to have converted the entry to * the normal HTTP parameter format rather than the comma-separated * one used by challenge and credentials. */ static int pack_challenge(Octstr *packed, Octstr *value) { Octstr *encoding = NULL; Octstr *scheme = NULL; Octstr *basic = octstr_imm("Basic"); Octstr *realm = octstr_imm("realm"); Octstr *parmstring = NULL; List *parms = NULL; Parameter *realmparm = NULL; long realmpos = -1; Octstr *realmval = NULL; long pos; encoding = octstr_create(""); /* Get authentication scheme */ for (pos = 0; pos < octstr_len(value); pos++) { if (!is_token_char(octstr_get_char(value, pos))) break; } scheme = octstr_copy(value, 0, pos); octstr_strip_blanks(scheme); /* Skip whitespace */ while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_case_compare(scheme, basic) == 0) { parmstring = octstr_copy(value, pos, octstr_len(value) - pos); realmparm = parm_parse(parmstring); octstr_append_char(encoding, BASIC_AUTHENTICATION); realmpos = octstr_len(encoding); } else { long i; wsp_pack_text(encoding, scheme); realmpos = octstr_len(encoding); /* Find the realm parameter and exclude it */ parms = wsp_strip_parameters(value); for (i = 0; i < gwlist_len(parms); i++) { Parameter *parm = gwlist_get(parms, i); if (octstr_case_compare(realm, parm->key) == 0) { realmparm = parm; gwlist_delete(parms, i, 1); break; } } wsp_pack_parameters(encoding, parms); } /* * In the WSP encoding we have to put the realm value first, but * with non-Basic challenges we don't know if it will come first * in the HTTP header. So we just start parsing parameters, and * go back and insert the realm value later. The same technique * is used for Basic authentication to simplify the code. */ if (realmparm == NULL || octstr_case_compare(realmparm->key, realm) != 0 || realmparm->value == NULL) goto error; /* Zap quote marks */ if (octstr_get_char(realmparm->value, 0) == '"' && octstr_get_char(realmparm->value, octstr_len(realmparm->value) - 1) == '"') { octstr_delete(realmparm->value, 0, 1); octstr_delete(realmparm->value, octstr_len(realmparm->value) - 1, 1); } gw_assert(realmpos >= 0); realmval = octstr_create(""); wsp_pack_text(realmval, realmparm->value); octstr_insert(encoding, realmval, realmpos); wsp_pack_value(packed, encoding); octstr_destroy(encoding); octstr_destroy(scheme); octstr_destroy(parmstring); parm_destroy(realmparm); gwlist_destroy(parms, parm_destroy_item); octstr_destroy(realmval); return 0; error: warning(0, "WSP: Cannot parse challenge."); octstr_destroy(encoding); octstr_destroy(scheme); octstr_destroy(parmstring); parm_destroy(realmparm); gwlist_destroy(parms, parm_destroy_item); octstr_destroy(realmval); return -1; } /* Actually packs a "Value-length Credentials" */ /* Relies on http_split_auth_value to have converted the entry to * the normal HTTP parameter format rather than the comma-separated * one used by challenge and credentials. */ static int pack_credentials(Octstr *packed, Octstr *value) { Octstr *encoding = NULL; Octstr *scheme = NULL; Octstr *basic = NULL; long pos; encoding = octstr_create(""); /* Get authentication scheme */ for (pos = 0; pos < octstr_len(value); pos++) { if (!is_token_char(octstr_get_char(value, pos))) break; } scheme = octstr_copy(value, 0, pos); octstr_strip_blanks(scheme); /* Skip whitespace */ while (isspace(octstr_get_char(value, pos))) pos++; basic = octstr_imm("Basic"); if (octstr_case_compare(scheme, basic) == 0) { Octstr *cookie; Octstr *userid; Octstr *password; octstr_append_char(encoding, BASIC_AUTHENTICATION); cookie = octstr_copy(value, pos, octstr_len(value) - pos); octstr_base64_to_binary(cookie); pos = octstr_search_char(cookie, ':', 0); if (pos < 0) { warning(0, "WSP: bad cookie in credentials '%s'.", octstr_get_cstr(value)); octstr_destroy(cookie); goto error; } userid = octstr_copy(cookie, 0, pos); password = octstr_copy(cookie, pos + 1, octstr_len(cookie) - pos); wsp_pack_text(encoding, userid); wsp_pack_text(encoding, password); octstr_destroy(cookie); octstr_destroy(userid); octstr_destroy(password); } else { List *parms; wsp_pack_text(encoding, scheme); parms = wsp_strip_parameters(value); wsp_pack_parameters(encoding, parms); gwlist_destroy(parms, parm_destroy_item); } wsp_pack_value(packed, encoding); octstr_destroy(encoding); octstr_destroy(scheme); return 0; error: octstr_destroy(encoding); octstr_destroy(scheme); return -1; } int wsp_pack_date(Octstr *packed, Octstr *value) { long timeval; /* If we get a negative timeval here, this means either * we're beyond the time_t 32 bit int positive border for the * timestamp or we're really handling time before epoch. */ timeval = date_parse_http(value); if (timeval == -1) { warning(0, "WSP headers: cannot decode date '%s'", octstr_get_cstr(value)); return -1; } /* We'll assume that we don't package time before epoch. */ wsp_pack_long_integer(packed, (unsigned long) timeval); return 0; } static int pack_connection(Octstr *packed, Octstr *value) { return wsp_pack_constrained_value(packed, value, wsp_string_to_connection(value)); } static int pack_encoding(Octstr *packed, Octstr *value) { return wsp_pack_constrained_value(packed, value, wsp_string_to_encoding(value)); } static int pack_field_name(Octstr *packed, Octstr *value) { /* XXX we need to obey which WSP encoding-version to use */ /* return pack_constrained_value(packed, value, wsp_string_to_header(value)); */ return wsp_pack_constrained_value(packed, value, wsp_string_to_versioned_header(value, WSP_1_2)); } static int pack_language(Octstr *packed, Octstr *value) { long language; /* Can't use pack_constrained_value here because * language does not necessarily fit in a Short-integer. */ language = wsp_string_to_language(value); if (language >= 0) wsp_pack_integer_value(packed, language); else wsp_pack_text(packed, value); return 0; } /* Encode value as Well-known-method | Token-text */ static int pack_method(Octstr *packed, Octstr *value) { /* In the future, we will need some way to refer to extended * method names negotiated for this session. */ return wsp_pack_constrained_value(packed, value, wsp_string_to_method(value)); } /* Encode value as Accept-ranges-value */ static int pack_range_unit(Octstr *packed, Octstr *value) { return wsp_pack_constrained_value(packed, value, wsp_string_to_ranges(value)); } /* Encode byte-range-spec | suffix-byte-range-spec as Range-value. * Return position after the parsed spec. */ static int pack_range_value(Octstr *packed, Octstr *value, long pos) { long first_byte_pos; long last_byte_pos; long suffix_length; Octstr *encoding; while (isspace(octstr_get_char(value, pos))) pos++; if (isdigit(octstr_get_char(value, pos))) { /* byte-range-spec */ pos = octstr_parse_long(&first_byte_pos, value, pos, 10); if (pos < 0 || first_byte_pos < 0) return -1; while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos) != '-') return -1; pos++; while (isspace(octstr_get_char(value, pos))) pos++; if (isdigit(octstr_get_char(value, pos))) { pos = octstr_parse_long(&last_byte_pos, value, pos, 10); if (pos < 0 || last_byte_pos < 0) return -1; } else { last_byte_pos = -1; } encoding = octstr_create(""); octstr_append_char(encoding, BYTE_RANGE); octstr_append_uintvar(encoding, first_byte_pos); if (last_byte_pos >= 0) octstr_append_uintvar(encoding, last_byte_pos); wsp_pack_value(packed, encoding); octstr_destroy(encoding); } else if (octstr_get_char(value, pos) == '-') { /* suffix-byte-range-spec */ pos++; pos = octstr_parse_long(&suffix_length, value, pos, 10); if (pos < 0 || suffix_length < 0) return -1; encoding = octstr_create(""); octstr_append_char(encoding, SUFFIX_BYTE_RANGE); octstr_append_uintvar(encoding, suffix_length); wsp_pack_value(packed, encoding); octstr_destroy(encoding); } else return -1; return pos; } static int pack_transfer_encoding(Octstr *packed, Octstr *value) { return wsp_pack_constrained_value(packed, value, wsp_string_to_transfer_encoding(value)); } /* Also used by pack_content_type */ static int pack_accept(Octstr *packed, Octstr *value) { List *parms; long media; parms = wsp_strip_parameters(value); /* XXX we need to obey which WSP encoding-version to use */ /* media = wsp_string_to_content_type(value); */ media = wsp_string_to_versioned_content_type(value, WSP_1_2); /* See if we can fit this in a Constrained-media encoding */ if (parms == NULL && media <= MAX_SHORT_INTEGER) { wsp_pack_constrained_value(packed, value, media); } else { Octstr *encoding = octstr_create(""); if (media >= 0) wsp_pack_integer_value(encoding, media); else wsp_pack_text(encoding, value); wsp_pack_parameters(encoding, parms); wsp_pack_value(packed, encoding); octstr_destroy(encoding); } gwlist_destroy(parms, parm_destroy_item); return 0; } static int pack_accept_charset(Octstr *packed, Octstr *value) { List *parms; long charset; long qvalue; parms = wsp_strip_parameters(value); charset = wsp_string_to_charset(value); qvalue = 1000; if (parms) qvalue = get_qvalue(parms, qvalue); gwlist_destroy(parms, parm_destroy_item); /* See if we can fit this in a Constrained-charset encoding */ if (qvalue == 1000 && charset <= MAX_SHORT_INTEGER) { wsp_pack_constrained_value(packed, value, charset); } else { Octstr *encoding = octstr_create(""); if (charset >= 0) wsp_pack_integer_value(encoding, charset); else wsp_pack_text(encoding, value); if (qvalue != 1000) pack_qvalue(encoding, qvalue); wsp_pack_value(packed, encoding); octstr_destroy(encoding); } return 0; } /* WSP 8.4.2.9 does not specify any way to encode parameters for * an Accept-encoding field, but RFC2616 allows q parameters. * We'll have to simplify: qvalue > 0 means encode it, qvalue == 0 * means don't encode it. */ static int pack_accept_encoding(Octstr *packed, Octstr *value) { List *parms; int qvalue; qvalue = 1000; /* default */ parms = wsp_strip_parameters(value); if (parms) qvalue = get_qvalue(parms, qvalue); gwlist_destroy(parms, parm_destroy_item); if (qvalue > 0) { if (qvalue < 1000) warning(0, "Cannot encode q-value in Accept-Encoding."); pack_encoding(packed, value); } else { warning(0, "Cannot encode q=0 in Accept-Encoding; skipping this encoding."); return -1; } return 0; } static int pack_accept_language(Octstr *packed, Octstr *value) { List *parms; long language; long qvalue; parms = wsp_strip_parameters(value); language = wsp_string_to_language(value); qvalue = 1000; if (parms) qvalue = get_qvalue(parms, qvalue); gwlist_destroy(parms, parm_destroy_item); /* See if we can fit this in a Constrained-language encoding. */ /* Note that our language table already includes Any-language */ if (qvalue == 1000 && language <= MAX_SHORT_INTEGER) { wsp_pack_constrained_value(packed, value, language); } else { Octstr *encoding = octstr_create(""); if (language >= 0) wsp_pack_integer_value(encoding, language); else wsp_pack_text(encoding, value); if (qvalue != 1000) pack_qvalue(encoding, qvalue); wsp_pack_value(packed, encoding); octstr_destroy(encoding); } return 0; } static int pack_cache_control(Octstr *packed, Octstr *value) { Parameter *parm; long tmp; parm = parm_parse(value); if (parm->value == NULL) { wsp_pack_constrained_value(packed, value, wsp_string_to_cache_control(parm->key)); } else { Octstr *encoding = octstr_create(""); tmp = wsp_string_to_cache_control(parm->key); if (tmp < 0) { /* According to WSP 8.4.2.15, the format * is "Cache-extension Parameter", and * Cache-extension is a Token-text. * But in HTTP a cache-extension is of * the form token=value, which maps * nicely to Parameter. So what is * this extra Token-text? I decided to leave it blank. * - Richard Braakman */ wsp_pack_text(encoding, octstr_imm("")); pack_parameter(encoding, parm); } else { int done = 0; Octstr *value_encoding; List *names; Octstr *element; value_encoding = octstr_create(""); switch (tmp) { case WSP_CACHE_CONTROL_NO_CACHE: case WSP_CACHE_CONTROL_PRIVATE: if (octstr_get_char(parm->value, 0) == '"') octstr_delete(parm->value, 0, 1); if (octstr_get_char(parm->value, octstr_len(parm->value) - 1) == '"') octstr_delete(parm->value, octstr_len(parm->value) - 1, 1); names = http_header_split_value(parm->value); while ((element = gwlist_consume(names))) { pack_field_name(value_encoding, element); octstr_destroy(element); } gwlist_destroy(names, octstr_destroy_item); done = 1; break; case WSP_CACHE_CONTROL_MAX_AGE: case WSP_CACHE_CONTROL_MAX_STALE: case WSP_CACHE_CONTROL_MIN_FRESH: if (wsp_pack_integer_string(value_encoding, parm->value) >= 0) done = 1; break; } if (done) { wsp_pack_short_integer(encoding, tmp); octstr_append(encoding, value_encoding); } else { /* See note above */ pack_parameter(encoding, parm); } octstr_destroy(value_encoding); } wsp_pack_value(packed, encoding); octstr_destroy(encoding); } parm_destroy(parm); return 1; } static int pack_content_disposition(Octstr *packed, Octstr *value) { List *parms; long disposition; parms = wsp_strip_parameters(value); disposition = wsp_string_to_disposition(value); if (disposition >= 0) { Octstr *encoding = octstr_create(""); wsp_pack_short_integer(encoding, disposition); wsp_pack_parameters(encoding, parms); wsp_pack_value(packed, encoding); octstr_destroy(encoding); } else { warning(0, "WSP: Cannot encode Content-Disposition '%s'.", octstr_get_cstr(value)); goto error; } gwlist_destroy(parms, parm_destroy_item); return 0; error: gwlist_destroy(parms, parm_destroy_item); return -1; } static int pack_content_range(Octstr *packed, Octstr *value) { Octstr *bytes; long pos; long firstbyte, lastbyte, instancelen; Octstr *encoding; bytes = octstr_imm("bytes "); if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0) goto error; pos = octstr_len(bytes); while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos) == '*') goto warning; pos = octstr_parse_long(&firstbyte, value, pos, 10); if (pos < 0) goto error; while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos++) != '-') goto error; pos = octstr_parse_long(&lastbyte, value, pos, 10); if (pos < 0) goto error; while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos++) != '/') goto error; while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos) == '*') goto warning; pos = octstr_parse_long(&instancelen, value, pos, 10); if (pos < 0) goto error; /* XXX: If the range is valid but not representable, * or if it's invalid, then should we refrain from sending * anything at all? It might pollute the client's cache. */ if (lastbyte < firstbyte || instancelen < lastbyte) { warning(0, "WSP: Content-Range '%s' is invalid.", octstr_get_cstr(value)); return -1; } encoding = octstr_create(""); octstr_append_uintvar(encoding, firstbyte); octstr_append_uintvar(encoding, instancelen); wsp_pack_value(packed, encoding); octstr_destroy(encoding); return 0; error: warning(0, "WSP: Cannot parse Content-Range '%s'.", octstr_get_cstr(value)); return -1; warning: warning(0, "WSP: Cannot encode Content-Range '%s'.", octstr_get_cstr(value)); return -1; } int wsp_pack_content_type(Octstr *packed, Octstr *value) { /* The expansion of Content-type-value works out to be * equivalent to Accept-value. */ return pack_accept(packed, value); } static int pack_expires(Octstr *packed, Octstr *value) { int ret; ret = wsp_pack_date(packed, value); if (ret < 0) { /* Responses with an invalid Expires header should be treated as already expired. If we just skip this header, then the client won't know that. So we encode one with a date far in the past. */ wsp_pack_long_integer(packed, LONG_AGO_VALUE); ret = 0; } return ret; } static int pack_if_range(Octstr *packed, Octstr *value) { if (octstr_get_char(value, 0) == '"' || (octstr_get_char(value, 0) == 'W' && octstr_get_char(value, 1) == '/')) { return wsp_pack_quoted_text(packed, value); /* It's an etag */ } else { return wsp_pack_date(packed, value); } } static int pack_pragma(Octstr *packed, Octstr *value) { Octstr *nocache; nocache = octstr_imm("no-cache"); if (octstr_case_compare(value, nocache) == 0) wsp_pack_short_integer(packed, WSP_CACHE_CONTROL_NO_CACHE); else { Parameter *parm; Octstr *encoding; encoding = octstr_create(""); parm = parm_parse(value); pack_parameter(encoding, parm); wsp_pack_value(packed, encoding); octstr_destroy(encoding); parm_destroy(parm); } return 0; } static int pack_range(Octstr *packed, Octstr *value) { Octstr *bytes = octstr_imm("bytes"); long pos; if (octstr_ncompare(value, bytes, octstr_len(bytes)) != 0 || is_token_char(octstr_get_char(value, octstr_len(bytes)))) goto error; pos = octstr_len(bytes); while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos) != '=') goto error; pos++; for (;;) { /* Discard the whole header if any part of it can't be * parsed. Probably a partial Range header is worse * than none at all. */ pos = pack_range_value(packed, value, pos); if (pos < 0) goto error; while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos) != ',') break; pos++; wsp_pack_short_integer(packed, WSP_HEADER_RANGE); } return 0; error: warning(0, "WSP: Cannot parse 'Range: %s'.", octstr_get_cstr(value)); return -1; } /* The value is either a HTTP-date or a delta-seconds (integer). */ int wsp_pack_retry_after(Octstr *packed, Octstr *value) { Octstr *encoded = NULL; encoded = octstr_create(""); if (isdigit(octstr_get_char(value, 0))) { octstr_append_char(encoded, RELATIVE_TIME); if (wsp_pack_integer_string(encoded, value) < 0) goto error; } else { octstr_append_char(encoded, ABSOLUTE_TIME); if (wsp_pack_date(encoded, value) < 0) goto error; } wsp_pack_value(packed, encoded); octstr_destroy(encoded); return 0; error: octstr_destroy(encoded); return -1; } static int convert_rfc2616_warning_to_rfc2068(int warn_code) { int i; struct { int rfc2616code; int rfc2068code; } code_transform[] = { { 110, 10 }, /* Response is stale */ { 111, 11 }, /* Revalidation failed */ { 112, 12 }, /* Disconnected operation */ { 113, 13 }, /* Heuristic expiration */ { 199, 99 }, /* Miscellaneous warning */ { 214, 14 }, /* Transformation applied */ { 299, 99 }, /* Miscellaneous (persistent) warning */ { -1, -1 } }; for (i = 0; code_transform[i].rfc2616code >= 0; i++) { if (code_transform[i].rfc2616code == warn_code) return code_transform[i].rfc2068code; } return warn_code; /* conversion failed */ } static int pack_warning(Octstr *packed, Octstr *value) { long warn_code = -1; Octstr *warn_agent = NULL; Octstr *warn_text = NULL; long pos; long start; pos = octstr_parse_long(&warn_code, value, 0, 10); if (pos < 0 || warn_code < 0) goto error; if (warn_code > 99) { /* RFC2068 uses 2-digit codes, and RFC2616 uses 3-digit codes. * This must be an RFC2616 code. We don't have room in the * encoding for such codes, so we try to convert it back to * an RFC2068 code. */ warn_code = convert_rfc2616_warning_to_rfc2068(warn_code); } if (warn_code > MAX_SHORT_INTEGER) { warning(0, "WSP: Cannot encode warning code %ld.", warn_code); return -1; } while (isspace(octstr_get_char(value, pos))) pos++; start = pos; while (pos < octstr_len(value) && !isspace(octstr_get_char(value, pos))) pos++; if (pos > start) warn_agent = octstr_copy(value, start, pos - start); while (isspace(octstr_get_char(value, pos))) pos++; start = pos; pos += http_header_quoted_string_len(value, pos); if (pos > start) warn_text = octstr_copy(value, start, pos - start); if (warn_agent == NULL && warn_text == NULL) { /* Simple encoding */ wsp_pack_short_integer(packed, warn_code); } else { /* General encoding */ Octstr *encoding = octstr_create(""); if (warn_agent == NULL) warn_agent = octstr_create(""); if (warn_text == NULL) warn_text = octstr_create(""); wsp_pack_short_integer(encoding, warn_code); wsp_pack_text(encoding, warn_agent); wsp_pack_text(encoding, warn_text); wsp_pack_value(packed, encoding); octstr_destroy(encoding); } octstr_destroy(warn_agent); octstr_destroy(warn_text); return 0; error: warning(0, "WSP: Cannot parse 'Warning: %s'.", octstr_get_cstr(value)); octstr_destroy(warn_agent); octstr_destroy(warn_text); return -1; } void wsp_pack_separate_content_type(Octstr *packed, List *headers) { Octstr *content_type; /* Can't use http_header_get_content_type because it * does not parse all possible parameters. */ content_type = http_header_find_first(headers, "Content-Type"); if (content_type == NULL) { warning(0, "WSP: Missing Content-Type header in " "response, guessing application/octet-stream"); content_type = octstr_create("application/octet-stream"); } octstr_strip_blanks(content_type); wsp_pack_content_type(packed, content_type); octstr_destroy(content_type); } int wsp_pack_list(Octstr *packed, long fieldnum, List *elements, int i) { long startpos; Octstr *element; while ((element = gwlist_consume(elements))) { startpos = octstr_len(packed); wsp_pack_short_integer(packed, fieldnum); if (headerinfo[i].func(packed, element) < 0) { /* Remove whatever we added */ octstr_delete(packed, startpos, octstr_len(packed) - startpos); /* But continue processing elements */ } octstr_destroy(element); } return 0; } static int pack_known_header(Octstr *packed, long fieldnum, Octstr *value) { List *elements = NULL; long startpos; long i; octstr_strip_blanks(value); startpos = octstr_len(packed); for (i = 0; i < TABLE_SIZE(headerinfo); i++) { if (headerinfo[i].header == fieldnum) break; } if (i == TABLE_SIZE(headerinfo)) { error(0, "WSP: Do not know how to encode header type %ld", fieldnum); goto error; } if (headerinfo[i].allows_list == LIST) elements = http_header_split_value(value); else if (headerinfo[i].allows_list == BROKEN_LIST) elements = http_header_split_auth_value(value); else elements = NULL; if (elements != NULL) { if (wsp_pack_list(packed, fieldnum, elements, i) < 0) goto error; } else { wsp_pack_short_integer(packed, fieldnum); debug("wsp",0,"WSP: Known header 0x%04lx, value `%s'.", fieldnum, octstr_get_cstr(value)); if (headerinfo[i].func(packed, value) < 0) goto error; } gwlist_destroy(elements, octstr_destroy_item); return 0; error: /* Remove whatever we added */ octstr_delete(packed, startpos, octstr_len(packed) - startpos); gwlist_destroy(elements, octstr_destroy_item); return -1; } int wsp_pack_application_header(Octstr *packed, Octstr *fieldname, Octstr *value) { if (!is_token(fieldname)) { warning(0, "WSP headers: `%s' is not a valid HTTP token.", octstr_get_cstr(fieldname)); return -1; } /* We have to deal specially with the X-WAP.TOD header, because it * is the only case of a text-format header defined with a non-text * field value. */ /* Normally this should be a case-insensitive comparison, but this * header will only be present if we generated it ourselves in the * application layer. */ if (octstr_str_compare(fieldname, "X-WAP.TOD") == 0) { wsp_pack_text(packed, fieldname); return wsp_pack_date(packed, value); } wsp_pack_text(packed, fieldname); wsp_pack_text(packed, value); return 0; } Octstr *wsp_headers_pack(List *headers, int separate_content_type, int wsp_version) { Octstr *packed; long i, len; int errors; packed = octstr_create(""); if (separate_content_type) wsp_pack_separate_content_type(packed, headers); len = gwlist_len(headers); for (i = 0; i < len; i++) { Octstr *fieldname; Octstr *value; long fieldnum; http_header_get(headers, i, &fieldname, &value); /* XXX we need to obey which WSP encoding-version to use */ /* fieldnum = wsp_string_to_header(fieldname); */ fieldnum = wsp_string_to_versioned_header(fieldname, wsp_version); errors = 0; if (separate_content_type && fieldnum == WSP_HEADER_CONTENT_TYPE) { /* already handled */ debug("wsp",0,"WSP: content type already handled."); } else if (fieldnum < 0) { if (wsp_pack_application_header(packed, fieldname, value) < 0) errors = 1; } else { if (pack_known_header(packed, fieldnum, value) < 0) errors = 1; } if (errors) warning(0, "Skipping header: %s: %s", octstr_get_cstr(fieldname), octstr_get_cstr(value)); octstr_destroy(fieldname); octstr_destroy(value); } /* http_header_dump(headers); octstr_dump(packed, 0); */ return packed; } gateway-1.4.5/wap/wtls_statesupport.h0000644000175000017500000001651613227613126016466 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wtls_statesupport.h * * Nikos Balkanas, Inaccess Networks (2009) */ #ifndef WTLS_STATESUPPORT_H #define WTLS_STATESUPPORT_H #include "gwlib/gwlib.h" #include "wtls_pdu.h" #include "wtls.h" #define KEYSIZE_MAX 2048 #define NOT_EXPORTABLE 0 #define EXPORTABLE 1 #define BLOCK 0 #define STREAM 1 #define ALG EVP_rc5_32_12_16_cbc() /* These enums and tables are pulled straight from the WTLS appendices. Go and have a look at them if these aren't particularly clear. Obviously, since NULL is a builtin, and since RSA/MD5/SHA are all macros referenced by the openssl libraries, the names have had to be slightly altered to protect the innocent :-> */ enum key_exchange_suites { NULL_keyxchg, SHARED_SECRET, DH_anon, DH_anon_512, RSA_anon, RSA_anon_512, RSA_anon_768, RSA_NOLIMIT, RSA_512, RSA_768, ECDH_anon, ECDH_anon_113, ECDH_anon_131, ECDH_ECDSA_NOLIMIT }; enum bulk_algorithms { NULL_bulk, RC5_CBC_40, RC5_CBC_56, RC5_CBC, DES_CBC_40, DES_CBC, TRIPLE_DES_CBC_EDE, IDEA_CBC_40, IDEA_CBC_56, IDEA_CBC }; enum keyed_macs { SHA_0, SHA_40, SHA_80, SHA_NOLIMIT, SHA_XOR_40, MD5_40, MD5_80, MD5_NOLIMIT }; typedef struct { const char *title; int key_size_limit; } keyxchg_table_t; typedef struct { const char *title; int is_exportable; int block_or_stream; int key_material; int expanded_key_material; int effective_key_bits; int iv_size; int block_size; } bulk_table_t; typedef struct { const char *title; int key_size; int mac_size; } hash_table_t; Octstr *wtls_calculate_prf(Octstr * secret, Octstr * label, Octstr * seed, int byteLength, WTLSMachine * wtls_machine); RSAPublicKey *wtls_get_rsapublickey(void); Random *wtls_get_random(void); Octstr *wtls_decrypt(wtls_Payload * payload, WTLSMachine * wtls_machine); Octstr *wtls_encrypt(Octstr * buffer, WTLSMachine * wtls_machine, int recordType); Octstr *wtls_decrypt_key(int type, Octstr * encryptedData); void wtls_decrypt_pdu_list(WTLSMachine * wtls_machine, List * pdu_list); Octstr *wtls_hash(Octstr * inputData, WTLSMachine * wtls_machine); /* The wtls_choose* functions implement the decision making process behind the protocol negotiations in wtls. */ CipherSuite *wtls_choose_ciphersuite(List * ciphersuites); int wtls_choose_clientkeyid(List * clientKeyIDs, int *algo); int wtls_choose_snmode(int snmode); int wtls_choose_krefresh(int krefresh); /* The *_are_identical functions all return 1 if the packets match the condition as * expressed in the function name. As each packet can contain a "list" of pdus, we * need to search that list and return whether or not they contain identical pdus as listed. * On failure, they will return non-zero */ int clienthellos_are_identical(List * pdu_list, List * last_received_packet); int certifcateverifys_are_identical(List * pdu_list, List *last_received_packet); int certificates_are_identical(List * pdu_list, List * last_received_packet); int clientkeyexchanges_are_identical(List * pdu_list, List *last_received_packet); int changecipherspecs_are_identical(List * pdu_list, List *last_received_packet); int finishes_are_indentical(List * pdu_list, List * last_received_packet); /* the packet_contains_* functions all return 1 if the packet contains a pdu of the type * expressed in the function name. */ int packet_contains_changecipherspec(List * pdu_list); int packet_contains_finished(List * pdu_list); int packet_contains_optional_stuff(List * pdu_list); int packet_contains_userdata(List * pdu_list); int packet_contains_clienthello(List * pdu_list); /* the is_type functions return 1 if all pdus in the list are of said type. * Else return 0. */ int packet_is_application_data(List * pdu_list); /* the is_*_alert functions return 1 if the packet is a pdu of the type expressed in the * function name. */ int is_critical_alert(List * pdu_list, WTLSMachine * wtls_machine); int is_warning_alert(List * pdu_list, WTLSMachine * wtls_machine); void calculate_client_key_block(WTLSMachine * wtls_machine); void calculate_server_key_block(WTLSMachine * wtls_machine); /* Printing naming functions. Free result from calling program. */ void cipherName(char *name, int cipher); void keyName(char *name, int key); void macName(char *name, int mac); void alertName(char *name, int alert); void pduName(char *name, int pdu); void hsName(char *name, int handshake); #endif /* WTLS_STATESUPPORT_H */ gateway-1.4.5/wap/wap_addr.c0000644000175000017500000001112113227613126014377 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_addr.c - implement WAPAddr and WAPAddrTuple types. */ #include #include #include "gwlib/gwlib.h" #include "wap_addr.h" WAPAddr *wap_addr_create(Octstr *address, long port) { WAPAddr *addr; addr = gw_malloc(sizeof(*addr)); addr->address = octstr_duplicate(address); addr->iaddr = inet_addr(octstr_get_cstr(address)); addr->port = port; return addr; } void wap_addr_destroy(WAPAddr *addr) { if (addr != NULL) { octstr_destroy(addr->address); gw_free(addr); } } int wap_addr_same(WAPAddr *a, WAPAddr *b) { /* XXX which ordering gives the best heuristical performance? */ return a->port == b->port && a->iaddr == b->iaddr; } WAPAddrTuple *wap_addr_tuple_create(Octstr *rmt_addr, long rmt_port, Octstr *lcl_addr, long lcl_port) { WAPAddrTuple *tuple; tuple = gw_malloc(sizeof(*tuple)); tuple->remote = wap_addr_create(rmt_addr, rmt_port); tuple->local = wap_addr_create(lcl_addr, lcl_port); return tuple; } void wap_addr_tuple_destroy(WAPAddrTuple *tuple) { if (tuple != NULL) { wap_addr_destroy(tuple->remote); wap_addr_destroy(tuple->local); gw_free(tuple); } } int wap_addr_tuple_same(WAPAddrTuple *a, WAPAddrTuple *b) { return wap_addr_same(a->remote, b->remote) && wap_addr_same(a->local, b->local); } WAPAddrTuple *wap_addr_tuple_duplicate(WAPAddrTuple *tuple) { if (tuple == NULL) return NULL; return wap_addr_tuple_create(tuple->remote->address, tuple->remote->port, tuple->local->address, tuple->local->port); } void wap_addr_tuple_dump(WAPAddrTuple *tuple) { debug("wap", 0, "WAPAddrTuple %p = <%s:%ld> - <%s:%ld>", (void *) tuple, octstr_get_cstr(tuple->remote->address), tuple->remote->port, octstr_get_cstr(tuple->local->address), tuple->local->port); } gateway-1.4.5/wap/wtls_pdusupport.c0000644000175000017500000011534313227613126016127 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtls_support.c: pack and unpack WTLS packets * * Support functions for packing and unpacking PDUs * * Nikos Balkanas, Inaccess Networks (2009) * */ #include "gwlib/gwlib.h" #ifdef HAVE_WTLS_OPENSSL #include "wtls_pdu.h" #include "wtls_pdusupport.h" #include "wtls_statesupport.h" extern PublicKeyAlgorithm public_key_algo; extern SignatureAlgorithm signature_algo; /* Function prototypes */ void destroy_octstr(Octstr * data); void destroy_octstr16(Octstr * data); void destroy_octstr_fixed(Octstr * data); void destroy_dhparams(DHParameters * dhparams); void destroy_ecparams(ECParameters * ecparams); void destroy_public_key(PublicKey * key); void destroy_rsa_secret(RSASecret * secret); void destroy_key_exchange_id(KeyExchangeId * keyexid); void destroy_signature(Signature * sig); void dump_void16(char *dbg, int level, int i); /***************************************************************** * PACK functions */ int pack_int16(Octstr * data, long charpos, int i) { octstr_append_char(data, (i & 0xFF00) >> 8); charpos += 1; octstr_append_char(data, i & 0x00FF); charpos += 1; return charpos; } int pack_int32(Octstr * data, long charpos, long i) { charpos = pack_int16(data, charpos, (i & 0xFFFF0000) >> 16); charpos = pack_int16(data, charpos, i & 0xFFFF); return charpos; } int pack_octstr(Octstr * data, long charpos, Octstr * opaque) { octstr_append_char(data, octstr_len(opaque)); charpos += 1; octstr_insert(data, opaque, octstr_len(data)); charpos += octstr_len(opaque); return charpos; } int pack_octstr16(Octstr * data, long charpos, Octstr * opaque) { charpos += pack_int16(data, charpos, octstr_len(opaque)); octstr_insert(data, opaque, octstr_len(data)); charpos += octstr_len(opaque); return charpos; } int pack_octstr_fixed(Octstr * data, long charpos, Octstr * opaque) { octstr_insert(data, opaque, octstr_len(data)); charpos += octstr_len(opaque); return charpos; } int pack_random(Octstr * data, long charpos, Random * random) { charpos = pack_int32(data, charpos, random->gmt_unix_time); charpos = pack_octstr_fixed(data, charpos, random->random_bytes); return charpos; } int pack_dhparams(Octstr * data, long charpos, DHParameters * dhparams) { octstr_append_char(data, dhparams->dh_e); charpos += 1; charpos = pack_octstr16(data, charpos, dhparams->dh_p); charpos = pack_octstr16(data, charpos, dhparams->dh_g); return charpos; } int pack_ecparams(Octstr * data, long charpos, ECParameters * ecparams) { /* field */ octstr_append_char(data, ecparams->field); charpos += 1; switch (ecparams->field) { case ec_prime_p: charpos = pack_octstr(data, charpos, ecparams->prime_p); break; case ec_characteristic_two: /* m (16 bits) */ charpos = pack_int16(data, charpos, ecparams->m); /* basis */ octstr_append_char(data, ecparams->basis); charpos += 1; switch (ecparams->basis) { case ec_basis_onb: break; case ec_basis_trinomial: charpos = pack_int16(data, charpos, ecparams->k); break; case ec_basis_pentanomial: charpos = pack_int16(data, charpos, ecparams->k1); charpos = pack_int16(data, charpos, ecparams->k2); charpos = pack_int16(data, charpos, ecparams->k3); break; case ec_basis_polynomial: charpos = pack_octstr(data, charpos, ecparams->irreducible); break; } break; } /* pack the ECCurve */ charpos = pack_octstr(data, charpos, ecparams->curve->a); charpos = pack_octstr(data, charpos, ecparams->curve->b); charpos = pack_octstr(data, charpos, ecparams->curve->seed); /* pack the ECPoint */ charpos = pack_octstr(data, charpos, ecparams->base->point); /* order and cofactor */ charpos = pack_octstr(data, charpos, ecparams->order); charpos = pack_octstr(data, charpos, ecparams->cofactor); return charpos; } int pack_param_spec(Octstr * data, long charpos, ParameterSpecifier * pspec) { if (pspec == NULL) { octstr_append_char(data, 0); charpos += 1; return charpos; } /* index */ octstr_append_char(data, pspec->param_index); charpos += 1; /* ParameterSet struct */ octstr_append_char(data, pspec->param_set->length); charpos += 1; switch (public_key_algo) { case diffie_hellman_pubkey: pack_dhparams(data, charpos, pspec->param_set->dhparams); break; case elliptic_curve_pubkey: pack_ecparams(data, charpos, pspec->param_set->ecparams); break; default: break; } return charpos; } int pack_public_key(Octstr * data, long charpos, PublicKey * key, PublicKeyType key_type) { switch (key_type) { case ecdh_key: charpos = pack_octstr(data, charpos, key->ecdh_pubkey->point); break; case ecdsa_key: charpos = pack_octstr(data, charpos, key->ecdsa_pubkey->point); break; case rsa_key: charpos = pack_rsa_pubkey(data, charpos, key->rsa_pubkey); break; } return charpos; } int pack_rsa_pubkey(Octstr * data, long charpos, RSAPublicKey * key) { charpos = pack_octstr16(data, charpos, key->rsa_exponent); charpos = pack_octstr16(data, charpos, key->rsa_modulus); return charpos; } int pack_ec_pubkey(Octstr * data, long charpos, ECPublicKey * key) { charpos = pack_octstr(data, charpos, key->point); return charpos; } int pack_dh_pubkey(Octstr * data, long charpos, DHPublicKey * key) { charpos = pack_octstr16(data, charpos, key->dh_Y); return charpos; } int pack_rsa_secret(Octstr * data, long charpos, RSASecret * secret) { octstr_append_char(data, secret->client_version); charpos += 1; charpos = pack_array(data, charpos, secret->random); return charpos; } int pack_rsa_encrypted_secret(Octstr * data, long charpos, RSAEncryptedSecret * secret) { charpos = pack_octstr16(data, charpos, secret->encrypted_secret); return charpos; } int pack_key_exchange_id(Octstr * data, long charpos, KeyExchangeId * keyexid) { octstr_set_char(data, charpos, keyexid->key_exchange_suite); charpos += 1; charpos = pack_param_spec(data, charpos, keyexid->param_specif); charpos = pack_identifier(data, charpos, keyexid->identifier); return charpos; } int pack_array(Octstr * data, long charpos, List * array) { int i; long pos = 0; Octstr *buffer; /* we need to know the length in bytes of the list so we pack everything in a buffer for now. */ buffer = octstr_create(""); /* pack each entry in the buffer */ for (i = 0; i < gwlist_len(array); i++) { pos = pack_octstr(buffer, pos, (Octstr *) gwlist_get(array, i)); } /* now we know the size of the list */ charpos = pack_int16(data, charpos, pos); /* append the buffer */ charpos = pack_octstr_fixed(data, charpos, buffer); return charpos; } int pack_key_list(Octstr * data, long charpos, List * key_list) { int i; long pos = 0; Octstr *buffer; KeyExchangeId *keyexid; /* we need to know the length in bytes of the list so we pack everything in a buffer for now. */ buffer = octstr_create(""); /* pack the KeyExchangeIds */ for (i = 0; i < gwlist_len(key_list); i++) { keyexid = (KeyExchangeId *) gwlist_get(key_list, i); pos = pack_key_exchange_id(buffer, pos, keyexid); } /* now we know the size of the list */ charpos = pack_int16(data, charpos, pos); /* append the buffer */ charpos = pack_octstr_fixed(data, charpos, buffer); return charpos; } int pack_ciphersuite_list(Octstr * data, long charpos, List * ciphersuites) { int i; CipherSuite *cs; /* vector starts with its length Each element uses 2 bytes */ octstr_set_char(data, charpos, gwlist_len(ciphersuites) * 2); charpos += 1; /* pack the CipherSuites */ for (i = 0; i < gwlist_len(ciphersuites); i++) { cs = (CipherSuite *) gwlist_get(ciphersuites, i); octstr_set_char(data, charpos, cs->bulk_cipher_algo); charpos += 1; octstr_set_char(data, charpos, cs->mac_algo); charpos += 1; } return charpos; } int pack_compression_method_list(Octstr * data, long charpos, List * compmethod_list) { int i; /* vector starts with its length */ octstr_set_char(data, charpos, gwlist_len(compmethod_list)); charpos += 1; /* pack the CompressionMethods */ for (i = 0; i < gwlist_len(compmethod_list); i++) { octstr_set_char(data, charpos, (CompressionMethod) gwlist_get(compmethod_list, i)); charpos += 1; } return charpos; } int pack_identifier(Octstr * data, long charpos, Identifier * ident) { switch (ident->id_type) { case text: octstr_set_char(data, charpos, ident->charset); charpos += 1; charpos = pack_octstr(data, charpos, ident->name); break; case binary: charpos = pack_octstr(data, charpos, ident->identifier); break; case key_hash_sha: charpos = pack_octstr(data, charpos, ident->key_hash); break; case x509_name: charpos = pack_octstr(data, charpos, ident->distinguished_name); break; default: break; } return charpos; } int pack_signature(Octstr * data, long charpos, Signature * sig) { switch (signature_algo) { case ecdsa_sha: case rsa_sha: charpos = pack_array(data, charpos, sig->sha_hash); break; default: break; } return charpos; } int pack_wtls_certificate(Octstr * data, long charpos, WTLSCertificate * cert) { /* === pack ToBeSignedCertificate === */ /* version */ octstr_set_char(data, charpos, cert->tobesigned_cert->certificate_version); charpos += 1; /* sig algo */ octstr_set_char(data, charpos, cert->tobesigned_cert->signature_algo); charpos += 1; /* identifier */ octstr_set_char(data, charpos, cert->tobesigned_cert->issuer->id_type); charpos += 1; /* issuer Identifier */ charpos = pack_identifier(data, charpos, cert->tobesigned_cert->issuer); /* validity periods */ charpos = pack_int32(data, charpos, cert->tobesigned_cert->valid_not_before); charpos = pack_int32(data, charpos, cert->tobesigned_cert->valid_not_after); /* subject Identifier */ charpos = pack_identifier(data, charpos, cert->tobesigned_cert->subject); /* public_key_type */ octstr_set_char(data, charpos, cert->tobesigned_cert->pubkey_type); charpos += 1; /* parameter specifier */ charpos = pack_param_spec(data, charpos, cert->tobesigned_cert->param_spec); /* public key */ charpos = pack_public_key(data, charpos, cert->tobesigned_cert->pubkey, cert->tobesigned_cert->pubkey_type); /* === pack Signature === */ charpos = pack_signature(data, charpos, cert->signature); return charpos; } /***************************************************************** * UNPACK functions */ int unpack_int16(Octstr * data, long *charpos) { int n; n = octstr_get_char(data, *charpos) << 8; *charpos += 1; n += octstr_get_char(data, *charpos); *charpos += 1; return n; } long unpack_int32(Octstr * data, long *charpos) { int n; n = octstr_get_char(data, *charpos); n = n << 8; *charpos += 1; n += octstr_get_char(data, *charpos); n = n << 8; *charpos += 1; n += octstr_get_char(data, *charpos); n = n << 8; *charpos += 1; n += octstr_get_char(data, *charpos); *charpos += 1; return n; } Octstr *unpack_octstr(Octstr * data, long *charpos) { int length; Octstr *opaque; length = octstr_get_char(data, *charpos); *charpos += 1; opaque = octstr_copy(data, *charpos, length); *charpos += length; return opaque; } Octstr *unpack_octstr16(Octstr * data, long *charpos) { long length; Octstr *opaque; length = unpack_int16(data, charpos); opaque = octstr_copy(data, *charpos, length); *charpos += length; return opaque; } Octstr *unpack_octstr_fixed(Octstr * data, long *charpos, long length) { Octstr *opaque; opaque = octstr_copy(data, *charpos, length); *charpos += length; return opaque; } Random *unpack_random(Octstr * data, long *charpos) { Random *random; /* create the Random structure */ random = (Random *) gw_malloc(sizeof(Random)); random->gmt_unix_time = unpack_int32(data, charpos); random->random_bytes = unpack_octstr_fixed(data, charpos, 12); return random; } DHParameters *unpack_dhparams(Octstr * data, long *charpos) { DHParameters *dhparams; /* create the DHParameters */ dhparams = (DHParameters *) gw_malloc(sizeof(DHParameters)); dhparams->dh_e = octstr_get_char(data, *charpos); *charpos += 1; dhparams->dh_p = unpack_octstr16(data, charpos); dhparams->dh_g = unpack_octstr16(data, charpos); return dhparams; } ECParameters *unpack_ecparams(Octstr * data, long *charpos) { ECParameters *ecparams; /* create the ECParameters */ ecparams = (ECParameters *) gw_malloc(sizeof(ECParameters)); /* field */ ecparams->field = octstr_get_char(data, *charpos); *charpos += 1; switch (ecparams->field) { case ec_prime_p: ecparams->prime_p = unpack_octstr(data, charpos); break; case ec_characteristic_two: /* m (16 bits) */ ecparams->m = unpack_int16(data, charpos); /* basis */ ecparams->basis = octstr_get_char(data, *charpos); *charpos += 1; switch (ecparams->basis) { case ec_basis_onb: break; case ec_basis_trinomial: ecparams->k = unpack_int16(data, charpos); break; case ec_basis_pentanomial: ecparams->k1 = unpack_int16(data, charpos); ecparams->k2 = unpack_int16(data, charpos); ecparams->k3 = unpack_int16(data, charpos); break; case ec_basis_polynomial: ecparams->irreducible = unpack_octstr(data, charpos); break; } break; } /* pack the ECCurve */ ecparams->curve->a = unpack_octstr(data, charpos); ecparams->curve->b = unpack_octstr(data, charpos); ecparams->curve->seed = unpack_octstr(data, charpos); /* pack the ECPoint */ ecparams->base->point = unpack_octstr(data, charpos); /* order and cofactor */ ecparams->order = unpack_octstr(data, charpos); ecparams->cofactor = unpack_octstr(data, charpos); return ecparams; } ParameterSpecifier *unpack_param_spec(Octstr * data, long *charpos) { ParameterSpecifier *pspec; /* create the ParameterSpecifier */ pspec = (ParameterSpecifier *) gw_malloc(sizeof(ParameterSpecifier)); /* index */ pspec->param_index = octstr_get_char(data, *charpos); *charpos += 1; /* ParameterSet struct */ if (pspec->param_index == 255) { pspec->param_set = (ParameterSet *) gw_malloc(sizeof(ParameterSet)); pspec->param_set->length = octstr_get_char(data, *charpos); *charpos += 1; switch (public_key_algo) { case diffie_hellman_pubkey: pspec->param_set->dhparams = unpack_dhparams(data, charpos); break; case elliptic_curve_pubkey: pspec->param_set->ecparams = unpack_ecparams(data, charpos); break; default: break; } } return pspec; } RSAPublicKey *unpack_rsa_pubkey(Octstr * data, long *charpos) { RSAPublicKey *key; /* create the RSAPublicKey */ key = (RSAPublicKey *) gw_malloc(sizeof(RSAPublicKey)); key->rsa_exponent = unpack_octstr16(data, charpos); key->rsa_modulus = unpack_octstr16(data, charpos); return key; } DHPublicKey *unpack_dh_pubkey(Octstr * data, long *charpos) { DHPublicKey *key; /* create the DHPublicKey */ key = (DHPublicKey *) gw_malloc(sizeof(DHPublicKey)); key->dh_Y = unpack_octstr16(data, charpos); return key; } ECPublicKey *unpack_ec_pubkey(Octstr * data, long *charpos) { ECPublicKey *key; /* create the ECPublicKey */ key = (ECPublicKey *) gw_malloc(sizeof(ECPublicKey)); key->point = unpack_octstr(data, charpos); return key; } RSASecret *unpack_rsa_secret(Octstr * data, long *charpos) { RSASecret *secret; /* create the RSASecret */ secret = (RSASecret *) gw_malloc(sizeof(RSASecret)); secret->client_version = octstr_get_char(data, *charpos); *charpos += 1; secret->random = unpack_array(data, charpos); return secret; } RSAEncryptedSecret *unpack_rsa_encrypted_secret(Octstr * data, long *charpos) { RSAEncryptedSecret *secret; /* create the RSASecret */ secret = (RSAEncryptedSecret *) gw_malloc(sizeof(RSAEncryptedSecret)); //secret->encrypted_secret = unpack_octstr16(data, charpos); secret->encrypted_secret = unpack_octstr_fixed(data, charpos, octstr_len(data) - *charpos); return secret; } PublicKey *unpack_public_key(Octstr * data, long *charpos, PublicKeyType key_type) { PublicKey *key; /* create the PublicKey */ key = (PublicKey *) gw_malloc(sizeof(PublicKey)); switch (key_type) { case ecdh_key: key->ecdh_pubkey = unpack_ec_pubkey(data, charpos); break; case ecdsa_key: key->ecdsa_pubkey = unpack_ec_pubkey(data, charpos); break; case rsa_key: key->rsa_pubkey = unpack_rsa_pubkey(data, charpos); break; } return key; } KeyExchangeId *unpack_key_exchange_id(Octstr * data, long *charpos) { KeyExchangeId *keyexid; /* create the KeyExchangeID */ keyexid = (KeyExchangeId *) gw_malloc(sizeof(KeyExchangeId)); keyexid->key_exchange_suite = octstr_get_char(data, *charpos); *charpos += 1; keyexid->param_specif = unpack_param_spec(data, charpos); keyexid->identifier = unpack_identifier(data, charpos); return keyexid; } List *unpack_array(Octstr * data, long *charpos) { int i; int array_length; List *array; /* create the list */ array = gwlist_create(); /* get the size of the array */ array_length = octstr_get_char(data, *charpos); *charpos += 1; /* store each entry in the list */ for (i = 0; i < array_length; i++) { gwlist_append(array, (void *)unpack_octstr(data, charpos)); } return array; } List *unpack_key_list(Octstr * data, long *charpos) { KeyExchangeId *keyexid; List *key_list; int gwlist_length; long endpos; /* create the list */ key_list = gwlist_create(); /* get the size of the array */ gwlist_length = unpack_int16(data, charpos); endpos = *charpos + gwlist_length; /* unpack the KeyExchangeIds */ while (*charpos < endpos) { keyexid = unpack_key_exchange_id(data, charpos); gwlist_append(key_list, (void *)keyexid); } return key_list; } List *unpack_ciphersuite_list(Octstr * data, long *charpos) { List *ciphersuites; int gwlist_length; int i; CipherSuite *cs; /* create the list */ ciphersuites = gwlist_create(); /* get the size of the array (in bytes, not elements) */ gwlist_length = octstr_get_char(data, *charpos); *charpos += 1; /* unpack the CipherSuites */ for (i = 0; i < gwlist_length; i += 2) { cs = (CipherSuite *) gw_malloc(sizeof(CipherSuite)); cs->bulk_cipher_algo = octstr_get_char(data, *charpos); *charpos += 1; cs->mac_algo = octstr_get_char(data, *charpos); *charpos += 1; gwlist_append(ciphersuites, (void *)cs); } return ciphersuites; } List *unpack_compression_method_list(Octstr * data, long *charpos) { List *compmethod_list; int gwlist_length; int i; CompressionMethod *cm; /* create the list */ compmethod_list = gwlist_create(); /* get the size of the array */ gwlist_length = octstr_get_char(data, *charpos); *charpos += 1; /* unpack the CompressionMethods */ for (i = 0; i < gwlist_length; i++) { cm = gw_malloc(sizeof(CompressionMethod)); *cm = octstr_get_char(data, *charpos); gwlist_append(compmethod_list, (void *)cm); } return compmethod_list; } Identifier *unpack_identifier(Octstr * data, long *charpos) { Identifier *ident; /* create Identifier */ ident = (Identifier *) gw_malloc(sizeof(Identifier)); ident->id_type = octstr_get_char(data, *charpos); *charpos += 1; switch (ident->id_type) { case text: ident->charset = octstr_get_char(data, *charpos); *charpos += 1; ident->name = unpack_octstr(data, charpos); break; case binary: ident->identifier = unpack_octstr(data, charpos); break; case key_hash_sha: ident->key_hash = unpack_octstr(data, charpos); break; case x509_name: ident->distinguished_name = unpack_octstr(data, charpos); break; default: break; } return ident; } Signature *unpack_signature(Octstr * data, long *charpos) { Signature *sig; /* create Signature */ sig = (Signature *) gw_malloc(sizeof(Signature)); switch (signature_algo) { case ecdsa_sha: case rsa_sha: sig->sha_hash = unpack_array(data, charpos); break; default: break; } return sig; } WTLSCertificate *unpack_wtls_certificate(Octstr * data, long *charpos) { WTLSCertificate *cert; /* create the Certificate */ cert = (WTLSCertificate *) gw_malloc(sizeof(WTLSCertificate)); /* === unpack ToBeSignedCertificate === */ cert->tobesigned_cert = (ToBeSignedCertificate *) gw_malloc(sizeof(ToBeSignedCertificate)); /* version */ cert->tobesigned_cert->certificate_version = octstr_get_char(data, *charpos); *charpos += 1; /* sig algo */ cert->tobesigned_cert->signature_algo = octstr_get_char(data, *charpos); *charpos += 1; /* identifier */ cert->tobesigned_cert->issuer->id_type = octstr_get_char(data, *charpos); *charpos += 1; /* issuer Identifier */ cert->tobesigned_cert->issuer = unpack_identifier(data, charpos); /* validity periods */ cert->tobesigned_cert->valid_not_before = unpack_int32(data, charpos); cert->tobesigned_cert->valid_not_after = unpack_int32(data, charpos); /* subject Identifier */ cert->tobesigned_cert->subject = unpack_identifier(data, charpos); /* public_key_type */ cert->tobesigned_cert->pubkey_type = octstr_get_char(data, *charpos); *charpos += 1; /* parameter specifier */ cert->tobesigned_cert->param_spec = unpack_param_spec(data, charpos); /* public key */ cert->tobesigned_cert->pubkey = unpack_public_key(data, charpos, cert-> tobesigned_cert-> pubkey_type); /* === pack Signature === */ cert->signature = unpack_signature(data, charpos); return cert; } /***************************************************************** * DESTROY functions */ void destroy_octstr(Octstr * data) { octstr_destroy(data); } void destroy_octstr16(Octstr * data) { octstr_destroy(data); } void destroy_octstr_fixed(Octstr * data) { octstr_destroy(data); } void destroy_random(Random * random) { octstr_destroy(random->random_bytes); gw_free(random); } void destroy_dhparams(DHParameters * dhparams) { destroy_octstr16(dhparams->dh_p); destroy_octstr16(dhparams->dh_g); gw_free(dhparams); } void destroy_ecparams(ECParameters * ecparams) { /* field */ switch (ecparams->field) { case ec_prime_p: octstr_destroy(ecparams->prime_p); break; case ec_characteristic_two: switch (ecparams->basis) { case ec_basis_onb: break; case ec_basis_trinomial: break; case ec_basis_pentanomial: break; case ec_basis_polynomial: octstr_destroy(ecparams->irreducible); break; } break; } /* pack the ECCurve */ octstr_destroy(ecparams->curve->a); octstr_destroy(ecparams->curve->b); octstr_destroy(ecparams->curve->seed); /* pack the ECPoint */ octstr_destroy(ecparams->base->point); /* order and cofactor */ octstr_destroy(ecparams->order); octstr_destroy(ecparams->cofactor); gw_free(ecparams); } void destroy_param_spec(ParameterSpecifier * pspec) { switch (public_key_algo) { case diffie_hellman_pubkey: destroy_dhparams(pspec->param_set->dhparams); break; case elliptic_curve_pubkey: destroy_ecparams(pspec->param_set->ecparams); break; default: break; } gw_free(pspec); } void destroy_public_key(PublicKey * key) { if (key->ecdh_pubkey) { octstr_destroy(key->ecdh_pubkey->point); gw_free(key->ecdh_pubkey); } if (key->ecdsa_pubkey) { octstr_destroy(key->ecdsa_pubkey->point); gw_free(key->ecdsa_pubkey); } if (key->rsa_pubkey) { destroy_rsa_pubkey(key->rsa_pubkey); } gw_free(key); } void destroy_rsa_pubkey(RSAPublicKey * key) { octstr_destroy(key->rsa_exponent); octstr_destroy(key->rsa_modulus); gw_free(key); } void destroy_ec_pubkey(ECPublicKey * key) { octstr_destroy(key->point); gw_free(key); } void destroy_dh_pubkey(DHPublicKey * key) { octstr_destroy(key->dh_Y); gw_free(key); } void destroy_rsa_secret(RSASecret * secret) { destroy_array(secret->random); gw_free(secret); } void destroy_rsa_encrypted_secret(RSAEncryptedSecret * secret) { octstr_destroy(secret->encrypted_secret); gw_free(secret); } void destroy_key_exchange_id(KeyExchangeId * keyexid) { destroy_param_spec(keyexid->param_specif); destroy_identifier(keyexid->identifier); gw_free(keyexid); } void destroy_array(List * array) { int i; /* pack each entry in the array */ for (i = 0; i < gwlist_len(array); i++) { octstr_destroy((Octstr *) gwlist_get(array, i)); } gwlist_destroy(array, NULL); } void destroy_key_list(List * key_list) { int i; /* destroy the KeyExchangeIds */ for (i = 0; i < gwlist_len(key_list); i++) { destroy_key_exchange_id((KeyExchangeId *) gwlist_get(key_list, i)); } gwlist_destroy(key_list, NULL); } void destroy_ciphersuite_list(List * ciphersuites) { int i; /* destroy the CipherSuites */ for (i = 0; i < gwlist_len(ciphersuites); i++) { gw_free((CipherSuite *) gwlist_get(ciphersuites, i)); } gwlist_destroy(ciphersuites, NULL); } void destroy_compression_method_list(List * compmethod_list) { int i; CompressionMethod *cm; /* destroy the CompressionMethods */ for (i = 0; i < gwlist_len(compmethod_list); i++) { cm = (CompressionMethod *) gwlist_get(compmethod_list, i); gw_free(cm); } gw_free(compmethod_list); } void destroy_identifier(Identifier * ident) { switch (ident->id_type) { case text: octstr_destroy(ident->name); break; case binary: octstr_destroy(ident->identifier); break; case key_hash_sha: octstr_destroy(ident->key_hash); break; case x509_name: octstr_destroy(ident->distinguished_name); break; default: break; } gw_free(ident); } void destroy_signature(Signature * sig) { switch (signature_algo) { case ecdsa_sha: case rsa_sha: destroy_array(sig->sha_hash); break; default: break; } gw_free(sig); } void destroy_wtls_certificate(WTLSCertificate * cert) { /* === destroy ToBeSignedCertificate === */ /* issuer Identifier */ destroy_identifier(cert->tobesigned_cert->issuer); /* subject Identifier */ destroy_identifier(cert->tobesigned_cert->subject); /* parameter specifier */ destroy_param_spec(cert->tobesigned_cert->param_spec); /* public key */ destroy_public_key(cert->tobesigned_cert->pubkey); /* === destroy Signature === */ destroy_signature(cert->signature); gw_free(cert); } /***************************************************************** * DUMP functions */ void dump_void16(char *dbg, int level, int i) { debug(dbg, 0, "%*s16 bit Int: %d", level, "", i); } void dump_int32(char *dbg, int level, long i) { debug(dbg, 0, "%*s32 bit Int: %ld", level, "", i); } void dump_octstr(char *dbg, int level, Octstr * opaque) { octstr_dump(opaque, 0); } void dump_octstr16(char *dbg, int level, Octstr * opaque) { octstr_dump(opaque, 0); } void dump_octstr_fixed(char *dbg, int level, Octstr * opaque) { octstr_dump(opaque, 0); } void dump_random(char *dbg, int level, Random * random) { debug(dbg, 0, "%*sRandom :", level, ""); debug(dbg, 0, "%*sGMT Unix Time: %ld", level + 1, "", random->gmt_unix_time); debug(dbg, 0, "%*sRandom Bytes:", level + 1, ""); dump_octstr_fixed(dbg, level + 2, random->random_bytes); } void dump_dhparams(char *dbg, int level, DHParameters * dhparams) { debug(dbg, 0, "%*sDH Parameters :", level, ""); debug(dbg, 0, "%*sdh_e: %d", level + 1, "", dhparams->dh_e); debug(dbg, 0, "%*sdh_p:", level + 1, ""); dump_octstr16(dbg, level + 2, dhparams->dh_p); debug(dbg, 0, "%*sdh_g:", level + 1, ""); dump_octstr16(dbg, level + 2, dhparams->dh_g); } void dump_ecparams(char *dbg, int level, ECParameters * ecparams) { debug(dbg, 0, "%*sEC Parameters :", level, ""); /* field */ debug(dbg, 0, "%*sField: %d", level + 1, "", ecparams->field); switch (ecparams->field) { case ec_prime_p: debug(dbg, 0, "%*sprime_p :", level + 1, ""); dump_octstr(dbg, level + 1, ecparams->prime_p); break; case ec_characteristic_two: /* m (16 bits) */ debug(dbg, 0, "%*sM: %d", level + 1, "", ecparams->m); /* basis */ debug(dbg, 0, "%*sBasis: %d", level + 1, "", ecparams->basis); switch (ecparams->basis) { case ec_basis_onb: break; case ec_basis_trinomial: debug(dbg, 0, "%*sK: %d", level + 1, "", ecparams->k); break; case ec_basis_pentanomial: debug(dbg, 0, "%*sk1: %d", level + 1, "", ecparams->k1); debug(dbg, 0, "%*sk2: %d", level + 1, "", ecparams->k2); debug(dbg, 0, "%*sk3: %d", level + 1, "", ecparams->k3); break; case ec_basis_polynomial: debug(dbg, 0, "%*sirreducible: 0x%p", level + 1, "", ecparams->irreducible); dump_octstr(dbg, level + 1, ecparams->irreducible); break; } break; } /* pack the ECCurve */ debug(dbg, 0, "%*sEC Curve: 0x%p", level + 1, "", ecparams->curve); debug(dbg, 0, "%*sa: 0x%p", level + 2, "", ecparams->curve->a); dump_octstr(dbg, level + 2, ecparams->curve->a); debug(dbg, 0, "%*sb: 0x%p", level + 2, "", ecparams->curve->b); dump_octstr(dbg, level + 2, ecparams->curve->b); debug(dbg, 0, "%*sseed: 0x%p", level + 2, "", ecparams->curve->seed); dump_octstr(dbg, level + 2, ecparams->curve->seed); /* pack the ECPoint */ debug(dbg, 0, "%*spoint: 0x%p", level + 2, "", ecparams->base->point); dump_octstr(dbg, level + 2, ecparams->base->point); /* order and cofactor */ debug(dbg, 0, "%*sorder: 0x%p", level + 2, "", ecparams->order); dump_octstr(dbg, level + 2, ecparams->order); debug(dbg, 0, "%*scofactor: 0x%p", level + 2, "", ecparams->cofactor); dump_octstr(dbg, level + 2, ecparams->cofactor); } void dump_param_spec(char *dbg, int level, ParameterSpecifier * pspec) { debug(dbg, 0, "%*sParameterSpecifier:", level, ""); /* index */ debug(dbg, 0, "%*sParameter Index: %d", level + 1, "", pspec->param_index); /* ParameterSet struct */ if (pspec->param_index == 255) { debug(dbg, 0, "%*sLength: %ld", level + 1, "", pspec->param_set->length); switch (public_key_algo) { case diffie_hellman_pubkey: dump_dhparams(dbg, level + 1, pspec->param_set->dhparams); break; case elliptic_curve_pubkey: dump_ecparams(dbg, level + 1, pspec->param_set->ecparams); break; default: break; } } } void dump_public_key(char *dbg, int level, PublicKey * key, PublicKeyType key_type) { switch (key_type) { case ecdh_key: debug(dbg, 0, "%*sPublicKey: 0x%p", level, "", key->ecdh_pubkey); debug(dbg, 0, "%*sECDH Point: 0x%p", level + 1, "", key->ecdh_pubkey->point); dump_octstr(dbg, level + 1, key->ecdh_pubkey->point); break; case ecdsa_key: debug(dbg, 0, "%*sECDSA Point: 0x%p", level + 1, "", key->ecdsa_pubkey->point); dump_octstr(dbg, level + 1, key->ecdsa_pubkey->point); break; case rsa_key: dump_rsa_pubkey(dbg, level + 1, key->rsa_pubkey); break; } } void dump_rsa_pubkey(char *dbg, int level, RSAPublicKey * key) { debug(dbg, 0, "%*sRSA Public Key: 0x%p", level, "", key); debug(dbg, 0, "%*sRSA Exponent: 0x%p", level + 1, "", key->rsa_exponent); dump_octstr(dbg, level + 2, key->rsa_exponent); debug(dbg, 0, "%*sRSA Modulus: 0x%p", level + 1, "", key->rsa_modulus); dump_octstr(dbg, level + 2, key->rsa_modulus); } void dump_ec_pubkey(char *dbg, int level, ECPublicKey * key) { debug(dbg, 0, "%*sEC Public Key: 0x%p", level, "", key); debug(dbg, 0, "%*sPoint: 0x%p", level + 1, "", key->point); dump_octstr(dbg, level + 2, key->point); } void dump_dh_pubkey(char *dbg, int level, DHPublicKey * key) { debug(dbg, 0, "%*sDH Public Key: 0x%p", level, "", key->dh_Y); dump_octstr(dbg, level + 2, key->dh_Y); } void dump_rsa_secret(char *dbg, int level, RSASecret * secret) { debug(dbg, 0, "%*sRSA Secret: 0x%p", level, "", secret); debug(dbg, 0, "%*sClient Version: %d", level + 1, "", secret->client_version); debug(dbg, 0, "%*sRandom: 0x%p", level, "", secret->random); dump_array(dbg, level + 2, secret->random); } void dump_rsa_encrypted_secret(char *dbg, int level, RSAEncryptedSecret * secret) { debug(dbg, 0, "%*sRSA Encrypted Secret: %p", level, "", secret->encrypted_secret); dump_octstr(dbg, level + 1, secret->encrypted_secret); } void dump_key_exchange_id(char *dbg, int level, KeyExchangeId * keyexid) { debug(dbg, 0, "%*sKey Exchange Id: 0x%p", level, "", keyexid); debug(dbg, 0, "%*sKey Exch Suite: %d", level + 1, "", keyexid->key_exchange_suite); dump_param_spec(dbg, level + 1, keyexid->param_specif); dump_identifier(dbg, level + 1, keyexid->identifier); } void dump_array(char *dbg, int level, List * array) { int i; /*debug(dbg, 0, "%*sOctstr Array: %p", level, ""); */ /* dump each entry in the array */ for (i = 0; i < gwlist_len(array); i++) { debug(dbg, 0, "%*sElement %d", level, "", i); dump_octstr(dbg, level + 1, (Octstr *) gwlist_get(array, i)); } } void dump_key_list(char *dbg, int level, List * key_list) { int i; KeyExchangeId *keyexid; debug(dbg, 0, "%*sKey List: 0x%p", level, "", key_list); /* pack the KeyExchangeIds */ for (i = 0; i < gwlist_len(key_list); i++) { keyexid = (KeyExchangeId *) gwlist_get(key_list, i); dump_key_exchange_id(dbg, level + 1, keyexid); } } void dump_ciphersuite_list(char *dbg, int level, List * ciphersuites) { int i; CipherSuite *cs; debug(dbg, 0, "%*sCipherSuite List: 0x%p", level, "", ciphersuites); /* dump the CipherSuites */ for (i = 0; i < gwlist_len(ciphersuites); i++) { cs = (CipherSuite *) gwlist_get(ciphersuites, i); debug(dbg, 0, "%*sBulk Cipher Algo: %d", level, "", cs->bulk_cipher_algo); debug(dbg, 0, "%*sMAC Algo: %d", level, "", cs->mac_algo); } } void dump_compression_method_list(char *dbg, int level, List * compmethod_list) { int i; debug(dbg, 0, "%*sCompression Method List: 0x%p", level, "", compmethod_list); /* pack the CompressionMethods */ for (i = 0; i < gwlist_len(compmethod_list); i++) { debug(dbg, 0, "%*sMethod %d: %d", level, "", i, (CompressionMethod) gwlist_get(compmethod_list, i)); } } void dump_identifier(char *dbg, int level, Identifier * ident) { debug(dbg, 0, "%*sIdentifier: 0x%p", level, "", ident); debug(dbg, 0, "%*sIdent type: %d", level + 1, "", ident->id_type); switch (ident->id_type) { case text: debug(dbg, 0, "%*sCharset: %d", level + 1, "", ident->charset); debug(dbg, 0, "%*sNamet: %s", level + 1, "", octstr_get_cstr(ident->name)); break; case binary: debug(dbg, 0, "%*sIdentifier: 0x%p", level + 1, "", ident->identifier); dump_octstr(dbg, level + 2, ident->identifier); break; case key_hash_sha: debug(dbg, 0, "%*sKey Hash: 0x%p", level + 1, "", ident->key_hash); dump_octstr(dbg, level + 2, ident->key_hash); break; case x509_name: debug(dbg, 0, "%*sDistinguished Name: 0x%p", level + 1, "", ident->distinguished_name); dump_octstr(dbg, level + 2, ident->distinguished_name); break; default: break; } } void dump_signature(char *dbg, int level, Signature * sig) { debug(dbg, 0, "%*sSignature: 0x%p", level, "", sig); switch (signature_algo) { case ecdsa_sha: case rsa_sha: dump_array(dbg, level + 1, sig->sha_hash); break; default: break; } } void dump_wtls_certificate(char *dbg, int level, WTLSCertificate * cert) { debug(dbg, 0, "%*sWTLS Certificate: 0x%p", level, "", cert); /* === pack ToBeSignedCertificate === */ /* version */ debug(dbg, 0, "%*sCertificate Version: %d", level + 1, "", cert->tobesigned_cert->certificate_version); /* sig algo */ debug(dbg, 0, "%*sSignature Algo: %d", level + 1, "", cert->tobesigned_cert->signature_algo); /* identifier */ debug(dbg, 0, "%*sID Type: %d", level + 1, "", cert->tobesigned_cert->issuer->id_type); /* issuer Identifier */ dump_identifier(dbg, level + 1, cert->tobesigned_cert->issuer); /* validity periods */ debug(dbg, 0, "%*sValid not Before: %ld", level + 1, "", cert->tobesigned_cert->valid_not_before); debug(dbg, 0, "%*sValid not After: %ld", level + 1, "", cert->tobesigned_cert->valid_not_after); /* subject Identifier */ dump_identifier(dbg, level + 1, cert->tobesigned_cert->subject); /* public_key_type */ debug(dbg, 0, "%*sPublic Key Type: %d", level + 1, "", cert->tobesigned_cert->pubkey_type); /* parameter specifier */ dump_param_spec(dbg, level + 1, cert->tobesigned_cert->param_spec); /* public key */ dump_public_key(dbg, level + 1, cert->tobesigned_cert->pubkey, cert->tobesigned_cert->pubkey_type); /* === pack Signature === */ dump_signature(dbg, level + 1, cert->signature); } #endif /* HAVE_WTLS_OPENSSL */ gateway-1.4.5/wap/wsp_strings.def0000644000175000017500000007771613227613126015542 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /**** Preprocessor magic ****/ /* String table with entries starting at 0 and numbered upwards. */ #if !defined(LINEAR) #error "Required macro LINEAR is missing." #endif /* Entry in a LINEAR table. Default is to do nothing for it. */ #if !defined(STRING) #define STRING #endif /* String table where entries have assigned numbers. Multiple * entries can have the same number (the first listed entry is used * when looking up by number). */ #if !defined(NUMBERED) #define NUMBERED LINEAR #endif /* Entry in a NUMBERED table */ #if !defined(ASSIGN) #define ASSIGN(string, number) STRING(string) #endif /* Entry in a versioned NUMBERED table */ #if !defined(VASSIGN) #define VASSIGN(version, string, number) VSTRING(version, string) #endif /* Just like LINEAR, but an enumerated type name##_enum is defined for * the entries. */ #if !defined(NAMED) #define NAMED LINEAR #endif /* Entry in a NAMED table */ #if !defined(NSTRING) #define NSTRING(string, name) STRING(string) #endif /* Entry in a versioned NAMED table */ #if !defined(VNSTRING) #define VNSTRING(version, string, name) VSTRING(version, string) #endif /**** End of preprocessor magic. Tables start here. ****/ /* * Wireless Session Protocol (WSP) 1.0 values. * * Document: OMA-WAP-TS-WSP-V1_0-20020920-C * URL: http://technical.openmobilealliance.org/technical/release_program/docs/Browser_Protocol_Stack/V2_1-20050204/OMA-WAP-TS-WSP-V1_0-20020920-C.pdf */ /* Table 39. Header Field Name Assignments. Note that headers Accept-Charset, Accept-Encoding, * Cache-Control and Content-Range are defined twice. First ones should be used only for * compatibility reasons. */ NAMED(header, VNSTRING(WSP_1_1, "Accept", WSP_HEADER_ACCEPT) VNSTRING(WSP_1_1, "Accept-Charset", WSP_HEADER_ACCEPT_CHARSET) VNSTRING(WSP_1_1, "Accept-Encoding", WSP_HEADER_ACCEPT_ENCODING) VNSTRING(WSP_1_1, "Accept-Language", WSP_HEADER_ACCEPT_LANGUAGE) VNSTRING(WSP_1_1, "Accept-Ranges", WSP_HEADER_ACCEPT_RANGES) VNSTRING(WSP_1_1, "Age", WSP_HEADER_AGE) VNSTRING(WSP_1_1, "Allow", WSP_HEADER_ALLOW) VNSTRING(WSP_1_1, "Authorization", WSP_HEADER_AUTHORIZATION) VNSTRING(WSP_1_1, "Cache-Control", WSP_HEADER_CACHE_CONTROL) VNSTRING(WSP_1_1, "Connection", WSP_HEADER_CONNECTION) VNSTRING(WSP_1_1, "Content-Base", WSP_HEADER_CONTENT_BASE) VNSTRING(WSP_1_1, "Content-Encoding", WSP_HEADER_CONTENT_ENCODING) VNSTRING(WSP_1_1, "Content-Language", WSP_HEADER_CONTENT_LANGUAGE) VNSTRING(WSP_1_1, "Content-Length", WSP_HEADER_CONTENT_LENGTH) VNSTRING(WSP_1_1, "Content-Location", WSP_HEADER_CONTENT_LOCATION) VNSTRING(WSP_1_1, "Content-MD5", WSP_HEADER_CONTENT_MD5) VNSTRING(WSP_1_1, "Content-Range", WSP_HEADER_CONTENT_RANGE) VNSTRING(WSP_1_1, "Content-Type", WSP_HEADER_CONTENT_TYPE) VNSTRING(WSP_1_1, "Date", WSP_HEADER_DATE) VNSTRING(WSP_1_1, "Etag", WSP_HEADER_ETAG) VNSTRING(WSP_1_1, "Expires", WSP_HEADER_EXPIRES) VNSTRING(WSP_1_1, "From", WSP_HEADER_FROM) VNSTRING(WSP_1_1, "Host", WSP_HEADER_HOST) VNSTRING(WSP_1_1, "If-Modified-Since", WSP_HEADER_IF_MODIFIED_SINCE) VNSTRING(WSP_1_1, "If-Match", WSP_HEADER_IF_MATCH) VNSTRING(WSP_1_1, "If-None-Match", WSP_HEADER_IF_NONE_MATCH) VNSTRING(WSP_1_1, "If-Range", WSP_HEADER_IF_RANGE) VNSTRING(WSP_1_1, "If-Unmodified-Since", WSP_HEADER_IF_UNMODIFIED_SINCE) VNSTRING(WSP_1_1, "Location", WSP_HEADER_LOCATION) VNSTRING(WSP_1_1, "Last-Modified", WSP_HEADER_LAST_MODIFIED) VNSTRING(WSP_1_1, "Max-Forwards", WSP_HEADER_MAX_FORWARDS) VNSTRING(WSP_1_1, "Pragma", WSP_HEADER_PRAGMA) VNSTRING(WSP_1_1, "Proxy-Authenticate", WSP_HEADER_PROXY_AUTHENTICATE) VNSTRING(WSP_1_1, "Proxy-Authorization", WSP_HEADER_PROXY_AUTHORIZATION) VNSTRING(WSP_1_1, "Public", WSP_HEADER_PUBLIC) VNSTRING(WSP_1_1, "Range", WSP_HEADER_RANGE) VNSTRING(WSP_1_1, "Referer", WSP_HEADER_REFERER) VNSTRING(WSP_1_1, "Retry-After", WSP_HEADER_RETRY_AFTER) VNSTRING(WSP_1_1, "Server", WSP_HEADER_SERVER) VNSTRING(WSP_1_1, "Transfer-Encoding", WSP_HEADER_TRANSFER_ENCODING) VNSTRING(WSP_1_1, "Upgrade", WSP_HEADER_UPGRADE) VNSTRING(WSP_1_1, "User-Agent", WSP_HEADER_USER_AGENT) VNSTRING(WSP_1_1, "Vary", WSP_HEADER_VARY) VNSTRING(WSP_1_1, "Via", WSP_HEADER_VIA) VNSTRING(WSP_1_1, "Warning", WSP_HEADER_WARNING) VNSTRING(WSP_1_1, "WWW-Authenticate", WSP_HEADER_WWW_AUTHENTICATE) VNSTRING(WSP_1_1, "Content-Disposition", WSP_HEADER_CONTENT_DISPOSITION) VNSTRING(WSP_1_2, "X-Wap-Application-Id", WSP_HEADER_X_WAP_APPLICATION_ID) VNSTRING(WSP_1_2, "X-Wap-Content-URI", WSP_HEADER_X_WAP_CONTENT_URI) VNSTRING(WSP_1_2, "X-Wap-Initiator-URI", WSP_HEADER_X_WAP_INITIATOR_URI) VNSTRING(WSP_1_2, "Accept-Application", WSP_HEADER_ACCEPT_APPLICATION) VNSTRING(WSP_1_2, "Bearer-Indication", WSP_HEADER_BEARER_INDICATION) VNSTRING(WSP_1_2, "Push-Flag", WSP_HEADER_PUSH_FLAG) VNSTRING(WSP_1_2, "Profile", WSP_HEADER_PROFILE) VNSTRING(WSP_1_2, "Profile-Diff", WSP_HEADER_PROFILE_DIFF) VNSTRING(WSP_1_2, "Profile-Warning", WSP_HEADER_PROFILE_WARNING) VNSTRING(WSP_1_3, "Expect", WSP_HEADER_EXPECT) VNSTRING(WSP_1_3, "TE", WSP_HEADER_TE) VNSTRING(WSP_1_3, "Trailer", WSP_HEADER_TRAILER) VNSTRING(WSP_1_3, "Accept-Charset", WSP_HEADER_ACCEPT_CHARSET_V13) VNSTRING(WSP_1_3, "Accept-Encoding", WSP_HEADER_ACCEPT_ENCODING_V13) VNSTRING(WSP_1_3, "Cache-Control", WSP_HEADER_CACHE_CONTROL_V13) VNSTRING(WSP_1_3, "Content-Range", WSP_HEADER_CONTENT_RANGE_V13) VNSTRING(WSP_1_3, "X-WAP-Tod", WSP_HEADER_X_WAP_TOD) VNSTRING(WSP_1_3, "Content-ID", WSP_HEADER_CONTENT_ID) VNSTRING(WSP_1_3, "Set-Cookie", WSP_HEADER_SET_COOKIE) VNSTRING(WSP_1_3, "Cookie", WSP_HEADER_COOKIE) VNSTRING(WSP_1_3, "Encoding-Version", WSP_HEADER_ENCODING_VERSION) VNSTRING(WSP_1_4, "Profile-Warning", WSP_HEADER_PROFILE_WARNING_V14) VNSTRING(WSP_1_4, "Content-Disposition", WSP_HEADER_CONTENT_DISPOSITION_V14) VNSTRING(WSP_1_4, "X-WAP-Security", WSP_HEADER_X_WAP_SECURITY) VNSTRING(WSP_1_4, "Cache-Control", WSP_HEADER_CACHE_CONTROL_V14) VNSTRING(WSP_1_5, "X-Wap-Loc-Invocation", WSP_HEADER_X_WAP_LOC_INVOCATION) VNSTRING(WSP_1_5, "X-Wap-Loc-Delivery", WSP_HEADER_X_WAP_LOC_DELIVERY) ) /* Table 40. Well Known WSP Content Type Codes Assignments. * These have been defined by WINA, * see http://www.wapforum.org/wina/wsp-content-type.htm * Now they are maintained by OMNA, see URL * * http://www.openmobilealliance.org/tech/omna/index.htm (depricated) * http://technical.openmobilealliance.org/tech/omna/omna-wsp-content-type.aspx * * NOTE: The assigned numbers in the above URL start with 0x00, where * the binary token values in the WBXML content start with 0x80. */ LINEAR(content_type, VSTRING(WSP_1_1, "*/*") /* 0x80 */ VSTRING(WSP_1_1, "text/*") /* 0x81 */ VSTRING(WSP_1_1, "text/html") /* 0x82 */ VSTRING(WSP_1_1, "text/plain") /* 0x83 */ VSTRING(WSP_1_1, "text/x-hdml") /* 0x84 */ VSTRING(WSP_1_1, "text/x-ttml") /* 0x85 */ VSTRING(WSP_1_1, "text/x-vCalendar") /* 0x86 */ VSTRING(WSP_1_1, "text/x-vCard") /* 0x87 */ VSTRING(WSP_1_1, "text/vnd.wap.wml") /* 0x88 */ VSTRING(WSP_1_1, "text/vnd.wap.wmlscript") /* 0x89 */ VSTRING(WSP_1_1, "application/vnd.wap.catc") /* 0x8A */ VSTRING(WSP_1_1, "multipart/*") /* 0x8B */ VSTRING(WSP_1_1, "multipart/mixed") /* 0x8C */ VSTRING(WSP_1_1, "multipart/form-data") /* 0x8D */ VSTRING(WSP_1_1, "multipart/byteranges") /* 0x8E */ VSTRING(WSP_1_1, "multipart/alternative") /* 0x8F */ VSTRING(WSP_1_1, "application/*") /* 0x90 */ VSTRING(WSP_1_1, "application/java-vm") /* 0x91 */ VSTRING(WSP_1_1, "application/x-www-form-urlencoded") /* 0x92 */ VSTRING(WSP_1_1, "application/x-hdmlc") /* 0x93 */ VSTRING(WSP_1_1, "application/vnd.wap.wmlc") /* 0x94 */ VSTRING(WSP_1_1, "application/vnd.wap.wmlscriptc") /* 0x95 */ VSTRING(WSP_1_1, "application/vnd.wap.wsic") /* 0x96 */ VSTRING(WSP_1_1, "application/vnd.wap.uaprof") /* 0x97 */ VSTRING(WSP_1_1, "application/vnd.wap.wtls-ca-certificate") /* 0x98 */ VSTRING(WSP_1_1, "application/vnd.wap.wtls-user-certificate") /* 0x99 */ VSTRING(WSP_1_1, "application/x-x509-ca-cert") /* 0x9A */ VSTRING(WSP_1_1, "application/x-x509-user-cert") /* 0x9B */ VSTRING(WSP_1_1, "image/*") /* 0x9C */ VSTRING(WSP_1_1, "image/gif") /* 0x9D */ VSTRING(WSP_1_1, "image/jpeg") /* 0x9E */ VSTRING(WSP_1_1, "image/tiff") /* 0x9F */ VSTRING(WSP_1_1, "image/png") /* 0xA0 */ VSTRING(WSP_1_1, "image/vnd.wap.wbmp") /* 0xA1 */ VSTRING(WSP_1_1, "application/vnd.wap.multipart.*") /* 0xA2 */ VSTRING(WSP_1_1, "application/vnd.wap.multipart.mixed") /* 0xA3 */ VSTRING(WSP_1_1, "application/vnd.wap.multipart.form-data") /* 0xA4 */ VSTRING(WSP_1_1, "application/vnd.wap.multipart.byteranges") /* 0xA5 */ VSTRING(WSP_1_1, "application/vnd.wap.multipart.alternative") /* 0xA6 */ VSTRING(WSP_1_1, "application/xml") /* 0xA7 */ VSTRING(WSP_1_1, "text/xml") /* 0xA8 */ VSTRING(WSP_1_1, "application/vnd.wap.wbxml") /* 0xA9 */ VSTRING(WSP_1_1, "application/x-x968-cross-cert") /* 0xAA */ VSTRING(WSP_1_1, "application/x-x968-ca-cert") /* 0xAB */ VSTRING(WSP_1_1, "application/x-x968-user-cert") /* 0xAC */ VSTRING(WSP_1_1, "text/vnd.wap.si") /* 0xAD */ VSTRING(WSP_1_2, "application/vnd.wap.sic") /* 0xAE */ VSTRING(WSP_1_2, "text/vnd.wap.sl") /* 0xAF */ VSTRING(WSP_1_2, "application/vnd.wap.slc") /* 0xB0 */ VSTRING(WSP_1_2, "text/vnd.wap.co") /* 0xB1 */ VSTRING(WSP_1_2, "application/vnd.wap.coc") /* 0xB2 */ VSTRING(WSP_1_2, "application/vnd.wap.multipart.related") /* 0xB3 */ VSTRING(WSP_1_2, "application/vnd.wap.sia") /* 0xB4 */ VSTRING(WSP_1_3, "text/vnd.wap.connectivity-xml") /* 0xB5 */ VSTRING(WSP_1_3, "application/vnd.wap.connectivity-wbxml") /* 0xB6 */ VSTRING(WSP_1_4, "application/pkcs7-mime") /* 0xB7 */ VSTRING(WSP_1_4, "application/vnd.wap.hashed-certificate") /* 0xB8 */ VSTRING(WSP_1_4, "application/vnd.wap.signed-certificate") /* 0xB9 */ VSTRING(WSP_1_4, "application/vnd.wap.cert-response") /* 0xBA */ VSTRING(WSP_1_4, "application/xhtml+xml") /* 0xBB */ VSTRING(WSP_1_4, "application/wml+xml") /* 0xBC */ VSTRING(WSP_1_4, "text/css") /* 0xBD */ VSTRING(WSP_1_4, "application/vnd.wap.mms-message") /* 0xBE */ VSTRING(WSP_1_4, "application/vnd.wap.rollover-certificate") /* 0xBF */ VSTRING(WSP_1_5, "application/vnd.wap.locc+wbxml") /* 0xC0 */ VSTRING(WSP_1_5, "application/vnd.wap.loc+xml") /* 0xC1 */ VSTRING(WSP_1_5, "application/vnd.syncml.dm+wbxml") /* 0xC2 */ VSTRING(WSP_1_5, "application/vnd.syncml.dm+xml") /* 0xC3 */ VSTRING(WSP_1_5, "application/vnd.syncml.notification") /* 0xC4 */ VSTRING(WSP_1_5, "application/vnd.wap.xhtml+xml") /* 0xC5 */ VSTRING(WSP_1_5, "application/vnd.wv.csp.cir") /* 0xC6 */ VSTRING(WSP_1_5, "application/vnd.oma.dd+xml") /* 0xC7 */ VSTRING(WSP_1_5, "application/vnd.oma.drm.message") /* 0xC8 */ VSTRING(WSP_1_5, "application/vnd.oma.drm.content") /* 0xC9 */ VSTRING(WSP_1_5, "application/vnd.oma.drm.rights+xml") /* 0xCA */ VSTRING(WSP_1_5, "application/vnd.oma.drm.rights+wbxml") /* 0xCB */ VSTRING(WSP_1_5, "application/vnd.wv.csp+xml") /* 0xCC */ VSTRING(WSP_1_5, "application/vnd.wv.csp+wbxml") /* 0xCD */ VSTRING(WSP_1_5, "application/vnd.syncml.ds.notification") /* 0xCE */ VSTRING(WSP_1_6, "audio/*") /* 0xCF */ VSTRING(WSP_1_6, "video/*") /* 0xD0 */ VSTRING(WSP_TBD, "application/vnd.oma.dd2+xml") /* 0xD1 */ VSTRING(WSP_TBD, "application/mikey") /* 0xD2 */ VSTRING(WSP_TBD, "application/vnd.oma.dcd") /* 0xD3 */ VSTRING(WSP_TBD, "application/vnd.oma.dcdc") /* 0xD4 */ VSTRING(WSP_TBD, "text/x-vMessage") /* 0xD5 */ VSTRING(WSP_TBD, "application/vnd.omads-email+wbxml") /* 0xD6 */ VSTRING(WSP_TBD, "text/x-vBookmark") /* 0xD7 */ VSTRING(WSP_TBD, "application/vnd.syncml.dm.notification") /* 0xD8 */ VSTRING(WSP_TBD, "") /* 0xD9 */ VSTRING(WSP_TBD, "application/octet-stream") /* 0xDA */ ) /* Registered WSP Content Type Codes Assignments. * Now they are maintained by OMNA, see URL * * http://www.openmobilealliance.org/tech/omna/index.htm (depricated) * http://technical.openmobilealliance.org/tech/omna/omna-wsp-content-type.aspx */ NUMBERED(content_type_registered, ASSIGN("application/vnd.uplanet.cacheop-wbxml", 0x0201) ASSIGN("application/vnd.uplanet.signal", 0x0202) ASSIGN("application/vnd.uplanet.alert-wbxml", 0x0203) ASSIGN("application/vnd.uplanet.list-wbxml", 0x0204) ASSIGN("application/vnd.uplanet.listcmd-wbxml", 0x0205) ASSIGN("application/vnd.uplanet.channel-wbxml", 0x0206) ASSIGN("application/vnd.uplanet.provisioning-status-uri", 0x0207) ASSIGN("x-wap.multipart/vnd.uplanet.header-set", 0x0208) ASSIGN("application/vnd.uplanet.bearer-choice-wbxml", 0x0209) ASSIGN("application/vnd.phonecom.mmc-wbxml", 0x020A) ASSIGN("application/vnd.nokia.syncset+wbxml", 0x020B) ASSIGN("image/x-up-wpng", 0x020C) ASSIGN("application/iota.mmc-wbxml", 0x0300) ASSIGN("application/iota.mmc-xml", 0x0301) ASSIGN("application/vnd.syncml+xml", 0x0302) ASSIGN("application/vnd.syncml+wbxml", 0x0303) ASSIGN("text/vnd.wap.emn+xml", 0x0304) ASSIGN("text/calendar", 0x0305) ASSIGN("application/vnd.omads-email+xml", 0x0306) ASSIGN("application/vnd.omads-file+xml", 0x0307) ASSIGN("application/vnd.omads-folder+xml", 0x0308) ASSIGN("text/directory;profile=vCard", 0x0309) ASSIGN("application/vnd.wap.emn+wbxml", 0x030A) ASSIGN("application/vnd.nokia.ipdc-purchase-response", 0x030B) ASSIGN("application/vnd.motorola.screen3+xml", 0x030C) ASSIGN("application/vnd.motorola.screen3+gzip", 0x030D) ASSIGN("application/vnd.cmcc.setting+wbxml", 0x030E) ASSIGN("application/vnd.cmcc.bombing+wbxml", 0x030F) ASSIGN("application/vnd.docomo.pf", 0x0310) ASSIGN("application/vnd.docomo.ub", 0x0311) ASSIGN("application/vnd.omaloc-supl-init", 0x0312) ASSIGN("application/vnd.oma.group-usage-list+xml", 0x0313) ASSIGN("application/oma-directory+xml", 0x0314) ASSIGN("application/vnd.docomo.pf2", 0x0315) ASSIGN("application/vnd.oma.drm.roap-trigger+wbxml", 0x0316) ASSIGN("application/vnd.sbm.mid2", 0x0317) ASSIGN("application/vnd.wmf.bootstrap", 0x0318) ASSIGN("application/vnc.cmcc.dcd+xml", 0x0319) ASSIGN("application/vnd.sbm.cid", 0x031A) ASSIGN("application/vnd.oma.bcast.provisioningtrigger", 0x031B) ASSIGN("application/vnd.docomo.dm", 0x031C) ASSIGN("application/vnd.oma.scidm.messages+xml", 0x031D) ASSIGN("application/vnd.innopath.wamp.notification", 0x031E) ) /* Table 42, Character Set Assignment (partial) */ /* The full list is at * ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets * but the WSP standard lists these values explicitly. */ NUMBERED(charset, ASSIGN("big5", 2026) /* 0x07EA */ ASSIGN("iso-10646-ucs-2", 1000) /* 0x03E8 */ ASSIGN("iso-8859-1", 4) /* 0x04 */ ASSIGN("iso-8859-2", 5) /* 0x05 */ ASSIGN("iso-8859-3", 6) /* 0x06 */ ASSIGN("iso-8859-4", 7) /* 0x07 */ ASSIGN("iso-8859-5", 8) /* 0x08 */ ASSIGN("iso-8859-6", 9) /* 0x09 */ ASSIGN("iso-8859-7", 10) /* 0x0A */ ASSIGN("iso-8859-8", 11) /* 0x0B */ ASSIGN("iso-8859-9", 12) /* 0x0C */ ASSIGN("shift_JIS", 17) /* 0x11 */ ASSIGN("us-ascii", 3) /* 0x03 */ ASSIGN("utf-8", 106) /* 0x6A */ ASSIGN("utf-16", 1015) /* 0x03F7 */ ) /* Table 38, Well-Known Parameter Assignments * Now defined by OMNA, see * http://www.openmobilealliance.org/tech/omna/omna-wsp-header-param.htm (depricated) * http://technical.openmobilealliance.org/tech/omna/omna-wsp-header-param.aspx */ NUMBERED(parameter, VASSIGN(WSP_1_1, "q", 0x00) VASSIGN(WSP_1_1, "charset", 0x01) VASSIGN(WSP_1_1, "level", 0x02) VASSIGN(WSP_1_1, "type", 0x03) VASSIGN(WSP_1_1, "uaprof", 0x04) VASSIGN(WSP_1_1, "name", 0x05) VASSIGN(WSP_1_1, "filename", 0x06) VASSIGN(WSP_1_1, "differences", 0x07) VASSIGN(WSP_1_1, "padding", 0x08) VASSIGN(WSP_1_2, "type", 0x09) VASSIGN(WSP_1_2, "start", 0x0A) VASSIGN(WSP_1_2, "start-info", 0x0B) VASSIGN(WSP_1_3, "comment", 0x0C) VASSIGN(WSP_1_3, "domain", 0x0D) VASSIGN(WSP_1_3, "max-age", 0x0E) VASSIGN(WSP_1_3, "path", 0x0F) VASSIGN(WSP_1_3, "secure", 0x10) VASSIGN(WSP_1_4, "sec", 0x11) VASSIGN(WSP_1_4, "mac", 0x12) VASSIGN(WSP_1_4, "creation-date", 0x13) VASSIGN(WSP_1_4, "modification-date", 0x14) VASSIGN(WSP_1_4, "read-date", 0x15) VASSIGN(WSP_1_4, "size", 0x16) VASSIGN(WSP_1_4, "name", 0x17) VASSIGN(WSP_1_4, "filename", 0x18) VASSIGN(WSP_1_4, "start", 0x19) VASSIGN(WSP_1_4, "start-info", 0x1A) VASSIGN(WSP_1_4, "comment", 0x1B) VASSIGN(WSP_1_4, "domain", 0x1C) VASSIGN(WSP_1_4, "path", 0x1D) ) /* 8.4.2.18, Content encoding field */ LINEAR(encoding, STRING("gzip") STRING("compress") STRING("deflate") ) /* 8.4.2.11, Accept ranges field */ LINEAR(ranges, STRING("none") STRING("bytes") ) /* 8.4.2.15, Cache-control field */ NAMED(cache_control, NSTRING("no-cache", WSP_CACHE_CONTROL_NO_CACHE) NSTRING("no-store", WSP_CACHE_CONTROL_NO_STORE) NSTRING("max-age", WSP_CACHE_CONTROL_MAX_AGE) NSTRING("max-stale", WSP_CACHE_CONTROL_MAX_STALE) NSTRING("min-fresh", WSP_CACHE_CONTROL_MIN_FRESH) NSTRING("only-if-cached", WSP_CACHE_CONTROL_ONLY_IF_CACHED) NSTRING("public", WSP_CACHE_CONTROL_PUBLIC) NSTRING("private", WSP_CACHE_CONTROL_PRIVATE) NSTRING("no-transform", WSP_CACHE_CONTROL_NO_TRANSFORM) NSTRING("must-revalidate", WSP_CACHE_CONTROL_MUST_REVALIDATE) NSTRING("proxy-revalidate", WSP_CACHE_CONTROL_PROXY_REVALIDATE) NSTRING("s-maxage", WSP_CACHE_CONTROL_S_MAXAGE) ) /* 8.4.2.53, Content-disposition field */ LINEAR(disposition, STRING("form-data") STRING("attachment") STRING("inline") ) /* Table 41, ISO 639 Language Assignments */ /* For some reason this table was incomplete in the spec. The languages * were listed, but not their abbreviations. */ NUMBERED(language, ASSIGN("*", 0) /* Special any-language value */ ASSIGN("aa", 0x01) /* Afar */ ASSIGN("ab", 0x02) /* Abkhazian */ ASSIGN("af", 0x03) /* Afrikaans */ ASSIGN("am", 0x04) /* Amharic */ ASSIGN("ar", 0x05) /* Arabic */ ASSIGN("as", 0x06) /* Assamese */ ASSIGN("ay", 0x07) /* Aymara */ ASSIGN("az", 0x08) /* Azerbaijani */ ASSIGN("ba", 0x09) /* Bashkir */ ASSIGN("be", 0x0a) /* Byelorussian */ ASSIGN("bg", 0x0b) /* Bulgarian */ ASSIGN("bh", 0x0c) /* Bihari */ ASSIGN("bi", 0x0d) /* Bislama */ ASSIGN("bn", 0x0e) /* Bengali; Bangla */ ASSIGN("bo", 0x0f) /* Tibetan */ ASSIGN("br", 0x10) /* Breton */ ASSIGN("ca", 0x11) /* Catalan */ ASSIGN("co", 0x12) /* Corsican */ ASSIGN("cs", 0x13) /* Czech */ ASSIGN("cy", 0x14) /* Welsh */ ASSIGN("da", 0x15) /* Danish */ ASSIGN("de", 0x16) /* German */ ASSIGN("dz", 0x17) /* Bhutani */ ASSIGN("el", 0x18) /* Greek */ ASSIGN("en", 0x19) /* English */ ASSIGN("eo", 0x1a) /* Esperanto */ ASSIGN("es", 0x1b) /* Spanish */ ASSIGN("et", 0x1c) /* Estonian */ ASSIGN("eu", 0x1d) /* Basque */ ASSIGN("fa", 0x1e) /* Persian */ ASSIGN("fi", 0x1f) /* Finnish */ ASSIGN("fj", 0x20) /* Fiji */ ASSIGN("fo", 0x82) /* Faroese */ ASSIGN("fr", 0x22) /* French */ ASSIGN("fy", 0x83) /* Frisian */ ASSIGN("ga", 0x24) /* Irish */ ASSIGN("gd", 0x25) /* Scots Gaelic */ ASSIGN("gl", 0x26) /* Galician */ ASSIGN("gn", 0x27) /* Guarani */ ASSIGN("gu", 0x28) /* Gujarati */ ASSIGN("ha", 0x29) /* Hausa */ ASSIGN("he", 0x2a) /* Hebrew (formerly iw) */ ASSIGN("hi", 0x2b) /* Hindi */ ASSIGN("hr", 0x2c) /* Croatian */ ASSIGN("hu", 0x2d) /* Hungarian */ ASSIGN("hy", 0x2e) /* Armenian */ ASSIGN("ia", 0x84) /* Interlingua */ ASSIGN("id", 0x30) /* Indonesian (formerly in) */ ASSIGN("ie", 0x86) /* Interlingue */ ASSIGN("ik", 0x87) /* Inupiak */ ASSIGN("is", 0x33) /* Icelandic */ ASSIGN("it", 0x34) /* Italian */ ASSIGN("iu", 0x89) /* Inuktitut */ ASSIGN("ja", 0x36) /* Japanese */ ASSIGN("jw", 0x37) /* Javanese */ ASSIGN("ka", 0x38) /* Georgian */ ASSIGN("kk", 0x39) /* Kazakh */ ASSIGN("kl", 0x8a) /* Greenlandic */ ASSIGN("km", 0x3b) /* Cambodian */ ASSIGN("kn", 0x3c) /* Kannada */ ASSIGN("ko", 0x3d) /* Korean */ ASSIGN("ks", 0x3e) /* Kashmiri */ ASSIGN("ku", 0x3f) /* Kurdish */ ASSIGN("ky", 0x40) /* Kirghiz */ ASSIGN("la", 0x8b) /* Latin */ ASSIGN("ln", 0x42) /* Lingala */ ASSIGN("lo", 0x43) /* Laothian */ ASSIGN("lt", 0x44) /* Lithuanian */ ASSIGN("lv", 0x45) /* Latvian, Lettish */ ASSIGN("mg", 0x46) /* Malagasy */ ASSIGN("mi", 0x47) /* Maori */ ASSIGN("mk", 0x48) /* Macedonian */ ASSIGN("ml", 0x49) /* Malayalam */ ASSIGN("mn", 0x4a) /* Mongolian */ ASSIGN("mo", 0x4b) /* Moldavian */ ASSIGN("mr", 0x4c) /* Marathi */ ASSIGN("ms", 0x4d) /* Malay */ ASSIGN("mt", 0x4e) /* Maltese */ ASSIGN("my", 0x4f) /* Burmese */ ASSIGN("na", 0x81) /* Nauru */ ASSIGN("ne", 0x51) /* Nepali */ ASSIGN("nl", 0x52) /* Dutch */ ASSIGN("no", 0x53) /* Norwegian */ ASSIGN("oc", 0x54) /* Occitan */ ASSIGN("om", 0x55) /* (Afan) Oromo */ ASSIGN("or", 0x56) /* Oriya */ ASSIGN("pa", 0x57) /* Punjabi */ ASSIGN("pl", 0x58) /* Polish */ ASSIGN("ps", 0x59) /* Pashto, Pushto */ ASSIGN("pt", 0x5a) /* Portuguese */ ASSIGN("qu", 0x5b) /* Quechua */ ASSIGN("rm", 0x8c) /* Rhaeto-Romance */ ASSIGN("rn", 0x5d) /* Kirundi */ ASSIGN("ro", 0x5e) /* Romanian */ ASSIGN("ru", 0x5f) /* Russian */ ASSIGN("rw", 0x60) /* Kinyarwanda */ ASSIGN("sa", 0x61) /* Sanskrit */ ASSIGN("sd", 0x62) /* Sindhi */ ASSIGN("sg", 0x63) /* Sangro (Sangho) */ ASSIGN("sh", 0x64) /* Serbo-Croatian */ ASSIGN("si", 0x65) /* Sinhalese */ ASSIGN("sk", 0x66) /* Slovak */ ASSIGN("sl", 0x67) /* Slovenian */ ASSIGN("sm", 0x68) /* Samoan */ ASSIGN("sn", 0x69) /* Shona */ ASSIGN("so", 0x6a) /* Somali */ ASSIGN("sq", 0x6b) /* Albanian */ ASSIGN("sr", 0x6c) /* Serbian */ ASSIGN("ss", 0x6d) /* Siswati */ ASSIGN("st", 0x6e) /* Sesotho */ ASSIGN("su", 0x6f) /* Sundanese */ ASSIGN("sv", 0x70) /* Swedish */ ASSIGN("sw", 0x71) /* Swahili */ ASSIGN("ta", 0x72) /* Tamil */ ASSIGN("te", 0x73) /* Telugu */ ASSIGN("tg", 0x74) /* Tajik */ ASSIGN("th", 0x75) /* Thai */ ASSIGN("ti", 0x76) /* Tigrinya */ ASSIGN("tk", 0x77) /* Turkmen */ ASSIGN("tl", 0x78) /* Tagalog */ ASSIGN("tn", 0x79) /* Setswana */ ASSIGN("to", 0x7a) /* Tonga */ ASSIGN("tr", 0x7b) /* Turkish */ ASSIGN("ts", 0x7c) /* Tsonga */ ASSIGN("tt", 0x7d) /* Tatar */ ASSIGN("tw", 0x7e) /* Twi */ ASSIGN("ug", 0x7f) /* Uighur */ ASSIGN("uk", 0x50) /* Ukrainian */ ASSIGN("ur", 0x21) /* Urdu */ ASSIGN("uz", 0x23) /* Uzbek */ ASSIGN("vi", 0x2f) /* Vietnamese */ ASSIGN("vo", 0x85) /* Volapuk */ ASSIGN("wo", 0x31) /* Wolof */ ASSIGN("xh", 0x32) /* Xhosa */ ASSIGN("yi", 0x88) /* Yiddish (formerly ji) */ ASSIGN("yo", 0x35) /* Yoruba */ ASSIGN("za", 0x3a) /* Zhuang */ ASSIGN("zh", 0x41) /* Chinese */ ASSIGN("zu", 0x5c) /* Zulu */ ) /* Table 34, Well known methods. */ NUMBERED(method, ASSIGN("GET", 0x40) ASSIGN("OPTIONS", 0x41) ASSIGN("HEAD", 0x42) ASSIGN("DELETE", 0x43) ASSIGN("TRACE", 0x44) ASSIGN("POST", 0x60) ASSIGN("PUT", 0x61) ASSIGN("DATA", 0x80) ) /* Connection-value tokens, from section 8.4.2.16 */ LINEAR(connection, STRING("close") ) /* Transfer-encoding values, from section 8.4.2.46 */ LINEAR(transfer_encoding, STRING("chunked") ) /* Well-known bearer type codes, from WDP Appendix C */ LINEAR(bearer_indication, STRING("any_ipv4") STRING("any_ipv6") STRING("gsm_usd_any") STRING("gsm_sms_gsmmsisdn") STRING("ansi-136_guts/r-data_ansi_136_msisdn") STRING("is-95_cdma_sms_is_637_msisdn") STRING("is-95_cdma_csd_ipv4") STRING("is-95_packet_data_ipv4") STRING("ansi-136_csd_ipv4") STRING("ansi-136_packet_data_ipv4") STRING("gsm_csd_ipv4") STRING("gsm_gprs_ipv4") STRING("gsm_ussd_ipv4") STRING("amps_cdpd_ipv4") STRING("pdc_csd_ipv4") STRING("pdc_packet_data_ipv4") STRING("iden_sms_iden_msisdn") STRING("iden_csd_ipv4") STRING("iden_packet_data_ipv4") STRING("paging_network_flex_flex_msisdn") STRING("phs_sms_phs_msisdn") STRING("phs_csd_ipv4") STRING("gsm_ussd_gsm_service_code") STRING("tetra_sds_tetra_itsi") STRING("tetra_sds_tetra_msisdn") STRING("tetra_packet_data_ipv4") STRING("paging_network_reflex_reflex_isdn") STRING("gsm_ussd_gsm_msisdn") STRING("mobitex_mpak_man") STRING("ansi-136_ghost/r_data_gsm_isdn") ) /* * Well known and registered push application ids, see URL * * http://www.openmobilealliance.org/tech/omna/omna-push-app-id.htm (depricated) * http://technical.openmobilealliance.org/tech/omna/omna-push-app-id.aspx * * NOTE: Generic id strings do not contain the "x-wap-application" prefix, * it's the default, otherwise an alternate is given. */ NUMBERED(application_id, ASSIGN("*", 0x00) ASSIGN("push.sia", 0x01) ASSIGN("wml.ua", 0x02) ASSIGN("wta.ua", 0x03) ASSIGN("mms.ua", 0x04) ASSIGN("push.syncml", 0x05) ASSIGN("loc.ua", 0x06) ASSIGN("syncml.dm", 0x07) ASSIGN("drm.ua", 0x08) ASSIGN("emn.ua", 0x09) ASSIGN("wv.ua", 0x0A) ASSIGN("x-oma-application:ulp.ua", 0x10) ASSIGN("x-oma-application:dlota.ua", 0x11) ASSIGN("x-oma-application:java-ams", 0x12) ASSIGN("x-oma-application:bcast.ua", 0x13) ASSIGN("x-oma-application:dpe.ua", 0x14) ASSIGN("x-oma-application:cpm:ua", 0x15) ASSIGN("x-oma-application:evvm.ua", 0x16) /* vendor-specific registered values */ ASSIGN("x-wap-microsoft:localcontent.ua", 0x8000) ASSIGN("x-wap-microsoft:IMclient.ua", 0x8001) ASSIGN("x-wap-docomo:imode.mail.ua", 0x8002) ASSIGN("x-wap-docomo:imode.mr.ua", 0x8003) ASSIGN("x-wap-docomo:imode.mf.ua", 0x8004) ASSIGN("x-motorola:location.ua", 0x8005) ASSIGN("x-motorola:now.ua", 0x8006) ASSIGN("x-motorola:otaprov.ua", 0x8007) ASSIGN("x-motorola:browser.ua", 0x8008) ASSIGN("x-motorola:splash.ua", 0x8009) ASSIGN("x-wap-nai:mvsw.command", 0x800B) ASSIGN("x-wap-openvawe:iota.ua", 0x8010) ASSIGN("x-wap-docomo:imode.mail2.ua", 0x9000) ASSIGN("x-oma-nec:otaprov.ua", 0x9001) ASSIGN("x-oma-nokia:call.ua", 0x9002) ASSIGN("x-oma-coremobility:sqa.ua", 0x9003) ASSIGN("x-oma-docomo:doja.jam.ua", 0x9004) ASSIGN("x-oma-nokia:sip.ua", 0x9010) ASSIGN("x-oma-vodafone:otaprov.ua", 0x9011) ASSIGN("x-hutchison:ad.ua", 0x9012) ASSIGN("x-oma-nokia:voip.ua", 0x9013) ASSIGN("x-oma-docomo:voice.ua", 0x9014) ASSIGN("x-oma-docomo:browser.ctl", 0x9015) ASSIGN("x-oma-docomo:dan.ua", 0x9016) ASSIGN("x-oma-nokia:vs.ua", 0x9017) ASSIGN("x-oma-nokia:voip.ext1.ua", 0x9018) ASSIGN("x-wap-vodafone:casting.ua", 0x9019) ASSIGN("x-oma-docomo:imode.data.ua", 0x901A) ASSIGN("x-oma-snapin:otaprov.ctl", 0x901B) ASSIGN("x-oma-nokia:vrs.ua", 0x901C) ASSIGN("x-oma-nokia:vrpg.ua", 0x901D) ASSIGN("x-oma-motorola:screen3.ua", 0x901E) ASSIGN("x-oma-docomo:device.ctl", 0x901F) ASSIGN("x-oma-nokia:msc.ua", 0x9020) ASSIGN("x-3gpp2:lcs.ua", 0x9021) ASSIGN("x-wap-vodafone:dcd.ua", 0x9022) ASSIGN("x-3gpp:mbms.service.announcement.ua", 0x9023) ASSIGN("x-oma-vodafone:dltmtbl.ua", 0x9024) ASSIGN("x-oma-vodafone:dvcctl.ua", 0x9025) ASSIGN("x-oma-cmcc:mail.ua", 0x9026) ASSIGN("x-oma-nokia:vmb.ua", 0x9027) ASSIGN("x-oma-nokia:ldapss.ua", 0x9028) ASSIGN("x-hutchison:al.ua", 0x9029) ASSIGN("x-oma-nokia:uma.ua", 0x902A) ASSIGN("x-oma-nokia:news.ua", 0x902B) ASSIGN("x-oma-docomo:pf", 0x902C) ASSIGN("x-oma-docomo:ub", 0x902D) ASSIGN("x-oma-nokia:nat.traversal.ua", 0x902E) ASSIGN("x-oma-intromobile:intropad.ua", 0x902F) ASSIGN("x-oma-docomo:uin.ua", 0x9030) ASSIGN("x-oma-nokia:iptv.ua", 0x9031) ASSIGN("x-hutchison:il.ua", 0x9032) ASSIGN("x-oma-nokia:voip.general.ua", 0x9033) ASSIGN("x-microsoft:drm.meter", 0x9034) ASSIGN("x-microsoft:drm.license", 0x9035) ASSIGN("x-oma-docomo:ic.ctl", 0x9036) ASSIGN("x-oma-slingmedia:SPM.ua", 0x9037) ASSIGN("x-cibenix:odp.ua", 0x9038) ASSIGN("x-oma-motorola:voip.ua", 0x9039) ASSIGN("x-oma-motorola:ims", 0x903A) ASSIGN("x-oma-docomo:imode.remote.ctl", 0x903B) ASSIGN("x-oma-docomo:device.ctl.um", 0x903C) ASSIGN("x-microsoft:playready.drm.initiator", 0x903D) ASSIGN("x-microsoft:playready.drm", 0x903E) ASSIGN("x-oma-sbm:ms.mexa.ua", 0x903F) ASSIGN("urn:oma:drms:org-LGE:L650V", 0x9040) ASSIGN("x-oma-docomo:um", 0x9041) ASSIGN("x-oma-docomo:uin.um", 0x9042) ASSIGN("urn:oma:drms:org-LGE:KU450", 0x9043) ASSIGN("x-wap-microsoft:cfgmgr.ua", 0x9044) ASSIGN("x-3gpp:mbms.download.delivery.ua", 0x9045) ASSIGN("x-oma-docomo:star.ctl", 0x9046) ASSIGN("urn:oma:drms:org-LGE:KU380", 0x9047) ASSIGN("x-oma-docomo:pf2", 0x9048) ASSIGN("x-oma-motorola:blogcentral.ua", 0x9049) ASSIGN("x-oma-docomo:imode.agent.ua", 0x904A) ASSIGN("x-wap-application:push.sia", 0x904B) ASSIGN("x-oma-nokia:destination.network.ua", 0x904C) ASSIGN("x-oma-sbm:mid2.ua", 0x904D) ASSIGN("x-carrieriq:avm.ctl", 0x904E) ASSIGN("x-oma-sbm:ms.xml.ua", 0x904F) ASSIGN("urn:dvb:ipdc:notification:2008", 0x9050) ASSIGN("x-oma-docomo:imode.mvch.ua", 0x9051) ASSIGN("x-oma-motorola:webui.ua", 0x9052) ASSIGN("x-oma-sbm:cid.ua", 0x9053) ASSIGN("x-oma-nokia:vcc.v1.ua", 0x9054) ASSIGN("x-oma-docomo:open.ctl", 0x9055) ASSIGN("x-oma-docomo:sp.mail.ua", 0x9056) ASSIGN("x-essoy-application:push.erace", 0x9057) ASSIGN("x-oma-docomo:open.fu", 0x9058) ASSIGN("x-samsung:osp.ua", 0x9059) ASSIGN("x-oma-docomo:imode.mchara.ua", 0x905A) ASSIGN("x-oma-application:scidm.ua", 0x905B) ASSIGN("x-oma-docomo:xmd.mail.ua", 0x905C) ASSIGN("x-oma-application:pal.ua", 0x905D) ASSIGN("x-oma-docomo:imode.relation.ua", 0x905E) ASSIGN("x-oma-docomo:xmd.storage.ua", 0x905F) ASSIGN("x-oma-docomo:xmd.lcsapp.ua", 0x9060) ASSIGN("x-oma-docomo:xmd.info.ua", 0x9061) ASSIGN("x-oma-docomo:xmd.agent.ua", 0x9062) ASSIGN("x-oma-docomo:xmd.sab.ua", 0x9063) ASSIGN("x-oma-docomo:xmd.am.ua", 0x9064) ASSIGN("x-oma-application:push.scws", 0x9065) ASSIGN("x-oma-docomo:xmd.disastermessageapp.ua", 0x9066) ASSIGN("x-innopath:wamp.notification", 0x9067) ASSIGN("x-wap-docomo:interp.ctl", 0x9068) ASSIGN("x-oma-kddi:apps.ua", 0x9069) ASSIGN("x-oma-kddi:push.ua", 0x906A) ASSIGN("x-oma-docomo:xmd.emdm.ua", 0x906B) ASSIGN("x-oma-docomo:xmd.lac.ua", 0x906C) ASSIGN("x-oma-docomo:xmd.osv.ua", 0x906D) ASSIGN("x-oma-docomo:xmd.dcs.ua", 0x906E) ASSIGN("x-oma-docomo:xmd.wipe.ua", 0x906F) ASSIGN("x-oma-docomo:xmd.vdapp.ua", 0x9070) ASSIGN("x-wap-3gpp:gba.andsf", 0x9071) ) /**** More preprocessor magic ****/ #undef LINEAR #undef STRING #undef VSTRING #undef NUMBERED #undef ASSIGN #undef VASSIGN #undef NAMED #undef NSTRING #undef VNSTRING gateway-1.4.5/wap/wsp_server_method_machine.def0000644000175000017500000000615013227613126020363 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_server_method_machine.def - define a WSP method machine * * Lars Wirzenius */ #if !defined(INTEGER) || \ !defined(ADDRTUPLE) || \ !defined(EVENT) || \ !defined(MACHINE) #error "Some required macro is missing." #endif MACHINE( INTEGER(transaction_id) INTEGER(state) ADDRTUPLE(addr_tuple) EVENT(invoke) INTEGER(session_id) ) #undef INTEGER #undef ADDRTUPLE #undef EVENT #undef MACHINE gateway-1.4.5/wap/wsp_pdu.c0000644000175000017500000002403213227613126014304 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wsp_pdu.c - pack and unpack WSP packets * * Generates packing and unpacking code from wsp_pdu.def. * Code is very similar to wsp_pdu.c, please make any changes in both files. * * Richard Braakman */ #include "gwlib/gwlib.h" #include "wsp_pdu.h" WSP_PDU *wsp_pdu_create(int type) { WSP_PDU *pdu; pdu = gw_malloc(sizeof(*pdu)); pdu->type = type; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: {\ struct name *p; p = &pdu->u.name; \ fields \ } break; #define UINT(field, docstring, bits) p->field = 0; #define UINTVAR(field, docstring) p->field = 0; #define OCTSTR(field, docstring, lengthfield) p->field = NULL; #define REST(field, docstring) p->field = NULL; #define TYPE(bits, value) #define RESERVED(bits) #include "wsp_pdu.def" #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: panic(0, "Internal error: Unknown PDU type %d", pdu->type); break; } return pdu; } void wsp_pdu_destroy(WSP_PDU *pdu) { if (pdu == NULL) return; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: {\ struct name *p; p = &pdu->u.name; \ fields \ } break; #define UINT(field, docstring, bits) #define UINTVAR(field, docstring) #define OCTSTR(field, docstring, lengthfield) octstr_destroy(p->field); #define REST(field, docstring) octstr_destroy(p->field); #define TYPE(bits, value) #define RESERVED(bits) #include "wsp_pdu.def" #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: panic(0, "Cannot destroy unknown WSP PDU type %d", pdu->type); break; } gw_free(pdu); } /* Determine which type of PDU this is, using the TYPE macros in * the definition file. */ static int wsp_pdu_type(Octstr *data) { long bitpos; long lastpos = -1; long lastnumbits = -1; long lastval = -1; int thistype; /* This code looks slow, but an optimizing compiler will * reduce it considerably. gcc -O2 will produce a single * call to octstr_get_bits, folllowed by a sequence of * tests on lastval. */ /* Only UINT and RESERVED fields may precede the TYPE */ #define PDU(name, docstring, fields, is_valid) \ bitpos = 0; \ thistype = name; \ fields #define UINT(field, docstring, bits) bitpos += (bits); #define UINTVAR(field, docstring) #define OCTSTR(field, docstring, lengthfield) #define REST(field, docstring) #define TYPE(bits, value) \ if ((bits) != lastnumbits || bitpos != lastpos) { \ lastval = octstr_get_bits(data, bitpos, (bits)); \ } \ if (lastval == (value)) \ return thistype; \ lastnumbits = (bits); \ lastpos = bitpos; #define RESERVED(bits) bitpos += (bits); #include "wsp_pdu.def" #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU return -1; } WSP_PDU *wsp_pdu_unpack(Octstr *data) { WSP_PDU *pdu = NULL; long bitpos = 0; gw_assert(data != NULL); pdu = gw_malloc(sizeof(*pdu)); pdu->type = wsp_pdu_type(data); switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: { \ struct name *p = &pdu->u.name; \ fields \ gw_assert(bitpos % 8 == 0); \ if (bitpos / 8 != octstr_len(data)) { \ warning(0, "Bad length for " #name " PDU, " \ "expected %ld", bitpos / 8); \ } \ if (!(is_valid)) { \ warning(0, #name " PDU failed %s", #is_valid); \ } \ } break; #define UINT(field, docstring, bits) \ p->field = octstr_get_bits(data, bitpos, (bits)); \ bitpos += (bits); #define UINTVAR(field, docstring) \ gw_assert(bitpos % 8 == 0); \ p->field = octstr_get_bits(data, bitpos + 1, 7); \ while (octstr_get_bits(data, bitpos, 1)) { \ bitpos += 8; \ p->field <<= 7; \ p->field |= octstr_get_bits(data, bitpos + 1, 7); \ } \ bitpos += 8; #define OCTSTR(field, docstring, lengthfield) \ gw_assert(bitpos % 8 == 0); \ p->field = octstr_copy(data, bitpos / 8, p->lengthfield); \ bitpos += 8 * p->lengthfield; #define REST(field, docstring) \ gw_assert(bitpos % 8 == 0); \ if (bitpos / 8 <= octstr_len(data)) { \ p->field = octstr_copy(data, bitpos / 8, \ octstr_len(data) - bitpos / 8); \ bitpos = octstr_len(data) * 8; \ } else { \ p->field = octstr_create(""); \ } #define TYPE(bits, value) bitpos += (bits); #define RESERVED(bits) bitpos += (bits); #include "wsp_pdu.def" #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: warning(0, "WSP PDU with unknown type %d", pdu->type); gw_free(pdu); return NULL; } return pdu; } static void fixup_length_fields(WSP_PDU *pdu) { switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: { \ struct name *p; p = &pdu->u.name; \ fields \ } break; #define UINT(field, docstring, bits) #define UINTVAR(field, docstring) #define OCTSTR(field, docstring, lengthfield) \ p->lengthfield = octstr_len(p->field); #define REST(field, docstring) #define TYPE(bits, value) #define RESERVED(bits) #include "wsp_pdu.def" #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU } } Octstr *wsp_pdu_pack(WSP_PDU *pdu) { Octstr *data; long bitpos; /* We rely on octstr_set_bits to lengthen our octstr as needed. */ data = octstr_create(""); fixup_length_fields(pdu); bitpos = 0; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: { \ struct name *p = &pdu->u.name; \ fields \ gw_assert(bitpos % 8 == 0); \ } break; #define UINT(field, docstring, bits) \ octstr_set_bits(data, bitpos, (bits), p->field); \ bitpos += (bits); #define UINTVAR(field, docstring) \ gw_assert(bitpos % 8 == 0); \ octstr_append_uintvar(data, p->field); \ bitpos = 8 * octstr_len(data); #define OCTSTR(field, docstring, lengthfield) \ gw_assert(bitpos % 8 == 0); \ if (p->field != NULL) \ octstr_append(data, p->field); \ bitpos += 8 * octstr_len(p->field); #define REST(field, docstring) \ gw_assert(bitpos % 8 == 0); \ if (p->field != NULL) \ octstr_append(data, p->field); \ bitpos += 8 * octstr_len(p->field); #define TYPE(bits, value) \ octstr_set_bits(data, bitpos, (bits), (value)); \ bitpos += (bits); #define RESERVED(bits) bitpos += (bits); #include "wsp_pdu.def" #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: panic(0, "Packing unknown WSP PDU type %ld", (long) pdu->type); } return data; } void wsp_pdu_dump(WSP_PDU *pdu, int level) { char *dbg = "wap.wsp"; switch (pdu->type) { #define PDU(name, docstring, fields, is_valid) \ case name: { \ struct name *p = &pdu->u.name; \ debug(dbg, 0, "%*sWSP %s PDU at %p:", \ level, "", #name, (void *)pdu); \ fields \ } break; #define UINT(field, docstring, bits) \ debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field); #define UINTVAR(field, docstring) \ debug(dbg, 0, "%*s %s: %lu", level, "", docstring, p->field); #define OCTSTR(field, docstring, lengthfield) \ debug(dbg, 0, "%*s %s:", level, "", docstring); \ octstr_dump(p->field, level + 1); #define REST(field, docstring) \ debug(dbg, 0, "%*s %s:", level, "", docstring); \ octstr_dump(p->field, level + 1); #define TYPE(bits, value) #define RESERVED(bits) #include "wsp_pdu.def" #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU default: debug(dbg, 0, "%*sWSP PDU at %p:", level, "", (void *)pdu); debug(dbg, 0, "%*s unknown type %u", level, "", pdu->type); break; } debug("wap.wsp", 0, "%*sWSP PDU dump ends.", level, ""); } gateway-1.4.5/wap/wsp.h0000644000175000017500000001141213227613126013437 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp.h - WSP implementation header */ #ifndef WSP_H #define WSP_H /* * int WSP_accepted_extended_methods[] = { -1 }; * int WSP_accepted_header_code_pages[] = { -1 }; */ typedef enum { WSP_TBD = 0, /* to be defined */ WSP_1_1 = 1, WSP_1_2 = 2, WSP_1_3 = 3, WSP_1_4 = 4, WSP_1_5 = 5, WSP_1_6 = 6, } wsp_encoding; /* See Table 35 of the WSP standard */ enum wsp_abort_values { WSP_ABORT_PROTOERR = 0xe0, WSP_ABORT_DISCONNECT = 0xe1, WSP_ABORT_SUSPEND = 0xe2, WSP_ABORT_RESUME = 0xe3, WSP_ABORT_CONGESTION = 0xe4, WSP_ABORT_CONNECTERR = 0xe5, WSP_ABORT_MRUEXCEEDED = 0xe6, WSP_ABORT_MOREXCEEDED = 0xe7, WSP_ABORT_PEERREQ = 0xe8, WSP_ABORT_NETERR = 0xe9, WSP_ABORT_USERREQ = 0xea, WSP_ABORT_USERRFS = 0xeb, WSP_ABORT_USERPND = 0xec, WSP_ABORT_USERDCR = 0xed, WSP_ABORT_USERDCU = 0xee }; typedef struct WSPMachine WSPMachine; typedef struct WSPMethodMachine WSPMethodMachine; typedef struct WSPPushMachine WSPPushMachine; #include "gwlib/gwlib.h" #include "wap_addr.h" #include "wap_events.h" struct WSPMachine { #define INTEGER(name) long name; #define OCTSTR(name) Octstr *name; #define HTTPHEADERS(name) List *name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define COOKIES(name) List *name; #define REFERER(name) Octstr *name; #define MACHINESLIST(name) List *name; #define CAPABILITIES(name) List *name; #define MACHINE(fields) fields #include "wsp_server_session_machine.def" }; struct WSPMethodMachine { #define INTEGER(name) long name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define EVENT(name) WAPEvent *name; #define MACHINE(fields) fields #include "wsp_server_method_machine.def" }; struct WSPPushMachine { #define INTEGER(name) long name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define HTTPHEADER(name) List *name; #define MACHINE(fields) fields #include "wsp_server_push_machine.def" }; /* * Shared stuff. */ long wsp_convert_http_status_to_wsp_status(long http_status); WSPMachine *find_session_machine_by_id(int); #endif gateway-1.4.5/wap/wsp_session.c0000644000175000017500000012547413227613126015213 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_session.c - Implement WSP session oriented service * * Lars Wirzenius * Stipe Tolj */ #include #include #include "gwlib/gwlib.h" #include "wsp.h" #include "wsp_pdu.h" #include "wsp_headers.h" #include "wsp_caps.h" #include "wsp_strings.h" #include "cookies.h" #include "wap.h" #include "wtp.h" typedef enum { #define STATE_NAME(name) name, #define ROW(state, event, condition, action, next_state) #include "wsp_server_session_states.def" #define STATE_NAME(name) name, #define ROW(state, event, condition, action, next_state) #include "wsp_server_method_states.def" #define STATE_NAME(name) name, #define ROW(state, event, condition, action, next_state) #include "wsp_server_push_states.def" WSPState_count } WSPState; /* * Give the status the module: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum { limbo, running, terminating } run_status = limbo; static wap_dispatch_func_t *dispatch_to_wtp_resp; static wap_dispatch_func_t *dispatch_to_wtp_init; static wap_dispatch_func_t *dispatch_to_appl; static wap_dispatch_func_t *dispatch_to_ota; /* * True iff "Session resume facility" is enabled. This means we are * willing to let sessions go to SUSPENDED state, and later resume them. * Currently we always support it, but this may become configurable * at some point. */ static int resume_enabled = 1; static List *queue = NULL; static List *session_machines = NULL; static Counter *session_id_counter = NULL; static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu); static void handle_session_event(WSPMachine *machine, WAPEvent *event, WSP_PDU *pdu); static WSPMachine *machine_create(void); static void machine_destroy(void *p); static void handle_method_event(WSPMachine *session, WSPMethodMachine *machine, WAPEvent *event, WSP_PDU *pdu); static void cant_handle_event(WSPMachine *sm, WAPEvent *event); static WSPMethodMachine *method_machine_create(WSPMachine *, long); static void method_machine_destroy(void *msm); static void handle_push_event(WSPMachine *session, WSPPushMachine *machine, WAPEvent *e); static WSPPushMachine *push_machine_create(WSPMachine *session, long id); static void push_machine_destroy(void *p); static char *state_name(WSPState state); static unsigned long next_wsp_session_id(void); static List *make_capabilities_reply(WSPMachine *m); static List *make_reply_headers(WSPMachine *m); static Octstr *make_connectreply_pdu(WSPMachine *m); static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers); static WSP_PDU *make_confirmedpush_pdu(WAPEvent *e); static WSP_PDU *make_push_pdu(WAPEvent *e); static int transaction_belongs_to_session(void *session, void *tuple); static int find_by_session_id(void *session, void *idp); static int same_client(void *sm1, void *sm2); static WSPMethodMachine *find_method_machine(WSPMachine *, long id); static WSPPushMachine *find_push_machine(WSPMachine *m, long id); static List *unpack_new_headers(WSPMachine *sm, Octstr *hdrs); static void disconnect_other_sessions(WSPMachine *sm); static void send_abort(long reason, long handle); static void indicate_disconnect(WSPMachine *sm, long reason); static void indicate_suspend(WSPMachine *sm, long reason); static void indicate_resume(WSPMachine *sm, WAPAddrTuple *tuple, List *client_headers); static void release_holding_methods(WSPMachine *sm); static void abort_methods(WSPMachine *sm, long reason); static void abort_pushes(WSPMachine *sm, long reason); static void method_abort(WSPMethodMachine *msm, long reason); static void indicate_method_abort(WSPMethodMachine *msm, long reason); static WAPEvent *make_abort(long reason, long handle); static void send_invoke(WSPMachine *session, WSP_PDU *pdu, WAPEvent *e, long class); static void send_abort_to_initiator(long reason, long handle); static void indicate_pushabort(WSPPushMachine *machine, long reason); static void confirm_push(WSPPushMachine *machine); static void main_thread(void *); static int id_belongs_to_session (void *, void *); static int wsp_encoding_string_to_version(Octstr *enc); static Octstr *wsp_encoding_version_to_string(int version); /*********************************************************************** * Public functions. */ void wsp_session_init(wap_dispatch_func_t *responder_dispatch, wap_dispatch_func_t *initiator_dispatch, wap_dispatch_func_t *application_dispatch, wap_dispatch_func_t *push_ota_dispatch) { queue = gwlist_create(); gwlist_add_producer(queue); session_machines = gwlist_create(); session_id_counter = counter_create(); dispatch_to_wtp_resp = responder_dispatch; dispatch_to_wtp_init = initiator_dispatch; dispatch_to_appl = application_dispatch; dispatch_to_ota = push_ota_dispatch; wsp_strings_init(); run_status = running; gwthread_create(main_thread, NULL); } void wsp_session_shutdown(void) { gw_assert(run_status == running); run_status = terminating; gwlist_remove_producer(queue); gwthread_join_every(main_thread); gwlist_destroy(queue, wap_event_destroy_item); debug("wap.wsp", 0, "WSP: %ld session machines left.", gwlist_len(session_machines)); gwlist_destroy(session_machines, machine_destroy); counter_destroy(session_id_counter); wsp_strings_shutdown(); } void wsp_session_dispatch_event(WAPEvent *event) { wap_event_assert(event); gwlist_produce(queue, event); } /*********************************************************************** * Local functions */ static void main_thread(void *arg) { WAPEvent *e; WSPMachine *sm; WSP_PDU *pdu; while (run_status == running && (e = gwlist_consume(queue)) != NULL) { wap_event_assert(e); switch (e->type) { case TR_Invoke_Ind: pdu = wsp_pdu_unpack(e->u.TR_Invoke_Ind.user_data); if (pdu == NULL) { warning(0, "WSP: Broken PDU ignored."); wap_event_destroy(e); continue; } break; default: pdu = NULL; break; } sm = find_session_machine(e, pdu); if (sm == NULL) { wap_event_destroy(e); } else { handle_session_event(sm, e, pdu); } wsp_pdu_destroy(pdu); } } static WSPMachine *find_session_machine(WAPEvent *event, WSP_PDU *pdu) { WSPMachine *sm; long session_id; WAPAddrTuple *tuple; tuple = NULL; session_id = -1; switch (event->type) { case TR_Invoke_Ind: tuple = wap_addr_tuple_duplicate( event->u.TR_Invoke_Ind.addr_tuple); break; case TR_Invoke_Cnf: tuple = wap_addr_tuple_duplicate( event->u.TR_Invoke_Cnf.addr_tuple); break; case TR_Result_Cnf: tuple = wap_addr_tuple_duplicate( event->u.TR_Result_Cnf.addr_tuple); break; case TR_Abort_Ind: tuple = wap_addr_tuple_duplicate( event->u.TR_Abort_Ind.addr_tuple); break; case S_Connect_Res: session_id = event->u.S_Connect_Res.session_id; break; case S_Resume_Res: session_id = event->u.S_Resume_Res.session_id; break; case Disconnect_Event: session_id = event->u.Disconnect_Event.session_handle; break; case Suspend_Event: session_id = event->u.Suspend_Event.session_handle; break; case S_MethodInvoke_Res: session_id = event->u.S_MethodInvoke_Res.session_id; break; case S_MethodResult_Req: session_id = event->u.S_MethodResult_Req.session_id; break; case S_ConfirmedPush_Req: session_id = event->u.S_ConfirmedPush_Req.session_id; break; case S_Push_Req: session_id = event->u.S_Push_Req.session_id; break; default: error(0, "WSP: Cannot find machine for %s event", wap_event_name(event->type)); } gw_assert(tuple != NULL || session_id != -1); /* Pre-state-machine tests, according to 7.1.5. After the tests, * caller will pass the event to sm if sm is not NULL. */ sm = NULL; /* First test is for MRUEXCEEDED, and we don't have a MRU */ /* Second test is for class 2 TR-Invoke.ind with Connect PDU */ if (event->type == TR_Invoke_Ind && event->u.TR_Invoke_Ind.tcl == 2 && pdu->type == Connect) { /* Create a new session, even if there is already * a session open for this address. The new session * will take care of killing the old ones. */ sm = machine_create(); gw_assert(tuple != NULL); sm->addr_tuple = wap_addr_tuple_duplicate(tuple); sm->connect_handle = event->u.TR_Invoke_Ind.handle; /* Third test is for class 2 TR-Invoke.ind with Resume PDU */ } else if (event->type == TR_Invoke_Ind && event->u.TR_Invoke_Ind.tcl == 2 && pdu->type == Resume) { /* Pass to session identified by session id, not * the address tuple. */ session_id = pdu->u.Resume.sessionid; sm = gwlist_search(session_machines, &session_id, find_by_session_id); if (sm == NULL) { /* No session; TR-Abort.req(DISCONNECT) */ send_abort(WSP_ABORT_DISCONNECT, event->u.TR_Invoke_Ind.handle); } /* Fourth test is for a class 1 or 2 TR-Invoke.Ind with no * session for that address tuple. We also handle class 0 * TR-Invoke.ind here by ignoring them; this seems to be * an omission in the spec table. */ } else if (event->type == TR_Invoke_Ind) { sm = gwlist_search(session_machines, tuple, transaction_belongs_to_session); if (sm == NULL && (event->u.TR_Invoke_Ind.tcl == 1 || event->u.TR_Invoke_Ind.tcl == 2)) { send_abort(WSP_ABORT_DISCONNECT, event->u.TR_Invoke_Ind.handle); } /* Other tests are for events not handled by the state tables; * do those later, after we've tried to handle them. */ } else { if (session_id != -1) { sm = gwlist_search(session_machines, &session_id, find_by_session_id); } else { sm = gwlist_search(session_machines, tuple, transaction_belongs_to_session); } /* The table doesn't really say what we should do with * non-Invoke events for which there is no session. But * such a situation means there is an error _somewhere_ * in the gateway. */ if (sm == NULL) { error(0, "WSP: Cannot find session machine for event."); wap_event_dump(event); } } wap_addr_tuple_destroy(tuple); return sm; } static void handle_session_event(WSPMachine *sm, WAPEvent *current_event, WSP_PDU *pdu) { debug("wap.wsp", 0, "WSP: machine %p, state %s, event %s", (void *) sm, state_name(sm->state), wap_event_name(current_event->type)); #define STATE_NAME(name) #define ROW(state_name, event, condition, action, next_state) \ { \ struct event *e; \ e = ¤t_event->u.event; \ if (sm->state == state_name && \ current_event->type == event && \ (condition)) { \ action \ sm->state = next_state; \ debug("wap.wsp", 0, "WSP %ld: New state %s", \ sm->session_id, #next_state); \ goto end; \ } \ } #include "wsp_server_session_states.def" cant_handle_event(sm, current_event); end: wap_event_destroy(current_event); if (sm->state == NULL_SESSION) machine_destroy(sm); } static void cant_handle_event(WSPMachine *sm, WAPEvent *event) { /* We do the rest of the pre-state-machine tests here. The first * four were done in find_session_machine(). The fifth is a * class 1 or 2 TR-Invoke.ind not handled by the state tables. */ if (event->type == TR_Invoke_Ind && (event->u.TR_Invoke_Ind.tcl == 1 || event->u.TR_Invoke_Ind.tcl == 2)) { warning(0, "WSP: Can't handle TR-Invoke.ind, aborting transaction."); debug("wap.wsp", 0, "WSP: The unhandled event:"); wap_event_dump(event); send_abort(WSP_ABORT_PROTOERR, event->u.TR_Invoke_Ind.handle); /* The sixth is a class 0 TR-Invoke.ind not handled by state tables. */ } else if (event->type == TR_Invoke_Ind) { warning(0, "WSP: Can't handle TR-Invoke.ind, ignoring."); debug("wap.wsp", 0, "WSP: The ignored event:"); wap_event_dump(event); /* The seventh is any other event not handled by state tables. */ } else { error(0, "WSP: Can't handle event. Aborting session."); debug("wap.wsp", 0, "WSP: The unhandled event:"); wap_event_dump(event); /* TR-Abort.req(PROTOERR) if it is some other transaction * event than abort. */ /* Currently that means TR-Result.cnf, because we already * tested for Invoke. */ /* FIXME We need a better way to get at event values than * by hardcoding the types. */ if (event->type == TR_Result_Cnf) { send_abort(WSP_ABORT_PROTOERR, event->u.TR_Result_Cnf.handle); } /* Abort(PROTOERR) all method and push transactions */ abort_methods(sm, WSP_ABORT_PROTOERR); abort_pushes(sm, WSP_ABORT_PROTOERR); /* S-Disconnect.ind(PROTOERR) */ indicate_disconnect(sm, WSP_ABORT_PROTOERR); } } static WSPMachine *machine_create(void) { WSPMachine *p; p = gw_malloc(sizeof(WSPMachine)); debug("wap.wsp", 0, "WSP: Created WSPMachine %p", (void *) p); #define INTEGER(name) p->name = 0; #define OCTSTR(name) p->name = NULL; #define HTTPHEADERS(name) p->name = NULL; #define ADDRTUPLE(name) p->name = NULL; #define MACHINESLIST(name) p->name = gwlist_create(); #define CAPABILITIES(name) p->name = NULL; #define COOKIES(name) p->name = gwlist_create(); #define REFERER(name) p->name = NULL; #define MACHINE(fields) fields #include "wsp_server_session_machine.def" p->state = NULL_SESSION; /* set capabilities to default values (defined in 1.1) */ p->client_SDU_size = 1400; p->MOR_push = 1; /* Insert new machine at the _front_, because 1) it's more likely * to get events than old machines are, so this speeds up the linear * search, and 2) we want the newest machine to get any method * invokes that come through before the Connect is established. */ gwlist_insert(session_machines, 0, p); return p; } static void destroy_methodmachines(List *machines) { if (gwlist_len(machines) > 0) { warning(0, "Destroying WSP session with %ld active methods\n", gwlist_len(machines)); } gwlist_destroy(machines, method_machine_destroy); } static void destroy_pushmachines(List *machines) { if (gwlist_len(machines) > 0) { warning(0, "Destroying WSP session with %ld active pushes\n", gwlist_len(machines)); } gwlist_destroy(machines, push_machine_destroy); } static void machine_destroy(void *pp) { WSPMachine *p; p = pp; debug("wap.wsp", 0, "Destroying WSPMachine %p", pp); gwlist_delete_equal(session_machines, p); #define INTEGER(name) p->name = 0; #define OCTSTR(name) octstr_destroy(p->name); #define HTTPHEADERS(name) http_destroy_headers(p->name); #define ADDRTUPLE(name) wap_addr_tuple_destroy(p->name); #define MACHINESLIST(name) destroy_##name(p->name); #define CAPABILITIES(name) wsp_cap_destroy_list(p->name); #define COOKIES(name) cookies_destroy(p->name); #define REFERER(name) octstr_destroy(p->name); #define MACHINE(fields) fields #include "wsp_server_session_machine.def" gw_free(p); } struct msm_pattern { WAPAddrTuple *addr_tuple; long msmid, tid; }; /* This function does NOT consume its event; it leaves that task up * to the parent session */ static void handle_method_event(WSPMachine *sm, WSPMethodMachine *msm, WAPEvent *current_event, WSP_PDU *pdu) { if (msm == NULL) { warning(0, "No method machine for event."); wap_event_dump(current_event); return; } debug("wap.wsp", 0, "WSP: method %ld, state %s, event %s", msm->transaction_id, state_name(msm->state), wap_event_name(current_event->type)); gw_assert(sm->session_id == msm->session_id); #define STATE_NAME(name) #define ROW(state_name, event, condition, action, next_state) \ { \ struct event *e; \ e = ¤t_event->u.event; \ if (msm->state == state_name && \ current_event->type == event && \ (condition)) { \ action \ msm->state = next_state; \ debug("wap.wsp", 0, "WSP %ld/%ld: New method state %s", \ msm->session_id, msm->transaction_id, #next_state); \ goto end; \ } \ } #include "wsp_server_method_states.def" cant_handle_event(sm, current_event); end: if (msm->state == NULL_METHOD) { method_machine_destroy(msm); gwlist_delete_equal(sm->methodmachines, msm); } } static WSPMethodMachine *method_machine_create(WSPMachine *sm, long wtp_handle) { WSPMethodMachine *msm; msm = gw_malloc(sizeof(*msm)); #define INTEGER(name) msm->name = 0; #define ADDRTUPLE(name) msm->name = NULL; #define EVENT(name) msm->name = NULL; #define MACHINE(fields) fields #include "wsp_server_method_machine.def" msm->transaction_id = wtp_handle; msm->state = NULL_METHOD; msm->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple); msm->session_id = sm->session_id; gwlist_append(sm->methodmachines, msm); return msm; } static void method_machine_destroy(void *p) { WSPMethodMachine *msm; if (p == NULL) return; msm = p; debug("wap.wsp", 0, "Destroying WSPMethodMachine %ld", msm->transaction_id); #define INTEGER(name) #define ADDRTUPLE(name) wap_addr_tuple_destroy(msm->name); #define EVENT(name) wap_event_destroy(msm->name); #define MACHINE(fields) fields #include "wsp_server_method_machine.def" gw_free(msm); } static void handle_push_event(WSPMachine *sm, WSPPushMachine *pm, WAPEvent *current_event) { if (pm == NULL) { warning(0, "No push machine for event."); wap_event_dump(current_event); return; } debug("wap.wsp", 0, "WSP(tid/pid): push %ld/%ld, state %s, event %s", pm->transaction_id, pm->server_push_id, state_name(pm->state), wap_event_name(current_event->type)); gw_assert(sm->session_id == pm->session_id); #define STATE_NAME(name) #define ROW(state_name, event, condition, action, next_state) \ { \ if (pm->state == state_name && \ current_event->type == event && \ (condition)) { \ action \ pm->state = next_state; \ debug("wap.wsp", 0, "WSP %ld/%ld: New push state %s", \ pm->session_id, pm->transaction_id, #next_state); \ goto end; \ } \ } #include "wsp_server_push_states.def" cant_handle_event(sm, current_event); end: if (pm->state == SERVER_PUSH_NULL_STATE) { push_machine_destroy(pm); gwlist_delete_equal(sm->pushmachines, pm); } } static WSPPushMachine *push_machine_create(WSPMachine *sm, long pid) { WSPPushMachine *m; m = gw_malloc(sizeof(WSPPushMachine)); #define INTEGER(name) m->name = 0; #define ADDRTUPLE(name) m->name = NULL; #define HTTPHEADER(name) m->name = http_create_empty_headers(); #define MACHINE(fields) fields #include "wsp_server_push_machine.def" m->server_push_id = pid; m->transaction_id = pid; m->state = SERVER_PUSH_NULL_STATE; m->addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple); m->session_id = sm->session_id; gwlist_append(sm->pushmachines, m); return m; } static void push_machine_destroy(void *p) { WSPPushMachine *m = NULL; if (p == NULL) return; m = p; debug("wap.wsp", 0, "Destroying WSPPushMachine %ld", m->transaction_id); #define INTEGER(name) #define ADDRTUPLE(name) wap_addr_tuple_destroy(m->name); #define HTTPHEADER(name) http_destroy_headers(m->name); #define MACHINE(fields) fields #include "wsp_server_push_machine.def" gw_free(m); } static char *state_name(WSPState state) { switch (state) { #define STATE_NAME(name) case name: return #name; #define ROW(state, event, cond, stmt, next_state) #include "wsp_server_session_states.def" #define STATE_NAME(name) case name: return #name; #define ROW(state, event, cond, stmt, next_state) #include "wsp_server_method_states.def" #define STATE_NAME(name) case name: return #name; #define ROW(state, event, cond, stmt, next_state) #include "wsp_server_push_states.def" default: return "unknown wsp state"; } } static unsigned long next_wsp_session_id(void) { return counter_increase(session_id_counter); } static void sanitize_capabilities(List *caps, WSPMachine *m) { long i; Capability *cap; unsigned long ui; for (i = 0; i < gwlist_len(caps); i++) { cap = gwlist_get(caps, i); /* We only know numbered capabilities. Let the application * layer negotiate whatever it wants for unknown ones. */ if (cap->name != NULL) continue; switch (cap->id) { case WSP_CAPS_CLIENT_SDU_SIZE: /* Check if it's a valid uintvar. The value is the * max SDU size we will send, and there's no * internal limit to that, so accept any value. */ if (cap->data != NULL && octstr_extract_uintvar(cap->data, &ui, 0) < 0) goto bad_cap; else m->client_SDU_size = ui; break; case WSP_CAPS_SERVER_SDU_SIZE: /* Check if it's a valid uintvar */ if (cap->data != NULL && (octstr_extract_uintvar(cap->data, &ui, 0) < 0)) goto bad_cap; /* XXX Our MRU is not quite unlimited, since we * use signed longs in the library functions -- * should we make sure we limit the reply value * to LONG_MAX? (That's already a 2GB packet) */ break; case WSP_CAPS_PROTOCOL_OPTIONS: /* Currently we don't support any Push, nor * session resume, nor acknowledgement headers, * so make sure those bits are not set. */ if (cap->data != NULL && octstr_len(cap->data) > 0 && (octstr_get_char(cap->data, 0) & 0xf0) != 0) { warning(0, "WSP: Application layer tried to " "negotiate protocol options."); octstr_set_bits(cap->data, 0, 4, 0); } break; case WSP_CAPS_EXTENDED_METHODS: /* XXX Check format here */ break; case WSP_CAPS_HEADER_CODE_PAGES: /* We don't support any yet, so don't let this * be negotiated. */ if (cap->data) goto bad_cap; break; } continue; bad_cap: error(0, "WSP: Found illegal value in capabilities reply."); wsp_cap_dump(cap); gwlist_delete(caps, i, 1); i--; wsp_cap_destroy(cap); continue; } } static void reply_known_capabilities(List *caps, List *req, WSPMachine *m) { unsigned long ui; Capability *cap; Octstr *data; if (wsp_cap_count(caps, WSP_CAPS_CLIENT_SDU_SIZE, NULL) == 0) { if (wsp_cap_get_client_sdu(req, &ui) > 0) { /* Accept value if it is not silly. */ if ((ui >= 256 && ui < LONG_MAX) || ui == 0) { m->client_SDU_size = ui; } } /* Reply with the client SDU we decided on */ data = octstr_create(""); octstr_append_uintvar(data, m->client_SDU_size); cap = wsp_cap_create(WSP_CAPS_CLIENT_SDU_SIZE, NULL, data); gwlist_append(caps, cap); } if (wsp_cap_count(caps, WSP_CAPS_SERVER_SDU_SIZE, NULL) == 0) { /* Accept whatever size the client is willing * to send. If the client did not specify anything, * then use the default. */ if (wsp_cap_get_server_sdu(req, &ui) <= 0) { ui = 1400; } data = octstr_create(""); octstr_append_uintvar(data, ui); cap = wsp_cap_create(WSP_CAPS_SERVER_SDU_SIZE, NULL, data); gwlist_append(caps, cap); } /* Currently we cannot handle any protocol options */ if (wsp_cap_count(caps, WSP_CAPS_PROTOCOL_OPTIONS, NULL) == 0) { data = octstr_create(""); octstr_append_char(data, 0); cap = wsp_cap_create(WSP_CAPS_PROTOCOL_OPTIONS, NULL, data); gwlist_append(caps, cap); } /* Accept any Method-MOR the client sent; if it sent none, * use the default. */ if (wsp_cap_count(caps, WSP_CAPS_METHOD_MOR, NULL) == 0) { if (wsp_cap_get_method_mor(req, &ui) <= 0) { ui = 1; } data = octstr_create(""); octstr_append_char(data, ui); cap = wsp_cap_create(WSP_CAPS_METHOD_MOR, NULL, data); gwlist_append(caps, cap); } /* We will never send any Push requests because we don't support * that yet. But we already specified that in protocol options; * so, pretend we do, and handle the value that way. */ if (wsp_cap_count(caps, WSP_CAPS_PUSH_MOR, NULL) == 0) { if (wsp_cap_get_push_mor(req, &ui) > 0) { m->MOR_push = ui; } data = octstr_create(""); octstr_append_char(data, m->MOR_push); cap = wsp_cap_create(WSP_CAPS_PUSH_MOR, NULL, data); gwlist_append(caps, cap); } /* Supporting extended methods is up to the application layer, * not up to us. If the application layer didn't specify any, * then we refuse whatever the client requested. The default * is to support none, so we don't really have to add anything here. */ /* We do not support any header code pages. sanitize_capabilities * must have already deleted any reply that indicates otherwise. * Again, not adding anything here is the same as refusing support. */ /* Listing aliases is something the application layer can do if * it wants to. We don't care. */ } /* Generate a refusal for all requested capabilities that are not * replied to. */ static void refuse_unreplied_capabilities(List *caps, List *req) { long i, len; Capability *cap; len = gwlist_len(req); for (i = 0; i < len; i++) { cap = gwlist_get(req, i); if (wsp_cap_count(caps, cap->id, cap->name) == 0) { cap = wsp_cap_create(cap->id, cap->name, NULL); gwlist_append(caps, cap); } } } static int is_default_cap(Capability *cap) { unsigned long ui; /* All unknown values are empty by default */ if (cap->name != NULL || cap->id < 0 || cap->id >= WSP_NUM_CAPS) return cap->data == NULL || octstr_len(cap->data) == 0; switch (cap->id) { case WSP_CAPS_CLIENT_SDU_SIZE: case WSP_CAPS_SERVER_SDU_SIZE: return (cap->data != NULL && octstr_extract_uintvar(cap->data, &ui, 0) >= 0 && ui == 1400); case WSP_CAPS_PROTOCOL_OPTIONS: return cap->data != NULL && octstr_get_char(cap->data, 0) == 0; case WSP_CAPS_METHOD_MOR: case WSP_CAPS_PUSH_MOR: return cap->data != NULL && octstr_get_char(cap->data, 0) == 1; case WSP_CAPS_EXTENDED_METHODS: case WSP_CAPS_HEADER_CODE_PAGES: case WSP_CAPS_ALIASES: return cap->data == NULL || octstr_len(cap->data) == 0; default: return 0; } } /* Remove any replies that have no corresponding request and that * are equal to the default. */ static void strip_default_capabilities(List *caps, List *req) { long i; Capability *cap; int count; /* Hmm, this is an O(N*N) operation, which may be bad. */ i = 0; while (i < gwlist_len(caps)) { cap = gwlist_get(caps, i); count = wsp_cap_count(req, cap->id, cap->name); if (count == 0 && is_default_cap(cap)) { gwlist_delete(caps, i, 1); wsp_cap_destroy(cap); } else { i++; } } } static List *make_capabilities_reply(WSPMachine *m) { List *caps; /* In principle, copy the application layer's capabilities * response, add refusals for all unknown requested capabilities, * and add responses for all known capabilities that are * not already responded to. Then eliminate any replies that * would have no effect because they are equal to the default. */ caps = wsp_cap_duplicate_list(m->reply_caps); /* Don't let the application layer negotiate anything we * cannot handle. Also parse the values it set if we're * interested. */ sanitize_capabilities(caps, m); /* Add capability records for all capabilities we know about * that are not already in the reply list. */ reply_known_capabilities(caps, m->request_caps, m); /* All remaining capabilities in the request list that are * not in the reply list at this point must be unknown ones * that we want to refuse. */ refuse_unreplied_capabilities(caps, m->request_caps); /* Now eliminate replies that would be equal to the requested * value, or (if there was none) to the default value. */ strip_default_capabilities(caps, m->request_caps); return caps; } static List *make_reply_headers(WSPMachine *m) { List *headers; Octstr *encoding_version; /* Add all server wsp level hop-by-hop headers. Currently only * Encoding-Version, as defined by wsp, chapter 8.4.2.70. * What headers belong to which version is defined in appendix A, * table 39.. encoding_version = request_version = NULL; * Essentially, if the client sends us an Encoding-Version * higher than ours (1.3) we send our version number to it, * if it is lower, we left version number intact. */ /* First the case that we have no Encoding-Version header at all. * This case we must assume that the client supports version 1.2 * or lower. */ headers = http_create_empty_headers(); encoding_version = wsp_encoding_version_to_string(m->encoding_version); http_header_add(headers, "Encoding-Version", octstr_get_cstr(encoding_version)); octstr_destroy(encoding_version); return headers; } static Octstr *make_connectreply_pdu(WSPMachine *m) { WSP_PDU *pdu; Octstr *os; List *caps; List *reply_headers; pdu = wsp_pdu_create(ConnectReply); pdu->u.ConnectReply.sessionid = m->session_id; caps = make_capabilities_reply(m); pdu->u.ConnectReply.capabilities = wsp_cap_pack_list(caps); wsp_cap_destroy_list(caps); reply_headers = make_reply_headers(m); pdu->u.ConnectReply.headers = wsp_headers_pack(reply_headers, 0, m->encoding_version); http_destroy_headers(reply_headers); os = wsp_pdu_pack(pdu); wsp_pdu_destroy(pdu); return os; } static Octstr *make_resume_reply_pdu(WSPMachine *m, List *headers) { WSP_PDU *pdu; Octstr *os; pdu = wsp_pdu_create(Reply); /* Not specified for Resume replies */ pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(HTTP_OK); if (headers == NULL) { headers = http_create_empty_headers(); pdu->u.Reply.headers = wsp_headers_pack(headers, 1, m->encoding_version); http_destroy_headers(headers); } else { pdu->u.Reply.headers = wsp_headers_pack(headers, 1, m->encoding_version); } pdu->u.Reply.data = octstr_create(""); os = wsp_pdu_pack(pdu); wsp_pdu_destroy(pdu); return os; } static WSP_PDU *make_confirmedpush_pdu(WAPEvent *e) { WSP_PDU *pdu; List *headers; pdu = wsp_pdu_create(ConfirmedPush); /* * Both push headers and push body are optional. */ if (e->u.S_ConfirmedPush_Req.push_headers == NULL) { headers = http_create_empty_headers(); pdu->u.ConfirmedPush.headers = wsp_headers_pack(headers, 1, WSP_1_2); http_destroy_headers(headers); } else pdu->u.ConfirmedPush.headers = wsp_headers_pack(e->u.S_ConfirmedPush_Req.push_headers, 1, WSP_1_2); if (e->u.S_ConfirmedPush_Req.push_body == NULL) pdu->u.ConfirmedPush.data = octstr_create(""); else pdu->u.ConfirmedPush.data = octstr_duplicate(e->u.S_ConfirmedPush_Req.push_body); return pdu; } static WSP_PDU *make_push_pdu(WAPEvent *e) { WSP_PDU *pdu; List *headers; pdu = wsp_pdu_create(Push); /* * Both push headers and push body are optional */ if (e->u.S_Push_Req.push_headers == NULL) { headers = http_create_empty_headers(); pdu->u.Push.headers = wsp_headers_pack(headers, 1, WSP_1_2); http_destroy_headers(headers); } else pdu->u.Push.headers = wsp_headers_pack(e->u.S_Push_Req.push_headers, 1, WSP_1_2); if (e->u.S_Push_Req.push_body == NULL) pdu->u.Push.data = octstr_create(""); else pdu->u.Push.data = octstr_duplicate(e->u.S_Push_Req.push_body); return pdu; } static int transaction_belongs_to_session(void *wsp_ptr, void *tuple_ptr) { WSPMachine *wsp; WAPAddrTuple *tuple; wsp = wsp_ptr; tuple = tuple_ptr; return wap_addr_tuple_same(wsp->addr_tuple, tuple); } static int find_by_session_id(void *wsp_ptr, void *id_ptr) { WSPMachine *wsp = wsp_ptr; long *idp = id_ptr; return wsp->session_id == *idp; } static int find_by_method_id(void *wspm_ptr, void *id_ptr) { WSPMethodMachine *msm = wspm_ptr; long *idp = id_ptr; return msm->transaction_id == *idp; } static int find_by_push_id(void *m_ptr, void *id_ptr) { WSPPushMachine *m = m_ptr; long *idp = id_ptr; return m->transaction_id == *idp; } static WSPMethodMachine *find_method_machine(WSPMachine *sm, long id) { return gwlist_search(sm->methodmachines, &id, find_by_method_id); } static WSPPushMachine *find_push_machine(WSPMachine *m, long id) { return gwlist_search(m->pushmachines, &id, find_by_push_id); } static int same_client(void *a, void *b) { WSPMachine *sm1, *sm2; sm1 = a; sm2 = b; return wap_addr_tuple_same(sm1->addr_tuple, sm2->addr_tuple); } static void disconnect_other_sessions(WSPMachine *sm) { List *old_sessions; WAPEvent *disconnect; WSPMachine *sm2; long i; old_sessions = gwlist_search_all(session_machines, sm, same_client); if (old_sessions == NULL) return; for (i = 0; i < gwlist_len(old_sessions); i++) { sm2 = gwlist_get(old_sessions, i); if (sm2 != sm) { disconnect = wap_event_create(Disconnect_Event); handle_session_event(sm2, disconnect, NULL); } } gwlist_destroy(old_sessions, NULL); } static List *unpack_new_headers(WSPMachine *sm, Octstr *hdrs) { List *new_headers; if (hdrs && octstr_len(hdrs) > 0) { new_headers = wsp_headers_unpack(hdrs, 0); if (sm->http_headers == NULL) sm->http_headers = http_create_empty_headers(); http_header_combine(sm->http_headers, new_headers); return new_headers; } return NULL; } static WAPEvent *make_abort(long reason, long handle) { WAPEvent *wtp_event; wtp_event = wap_event_create(TR_Abort_Req); wtp_event->u.TR_Abort_Req.abort_type = 0x01; wtp_event->u.TR_Abort_Req.abort_reason = reason; wtp_event->u.TR_Abort_Req.handle = handle; return wtp_event; } static void send_abort(long reason, long handle) { WAPEvent *wtp_event; wtp_event = make_abort(reason, handle); dispatch_to_wtp_resp(wtp_event); } static void send_abort_to_initiator(long reason, long handle) { WAPEvent *wtp_event; wtp_event = make_abort(reason, handle); dispatch_to_wtp_init(wtp_event); } /* * The server sends invoke (to be exact, makes TR-Invoke.req) only when it is * pushing. (Only the client disconnects sessions.) */ static void send_invoke(WSPMachine *m, WSP_PDU *pdu, WAPEvent *e, long class) { WAPEvent *wtp_event; wtp_event = wap_event_create(TR_Invoke_Req); wtp_event->u.TR_Invoke_Req.addr_tuple = wap_addr_tuple_duplicate(m->addr_tuple); /* * There is no mention of acknowledgement type in the specs. But because * confirmed push is confirmed after response from OTA, provider acknowledge- * ments seem redundant. */ wtp_event->u.TR_Invoke_Req.up_flag = USER_ACKNOWLEDGEMENT; wtp_event->u.TR_Invoke_Req.tcl = class; if (e->type == S_ConfirmedPush_Req) wtp_event->u.TR_Invoke_Req.handle = e->u.S_ConfirmedPush_Req.server_push_id; wtp_event->u.TR_Invoke_Req.user_data = wsp_pdu_pack(pdu); wsp_pdu_destroy(pdu); dispatch_to_wtp_init(wtp_event); } static void indicate_disconnect(WSPMachine *sm, long reason) { WAPEvent *new_event; new_event = wap_event_create(S_Disconnect_Ind); new_event->u.S_Disconnect_Ind.reason_code = reason; new_event->u.S_Disconnect_Ind.redirect_security = 0; new_event->u.S_Disconnect_Ind.redirect_addresses = 0; new_event->u.S_Disconnect_Ind.error_headers = NULL; new_event->u.S_Disconnect_Ind.error_body = NULL; new_event->u.S_Disconnect_Ind.session_handle = sm->session_id; dispatch_to_appl(new_event); } static void indicate_suspend(WSPMachine *sm, long reason) { WAPEvent *new_event; new_event = wap_event_create(S_Suspend_Ind); new_event->u.S_Suspend_Ind.reason = reason; new_event->u.S_Suspend_Ind.session_id = sm->session_id; dispatch_to_appl(new_event); } static void indicate_resume(WSPMachine *sm, WAPAddrTuple *tuple, List *headers) { WAPEvent *new_event; new_event = wap_event_create(S_Resume_Ind); new_event->u.S_Resume_Ind.addr_tuple = wap_addr_tuple_duplicate(tuple); new_event->u.S_Resume_Ind.client_headers = http_header_duplicate(headers); new_event->u.S_Resume_Ind.session_id = sm->session_id; dispatch_to_appl(new_event); } static void indicate_pushabort(WSPPushMachine *spm, long reason) { WAPEvent *ota_event; ota_event = wap_event_create(S_PushAbort_Ind); ota_event->u.S_PushAbort_Ind.push_id = spm->server_push_id; ota_event->u.S_PushAbort_Ind.reason = reason; ota_event->u.S_PushAbort_Ind.session_id = spm->session_id; dispatch_to_appl(ota_event); } static void confirm_push(WSPPushMachine *m) { WAPEvent *ota_event; ota_event = wap_event_create(S_ConfirmedPush_Cnf); ota_event->u.S_ConfirmedPush_Cnf.server_push_id = m->server_push_id; ota_event->u.S_ConfirmedPush_Cnf.session_id = m->session_id; dispatch_to_appl(ota_event); } static void method_abort(WSPMethodMachine *msm, long reason) { WAPEvent *wtp_event; /* Send TR-Abort.req(reason) */ wtp_event = wap_event_create(TR_Abort_Req); /* FIXME: Specs are unclear about this; we may indeed have to * guess abort whether this is a WSP or WTP level abort code */ if (reason < WSP_ABORT_PROTOERR) { wtp_event->u.TR_Abort_Req.abort_type = 0x00; } else { wtp_event->u.TR_Abort_Req.abort_type = 0x01; } wtp_event->u.TR_Abort_Req.abort_reason = reason; wtp_event->u.TR_Abort_Req.handle = msm->transaction_id; dispatch_to_wtp_resp(wtp_event); } static void indicate_method_abort(WSPMethodMachine *msm, long reason) { WAPEvent *new_event; /* Send S-MethodAbort.ind(reason) */ new_event = wap_event_create(S_MethodAbort_Ind); new_event->u.S_MethodAbort_Ind.transaction_id = msm->transaction_id; new_event->u.S_MethodAbort_Ind.reason = reason; new_event->u.S_MethodAbort_Ind.session_handle = msm->session_id; dispatch_to_appl(new_event); } static int method_is_holding(void *item, void *pattern) { WSPMethodMachine *msm = item; return msm->state == HOLDING; } static void release_holding_methods(WSPMachine *sm) { WAPEvent *release; WSPMethodMachine *msm; List *holding; long i, len; holding = gwlist_search_all(sm->methodmachines, NULL, method_is_holding); if (holding == NULL) return; /* We can re-use this because wsp_handle_method_event does not * destroy its event */ release = wap_event_create(Release_Event); len = gwlist_len(holding); for (i = 0; i < len; i++) { msm = gwlist_get(holding, i); handle_method_event(sm, msm, release, NULL); } gwlist_destroy(holding, NULL); wap_event_destroy(release); } static void abort_methods(WSPMachine *sm, long reason) { WAPEvent *ab; WSPMethodMachine *msm; long i, len; ab = wap_event_create(Abort_Event); ab->u.Abort_Event.reason = reason; /* This loop goes backward because it has to deal with the * possibility of method machines disappearing after their event. */ len = gwlist_len(sm->methodmachines); for (i = len - 1; i >= 0; i--) { msm = gwlist_get(sm->methodmachines, i); handle_method_event(sm, msm, ab, NULL); } wap_event_destroy(ab); } static void abort_pushes(WSPMachine *sm, long reason) { WAPEvent *ab; WSPPushMachine *psm; long i, len; ab = wap_event_create(Abort_Event); ab->u.Abort_Event.reason = reason; len = gwlist_len(sm->pushmachines); for (i = len - 1; i >= 0; i--) { psm = gwlist_get(sm->pushmachines, i); handle_push_event(sm, psm, ab); } wap_event_destroy(ab); } WSPMachine *find_session_machine_by_id (int id) { return gwlist_search(session_machines, &id, id_belongs_to_session); } static int id_belongs_to_session (void *wsp_ptr, void *pid) { WSPMachine *wsp; int *id; wsp = wsp_ptr; id = (int *) pid; if (*id == wsp->session_id) return 1; return 0; } static int wsp_encoding_string_to_version(Octstr *enc) { int v; /* default will be WSP 1.2, as defined by WAPWSP */ v = WSP_1_2; if (octstr_compare(enc, octstr_imm("1.1")) == 0) { v = WSP_1_1; } else if (octstr_compare(enc, octstr_imm("1.2")) == 0) { v = WSP_1_2; } else if (octstr_compare(enc, octstr_imm("1.3")) == 0) { v = WSP_1_3; } else if (octstr_compare(enc, octstr_imm("1.4")) == 0) { v = WSP_1_4; } else if (octstr_compare(enc, octstr_imm("1.5")) == 0) { v = WSP_1_5; } return v; } static Octstr *wsp_encoding_version_to_string(int version) { Octstr *os; switch (version) { case WSP_1_1: os = octstr_create("1.1"); break; case WSP_1_2: os = octstr_create("1.2"); break; case WSP_1_3: os = octstr_create("1.3"); break; case WSP_1_4: os = octstr_create("1.4"); break; case WSP_1_5: os = octstr_create("1.5"); break; default: os = octstr_create("1.2"); break; } return os; } gateway-1.4.5/wap/wtp_tid.h0000644000175000017500000000763013227613126014307 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_tid.h - tid verification implementation header * * By Aarno Syvänen for WapIT Ltd */ #ifndef WTP_TID_H #define WTP_TID_H typedef struct WTPCached_tid WTPCached_tid; #include #include #include "gwlib/gwlib.h" #include "wap_events.h" #include "wtp_resp.h" #define WTP_TID_WINDOW_SIZE (1L << 14) /* * Constants defining the result of tid validation */ enum { no_cached_tid, ok, fail }; /* * Tid cache item consists of initiator identifier and cached tid. */ struct WTPCached_tid { WAPAddrTuple *addr_tuple; long tid; }; /* * Initialize tid cache. MUST be called before calling other functions in this * module. */ void wtp_tid_cache_init(void); /* * Shut down the tid cache. MUST be called after tid cache isn't used anymore. */ void wtp_tid_cache_shutdown(void); /* * Does the tid validation test, by using a simple window mechanism * * Returns: no_cached_tid, if the peer has no cached last tid, or the result * of the test (ok, fail); */ int wtp_tid_is_valid(WAPEvent *event, WTPRespMachine *machine); /* * Changes the tid value belonging to an existing initiator */ void wtp_tid_set_by_machine(WTPRespMachine *machine, long tid); #endif gateway-1.4.5/wap/wsp_server_method_states.def0000644000175000017500000003030213227613126020256 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_server_method_states.def * * Macro calls to generate rows of the state table. See the documentation for * guidance how to use and update these. * * Note that the `NULL' state has been renamed to `NULL_METHOD' because * NULL is reserved by C. */ STATE_NAME(NULL_METHOD) STATE_NAME(HOLDING) STATE_NAME(REQUESTING) STATE_NAME(PROCESSING) STATE_NAME(REPLYING) /* MISSING: TR_Invoke.ind, N_Methods == MOM */ ROW(NULL_METHOD, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Get, { List *headers; WAPEvent *invoke; int method; Octstr *method_name; /* Prepare the MethodInvoke here, because we have all * the information nicely available. */ if (octstr_len(pdu->u.Get.headers) > 0) headers = wsp_headers_unpack(pdu->u.Get.headers, 0); else headers = NULL; invoke = wap_event_create(S_MethodInvoke_Ind); invoke->u.S_MethodInvoke_Ind.server_transaction_id = msm->transaction_id; method = GET_METHODS + pdu->u.Get.subtype; method_name = wsp_method_to_string(method); if (method_name == NULL) method_name = octstr_format("UNKNOWN%02X", method); invoke->u.S_MethodInvoke_Ind.method = method_name; invoke->u.S_MethodInvoke_Ind.request_uri = octstr_duplicate(pdu->u.Get.uri); invoke->u.S_MethodInvoke_Ind.request_headers = headers; invoke->u.S_MethodInvoke_Ind.request_body = NULL; invoke->u.S_MethodInvoke_Ind.session_headers = http_header_duplicate(sm->http_headers); invoke->u.S_MethodInvoke_Ind.addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple); invoke->u.S_MethodInvoke_Ind.client_SDU_size = sm->client_SDU_size; invoke->u.S_MethodInvoke_Ind.session_id = msm->session_id; msm->invoke = invoke; }, HOLDING) ROW(NULL_METHOD, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Post, { List *headers; WAPEvent *invoke; int method; Octstr *method_name; /* Prepare the MethodInvoke here, because we have all * the information nicely available. */ if (octstr_len(pdu->u.Post.headers) > 0) headers = wsp_headers_unpack(pdu->u.Post.headers, 1); else headers = NULL; invoke = wap_event_create(S_MethodInvoke_Ind); invoke->u.S_MethodInvoke_Ind.server_transaction_id = msm->transaction_id; method = POST_METHODS + pdu->u.Get.subtype; method_name = wsp_method_to_string(method); if (method_name == NULL) method_name = octstr_format("UNKNOWN%02X", method); invoke->u.S_MethodInvoke_Ind.method = method_name; invoke->u.S_MethodInvoke_Ind.request_uri = octstr_duplicate(pdu->u.Post.uri); invoke->u.S_MethodInvoke_Ind.request_headers = headers; invoke->u.S_MethodInvoke_Ind.request_body = octstr_duplicate(pdu->u.Post.data); invoke->u.S_MethodInvoke_Ind.session_headers = http_header_duplicate(sm->http_headers); invoke->u.S_MethodInvoke_Ind.addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple); invoke->u.S_MethodInvoke_Ind.client_SDU_size = sm->client_SDU_size; invoke->u.S_MethodInvoke_Ind.session_id = msm->session_id; msm->invoke = invoke; }, HOLDING) ROW(HOLDING, Release_Event, 1, { /* S-MethodInvoke.ind */ dispatch_to_appl(msm->invoke); msm->invoke = NULL; }, REQUESTING) ROW(HOLDING, Abort_Event, 1, { /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ /* Tr-Abort.req(abort reason) the method */ method_abort(msm, e->reason); }, NULL_METHOD) ROW(HOLDING, TR_Abort_Ind, e->abort_code == WSP_ABORT_DISCONNECT, { WAPEvent *wsp_event; /* Disconnect the session */ wsp_event = wap_event_create(Disconnect_Event); wsp_event->u.Disconnect_Event.session_handle = msm->session_id; /* We put this on the queue instead of doing it right away, * because the session machine is currently our caller and * we don't want to recurse. We put it in the front of * the queue because the state machine definitions expect * an event to be handled completely before the next is * started. */ gwlist_insert(queue, 0, wsp_event); }, HOLDING) ROW(HOLDING, TR_Abort_Ind, e->abort_code == WSP_ABORT_SUSPEND, { WAPEvent *wsp_event; /* Suspend the session */ wsp_event = wap_event_create(Suspend_Event); wsp_event->u.Suspend_Event.session_handle = msm->session_id; /* See story for Disconnect, above */ gwlist_insert(queue, 0, wsp_event); }, HOLDING) ROW(HOLDING, TR_Abort_Ind, e->abort_code != WSP_ABORT_DISCONNECT && e->abort_code != WSP_ABORT_SUSPEND, { /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ }, NULL_METHOD) ROW(REQUESTING, S_MethodInvoke_Res, 1, { WAPEvent *wtp_event; /* Send TR-Invoke.res to WTP */ wtp_event = wap_event_create(TR_Invoke_Res); wtp_event->u.TR_Invoke_Res.handle = msm->transaction_id; dispatch_to_wtp_resp(wtp_event); }, PROCESSING) /* MISSING: REQUESTING, S-MethodAbort.req */ ROW(REQUESTING, Abort_Event, 1, { /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ /* TR-Abort.req(abort reason) the method */ method_abort(msm, e->reason); /* S-MethodAbort.ind(abort reason) */ indicate_method_abort(msm, e->reason); }, NULL_METHOD) ROW(REQUESTING, TR_Abort_Ind, e->abort_code == WSP_ABORT_DISCONNECT, { WAPEvent *wsp_event; /* Disconnect the session */ wsp_event = wap_event_create(Disconnect_Event); wsp_event->u.Disconnect_Event.session_handle = msm->session_id; gwlist_insert(queue, 0, wsp_event); }, REQUESTING) ROW(REQUESTING, TR_Abort_Ind, e->abort_code == WSP_ABORT_SUSPEND, { WAPEvent *wsp_event; /* Suspend the session */ wsp_event = wap_event_create(Suspend_Event); wsp_event->u.Suspend_Event.session_handle = msm->session_id; gwlist_insert(queue, 0, wsp_event); }, REQUESTING) ROW(REQUESTING, TR_Abort_Ind, e->abort_code != WSP_ABORT_DISCONNECT && e->abort_code != WSP_ABORT_SUSPEND, { /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ /* S-MethodAbort.ind(abort reason) */ indicate_method_abort(msm, e->abort_code); }, NULL_METHOD) ROW(PROCESSING, S_MethodResult_Req, 1, { WAPEvent *wtp_event; WSP_PDU *new_pdu; /* TR-Result.req */ new_pdu = wsp_pdu_create(Reply); new_pdu->u.Reply.status = wsp_convert_http_status_to_wsp_status(e->status); new_pdu->u.Reply.headers = wsp_headers_pack(e->response_headers, 1, sm->encoding_version); new_pdu->u.Reply.data = octstr_duplicate(e->response_body); /* Send TR-Result.req to WTP */ wtp_event = wap_event_create(TR_Result_Req); wtp_event->u.TR_Result_Req.user_data = wsp_pdu_pack(new_pdu); wtp_event->u.TR_Result_Req.handle = msm->transaction_id; dispatch_to_wtp_resp(wtp_event); wsp_pdu_destroy(new_pdu); }, REPLYING) /* MISSING: PROCESSING, S-MethodAbort.req */ ROW(PROCESSING, Abort_Event, 1, { /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ /* TR-Abort.req(abort reason) the method */ method_abort(msm, e->reason); /* S-MethodAbort.ind(abort reason) */ indicate_method_abort(msm, e->reason); }, NULL_METHOD) ROW(PROCESSING, TR_Abort_Ind, e->abort_code == WSP_ABORT_DISCONNECT, { WAPEvent *wsp_event; /* Disconnect the session */ wsp_event = wap_event_create(Disconnect_Event); wsp_event->u.Disconnect_Event.session_handle = msm->session_id; gwlist_insert(queue, 0, wsp_event); }, PROCESSING) ROW(PROCESSING, TR_Abort_Ind, e->abort_code == WSP_ABORT_SUSPEND, { WAPEvent *wsp_event; /* Suspend the session */ wsp_event = wap_event_create(Suspend_Event); wsp_event->u.Suspend_Event.session_handle = msm->session_id; gwlist_insert(queue, 0, wsp_event); }, PROCESSING) ROW(PROCESSING, TR_Abort_Ind, e->abort_code != WSP_ABORT_DISCONNECT && e->abort_code != WSP_ABORT_SUSPEND, { /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ /* S-MethodAbort.ind(abort reason) */ indicate_method_abort(msm, e->abort_code); }, NULL_METHOD) /* MISSING: REPLYING, S-MethodAbort.req */ ROW(REPLYING, Abort_Event, 1, { /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ /* TR-Abort.req(abort reason) the method */ method_abort(msm, e->reason); /* S-MethodAbort.ind(abort reason) */ indicate_method_abort(msm, e->reason); }, NULL_METHOD) ROW(REPLYING, TR_Result_Cnf, 1, { WAPEvent *new_event; /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ /* S-MethodResult.cnf */ /* we don't do acknowledgement headers */ new_event = wap_event_create(S_MethodResult_Cnf); new_event->u.S_MethodResult_Cnf.server_transaction_id = msm->transaction_id; new_event->u.S_MethodResult_Cnf.session_id = msm->session_id; dispatch_to_appl(new_event); }, NULL_METHOD) ROW(REPLYING, TR_Abort_Ind, e->abort_code == WSP_ABORT_DISCONNECT, { WAPEvent *wsp_event; /* Disconnect the session */ wsp_event = wap_event_create(Disconnect_Event); wsp_event->u.Disconnect_Event.session_handle = msm->session_id; gwlist_insert(queue, 0, wsp_event); }, REPLYING) ROW(REPLYING, TR_Abort_Ind, e->abort_code == WSP_ABORT_SUSPEND, { WAPEvent *wsp_event; /* Suspend the session */ wsp_event = wap_event_create(Suspend_Event); wsp_event->u.Suspend_Event.session_handle = msm->session_id; gwlist_insert(queue, 0, wsp_event); }, REPLYING) ROW(REPLYING, TR_Abort_Ind, e->abort_code != WSP_ABORT_DISCONNECT && e->abort_code != WSP_ABORT_SUSPEND, { /* Decrement N_Methods */ /* we don't keep track of N_Methods because it's unlimited */ /* S-MethodAbort.ind(abort reason) */ indicate_method_abort(msm, e->abort_code); }, NULL_METHOD) #undef ROW #undef STATE_NAME gateway-1.4.5/wap/wtls_pdusupport.h0000644000175000017500000001736411443121512016127 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2008 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. * * Nikos Balkanas, Inaccess Networks (2009) */ #ifndef PDUSUPPORT_H #define PDUSUPPORT_H int pack_int16(Octstr *data, long charpos, int i); int pack_int32(Octstr *data, long charpos, long i); int pack_octstr(Octstr *data, long charpos, Octstr *opaque); int pack_octstr16(Octstr *data, long charpos, Octstr *opaque); int pack_octstr_fixed(Octstr *data, long charpos, Octstr *opaque); int pack_random(Octstr *data, long charpos, Random *random); int pack_dhparams(Octstr *data, long charpos, DHParameters *dhparams); int pack_ecparams(Octstr *data, long charpos, ECParameters *ecparams); int pack_param_spec(Octstr *data, long charpos, ParameterSpecifier *pspec); int pack_public_key(Octstr *data, long charpos, PublicKey *key, PublicKeyType key_type); int pack_rsa_pubkey(Octstr *data, long charpos, RSAPublicKey *key); int pack_dh_pubkey(Octstr *data, long charpos, DHPublicKey *key); int pack_ec_pubkey(Octstr *data, long charpos, ECPublicKey *key); int pack_rsa_secret(Octstr *data, long charpos, RSASecret *secret); int pack_rsa_encrypted_secret(Octstr *data, long charpos, RSAEncryptedSecret *secret); int pack_key_exchange_id(Octstr *data, long charpos, KeyExchangeId *keyexid); int pack_array(Octstr *data, long charpos, List *array); int pack_key_list(Octstr *data, long charpos, List *key_list); int pack_ciphersuite_list(Octstr *data, long charpos, List *ciphersuites); int pack_compression_method_list(Octstr *data, long charpos, List *compmethod_list); int pack_identifier(Octstr *data, long charpos, Identifier *ident); int pack_signature(Octstr *data, long charpos, Signature *sig); int pack_wtls_certificate(Octstr *data, long charpos, WTLSCertificate *cert); int unpack_int16(Octstr *data, long *charpos); long unpack_int32(Octstr *data, long *charpos); Octstr * unpack_octstr(Octstr *data, long *charpos); Octstr * unpack_octstr16(Octstr *data, long *charpos); Octstr * unpack_octstr_fixed(Octstr *data, long *charpos, long length); Random * unpack_random(Octstr *data, long *charpos); DHParameters * unpack_dhparams(Octstr *data, long *charpos); ECParameters * unpack_ecparams(Octstr *data, long *charpos); ParameterSpecifier * unpack_param_spec(Octstr *data, long *charpos); PublicKey * unpack_public_key(Octstr *data, long *charpos, PublicKeyType key_type); RSAPublicKey * unpack_rsa_pubkey(Octstr *data, long *charpos); DHPublicKey * unpack_dh_pubkey(Octstr *data, long *charpos); ECPublicKey * unpack_ec_pubkey(Octstr *data, long *charpos); RSASecret * unpack_rsa_secret(Octstr *data, long *charpos); RSAEncryptedSecret * unpack_rsa_encrypted_secret(Octstr *data, long *charpos); KeyExchangeId * unpack_key_exchange_id(Octstr *data, long *charpos); List * unpack_array(Octstr *data, long *charpos); List * unpack_ciphersuite_list(Octstr *data, long *charpos); List * unpack_key_list(Octstr *data, long *charpos); List * unpack_compression_method_list(Octstr *data, long *charpos); Identifier * unpack_identifier(Octstr *data, long *charpos); Signature * unpack_signature(Octstr *data, long *charpos); WTLSCertificate * unpack_wtls_certificate(Octstr *data, long *charpos); void dump_int16(char *dbg, int level, int i); void dump_int32(char *dbg, int level, long i); void dump_octstr(char *dbg, int level, Octstr *opaque); void dump_octstr16(char *dbg, int level, Octstr *opaque); void dump_octstr_fixed(char *dbg, int level, Octstr *opaque); void dump_random(char *dbg, int level, Random *random); void dump_dhparams(char *dbg, int level, DHParameters *dhparams); void dump_ecparams(char *dbg, int level, ECParameters *ecparams); void dump_param_spec(char *dbg, int level, ParameterSpecifier *pspec); void dump_public_key(char *dbg, int level, PublicKey *key, PublicKeyType key_type); void dump_rsa_pubkey(char *dbg, int level, RSAPublicKey *key); void dump_dh_pubkey(char *dbg, int level, DHPublicKey *key); void dump_ec_pubkey(char *dbg, int level, ECPublicKey *key); void dump_rsa_secret(char *dbg, int level, RSASecret *secret); void dump_rsa_encrypted_secret(char *dbg, int level, RSAEncryptedSecret *secret); void dump_key_exchange_id(char *dbg, int level, KeyExchangeId *keyexid); void dump_array(char *dbg, int level, List *array); void dump_key_list(char *dbg, int level, List *key_list); void dump_ciphersuite_list(char *dbg, int level, List *ciphersuites); void dump_compression_method_list(char *dbg, int level, List *compmethod_list); void dump_identifier(char *dbg, int level, Identifier *ident); void dump_signature(char *dbg, int level, Signature *sig); void dump_wtls_certificate(char *dbg, int level, WTLSCertificate *cert); void destroy_rsa_pubkey(RSAPublicKey *key); void destroy_array(List *array); void destroy_identifier(Identifier *ident); void destroy_random(Random *random); void destroy_key_list(List *key_list); void destroy_ciphersuite_list(List *ciphersuites); void destroy_compression_method_list(List *compmethod_list); void destroy_wtls_certificate(WTLSCertificate *cert); void destroy_param_spec(ParameterSpecifier *pspec); void destroy_dh_pubkey(DHPublicKey *key); void destroy_ec_pubkey(ECPublicKey *key); void destroy_rsa_encrypted_secret(RSAEncryptedSecret *secret); #endif /* PDUSUPPORT_H */ gateway-1.4.5/wap/wtls-secmgr.c0000644000175000017500000001571013227613126015075 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/wtls-secmgr.c - wapbox wtls security manager * * The security manager's interface consists of two functions: * * wtls_secmgr_start() * This starts the security manager thread. * * wtls_secmgr_dispatch(event) * This adds a new event to the security manager's event * queue. * * The wtls security manager is a thread that reads events from its event * queue, and feeds back events to the WTLS layer. Here is where various * approvals or rejections are made to requested security settings. * */ #include #include "gwlib/gwlib.h" #if (HAVE_WTLS_OPENSSL) #include "wtls.h" /* * Give the status the module: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum { limbo, running, terminating } run_status = limbo; /* * The queue of incoming events. */ static List *secmgr_queue = NULL; /* * Private functions. */ static void main_thread(void *); /* * Public functions. */ void wtls_secmgr_init(void); void wtls_secmgr_shutdown(void); void wtls_secmgr_dispatch(WAPEvent *event); long wtls_secmgr_get_load(void); /*********************************************************************** * The public interface to the application layer. */ void wtls_secmgr_init(void) { gw_assert(run_status == limbo); secmgr_queue = gwlist_create(); gwlist_add_producer(secmgr_queue); run_status = running; gwthread_create(main_thread, NULL); } void wtls_secmgr_shutdown(void) { gw_assert(run_status == running); gwlist_remove_producer(secmgr_queue); run_status = terminating; gwthread_join_every(main_thread); gwlist_destroy(secmgr_queue, wap_event_destroy_item); } void wtls_secmgr_dispatch(WAPEvent *event) { gw_assert(run_status == running); gwlist_produce(secmgr_queue, event); } long wtls_secmgr_get_load(void) { gw_assert(run_status == running); return gwlist_len(secmgr_queue); } /*********************************************************************** * Private functions. */ static void main_thread(void *arg) { WAPEvent *ind, *res, *req, *term; while (run_status == running && (ind = gwlist_consume(secmgr_queue)) != NULL) { switch (ind->type) { case SEC_Create_Ind: /* Process the cipherlist */ /* Process the MAClist */ /* Process the PKIlist */ /* Dispatch a SEC_Create_Res */ res = wap_event_create(SEC_Create_Res); res->u.SEC_Create_Res.addr_tuple = wap_addr_tuple_duplicate(ind->u.SEC_Create_Ind.addr_tuple); wtls_dispatch_event(res); debug("wtls_secmgr : main_thread", 0,"Dispatching SEC_Create_Res event"); /* Dispatch a SEC_Exchange_Req or maybe a SEC_Commit_Req */ req = wap_event_create(SEC_Exchange_Req); req->u.SEC_Exchange_Req.addr_tuple = wap_addr_tuple_duplicate(ind->u.SEC_Create_Ind.addr_tuple); wtls_dispatch_event(req); debug("wtls_secmgr : main_thread", 0,"Dispatching SEC_Exchange_Req event"); wap_event_destroy(ind); break; case SEC_Terminate_Req: /* Dispatch a SEC_Terminate_Req */ term = wap_event_create(SEC_Terminate_Req); term->u.SEC_Terminate_Req.addr_tuple = wap_addr_tuple_duplicate(ind->u.SEC_Create_Ind.addr_tuple); term->u.SEC_Terminate_Req.alert_desc = 0; term->u.SEC_Terminate_Req.alert_level = 3; wtls_dispatch_event(term); default: panic(0, "WTLS-secmgr: Can't handle %s event", wap_event_name(ind->type)); break; } } } #endif gateway-1.4.5/wap/timers.h0000644000175000017500000001307313227613126014136 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * timers.h - interface to timers and timer sets. * * Timers can be set to elapse after a specified number of seconds * (the "interval"). They can be stopped before elapsing, and the * interval can be changed. * * An "output list" is defined for each timer. When it elapses, an * event is generated on this list. The event may be removed from * the output list if the timer is destroyed or extended before the * event is consumed. * * The event to use when a timer elapses is provided by the caller. * The timer module will "own" it, and be responsible for deallocation. * This will be true until the event has been consumed from the output * list (at which point it is owned by the consuming thread). * While the event is on the output list, it is in a gray area, because * the timer module might still take it back. This won't be a problem * as long as you access the event only by consuming it. * * Timers work best if the thread that manipulates the timer (the * "calling thread") is the same thread that consumes the output list. * This way, it can be guaranteed that the calling thread will not * see a timer elapse after being destroyed, or while being extended, * because the elapse event will be deleted during such an operation. * * The timer_* functions have been renamed to gwtimer_* to avoid * a name conflict on Solaris systems. */ #ifndef TIMERS_H #define TIMERS_H #include "gwlib/gwlib.h" #include "wap_events.h" typedef struct Timer Timer; /* * Start up the timer system. * Can be called more than once, in which case multiple shutdowns are * also required. */ void timers_init(void); /* * Stop all timers and shut down the timer system. */ void timers_shutdown(void); /* * Create a timer and tell it to use the specified output list when * it elapses. Do not start it yet. Return the new timer. */ Timer *gwtimer_create(List *outputlist); /* * Destroy this timer and free its resources. Stop it first, if needed. */ void gwtimer_destroy(Timer *timer); /* * Make the timer elapse after 'interval' seconds, at which time it * will push event 'event' on the output list defined for its timer set. * - If the timer was already running, these parameters will override * its old settings. * - If the timer has already elapsed, try to remove its event from * the output list. * If this is not the first time the timer was started, the event * pointer is allowed to be NULL. In that case the event pointer * from the previous call to timer_start for this timer is re-used. * NOTE: Each timer must have a unique event pointer. The caller must * create the event, and passes control of it to the timer module with * this call. */ void gwtimer_start(Timer *timer, int interval, WAPEvent *event); /* * Stop this timer. If it has already elapsed, try to remove its * event from the output list. */ void gwtimer_stop(Timer *timer); #endif gateway-1.4.5/wap/wtp.h0000644000175000017500000001317313227613126013446 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp.h - WTP implementation general header, common things for the iniator * and the responder. */ #ifndef WTP_H #define WTP_H #include #include #include #include #include "gwlib/gwlib.h" #include "wap_addr.h" #include "wap_events.h" /* * Use this structure for storing segments to be reassembled */ typedef struct WTPSegment WTPSegment; /* * For removing the magic */ enum { NUMBER_OF_ABORT_TYPES = 2, NUMBER_OF_ABORT_REASONS = 10, NUMBER_OF_TRANSACTION_CLASSES = 3 }; /* * For now, timers are defined. They will depend on bearer information fetched * from address (or from a header field of the protocol speaking with the * bearerbox). For suggested timers, see WTP, Appendix A. */ enum { L_A_WITH_USER_ACK = 4, L_R_WITH_USER_ACK = 7, S_R_WITHOUT_USER_ACK = 3, S_R_WITH_USER_ACK = 4, G_R_WITHOUT_USER_ACK = 3, G_R_WITH_USER_ACK = 3, W_WITH_USER_ACK = 30 }; /* * Maximum values for counters (for retransmissions and acknowledgement waiting * periods) */ enum { AEC_MAX = 6, MAX_RCR = 8 }; /* * Types of acknowledgement PDU (normal acknowledgement or tid verification) */ enum { ACKNOWLEDGEMENT = 0, TID_VERIFICATION = 1 }; /* * Who is aborting (WTP or WTP user) */ enum { PROVIDER = 0x00, USER = 0x01 }; /* * WTP abort types (i.e., provider abort codes defined by WAP) */ enum { UNKNOWN = 0x00, PROTOERR = 0x01, INVALIDTID = 0x02, NOTIMPLEMENTEDCL2 = 0x03, NOTIMPLEMENTEDSAR = 0x04, NOTIMPLEMENTEDUACK = 0x05, WTPVERSIONZERO = 0x06, CAPTEMPEXCEEDED = 0x07, NORESPONSE = 0x08, MESSAGETOOLARGE = 0x09, NOTIMPLEMENTEDESAR = 0x0A }; /* * Transaction classes */ enum { TRANSACTION_CLASS_0 = 0, TRANSACTION_CLASS_1 = 1, TRANSACTION_CLASS_2 = 2 }; /* * Types of acknowledgement */ enum { PROVIDER_ACKNOWLEDGEMENT = 0, USER_ACKNOWLEDGEMENT = 1 }; /* * Who is indicating, wtp initiator or responder. */ enum { INITIATOR_INDICATION = 0, RESPONDER_INDICATION = 1 }; enum { TPI_ERROR = 0, TPI_INFO = 1, TPI_OPTION = 2, TPI_PSN = 3, TPI_SDU_BOUNDARY = 4, TPI_FRAME_BOUNDARY = 5 }; /* * Responder set first tid, initiator not. So all tids send by initiator are * greater than 2**15. */ #define INITIATOR_TID_LIMIT (1 << 15) /* * Transaction is identified by the address four-tuple and tid. */ struct machine_pattern { WAPAddrTuple *tuple; long tid; long mid; }; typedef struct machine_pattern machine_pattern; /* * Handles possible concatenated messages. Returns a list of wap events, * consisting of these events. */ List *wtp_unpack_wdp_datagram(WAPEvent *datagram); /* * Responder set the first bit of the tid field. If we get a packet from the * responder, we are the initiator. * * Returns 1 for responder, 0 for iniator and -1 for error. */ int wtp_event_is_for_responder(WAPEvent *event); #endif gateway-1.4.5/wap/wtp_tid.c0000644000175000017500000002137713227613126014306 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_tid.c - Implementation of WTP tid validation tests. Note that only * WTP responder uses tid validation. * * By Aarno Syvänen for Wapit Ltd. */ #include "gwlib/gwlib.h" #include "wtp_tid.h" /* * Constants used for defining the tid cache status */ enum { no_cache = -1, iniatilised = -2, not_iniatilised = -3, cached = 0 }; /* * Global data structure: * * Tid cache is implemented by using a library object List */ static List *tid_cache = NULL; /***************************************************************************** * Prototypes of internal functions */ static WTPCached_tid *cache_item_create_empty(void); static void cache_item_destroy(void *item); /* static void cache_item_dump(WTPCached_tid *item); */ static void add_tid(WTPRespMachine *resp_machine, long tid); static void set_tid_by_item(WTPCached_tid *item, long tid); static int tid_in_window(long rcv_tid, long last_tid); static WTPCached_tid *tid_cached(WTPRespMachine *resp_machine); /****************************************************************************** * * External functions: */ void wtp_tid_cache_init(void) { tid_cache = gwlist_create(); } void wtp_tid_cache_shutdown(void) { debug("wap.wtp_tid", 0, "%ld items left in the tid cache", gwlist_len(tid_cache)); gwlist_destroy(tid_cache, cache_item_destroy); } /* * Tid verification is invoked, when tid_new flag of the incoming message is * on. It is not, if the initiator is not yet cached. If initiator is cached, * the received tid is stored. */ int wtp_tid_is_valid(WAPEvent *event, WTPRespMachine *resp_machine) { long rcv_tid = -1, last_tid = -1; WTPCached_tid *item = NULL; #if 0 debug("wap.wtp.tid", 0, "starting validation"); #endif rcv_tid = resp_machine->tid; if (!event->u.RcvInvoke.tid_new) { /* * First we check whether the current initiator has a cache item for it. */ if ((item = tid_cached(resp_machine)) == NULL) { if (event->u.RcvInvoke.no_cache_supported) return no_cached_tid; else { #if 0 debug("wap.wtp.tid", 0, "empty cache"); #endif add_tid(resp_machine, rcv_tid); return ok; } } /* * If it has, we check if the message is a duplicate or has tid wrapped up * confusingly. */ last_tid = item->tid; if (tid_in_window(rcv_tid, last_tid) == 0){ info(0, "WTP_TID: tid out of the window"); return fail; } else { #if 0 debug("wap.wtp.tid", 0, "tid in the window"); #endif set_tid_by_item(item, rcv_tid); return ok; } } else { info(0, "WTP_TID: tid_new flag on"); rcv_tid = 0; if (item == NULL) { add_tid(resp_machine, rcv_tid); } else { set_tid_by_item(item, rcv_tid); } return fail; } /* * This return is unnecessary but the compiler demands it */ return fail; } /* * Changes tid value used by an existing initiator. Input responder machine * and the new tid. */ void wtp_tid_set_by_machine(WTPRespMachine *resp_machine, long tid) { WTPCached_tid *item = NULL; item = tid_cached(resp_machine); set_tid_by_item(item, tid); } /***************************************************************************** * * Internal functions: * * Checks whether the received tid is inside the window of acceptable ones. * The size of the window is set by the constant WTP_TID_WINDOW_SIZE (half of * the tid space is the recommended value). * * Inputs: stored tid, received tid. Output 0, if received tid is outside the * window, 1, if it is inside. */ static int tid_in_window(long rcv_tid, long last_tid) { #if 0 debug("wap.wtp.tid", 0, "tids were rcv_tid, %ld and last_tid, %ld" " and test window %ld", rcv_tid, last_tid, WTP_TID_WINDOW_SIZE); #endif if (last_tid == rcv_tid) { return 0; } if (rcv_tid > last_tid) { if (abs(rcv_tid - last_tid) <= WTP_TID_WINDOW_SIZE) { return 1; } else { return 0; } } if (rcv_tid < last_tid) { if (abs(rcv_tid - last_tid) >= WTP_TID_WINDOW_SIZE){ return 1; } else { return 0; } } /* * Following return is unnecessary but our compiler demands it */ return 0; } static WTPCached_tid *cache_item_create_empty(void) { WTPCached_tid *item = NULL; item = gw_malloc(sizeof(*item)); item->addr_tuple = NULL; item->tid = 0; return item; } static void cache_item_destroy(void *p) { WTPCached_tid *item; item = p; wap_addr_tuple_destroy(item->addr_tuple); gw_free(item); } /* * Checking whether there is an item stored for a specific initiator. Receives * address quadruplet - the identifier it uses - from object WTPRespMachine. * Ditto tid. Returns the item or NULL, if there is not one. Initiator is * identified by the address four-tuple. */ static int tid_is_cached(void *a, void *b) { WAPAddrTuple *initiator_profile; WTPCached_tid *item; item = a; initiator_profile = b; return wap_addr_tuple_same(item->addr_tuple, initiator_profile); } static WTPCached_tid *tid_cached(WTPRespMachine *resp_machine) { WTPCached_tid *item = NULL; item = gwlist_search(tid_cache, resp_machine->addr_tuple, tid_is_cached); return item; } /* * Adds an item to the tid cache, one item per every initiator. Initiator is * identified by the address four-tuple, fetched from a wtp responder machine. */ static void add_tid(WTPRespMachine *resp_machine, long tid) { WTPCached_tid *new_item = NULL; new_item = cache_item_create_empty(); new_item->addr_tuple = wap_addr_tuple_duplicate(resp_machine->addr_tuple); new_item->tid = tid; gwlist_append(tid_cache, new_item); } /* * Set tid for an existing initiator. Input a cache item and the new tid. */ static void set_tid_by_item(WTPCached_tid *item, long tid) { gwlist_lock(tid_cache); item->tid = tid; gwlist_unlock(tid_cache); } gateway-1.4.5/wap/wtp_resp.h0000644000175000017500000001064613227613126014501 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * WTP responder header * * Aarno Syvänen for Wapit Ltd */ #ifndef WTP_RESPONDER_H #define WTP_RESPONDER_H typedef struct WTPRespMachine WTPRespMachine; #include "gwlib/gwlib.h" #include "wap_events.h" #include "timers.h" typedef struct sar_info_t { int sar_psn; Octstr *sar_data; } sar_info_t; /* * Structure to keep SAR data during transmission */ typedef struct WTPSARData { int nsegm; /* number of the last segment, i.e. total number - 1 */ int csegm; /* last segment confirmed by recipient */ int lsegm; /* last sent segment */ int tr; /* if current psn is gtr or ttr */ Octstr *data; } WTPSARData; /* * Maximum segment size. (Nokia WAP GW uses the size of 576, * but mobiles use 1,5K size). */ #define SAR_SEGM_SIZE 1400 #define SAR_GROUP_LEN 3 /* * Responder machine states and responder WTP machine. * See file wtp_resp_state-decl.h for comments. Note that we must define macro * ROW to produce an empty string. */ enum resp_states { #define STATE_NAME(state) state, #define ROW(state, event, condition, action, next_state) #include "wtp_resp_states.def" resp_states_count }; typedef enum resp_states resp_states; /* * See files wtp_resp_machine-decl.h and for comments. We define one macro for * every separate type. */ struct WTPRespMachine { unsigned long mid; #define INTEGER(name) int name; #define TIMER(name) Timer *name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define ENUM(name) resp_states name; #define EVENT(name) WAPEvent *name; #define LIST(name) List *name; #define SARDATA(name) WTPSARData *name; #define MACHINE(field) field #include "wtp_resp_machine.def" }; #endif gateway-1.4.5/wap/wsp_server_session_states.def0000644000175000017500000007243713227613126020500 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_server_session_states.def - states for WSP session state machines * * Macro calls to generate rows of the state table. See the documentation for * guidance how to use and update these. * * Note that `NULL' state is renamed to `NULL_SESSION' because NULL is * reserved by C. * * Lars Wirzenius */ STATE_NAME(NULL_SESSION) STATE_NAME(CONNECTING) STATE_NAME(TERMINATING) STATE_NAME(CONNECTING_2) STATE_NAME(CONNECTED) STATE_NAME(SUSPENDED) STATE_NAME(RESUMING) STATE_NAME(RESUMING_2) ROW(NULL_SESSION, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Connect, { WAPEvent *new_event; WAPEvent *wtp_event; /* Send TR-Invoke.res to WTP */ wtp_event = wap_event_create(TR_Invoke_Res); wtp_event->u.TR_Invoke_Res.handle = e->handle; dispatch_to_wtp_resp(wtp_event); /* Assign a session ID for this session. We do this * early, instead of in the CONNECTING state, because * we want to use the session id as a way for the * application layer to refer back to this machine. */ sm->session_id = next_wsp_session_id(); if (pdu->u.Connect.capabilities_len > 0) { unsigned long sdu; sm->request_caps = wsp_cap_unpack_list( pdu->u.Connect.capabilities); if (wsp_cap_get_client_sdu(sm->request_caps,&sdu)) { sm->client_SDU_size = sdu; } } else { sm->request_caps = gwlist_create(); } if (pdu->u.Connect.headers_len > 0) { List *hdrs; Octstr *encoding; hdrs = wsp_headers_unpack(pdu->u.Connect.headers, 0); http_header_pack(hdrs); gw_assert(sm->http_headers == NULL); sm->http_headers = hdrs; /* * Get WSP encoding version if provided by device and remember in * session machine for later use in encoding tokenized values. */ encoding = http_header_value(sm->http_headers, octstr_imm("Encoding-Version")); if (encoding != NULL) { debug("wsp",0,"WSP: Session machine: Encoding-Version: %s", octstr_get_cstr(encoding)); sm->encoding_version = wsp_encoding_string_to_version(encoding); } else { /* WAP-230-WSP-20010705-a, section 8.4.2.70, page 97 defines * by a MUST argument that a non-present Encoding-Version header * should be interpreted as WSP 1.2 compliant. */ sm->encoding_version = WSP_1_2; } octstr_destroy(encoding); } /* Send S-Connect.ind to application layer */ new_event = wap_event_create(S_Connect_Ind); new_event->u.S_Connect_Ind.addr_tuple = wap_addr_tuple_duplicate(e->addr_tuple); new_event->u.S_Connect_Ind.client_headers = http_header_duplicate(sm->http_headers); new_event->u.S_Connect_Ind.requested_capabilities = wsp_cap_duplicate_list(sm->request_caps); new_event->u.S_Connect_Ind.session_id = sm->session_id; dispatch_to_appl(new_event); }, CONNECTING) ROW(CONNECTING, S_Connect_Res, 1, { WAPEvent *wtp_event; Octstr *ospdu; sm->reply_caps = wsp_cap_duplicate_list( e->negotiated_capabilities); /* Send Disconnect event to existing sessions for client. */ disconnect_other_sessions(sm); /* Assign a Session_ID for this session. */ /* We've already done that in the NULL_STATE. */ /* TR-Result.req(ConnectReply) */ ospdu = make_connectreply_pdu(sm); wtp_event = wap_event_create(TR_Result_Req); wtp_event->u.TR_Result_Req.user_data = ospdu; wtp_event->u.TR_Result_Req.handle = sm->connect_handle; dispatch_to_wtp_resp(wtp_event); /* Release all method transactions in HOLDING state. */ release_holding_methods(sm); }, CONNECTING_2) /* MISSING: CONNECTING, S_Disconnect_Req, reason == 301 (moved permanently) or * 302 (moved temporarily). */ /* MISSING: CONNECTING, S_Disconnect_Req, reason == anything else */ ROW(CONNECTING, Disconnect_Event, 1, { /* TR-Abort.req(DISCONNECT) the Connect transaction */ send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle); /* Abort(DISCONNECT) all method transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(CONNECTING, Suspend_Event, 1, { /* TR-Abort.req(DISCONNECT) the Connect transaction */ send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle); /* Abort(DISCONNECT) all method transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(SUSPEND) */ indicate_disconnect(sm, WSP_ABORT_SUSPEND); }, NULL_SESSION) ROW(CONNECTING, TR_Invoke_Ind, e->tcl == 2 && (pdu->type == Get || pdu->type == Post), { WSPMethodMachine *msm; /* Start new method transaction */ msm = method_machine_create(sm, e->handle); /* Hand off the event to the new method machine */ handle_method_event(sm, msm, current_event, pdu); }, CONNECTING) ROW(CONNECTING, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Resume, { /* TR-Abort.req(DISCONNECT) the TR-Invoke */ send_abort(WSP_ABORT_DISCONNECT, e->handle); }, CONNECTING) ROW(CONNECTING, TR_Abort_Ind, e->handle == sm->connect_handle, { /* Abort(DISCONNECT) all method transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(abort reason) */ indicate_disconnect(sm, e->abort_code); }, NULL_SESSION) ROW(CONNECTING, TR_Abort_Ind, e->handle != sm->connect_handle, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); }, CONNECTING) ROW(TERMINATING, Disconnect_Event, 1, { /* TR-Abort.req(DISCONNECT) remaining transport transaction */ send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle); }, NULL_SESSION) ROW(TERMINATING, Suspend_Event, 1, { /* TR-Abort.req(SUSPEND) remaining transport transaction */ send_abort(WSP_ABORT_SUSPEND, sm->connect_handle); }, NULL_SESSION) ROW(TERMINATING, TR_Result_Cnf, 1, { /* Ignore */ }, NULL_SESSION) ROW(TERMINATING, TR_Abort_Ind, 1, { /* Ignore */ }, NULL_SESSION) /* MISSING: CONNECTING_2, S-Disconnect.req */ ROW(CONNECTING_2, Disconnect_Event, 1, { /* TR-Abort.req(DISCONNECT) the Connect transaction */ send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle); /* Abort(DISCONNECT) all method and push transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(CONNECTING_2, S_MethodInvoke_Res, 1, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->server_transaction_id); handle_method_event(sm, msm, current_event, pdu); }, CONNECTING_2) ROW(CONNECTING_2, S_MethodResult_Req, 1, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->server_transaction_id); handle_method_event(sm, msm, current_event, pdu); }, CONNECTING_2) ROW(CONNECTING_2, S_Push_Req, 1, { WSP_PDU *pdu; pdu = make_push_pdu(current_event); send_invoke(sm, pdu, current_event, TRANSACTION_CLASS_0); }, CONNECTING_2) ROW(CONNECTING_2, S_ConfirmedPush_Req, 1, { /* Start new push transaction*/ WSPPushMachine *spm; spm = push_machine_create(sm, e->server_push_id); handle_push_event(sm, spm, current_event); }, CONNECTING_2) ROW(CONNECTING_2, Suspend_Event, !resume_enabled, { /* Session Resume facility disabled */ /* TR-Abort.req(DISCONNECT) the Connect transaction */ send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle); /* Abort(DISCONNECT) all method and push transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(SUSPEND) */ indicate_disconnect(sm, WSP_ABORT_SUSPEND); }, NULL_SESSION) ROW(CONNECTING_2, Suspend_Event, resume_enabled, { /* Session Resume facility enabled */ /* TR-Abort.req(SUSPEND) the Connect transaction */ send_abort(WSP_ABORT_SUSPEND, sm->connect_handle); /* Abort(SUSPEND) all method and push transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(SUSPEND) */ indicate_suspend(sm, WSP_ABORT_SUSPEND); }, SUSPENDED) ROW(CONNECTING_2, TR_Invoke_Ind, e->tcl == 2 && (pdu->type == Get || pdu->type == Post), { WSPMethodMachine *msm; WAPEvent *new_event; /* Start new method transaction */ msm = method_machine_create(sm, e->handle); /* Hand off the event to the new method machine */ handle_method_event(sm, msm, current_event, pdu); /* Release the new method transaction */ new_event = wap_event_create(Release_Event); handle_method_event(sm, msm, new_event, NULL); wap_event_destroy(new_event); }, CONNECTING_2) ROW(CONNECTING_2, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Resume && !resume_enabled, { /* Resume facility disabled */ /* TR-Abort.req(DISCONNECT) the TR-Invoke */ send_abort(WSP_ABORT_DISCONNECT, e->handle); }, CONNECTING_2) ROW(CONNECTING_2, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Resume && resume_enabled, { /* Resume facility enabled */ WAPEvent *wtp_event; List *new_headers; /* TR-Invoke.res */ wtp_event = wap_event_create(TR_Invoke_Res); wtp_event->u.TR_Invoke_Res.handle = e->handle; dispatch_to_wtp_resp(wtp_event); /* TR-Abort.req(RESUME) the Connect transaction */ send_abort(WSP_ABORT_RESUME, sm->connect_handle); /* Abort(RESUME) all method and push transactions */ abort_methods(sm, WSP_ABORT_RESUME); /* S-Suspend.ind(RESUME) */ indicate_suspend(sm, WSP_ABORT_RESUME); /* S-Resume.ind */ new_headers = unpack_new_headers(sm, pdu->u.Resume.headers); indicate_resume(sm, e->addr_tuple, new_headers); http_destroy_headers(new_headers); sm->resume_handle = e->handle; }, RESUMING) ROW(CONNECTING_2, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Disconnect, { /* TR-Abort.req(DISCONNECT) the Connect transaction */ send_abort(WSP_ABORT_DISCONNECT, sm->connect_handle); /* Abort(DISCONNECT) all method and push transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(CONNECTING_2, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Suspend && resume_enabled, { /* Resume facility enabled */ /* TR-Abort.req(SUSPEND) the Connect transaction */ send_abort(WSP_ABORT_SUSPEND, sm->connect_handle); /* Abort(SUSPEND) all method and push transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(SUSPEND) */ indicate_suspend(sm, WSP_ABORT_SUSPEND); }, SUSPENDED) ROW(CONNECTING_2, TR_Invoke_Cnf, 1, { /* See push state table*/ WSPPushMachine *spm; spm = find_push_machine(sm, e->handle); handle_push_event(sm, spm, current_event); }, CONNECTING_2) ROW(CONNECTING_2, TR_Result_Cnf, e->handle == sm->connect_handle, { }, CONNECTED) ROW(CONNECTING_2, TR_Result_Cnf, e->handle != sm->connect_handle, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); }, CONNECTING_2) ROW(CONNECTING_2, TR_Abort_Ind, e->handle == sm->connect_handle, { /* Abort(DISCONNECT) all method and push transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(abort reason) */ indicate_disconnect(sm, e->abort_code); }, NULL_SESSION) /* * A separate flag tells is the indicator the initiator or the responder. */ ROW(CONNECTING_2, TR_Abort_Ind, e->handle != sm->connect_handle && e->ir_flag == RESPONDER_INDICATION, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); }, CONNECTING_2) ROW(CONNECTING_2, TR_Abort_Ind, e->handle != sm->connect_handle && e->ir_flag == INITIATOR_INDICATION, { WSPPushMachine *m; /* See push state table */ m = find_push_machine(sm, e->handle); handle_push_event(sm, m, current_event); }, CONNECTING_2) /* MISSING: CONNECTED, S-Disconnect.req */ ROW(CONNECTED, Disconnect_Event, 1, { /* Abort(DISCONNECT) all method and push transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(CONNECTED, S_MethodInvoke_Res, 1, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->server_transaction_id); handle_method_event(sm, msm, current_event, pdu); }, CONNECTED) ROW(CONNECTED, S_MethodResult_Req, 1, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->server_transaction_id); handle_method_event(sm, msm, current_event, pdu); }, CONNECTED) ROW(CONNECTED, S_Push_Req, 1, { WSP_PDU *pdu; pdu = make_push_pdu(current_event); send_invoke(sm, pdu, current_event, TRANSACTION_CLASS_0); }, CONNECTED) ROW(CONNECTED, S_ConfirmedPush_Req, 1, { /* Start new push transaction*/ WSPPushMachine *spm; spm = push_machine_create(sm, e->server_push_id); handle_push_event(sm, spm, current_event); }, CONNECTED) ROW(CONNECTED, Suspend_Event, !resume_enabled, { /* Session Resume facility disabled */ /* Abort(SUSPEND) all method and push transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Disconnect.ind(SUSPEND) */ indicate_disconnect(sm, WSP_ABORT_SUSPEND); }, NULL_SESSION) ROW(CONNECTED, Suspend_Event, resume_enabled, { /* Session Resume facility enabled */ /* Abort(SUSPEND) all method and push transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(SUSPEND) */ indicate_suspend(sm, WSP_ABORT_SUSPEND); }, SUSPENDED) ROW(CONNECTED, TR_Invoke_Ind, e->tcl == 2 && (pdu->type == Get || pdu->type == Post), { WSPMethodMachine *msm; WAPEvent *new_event; /* Start new method transaction */ msm = method_machine_create(sm, e->handle); /* Hand off the event to the new method machine */ handle_method_event(sm, msm, current_event, pdu); /* Release the new method transaction */ new_event = wap_event_create(Release_Event); handle_method_event(sm, msm, new_event, NULL); wap_event_destroy(new_event); }, CONNECTED) ROW(CONNECTED, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Resume && !resume_enabled, { /* Resume facility disabled */ /* TR-Abort.req(DISCONNECT) the TR-Invoke */ send_abort(WSP_ABORT_DISCONNECT, e->handle); }, CONNECTED) ROW(CONNECTED, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Resume && resume_enabled, { /* Resume facility enabled */ WAPEvent *wtp_event; List *new_headers; /* TR-Invoke.res */ wtp_event = wap_event_create(TR_Invoke_Res); wtp_event->u.TR_Invoke_Res.handle = e->handle; dispatch_to_wtp_resp(wtp_event); /* Abort(RESUME) all method and push transactions */ abort_methods(sm, WSP_ABORT_RESUME); /* S-Suspend.ind(RESUME) */ indicate_suspend(sm, WSP_ABORT_RESUME); /* S-Resume.ind */ new_headers = unpack_new_headers(sm, pdu->u.Resume.headers); indicate_resume(sm, e->addr_tuple, new_headers); http_destroy_headers(new_headers); sm->resume_handle = e->handle; }, RESUMING) ROW(CONNECTED, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Disconnect, { /* Abort(DISCONNECT) all method and push transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(CONNECTED, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Suspend && resume_enabled, { /* Abort(SUSPEND) all method and push transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(SUSPEND) */ indicate_suspend(sm, WSP_ABORT_SUSPEND); }, SUSPENDED) ROW(CONNECTED, TR_Invoke_Cnf, 1, { /* See push state table*/ WSPPushMachine *spm; spm = find_push_machine(sm, e->handle); handle_push_event(sm, spm, current_event); }, CONNECTED) ROW(CONNECTED, TR_Result_Cnf, e->handle != sm->connect_handle, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); }, CONNECTED) /* * Event TR-Abort.ind has a separate flag telling is the indicator the * initiator or the responder. */ ROW(CONNECTED, TR_Abort_Ind, e->handle != sm->connect_handle && e->ir_flag == RESPONDER_INDICATION, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); }, CONNECTED) ROW(CONNECTED, TR_Abort_Ind, e->handle != sm->connect_handle && e->ir_flag == INITIATOR_INDICATION, { WSPPushMachine *m; /* See push state table */ m = find_push_machine(sm, e->handle); handle_push_event(sm, m, current_event); }, CONNECTED) /* MISSING: SUSPENDED, S-Disconnect.req */ ROW(SUSPENDED, Disconnect_Event, 1, { /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(SUSPENDED, TR_Invoke_Ind, e->tcl == 2 && (pdu->type == Get || pdu->type == Post), { /* TR-Abort.req(SUSPEND) the TR-Invoke */ send_abort(WSP_ABORT_SUSPEND, e->handle); }, SUSPENDED) ROW(SUSPENDED, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Resume, { WAPEvent *wtp_event; List *new_headers; /* TR-Invoke.res */ wtp_event = wap_event_create(TR_Invoke_Res); wtp_event->u.TR_Invoke_Res.handle = e->handle; dispatch_to_wtp_resp(wtp_event); /* S-Resume.ind */ new_headers = unpack_new_headers(sm, pdu->u.Resume.headers); indicate_resume(sm, e->addr_tuple, new_headers); http_destroy_headers(new_headers); sm->resume_handle = e->handle; }, RESUMING) ROW(SUSPENDED, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Disconnect, { /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) /* MISSING: RESUMING, S-Disconnect.req */ ROW(RESUMING, Disconnect_Event, 1, { /* TR-Abort.req(DISCONNECT) the Resume transaction */ send_abort(WSP_ABORT_DISCONNECT, sm->resume_handle); /* Abort(DISCONNECT) all method transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(RESUMING, S_Resume_Res, 1, { WAPEvent *wtp_event; Octstr *ospdu; /* Disconnect any other session for the peer address quadruplet */ disconnect_other_sessions(sm); /* Bind session to new peer address quadruplet */ /* this happens automatically XXX Not true */ /* TR-Result.req(Reply) */ if (e->server_headers == NULL) e->server_headers = http_create_empty_headers(); ospdu = make_resume_reply_pdu(sm, e->server_headers); wtp_event = wap_event_create(TR_Result_Req); wtp_event->u.TR_Result_Req.user_data = ospdu; wtp_event->u.TR_Result_Req.handle = sm->resume_handle; dispatch_to_wtp_resp(wtp_event); /* Release all method transactions in HOLDING state */ release_holding_methods(sm); }, RESUMING_2) ROW(RESUMING, Suspend_Event, 1, { /* TR-Abort.req(SUSPEND) the Resume transaction */ send_abort(WSP_ABORT_SUSPEND, sm->resume_handle); /* Abort(SUSPEND) all method transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(SUSPEND) */ indicate_suspend(sm, WSP_ABORT_SUSPEND); }, SUSPENDED) ROW(RESUMING, TR_Invoke_Ind, e->tcl == 2 && (pdu->type == Get || pdu->type == Post), { /* Start new method transaction (see method state table) */ WSPMethodMachine *msm; msm = method_machine_create(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); }, RESUMING) ROW(RESUMING, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Resume, { WAPEvent *wtp_event; List *new_headers; /* TR-Invoke.res */ wtp_event = wap_event_create(TR_Invoke_Res); wtp_event->u.TR_Invoke_Res.handle = e->handle; dispatch_to_wtp_resp(wtp_event); /* TR-Abort.req(RESUME) the old Resume transaction */ send_abort(WSP_ABORT_RESUME, sm->resume_handle); /* Abort(RESUME) all method transactions */ abort_methods(sm, WSP_ABORT_RESUME); /* S-Suspend.ind(RESUME) */ indicate_suspend(sm, WSP_ABORT_RESUME); /* S-Resume.ind */ new_headers = unpack_new_headers(sm, pdu->u.Resume.headers); indicate_resume(sm, e->addr_tuple, new_headers); http_destroy_headers(new_headers); sm->resume_handle = e->handle; }, RESUMING) ROW(RESUMING, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Suspend, { /* TR-Abort.req(SUSPEND) the Resume transaction */ send_abort(WSP_ABORT_SUSPEND, sm->resume_handle); /* Abort(SUSPEND) all method transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(SUSPEND) */ indicate_suspend(sm, WSP_ABORT_SUSPEND); }, SUSPENDED) ROW(RESUMING, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Disconnect, { /* TR-Abort.req(DISCONNECT) the Resume transaction */ send_abort(WSP_ABORT_DISCONNECT, sm->resume_handle); /* Abort(DISCONNECT) all method transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(RESUMING, TR_Abort_Ind, e->handle == sm->resume_handle, { /* Abort(SUSPEND) all method transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(abort reason) */ indicate_suspend(sm, e->abort_code); }, SUSPENDED) /* MISSING: RESUMING_2, S-Disconnect.req */ ROW(RESUMING_2, Disconnect_Event, 1, { /* TR-Abort.req(DISCONNECT) the Resume */ send_abort(WSP_ABORT_DISCONNECT, sm->resume_handle); /* Abort(DISCONNECT) all method and push transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(RESUMING_2, S_MethodInvoke_Res, 1, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->server_transaction_id); handle_method_event(sm, msm, current_event, pdu); }, RESUMING_2) ROW(RESUMING_2, S_MethodResult_Req, 1, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->server_transaction_id); handle_method_event(sm, msm, current_event, pdu); }, RESUMING_2) ROW(RESUMING_2, S_Push_Req, 1, { WSP_PDU *pdu; pdu = make_push_pdu(current_event); send_invoke(sm, pdu, current_event, TRANSACTION_CLASS_0); }, RESUMING_2) ROW(RESUMING_2, S_ConfirmedPush_Req, 1, { /* Start new push transaction*/ WSPPushMachine *spm; spm = push_machine_create(sm, e->server_push_id); handle_push_event(sm, spm, current_event); }, RESUMING_2) ROW(RESUMING_2, Suspend_Event, 1, { /* TR-Abort.req(SUSPEND) the Resume transaction */ send_abort(WSP_ABORT_SUSPEND, sm->resume_handle); /* Abort(SUSPEND) all method and push transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(SUSPEND) */ indicate_suspend(sm, WSP_ABORT_SUSPEND); }, SUSPENDED) ROW(RESUMING_2, TR_Invoke_Ind, e->tcl == 2 && (pdu->type == Get || pdu->type == Post), { WSPMethodMachine *msm; WAPEvent *new_event; /* Start new method transaction (see method state table) */ msm = method_machine_create(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); /* Release the new method transaction */ new_event = wap_event_create(Release_Event); handle_method_event(sm, msm, new_event, NULL); wap_event_destroy(new_event); }, RESUMING_2) ROW(RESUMING_2, TR_Invoke_Ind, e->tcl == 2 && pdu->type == Resume, { WAPEvent *wtp_event; List *new_headers; /* TR-Invoke.res */ wtp_event = wap_event_create(TR_Invoke_Res); wtp_event->u.TR_Invoke_Res.handle = e->handle; dispatch_to_wtp_resp(wtp_event); /* TR-Abort.req(RESUME) the old Resume transaction*/ send_abort(WSP_ABORT_RESUME, sm->resume_handle); /* Abort(RESUME) all method and push transactions */ abort_methods(sm, WSP_ABORT_RESUME); /* S-Suspend.ind(RESUME) */ indicate_suspend(sm, WSP_ABORT_RESUME); /* S-Resume.ind */ new_headers = unpack_new_headers(sm, pdu->u.Resume.headers); indicate_resume(sm, e->addr_tuple, new_headers); http_destroy_headers(new_headers); sm->resume_handle = e->handle; }, RESUMING) ROW(RESUMING_2, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Suspend, { /* TR-Abort.req(SUSPEND) the Resume transaction */ send_abort(WSP_ABORT_SUSPEND, sm->resume_handle); /* Abort(SUSPEND) all method and push transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(SUSPEND) */ indicate_suspend(sm, WSP_ABORT_SUSPEND); }, SUSPENDED) ROW(RESUMING_2, TR_Invoke_Ind, e->tcl == 0 && pdu->type == Disconnect, { /* TR-Abort.req(DISCONNECT) the Resume */ send_abort(WSP_ABORT_DISCONNECT, sm->resume_handle); /* Abort(DISCONNECT) all method and push transactions */ abort_methods(sm, WSP_ABORT_DISCONNECT); /* S-Disconnect.ind(DISCONNECT) */ indicate_disconnect(sm, WSP_ABORT_DISCONNECT); }, NULL_SESSION) ROW(RESUMING_2, TR_Invoke_Cnf, 1, { /* See push state table*/ WSPPushMachine *spm; spm = find_push_machine(sm, e->handle); handle_push_event(sm, spm, current_event); }, RESUMING_2) ROW(RESUMING_2, TR_Result_Cnf, e->handle == sm->resume_handle, { }, CONNECTED) ROW(RESUMING_2, TR_Result_Cnf, e->handle != sm->resume_handle, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); }, RESUMING_2) ROW(RESUMING_2, TR_Abort_Ind, e->handle == sm->resume_handle, { /* Abort(SUSPEND) all method and push transactions */ abort_methods(sm, WSP_ABORT_SUSPEND); /* S-Suspend.ind(abort reason) */ indicate_suspend(sm, e->abort_code); }, SUSPENDED) /* * A separate flag tells is the indicator the initiator or the responder */ ROW(RESUMING_2, TR_Abort_Ind, e->handle != sm->resume_handle && e->ir_flag == RESPONDER_INDICATION, { WSPMethodMachine *msm; /* See method state table */ msm = find_method_machine(sm, e->handle); handle_method_event(sm, msm, current_event, pdu); }, RESUMING_2) ROW(CONNECTING_2, TR_Abort_Ind, e->handle != sm->connect_handle && e->ir_flag == INITIATOR_INDICATION, { WSPPushMachine *m; /* See push state table */ m = find_push_machine(sm, e->handle); handle_push_event(sm, m, current_event); }, CONNECTING_2) #undef ROW #undef STATE_NAME gateway-1.4.5/wap/wap.c0000644000175000017500000001011211443121512013373 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2008 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap.c - Generic functions for wap library */ #include "gwlib/gwlib.h" #include "wap.h" #include "wtp.h" #define CONNECTIONLESS_PORT 9200 #define WTLS_CONNECTIONLESS_PORT 9202 void wap_dispatch_datagram(WAPEvent *dgram) { long len; gw_assert(dgram != NULL); if (dgram->type != T_DUnitdata_Ind) { warning(0, "wap_dispatch_datagram got event of unexpected type."); wap_event_dump(dgram); wap_event_destroy(dgram); return; } /* XXX Assumption does not hold for client side */ if (dgram->u.T_DUnitdata_Ind.addr_tuple->local->port == CONNECTIONLESS_PORT || dgram->u.T_DUnitdata_Ind.addr_tuple-> local->port == WTLS_CONNECTIONLESS_PORT) { wsp_unit_dispatch_event(dgram); } else { List *events; events = wtp_unpack_wdp_datagram(dgram); if (!events) { debug("wap.wap", 0, "ignoring truncated datagram"); wap_event_dump(dgram); wap_event_destroy(dgram); return; } len = gwlist_len(events); while (len-- > 0) { WAPEvent *event; event = gwlist_extract_first(events); if (wtp_event_is_for_responder(event)) wtp_resp_dispatch_event(event); else wtp_initiator_dispatch_event(event); } wap_event_destroy(dgram); gwlist_destroy(events, NULL); } } gateway-1.4.5/wap/wsp_strings.c0000644000175000017500000002312713227613126015211 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wsp_strings.c: lookup code for various tables defined by WSP standard * * This file provides functions to translate strings to numbers and numbers * to strings according to the Assigned Numbers tables in appendix A * of the WSP specification. * * The tables are in wsp_strings.def, in a special format suitable for * use with the C preprocessor, which we abuse liberally to get the * interface we want. * * Richard Braakman */ #include "gwlib/gwlib.h" #include "wsp_strings.h" #define TABLE_SIZE(table) ((long)(sizeof(table) / sizeof(table[0]))) static int initialized; /* The arrays in a table structure are all of equal length, and their * elements correspond. The number for string 0 is in numbers[0], etc. * Table structures are initialized dynamically. */ struct table { long size; /* Nr of entries in each of the tables below */ Octstr **strings; /* Immutable octstrs */ long *numbers; /* Assigned numbers, or NULL for linear tables */ int *versions; /* WSP Encoding-versions, or NULL if non-versioned */ int linear; /* True for tables defined as LINEAR */ }; struct numbered_element { char *str; long number; int version; }; struct linear_element { char *str; int version; }; /* Local functions */ static Octstr *number_to_string(long number, struct table *table); static unsigned char *number_to_cstr(long number, struct table *table); static long string_to_number(Octstr *ostr, struct table *table); static long string_to_versioned_number(Octstr *ostr, struct table *table, int version); /* Declare the data. For each table "foo", create a foo_strings array * to hold the data, and a (still empty) foo_table structure. */ #define LINEAR(name, strings) \ static const struct linear_element name##_strings[] = { strings }; \ static struct table name##_table; #define STRING(string) { string, 0 }, #define VSTRING(version, string) { string, version }, #define NUMBERED(name, strings) \ static const struct numbered_element name##_strings[] = { strings }; \ static struct table name##_table; #define ASSIGN(string, number) { string, number, 0 }, #define VASSIGN(version, string, number) { string, number, version }, #include "wsp_strings.def" /* Define the functions for translating number to Octstr */ #define LINEAR(name, strings) \ Octstr *wsp_##name##_to_string(long number) { \ return number_to_string(number, &name##_table); \ } #include "wsp_strings.def" /* Define the functions for translating number to constant string */ #define LINEAR(name, strings) \ unsigned char *wsp_##name##_to_cstr(long number) { \ return number_to_cstr(number, &name##_table); \ } #include "wsp_strings.def" #define LINEAR(name, strings) \ long wsp_string_to_##name(Octstr *ostr) { \ return string_to_number(ostr, &name##_table); \ } #include "wsp_strings.def" #define LINEAR(name, strings) \ long wsp_string_to_versioned_##name(Octstr *ostr, int version) { \ return string_to_versioned_number(ostr, &name##_table, version); \ } #include "wsp_strings.def" static Octstr *number_to_string(long number, struct table *table) { long i; gw_assert(initialized); if (table->linear) { if (number >= 0 && number < table->size) return octstr_duplicate(table->strings[number]); } else { for (i = 0; i < table->size; i++) { if (table->numbers[i] == number) return octstr_duplicate(table->strings[i]); } } return NULL; } static unsigned char *number_to_cstr(long number, struct table *table) { long i; gw_assert(initialized); if (table->linear) { if (number >= 0 && number < table->size) return (unsigned char *)octstr_get_cstr(table->strings[number]); } else { for (i = 0; i < table->size; i++) { if (table->numbers[i] == number) return (unsigned char *)octstr_get_cstr(table->strings[i]); } } return NULL; } /* Case-insensitive string lookup */ static long string_to_number(Octstr *ostr, struct table *table) { long i; gw_assert(initialized); for (i = 0; i < table->size; i++) { if (octstr_case_compare(ostr, table->strings[i]) == 0) { return table->linear ? i : table->numbers[i]; } } return -1; } /* Case-insensitive string lookup according to passed WSP encoding version */ static long string_to_versioned_number(Octstr *ostr, struct table *table, int version) { long i, ret; gw_assert(initialized); /* walk the whole table and pick the highest versioned token */ ret = -1; for (i = 0; i < table->size; i++) { if (octstr_case_compare(ostr, table->strings[i]) == 0 && table->versions[i] <= version) { ret = table->linear ? i : table->numbers[i]; } } debug("wsp.strings",0,"WSP: Mapping `%s', WSP 1.%d to 0x%04lx.", octstr_get_cstr(ostr), version, ret); return ret; } static void construct_linear_table(struct table *table, const struct linear_element *strings, long size) { long i; table->size = size; table->strings = gw_malloc(size * (sizeof table->strings[0])); table->numbers = NULL; table->versions = gw_malloc(size * (sizeof table->versions[0])); table->linear = 1; for (i = 0; i < size; i++) { table->strings[i] = octstr_imm(strings[i].str); table->versions[i] = strings[i].version; } } static void construct_numbered_table(struct table *table, const struct numbered_element *strings, long size) { long i; table->size = size; table->strings = gw_malloc(size * (sizeof table->strings[0])); table->numbers = gw_malloc(size * (sizeof table->numbers[0])); table->versions = gw_malloc(size * (sizeof table->versions[0])); table->linear = 0; for (i = 0; i < size; i++) { table->strings[i] = octstr_imm(strings[i].str); table->numbers[i] = strings[i].number; table->versions[i] = strings[i].version; } } static void destroy_table(struct table *table) { /* No need to call octstr_destroy on immutable octstrs */ gw_free(table->strings); gw_free(table->numbers); gw_free(table->versions); } void wsp_strings_init(void) { if (initialized > 0) { initialized++; return; } #define LINEAR(name, strings) \ construct_linear_table(&name##_table, \ name##_strings, TABLE_SIZE(name##_strings)); #define NUMBERED(name, strings) \ construct_numbered_table(&name##_table, \ name##_strings, TABLE_SIZE(name##_strings)); #include "wsp_strings.def" initialized++; } void wsp_strings_shutdown(void) { /* If we were initialized more than once, then wait for more than * one shutdown. */ if (initialized > 1) { initialized--; return; } #define LINEAR(name, strings) \ destroy_table(&name##_table); #include "wsp_strings.def" initialized = 0; } gateway-1.4.5/wap/wsp_push_client_machine.def0000644000175000017500000000634513227613126020040 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp-push-client-machine.h: Define wsp push client state machine * * By Aarno Syvänen for Wapit Ltd. */ #if !defined(INTEGER) #error "Macro INTEGER not defined." #elif !defined(HTTPHEADERS) #error "Macro HTTPHEADERS not defined." #elif !defined(MACHINE) #error "Macro MACHINE is not defined." #endif MACHINE( INTEGER(state) INTEGER(client_push_id) INTEGER(transaction_id) INTEGER(session_id) HTTPHEADERS(push_headers) ) #undef INTEGER #undef HTTPHEADERS #undef MACHINE gateway-1.4.5/wap/wtp_pdu.def0000644000175000017500000001144713227613126014627 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ PDU(Invoke, "...", UINT(con, "Continue flag (CON)", 1) TYPE(4, 1) UINT(gtr, "Group trailer (GTR)", 1) UINT(ttr, "Transmission trailer (TTR)", 1) UINT(rid, "Re-transmission indicator (RID)", 1) UINT(tid, "Transaction ID (TID)", 16) UINT(version, "WTP protocol version", 2) UINT(tidnew, "TIDnew flag", 1) UINT(uack, "User ack flag", 1) RESERVED(2) UINT(class, "Transaction class (TCL)", 2) TPI(con) REST(user_data, "Payload") , p->class <= 2) PDU(Result, "...", UINT(con, "Continue flag (CON)", 1) TYPE(4, 2) UINT(gtr, "Group trailer (GTR)", 1) UINT(ttr, "Transmission trailer (TTR)", 1) UINT(rid, "Re-transmission indicator (RID)", 1) UINT(tid, "Transaction ID (TID)", 16) TPI(con) REST(user_data, "Payload") , 1) PDU(Ack, "...", UINT(con, "Continue flag (CON)", 1) TYPE(4, 3) UINT(tidverify, "TID verify / TID OK flag", 1) RESERVED(1) UINT(rid, "Re-transmission indicator (RID)", 1) UINT(tid, "Transaction ID (TID)", 16) TPI(con) , 1) PDU(Abort, "...", UINT(con, "Continue flag (CON)", 1) TYPE(4, 4) UINT(abort_type, "Abort type", 3) UINT(tid, "Transaction ID (TID)", 16) UINT(abort_reason, "Abort reason", 8) TPI(con) , p->abort_type <= 1) PDU(Segmented_invoke, "...", UINT(con, "Continue flag (CON)", 1) TYPE(4, 5) UINT(gtr, "Group trailer (GTR)", 1) UINT(ttr, "Transmission trailer (TTR)", 1) UINT(rid, "Re-transmission indicator (RID)", 1) UINT(tid, "Transaction ID (TID)", 16) UINT(psn, "Packet sequence number", 8) TPI(con) REST(user_data, "Payload") , 1) PDU(Segmented_result, "...", UINT(con, "Continue flag (CON)", 1) TYPE(4, 6) UINT(gtr, "Group trailer (GTR)", 1) UINT(ttr, "Transmission trailer (TTR)", 1) UINT(rid, "Re-transmission indicator (RID)", 1) UINT(tid, "Transaction ID (TID)", 16) UINT(psn, "Packet sequence number", 8) TPI(con) REST(user_data, "Payload") , 1) PDU(Negative_ack, "...", UINT(con, "Continue flag (CON)", 1) TYPE(4, 7) RESERVED(2) UINT(rid, "Re-transmission indicator (RID)", 1) UINT(tid, "Transaction ID (TID)", 16) UINT(nmissing, "Number of missing packets", 8) OCTSTR(missing, "Missing packet PSNs", nmissing) TPI(con) , 1) gateway-1.4.5/wap/wtp_init_machine.def0000644000175000017500000001164713227613126016470 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_init_machine.def: macro call for generating WTP initiator state * machine. See the architecture document for guidance how to use and update * it. * * By Aarno Syvänen for Wapit Ltd. * * WTPRespMachine data structure includes current state of WTP responder state * machine for a specific transaction. This means all data needed to handle at * least two incoming events of a certain transaction. Its fields can be * grouped following way: * * General: a) wtp initiator machine state * b) tidnew flag, telling whether tid is wrapped up * * Fields telling the service required: * a) transaction class (is transaction confirmed or not) * b) user acknowledgement flag (do we wait for response * primitive of WTP user (for instance, WSP) or not) * * Machine identification: address four-tuple and transaction identifier * * Fields required for reliable transmission: * a) pointer to the timer of this machine in the timers list * b) counter for retransmissions * c) flag telling are we resending ack pdu doing tid verifica- * tion or not * d) packed invoke message, for greater effectivity */ #if !defined(MACHINE) #error "Macro MACHINE is missing." #elif !defined(INTEGER) #error "Macro INTEGER is missing." #elif !defined(ENUM) #error "Macro ENUM is missing." #elif !defined(EVENT) #error "Macro EVENT is missing." #elif !defined(TIMER) #error "Macro TIMER is missing." #elif !defined(ADDRTUPLE) #error "Macro ADDRTUPLE is missing." #endif MACHINE(ENUM(state) INTEGER(tid) /* transaction identifier */ ADDRTUPLE(addr_tuple) INTEGER(tidnew) /* tidnew flag */ INTEGER(u_ack) /* user acknowledgement flag */ EVENT(invoke) /* invoke datagram for resending */ TIMER(timer) INTEGER(rcr) /* retransmission counter */ INTEGER(tidok_sent) /* are we resending tid verification */ INTEGER(rid) /* are we resending invoke */ ) #undef MACHINE #undef ENUM #undef EVENT #undef INTEGER #undef ADDRTUPLE #undef TIMER gateway-1.4.5/wap/wsp_pdu.def0000644000175000017500000001233213227613126014620 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ PDU(Connect, "...", TYPE(8, 1) UINT(version, "WSP protocol version", 8) UINTVAR(capabilities_len, "Length of capabilities") UINTVAR(headers_len, "Length of session headers") OCTSTR(capabilities, "Requested capabilities", capabilities_len) OCTSTR(headers, "Session headers", headers_len) , 1) PDU(ConnectReply, "...", TYPE(8, 2) UINTVAR(sessionid, "Session ID") UINTVAR(capabilities_len, "Length of capabilities") UINTVAR(headers_len, "Length of session headers") OCTSTR(capabilities, "Accepted capabilities", capabilities_len) OCTSTR(headers, "Session headers", headers_len) , 1) PDU(Redirect, "Problem: need REPEAT structure to parse addresses", TYPE(8, 3) UINT(permanent, "Permanent Redirect flag", 1) UINT(reuse_security, "Reuse Security Session flag", 1) RESERVED(6) REST(addresses, "Redirect addresses") , 1) PDU(Disconnect, "...", TYPE(8, 5) UINTVAR(sessionid, "Session ID") , 1) PDU(Get, "...", TYPE(4, 0x4) UINT(subtype, "GET, OPTIONS, HEAD, DELETE, or TRACE", 4) UINTVAR(uri_len, "Length of URI") OCTSTR(uri, "URI", uri_len) REST(headers, "Request headers") , p->subtype <= 4) PDU(Post, "...", TYPE(4, 0x6) UINT(subtype, "POST or PUT", 4) UINTVAR(uri_len, "Length of URI") UINTVAR(headers_len, "Length of headers") OCTSTR(uri, "URI", uri_len) OCTSTR(headers, "Content type and request headers", headers_len) REST(data, "Request data") , p->subtype <= 1) PDU(Reply, "...", TYPE(8, 4) UINT(status, "Status code", 8) UINTVAR(headers_len, "Length of headers") OCTSTR(headers, "Content type and reply headers", headers_len) REST(data, "Reply data") , 1) PDU(Push, "...", TYPE(8, 6) UINTVAR(headers_len, "Length of headers") OCTSTR(headers, "Content type and headers", headers_len) REST(data, "Push data") , 1) PDU(ConfirmedPush, "...", TYPE(8, 7) UINTVAR(headers_len, "Length of headers") OCTSTR(headers, "Content type and headers", headers_len) REST(data, "Push data") , 1) PDU(Suspend, "...", TYPE(8, 8) UINTVAR(sessionid, "Session ID") , 1) PDU(Resume, "...", TYPE(8, 9) UINTVAR(sessionid, "Session ID") UINTVAR(capabilities_len, "Length of capabilities") OCTSTR(capabilities, "Reserved capabilities field", capabilities_len) REST(headers, "Session headers") , 1) PDU(sia, "...", UINT(version, "sia version", 8) UINTVAR(appidlist_len, "Length of application id list") OCTSTR(application_id_list, "application id list", appidlist_len) UINTVAR(contactpoints_len, "Length of contact point list") OCTSTR(contactpoints, "list of contact points", contactpoints_len) , 1) gateway-1.4.5/wap/wtp_init.c0000644000175000017500000004237413227613126014471 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_init.c - WTP initiator implementation * * By Aarno Syvänen for Wapit Ltd */ #include "gwlib/gwlib.h" #include "wtp_init.h" #include "wtp_pack.h" #include "wap.h" /***************************************************************************** * Internal data structures. * * List of initiator WTP machines */ static List *init_machines = NULL; /* * Counter for initiator WTP machine id numbers, to make sure they are unique. */ static Counter *init_machine_id_counter = NULL; /* * When we restart an iniator, we must set tidnew flag to avoid excessive tid * validations (WTP 8.8.3.2). Only an iniator uses this flag. */ static int tidnew = 1; /* * Queue of events to be handled by WTP initiator. */ static List *queue = NULL; /* * Give the status of the wtp initiator: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum { limbo, running, terminating } initiator_run_status = limbo; static wap_dispatch_func_t *dispatch_to_wdp; static wap_dispatch_func_t *dispatch_to_wsp; /* * This is a timer 'tick'. All timer values multiplies of this value. */ static long init_timer_freq = -1; /*************************************************************************** * * Prototypes for internal functions: */ static void main_thread(void *arg); /* * Create and destroy an uniniatilised wtp initiator state machine */ static WTPInitMachine *init_machine_create(WAPAddrTuple *tuple, unsigned short tid, int tidnew); static void init_machine_destroy(void *sm); static void handle_init_event(WTPInitMachine *machine, WAPEvent *event); /* * Checks whether wtp initiator machines data structure includes a specific * machine. * The machine in question is identified with with source and destination * address and port and tid. */ static WTPInitMachine *init_machine_find_or_create(WAPEvent *event); /* * Creates TR-Abort.ind event. */ static WAPEvent *create_tr_abort_ind(WTPInitMachine *sm, long abort_reason); /* * Creates TR-Invoke.cnf event */ static WAPEvent *create_tr_invoke_cnf(WTPInitMachine *machine); static int tid_wrapped(unsigned short tid); /* * Create a datagram with an Abort PDU and send it to the WDP layer. */ static void send_abort(WTPInitMachine *machine, long type, long reason); /* * Create a datagram with an Ack PDU and send it to the WDP layer. */ static void send_ack(WTPInitMachine *machine, long ack_type, int rid_flag); /* * We use RcvTID consistently as a internal tid representation. So newly * created tids are converted. SendTID = RcvTID ^ 0x8000 (WTP 10.4.3) and for * an initiator, GenTID = SendTID (WTP 10.5). */ static unsigned short rcv_tid(unsigned short tid); static void start_initiator_timer_R(WTPInitMachine *machine); static void stop_initiator_timer(Timer *timer); /************************************************************************** * * EXTERNAL FUNCTIONS */ void wtp_initiator_init(wap_dispatch_func_t *datagram_dispatch, wap_dispatch_func_t *session_dispatch, long timer_freq) { init_machines = gwlist_create(); init_machine_id_counter = counter_create(); queue = gwlist_create(); gwlist_add_producer(queue); dispatch_to_wdp = datagram_dispatch; dispatch_to_wsp = session_dispatch; timers_init(); init_timer_freq = timer_freq; gw_assert(initiator_run_status == limbo); initiator_run_status = running; gwthread_create(main_thread, NULL); } void wtp_initiator_shutdown(void) { gw_assert(initiator_run_status == running); initiator_run_status = terminating; gwlist_remove_producer(queue); gwthread_join_every(main_thread); debug("wap.wtp", 0, "wtp_initiator_shutdown: %ld init_machines left", gwlist_len(init_machines)); gwlist_destroy(init_machines, init_machine_destroy); gwlist_destroy(queue, wap_event_destroy_item); counter_destroy(init_machine_id_counter); timers_shutdown(); } void wtp_initiator_dispatch_event(WAPEvent *event) { gwlist_produce(queue, event); } /************************************************************************** * * INTERNAL FUNCTIONS: */ static void main_thread(void *arg) { WTPInitMachine *sm; WAPEvent *e; while (initiator_run_status == running && (e = gwlist_consume(queue)) != NULL) { sm = init_machine_find_or_create(e); if (sm == NULL) wap_event_destroy(e); else handle_init_event(sm, e); } } static WTPInitMachine *init_machine_create(WAPAddrTuple *tuple, unsigned short tid, int tidnew) { WTPInitMachine *init_machine; init_machine = gw_malloc(sizeof(WTPInitMachine)); #define ENUM(name) init_machine->name = INITIATOR_NULL_STATE; #define INTEGER(name) init_machine->name = 0; #define EVENT(name) init_machine->name = NULL; #define TIMER(name) init_machine->name = gwtimer_create(queue); #define ADDRTUPLE(name) init_machine->name = NULL; #define MACHINE(field) field #include "wtp_init_machine.def" gwlist_append(init_machines, init_machine); init_machine->mid = counter_increase(init_machine_id_counter); init_machine->addr_tuple = wap_addr_tuple_duplicate(tuple); init_machine->tid = tid; init_machine->tidnew = tidnew; debug("wap.wtp", 0, "WTP: Created WTPInitMachine %p (%ld)", (void *) init_machine, init_machine->mid); return init_machine; } /* * Destroys a WTPInitMachine. Assumes it is safe to do so. Assumes it has * already been deleted from the machines list. */ static void init_machine_destroy(void *p) { WTPInitMachine *init_machine; init_machine = p; debug("wap.wtp", 0, "WTP: Destroying WTPInitMachine %p (%ld)", (void *) init_machine, init_machine->mid); gwlist_delete_equal(init_machines, init_machine); #define ENUM(name) init_machine->name = INITIATOR_NULL_STATE; #define INTEGER(name) init_machine->name = 0; #define EVENT(name) wap_event_destroy(init_machine->name); #define TIMER(name) gwtimer_destroy(init_machine->name); #define ADDRTUPLE(name) wap_addr_tuple_destroy(init_machine->name); #define MACHINE(field) field #include "wtp_init_machine.def" gw_free(init_machine); } /* * Give the name of an initiator state in a readable form. */ static unsigned char *name_init_state(int s) { switch (s){ #define INIT_STATE_NAME(state) case state: return (unsigned char *) #state; #define ROW(state, event, condition, action, new_state) #include "wtp_init_states.def" default: return (unsigned char *)"unknown state"; } } /* * Feed an event to a WTP initiator state machine. Handle all errors by do not * report them to the caller. WSP indication or conformation is handled by an * included state table. Note: Do not put {}s of the else block inside the * macro definition . */ static void handle_init_event(WTPInitMachine *init_machine, WAPEvent *event) { WAPEvent *wsp_event = NULL; debug("wap.wtp", 0, "WTP_INIT: initiator machine %ld, state %s," " event %s.", init_machine->mid, name_init_state(init_machine->state), wap_event_name(event->type)); #define INIT_STATE_NAME(state) #define ROW(init_state, event_type, condition, action, next_state) \ if (init_machine->state == init_state && \ event->type == event_type && \ (condition)) { \ action \ init_machine->state = next_state; \ debug("wap.wtp", 0, "WTP_INIT %ld: New state %s", \ init_machine->mid, #next_state); \ } else #include "wtp_init_states.def" { error(1, "WTP_INIT: handle_init_event: unhandled event!"); debug("wap.wtp.init", 0, "WTP_INIT: handle_init_event:" "Unhandled event was:"); wap_event_dump(event); wap_event_destroy(event); return; } if (event != NULL) { wap_event_destroy(event); } if (init_machine->state == INITIATOR_NULL_STATE) init_machine_destroy(init_machine); } static int is_wanted_init_machine(void *a, void *b) { struct machine_pattern *pat; WTPInitMachine *m; m = a; pat = b; if (m->mid == pat->mid) return 1; if (pat->mid != -1) return 0; return m->tid == pat->tid && wap_addr_tuple_same(m->addr_tuple, pat->tuple); } static WTPInitMachine *init_machine_find(WAPAddrTuple *tuple, long tid, long mid) { struct machine_pattern pat; WTPInitMachine *m; pat.tuple = tuple; pat.tid = tid; pat.mid = mid; m = gwlist_search(init_machines, &pat, is_wanted_init_machine); return m; } /* * Checks whether wtp initiator machines data structure includes a specific * machine. The machine in question is identified with with source and * destination address and port and tid. First test incoming events * (WTP 10.2) (Exception are tests nro 4 and 5: if we have a memory error, * we panic (nro 4); nro 5 is already checked). If we have an ack with tid * verification flag set and no corresponding transaction, we abort.(case nro * 2). If the event was a normal ack or an abort, it is ignored (error nro 3). * In the case of TR-Invoke.req a new machine is created, in the case of * TR-Abort.req we have a serious error. We must create a new tid for a new * transaction here, because machines are identified by an address tuple and a * tid. This tid is GenTID (WTP 10.4.2), which is used only by the wtp iniator * thread. * Note that as internal tid representation, module uses RcvTID (as required * by module wtp_pack). So we we turn the first bit of the tid stored by the * init machine. */ static WTPInitMachine *init_machine_find_or_create(WAPEvent *event) { WTPInitMachine *machine = NULL; long mid; static long tid = -1; WAPAddrTuple *tuple; mid = -1; tuple = NULL; switch (event->type) { case RcvAck: tid = event->u.RcvAck.tid; tuple = event->u.RcvAck.addr_tuple; break; case RcvAbort: tid = event->u.RcvAbort.tid; tuple = event->u.RcvAbort.addr_tuple; break; case RcvErrorPDU: mid = event->u.RcvErrorPDU.tid; tid = event->u.RcvErrorPDU.tid; tuple = event->u.RcvErrorPDU.addr_tuple; break; /* * When we are receiving an invoke requirement, we must create a new trans- * action and generate a new tid. This can be wrapped, and should have its * first bit turned. */ case TR_Invoke_Req: ++tid; if (tid_wrapped(tid)) { tidnew = 1; tid = 0; } tid = rcv_tid(tid); tuple = event->u.TR_Invoke_Req.addr_tuple; mid = event->u.TR_Invoke_Req.handle; break; case TR_Abort_Req: tid = event->u.TR_Abort_Req.handle; break; case TimerTO_R: mid = event->u.TimerTO_R.handle; break; default: error(0, "WTP_INIT: machine_find_or_create: unhandled event"); wap_event_dump(event); return NULL; } gw_assert(tuple != NULL || mid != -1); machine = init_machine_find(tuple, tid, mid); if (machine == NULL){ switch (event->type){ case RcvAck: /* * Case nro 2 If we do not have a tid asked for, we send a negative answer, * i.e. an abort with reason INVALIDTID. */ if (event->u.RcvAck.tid_ok) { dispatch_to_wdp(wtp_pack_abort(PROVIDER, INVALIDTID, tid, tuple)); } /* Case nro 3, normal ack */ else info(0, "WTP_INIT: machine_find_or_create: ack " "received, yet having no machine"); break; /* Case nro 3, abort */ case RcvAbort: info(0, "WTP_INIT: machine_find_or_create: abort " "received, yet having no machine"); break; case TR_Invoke_Req: machine = init_machine_create(tuple, tid, tidnew); machine->mid = event->u.TR_Invoke_Req.handle; break; case TR_Abort_Req: error(0, "WTP_INIT: machine_find_or_create: WSP " "primitive to a wrong WTP machine"); break; case TimerTO_R: error(0, "WTP_INIT: machine_find_or_create: timer " "event without a corresponding machine"); break; default: error(0, "WTP_INIT: machine_find_or_create: unhandled" "event"); wap_event_dump(event); break; } } return machine; } /* * Creates TR-Invoke.cnf event */ static WAPEvent *create_tr_invoke_cnf(WTPInitMachine *init_machine) { WAPEvent *event; gw_assert(init_machine != NULL); event = wap_event_create(TR_Invoke_Cnf); event->u.TR_Invoke_Cnf.handle = init_machine->mid; event->u.TR_Invoke_Cnf.addr_tuple = wap_addr_tuple_duplicate(init_machine->addr_tuple); return event; } /* * Creates TR-Abort.ind event from an initiator state machine. In addtion, set * the ir_flag on. */ static WAPEvent *create_tr_abort_ind(WTPInitMachine *sm, long abort_reason) { WAPEvent *event; event = wap_event_create(TR_Abort_Ind); event->u.TR_Abort_Ind.abort_code = abort_reason; event->u.TR_Abort_Ind.addr_tuple = wap_addr_tuple_duplicate(sm->addr_tuple); event->u.TR_Abort_Ind.handle = sm->mid; event->u.TR_Abort_Ind.ir_flag = INITIATOR_INDICATION; return event; } static int tid_wrapped(unsigned short tid) { return tid > (1 << 15); } static unsigned short rcv_tid(unsigned short tid) { return tid ^ 0x8000; } /* * Start retry interval timer (strictly speaking, timer iniatilised with retry * interval). Multiply timer value with init_timer_freq. */ static void start_initiator_timer_R(WTPInitMachine *machine) { WAPEvent *timer_event; int seconds; timer_event = wap_event_create(TimerTO_R); timer_event->u.TimerTO_R.handle = machine->mid; if (machine->u_ack) seconds = S_R_WITH_USER_ACK * init_timer_freq; else seconds = S_R_WITHOUT_USER_ACK * init_timer_freq; gwtimer_start(machine->timer, seconds, timer_event); } static void stop_initiator_timer(Timer *timer) { debug("wap.wtp_init", 0, "stopping timer"); gw_assert(timer); gwtimer_stop(timer); } static void send_abort(WTPInitMachine *machine, long type, long reason) { WAPEvent *e; e = wtp_pack_abort(type, reason, machine->tid, machine->addr_tuple); dispatch_to_wdp(e); } static void send_ack(WTPInitMachine *machine, long ack_type, int rid_flag) { WAPEvent *e; e = wtp_pack_ack(ack_type, rid_flag, machine->tid, machine->addr_tuple); dispatch_to_wdp(e); } gateway-1.4.5/wap/wsp_push_client_states.def0000644000175000017500000001277413227613126017742 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_push_client_states.def: Macros defining wsp push client state table * rows. * See documentation for guidance how to use and update these. * 1 means an unconditional action, {} an ignored event. * * By Aarno Syvänen for Wapit Ltd. */ PUSH_CLIENT_STATE_NAME(PUSH_CLIENT_NULL_STATE) PUSH_CLIENT_STATE_NAME(PUSH_CLIENT_RECEIVING) ROW(PUSH_CLIENT_NULL_STATE, TR_Invoke_Ind, e->u.TR_Invoke_Ind.tcl == 1 && pdu->type == ConfirmedPush, { Octstr *push_body; List *push_headers; if (pdu->u.ConfirmedPush.headers_len > 0) push_headers = wsp_headers_unpack(pdu->u.ConfirmedPush.headers, 0); else push_headers = NULL; http_remove_hop_headers(push_headers); http_header_pack(push_headers); gw_assert(push_headers); cpm->push_headers = http_header_duplicate(push_headers); push_body = octstr_duplicate(pdu->u.ConfirmedPush.data); http_destroy_headers(push_headers); /* * For debugging: just tell about the push OTA event, and destroy it here - * handle_event does not do it. */ indicate_confirmedpush(cpm, push_body); octstr_destroy(push_body); /* * For debugging: create S_ConfirmedPush_Res by ourselves and send it to * ourselves. */ response_confirmedpush(cpm); }, PUSH_CLIENT_RECEIVING) ROW(PUSH_CLIENT_RECEIVING, S_ConfirmedPush_Res, 1, { response_responder_invoke(cpm); }, PUSH_CLIENT_NULL_STATE) ROW(PUSH_CLIENT_RECEIVING, S_PushAbort_Req, 1, { send_abort_to_responder(cpm, e->u.S_PushAbort_Req.reason); indicate_pushabort(cpm, e->u.S_PushAbort_Req.reason); }, PUSH_CLIENT_NULL_STATE) ROW(PUSH_CLIENT_RECEIVING, Abort_Event, 1, { send_abort_to_responder(cpm, e->u.S_PushAbort_Req.reason); indicate_pushabort(cpm, WSP_ABORT_USERREQ); }, PUSH_CLIENT_NULL_STATE) ROW(PUSH_CLIENT_RECEIVING, TR_Abort_Ind, e->u.TR_Abort_Ind.abort_code == WSP_ABORT_DISCONNECT, { WAPEvent *wsp_event; wsp_event = wap_event_create(Disconnect_Event); wsp_event->u.Disconnect_Event.session_handle = cpm->client_push_id; gwlist_append(push_client_queue, wsp_event); }, PUSH_CLIENT_NULL_STATE) ROW(PUSH_CLIENT_RECEIVING, TR_Abort_Ind, e->u.TR_Abort_Ind.abort_code == WSP_ABORT_SUSPEND, { WAPEvent *wsp_event; wsp_event = wap_event_create(Suspend_Event); wsp_event->u.Suspend_Event.session_handle = cpm->client_push_id; gwlist_append(push_client_queue, wsp_event); }, PUSH_CLIENT_NULL_STATE) ROW(PUSH_CLIENT_RECEIVING, TR_Abort_Ind, e->u.TR_Abort_Ind.abort_code != WSP_ABORT_DISCONNECT && e->u.TR_Abort_Ind.abort_code != WSP_ABORT_SUSPEND, { indicate_pushabort(cpm, e->u.S_PushAbort_Req.reason); }, PUSH_CLIENT_NULL_STATE) #undef PUSH_CLIENT_STATE_NAME #undef ROW gateway-1.4.5/wap/wtp_resp_states.def0000644000175000017500000005302513227613126016371 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Macro calls to generate rows of the state table. See the documentation for * guidance how to use and update these. * * Macros have following arguments: * * STATE_NAME(name of a wtp machine state) * * ROW(the name of the current state, * the event feeded to wtp machine, * the condition for the action, * {the action itself}, * the state wtp machine will transit) * * Condition 1 means that the action will be performed unconditionally, action * {} means that the event in question will be ignored (of course, the state * of the machine can change). * * There are many ROWS generating code for ignoring a certain event (ones hav- * ing {} as their action). In these cases the event in question is caused by a * duplicate message and the first one has already changed wtp responder mach- * ine. In this case ignoring the event is natural. * * State tables use the phrase "abort transaction" many times. In this imple- * mentation this means "clear data structures used for storing transaction * data". This happens in function resp_event_handle, after included state * table code. * * Commenting the state table is perhaps best done by pointing out how various * services provided by WTP contribute rows to the state table. * * Normal transaction goes as follows (timers excluded): * - WTP get an invoke pdu from the peer. WTP does TR-Invoke.ind (trans- * mitting to WSP its PDU) and the state changes to INVOKE_RESP_WAIT * - WSP does TR-Invoke.res, telling that it has handled the * indication. * The state changes to RESULT_WAIT. * - WSP tells that it has results from the content server, or reply * pdu to send. It does TR-Result.req. State changes to * RESULT_RESP_WAIT. * - WTP gets acknowledgement from the peer. It generates TR_Result.cnf * and state changes to LISTEN. The transaction is over. * * Retransmission until acknowledgement guarantees reliability of the trans- * action, if the peer stays up. It is implemented by using retransmissions * controlled by timers and counters. There are two kind of timers, retrans- * mission and acknowledgement timers. (Actually, there is one timer * iniatilised with two intervals. But let us keep the language simple). * These are used in concert with corresponding counters, RCR (retransmission * counter) and AEC (acknowledgement expiration counter). AEC counts expired * acknowledgement intervals. * * WTP starts an acknowledgement timer when it waits a WSP acknowledgement, * and retransmission timer when it sends something. So when the acknowledge_ * ment timer expires, the action is to increment AEC, and when the retrans- * mission timer expires, the action is to resend a packet. (Note, however, * the chapter concerning user acknowledgement.) * * WTP ignores invoke pdus having same tid as the current transaction. This * quarantees rejection of the duplicates. Note, however, how reliability is * achieved when WTP is doing tid verification (next chapter). * * Tid verification is done if tid validation fails (which happens when the * message is a duplicate or when tid wrapping-up could confuse the protocol). * In this case, the state changes to TIDOK_WAIT. WSP is indicated only after * an acknowledgement is received. After a negative answer (Abort PDU) the * transaction is teared down. Reliablity is quaranteed by resending, which * happens when WTP receives a resent invoke pdu, when its state TIDOK_WAIT. * Abort pdu now means a negative answer to a question "have you a transaction * having tid included in the tid verification message". So there is no need * to indicate WSP. * * Error handling is mostly done before feeding an event to the state machine. * However, when a pdu with an illegal header (header WTP does not understand) * is received, this is a special kind of event, because its handling depends * of the state. WTP must always send an abort pdu. If a transaction is * established, it must be teared down. If WSP has been indicated about a * transaction, WTP must do TR-Abort.ind. * * There are two kind of aborts: by the peer, when it sends abort pdu and by the * wsp, when it does a primitive TR-Abort.req. When WSP does an abort, WTP * must send an abort pdu to the peer; when WTP receives an abort, WSP must be * indicated (note, however, the special meaning abort pdu has in tid * verification; see the relevant chapter). * * User acknowledgement means that WTP waits WSP (which in most cases is WTP * user) acknowledgement, instead of doing it by itself. This means, that if * user acknowledgement flag is off, WTP sends an ack pdu when acknowledgement * timer expires. * * By Aarno Syvänen for WapIT Ltd. */ STATE_NAME(LISTEN) STATE_NAME(TIDOK_WAIT) STATE_NAME(INVOKE_RESP_WAIT) STATE_NAME(RESULT_WAIT) STATE_NAME(RESULT_RESP_WAIT) STATE_NAME(WAIT_TIMEOUT_STATE) ROW(LISTEN, RcvInvoke, (event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) && wtp_tid_is_valid(event, resp_machine) == ok, { resp_machine->u_ack = event->u.RcvInvoke.up_flag; resp_machine->tcl = event->u.RcvInvoke.tcl; wsp_event = create_tr_invoke_ind(resp_machine, event->u.RcvInvoke.user_data); if (resp_machine->tcl == 1) wsp_push_client_dispatch_event(wsp_event); else wsp_session_dispatch_event(wsp_event); start_timer_A(resp_machine); resp_machine->ack_pdu_sent = 0; }, INVOKE_RESP_WAIT) /* * We must here store event fields and wsp indication into the wtp responder * state machine: if tid is valid, we will continue the transaction without a * new event. */ ROW(LISTEN, RcvInvoke, (event->u.RcvInvoke.tcl == 2 || event->u.RcvInvoke.tcl == 1) && (wtp_tid_is_valid(event, resp_machine) == fail || wtp_tid_is_valid(event, resp_machine) == no_cached_tid), { send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid); resp_machine->u_ack = event->u.RcvInvoke.up_flag; resp_machine->tcl = event->u.RcvInvoke.tcl; resp_machine->invoke_indication = create_tr_invoke_ind(resp_machine, event->u.RcvInvoke.user_data); debug("wap.wtp", 0, "WTP_STATE: generating invoke indication, tid being" "invalid"); }, TIDOK_WAIT) /* * Do not change state when class 0 message is received. */ ROW(LISTEN, RcvInvoke, event->u.RcvInvoke.tcl == 0, { wsp_event = create_tr_invoke_ind(resp_machine, event->u.RcvInvoke.user_data); wsp_session_dispatch_event(wsp_event); }, LISTEN) /* * No user indication here: transaction is not yet started. */ ROW(LISTEN, RcvErrorPDU, 1, { send_abort(resp_machine, PROVIDER, PROTOERR); }, LISTEN) /* * Need to control SAR incomplete packets */ ROW(LISTEN, TimerTO_W, 1, {}, LISTEN) /* * We must cache the newly accepted tid item, otherwise every tid after a * suspected one will be validated. We use wsp event stored by the responder * machine. */ ROW(TIDOK_WAIT, RcvAck, (resp_machine->tcl == 2 || resp_machine->tcl == 1) && event->u.RcvAck.tid_ok == 1, { wsp_event = wap_event_duplicate(resp_machine->invoke_indication); if (resp_machine->tcl == 1) wsp_push_client_dispatch_event(wsp_event); else wsp_session_dispatch_event(wsp_event); wtp_tid_set_by_machine(resp_machine, event->u.RcvAck.tid); start_timer_A(resp_machine); resp_machine->ack_pdu_sent = 0; }, INVOKE_RESP_WAIT) /* * When we get a negative answer to tid verification, we just abort trans- * action. Because wtp machines are destroyed when their state return to * LISTEN and because no transaction is yet started, there is no need to do * anything here. */ ROW(TIDOK_WAIT, RcvAbort, 1, { }, LISTEN) ROW(TIDOK_WAIT, RcvInvoke, event->u.RcvInvoke.rid == 0, { }, TIDOK_WAIT) /* * Because the phone sends invoke again, previous ack was dropped by the * bearer. */ ROW(TIDOK_WAIT, RcvInvoke, event->u.RcvInvoke.rid == 1, { send_ack(resp_machine, TID_VERIFICATION, resp_machine->rid); }, TIDOK_WAIT) /* * No need for wsp indication: the transaction is not yet started. */ ROW(TIDOK_WAIT, RcvErrorPDU, 1, { send_abort(resp_machine, PROVIDER, PROTOERR); }, LISTEN) ROW(INVOKE_RESP_WAIT, RcvInvoke, 1, { }, INVOKE_RESP_WAIT) ROW(INVOKE_RESP_WAIT, TR_Invoke_Res, resp_machine->tcl == 2, { start_timer_A(resp_machine); resp_machine->aec = 0; }, RESULT_WAIT) ROW(INVOKE_RESP_WAIT, TR_Invoke_Res, resp_machine->tcl == 1, { send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid); start_timer_W(resp_machine); }, WAIT_TIMEOUT_STATE) ROW(INVOKE_RESP_WAIT, RcvAbort, 1, { wsp_event = create_tr_abort_ind(resp_machine, event->u.RcvAbort.abort_reason); if (resp_machine->tcl == 1) wsp_push_client_dispatch_event(wsp_event); else wsp_session_dispatch_event(wsp_event); }, LISTEN) ROW(INVOKE_RESP_WAIT, TR_Abort_Req, 1, { send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason); }, LISTEN) /* * non-SARed */ ROW(INVOKE_RESP_WAIT, TR_Result_Req, resp_machine->sar == NULL, { WAPEvent *result; resp_machine->rcr = 0; start_timer_R(resp_machine); wap_event_destroy(resp_machine->result); resp_machine->rid = 0; result = wtp_pack_result(resp_machine, event); resp_machine->result = wap_event_duplicate(result); dispatch_to_wdp(result); resp_machine->rid = 1; }, RESULT_RESP_WAIT) /* * SARed */ ROW(INVOKE_RESP_WAIT, TR_Result_Req, resp_machine->sar != NULL, { resp_machine->rcr = 0; start_timer_R(resp_machine); wap_event_destroy(resp_machine->result); resp_machine->rid = 0; begin_sar_result(resp_machine, event); }, RESULT_RESP_WAIT) /* * Conditions below do not correspond wholly ones found from the spec. (If * they does, user acknowledgement flag would never be used by the protocol, * which cannot be the original intention.) * User acknowledgement flag is used following way: if it is on, WTP does not * send an acknowledgement (user acknowledgement in form of TR-Invoke.res or * TR-Result.req instead of provider acknowledgement is awaited); if it is * off, WTP does this. IMHO, specs support this exegesis: there is condition * Uack == False && class == 2 with action send ack pdu. In addition, WTP * 8.3.1 says " When [user acknowledgement] is enabled WTP provider does not * respond to a received message until after WTP user has confirmed the * indication service primitive by issuing the response primitive". * * BTW: CR correcting this shall appear soonish. */ ROW(INVOKE_RESP_WAIT, TimerTO_A, resp_machine->aec < AEC_MAX && resp_machine->u_ack == 1, { ++resp_machine->aec; start_timer_A(resp_machine); }, INVOKE_RESP_WAIT) ROW(INVOKE_RESP_WAIT, TimerTO_A, (resp_machine->aec < AEC_MAX && resp_machine->u_ack == 0), { ++resp_machine->aec; start_timer_A(resp_machine); send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid); if (resp_machine->ack_pdu_sent == 0) resp_machine->ack_pdu_sent = 1; }, INVOKE_RESP_WAIT) /* * When a transaction is aborted, WSP must surely know this. One of corrections * in MOT_WTP_CR_01. What to do when a counter reaches its maximum value dep- * ends on whether we have opened the connection or not. In previous case, we * must go to the state WAIT_TIMEOUT_STATE, for instance to prevent bad incarn- * ations. */ ROW(INVOKE_RESP_WAIT, TimerTO_A, resp_machine->aec == AEC_MAX && resp_machine->tcl == 2, { send_abort(resp_machine, PROVIDER, NORESPONSE); wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE); wsp_session_dispatch_event(wsp_event); }, LISTEN) ROW(INVOKE_RESP_WAIT, TimerTO_A, resp_machine->aec == AEC_MAX && resp_machine->tcl == 1, { start_timer_W(resp_machine); }, WAIT_TIMEOUT_STATE) ROW(INVOKE_RESP_WAIT, RcvErrorPDU, 1, { send_abort(resp_machine, PROVIDER, PROTOERR); wsp_event = create_tr_abort_ind(resp_machine, PROTOERR); if (resp_machine->tcl == 1) wsp_push_client_dispatch_event(wsp_event); else wsp_session_dispatch_event(wsp_event); }, LISTEN) /* * Non-SARed */ ROW(RESULT_WAIT, TR_Result_Req, resp_machine->sar == NULL, { WAPEvent *result; resp_machine->rcr = 0; start_timer_R(resp_machine); wap_event_destroy(resp_machine->result); resp_machine->rid = 0; result = wtp_pack_result(resp_machine, event); resp_machine->result = wap_event_duplicate(result); dispatch_to_wdp(result); resp_machine->rid = 1; }, RESULT_RESP_WAIT) /* * SARed */ ROW(RESULT_WAIT, TR_Result_Req, (resp_machine->sar != NULL) && ((octstr_len(event->u.TR_Result_Req.user_data)-1)/SAR_SEGM_SIZE < 255), { resp_machine->rcr = 0; start_timer_R(resp_machine); wap_event_destroy(resp_machine->result); resp_machine->rid = 0; begin_sar_result(resp_machine, event); }, RESULT_RESP_WAIT) ROW(RESULT_WAIT, TR_Result_Req, (resp_machine->sar != NULL) && ((octstr_len(event->u.TR_Result_Req.user_data)-1)/SAR_SEGM_SIZE >= 255), { send_abort(resp_machine, PROVIDER, NOTIMPLEMENTEDESAR); wsp_event = create_tr_abort_ind(resp_machine, NOTIMPLEMENTEDESAR); wsp_session_dispatch_event(wsp_event); wap_event_destroy(resp_machine->result); }, LISTEN) ROW(RESULT_WAIT, RcvAbort, 1, { wsp_event = create_tr_abort_ind(resp_machine, event->u.RcvAbort.abort_reason); wsp_session_dispatch_event(wsp_event); }, LISTEN) ROW(RESULT_WAIT, RcvInvoke, event->u.RcvInvoke.rid == 0, { }, RESULT_WAIT) ROW(RESULT_WAIT, RcvInvoke, event->u.RcvInvoke.rid == 1 && resp_machine->ack_pdu_sent == 0, { }, RESULT_WAIT) ROW(RESULT_WAIT, RcvInvoke, event->u.RcvInvoke.rid == 1 && resp_machine->ack_pdu_sent == 1, { send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid); }, RESULT_WAIT) ROW(RESULT_WAIT, TR_Abort_Req, 1, { send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason); }, LISTEN) ROW(RESULT_WAIT, RcvErrorPDU, 1, { send_abort(resp_machine, PROVIDER, PROTOERR); wsp_event = create_tr_abort_ind(resp_machine, PROTOERR); wsp_session_dispatch_event(wsp_event); }, LISTEN) /* * This state follows two possible ones: INVOKE_RESP_WAIT & TR-Invoke.res and * INVOKE_RESP_WAIT & TimerTO_A & Class == 2 & Uack == FALSE. Contrary what * spec says, in first case we are now sending first time. We must, too, abort * after AEC_MAX timer periods. */ ROW(RESULT_WAIT, TimerTO_A, resp_machine->aec < AEC_MAX, { start_timer_A(resp_machine); send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid); if (resp_machine->ack_pdu_sent == 0) resp_machine->ack_pdu_sent = 1; resp_machine->aec++; }, RESULT_WAIT) ROW(RESULT_WAIT, TimerTO_A, resp_machine->aec == AEC_MAX, { send_abort(resp_machine, PROVIDER, NORESPONSE); wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE); wsp_session_dispatch_event(wsp_event); }, LISTEN) /* * A duplicate ack(tidok) caused by a heavy load (the original changed state * from TIDOK_WAIT). This implements CR-Nokia-WTP-20-March-2000/2. */ ROW(RESULT_WAIT, RcvAck, event->u.RcvAck.tid_ok, {}, RESULT_WAIT) /* * Non-SARed */ ROW(RESULT_RESP_WAIT, RcvAck, resp_machine->sar == NULL || event->u.RcvAck.psn == resp_machine->sar->nsegm, { wsp_event = create_tr_result_cnf(resp_machine); wsp_session_dispatch_event(wsp_event); }, LISTEN) /* * SARed */ ROW(RESULT_RESP_WAIT, RcvAck, resp_machine->sar != NULL && event->u.RcvAck.psn != resp_machine->sar->nsegm, { continue_sar_result(resp_machine, event); }, RESULT_RESP_WAIT) ROW(RESULT_RESP_WAIT, RcvNegativeAck, resp_machine->sar != NULL, { resend_sar_result(resp_machine, event); }, RESULT_RESP_WAIT) /* * Specs does not tell what to do, when wtp responder receives invoke pdu and * its state is RESULT_RESP_WAIT. This can happen, however: event causing the * transition RESULT_WAIT -> RESULT_RESP_WAIT is TR-Result.req, an internal * responder event. */ ROW(RESULT_RESP_WAIT, RcvInvoke, 1, { }, RESULT_RESP_WAIT) ROW(RESULT_RESP_WAIT, RcvAbort, 1, { wsp_event = create_tr_abort_ind(resp_machine, event->u.RcvAbort.abort_reason); wsp_session_dispatch_event(wsp_event); }, LISTEN) ROW(RESULT_RESP_WAIT, TR_Abort_Req, 1, { send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason); }, LISTEN) ROW(RESULT_RESP_WAIT, TimerTO_R, resp_machine->rcr < MAX_RCR, { WAPEvent *resend; start_timer_R(resp_machine); resend = wap_event_duplicate(resp_machine->result); wtp_pack_set_rid(resend, resp_machine->rid); dispatch_to_wdp(resend); ++resp_machine->rcr; }, RESULT_RESP_WAIT) ROW(RESULT_RESP_WAIT, TimerTO_R, resp_machine->rcr == MAX_RCR, { send_abort(resp_machine, PROVIDER, NORESPONSE); wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE); wsp_session_dispatch_event(wsp_event); }, LISTEN) ROW(RESULT_RESP_WAIT, RcvErrorPDU, 1, { send_abort(resp_machine, PROVIDER, PROTOERR); wsp_event = create_tr_abort_ind(resp_machine, PROTOERR); wsp_session_dispatch_event(wsp_event); }, LISTEN) ROW(WAIT_TIMEOUT_STATE, RcvInvoke, event->u.RcvInvoke.rid == 0, { }, WAIT_TIMEOUT_STATE) ROW(WAIT_TIMEOUT_STATE, RcvInvoke, event->u.RcvInvoke.rid == 1, { send_ack(resp_machine, ACKNOWLEDGEMENT, resp_machine->rid); }, WAIT_TIMEOUT_STATE) ROW(WAIT_TIMEOUT_STATE, RcvErrorPDU, 1, { send_abort(resp_machine, PROVIDER, PROTOERR); wsp_event = create_tr_abort_ind(resp_machine, PROTOERR); wsp_push_client_dispatch_event(wsp_event); }, LISTEN) ROW(WAIT_TIMEOUT_STATE, RcvAbort, 1, { wsp_event = create_tr_abort_ind(resp_machine, PROTOERR); wsp_push_client_dispatch_event(wsp_event); }, LISTEN) /* * Waiting to prevent premature incarnations. */ ROW(WAIT_TIMEOUT_STATE, TimerTO_W, 1, { wsp_event = create_tr_abort_ind(resp_machine, NORESPONSE); wsp_push_client_dispatch_event(wsp_event); }, LISTEN) ROW(WAIT_TIMEOUT_STATE, TR_Abort_Req, 1, { send_abort(resp_machine, USER, event->u.TR_Abort_Req.abort_reason); }, LISTEN) #undef ROW #undef STATE_NAME gateway-1.4.5/wap/wsp_caps.c0000644000175000017500000002135213227613126014444 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wsp_caps.c - implement interface to WSP capability negotiation * * Richard Braakman */ #include "gwlib/gwlib.h" #include "wsp_caps.h" static void wsp_cap_destroy_item(void *cap) { wsp_cap_destroy(cap); } Capability *wsp_cap_create(int id, Octstr *name, Octstr *data) { Capability *new_cap; new_cap = gw_malloc(sizeof(*new_cap)); new_cap->id = id; new_cap->name = name; new_cap->data = data; new_cap->accept = 0; return new_cap; } void wsp_cap_destroy(Capability *cap) { if (cap == NULL) return; octstr_destroy(cap->name); octstr_destroy(cap->data); gw_free(cap); } void wsp_cap_dump(Capability *cap) { debug("wsp", 0, "Dumping capability at %p:", cap); if (cap) { debug("wsp", 0, " id = %d", cap->id); debug("wsp", 0, " name:"); octstr_dump(cap->name, 1); debug("wsp", 0, " data:"); octstr_dump(cap->data, 1); if (cap->data == NULL) debug("wsp", 0, " accept: %d", cap->accept); } debug("wsp", 0, "Capability dump ends."); } void wsp_cap_dump_list(List *caps_list) { long i; if (caps_list == NULL) { debug("wsp", 0, "NULL capability list"); return; } debug("wsp", 0, "Dumping capability list at %p, length %ld", caps_list, gwlist_len(caps_list)); for (i = 0; i < gwlist_len(caps_list); i++) { wsp_cap_dump(gwlist_get(caps_list, i)); } debug("wsp", 0, "End of capability list dump"); } void wsp_cap_destroy_list(List *caps_list) { gwlist_destroy(caps_list, wsp_cap_destroy_item); } List *wsp_cap_duplicate_list(List *caps_list) { Capability *cap; List *new_list; long i; new_list = gwlist_create(); if (caps_list == NULL) return new_list; for (i = 0; i < gwlist_len(caps_list); i++) { cap = gwlist_get(caps_list, i); gwlist_append(new_list, wsp_cap_duplicate(cap)); } return new_list; }; Capability *wsp_cap_duplicate(Capability *cap) { Capability *new_cap; if (!cap) return NULL; new_cap = wsp_cap_create(cap->id, octstr_duplicate(cap->name), octstr_duplicate(cap->data)); new_cap->accept = cap->accept; return new_cap; } List *wsp_cap_unpack_list(Octstr *caps) { List *caps_list; long pos, capslen; caps_list = gwlist_create(); if (caps == NULL) return caps_list; capslen = octstr_len(caps); pos = 0; while (pos < capslen) { unsigned long length; int id; Octstr *name; Octstr *data; pos = octstr_extract_uintvar(caps, &length, pos); if (pos < 0 || length == 0) goto error; id = octstr_get_char(caps, pos); if (id >= 0x80) { id &= 0x7f; /* It's encoded as a short-integer */ name = NULL; data = octstr_copy(caps, pos + 1, length - 1); } else { long nullpos; id = -1; /* It's encoded as token-text */ nullpos = octstr_search_char(caps, 0, pos); if (nullpos < 0) goto error; /* check length * FIXME: If it's not allowed that data is empty then change check * to <= . */ if (length < (nullpos + 1 - pos)) goto error; name = octstr_copy(caps, pos, nullpos - pos); data = octstr_copy(caps, nullpos + 1, length - (nullpos + 1 - pos)); } gwlist_append(caps_list, wsp_cap_create(id, name, data)); pos += length; } return caps_list; error: warning(0, "WSP: Error unpacking capabilities"); return caps_list; } Octstr *wsp_cap_pack_list(List *caps_list) { Octstr *result; Capability *cap; long i, len; result = octstr_create(""); len = gwlist_len(caps_list); for (i = 0; i < len; i++) { long datalen; cap = gwlist_get(caps_list, i); datalen = 0; if (cap->data) datalen = octstr_len(cap->data); if (datalen == 0 && cap->accept) continue; if (cap->name) { if (octstr_get_char(cap->name, 0) >= 0x80 || octstr_search_char(cap->name, 0, 0) >= 0) { error(0, "WSP: Bad capability."); wsp_cap_dump(cap); continue; } /* Add length */ octstr_append_uintvar(result, octstr_len(cap->name) + 1 + datalen); /* Add identifier */ octstr_append(result, cap->name); octstr_append_char(result, 0); } else { if (cap->id >= 0x80 || cap->id < 0) { error(0, "WSP: Bad capability."); wsp_cap_dump(cap); continue; } /* Add length */ octstr_append_uintvar(result, 1 + datalen); /* Add identifier */ octstr_append_char(result, 0x80 | cap->id); } /* Add payload, if any */ if (cap->data) { octstr_append(result, cap->data); } } return result; } static int wsp_cap_get_data(List *caps_list, int id, Octstr *name, Octstr **data) { long i, len; Capability *cap; int found; len = gwlist_len(caps_list); found = 0; *data = NULL; for (i = 0; i < len; i++) { cap = gwlist_get(caps_list, i); if ((name && cap->name && octstr_compare(name, cap->name) == 0) || (!name && cap->id == id)) { if (!found) *data = cap->data; found++; } } return found; } int wsp_cap_count(List *caps_list, int id, Octstr *name) { Octstr *data; return wsp_cap_get_data(caps_list, id, name, &data); } int wsp_cap_get_client_sdu(List *caps_list, unsigned long *sdu) { Octstr *data; int found; found = wsp_cap_get_data(caps_list, WSP_CAPS_CLIENT_SDU_SIZE, NULL, &data); if (found > 0 && octstr_extract_uintvar(data, sdu, 0) < 0) return -1; return found; } int wsp_cap_get_server_sdu(List *caps_list, unsigned long *sdu) { Octstr *data; int found; found = wsp_cap_get_data(caps_list, WSP_CAPS_SERVER_SDU_SIZE, NULL, &data); if (found > 0 && octstr_extract_uintvar(data, sdu, 0) < 0) return -1; return found; } int wsp_cap_get_method_mor(List *caps_list, unsigned long *mor) { Octstr *data; int found; int c; found = wsp_cap_get_data(caps_list, WSP_CAPS_METHOD_MOR, NULL, &data); if (found > 0) { c = octstr_get_char(data, 0); if (c < 0) return -1; *mor = c; } return found; } int wsp_cap_get_push_mor(List *caps_list, unsigned long *mor) { Octstr *data; int found; int c; found = wsp_cap_get_data(caps_list, WSP_CAPS_PUSH_MOR, NULL, &data); if (found > 0) { c = octstr_get_char(data, 0); if (c < 0) return -1; *mor = c; } return found; } gateway-1.4.5/wap/wtp_init.h0000644000175000017500000000732313227613126014471 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * WTP initiator header * * Aarno Syvänen for Wapit Ltd */ #ifndef WTP_INIT_H #define WTP_INIT_H #include "gwlib/gwlib.h" #include "wap_addr.h" #include "wap_events.h" #include "timers.h" /* * Initiator machine states and initiator WTP machine. * See included file for comments. Note that we must define macro * ROW to produce an empty string. */ enum init_states { #define INIT_STATE_NAME(state) state, #define ROW(state, event, condition, action, next_state) #include "wtp_init_states.def" init_states_count }; typedef enum init_states init_states; /* * See included file for comments. We define one macro for * every separate type. */ typedef struct WTPInitMachine { unsigned long mid; #define INTEGER(name) int name; #define EVENT(name) WAPEvent *name; #define TIMER(name) Timer *name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define ENUM(name) init_states name; #define MACHINE(field) field #include "wtp_init_machine.def" } WTPInitMachine; #endif gateway-1.4.5/wap/wsp_server_session_machine.def0000644000175000017500000000721113227613126020565 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_server_session_machine.def - Define a WSP session machine. * * Lars Wirzenius */ #if !defined(HTTPHEADERS) || \ !defined(INTEGER) || \ !defined(OCTSTR) || \ !defined(ADDRTUPLE) || \ !defined(COOKIES) || \ !defined(MACHINESLIST) || \ !defined(CAPABILITIES) || \ !defined(MACHINE) || \ !defined(REFERER) #error "Some required macro is missing." #endif MACHINE( INTEGER(state) INTEGER(connect_handle) INTEGER(resume_handle) INTEGER(session_id) ADDRTUPLE(addr_tuple) CAPABILITIES(request_caps) CAPABILITIES(reply_caps) INTEGER(MOR_push) INTEGER(client_SDU_size) INTEGER(encoding_version) HTTPHEADERS(http_headers) COOKIES(cookies) REFERER(referer_url) MACHINESLIST(methodmachines) MACHINESLIST(pushmachines) ) #undef INTEGER #undef OCTSTR #undef HTTPHEADERS #undef ADDRTUPLE #undef MACHINESLIST #undef MACHINE #undef COOKIES #undef CAPABILITIES #undef REFERER gateway-1.4.5/wap/cookies.h0000644000175000017500000000744113227613126014271 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Module: cookies.h * * Description: Include module for cookies.c * * References: RFC 2109 * * Author: Paul Keogh, ANAM Wireless Internet Solutions * * Date: May 2000 */ #ifndef COOKIES_H #define COOKIES_H /* No support for Secure or Comment fields */ typedef struct _cookie { Octstr *name; Octstr *value; Octstr *version; Octstr *domain; Octstr *path; time_t max_age; time_t birth; } Cookie; /* Function prototypes for external interface */ /* * Memory management wrappers for cookies. */ Cookie *cookie_create(void); void cookies_destroy(List*); /* * Parses the returned HTTP headers and adds the Cookie: headers to * the cookie cache of the active WSPMachine. * Returns: 0 on success, -1 on failure */ int get_cookies(List*, const WSPMachine*); /* * Adds the cookies from the WSPMachine cache to the outgoing HTTP request, * rewriting the standard attributes and expiring the cookies if necessary. * Returns: 0 on success, -1 on failure */ int set_cookies(List*, WSPMachine*); #define MAX_HTTP_DATE_LENGTH 128 #endif gateway-1.4.5/wap/wtp.c0000644000175000017500000003446013227613126013443 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp.c - WTP common functions implementation * * Aarno Syvänen * Lars Wirzenius */ #include "wtp.h" #include "wap_events.h" #include "wtp_pdu.h" /***************************************************************************** * * Prototypes of internal functions: * * Parse a datagram event (T-DUnitdata.ind) to create a corresponding * WTPEvents list object. Also check that the datagram is syntactically * valid. Return a pointer to the event structure that has been created. * This will be a RcvError packet if there was a problem unpacking the * datagram. */ static WAPEvent *unpack_wdp_datagram_real(WAPEvent *datagram); static int deduce_tid(Octstr *user_data); static int concatenated_message(Octstr *user_data); static int truncated_datagram(WAPEvent *event); static WAPEvent *unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple); static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple); static WAPEvent *unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple); static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple); static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple); static WAPEvent *unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple); static WAPEvent *pack_error(WAPEvent *datagram); /****************************************************************************** * * EXTERNAL FUNCTIONS: * * Handles a possible concatenated message. Creates a list of wap events. */ List *wtp_unpack_wdp_datagram(WAPEvent *datagram) { List *events = NULL; WAPEvent *event = NULL; WAPEvent *subdgram = NULL; Octstr *data = NULL; long pdu_len; gw_assert(datagram->type == T_DUnitdata_Ind); events = gwlist_create(); if (concatenated_message(datagram->u.T_DUnitdata_Ind.user_data)) { data = octstr_duplicate(datagram->u.T_DUnitdata_Ind.user_data); octstr_delete(data, 0, 1); while (octstr_len(data) != 0) { if (octstr_get_bits(data, 0, 1) == 0) { pdu_len = octstr_get_char(data, 0); octstr_delete(data, 0, 1); } else { pdu_len = octstr_get_bits(data, 1, 15); octstr_delete(data, 0, 2); } subdgram = wap_event_duplicate(datagram); octstr_destroy(subdgram->u.T_DUnitdata_Ind.user_data); subdgram->u.T_DUnitdata_Ind.user_data = octstr_copy(data, 0, pdu_len); wap_event_assert(subdgram); if ((event = unpack_wdp_datagram_real(subdgram)) != NULL) { wap_event_assert(event); gwlist_append(events, event); } octstr_delete(data, 0, pdu_len); wap_event_destroy(subdgram); } octstr_destroy(data); } else if ((event = unpack_wdp_datagram_real(datagram)) != NULL) { wap_event_assert(event); gwlist_append(events, event); } else { warning(0, "WTP: Dropping unhandled datagram data:"); octstr_dump(datagram->u.T_DUnitdata_Ind.user_data, 0, GW_WARNING); } return events; } /* * Responder set the first bit of the tid field. If we get a packet from the * responder, we are the initiator and vice versa. * * Return 1, when the event is for responder, 0 when it is for initiator and * -1 when error. */ int wtp_event_is_for_responder(WAPEvent *event) { switch(event->type){ case RcvInvoke: return event->u.RcvInvoke.tid < INITIATOR_TID_LIMIT; case RcvSegInvoke: return event->u.RcvSegInvoke.tid < INITIATOR_TID_LIMIT; case RcvResult: return event->u.RcvResult.tid < INITIATOR_TID_LIMIT; case RcvAck: return event->u.RcvAck.tid < INITIATOR_TID_LIMIT; case RcvNegativeAck: return event->u.RcvNegativeAck.tid < INITIATOR_TID_LIMIT; case RcvAbort: return event->u.RcvAbort.tid < INITIATOR_TID_LIMIT; case RcvErrorPDU: return event->u.RcvErrorPDU.tid < INITIATOR_TID_LIMIT; default: error(1, "Received an erroneous PDU corresponding an event"); wap_event_dump(event); return -1; } } /***************************************************************************** * * INTERNAL FUNCTIONS: * * If pdu was truncated, tid cannot be trusted. We ignore this message. */ static int truncated_datagram(WAPEvent *dgram) { gw_assert(dgram->type == T_DUnitdata_Ind); if (octstr_len(dgram->u.T_DUnitdata_Ind.user_data) < 3) { debug("wap.wtp", 0, "A too short PDU received"); wap_event_dump(dgram); return 1; } else return 0; } static WAPEvent *unpack_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple) { WAPEvent *event; event = wap_event_create(RcvInvoke); event->u.RcvInvoke.user_data = octstr_duplicate(pdu->u.Invoke.user_data); event->u.RcvInvoke.tcl = pdu->u.Invoke.class; event->u.RcvInvoke.tid = pdu->u.Invoke.tid; event->u.RcvInvoke.tid_new = pdu->u.Invoke.tidnew; event->u.RcvInvoke.rid = pdu->u.Invoke.rid; event->u.RcvInvoke.up_flag = pdu->u.Invoke.uack; event->u.RcvInvoke.no_cache_supported = 0; event->u.RcvInvoke.version = pdu->u.Invoke.version; event->u.RcvInvoke.gtr = pdu->u.Invoke.gtr; event->u.RcvInvoke.ttr = pdu->u.Invoke.ttr; event->u.RcvInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple); return event; } static WAPEvent *unpack_segmented_invoke(WTP_PDU *pdu, WAPAddrTuple *addr_tuple) { WAPEvent *event; event = wap_event_create(RcvSegInvoke); event->u.RcvSegInvoke.user_data = octstr_duplicate(pdu->u.Segmented_invoke.user_data); event->u.RcvSegInvoke.tid = pdu->u.Segmented_invoke.tid; event->u.RcvSegInvoke.rid = pdu->u.Segmented_invoke.rid; event->u.RcvSegInvoke.no_cache_supported = 0; event->u.RcvSegInvoke.gtr = pdu->u.Segmented_invoke.gtr; event->u.RcvSegInvoke.ttr = pdu->u.Segmented_invoke.ttr; event->u.RcvSegInvoke.psn = pdu->u.Segmented_invoke.psn; event->u.RcvSegInvoke.addr_tuple = wap_addr_tuple_duplicate(addr_tuple); return event; } static WAPEvent *unpack_result(WTP_PDU *pdu, WAPAddrTuple *addr_tuple) { WAPEvent *event; event = wap_event_create(RcvResult); event->u.RcvResult.user_data = octstr_duplicate(pdu->u.Result.user_data); event->u.RcvResult.tid = pdu->u.Result.tid; event->u.RcvResult.rid = pdu->u.Result.rid; event->u.RcvResult.gtr = pdu->u.Result.gtr; event->u.RcvResult.ttr = pdu->u.Result.ttr; event->u.RcvResult.addr_tuple = wap_addr_tuple_duplicate(addr_tuple); return event; } static WAPEvent *unpack_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple) { WAPEvent *event; WTP_TPI *tpi; int i, num_tpis; event = wap_event_create(RcvAck); event->u.RcvAck.tid = pdu->u.Ack.tid; event->u.RcvAck.tid_ok = pdu->u.Ack.tidverify; event->u.RcvAck.rid = pdu->u.Ack.rid; event->u.RcvAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple); /* Set default to 0 because Ack on 1 piece message has no tpi */ event->u.RcvAck.psn = 0; num_tpis = gwlist_len(pdu->options); for (i = 0; i < num_tpis; i++) { tpi = gwlist_get(pdu->options, i); if (tpi->type == TPI_PSN) { event->u.RcvAck.psn = octstr_get_bits(tpi->data,0,8); break; } } return event; } static WAPEvent *unpack_negative_ack(WTP_PDU *pdu, WAPAddrTuple *addr_tuple) { WAPEvent *event; event = wap_event_create(RcvNegativeAck); event->u.RcvNegativeAck.tid = pdu->u.Negative_ack.tid; event->u.RcvNegativeAck.rid = pdu->u.Negative_ack.rid; event->u.RcvNegativeAck.nmissing = pdu->u.Negative_ack.nmissing; event->u.RcvNegativeAck.missing = octstr_duplicate(pdu->u.Negative_ack.missing); event->u.RcvNegativeAck.addr_tuple = wap_addr_tuple_duplicate(addr_tuple); return event; } static WAPEvent *unpack_abort(WTP_PDU *pdu, WAPAddrTuple *addr_tuple) { WAPEvent *event; event = wap_event_create(RcvAbort); event->u.RcvAbort.tid = pdu->u.Abort.tid; event->u.RcvAbort.abort_type = pdu->u.Abort.abort_type; event->u.RcvAbort.abort_reason = pdu->u.Abort.abort_reason; event->u.RcvAbort.addr_tuple = wap_addr_tuple_duplicate(addr_tuple); return event; } static WAPEvent *pack_error(WAPEvent *datagram) { WAPEvent *event; gw_assert(datagram->type == T_DUnitdata_Ind); event = wap_event_create(RcvErrorPDU); event->u.RcvErrorPDU.tid = deduce_tid(datagram->u.T_DUnitdata_Ind.user_data); event->u.RcvErrorPDU.addr_tuple = wap_addr_tuple_duplicate(datagram->u.T_DUnitdata_Ind.addr_tuple); return event; } /* * Transfers data from fields of a message to fields of WTP event. User data * has the host byte order. Updates the log. * * This function does incoming events check nro 4 (checking illegal headers * WTP 10.2). * * Return event, when we have a partially correct message or the message * received has illegal header (WTP 10.2 nro 4); NULL, when the message was * truncated or unpacking function returned NULL. */ WAPEvent *unpack_wdp_datagram_real(WAPEvent *datagram) { WTP_PDU *pdu; WAPEvent *event; Octstr *data; gw_assert(datagram->type == T_DUnitdata_Ind); data = datagram->u.T_DUnitdata_Ind.user_data; if (truncated_datagram(datagram)) { warning(0, "WTP: got a truncated datagram, ignoring"); return NULL; } pdu = wtp_pdu_unpack(data); /* * wtp_pdu_unpack returned NULL, we have send here a rcv error event, * but now we silently drop the packet. Because we can't figure out * in the pack_error() call if the TID value and hence the direction * inditation is really for initiator or responder. */ if (pdu == NULL) { error(0, "WTP: cannot unpack pdu, dropping packet."); return NULL; } event = NULL; switch (pdu->type) { case Invoke: event = unpack_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple); /* if an WTP initiator gets invoke, it would be an illegal pdu. */ if (!wtp_event_is_for_responder(event)){ debug("wap.wtp", 0, "WTP: Invoke when initiator. Message was"); wap_event_destroy(event); event = pack_error(datagram); } break; case Segmented_invoke: event = unpack_segmented_invoke(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple); break; case Result: event = unpack_result(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple); /* if an WTP responder gets result, it would be an illegal pdu. */ if (wtp_event_is_for_responder(event)){ debug("wap.wtp", 0, "WTP: Result when responder. Message was"); wap_event_destroy(event); event = pack_error(datagram); } break; case Ack: event = unpack_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple); break; case Negative_ack: event = unpack_negative_ack(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple); break; case Abort: event = unpack_abort(pdu, datagram->u.T_DUnitdata_Ind.addr_tuple); break; default: event = pack_error(datagram); debug("wap.wtp", 0, "WTP: Unhandled PDU type. Message was"); wap_event_dump(datagram); return event; } wtp_pdu_destroy(pdu); wap_event_assert(event); return event; } /* * Used for debugging and when wtp unpack does not return a tid. We include * first bit; it tells does message received belong to the initiator or to the * responder. */ static int deduce_tid(Octstr *user_data) { return octstr_get_bits(user_data, 8, 16); } static int concatenated_message(Octstr *user_data) { return octstr_get_char(user_data, 0) == 0x00; } gateway-1.4.5/wap/wsp_server_push_machine.def0000644000175000017500000000672213227613126020067 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_server_push_machine.def: Macro calls to generate monotonous push * machine code. See documentation for guidance how to update these. * * By Aarno Syvänen for Wapit Ltd */ #if !defined(MACHINE) #error "Definition of macro MACHINE is missing" #elif !defined(INTEGER) #error "Definition of macro INTEGER is missing" #elif !defined(ADDRTUPLE) #error "Definition of macro ADDRTUPLE is missing" #elif !defined(HTTPHEADER) #error "Definition of macro HTTPHEADER is missing" #endif MACHINE( INTEGER(state) INTEGER(server_push_id) INTEGER(session_id) INTEGER(transaction_id) ADDRTUPLE(addr_tuple) HTTPHEADER(push_header) ) #undef MACHINE #undef INTEGER #undef ADDRTUPLE #undef HTTPHEADER #undef OCTSTR gateway-1.4.5/wap/wsp_caps.h0000644000175000017500000001163313227613126014452 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wsp_caps.h - interface to WSP capability negotiation * * Richard Braakman */ #ifndef WSP_CAPS_H #define WSP_CAPS_H #include "gwlib/gwlib.h" struct capability { /* One or the other of these is set. id is only meaningful * if name is NULL. (Unfortunately the WSP spec does not * really assign names to the numeric ids, so we can't translate * them all to text.) */ int id; Octstr *name; /* Raw data for this capability. Can be NULL if there is none. */ Octstr *data; /* If data is NULL, this field determines if the request should * be accepted or rejected. */ int accept; }; typedef struct capability Capability; /* See table 37 */ enum known_caps { WSP_CAPS_CLIENT_SDU_SIZE = 0, WSP_CAPS_SERVER_SDU_SIZE = 1, WSP_CAPS_PROTOCOL_OPTIONS = 2, WSP_CAPS_METHOD_MOR = 3, WSP_CAPS_PUSH_MOR = 4, WSP_CAPS_EXTENDED_METHODS = 5, WSP_CAPS_HEADER_CODE_PAGES = 6, WSP_CAPS_ALIASES = 7, WSP_NUM_CAPS }; /* Create a new Capability structure. For numbered capabilities (which * is all of the known ones), use NULL for the name. The data may also * be NULL. */ Capability *wsp_cap_create(int id, Octstr *name, Octstr *data); void wsp_cap_destroy(Capability *cap); void wsp_cap_dump(Capability *cap); void wsp_cap_dump_list(List *caps_list); /* Destroy all Capabilities in a list, as well as the list itself. */ void wsp_cap_destroy_list(List *caps_list); /* Duplicate a list of Capabilities */ List *wsp_cap_duplicate_list(List *cap); Capability *wsp_cap_duplicate(Capability *cap); /* Return a list of Capability structures */ List *wsp_cap_unpack_list(Octstr *caps); /* Encode a list of Capability structures according to the WSP spec */ Octstr *wsp_cap_pack_list(List *caps_list); /* Access functions. All of them return the number of requests that * match the capability being searched for, and if they have an output * parameter, they set it to the value of the first such request. */ int wsp_cap_count(List *caps_list, int id, Octstr *name); int wsp_cap_get_client_sdu(List *caps_list, unsigned long *sdu); int wsp_cap_get_server_sdu(List *caps_list, unsigned long *sdu); int wsp_cap_get_method_mor(List *caps_list, unsigned long *mor); int wsp_cap_get_push_mor(List *caps_list, unsigned long *mor); #endif gateway-1.4.5/wap/wtp_pdu.h0000644000175000017500000001026013227613126014310 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wtp_pdu.h - definitions for unpacked WTP protocol data units * * This file generates a structure definition and some function * declarations from wtp_pdu.def, using preprocessor magic. * * Richard Braakman */ #ifndef WTP_PDU_H #define WTP_PDU_H #include "gwlib/gwlib.h" struct wtp_tpi { int type; Octstr *data; }; typedef struct wtp_tpi WTP_TPI; /* Enumerate the symbolic names of the PDUs */ enum wtp_pdu_types { #define PDU(name, docstring, fields, is_valid) name, #include "wtp_pdu.def" #undef PDU }; struct wtp_pdu { int type; List *options; /* List of WTP_TPI */ union { /* For each PDU, declare a structure with its fields, named after the PDU */ #define PDU(name, docstring, fields, is_valid) struct name { fields } name; #define UINT(field, docstring, bits) unsigned long field; #define UINTVAR(field, docstring) unsigned long field; #define OCTSTR(field, docstring, lengthfield) Octstr *field; #define REST(field, docstring) Octstr *field; #define TYPE(bits, value) #define RESERVED(bits) #define TPI(confield) #include "wtp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU } u; }; typedef struct wtp_pdu WTP_PDU; void wtp_pdu_append_tpi(WTP_PDU *pdu, int type, Octstr *data); WTP_PDU *wtp_pdu_create(int type); WTP_PDU *wtp_pdu_unpack(Octstr *data); Octstr *wtp_pdu_pack(WTP_PDU *pdu); void wtp_pdu_dump(WTP_PDU *pdu, int level); void wtp_pdu_destroy(WTP_PDU *pdu); void wtp_tpi_destroy(WTP_TPI *tpi); #endif gateway-1.4.5/wap/wtp_init_states.def0000644000175000017500000002101013227613126016350 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_init_state.h: Macro calls for implementing wtp initiator state tables * See documentation for guidance how to use and update these. * * Only classes 0 and 1 are implemented. State NULL is called INITIATOR_NULL_ * STATE. 1 in the action field means that action is unconditional. * * Class 0 service is here a stateless invoke message (used for disconnection * or unconfirmed push). * * Basic class 1 transaction, without timers, is following: * - initiator sends an invoke message to the responder * - responder acknowledges it, with an pdu with tid verification * off (if it is on, we have a tid verification transaction, * see below). * * Retransmission until acknowledgement is implemented using timers and * retransmission counters. When the initiator sends an invoke it starts a * timer. When it expires, it resends the packet (either ack or invoke), until * counter reaches the maximum value. Then the transaction is aborted. * * If user acknowledgement is on, timers have different values. * * When the initiator aborts the transaction, it sends an abort pdu. When the * responder does it, the initiator wtp user is indicated. * * Tid verification in the initiator means answering the question posed by the * responder: "Have you an outstanding transaction having this tid". If we do * not have it, we have already, before feeding the event into the state * machine, sent an abort with reason INVALIDTID. So here we answer to an * ack pdu with tidve-flag set with an ack pdu with tidok-flag set. See WTP * 5.6, table 2; WTP 8.9; WTP 9.3.4.1. * * By Aarno Syvänen for Wapit Ltd. */ INIT_STATE_NAME(INITIATOR_NULL_STATE) INIT_STATE_NAME(INITIATOR_RESULT_WAIT) /* * We do not use transaction class 2 here: Server is initiator only when it is * pushing (class 1 or class 0) or disconnecting (class 0). First and second * rows are similar, with exception of timer period. */ ROW(INITIATOR_NULL_STATE, TR_Invoke_Req, event->u.TR_Invoke_Req.tcl == 1, { WAPEvent *invoke; /* * A special counter is used for storing value used (1) for tidnew flag when * restarting (See WTP 8.8.3.2) */ init_machine->tidnew = tidnew; wap_event_destroy(init_machine->invoke); init_machine->rid = 0; init_machine->rcr = 0; invoke = wtp_pack_invoke(init_machine, event); init_machine->invoke = wap_event_duplicate(invoke); dispatch_to_wdp(invoke); init_machine->rid = 1; /* * Turn the tidnew-flag off if it was on. (This can happen when tid was * wrapped or when we are restarting, see WTP 8.8.3.2) */ if (init_machine->tidnew) { init_machine->tidnew = 0; tidnew = 0; } init_machine->u_ack = event->u.TR_Invoke_Req.up_flag; init_machine->rcr = 0; start_initiator_timer_R(init_machine); }, INITIATOR_RESULT_WAIT) /* * No need to turn tidnew flag when sending class 0 message; tid validation is * not invoked in this case. */ ROW(INITIATOR_NULL_STATE, TR_Invoke_Req, event->u.TR_Invoke_Req.tcl == 0, { WAPEvent *invoke; wap_event_destroy(init_machine->invoke); invoke = wtp_pack_invoke(init_machine, event); init_machine->invoke = wap_event_duplicate(invoke); dispatch_to_wdp(invoke); }, INITIATOR_NULL_STATE) ROW(INITIATOR_RESULT_WAIT, TR_Abort_Req, 1, { send_abort(init_machine, USER, event->u.TR_Abort_Req.abort_reason); }, INITIATOR_NULL_STATE) /* * Neither we check transaction class here: this can only be acknowledgement of * class 1 transaction. */ ROW(INITIATOR_RESULT_WAIT, RcvAck, event->u.RcvAck.tid_ok == 0, { stop_initiator_timer(init_machine->timer); wsp_event = create_tr_invoke_cnf(init_machine); dispatch_to_wsp(wsp_event); }, INITIATOR_NULL_STATE) /* * This is a positive answer to a tid verification (negative one being * already sent by init_machine_find_or_create). */ ROW(INITIATOR_RESULT_WAIT, RcvAck, event->u.RcvAck.tid_ok == 1 && init_machine->rcr < MAX_RCR, { send_ack(init_machine, TID_VERIFICATION, init_machine->rid); init_machine->tidok_sent = 1; ++init_machine->rcr; start_initiator_timer_R(init_machine); }, INITIATOR_RESULT_WAIT) /* * RCR must not be greater than RCR_MAX. One of corrections from MOT_WTP_CR_01. */ ROW(INITIATOR_RESULT_WAIT, RcvAck, event->u.RcvAck.tid_ok, { }, INITIATOR_RESULT_WAIT) ROW(INITIATOR_RESULT_WAIT, RcvAbort, 1, { wsp_event = create_tr_abort_ind(init_machine, event->u.RcvAbort.abort_reason); dispatch_to_wsp(wsp_event); }, INITIATOR_NULL_STATE) ROW(INITIATOR_RESULT_WAIT, RcvErrorPDU, 1, { send_abort(init_machine, USER, PROTOERR); wsp_event = create_tr_abort_ind(init_machine, PROTOERR); dispatch_to_wsp(wsp_event); }, INITIATOR_NULL_STATE) ROW(INITIATOR_RESULT_WAIT, TimerTO_R, init_machine->rcr < MAX_RCR && !init_machine->tidok_sent, { WAPEvent *resend; ++init_machine->rcr; start_initiator_timer_R(init_machine); resend = wap_event_duplicate(init_machine->invoke); wtp_pack_set_rid(resend, init_machine->rid); dispatch_to_wdp(resend); }, INITIATOR_RESULT_WAIT) ROW(INITIATOR_RESULT_WAIT, TimerTO_R, init_machine->rcr < MAX_RCR && init_machine->tidok_sent, { ++init_machine->rcr; start_initiator_timer_R(init_machine); send_ack(init_machine, TID_VERIFICATION, init_machine->tidok_sent); }, INITIATOR_RESULT_WAIT) ROW(INITIATOR_RESULT_WAIT, TimerTO_R, init_machine->rcr == MAX_RCR, { wsp_event = create_tr_abort_ind(init_machine, NORESPONSE); dispatch_to_wsp(wsp_event); }, INITIATOR_NULL_STATE) #undef ROW #undef INIT_STATE_NAME gateway-1.4.5/wap/wsp_pdu.h0000644000175000017500000001042113227613126014306 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* wsp_pdu.h - definitions for unpacked WTP protocol data units * * This file generates a structure definition and some function * declarations from wtp_pdu.def, using preprocessor magic. * * Richard Braakman */ #ifndef WSP_PDU_H #define WSP_PDU_H #include "gwlib/gwlib.h" /* The Get and Post PDUs contain a "subtype" field. Sometimes we * have to reconstruct the full method number. For methods encoded * in Get PDUs, this is GET_METHODS + subtype. For methods encoded * in Post PDUs, this is POST_METHODS + subtype. */ enum { GET_METHODS = 0x40, POST_METHODS = 0x60 }; /* Enumerate the symbolic names of the PDUs */ enum wsp_pdu_types { #define PDU(name, docstring, fields, is_valid) name, #include "wsp_pdu.def" #undef PDU }; struct wsp_pdu { int type; union { /* For each PDU, declare a structure with its fields, named after the PDU */ #define PDU(name, docstring, fields, is_valid) struct name { fields } name; #define UINT(field, docstring, bits) unsigned long field; #define UINTVAR(field, docstring) unsigned long field; #define OCTSTR(field, docstring, lengthfield) Octstr *field; #define REST(field, docstring) Octstr *field; #define TYPE(bits, value) #define RESERVED(bits) #define TPI(confield) #include "wsp_pdu.def" #undef TPI #undef RESERVED #undef TYPE #undef REST #undef OCTSTR #undef UINTVAR #undef UINT #undef PDU } u; }; typedef struct wsp_pdu WSP_PDU; WSP_PDU *wsp_pdu_create(int type); WSP_PDU *wsp_pdu_unpack(Octstr *data); Octstr *wsp_pdu_pack(WSP_PDU *pdu); void wsp_pdu_dump(WSP_PDU *pdu, int level); void wsp_pdu_destroy(WSP_PDU *pdu); #endif gateway-1.4.5/wap/timers.c0000644000175000017500000003756313227613126014143 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * timers.c - timers and set of timers, mainly for WTP. * * See timers.h for a description of the interface. */ #include #include "gwlib/gwlib.h" #include "wap_events.h" #include "timers.h" /* * Active timers are stored in a TimerHeap. It is a partially ordered * array. Each element i is the child of element i/2 (rounded down), * and a child never elapses before its parent. The result is that * element 0, the top of the heap, is always the first timer to * elapse. The heap is kept in this partial order by all operations on * it. Maintaining a partial order is much cheaper than maintaining * a sorted list. * The array will be resized as needed. The size field is the number * of elements for which space is reserved, and the len field is the * number of elements actually used. The elements used will always be * at tab[0] through tab[len-1]. */ struct TimerHeap { Timer **tab; long len; long size; }; typedef struct TimerHeap TimerHeap; struct Timerset { /* * This field is set to true when the timer thread should shut down. */ volatile sig_atomic_t stopping; /* * The entire set is locked for any operation on it. This is * not as expensive as it sounds because usually each set is * used by one caller thread and one (internal) timer thread, * and the timer thread does not wake up very often. */ Mutex *mutex; /* * Active timers are stored here in a partially ordered structure. * See the definition of TimerHeap, above, for an explanation. */ TimerHeap *heap; /* * The thread that watches the top of the heap, and processes * timers that have elapsed. */ long thread; }; typedef struct Timerset Timerset; struct Timer { /* * An event is produced on the output list when the * timer elapses. The timer is not considered to have * elapsed completely until that pointer has also been * consumed from this list (by the caller, presumably). * That is why the timer code sometimes goes back and * removes a pointer from the output list. */ List *output; /* * The timer is set to elapse at this time, expressed in * Unix time format. This field is set to -1 if the timer * is not active (i.e. in the timer set's heap). */ long elapses; /* * A duplicate of this event will be put on the output list * when the timer elapses. It can be NULL if the timer has * not been started yet. */ WAPEvent *event; /* * This field is normally NULL, but after the timer elapses * it points to the event that was put on the output list. * It is set back to NULL if the event was taken back from * the list, or if it's confirmed that the event was consumed. */ WAPEvent *elapsed_event; /* * Index in the timer set's heap. This field is managed by * the heap operations, and is used to make them faster. * If this timer is not in the heap, this field is -1. */ long index; }; /* * Currently we have one timerset (and thus one heap and one thread) * for all timers. This might change in the future in order to tune * performance. In that case, it will be necessary to add a "set" * field to the Timer structure. */ static Timerset *timers; /* * Used by timer functions to assert that the timer module has been * intialized. */ static int initialized = 0; /* * Internal functions */ static void abort_elapsed(Timer *timer); static TimerHeap *heap_create(void); static void heap_destroy(TimerHeap *heap); static void heap_delete(TimerHeap *heap, long index); static int heap_adjust(TimerHeap *heap, long index); static void heap_insert(TimerHeap *heap, Timer *timer); static void heap_swap(TimerHeap *heap, long index1, long index2); static void lock(Timerset *set); static void unlock(Timerset *set); static void watch_timers(void *arg); /* The timer thread */ static void elapse_timer(Timer *timer); void timers_init(void) { if (initialized == 0) { timers = gw_malloc(sizeof(*timers)); timers->mutex = mutex_create(); timers->heap = heap_create(); timers->stopping = 0; timers->thread = gwthread_create(watch_timers, timers); } initialized++; } void timers_shutdown(void) { if (initialized > 1) { initialized--; return; } /* Stop all timers. */ if (timers->heap->len > 0) warning(0, "Timers shutting down with %ld active timers.", timers->heap->len); while (timers->heap->len > 0) gwtimer_stop(timers->heap->tab[0]); /* Kill timer thread */ timers->stopping = 1; gwthread_wakeup(timers->thread); gwthread_join(timers->thread); initialized = 0; /* Free resources */ heap_destroy(timers->heap); mutex_destroy(timers->mutex); gw_free(timers); } Timer *gwtimer_create(List *outputlist) { Timer *t; gw_assert(initialized); t = gw_malloc(sizeof(*t)); t->elapses = -1; t->event = NULL; t->elapsed_event = NULL; t->index = -1; t->output = outputlist; gwlist_add_producer(outputlist); return t; } void gwtimer_destroy(Timer *timer) { gw_assert(initialized); if (timer == NULL) return; gwtimer_stop(timer); gwlist_remove_producer(timer->output); wap_event_destroy(timer->event); gw_free(timer); } void gwtimer_start(Timer *timer, int interval, WAPEvent *event) { int wakeup = 0; gw_assert(initialized); gw_assert(timer != NULL); gw_assert(event != NULL || timer->event != NULL); lock(timers); /* Convert to absolute time */ interval += time(NULL); if (timer->elapses > 0) { /* Resetting an existing timer. Move it to its new * position in the heap. */ if (interval < timer->elapses && timer->index == 0) wakeup = 1; timer->elapses = interval; gw_assert(timers->heap->tab[timer->index] == timer); wakeup |= heap_adjust(timers->heap, timer->index); } else { /* Setting a new timer, or resetting an elapsed one. * First deal with a possible elapse event that may * still be on the output list. */ abort_elapsed(timer); /* Then activate the timer. */ timer->elapses = interval; gw_assert(timer->index < 0); heap_insert(timers->heap, timer); wakeup = timer->index == 0; /* Do we have a new top? */ } if (event != NULL) { wap_event_destroy(timer->event); timer->event = event; } unlock(timers); if (wakeup) gwthread_wakeup(timers->thread); } void gwtimer_stop(Timer *timer) { gw_assert(initialized); gw_assert(timer != NULL); lock(timers); /* * If the timer is active, make it inactive and remove it from * the heap. */ if (timer->elapses > 0) { timer->elapses = -1; gw_assert(timers->heap->tab[timer->index] == timer); heap_delete(timers->heap, timer->index); } abort_elapsed(timer); unlock(timers); } static void lock(Timerset *set) { gw_assert(set != NULL); mutex_lock(set->mutex); } static void unlock(Timerset *set) { gw_assert(set != NULL); mutex_unlock(set->mutex); } /* * Go back and remove this timer's elapse event from the output list, * to pretend that it didn't elapse after all. This is necessary * to deal with some races between the timer thread and the caller's * start/stop actions. */ static void abort_elapsed(Timer *timer) { long count; if (timer->elapsed_event == NULL) return; count = gwlist_delete_equal(timer->output, timer->elapsed_event); if (count > 0) { debug("timers", 0, "Aborting %s timer.", wap_event_name(timer->elapsed_event->type)); wap_event_destroy(timer->elapsed_event); } timer->elapsed_event = NULL; } /* * Create a new timer heap. */ static TimerHeap *heap_create(void) { TimerHeap *heap; heap = gw_malloc(sizeof(*heap)); heap->tab = gw_malloc(sizeof(heap->tab[0])); heap->size = 1; heap->len = 0; return heap; } static void heap_destroy(TimerHeap *heap) { if (heap == NULL) return; gw_free(heap->tab); gw_free(heap); } /* * Remove a timer from the heap. Do this by swapping it with the element * in the last position, then shortening the heap, then moving the * swapped element up or down to maintain the partial ordering. */ static void heap_delete(TimerHeap *heap, long index) { long last; gw_assert(index >= 0); gw_assert(index < heap->len); gw_assert(heap->tab[index]->index == index); last = heap->len - 1; heap_swap(heap, index, last); heap->tab[last]->index = -1; heap->len--; if (index != last) heap_adjust(heap, index); } /* * Add a timer to the heap. Do this by adding it at the end, then * moving it up or down as necessary to achieve partial ordering. */ static void heap_insert(TimerHeap *heap, Timer *timer) { heap->len++; if (heap->len > heap->size) { heap->tab = gw_realloc(heap->tab, heap->len * sizeof(heap->tab[0])); heap->size = heap->len; } heap->tab[heap->len - 1] = timer; timer->index = heap->len - 1; heap_adjust(heap, timer->index); } /* * Swap two elements of the heap, and update their index fields. * This is the basic heap operation. */ static void heap_swap(TimerHeap *heap, long index1, long index2) { Timer *t; gw_assert(index1 >= 0); gw_assert(index1 < heap->len); gw_assert(index2 >= 0); gw_assert(index2 < heap->len); if (index1 == index2) return; t = heap->tab[index1]; heap->tab[index1] = heap->tab[index2]; heap->tab[index2] = t; heap->tab[index1]->index = index1; heap->tab[index2]->index = index2; } /* * The current element has broken the partial ordering of the * heap (see explanation in the definition of Timerset), and * it has to be moved up or down until the ordering is restored. * Return 1 if the timer at the heap's top is now earlier than * before this operation, otherwise 0. */ static int heap_adjust(TimerHeap *heap, long index) { Timer *t; Timer *parent; long child_index; /* * We can assume that the heap was fine before this element's * elapse time was changed. There are three cases to deal * with: * - Element's new elapse time is too small; it should be * moved toward the top. * - Element's new elapse time is too large; it should be * moved toward the bottom. * - Element's new elapse time still fits here, we don't * have to do anything. */ gw_assert(index >= 0); gw_assert(index < heap->len); /* Move to top? */ t = heap->tab[index]; parent = heap->tab[index / 2]; if (t->elapses < parent->elapses) { /* This will automatically terminate when it reaches * the top, because in that t == parent. */ do { heap_swap(heap, index, index / 2); index = index / 2; parent = heap->tab[index / 2]; } while (t->elapses < parent->elapses); /* We're done. Return 1 if we changed the top. */ return index == 0; } /* Move to bottom? */ for (; ; ) { child_index = index * 2; if (child_index >= heap->len) return 0; /* Already at bottom */ if (child_index == heap->len - 1) { /* Only one child */ if (heap->tab[child_index]->elapses < t->elapses) heap_swap(heap, index, child_index); break; } /* Find out which child elapses first */ if (heap->tab[child_index + 1]->elapses < heap->tab[child_index]->elapses) { child_index++; } if (heap->tab[child_index]->elapses < t->elapses) { heap_swap(heap, index, child_index); index = child_index; } else { break; } } return 0; } /* * This timer has elapsed. Do the housekeeping. We have its set locked. */ static void elapse_timer(Timer *timer) { gw_assert(timer != NULL); gw_assert(timers != NULL); /* This must be true because abort_elapsed is always called * before a timer is activated. */ gw_assert(timer->elapsed_event == NULL); debug("timers", 0, "%s elapsed.", wap_event_name(timer->event->type)); timer->elapsed_event = wap_event_duplicate(timer->event); gwlist_produce(timer->output, timer->elapsed_event); timer->elapses = -1; } /* * Main function for timer thread. */ static void watch_timers(void *arg) { Timerset *set; long top_time; long now; set = arg; while (!set->stopping) { lock(set); now = time(NULL); while (set->heap->len > 0 && set->heap->tab[0]->elapses <= now) { elapse_timer(set->heap->tab[0]); heap_delete(set->heap, 0); } /* * Now sleep until the next timer elapses. If there isn't one, * then just sleep very long. We will get woken up if the * top of the heap changes before we wake. */ if (set->heap->len == 0) { unlock(set); gwthread_sleep(1000000.0); } else { top_time = set->heap->tab[0]->elapses; unlock(set); gwthread_sleep(top_time - now); } } } gateway-1.4.5/wap/wsp_server_push_states.def0000644000175000017500000001122413227613126017757 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wsp_push_server_states.def - macro calls to generate rows of the state * table. See the documentation for guidance how to use and update these. * * Note that NULL state is called here SERVER_PUSH_NULL_STATE. Condition 1 * means that an action is unconditional. * * By Aarno Syvänen for Wapit Ltd */ STATE_NAME(SERVER_PUSH_NULL_STATE) STATE_NAME(SERVER_PUSH_PUSHING) ROW(SERVER_PUSH_NULL_STATE, S_ConfirmedPush_Req, 1, { WSP_PDU *pdu; pdu = make_confirmedpush_pdu(current_event); send_invoke(sm, pdu, current_event, TRANSACTION_CLASS_1); }, SERVER_PUSH_PUSHING) ROW(SERVER_PUSH_PUSHING, Push_Abort, 1, { send_abort_to_initiator(current_event->u.Push_Abort.reason, pm->transaction_id); indicate_pushabort(pm, current_event->u.Push_Abort.reason); }, SERVER_PUSH_NULL_STATE) ROW(SERVER_PUSH_PUSHING, TR_Invoke_Cnf, 1, { confirm_push(pm); }, SERVER_PUSH_NULL_STATE) ROW(SERVER_PUSH_PUSHING, TR_Abort_Ind, current_event->u.TR_Abort_Ind.abort_code == WSP_ABORT_DISCONNECT, { WAPEvent *wsp_event; wsp_event = wap_event_create(Disconnect_Event); wsp_event->u.Disconnect_Event.session_handle = pm->server_push_id; gwlist_append(queue, wsp_event); }, SERVER_PUSH_NULL_STATE) ROW(SERVER_PUSH_PUSHING, TR_Abort_Ind, current_event->u.TR_Abort_Ind.abort_code == WSP_ABORT_SUSPEND, { WAPEvent *wsp_event; wsp_event = wap_event_create(Suspend_Event); wsp_event->u.Suspend_Event.session_handle = pm->server_push_id; gwlist_append(queue, wsp_event); }, SERVER_PUSH_NULL_STATE) ROW(SERVER_PUSH_PUSHING, TR_Abort_Ind, current_event->u.TR_Abort_Ind.abort_code != WSP_ABORT_DISCONNECT && current_event->u.TR_Abort_Ind.abort_code != WSP_ABORT_SUSPEND, { indicate_pushabort(pm, current_event->u.Push_Abort.reason); }, SERVER_PUSH_NULL_STATE) #undef STATE_NAME #undef ROW gateway-1.4.5/wap/wtp_resp_machine.def0000644000175000017500000001335113227613126016470 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wtp_resp_machine.def - macro call for generating WTP responder statemachine. * See the architecture document for guidance how to use and update it. * * By Aarno Syvänen for Wapit Ltd. * * WTPRespMachine data structure includes current state of WTP responder state * machine for a specific transaction. This means all data needed to handle at * least two incoming events of a certain transaction. Its fields can be * grouped following way: * * General: wtp responder machine state * * Fields telling the service required: * a) transaction class (is transaction confirmed or not) * b) user acknowledgement flag (do we wait for response primit- * ive of WTP user (for instance, WSP) or not) * * Machine identification: address four-tuple and transaction identifier * * Field required for tid verification: * a) packed wsp invoke indication, which is required by the * protocol * * Fields required for reliable transmission: * a) pointer to the timer of this machine in the timers list * b) counters for acknowledgement waiting periods and retrans- * missions * c) flag telling are we resending the result or not * d) similar flag for acknowledgements * e) packed result message, for greater effectivity */ #if !defined(MACHINE) #error "Macro MACHINE is missing." #elif !defined(INTEGER) #error "Macro INTEGER is missing." #elif !defined(ENUM) #error "Macro ENUM is missing." #elif !defined(TIMER) #error "Macro TIMER is missing." #elif !defined(EVENT) #error "Macro EVENT is missing." #elif !defined(LIST) #error "Macro LIST is missing." #elif !defined(SARDATA) #error "Macro SARDATA is missing." #elif !defined(ADDRTUPLE) #error "Macro ADDRTUPLE is missing." #endif MACHINE(ENUM(state) INTEGER(tid) /* transaction identifier */ ADDRTUPLE(addr_tuple) INTEGER(tcl) /* transaction class */ INTEGER(aec) /* counter telling how many timer periods we have waited for acknowledgement */ INTEGER(rcr) /* retransmission counter */ INTEGER(u_ack) /* user acknowledgement flag (are user acknowledgement required) */ INTEGER(rid) /* retransmission flag, telling are we resending the result */ EVENT(result) /* packed result message - for resending */ INTEGER(ack_pdu_sent) /* are we resending the acknowledgement */ TIMER(timer) /* pointer to the timer of this machine timer in the global timers list */ EVENT(invoke_indication) /* packed wsp invoke indication - for tid verification */ EVENT(sar_invoke) /* initial invoke for SAR, accumulate user_data */ LIST(sar_info) SARDATA(sar) /* ! NULL if were we asked for SAR */ ) #undef MACHINE #undef INTEGER #undef ENUM #undef TIMER #undef EVENT #undef LIST #undef SARDATA #undef ADDRTUPLE gateway-1.4.5/README0000644000175000017500000002340113312226023012536 0ustar toljtoljREADME for Kannel: Open Source WAP and SMS Gateway Abstract This README describes Kannel, the Open Source WAP and SMS gateway, and how it can be used and installed. Introduction The Kannel Open Source WAP and SMS gateway works as both an SMS gateway, for implementing keyword based services via GSM text messages, and a WAP gateway, via UDP. The SMS part is fairly mature, the WAP part is early in its development. In this release, the GET request for WML pages and WMLScript files via HTTP works, including compilation for WML and WMLScript to binary forms. Only the data call bearer (UDP) is supported, not SMS. Requirements You need a Unix-like operating system that supports POSIX threads (pthreads.h). We use RedHat/CentOS Linux and Debian/Ubuntu GNU/Linux systems as main targets. There is also support for the Cygwin POSIX emulation layer for the Win32 platforms. You need GNU make, other make's tend not to work. For example, the FreeBSD and Solaris versions of make do not work. Check the version of your make with "make --version"; if it does not reply with "GNU Make version x.y.z", then it is not GNU make. On Solaris, you probably want to install gcc, GNU make and GNU binutils from www.sunfreeware.com. On MacOS X, you may have problems in compiling the latest libxml (2.4.23). There may be linking errors for those library. A work- arround is either using an older version of libxml (2.3.9 for example) or to build it as static library without the dynamic one being built. Documentation The user manual is in the doc/userguide directory and although it is not complete, explain almost all parts of Kannel. Developer documentation (currently very outdated) is in the doc/arch directory. In order to convert the documentation from DocBook (a mark-up language) to HTML and PostScript, you need some tools. Please find here the required packages: Debian 8 GNU/Linux: $ sudo apt-get install openjade jadetex transfig imagemagick \ docbook-dsssl docbook-utils Red Hat Linux 7 (RHEL/CentOS): $ sudo yum install openjade texlive-jadetex transfig ImageMagick \ docbook-style-dsssl texlive Fedora Core 7 (and higher): $ sudo yum install openjade jadetex transfig ImageMagick \ docbook-style-dsssl Gentoo: $ sudo emerge transfig jadetex docbook-dsssl-stylesheets Mandrake: $ urpmi transfig jadetex docbook-style-dsssl Then apply this change to /usr/share/texmf/web2c/texmf.cnf: hash_extra.jadetex = 15000 hash_extra.pdfjadetex = 15000 pool_size.jadetex = 500000 pool_size.pdfjadetex = 500000 string_vacancies.jadetex = 45000 string_vacancies.pdfjadetex = 45000 max_strings.jadetex = 55000 max_strings.pdfjadetex = 55000 pool_free.jadetex = 47500 pool_free.pdfjadetex = 47500 nest_size.jadetex = 500 nest_size.pdfjadetex = 500 param_size.jadetex = 1500 param_size.pdfjadetex = 1500 save_size.jadetex = 5000 save_size.pdfjadetex = 5000 stack_size.jadetex = 1500 stack_size.pdfjadetex = 1500 On other systems, you'll have to figure it out yourself. Getting the gateway sources You can download the sources from http://www.kannel.org/download.shtml. Note that you also need the Gnome-xml library from http://xmlsoft.org/xml.html. That one probably requires zlib, depending on how it is configured. You need at least version 2.2.0 Compiling and installing the gateway See the file INSTALL for generic installation instructions. The short form: ./configure touch .depend make depend make make bindir=/somewhere/suitable install See the User Guide (doc/userguide/ or http://www.kannel.org/userguide.shtml) for Kannel specific options to configure. For developers only: autoconf, configure, config.status, and Makefile We use the GNU autoconf tool to make it easier to adapt Kannel to each platform. The `autoconf' program reads the file configure.in, and generates a corresponding shell script called configure, which investigates the system it runs on to see what it supports and what it does not. configure then reads Makefile.in and config.h.in and writes out Makefile, config.h, and a shell script config.status. If you modify configure.in, you need to run autoconf. If you modify Makefile.in or config.h.in, you need to run config.status. If you modify any source files to add or change any header includes, you need to run "make depend". You always need to run "make" (which is the same as "make all"). If you have trouble building things and suspect that there is a problem with the Makefile, run "make clean all". If that solves it, report it as a bug (see the end of this README). For developers only: adding new SMS Center protocol support As Kannel does not support all the SMSC protocols that exists, it might become necessary to add new kind of protocols, including support to use mobile phones as SMSCes. When doing this, read interface specification in gw/smscconn_p.h. Drivers should stick to these rules as good as they can. For developers only: "make check" The Kannel Makefile contains a target called "check", which is used to run a series of automatic, non-interactive tests on various subsystems. Each test program MUST stored in the `checks' subdirectory. Each test MUST be written either as a C program named `check_*.c' or a Bourne shell script named `check_*.sh'. The C programs are compiled by the Makefile, the shell scripts MUST be executable. The test programs MUST output nothing to stdout, and MUST use a zero exit code to indicate that the test was successful, and a non-zero exit code to indicate a failure of the test. This way, if one runs "make -s check", one can easily see which tests are run and which tests work. The test programs MUST output error messages to stderr and they MUST mention which test program and which subtest failed. In case of failure, they may leave log files or other auxiliary files, and these MUST be listed in the error messages to stderr, so that the user has a reasonable way to diagnose the error. The Makefile captures the stderr output to `check.log'. The tests SHOULD take a reasonable time, preferably less than fifteen seconds each. This way, one can run "make -s check" before each commit. If there is a need to run longer tests, then the tests need to be divided into fast and slow ones. These tests are meant to test whether subsystems mostly work, stress testing needs to be done separately, and tends to require testing against real applications. For developers only: Source tree organization The source tree is organized as follows: gateway root of source tree: some docs, no sources |-- contrib contributed extra material |-- doc documentation |-- gw the gateway itself |-- gwlib utility functions |-- test programs for testing the gateway `-- utils utility programs For developers only: WMLScript references WMLScript Specification Wireless Application Protocol WMLScript Language Specification Version 1.1 http://www.wapforum.org/ WMLScript Standard Libraries Specification Wireless Aplication Protocol WMLScript Standard Libraries Specification Version 1.1 http://www.wapforum.org/ RFC-2279 UTF-8, a transformation format of ISO 10646 rfc/iana/assignments/character-sets The official names for character sets that may be used in the Internet and may be referred to in Internet Documentation. ANSI/IEEE Std 754-1985 IEEE Standard for Binary Floating-Point Arithmetic. Institute of Electrical and Electronics Engineers, New York (1985). Configuring and running the gateway See the user guide in doc/userguide or on the web at http://www.kannel.org/doc.shtml. For test use, you can see sample configurations gw/smskannel.conf (SMS gateway) and gw/wapkannel.conf (WAP gateway). Using the gateway with a Nokia 7110 To configure a Nokia 7110 to use the gateway, fill in the following (note that you need to provide your own dialup line): Home page: http://www.kannel.org/wap/hello.wml (or any other WML page) Connection type: continuous Connection security: off Bearer: data Dial-up number: IP address: Authentication type: normal Data call type: Data call speed: 9600 User name: Password: After you have modified the profile, activate it and load the home page. If you use the sample page above, you should see "hello, world" on the screen after a few moments. Modifications to old Kannel (0.8 and older) After release 0.8 Kannel architecture has been modified considerably, resulting changes in basic running of the standard WAP or WAP gateway. In new design, there is only one configuration file (to be more exact, you can have several of them, one for each kind of box, but that is advanced feature, which is not very usable) for bearerbox, smsboxes and wapboxes. Details of that file is in doc/userguide/newconf.txt. As a quick reference, you just put all your old configuration files into same file, remove some rows and add 'group = xxx' variables into it. Moreover, there is no internal smsbox in new Kannel. So, when running SMS services you MUST run separate smsbox. This is most easily done with Kannel as daemon, launched with init.d. See utils/ directory for any supplied systems. Feedback and more information You may want to subscribe the announce and devel lists at www.kannel.org. If you need help or want to participate in the development of Kannel. Send e-mail to announce-subscribe@kannel.org devel-subscribe@kannel.org (You'll get further instructions via automatic reply mails.) gateway-1.4.5/install-sh0000755000175000017500000003246411155030667013705 0ustar toljtolj#!/bin/sh # install - install a program, script, or datafile scriptversion=2006-12-25.00 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then trap '(exit $?); exit' 1 2 13 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names starting with `-'. case $src in -*) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # Protect names starting with `-'. case $dst in -*) dst=./$dst;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; -*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test -z "$d" && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: gateway-1.4.5/gwlib/0000755000175000017500000000000013312227713012771 5ustar toljtoljgateway-1.4.5/gwlib/gw_uuid.c0000644000175000017500000003225013307520564014606 0ustar toljtolj/* * clear.c -- Clear a UUID * * Copyright (C) 1996, 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ /* * Force inclusion of SVID stuff since we need it if we're compiling in * gcc-wall wall mode */ #ifndef _SVID_SOURCE #define _SVID_SOURCE #endif #include "gw-config.h" #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_SYS_SOCKIO_H #include #endif #ifdef HAVE_NET_IF_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #include #include "gwlib/gw_uuid_types.h" #include "gwlib/gw_uuid.h" /* * Offset between 15-Oct-1582 and 1-Jan-70 */ #define TIME_OFFSET_HIGH 0x01B21DD2 #define TIME_OFFSET_LOW 0x13814000 struct uuid { __u32 time_low; __u16 time_mid; __u16 time_hi_and_version; __u16 clock_seq; __u8 node[6]; }; /* * prototypes */ static void uuid_pack(const struct uuid *uu, uuid_t ptr); static void uuid_unpack(const uuid_t in, struct uuid *uu); static int get_random_fd(void); #ifdef HAVE_SRANDOM #define srand(x) srandom(x) #define rand() random() #endif void uuid_init(void) { /* * open random device if any. * We should do it here because otherwise it's * possible that we open device twice. */ get_random_fd(); } void uuid_shutdown(void) { int fd = get_random_fd(); if (fd > 0) close(fd); } void uuid_clear(uuid_t uu) { memset(uu, 0, 16); } /* * compare.c --- compare whether or not two UUID's are the same * * Returns an integer less than, equal to, or greater than zero if * uu1 respectively, to be less than, to match, or be greater than * uu2. * * Copyright (C) 1996, 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ #define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1); int uuid_compare(const uuid_t uu1, const uuid_t uu2) { struct uuid uuid1, uuid2; uuid_unpack(uu1, &uuid1); uuid_unpack(uu2, &uuid2); UUCMP(uuid1.time_low, uuid2.time_low); UUCMP(uuid1.time_mid, uuid2.time_mid); UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version); UUCMP(uuid1.clock_seq, uuid2.clock_seq); return memcmp(uuid1.node, uuid2.node, 6); } /* * copy.c --- copy UUIDs * * Copyright (C) 1996, 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ void uuid_copy(uuid_t dst, const uuid_t src) { unsigned char *cp1; const unsigned char *cp2; int i; for (i=0, cp1 = dst, cp2 = src; i < 16; i++) *cp1++ = *cp2++; } /* * gen_uuid.c --- generate a DCE-compatible uuid * * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ static int get_random_fd(void) { struct timeval tv; static int fd = -2; int i; if (fd == -2) { gettimeofday(&tv, 0); fd = open("/dev/urandom", O_RDONLY); if (fd == -1) fd = open("/dev/random", O_RDONLY | O_NONBLOCK); srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); } /* Crank the random number generator a few times */ gettimeofday(&tv, 0); for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) rand(); return fd; } /* * Generate a series of random bytes. Use /dev/urandom if possible, * and if not, use srandom/random. */ static void get_random_bytes(void *buf, int nbytes) { int i, n = nbytes, fd = get_random_fd(); int lose_counter = 0; unsigned char *cp = (unsigned char *) buf; if (fd >= 0) { while (n > 0) { i = read(fd, cp, n); if (i <= 0) { if (lose_counter++ > 16) break; continue; } n -= i; cp += i; lose_counter = 0; } } /* * We do this all the time, but this is the only source of * randomness if /dev/random/urandom is out to lunch. */ for (cp = buf, i = 0; i < nbytes; i++) *cp++ ^= (rand() >> 7) & 0xFF; return; } /* * Get the ethernet hardware address, if we can find it... */ static int get_node_id(unsigned char *node_id) { #ifdef HAVE_NET_IF_H int sd; struct ifreq ifr, *ifrp; struct ifconf ifc; char buf[1024]; int n, i; unsigned char *a; /* * BSD 4.4 defines the size of an ifreq to be * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len * However, under earlier systems, sa_len isn't present, so the size is * just sizeof(struct ifreq) */ #ifdef HAVE_SA_LEN #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) #endif #define ifreq_size(i) max(sizeof(struct ifreq),\ sizeof((i).ifr_name)+(i).ifr_addr.sa_len) #else #define ifreq_size(i) sizeof(struct ifreq) #endif /* HAVE_SA_LEN*/ sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (sd < 0) { return -1; } memset(buf, 0, sizeof(buf)); ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) { close(sd); return -1; } n = ifc.ifc_len; for (i = 0; i < n; i+= ifreq_size(*ifr) ) { ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i); strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Solaris 11 defines SIOCGIFHWADDR, but has no ifr_hwaddr member */ #if defined(SIOCGIFHWADDR) && !defined(__sun__) if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) continue; a = (unsigned char *) &ifr.ifr_hwaddr.sa_data; #else #ifdef SIOCGENADDR if (ioctl(sd, SIOCGENADDR, &ifr) < 0) continue; a = (unsigned char *) ifr.ifr_enaddr; #else /* * XXX we don't have a way of getting the hardware * address */ close(sd); return 0; #endif /* SIOCGENADDR */ #endif /* SIOCGIFHWADDR */ if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue; if (node_id) { memcpy(node_id, a, 6); close(sd); return 1; } } close(sd); #endif return 0; } /* Assume that the gettimeofday() has microsecond granularity */ #define MAX_ADJUSTMENT 10 static int get_clock(__u32 *clock_high, __u32 *clock_low, __u16 *ret_clock_seq) { static int adjustment = 0; static struct timeval last = {0, 0}; static __u16 clock_seq; struct timeval tv; unsigned long long clock_reg; try_again: gettimeofday(&tv, 0); if ((last.tv_sec == 0) && (last.tv_usec == 0)) { get_random_bytes(&clock_seq, sizeof(clock_seq)); clock_seq &= 0x1FFF; last = tv; last.tv_sec--; } if ((tv.tv_sec < last.tv_sec) || ((tv.tv_sec == last.tv_sec) && (tv.tv_usec < last.tv_usec))) { clock_seq = (clock_seq+1) & 0x1FFF; adjustment = 0; last = tv; } else if ((tv.tv_sec == last.tv_sec) && (tv.tv_usec == last.tv_usec)) { if (adjustment >= MAX_ADJUSTMENT) goto try_again; adjustment++; } else { adjustment = 0; last = tv; } clock_reg = tv.tv_usec*10 + adjustment; clock_reg += ((unsigned long long) tv.tv_sec)*10000000; clock_reg += (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; *clock_high = clock_reg >> 32; *clock_low = clock_reg; *ret_clock_seq = clock_seq; return 0; } void uuid_generate_time(uuid_t out) { static unsigned char node_id[6]; static int has_init = 0; struct uuid uu; __u32 clock_mid; if (!has_init) { if (get_node_id(node_id) <= 0) { get_random_bytes(node_id, 6); /* * Set multicast bit, to prevent conflicts * with IEEE 802 addresses obtained from * network cards */ node_id[0] |= 0x80; } has_init = 1; } get_clock(&clock_mid, &uu.time_low, &uu.clock_seq); uu.clock_seq |= 0x8000; uu.time_mid = (__u16) clock_mid; uu.time_hi_and_version = (clock_mid >> 16) | 0x1000; memcpy(uu.node, node_id, 6); uuid_pack(&uu, out); } void uuid_generate_random(uuid_t out) { uuid_t buf; struct uuid uu; get_random_bytes(buf, sizeof(buf)); uuid_unpack(buf, &uu); uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | 0x4000; uuid_pack(&uu, out); } /* * This is the generic front-end to uuid_generate_random and * uuid_generate_time. It uses uuid_generate_random only if * /dev/urandom is available, since otherwise we won't have * high-quality randomness. */ void uuid_generate(uuid_t out) { if (get_random_fd() >= 0) { uuid_generate_random(out); } else uuid_generate_time(out); } /* * isnull.c --- Check whether or not the UUID is null * * Copyright (C) 1996, 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ /* Returns 1 if the uuid is the NULL uuid */ int uuid_is_null(const uuid_t uu) { const unsigned char *cp; int i; for (i=0, cp = uu; i < 16; i++) if (*cp++) return 0; return 1; } /* * Internal routine for packing UUID's * * Copyright (C) 1996, 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ void uuid_pack(const struct uuid *uu, uuid_t ptr) { __u32 tmp; unsigned char *out = ptr; tmp = uu->time_low; out[3] = (unsigned char) tmp; tmp >>= 8; out[2] = (unsigned char) tmp; tmp >>= 8; out[1] = (unsigned char) tmp; tmp >>= 8; out[0] = (unsigned char) tmp; tmp = uu->time_mid; out[5] = (unsigned char) tmp; tmp >>= 8; out[4] = (unsigned char) tmp; tmp = uu->time_hi_and_version; out[7] = (unsigned char) tmp; tmp >>= 8; out[6] = (unsigned char) tmp; tmp = uu->clock_seq; out[9] = (unsigned char) tmp; tmp >>= 8; out[8] = (unsigned char) tmp; memcpy(out+10, uu->node, 6); } /* * parse.c --- UUID parsing * * Copyright (C) 1996, 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ int uuid_parse(const char *in, uuid_t uu) { struct uuid uuid; int i; const char *cp; char buf[3]; if (strlen(in) != 36) return -1; for (i=0, cp = in; i <= 36; i++,cp++) { if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) { if (*cp == '-') continue; else return -1; } if (i== 36) if (*cp == 0) continue; if (!isxdigit(*cp)) return -1; } uuid.time_low = strtoul(in, NULL, 16); uuid.time_mid = strtoul(in+9, NULL, 16); uuid.time_hi_and_version = strtoul(in+14, NULL, 16); uuid.clock_seq = strtoul(in+19, NULL, 16); cp = in+24; buf[2] = 0; for (i=0; i < 6; i++) { buf[0] = *cp++; buf[1] = *cp++; uuid.node[i] = strtoul(buf, NULL, 16); } uuid_pack(&uuid, uu); return 0; } /* * Internal routine for unpacking UUID * * Copyright (C) 1996, 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ void uuid_unpack(const uuid_t in, struct uuid *uu) { const __u8 *ptr = in; __u32 tmp; tmp = *ptr++; tmp = (tmp << 8) | *ptr++; tmp = (tmp << 8) | *ptr++; tmp = (tmp << 8) | *ptr++; uu->time_low = tmp; tmp = *ptr++; tmp = (tmp << 8) | *ptr++; uu->time_mid = tmp; tmp = *ptr++; tmp = (tmp << 8) | *ptr++; uu->time_hi_and_version = tmp; tmp = *ptr++; tmp = (tmp << 8) | *ptr++; uu->clock_seq = tmp; memcpy(uu->node, ptr, 6); } /* * unparse.c -- convert a UUID to string * * Copyright (C) 1996, 1997 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ void uuid_unparse(const uuid_t uu, char *out) { struct uuid uuid; uuid_unpack(uu, &uuid); sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, uuid.node[0], uuid.node[1], uuid.node[2], uuid.node[3], uuid.node[4], uuid.node[5]); } /* * uuid_time.c --- Interpret the time field from a uuid. This program * violates the UUID abstraction barrier by reaching into the guts * of a UUID and interpreting it. * * Copyright (C) 1998, 1999 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) { struct uuid uuid; __u32 high; struct timeval tv; unsigned long long clock_reg; uuid_unpack(uu, &uuid); high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); clock_reg = uuid.time_low | ((unsigned long long) high << 32); clock_reg -= (((unsigned long long) 0x01B21DD2) << 32) + 0x13814000; tv.tv_sec = clock_reg / 10000000; tv.tv_usec = (clock_reg % 10000000) / 10; if (ret_tv) *ret_tv = tv; return tv.tv_sec; } int uuid_type(const uuid_t uu) { struct uuid uuid; uuid_unpack(uu, &uuid); return ((uuid.time_hi_and_version >> 12) & 0xF); } int uuid_variant(const uuid_t uu) { struct uuid uuid; int var; uuid_unpack(uu, &uuid); var = uuid.clock_seq; if ((var & 0x8000) == 0) return UUID_VARIANT_NCS; if ((var & 0x4000) == 0) return UUID_VARIANT_DCE; if ((var & 0x2000) == 0) return UUID_VARIANT_MICROSOFT; return UUID_VARIANT_OTHER; } gateway-1.4.5/gwlib/list.c0000644000175000017500000004611613227613126014122 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * list.c - generic dynamic list * * This module implements the generic list. See list.h for an explanation * of how to use the list. * * The list is implemented as an array, a starting index into the array, * and an integer giving the length of the list. The list's element i is * not necessarily at array element i, but instead it is found at element * * (start + i) % len * * This is because we need to make it fast to use the list as a queue, * meaning that adding elements to the end and removing them from the * beginning must be very fast. Insertions into the middle of the list * need not be fast, however. It would be possible to implement the list * with a linked list, of course, but this would cause many more memory * allocations: every time an item is added to the list, a new node would * need to be allocated, and when it is removed, it would need to be freed. * Using an array lets us reduce the number of allocations. It also lets * us access an arbitrary element in constant time, which is specially * useful since it lets us simplify the list API by not adding iterators * or an explicit list item type. * * If insertions and deletions into the middle of the list become common, * it would be more efficient to use a buffer gap implementation, but * there's no point in doing that until the need arises. * * Lars Wirzenius */ #include "gw-config.h" #include #include #include #include #include "gwassert.h" #include "list.h" #include "log.h" #include "thread.h" #include "gwmem.h" struct List { void **tab; long tab_size; long start; long len; Mutex *single_operation_lock; Mutex *permanent_lock; pthread_cond_t nonempty; long num_producers; long num_consumers; }; #define INDEX(list, i) (((list)->start + i) % (list)->tab_size) #define GET(list, i) ((list)->tab[INDEX(list, i)]) long gwthread_self(void); static void lock(List *list); static void unlock(List *list); static void make_bigger(List *list, long items); static void delete_items_from_list(List *list, long pos, long count); List *gwlist_create_real(void) { List *list; list = gw_malloc(sizeof(List)); list->tab = NULL; list->tab_size = 0; list->start = 0; list->len = 0; list->single_operation_lock = mutex_create(); list->permanent_lock = mutex_create(); pthread_cond_init(&list->nonempty, NULL); list->num_producers = 0; list->num_consumers = 0; return list; } void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor) { long len, i; if (list == NULL) return; if (destructor != NULL) { len = gwlist_len(list); /* Using while(x != NULL) is unreliable, what if someone added NULL values? */ for (i = 0; i < len; i++) destructor(gwlist_extract_first(list)); } mutex_destroy(list->permanent_lock); mutex_destroy(list->single_operation_lock); pthread_cond_destroy(&list->nonempty); gw_free(list->tab); gw_free(list); } long gwlist_len(List *list) { long len; if (list == NULL) return 0; lock(list); len = list->len; unlock(list); return len; } void gwlist_append(List *list, void *item) { lock(list); make_bigger(list, 1); list->tab[INDEX(list, list->len)] = item; ++list->len; pthread_cond_signal(&list->nonempty); unlock(list); } void gwlist_append_unique(List *list, void *item, int (*cmp)(void *, void *)) { void *it; long i; lock(list); it = NULL; for (i = 0; i < list->len; ++i) { it = GET(list, i); if (cmp(it, item)) { break; } } if (i == list->len) { /* not yet in list, so add it */ make_bigger(list, 1); list->tab[INDEX(list, list->len)] = item; ++list->len; pthread_cond_signal(&list->nonempty); } unlock(list); } void gwlist_insert(List *list, long pos, void *item) { long i; lock(list); gw_assert(pos >= 0); gw_assert(pos <= list->len); make_bigger(list, 1); for (i = list->len; i > pos; --i) list->tab[INDEX(list, i)] = GET(list, i - 1); list->tab[INDEX(list, pos)] = item; ++list->len; pthread_cond_signal(&list->nonempty); unlock(list); } void gwlist_delete(List *list, long pos, long count) { lock(list); delete_items_from_list(list, pos, count); unlock(list); } long gwlist_delete_matching(List *list, void *pat, gwlist_item_matches_t *matches) { long i; long count; lock(list); /* XXX this could be made more efficient by noticing consecutive items to be removed, but leave that for later. --liw */ i = 0; count = 0; while (i < list->len) { if (matches(GET(list, i), pat)) { delete_items_from_list(list, i, 1); count++; } else { ++i; } } unlock(list); return count; } long gwlist_delete_equal(List *list, void *item) { long i; long count; lock(list); /* XXX this could be made more efficient by noticing consecutive items to be removed, but leave that for later. --liw */ i = 0; count = 0; while (i < list->len) { if (GET(list, i) == item) { delete_items_from_list(list, i, 1); count++; } else { ++i; } } unlock(list); return count; } void *gwlist_get(List *list, long pos) { void *item; lock(list); gw_assert(pos >= 0); gw_assert(pos < list->len); item = GET(list, pos); unlock(list); return item; } void *gwlist_extract_first(List *list) { void *item; gw_assert(list != NULL); lock(list); if (list->len == 0) item = NULL; else { item = GET(list, 0); delete_items_from_list(list, 0, 1); } unlock(list); return item; } List *gwlist_extract_matching(List *list, void *pat, gwlist_item_matches_t *cmp) { List *new_list; long i; new_list = gwlist_create(); lock(list); i = 0; while (i < list->len) { if (cmp(GET(list, i), pat)) { gwlist_append(new_list, GET(list, i)); delete_items_from_list(list, i, 1); } else ++i; } unlock(list); if (gwlist_len(new_list) == 0) { gwlist_destroy(new_list, NULL); return NULL; } return new_list; } void gwlist_lock(List *list) { gw_assert(list != NULL); mutex_lock(list->permanent_lock); } void gwlist_unlock(List *list) { gw_assert(list != NULL); mutex_unlock(list->permanent_lock); } int gwlist_wait_until_nonempty(List *list) { int ret; lock(list); while (list->len == 0 && list->num_producers > 0) { list->single_operation_lock->owner = -1; pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &list->single_operation_lock->mutex); pthread_cond_wait(&list->nonempty, &list->single_operation_lock->mutex); list->single_operation_lock->owner = gwthread_self(); pthread_cleanup_pop(0); } if (list->len > 0) ret = 1; else ret = -1; unlock(list); return ret; } void gwlist_add_producer(List *list) { lock(list); ++list->num_producers; unlock(list); } int gwlist_producer_count(List *list) { int ret; lock(list); ret = list->num_producers; unlock(list); return ret; } void gwlist_remove_producer(List *list) { lock(list); gw_assert(list->num_producers > 0); --list->num_producers; pthread_cond_broadcast(&list->nonempty); unlock(list); } void gwlist_produce(List *list, void *item) { gwlist_append(list, item); } int gwlist_consumer_count(List *list) { int ret; lock(list); ret = list->num_consumers; unlock(list); return ret; } void *gwlist_consume(List *list) { void *item; lock(list); ++list->num_consumers; while (list->len == 0 && list->num_producers > 0) { list->single_operation_lock->owner = -1; pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &list->single_operation_lock->mutex); pthread_cond_wait(&list->nonempty, &list->single_operation_lock->mutex); pthread_cleanup_pop(0); list->single_operation_lock->owner = gwthread_self(); } if (list->len > 0) { item = GET(list, 0); delete_items_from_list(list, 0, 1); } else { item = NULL; } --list->num_consumers; unlock(list); return item; } void *gwlist_timed_consume(List *list, long sec) { void *item; struct timespec abstime; int rc; abstime.tv_sec = time(NULL) + sec; abstime.tv_nsec = 0; lock(list); ++list->num_consumers; while (list->len == 0 && list->num_producers > 0) { list->single_operation_lock->owner = -1; pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &list->single_operation_lock->mutex); rc = pthread_cond_timedwait(&list->nonempty, &list->single_operation_lock->mutex, &abstime); pthread_cleanup_pop(0); list->single_operation_lock->owner = gwthread_self(); if (rc == ETIMEDOUT) break; } if (list->len > 0) { item = GET(list, 0); delete_items_from_list(list, 0, 1); } else { item = NULL; } --list->num_consumers; unlock(list); return item; } void *gwlist_search(List *list, void *pattern, int (*cmp)(void *, void *)) { void *item; long i; lock(list); item = NULL; for (i = 0; i < list->len; ++i) { item = GET(list, i); if (cmp(item, pattern)) { break; } } if (i == list->len) { item = NULL; } unlock(list); return item; } List *gwlist_search_all(List *list, void *pattern, int (*cmp)(void *, void *)) { List *new_list; void *item; long i; new_list = gwlist_create(); lock(list); item = NULL; for (i = 0; i < list->len; ++i) { item = GET(list, i); if (cmp(item, pattern)) gwlist_append(new_list, item); } unlock(list); if (gwlist_len(new_list) == 0) { gwlist_destroy(new_list, NULL); new_list = NULL; } return new_list; } long gwlist_search_equal(List *list, void *item) { long i; long ret = -1; lock(list); for (i = 0; i < list->len; i++) { if (GET(list, i) == item) { ret = i; break; } } unlock(list); return ret; } static void quicksort(List *list, long left, long right, int(*cmp)(const void *, const void *)) { if (left < right) { long l = left; long r = right; void *pivot = GET(list, right); do { while (cmp(GET(list, l), pivot) < 0) l++; while (cmp(GET(list, r), pivot) > 0) r--; if (l <= r) { void *swap = GET(list, l); GET(list, l) = GET(list, r); GET(list, r) = swap; l++; r--; } } while(l <= r); quicksort(list, left, r, cmp); quicksort(list, l, right, cmp); } } void gwlist_sort(List *list, int(*cmp)(const void *, const void *)) { gw_assert(list != NULL && cmp != NULL); lock(list); if (list->len == 0) { /* nothing to sort */ unlock(list); return; } quicksort(list, 0, list->len - 1, cmp); unlock(list); } /*************************************************************************/ static void lock(List *list) { gw_assert(list != NULL); mutex_lock(list->single_operation_lock); } static void unlock(List *list) { gw_assert(list != NULL); mutex_unlock(list->single_operation_lock); } /* * Make the array bigger. It might be more efficient to make the size * bigger than what is explicitly requested. * * Assume list has been locked for a single operation already. */ static void make_bigger(List *list, long items) { long old_size, new_size; long len_at_beginning, len_at_end; if (list->len + items <= list->tab_size) return; old_size = list->tab_size; new_size = old_size + items; list->tab = gw_realloc(list->tab, new_size * sizeof(void *)); list->tab_size = new_size; /* * Now, one of the following situations is in effect * (* is used, empty is unused element): * * Case 1: Used area did not wrap. No action is necessary. * * old_size new_size * v v * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | |*|*|*|*|*|*| | | | | | | | | | | | | | | | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * ^ ^ * start start+len * * Case 2: Used area wrapped, but the part at the beginning * of the array fits into the new area. Action: move part * from beginning to new area. * * old_size new_size * v v * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |*|*| | | | | | | |*|*|*| | | | | | | | | | | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * ^ ^ * start+len start * * Case 3: Used area wrapped, and the part at the beginning * of the array does not fit into the new area. Action: move * as much as will fit from beginning to new area and move * the rest to the beginning. * * old_size new_size * v v * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |*|*|*|*|*|*|*|*|*| | | | | | | | |*|*|*|*| | | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * ^ ^ * start+len start */ gw_assert(list->start < old_size || (list->start == 0 && old_size == 0)); if (list->start + list->len > old_size) { len_at_end = old_size - list->start; len_at_beginning = list->len - len_at_end; if (len_at_beginning <= new_size - old_size) { /* This is Case 2. */ memmove(list->tab + old_size, list->tab, len_at_beginning * sizeof(void *)); } else { /* This is Case 3. */ memmove(list->tab + old_size, list->tab, (new_size - old_size) * sizeof(void *)); memmove(list->tab, list->tab + (new_size - old_size), (len_at_beginning - (new_size - old_size)) * sizeof(void *)); } } } /* * Remove items `pos' through `pos+count-1' from list. Assume list has * been locked by caller already. */ static void delete_items_from_list(List *list, long pos, long count) { long i, from, to; gw_assert(pos >= 0); gw_assert(pos < list->len); gw_assert(count >= 0); gw_assert(pos + count <= list->len); /* * There are four cases: * * Case 1: Deletion at beginning of list. Just move start * marker forwards (wrapping it at end of array). No need * to move any items. * * Case 2: Deletion at end of list. Just shorten the length * of the list. No need to move any items. * * Case 3: Deletion in the middle so that the list does not * wrap in the array. Move remaining items at end of list * to the place of the deletion. * * Case 4: Deletion in the middle so that the list does indeed * wrap in the array. Move as many remaining items at the end * of the list as will fit to the end of the array, then move * the rest to the beginning of the array. */ if (pos == 0) { list->start = (list->start + count) % list->tab_size; list->len -= count; } else if (pos + count == list->len) { list->len -= count; } else if (list->start + list->len < list->tab_size) { memmove(list->tab + list->start + pos, list->tab + list->start + pos + count, (list->len - pos - count) * sizeof(void *)); list->len -= count; } else { /* * This is not specially efficient, but it's simple and * works. Faster methods would have to take more special * cases into account. */ for (i = 0; i < list->len - count - pos; ++i) { from = INDEX(list, pos + i + count); to = INDEX(list, pos + i); list->tab[to] = list->tab[from]; } list->len -= count; } } gateway-1.4.5/gwlib/counter.c0000644000175000017500000001143113227613126014616 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwlib/counter.c - a counter object * * This file implements the Counter objects declared in counter.h. * * Lars Wirzenius. * * Changed the counter type 'long' into 'unsigned long' so it wraps * by itself. Just keep increasing it. * Also added a counter_increase_with function. * harrie@lisanza.net */ #include #include "gwlib.h" struct Counter { #ifdef HAVE_PTHREAD_SPINLOCK_T pthread_spinlock_t lock; #else Mutex *lock; #endif unsigned long n; }; #ifdef HAVE_PTHREAD_SPINLOCK_T #define lock(c) pthread_spin_lock(&c->lock) #define unlock(c) pthread_spin_unlock(&c->lock) #else #define lock(c) mutex_lock(c->lock) #define unlock(c) mutex_unlock(c->lock) #endif Counter *counter_create(void) { Counter *counter; counter = gw_malloc(sizeof(Counter)); #ifdef HAVE_PTHREAD_SPINLOCK_T pthread_spin_init(&counter->lock, 0); #else counter->lock = mutex_create(); #endif counter->n = 0; return counter; } void counter_destroy(Counter *counter) { if (counter == NULL) return; #ifdef HAVE_PTHREAD_SPINLOCK_T pthread_spin_destroy(&counter->lock); #else mutex_destroy(counter->lock); #endif gw_free(counter); } unsigned long counter_increase(Counter *counter) { unsigned long ret; lock(counter); ret = counter->n; ++counter->n; unlock(counter); return ret; } unsigned long counter_increase_with(Counter *counter, unsigned long value) { unsigned long ret; lock(counter); ret = counter->n; counter->n += value; unlock(counter); return ret; } unsigned long counter_value(Counter *counter) { unsigned long ret; lock(counter); ret = counter->n; unlock(counter); return ret; } unsigned long counter_decrease(Counter *counter) { unsigned long ret; lock(counter); ret = counter->n; if (counter->n > 0) --counter->n; unlock(counter); return ret; } unsigned long counter_set(Counter *counter, unsigned long n) { unsigned long ret; lock(counter); ret = counter->n; counter->n = n; unlock(counter); return ret; } gateway-1.4.5/gwlib/pki.c0000644000175000017500000001101313227613126013716 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * pki.c: PKI and certificate handling routines * */ #include #include "gwlib/gwlib.h" #if (HAVE_WTLS_OPENSSL) #include #include #include #include #include #include #include #include "pki.h" void pki_init(void) { OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); } void pki_shutdown(void) { EVP_cleanup(); } void get_cert_from_file(Octstr *s, X509 **x509) { char *filename; /* Check errors!!!! */ FILE* fp; /* Open the file specified by "s" */ filename = octstr_get_cstr(s); fp = fopen(filename,"r"); if (fp == NULL) warning(0,"Can't read certificate %s", filename); /* Load up that there certificate */ *x509 = PEM_read_X509(fp,NULL,NULL,NULL); /* Close the file specified by "s" */ fclose(fp); if (x509 == NULL) { ERR_print_errors_fp (stderr); } } void get_privkey_from_file(Octstr* s, RSA** priv_key, Octstr* passwd) { char *password; char *filename; /* Check errors!!!! */ FILE* fp; filename = octstr_get_cstr(s); password = passwd != NULL ? octstr_get_cstr(passwd) : NULL; /* Open the file specified by "s" */ fp = fopen(filename,"r"); if (fp == NULL) warning(0,"Can't read private key %s", filename); /* Load up that there certificate */ *priv_key = PEM_read_RSAPrivateKey(fp,NULL,NULL,password); /* Close the file specified by "s" */ fclose(fp); if (priv_key == NULL) { ERR_print_errors_fp (stderr); } } void dump_cert(X509* x509) { } void dump_privkey(RSA* priv_key) { } #endif gateway-1.4.5/gwlib/gw-rwlock.c0000644000175000017500000001351713227613126015062 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw-rwlock.c: Implements Reader/Writer Lock. * If pthread_rwlock_XXX functions are present then those will be used; * otherwise emulation with mutexes/condition should be done. * * Alexander Malysh , initial version 2004 */ #include "gw-config.h" #include "gwlib.h" #include "gw-rwlock.h" #define DEBUG 0 #if DEBUG #define RWDEBUG(str,lev,frm,args...) debug(str, lev, frm, ## args) #else #define RWDEBUG(str,lev,frm,args...) do{}while(0) #endif RWLock *gw_rwlock_create(void) { RWLock *ret = gw_malloc(sizeof(*ret)); #ifdef HAVE_PTHREAD_RWLOCK int rc = pthread_rwlock_init(&ret->rwlock, NULL); if (rc != 0) panic(rc, "Initialization of RWLock failed."); #else ret->writer = -1; ret->rwlock = gwlist_create(); if (ret->rwlock == NULL) panic(0, "Initialization of RWLock failed."); #endif ret->dynamic = 1; return ret; } void gw_rwlock_init_static(RWLock *lock) { #ifdef HAVE_PTHREAD_RWLOCK int rc = pthread_rwlock_init(&lock->rwlock, NULL); if (rc != 0) panic(rc, "Initialization of RWLock failed."); #else lock->writer = -1; lock->rwlock = gwlist_create(); if (lock->rwlock == NULL) panic(0, "Initialization of RWLock failed."); #endif lock->dynamic = 0; } void gw_rwlock_destroy(RWLock *lock) { #ifdef HAVE_PTHREAD_RWLOCK int ret; #endif if (!lock) return; #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_destroy(&lock->rwlock); if (ret != 0) panic(ret, "Attempt to destroy locked rwlock."); #else gwlist_destroy(lock->rwlock, NULL); #endif if (lock->dynamic) gw_free(lock); } int gw_rwlock_rdlock(RWLock *lock) { int ret = 0; gw_assert(lock != NULL); #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_rdlock(&lock->rwlock); if (ret != 0) { panic(ret, "Error while pthread_rwlock_rdlock."); } #else gwlist_lock(lock->rwlock); gwlist_add_producer(lock->rwlock); gwlist_unlock(lock->rwlock); RWDEBUG("", 0, "------------ gw_rwlock_rdlock(%p) ----------", lock); #endif return ret; } int gw_rwlock_unlock(RWLock *lock) { int ret = 0; gw_assert(lock != NULL); #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_unlock(&lock->rwlock); if (ret != 0) panic(ret, "Error while gw_rwlock_unlock."); #else RWDEBUG("", 0, "------------ gw_rwlock_unlock(%p) ----------", lock); if (lock->writer == gwthread_self()) { lock->writer = -1; gwlist_unlock(lock->rwlock); } else gwlist_remove_producer(lock->rwlock); #endif return ret; } int gw_rwlock_wrlock(RWLock *lock) { int ret = 0; gw_assert(lock != NULL); #ifdef HAVE_PTHREAD_RWLOCK ret = pthread_rwlock_wrlock(&lock->rwlock); if (ret != 0) panic(ret, "Error while pthread_rwlock_wrlock."); #else RWDEBUG("", 0, "------------ gw_rwlock_wrlock(%p) ----------", lock); gwlist_lock(lock->rwlock); RWDEBUG("", 0, "------------ gw_rwlock_wrlock(%p) producers=%d", lock, gwlist_producer_count(lock->rwlock)); /* wait for reader */ gwlist_consume(lock->rwlock); lock->writer = gwthread_self(); #endif return ret; } gateway-1.4.5/gwlib/date.c0000644000175000017500000002315513227613126014062 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* date.c - utility functions for handling times and dates * * Richard Braakman */ #include #include #include #include "gwlib.h" static char const *wkday[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char const *monthname[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; /* The starting day of each month, if there's not a leap year. * January 1 is day 0, December 31 is day 355. */ static int monthstart[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; /* Value in seconds */ #define MINUTE 60 #define HOUR (60 * MINUTE) #define DAY (24 * HOUR) Octstr *date_format_http(unsigned long unixtime) { struct tm tm; char buffer[30]; tm = gw_gmtime((time_t) unixtime); /* Make sure gmtime gave us a good date. We check this to * protect the sprintf call below, which might overflow its * buffer if the field values are bad. */ if (tm.tm_wday < 0 || tm.tm_wday > 6 || tm.tm_mday < 0 || tm.tm_mday > 31 || tm.tm_mon < 0 || tm.tm_mon > 11 || tm.tm_year < 0 || tm.tm_hour < 0 || tm.tm_hour > 23 || tm.tm_min < 0 || tm.tm_min > 59 || tm.tm_sec < 0 || tm.tm_sec > 61) { warning(0, "Bad date for timestamp %lu, cannot format.", unixtime); return NULL; } sprintf(buffer, "%s, %02d %s %04d %02d:%02d:%02d GMT", wkday[tm.tm_wday], tm.tm_mday, monthname[tm.tm_mon], tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec); return octstr_create(buffer); } long date_convert_universal(struct universaltime *t) { long date; int leapyears; long year; date = (t->year - 1970) * (365 * DAY); /* If we haven't had this year's leap day yet, pretend it's * the previous year. */ year = t->year; if (t->month <= 1) year--; /* Add leap years since 1970. The magic number 477 is the value * this formula would give for 1970 itself. Notice the extra * effort we make to keep it correct for the year 2100. */ leapyears = (year / 4) - (year / 100) + (year / 400) - 477; date += leapyears * DAY; date += monthstart[t->month] * DAY; date += (t->day - 1) * DAY; date += t->hour * HOUR; date += t->minute * MINUTE; date += t->second; return date; } long date_parse_http(Octstr *date) { long pos; struct universaltime t; Octstr *monthstr = NULL; /* First, skip the leading day-of-week string. */ pos = octstr_search_char(date, ' ', 0); if (pos < 0 || pos == octstr_len(date) - 1) return -1; pos++; /* Skip the space */ /* Distinguish between the three acceptable formats */ if (isdigit(octstr_get_char(date, pos)) && octstr_get_char(date, pos + 2) == ' ') { if (octstr_len(date) - pos < (long)strlen("06 Nov 1994 08:49:37 GMT")) goto error; if (octstr_parse_long(&t.day, date, pos, 10) != pos + 2) goto error; monthstr = octstr_copy(date, pos + 3, 3); if (octstr_parse_long(&t.year, date, pos + 7, 10) != pos + 11) goto error; if (octstr_parse_long(&t.hour, date, pos + 12, 10) != pos + 14) goto error; if (octstr_parse_long(&t.minute, date, pos + 15, 10) != pos + 17) goto error; if (octstr_parse_long(&t.second, date, pos + 18, 10) != pos + 20) goto error; /* Take the GMT part on faith. */ } else if (isdigit(octstr_get_char(date, pos)) && octstr_get_char(date, pos + 2) == '-') { if (octstr_len(date) - pos < (long)strlen("06-Nov-94 08:49:37 GMT")) goto error; if (octstr_parse_long(&t.day, date, pos, 10) != pos + 2) goto error; monthstr = octstr_copy(date, pos + 3, 3); if (octstr_parse_long(&t.year, date, pos + 7, 10) != pos + 9) goto error; if (t.year > 60) t.year += 1900; else t.year += 2000; if (octstr_parse_long(&t.hour, date, pos + 10, 10) != pos + 12) goto error; if (octstr_parse_long(&t.minute, date, pos + 13, 10) != pos + 15) goto error; if (octstr_parse_long(&t.second, date, pos + 16, 10) != pos + 18) goto error; /* Take the GMT part on faith. */ } else { if (octstr_len(date) - pos < (long)strlen(" 6 08:49:37 1994")) goto error; monthstr = octstr_copy(date, pos, 3); if (octstr_parse_long(&t.day, date, pos + 4, 10) != pos + 6) goto error; if (octstr_parse_long(&t.hour, date, pos + 7, 10) != pos + 9) goto error; if (octstr_parse_long(&t.minute, date, pos + 10, 10) != pos + 12) goto error; if (octstr_parse_long(&t.second, date, pos + 13, 10) != pos + 15) goto error; if (octstr_parse_long(&t.year, date, pos + 16, 10) != pos + 20) goto error; } for (t.month = 0; t.month < 12; t.month++) { if (octstr_str_compare(monthstr, monthname[t.month]) == 0) break; } if (t.month == 12) goto error; octstr_destroy(monthstr); return date_convert_universal(&t); error: octstr_destroy(monthstr); return -1; } int date_parse_iso (struct universaltime *ut, Octstr *os) { int n = 0; char *p, *q; /* assign defaults */ ut->month = 0; ut->day = 1; ut->hour = 0; ut->minute = 0; ut->second = 0; p = octstr_get_cstr(os); q = p + ((n = octstr_search_char(os, 'T', 0)) >= 0 ? n : octstr_len(os)); /* stop at the end of string or at the time separator */ if (sscanf(p, "%4ld%n", &ut->year, &n) < 1) return -1; p += n; if (ut->year < 70) ut->year += 2000; else if (ut->year < 100) ut->year += 1900; while (p < q && !gw_isdigit(*p)) p++; if (sscanf(p, "%2ld%n", &ut->month, &n) < 1) return 0; p += n; /* 0-based months */ if (ut->month > 0) ut->month--; while (p < q && !gw_isdigit(*p)) p++; if (sscanf(p, "%2ld%n", &ut->day, &n) < 1) return 0; p += n; if (*q == 'T') p = q+1; else return 0; while (*p && !gw_isdigit(*p)) p++; if (sscanf(p, "%2ld%n", &ut->hour, &n) < 1) return 0; p += n; while (*p && !gw_isdigit(*p)) p++; if (sscanf(p, "%2ld%n", &ut->minute, &n) < 1) return 0; p += n; while (*p && !gw_isdigit(*p)) p++; if (sscanf(p, "%2ld%n", &ut->second, &n) < 1) return 0; p += n; return 0; } Octstr* date_create_iso(time_t unixtime) { struct tm tm; tm = gw_gmtime(unixtime); return octstr_format("%d-%02d-%02dT%02d:%02d:%02dZ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } /* Note that this implementation makes unportable assumptions about time_t. */ long date_universal_now(void) { return (long) time(NULL); } gateway-1.4.5/gwlib/accesslog.c0000644000175000017500000001365413227613126015113 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * accesslog.c - implement access logging functions * * see accesslog.h. * * Kalle Marjola 2000 for Project Kannel */ #include #include #include #include #include #include #include "gwlib.h" static FILE *file = NULL; static char filename[FILENAME_MAX + 1]; /* to allow re-open */ static int use_localtime; static int markers = 1; /* can be turned-off by 'access-log-clean = yes' */ /* * Reopen/rotate lock. */ static List *writers = NULL; void alog_reopen(void) { if (file == NULL) return; if (markers) alog("Log ends"); gwlist_lock(writers); /* wait for writers to complete */ gwlist_consume(writers); fclose(file); file = fopen(filename, "a"); gwlist_unlock(writers); if (file == NULL) { error(errno, "Couldn't re-open access logfile `%s'.", filename); } else if (markers) { alog("Log begins"); } } void alog_close(void) { if (file != NULL) { if (markers) alog("Log ends"); gwlist_lock(writers); /* wait for writers to complete */ gwlist_consume(writers); fclose(file); file = NULL; gwlist_unlock(writers); gwlist_destroy(writers, NULL); writers = NULL; } } void alog_open(char *fname, int use_localtm, int use_markers) { FILE *f; use_localtime = use_localtm; markers = use_markers; if (file != NULL) { warning(0, "Opening an already opened access log"); alog_close(); } if (strlen(fname) > FILENAME_MAX) { error(0, "Access Log filename too long: `%s', cannot open.", fname); return; } if (writers == NULL) writers = gwlist_create(); f = fopen(fname, "a"); if (f == NULL) { error(errno, "Couldn't open logfile `%s'.", fname); return; } file = f; strcpy(filename, fname); info(0, "Started access logfile `%s'.", filename); if (markers) alog("Log begins"); } void alog_use_localtime(void) { use_localtime = 1; } void alog_use_gmtime(void) { use_localtime = 0; } #define FORMAT_SIZE (10*1024) static void format(char *buf, const char *fmt) { time_t t; struct tm tm; char *p, prefix[1024]; p = prefix; if (markers) { time(&t); if (use_localtime) tm = gw_localtime(t); else tm = gw_gmtime(t); sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } else { *p = '\0'; } if (strlen(prefix) + strlen(fmt) > FORMAT_SIZE / 2) { sprintf(buf, "%s \n", prefix); return; } sprintf(buf, "%s%s\n", prefix, fmt); } /* XXX should we also log automatically into main log, too? */ void alog(const char *fmt, ...) { char buf[FORMAT_SIZE + 1]; va_list args; if (file == NULL) return; format(buf, fmt); va_start(args, fmt); gwlist_lock(writers); gwlist_add_producer(writers); gwlist_unlock(writers); vfprintf(file, buf, args); fflush(file); gwlist_remove_producer(writers); va_end(args); } gateway-1.4.5/gwlib/gwmem-native.c0000644000175000017500000001020713227613126015537 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwmem-native.h - memory managment wrapper functions, native flavor * * Lars Wirzenius */ #include #include #include #include "gwlib.h" /* * In this module, we must use the real versions so let's undefine the * accident protectors. */ #undef malloc #undef calloc #undef realloc #undef free void *gw_native_noop(void *ptr) { return ptr; } void *gw_native_malloc(size_t size) { void *ptr; /* ANSI C89 says malloc(0) is implementation-defined. Avoid it. */ gw_assert(size > 0); ptr = malloc(size); if (ptr == NULL) panic(errno, "Memory allocation failed"); return ptr; } void *gw_native_calloc(int nmemb, size_t size) { void *ptr; /* ANSI C89 says malloc(0) is implementation-defined. Avoid it. */ gw_assert(size > 0); gw_assert(nmemb > 0); ptr = calloc(nmemb, size); if (ptr == NULL) panic(errno, "Memory allocation failed"); return ptr; } void *gw_native_realloc(void *ptr, size_t size) { void *new_ptr; gw_assert(size > 0); new_ptr = realloc(ptr, size); if (new_ptr == NULL) panic(errno, "Memory re-allocation failed"); return new_ptr; } void gw_native_free(void *ptr) { free(ptr); } char *gw_native_strdup(const char *str) { char *copy; int size; gw_assert(str != NULL); size = strlen(str) + 1; copy = gw_native_malloc(size); memcpy(copy, str, size); return copy; } gateway-1.4.5/gwlib/gwpoll.c0000644000175000017500000001226413227613126014450 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* gwpoll.c - implement poll() for systems that don't have it */ #include "gwlib/gwlib.h" #ifndef HAVE_SYS_POLL_H #include #include #include int gw_poll(struct pollfd *fdarray, unsigned int numfds, int timeout) { struct timeval tv, *tvp; unsigned int i; int maxfd; fd_set readfds, *rfdp; fd_set writefds, *wfdp; fd_set exceptfds, *xfdp; int ret; int result; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds); maxfd = -1; /* These are the pointers we will pass to select(). We use them because * we may want to pass NULL for some of them. */ tvp = NULL; rfdp = NULL; wfdp = NULL; xfdp = NULL; /* Deal with timeout. We get it in milliseconds. If it's negative, * block indefinitely, which we do in select() by passing a NULL * timeval pointer. */ if (timeout >= 0) { tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; tvp = &tv; } /* Deal with fdarray, and convert it to the three fd_sets used by select. */ for (i = 0; i < numfds; i++) { int fd = fdarray[i].fd; int events = fdarray[i].events; if (fd < 0) continue; if (events & POLLIN) { FD_SET(fd, &readfds); rfdp = &readfds; } if (events & POLLOUT) { FD_SET(fd, &writefds); wfdp = &writefds; } if (events & POLLPRI) { FD_SET(fd, &exceptfds); xfdp = &exceptfds; } if (fd > maxfd && events & (POLLIN | POLLOUT | POLLPRI)) maxfd = fd; } ret = select(maxfd + 1, rfdp, wfdp, xfdp, tvp); if (ret < 0) return ret; /* Move the returned data from the fd sets to the revents fields * in fdarray. We can't detect POLLNVAL except for obviously * invalid fd's, and detecting POLLHUP or POLLERR would require * an extra read() call per fd which is too expensive. */ result = 0; for (i = 0; i < numfds; i++) { if (fdarray[i].fd < 0) { fdarray[i].revents = POLLNVAL; continue; } fdarray[i].revents = 0; if (rfdp && FD_ISSET(fdarray[i].fd, &readfds)) fdarray[i].revents |= POLLIN; if (wfdp && FD_ISSET(fdarray[i].fd, &writefds)) fdarray[i].revents |= POLLOUT; if (xfdp && FD_ISSET(fdarray[i].fd, &exceptfds)) fdarray[i].revents |= POLLPRI; if (fdarray[i].revents != 0) result++; } return result; } #endif gateway-1.4.5/gwlib/octstr.h0000644000175000017500000005743613227613126014501 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * octstr.h - Octet strings * * This header file declares an abstract data type, Octstr, for storing * and manipulating octet strings: strings of arbitrary binary data in * 8-bit bytes. Unlike C strings, they can contain the NUL byte ('\0'). * Conceptually, they consist of a sequence of octets (bytes) and the * length of the sequence. There are various basic operations on octet * strings: concatenating, comparing, printing, etc. * * Octet strings come in two flavors: mutable and immutable. Mutable * octet strings are the normal kind and they can be modified and * otherwise manipulated at will. Immutable octet strings are meant to * be wrappers around a C string literal. They may not be modified, though * they may be destroyed. * * Immutable octet strings are meant to simplify usage of octet strings * together with C strings by reducing the number of octstr_* functions. * For example, we need a function for searching one string within another. * There needs to be different flavors of this: exact search, case-insensitive * search, and a search limited to the first N octets of the strings. * If in each of these one of the arguments may be either an octet string * or a C string, the number of functions doubles. Thus, we use immutable * strings instead: * * octstr_search(os, octstr_imm("foo"), 0) * * The above looks like a memory leak, but it is not. Each immutable * octet string (i.e., with the same C string literal pointer) is really * created only the first time, and octstr_destroy won't destroy it, * either. The immutable octet strings are destroyed automatically when * the process ends. * * See comments below for explanations on individual functions. Note that * all functions use gw_malloc and friends, so they won't return if the * memory allocations fail. Octet string functions are thread safe, as * long as they only one thread at a time operates on each octet string. */ #ifndef OCTSTR_H #define OCTSTR_H #include #include #include "list.h" typedef struct Octstr Octstr; /* * Initialize the Octstr subsystem. */ void octstr_init(void); /* * Shut down the Octstr subsystem. */ void octstr_shutdown(void); /* * Create an octet string from a NUL-terminated C string. Return pointer to * the new object. */ Octstr *octstr_create_real(const char *cstr, const char *file, long line, const char *func); #define octstr_create(cstr) \ (Octstr*)gw_claim_area(octstr_create_real((cstr), __FILE__, __LINE__, __func__)) /* * Create an octet string from arbitrary binary data. The length of the * data is given, so it can contain NUL characters. */ Octstr *octstr_create_from_data_real(const char *data, long len, const char *file, long line, const char *func); #define octstr_create_from_data(data, len) \ (Octstr*)gw_claim_area(octstr_create_from_data_real((data), (len), __FILE__, __LINE__, __func__)) #define octstr_create_from_data_trace(data, len, file, line, func) \ (Octstr*)gw_claim_area(octstr_create_from_data_real(data, len, file, line, func)) /* * Create an immutable octet string from a C string literal. The * C string literal MUST NOT be modified and it MUST exist until the * octet string is destroyed. The immutable octet string need not be * destroyed - it is destroyed automatically when octstr_shutdown is * called. In fact, octstr_destroy is a no-op for immutables. */ Octstr *octstr_imm(const char *cstr); /* * Destroy an octet string, freeing all memory it uses. A NULL argument * is ignored. */ void octstr_destroy(Octstr *ostr); /* * Destroy an octet string. Wrapper around octstr_destroy that is callable * via gwlist_destroy. */ void octstr_destroy_item(void *os); /* * Return the length of (number of octets in) an object string. */ long octstr_len(const Octstr *ostr); /* * Create a new octet string by copying part of an existing one. Return * pointer to the new object. If `from' is after end of `ostr', an empty * octet string is created. If `from+len' is after the end of `ostr', * `len' is reduced appropriately. */ Octstr *octstr_copy_real(const Octstr *ostr, long from, long len, const char *file, long line, const char *func); #define octstr_copy(ostr, from, len) \ gw_claim_area(octstr_copy_real((ostr), (from), (len), __FILE__, __LINE__, __func__)) /* * Copy all of an octet string. */ Octstr *octstr_duplicate_real(const Octstr *ostr, const char *file, long line, const char *func); #define octstr_duplicate(ostr) \ gw_claim_area(octstr_duplicate_real((ostr), __FILE__, __LINE__, __func__)) /* * Create a new octet string by catenating two existing ones. Return * pointer to the new object. */ Octstr *octstr_cat(Octstr *ostr1, Octstr *ostr2); /* * Return value of octet at a given position in an octet string. The returned * value has a range of 0..255 for valid positions, and -1 if `pos' is * after the end of the octet string. */ int octstr_get_char(const Octstr *ostr, long pos); /* * Replace a single, existing character in an octet string. Operation cannot * fail: if pos is not inside the string, the operation will silently be * ignored. */ void octstr_set_char(Octstr *ostr, long pos, int ch); /* * Copy bytes from octet string into array. */ void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len); /* * Return pointer to contents of octet string as a NUL-terminated C string. * This is guaranteed to have a NUL character at the end, but it is not * guaranteed (how could it?) to not contain NUL characters elsewhere. * The pointer points directly into the internal buffer of the octet * string, and must not be modified, and must not be used after any * octstr_* function that modifies the octet string is called after this * one. It is meant for printing debug messages easily. * * If the octet string is empty, an empty C string is returned, not NULL. */ char *octstr_get_cstr_real(const Octstr *ostr, const char *file, long line, const char *func); #define octstr_get_cstr(ostr) \ (octstr_get_cstr_real(ostr, __FILE__, __LINE__, __func__)) /* * Append characters from printable hexadecimal format at the tail of * an octet string. "78797a" or "78797A" would be converted to "xyz" * and then appended. */ void octstr_append_from_hex(Octstr *ostr, char *hex); /* Convert the octet string in-place to printable hexadecimal format. * "xyz" would be converted to "78797a". If the uppercase * flag is set, 'A' through 'F' are used instead of 'a' through 'f'. */ void octstr_binary_to_hex(Octstr *ostr, int uppercase); /* Convert the octet string in-place from printable hexadecimal * format to binary. "78797a" or "78797A" would be converted to "xyz". * If the string is not in the expected format, return -1 and leave * the string unchanged. If all was fine, return 0. */ int octstr_hex_to_binary(Octstr *ostr); /* Base64-encode the octet string in-place, using the MIME base64 * encoding defined in RFC 2045. Note that the result may be * multi-line and is always terminated with a CR LF sequence. */ void octstr_binary_to_base64(Octstr *ostr); /* Base64-decode the octet string in-place, using the MIME base64 * encoding defined in RFC 2045. */ void octstr_base64_to_binary(Octstr *ostr); /* Parse a number at position 'pos' in 'ostr', using the same rules as * strtol uses regarding 'base'. Skip leading whitespace. * * Return the position of the first character after the number, * or -1 if there was an error. Return the length of the octet string * if the number ran to the end of the string. * * Assign the number itself to the location pointed to by 'number', if * there was no error. * * Possible errno values in case of an error: * ERANGE The number did not fit in a long. * EINVAL No digits of the appropriate base were found. */ long octstr_parse_long(long *number, Octstr *ostr, long pos, int base); /* As above but parses and assigns double number. */ long octstr_parse_double(double *number, Octstr *ostr, long pos); /* Run the 'filter' function over each character in the specified range. * Return 1 if the filter returned true for all characters, otherwise 0. * The octet string is not changed. * For example: ok = octstr_check_range(o, 1, 10, gw_isdigit); */ typedef int (*octstr_func_t)(int); int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter); /* Run the 'map' function over each character in the specified range, * replacing each character with the return value of that function. * For example: octstr_convert_range(o, 1, 10, tolower); */ void octstr_convert_range(Octstr *ostr, long pos, long len, octstr_func_t map); /* * Use the octstr_convert_range() with make_printable() to ensure * every char in the octstr can be printed in the current locale. Each * character that is NOT printable is converted to a '.' (dot). */ void octstr_convert_printable(Octstr *ostr); /* * Compare two octet strings, returning 0 if they are equal, negative if * `ostr1' is less than `ostr2' (when compared octet-value by octet-value), * and positive if greater. */ int octstr_compare(const Octstr *ostr1, const Octstr *ostr2); /* * Like octstr_compare, except compares bytes without case sensitivity. * Note that this probably doesn't work for Unicode, but should work * for such 8-bit character sets as are supported by libc. */ int octstr_case_compare(const Octstr *ostr1, const Octstr *ostr2); /* * as above, but comparing is done only up to n bytes */ int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n); /* * Same as octstr_compare, but compares the content of the octet string to * a C string. */ int octstr_str_compare(const Octstr *ostr1, const char *str); /* * Like octstr_str_compare, except compares bytes without case sensitifity. */ int octstr_str_case_compare(const Octstr *ostr1, const char *str); /* * Same as octstr_str_compare, but comparing is done only up to n bytes. */ int octstr_str_ncompare(const Octstr *ostr, const char *str, long n); /* * Write contents of octet string to a file. Return -1 for error, 0 for OK. */ int octstr_print(FILE *f, Octstr *ostr); /* * Search the character from octet string starting from position pos. Returns * the position (index) of the char in string, -1 if not found. */ long octstr_search_char(const Octstr *ostr, int ch, long pos); /* * Search the character backwards from octet string starting from position pos. Returns * the position (index) of the char in string, -1 if not found. */ long octstr_rsearch_char(const Octstr *ostr, int ch, long pos); /* * Search several character from octet string starting from position pos. Returns * the position (index) of the first char found in string, -1 if none was found. */ long octstr_search_chars(const Octstr *ostr, const Octstr *chars, long pos); /* * Search for the octet string 'needle' in the octet string 'haystack'. * Return the start position (index) of 'needle' in 'haystack'. * Return -1 if not found. */ long octstr_search(const Octstr *haystack, const Octstr *needle, long pos); /* * Like octstr_search, but ignores 8-bit byte case. */ long octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos); /* * Like octstr_case_search, but searchs only first n octets. */ long octstr_case_nsearch(const Octstr *haystack, const Octstr *needle, long pos, long n); /* * Like octstr_search, but with needle as C-String. */ long octstr_str_search(const Octstr *haystack, const char *needle, long pos); /* * Write contents of octet string to a file, in human readable form. * Return -1 for error, 0 for OK. Octets that are not printable characters * are printed using C-style escape notation. */ int octstr_pretty_print(FILE *f, Octstr *ostr); /* * Write contents of octet string to a socket. Return -1 for error, 0 for OK. */ int octstr_write_to_socket(int socket, Octstr *ostr); /* * Write contents of octet string starting at 'from' to a * non-blocking file descriptor. * Return the number of octets written. Return -1 for error. * It is possible for this function to write only part of the octstr. */ long octstr_write_data(Octstr *ostr, int fd, long from); /* * Read available data from socket and return it as an octstr. * Block if no data is available. If a lot of data is available, * read only up to an internal limit. * Return -1 for error. */ int octstr_append_from_socket(Octstr *ostr, int socket); /* * Insert one octet string into another. `pos' gives the position * in `ostr1' where `ostr2' should be inserted. */ void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos); /* * Insert characters from C array into an octet string. `pos' * gives the position in `ostr' where `data' should be inserted. `len' * gives the number of characters in `data'. * If the given `pos' is greater than the length of the input octet string, * it is set to that length, resulting in an append. */ void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len); /* * Similar as previous, expect that now a single character is inserted. */ void octstr_insert_char(Octstr *ostr, long pos, const char c); /* * Append characters from C array at the tail of an octet string. */ void octstr_append_data(Octstr *ostr, const char *data, long len); /* * Append a second octstr to the first. */ void octstr_append(Octstr *ostr1, const Octstr *ostr2); /* * Append a normal C string at the tail of an octet string. */ void octstr_append_cstr(Octstr *ostr, const char *cstr); /* * Append a single character at the tail of an octet string. */ void octstr_append_char(Octstr *ostr, int ch); /* * Truncate octet string at `new_len'. If new_len is same or more * than current, do nothing. */ void octstr_truncate(Octstr *ostr, int new_len); /* * Strip white space from start and end of a octet string. */ void octstr_strip_blanks(Octstr *ostr); /* * Strip CR and LF from start and end of a octet string. */ void octstr_strip_crlfs(Octstr *ostr); /* * Strip non-alphanums from start and end of a octet string. */ void octstr_strip_nonalphanums(Octstr *ostr); /* * Shrink consecutive white space characters into one space. */ void octstr_shrink_blanks(Octstr *ostr); /* * Delete part of an octet string. */ void octstr_delete(Octstr *ostr1, long pos, long len); /* * Read the contents of a named file to an octet string. Return pointer to * octet string. */ Octstr *octstr_read_file(const char *filename); /* * Read the contents of a file descriptor pipe to an octet string. * Return pointer to octet string. */ Octstr *octstr_read_pipe(FILE *f); /* * Split an octet string into words at whitespace, and return a list * containing the new octet strings. */ List *octstr_split_words(const Octstr *ostr); /* * Split an octet string into substrings at every occurence of `sep'. * Return List with the substrings. */ List *octstr_split(const Octstr *os, const Octstr *sep); /* * Compare two octet strings in a manner suitable for gwlist_search. */ int octstr_item_match(void *item, void *pattern); /* * Same as above, except compares bytes without case sensitivity */ int octstr_item_case_match(void *item, void *pattern); /* * Print debugging information about octet string. This is abstracted to the * various log levels we have: GW_DEBUG, GW_INFO, GW_WARNING, GW_ERROR * * If a third parameter in the argument list is given, we will dump the * octstr in that log level instead of the default GW_DEBUG level. */ void octstr_dump_real(const Octstr *ostr, int level, ...); #define octstr_dump(ostr, level, ...) \ octstr_dump_real(ostr, level, GW_DEBUG, ##__VA_ARGS__) /* * Write the contents of an octet string to the debug log. * Keep it on one line if the octet string is short and printable, * otherwise use a hex dump. */ void octstr_dump_short(Octstr *ostr, int level, const char *name); /* * decode url-encoded octstr in-place. * Return 0 if all went fine, or -1 if there was some garbage */ int octstr_url_decode(Octstr *ostr); /* * URL encode the argument string in place. */ void octstr_url_encode(Octstr *ostr); /* * Treat the octstr as an unsigned array of bits, most significant bit * first, and return the indicated bit range as an integer. numbits * must not be larger than 32. Bits beyond the end of the string will * be read as 0. */ long octstr_get_bits(Octstr *ostr, long bitpos, int numbits); /* * Treat the octstr as an unsigned array of bits, most significant bit * first, and set the indicated bit range to the given value. numbits * must not be larger than 32. The value must fit in that number of bits. * The string will be extended with 0-valued octets as necessary to hold * the indicated bit range. */ void octstr_set_bits(Octstr *ostr, long bitpos, int numbits, unsigned long value); /* * Encode value in WSP's uintvar format, and append it to the octstr */ void octstr_append_uintvar(Octstr *ostr, unsigned long value); /* * Decode a value in WSP's uintvar format at position pos of the octstr, * and put the result in *value. Return the position after the uintvar. * Return -1 if there is not a valid uintvar at pos. */ long octstr_extract_uintvar(Octstr *ostr, unsigned long *value, long pos); /* * Append the decimal representation of the given value to ostr */ void octstr_append_decimal(Octstr *ostr, long value); /* * Create a new octet string based on a printf-like (but not identical) * format string, and a list of other arguments. The format string is * a C string for convenience, but this may change later. * * The syntax for the format string is as follows: * * % [-] [0] [width] [. prec] [type] conversion * * where [] denotes optional parts and the various parts have the * following meanings: * * - add padding to the right, instead of the left of the field * * 0 pad with zeroes, not spaces * * width minimum output width; non-negative integer or '*', indicating * that the next argument is an int and gives the width * * . a dot to indicate that precision follows * * prec precision: maximum length of strings, maximum number of * decimals for floating point numbers; non-negative integer * or '*' indicating that the next argument is an int and * gives the precision * * type type of integer argument: either h (for short int) or * l (for long int); may only be used with conversion 'd' * * conversion * how the field is to be converted, also implicitly defines * the type of the next argument; one of * * d int (unless type says otherwise) * output as a decimal integer * * e, f, g double * output in various formats of floating * point, see printf(3) for details * * s char * * output as character string * * S Octstr * * output as character string, except '\0' * inside the string is included in the * output * * E Octstr * * output as character string, except that * contents are URL-encoded when need to. Note * that trunctae is done afterwards and can * cut escape '%EE' in half * * H Octstr * * output as character string, except that * contents are HEX-encoded in uppercase */ Octstr *octstr_format(const char *fmt, ...); /* * Like octstr_format, but takes the argument list as a va_list. */ Octstr *octstr_format_valist_real(const char *fmt, va_list args); #define octstr_format_valist(fmt, args) gw_claim_area(octstr_format_valist_real(fmt, args)) /* * Like octstr_format, but appends output to an existing octet * string, instead of creating a new one. */ void octstr_format_append(Octstr *os, const char *fmt, ...); /* * Compute a hash key value for an octet string by adding all the * octets together. */ unsigned long octstr_hash_key(Octstr *ostr); /* * return an Octstr encoded in charset named tocode created from the data * in the Octstr orig that is encoded in the charset fromcode. */ int octstr_recode(Octstr *tocode, Octstr *fromcode, Octstr *orig); /* * Strip all occurence of char ch from start of Octstr */ void octstr_strip_char(Octstr *text, char ch); /* * Check if ostr is numeric */ int octstr_isnum(Octstr *ostr1); /* * Replace all occurences of needle with repl within haystack */ void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl); /* * Replace first occurence of needle with repl within haystack */ void octstr_replace_first(Octstr *haystack, Octstr *needle, Octstr *repl); /* * Symbolize hex string '78797a' becomes '%78%79%7a' */ int octstr_symbolize(Octstr *ostr); /* * Remove all occurrences of 'needle' within 'haystack'. */ void octstr_delete_matching(Octstr *haystack, Octstr *needle); /* * Return 1, if octstr 'os' contains only hex chars, 0 otherwise. */ int octstr_is_all_hex(Octstr *os); /* * make data HTML safe by converting appropriate characters to HTML entities. * conversion is done in place */ void octstr_convert_to_html_entities(Octstr* input); /* * convert HTML safe data back to binary data by replacing HTML entities with their * respective character values. * conversion is done in place */ void octstr_convert_from_html_entities(Octstr* input); #endif gateway-1.4.5/gwlib/gw-prioqueue.h0000644000175000017500000001154513227613126015603 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw-prioqueue.h - generic priority queue. * * Algorithm ala Robert Sedgewick. * * Alexander Malysh , 2004 */ #ifndef GW_PRIOQUEUE_H #define GW_PRIOQUEUE_H 1 typedef struct gw_prioqueue gw_prioqueue_t; /** * Create priority queue * @cmp - compare function * @return newly created priority queue */ gw_prioqueue_t *gw_prioqueue_create(int(*cmp)(const void*, const void *)); /** * Destroy priority queue * @queue - queue to destroy * @item_destroy - item destructor */ void gw_prioqueue_destroy(gw_prioqueue_t *queue, void(*item_destroy)(void*)); /** * Return priority queue length * @queue - priority queue * @return length of this priority queue */ long gw_prioqueue_len(gw_prioqueue_t *queue); /** * Insert item into the priority queue * @queue - priority queue * @item - to be inserted item */ void gw_prioqueue_insert(gw_prioqueue_t *queue, void *item); #define gw_prioqueue_produce(queue, item) gw_prioqueue_insert(queue, item) void gw_prioqueue_foreach(gw_prioqueue_t *queue, void(*fn)(const void *, long)); /** * Remove biggest item from the priority queue, but not block if producers * available and none items in the queue * @queue - priority queue * @return - biggest item or NULL if none items in the queue */ void *gw_prioqueue_remove(gw_prioqueue_t *queue); /* * Same as gw_prioqueue_remove, except that item is not removed from the * priority queue */ void *gw_prioqueue_get(gw_prioqueue_t *queue); /** * Remove biggest item from the priority queue, but block if producers * available and none items in the queue * @queue - priority queue * @return biggest item or NULL if none items and none producers in the queue */ void *gw_prioqueue_consume(gw_prioqueue_t *queue); /** * Add producer to the priority queue * @queue - priority queue */ void gw_prioqueue_add_producer(gw_prioqueue_t *queue); /** * Remove producer from the priority queue * @queue - priority queue */ void gw_prioqueue_remove_producer(gw_prioqueue_t *queue); /** * Return producer count for the priority queue * @queue - priority queue * @return producer count */ long gw_prioqueue_producer_count(gw_prioqueue_t *queue); #endif gateway-1.4.5/gwlib/octstr.h.debug0000644000175000017500000004430510177757502015565 0ustar toljtolj/* * octstr.h - Octet strings * * This header file declares an abstract data type, Octstr, for storing * and manipulating octet strings: strings of arbitrary binary data in * 8-bit bytes. Unlike C strings, they can contain the NUL byte ('\0'). * Conceptually, they consist of a sequence of octets (bytes) and the * length of the sequence. There are various basic operations on octet * strings: concatenating, comparing, printing, etc. * * Octet strings come in two flavors: mutable and immutable. Mutable * octet strings are the normal kind and they can be modified and * otherwise manipulated at will. Immutable octet strings are meant to * be wrappers around a C string literal. They may not be modified, though * they may be destroyed. * * Immutable octet strings are meant to simplify usage of octet strings * together with C strings by reducing the number of octstr_* functions. * For example, we need a function for searching one string within another. * There needs to be different flavors of this: exact search, case-insensitive * search, and a search limited to the first N octets of the strings. * If in each of these one of the arguments may be either an octet string * or a C string, the number of functions doubles. Thus, we use immutable * strings instead: * * octstr_search(os, octstr_imm("foo"), 0) * * The above looks like a memory leak, but it is not. Each immutable * octet string (i.e., with the same C string literal pointer) is really * created only the first time, and octstr_destroy won't destroy it, * either. The immutable octet strings are destroyed automatically when * the process ends. * * See comments below for explanations on individual functions. Note that * all functions use gw_malloc and friends, so they won't return if the * memory allocations fail. Octet string functions are thread safe, as * long as they only one thread at a time operates on each octet string. */ #ifndef OCTSTR_H #define OCTSTR_H #include #include #include "list.h" typedef struct Octstr Octstr; /* * Initialize the Octstr subsystem. */ void octstr_init(void); /* * Shut down the Octstr subsystem. */ void octstr_shutdown(void); /* * Create an octet string from a NUL-terminated C string. Return pointer to * the new object. */ Octstr *octstr_create_real(const char *cstr); #define octstr_create(cstr) gw_claim_area(octstr_create_real((cstr))) /* * Create an octet string from arbitrary binary data. The length of the * data is given, so it can contain NUL characters. */ Octstr *octstr_create_from_data_real(const char *data, long len); #define octstr_create_from_data(data, len)\ gw_claim_area(octstr_create_from_data_real((data), (len))) /* * Create an immutable octet string from a C string literal. The * C string literal MUST NOT be modified and it MUST exist until the * octet string is destroyed. The immutable octet string need not be * destroyed - it is destroyed automatically when octstr_shutdown is * called. In fact, octstr_destroy is a no-op for immutables. */ Octstr *octstr_imm(const char *cstr); /* * Destroy an octet string, freeing all memory it uses. A NULL argument * is ignored. */ void octstr_destroy_impl(Octstr *ostr, const char *file, long line, const char *func); #define octstr_destroy(ostr)\ octstr_destroy_impl((ostr),__FILE__,__LINE__,__PRETTY_FUNCTION__) /* * Destroy an octet string. Wrapper around octstr_destroy that is callable * via gwlist_destroy. */ void octstr_destroy_item(void *os); /* * Return the length of (number of octets in) an object string. */ long octstr_len(Octstr *ostr); /* * Create a new octet string by copying part of an existing one. Return * pointer to the new object. If `from' is after end of `ostr', an empty * octet string is created. If `from+len' is after the end of `ostr', * `len' is reduced appropriately. */ Octstr *octstr_copy_real(Octstr *ostr, long from, long len); #define octstr_copy(ostr, from, len) \ gw_claim_area(octstr_copy_real((ostr), (from), (len))) /* * Copy all of an octet string. */ Octstr *octstr_duplicate_real(Octstr *ostr); #define octstr_duplicate(ostr) gw_claim_area(octstr_duplicate_real((ostr))) /* * Create a new octet string by catenating two existing ones. Return * pointer to the new object. */ Octstr *octstr_cat(Octstr *ostr1, Octstr *ostr2); /* * Return value of octet at a given position in an octet string. The returned * value has a range of 0..255 for valid positions, and -1 if `pos' is * after the end of the octet string. */ int octstr_get_char(Octstr *ostr, long pos); /* * Replace a single, existing character in an octet string. Operation cannot * fail: if pos is not inside the string, the operation will silently be * ignored. */ void octstr_set_char(Octstr *ostr, long pos, int ch); /* * Copy bytes from octet string into array. */ void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len); /* * Return pointer to contents of octet string as a NUL-terminated C string. * This is guaranteed to have a NUL character at the end, but it is not * guaranteed (how could it?) to not contain NUL characters elsewhere. * The pointer points directly into the internal buffer of the octet * string, and must not be modified, and must not be used after any * octstr_* function that modifies the octet string is called after this * one. It is meant for printing debug messages easily. * * If the octet string is empty, an empty C string is returned, not NULL. */ char *octstr_get_cstr_real(Octstr *ostr, const char *file, long line, const char *func); #define octstr_get_cstr(ostr) \ (octstr_get_cstr_real(ostr, __FILE__, __LINE__, __func__)) /* * Append characters from printable hexadecimal format at the tail of * an octet string. "78797a" or "78797A" would be converted to "xyz" * and then appended. */ void octstr_append_from_hex(Octstr *ostr, char *hex); /* Convert the octet string in-place to printable hexadecimal format. * "xyz" would be converted to "78797a". If the uppercase * flag is set, 'A' through 'F' are used instead of 'a' through 'f'. */ void octstr_binary_to_hex(Octstr *ostr, int uppercase); /* Convert the octet string in-place from printable hexadecimal * format to binary. "78797a" or "78797A" would be converted to "xyz". * If the string is not in the expected format, return -1 and leave * the string unchanged. If all was fine, return 0. */ int octstr_hex_to_binary(Octstr *ostr); /* Base64-encode the octet string in-place, using the MIME base64 * encoding defined in RFC 2045. Note that the result may be * multi-line and is always terminated with a CR LF sequence. */ void octstr_binary_to_base64(Octstr *ostr); /* Base64-decode the octet string in-place, using the MIME base64 * encoding defined in RFC 2045. */ void octstr_base64_to_binary(Octstr *ostr); /* Parse a number at position 'pos' in 'ostr', using the same rules as * strtol uses regarding 'base'. Skip leading whitespace. * * Return the position of the first character after the number, * or -1 if there was an error. Return the length of the octet string * if the number ran to the end of the string. * * Assign the number itself to the location pointed to by 'number', if * there was no error. * * Possible errno values in case of an error: * ERANGE The number did not fit in a long. * EINVAL No digits of the appropriate base were found. */ long octstr_parse_long(long *number, Octstr *ostr, long pos, int base); /* Run the 'filter' function over each character in the specified range. * Return 1 if the filter returned true for all characters, otherwise 0. * The octet string is not changed. * For example: ok = octstr_check_range(o, 1, 10, gw_isdigit); */ typedef int (*octstr_func_t)(int); int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter); /* Run the 'map' function over each character in the specified range, * replacing each character with the return value of that function. * For example: octstr_convert_range(o, 1, 10, tolower); */ void octstr_convert_range(Octstr *ostr, long pos, long len, octstr_func_t map); /* * Compare two octet strings, returning 0 if they are equal, negative if * `ostr1' is less than `ostr2' (when compared octet-value by octet-value), * and positive if greater. */ int octstr_compare(Octstr *ostr1, Octstr *ostr2); /* * Like octstr_compare, except compares bytes without case sensitivity. * Note that this probably doesn't work for Unicode, but should work * for such 8-bit character sets as are supported by libc. */ int octstr_case_compare(Octstr *ostr1, Octstr *ostr2); /* * as above, but comparing is done only up to n bytes */ int octstr_ncompare(Octstr *ostr1, Octstr *ostr2, long n); /* * Same as octstr_compare, but compares the content of the octet string to * a C string. */ int octstr_str_compare(Octstr *ostr1, const char *str); /* * Write contents of octet string to a file. Return -1 for error, 0 for OK. */ int octstr_print(FILE *f, Octstr *ostr); /* * Search the character from octet string starting from position pos. Returns * the position (index) of the char in string, -1 if not found. */ int octstr_search_char(Octstr *ostr, int ch, long pos); /* * Search for the octet string 'needle' in the octet string 'haystack'. * Return the start position (index) of 'needle' in 'haystack'. * Return -1 if not found. */ int octstr_search(Octstr *haystack, Octstr *needle, long pos); /* * Like octstr_search, but ignores 8-bit byte case. */ int octstr_case_search(Octstr *haystack, Octstr *needle, long pos); /* * Write contents of octet string to a file, in human readable form. * Return -1 for error, 0 for OK. Octets that are not printable characters * are printed using C-style escape notation. */ int octstr_pretty_print(FILE *f, Octstr *ostr); /* * Write contents of octet string to a socket. Return -1 for error, 0 for OK. */ int octstr_write_to_socket(int socket, Octstr *ostr); /* * Write contents of octet string starting at 'from' to a * non-blocking file descriptor. * Return the number of octets written. Return -1 for error. * It is possible for this function to write only part of the octstr. */ long octstr_write_data(Octstr *ostr, int fd, long from); /* * Read available data from socket and return it as an octstr. * Block if no data is available. If a lot of data is available, * read only up to an internal limit. * Return -1 for error. */ int octstr_append_from_socket(Octstr *ostr, int socket); /* * Insert one octet string into another. `pos' gives the position * in `ostr1' where `ostr2' should be inserted. */ void octstr_insert_impl (Octstr *ostr1, Octstr *ostr2, long pos, const char *file, long line, const char *func); #define octstr_insert(ostr1,ostr2,pos)\ octstr_insert_impl ((ostr1),(ostr2),(pos),__FILE__,__LINE__,__PRETTY_FUNCTION__) /* * Insert characters from C array into an octet string. `pos' * gives the position in `ostr' where `data' should be inserted. `len' * gives the number of characters in `data'. * If the given `pos' is greater than the length of the input octet string, * it is set to that length, resulting in an append. */ void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len); /* * Append characters from C array at the tail of an octet string. */ void octstr_append_data(Octstr *ostr, const char *data, long len); /* * Append a second octstr to the first. */ void octstr_append_impl(Octstr *ostr1, Octstr *ostr2, const char *file, long line, const char *func); #define octstr_append(ostr1,ostr2)\ octstr_append_impl ((ostr1),(ostr2),__FILE__,__LINE__,__PRETTY_FUNCTION__) /* * Append a normal C string at the tail of an octet string. */ void octstr_append_cstr(Octstr *ostr, const char *cstr); /* * Append a single character at the tail of an octet string. */ void octstr_append_char(Octstr *ostr, int ch); /* * Truncate octet string at `new_len'. If new_len is same or more * than current, do nothing. */ void octstr_truncate(Octstr *ostr, int new_len); /* * Strip white space from start and end of a octet string. */ void octstr_strip_blanks(Octstr *ostr); /* * Strip non-alphanums from start and end of a octet string. */ void octstr_strip_nonalphanums(Octstr *ostr); /* * Shrink consecutive white space characters into one space. */ void octstr_shrink_blanks(Octstr *ostr); /* * Delete part of an octet string. */ void octstr_delete(Octstr *ostr1, long pos, long len); /* * Read the contents of a named file to an octet string. Return pointer to * octet string. */ Octstr *octstr_read_file(const char *filename); /* * Read the contents of a file descriptor pipe to an octet string. * Return pointer to octet string. */ Octstr *octstr_read_pipe(FILE *f); /* * Split an octet string into words at whitespace, and return a list * containing the new octet strings. */ List *octstr_split_words(Octstr *ostr); /* * Split an octet string into substrings at every occurence of `sep'. * Return List with the substrings. */ List *octstr_split(Octstr *os, Octstr *sep); /* * Compare two octet strings in a manner suitable for gwlist_search. */ int octstr_item_match(void *item, void *pattern); /* * Same as above, except compares bytes without case sensitivity */ int octstr_item_case_match(void *item, void *pattern); /* * Print debugging information about octet string. */ void octstr_dump(Octstr *ostr, int level); /* * Write the contents of an octet string to the debug log. * Keep it on one line if the octet string is short and printable, * otherwise use a hex dump. */ void octstr_dump_short(Octstr *ostr, int level, const char *name); /* * decode url-encoded octstr in-place. * Return 0 if all went fine, or -1 if there was some garbage */ int octstr_url_decode(Octstr *ostr); /* * URL encode the argument string in place. */ void octstr_url_encode(Octstr *ostr); /* * Treat the octstr as an unsigned array of bits, most significant bit * first, and return the indicated bit range as an integer. numbits * must not be larger than 32. Bits beyond the end of the string will * be read as 0. */ long octstr_get_bits(Octstr *ostr, long bitpos, int numbits); /* * Treat the octstr as an unsigned array of bits, most significant bit * first, and set the indicated bit range to the given value. numbits * must not be larger than 32. The value must fit in that number of bits. * The string will be extended with 0-valued octets as necessary to hold * the indicated bit range. */ void octstr_set_bits(Octstr *ostr, long bitpos, int numbits, unsigned long value); /* * Encode value in WSP's uintvar format, and append it to the octstr */ void octstr_append_uintvar(Octstr *ostr, unsigned long value); /* * Decode a value in WSP's uintvar format at position pos of the octstr, * and put the result in *value. Return the position after the uintvar. * Return -1 if there is not a valid uintvar at pos. */ long octstr_extract_uintvar(Octstr *ostr, unsigned long *value, long pos); /* * Append the decimal representation of the given value to ostr */ void octstr_append_decimal(Octstr *ostr, long value); /* * Create a new octet string based on a printf-like (but not identical) * format string, and a list of other arguments. The format string is * a C string for convenience, but this may change later. * * The syntax for the format string is as follows: * * % [-] [0] [width] [. prec] [type] conversion * * where [] denotes optional parts and the various parts have the * following meanings: * * - add padding to the right, instead of the left of the field * * 0 pad with zeroes, not spaces * * width minimum output width; non-negative integer or '*', indicating * that the next argument is an int and gives the width * * . a dot to indicate that precision follows * * prec precision: maximum length of strings, maximum number of * decimals for floating point numbers; non-negative integer * or '*' indicating that the next argument is an int and * gives the precision * * type type of integer argument: either h (for short int) or * l (for long int); may only be used with conversion 'd' * * conversion * how the field is to be converted, also implicitly defines * the type of the next argument; one of * * d int (unless type says otherwise) * output as a decimal integer * * e, f, g double * output in various formats of floating * point, see printf(3) for details * * s char * * output as character string * * S Octstr * * output as character string, except '\0' * inside the string is included in the * output * * E Octstr * * output as character string, except that * contents are URL-encoded when need to. Note * that trunctae is done afterwards and can * cut escape '%EE' in half */ Octstr *octstr_format(const char *fmt, ...); /* * Like octstr_format, but takes the argument list as a va_list. */ Octstr *octstr_format_valist(const char *fmt, va_list args); /* * Like octstr_format, but appends output to an existing octet * string, instead of creating a new one. */ void octstr_format_append(Octstr *os, const char *fmt, ...); /* * Compute a hash key value for an octet string by adding all the * octets together. */ unsigned long octstr_hash_key(Octstr *ostr); /* * return an Octstr encoded in chrset named tocode created from the data * in the Octstr orig that is encoded in the charset fromcode. */ int octstr_recode (Octstr *tocode, Octstr *fromcode, Octstr *orig); /* * Strip all occurence of char ch from start of Octstr */ void octstr_strip_char(Octstr *text, char ch); /* * Check if ostr is numeric */ int octstr_isnum(Octstr *ostr1); /* * Replace all occurences of needle with repl within haystack */ void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl); /* * Symbolize hex string '78797a' becomes '%78%79%7a' */ int octstr_symbolize(Octstr *ostr); /* * Remove all occurrences of 'needle' within 'haystack'. */ void octstr_delete_matching(Octstr *haystack, Octstr *needle); /* * Return 1, if octstr 'os' contains only hex chars, 0 otherwise. */ int octstr_is_all_hex(Octstr *os); #endif gateway-1.4.5/gwlib/utils.c0000644000175000017500000007056413227613126014313 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * utils.c - generally useful, non-application specific functions for Gateway * */ #include "gw-config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_UCONTEXT #include #endif #include "gwlib.h" #if HAVE_BACKTRACE #include /*backtrace */ #endif /* Headers required for the version dump. */ #if defined(HAVE_LIBSSL) || defined(HAVE_WTLS_OPENSSL) #include #endif #ifdef HAVE_MYSQL #include #include #endif /* * PostgreSQL drives us in a mess here slights. Even * if our own configure run didn't detect openssl and hence * gw-config.h has no HAVE_LIBSSL set, it is generally set * on most distro in , so we end up in unresolved * items at some point. We trick this by undef it again here. */ #ifdef HAVE_PGSQL # ifndef HAVE_LIBSSL # define UNDEF_LIBSSL 1 # endif #include #include # ifdef UNDEF_LIBSSL # undef HAVE_LIBSSL # undef UNDEF_LIBSSL # endif #endif /* HAVE_PGSQL */ #ifdef HAVE_SQLITE #include #endif #ifdef HAVE_SQLITE3 #include #endif #ifdef HAVE_ORACLE #include #endif #ifdef HAVE_REDIS #include #endif /* pid of child process when parachute is used */ static pid_t child_pid = -1; /* pid of pid file owner */ static pid_t pidfile_owner_pid = -1; /* saved child signal handlers */ static struct sigaction child_actions[32]; /* just a flag that child signal handlers are stored */ static int child_actions_init = 0; /* our pid file name */ static char *pid_file = NULL; static volatile sig_atomic_t parachute_shutdown = 0; static void fatal_handler(int sig, siginfo_t *info, void *secret) { #ifdef HAVE_BACKTRACE void *trace[50]; #ifdef REG_EIP ucontext_t *uc = (ucontext_t*)secret; #endif size_t size; #endif struct sigaction act; act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(sig, &act, NULL); #ifdef HAVE_BACKTRACE size = backtrace(trace, sizeof(trace) / sizeof(void*)); #ifdef REG_EIP /* overwrite sigaction with caller's address */ trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP]; #endif gw_backtrace(trace, size, 0); #endif raise(sig); } static void parachute_sig_handler(int signum) { info(0, "Signal %d received, forward to child pid (%ld)", signum, (long) child_pid); /* we do not handle any signal, just forward these to child process */ if (child_pid != -1 && getpid() != child_pid) kill(child_pid, signum); /* if signal received and no child there, terminating */ switch(signum) { case SIGTERM: case SIGINT: case SIGABRT: if (child_pid == -1) exit(0); else parachute_shutdown = 1; } } static void parachute_init_signals(int child) { struct sigaction sa; if (child_actions_init && child) { sigaction(SIGTERM, &child_actions[SIGTERM], NULL); sigaction(SIGQUIT, &child_actions[SIGQUIT], NULL); sigaction(SIGINT, &child_actions[SIGINT], NULL); sigaction(SIGABRT, &child_actions[SIGABRT], NULL); sigaction(SIGHUP, &child_actions[SIGHUP], NULL); sigaction(SIGALRM, &child_actions[SIGALRM], NULL); sigaction(SIGUSR1, &child_actions[SIGUSR1], NULL); sigaction(SIGUSR2, &child_actions[SIGUSR2], NULL); sigaction(SIGPIPE, &child_actions[SIGPIPE], NULL); } else if (!child && !child_actions_init) { sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = parachute_sig_handler; sigaction(SIGTERM, &sa, &child_actions[SIGTERM]); sigaction(SIGQUIT, &sa, &child_actions[SIGQUIT]); sigaction(SIGINT, &sa, &child_actions[SIGINT]); sigaction(SIGABRT, &sa, &child_actions[SIGABRT]); sigaction(SIGHUP, &sa, &child_actions[SIGHUP]); sigaction(SIGALRM, &sa, &child_actions[SIGALRM]); sigaction(SIGUSR1, &sa, &child_actions[SIGUSR1]); sigaction(SIGUSR2, &sa, &child_actions[SIGUSR2]); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, &child_actions[SIGPIPE]); sigaction(SIGTTOU, &sa, NULL); sigaction(SIGTTIN, &sa, NULL); sigaction(SIGTSTP, &sa, NULL); child_actions_init = 1; init_fatal_signals(); } else panic(0, "Child process signal handlers not initialized before."); } static int is_executable(const char *filename) { struct stat buf; if (stat(filename, &buf)) { error(errno, "Error while stat of file `%s'", filename); return 0; } if (!S_ISREG(buf.st_mode) && !S_ISLNK(buf.st_mode)) { error(0, "File `%s' is not a regular file.", filename); return 0; } /* others has exec permission */ if (S_IXOTH & buf.st_mode) return 1; /* group has exec permission */ if ((S_IXGRP & buf.st_mode) && buf.st_gid == getgid()) return 1; /* owner has exec permission */ if ((S_IXUSR & buf.st_mode) && buf.st_uid == getuid()) return 1; return 0; } /* * become daemon. * returns 0 for father process; 1 for child process */ static int become_daemon(void) { int fd; if (getppid() != 1) { signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); if (fork()) return 0; setsid(); } close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); fd = open("/dev/null", O_RDWR); /* stdin */ if (fd == -1) panic(errno, "Could not open `/dev/null'"); dup(fd); /* stdout */ dup(fd); /* stderr */ chdir("/"); return 1; } #define PANIC_SCRIPT_MAX_LEN 4096 static PRINTFLIKE(2,3) void execute_panic_script(const char *panic_script, const char *format, ...) { char *args[3]; char buf[PANIC_SCRIPT_MAX_LEN + 1]; va_list ap; va_start(ap, format); vsnprintf(buf, PANIC_SCRIPT_MAX_LEN, format, ap); va_end(ap); if (fork()) return; close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); args[0] = (char*) panic_script; args[1] = buf; args[2] = NULL; execv(args[0], args); } static void parachute_start(const char *myname, const char *panic_script) { time_t last_start = 0, last_panic = 0; long respawn_count = 0; int status; if (panic_script && !is_executable(panic_script)) panic(0, "Panic script `%s' is not executable for us.", panic_script); /* setup sighandler */ parachute_init_signals(0); for (;;) { if (respawn_count > 0 && difftime(time(NULL), last_start) < 10) { error(0, "Child process died too fast, disabling for 30 sec."); gwthread_sleep(30.0); } if (!(child_pid = fork())) { /* child process */ parachute_init_signals(1); /* reset sighandlers */ return; } else if (child_pid < 0) { error(errno, "Could not start child process! Will retry in 5 sec."); gwthread_sleep(5.0); continue; } else { /* father process */ time(&last_start); info(0, "Child process with PID (%ld) started.", (long) child_pid); do { if (waitpid(child_pid, &status, 0) == child_pid) { /* check here why child terminated */ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { info(0, "Child process exited gracefully, exit..."); gwlib_shutdown(); exit(0); } else if (WIFEXITED(status)) { error(0, "Caught child PID (%ld) which died with return code %d", (long) child_pid, WEXITSTATUS(status)); child_pid = -1; } else if (WIFSIGNALED(status)) { error(0, "Caught child PID (%ld) which died due to signal %d", (long) child_pid, WTERMSIG(status)); child_pid = -1; } } else if (errno != EINTR) { error(errno, "Error while waiting of child process."); } } while(child_pid > 0); if (parachute_shutdown) { /* may only happens if child process crashed while shutdown */ info(0, "Child process crashed while shutdown. Exiting due to signal..."); info(0, "Going into gwlib_shutdown..."); gwlib_shutdown(); exit(WIFEXITED(status) ? WEXITSTATUS(status) : 0); } /* check whether it's panic while start */ if (respawn_count == 0 && difftime(time(NULL), last_start) < 2) { info(0, "Child process crashed while starting. Exiting..."); info(0, "Going into gwlib_shutdown..."); gwlib_shutdown(); exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1); } respawn_count++; if (panic_script && myname && difftime(time(NULL), last_panic) > 300) { time(&last_panic); debug("kannel", 0, "Executing panic script: %s %s %ld", panic_script, myname, respawn_count); execute_panic_script(panic_script, "%s %ld", myname, respawn_count); } /* sleep a while to get e.g. sockets released */ gwthread_sleep(5.0); } } } static void write_pid_file(void) { int fd; FILE *file; if (!pid_file) return; fd = open(pid_file, O_WRONLY|O_NOCTTY|O_TRUNC|O_CREAT|O_EXCL, 0644); if (fd == -1) panic(errno, "Could not open pid-file `%s'", pid_file); file = fdopen(fd, "w"); if (!file) panic(errno, "Could not open file-stream `%s'", pid_file); fprintf(file, "%ld\n", (long) (pidfile_owner_pid = getpid())); fclose(file); } static void remove_pid_file(void) { if (!pid_file) return; /* ensure that only pidfile owner can remove it */ if (pidfile_owner_pid != getpid()) return; if (-1 == unlink(pid_file)) { int initdone = gwlib_initialized(); /* we are called at exit so gwlib may be shutdown already, init again */ if (!initdone) { gwlib_init(); log_set_syslog("kannel", 0); } error(errno, "Could not unlink pid-file `%s'", pid_file); if (!initdone) gwlib_shutdown(); } } static int change_user(const char *user) { struct passwd *pass; if (!user) return -1; pass = getpwnam(user); if (!pass) { error(0, "Could not find a user `%s' in system.", user); return -1; } if (-1 == setgid(pass->pw_gid)) { error(errno, "Could not change group id from %ld to %ld.", (long) getgid(), (long) pass->pw_gid); return -1; } #ifdef HAVE_INITGROUPS if (initgroups(user, pass->pw_gid) == -1) { error(errno, "Could not set supplementary group ID's."); } #endif if (-1 == setuid(pass->pw_uid)) { error(errno, "Could not change user id from %ld to %ld.", (long) getuid(), (long) pass->pw_uid); return -1; } return 0; } /* * new datatype functions */ MultibyteInt get_variable_value(Octet *source, int *len) { MultibyteInt retval = 0; for(*len=1;; (*len)++, source++) { retval = retval * 0x80 + (*source & 0x7F); if (*source < 0x80) /* if the continue-bit (high bit) is not set */ break; } return retval; } int write_variable_value(MultibyteInt value, Octet *dest) { int i, loc = 0; Octet revbuffer[20]; /* we write it backwards */ for (;;) { revbuffer[loc++] = (value & 0x7F) + 0x80; if (value >= 0x80) value = value >> 7; else break; } for(i=0; i < loc; i++) /* reverse the buffer */ dest[i] = revbuffer[loc-i-1]; dest[loc-1] &= 0x7F; /* remove trailer-bit from last */ return loc; } Octet reverse_octet(Octet source) { Octet dest; dest = (source & 1) <<7; dest += (source & 2) <<5; dest += (source & 4) <<3; dest += (source & 8) <<1; dest += (source & 16) >>1; dest += (source & 32) >>3; dest += (source & 64) >>5; dest += (source & 128) >>7; return dest; } void init_fatal_signals() { /* install fatal signal handler */ struct sigaction act; /* set segfault handler */ sigemptyset(&act.sa_mask); act.sa_sigaction = fatal_handler; act.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &act, NULL); } void report_versions(const char *boxname) { Octstr *os; os = version_report_string(boxname); debug("gwlib.gwlib", 0, "%s", octstr_get_cstr(os)); octstr_destroy(os); } Octstr *version_report_string(const char *boxname) { struct utsname u; uname(&u); return octstr_format(GW_NAME " %s version `%s'.\nBuild `%s', compiler `%s'.\n" "System %s, release %s, version %s, machine %s.\n" "Hostname %s, IP %s.\n" "Libxml version %s.\n" #ifdef HAVE_LIBSSL "Using " #ifdef HAVE_WTLS_OPENSSL "WTLS library " #endif "%s.\n" #endif #ifdef HAVE_MYSQL "Compiled with MySQL %s, using MySQL %s.\n" #endif #ifdef HAVE_PGSQL "Compiled with PostgreSQL %s.\n" #endif #ifdef HAVE_SDB "Using LibSDB %s.\n" #endif #if defined(HAVE_SQLITE) || defined(HAVE_SQLITE3) "Using SQLite %s.\n" #endif #ifdef HAVE_ORACLE #if defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION) "Using Oracle OCI %d.%d.\n" #else "Using Oracle OCI.\n" #endif #endif #ifdef HAVE_REDIS "Using hiredis API %d.%d.%d\n" #endif "Using %s malloc.\n", boxname, GW_VERSION, #ifdef __GNUC__ (__DATE__ " " __TIME__) , __VERSION__, #else "unknown" , "unknown", #endif u.sysname, u.release, u.version, u.machine, octstr_get_cstr(get_official_name()), octstr_get_cstr(get_official_ip()), LIBXML_DOTTED_VERSION, #ifdef HAVE_LIBSSL OPENSSL_VERSION_TEXT, #endif #ifdef HAVE_MYSQL MYSQL_SERVER_VERSION, mysql_get_client_info(), #endif #ifdef HAVE_PGSQL PG_VERSION, #endif #ifdef HAVE_SDB LIBSDB_VERSION, #endif #if defined(HAVE_SQLITE) || defined(HAVE_SQLITE3) SQLITE_VERSION, #endif #ifdef HAVE_ORACLE #if defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION) OCI_MAJOR_VERSION, OCI_MINOR_VERSION, #endif #endif #ifdef HAVE_REDIS HIREDIS_MAJOR, HIREDIS_MINOR, HIREDIS_PATCH, #endif octstr_get_cstr(gwmem_type())); } int get_and_set_debugs(int argc, char **argv, int (*find_own) (int index, int argc, char **argv)) { int i, ret = -1; int debug_lvl = -1; int file_lvl = GW_DEBUG; char *log_file = NULL; char *debug_places = NULL; char *panic_script = NULL, *user = NULL; int parachute = 0, daemonize = 0; for (i=1; i < argc; i++) { if (strcmp(argv[i],"-v")==0 || strcmp(argv[i],"--verbosity")==0) { if (i+1 < argc) { debug_lvl = atoi(argv[i+1]); i++; } else panic(0, "Missing argument for option %s\n", argv[i]); } else if (strcmp(argv[i],"-F")==0 || strcmp(argv[i],"--logfile")==0) { if (i+1 < argc && *(argv[i+1]) != '-') { log_file = argv[i+1]; i++; } else panic(0, "Missing argument for option %s\n", argv[i]); } else if (strcmp(argv[i],"-V")==0 || strcmp(argv[i],"--fileverbosity")==0) { if (i+1 < argc) { file_lvl = atoi(argv[i+1]); i++; } else panic(0, "Missing argument for option %s\n", argv[i]); } else if (strcmp(argv[i],"-D")==0 || strcmp(argv[i],"--debug")==0) { if (i+1 < argc) { debug_places = argv[i+1]; i++; } else panic(0, "Missing argument for option %s\n", argv[i]); } else if (strcmp(argv[i], "-X")==0 || strcmp(argv[i], "--panic-script")==0) { if (i+1 < argc) { panic_script = argv[i+1]; i++; } else panic(0, "Missing argument for option %s\n", argv[i]); } else if (strcmp(argv[i], "-P")==0 || strcmp(argv[i], "--parachute")==0) { parachute = 1; } else if (strcmp(argv[i], "-d")==0 || strcmp(argv[i], "--daemonize")==0) { daemonize = 1; } else if (strcmp(argv[i], "-p")==0 || strcmp(argv[i], "--pid-file")==0) { if (i+1 < argc) { pid_file = argv[i+1]; i++; } else panic(0, "Missing argument for option %s\n", argv[i]); } else if (strcmp(argv[i], "-u")==0 || strcmp(argv[i], "--user")==0) { if (i+1 < argc) { user = argv[i+1]; i++; } else panic(0, "Missing argument for option %s\n", argv[i]); } else if (strcmp(argv[i], "-g")==0 || strcmp(argv[i], "--generate")==0) { cfg_dump_all(); exit(0); } else if (strcmp(argv[i], "--version")==0) { Octstr *version = version_report_string(basename(argv[0])); printf("%s", octstr_get_cstr(version)); octstr_destroy(version); exit(0); } else if (strcmp(argv[i],"--")==0) { i++; break; } else if (*argv[i] != '-') { break; } else { if (find_own != NULL) { ret = find_own(i, argc, argv); } if (ret < 0) { fprintf(stderr, "Unknown option %s, exiting.\n", argv[i]); panic(0, "Option parsing failed"); } else i += ret; /* advance additional args */ } } if (user && -1 == change_user(user)) panic(0, "Could not change to user `%s'.", user); /* deamonize */ if (daemonize && !become_daemon()) exit(0); if (pid_file) { write_pid_file(); atexit(remove_pid_file); } if (parachute) { /* * if we are running as daemon so open syslog * in order not to deal with i.e. log rotate. */ if (daemonize) { char *ident = strrchr(argv[0], '/'); if (!ident) ident = argv[0]; else ident++; log_set_syslog(ident, (debug_lvl > -1 ? debug_lvl : 0)); } parachute_start(argv[0], panic_script); /* now we are in child process so close syslog */ if (daemonize) log_close_all(); } if (debug_lvl > -1) log_set_output_level(debug_lvl); if (debug_places != NULL) log_set_debug_places(debug_places); if (log_file != NULL) log_open(log_file, file_lvl, GW_NON_EXCL); info(0, "Debug_lvl = %d, log_file = %s, log_lvl = %d", debug_lvl, log_file ? log_file : "", file_lvl); if (debug_places != NULL) info(0, "Debug places: `%s'", debug_places); init_fatal_signals(); return i; } static int pattern_matches_ip(Octstr *pattern, Octstr *ip) { long i, j; long pat_len, ip_len; int pat_c, ip_c; pat_len = octstr_len(pattern); ip_len = octstr_len(ip); i = 0; j = 0; while (i < pat_len && j < ip_len) { pat_c = octstr_get_char(pattern, i); ip_c = octstr_get_char(ip, j); if (pat_c == ip_c) { /* The characters match, go to the next ones. */ ++i; ++j; } else if (pat_c != '*') { /* They differ, and the pattern isn't a wildcard one. */ return 0; } else { /* We found a wildcard in the pattern. Skip in ip. */ ++i; while (j < ip_len && ip_c != '.') { ++j; ip_c = octstr_get_char(ip, j); } } } if (i >= pat_len && j >= ip_len) return 1; return 0; } static int pattern_list_matches_ip(Octstr *pattern_list, Octstr *ip) { List *patterns; Octstr *pattern; int matches; patterns = octstr_split(pattern_list, octstr_imm(";")); matches = 0; while (!matches && (pattern = gwlist_extract_first(patterns)) != NULL) { matches = pattern_matches_ip(pattern, ip); octstr_destroy(pattern); } gwlist_destroy(patterns, octstr_destroy_item); return matches; } int is_allowed_ip(Octstr *allow_ip, Octstr *deny_ip, Octstr *ip) { if (ip == NULL) return 0; if (octstr_len(deny_ip) == 0) return 1; if (allow_ip != NULL && pattern_list_matches_ip(allow_ip, ip)) return 1; if (pattern_list_matches_ip(deny_ip, ip)) return 0; return 1; } int connect_denied(Octstr *allow_ip, Octstr *ip) { if (ip == NULL) return 1; /* If IP not set, allow from Localhost */ if (allow_ip == NULL) { if (pattern_list_matches_ip(octstr_imm("127.0.0.1"), ip)) return 0; } else { if (pattern_list_matches_ip(allow_ip, ip)) return 0; } return 1; } int does_prefix_match(Octstr *prefix, Octstr *number) { /* XXX modify to use just octstr operations */ char *b, *p, *n; gw_assert(prefix != NULL); gw_assert(number != NULL); p = octstr_get_cstr(prefix); n = octstr_get_cstr(number); while (*p != '\0') { b = n; for (b = n; *b != '\0'; b++, p++) { if (*p == ';' || *p == '\0') { return 1; } if (*p != *b) break; } if (*p == ';' || *p == '\0') { return 1; } while (*p != '\0' && *p != ';') p++; while (*p == ';') p++; } return 0; } int normalize_number(char *dial_prefixes, Octstr **number) { char *t, *p, *official, *start; int len, official_len; if (dial_prefixes == NULL || dial_prefixes[0] == '\0') return 0; t = official = dial_prefixes; official_len = 0; gw_assert(number != NULL); while(1) { p = octstr_get_cstr(*number); for(start = t, len = 0; ; t++, p++, len++) { if (*t == ',' || *t == ';' || *t == '\0') { if (start != official) { Octstr *nstr; long n; if ( official[0] == '-' ) official_len=0; n = official_len; if (strlen(official) < (size_t) n) n = strlen(official); nstr = octstr_create_from_data(official, n); octstr_insert_data(nstr, official_len, octstr_get_cstr(*number) + len, octstr_len(*number) - len); octstr_destroy(*number); *number = nstr; } return 1; } if (*p == '\0' || *t != *p) break; /* not matching */ } for(; *t != ',' && *t != ';' && *t != '\0'; t++, len++) ; if (*t == '\0') break; if (start == official) official_len = len; if (*t == ';') official = t+1; t++; } return 0; } long decode_network_long(unsigned char *data) { return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; } void encode_network_long(unsigned char *data, unsigned long value) { data[0] = (value >> 24) & 0xff; data[1] = (value >> 16) & 0xff; data[2] = (value >> 8) & 0xff; data[3] = value & 0xff; } /* Something that does the same as GNU cfmakeraw. We don't use cfmakeraw so that we always know what it does, and also to reduce configure.in complexity. */ void kannel_cfmakeraw (struct termios *tio){ /* Block until a charactor is available, but it only needs to be one*/ tio->c_cc[VMIN] = 1; tio->c_cc[VTIME] = 0; /* GNU cfmakeraw sets these flags so we had better too...*/ /* Control modes */ /* Mask out character size (CSIZE), then set it to 8 bits (CS8). * Enable parity bit generation in both directions (PARENB). */ tio->c_cflag &= ~(CSIZE|PARENB); tio->c_cflag |= CS8; /* Input Flags,*/ /* Turn off all input flags that interfere with the byte stream: * BRKINT - generate SIGINT when receiving BREAK, ICRNL - translate * NL to CR, IGNCR - ignore CR, IGNBRK - ignore BREAK, * INLCR - translate NL to CR, IXON - use XON/XOFF flow control, * ISTRIP - strip off eighth bit. */ tio->c_iflag &= ~(BRKINT|ICRNL|IGNCR|IGNBRK|INLCR|IXON|ISTRIP); /* Other flags,*/ /* Turn off all local flags that interpret the byte stream: * ECHO - echo input chars, ECHONL - always echo NL even if ECHO is off, * ICANON - enable canonical mode (basically line-oriented mode), * IEXTEN - enable implementation-defined input processing, * ISIG - generate signals when certain characters are received. */ tio->c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); /* Output flags,*/ /* Disable implementation defined processing on the output stream*/ tio->c_oflag &= ~OPOST; } int gw_isdigit(int c) { return isdigit(c); } int gw_isxdigit(int c) { return isxdigit(c); } /* Rounds up the result of a division */ int roundup_div(int a, int b) { int t; t = a / b; if (t * b != a) t += 1; return t; } unsigned long long gw_generate_id(void) { /* create a 64 bit unique Id by putting a 32 bit epoch time value * and a 32 bit random value together */ unsigned long random, timer; random = gw_rand(); timer = (unsigned long)time(NULL); return ((unsigned long long)timer << 32) + random; } gateway-1.4.5/gwlib/octstr.c.debug0000644000175000017500000014232313035215464015547 0ustar toljtolj/* * octstr.c - implementation of Octet strings * * See octstr.h for explanations of what public functions should do. * * Lars Wirzenius */ #include #include #include #include #include #include #include #include #include #include "gwlib.h" /*********************************************************************** * Definitions of data structures. These are not visible to the external * world -- they may be accessed only via the functions declared in * octstr.h. This ensures they really are abstract. */ /* * The octet string. * * `data' is a pointer to dynamically allocated memory are where the * octets in the string. It may be bigger than the actual length of the * string. * * `len' is the length of the string. * * `size' is the size of the memory area `data' points at. * * When `size' is greater than zero, it is at least `len+1', and the * character at `len' is '\0'. This is so that octstr_get_cstr will * always work. * * `immutable' defines whether the octet string is immutable or not. */ struct Octstr { unsigned char *data; long len; long size; int immutable; }; /********************************************************************** * Hash table of immutable octet strings. */ #define MAX_IMMUTABLES 1024 static Octstr *immutables[MAX_IMMUTABLES]; static Mutex immutables_mutex; static int immutables_init = 0; static char is_safe[UCHAR_MAX + 1]; /* * Convert a pointer to a C string literal to a long that can be used * for hashing. This is done by converting the pointer into an integer * and discarding the lowest to bits to get rid of typical alignment * bits. */ #define CSTR_TO_LONG(ptr) (((unsigned long) ptr) >> 2) /*********************************************************************** * Declarations of internal functions. These are defined at the end of * the file. */ static void seems_valid_real(Octstr *ostr, const char *filename, long lineno, const char *function); #ifdef NO_GWASSERT #define seems_valid(ostr) #else #define seems_valid(ostr) \ (seems_valid_real(ostr, __FILE__, __LINE__, __func__)) #endif /*********************************************************************** * Implementations of the functions declared in octstr.h. See the * header for explanations of what they should do. */ /* Reserve space for at least 'size' octets */ static void octstr_grow(Octstr *ostr, long size) { gw_assert(!ostr->immutable); seems_valid(ostr); gw_assert(size >= 0); size++; /* make room for the invisible terminating NUL */ if (size > ostr->size) { ostr->data = gw_realloc(ostr->data, size); ostr->size = size; } } /* * Fill is_safe table. is_safe[c] means that c can be left as such when * url-encoded. * RFC 2396 defines the list of characters that need to be encoded. * Space is treated as an exception by the encoding routine; * it's listed as safe here, but is actually changed to '+'. */ static void urlcode_init(void) { int i; unsigned char *safe = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz-_.!~*'()"; for (i = 0; safe[i] != '\0'; ++i) is_safe[safe[i]] = 1; } void octstr_init(void) { urlcode_init(); mutex_init_static(&immutables_mutex); immutables_init = 1; } void octstr_shutdown(void) { long i, n; n = 0; for (i = 0; i < MAX_IMMUTABLES; ++i) { if (immutables[i] != NULL) { gw_free(immutables[i]); ++n; } } debug("gwlib.octstr", 0, "Immutable octet strings: %ld.", n); mutex_destroy(&immutables_mutex); } Octstr *octstr_create_real(const char *cstr) { gw_assert(cstr != NULL); return octstr_create_from_data(cstr, strlen(cstr)); } Octstr *octstr_create_from_data_real(const char *data, long len) { Octstr *ostr; gw_assert(len >= 0); if (data == NULL) gw_assert(len == 0); ostr = gw_malloc(sizeof(*ostr)); if (len == 0) { ostr->len = 0; ostr->size = 0; ostr->data = NULL; } else { ostr->len = len; ostr->size = len + 1; ostr->data = gw_malloc(ostr->size); memcpy(ostr->data, data, len); ostr->data[len] = '\0'; } ostr->immutable = 0; seems_valid(ostr); return ostr; } Octstr *octstr_imm(const char *cstr) { Octstr *os; long i, index; unsigned char *data; gw_assert(immutables_init); gw_assert(cstr != NULL); index = CSTR_TO_LONG(cstr) % MAX_IMMUTABLES; data = (unsigned char *) cstr; mutex_lock(&immutables_mutex); i = index; for (; ; ) { if (immutables[i] == NULL || immutables[i]->data == data) break; i = (i + 1) % MAX_IMMUTABLES; if (i == index) panic(0, "Too many immutable strings."); } os = immutables[i]; if (os == NULL) { /* * Can't use octstr_create() because it copies the string, * which would break our hashing. */ os = gw_malloc(sizeof(*os)); os->data = data; os->len = strlen(data); os->size = os->len + 1; os->immutable = 1; immutables[i] = os; seems_valid(os); } mutex_unlock(&immutables_mutex); return os; } void octstr_destroy_impl(Octstr *ostr, const char *file, long line, const char *func) { if (ostr != NULL) { seems_valid_real(ostr, file, line, func); if (!ostr->immutable) { gw_free(ostr->data); gw_free(ostr); } } } void octstr_destroy_item(void *os) { octstr_destroy(os); } long octstr_len(Octstr *ostr) { if (ostr == NULL) return 0; seems_valid(ostr); return ostr->len; } Octstr *octstr_copy_real(Octstr *ostr, long from, long len) { seems_valid(ostr); gw_assert(from >= 0); gw_assert(len >= 0); if (from >= ostr->len) return octstr_create(""); if (len > ostr->len - from) len = ostr->len - from; return octstr_create_from_data(ostr->data + from, len); } Octstr *octstr_duplicate_real(Octstr *ostr) { if (ostr == NULL) return NULL; seems_valid(ostr); return octstr_create_from_data(ostr->data, ostr->len); } Octstr *octstr_cat(Octstr *ostr1, Octstr *ostr2) { Octstr *ostr; seems_valid(ostr1); seems_valid(ostr2); ostr = octstr_create(""); ostr->len = ostr1->len + ostr2->len; ostr->size = ostr->len + 1; ostr->data = gw_malloc(ostr->size); if (ostr1->len > 0) memcpy(ostr->data, ostr1->data, ostr1->len); if (ostr2->len > 0) memcpy(ostr->data + ostr1->len, ostr2->data, ostr2->len); ostr->data[ostr->len] = '\0'; seems_valid(ostr); return ostr; } int octstr_get_char(Octstr *ostr, long pos) { seems_valid(ostr); if (pos >= ostr->len || pos < 0) return -1; return ostr->data[pos]; } void octstr_set_char(Octstr *ostr, long pos, int ch) { seems_valid(ostr); gw_assert(!ostr->immutable); if (pos < ostr->len) ostr->data[pos] = ch; seems_valid(ostr); } void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len) { gw_assert(buf != NULL); seems_valid(ostr); if (pos >= ostr->len) return; if (pos + len > ostr->len) len = ostr->len - pos; if (len > 0) memcpy(buf, ostr->data + pos, len); } char *octstr_get_cstr_real(Octstr *ostr, const char *file, long line, const char *func) { seems_valid_real(ostr, file, line, func); if (ostr->len == 0) return ""; return ostr->data; } void octstr_append_from_hex(Octstr *ostr, char *hex) { Octstr *output; seems_valid(ostr); gw_assert(!ostr->immutable); output = octstr_create(hex); octstr_hex_to_binary(output); octstr_append(ostr, output); octstr_destroy(output); } void octstr_binary_to_hex(Octstr *ostr, int uppercase) { unsigned char *hexits; long i; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return; hexits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef"; octstr_grow(ostr, ostr->len * 2); /* In-place modification must be done back-to-front to avoid * overwriting the data while we read it. Even the order of * the two assignments is important, to get i == 0 right. */ for (i = ostr->len - 1; i >= 0; i--) { ostr->data[i * 2 + 1] = hexits[ostr->data[i] % 16]; ostr->data[i * 2] = hexits[(ostr->data[i] / 16) & 0xf]; } ostr->len = ostr->len * 2; ostr->data[ostr->len] = '\0'; seems_valid(ostr); } int octstr_hex_to_binary(Octstr *ostr) { long len, i; unsigned char *p; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return 0; /* Check if it's in the right format */ if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit)) return -1; len = ostr->len; /* Convert ascii data to binary values */ for (i = 0, p = ostr->data; i < len; i++, p++) { if (*p >= '0' && *p <= '9') *p -= '0'; else if (*p >= 'a' && *p <= 'f') *p = *p - 'a' + 10; else if (*p >= 'A' && *p <= 'F') *p = *p - 'A' + 10; else { /* isxdigit checked the whole string, so we should * not be able to get here. */ gw_assert(0); *p = 0; } } /* De-hexing will compress data by factor of 2 */ len = ostr->len / 2; for (i = 0; i < len; i++) { ostr->data[i] = ostr->data[i * 2] * 16 | ostr->data[i * 2 + 1]; } ostr->len = len; ostr->data[len] = '\0'; seems_valid(ostr); return 0; } void octstr_binary_to_base64(Octstr *ostr) { static const unsigned char base64[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; long triplets; long lines; long orig_len; unsigned char *data; long from, to; int left_on_line; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) { /* Always terminate with CR LF */ octstr_insert(ostr, octstr_imm("\015\012"), 0); return; } /* The lines must be 76 characters each (or less), and each * triplet will expand to 4 characters, so we can fit 19 * triplets on one line. We need a CR LF after each line, * which will add 2 octets per 19 triplets (rounded up). */ triplets = (ostr->len + 2) / 3; /* round up */ lines = (triplets + 18) / 19; octstr_grow(ostr, triplets * 4 + lines * 2); orig_len = ostr->len; data = ostr->data; ostr->len = triplets * 4 + lines * 2; data[ostr->len] = '\0'; /* This function works back-to-front, so that encoded data will * not overwrite source data. * from points to the start of the last triplet (which may be * an odd-sized one), and to points to the start of where the * last quad should go. */ from = (triplets - 1) * 3; to = (triplets - 1) * 4 + (lines - 1) * 2; /* First write the CR LF after the last quad */ data[to + 5] = 10; /* LF */ data[to + 4] = 13; /* CR */ left_on_line = triplets - ((lines - 1) * 19); /* base64 encoding is in 3-octet units. To handle leftover * octets, conceptually we have to zero-pad up to the next * 6-bit unit, and pad with '=' characters for missing 6-bit * units. * We do it by first completing the first triplet with * zero-octets, and after the loop replacing some of the * result characters with '=' characters. * There is enough room for this, because even with a 1 or 2 * octet source string, space for four octets of output * will be reserved. */ switch (orig_len % 3) { case 0: break; case 1: data[orig_len] = 0; data[orig_len + 1] = 0; break; case 2: data[orig_len + 1] = 0; break; } /* Now we only have perfect triplets. */ while (from >= 0) { long whole_triplet; /* Add a newline, if necessary */ if (left_on_line == 0) { to -= 2; data[to + 5] = 10; /* LF */ data[to + 4] = 13; /* CR */ left_on_line = 19; } whole_triplet = (data[from] << 16) | (data[from + 1] << 8) | data[from + 2]; data[to + 3] = base64[whole_triplet % 64]; data[to + 2] = base64[(whole_triplet >> 6) % 64]; data[to + 1] = base64[(whole_triplet >> 12) % 64]; data[to] = base64[(whole_triplet >> 18) % 64]; to -= 4; from -= 3; left_on_line--; } gw_assert(left_on_line == 0); gw_assert(from == -3); gw_assert(to == -4); /* Insert padding characters in the last quad. Remember that * there is a CR LF between the last quad and the end of the * string. */ switch (orig_len % 3) { case 0: break; case 1: gw_assert(data[ostr->len - 3] == 'A'); gw_assert(data[ostr->len - 4] == 'A'); data[ostr->len - 3] = '='; data[ostr->len - 4] = '='; break; case 2: gw_assert(data[ostr->len - 3] == 'A'); data[ostr->len - 3] = '='; break; } seems_valid(ostr); } void octstr_base64_to_binary(Octstr *ostr) { long triplet; long pos, len; long to; int quadpos = 0; int warned = 0; unsigned char *data; seems_valid(ostr); gw_assert(!ostr->immutable); len = ostr->len; data = ostr->data; if (len == 0) return; to = 0; triplet = 0; quadpos = 0; for (pos = 0; pos < len; pos++) { int c = data[pos]; int sixbits; if (c >= 'A' && c <= 'Z') { sixbits = c - 'A'; } else if (c >= 'a' && c <= 'z') { sixbits = 26 + c - 'a'; } else if (c >= '0' && c <= '9') { sixbits = 52 + c - '0'; } else if (c == '+') { sixbits = 62; } else if (c == '/') { sixbits = 63; } else if (c == '=') { /* These can only occur at the end of encoded * text. RFC 2045 says we can assume it really * is the end. */ break; } else if (isspace(c)) { /* skip whitespace */ continue; } else { if (!warned) { warning(0, "Unusual characters in base64 " "encoded text."); warned = 1; } continue; } triplet = (triplet << 6) | sixbits; quadpos++; if (quadpos == 4) { data[to++] = (triplet >> 16) & 0xff; data[to++] = (triplet >> 8) & 0xff; data[to++] = triplet & 0xff; quadpos = 0; } } /* Deal with leftover octets */ switch (quadpos) { case 0: break; case 3: /* triplet has 18 bits, we want the first 16 */ data[to++] = (triplet >> 10) & 0xff; data[to++] = (triplet >> 2) & 0xff; break; case 2: /* triplet has 12 bits, we want the first 8 */ data[to++] = (triplet >> 4) & 0xff; break; case 1: warning(0, "Bad padding in base64 encoded text."); break; } ostr->len = to; data[to] = '\0'; seems_valid(ostr); } long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base) { /* strtol wants a char *, and we have to compare the result to * an unsigned char *. The easiest way to avoid warnings without * introducing typecasts is to use two variables. */ char *endptr; unsigned char *endpos; long number; seems_valid(ostr); gw_assert(nump != NULL); gw_assert(base == 0 || (base >= 2 && base <= 36)); if (pos >= ostr->len) { errno = EINVAL; return -1; } errno = 0; number = strtol(ostr->data + pos, &endptr, base); endpos = endptr; if (errno == ERANGE) return -1; if (endpos == ostr->data + pos) { errno = EINVAL; return -1; } *nump = number; return endpos - ostr->data; } int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter) { long end = pos + len; seems_valid(ostr); gw_assert(len >= 0); if (pos >= ostr->len) return 1; if (end > ostr->len) end = ostr->len; for ( ; pos < end; pos++) { if (!filter(ostr->data[pos])) return 0; } return 1; } void octstr_convert_range(Octstr *ostr, long pos, long len, octstr_func_t map) { long end = pos + len; seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(len >= 0); if (pos >= ostr->len) return; if (end > ostr->len) end = ostr->len; for ( ; pos < end; pos++) { ostr->data[pos] = map(ostr->data[pos]); } seems_valid(ostr); } int octstr_compare(Octstr *ostr1, Octstr *ostr2) { int ret; long len; seems_valid(ostr1); seems_valid(ostr2); if (ostr1->len < ostr2->len) len = ostr1->len; else len = ostr2->len; if (len == 0) { if (ostr1->len == 0 && ostr2->len > 0) return -1; if (ostr1->len > 0 && ostr2->len == 0) return 1; return 0; } ret = memcmp(ostr1->data, ostr2->data, len); if (ret == 0) { if (ostr1->len < ostr2->len) ret = -1; else if (ostr1->len > ostr2->len) ret = 1; } return ret; } int octstr_case_compare(Octstr *os1, Octstr *os2) { int c1, c2; long i, len; seems_valid(os1); seems_valid(os2); if (os1->len < os2->len) len = os1->len; else len = os2->len; if (len == 0) { if (os1->len == 0 && os2->len > 0) return -1; if (os1->len > 0 && os2->len == 0) return 1; return 0; } for (i = 0; i < len; ++i) { c1 = toupper(os1->data[i]); c2 = toupper(os2->data[i]); if (c1 != c2) break; } if (i == len) { if (i == os1->len && i == os2->len) return 0; if (i == os1->len) return -1; return 1; } else { c1 = toupper(os1->data[i]); c2 = toupper(os2->data[i]); if (c1 < c2) return -1; if (c1 == c2) return 0; return 1; } } int octstr_ncompare(Octstr *ostr1, Octstr *ostr2, long n) { long len; seems_valid(ostr1); seems_valid(ostr2); if ((ostr1->len < ostr2->len) && (ostr1->len < n)) len = ostr1->len; else if ((ostr2->len < ostr1->len) && (ostr2->len < n)) len = ostr2->len; else len = n; if (len == 0) return 0; return memcmp(ostr1->data, ostr2->data, len); } int octstr_str_compare(Octstr *ostr, const char *str) { seems_valid(ostr); if (str == NULL) return -1; if (ostr->data == NULL) return strcmp("", str); return strcmp(ostr->data, str); } int octstr_search_char(Octstr *ostr, int ch, long pos) { unsigned char *p; seems_valid(ostr); gw_assert(ch >= 0); gw_assert(ch <= UCHAR_MAX); gw_assert(pos >= 0); if (pos >= ostr->len) return -1; p = memchr(ostr->data + pos, ch, ostr->len - pos); if (!p) return -1; return p - ostr->data; } int octstr_search(Octstr *haystack, Octstr *needle, long pos) { int first; seems_valid(haystack); seems_valid(needle); gw_assert(pos >= 0); /* Always "find" an empty string */ if (needle->len == 0) return 0; if (needle->len == 1) return octstr_search_char(haystack, needle->data[0], pos); /* For each occurrence of needle's first character in ostr, * check if the rest of needle follows. Stop if there are no * more occurrences, or if the rest of needle can't possibly * fit in the haystack. */ first = needle->data[0]; pos = octstr_search_char(haystack, first, pos); while (pos >= 0 && haystack->len - pos >= needle->len) { if (memcmp(haystack->data + pos, needle->data, needle->len) == 0) return pos; pos = octstr_search_char(haystack, first, pos + 1); } return -1; } int octstr_case_search(Octstr *haystack, Octstr *needle, long pos) { long i, j; int c1, c2; seems_valid(haystack); seems_valid(needle); gw_assert(pos >= 0); /* Always "find" an empty string */ if (needle->len == 0) return 0; for (i = pos; i <= haystack->len - needle->len; ++i) { for (j = 0; j < needle->len; ++j) { c1 = toupper(haystack->data[i + j]); c2 = toupper(needle->data[j]); if (c1 != c2) break; } if (j == needle->len) return i; } return -1; } int octstr_print(FILE *f, Octstr *ostr) { gw_assert(f != NULL); seems_valid(ostr); if (ostr->len == 0) return 0; if (fwrite(ostr->data, ostr->len, 1, f) != 1) { error(errno, "Couldn't write all of octet string to file."); return -1; } return 0; } int octstr_pretty_print(FILE *f, Octstr *ostr) { unsigned char *p; long i; gw_assert(f != NULL); seems_valid(ostr); p = ostr->data; for (i = 0; i < ostr->len; ++i, ++p) { if (isprint(*p)) fprintf(f, "%c", *p); else fprintf(f, "\\x%02x", *p); } if (ferror(f)) return -1; return 0; } int octstr_write_to_socket(int socket, Octstr *ostr) { long len; unsigned char *data; int ret; gw_assert(socket >= 0); seems_valid(ostr); data = ostr->data; len = ostr->len; while (len > 0) { ret = write(socket, data, len); if (ret == -1) { if (errno != EINTR) { error(errno, "Writing to socket failed"); return -1; } } else { /* ret may be less than len */ len -= ret; data += ret; } } return 0; } long octstr_write_data(Octstr *ostr, int fd, long from) { long ret; gw_assert(fd >= 0); gw_assert(from >= 0); seems_valid(ostr); if (from >= ostr->len) return 0; ret = write(fd, ostr->data + from, ostr->len - from); if (ret < 0) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) return 0; error(errno, "Error writing %ld octets to fd %d:", ostr->len - from, fd); return -1; } return ret; } int octstr_append_from_socket(Octstr *ostr, int socket) { unsigned char buf[4096]; int len; seems_valid(ostr); gw_assert(!ostr->immutable); again: len = recv(socket, buf, sizeof(buf), 0); if (len < 0 && errno == EINTR) goto again; if (len < 0) { error(errno, "Could not read from socket %d", socket); return -1; } octstr_append_data(ostr, buf, len); return len; } void octstr_insert_impl (Octstr *ostr1, Octstr *ostr2, long pos, const char *file, long line, const char *func) { seems_valid_real(ostr1, file, line, func); seems_valid_real(ostr2, file, line, func); gw_assert(pos <= ostr1->len); gw_assert(!ostr1->immutable); if (ostr2->len == 0) return; octstr_grow(ostr1, ostr1->len + ostr2->len); memmove(ostr1->data + pos + ostr2->len, ostr1->data + pos, ostr1->len - pos); memcpy(ostr1->data + pos, ostr2->data, ostr2->len); ostr1->len += ostr2->len; ostr1->data[ostr1->len] = '\0'; seems_valid(ostr1); } void octstr_truncate(Octstr *ostr, int new_len) { seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(new_len >= 0); if (new_len >= ostr->len) return; ostr->len = new_len; ostr->data[new_len] = '\0'; seems_valid(ostr); } void octstr_strip_blanks(Octstr *text) { int start = 0, end, len = 0; seems_valid(text); gw_assert(!text->immutable); /* Remove white space from the beginning of the text */ while (isspace(octstr_get_char(text, start)) && start <= octstr_len(text)) start ++; if (start > 0) octstr_delete(text, 0, start); /* and from the end. */ if ((len = octstr_len(text)) > 0) { end = len = len - 1; while (isspace(octstr_get_char(text, end)) && end >= 0) end--; octstr_delete(text, end + 1, len - end); } seems_valid(text); } void octstr_strip_nonalphanums(Octstr *text) { int start = 0, end, len = 0; seems_valid(text); gw_assert(!text->immutable); /* Remove white space from the beginning of the text */ while (!isalnum(octstr_get_char(text, start)) && start <= octstr_len(text)) start ++; if (start > 0) octstr_delete(text, 0, start); /* and from the end. */ if ((len = octstr_len(text)) > 0) { end = len = len - 1; while (!isalnum(octstr_get_char(text, end)) && end >= 0) end--; octstr_delete(text, end + 1, len - end); } seems_valid(text); } void octstr_shrink_blanks(Octstr *text) { int i, j, end; seems_valid(text); gw_assert(!text->immutable); end = octstr_len(text); /* Shrink white spaces to one */ for (i = 0; i < end; i++) { if (isspace(octstr_get_char(text, i))) { /* Change the remaining space into single space. */ if (octstr_get_char(text, i) != ' ') octstr_set_char(text, i, ' '); j = i = i + 1; while (isspace(octstr_get_char(text, j))) j ++; if (j - i > 1) octstr_delete(text, i, j - i); } } seems_valid(text); } void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len) { seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(pos <= ostr->len); if (len == 0) return; octstr_grow(ostr, ostr->len + len); if (ostr->len > pos) { /* only if neccessary */ memmove(ostr->data + pos + len, ostr->data + pos, ostr->len - pos); } memcpy(ostr->data + pos, data, len); ostr->len += len; ostr->data[ostr->len] = '\0'; seems_valid(ostr); } void octstr_append_data(Octstr *ostr, const char *data, long len) { gw_assert(ostr != NULL); octstr_insert_data(ostr, ostr->len, data, len); } void octstr_append_impl(Octstr *ostr1, Octstr *ostr2, const char *file, long line, const char *func) { gw_assert(ostr1 != NULL); octstr_insert_impl(ostr1, ostr2, ostr1->len, file, line, func); } void octstr_append_cstr(Octstr *ostr, const char *cstr) { octstr_insert_data(ostr, ostr->len, cstr, strlen(cstr)); } void octstr_append_char(Octstr *ostr, int ch) { unsigned char c = ch; gw_assert(ch >= 0); gw_assert(ch <= UCHAR_MAX); octstr_insert_data(ostr, ostr->len, &c, 1); } void octstr_delete(Octstr *ostr1, long pos, long len) { seems_valid(ostr1); gw_assert(!ostr1->immutable); if (pos > ostr1->len) pos = ostr1->len; if (pos + len > ostr1->len) len = ostr1->len - pos; if (len > 0) { memmove(ostr1->data + pos, ostr1->data + pos + len, ostr1->len - pos - len); ostr1->len -= len; ostr1->data[ostr1->len] = '\0'; } seems_valid(ostr1); } Octstr *octstr_read_file(const char *filename) { FILE *f; Octstr *os; char buf[4096]; long n; gw_assert(filename != NULL); f = fopen(filename, "r"); if (f == NULL) { error(errno, "fopen failed: couldn't open `%s'", filename); return NULL; } os = octstr_create(""); if (os == NULL) goto error; while ((n = fread(buf, 1, sizeof(buf), f)) > 0) octstr_insert_data(os, octstr_len(os), buf, n); (void) fclose(f); return os; error: (void) fclose(f); octstr_destroy(os); return NULL; } Octstr *octstr_read_pipe(FILE *f) { Octstr *os; char buf[4096]; gw_assert(f != NULL); os = octstr_create(""); if (os == NULL) goto error; while (fgets(buf, sizeof(buf), f) != NULL) octstr_append_data(os, buf, strlen(buf)); return os; error: octstr_destroy(os); return NULL; } List *octstr_split_words(Octstr *ostr) { unsigned char *p; List *list; Octstr *word; long i, start, end; seems_valid(ostr); list = gwlist_create(); p = ostr->data; i = 0; for (; ; ) { while (i < ostr->len && isspace(*p)) { ++p; ++i; } start = i; while (i < ostr->len && !isspace(*p)) { ++p; ++i; } end = i; if (start == end) break; word = octstr_create_from_data(ostr->data + start, end - start); gwlist_append(list, word); } return list; } List *octstr_split(Octstr *os, Octstr *sep) { List *list; long next, pos, seplen; list = gwlist_create(); pos = 0; seplen = octstr_len(sep); while ((next = octstr_search(os, sep, pos)) != -1) { gwlist_append(list, octstr_copy(os, pos, next - pos)); pos = next + seplen; } if (pos < octstr_len(os)) gwlist_append(list, octstr_copy(os, pos, octstr_len(os))); return list; } int octstr_item_match(void *item, void *pattern) { return octstr_compare(item, pattern) == 0; } int octstr_item_case_match(void *item, void *pattern) { return octstr_case_compare(item, pattern) == 0; } void octstr_dump(Octstr *ostr, int level) { unsigned char *p, *d, buf[1024], charbuf[256]; long pos; const int octets_per_line = 8; int c, this_line_begins_at; if (ostr == NULL) return; seems_valid(ostr); debug("gwlib.octstr", 0, "%*sOctet string at %p:", level, "", (void *) ostr); debug("gwlib.octstr", 0, "%*s len: %lu", level, "", (unsigned long) ostr->len); debug("gwlib.octstr", 0, "%*s size: %lu", level, "", (unsigned long) ostr->size); debug("gwlib.octstr", 0, "%*s immutable: %d", level, "", ostr->immutable); buf[0] = '\0'; p = buf; d = charbuf; this_line_begins_at = 0; for (pos = 0; pos < octstr_len(ostr); ) { c = octstr_get_char(ostr, pos); sprintf(p, "%02x ", c); p = strchr(p, '\0'); if (isprint(c)) *d++ = c; else *d++ = '.'; ++pos; if (pos - this_line_begins_at == octets_per_line) { *d = '\0'; debug("gwlib.octstr", 0, "%*s data: %s %s", level, "", buf, charbuf); buf[0] = '\0'; charbuf[0] = '\0'; p = buf; d = charbuf; this_line_begins_at = pos; } } if (pos - this_line_begins_at > 0) { *d = '\0'; debug("gwlib.octstr", 0, "%*s data: %-*.*s %s", level, "", octets_per_line*3, octets_per_line*3, buf, charbuf); } debug("gwlib.octstr", 0, "%*sOctet string dump ends.", level, ""); } void octstr_dump_short(Octstr *ostr, int level, const char *name) { char buf[100]; char *p; long i; int c; if (ostr == NULL) { debug("gwlib.octstr", 0, "%*s%s: NULL", level, "", name); return; } seems_valid(ostr); if (ostr->len < 20) { p = buf; for (i = 0; i < ostr->len; i++) { c = ostr->data[i]; if (c == '\n') { *p++ = '\\'; *p++ = 'n'; } else if (!isprint(c)) { break; } else if (c == '"') { *p++ = '\\'; *p++ = '"'; } else if (c == '\\') { *p++ = '\\'; *p++ = '\\'; } else { *p++ = c; } } if (i == ostr->len) { *p++ = 0; /* We got through the loop without hitting nonprintable * characters. */ debug("gwlib.octstr", 0, "%*s%s: \"%s\"", level, "", name, buf); return; } } debug("gwlib.octstr", 0, "%*s%s:", level, "", name); octstr_dump(ostr, level + 1); } void octstr_url_encode(Octstr *ostr) { int i, n, newlen; unsigned char *str, *str2, *hexits; unsigned char c; Octstr *res; seems_valid(ostr); res = octstr_create(""); if (ostr->immutable || ostr->len == 0) return; str = ostr->data; n = 0; for (i = 0; i < ostr->len; i++) if (!is_safe[*str++]) n++; newlen = ostr->len + 2 * n; res->len = newlen; res->size = res->len + 1; res->data = gw_malloc(res->size); hexits = "0123456789ABCDEF"; str = ostr->data; str2 = res->data; for (i = 0; i < ostr->len; i++) { c = *str++; if (!is_safe[c]) { *str2++ = '%'; *str2++ = hexits[c >> 4 & 0xf]; *str2++ = hexits[c & 0xf]; } else if (c == ' ') *str2++ = '+'; else *str2++ = c; } *str2 = 0; seems_valid(res); octstr_truncate(ostr, 0); octstr_insert(ostr, res, 0); octstr_destroy(res); } int octstr_url_decode(Octstr *ostr) { long value; unsigned char *string = ostr->data; unsigned char *dptr = ostr->data; unsigned char buf[3]; /* buffer for strtol conversion */ buf[2] = '\0'; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return 0; do { if (*string == '%') { if (*(string + 1) == '\0' || *(string + 2) == '\0') goto error; buf[0] = *(string + 1); buf[1] = *(string + 2); value = strtol(buf, NULL, 16); if (value >= 0 && value < 256) { *dptr = (unsigned char)value; string += 3; dptr++; continue; } warning(0, "Garbage encoded (value = %ld)", value); } if (*string == '+') { *dptr++ = ' '; string++; } else *dptr++ = *string++; } while (*string); /* we stop here because it terimates encoded string */ *dptr = '\0'; ostr->len = (dptr - ostr->data); seems_valid(ostr); return 0; error: *dptr = '\0'; ostr->len = (dptr - ostr->data); warning(0, "octstr_url_decode: corrupted end-of-string <%s>", string); seems_valid(ostr); return -1; } long octstr_get_bits(Octstr *ostr, long bitpos, int numbits) { long pos; long result; int mask; int shiftwidth; seems_valid(ostr); gw_assert(bitpos >= 0); gw_assert(numbits <= 32); gw_assert(numbits >= 0); pos = bitpos / 8; bitpos = bitpos % 8; /* This also takes care of the len == 0 case */ if (pos >= ostr->len) return 0; mask = (1 << numbits) - 1; /* It's easy if the range fits in one octet */ if (bitpos + numbits <= 8) { /* shiftwidth is the number of bits to ignore on the right. * bitpos 0 is the leftmost bit. */ shiftwidth = 8 - (bitpos + numbits); return (ostr->data[pos] >> shiftwidth) & mask; } /* Otherwise... */ result = 0; while (bitpos + numbits > 8) { result = (result << 8) | ostr->data[pos]; numbits -= (8 - bitpos); bitpos = 0; pos++; if (pos >= ostr->len) return (result << numbits) & mask; } gw_assert(bitpos == 0); result <<= numbits; result |= ostr->data[pos] >> (8 - numbits); return result & mask; } void octstr_set_bits(Octstr *ostr, long bitpos, int numbits, unsigned long value) { long pos; unsigned long mask; int shiftwidth; int bits; int maxlen; int c; seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(bitpos >= 0); gw_assert(numbits <= 32); gw_assert(numbits >= 0); maxlen = (bitpos + numbits + 7) / 8; if (maxlen > ostr->len) { octstr_grow(ostr, maxlen); /* Make sure the new octets start out with value 0 */ for (pos = ostr->len; pos < maxlen; pos++) { ostr->data[pos] = 0; } ostr->len = maxlen; ostr->data[maxlen] = 0; } mask = (1 << numbits) - 1; /* mask is also the largest value that fits */ gw_assert(value <= mask); pos = bitpos / 8; bitpos = bitpos % 8; /* Does the range fit in one octet? */ if (bitpos + numbits <= 8) { /* shiftwidth is the number of bits to ignore on the right. * bitpos 0 is the leftmost bit. */ shiftwidth = 8 - (bitpos + numbits); /* Extract the bits we don't want to affect */ c = ostr->data[pos] & ~(mask << shiftwidth); c |= value << shiftwidth; gw_assert(pos < ostr->len); ostr->data[pos] = c; return; } /* Otherwise... */ /* If speed is a problem here, we could have separate cases for * the first octet (which may have bitpos > 0), and the rest, * which don't. */ while (bitpos + numbits > 8) { /* We want this many bits from the value */ bits = 8 - bitpos; /* There are this many bits to their right in the value */ shiftwidth = numbits - bits; /* Construct a mask for "bits" bits on the far right */ mask = (1 << bits) - 1; /* Get the bits we want */ c = (value >> shiftwidth) & mask; /* Merge them with the bits that are already there */ gw_assert(pos < ostr->len); ostr->data[pos] = (ostr->data[pos] & ~mask) | c; numbits -= (8 - bitpos); bitpos = 0; pos++; } gw_assert(bitpos == 0); gw_assert(pos < ostr->len); /* Set remaining bits. This is just like the single-octet case * before the loop, except that we know bitpos is 0. */ mask = (1 << numbits) - 1; shiftwidth = 8 - numbits; c = ostr->data[pos] & ~(mask << shiftwidth); c |= value << shiftwidth; ostr->data[pos] = c; seems_valid(ostr); } void octstr_append_uintvar(Octstr *ostr, unsigned long value) { /* A uintvar is defined to be up to 32 bits large, so it will * fit in 5 octets. */ unsigned char octets[5]; int i; int start; /* Handle last byte separately; it has no continuation bit, * and must be encoded even if value is 0. */ octets[4] = value & 0x7f; value >>= 7; for (i = 3; value > 0 && i >= 0; i--) { octets[i] = 0x80 | (value & 0x7f); value >>= 7; } start = i + 1; octstr_append_data(ostr, octets + start, 5 - start); } long octstr_extract_uintvar(Octstr *ostr, unsigned long *value, long pos) { int c; int count; unsigned long ui; ui = 0; for (count = 0; count < 5; count++) { c = octstr_get_char(ostr, pos + count); if (c < 0) return -1; ui = (ui << 7) | (c & 0x7f); if (!(c & 0x80)) { *value = ui; return pos + count + 1; } } return -1; } void octstr_append_decimal(Octstr *ostr, long value) { char tmp[128]; Octstr *ostmp; sprintf(tmp, "%ld", value); ostmp = octstr_create(tmp); octstr_append(ostr, ostmp); octstr_destroy(ostmp); } /********************************************************************** * octstr_format and related private functions */ /* * A parsed form of the format string. This struct has been carefully * defined so that it can be initialized with {0} and it will have * the correct defaults. */ struct format { int minus; int zero; long min_width; int has_prec; long prec; long type; }; static void format_flags(struct format *format, const char **fmt) { int done; done = 0; do { switch (**fmt) { case '-': format->minus = 1; break; case '0': format->zero = 1; break; default: done = 1; } if (!done) ++(*fmt); } while (!done); } static void format_width(struct format *format, const char **fmt, va_list *args) { char *end; if (**fmt == '*') { format->min_width = va_arg(*args, int); ++(*fmt); } else if (isdigit(**(const unsigned char **) fmt)) { format->min_width = strtol(*fmt, &end, 10); *fmt = end; /* XXX error checking is missing from here */ } } static void format_prec(struct format *format, const char **fmt, va_list *args) { char *end; if (**fmt != '.') return; ++(*fmt); if (**fmt == '*') { format->has_prec = 1; format->prec = va_arg(*args, int); ++(*fmt); } else if (isdigit(**(const unsigned char **) fmt)) { format->has_prec = 1; format->prec = strtol(*fmt, &end, 10); *fmt = end; /* XXX error checking is missing from here */ } } static void format_type(struct format *format, const char **fmt) { switch (**fmt) { case 'h': case 'l': format->type = **fmt; ++(*fmt); break; } } static void convert(Octstr *os, struct format *format, const char **fmt, va_list *args) { Octstr *new; char *s, *pad; long n; unsigned long u; char tmpfmt[1024]; char tmpbuf[1024]; char c; void *p; new = NULL; switch (**fmt) { case 'c': c = va_arg(*args, int); new = octstr_create_from_data(&c, 1); break; case 'd': case 'i': switch (format->type) { case 'l': n = va_arg(*args, long); break; case 'h': n = (short) va_arg(*args, int); break; default: n = va_arg(*args, int); break; } new = octstr_create(""); octstr_append_decimal(new, n); break; case 'o': case 'u': case 'x': case 'X': switch (format->type) { case 'l': u = va_arg(*args, unsigned long); break; case 'h': u = (unsigned short) va_arg(*args, unsigned int); break; default: u = va_arg(*args, unsigned int); break; } tmpfmt[0] = '%'; tmpfmt[1] = 'l'; tmpfmt[2] = **fmt; tmpfmt[3] = '\0'; sprintf(tmpbuf, tmpfmt, u); new = octstr_create(tmpbuf); break; case 'e': case 'f': case 'g': sprintf(tmpfmt, "%%"); if (format->minus) strcat(tmpfmt, "-"); if (format->zero) strcat(tmpfmt, "0"); if (format->min_width > 0) sprintf(strchr(tmpfmt, '\0'), "%ld", format->min_width); if (format->has_prec) sprintf(strchr(tmpfmt, '\0'), ".%ld", format->prec); if (format->type != '\0') sprintf(strchr(tmpfmt, '\0'), "%c", (int) format->type); sprintf(strchr(tmpfmt, '\0'), "%c", **fmt); snprintf(tmpbuf, sizeof(tmpbuf), tmpfmt, va_arg(*args, double)); new = octstr_create(tmpbuf); break; case 's': s = va_arg(*args, char *); if (format->has_prec && format->prec < (long) strlen(s)) n = format->prec; else n = (long) strlen(s); new = octstr_create_from_data(s, n); break; case 'p': p = va_arg(*args, void *); sprintf(tmpfmt, "%p", p); new = octstr_create(tmpfmt); break; case 'S': new = octstr_duplicate(va_arg(*args, Octstr *)); if (format->has_prec) octstr_truncate(new, format->prec); break; case 'E': new = octstr_duplicate(va_arg(*args, Octstr *)); octstr_url_encode(new); /* * note: we use blind truncate - encoded character can get cut half-way. */ if (format->has_prec) octstr_truncate(new, format->prec); break; case '%': new = octstr_imm("%"); break; default: panic(0, "octstr_format format string syntax error."); } if (format->zero) pad = "0"; else pad = " "; if (format->minus) { while (format->min_width > octstr_len(new)) octstr_append_data(new, pad, 1); } else { while (format->min_width > octstr_len(new)) octstr_insert_data(new, 0, pad, 1); } octstr_append(os, new); octstr_destroy(new); if (**fmt != '\0') ++(*fmt); } Octstr *octstr_format(const char *fmt, ...) { va_list args; Octstr *os; va_start(args, fmt); os = octstr_format_valist(fmt, args); va_end(args); return os; } Octstr *octstr_format_valist(const char *fmt, va_list args) { Octstr *os; size_t n; os = octstr_create(""); while (*fmt != '\0') { struct format format = { 0, }; n = strcspn(fmt, "%"); octstr_append_data(os, fmt, n); fmt += n; gw_assert(*fmt == '%' || *fmt == '\0'); if (*fmt == '\0') continue; ++fmt; format_flags(&format, &fmt); format_width(&format, &fmt, &args); format_prec(&format, &fmt, &args); format_type(&format, &fmt); convert(os, &format, &fmt, &args); } seems_valid(os); return os; } void octstr_format_append(Octstr *os, const char *fmt, ...) { Octstr *temp; va_list args; va_start(args, fmt); temp = octstr_format_valist(fmt, args); va_end(args); octstr_append(os, temp); octstr_destroy(temp); } unsigned long octstr_hash_key(Octstr *ostr) { unsigned long key = 0; long i; if (ostr == NULL) return 0; for (i = 0; i < octstr_len(ostr); i++) key = key + octstr_get_char(ostr, i); return key; } /********************************************************************** * Local functions. */ static void seems_valid_real(Octstr *ostr, const char *filename, long lineno, const char *function) { gw_assert(immutables_init); gw_assert_place(ostr != NULL, filename, lineno, function); gw_assert_allocated(ostr, filename, lineno, function); gw_assert_place(ostr->len >= 0, filename, lineno, function); gw_assert_place(ostr->size >= 0, filename, lineno, function); if (ostr->size == 0) { gw_assert_place(ostr->len == 0, filename, lineno, function); gw_assert_place(ostr->data == NULL, filename, lineno, function); } else { gw_assert_place(ostr->len + 1 <= ostr->size, filename, lineno, function); gw_assert_place(ostr->data != NULL, filename, lineno, function); if (!ostr->immutable) gw_assert_allocated(ostr->data, filename, lineno, function); gw_assert_place(ostr->data[ostr->len] == '\0', filename, lineno, function); } } int octstr_recode (Octstr *tocode, Octstr *fromcode, Octstr *orig) { Octstr *octstr_utf8 = NULL; Octstr *octstr_final = NULL; int resultcode = 0; if (octstr_case_compare(tocode, fromcode) == 0) { goto cleanup_and_exit; } if ((octstr_case_compare(fromcode, octstr_imm ("utf-8")) != 0) && (octstr_case_compare(fromcode, octstr_imm ("utf8")) != 0)) { if (charset_to_utf8(orig, &octstr_utf8, fromcode) < 0) { resultcode = -1; goto cleanup_and_exit; } } else { octstr_utf8 = octstr_duplicate(orig); } if ((octstr_case_compare(tocode, octstr_imm ("utf-8")) != 0) && (octstr_case_compare(tocode, octstr_imm ("utf8")) != 0)) { if (charset_from_utf8(octstr_utf8, &octstr_final, tocode) < 0) { resultcode = -1; goto cleanup_and_exit; } } else { octstr_final = octstr_duplicate(octstr_utf8); } octstr_truncate(orig, 0); octstr_append(orig, octstr_final); cleanup_and_exit: octstr_destroy (octstr_utf8); octstr_destroy (octstr_final); return resultcode; } void octstr_strip_char(Octstr *text, char ch) { int start = 0; seems_valid(text); gw_assert(!text->immutable); /* Remove char from the beginning of the text */ while ((ch == octstr_get_char(text, start)) && start <= octstr_len(text)) start ++; if (start > 0) octstr_delete(text, 0, start); seems_valid(text); } int octstr_isnum(Octstr *ostr1) { int start = 0; char c; seems_valid(ostr1); while (start < octstr_len(ostr1)) { c = octstr_get_char(ostr1, start); if (!isdigit(c) && (c!='+')) return 0; start++; } return 1; } void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl) { int p = -1; long len; len = octstr_len(needle); while ((p = octstr_search(haystack, needle, p + 1)) != -1) { octstr_delete(haystack, p, len); octstr_insert(haystack, repl, p); } } int octstr_symbolize(Octstr *ostr) { long len, i; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return 0; /* Check if it's in the right format */ if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit)) return -1; len = ostr->len + (ostr->len/2); octstr_grow(ostr, ostr->len * 2); for (i = 0; i < len; i += 3) octstr_insert_data(ostr, i, "%", 1); return 1; } void octstr_delete_matching(Octstr *haystack, Octstr *needle) { int p = -1; long len; seems_valid(haystack); seems_valid(needle); gw_assert(!haystack->immutable); len = octstr_len(needle); while ((p = octstr_search(haystack, needle, p + 1)) != -1) { octstr_delete(haystack, p, len); p -= len; } } int octstr_is_all_hex(Octstr *os) { long len, i; int ch; seems_valid(os); len = octstr_len(os); for (i = 0; i < len; ++i) { ch = octstr_get_char(os, i); if (!gw_isxdigit(ch)) return 0; } return 1; } gateway-1.4.5/gwlib/cfg.h0000644000175000017500000001023113227613126013700 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * cfg.h - configuration file handling * * All returned octet strings are copies which the caller should destroy. * * Lars Wirzenius */ #ifndef CFG_H #define CFG_H typedef struct Cfg Cfg; typedef struct CfgLoc CfgLoc; typedef struct CfgGroup CfgGroup; Cfg *cfg_create(Octstr *filename); void cfg_destroy(Cfg *cfg); int cfg_read(Cfg *cfg); void cfg_add_hooks(void *allowed, void *single); CfgGroup *cfg_get_single_group(Cfg *cfg, Octstr *name); List *cfg_get_multi_group(Cfg *cfg, Octstr *name); Octstr *cfg_get_group_name(CfgGroup *grp); Octstr *cfg_get_group_checksum(CfgGroup *grp, ...); Octstr *cfg_get_configfile(CfgGroup *grp); Octstr *cfg_get_real(CfgGroup *grp, Octstr *varname, const char *file, long line, const char *func); #define cfg_get(grp, varname) \ cfg_get_real(grp, varname, __FILE__, __LINE__, __func__) int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname); /* Return -1 and set n to 0 if no varname found * otherwise return 0 and set n to 0 if value is no, false, off or 0, * and 1 if it is true, yes, on or 1. Set n to 1 for other values, too */ int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname); List *cfg_get_list(CfgGroup *grp, Octstr *varname); void cfg_set(CfgGroup *grp, Octstr *varname, Octstr *value); void grp_dump(CfgGroup *grp); void cfg_dump(Cfg *cfg); void cfg_init(void); void cfg_shutdown(void); /* * Dump all known config groups and values to stdout. */ void cfg_dump_all(void); #endif gateway-1.4.5/gwlib/dbpool_oracle.c0000644000175000017500000004320613227613126015750 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_oracle.c - implement Oracle operations for generic database connection pool * * Note: Oracle 8i and 9i support tested. This implementation will not * work with Oracle 7 version. Please do not use Oracle 9i-rc2 OCI * libraries on Linux, due to strange memory problems. If you do not * believe me, just check it youself with valgrind ;) * * Alexander Malysh * Robert Ga³ach * 2004 Added support for binding variables. */ #ifdef HAVE_ORACLE #include /* forward declaration */ static int oracle_select(void *theconn, const Octstr *sql, List *binds, List **res); struct ora_conn { /* environment handle */ OCIEnv *envp; /* context handle */ OCISvcCtx *svchp; /* error handle */ OCIError *errhp; }; /* This function prints the error */ static void oracle_checkerr(OCIError *errhp, sword status) { text errbuf[512]; sb4 errcode = 0; switch (status) { case OCI_SUCCESS: break; case OCI_SUCCESS_WITH_INFO: error(0, "Error - OCI_SUCCESS_WITH_INFO"); break; case OCI_NEED_DATA: error(0, "Error - OCI_NEED_DATA"); break; case OCI_NO_DATA: error(0, "Error - OCI_NODATA"); break; case OCI_ERROR: if (errhp == NULL) break; (void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); error(0, "Error - %.*s", 512, errbuf); break; case OCI_INVALID_HANDLE: error(0, "Error - OCI_INVALID_HANDLE"); break; case OCI_STILL_EXECUTING: error(0, "Error - OCI_STILL_EXECUTE"); break; case OCI_CONTINUE: error(0, "Error - OCI_CONTINUE"); break; default: break; } } /* * Malloc callback function to get tracking of OCI allocs. */ static void *oracle_malloc(void *ctx, size_t size) { void *ret = gw_malloc(size); debug("dbpool.oracle",0,"oracle_malloc called size=%ld @%08lx", (long) size, (long) ret); return ret; } /* * Free callback function to get tracking of OCI allocs. */ static void oracle_free(void *ctx, void *ptr) { debug("dbpool.oracle",0,"oracle_free called @%08lx", (long) ptr); gw_free(ptr); } /* * Realloc callback function to get tracking of OCI allocs. */ static void *oracle_realloc(void *ctx, void *ptr, size_t size) { void *ret = gw_realloc(ptr, size); debug("dbpool.oracle",0,"oracle_realloc called size=%ld", (long) size); return ret; } static void* oracle_open_conn(const DBConf *db_conf) { OracleConf *cfg = db_conf->oracle; sword errorcode = 0; text version[512]; struct ora_conn *conn = gw_malloc(sizeof(struct ora_conn)); gw_assert(conn != NULL); memset(conn, 0, sizeof(struct ora_conn)); debug("dbpool.oracle",0,"oracle_open_conn called"); /* init OCI environment */ errorcode = OCIEnvCreate(&conn->envp, OCI_THREADED|OCI_ENV_NO_MUTEX, NULL, oracle_malloc, oracle_realloc, oracle_free, 0,0); if (errorcode != OCI_SUCCESS) { oracle_checkerr(NULL, errorcode); error(0, "Got error while OCIEnvCreate %d", errorcode); gw_free(conn); return NULL; } debug("dbpool.oracle",0,"oci environment created"); /* allocate error handle */ errorcode = OCIHandleAlloc(conn->envp, (dvoid**) &conn->errhp, OCI_HTYPE_ERROR, 0, 0); if (errorcode != OCI_SUCCESS) { oracle_checkerr(NULL, errorcode); OCIHandleFree(conn->envp, OCI_HTYPE_ENV); gw_free(conn); return NULL; } debug("dbpool.oracle",0,"oci error handle allocated"); /* open oracle user session */ errorcode = OCILogon(conn->envp, conn->errhp, &conn->svchp, (unsigned char*)octstr_get_cstr(cfg->username), octstr_len(cfg->username), (unsigned char*)octstr_get_cstr(cfg->password), octstr_len(cfg->password), (unsigned char*)octstr_get_cstr(cfg->tnsname), octstr_len(cfg->tnsname)); if (errorcode != OCI_SUCCESS) { oracle_checkerr(conn->errhp, errorcode); OCIHandleFree(conn->errhp, OCI_HTYPE_ERROR); OCIHandleFree(conn->envp, OCI_HTYPE_ENV); gw_free(conn); return NULL; } debug("dbpool.oracle",0,"connected to database"); errorcode = OCIServerVersion(conn->svchp, conn->errhp, version, sizeof(version), OCI_HTYPE_SVCCTX); if (errorcode != OCI_SUCCESS) { oracle_checkerr(conn->errhp, errorcode); } else { info(0, "Connected to: %s", version); } return conn; } static void oracle_close_conn(void *theconn) { struct ora_conn *conn = (struct ora_conn*) theconn; gw_assert(conn != NULL); if (conn->svchp != NULL) oracle_checkerr(conn->errhp, OCILogoff(conn->svchp, conn->errhp)); OCIHandleFree(conn->errhp, OCI_HTYPE_ERROR); OCIHandleFree(conn->envp, OCI_HTYPE_ENV); /* OCITerminate(OCI_DEFAULT); */ gw_free(conn); } static int oracle_check_conn(void *theconn) { int ret; #ifdef HAVE_OCIPING struct ora_conn *conn = (struct ora_conn*) theconn; sword result; gw_assert(conn != NULL); result = OCIPing(conn->svchp, conn->errhp, OCI_DEFAULT); if (result != OCI_SUCCESS) { oracle_checkerr(conn->errhp, result); ret = -1; } else { ret = 0; } #else Octstr *sql; List *res; /* TODO Check for appropriate OCI function */ sql = octstr_create("SELECT 1 FROM DUAL"); ret = oracle_select(conn, sql, NULL, &res); if (ret != -1 && gwlist_len(res) > 0) { List *row = gwlist_extract_first(res); gwlist_destroy(row, octstr_destroy_item); } if (ret != -1) gwlist_destroy(res, NULL); octstr_destroy(sql); #endif return ret; } static void oracle_conf_destroy(DBConf *theconf) { OracleConf *conf = theconf->oracle; octstr_destroy(conf->username); octstr_destroy(conf->password); octstr_destroy(conf->tnsname); gw_free(conf); gw_free(theconf); } static int oracle_select(void *theconn, const Octstr *sql, List *binds, List **res) { List *row; OCIStmt *stmt; OCIParam *dparam; sword status; ub4 columns; ub4 i; struct data_s { text *data; ub2 size; sb2 ind; ub2 type; }; struct data_s *data; struct ora_conn *conn = (struct ora_conn*) theconn; int binds_len = (binds ? gwlist_len(binds) : 0); *res = NULL; /* allocate statement handle */ status = OCIHandleAlloc(conn->envp, (dvoid**)&stmt, OCI_HTYPE_STMT, 0,0); if (OCI_SUCCESS != status) { oracle_checkerr(conn->errhp, status); return -1; } /* prepare statement */ status = OCIStmtPrepare(stmt, conn->errhp, (unsigned char*)octstr_get_cstr(sql), octstr_len(sql), OCI_NTV_SYNTAX, OCI_DEFAULT); if (OCI_SUCCESS != status) { oracle_checkerr(conn->errhp, status); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } /* bind variables */ for (i = 0; i < binds_len; i++) { OCIBind *bndhp = NULL; Octstr *bind = gwlist_get(binds, i); status = OCIBindByPos(stmt, &bndhp, conn->errhp, (i+1), (dvoid *) octstr_get_cstr(bind), (sword) octstr_len(bind)+1, SQLT_STR, (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT); if (OCI_SUCCESS != status) { oracle_checkerr(conn->errhp, status); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } } /* execute our statement */ status = OCIStmtExecute(conn->svchp, stmt, conn->errhp, 0, 0, NULL, NULL, OCI_DEFAULT); if (OCI_SUCCESS != status && OCI_NO_DATA != status) { oracle_checkerr(conn->errhp, status); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } /* receive column count */ status = OCIAttrGet(stmt, OCI_HTYPE_STMT, &columns, 0, OCI_ATTR_PARAM_COUNT, conn->errhp); if (status != OCI_SUCCESS) { oracle_checkerr(conn->errhp, status); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } debug("dbpool.oracle",0,"SQL has %d columns", columns); /* allocate array of pointers */ debug("dbpool.oracle",0,"alloc size=%ld",sizeof(text*)*columns); data = gw_malloc(sizeof(struct data_s)*columns); debug("dbpool.oracle",0,"retrieve data_size"); /* retrieve data size for every column and allocate it */ for (i=0 ; i < columns; i++) { OCIDefine *defh; status = OCIParamGet(stmt, OCI_HTYPE_STMT, conn->errhp, (dvoid**) &dparam, i+1); if (status != OCI_SUCCESS) { oracle_checkerr(conn->errhp, status); columns = i; for (i = 0; i < columns; i++) gw_free(data[i].data); gw_free(data); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } status = OCIAttrGet(dparam, OCI_DTYPE_PARAM, (dvoid*) &data[i].size, 0, OCI_ATTR_DATA_SIZE, conn->errhp); if (status != OCI_SUCCESS) { oracle_checkerr(conn->errhp, status); columns = i; for (i = 0; i < columns; i++) gw_free(data[i].data); gw_free(data); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } status = OCIAttrGet(dparam, OCI_DTYPE_PARAM, (dvoid*) &data[i].type, 0, OCI_ATTR_DATA_TYPE, conn->errhp); if (status != OCI_SUCCESS) { oracle_checkerr(conn->errhp, status); columns = i; for (i = 0; i < columns; i++) gw_free(data[i].data); gw_free(data); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } /* convert all data types to C-Strings except DATE */ if (data[i].type != SQLT_DAT) { data[i].size++; /* terminating zero */ data[i].type = SQLT_STR; } debug("dbpool.oracle",0,"alloc size=%d", data[i].size); data[i].data = gw_malloc(data[i].size); /* bind allocated values to statement handle */ status = OCIDefineByPos(stmt, &defh, conn->errhp, i+1, data[i].data, data[i].size, data[i].type, &data[i].ind, 0, 0, OCI_DEFAULT); if (status != OCI_SUCCESS) { oracle_checkerr(conn->errhp, status); columns = i; for (i = 0; i <= columns; i++) gw_free(data[i].data); gw_free(data); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } } *res = gwlist_create(); /* fetch data */ while ((status = OCIStmtFetch(stmt, conn->errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT)) == OCI_SUCCESS || status == OCI_SUCCESS_WITH_INFO) { row = gwlist_create(); for (i = 0; i < columns; i++) { if (data[i].data == NULL || data[i].ind == -1) { gwlist_insert(row, i, octstr_create("")); } else { gwlist_insert(row, i, octstr_create_from_data((const char*)data[i].data, data[i].size)); } /* debug("dbpool.oracle",0,"inserted value = '%s'", octstr_get_cstr(gwlist_get(row,i))); */ } gwlist_append(*res, row); } /* ignore OCI_NO_DATA error */ if (status != OCI_NO_DATA) { List *row; oracle_checkerr(conn->errhp, status); for (i = 0; i < columns; i++) gw_free(data[i].data); gw_free(data); while ((row = gwlist_extract_first(*res)) != NULL) gwlist_destroy(row, octstr_destroy_item); gwlist_destroy(*res, NULL); *res = NULL; OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } for (i = 0; i < columns; i++) gw_free(data[i].data); gw_free(data); OCIHandleFree(stmt, OCI_HTYPE_STMT); return 0; } static int oracle_update(void *theconn, const Octstr *sql, List *binds) { OCIStmt *stmt; sword status; ub4 rows = 0, i; struct ora_conn *conn = (struct ora_conn*) theconn; int binds_len = (binds ? gwlist_len(binds) : 0); /* allocate statement handle */ status = OCIHandleAlloc(conn->envp, (dvoid**)&stmt, OCI_HTYPE_STMT, 0,0); if (OCI_SUCCESS != status) { oracle_checkerr(conn->errhp, status); return -1; } debug("dbpool.oracle",0,"OCIStmt allocated"); /* prepare statement */ status = OCIStmtPrepare(stmt, conn->errhp, (unsigned char*)octstr_get_cstr(sql), octstr_len(sql), OCI_NTV_SYNTAX, OCI_DEFAULT); if (OCI_SUCCESS != status) { oracle_checkerr(conn->errhp, status); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } debug("dbpool.oracle",0,"OCIStmtPrepare done"); /* bind variables */ for (i = 0; i < binds_len; i++) { Octstr *bind = gwlist_get(binds, i); OCIBind *bndhp = NULL; status = OCIBindByPos(stmt, &bndhp, conn->errhp, (i+1), (dvoid *) octstr_get_cstr(bind), (sword) octstr_len(bind)+1, SQLT_STR, (dvoid *) 0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0, OCI_DEFAULT); if (OCI_SUCCESS != status) { oracle_checkerr(conn->errhp, status); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } } /* execute our statement */ status = OCIStmtExecute(conn->svchp, stmt, conn->errhp, 1, 0, NULL, NULL, /*OCI_DEFAULT*/ OCI_COMMIT_ON_SUCCESS); if (OCI_SUCCESS != status && OCI_NO_DATA != status) { oracle_checkerr(conn->errhp, status); OCIHandleFree(stmt, OCI_HTYPE_STMT); return -1; } debug("dbpool.oracle",0,"OCIStmtExecute done"); /* retrieve #rows processed so far */ status = OCIAttrGet(stmt, OCI_HTYPE_STMT, &rows, 0, OCI_ATTR_ROW_COUNT, conn->errhp); if (status != OCI_SUCCESS) { oracle_checkerr(conn->errhp, status); /* we doesn't return error here, because sql is executed and commited already */ } debug("dbpool.oracle",0,"rows processed = %d", rows); OCIHandleFree(stmt, OCI_HTYPE_STMT); return (int) rows; } static struct db_ops oracle_ops = { .open = oracle_open_conn, .close = oracle_close_conn, .check = oracle_check_conn, .conf_destroy = oracle_conf_destroy, .select = oracle_select, .update = oracle_update }; #endif gateway-1.4.5/gwlib/dbpool_cass.c0000644000175000017500000002674113227613126015441 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_cass.c - implement Cassandra 2.x, 3.0 operations for generic database connection pool * * Stipe Tolj , 2015-09-25 */ #ifdef HAVE_CASS #include struct CassInstance { CassCluster *cluster; CassSession *session; }; typedef struct CassInstance CassInstance; static void cass_log(const CassLogMessage *message, void *data) { switch (message->severity) { #define CASS_LEVEL(e, f) \ case e: \ f(0, "Cassandra: (%s:%d:%s): %s", \ message->file, message->line, message->function, \ message->message); \ break; CASS_LEVEL(CASS_LOG_INFO, info) CASS_LEVEL(CASS_LOG_WARN, warning) CASS_LEVEL(CASS_LOG_ERROR, error) CASS_LEVEL(CASS_LOG_CRITICAL, panic) default: break; } } static void print_error(CassFuture* future) { const char* message; size_t message_length; cass_future_error_message(future, &message, &message_length); error(0, "Cassandra: %s", message); } static CassError connect_session(CassSession* session, const CassCluster* cluster) { CassError rc = CASS_OK; CassFuture* future = cass_session_connect(session, cluster); cass_future_wait(future); rc = cass_future_error_code(future); if (rc != CASS_OK) { print_error(future); } cass_future_free(future); return rc; } static void *cass_open_conn(const DBConf *db_conf) { CassInstance *i; CassConf *conf = db_conf->cass; /* make compiler happy */ /* sanity check */ if (conf == NULL) return NULL; /* set logging callback */ cass_log_set_level(CASS_LOG_INFO); cass_log_set_callback(cass_log, NULL); /* create instance */ i = gw_malloc(sizeof(CassInstance)); i->cluster = cass_cluster_new(); cass_cluster_set_contact_points(i->cluster, octstr_get_cstr(conf->host)); /* set authentication credentials */ cass_cluster_set_credentials(i->cluster, octstr_get_cstr(conf->username), octstr_get_cstr(conf->password)); /* change idle timeout (default 60s) */ cass_cluster_set_connection_idle_timeout(i->cluster, conf->idle_timeout); i->session = cass_session_new(); if (connect_session(i->session, i->cluster) != CASS_OK) { error(0, "Cassandra: Can not connect to cluster!"); goto failed; } info(0, "Cassandra: Connected to cluster <%s>", octstr_get_cstr(conf->host)); return i; failed: cass_cluster_free(i->cluster); cass_session_free(i->session); gw_free(i); return NULL; } static void cass_close_conn(void *conn) { CassInstance *i = (CassInstance*) conn; CassFuture *close_future = NULL; if (conn == NULL) return; close_future = cass_session_close(i->session); cass_future_wait(close_future); cass_future_free(close_future); cass_cluster_free(i->cluster); cass_session_free(i->session); gw_free(i); } static int cass_check_conn(void *conn) { if (conn == NULL) return -1; return 0; } static int cass_select(void *conn, const Octstr *sql, List *binds, List **res) { CassInstance *instance = conn; CassError rc = CASS_OK; CassStatement *statement = NULL; CassFuture *future = NULL; long i, binds_len; List *res_row; binds_len = gwlist_len(binds); /* allocate statement handle */ statement = cass_statement_new(octstr_get_cstr(sql), binds_len); /* bind parameters if any */ if (binds_len > 0) { for (i = 0; i < binds_len; i++) { cass_statement_bind_string(statement, i, octstr_get_cstr(gwlist_get(binds, i))); } } /* execute statement */ future = cass_session_execute(instance->session, statement); cass_future_wait(future); /* evaluate result */ rc = cass_future_error_code(future); if (rc != CASS_OK) { print_error(future); cass_future_free(future); cass_statement_free(statement); return -1; } else { const CassResult *result = cass_future_get_result(future); CassIterator *iterator_row = cass_iterator_from_result(result); *res = gwlist_create(); /* iterate through all rows */ while (cass_iterator_next(iterator_row)) { const CassRow *row = cass_iterator_get_row(iterator_row); CassIterator *iterator_column = cass_iterator_from_row(row); res_row = gwlist_create(); /* iterate through all columns (of one row) */ while (cass_iterator_next(iterator_column)) { const CassValue *value; CassValueType type; cass_int32_t i; cass_int64_t bi; cass_bool_t b; cass_double_t d; cass_float_t f; const char* s; size_t s_length; CassUuid u; char us[CASS_UUID_STRING_LENGTH]; value = cass_iterator_get_column(iterator_column); type = cass_value_type(value); /* determine value type and convert */ switch (type) { case CASS_VALUE_TYPE_INT: cass_value_get_int32(value, &i); gwlist_append(res_row, octstr_format("%d", i)); break; case CASS_VALUE_TYPE_BIGINT: cass_value_get_int64(value, &bi); gwlist_append(res_row, octstr_format("%ld", bi)); break; case CASS_VALUE_TYPE_BOOLEAN: cass_value_get_bool(value, &b); gwlist_append(res_row, (b ? octstr_imm("true") : octstr_imm("false"))); break; case CASS_VALUE_TYPE_DOUBLE: cass_value_get_double(value, &d); gwlist_append(res_row, octstr_format("%g", d)); break; case CASS_VALUE_TYPE_FLOAT: cass_value_get_float(value, &f); gwlist_append(res_row, octstr_format("%f", f)); break; case CASS_VALUE_TYPE_TEXT: case CASS_VALUE_TYPE_ASCII: case CASS_VALUE_TYPE_VARCHAR: cass_value_get_string(value, &s, &s_length); gwlist_append(res_row, octstr_create_from_data(s, s_length)); break; case CASS_VALUE_TYPE_UUID: cass_value_get_uuid(value, &u); cass_uuid_string(u, us); gwlist_append(res_row, octstr_create(us)); break; default: if (cass_value_is_null(value)) { gwlist_append(res_row, octstr_imm("_NULL_")); } else { error(0, "Cassandra: %s: unhandled type %d", __func__, type); } break; } } gwlist_append(*res, res_row); cass_iterator_free(iterator_column); } cass_result_free(result); cass_iterator_free(iterator_row); } cass_future_free(future); cass_statement_free(statement); return 0; } static int cass_update(void *conn, const Octstr *sql, List *binds) { CassInstance *instance = conn; CassError rc = CASS_OK; CassStatement *statement = NULL; CassFuture *future = NULL; long i, binds_len; binds_len = gwlist_len(binds); /* allocate statement handle */ statement = cass_statement_new(octstr_get_cstr(sql), binds_len); /* bind parameters if any */ if (binds_len > 0) { for (i = 0; i < binds_len; i++) { cass_statement_bind_string(statement, i, octstr_get_cstr(gwlist_get(binds, i))); } } /* execute statement */ future = cass_session_execute(instance->session, statement); cass_future_wait(future); /* evaluate result */ rc = cass_future_error_code(future); if (rc != CASS_OK) { print_error(future); cass_future_free(future); cass_statement_free(statement); return -1; } cass_future_free(future); cass_statement_free(statement); return 0; } static void cass_conf_destroy(DBConf *db_conf) { CassConf *conf = db_conf->cass; octstr_destroy(conf->host); octstr_destroy(conf->username); octstr_destroy(conf->password); octstr_destroy(conf->database); gw_free(conf); gw_free(db_conf); } static struct db_ops cass_ops = { .open = cass_open_conn, .close = cass_close_conn, .check = cass_check_conn, .select = cass_select, .update = cass_update, .conf_destroy = cass_conf_destroy }; #endif /* HAVE_CASS */ gateway-1.4.5/gwlib/xmlrpc.c0000644000175000017500000023141713227613126014454 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwlib/xmlrpc.c: functions to handle XML-RPC structure - building and parsing * * XML-RPC is HTTP-based XML defination to handle remote procedure calls, * and is defined at http://www.xml-rpc.org * * Kalle Marjola 2001 for project Kannel * Stipe Tolj * Robert Gaach */ #include #include #include #include #include #include "gwlib/gwlib.h" #include "gwlib/xmlrpc.h" #define XR_ENABLE_EMPTY_STRING_VALUES #define OPTIMAL_STRUCT_SIZE 7 typedef struct xmlrpc_methodresponse XMLRPCMethodResponse; typedef struct xmlrpc_member XMLRPCMember; typedef struct xmlrpc_methodcall XMLRPCMethodCall; typedef struct xmlrpc_fault XMLRPCFault; typedef struct xmlrpc_table_t xmlrpc_table_t; typedef struct xmlrpc_2table_t xmlrpc_2table_t; struct xmlrpc_methodcall { Octstr *method_name; List *params; /* List of XMLRPCValues */ }; struct xmlrpc_methodresponse { XMLRPCValue *param; /* Param value */ XMLRPCFault *fault; /* ..or this */ }; struct xmlrpc_fault { long f_code; /* Fault code */ Octstr *f_string; /* and description */ }; struct xmlrpc_document { int d_type; /* enum here */ int parse_status; /* enum here */ Octstr *parse_error; /* error string in case of parsing error */ XMLRPCMethodCall *methodcall; XMLRPCMethodResponse *methodresponse; }; struct xmlrpc_value { int v_type; /* enum here */ XMLRPCScalar *v_scalar; List *v_array; /* List of XMLRPCValues */ Dict *v_struct; /* Dict of XMLRPCValues */ }; struct xmlrpc_member { /* member of struct */ Octstr *name; XMLRPCValue *value; }; struct xmlrpc_scalar { int s_type; /* enum here */ Octstr *s_str; long s_int; int s_bool; double s_double; Octstr *s_date; Octstr *s_base64; }; struct xmlrpc_table_t { char *name; }; struct xmlrpc_2table_t { char *name; int s_type; /* enum here */ }; static xmlrpc_table_t methodcall_elements[] = { { "METHODNAME" }, { "PARAMS" } }; static xmlrpc_table_t methodresponse_elements[] = { { "FAULT" }, { "PARAMS" } }; static xmlrpc_table_t params_elements[] = { { "PARAM" } }; static xmlrpc_table_t param_elements[] = { { "VALUE" } }; static xmlrpc_2table_t value_elements[] = { { "I4", xr_int }, { "INT", xr_int }, { "BOOLEAN", xr_bool }, { "STRING", xr_string }, { "DOUBLE", xr_double }, { "DATETIME.ISO8601", xr_date }, { "BASE64", xr_base64 }, { "STRUCT", xr_struct }, { "ARRAY", xr_array } }; static xmlrpc_table_t struct_elements[] = { { "MEMBER" } }; static xmlrpc_table_t member_elements[] = { { "NAME" }, { "VALUE" } }; static xmlrpc_table_t array_elements[] = { { "DATA" } }; static xmlrpc_table_t data_elements[] = { { "VALUE" } }; static xmlrpc_table_t fault_elements[] = { { "VALUE" } }; #define NUMBER_OF_METHODCALL_ELEMENTS \ sizeof(methodcall_elements)/sizeof(methodcall_elements[0]) #define NUMBER_OF_METHODRESPONSE_ELEMENTS \ sizeof(methodresponse_elements)/sizeof(methodresponse_elements[0]) #define NUMBER_OF_PARAMS_ELEMENTS \ sizeof(params_elements)/sizeof(params_elements[0]) #define NUMBER_OF_PARAM_ELEMENTS \ sizeof(param_elements)/sizeof(param_elements[0]) #define NUMBER_OF_VALUE_ELEMENTS \ sizeof(value_elements)/sizeof(value_elements[0]) #define NUMBER_OF_STRUCT_ELEMENTS \ sizeof(struct_elements)/sizeof(struct_elements[0]) #define NUMBER_OF_MEMBER_ELEMENTS \ sizeof(member_elements)/sizeof(member_elements[0]) #define NUMBER_OF_ARRAY_ELEMENTS \ sizeof(array_elements)/sizeof(array_elements[0]) #define NUMBER_OF_DATA_ELEMENTS \ sizeof(data_elements)/sizeof(data_elements[0]) #define NUMBER_OF_FAULT_ELEMENTS \ sizeof(fault_elements)/sizeof(fault_elements[0]) /* -------------------------------------- * internal parser function declarations */ static int parse_document(xmlDocPtr document, XMLRPCDocument *xrdoc); static int parse_methodcall(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMethodCall *methodcall); static int parse_methodcall_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMethodCall *methodcall); static int parse_methodresponse(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMethodResponse *methodresponse, int* n); static int parse_methodresponse_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMethodResponse *methodresponse); static int parse_params(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *params); static int parse_params_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *params); static int parse_param(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *params, int *n); static int parse_param_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *params); static int parse_value(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCValue *value); static int parse_value_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCValue *xrvalue); static int parse_struct(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, Dict *members); static int parse_struct_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, Dict *members); static int parse_member(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMember *member); static int parse_member_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMember *member); static int parse_array(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *elements); static int parse_array_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *elements); static int parse_data(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *elements); static int parse_data_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *elements); static int parse_fault(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCFault *fault); static int parse_fault_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCFault *fault); /*------------------------------------- * MethodCall */ static XMLRPCMethodCall *xmlrpc_call_create(Octstr *name) { XMLRPCMethodCall *nmsg = gw_malloc(sizeof(XMLRPCMethodCall)); nmsg->method_name = octstr_duplicate(name); nmsg->params = gwlist_create(); return nmsg; } static void xmlrpc_call_destroy(XMLRPCMethodCall *call) { if (call == NULL) return; octstr_destroy(call->method_name); gwlist_destroy(call->params, xmlrpc_value_destroy_item); gw_free(call); } static Octstr *xmlrpc_call_get_name(XMLRPCMethodCall *call) { return call->method_name; } static int xmlrpc_call_add_param(XMLRPCMethodCall *method, XMLRPCValue *value) { if (method == NULL || value == NULL) return -1; gwlist_produce(method->params, value); return 0; } static Octstr *xmlrpc_call_print(XMLRPCMethodCall *call, int level) { Octstr *body, *os_value; XMLRPCValue *val; long i; if (call == NULL || call->method_name == NULL) return NULL; body = octstr_format("%*s\n" "%*s%S\n", level, "", level + 2, "", call->method_name); gwlist_lock(call->params); if (gwlist_len(call->params) > 0) { octstr_format_append(body, "%*s\n", level + 2, ""); for (i = 0; i < gwlist_len(call->params); i++) { val = gwlist_get(call->params, i); os_value = xmlrpc_value_print(val, level + 6); if (os_value == NULL) { error(0, "XMLRPC: Could not print method call, param %ld malformed", i); octstr_destroy(body); return NULL; } octstr_format_append(body, "%*s\n%S%*s\n", level + 4, "", os_value, level + 4, ""); octstr_destroy(os_value); } octstr_format_append(body, "%*s\n", level + 2, ""); } gwlist_unlock(call->params); octstr_format_append(body, "%*s\n", level, ""); return body; } /*------------------------------------- * XMLRPCFault */ static XMLRPCFault *xmlrpc_fault_create(long fcode, Octstr *fstring) { XMLRPCFault *fault = gw_malloc(sizeof(XMLRPCFault)); fault->f_code = fcode; fault->f_string = octstr_duplicate(fstring); return fault; } static void xmlrpc_fault_destroy(XMLRPCFault *fault) { if (fault == NULL) return; octstr_destroy(fault->f_string); gw_free(fault); } static long xmlrpc_fault_get_code(XMLRPCFault *fault) { if (fault == NULL) return -1; return fault->f_code; } static Octstr *xmlrpc_fault_get_string(XMLRPCFault *fault) { if (fault == NULL) return NULL; return fault->f_string; } static Octstr *xmlrpc_fault_print(XMLRPCFault *fault, int level) { Octstr *os; if (fault == NULL) return NULL; os = octstr_format("%*s\n%*s\n" "%*s\n" "%*s\n" "%*sfaultCode\n" "%*s%ld\n" "%*s\n" "%*s\n" "%*sfaultString\n" "%*s%S\n" "%*s\n" "%*s\n" "%*s\n%*s\n", level, "", level+2, "", level+4, "", level+6, "", level+8, "", level+8, "", fault->f_code, level+6, "", level+6, "", level+8, "", level+8, "", (fault->f_string == NULL ? octstr_imm("/") : fault->f_string), level+6, "", level+4, "", level+2, "", level, ""); return os; } /*------------------------------------- * MethodResponse */ static XMLRPCMethodResponse *xmlrpc_response_create(void) { XMLRPCMethodResponse *nmsg = gw_malloc(sizeof(XMLRPCMethodResponse)); nmsg->param = NULL; nmsg->fault = NULL; return nmsg; } static void xmlrpc_response_destroy(XMLRPCMethodResponse *response) { if (response == NULL) return; xmlrpc_value_destroy(response->param); xmlrpc_fault_destroy(response->fault); gw_free(response); } static int xmlrpc_response_add_param(XMLRPCMethodResponse *response, XMLRPCValue *value) { if (response == NULL || value == NULL) return -1; if (response->param != NULL) { error(0, "XMLRPC: Method Response may contain only one param."); return -1; } if (response->fault != NULL) { error(0, "XMLRPC: Fault Response may not contain any param."); return -1; } response->param = value; return 0; } static int xmlrpc_response_is_fault(XMLRPCMethodResponse *response) { if (response == NULL || response->fault == NULL) return 0; return 1; } static long xmlrpc_response_get_faultcode(XMLRPCMethodResponse *faultresponse) { if (! xmlrpc_response_is_fault(faultresponse)) { error(0, "XMLRPC response is not fault response."); return -1; } return xmlrpc_fault_get_code(faultresponse->fault); } static Octstr *xmlrpc_response_get_faultstring(XMLRPCMethodResponse *faultresponse) { if (! xmlrpc_response_is_fault(faultresponse)) { error(0, "XMLRPC response is not fault response."); return NULL; } return xmlrpc_fault_get_string(faultresponse->fault); } static Octstr *xmlrpc_response_print(XMLRPCMethodResponse *response, int level) { Octstr *body = NULL, *os_value = NULL; if (response->fault == NULL && response->param != NULL) { os_value = xmlrpc_value_print(response->param, level + 6); body = octstr_format("%*s\n" "%*s\n%*s\n" "%S" "%*s\n%*s\n" "%*s\n", level, "", level+2, "", level+4, "", os_value, level+4, "", level+2, "", level, ""); } else if (response->fault != NULL && response->param == NULL) { os_value = xmlrpc_fault_print(response->fault, level + 2); body = octstr_format("%*s\n" "%S" "%*s\n", level, "", os_value, level, ""); } octstr_destroy(os_value); return body; } /*------------------------------------- * Document */ XMLRPCDocument *xmlrpc_doc_create(void) { XMLRPCDocument *xrdoc = gw_malloc(sizeof(XMLRPCDocument)); xrdoc->d_type = xr_undefined; xrdoc->parse_status = XMLRPC_COMPILE_OK; xrdoc->parse_error = NULL; xrdoc->methodcall = NULL; xrdoc->methodresponse = NULL; return xrdoc; } XMLRPCDocument *xmlrpc_doc_create_call(Octstr *name) { XMLRPCDocument *xrdoc; xrdoc = xmlrpc_doc_create(); xrdoc->d_type = xr_methodcall; xrdoc->methodcall = xmlrpc_call_create(name); return xrdoc; } XMLRPCDocument *xmlrpc_doc_create_response(void) { XMLRPCDocument *xrdoc; xrdoc = xmlrpc_doc_create(); xrdoc->d_type = xr_methodresponse; xrdoc->methodresponse = xmlrpc_response_create(); return xrdoc; } XMLRPCDocument *xmlrpc_doc_create_faultresponse(long faultcode, Octstr *faultstring) { XMLRPCDocument *xrdoc; XMLRPCMethodResponse *response; xrdoc = xmlrpc_doc_create_response(); response = xrdoc->methodresponse; response->fault = xmlrpc_fault_create(faultcode, faultstring); return xrdoc; } XMLRPCDocument *xmlrpc_doc_parse(Octstr *post_body, int d_type) { XMLRPCDocument *xrdoc = xmlrpc_doc_create(); xmlDocPtr pDoc; size_t size; char *body; if (post_body == NULL) { xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_create("XMLRPC: (null) XML document given."); return xrdoc; } xrdoc->d_type = d_type; octstr_strip_blanks(post_body); octstr_shrink_blanks(post_body); size = octstr_len(post_body); body = octstr_get_cstr(post_body); /* parse XML document to a XML tree */ pDoc = xmlParseMemory(body, size); if (!pDoc) { xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_create("XMLRPC: not valid XML document given."); return xrdoc; } parse_document(pDoc, xrdoc); xmlFreeDoc(pDoc); return xrdoc; } /* Destroy XMLRPCDocument object */ void xmlrpc_doc_destroy(XMLRPCDocument *xrdoc, int d_type) { if (xrdoc == NULL) return; if (xrdoc->d_type != d_type) warning(0, "Destroying document with different type then given."); xmlrpc_call_destroy(xrdoc->methodcall); xmlrpc_response_destroy(xrdoc->methodresponse); octstr_destroy(xrdoc->parse_error); gw_free(xrdoc); } /* Add given param to XMLRPCDocument object. * Return 0 if ok or -1 if something wrong (e.g. xrdoc is null or faultresponse) */ int xmlrpc_doc_add_value(XMLRPCDocument *xrdoc, int d_type, XMLRPCValue *value) { if (xrdoc == NULL) return -1; if (xrdoc->d_type != d_type && d_type != xr_undefined) { error(0, "Wrong xmlrpc document type. Param not added."); return -1; } if (xrdoc->d_type == xr_methodresponse) { if (xmlrpc_response_add_param(xrdoc->methodresponse, value) < 0) return -1; } else if (xrdoc->d_type == xr_methodcall) { if (xmlrpc_call_add_param(xrdoc->methodcall, value) < 0) return -1; } else { error(0, "Unknown xmlrpc document type. Param not added."); return -1; } return 0; } /* Add a scalar param to MethodCall/MethodResponse. * Return 0 if ok or -1 if something wrong (e.g. xrdoc is null or faultresponse) */ int xmlrpc_doc_add_scalar(XMLRPCDocument *xrdoc, int d_type, int type, void *arg) { XMLRPCValue *param; param = xmlrpc_create_scalar_value(type, arg); if (xmlrpc_doc_add_value(xrdoc, d_type, param) < 0) { xmlrpc_value_destroy(param); return -1; } return 0; } /* Create Octstr (text/xml string) out of given XMLRPCDocument. Caller * must free returned Octstr */ Octstr *xmlrpc_doc_print(XMLRPCDocument *xrdoc, int d_type, int level) { Octstr *body = NULL, *pref = NULL; if (xrdoc == NULL) return NULL; if (xrdoc->d_type != d_type) { error(0, "Wrong xmlrpc document type."); return NULL; } if (xrdoc->d_type == xr_methodresponse) { body = xmlrpc_response_print(xrdoc->methodresponse, level); } else if (xrdoc->d_type == xr_methodcall) { body = xmlrpc_call_print(xrdoc->methodcall, level); } else { error(0, "Unknown xmlrpc document type."); } if (body != NULL) { pref = octstr_format("%*s\n", level, ""); octstr_insert(body, pref, 0); octstr_destroy(pref); } return body; } /* Send XMLRPCDocument to given URL with given Headers. * Return 0 if all went fine, -1 if failure. As user reference, uses *void */ int xmlrpc_doc_send(XMLRPCDocument *xrdoc, int d_type, HTTPCaller *http_ref, Octstr *url, List *headers, void *ref) { Octstr *body; if (http_ref == NULL || xrdoc == NULL) return -1; if (xrdoc->d_type != d_type) { error(0, "Wrong xmlrpc document type."); return -1; } if (headers == NULL) headers = gwlist_create(); http_header_remove_all(headers, "Content-Type"); http_header_add(headers, "Content-Type", "text/xml"); /* * XML-RPC specs say we at least need Host and User-Agent * HTTP headers to be defined. * These are set anyway within gwlib/http.c:build_request() */ body = xmlrpc_doc_print(xrdoc, d_type, 0); http_start_request(http_ref, HTTP_METHOD_POST, url, headers, body, 0, ref, NULL); octstr_destroy(body); /* XXX: should headers be destroyed here? */ /*http_destroy_headers(headers); */ return 0; } /*------------------------------------- * XMLRPCValue */ /* Create new value. Set type of it to xr_undefined, so it must be * set laterwards to correct one */ XMLRPCValue *xmlrpc_value_create(void) { XMLRPCValue *val = gw_malloc(sizeof(XMLRPCValue)); val->v_type = xr_undefined; val->v_scalar = NULL; val->v_array = NULL; val->v_struct = NULL; return val; } /* Destroy value with its information, recursively if need to */ void xmlrpc_value_destroy(XMLRPCValue *val) { if (val == NULL) return; switch(val->v_type) { case xr_scalar: xmlrpc_scalar_destroy(val->v_scalar); break; case xr_array: gwlist_destroy(val->v_array, xmlrpc_value_destroy_item); break; case xr_struct: dict_destroy(val->v_struct); break; } gw_free(val); } /* wrapper to destroy to be used with list */ void xmlrpc_value_destroy_item(void *val) { xmlrpc_value_destroy(val); } int xmlrpc_value_set_type(XMLRPCValue *val, int v_type) { if (val == NULL) return -1; switch(v_type) { case xr_scalar: case xr_array: case xr_struct: val->v_type = v_type; break; default: error(0, "XMLRPC: value type not supported."); return -1; } return 0; } int xmlrpc_value_set_content(XMLRPCValue *val, void *content) { if (val == NULL) return -1; switch(val->v_type) { case xr_scalar: val->v_scalar = (XMLRPCScalar *)content; break; case xr_array: val->v_array = (List *)content; break; case xr_struct: val->v_struct = (Dict *)content; break; default: error(0, "XMLRPC: value type not supported."); return -1; } return 0; } int xmlrpc_value_get_type(XMLRPCValue *val) { if (val == NULL) return -1; return val->v_type; } int xmlrpc_value_get_type_smart(XMLRPCValue *val) { int type = xmlrpc_value_get_type(val); if (type == xr_scalar) return xmlrpc_get_scalar_value_type(val); return type; } void *xmlrpc_value_get_content(XMLRPCValue *val) { if (val == NULL) return NULL; switch(val->v_type) { case xr_scalar: return val->v_scalar; case xr_array: return val->v_array; case xr_struct: return val->v_struct; default: error(0, "XMLRPC: value type not supported."); return NULL; } } Octstr *xmlrpc_value_print(XMLRPCValue *val, int level) { Octstr *body = NULL, *os = NULL; if (val == NULL) return NULL; switch(val->v_type) { case xr_scalar: os = xmlrpc_scalar_print(val->v_scalar, level+2); break; case xr_struct: os = xmlrpc_print_struct(val->v_struct, level+2); break; case xr_array: os = xmlrpc_print_array(val->v_array, level+2); break; default: return NULL; } if (os != NULL) { body = octstr_format("%*s\n%S%*s\n", level, "", os, level, ""); octstr_destroy(os); } return body; } /*------------------------------------- * XMLRPCScalar */ /* Create new scalar of given type with given argument */ XMLRPCScalar *xmlrpc_scalar_create(int type, void *arg) { XMLRPCScalar *scalar = gw_malloc(sizeof(XMLRPCScalar)); scalar->s_type = type; scalar->s_int = 0; scalar->s_bool = 0; scalar->s_double = 0.0; scalar->s_str = NULL; scalar->s_date = NULL; scalar->s_base64 = NULL; if (arg == NULL) { #ifdef XR_ENABLE_EMPTY_STRING_VALUES if (scalar->s_type != xr_string) { #endif error(0,"XML-RPC: scalar value may not be null!"); xmlrpc_scalar_destroy(scalar); return NULL; #ifdef XR_ENABLE_EMPTY_STRING_VALUES } #endif } switch (type) { case xr_int: if (arg != NULL) scalar->s_int = *(long*)arg; break; case xr_bool: if (arg != NULL) scalar->s_bool = *(int*)arg; break; case xr_double: if (arg != NULL) scalar->s_double = *(double*)arg; break; case xr_string: scalar->s_str = octstr_duplicate((Octstr *)arg); break; case xr_date: scalar->s_date = octstr_duplicate((Octstr *)arg); break; case xr_base64: scalar->s_base64 = octstr_duplicate((Octstr *)arg); break; default: error(0,"XML-RPC: scalar type not supported!"); xmlrpc_scalar_destroy(scalar); return NULL; } return scalar; } /* Destroy scalar */ void xmlrpc_scalar_destroy(XMLRPCScalar *scalar) { if (scalar == NULL) return; octstr_destroy(scalar->s_str); octstr_destroy(scalar->s_date); octstr_destroy(scalar->s_base64); gw_free(scalar); } int xmlrpc_scalar_get_type(XMLRPCScalar *scalar) { if (scalar == NULL) return -1; return scalar->s_type; } void *xmlrpc_scalar_get_content(XMLRPCScalar *scalar, int s_type) { if (scalar == NULL) return NULL; if (scalar->s_type != s_type) { error(0, "XMLRPC: Scalar content request with bogus type"); return NULL; } switch (scalar->s_type) { case xr_int: return &(scalar->s_int); case xr_bool: return &(scalar->s_bool); case xr_double: return &(scalar->s_double); case xr_string: return scalar->s_str; case xr_date: return scalar->s_date; case xr_base64: return scalar->s_base64; default: error(0,"XML-RPC: scalar type not supported!"); return NULL; } } Octstr *xmlrpc_scalar_print(XMLRPCScalar *scalar, int level) { Octstr *os = NULL; if (scalar == NULL) return NULL; switch (scalar->s_type) { case xr_int: os = octstr_format("%*s%ld\n", level, "", scalar->s_int); break; case xr_bool: os = octstr_format("%*s%d\n", level, "", scalar->s_bool); break; case xr_double: os = octstr_format("%*s%d\n", level, "", scalar->s_double); break; case xr_string: if (scalar->s_str == NULL) { #ifdef XR_ENABLE_EMPTY_STRING_VALUES os = octstr_format("%*s\n", level, ""); #endif } else { Octstr *tmp = octstr_duplicate(scalar->s_str); octstr_convert_to_html_entities(tmp); os = octstr_format("%*s%S\n", level, "", tmp); octstr_destroy(tmp); } break; case xr_date: os = octstr_format("%*s%S\n", level, "", scalar->s_date); break; case xr_base64: os = octstr_format("%*s%S\n", level, "", scalar->s_base64); break; } return os; } /*------------------------------------- * XMLRPCMember - internal functions */ /* Create new member with undefined name and value */ static XMLRPCMember *xmlrpc_member_create(void) { XMLRPCMember *member = gw_malloc(sizeof(XMLRPCMember)); member->name = NULL; member->value = NULL; return member; } /* Destroy member and if destroy_value != 0 destroy its content */ static void xmlrpc_member_destroy(XMLRPCMember *member, int destroy_value) { if (member == NULL) return; octstr_destroy(member->name); if (destroy_value == 1) xmlrpc_value_destroy(member->value); gw_free(member); } /*------------------------------------------------- * Utilities to make things easier */ Octstr *xmlrpc_get_call_name(XMLRPCDocument *call) { if (call == NULL || call->methodcall == NULL) return NULL; return xmlrpc_call_get_name(call->methodcall); } /*** PARAMS HANDLING ***/ int xmlrpc_count_params(XMLRPCDocument *xrdoc) { if (xrdoc == NULL) return -1; if (xrdoc->d_type == xr_methodcall && xrdoc->methodcall != NULL) return gwlist_len(xrdoc->methodcall->params); else if (xrdoc->d_type == xr_methodresponse && xrdoc->methodresponse != NULL) return (xrdoc->methodresponse->param != NULL ? 1 : 0); return -1; } XMLRPCValue *xmlrpc_get_param(XMLRPCDocument *xrdoc, int i) { if (xrdoc == NULL) return NULL; if (xrdoc->d_type == xr_methodcall && xrdoc->methodcall != NULL) return gwlist_len(xrdoc->methodcall->params) > i ? gwlist_get(xrdoc->methodcall->params, i) : NULL; else if (xrdoc->d_type == xr_methodresponse && xrdoc->methodresponse != NULL && i == 0) return xrdoc->methodresponse->param; return NULL; } int xmlrpc_get_type_param(XMLRPCDocument *xrdoc, int i) { XMLRPCValue *param = xmlrpc_get_param(xrdoc, i); return xmlrpc_value_get_type(param); } void *xmlrpc_get_content_param(XMLRPCDocument *xrdoc, int i) { XMLRPCValue *param = xmlrpc_get_param(xrdoc, i); return xmlrpc_value_get_content(param); } /*** STRUCT VALUE HANDLING ***/ XMLRPCValue *xmlrpc_create_struct_value(int count_members) { XMLRPCValue *value = xmlrpc_value_create(); int len = (count_members > 0 ? count_members : OPTIMAL_STRUCT_SIZE); value->v_type = xr_struct; value->v_struct = dict_create(len, xmlrpc_value_destroy_item); return value; } long xmlrpc_count_members(XMLRPCValue *xrstruct) { if (xrstruct == NULL || xrstruct->v_type != xr_struct) return -1; return dict_key_count(xrstruct->v_struct); } int xmlrpc_add_member(XMLRPCValue *xrstruct, Octstr *name, XMLRPCValue *value) { if (xrstruct == NULL || xrstruct->v_type != xr_struct || name == NULL || value == NULL) return -1; return dict_put_once(xrstruct->v_struct, name, value); } int xmlrpc_add_member_scalar(XMLRPCValue *xrstruct, Octstr *name, int type, void *arg) { XMLRPCValue *value = xmlrpc_create_scalar_value(type, arg); int status; status = xmlrpc_add_member(xrstruct, name, value); if (status < 0) xmlrpc_value_destroy(value); return status; } XMLRPCValue *xmlrpc_get_member(XMLRPCValue *xrstruct, Octstr *name) { if (xrstruct == NULL || xrstruct->v_type != xr_struct || name == NULL) return NULL; return dict_get(xrstruct->v_struct, name); } int xmlrpc_get_member_type(XMLRPCValue *xrstruct, Octstr *name) { XMLRPCValue *value = xmlrpc_get_member(xrstruct, name); return xmlrpc_value_get_type(value); } void *xmlrpc_get_member_content(XMLRPCValue *xrstruct, Octstr *name) { XMLRPCValue *value = xmlrpc_get_member(xrstruct, name); return xmlrpc_value_get_content(value); } Octstr *xmlrpc_print_struct(Dict *v_struct, int level) { Octstr *body, *os_val, *key; List *keys; XMLRPCValue *member_val; if (v_struct == NULL || dict_key_count(v_struct) == 0) return NULL; keys = dict_keys(v_struct); body = octstr_format("%*s\n", level, ""); while ((key = gwlist_consume(keys)) != NULL) { member_val = dict_get(v_struct, key); os_val = xmlrpc_value_print(member_val, level+4); if (os_val == NULL) { gwlist_destroy(keys, octstr_destroy_item); octstr_destroy(key); octstr_destroy(body); return NULL; } octstr_format_append(body, "%*s\n" "%*s%S\n%S" "%*s\n", level+2, "", level+4, "", key, os_val, level+2, ""); octstr_destroy(key); octstr_destroy(os_val); } gwlist_destroy(keys, octstr_destroy_item); octstr_format_append(body, "%*s\n", level, ""); return body; } /*** ARRAY VALUE HANDLING ***/ XMLRPCValue *xmlrpc_create_array_value(void) { XMLRPCValue *value = xmlrpc_value_create(); value->v_type = xr_array; value->v_array = gwlist_create(); return value; } int xmlrpc_count_elements(XMLRPCValue *xrarray) { if (xrarray == NULL || xrarray->v_type != xr_array) return -1; return gwlist_len(xrarray->v_array); } int xmlrpc_add_element(XMLRPCValue *xrarray, XMLRPCValue *value) { if (xrarray == NULL || xrarray->v_type != xr_array || value == NULL) return -1; gwlist_produce(xrarray->v_array, value); return 1; } int xmlrpc_add_element_scalar(XMLRPCValue *xrarray, int type, void *arg) { XMLRPCValue *value = xmlrpc_create_scalar_value(type, arg); int status; status = xmlrpc_add_element(xrarray, value); if (status < 0) xmlrpc_value_destroy(value); return status; } XMLRPCValue *xmlrpc_get_element(XMLRPCValue *xrarray, int i) { if (xrarray == NULL || xrarray->v_type != xr_array || i < 0) return NULL; return gwlist_get(xrarray->v_array, i); } int xmlrpc_get_element_type(XMLRPCValue *xrarray, int i) { XMLRPCValue *value = xmlrpc_get_element(xrarray, i); return xmlrpc_value_get_type(value); } void *xmlrpc_get_element_content(XMLRPCValue *xrarray, int i) { XMLRPCValue *value = xmlrpc_get_element(xrarray, i); return xmlrpc_value_get_content(value); } Octstr *xmlrpc_print_array(List *v_array, int level) { Octstr *body, *os_element; XMLRPCValue *element = NULL; int i; if (v_array == NULL) return NULL; body = octstr_format("%*s\n%*s\n", level, "", level+2, ""); for(i = 0; i < gwlist_len(v_array); i++) { element = gwlist_get(v_array, i); os_element = xmlrpc_value_print(element, level+4); if (os_element == NULL) { octstr_destroy(body); return NULL; } octstr_append(body, os_element); octstr_destroy(os_element); } octstr_format_append(body, "%*s\n%*s\n", level+2, "", level, ""); return body; } /*** SCALAR VALUE HANDLING ***/ XMLRPCValue *xmlrpc_create_scalar_value(int type, void *arg) { XMLRPCValue *value = xmlrpc_value_create(); value->v_type = xr_scalar; value->v_scalar = xmlrpc_scalar_create(type, arg); return value; } XMLRPCValue *xmlrpc_create_double_value(double val) { return xmlrpc_create_scalar_value(xr_double, &val); } XMLRPCValue *xmlrpc_create_int_value(long val) { return xmlrpc_create_scalar_value(xr_int, &val); } XMLRPCValue *xmlrpc_create_string_value(Octstr *val) { return xmlrpc_create_scalar_value(xr_string, val); } /*** FAULT HANDLING ***/ int xmlrpc_is_fault(XMLRPCDocument *response) { if (response == NULL || response->d_type != xr_methodresponse) return 0; return xmlrpc_response_is_fault(response->methodresponse); } long xmlrpc_get_faultcode(XMLRPCDocument *faultresponse) { if (! xmlrpc_is_fault(faultresponse)) { error(0, "XMLRPC object is not fault response."); return -1; } return xmlrpc_response_get_faultcode(faultresponse->methodresponse); } Octstr *xmlrpc_get_faultstring(XMLRPCDocument *faultresponse) { if (! xmlrpc_is_fault(faultresponse)) { error(0, "XMLRPC object is not fault response."); return NULL; } return xmlrpc_response_get_faultstring(faultresponse->methodresponse); } /*** PARSE STATUS HANDLING***/ int xmlrpc_parse_status(XMLRPCDocument *xrdoc) { if (xrdoc == NULL) return -1; return xrdoc->parse_status; } Octstr *xmlrpc_parse_error(XMLRPCDocument *xrdoc) { if (xrdoc == NULL) return NULL; return octstr_duplicate(xrdoc->parse_error); } /*------------------------------------------------- * Internal parser functions */ static int parse_document(xmlDocPtr document, XMLRPCDocument *xrdoc) { xmlNodePtr node; Octstr *name; int n = 0, status = 0; node = xmlDocGetRootElement(document); /* * check if this is at least a valid root element */ if (node == NULL || node->name == NULL) { error(0, "XMLRPC: XML document - not valid root node!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } if ((xrdoc->d_type == xr_methodcall || xrdoc->d_type == xr_undefined) && octstr_case_compare(name, octstr_imm("METHODCALL")) == 0) { xrdoc->d_type = xr_methodcall; xrdoc->methodcall = xmlrpc_call_create(NULL); octstr_destroy(name); status = parse_methodcall(document, node->xmlChildrenNode, xrdoc, xrdoc->methodcall); if (status < 0) { xmlrpc_call_destroy(xrdoc->methodcall); xrdoc->methodcall = NULL; if (xrdoc->parse_status == XMLRPC_COMPILE_OK) { xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); } } else if ((xrdoc->methodcall->method_name) == NULL) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: tag expected!"); status = -1; } return status; } else if ((xrdoc->d_type == xr_methodresponse || xrdoc->d_type == xr_undefined) && octstr_case_compare(name, octstr_imm("METHODRESPONSE")) == 0) { xrdoc->d_type = xr_methodresponse; xrdoc->methodresponse = xmlrpc_response_create(); octstr_destroy(name); status = parse_methodresponse(document, node->xmlChildrenNode, xrdoc, xrdoc->methodresponse, &n); if (status < 0) { xmlrpc_response_destroy(xrdoc->methodresponse); xrdoc->methodresponse = NULL; } return status; } else { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: wrong root element <%s>, " "<%s> expected!", octstr_get_cstr(name), (xrdoc->d_type == xr_methodcall ? "methodCall" : "methodResponse")); octstr_destroy(name); return -1; } } static int parse_methodcall(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMethodCall *methodcall) { int status = 0; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_methodcall_element(doc, node, xrdoc, methodcall); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown XML node " "in the XML-RPC source."); return -1; break; } if (node->next != NULL) return parse_methodcall(doc, node->next, xrdoc, methodcall); return status; } static int parse_methodcall_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMethodCall *methodcall) { Octstr *name; xmlChar *content_buff; size_t i; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML methodcall element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_METHODCALL_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(methodcall_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_METHODCALL_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' in XML source " "at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * methodName [0] * params [1] */ if (i == 0) { /* this has been the tag */ if (methodcall->method_name == NULL) { /*only one tag allowed*/ content_buff = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (content_buff != NULL) { methodcall->method_name = octstr_create(content_buff); xmlFree(content_buff); } else { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: empty tag in XML source " "at level "); return -1; } } else { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: duplicated tag in XML source " "at level "); octstr_destroy(name); return -1; } } else { /* * ok, this has to be an tag, otherwise we would * have returned previosly */ return parse_params(doc, node->xmlChildrenNode, xrdoc, methodcall->params); } return 0; } static int parse_methodresponse(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMethodResponse *methodresponse, int* n) { int status = 0; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: if (*n > 0) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unexpected XML node <%s> " "in the XML-RPC source.", node->name); return -1; } status = parse_methodresponse_element(doc, node, xrdoc, methodresponse); (*n)++; break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown XML node " "in the XML-RPC source."); return -1; break; } if (node->next != NULL) { if (parse_methodresponse(doc, node->next, xrdoc, methodresponse, n) == -1) { return -1; } } return status; } static int parse_methodresponse_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMethodResponse *methodresponse) { Octstr *name; size_t i; int status; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML methodResponse element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_METHODRESPONSE_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(methodresponse_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_METHODRESPONSE_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' in XML source " "at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * fault [0] * params [1] */ if (i == 0) { /* this has been the tag */ methodresponse->fault = xmlrpc_fault_create(0, NULL); return parse_fault(doc, node->xmlChildrenNode, xrdoc, methodresponse->fault); } else { /* * ok, this has to be an tag, otherwise we would * have returned previosly */ List *params = gwlist_create();; status = parse_params(doc, node->xmlChildrenNode, xrdoc, params); if (status < 0) return -1; if (gwlist_len(params) != 1) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler:wrong number of params " "at level "); gwlist_destroy(params, xmlrpc_value_destroy_item); return -1; } methodresponse->param = gwlist_consume(params); gwlist_destroy(params, xmlrpc_value_destroy_item); return status; } } static int parse_params(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *params) { int status = 0; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_params_element(doc, node, xrdoc, params); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown XML node in XML-RPC source."); return -1; break; } if (node->next != NULL) if (parse_params(doc, node->next, xrdoc, params) == -1) return -1; return status; } static int parse_params_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *params) { Octstr *name; size_t i; int n = 0; /* * check if the element is allowed at this level * within we only have one or more */ if (node->name == NULL) { error(0, "XMLRPC: XML params element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_PARAMS_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(params_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_PARAMS_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' " "in XML source at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * param [0] */ if (i == 0) { /* this has been a tag */ if (parse_param(doc, node->xmlChildrenNode, xrdoc, params, &n) == -1) return -1; } else { /* we should never be here */ xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bogus parsing exception in parse_params!"); return -1; } return 0; } static int parse_param(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *params, int *n) { int status = 0; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: /* a can only have one value element type */ if ((*n) > 0) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: param may only have one value!"); return -1; } status = parse_param_element(doc, node, xrdoc, params); (*n)++; break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: Unknown XML node in the XML-RPC source."); return -1; break; } if (node->next != NULL) if (parse_param(doc, node->next, xrdoc, params, n) == -1) return -1; return status; } static int parse_param_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *params) { Octstr *name; size_t i; XMLRPCValue *value; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML param element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_PARAM_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(param_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_PARAM_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' " "in XML source at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * value [0] */ if (i == 0) { /* this has been a tag */ value = xmlrpc_value_create(); if (parse_value(doc, node->xmlChildrenNode, xrdoc, value) == -1) { xmlrpc_value_destroy(value); return -1; } gwlist_append(params, value); } else { /* we should never be here */ xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bogus parsing exception in parse_param!"); return -1; } return 0; } static int parse_value(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCValue *value) { int status = 0; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_value_element(doc, node, xrdoc, value); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: Unknown XML node in the XML-RPC source."); return -1; break; } if (node->next != NULL) if (parse_value(doc, node->next, xrdoc, value) == -1) return -1; return status; } static int parse_value_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCValue *xrvalue) { Octstr *name; Octstr *value = NULL; xmlChar *content_buff; long lval = 0; double dval = 0.0; size_t i; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML value element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_VALUE_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(value_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_VALUE_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' " "in XML source at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); content_buff = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (content_buff != NULL) { value = octstr_create(content_buff); xmlFree(content_buff); } /* * now check which type it is and process * * valid tags at this level are: * i4, int * boolean * string * double * dateTime.iso8601 * base64 * struct * array */ switch (value_elements[i].s_type) { /* * scalar types */ case xr_int: case xr_bool: case xr_double: case xr_date: case xr_base64: #ifndef XR_ENABLE_EMPTY_STRING_VALUES case xr_string: #endif if (value == NULL) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: no value for '%s'", node->name); return -1; } break; } switch (value_elements[i].s_type) { /* * scalar types */ case xr_int: if (value != NULL && octstr_parse_long(&lval, value, 0, 10) < 0) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: could not parse int value '%s'", octstr_get_cstr(value)); octstr_destroy(value); return -1; } xrvalue->v_type = xr_scalar; xrvalue->v_scalar = xmlrpc_scalar_create(xr_int, (void *) &lval); break; case xr_bool: if (value != NULL && octstr_parse_long(&lval, value, 0, 10) < 0) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: could not parse boolean value '%s'", octstr_get_cstr(value)); octstr_destroy(value); return -1; } xrvalue->v_type = xr_scalar; xrvalue->v_scalar = xmlrpc_scalar_create(xr_bool, (void *) &lval); break; case xr_double: if (value != NULL && octstr_parse_double(&dval, value, 0) < 0) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: could not parse double value '%s'", octstr_get_cstr(value)); octstr_destroy(value); return -1; } xrvalue->v_type = xr_scalar; xrvalue->v_scalar = xmlrpc_scalar_create(xr_double, (void *) &dval); break; case xr_string: xrvalue->v_type = xr_scalar; xrvalue->v_scalar = xmlrpc_scalar_create(xr_string, (void *) value); break; case xr_date: xrvalue->v_type = xr_scalar; xrvalue->v_scalar = xmlrpc_scalar_create(xr_date, (void *) value); break; case xr_base64: xrvalue->v_type = xr_scalar; xrvalue->v_scalar = xmlrpc_scalar_create(xr_base64, (void *) value); break; case xr_struct: xrvalue->v_type = xr_struct; xrvalue->v_struct = dict_create(OPTIMAL_STRUCT_SIZE, xmlrpc_value_destroy_item); if (parse_struct(doc, node->xmlChildrenNode, xrdoc, xrvalue->v_struct) == -1) { octstr_destroy(value); return -1; } break; case xr_array: xrvalue->v_type = xr_array; xrvalue->v_array = gwlist_create(); if (parse_array(doc, node->xmlChildrenNode, xrdoc, xrvalue->v_array) == -1) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: could not parse array"); octstr_destroy(value); return -1; } break; default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bogus parsing exception in parse_value!"); return -1; } octstr_destroy(value); return 0; } static int parse_struct(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, Dict *members) { int status = 0; if (node == NULL) return -1; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_struct_element(doc, node, xrdoc, members); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: Unknown XML node in the XML-RPC source."); return -1; break; } if (node->next != NULL) if (parse_struct(doc, node->next, xrdoc, members) == -1) return -1; return status; } static int parse_struct_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, Dict *members) { Octstr *name; size_t i; XMLRPCMember *member; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML struct element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_STRUCT_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(struct_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_STRUCT_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' " "in XML source at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * member [0] */ if (i == 0) { /* this has been a tag */ member = xmlrpc_member_create(); if (parse_member(doc, node->xmlChildrenNode, xrdoc, member) == -1) { xmlrpc_member_destroy(member, 1); return -1; } if (! dict_put_once(members, member->name, member->value)) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: at least two members have same name."); xmlrpc_member_destroy(member, 1); return -1; } xmlrpc_member_destroy(member, 0); } else { /* we should never be here */ xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bogus parsing exception in parse_struct!"); return -1; } return 0; } static int parse_member(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMember *member) { int status = 0; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_member_element(doc, node, xrdoc, member); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: Unknown XML node in the XML-RPC source."); return -1; break; } if (node->next != NULL) if (parse_member(doc, node->next, xrdoc, member) == -1) return -1; return status; } static int parse_member_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCMember *member) { Octstr *name; xmlChar *content_buff; size_t i; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML member element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create((const char*)node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_MEMBER_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(member_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_MEMBER_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' " "in XML source at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * name [0] * value [1] */ if (i == 0) { /* this has been a tag */ if (member->name != NULL) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: duplicated tag '' " "in XML source at level "); return -1; } content_buff = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); if (content_buff != NULL) { member->name = octstr_create((const char*)content_buff); xmlFree(content_buff); } else { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: empty tag in XML source " "at level "); return -1; } } else { member->value = xmlrpc_value_create(); if (parse_value(doc, node->xmlChildrenNode, xrdoc, member->value) == -1) { xmlrpc_value_destroy(member->value); member->value = NULL; return -1; } } return 0; } static int parse_array(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *elements) { int status = 0; if (node == NULL) return -1; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_array_element(doc, node, xrdoc, elements); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: Unknown XML node in the XML-RPC source."); return -1; break; } if (node->next != NULL) if (parse_array(doc, node->next, xrdoc, elements) == -1) return -1; return status; } static int parse_array_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *elements) { Octstr *name; size_t i; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML array element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_ARRAY_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(array_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_ARRAY_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' " "in XML source at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * data [0] */ if (i == 0) { /* this has been a tag */ if (parse_data(doc, node->xmlChildrenNode, xrdoc, elements) == -1) return -1; } else { /* we should never be here */ xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bogus parsing exception in parse_array!"); return -1; } return 0; } static int parse_data(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *elements) { int status = 0; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_data_element(doc, node, xrdoc, elements); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: Unknown XML node in the XML-RPC source."); return -1; break; } if (node->next != NULL) if (parse_data(doc, node->next, xrdoc, elements) == -1) return -1; return status; } static int parse_data_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, List *elements) { Octstr *name; XMLRPCValue *value; size_t i; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML data element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_DATA_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(data_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_DATA_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' " "in XML source at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * value [0] */ if (i == 0) { /* this has been a tag */ value = xmlrpc_value_create(); if (parse_value(doc, node->xmlChildrenNode, xrdoc, value) == -1) { xmlrpc_value_destroy(value); return -1; } gwlist_append(elements, value); } else { /* we should never be here */ xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bogus parsing exception in parse_array!"); return -1; } return 0; } static int parse_fault(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCFault *fault) { int status = 0; /* call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_fault_element(doc, node, xrdoc, fault); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * XML-RPC. Therefore they are assumed to be an error. */ default: xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: Unknown XML node in the XML-RPC source."); return -1; break; } if (node->next != NULL) if (parse_fault(doc, node->next, xrdoc, fault) == -1) return -1; return status; } static int parse_fault_element(xmlDocPtr doc, xmlNodePtr node, XMLRPCDocument *xrdoc, XMLRPCFault *fault) { Octstr *name; XMLRPCValue *value, *v_code, *v_string; size_t i; /* * check if the element is allowed at this level */ if (node->name == NULL) { error(0, "XMLRPC: XML fault element nodes without name!"); xrdoc->parse_status = XMLRPC_XMLPARSE_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bad XML"); return -1; } name = octstr_create(node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_FAULT_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(fault_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_FAULT_ELEMENTS) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: unknown tag '%s' " "in XML source at level ", octstr_get_cstr(name)); octstr_destroy(name); return -1; } octstr_destroy(name); /* * now check which type it is and process * * valid tags at this level are: * value [0] */ if (i == 0) { /* this has been a tag */ value = xmlrpc_value_create(); if (parse_value(doc, node->xmlChildrenNode, xrdoc, value) == -1) { xmlrpc_value_destroy(value); return -1; } /* must be : * * * faultCode * ... * * * faultString * ... * * */ if (xmlrpc_value_get_type(value) != xr_struct || (v_code = xmlrpc_get_member(value, octstr_imm("faultCode"))) == NULL || xmlrpc_value_get_type_smart(v_code) != xr_int || (v_string = xmlrpc_get_member(value, octstr_imm("faultString"))) == NULL || xmlrpc_value_get_type_smart(v_string) != xr_string || xmlrpc_count_members(value) != 2) { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: bogus value " "in XML source at level "); xmlrpc_value_destroy(value); return -1; } fault->f_code = xmlrpc_scalar_get_int((XMLRPCScalar *) xmlrpc_value_get_content(v_code)); fault->f_string = xmlrpc_scalar_get_string((XMLRPCScalar *) xmlrpc_value_get_content(v_string)); xmlrpc_value_destroy(value); } else { xrdoc->parse_status = XMLRPC_PARSING_FAILED; xrdoc->parse_error = octstr_format("XML-RPC compiler: duplicated tag '' " "in XML source at level "); return -1; } return 0; } gateway-1.4.5/gwlib/ssl.c0000644000175000017500000000744413227613126013751 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * ssl.c - implements SSL specific routines and types * * This file implements the secure socket layer (SSL) specific * routines and types. * * This product includes software developed by Ralf S. Engelschall * for use in the mod_ssl project * (http://www.modssl.org/). * * Stipe Tolj * for Kannel Project and Wapme Systems AG */ #include "gwlib/gwlib.h" #ifdef HAVE_LIBSSL #include int SSL_smart_shutdown(SSL *ssl) { int i; int rc; /* * Repeat the calls, because SSL_shutdown internally dispatches through a * little state machine. Usually only one or two interation should be * needed, so we restrict the total number of restrictions in order to * avoid process hangs in case the client played bad with the socket * connection and OpenSSL cannot recognize it. */ rc = 0; for (i = 0; i < 4 /* max 2x pending + 2x data = 4 */; i++) { if ((rc = SSL_shutdown(ssl))) break; } return rc; } #endif /* HAVE_LIBSSL */ gateway-1.4.5/gwlib/dict.h0000644000175000017500000001307313227613126014073 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dict.h - lookup data structure using octet strings as keys * * A Dict is an abstract data structure that stores values, represented as * void pointers, and uses octet strings (Octstr) as keys. You can think * of it as an array indexed by octet strings. * * Lars Wirzenius */ #ifndef DICT_H #define DICT_H typedef struct Dict Dict; /* * Create a Dict. `size_hint' gives an indication of how many different * keys will be in the Dict at the same time, at most. This is used for * performance optimization; things will work fine, though somewhat * slower, even if it the number is exceeded. `destroy_value' is a pointer * to a function that is called whenever a value stored in the Dict needs * to be destroyed. If `destroy_value' is NULL, then values are not * destroyed by the Dict, they are just discarded. */ Dict *dict_create(long size_hint, void (*destroy_value)(void *)); /* * Destroy a Dict and all values in it. */ void dict_destroy(Dict *dict); /* * Put a new value into a Dict. If the same key existed already, the * old value is destroyed. If `value' is NULL, the old value is destroyed * and the key is removed from the Dict. */ void dict_put(Dict *dict, Octstr *key, void *value); /* * Put a new value into a Dict. Return error, if the same key existed all- * ready. */ int dict_put_once(Dict *dict, Octstr *key, void *value); /* * Look up a value in a Dict. If there is no value corresponding to a * key, return NULL, otherwise return the value. The value will not * be removed from the Dict. */ void *dict_get(Dict *dict, Octstr *key); /* * Remove a value from a Dict without destroying it. */ void *dict_remove(Dict *dict, Octstr *key); /* * Return the number of keys which currently exist in the Dict. */ long dict_key_count(Dict *dict); /* * Return a list of all the currently defined keys in the Dict. The * caller must destroy the list. */ List *dict_keys(Dict *dict); /* * Return a Dict with the duplicate entries, by using the duplicate_value() * function callback to duplicate the value entries. */ Dict *dict_duplicate(Dict *dict, void *(*duplicate_value)(void *)); /* * Traverse to all elements of a Dict, and execute the passed callback * function with the key as first argument, a void pointer as data argument * and a user defined pointer that is passed along all calls to func. * Returns the number of Dict elements that have been traversed. */ long dict_traverse(Dict *dict, void (*func)(Octstr *, void *, void *), void *data); /* * Same as dict_traverse(), but ensures that the elements are sorted before * the traversal. The sorting is done via quick sort, applied via a compare * callback function that compares 2 elements of the overall elements list. */ long dict_traverse_sorted(Dict *dict, int (*cmp)(const void *, const void *), void (*func)(Octstr *, void *, void *), void *data); #endif gateway-1.4.5/gwlib/pcre.c0000644000175000017500000001357313227613126014101 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * pcre.c - Perl compatible regular expressions (PCREs) * * This modules implements wrapper functions to the pcre_foobar() et all * functions implemented in the libpcre.a library. * PCRE is a library of functions to support regular expressions whose syntax * and semantics are as close as possible to those of the Perl 5 language. * * See http://www.pcre.org/ for more details on PCRE regular expressions. * * Stipe Tolj */ #include #include "gwlib/gwlib.h" #include "pcre.h" #ifdef HAVE_PCRE /******************************************************************** * Generic pcre functions. */ pcre *gw_pcre_comp_real(const Octstr *pattern, int cflags, const char *file, long line, const char *func) { pcre *preg; const char *err; const char *pat; int erroffset; pat = pattern ? octstr_get_cstr(pattern) : NULL; if ((preg = pcre_compile(pat, cflags, &err, &erroffset, NULL)) == NULL) { error(0, "%s:%ld: %s: pcre compilation `%s' failed at offset %d: %s " "(Called from %s:%ld:%s.)", __FILE__, (long) __LINE__, __func__, octstr_get_cstr(pattern), erroffset, err, (file), (long) (line), (func)); } return preg; } int gw_pcre_exec_real(const pcre *preg, const Octstr *string, int start, int eflags, int *ovector, int oveccount, const char *file, long line, const char *func) { int rc; char *sub; gw_assert(preg != NULL); sub = string ? octstr_get_cstr(string) : NULL; rc = pcre_exec(preg, NULL, sub, octstr_len(string), start, eflags, ovector, oveccount); if (rc < 0 && rc != PCRE_ERROR_NOMATCH) { error(0, "%s:%ld: %s: pcre execution on `%s' failed with error %d " "(Called from %s:%ld:%s.)", __FILE__, (long) __LINE__, __func__, octstr_get_cstr(string), rc, (file), (long) (line), (func)); } return rc; } /******************************************************************** * Matching wrapper functions. * * Beware that the regex compilation takes the most significant CPU time, * so always try to have pre-compiled regular expressions that keep being * reused and re-matched on variable string patterns. */ int gw_pcre_match_real(const Octstr *re, const Octstr *os, const char *file, long line, const char *func) { pcre *regexp; int rc; int ovector[PCRE_OVECCOUNT]; /* compile */ regexp = gw_pcre_comp_real(re, 0, file, line, func); if (regexp == NULL) return 0; /* execute and match */ rc = gw_pcre_exec_real(regexp, os, 0, 0, ovector, PCRE_OVECCOUNT, file, line, func); return (rc > 0) ? 1 : 0; } int gw_pcre_match_pre_real(const pcre *preg, const Octstr *os, const char *file, long line, const char *func) { int rc; int ovector[PCRE_OVECCOUNT]; gw_assert(preg != NULL); /* execute and match */ rc = gw_pcre_exec_real(preg, os, 0, 0, ovector, PCRE_OVECCOUNT, file, line, func); return (rc > 0) ? 1 : 0; } #endif /* HAVE_PCRE */ gateway-1.4.5/gwlib/gw-prioqueue.c0000644000175000017500000002175213227613126015577 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw-prioqueue.c - generic priority queue with guaranteed order. * * Algorithm ala Robert Sedgewick. * * Alexander Malysh , 2004, 2008 */ #include "gw-config.h" #include #include "thread.h" #include "gwmem.h" #include "gwassert.h" #include "gwthread.h" #include "gw-prioqueue.h" struct element { void *item; long long seq; }; struct gw_prioqueue { Mutex *mutex; struct element **tab; size_t size; long len; long producers; long long seq; pthread_cond_t nonempty; int (*cmp)(const void*, const void *); }; static void inline queue_lock(gw_prioqueue_t *queue) { mutex_lock(queue->mutex); } static void inline queue_unlock(gw_prioqueue_t *queue) { mutex_unlock(queue->mutex); } static void make_bigger(gw_prioqueue_t *queue, long items) { size_t size = queue->size; size_t new_size = sizeof(*queue->tab) * (queue->len + items); if (size >= new_size) return; queue->tab = gw_realloc(queue->tab, new_size); queue->size = new_size; } static int compare(struct element *a, struct element *b, int(*cmp)(const void*, const void *)) { int rc; rc = cmp(a->item, b->item); if (rc == 0) { /* check sequence to guarantee order */ if (a->seq < b->seq) rc = 1; else if (a->seq > b->seq) rc = -1; } return rc; } /** * Heapize up * @queue - our prioqueue + @index - start index */ static void upheap(gw_prioqueue_t *queue, register long index) { struct element *v = queue->tab[index]; while (queue->tab[index / 2]->item != NULL && compare(queue->tab[index / 2], v, queue->cmp) < 0) { queue->tab[index] = queue->tab[index / 2]; index /= 2; } queue->tab[index] = v; } /** * Heapize down * @queue - our prioqueue * @index - start index */ static void downheap(gw_prioqueue_t *queue, register long index) { struct element *v = queue->tab[index]; register long j; while (index <= queue->len / 2) { j = 2 * index; /* take the biggest child item */ if (j < queue->len && compare(queue->tab[j], queue->tab[j + 1], queue->cmp) < 0) j++; /* break if our item bigger */ if (compare(v, queue->tab[j], queue->cmp) >= 0) break; queue->tab[index] = queue->tab[j]; index = j; } queue->tab[index] = v; } gw_prioqueue_t *gw_prioqueue_create(int(*cmp)(const void*, const void *)) { gw_prioqueue_t *ret; gw_assert(cmp != NULL); ret = gw_malloc(sizeof(*ret)); ret->producers = 0; pthread_cond_init(&ret->nonempty, NULL); ret->mutex = mutex_create(); ret->tab = NULL; ret->size = 0; ret->len = 0; ret->seq = 0; ret->cmp = cmp; /* put NULL item at pos 0 that is our stop marker */ make_bigger(ret, 1); ret->tab[0] = gw_malloc(sizeof(**ret->tab)); ret->tab[0]->item = NULL; ret->tab[0]->seq = ret->seq++; ret->len++; return ret; } void gw_prioqueue_destroy(gw_prioqueue_t *queue, void(*item_destroy)(void*)) { long i; if (queue == NULL) return; for (i = 0; i < queue->len; i++) { if (item_destroy != NULL && queue->tab[i]->item != NULL) item_destroy(queue->tab[i]->item); gw_free(queue->tab[i]); } mutex_destroy(queue->mutex); pthread_cond_destroy(&queue->nonempty); gw_free(queue->tab); gw_free(queue); } long gw_prioqueue_len(gw_prioqueue_t *queue) { long len; if (queue == NULL) return 0; queue_lock(queue); len = queue->len - 1; queue_unlock(queue); return len; } void gw_prioqueue_insert(gw_prioqueue_t *queue, void *item) { gw_assert(queue != NULL); gw_assert(item != NULL); queue_lock(queue); make_bigger(queue, 1); queue->tab[queue->len] = gw_malloc(sizeof(**queue->tab)); queue->tab[queue->len]->item = item; queue->tab[queue->len]->seq = queue->seq++; upheap(queue, queue->len); queue->len++; pthread_cond_signal(&queue->nonempty); queue_unlock(queue); } void gw_prioqueue_foreach(gw_prioqueue_t *queue, void(*fn)(const void *, long)) { register long i; gw_assert(queue != NULL && fn != NULL); queue_lock(queue); for (i = 1; i < queue->len; i++) fn(queue->tab[i]->item, i - 1); queue_unlock(queue); } void *gw_prioqueue_remove(gw_prioqueue_t *queue) { void *ret; gw_assert(queue != NULL); queue_lock(queue); if (queue->len <= 1) { queue_unlock(queue); return NULL; } ret = queue->tab[1]->item; gw_free(queue->tab[1]); queue->tab[1] = queue->tab[--queue->len]; downheap(queue, 1); queue_unlock(queue); return ret; } void *gw_prioqueue_get(gw_prioqueue_t *queue) { void *ret; gw_assert(queue != NULL); queue_lock(queue); if (queue->len > 1) ret = queue->tab[1]->item; else ret = NULL; queue_unlock(queue); return ret; } void *gw_prioqueue_consume(gw_prioqueue_t *queue) { void *ret; gw_assert(queue != NULL); queue_lock(queue); while (queue->len == 1 && queue->producers > 0) { queue->mutex->owner = -1; pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &queue->mutex->mutex); pthread_cond_wait(&queue->nonempty, &queue->mutex->mutex); pthread_cleanup_pop(0); queue->mutex->owner = gwthread_self(); } if (queue->len > 1) { ret = queue->tab[1]->item; gw_free(queue->tab[1]); queue->tab[1] = queue->tab[--queue->len]; downheap(queue, 1); } else { ret = NULL; } queue_unlock(queue); return ret; } void gw_prioqueue_add_producer(gw_prioqueue_t *queue) { gw_assert(queue != NULL); queue_lock(queue); queue->producers++; queue_unlock(queue); } void gw_prioqueue_remove_producer(gw_prioqueue_t *queue) { gw_assert(queue != NULL); queue_lock(queue); gw_assert(queue->producers > 0); queue->producers--; pthread_cond_broadcast(&queue->nonempty); queue_unlock(queue); } long gw_prioqueue_producer_count(gw_prioqueue_t *queue) { long ret; gw_assert(queue != NULL); queue_lock(queue); ret = queue->producers; queue_unlock(queue); return ret; } gateway-1.4.5/gwlib/pki.h0000644000175000017500000000622013227613126013727 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef PKI_H #define PKI_H #include "gwlib.h" #include /* pki.c /pki.h contain an interface to openssl to read and manipulate various encryption and certificate functions */ void pki_init(void); void pki_shutdown(void); void get_cert_from_file(Octstr *s, X509 **x509); void get_privkey_from_file(Octstr *s, RSA **priv_key, Octstr *password); void dump_cert(X509 *x509); void dump_privkey(RSA *priv_key); #endif /* PKI_H */ gateway-1.4.5/gwlib/utils.h0000644000175000017500000001703013227613126014305 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * utils.c - generally useful, non-application specific functions for Gateway * * Kalle Marjola */ #ifndef GW_UTILS_H #define GW_UTILS_H #include #include #include "octstr.h" #include /* * Octet and MultibyteInteger (variable length) functions */ typedef unsigned char Octet; /* 8-bit basic data */ typedef unsigned long MultibyteInt; /* limited to 32 bits, not 35 */ /* get value of a multibyte ineteger. Note that it MUST be a valid * numbers, otherwise an overflow may occur as the function keeps * on reading the number until continue-bit (high bit) is not set. * Does not fail, always returns some number, but may overflow. */ MultibyteInt get_variable_value(Octet *source, int *len); /* write given multibyte integer into given destination string, which * must be large enough to handle the number (5 bytes is always sufficient) * returns the total length of the written number, in bytes. Does not fail */ int write_variable_value(MultibyteInt value, Octet *dest); /* reverse the value of an octet */ Octet reverse_octet(Octet source); /* parse command line arguments and set options for the following * global arguments: * * -v or --verbosity * -D or --debug * -F or --logfile * -V or --fileverbosity * -X or --panic-script * -P or --parachute * -d or --daemonize * -p or --pid-file * -u or --user * -g or --generate * * Any other argument starting with '-' calls 'find_own' function, * which is provided by the user. If set to NULL, these are ignored * (but error message is put into stderr) * * Returns index of next argument after any parsing * * Function 'find_own' has following parameters: * index is the current index in argv * argc and argv are command line parameters, directly transfered * * the function returns any extra number of parameters needed to be * skipped. It must personally deal with any malformed arguments. * It return -1 if it cannot find match for the argument * * sample simple function is like: * int find_is_there_X(int i, int argc, char **argv) * { if (strcmp(argv[i], "-X")==0) return 0; else return -1; } */ int get_and_set_debugs(int argc, char **argv, int (*find_own) (int index, int argc, char **argv)); /* * return 0 if 'ip' is denied by deny_ip and not allowed by allow_ip * return 1 otherwise (deny_ip is NULL or 'ip' is in allow_ip or is not * in deny_ip) * return -1 on error ('ip' is NULL) */ int is_allowed_ip(Octstr *allow_ip, Octstr *deny_ip, Octstr *ip); /* * Return 1 if 'ip' is not allowed to connect, when 'allow_ip' defines * allowed hosts, and 0 if connect ok. If 'allow_ip' is NULL, check against * "127.0.0.1" (localhost) */ int connect_denied(Octstr *allow_ip, Octstr *ip); /* * Checks if a given prefix list seperated with semicolon does match * a given number. * * This is mainly used for the allowed-prefix, denied-prefix configuration * directives. */ int does_prefix_match(Octstr *prefix, Octstr *number); /* * Normalize 'number', like change number "040500" to "0035840500" if * the dial-prefix is like "0035840,040;0035850,050" * * return -1 on error, 0 if no match in dial_prefixes and 1 if match found * If the 'number' needs normalization, it is done. */ int normalize_number(char *dial_prefixes, Octstr **number); /* * Convert a standard "network long" (32 bits in 4 octets, most significant * octet first) to the host representation. */ long decode_network_long(unsigned char *data); /* * Convert a long to the standard network representation (32 bits in 4 * octets, most significant octet first). */ void encode_network_long(unsigned char *data, unsigned long value); /* kannel implementation of cfmakeraw, which is an extension in GNU libc */ void kannel_cfmakeraw (struct termios *tio); /* * Wrappers around the isdigit and isxdigit functions that are guaranteed * to be functions, not macros. (The standard library functions are also * guaranteed by the C standard to be functions, in addition to possibly * also being macros, but not all implementations follow the standard.) */ int gw_isdigit(int); int gw_isxdigit(int); /* * Rounds up the result of a division */ int roundup_div(int a, int b); /* * generate a unique id * (not guarenteed to be unique, but it's extremly unlikely for it not to be) */ unsigned long long gw_generate_id(void); /** * Install fatal signal handler. Usefull to receive backtrace if * program crash with SEGFAULT. */ void init_fatal_signals(void); /* * Return an octet string with information about Kannel version, * operating system, and libxml version. The caller must take care to * destroy the string when done. */ Octstr *version_report_string(const char *boxname); /* * Output the information returned by version_report_string to the log * files. */ void report_versions(const char *boxname); #endif gateway-1.4.5/gwlib/semaphore.c0000644000175000017500000001114413227613126015123 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * semaphore.c - implementation of semaphores * * Lars Wirzenius * Alexander Malysh , 2004 */ #include "gwlib/gwlib.h" #ifdef HAVE_SEMAPHORE #include #include #endif struct Semaphore { #ifdef HAVE_SEMAPHORE sem_t sem; #else List *list; #endif }; Semaphore *semaphore_create(long n) { Semaphore *semaphore; #ifndef HAVE_SEMAPHORE static char item; #endif semaphore = gw_malloc(sizeof(*semaphore)); #ifdef HAVE_SEMAPHORE if (sem_init(&semaphore->sem, 0, (unsigned int) n) != 0) panic(errno, "Could not initialize semaphore."); #else semaphore->list = gwlist_create(); gwlist_add_producer(semaphore->list); while (n-- > 0) gwlist_produce(semaphore->list, &item); #endif return semaphore; } void semaphore_destroy(Semaphore *semaphore) { if (semaphore != NULL) { #ifdef HAVE_SEMAPHORE if (sem_destroy(&semaphore->sem) != 0) panic(errno, "Destroying semaphore while some threads are waiting."); #else gwlist_destroy(semaphore->list, NULL); #endif gw_free(semaphore); } } void semaphore_up(Semaphore *semaphore) { #ifndef HAVE_SEMAPHORE static char item; gw_assert(semaphore != NULL); gwlist_produce(semaphore->list, &item); #else gw_assert(semaphore != NULL); if (sem_post(&semaphore->sem) != 0) error(errno, "Value for semaphore is out of range."); #endif } void semaphore_down(Semaphore *semaphore) { gw_assert(semaphore != NULL); #ifdef HAVE_SEMAPHORE sem_wait(&semaphore->sem); #else gwlist_consume(semaphore->list); #endif } long semaphore_getvalue(Semaphore *semaphore) { gw_assert(semaphore != NULL); #ifdef HAVE_SEMAPHORE { int val; if (sem_getvalue(&semaphore->sem, &val) != 0) panic(errno, "Could not get semaphore value."); return val; } #else return gwlist_len(semaphore->list); #endif } gateway-1.4.5/gwlib/xmlrpc.h0000644000175000017500000004515013227613126014456 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * xmlrpc.h - XML-RPC functions * * Functions to handle XML-RPC structure - building and parsing * * XML-RPC is HTTP-based XML defination to handle remote procedure calls, * and is defined in http://www.xml-rpc.org * * The current implementation is not yet ready (it does not, for example, * do any parsing nor building the tree), and is not used for any real use, * yet, but probably future interfaces might be able to use this, too * * * Kalle Marjola 2001 for project Kannel * Robert Ga³ach */ #ifndef __XMLRPC_H #define __XMLRPC_H #include "gwlib/gwlib.h" /* * types and structures defined by www.xml-rpc.com */ typedef struct xmlrpc_document XMLRPCDocument; typedef struct xmlrpc_value XMLRPCValue; typedef struct xmlrpc_scalar XMLRPCScalar; enum { xr_undefined, xr_scalar, xr_array, xr_struct, xr_string, xr_int, xr_bool, xr_double, xr_date, xr_base64, xr_methodcall, xr_methodresponse }; /* * status codes while parsing */ enum { XMLRPC_COMPILE_OK, XMLRPC_XMLPARSE_FAILED, XMLRPC_PARSING_FAILED }; /*** DOCUMENTS ***/ /* Create new XMLRPCDocument object of undefined_type */ XMLRPCDocument *xmlrpc_doc_create(void); /* Create new MethodCall with given name */ XMLRPCDocument *xmlrpc_doc_create_call(Octstr *name); /* Create new MethodResponse */ XMLRPCDocument *xmlrpc_doc_create_response(void); /* Create new fault MethodResponse with given code and fault string */ XMLRPCDocument *xmlrpc_doc_create_faultresponse(long faultcode, Octstr *faultstring); /* Create new XMLRPCDocument object from given body of text/xml, * d_type is expected document type: xr_methodcall, xr_methodresponse or xr_undefined if any */ XMLRPCDocument *xmlrpc_doc_parse(Octstr *post_body, int d_type); /* Destroy XMLRPCDocument object */ void xmlrpc_doc_destroy(XMLRPCDocument *xrdoc, int d_type); /* Add a scalar param to XMLRPCDocument object. * d_type is expected document type: xr_methodcall or xr_methodresponse. * Return 0 if ok or -1 if something wrong (e.g. xrdoc is null or faultresponse) */ int xmlrpc_doc_add_scalar(XMLRPCDocument *xrdoc, int d_type, int type, void *arg); /* Add given XMLRPCValue param to XMLRPCDocument object. * d_type is expected document type: xr_methodcall or xr_methodresponse. * Return 0 if ok or -1 if something wrong. * NOTE that value is NOT duplicated */ int xmlrpc_doc_add_value(XMLRPCDocument *xrdoc, int d_type, XMLRPCValue *value); /* Create Octstr (text/xml string) out of given XMLRPCDocument. * d_type is expected document type. * level is the indent width. * Caller must free returned Octstr. */ Octstr *xmlrpc_doc_print(XMLRPCDocument *xrdoc, int d_type, int level); /* Send XMLRPCDocument to given url with given headers. * d_type is expected document type. * Note: adds XML-RPC specified headers into given list if needed. * and if NULL when this function called, automatically generated * * Return 0 if all went fine, -1 if failure. As user reference, uses *void */ int xmlrpc_doc_send(XMLRPCDocument *xrdoc, int d_type, HTTPCaller *http_ref, Octstr *url, List *headers, void *ref); /*** METHOD CALLS ***/ /* Create new MethodCall with given name and no params */ #define xmlrpc_create_call(method) \ xmlrpc_doc_create_call(method) /* Create new MethodCall from given body of text/xml */ #define xmlrpc_parse_call(post_body) \ xmlrpc_doc_parse(post_body, xr_methodcall) /* Destroy MethodCall */ #define xmlrpc_destroy_call(call) \ xmlrpc_doc_destroy(call, xr_methodcall) /* Add a scalar param to MethodCall. * type is scalar type: xr_string, xr_int, xr_bool, xr_double, xr_date or xr_base64 * arg is pointer to value of given type: Octstr*, long*, int*, double*, Octstr* or Octstr* * respectively * Return 0 if ok or -1 if something wrong. */ #define xmlrpc_add_call_scalar(call, type, arg) \ xmlrpc_doc_add_scalar(call, xr_methodcall, type, arg) /* Add given XMLRPCValue param to MethodCall. * Return 0 if ok or -1 if something wrong. * NOTE: value is NOT duplicated */ #define xmlrpc_add_call_value(call, value) \ xmlrpc_doc_add_value(call, xr_methodcall, value) /* Create Octstr (text/xml string) out of given MethodCall. Caller * must free returned Octstr */ #define xmlrpc_print_call(call) \ xmlrpc_doc_print(call, xr_methodcall, 0) /* Send MethodCall to given url with given headers. * d_type is expected document type. * Note: adds XML-RPC specified headers into given list if needed. * and if NULL when this function called, automatically generated * * Return 0 if all went fine, -1 if failure. As user reference, uses *void */ #define xmlrpc_send_call(call,http_ref, url, headers, ref) \ xmlrpc_doc_send(call, xr_methodcall, http_ref, url, headers, ref) /* Return the name of the method requested or NULL if document is not method call */ Octstr *xmlrpc_get_call_name(XMLRPCDocument *call); /*** METHOD RESPONSES ***/ /* Create a new MethodResponse with no param value */ #define xmlrpc_create_response() \ xmlrpc_doc_create_response() /* Create a new fault MethodResponse with given faultcode and faultstring */ #define xmlrpc_create_faultresponse(faultcode, faultstring) \ xmlrpc_doc_create_faultresponse(faultcode, faultstring) /* Create a new MethodResponse from given text/xml string */ #define xmlrpc_parse_response(post_body) \ xmlrpc_doc_parse(post_body, xr_methodresponse) /* Destroy MethodResponse */ #define xmlrpc_destroy_response(response) \ xmlrpc_doc_destroy(response, xr_methodresponse) /* Add a scalar param to MethodResponse. * type is scalar type: xr_string, xr_int, xr_bool, xr_double, xr_date or xr_base64 * arg is pointer to value of given type: Octstr*, long*, int*, double*, Octstr* or Octstr* * respectively * Return 0 if ok or -1 if something wrong. */ #define xmlrpc_add_response_scalar(response, type, arg) \ xmlrpc_doc_add_scalar(response, xr_methodresponse, type, arg) /* Add given XMLRPCValue param to MethodResponse. * Return 0 if ok or -1 if something wrong. * NOTE: value is NOT duplicated */ #define xmlrpc_add_response_value(response, value) \ xmlrpc_doc_add_value(response, xr_methodresponse, value) /* Create Octstr (text/xml string) out of given MethodCall. Caller * must free returned Octstr */ #define xmlrpc_print_response(response) \ xmlrpc_doc_print(response, xr_methodresponse, 0) /* Send MethodResponse to given url with given headers. * d_type is expected document type. * Note: adds XML-RPC specified headers into given list if needed. * and if NULL when this function called, automatically generated * * Return 0 if all went fine, -1 if failure. As user reference, uses *void */ #define xmlrpc_send_response(response, http_ref, url, headers, ref) \ xmlrpc_doc_send(call, xr_methodresponse, http_ref, url, headers, ref) /*** PARAMS HANDLING ***/ /* Return -1 if XMLRPCDocument can't have params or number of params */ int xmlrpc_count_params(XMLRPCDocument *xrdoc); /* Return i'th MethodCall/MethodResponse param * or NULL if something wrong */ XMLRPCValue *xmlrpc_get_param(XMLRPCDocument *xrdoc, int i); /* Return type of i'th MethodCall/MethodResponse param: xr_scalar, xr_array or xr_struct * or -1 if no param */ int xmlrpc_get_type_param(XMLRPCDocument *xrdoc, int i); /* Return content of i'th MethodCall/MethodResponse param: * XMLRPCScalar if xr_scalar, List of XMLRPCValues if xr_array * or Dict of XMLRPCValues if xr_struct (member names as keys) * or NULL if no param */ void *xmlrpc_get_content_param(XMLRPCDocument *xrdoc, int i); /* Identify d_type of given XMLRPCDocument and add a scalar param. * type is scalar type: xr_string, xr_int, xr_bool, xr_double, xr_date or xr_base64 * arg is pointer to value of given type: Octstr*, long*, int*, double*, Octstr* or Octstr* * respectively * Return 0 if ok or -1 if something wrong. */ #define xmlrpc_add_scalar_param(xrdoc, type, arg) \ xmlrpc_doc_add_scalar(xrdoc, xr_undefined, type, arg) /* Identify d_type of given XMLRPCDocument and add XMLRPCValue param. * Return 0 if ok or -1 if something wrong. * NOTE: value is NOT duplicated */ #define xmlrpc_add_param(xrdoc, value) \ xmlrpc_doc_add_value(xrdoc, xr_undefined, value) /*** VALUES HANDLING ***/ /* Create a new XMLRPCValue object of undefined type */ XMLRPCValue *xmlrpc_value_create(void); /* Destroy given XMLRPCValue object */ void xmlrpc_value_destroy(XMLRPCValue *val); /* Wrapper for destroy */ void xmlrpc_value_destroy_item(void *val); /* Set type of XMLRPCValue: xr_scalar, xr_array or xr_struct * Return 0 if ok or -1 if something wrong. */ int xmlrpc_value_set_type(XMLRPCValue *val, int v_type); /* Set XMLRPCValue content: * XMLRPCScalar if xr_scalar, List of XMLRPCValues if xr_array * or Dict of XMLRPCValues if xr_struct (member names as keys) * Return 0 if ok or -1 if something wrong. */ int xmlrpc_value_set_content(XMLRPCValue *val, void *content); /* Return type of XMLRPCValue: xr_scalar, xr_array or xr_struct */ int xmlrpc_value_get_type(XMLRPCValue *val); /* Return leaf type of XMLRPCValue: * as above, but if value is xr_scalar return type of scalar */ int xmlrpc_value_get_type_smart(XMLRPCValue *val); /* Return XMLRPCValue content: * XMLRPCScalar if xr_scalar, List of XMLRPCValues if xr_array * or Dict of XMLRPCValues if xr_struct (member names as keys) * or NULL if something wrong. */ void *xmlrpc_value_get_content(XMLRPCValue *val); /* Create Octstr (text/xml string) out of given XMLRPCValue. Caller * must free returned Octstr */ Octstr *xmlrpc_value_print(XMLRPCValue *val, int level); /*** STRUCT VALUE HANDLING ***/ /* Create a new XMLRPCValue object of xr_struct type. * size is expected number of struct members */ XMLRPCValue *xmlrpc_create_struct_value(int size); /* Return -1 if not a struct or number of members */ long xmlrpc_count_members(XMLRPCValue *xrstruct); /* Add member with given name and value to the struct */ int xmlrpc_add_member(XMLRPCValue *xrstruct, Octstr *name, XMLRPCValue *value); /* Add member with given name and scalar value built with type and arg to the struct */ int xmlrpc_add_member_scalar(XMLRPCValue *xrstruct, Octstr *name, int type, void *arg); /* Return value of member with given name or NULL if not found */ XMLRPCValue *xmlrpc_get_member(XMLRPCValue *xrstruct, Octstr *name); /* Return type of member with given name (xr_scalar, xr_array or xr_struct) * or -1 if not found */ int xmlrpc_get_member_type(XMLRPCValue *xrstruct, Octstr *name); /* Return content of member with given name: * XMLRPCScalar if xr_scalar, List of XMLRPCValues if xr_array * or Dict of XMLRPCValues if xr_struct (member names as keys) * or NULL if not found. */ void *xmlrpc_get_member_content(XMLRPCValue *xrstruct, Octstr *name); /* Create Octstr (text/xml string) out of struct. Caller * must free returned Octstr. */ Octstr *xmlrpc_print_struct(Dict *members, int level); /*** ARRAY VALUE HANDLING ***/ /* Create a new XMLRPCValue object of xr_array type. */ XMLRPCValue *xmlrpc_create_array_value(void); /* Return -1 if not an array or number of elements */ int xmlrpc_count_elements(XMLRPCValue *xrarray); /* Add XMLRPCValue element to the end of array */ int xmlrpc_add_element(XMLRPCValue *xrarray, XMLRPCValue *value); /* Build scalar XMLRPCValue with type and arg, *and add this element to the end of array */ int xmlrpc_add_element_scalar(XMLRPCValue *xrarray, int type, void *arg); /* Return value of i'th element in array or NULL if something wrong*/ XMLRPCValue *xmlrpc_get_element(XMLRPCValue *xrarray, int i); /* Return type of i'th element in array (xr_scalar, xr_array or xr_struct) * or -1 if not found */ int xmlrpc_get_element_type(XMLRPCValue *xrarray, int i); /* Return content of i'th element: * XMLRPCScalar if xr_scalar, List of XMLRPCValues if xr_array * or Dict of XMLRPCValues if xr_struct (member names as keys) * or NULL if not found. */ void *xmlrpc_get_element_content(XMLRPCValue *xrarray, int i); /* Create Octstr (text/xml string) out of array. Caller * must free returned Octstr. */ Octstr *xmlrpc_print_array(List *elements, int level); /*** SCALAR HANDLING ***/ /* Create a new scalar of given type and value * (which must be in right format) * type is scalar type: xr_string, xr_int, xr_bool, xr_double, xr_date or xr_base64 * arg is pointer to value of given type: Octstr*, long*, int*, double*, Octstr* or Octstr* * respectively * Return NULL if something wrong. */ XMLRPCScalar *xmlrpc_scalar_create(int type, void *arg); /* Destroy XMLRPCScalar */ void xmlrpc_scalar_destroy(XMLRPCScalar *scalar); /* Return type of scalar or -1 if scalar is NULL */ int xmlrpc_scalar_get_type(XMLRPCScalar *scalar); /* Return content of scalar * s_type is expected type of scalar */ void *xmlrpc_scalar_get_content(XMLRPCScalar *scalar, int s_type); /* Create Octstr (text/xml string) out of scalar. Caller * must free returned Octstr. */ Octstr *xmlrpc_scalar_print(XMLRPCScalar *scalar, int level); /* Wrappers to get scalar content of proper type * NOTE: returned values are copies, caller must free returned Octstr */ #define xmlrpc_scalar_get_double(scalar) \ *(double *)xmlrpc_scalar_get_content(scalar, xr_double) #define xmlrpc_scalar_get_int(scalar) \ *(long *)xmlrpc_scalar_get_content(scalar, xr_int) #define xmlrpc_scalar_get_bool(scalar) \ *(int *)xmlrpc_scalar_get_content(scalar, xr_bool) #define xmlrpc_scalar_get_date(scalar) \ octstr_duplicate((Octstr *)xmlrpc_scalar_get_content(scalar, xr_date)) #define xmlrpc_scalar_get_string(scalar) \ octstr_duplicate((Octstr *)xmlrpc_scalar_get_content(scalar, xr_string)) #define xmlrpc_scalar_get_base64(scalar) \ octstr_duplicate((Octstr *)xmlrpc_scalar_get_content(scalar, xr_base64)) /*** SCALAR VALUE HANDLING ***/ /* Create XMLRPCScalar with type and arg, * and then create XMLRPCValue with xr_scalar type and * created XMLRPCScalar as content */ XMLRPCValue *xmlrpc_create_scalar_value(int type, void *arg); /* As above, but scalar is xr_double type */ XMLRPCValue *xmlrpc_create_double_value(double val); /* As above, but scalar is xr_int type */ XMLRPCValue *xmlrpc_create_int_value(long val); /* As above, but scalar is xr_string type */ XMLRPCValue *xmlrpc_create_string_value(Octstr *val); /* Return type of scalar in given XMLRPCValue */ #define xmlrpc_get_scalar_value_type(value) \ xmlrpc_scalar_get_type(xmlrpc_value_get_content(value)) /* Wrappers to get scalar content of proper type from XMLRPCValue */ #define xmlrpc_get_double_value(value) \ xmlrpc_scalar_get_double(xmlrpc_value_get_content(value)) #define xmlrpc_get_int_value(value) \ xmlrpc_scalar_get_int(xmlrpc_value_get_content(value)) #define xmlrpc_get_string_value(value) \ xmlrpc_scalar_get_string(xmlrpc_value_get_content(value)) #define xmlrpc_get_base64_value(value) \ xmlrpc_scalar_get_base64(xmlrpc_value_get_content(value)) /*** FAULT HANDLING ***/ /* Return 1 if XMLRPCDocument is fault MethodResponse */ int xmlrpc_is_fault(XMLRPCDocument *response); /* Return faultcode from fault MethodResponse * or -1 if XMLRPCDocument is not valid fault MethodResponse */ long xmlrpc_get_faultcode(XMLRPCDocument *faultresponse); /* Return faultstring from fault MethodResponse * or NULL if XMLRPCDocument is not valid fault MethodResponse */ Octstr *xmlrpc_get_faultstring(XMLRPCDocument *faultresponse); /*** PARSE STATUS HANDLING***/ /* * Check if parsing had any errors, return status code of parsing by * returning one of the following: * XMLRPC_COMPILE_OK, * XMLRPC_XMLPARSE_FAILED, * XMLRPC_PARSING_FAILED * -1 if call has been NULL */ int xmlrpc_parse_status(XMLRPCDocument *xrdoc); /* Return parser error string if parse_status != XMLRPC_COMPILE_OK */ /* return NULL if no error occured or no error string was available */ Octstr *xmlrpc_parse_error(XMLRPCDocument *xrdoc); #endif gateway-1.4.5/gwlib/list.h0000644000175000017500000002573013227613126014126 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * list.h - generic dynamic list * * This is a generic, dynamic list. Generic means that it stores void pointers * (void *), instead of a more specific data type. This allows storage of * any type of items in the list. The pointers may not be NULL pointers. * * A number of operations are defined for the list: create, destroy, * query of length, inserting and deleting items, getting items, and so on. * See below for a detailed list. * * The list is also thread safe: each single operation is atomic. For * list manipulation that needs to be atomic but uses several single * operations, the list supports locking and unlocking. It is up to the * caller to make sure the list lock is used properly; the implementation * only guarantees the atomicity of single operations. * * The API also has functions for solving typical producer-consumer problems: * the list counts the number of producers it has (they need to register * _and_ unregister explicitly) and has functions for adding a produced * item to the list and removing an item so that it can be consumed. The * consumption function (`gwlist_consume') sleeps, without using processor * time, until there is an item to be consumed or there are no more * producers. Thus, a typical producer would look like this: * * gwlist_add_producer(list); * while ((item = foo()) != NULL) * gwlist_produce(list, item); * gwlist_remove_producer(list); * * and the corresponding consumer would look like this: * * while ((item = gwlist_consume(list)) != NULL) * bar(item); * * There can be any number of producers and consumers at the same time. * * List items are numbered starting with `0'. * * Most list functions can do memory allocations. If these allocations * fail, they will kill the program (they use gwlib/gwmem.c for * memory allocations, and those do the killing). This is not mentioned * explicitly for each function. * * The module prefix is `list' (in any combination of upper and lower case * characters). All externally visible symbols (i.e., those defined by * this header file) start with the prefix. */ #ifndef LIST_H #define LIST_H /* * The list type. It is opaque: do not touch it except via the functions * defined in this header. */ typedef struct List List; /* * A comparison function for list items. Returns true (non-zero) for * equal, false for non-equal. Gets an item from the list as the first * argument, the pattern as a second argument. */ typedef int gwlist_item_matches_t(void *item, void *pattern); /* * A destructor function for list items. Must free all memory associated * with the list item. */ typedef void gwlist_item_destructor_t(void *item); /* * Create a list and return a pointer to the list object. */ List *gwlist_create_real(void); #define gwlist_create() gw_claim_area(gwlist_create_real()) /* * Destroy the list. If `destructor' is not NULL, first destroy all items * by calling it for each item. If it is NULL, the caller is responsible * for destroying items. The caller is also responsible for making sure * that nothing else tries to touch the list from the time the call to * gwlist_destroy starts - this includes the item destructor function. */ void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor); /* * Return the number of items in the list. Return 0 if list is NULL. */ long gwlist_len(List *list); /* * Add a new item to the end of the list. */ void gwlist_append(List *list, void *item); /* * This is similar to gwlist_append(). If the item is *not* present in the * list it is added to the end of the list, otherwise the item is * discarded and *not* added to the list. Hence you can assume that using * this append function you result in a unique item inside the list. */ void gwlist_append_unique(List *list, void *item, gwlist_item_matches_t *cmp); /* * Insert an item into the list so that it becomes item number `pos'. */ void gwlist_insert(List *list, long pos, void *item); /* * Delete items from the list. Note that this does _not_ free the memory * for the items, they are just dropped from the list. */ void gwlist_delete(List *list, long pos, long count); /* * Delete all items from the list that match `pattern'. Like gwlist_delete, * the items are removed from the list, but are not destroyed themselves. * Return the number of items deleted. */ long gwlist_delete_matching(List *list, void *pat, gwlist_item_matches_t *cmp); /* * Delete all items from the list whose pointer value is exactly `item'. * Return the number of items deleted. */ long gwlist_delete_equal(List *list, void *item); /* * Return the item at position `pos'. */ void *gwlist_get(List *list, long pos); /* * Remove and return the first item in the list. Return NULL if list is * empty. Note that unlike gwlist_consume, this won't sleep until there is * something in the list. */ void *gwlist_extract_first(List *list); /* * Create a new list with items from `list' that match a pattern. The items * are removed from `list'. Return NULL if no matching items are found. * Note that unlike gwlist_consume, this won't sleep until there is * something in the list. */ List *gwlist_extract_matching(List *list, void *pat, gwlist_item_matches_t *cmp); /* * Lock the list. This protects the list from other threads that also * lock the list with gwlist_lock, but not from threads that do not. * (This is intentional.) */ void gwlist_lock(List *list); /* * Unlock the list lock locked by gwlist_lock. Only the owner of the lock * may unlock it (although this might not be checked). */ void gwlist_unlock(List *list); /* * Sleep until the list is non-empty. Note that after the thread awakes * another thread may already have emptied the list again. Those who wish * to use this function need to be very careful with gwlist_lock and * gwlist_unlock. */ int gwlist_wait_until_nonempty(List *list); /* * Register a new producer to the list. */ void gwlist_add_producer(List *list); /* * Return the current number of producers for the list */ int gwlist_producer_count(List *list); /* * Remove a producer from the list. If the number of producers drops to * zero, all threads sleeping in gwlist_consume will awake and return NULL. */ void gwlist_remove_producer(List *list); /* * Add an item to the list. This equivalent to gwlist_append, but may be * easier to remember. */ void gwlist_produce(List *list, void *item); /* * Return the current number of consumers for the list */ int gwlist_consumer_count(List *list); /* * Remove an item from the list, or return NULL if the list was empty * and there were no producers. If the list is empty but there are * producers, sleep until there is something to return. */ void *gwlist_consume(List *list); /* * Remove an item from the list, or return NULL if the list was empty * and there were no producers. If the list is empty but there are * producers, sleep until there is something to return or timeout occur. */ void *gwlist_timed_consume(List *list, long sec); /* * Search the list for a particular item. If not found, return NULL. If found, * return the list element. Compare items to search pattern with * `cmp(item, pattern)'. If the function returns non-zero, the items are * equal. */ void *gwlist_search(List *list, void *pattern, gwlist_item_matches_t *cmp); /* * Search the list for all items matching a pattern. If not found, return * NULL. If found, return a list with the matching elements. Compare items * to search pattern with `cmp(item, pattern)'. If the function returns * non-zero, the items are equal. */ List *gwlist_search_all(List *list, void *pattern, gwlist_item_matches_t *cmp); /* * Search the list for the first equal item. If not found, return -1. If found * return position. */ long gwlist_search_equal(List *list, void *item); /* * Sort the list with qsort. * if you have a list that you feed like that: * Msg *message; * gwlist_add(mylist, message); * a function that could sort messages by their data length would look like that: * int sort_by_messagelength(void* first_msg_pp, void* second_msg_pp) * { * Msg *first_msg=(Msg*)first_msg_pp; * Msg *second_msg=(Msg*)second_msg_pp; * return octstr_len(first_msg->sms.msgdata) - octstr_len(second_msg->sms.msgdata); * } */ void gwlist_sort(List *list, int(*cmp)(const void *, const void *)); #endif gateway-1.4.5/gwlib/dbpool_sdb.c0000644000175000017500000000764013227613126015255 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_sdbl.c - implement SDB operations for generic database connection pool * * Guillaume Cottenceau, 2004 */ #ifdef HAVE_SDB #include static void* sdb_open_conn(const DBConf *db_conf) { SDBConf *conf = db_conf->sdb; /* make compiler happy */ char *connection; /* sanity check */ if (conf == NULL) return NULL; connection = sdb_open(octstr_get_cstr(conf->url)); if (connection == NULL) { error(0, "SDB: could not connect to database"); return NULL; } info(0, "SDB: Connected to %s.", octstr_get_cstr(conf->url)); return connection; } static void sdb_close_conn(void *conn) { if (conn == NULL) return; sdb_close(conn); } static int sdb_check_conn(void *conn) { if (conn == NULL) return -1; /* nothing in SDB to check for the connection, always succeed */ return 0; } static void sdb_conf_destroy(DBConf *db_conf) { SDBConf *conf = db_conf->sdb; octstr_destroy(conf->url); gw_free(conf); gw_free(db_conf); } static struct db_ops sdb_ops = { .open = sdb_open_conn, .close = sdb_close_conn, .check = sdb_check_conn, .conf_destroy = sdb_conf_destroy }; #endif /* HAVE_SDB */ gateway-1.4.5/gwlib/log.h0000644000175000017500000001534713227613126013737 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * log.h - logging functions * * Please note that opening and closing of log files are not thread safe. * Don't do it unless you're in single-thread mode. */ #ifndef GWLOG_H #define GWLOG_H /* Symbolic levels for output levels. */ enum output_level { GW_DEBUG, GW_INFO, GW_WARNING, GW_ERROR, GW_PANIC, GW_BACKTRACE }; /* defines if a log-file is exclusive or not */ enum excl_state { GW_NON_EXCL, GW_EXCL }; /* Initialize the log file module */ void log_init(void); /* Shutdown the log file module */ void log_shutdown(void); /* Print a panicky error message and terminate the program with a failure. * So, this function is called when there is no other choice than to exit * immediately, with given reason */ #define panic gw_panic void gw_panic(int, const char *, ...) PRINTFLIKE(2,3); /* * Print given stacktrace. If no stackstrace given then stacktrace will be * initialized */ void gw_backtrace(void **, size_t, int); /* Print a normal error message. Used when something which should be * investigated and possibly fixed, happens. The error might be fatal, too, * but we have time to put system down peacefully. */ void error(int, const char *, ...) PRINTFLIKE(2,3); /* Print a warning message. 'Warning' is a message that should be told and * distinguished from normal information (info), but does not necessary * require any further investigations. Like 'warning, no sender number set' */ void warning(int, const char *, ...) PRINTFLIKE(2,3); /* Print an informational message. This information should be limited to * one or two rows per request, if real debugging information is needed, * use debug */ void info(int, const char *, ...) PRINTFLIKE(2,3); /* * Print a debug message. Most of the log messages should be of this level * when the system is under development. The first argument gives the `place' * where the function is called from; see function set_debug_places. */ void debug(const char *, int, const char *, ...) PRINTFLIKE(3,4); /* * Set the places from which debug messages are actually printed. This * allows run-time configuration of what is and is not logged when debug * is called. `places' is a string of tokens, separated by whitespace and/or * commas, with trailing asterisks (`*') matching anything. For instance, * if `places' is "wap.wsp.* wap.wtp.* wapbox", then all places that begin * with "wap.wsp." or "wap.wtp." (including the dots) are logged, and so * is the place called "wapbox". Nothing else is logged at debug level, * however. The 'places' string can also have negations, marked with '-' at * the start, so that nothing in that place is outputted. So if the string is * "wap.wsp.* -wap.wap.http", only wap.wsp is logged, but not http-parts on * it */ void log_set_debug_places(const char *places); /* Set minimum level for output messages to stderr. Messages with a lower level are not printed to standard error, but may be printed to files (see below). */ void log_set_output_level(enum output_level level); /* Set minimum level for output messages to logfiles */ void log_set_log_level(enum output_level level); /* * Set the syslog facility to use. */ void log_set_syslog_facility(char *facility); /* * Set syslog usage. If `ident' is NULL, syslog is not used. */ void log_set_syslog(const char *ident, int syslog_level); /* Start logging to a file as well. The file will get messages at least of level `level'. There is no need and no way to close the log file; it will be closed automatically when the program finishes. Failures when opening to the log file are printed to stderr. Where `excl' defines if the log file will be exclusive or not. Returns the index within the global logfiles[] array where this log file entry has been added. */ int log_open(char *filename, int level, enum excl_state excl); /* Close and re-open all logfiles */ void log_reopen(void); /* * Close all log files. */ void log_close_all(void); /* * Register a thread to a specific logfiles[] index and hence * to a specific exclusive log file. */ void log_thread_to(int idx); #endif gateway-1.4.5/gwlib/cfg.def0000644000175000017500000004121013227613126014210 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * cfg.def - definition of configuration groups and variables * * Lars Wirzenius */ #ifndef OCTSTR #error OCTSTR not defined. #endif #ifndef SINGLE_GROUP #error SINGLE_GROUP not defined. #endif #ifndef MULTI_GROUP #error MULTI_GROUP not defined. #endif SINGLE_GROUP(core, OCTSTR(admin-port) OCTSTR(admin-port-ssl) OCTSTR(admin-interface) OCTSTR(admin-password) OCTSTR(status-password) OCTSTR(admin-deny-ip) OCTSTR(admin-allow-ip) OCTSTR(smsbox-port) OCTSTR(smsbox-port-ssl) OCTSTR(smsbox-interface) OCTSTR(smsbox-max-pending) OCTSTR(wapbox-port) OCTSTR(wapbox-port-ssl) OCTSTR(box-deny-ip) OCTSTR(box-allow-ip) OCTSTR(udp-deny-ip) OCTSTR(udp-allow-ip) OCTSTR(wdp-interface-name) OCTSTR(log-file) OCTSTR(log-level) OCTSTR(syslog-level) OCTSTR(syslog-facility) OCTSTR(access-log) OCTSTR(access-log-time) OCTSTR(access-log-format) OCTSTR(access-log-clean) OCTSTR(store-file) OCTSTR(store-dump-freq) OCTSTR(store-type) OCTSTR(store-location) OCTSTR(unified-prefix) OCTSTR(white-list) /* deprecated, supported until next major stable release - start */ OCTSTR(white-list-regex) OCTSTR(black-list) OCTSTR(black-list-regex) /* deprecated, supported until next major stable release - end */ OCTSTR(white-list-sender) OCTSTR(white-list-sender-regex) OCTSTR(black-list-sender) OCTSTR(black-list-sender-regex) OCTSTR(white-list-receiver) OCTSTR(white-list-receiver-regex) OCTSTR(black-list-receiver) OCTSTR(black-list-receiver-regex) OCTSTR(http-proxy-host) OCTSTR(http-proxy-port) OCTSTR(http-proxy-ssl) OCTSTR(http-proxy-exceptions) OCTSTR(http-proxy-exceptions-regex) OCTSTR(http-proxy-username) OCTSTR(http-proxy-password) OCTSTR(ssl-client-certkey-file) OCTSTR(ssl-server-cert-file) OCTSTR(ssl-server-key-file) OCTSTR(ssl-trusted-ca-file) OCTSTR(ssl-client-cipher-list) OCTSTR(ssl-server-cipher-list) OCTSTR(dlr-storage) OCTSTR(dlr-spool) OCTSTR(maximum-queue-length) /* deprecated, supported until next major stable release */ OCTSTR(sms-incoming-queue-limit) OCTSTR(sms-outgoing-queue-limit) OCTSTR(sms-resend-freq) OCTSTR(sms-resend-retry) OCTSTR(sms-combine-concatenated-mo) OCTSTR(sms-combine-concatenated-mo-timeout) OCTSTR(http-timeout) ) SINGLE_GROUP(wapbox, OCTSTR(bearerbox-host) OCTSTR(timer-freq) OCTSTR(url-map) OCTSTR(map-url) /* deprecated, supported until next major stable release - start */ OCTSTR(map-url-max) OCTSTR(map-url-0) OCTSTR(map-url-1) OCTSTR(map-url-2) OCTSTR(map-url-3) OCTSTR(map-url-4) OCTSTR(map-url-5) OCTSTR(map-url-6) OCTSTR(map-url-7) OCTSTR(map-url-8) OCTSTR(map-url-9) /* deprecated, supported until next major stable release - end */ OCTSTR(device-home) OCTSTR(log-file) OCTSTR(log-level) OCTSTR(syslog-level) OCTSTR(syslog-facility) OCTSTR(smart-errors) OCTSTR(access-log) OCTSTR(access-log-time) OCTSTR(access-log-clean) OCTSTR(http-interface-name) OCTSTR(concatenation) OCTSTR(max-messages) OCTSTR(wml-strict) OCTSTR(http-timeout) ) MULTI_GROUP(wap-url-map, OCTSTR(name) OCTSTR(url) OCTSTR(map-url) OCTSTR(send-msisdn-query) OCTSTR(send-msisdn-header) OCTSTR(send-msisdn-format) OCTSTR(accept-cookies) ) MULTI_GROUP(wap-user-map, OCTSTR(name) OCTSTR(user) OCTSTR(pass) OCTSTR(msisdn) ) SINGLE_GROUP(wtls, OCTSTR(certificate-file) OCTSTR(privatekey-file) OCTSTR(privatekey-password) ) SINGLE_GROUP(ppg, OCTSTR(ppg-url) OCTSTR(ppg-port) OCTSTR(ppg-ssl-port) OCTSTR(trusted-pi) OCTSTR(concurrent-pushes) OCTSTR(users) OCTSTR(ppg-allow-ip) OCTSTR(ppg-deny-ip) OCTSTR(ssl-server-cert-file) OCTSTR(ssl-server-key-file) OCTSTR(global-sender) OCTSTR(default-smsc) OCTSTR(default-dlr-url) OCTSTR(ppg-smsbox-id) OCTSTR(service-name) ) MULTI_GROUP(wap-push-user, OCTSTR(wap-push-user) OCTSTR(ppg-username) OCTSTR(ppg-password) OCTSTR(country-prefix) OCTSTR(allowed-prefix) OCTSTR(allowed-prefix-regex) OCTSTR(denied-prefix) OCTSTR(denied-prefix-regex) OCTSTR(white-list) OCTSTR(white-list-regex) OCTSTR(black-list-regex) OCTSTR(black-list) OCTSTR(deny-ip) OCTSTR(allow-ip) OCTSTR(forced-smsc) OCTSTR(default-smsc) OCTSTR(dlr-url) OCTSTR(smsbox-id) ) SINGLE_GROUP(test-ppg, OCTSTR(retries) OCTSTR(pi-ssl) OCTSTR(ssl-client-certkey-file) OCTSTR(ssl-trusted-ca-file) ) SINGLE_GROUP(configuration, OCTSTR(push-url) OCTSTR(content-file) OCTSTR(pap-file) OCTSTR(username) OCTSTR(password) ) SINGLE_GROUP(smsbox, OCTSTR(smsbox-id) OCTSTR(bearerbox-host) OCTSTR(bearerbox-port) OCTSTR(bearerbox-port-ssl) OCTSTR(sendsms-port) OCTSTR(sendsms-port-ssl) OCTSTR(sendsms-interface) OCTSTR(sendsms-url) OCTSTR(sendota-url) OCTSTR(xmlrpc-url) OCTSTR(sendsms-chars) OCTSTR(global-sender) OCTSTR(log-file) OCTSTR(log-level) OCTSTR(syslog-level) OCTSTR(syslog-facility) OCTSTR(access-log) OCTSTR(access-log-time) OCTSTR(access-log-clean) OCTSTR(sms-length) OCTSTR(reply-couldnotfetch) OCTSTR(reply-couldnotrepresent) OCTSTR(reply-requestfailed) OCTSTR(reply-emptymessage) OCTSTR(allowed-prefix) OCTSTR(denied-prefix) OCTSTR(white-list) OCTSTR(black-list) OCTSTR(mo-recode) OCTSTR(http-request-retry) OCTSTR(http-queue-delay) OCTSTR(white-list-regex) OCTSTR(black-list-regex) OCTSTR(immediate-sendsms-reply) OCTSTR(max-pending-requests) OCTSTR(http-timeout) ) MULTI_GROUP(smsbox-route, OCTSTR(smsbox-id) OCTSTR(smsc-id) OCTSTR(shortcode) ) MULTI_GROUP(smsc, OCTSTR(smsc) OCTSTR(smsc-id) OCTSTR(smsc-admin-id) OCTSTR(denied-smsc-id) OCTSTR(allowed-smsc-id) OCTSTR(preferred-smsc-id) OCTSTR(allowed-prefix) OCTSTR(denied-prefix) OCTSTR(preferred-prefix) OCTSTR(unified-prefix) OCTSTR(reroute) OCTSTR(reroute-smsc-id) OCTSTR(reroute-receiver) OCTSTR(reroute-dlr) OCTSTR(log-file) OCTSTR(log-level) OCTSTR(log-format) OCTSTR(our-host) OCTSTR(alt-dcs) OCTSTR(throughput) OCTSTR(dead-start) OCTSTR(alt-charset) OCTSTR(host) OCTSTR(alt-host) OCTSTR(port) OCTSTR(use-ssl) OCTSTR(alt-port) OCTSTR(smsc-username) OCTSTR(smsc-password) OCTSTR(keepalive) OCTSTR(sim-buffering) OCTSTR(modemtype) OCTSTR(device) OCTSTR(speed) OCTSTR(validityperiod) OCTSTR(our-port) OCTSTR(receive-port) OCTSTR(our-receiver-port) OCTSTR(connect-allow-ip) OCTSTR(system-id) OCTSTR(system-type) OCTSTR(address-range) OCTSTR(smsc_nua) OCTSTR(home_nua) OCTSTR(wait_report) OCTSTR(ois-debug-level) OCTSTR(modem-type) OCTSTR(pin) OCTSTR(phone) OCTSTR(send-url) OCTSTR(dlr-url) OCTSTR(sender-prefix) OCTSTR(flow-control) OCTSTR(wait-ack) OCTSTR(wait-ack-expire) OCTSTR(no-sender) OCTSTR(no-coding) OCTSTR(window) OCTSTR(idle-timeout) OCTSTR(no-sep) OCTSTR(appname) OCTSTR(ussdc) OCTSTR(session-length) OCTSTR(my-number) OCTSTR(sms-center) OCTSTR(source-addr-ton) OCTSTR(source-addr-npi) OCTSTR(dest-addr-ton) OCTSTR(dest-addr-npi) OCTSTR(bind-addr-ton) OCTSTR(bind-addr-npi) OCTSTR(service-type) OCTSTR(esm-class) OCTSTR(source-addr-autodetect) OCTSTR(enquire-link-interval) OCTSTR(max-pending-submits) OCTSTR(reconnect-delay) OCTSTR(transceiver-mode) OCTSTR(interface-version) OCTSTR(priority) OCTSTR(notification-pid) OCTSTR(notification-addr) OCTSTR(msg-id-type) OCTSTR(no-dlr) OCTSTR(connection-timeout) OCTSTR(allowed-smsc-id-regex) OCTSTR(denied-smsc-id-regex) OCTSTR(preferred-smsc-id-regex) OCTSTR(allowed-prefix-regex) OCTSTR(denied-prefix-regex) OCTSTR(preferred-prefix-regex) OCTSTR(max-error-count) OCTSTR(alt-addr-charset) OCTSTR(status-success-regex) OCTSTR(status-permfail-regex) OCTSTR(status-tempfail-regex) OCTSTR(max-sms-octets) OCTSTR(login-prompt) OCTSTR(password-prompt) OCTSTR(ssl-client-certkey-file) OCTSTR(generic-param-username) OCTSTR(generic-param-password) OCTSTR(generic-param-from) OCTSTR(generic-param-to) OCTSTR(generic-param-text) OCTSTR(generic-param-udh) OCTSTR(generic-param-service) OCTSTR(generic-param-account) OCTSTR(generic-param-binfo) OCTSTR(generic-param-dlr-mask) OCTSTR(generic-param-dlr-err) OCTSTR(generic-param-dlr-url) OCTSTR(generic-param-dlr-mid) OCTSTR(generic-param-flash) OCTSTR(generic-param-mclass) OCTSTR(generic-param-mwi) OCTSTR(generic-param-coding) OCTSTR(generic-param-validity) OCTSTR(generic-param-deferred) OCTSTR(generic-param-foreign-id) OCTSTR(generic-param-meta-data) OCTSTR(generic-message-sent) OCTSTR(generic-status-sent) OCTSTR(generic-status-error) OCTSTR(generic-foreign-id-regex) OCTSTR(instances) ) MULTI_GROUP(sms-service, OCTSTR(name) OCTSTR(keyword) OCTSTR(aliases) OCTSTR(url) OCTSTR(get-url) OCTSTR(post-url) OCTSTR(post-xml) OCTSTR(file) OCTSTR(text) OCTSTR(exec) OCTSTR(accepted-smsc) OCTSTR(accepted-smsc-regex) OCTSTR(accepted-account) OCTSTR(accepted-account-regex) OCTSTR(forced-smsc) OCTSTR(default-smsc) OCTSTR(faked-sender) OCTSTR(max-messages) OCTSTR(concatenation) OCTSTR(split-chars) OCTSTR(split-suffix) OCTSTR(omit-empty) OCTSTR(header) OCTSTR(footer) OCTSTR(prefix) OCTSTR(suffix) OCTSTR(assume-plain-text) OCTSTR(accept-x-kannel-headers) OCTSTR(strip-keyword) OCTSTR(send-sender) OCTSTR(catch-all) OCTSTR(allowed-prefix) OCTSTR(allowed-prefix-regex) OCTSTR(denied-prefix) OCTSTR(denied-prefix-regex) OCTSTR(allowed-receiver-prefix) OCTSTR(allowed-receiver-prefix-regex) OCTSTR(denied-receiver-prefix) OCTSTR(denied-receiver-prefix-regex) OCTSTR(white-list) OCTSTR(white-list-regex) OCTSTR(black-list) OCTSTR(black-list-regex) OCTSTR(dlr-url) OCTSTR(dlr-mask) OCTSTR(keyword-regex) OCTSTR(alt-charset) ) MULTI_GROUP(sendsms-user, OCTSTR(name) OCTSTR(username) OCTSTR(password) OCTSTR(user-deny-ip) OCTSTR(user-allow-ip) OCTSTR(forced-smsc) OCTSTR(default-smsc) OCTSTR(faked-sender) OCTSTR(default-sender) OCTSTR(max-messages) OCTSTR(concatenation) OCTSTR(split-chars) OCTSTR(split-suffix) OCTSTR(omit-empty) OCTSTR(header) OCTSTR(footer) OCTSTR(allowed-prefix) OCTSTR(denied-prefix) OCTSTR(white-list) OCTSTR(black-list) OCTSTR(dlr-url) OCTSTR(allowed-prefix-regex) OCTSTR(denied-prefix-regex) OCTSTR(white-list-regex) OCTSTR(black-list-regex) ) MULTI_GROUP(ota-setting, OCTSTR(ota-id) OCTSTR(location) OCTSTR(service) OCTSTR(ipaddress) OCTSTR(phonenumber) OCTSTR(bearer) OCTSTR(connection) OCTSTR(calltype) OCTSTR(speed) OCTSTR(pppsecurity) OCTSTR(authentication) OCTSTR(login) OCTSTR(secret) ) MULTI_GROUP(ota-bookmark, OCTSTR(ota-id) OCTSTR(name) OCTSTR(url) ) MULTI_GROUP(modems, OCTSTR(id) OCTSTR(name) OCTSTR(detect-string) OCTSTR(detect-string2) OCTSTR(init-string) OCTSTR(speed) OCTSTR(enable-hwhs) OCTSTR(need-sleep) OCTSTR(no-pin) OCTSTR(no-smsc) OCTSTR(sendline-sleep) OCTSTR(keepalive-cmd) OCTSTR(broken) OCTSTR(message-storage) OCTSTR(message-start) OCTSTR(enable-mms) OCTSTR(reset-string) OCTSTR(hardware-flow-control) ) MULTI_GROUP(mssql-connection, OCTSTR(id) OCTSTR(username) OCTSTR(password) OCTSTR(server) OCTSTR(database) OCTSTR(max-connections) ) MULTI_GROUP(mysql-connection, OCTSTR(id) OCTSTR(host) OCTSTR(port) OCTSTR(username) OCTSTR(password) OCTSTR(database) OCTSTR(max-connections) ) MULTI_GROUP(oracle-connection, OCTSTR(id) OCTSTR(username) OCTSTR(password) OCTSTR(tnsname) OCTSTR(max-connections) ) MULTI_GROUP(sdb-connection, OCTSTR(id) OCTSTR(url) OCTSTR(max-connections) ) MULTI_GROUP(pgsql-connection, OCTSTR(id) OCTSTR(host) OCTSTR(port) OCTSTR(username) OCTSTR(password) OCTSTR(database) OCTSTR(max-connections) ) MULTI_GROUP(sqlite-connection, OCTSTR(id) OCTSTR(database) OCTSTR(max-connections) OCTSTR(lock-timeout) ) MULTI_GROUP(sqlite3-connection, OCTSTR(id) OCTSTR(database) OCTSTR(max-connections) OCTSTR(lock-timeout) ) MULTI_GROUP(redis-connection, OCTSTR(id) OCTSTR(host) OCTSTR(port) OCTSTR(password) OCTSTR(database) OCTSTR(max-connections) OCTSTR(idle-timeout) ) MULTI_GROUP(cassandra-connection, OCTSTR(id) OCTSTR(host) OCTSTR(port) OCTSTR(username) OCTSTR(password) OCTSTR(database) OCTSTR(max-connections) OCTSTR(idle-timeout) ) SINGLE_GROUP(dlr-db, OCTSTR(id) OCTSTR(table) OCTSTR(ttl) OCTSTR(field-smsc) OCTSTR(field-timestamp) OCTSTR(field-source) OCTSTR(field-destination) OCTSTR(field-service) OCTSTR(field-url) OCTSTR(field-mask) OCTSTR(field-status) OCTSTR(field-boxc-id) ) SINGLE_GROUP(store-db, OCTSTR(id) OCTSTR(table) OCTSTR(hash) ) SINGLE_GROUP(radius-acct, OCTSTR(our-host) OCTSTR(our-port) OCTSTR(remote-host) OCTSTR(remote-port) OCTSTR(remote-timeout) OCTSTR(nas-ports) OCTSTR(secret-nas) OCTSTR(secret-radius) OCTSTR(unified-prefix) ) MULTI_GROUP(smpp-tlv, OCTSTR(name) OCTSTR(tag) OCTSTR(length) OCTSTR(type) OCTSTR(smsc-id) OCTSTR(const) ) #undef OCTSTR #undef SINGLE_GROUP #undef MULTI_GROUP gateway-1.4.5/gwlib/dbpool_pgsql.c0000644000175000017500000001705513227613126015634 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_pgsql.c - implement PostgreSQL operations for generic database connection pool * * modeled after dbpool_mysql.c * Martiin Atukunda */ #ifdef HAVE_PGSQL #include #define add1(str, value) \ if (value != NULL && octstr_len(value) > 0) { \ tmp = octstr_format(str, value); \ octstr_append(cs, tmp); \ octstr_destroy(tmp); \ } static void *pgsql_open_conn(const DBConf *db_conf) { PGconn *conn = NULL; PgSQLConf *conf = db_conf->pgsql; /* make compiler happy */ Octstr *tmp, *cs; /* sanity check */ if (conf == NULL) return NULL; cs = octstr_create(""); add1(" host=%S", conf->host); /* TODO: add hostaddr support via 'host' directive too. * This needs an octstr_is_addr(Octstr *os) checking if a given string * contains a valid IPv4 address. Obviously parsing on our own via gwlib * functions or using regex. If found, insert hostaddr instead of host * for the connection string. */ /* add1(" hostaddr=%S", conf->host); */ if (conf->port > 0) { /* add only if user set a value */ octstr_append_cstr(cs, " port="); octstr_append_decimal(cs, conf->port); } add1(" user=%S", conf->username); add1(" password=%S", conf->password); add1(" dbname=%S", conf->database); #if 0 /* TODO: This is very bad to show password in the log file */ info(0, "PGSQL: Using connection string: %s.", octstr_get_cstr(cs)); #endif conn = PQconnectdb(octstr_get_cstr(cs)); octstr_destroy(cs); if (conn == NULL) goto failed; gw_assert(conn != NULL); if (PQstatus(conn) == CONNECTION_BAD) { error(0, "PGSQL: connection to database '%s' failed!", octstr_get_cstr(conf->database)); panic(0, "PGSQL: %s", PQerrorMessage(conn)); goto failed; } info(0, "PGSQL: Connected to server at '%s'.", octstr_get_cstr(conf->host)); return conn; failed: PQfinish(conn); return NULL; } static void pgsql_close_conn(void *conn) { if (conn == NULL) return; PQfinish(conn); return; } static int pgsql_check_conn(void *conn) { if (conn == NULL) return -1; if (PQstatus(conn) == CONNECTION_BAD) { error(0, "PGSQL: Database check failed!"); error(0, "PGSQL: %s", PQerrorMessage(conn)); return -1; } return 0; } static void pgsql_conf_destroy(DBConf *db_conf) { PgSQLConf *conf = db_conf->pgsql; octstr_destroy(conf->host); octstr_destroy(conf->username); octstr_destroy(conf->password); octstr_destroy(conf->database); gw_free(conf); gw_free(db_conf); } static int pgsql_update(void *theconn, const Octstr *sql, List *binds) { int rows; PGresult *res = NULL; PGconn *conn = (PGconn*) theconn; res = PQexec(conn, octstr_get_cstr(sql)); if (res == NULL) return -1; switch (PQresultStatus(res)) { case PGRES_BAD_RESPONSE: case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: error(0, "PGSQL: %s", octstr_get_cstr(sql)); error(0, "PGSQL: %s", PQresultErrorMessage(res)); PQclear(res); return -1; default: /* for compiler please */ break; } rows = atoi(PQcmdTuples(res)); PQclear(res); return rows; } static int pgsql_select(void *theconn, const Octstr *sql, List *binds, List **list) { int nTuples, nFields, row_loop, field_loop; PGresult *res = NULL; List *fields; PGconn *conn = (PGconn*) theconn; gw_assert(list != NULL); *list = NULL; res = PQexec(conn, octstr_get_cstr(sql)); if (res == NULL) return -1; switch (PQresultStatus(res)) { case PGRES_EMPTY_QUERY: case PGRES_BAD_RESPONSE: case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: error(0, "PGSQL: %s", octstr_get_cstr(sql)); error(0, "PGSQL: %s", PQresultErrorMessage(res)); PQclear(res); return -1; default: /* for compiler please */ break; } nTuples = PQntuples(res); nFields = PQnfields(res); *list = gwlist_create(); for (row_loop = 0; row_loop < nTuples; row_loop++) { fields = gwlist_create(); for (field_loop = 0; field_loop < nFields; field_loop++) { if (PQgetisnull(res, row_loop, field_loop)) gwlist_produce(fields, octstr_create("")); else gwlist_produce(fields, octstr_create(PQgetvalue(res, row_loop, field_loop))); } gwlist_produce(*list, fields); } PQclear(res); return 0; } static struct db_ops pgsql_ops = { .open = pgsql_open_conn, .close = pgsql_close_conn, .check = pgsql_check_conn, .conf_destroy = pgsql_conf_destroy, .update = pgsql_update, .select = pgsql_select }; #endif /* HAVE_PGSQL */ gateway-1.4.5/gwlib/parse.c0000644000175000017500000002042613227613126014255 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * parse.c - implement parse.h interface * * Richard Braakman */ #include "gwlib/gwlib.h" struct context { Octstr *data; long pos; long limit; List *limit_stack; int error; }; ParseContext *parse_context_create(Octstr *str) { ParseContext *result; result = gw_malloc(sizeof(*result)); result->data = str; result->pos = 0; result->limit = octstr_len(str); result->limit_stack = NULL; result->error = 0; return result; } void parse_context_destroy(ParseContext *context) { gw_assert(context != NULL); if (context->limit_stack) { while (gwlist_len(context->limit_stack) > 0) gw_free(gwlist_extract_first(context->limit_stack)); gwlist_destroy(context->limit_stack, NULL); } gw_free(context); } int parse_error(ParseContext *context) { gw_assert(context != NULL); return context->error; } void parse_clear_error(ParseContext *context) { gw_assert(context != NULL); context->error = 0; } void parse_set_error(ParseContext *context) { gw_assert(context != NULL); context->error = 1; } int parse_limit(ParseContext *context, long length) { long *elem; gw_assert(context != NULL); if (context->pos + length > context->limit) { context->error = 1; return -1; } if (context->limit_stack == NULL) context->limit_stack = gwlist_create(); elem = gw_malloc(sizeof(*elem)); *elem = context->limit; gwlist_insert(context->limit_stack, 0, elem); context->limit = context->pos + length; return 0; } int parse_pop_limit(ParseContext *context) { long *elem; gw_assert(context != NULL); if (context->limit_stack == NULL || gwlist_len(context->limit_stack) == 0) { context->error = 1; return -1; } elem = gwlist_extract_first(context->limit_stack); context->limit = *elem; gw_free(elem); return 0; } long parse_octets_left(ParseContext *context) { gw_assert(context != NULL); return context->limit - context->pos; } int parse_skip(ParseContext *context, long count) { gw_assert(context != NULL); if (context->pos + count > context->limit) { context->pos = context->limit; context->error = 1; return -1; } context->pos += count; return 0; } void parse_skip_to_limit(ParseContext *context) { gw_assert(context != NULL); context->pos = context->limit; } int parse_skip_to(ParseContext *context, long pos) { gw_assert(context != NULL); if (pos < 0) { context->error = 1; return -1; } if (pos > context->limit) { context->pos = context->limit; context->error = 1; return -1; } context->pos = pos; return 0; } int parse_peek_char(ParseContext *context) { gw_assert(context != NULL); if (context->pos == context->limit) { context->error = 1; return -1; } return octstr_get_char(context->data, context->pos); } int parse_get_char(ParseContext *context) { gw_assert(context != NULL); if (context->pos == context->limit) { context->error = 1; return -1; } return octstr_get_char(context->data, context->pos++); } Octstr *parse_get_octets(ParseContext *context, long length) { Octstr *result; gw_assert(context != NULL); if (context->pos + length > context->limit) { context->error = 1; return NULL; } result = octstr_copy(context->data, context->pos, length); context->pos += length; return result; } unsigned long parse_get_uintvar(ParseContext *context) { long pos; unsigned long value; gw_assert(context != NULL); pos = octstr_extract_uintvar(context->data, &value, context->pos); if (pos < 0 || pos > context->limit) { context->error = 1; return 0; } context->pos = pos; return value; } Octstr *parse_get_nul_string(ParseContext *context) { Octstr *result; long pos; gw_assert(context != NULL); pos = octstr_search_char(context->data, 0, context->pos); if (pos < 0 || pos >= context->limit) { context->error = 1; return NULL; } result = octstr_copy(context->data, context->pos, pos - context->pos); context->pos = pos + 1; return result; } Octstr *parse_get_line(ParseContext *context) { Octstr *result; long pos; gw_assert(context != NULL); pos = octstr_search_char(context->data, '\n', context->pos); if (pos < 0 || pos >= context->limit) { context->error = 1; return NULL; } result = octstr_copy(context->data, context->pos, pos - context->pos); context->pos = pos + 1; octstr_strip_crlfs(result); return result; } Octstr *parse_get_seperated_block(ParseContext *context, Octstr *seperator) { Octstr *result; long spos, epos; gw_assert(context != NULL); gw_assert(seperator != NULL); spos = octstr_search(context->data, seperator, context->pos); if (spos < 0 || spos >= context->limit) { context->error = 1; return NULL; } epos = octstr_search(context->data, seperator, spos + octstr_len(seperator)); if (epos < 0 || epos >= context->limit) { context->error = 1; return NULL; } spos = spos + octstr_len(seperator); result = octstr_copy(context->data, spos, epos - spos); context->pos = epos; return result; } Octstr *parse_get_rest(ParseContext *context) { Octstr *rest; gw_assert(context != NULL); octstr_delete(context->data, 0, context->pos); rest = octstr_duplicate(context->data); return rest; } gateway-1.4.5/gwlib/protected.h0000644000175000017500000001002213227613126015130 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * protected.h - thread-safe versions of standard library functions * * The standard (or commonly available) C library functions are not always * thread-safe, or re-entrant. This module provides wrappers. The wrappers * are not always the most efficient, but the interface is meant to * allow a more efficient version be implemented later. * * Lars Wirzenius */ #ifndef PROTECTED_H #define PROTECTED_H #include #include void gwlib_protected_init(void); void gwlib_protected_shutdown(void); struct tm gw_localtime(time_t t); struct tm gw_gmtime(time_t t); time_t gw_mktime(struct tm *tm); int gw_rand(void); int gw_gethostbyname(struct hostent *ret, const char *name, char **buff); size_t gw_strftime(char *s, size_t max, const char *format, const struct tm *tm); /* * Make it harder to use these by mistake. */ #undef localtime #define localtime(t) do_not_use_localtime_directly #undef gmtime #define gmtime(t) do_not_use_gmtime_directly #undef mktime #define mktime(t) do_not_use_mktime_directly #undef strftime #define strftime(a, b, c, d) do_not_use_strftime_directly #undef rand #define rand() do_not_use_rand_directly #undef gethostbyname #define gethostbyname(a, b, c) do_not_use_gethostbyname_directly #undef inet_ntoa #define inet_ntoa(in) use_gw_netaddr_to_octstr_instead_of_inet_ntoa #endif gateway-1.4.5/gwlib/date.h0000644000175000017500000001120513227613126014060 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * date.h - interface to utilities for handling date and time values * * Richard Braakman */ #include "gwlib.h" /* Broken-down time structure without timezone. The values are * longs because that makes them easier to use with octstr_parse_long(). */ struct universaltime { long day; /* 1-31 */ long month; /* 0-11 */ long year; /* 1970- */ long hour; /* 0-23 */ long minute; /* 0-59 */ long second; /* 0-59 */ }; /* Calculate the unix time value (seconds since 1970) given a broken-down * date structure in GMT. */ long date_convert_universal(struct universaltime *t); /* * Convert a unix time value to a value of the form * Sun, 06 Nov 1994 08:49:37 GMT * This is the format required by the HTTP protocol (RFC 2616), * and it is defined in RFC 822 as updated by RFC 1123. */ Octstr *date_format_http(unsigned long unixtime); /* * Convert a date string as defined by the HTTP protocol (RFC 2616) * to a unix time value. Return -1 if the date string was invalid. * Three date formats are acceptable: * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format * White space is significant. */ long date_parse_http(Octstr *date); /* * attempt to read an ISO-8601 format or similar, making no assumptions on * seperators and number of elements, adding 0 or 1 to missing fields * For example, acceptable formats : * 2002-05-15 13:23:44 * 02/05/15:13:23 * support of 2 digit years is done by assuming years 70 an over are 20th century. this will * have to be revised sometime in the next 50 or so years */ int date_parse_iso(struct universaltime *ut, Octstr *os); /* * create an ISO-8601 formated time stamp */ Octstr* date_create_iso(time_t unixtime); /* * Return the current date and time as a unix time value. */ long date_universal_now(void); gateway-1.4.5/gwlib/fdset.c0000644000175000017500000004276213227613126014257 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * fdset.c - module for managing a large collection of file descriptors */ #include "gw-config.h" #include #include #include #include "gwlib/gwlib.h" struct FDSet { /* Thread ID of the set's internal thread, which will spend most * of its time blocking on poll(). This is set when the thread * is created, and not changed after that. It's not protected * by any lock. */ long poll_thread; /* The following fields are for use by the polling thread only. * No-one else may touch them. It's not protected by any lock. */ /* Array for use with poll(). Elements 0 through size-1 are allocated. * Elements 0 through entries-1 are in use. */ struct pollfd *pollinfo; int size; int entries; /* Array of times when appropriate fd got any event or events bitmask changed */ time_t *times; /* timeout for this fdset */ long timeout; /* Arrays of callback and data fields. They are kept in sync with * the pollinfo array, and are basically extra fields that we couldn't * put in struct pollfd because that structure is defined externally. */ fdset_callback_t **callbacks; void **datafields; /* The poller function loops over the table after poll() returns, * and calls callback functions that may modify the table that is * being scanned. We can't just copy the table to avoid interference, * because fdset_unregister and fdset_listen guarantee that their * operations are complete when they return -- that does not work * if poller() is scanning an outdated copy of the table. * To solve this, we have a field that marks when the table is * being scanned. If this field is true, fdset_unregister merely * sets the fd to -1 instead of deleting the whole entry. * fdset_listen will takes care to modify revents as well as * events. fdset_register always adds to the end of the table, * so it does not have to do anything special. */ int scanning; /* This field keeps track of how many fds were set to -1 by * fdset_unregister while "scanning" is true. That way we can * efficiently check if we need to scan the table to really * delete those entries. */ int deleted_entries; /* The following fields are for general use, and are of types that * have internal locks. */ /* List of struct action. Used by other threads to make requests * of the polling thread. */ List *actions; }; /* Datatype to describe changes to the fdset fields that only the polling * thread may touch. Other threads use this type to submit requests to * change those fields. */ /* Action life cycle: Created, then pushed on set->actions list by * action_submit. Poller thread wakes up and takes it from the list, * then calls handle_action, which performs the action and pushes it * on the action's done list. action_submit then takes it back and * destroys it. */ /* If no synchronization is needed, action_submit_nosync can be used. * In that case handle_action will destroy the action itself instead * of putting it on any list. */ struct action { enum { REGISTER, LISTEN, UNREGISTER, DESTROY, SET_TIMEOUT } type; int fd; /* Used by REGISTER, LISTEN, and UNREGISTER */ int mask; /* Used by LISTEN */ int events; /* Used by REGISTER and LISTEN */ fdset_callback_t *callback; /* Used by REGISTER */ void *data; /* Used by REGISTER */ long timeout; /* Used by SET_TIMEOUT */ /* When the request has been handled, an element is produced on this * list, so that the submitter can synchronize. Can be left NULL. */ List *done; /* Used by LISTEN, UNREGISTER, and DESTROY */ }; /* Return a new action structure of the given type, with all fields empty. */ static struct action *action_create(int type) { struct action *new; new = gw_malloc(sizeof(*new)); new->type = type; new->fd = -1; new->mask = 0; new->events = 0; new->callback = NULL; new->data = NULL; new->done = NULL; return new; } static void action_destroy(struct action *action) { if (action == NULL) return; gwlist_destroy(action->done, NULL); gw_free(action); } /* For use with gwlist_destroy */ static void action_destroy_item(void *action) { action_destroy(action); } /* * Submit an action for this set, and wait for the polling thread to * confirm that it's been done, by pushing the action on its done list. */ static void submit_action(FDSet *set, struct action *action) { List *done; void *sync; gw_assert(set != NULL); gw_assert(action != NULL); done = gwlist_create(); gwlist_add_producer(done); action->done = done; gwlist_append(set->actions, action); gwthread_wakeup(set->poll_thread); sync = gwlist_consume(done); gw_assert(sync == action); action_destroy(action); } /* * As above, but don't wait for confirmation. */ static void submit_action_nosync(FDSet *set, struct action *action) { gwlist_append(set->actions, action); gwthread_wakeup(set->poll_thread); } /* Do one action for this thread and confirm that it's been done by * appending the action to its done list. May only be called by * the polling thread. Returns 0 normally, and returns -1 if the * action destroyed the set. */ static int handle_action(FDSet *set, struct action *action) { int result; gw_assert(set != NULL); gw_assert(set->poll_thread == gwthread_self()); gw_assert(action != NULL); result = 0; switch (action->type) { case REGISTER: fdset_register(set, action->fd, action->events, action->callback, action->data); break; case LISTEN: fdset_listen(set, action->fd, action->mask, action->events); break; case UNREGISTER: fdset_unregister(set, action->fd); break; case DESTROY: fdset_destroy(set); result = -1; break; case SET_TIMEOUT: set->timeout = action->timeout; break; default: panic(0, "fdset: handle_action got unknown action type %d.", action->type); } if (action->done == NULL) action_destroy(action); else gwlist_produce(action->done, action); return result; } /* Look up the entry number in the pollinfo array for this fd. * Right now it's a linear search, this may have to be improved. */ static int find_entry(FDSet *set, int fd) { int i; gw_assert(set != NULL); gw_assert(gwthread_self() == set->poll_thread); for (i = 0; i < set->entries; i++) { if (set->pollinfo[i].fd == fd) return i; } return -1; } static void remove_entry(FDSet *set, int entry) { if (entry != set->entries - 1) { /* We need to keep the array contiguous, so move the last element * to fill in the hole. */ set->pollinfo[entry] = set->pollinfo[set->entries - 1]; set->callbacks[entry] = set->callbacks[set->entries - 1]; set->datafields[entry] = set->datafields[set->entries - 1]; set->times[entry] = set->times[set->entries - 1]; } set->entries--; } static void remove_deleted_entries(FDSet *set) { int i; i = 0; while (i < set->entries && set->deleted_entries > 0) { if (set->pollinfo[i].fd < 0) { remove_entry(set, i); set->deleted_entries--; } else { i++; } } } /* Main function for polling thread. Most its time is spent blocking * in poll(). No-one else is allowed to change the fields it uses, * so other threads just put something on the actions list and wake * up this thread. That's why it checks the actions list every time * it goes through the loop. */ static void poller(void *arg) { FDSet *set = arg; struct action *action; int ret; int i; time_t now; gw_assert(set != NULL); for (;;) { while ((action = gwlist_extract_first(set->actions)) != NULL) { /* handle_action returns -1 if the set was destroyed. */ if (handle_action(set, action) < 0) return; } /* Block for defined timeout, waiting for activity */ ret = gwthread_poll(set->pollinfo, set->entries, set->timeout); if (ret < 0) { if (errno != EINTR) { error(errno, "Poller: can't handle error; sleeping 1 second."); gwthread_sleep(1.0); } continue; } time(&now); /* Callbacks may modify the table while we scan it, so be careful. */ set->scanning = 1; for (i = 0; i < set->entries; i++) { if (set->pollinfo[i].revents != 0) { set->callbacks[i](set->pollinfo[i].fd, set->pollinfo[i].revents, set->datafields[i]); /* update event time */ time(&set->times[i]); } else if (set->timeout > 0 && difftime(set->times[i] + set->timeout, now) <= 0) { debug("gwlib.fdset", 0, "Timeout for fd:%d appears.", set->pollinfo[i].fd); set->callbacks[i](set->pollinfo[i].fd, POLLERR, set->datafields[i]); } } set->scanning = 0; if (set->deleted_entries > 0) remove_deleted_entries(set); } } FDSet *fdset_create_real(long timeout) { FDSet *new; new = gw_malloc(sizeof(*new)); /* Start off with space for one element because we can't malloc 0 bytes * and we don't want to worry about these pointers being NULL. */ new->size = 1; new->entries = 0; new->pollinfo = gw_malloc(sizeof(new->pollinfo[0]) * new->size); new->callbacks = gw_malloc(sizeof(new->callbacks[0]) * new->size); new->datafields = gw_malloc(sizeof(new->datafields[0]) * new->size); new->times = gw_malloc(sizeof(new->times[0]) * new->size); new->timeout = timeout > 0 ? timeout : -1; new->scanning = 0; new->deleted_entries = 0; new->actions = gwlist_create(); new->poll_thread = gwthread_create(poller, new); if (new->poll_thread < 0) { error(0, "Could not start internal thread for fdset."); fdset_destroy(new); return NULL; } return new; } void fdset_destroy(FDSet *set) { if (set == NULL) return; if (set->poll_thread < 0 || gwthread_self() == set->poll_thread) { if (set->entries > 0) { warning(0, "Destroying fdset with %d active entries.", set->entries); } gw_free(set->pollinfo); gw_free(set->callbacks); gw_free(set->datafields); gw_free(set->times); if (gwlist_len(set->actions) > 0) { error(0, "Destroying fdset with %ld pending actions.", gwlist_len(set->actions)); } gwlist_destroy(set->actions, action_destroy_item); gw_free(set); } else { long thread = set->poll_thread; submit_action(set, action_create(DESTROY)); gwthread_join(thread); } } void fdset_register(FDSet *set, int fd, int events, fdset_callback_t callback, void *data) { int new; gw_assert(set != NULL); if (gwthread_self() != set->poll_thread) { struct action *action; action = action_create(REGISTER); action->fd = fd; action->events = events; action->callback = callback; action->data = data; submit_action_nosync(set, action); return; } gw_assert(set->entries <= set->size); if (set->entries >= set->size) { int newsize = set->entries + 1; set->pollinfo = gw_realloc(set->pollinfo, sizeof(set->pollinfo[0]) * newsize); set->callbacks = gw_realloc(set->callbacks, sizeof(set->callbacks[0]) * newsize); set->datafields = gw_realloc(set->datafields, sizeof(set->datafields[0]) * newsize); set->times = gw_realloc(set->times, sizeof(set->times[0]) * newsize); set->size = newsize; } /* We don't check set->scanning. Adding new entries is not harmful * because their revents fields are 0. */ new = set->entries++; set->pollinfo[new].fd = fd; set->pollinfo[new].events = events; set->pollinfo[new].revents = 0; set->callbacks[new] = callback; set->datafields[new] = data; time(&set->times[new]); } void fdset_listen(FDSet *set, int fd, int mask, int events) { int entry; gw_assert(set != NULL); if (gwthread_self() != set->poll_thread) { struct action *action; action = action_create(LISTEN); action->fd = fd; action->mask = mask; action->events = events; submit_action(set, action); return; } entry = find_entry(set, fd); if (entry < 0) { warning(0, "fdset_listen called on unregistered fd %d.", fd); return; } /* Copy the bits from events specified by the mask, and preserve the * bits not specified by the mask. */ set->pollinfo[entry].events = (set->pollinfo[entry].events & ~mask) | (events & mask); /* If poller is currently scanning the array, then change the * revents field so that the callback function will not be called * for events we should no longer listen for. The idea is the * same as for the events field, except that we only turn bits off. */ if (set->scanning) { set->pollinfo[entry].revents = set->pollinfo[entry].revents & (events | ~mask); } time(&set->times[entry]); } void fdset_unregister(FDSet *set, int fd) { int entry; gw_assert(set != NULL); if (gwthread_self() != set->poll_thread) { struct action *action; action = action_create(UNREGISTER); action->fd = fd; submit_action(set, action); return; } /* Remove the entry from the pollinfo array */ entry = find_entry(set, fd); if (entry < 0) { warning(0, "fdset_listen called on unregistered fd %d.", fd); return; } if (entry == set->entries - 1) { /* It's the last entry. We can safely remove it even while * the array is being scanned, because the scan checks set->entries. */ set->entries--; } else if (set->scanning) { /* We can't remove entries because the array is being * scanned. Mark it as deleted. */ set->pollinfo[entry].fd = -1; set->deleted_entries++; } else { remove_entry(set, entry); } } void fdset_set_timeout(FDSet *set, long timeout) { gw_assert(set != NULL); if (gwthread_self() != set->poll_thread) { struct action *action; action = action_create(SET_TIMEOUT); action->timeout = timeout; submit_action(set, action); return; } set->timeout = timeout; } gateway-1.4.5/gwlib/md5.c0000644000175000017500000003251113227613126013626 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * md5.c - MD5 digest algorithm * * The remaining code is the reference MD5 code (md5c.c) from rfc1321 */ /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ #include #include "gwlib.h" #include "md5.h" /* Declaration of static functions */ static void md5_digest(char *md5str, unsigned char *digest); static void md5_init(md5_ctx *); static void md5_update(md5_ctx *, const unsigned char *, unsigned int); static void md5_final(unsigned char[16], md5_ctx *); static void md5_digest(char *md5str, unsigned char *digest) { int i; for (i = 0; i < 16; i++) { sprintf(md5str, "%02x", digest[i]); md5str += 2; } *md5str = '\0'; } /* * Constants for MD5Transform routine. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 static void md5_transform(unsigned int[4], const unsigned char[64]); static void md5_encode(unsigned char *, unsigned int *, unsigned int); static void md5_decode(unsigned int *, const unsigned char *, unsigned int); static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) /* ROTATE_LEFT rotates x left n bits. */ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ #define FF(a, b, c, d, x, s, ac) { \ (a) += F ((b), (c), (d)) + (x) + (unsigned int)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + (unsigned int)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + (unsigned int)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + (unsigned int)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } static void md5_init(md5_ctx *context) { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; context->state[2] = 0x98badcfe; context->state[3] = 0x10325476; } /* * MD5 block update operation. Continues an MD5 message-digest * operation, processing another message block, and updating the * context. */ static void md5_update(md5_ctx *context, const unsigned char *input, unsigned int inputLen) { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int) ((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((unsigned int) inputLen << 3)) < ((unsigned int) inputLen << 3)) context->count[1]++; context->count[1] += ((unsigned int) inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { memcpy((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen); md5_transform(context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) md5_transform(context->state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ memcpy((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], inputLen - i); } /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */ static void md5_final(unsigned char digest[16], md5_ctx *context) { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ md5_encode(bits, context->count, 8); /* Pad out to 56 mod 64. */ index = (unsigned int) ((context->count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); md5_update(context, PADDING, padLen); /* Append length (before padding) */ md5_update(context, bits, 8); /* Store state in digest */ md5_encode(digest, context->state, 16); /* Zeroize sensitive information. */ memset((unsigned char*) context, 0, sizeof(*context)); } /* * MD5 basic transformation. Transforms state based on block. */ static void md5_transform(state, block) unsigned int state[4]; const unsigned char block[64]; { unsigned int a = state[0], b = state[1], c = state[2], d = state[3], x[16]; md5_decode(x, block, 64); /* Round 1 */ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ memset((unsigned char*) x, 0, sizeof(x)); } /* Encodes input (unsigned int) into output (unsigned char). Assumes len is a multiple of 4. */ static void md5_encode(output, input, len) unsigned char *output; unsigned int *input; unsigned int len; { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char) (input[i] & 0xff); output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff); output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff); output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (unsigned int). Assumes len is a multiple of 4. */ static void md5_decode(output, input, len) unsigned int *output; const unsigned char *input; unsigned int len; { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((unsigned int) input[j]) | (((unsigned int) input[j + 1]) << 8) | (((unsigned int) input[j + 2]) << 16) | (((unsigned int) input[j + 3]) << 24); } Octstr *md5(Octstr *data) { md5_ctx context; unsigned char digest[16]; Octstr *enc; if (data == NULL) return NULL; md5_init(&context); md5_update(&context, octstr_get_cstr(data), octstr_len(data)); md5_final(digest, &context); enc = octstr_create_from_data(digest, 16); return enc; } Octstr *md5digest(Octstr *data) { char md5str[33]; Octstr *digest; if (data == NULL) return NULL; md5str[0] = '\0'; digest = md5(data); md5_digest(md5str, octstr_get_cstr(digest)); octstr_destroy(digest); digest = octstr_create(md5str); return digest; } gateway-1.4.5/gwlib/parse.h0000644000175000017500000001651213227613126014263 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * parse.h - functions for octet-by-octet parsing of an octstr * * Interface to keep track of position in an octstr, and remember * error conditions so that they can be checked after a bunch of * calls. Also allows temporary clipping of the string, so that * parsing doesn't go past a boundary until it's explicitly allowed * to. This helps parse strings containing length-defined chunks. * * The main use of this interface is to simplify code that does * this kind of parsing, so that it can pass around a single * ParseContext value instead of an octstr and one or more offset * and length parameters. * * Note: The octstr involved MUST NOT change during parsing. * * Richard Braakman */ #ifndef PARSE_H #define PARSE_H typedef struct context ParseContext; /* * Return a ParseContext object for this octstr, with parsing starting * at position 0 and the limit at the end of the string. */ ParseContext *parse_context_create(Octstr *str); /* * Destroy a ParseContext object. Note that this does not free the string * that was parsed. */ void parse_context_destroy(ParseContext *context); /* * Return -1 if any error has occurred during parsing, otherwise 0. */ int parse_error(ParseContext *context); /* * Clear the error flag for the next call to parse_error. */ void parse_clear_error(ParseContext *context); /* * Set the error flag. */ void parse_set_error(ParseContext *context); /* * Set a new "end" of the string, for parsing purposes, at length * octets from the current position. Return 0 if it's okay. * If it doesn't fit in the current limit, don't do anything and * return -1. */ int parse_limit(ParseContext *context, long length); /* * Restore the previous "end" of the string. Limits can be stacked * as deeply as needed. The original limit (end-of-string) can * not be popped. Return -1 and set the error flag if there was * nothing to pop, otherwise return 0. */ int parse_pop_limit(ParseContext *context); /* * Return the number of octets between the current position and * the current limit. */ long parse_octets_left(ParseContext *context); /* * Skip count octets. If that would go past the limit, return -1, * skip to the limit, and set the error flag. Otherwise return 0. */ int parse_skip(ParseContext *context, long count); /* * Skip to the current limit. Cannot fail. */ void parse_skip_to_limit(ParseContext *context); /* * Set offset to new position. If that would go past the limit, return * -1, skip to the limit, and set the error flag. Otherwise return 0. */ int parse_skip_to(ParseContext *context, long pos); /* * Return the next octet, but do not skip over it. * If already at the limit, return -1 and set the error flag. */ int parse_peek_char(ParseContext *context); /* * Return the next octet and skip one position forward. * If already at the limit, return -1 and set the error flag. */ int parse_get_char(ParseContext *context); /* * Return "length" octets starting at current position, and skip * that many octets forward. If that would go over the limit, * return NULL, do not skip, and set the error flag. */ Octstr *parse_get_octets(ParseContext *context, long length); /* * Return the value of an uintvar-encoded integer at current * position, then skip over it. If there's an error in the * encoding, or if it would go past the limit, then return 0, * do not skip, and set the error flag. Since 0 is a valid * uintvar value, the error flag is only way to detect this error. */ unsigned long parse_get_uintvar(ParseContext *context); /* * Look for a NUL-terminated string starting at the current offset, * and return it (without the NUL) as an Octstr. Skip forward past * the NUL. If there is no NUL, return NULL and set the error flag. */ Octstr *parse_get_nul_string(ParseContext *context); /* * Look for a EOL-terminated line starting at the current offset, * and return it (without the EOL) as an Octstr. Skip forward past * the EOL. If there is no EOL, return NULL and set the error flag. */ Octstr *parse_get_line(ParseContext *context); /* * Look for an Octstr block that is between two seperators defined by * the seperator Octstr. Return the Octstr between the seperators and * move the parsing context up before the last of the two seperators. * So the last seperator is next in the parsing scope. If there are * no two seperators in the parsing scope return NULL. */ Octstr *parse_get_seperated_block(ParseContext *context, Octstr *seperator); /* * Return unparsed content. This should be used only after all * headers are parsed (and the headers and content are stored in * same octstr). */ Octstr *parse_get_rest(ParseContext *context); #endif gateway-1.4.5/gwlib/pcre.h0000644000175000017500000001222613227613126014100 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * pcre.h - Perl compatible regular expressions (PCREs) * * This modules implements wrapper functions to the pcre_foobar() et all * functions implemented in the libpcre.a library. * PCRE is a library of functions to support regular expressions whose syntax * and semantics are as close as possible to those of the Perl 5 language. * * See http://www.pcre.org/ for more details on PCRE regular expressions. * * Stipe Tolj */ #ifndef PCRE_H #define PCRE_H #ifdef HAVE_PCRE #include #define PCRE_OVECCOUNT 30 /* should be a multiple of 3 */ /* * Compile a regular expression provided by pattern and return * the regular expression type as function result. * If the compilation fails, return NULL. */ pcre *gw_pcre_comp_real(const Octstr *pattern, int cflags, const char *file, long line, const char *func); #define gw_pcre_comp(pattern, cflags) \ gw_pcre_comp_real(pattern, cflags, __FILE__, __LINE__, __func__) /* * Execute a previously compile regular expression on a given * string and provide the matches via nmatch and pmatch[]. */ int gw_pcre_exec_real(const pcre *preg, const Octstr *string, int start, int eflags, int *ovector, int oveccount, const char *file, long line, const char *func); #define gw_pcre_exec(preg, string, start, eflags, ovector, oveccount) \ gw_pcre_exec_real(preg, string, start, eflags, ovector, oveccount, \ __FILE__, __LINE__, __func__) /* * Match directly a given regular expression and a source string. This assumes * that the RE has not been pre-compiled and hence perform the compile and * exec step in this matching step. * Return 1 if the regular expression is successfully matching, 0 otherwise. */ int gw_pcre_match_real(const Octstr *re, const Octstr *os, const char *file, long line, const char *func); #define gw_pcre_match(re, os) \ gw_pcre_match_real(re, os, __FILE__, __LINE__, __func__) /* * Match directly a given source string against a previously pre-compiled * regular expression. * Return 1 if the regular expression is successfully matching, 0 otherwise. */ int gw_pcre_match_pre_real(const pcre *preg, const Octstr *os, const char *file, long line, const char *func); #define gw_pcre_match_pre(preg, os) \ gw_pcre_match_pre_real(preg, os, __FILE__, __LINE__, __func__) #endif /* HAVE_PCRE */ #endif /* PCRE_H */ gateway-1.4.5/gwlib/regex.c0000644000175000017500000002462213227613126014257 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * regex.c - POSIX regular expressions (REs) * * This modules implements wrapper functions to regcomp(3), regexec(3), * et all functions from the POSIX compliance standard. Additinally * it provides subexpression substitution routines in order to easily * substitute strings arround regular expressions. * * See regex(3) man page for more details on POSIX regular expressions. * * Stipe Tolj */ #include #include "gwlib/gwlib.h" #include "regex.h" /* * We allow to substitute the POSIX compliant regex routines via PCRE * provided routines if no system own regex implementation is available. */ #if defined(HAVE_REGEX) || defined(HAVE_PCRE) /******************************************************************** * Generic regular expression functions. */ void gw_regex_destroy(regex_t *preg) { if (preg == NULL) return; regfree(preg); gw_free(preg); } regex_t *gw_regex_comp_real(const Octstr *pattern, int cflags, const char *file, long line, const char *func) { int rc; regex_t *preg; preg = gw_malloc(sizeof(regex_t)); if ((rc = regcomp(preg, pattern ? octstr_get_cstr(pattern) : NULL, cflags)) != 0) { char buffer[512]; regerror(rc, preg, buffer, sizeof(buffer)); error(0, "%s:%ld: %s: regex compilation `%s' failed: %s (Called from %s:%ld:%s.)", __FILE__, (long) __LINE__, __func__, octstr_get_cstr(pattern), buffer, (file), (long) (line), (func)); gw_free(preg); return NULL; } return preg; } int gw_regex_exec_real(const regex_t *preg, const Octstr *string, size_t nmatch, regmatch_t pmatch[], int eflags, const char *file, long line, const char *func) { int rc; gw_assert(preg != NULL); rc = regexec(preg, string ? octstr_get_cstr(string) : NULL, nmatch, pmatch, eflags); if (rc != REG_NOMATCH && rc != 0) { char buffer[512]; regerror(rc, preg, buffer, sizeof(buffer)); error(0, "%s:%ld: %s: regex execution on `%s' failed: %s (Called from %s:%ld:%s.)", __FILE__, (long) __LINE__, __func__, octstr_get_cstr(string), buffer, (file), (long) (line), (func)); } return rc; } Octstr *gw_regex_error(int errcode, const regex_t *preg) { char errbuf[512]; Octstr *os; regerror(errcode, preg, errbuf, sizeof(errbuf)); os = octstr_create(errbuf); return os; } /* Duplicate a string. */ static char *pstrdup(const char *s) { char *res; size_t len; if (s == NULL) return NULL; len = strlen(s) + 1; res = gw_malloc(len); memcpy(res, s, len); return res; } /* This function substitutes for $0-$9, filling in regular expression * submatches. Pass it the same nmatch and pmatch arguments that you * passed gw_regexec(). pmatch should not be greater than the maximum number * of subexpressions - i.e. one more than the re_nsub member of regex_t. * * input should be the string with the $-expressions, source should be the * string that was matched against. * * It returns the substituted string, or NULL on error. * BEWARE: Caller must free allocated memory of the result. * * Parts of this code are based on Henry Spencer's regsub(), from his * AT&T V8 regexp package. Function borrowed from apache-1.3/src/main/util.c */ char *gw_regex_sub(const char *input, const char *source, size_t nmatch, regmatch_t pmatch[]) { const char *src = input; char *dest, *dst; char c; size_t no; int len; if (!source) return NULL; if (!nmatch) return pstrdup(src); /* First pass, find the size */ len = 0; while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '$' && isdigit(*src)) no = *src++ - '0'; else no = 10; if (no > 9) { /* Ordinary character. */ if (c == '\\' && (*src == '$' || *src == '&')) c = *src++; len++; } else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { len += pmatch[no].rm_eo - pmatch[no].rm_so; } } dest = dst = gw_malloc(len + 1); /* Now actually fill in the string */ src = input; while ((c = *src++) != '\0') { if (c == '&') no = 0; else if (c == '$' && isdigit(*src)) no = *src++ - '0'; else no = 10; if (no > 9) { /* Ordinary character. */ if (c == '\\' && (*src == '$' || *src == '&')) c = *src++; *dst++ = c; } else if (no < nmatch && pmatch[no].rm_so < pmatch[no].rm_eo) { len = pmatch[no].rm_eo - pmatch[no].rm_so; memcpy(dst, source + pmatch[no].rm_so, len); dst += len; } } *dst = '\0'; return dest; } /******************************************************************** * Matching and substitution wrapper functions. * * Beware that the regex compilation takes the most significant CPU time, * so always try to have pre-compiled regular expressions that keep being * reused and re-matched on variable string patterns. */ int gw_regex_match_real(const Octstr *re, const Octstr *os, const char *file, long line, const char *func) { regex_t *regexp; int rc; /* compile */ regexp = gw_regex_comp_real(re, REG_EXTENDED|REG_ICASE, file, line, func); if (regexp == NULL) return 0; /* execute and match */ rc = gw_regex_exec_real(regexp, os, 0, NULL, 0, file, line, func); gw_regex_destroy(regexp); return (rc == 0) ? 1 : 0; } int gw_regex_match_pre_real(const regex_t *preg, const Octstr *os, const char *file, long line, const char *func) { int rc; gw_assert(preg != NULL); /* execute and match */ rc = gw_regex_exec_real(preg, os, 0, NULL, 0, file, line, func); return (rc == 0) ? 1 : 0; } Octstr *gw_regex_subst_real(const Octstr *re, const Octstr *os, const Octstr *rule, const char *file, long line, const char *func) { Octstr *result; regex_t *regexp; regmatch_t pmatch[REGEX_MAX_SUB_MATCH]; int rc; char *rsub; /* compile */ regexp = gw_regex_comp_real(re, REG_EXTENDED|REG_ICASE, file, line, func); if (regexp == NULL) return 0; /* execute and match */ rc = gw_regex_exec_real(regexp, os, REGEX_MAX_SUB_MATCH, &pmatch[0], 0, file, line, func); gw_regex_destroy(regexp); /* substitute via rule if matched */ if (rc != 0) return NULL; rsub = gw_regex_sub(octstr_get_cstr(rule), octstr_get_cstr(os), REGEX_MAX_SUB_MATCH, &pmatch[0]); if (rsub == NULL) return NULL; result = octstr_create(rsub); gw_free(rsub); return result; } Octstr *gw_regex_subst_pre_real(const regex_t *preg, const Octstr *os, const Octstr *rule, const char *file, long line, const char *func) { Octstr *result; regmatch_t pmatch[REGEX_MAX_SUB_MATCH]; int rc; char *rsub; gw_assert(preg != NULL); /* execute and match */ rc = gw_regex_exec_real(preg, os, REGEX_MAX_SUB_MATCH, &pmatch[0], 0, file, line, func); /* substitute via rule if matched */ if (rc != 0) return NULL; rsub = gw_regex_sub(octstr_get_cstr(rule), octstr_get_cstr(os), REGEX_MAX_SUB_MATCH, &pmatch[0]); if (rsub == NULL) return NULL; result = octstr_create(rsub); gw_free(rsub); return result; } #endif /* HAVE_REGEX || HAVE_PCRE */ gateway-1.4.5/gwlib/log.c0000644000175000017500000004611013307520564013724 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * log.c - implement logging functions */ #include "gwlib.h" #include #include #include #include #include #include #include #include #ifdef HAVE_EXECINFO_H #include #endif #if HAVE_SYSLOG_H #ifdef __sun__ #include typedef struct _code { char *c_name; int c_val; } CODE; CODE facilitynames[] = { { "auth", LOG_AUTH }, /* { "authpriv", LOG_AUTHPRIV }, */ { "cron", LOG_CRON }, { "daemon", LOG_DAEMON }, /* { "ftp", LOG_FTP }, */ { "kern", LOG_KERN }, { "lpr", LOG_LPR }, { "mail", LOG_MAIL }, /* { "mark", INTERNAL_MARK }, */ /* INTERNAL */ { "news", LOG_NEWS }, { "security", LOG_AUTH }, /* DEPRECATED */ { "syslog", LOG_SYSLOG }, { "user", LOG_USER }, { "uucp", LOG_UUCP }, { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, { NULL, -1 } }; #else #define SYSLOG_NAMES #include #endif /* * Decode the syslog name to its int value */ static int decode(char *name) { register CODE *c; CODE *facilities = facilitynames; if (isdigit(*name)) { return (atoi(name)); } for (c = facilities; c->c_name; c++) { if (!strcasecmp(name, c->c_name)) { return (c->c_val); } } return LOG_DAEMON; } #else /* * If we don't have syslog.h, then we'll use the following dummy definitions * to avoid writing #if HAVE_SYSLOG_H everywhere. */ enum { LOG_PID, LOG_DAEMON, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_ALERT }; static int decode(char *name) { return LOG_DAEMON; } static void openlog(const char *ident, int option, int facility) { } static void syslog(int translog, const char *msg, ...) { } static void closelog(void) { } #endif /* * List of currently open log files. */ #define MAX_LOGFILES 128 static struct { FILE *file; int minimum_output_level; char filename[FILENAME_MAX + 1]; /* to allow re-open */ enum excl_state exclusive; } logfiles[MAX_LOGFILES]; static int num_logfiles = 0; /* * Mapping array between thread id and logfiles[] index. * This is used for smsc specific logging. */ #define THREADTABLE_SIZE 1024 static unsigned int thread_to[(long)THREADTABLE_SIZE]; /* * Ensure we use the real threadtable slot number to map the thread id * instead of the thread id reported by gwthread_self() */ #define thread_slot() \ (gwthread_self() % THREADTABLE_SIZE) /* * List of places that should be logged at debug-level. */ #define MAX_LOGGABLE_PLACES (10*1000) static char *loggable_places[MAX_LOGGABLE_PLACES]; static int num_places = 0; /* * Reopen/rotate locking things. */ static RWLock rwlock; /* * Syslog support. */ static int sysloglevel; static int syslogfacility = LOG_DAEMON; static int dosyslog = 0; /* * Make sure stderr is included in the list. */ static void add_stderr(void) { int i; for (i = 0; i < num_logfiles; ++i) if (logfiles[i].file == stderr) return; logfiles[num_logfiles].file = stderr; logfiles[num_logfiles].minimum_output_level = GW_DEBUG; logfiles[num_logfiles].exclusive = GW_NON_EXCL; ++num_logfiles; } void log_init(void) { unsigned long i; /* Initialize rwlock */ gw_rwlock_init_static(&rwlock); /* default all possible thread to logging index 0, stderr */ for (i = 0; i < THREADTABLE_SIZE; i++) { thread_to[i] = 0; } add_stderr(); } void log_shutdown(void) { log_close_all(); /* destroy rwlock */ gw_rwlock_destroy(&rwlock); } void log_set_output_level(enum output_level level) { int i; for (i = 0; i < num_logfiles; ++i) { if (logfiles[i].file == stderr) { logfiles[i].minimum_output_level = level; break; } } } void log_set_log_level(enum output_level level) { int i; /* change everything but stderr */ for (i = 0; i < num_logfiles; ++i) { if (logfiles[i].file != stderr) { logfiles[i].minimum_output_level = level; info(0, "Changed logfile `%s' to level `%d'.", logfiles[i].filename, level); } } } void log_set_syslog_facility(char *facility) { if (facility != NULL) syslogfacility = decode(facility); } void log_set_syslog(const char *ident, int syslog_level) { if (ident == NULL) dosyslog = 0; else { dosyslog = 1; sysloglevel = syslog_level; openlog(ident, LOG_PID, syslogfacility); debug("gwlib.log", 0, "Syslog logging enabled."); } } void log_reopen(void) { int i, j, found; /* * Writer lock. */ gw_rwlock_wrlock(&rwlock); for (i = 0; i < num_logfiles; ++i) { if (logfiles[i].file != stderr) { found = 0; /* * Reverse seek for allready reopened logfile. * If we find a previous file descriptor for the same file * name, then don't reopen that duplicate, but assign the * file pointer to it. */ for (j = i-1; j >= 0 && found == 0; j--) { if (strcmp(logfiles[i].filename, logfiles[j].filename) == 0) { logfiles[i].file = logfiles[j].file; found = 1; } } if (found) continue; if (logfiles[i].file != NULL) fclose(logfiles[i].file); logfiles[i].file = fopen(logfiles[i].filename, "a"); if (logfiles[i].file == NULL) { error(errno, "Couldn't re-open logfile `%s'.", logfiles[i].filename); } } } /* * Unlock writer. */ gw_rwlock_unlock(&rwlock); } void log_close_all(void) { /* * Writer lock. */ gw_rwlock_wrlock(&rwlock); while (num_logfiles > 0) { --num_logfiles; if (logfiles[num_logfiles].file != stderr && logfiles[num_logfiles].file != NULL) { int i; /* look for the same filename and set file to NULL */ for (i = num_logfiles - 1; i >= 0; i--) { if (strcmp(logfiles[num_logfiles].filename, logfiles[i].filename) == 0) logfiles[i].file = NULL; } fclose(logfiles[num_logfiles].file); logfiles[num_logfiles].file = NULL; } } /* * Unlock writer. */ gw_rwlock_unlock(&rwlock); /* close syslog if used */ if (dosyslog) { closelog(); dosyslog = 0; } } int log_open(char *filename, int level, enum excl_state excl) { FILE *f = NULL; int i; gw_rwlock_wrlock(&rwlock); if (num_logfiles == MAX_LOGFILES) { gw_rwlock_unlock(&rwlock); error(0, "Too many log files already open, not adding `%s'", filename); return -1; } if (strlen(filename) > FILENAME_MAX) { gw_rwlock_unlock(&rwlock); error(0, "Log filename too long: `%s'.", filename); return -1; } /* * Check if the file is already opened for logging. * If there is an open file, then assign the file descriptor * that is already existing for this log file. */ for (i = 0; i < num_logfiles && f == NULL; ++i) { if (strcmp(logfiles[i].filename, filename) == 0) f = logfiles[i].file; } /* if not previously opened, then open it now */ if (f == NULL) { f = fopen(filename, "a"); if (f == NULL) { gw_rwlock_unlock(&rwlock); error(errno, "Couldn't open logfile `%s'.", filename); return -1; } } logfiles[num_logfiles].file = f; logfiles[num_logfiles].minimum_output_level = level; logfiles[num_logfiles].exclusive = excl; strcpy(logfiles[num_logfiles].filename, filename); ++num_logfiles; i = num_logfiles - 1; gw_rwlock_unlock(&rwlock); info(0, "Added logfile `%s' with level `%d'.", filename, level); return i; } #define FORMAT_SIZE (1024) static void format(char *buf, int level, const char *place, int e, const char *fmt, int with_timestamp_and_pid) { static char *tab[] = { "DEBUG: ", "INFO: ", "WARNING: ", "ERROR: ", "PANIC: ", "LOG: " }; static int tab_size = sizeof(tab) / sizeof(tab[0]); time_t t; struct tm tm; char *p, prefix[1024]; long tid, pid; p = prefix; if (with_timestamp_and_pid) { time(&t); #if LOG_TIMESTAMP_LOCALTIME tm = gw_localtime(t); #else tm = gw_gmtime(t); #endif sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d ", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); p = strchr(p, '\0'); /* print PID and thread ID */ gwthread_self_ids(&tid, &pid); sprintf(p, "[%ld] [%ld] ", pid, tid); } else { /* thread ID only */ tid = gwthread_self(); sprintf(p, "[%ld] ", tid); } p = strchr(p, '\0'); if (level < 0 || level >= tab_size) sprintf(p, "UNKNOWN: "); else sprintf(p, "%s", tab[level]); p = strchr(p, '\0'); if (place != NULL && *place != '\0') sprintf(p, "%s: ", place); if (strlen(prefix) + strlen(fmt) > FORMAT_SIZE / 2) { sprintf(buf, "%s \n", prefix); return; } if (e == 0) sprintf(buf, "%s%s\n", prefix, fmt); else sprintf(buf, "%s%s\n%sSystem error %d: %s\n", prefix, fmt, prefix, e, strerror(e)); } static void PRINTFLIKE(2,0) output(FILE *f, char *buf, va_list args) { vfprintf(f, buf, args); fflush(f); } static void PRINTFLIKE(1,0) kannel_syslog(char *format, va_list args, int level) { char buf[4096]; /* Trying to syslog more than 4K could be bad */ int translog; if (level >= sysloglevel && dosyslog) { vsnprintf(buf, sizeof(buf), format, args); /* XXX vsnprint not 100% portable */ switch(level) { case GW_DEBUG: translog = LOG_DEBUG; break; case GW_INFO: translog = LOG_INFO; break; case GW_WARNING: translog = LOG_WARNING; break; case GW_ERROR: translog = LOG_ERR; break; case GW_PANIC: translog = LOG_ALERT; break; default: translog = LOG_INFO; break; } syslog(translog, "%s", buf); } } /* * Almost all of the message printing functions are identical, except for * the output level they use. This macro contains the identical parts of * the functions so that the code needs to exist only once. It's a bit * more awkward to edit, but that can't be helped. The "do {} while (0)" * construct is a gimmick to be more like a function call in all syntactic * situation. */ #define FUNCTION_GUTS(level, place) \ do { \ int i; \ int formatted = 0; \ char buf[FORMAT_SIZE]; \ va_list args; \ \ gw_rwlock_rdlock(&rwlock); \ for (i = 0; i < num_logfiles; ++i) { \ if (logfiles[i].exclusive == GW_NON_EXCL && \ level >= logfiles[i].minimum_output_level && \ logfiles[i].file != NULL) { \ if (!formatted) { \ format(buf, level, place, err, fmt, 1); \ formatted = 1; \ } \ va_start(args, fmt); \ output(logfiles[i].file, buf, args); \ va_end(args); \ } \ } \ gw_rwlock_unlock(&rwlock); \ if (dosyslog) { \ format(buf, level, place, err, fmt, 0); \ va_start(args, fmt); \ kannel_syslog(buf,args,level); \ va_end(args); \ } \ } while (0) #define FUNCTION_GUTS_EXCL(level, place) \ do { \ char buf[FORMAT_SIZE]; \ va_list args; \ \ gw_rwlock_rdlock(&rwlock); \ if (logfiles[e].exclusive == GW_EXCL && \ level >= logfiles[e].minimum_output_level && \ logfiles[e].file != NULL) { \ format(buf, level, place, err, fmt, 1); \ va_start(args, fmt); \ output(logfiles[e].file, buf, args); \ va_end(args); \ } \ gw_rwlock_unlock(&rwlock); \ } while (0) #ifdef HAVE_BACKTRACE static void PRINTFLIKE(2,3) gw_panic_output(int err, const char *fmt, ...) { FUNCTION_GUTS(GW_PANIC, ""); } #endif void gw_backtrace(void **stack_frames, size_t size, int lock) { #if HAVE_BACKTRACE void *frames[50]; size_t i; char **strings; if (stack_frames == NULL) { stack_frames = frames; size = backtrace(stack_frames, sizeof(frames) / sizeof(void*)); } strings = backtrace_symbols(stack_frames, size); if (strings) { for (i = 0; i < size; i++) gw_panic_output(0, "%s", strings[i]); } else { /* hmm, no memory available */ for (i = 0; i < size; i++) gw_panic_output(0, "%p", stack_frames[i]); } /* * Note: we must call gw_native_free directly because if gw_free points to gw_check_free we could * panic's and we have endless loop with SEGFAULT at the end. */ gw_native_free(strings); #endif } void gw_panic(int err, const char *fmt, ...) { /* * we don't want PANICs to spread accross smsc logs, so * this will be always within the main core log. */ FUNCTION_GUTS(GW_PANIC, ""); gw_backtrace(NULL, 0, 0); #ifdef SEGFAULT_PANIC *((char*)0) = 0; #endif exit(EXIT_FAILURE); } void error(int err, const char *fmt, ...) { int e; if ((e = thread_to[thread_slot()])) { FUNCTION_GUTS_EXCL(GW_ERROR, ""); } else { FUNCTION_GUTS(GW_ERROR, ""); } } void warning(int err, const char *fmt, ...) { int e; if ((e = thread_to[thread_slot()])) { FUNCTION_GUTS_EXCL(GW_WARNING, ""); } else { FUNCTION_GUTS(GW_WARNING, ""); } } void info(int err, const char *fmt, ...) { int e; if ((e = thread_to[thread_slot()])) { FUNCTION_GUTS_EXCL(GW_INFO, ""); } else { FUNCTION_GUTS(GW_INFO, ""); } } static int place_matches(const char *place, const char *pat) { size_t len; len = strlen(pat); if (pat[len-1] == '*') return (strncasecmp(place, pat, len - 1) == 0); return (strcasecmp(place, pat) == 0); } static int place_should_be_logged(const char *place) { int i; if (num_places == 0) return 1; for (i = 0; i < num_places; ++i) { if (*loggable_places[i] != '-' && place_matches(place, loggable_places[i])) return 1; } return 0; } static int place_is_not_logged(const char *place) { int i; if (num_places == 0) return 0; for (i = 0; i < num_places; ++i) { if (*loggable_places[i] == '-' && place_matches(place, loggable_places[i]+1)) return 1; } return 0; } void debug(const char *place, int err, const char *fmt, ...) { int e; if (place_should_be_logged(place) && place_is_not_logged(place) == 0) { /* * Note: giving `place' to FUNCTION_GUTS makes log lines * too long and hard to follow. We'll rely on an external * list of what places are used instead of reading them * from the log file. */ if ((e = thread_to[thread_slot()])) { FUNCTION_GUTS_EXCL(GW_DEBUG, ""); } else { FUNCTION_GUTS(GW_DEBUG, ""); } } } void log_set_debug_places(const char *places) { char *p; p = strtok(gw_strdup(places), " ,"); num_places = 0; while (p != NULL && num_places < MAX_LOGGABLE_PLACES) { loggable_places[num_places++] = p; p = strtok(NULL, " ,"); } } void log_thread_to(int idx) { long thread_id = thread_slot(); if (idx > 0) { info(0, "Logging thread `%ld' to logfile `%s' with level `%d'.", thread_id, logfiles[idx].filename, logfiles[idx].minimum_output_level); thread_to[thread_id] = idx; } else if (idx != 0 && num_logfiles > 0) { warning(0, "Logging thread `%ld' to logfile `%s' with level `%d'.", thread_id, logfiles[0].filename, logfiles[0].minimum_output_level); } } gateway-1.4.5/gwlib/accesslog.h0000644000175000017500000000754313227613126015120 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * accesslog.c - implement access logging functions * * this module is somewhat similar to general logging module log.c, * but is far more simplified and is meant for access logs; * i.e. no multiple 'debug levels' nor multiple files, just one * file to save access information * * This way the Kannel adminstration can destroy all standard log files * when extra room is needed and only store these access logs for * statistics/billing information * */ #ifndef ACCESSLOG_H #define ACCESSLOG_H /* open access log with filename fname. if use_localtime != 0 then * all events are logged with localtime, not GMT */ void alog_open(char *fname, int use_localtime, int use_markers); /* close access log. Do nothing if no open file */ void alog_close(void); /* close and reopen access log. Do nothing if no open file */ void alog_reopen(void); /* set access log to use localtimer in timestamps */ void alog_use_localtime(void); /* set access log to use GMT in timestamps */ void alog_use_gmtime(void); /* log given message with arguments (normal printf) into access log, * along with timestamp */ void alog(const char *fmt, ...) PRINTFLIKE(1,2); #endif gateway-1.4.5/gwlib/gwpoll.h0000644000175000017500000001045413227613126014454 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* gwpoll.h - define poll() for systems that don't have it */ #ifndef GWPOLL_H #define GWPOLL_H /* If the system supplies it, we're done. Assume that if the header file * exists, it will define poll() and struct pollfd for us. */ #ifdef HAVE_SYS_POLL_H #include /* Most systems accept any negative timeout value as meaning infinite * timeout. FreeBSD explicitly wants INFTIM, however. Other systems * don't define INFTIM. So we use it if it's defined, and -1 otherwise. */ #ifdef INFTIM #define POLL_NOTIMEOUT INFTIM #else #define POLL_NOTIMEOUT (-1) #endif #else /* Define struct pollfd and the event bits, and declare a function poll() * that uses them and is a wrapper around select(). */ struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ }; /* Bits for events and revents */ #define POLLIN 1 /* Reading will not block */ #define POLLPRI 2 /* Urgent data available for reading */ #define POLLOUT 4 /* Writing will not block */ /* Bits only used in revents */ #define POLLERR 8 /* Error condition */ #define POLLHUP 16 /* Hung up: fd was closed by other side */ #define POLLNVAL 32 /* Invalid: fd not open or not valid */ #define POLL_NOTIMEOUT (-1) /* Implement the function as gw_poll, in case the system does have a poll() * function in its libraries but just fails to define it in sys/poll.h. */ #define poll(fdarray, numfds, timeout) gw_poll(fdarray, numfds, timeout) int gw_poll(struct pollfd *fdarray, unsigned int numfds, int timeout); #endif /* !HAVE_SYS_POLL_H */ #endif gateway-1.4.5/gwlib/socket.h0000644000175000017500000001535113227613126014441 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * General useful socket functions */ #ifndef GW_SOCKET_H #define GW_SOCKET_H #include #include #include #include #include #include "gw-config.h" #ifndef HAVE_SOCKLEN_T typedef int socklen_t; #endif #include "octstr.h" /* Return the official and fully qualified domain name of the host. Caller should treat this as read-only. Caller MUST NOT destroy it. */ Octstr *get_official_name(void); /* Return an official IP number for the host. Caller should treat this as read-only. Caller MUST NOT destroy it. Note that there can be multiple official IP numbers for the host. */ Octstr *get_official_ip(void); /* Open a server socket. Return -1 for error, >= 0 socket number for OK.*/ int make_server_socket(int port, const char *source_addr); /* Open a client socket. */ int tcpip_connect_to_server(char *hostname, int port, const char *source_addr); /* As above, but binds our end to 'our_port' */ int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr); /* Open a client socket in nonblocking mode, done is 0 if socket connected immediatly, overwise done is 1 */ int tcpip_connect_nb_to_server(char *hostname, int port, const char *source_addr, int *done); /* As above, but binds our end to 'our_port' */ int tcpip_connect_nb_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr, int *done); /* Write string to socket. */ int write_to_socket(int socket, char *str); /* Set socket to blocking or non-blocking mode. Return -1 for error, * 0 for success. */ int socket_set_blocking(int socket, int blocking); /* Diable or enable TCP_NODELAY. * Return -1 for error, 0 for success. */ int socket_set_nodelay(int fd, int on); /* Check if there is something to be read in 'fd'. Return 1 if there * is data, 0 otherwise, -1 on error */ int read_available(int fd, long wait_usec); /* * Create a UDP socket for receiving from clients. Return -1 for failure, * a socket file descriptor >= 0 for OK. */ int udp_bind(int port, const char *source_addr); /* * Create the client end of a UDP socket (i.e., a UDP socket that can * be on any port). Return -1 for failure, a socket file descriptor >= 0 * for OK. */ int udp_client_socket(void); /* * Encode a hostname or IP number and port number into a binary address, * and return that as an Octstr. Return NULL if the host doesn't exist * or the IP number is syntactically invalid, or the port is bad. */ Octstr *udp_create_address(Octstr *host_or_ip, int port); /* * Return the IP number of an encoded binary address, as a cleartext string. */ Octstr *udp_get_ip(Octstr *addr); /* * Return the port number of an encoded binary address, as a cleartext string. */ int udp_get_port(Octstr *addr); /* * Send a UDP message to a given server. */ int udp_sendto(int s, Octstr *datagram, Octstr *addr); /* * Receive a UDP message from a client. */ int udp_recvfrom_flags(int s, Octstr **datagram, Octstr **addr, int sockrcvflags); int udp_recvfrom(int s, Octstr **datagram, Octstr **addr); /* * Create an Octstr of character representation of an IP */ Octstr *host_ip(struct sockaddr_in addr); /* * Return the port number of an IP connection. */ int host_port(struct sockaddr_in addr); /* * This must be called before sockets are used. gwlib_init does that */ void socket_init(void); /* * Likewise, shutdown, called by gwlib_shutdown */ void socket_shutdown(void); /* * Converts an address of various types to an Octstr representation. * Similar to host_ip, but works with more than IPv4 */ Octstr *gw_netaddr_to_octstr(int af, void* src); /* * Do an accept() system call for the given file descriptor. Return -1 * for error (from accept or gwthread_poll, or gwthread_poll was * interrupted by gwthread_wakeup) or the new file descriptor for success. * Return IP number (as formatted by host_ip) via *client_addr. */ int gw_accept(int fd, Octstr **client_addr); #endif gateway-1.4.5/gwlib/gwmem-check.c0000644000175000017500000005351013227613126015332 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwmem-check.c - memory management wrapper functions, check flavor * * This implementation of the gwmem.h interface checks for writes to * non-allocated areas, and fills freshly allocated and freshly freed * areas with garbage to prevent their use. It also reports memory * leaks. * * Design: Memory is allocated with markers before and after the * area to be used. These markers can be checked to see if anything * has written to them. There is a table of all allocated areas, * which is used to detect memory leaks and which contains context * information about each area. * * The start marker contains the index into this table, so that it * can be looked up quickly -- but if the start marker has been damaged, * the index can still be found by searching the table. * * Enlarging an area with realloc is handled by allocating new area, * copying the old data, and freeing the old area. This is an expensive * operation which is avoided by reserving extra space (up to the nearest * power of two), and only enlarging the area if the requested space is * larger than this extra space. The markers are still placed at exactly * the size requested, so every realloc does mean moving the end marker. * * When data is freed, it is overwritten with 0xdeadbeef, so that code * that tries to use it after freeing will likely crash. The freed area * is kept around for a while, to see if anything tries to write to it * after it's been freed. * * Richard Braakman * Alexander Malysh (added backtrace support) */ #include "gw-config.h" #include #include #include #if HAVE_BACKTRACE #include #endif #include "gwlib.h" /* In this module, we must use the real versions so let's undefine the * accident protectors. */ #undef malloc #undef realloc #undef calloc #undef free /* Freshly malloced space is filled with NEW_AREA_PATTERN, to break * code that assumes it is filled with zeroes. */ #define NEW_AREA_PATTERN 0xcafebabe /* Freed space is filled with FREE_AREA_PATTERN, to break code that * tries to read from it after freeing. */ #define FREE_AREA_PATTERN 0xdeadbeef /* The marker before an area is filled with START_MARK_PATTERN * (except for some bookkeeping bytes at the start of the marker). */ #define START_MARK_PATTERN 0xdadaface /* The marker beyond an area is filled with END_MARK_PATTERN. */ #define END_MARK_PATTERN 0xadadafec /* How many bytes to dump when listing unfreed areas. */ #define MAX_DUMP 16 static int initialized = 0; /* Use slower, more reliable method of detecting memory corruption. */ static int slow = 0; /* We have to use a static mutex here, because otherwise the mutex_create * call would try to allocate memory with gw_malloc before we're * initialized. */ static Mutex gwmem_lock; struct location { const char *filename; long lineno; const char *function; }; /* Duplicating the often-identical location information in every table * entry uses a lot of memory, but saves the effort of maintaining a * data structure for it, and keeps access to it fast. */ struct area { void *area; /* The allocated memory area, as seen by caller */ size_t area_size; /* Size requested by caller */ size_t max_size; /* Size we can expand area to when reallocing */ struct location allocator; /* Caller that alloced area */ struct location reallocator; /* Caller that last realloced area */ struct location claimer; /* Owner of area, set by caller */ #if HAVE_BACKTRACE void *frames[10]; /* 10 callers should be sufficient */ size_t frame_size; #endif }; /* Number of bytes to reserve on either side of each allocated area, * to detect writes just outside the area. It must be at least large * enough to hold a long. */ #define MARKER_SIZE 16 /* 100 MB */ #define MAX_TAB_SIZE (100*1024*1024L) #define MAX_ALLOCATIONS ((long) (MAX_TAB_SIZE/sizeof(struct area))) /* Freed areas are thrown into the free ring. They are not released * back to the system until FREE_RING_SIZE other allocations have been * made. This is more effective at finding bugs than releasing them * immediately, because when we eventually release them we can check * that they have not been tampered with in that time. */ #define FREE_RING_SIZE 1024 static struct area allocated[MAX_ALLOCATIONS]; static struct area free_ring[FREE_RING_SIZE]; /* Current number of allocations in the "allocated" table. They are * always consecutive and start at the beginning of the table. */ static long num_allocations; /* The free ring can wrap around the edges of its array. */ static long free_ring_start; static long free_ring_len; /* The next three are used for informational messages at shutdown */ /* Largest number of allocations we've had at one time */ static long highest_num_allocations; /* Largest value of the sum of allocated areas we've had at one time */ static long highest_total_size; /* Current sum of allocated areas */ static long total_size; /* Static functions */ static inline void lock(void) { mutex_lock(&gwmem_lock); } static inline void unlock(void) { mutex_unlock(&gwmem_lock); } static unsigned long round_pow2(unsigned long num) { unsigned long i; if (num <= 16) return 16; for (i = 32; i < 0x80000000L; i <<= 1) { if (num <= i) return i; } /* We have to handle this case separately; the loop cannot go that * far because i would overflow. */ if (num <= 0x80000000L) return 0x80000000L; return 0xffffffffL; } /* Fill a memory area with a bit pattern */ static void fill(unsigned char *p, size_t bytes, long pattern) { while (bytes > sizeof(pattern)) { memcpy(p, &pattern, sizeof(pattern)); p += sizeof(pattern); bytes -= sizeof(pattern); } if (bytes > 0) memcpy(p, &pattern, bytes); } /* Check that a filled memory area has not changed */ static int untouched(unsigned char *p, size_t bytes, long pattern) { while (bytes > sizeof(pattern)) { if (memcmp(p, &pattern, sizeof(pattern)) != 0) return 0; p += sizeof(pattern); bytes -= sizeof(pattern); } if (bytes > 0 && memcmp(p, &pattern, bytes) != 0) return 0; return 1; } /* Fill the end marker for this area */ static inline void endmark(unsigned char *p, size_t size) { fill(p + size, MARKER_SIZE, END_MARK_PATTERN); } /* Fill the start marker for this area, and assign an number to the * area which can be used for quick lookups later. The number must * not be negative. */ static void startmark(unsigned char *p, long number) { gw_assert(MARKER_SIZE >= sizeof(long)); gw_assert(number >= 0); fill(p - MARKER_SIZE, sizeof(long), number); fill(p - MARKER_SIZE + sizeof(long), MARKER_SIZE - sizeof(long), START_MARK_PATTERN); } /* Check that the start marker for this area are intact, and return the * marker number if it seems intact. Return a negative number if * it does not seem intact. */ static long check_startmark(unsigned char *p) { long number; if (!untouched(p - MARKER_SIZE + sizeof(long), MARKER_SIZE - sizeof(long), START_MARK_PATTERN)) return -1; memcpy(&number, p - MARKER_SIZE, sizeof(number)); return number; } static int check_endmark(unsigned char *p, size_t size) { if (!untouched(p + size, MARKER_SIZE, END_MARK_PATTERN)) return -1; return 0; } static int check_marks(struct area *area, long index) { int result = 0; if (check_startmark(area->area) != index) { error(0, "Start marker was damaged for area %ld", index); result = -1; } if (check_endmark(area->area, area->area_size) < 0) { error(0, "End marker was damaged for area %ld", index); result = -1; } return result; } static void dump_area(struct area *area) { debug("gwlib.gwmem", 0, "Area %p, size %ld, max_size %ld", area->area, (long) area->area_size, (long) area->max_size); debug("gwlib.gwmem", 0, "Allocated by %s() at %s:%ld", area->allocator.function, area->allocator.filename, area->allocator.lineno); if (area->reallocator.function) { debug("gwlib.gwmem", 0, "Re-allocated by %s() at %s:%ld", area->reallocator.function, area->reallocator.filename, area->reallocator.lineno); } if (area->claimer.function) { debug("gwlib.gwmem", 0, "Claimed by %s() at %s:%ld", area->claimer.function, area->claimer.filename, area->claimer.lineno); } if (area->area_size > 0) { size_t i; unsigned char *p; char buf[MAX_DUMP * 3 + 1]; p = area->area; buf[0] = '\0'; for (i = 0; i < area->area_size && i < MAX_DUMP; ++i) sprintf(strchr(buf, '\0'), "%02x ", p[i]); debug("gwlib.gwmem", 0, "Contents of area (first %d bytes):", MAX_DUMP); debug("gwlib.gwmem", 0, " %s", buf); } #if HAVE_BACKTRACE { size_t i; char **strings = backtrace_symbols(area->frames, area->frame_size); debug("gwlib.gwmem", 0, "Backtrace of last malloc/realloc:"); for (i = 0; i < area->frame_size; i++) { if (strings != NULL) debug("gwlib.gwmem", 0, "%s", strings[i]); else debug("gwlib.gwmem", 0, "%p", area->frames[i]); } free(strings); } #endif } static struct area *find_area(unsigned char *p) { long index; struct area *area; long suspicious_pointer; unsigned long p_ul; gw_assert(p != NULL); p_ul = (unsigned long) p; suspicious_pointer = (sizeof(p) == sizeof(long) && (p_ul == NEW_AREA_PATTERN || p_ul == FREE_AREA_PATTERN || p_ul == START_MARK_PATTERN || p_ul == END_MARK_PATTERN)); if (slow || suspicious_pointer) { /* Extra check, which does not touch the (perhaps not allocated) * memory area. It's slow, but may help pinpoint problems that * would otherwise cause segfaults. */ for (index = 0; index < num_allocations; index++) { if (allocated[index].area == p) break; } if (index == num_allocations) { error(0, "Area %p not found in allocation table.", p); return NULL; } } index = check_startmark(p); if (index >= 0 && index < num_allocations && allocated[index].area == p) { area = &allocated[index]; if (check_endmark(p, area->area_size) < 0) { error(0, "End marker was damaged for area %p", p); dump_area(area); } return area; } error(0, "Start marker was damaged for area %p", p); for (index = 0; index < num_allocations; index++) { if (allocated[index].area == p) { area = &allocated[index]; dump_area(area); return area; } } error(0, "Could not find area information."); return NULL; } static void change_total_size(long change) { total_size += change; if (total_size > highest_total_size) highest_total_size = total_size; } static struct area *record_allocation(unsigned char *p, size_t size, const char *filename, long lineno, const char *function) { struct area *area; static struct area empty_area; if (num_allocations == MAX_ALLOCATIONS) { panic(0, "Too many concurrent allocations."); } area = &allocated[num_allocations]; *area = empty_area; area->area = p; area->area_size = size; area->max_size = size; area->allocator.filename = filename; area->allocator.lineno = lineno; area->allocator.function = function; #if HAVE_BACKTRACE area->frame_size = backtrace(area->frames, sizeof(area->frames) / sizeof(void*)); #endif startmark(area->area, num_allocations); endmark(area->area, area->area_size); num_allocations++; if (num_allocations > highest_num_allocations) highest_num_allocations = num_allocations; change_total_size(size); return area; } static void remove_allocation(struct area *area) { change_total_size(-1*area->area_size); num_allocations--; if (area == &allocated[num_allocations]) return; check_marks(&allocated[num_allocations], num_allocations); *area = allocated[num_allocations]; startmark(area->area, area - allocated); } static void drop_from_free_ring(long index) { struct area *area; area = &free_ring[index]; if (check_marks(area, index) < 0 || !untouched(area->area, area->area_size, FREE_AREA_PATTERN)) { error(0, "Freed area %p has been tampered with.", area->area); dump_area(area); } free((unsigned char *)area->area - MARKER_SIZE); } static void put_on_free_ring(struct area *area) { /* Simple case: We're still filling the free ring. */ if (free_ring_len < FREE_RING_SIZE) { free_ring[free_ring_len] = *area; startmark(area->area, free_ring_len); free_ring_len++; return; } /* Normal case: We need to check and release a free ring entry, * then put this one in its place. */ drop_from_free_ring(free_ring_start); free_ring[free_ring_start] = *area; startmark(area->area, free_ring_start); free_ring_start = (free_ring_start + 1) % FREE_RING_SIZE; } static void free_area(struct area *area) { fill(area->area, area->area_size, FREE_AREA_PATTERN); put_on_free_ring(area); remove_allocation(area); } void gw_check_init_mem(int slow_flag) { mutex_init_static(&gwmem_lock); slow = slow_flag; initialized = 1; } void gw_check_shutdown(void) { mutex_destroy(&gwmem_lock); initialized = 0; } void *gw_check_malloc(size_t size, const char *filename, long lineno, const char *function) { unsigned char *p; gw_assert(initialized); /* ANSI C89 says malloc(0) is implementation-defined. Avoid it. */ gw_assert(size > 0); p = malloc(size + 2 * MARKER_SIZE); if (p == NULL) panic(errno, "Memory allocation of %ld bytes failed.", (long)size); p += MARKER_SIZE; lock(); fill(p, size, NEW_AREA_PATTERN); record_allocation(p, size, filename, lineno, function); unlock(); return p; } void *gw_check_calloc(int nmemb, size_t size, const char *filename, long lineno, const char *function) { unsigned char *p; gw_assert(initialized); /* ANSI C89 says malloc(0) is implementation-defined. Avoid it. */ gw_assert(size > 0); gw_assert(nmemb > 0); p = calloc(1, (nmemb*size) + 2 * MARKER_SIZE); if (p == NULL) panic(errno, "Memory allocation of %ld bytes failed.", (long)size); p += MARKER_SIZE; lock(); record_allocation(p, size, filename, lineno, function); unlock(); return p; } void *gw_check_realloc(void *p, size_t size, const char *filename, long lineno, const char *function) { struct area *area; if (p == NULL) return gw_check_malloc(size, filename, lineno, function); gw_assert(initialized); gw_assert(size > 0); lock(); area = find_area(p); if (!area) { unlock(); panic(0, "Realloc called on non-allocated area"); } if (size == area->area_size) { /* No changes */ } else if (size <= area->max_size) { change_total_size(size - area->area_size); area->area_size = size; endmark(p, size); } else if (size > area->max_size) { /* The current block is not large enough for the reallocation. * We will allocate a new block, copy the data over, and free * the old block. We round the size up to a power of two, * to prevent frequent reallocations. */ struct area *new_area; size_t new_size; unsigned char *new_p; new_size = round_pow2(size + 2 * MARKER_SIZE); new_p = malloc(new_size); new_size -= 2 * MARKER_SIZE; new_p += MARKER_SIZE; memcpy(new_p, p, area->area_size); fill(new_p + area->area_size, size - area->area_size, NEW_AREA_PATTERN); new_area = record_allocation(new_p, size, area->allocator.filename, area->allocator.lineno, area->allocator.function); new_area->max_size = new_size; free_area(area); p = new_p; area = new_area; } area->reallocator.filename = filename; area->reallocator.lineno = lineno; area->reallocator.function = function; unlock(); return p; } void gw_check_free(void *p, const char *filename, long lineno, const char *function) { struct area *area; gw_assert(initialized); if (p == NULL) return; lock(); area = find_area(p); if (!area) { unlock(); panic(0, "Free called on non-allocated area"); } free_area(area); unlock(); } char *gw_check_strdup(const char *str, const char *filename, long lineno, const char *function) { char *copy; int size; gw_assert(initialized); gw_assert(str != NULL); size = strlen(str) + 1; copy = gw_check_malloc(size, filename, lineno, function); memcpy(copy, str, size); return copy; } void *gw_check_claim_area(void *p, const char *filename, long lineno, const char *function) { struct area *area; /* Allow this for the convenience of wrapper macros. */ if (p == NULL) return NULL; lock(); area = find_area(p); if (!area) { unlock(); panic(0, "Claim_area called on non-allocated area"); } area->claimer.filename = filename; area->claimer.lineno = lineno; area->claimer.function = function; unlock(); /* For convenience of calling macros */ return p; } void gw_check_check_leaks(void) { long calculated_size; long index; gw_assert(initialized); lock(); for (index = 0; index < free_ring_len; index++) { drop_from_free_ring(index); } free_ring_len = 0; calculated_size = 0; for (index = 0; index < num_allocations; index++) { calculated_size += allocated[index].area_size; } gw_assert(calculated_size == total_size); debug("gwlib.gwmem", 0, "----------------------------------------"); debug("gwlib.gwmem", 0, "Current allocations: %ld areas, %ld bytes", num_allocations, total_size); debug("gwlib.gwmem", 0, "Highest number of allocations: %ld areas", highest_num_allocations); debug("gwlib.gwmem", 0, "Highest memory usage: %ld bytes", highest_total_size); for (index = 0; index < num_allocations; index++) { check_marks(&allocated[index], index); dump_area(&allocated[index]); } unlock(); } int gw_check_is_allocated(void *p) { struct area *area; lock(); area = find_area(p); unlock(); return area != NULL; } long gw_check_area_size(void *p) { struct area *area; size_t size; lock(); area = find_area(p); if (!area) { unlock(); warning(0, "Area_size called on non-allocated area %p", p); return -1; } size = area->area_size; unlock(); return size; } gateway-1.4.5/gwlib/dbpool_redis.c0000644000175000017500000003513213227613126015610 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_redis.c - implement REDIS operations for generic database connection pool * * In the redis_[update|select]() functions no NULL values are allowed in the * binds list, otherwise we may get value corruption when getting back values * from redis. * * Toby Phipps , 2011 Initial version. * Stipe Tolj , 2013, 2015 */ #ifdef HAVE_REDIS #include /* * Define REDIS_DEBUG to get DEBUG level output of the * Redis commands send to the server. */ /* #define REDIS_DEBUG 1 */ #define REDIS_DEFAULT_PORT 6379 static void *redis_open_conn(const DBConf *db_conf) { redisContext *redis = NULL; RedisConf *conf = db_conf->redis; /* make compiler happy */ redisReply *reply = NULL; Octstr *os, *line; List *lines; long delimiter; /* sanity check */ if (conf == NULL) return NULL; struct timeval timeout = { 1, 500000 }; /* 1.5 seconds */ redis = redisConnectWithTimeout(octstr_get_cstr(conf->host), conf->port, timeout); if (redis->err) { error(0, "REDIS: can not connect to server!"); error(0, "REDIS: %s", redis->errstr); goto failed; } info(0, "REDIS: Connected to server at %s:%ld.", octstr_get_cstr(conf->host), conf->port); if (conf->password != NULL) { reply = redisCommand(redis, "AUTH %s", octstr_get_cstr(conf->password)); if (strncmp("OK", reply->str, 2) != 0) { error(0, "REDIS: Password authentication failed!"); goto failed; } freeReplyObject(reply); } if (conf->idle_timeout != -1) { reply = redisCommand(redis, "CONFIG SET TIMEOUT %ld", conf->idle_timeout); if (strncmp("OK", reply->str, 2) != 0) warning(0, "REDIS: CONFIG SET TIMEOUT %ld failed - could not set timeout", conf->idle_timeout); else info(0, "REDIS: Set idle timeout to %ld seconds", conf->idle_timeout); freeReplyObject(reply); } if (conf->database != -1) { reply = redisCommand(redis,"SELECT %ld", conf->database); if (strncmp("OK", reply->str, 2) != 0) error(0,"REDIS: SELECT %ld failed - could not select database", conf->database); else info(0,"REDIS: Selected database %ld", conf->database); freeReplyObject(reply); } reply = redisCommand(redis, "INFO"); if (reply->type != REDIS_REPLY_STRING) { error(0, "REDIS: INFO command to get version failed!"); goto failed; } os = octstr_create(reply->str); #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_STRING for INFO cmd"); /* octstr_dump(os, 0); */ #endif lines = octstr_split(os, octstr_imm("\n")); octstr_destroy(os); os = NULL; while ((line = gwlist_extract_first(lines)) != NULL) { Octstr *key, *value; /* comment line */ if (octstr_get_char(line, 0) == '#') { octstr_destroy(line); continue; } delimiter = octstr_search_char(line, ':', 0); key = octstr_copy(line, 0, delimiter); octstr_strip_blanks(key); value = octstr_copy(line, delimiter + 1, octstr_len(line)); octstr_strip_blanks(value); if (octstr_str_compare(key, "redis_version") == 0) { os = octstr_duplicate(value); octstr_destroy(key); octstr_destroy(value); octstr_destroy(line); break; } octstr_destroy(key); octstr_destroy(value); octstr_destroy(line); } gwlist_destroy(lines, octstr_destroy_item); if (os == NULL) { error(0, "REDIS: Could not parse version from INFO output!"); goto failed; } info(0, "REDIS: server version %s.", octstr_get_cstr(os)); octstr_destroy(os); freeReplyObject(reply); return redis; failed: if (reply != NULL) freeReplyObject(reply); if (redis != NULL) redisFree(redis); return NULL; } static void redis_close_conn(void *conn) { if (conn == NULL) return; redisFree((redisContext*) conn); } static int redis_check_conn(void *conn) { redisReply *reply; if (conn == NULL) return -1; reply = redisCommand(conn, "PING"); if (reply != NULL) { if (strcmp(reply->str,"PONG") == 0) { freeReplyObject(reply); return 0; } } error(0, "REDIS: server connection check failed!"); error(0, "REDIS: %s", ((redisContext*)conn)->errstr); if (reply != NULL) freeReplyObject(reply); return -1; } static int redis_select(void *conn, const Octstr *sql, List *binds, List **res) { redisReply *reply; long i, binds_len; List *row; Octstr *temp = NULL; const char **argv; /* bind parameters if any */ binds_len = gwlist_len(binds); if (binds_len > 0) { #if defined(REDIS_DEBUG) Octstr *os = octstr_create("");; #endif argv = gw_malloc(sizeof(*argv) * binds_len); for (i = 0; i < binds_len; i++) { argv[i] = (char*)octstr_get_cstr(gwlist_get(binds, i)); #if defined(REDIS_DEBUG) octstr_format_append(os, "\"%s\" ", argv[i]); #endif } #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"redis cmd: %s", octstr_get_cstr(os)); octstr_destroy(os); #endif /* execute statement */ reply = redisCommandArgv(conn, binds_len, argv, NULL); gw_free(argv); } else { #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"redis cmd: %s", octstr_get_cstr(sql)); #endif /* execute statement */ reply = redisCommand(conn, octstr_get_cstr(sql)); } if (reply == NULL) return -1; /* evaluate reply */ switch (reply->type) { case REDIS_REPLY_ERROR: #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_ERROR"); #endif error(0, "REDIS: redisCommand() failed: `%s'", reply->str); break; case REDIS_REPLY_NIL: #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_NIL"); #endif break; case REDIS_REPLY_STATUS: #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_STATUS"); #endif break; case REDIS_REPLY_STRING: #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_STRING"); #endif *res = gwlist_create(); row = gwlist_create(); temp = octstr_create_from_data(reply->str, reply->len); gwlist_append(row, temp); gwlist_produce(*res, row); freeReplyObject(reply); return 0; break; case REDIS_REPLY_INTEGER: #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_INTEGER"); #endif *res = gwlist_create(); row = gwlist_create(); temp = octstr_format("%ld", reply->integer); gwlist_append(row, temp); gwlist_produce(*res, row); freeReplyObject(reply); return 0; break; case REDIS_REPLY_ARRAY: #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_ARRAY"); #endif *res = gwlist_create(); row = gwlist_create(); for (i = 0; i < reply->elements; i++) { if (reply->element[i]->type == REDIS_REPLY_NIL || reply->element[i]->str == NULL || reply->element[i]->len == 0) { gwlist_produce(row, octstr_imm("")); continue; } temp = octstr_create_from_data(reply->element[i]->str, reply->element[i]->len); #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_ARRAY[%ld]: %s", i, octstr_get_cstr(temp)); #endif gwlist_append(row, temp); } gwlist_produce(*res, row); freeReplyObject(reply); return 0; break; default: #if defined(REDIS_DEBUG) error(0,"REDIS: Received unknown Redis reply type %d", reply->type); #endif break; } freeReplyObject(reply); return -1; } static int redis_update(void *conn, const Octstr *sql, List *binds) { long i, binds_len; int ret; redisReply *reply; const char **argv; /* bind parameters if any */ binds_len = gwlist_len(binds); if (binds_len > 0) { #if defined(REDIS_DEBUG) Octstr *os = octstr_create("");; #endif argv = gw_malloc(sizeof(*argv) * binds_len); for (i = 0; i < binds_len; i++) { argv[i] = (char*)octstr_get_cstr(gwlist_get(binds, i)); #if defined(REDIS_DEBUG) octstr_format_append(os, "\"%s\" ", argv[i]); #endif } #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"redis cmd: %s", octstr_get_cstr(os)); octstr_destroy(os); #endif /* execute statement */ reply = redisCommandArgv(conn, binds_len, argv, NULL); gw_free(argv); } else { #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"redis cmd: %s", octstr_get_cstr(sql)); #endif /* execute statement */ reply = redisCommand(conn, octstr_get_cstr(sql)); } if (reply == NULL) return -1; /* evaluate reply */ switch (reply->type) { case REDIS_REPLY_ERROR: #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_ERROR"); #endif error(0, "REDIS: redisCommand() failed: `%s'", reply->str); break; case REDIS_REPLY_STATUS: /* Some Redis commands (e.g. WATCH) return a boolean status */ #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_STATUS: %s", reply->str); #endif if (strcmp(reply->str, "OK") == 0) { freeReplyObject(reply); return 0; } break; case REDIS_REPLY_INTEGER: /* Other commands (e.g. DEL) return an integer indicating * the number of keys affected */ #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_INTEGER: %qi", reply->integer); #endif /* * Note: Redis returns a long long. Casting it to an int here could * cause precision loss, however as we're returning an update status, * this should only ever be used to return a count of keys * deleted/updated, and this will almost invariably be 1. */ ret = (int)reply->integer; freeReplyObject(reply); return ret; break; case REDIS_REPLY_ARRAY: /* The EXEC command returns an array of replies * when executed successfully */ #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_ARRAY"); #endif freeReplyObject(reply); /* For now, we only support EXEC commands with an array * return and in that case, all is well */ return 0; break; case REDIS_REPLY_NIL: /* Finally, the EXEC command can return a NULL * if it fails (e.g. due to a WATCH triggering */ #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received REDIS_REPLY_NIL"); #endif break; default: #if defined(REDIS_DEBUG) debug("dbpool.redis",0,"Received unknown Redis reply %d", reply->type); #endif break; } freeReplyObject(reply); return -1; } static void redis_conf_destroy(DBConf *db_conf) { RedisConf *conf = db_conf->redis; octstr_destroy(conf->host); octstr_destroy(conf->password); gw_free(conf); gw_free(db_conf); } static struct db_ops redis_ops = { .open = redis_open_conn, .close = redis_close_conn, .check = redis_check_conn, .select = redis_select, .update = redis_update, .conf_destroy = redis_conf_destroy }; #endif /* HAVE_REDIS */ gateway-1.4.5/gwlib/gw_uuid_types.h.in0000644000175000017500000000226707765057716016470 0ustar toljtolj/* * If linux/types.h is already been included, assume it has defined * everything we need. (cross fingers) Other header files may have * also defined the types that we need. */ #if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \ !defined(_UUID_TYPES) && !defined(_EXT2_TYPES_H)) #define _UUID_TYPES_H typedef unsigned char __u8; typedef signed char __s8; #if (@SIZEOF_INT@ == 8) typedef int __s64; typedef unsigned int __u64; #elif (@SIZEOF_LONG@ == 8) typedef long __s64; typedef unsigned long __u64; #elif (@SIZEOF_LONG_LONG@ == 8) #if defined(__GNUC__) typedef __signed__ long long __s64; #else typedef signed long long __s64; #endif typedef unsigned long long __u64; #endif #if (@SIZEOF_INT@ == 2) typedef int __s16; typedef unsigned int __u16; #elif (@SIZEOF_SHORT@ == 2) typedef short __s16; typedef unsigned short __u16; #else ?==error: undefined 16 bit type #endif #if (@SIZEOF_INT@ == 4) typedef int __s32; typedef unsigned int __u32; #elif (@SIZEOF_LONG@ == 4) typedef long __s32; typedef unsigned long __u32; #elif (@SIZEOF_SHORT@ == 4) typedef short __s32; typedef unsigned short __u32; #else ?== error: undefined 32 bit type #endif #endif /* _*_TYPES_H */ gateway-1.4.5/gwlib/ssl.h0000644000175000017500000000601713227613126013751 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * ssl.h - declares SSL specific routines and types * * This file defines the secure socket layer (SSL) specific * routines and types. * * Stipe Tolj * for Kannel Project and Wapme Systems AG */ #ifdef HAVE_LIBSSL int SSL_smart_shutdown(SSL *ssl); #endif /* HAVE_LIBSSL */ gateway-1.4.5/gwlib/conn.c0000644000175000017500000012726413245353052014107 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* conn.c - implement Connection type * * This file implements the interface defined in conn.h. * * Richard Braakman * * SSL client implementation contributed by * Jarkko Kovala * * SSL server implementation contributed by * Stipe Tolj */ /* TODO: unlocked_close() on error */ /* TODO: have I/O functions check if connection is open */ /* TODO: have conn_open_tcp do a non-blocking connect() */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #ifdef HAVE_LIBSSL #include #include #include #include static SSL_CTX *global_ssl_context = NULL; static SSL_CTX *global_server_ssl_context = NULL; #endif /* HAVE_LIBSSL */ typedef unsigned long (*CRYPTO_CALLBACK_PTR)(void); /* * This used to be 4096. It is now 0 so that callers don't have to * deal with the complexities of buffering (i.e. deciding when to * flush) unless they want to. * FIXME: Figure out how to combine buffering sensibly with use of * conn_register. */ #define DEFAULT_OUTPUT_BUFFERING 0 #define SSL_CONN_TIMEOUT 30 struct Connection { /* We use separate locks for input and ouput fields, so that * read and write activities don't have to get in each other's * way. If you need both, then acquire the outlock first. */ Mutex *inlock; Mutex *outlock; volatile sig_atomic_t claimed; #ifndef NO_GWASSERT long claiming_thread; #endif /* fd value is read-only and is not locked */ int fd; /* socket state */ enum {yes,no} connected; /* Protected by outlock */ Octstr *outbuf; long outbufpos; /* start of unwritten data in outbuf */ /* Try to buffer writes until there are this many octets to send. * Set it to 0 to get an unbuffered connection. */ unsigned int output_buffering; /* Protected by inlock */ Octstr *inbuf; long inbufpos; /* start of unread data in inbuf */ int read_eof; /* we encountered eof on read */ int io_error; /* we encountered error on IO operation */ /* Protected by both locks when updating, so you need only one * of the locks when reading. */ FDSet *registered; conn_callback_t *callback; void *callback_data; conn_callback_data_destroyer_t *callback_data_destroyer; /* Protected by inlock */ int listening_pollin; /* Protected by outlock */ int listening_pollout; #ifdef HAVE_LIBSSL SSL *ssl; X509 *peer_certificate; #endif /* HAVE_LIBSSL */ }; static void unlocked_register_pollin(Connection *conn, int onoff); static void unlocked_register_pollout(Connection *conn, int onoff); /* There are a number of functions that play with POLLIN and POLLOUT flags. * The general rule is that we always want to poll for POLLIN except when * we have detected eof (which may be reported as eternal POLLIN), and * we want to poll for POLLOUT only if there's data waiting in the * output buffer. If output buffering is set, we may not want to poll for * POLLOUT if there's not enough data waiting, which is why we have * unlocked_try_write. */ /* Macros to get more information for debugging purposes */ #define unlock_in(conn) unlock_in_real(conn, __FILE__, __LINE__, __func__) #define unlock_out(conn) unlock_out_real(conn, __FILE__, __LINE__, __func__) /* Lock a Connection's read direction, if the Connection is unclaimed */ static void inline lock_in(Connection *conn) { gw_assert(conn != NULL); if (conn->claimed) gw_assert(gwthread_self() == conn->claiming_thread); else mutex_lock(conn->inlock); } /* Unlock a Connection's read direction, if the Connection is unclaimed */ static void inline unlock_in_real(Connection *conn, char *file, int line, const char *func) { int ret; gw_assert(conn != NULL); if (!conn->claimed && (ret = mutex_unlock(conn->inlock)) != 0) { panic(0, "%s:%ld: %s: Mutex unlock failed. " "(Called from %s:%ld:%s.)", __FILE__, (long) __LINE__, __func__, file, (long) line, func); } } /* Lock a Connection's write direction, if the Connection is unclaimed */ static void inline lock_out(Connection *conn) { gw_assert(conn != NULL); if (conn->claimed) gw_assert(gwthread_self() == conn->claiming_thread); else mutex_lock(conn->outlock); } /* Unlock a Connection's write direction, if the Connection is unclaimed */ static void inline unlock_out_real(Connection *conn, char *file, int line, const char *func) { int ret; gw_assert(conn != NULL); if (!conn->claimed && (ret = mutex_unlock(conn->outlock)) != 0) { panic(0, "%s:%ld: %s: Mutex unlock failed. " "(Called from %s:%ld:%s.)", __FILE__, (long) __LINE__, __func__, file, (long) line, func); } } /* Return the number of bytes in the Connection's output buffer */ static long inline unlocked_outbuf_len(Connection *conn) { return octstr_len(conn->outbuf) - conn->outbufpos; } /* Return the number of bytes in the Connection's input buffer */ static long inline unlocked_inbuf_len(Connection *conn) { return octstr_len(conn->inbuf) - conn->inbufpos; } /* Send as much data as can be sent without blocking. Return the number * of bytes written, or -1 in case of error. */ static long unlocked_write(Connection *conn) { long ret = 0; #ifdef HAVE_LIBSSL if (conn->ssl != NULL) { if (octstr_len(conn->outbuf) - conn->outbufpos > 0) ret = SSL_write(conn->ssl, octstr_get_cstr(conn->outbuf) + conn->outbufpos, octstr_len(conn->outbuf) - conn->outbufpos); if (ret < 0) { int SSL_error = SSL_get_error(conn->ssl, ret); if (SSL_error == SSL_ERROR_WANT_READ || SSL_error == SSL_ERROR_WANT_WRITE) { ret = 0; /* no error */ } else { error(errno, "SSL write failed: OpenSSL error %d: %s", SSL_error, ERR_error_string(SSL_error, NULL)); if (SSL_error == SSL_ERROR_SSL) { /* trace library errors */ long err; while ((err = ERR_get_error()) != 0) error(0, "SSL %s", ERR_error_string(err, NULL)); } return -1; } } } else #endif /* HAVE_LIBSSL */ ret = octstr_write_data(conn->outbuf, conn->fd, conn->outbufpos); if (ret < 0) { conn->io_error = 1; return -1; } conn->outbufpos += ret; /* Heuristic: Discard the already-written data if it's more than * half of the total. This should keep the buffer size small * without wasting too many cycles on moving data around. */ if (conn->outbufpos > octstr_len(conn->outbuf) / 2) { octstr_delete(conn->outbuf, 0, conn->outbufpos); conn->outbufpos = 0; } if (conn->registered) unlocked_register_pollout(conn, unlocked_outbuf_len(conn) > 0); return ret; } /* Try to empty the output buffer without blocking. Return 0 for success, * 1 if there is still data left in the buffer, and -1 for errors. */ static int unlocked_try_write(Connection *conn) { long len; len = unlocked_outbuf_len(conn); if (len == 0) return 0; if (len < (long) conn->output_buffering) return 1; if (unlocked_write(conn) < 0) return -1; if (unlocked_outbuf_len(conn) > 0) return 1; return 0; } /* Read whatever data is currently available, up to an internal maximum. */ static void unlocked_read(Connection *conn) { unsigned char buf[4096]; long len; if (conn->inbufpos > 0) { octstr_delete(conn->inbuf, 0, conn->inbufpos); conn->inbufpos = 0; } #ifdef HAVE_LIBSSL if (conn->ssl != NULL) { len = SSL_read(conn->ssl, buf, sizeof(buf)); } else #endif /* HAVE_LIBSSL */ len = read(conn->fd, buf, sizeof(buf)); if (len < 0) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) return; #ifdef HAVE_LIBSSL if (conn->ssl) { int SSL_error = SSL_get_error(conn->ssl, len); if (SSL_error == SSL_ERROR_WANT_WRITE || SSL_error == SSL_ERROR_WANT_READ) return; /* no error */ error(errno, "SSL read failed: OpenSSL error %d: %s", SSL_error, ERR_error_string(SSL_error, NULL)); } else #endif /* HAVE_LIBSSL */ error(errno, "Error reading from fd %d:", conn->fd); conn->io_error = 1; if (conn->registered) unlocked_register_pollin(conn, 0); return; } else if (len == 0) { conn->read_eof = 1; if (conn->registered) unlocked_register_pollin(conn, 0); } else { octstr_append_data(conn->inbuf, buf, len); } } /* Cut "length" octets from the input buffer and return them as an Octstr */ static Octstr *unlocked_get(Connection *conn, long length) { Octstr *result = NULL; gw_assert(unlocked_inbuf_len(conn) >= length); result = octstr_copy(conn->inbuf, conn->inbufpos, length); conn->inbufpos += length; return result; } /* Tell the fdset whether we are interested in POLLIN events, but only * if the status changed. (Calling fdset_listen can be expensive if * it requires synchronization with the polling thread.) * We must already have the inlock. */ static void unlocked_register_pollin(Connection *conn, int onoff) { gw_assert(conn->registered); if (onoff == 1 && !conn->listening_pollin) { /* Turn it on */ conn->listening_pollin = 1; fdset_listen(conn->registered, conn->fd, POLLIN, POLLIN); } else if (onoff == 0 && conn->listening_pollin) { /* Turn it off */ conn->listening_pollin = 0; fdset_listen(conn->registered, conn->fd, POLLIN, 0); } } /* Tell the fdset whether we are interested in POLLOUT events, but only * if the status changed. (Calling fdset_listen can be expensive if * it requires synchronization with the polling thread.) * We must already have the outlock. */ static void unlocked_register_pollout(Connection *conn, int onoff) { gw_assert(conn->registered); if (onoff == 1 && !conn->listening_pollout) { /* Turn it on */ conn->listening_pollout = 1; fdset_listen(conn->registered, conn->fd, POLLOUT, POLLOUT); } else if (onoff == 0 && conn->listening_pollout) { /* Turn it off */ conn->listening_pollout = 0; fdset_listen(conn->registered, conn->fd, POLLOUT, 0); } } #ifdef HAVE_LIBSSL static int conn_init_client_ssl(Connection *ret, Octstr *certkeyfile) { ret->ssl = SSL_new(global_ssl_context); /* * The current thread's error queue must be empty before * the TLS/SSL I/O operation is attempted, or SSL_get_error() * will not work reliably. */ ERR_clear_error(); if (certkeyfile != NULL) { SSL_use_certificate_file(ret->ssl, octstr_get_cstr(certkeyfile), SSL_FILETYPE_PEM); SSL_use_PrivateKey_file(ret->ssl, octstr_get_cstr(certkeyfile), SSL_FILETYPE_PEM); if (SSL_check_private_key(ret->ssl) != 1) { error(0, "conn_open_ssl: private key isn't consistent with the " "certificate from file %s (or failed reading the file)", octstr_get_cstr(certkeyfile)); return -1; } } /* SSL_set_fd can fail, so check it */ if (SSL_set_fd(ret->ssl, ret->fd) == 0) { /* SSL_set_fd failed, log error */ error(errno, "SSL: OpenSSL: %.256s", ERR_error_string(ERR_get_error(), NULL)); return -1; } /* * make sure the socket is non-blocking while we do SSL_connect */ if (socket_set_blocking(ret->fd, 0) < 0) { return -1; } BIO_set_nbio(SSL_get_rbio(ret->ssl), 1); BIO_set_nbio(SSL_get_wbio(ret->ssl), 1); SSL_set_connect_state(ret->ssl); return 0; } Connection *conn_open_ssl_nb(Octstr *host, int port, Octstr *certkeyfile, Octstr *our_host) { Connection *ret; /* open the TCP connection */ if (!(ret = conn_open_tcp_nb(host, port, our_host))) { return NULL; } if (conn_init_client_ssl(ret, certkeyfile) == -1) { conn_destroy(ret); return NULL; } return ret; } Connection *conn_open_ssl(Octstr *host, int port, Octstr *certkeyfile, Octstr *our_host) { Connection *ret; /* open the TCP connection */ if (!(ret = conn_open_tcp(host, port, our_host))) { return NULL; } if (conn_init_client_ssl(ret, certkeyfile) == -1) { conn_destroy(ret); return NULL; } return ret; } #endif /* HAVE_LIBSSL */ Connection *conn_open_tcp(Octstr *host, int port, Octstr *our_host) { return conn_open_tcp_with_port(host, port, 0, our_host); } Connection *conn_open_tcp_nb(Octstr *host, int port, Octstr *our_host) { return conn_open_tcp_nb_with_port(host, port, 0, our_host); } Connection *conn_open_tcp_nb_with_port(Octstr *host, int port, int our_port, Octstr *our_host) { int sockfd; int done = -1; Connection *c; sockfd = tcpip_connect_nb_to_server_with_port(octstr_get_cstr(host), port, our_port, our_host == NULL ? NULL : octstr_get_cstr(our_host), &done); if (sockfd < 0) return NULL; c = conn_wrap_fd(sockfd, 0); if (done != 0) { c->connected = no; } return c; } int conn_is_connected(Connection *conn) { return conn->connected == yes ? 0 : -1; } int conn_get_connect_result(Connection *conn) { int err; socklen_t len; len = sizeof(err); if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { return -1; } if (err) { return -1; } conn->connected = yes; return 0; } Connection *conn_open_tcp_with_port(Octstr *host, int port, int our_port, Octstr *our_host) { int sockfd; sockfd = tcpip_connect_to_server_with_port(octstr_get_cstr(host), port, our_port, our_host == NULL ? NULL : octstr_get_cstr(our_host)); if (sockfd < 0) return NULL; return conn_wrap_fd(sockfd, 0); } /* * XXX bad assumption here that conn_wrap_fd for SSL can only happens * for the server side!!!! FIXME !!!! */ Connection *conn_wrap_fd(int fd, int ssl) { Connection *conn; if (socket_set_blocking(fd, 0) < 0) return NULL; conn = gw_malloc(sizeof(*conn)); conn->inlock = mutex_create(); conn->outlock = mutex_create(); conn->claimed = 0; conn->outbuf = octstr_create(""); conn->outbufpos = 0; conn->inbuf = octstr_create(""); conn->inbufpos = 0; conn->fd = fd; conn->connected = yes; conn->read_eof = 0; conn->io_error = 0; conn->output_buffering = DEFAULT_OUTPUT_BUFFERING; conn->registered = NULL; conn->callback = NULL; conn->callback_data = NULL; conn->callback_data_destroyer = NULL; conn->listening_pollin = 0; conn->listening_pollout = 0; #ifdef HAVE_LIBSSL /* * do all the SSL magic for this connection */ if (ssl) { conn->ssl = SSL_new(global_server_ssl_context); conn->peer_certificate = NULL; /* SSL_set_fd can fail, so check it */ if (SSL_set_fd(conn->ssl, conn->fd) == 0) { /* SSL_set_fd failed, log error and return NULL */ error(errno, "SSL: OpenSSL: %.256s", ERR_error_string(ERR_get_error(), NULL)); conn_destroy(conn); return NULL; } /* SSL_set_verify(conn->ssl, 0, NULL); */ /* set read/write BIO layer to non-blocking mode */ BIO_set_nbio(SSL_get_rbio(conn->ssl), 1); BIO_set_nbio(SSL_get_wbio(conn->ssl), 1); /* set accept state , SSL-Handshake will be handled transparent while SSL_[read|write] */ SSL_set_accept_state(conn->ssl); } else { conn->ssl = NULL; conn->peer_certificate = NULL; } #endif /* HAVE_LIBSSL */ return conn; } void conn_destroy(Connection *conn) { int ret; if (conn == NULL) return; /* No locking done here. conn_destroy should not be called * if any thread might still be interested in the connection. */ if (conn->registered) { fdset_unregister(conn->registered, conn->fd); /* call data destroyer if any */ if (conn->callback_data != NULL && conn->callback_data_destroyer != NULL) conn->callback_data_destroyer(conn->callback_data); } if (conn->fd >= 0) { /* Try to flush any remaining data */ unlocked_try_write(conn); #ifdef HAVE_LIBSSL if (conn->ssl != NULL) { SSL_smart_shutdown(conn->ssl); SSL_free(conn->ssl); if (conn->peer_certificate != NULL) X509_free(conn->peer_certificate); } #endif /* HAVE_LIBSSL */ ret = close(conn->fd); if (ret < 0) error(errno, "conn_destroy: error on close"); conn->fd = -1; } octstr_destroy(conn->outbuf); octstr_destroy(conn->inbuf); mutex_destroy(conn->inlock); mutex_destroy(conn->outlock); gw_free(conn); } void conn_claim(Connection *conn) { gw_assert(conn != NULL); if (conn->claimed) panic(0, "Connection is being claimed twice!"); conn->claimed = 1; #ifndef NO_GWASSERT conn->claiming_thread = gwthread_self(); #endif } long conn_outbuf_len(Connection *conn) { long len; lock_out(conn); len = unlocked_outbuf_len(conn); unlock_out(conn); return len; } long conn_inbuf_len(Connection *conn) { long len; lock_in(conn); len = unlocked_inbuf_len(conn); unlock_in(conn); return len; } int conn_eof(Connection *conn) { int eof; lock_in(conn); eof = conn->read_eof; unlock_in(conn); return eof; } int conn_error(Connection *conn) { int err; lock_out(conn); lock_in(conn); err = conn->io_error; unlock_in(conn); unlock_out(conn); return err; } void conn_set_output_buffering(Connection *conn, unsigned int size) { lock_out(conn); conn->output_buffering = size; /* If the buffer size is smaller, we may have to write immediately. */ unlocked_try_write(conn); unlock_out(conn); } static void poll_callback(int fd, int revents, void *data) { Connection *conn; int do_callback = 0; conn = data; if (conn == NULL) { error(0, "poll_callback called with NULL connection."); return; } if (conn->fd != fd) { error(0, "poll_callback called on wrong connection."); return; } /* Get result of nonblocking connect, before any reads and writes * we must check result (it must be handled in initial callback) */ if (conn->connected == no) { if (conn->callback) conn->callback(conn, conn->callback_data); return; } /* If got POLLERR or POLHUP, then unregister the descriptor from the * fdset and set the error condition variable to let the upper layer * close and destroy the connection. */ if (revents & (POLLERR|POLLHUP)) { lock_out(conn); lock_in(conn); if (conn->listening_pollin) unlocked_register_pollin(conn, 0); if (conn->listening_pollout) unlocked_register_pollout(conn, 0); conn->io_error = 1; unlock_in(conn); unlock_out(conn); do_callback = 1; } /* If unlocked_write manages to write all pending data, it will * tell the fdset to stop listening for POLLOUT. */ if (revents & POLLOUT) { lock_out(conn); unlocked_write(conn); if (unlocked_outbuf_len(conn) == 0) do_callback = 1; unlock_out(conn); } /* We read only in unlocked_read in we received POLLIN, cause the * descriptor is already broken and of no use anymore. */ if (revents & POLLIN) { lock_in(conn); unlocked_read(conn); unlock_in(conn); do_callback = 1; } if (do_callback && conn->callback) conn->callback(conn, conn->callback_data); } int conn_register_real(Connection *conn, FDSet *fdset, conn_callback_t callback, void *data, conn_callback_data_destroyer_t *data_destroyer) { int events; int result = 0; gw_assert(conn != NULL); if (conn->fd < 0) return -1; /* We need both locks if we want to update the registration * information. */ lock_out(conn); lock_in(conn); if (conn->registered == fdset) { /* Re-registering. Change only the callback info. */ conn->callback = callback; /* call data destroyer if new data supplied */ if (conn->callback_data != NULL && conn->callback_data != data && conn->callback_data_destroyer != NULL) conn->callback_data_destroyer(conn->callback_data); conn->callback_data = data; conn->callback_data_destroyer = data_destroyer; result = 0; } else if (conn->registered) { /* Already registered to a different fdset. */ result = -1; } else { events = 0; /* For nonconnected socket we must lesten both directions */ if (conn->connected == yes) { if (conn->read_eof == 0 && conn->io_error == 0) events |= POLLIN; if (unlocked_outbuf_len(conn) > 0) events |= POLLOUT; } else { events |= POLLIN | POLLOUT; } conn->registered = fdset; conn->callback = callback; conn->callback_data = data; conn->callback_data_destroyer = data_destroyer; conn->listening_pollin = (events & POLLIN) != 0; conn->listening_pollout = (events & POLLOUT) != 0; fdset_register(fdset, conn->fd, events, poll_callback, conn); result = 0; } unlock_in(conn); unlock_out(conn); return result; } void conn_unregister(Connection *conn) { FDSet *set = NULL; int fd = -1; void *data = NULL; conn_callback_data_destroyer_t *destroyer = NULL; gw_assert(conn != NULL); if (conn == NULL || conn->fd < 0) return; /* We need both locks to update the registration information */ lock_out(conn); lock_in(conn); if (conn->registered) { set = conn->registered; fd = conn->fd; conn->registered = NULL; conn->callback = NULL; /* * remember and don't destroy data and data_destroyer because we * may be in callback right now. So destroy only after fdset_unregister * call which guarantee us we are not in callback anymore. */ data = conn->callback_data; conn->callback_data = NULL; destroyer = conn->callback_data_destroyer; conn->callback_data_destroyer = NULL; conn->listening_pollin = 0; conn->listening_pollout = 0; } unlock_in(conn); unlock_out(conn); /* now unregister from FDSet */ if (set != NULL) fdset_unregister(set, fd); /* ok we are not in callback anymore, destroy data if any */ if (data != NULL && destroyer != NULL) destroyer(data); } int conn_wait(Connection *conn, double seconds) { int events; int ret; int fd; lock_out(conn); /* Try to write any data that might still be waiting to be sent */ ret = unlocked_write(conn); if (ret < 0) { unlock_out(conn); return -1; } if (ret > 0) { /* We did something useful. No need to poll or wait now. */ unlock_out(conn); return 0; } fd = conn->fd; /* Normally, we block until there is more data available. But * if any data still needs to be sent, we block until we can * send it (or there is more data available). We always block * for reading, unless we know there is no more data coming. * (Because in that case, poll will keep reporting POLLIN to * signal the end of the file). If the caller explicitly wants * to wait even though there is no data to write and we're at * end of file, then poll for new data anyway because the caller * apparently doesn't trust eof. */ events = 0; if (unlocked_outbuf_len(conn) > 0) events |= POLLOUT; /* Don't keep the connection locked while we wait */ unlock_out(conn); /* We need the in lock to query read_eof */ lock_in(conn); if ((conn->read_eof == 0 && conn->io_error == 0) || events == 0) events |= POLLIN; unlock_in(conn); ret = gwthread_pollfd(fd, events, seconds); if (ret < 0) { if (errno == EINTR) return 0; error(0, "conn_wait: poll failed on fd %d:", fd); return -1; } if (ret == 0) return 1; if (ret & POLLNVAL) { error(0, "conn_wait: fd %d not open.", fd); return -1; } if (ret & (POLLERR | POLLHUP)) { /* Call unlocked_read to report the specific error, * and handle the results of the error. We can't be * certain that the error still exists, because we * released the lock for a while. */ lock_in(conn); unlocked_read(conn); unlock_in(conn); return -1; } /* If POLLOUT is on, then we must have wanted * to write something. */ if (ret & POLLOUT) { lock_out(conn); unlocked_write(conn); unlock_out(conn); } /* Since we normally select for reading, we must * try to read here. Otherwise, if the caller loops * around conn_wait without making conn_read* calls * in between, we will keep polling this same data. */ if (ret & POLLIN) { lock_in(conn); unlocked_read(conn); unlock_in(conn); } return 0; } int conn_flush(Connection *conn) { int ret; int revents; int fd; lock_out(conn); ret = unlocked_write(conn); if (ret < 0) { unlock_out(conn); return -1; } while (unlocked_outbuf_len(conn) != 0) { fd = conn->fd; unlock_out(conn); revents = gwthread_pollfd(fd, POLLOUT, -1.0); /* Note: Make sure we have the "out" lock when * going through the loop again, because the * loop condition needs it. */ if (revents < 0) { if (errno == EINTR) return 1; error(0, "conn_flush: poll failed on fd %d:", fd); return -1; } if (revents == 0) { /* We were woken up */ return 1; } if (revents & POLLNVAL) { error(0, "conn_flush: fd %d not open.", fd); return -1; } lock_out(conn); if (revents & (POLLOUT | POLLERR | POLLHUP)) { ret = unlocked_write(conn); if (ret < 0) { unlock_out(conn); return -1; } } } unlock_out(conn); return 0; } int conn_write(Connection *conn, Octstr *data) { int ret; lock_out(conn); octstr_append(conn->outbuf, data); ret = unlocked_try_write(conn); unlock_out(conn); return ret; } int conn_write_data(Connection *conn, unsigned char *data, long length) { int ret; lock_out(conn); octstr_append_data(conn->outbuf, data, length); ret = unlocked_try_write(conn); unlock_out(conn); return ret; } int conn_write_withlen(Connection *conn, Octstr *data) { int ret; unsigned char lengthbuf[4]; encode_network_long(lengthbuf, octstr_len(data)); lock_out(conn); octstr_append_data(conn->outbuf, lengthbuf, 4); octstr_append(conn->outbuf, data); ret = unlocked_try_write(conn); unlock_out(conn); return ret; } Octstr *conn_read_everything(Connection *conn) { Octstr *result = NULL; lock_in(conn); if (unlocked_inbuf_len(conn) == 0) { unlocked_read(conn); if (unlocked_inbuf_len(conn) == 0) { unlock_in(conn); return NULL; } } result = unlocked_get(conn, unlocked_inbuf_len(conn)); gw_claim_area(result); unlock_in(conn); return result; } Octstr *conn_read_fixed(Connection *conn, long length) { Octstr *result = NULL; if (length < 1) return NULL; /* See if the data is already available. If not, try a read(), * then see if we have enough data after that. If not, give up. */ lock_in(conn); if (unlocked_inbuf_len(conn) < length) { unlocked_read(conn); if (unlocked_inbuf_len(conn) < length) { unlock_in(conn); return NULL; } } result = unlocked_get(conn, length); gw_claim_area(result); unlock_in(conn); return result; } Octstr *conn_read_line(Connection *conn) { Octstr *result = NULL; long pos; lock_in(conn); /* 10 is the code for linefeed. We don't rely on \n because that * might be a different value on some (strange) systems, and * we are reading from a network connection. */ pos = octstr_search_char(conn->inbuf, 10, conn->inbufpos); if (pos < 0) { unlocked_read(conn); pos = octstr_search_char(conn->inbuf, 10, conn->inbufpos); if (pos < 0) { unlock_in(conn); return NULL; } } result = unlocked_get(conn, pos - conn->inbufpos); gw_claim_area(result); /* Skip the LF, which we left in the buffer */ conn->inbufpos++; /* If the line was terminated with CR LF, we have to remove * the CR from the result. */ if (octstr_len(result) > 0 && octstr_get_char(result, octstr_len(result) - 1) == 13) octstr_delete(result, octstr_len(result) - 1, 1); unlock_in(conn); return result; } Octstr *conn_read_withlen(Connection *conn) { Octstr *result = NULL; unsigned char lengthbuf[4]; long length = 0; /* for compiler please */ int try, retry; lock_in(conn); for (try = 1; try <= 2; try++) { if (try > 1) unlocked_read(conn); do { retry = 0; /* First get the length. */ if (unlocked_inbuf_len(conn) < 4) continue; octstr_get_many_chars(lengthbuf, conn->inbuf, conn->inbufpos, 4); length = decode_network_long(lengthbuf); if (length < 0) { warning(0, "conn_read_withlen: got negative length, skipping"); conn->inbufpos += 4; retry = 1; } } while(retry == 1); /* Then get the data. */ if (unlocked_inbuf_len(conn) - 4 < length) continue; conn->inbufpos += 4; result = unlocked_get(conn, length); gw_claim_area(result); break; } unlock_in(conn); return result; } Octstr *conn_read_packet(Connection *conn, int startmark, int endmark) { int startpos, endpos; Octstr *result = NULL; int try; lock_in(conn); for (try = 1; try <= 2; try++) { if (try > 1) unlocked_read(conn); /* Find startmark, and discard everything up to it */ if (startmark >= 0) { startpos = octstr_search_char(conn->inbuf, startmark, conn->inbufpos); if (startpos < 0) { conn->inbufpos = octstr_len(conn->inbuf); continue; } else { conn->inbufpos = startpos; } } else { startpos = conn->inbufpos; } /* Find first endmark after startmark */ endpos = octstr_search_char(conn->inbuf, endmark, conn->inbufpos); if (endpos < 0) continue; result = unlocked_get(conn, endpos - startpos + 1); gw_claim_area(result); break; } unlock_in(conn); return result; } #ifdef HAVE_LIBSSL X509 *conn_get_peer_certificate(Connection *conn) { /* Don't know if it needed to be locked , but better safe as crash */ lock_out(conn); lock_in(conn); if (conn->peer_certificate == NULL && conn->ssl != NULL) conn->peer_certificate = SSL_get_peer_certificate(conn->ssl); unlock_in(conn); unlock_out(conn); return conn->peer_certificate; } /* * XXX Alex decalred the RSA callback routine static and now we're getting * warning messages for our automatic compilation tests. So we are commenting * the function out to avoid the warnings. * static RSA *tmp_rsa_callback(SSL *ssl, int export, int key_len) { static RSA *rsa = NULL; debug("gwlib.http", 0, "SSL: Generating new RSA key (export=%d, keylen=%d)", export, key_len); if (export) { rsa = RSA_generate_key(key_len, RSA_F4, NULL, NULL); } else { debug("gwlib.http", 0, "SSL: Export not set"); } return rsa; } */ #if OPENSSL_VERSION_NUMBER < 0x10100000L static Mutex **ssl_static_locks = NULL; /* the call-back function for the openssl crypto thread locking */ static void openssl_locking_function(int mode, int n, const char *file, int line) { if (mode & CRYPTO_LOCK) mutex_lock(ssl_static_locks[n-1]); else mutex_unlock(ssl_static_locks[n-1]); } void openssl_init_locks(void) { int c, maxlocks = CRYPTO_num_locks(); gw_assert(ssl_static_locks == NULL); ssl_static_locks = gw_malloc(sizeof(Mutex *) * maxlocks); for (c = 0; c < maxlocks; c++) ssl_static_locks[c] = mutex_create(); /* after the mutexes have been created, apply the call-back to it */ CRYPTO_set_locking_callback(openssl_locking_function); CRYPTO_set_id_callback((CRYPTO_CALLBACK_PTR)gwthread_self); } void openssl_shutdown_locks(void) { int c, maxlocks = CRYPTO_num_locks(); gw_assert(ssl_static_locks != NULL); /* remove call-back from the locks */ CRYPTO_set_locking_callback(NULL); for (c = 0; c < maxlocks; c++) mutex_destroy(ssl_static_locks[c]); gw_free(ssl_static_locks); ssl_static_locks = NULL; } #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ void conn_init_ssl(void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L openssl_init_locks(); #endif SSL_library_init(); SSL_load_error_strings(); global_ssl_context = SSL_CTX_new(SSLv23_client_method()); SSL_CTX_set_mode(global_ssl_context, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); } void server_ssl_init(void) { SSLeay_add_ssl_algorithms(); SSL_load_error_strings(); global_server_ssl_context = SSL_CTX_new(SSLv23_server_method()); SSL_CTX_set_mode(global_server_ssl_context, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); if (!SSL_CTX_set_default_verify_paths(global_server_ssl_context)) { panic(0, "can not set default path for server"); } } void conn_shutdown_ssl(void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L openssl_shutdown_locks(); #endif if (global_ssl_context) SSL_CTX_free(global_ssl_context); CONF_modules_free(); ERR_remove_state(0); ENGINE_cleanup(); CONF_modules_unload(1); ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); } void server_shutdown_ssl(void) { if (global_server_ssl_context) SSL_CTX_free(global_server_ssl_context); CONF_modules_free(); ERR_remove_state(0); ENGINE_cleanup(); CONF_modules_unload(1); ERR_free_strings(); EVP_cleanup(); CRYPTO_cleanup_all_ex_data(); } void conn_use_global_client_certkey_file(Octstr *certkeyfile) { SSL_CTX_use_certificate_chain_file(global_ssl_context, octstr_get_cstr(certkeyfile)); SSL_CTX_use_PrivateKey_file(global_ssl_context, octstr_get_cstr(certkeyfile), SSL_FILETYPE_PEM); if (SSL_CTX_check_private_key(global_ssl_context) != 1) panic(0, "reading global client certificate file `%s', the certificate " "isn't consistent with the private key (or failed reading the file)", octstr_get_cstr(certkeyfile)); info(0, "Using global SSL certificate and key from file `%s'", octstr_get_cstr(certkeyfile)); } void conn_use_global_server_certkey_file(Octstr *certfile, Octstr *keyfile) { SSL_CTX_use_certificate_chain_file(global_server_ssl_context, octstr_get_cstr(certfile)); SSL_CTX_use_PrivateKey_file(global_server_ssl_context, octstr_get_cstr(keyfile), SSL_FILETYPE_PEM); if (SSL_CTX_check_private_key(global_server_ssl_context) != 1) { error(0, "SSL: %s", ERR_error_string(ERR_get_error(), NULL)); panic(0, "reading global server certificate file %s, the certificate \ isn't consistent with the private key in file %s \ (or failed reading the file)", octstr_get_cstr(certfile), octstr_get_cstr(keyfile)); } info(0, "Using global server SSL certificate from file `%s'", octstr_get_cstr(certfile)); info(0, "Using global server SSL key from file `%s'", octstr_get_cstr(keyfile)); } void conn_use_global_client_cipher_list(Octstr *cipher) { if (SSL_CTX_set_cipher_list(global_ssl_context, octstr_get_cstr(cipher)) != 1) { error(0, "SSL: %s", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(global_ssl_context); panic(0, "cipher list <%s> contains no supported ciphers!", octstr_get_cstr(cipher)); } } void conn_use_global_server_cipher_list(Octstr *cipher) { if (SSL_CTX_set_cipher_list(global_server_ssl_context, octstr_get_cstr(cipher)) != 1) { error(0, "SSL: %s", ERR_error_string(ERR_get_error(), NULL)); SSL_CTX_free(global_server_ssl_context); panic(0, "cipher list <%s> contains no supported ciphers!", octstr_get_cstr(cipher)); } } static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { char subject[256]; char issuer [256]; char *status; X509 *curr_cert; #if OPENSSL_VERSION_NUMBER < 0x10100000L curr_cert = ctx->current_cert; X509_NAME_oneline(X509_get_subject_name(curr_cert), subject, sizeof(subject)); X509_NAME_oneline(X509_get_issuer_name(curr_cert), issuer, sizeof (issuer)); #else curr_cert = X509_STORE_CTX_get_current_cert(ctx); X509_NAME_oneline(X509_get_subject_name(curr_cert), subject, sizeof(subject)); X509_NAME_oneline(X509_get_issuer_name(curr_cert), issuer, sizeof (issuer)); #endif status = preverify_ok ? "Accepting" : "Rejecting"; info(0, "%s certificate for \"%s\" signed by \"%s\"", status, subject, issuer); return preverify_ok; } void conn_use_global_trusted_ca_file(Octstr *ssl_trusted_ca_file) { if (ssl_trusted_ca_file != NULL) { if (!SSL_CTX_load_verify_locations(global_ssl_context, octstr_get_cstr(ssl_trusted_ca_file), NULL)) { panic(0, "Failed to load SSL CA file: %s", octstr_get_cstr(ssl_trusted_ca_file)); } else { info(0, "Using CA root certificates from file %s", octstr_get_cstr(ssl_trusted_ca_file)); SSL_CTX_set_verify(global_ssl_context, SSL_VERIFY_PEER, verify_callback); } } else { SSL_CTX_set_verify(global_ssl_context, SSL_VERIFY_NONE, NULL); } } void conn_config_ssl (CfgGroup *grp) { Octstr *ssl_client_certkey_file = NULL; Octstr *ssl_server_cert_file = NULL; Octstr *ssl_server_key_file = NULL; Octstr *ssl_trusted_ca_file = NULL; Octstr *ssl_client_cipher_list = NULL; Octstr *ssl_server_cipher_list = 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 = cfg_get(grp, octstr_imm("ssl-client-certkey-file")); if (ssl_client_certkey_file != NULL) conn_use_global_client_certkey_file(ssl_client_certkey_file); ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file")); ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file")); if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) { conn_use_global_server_certkey_file(ssl_server_cert_file, ssl_server_key_file); } ssl_trusted_ca_file = cfg_get(grp, octstr_imm("ssl-trusted-ca-file")); conn_use_global_trusted_ca_file(ssl_trusted_ca_file); /* * Check if specific ciphers are selected/de-selected. */ if ((ssl_client_cipher_list = cfg_get(grp, octstr_imm("ssl-client-cipher-list"))) != NULL) { conn_use_global_client_cipher_list(ssl_client_cipher_list); } if ((ssl_server_cipher_list = cfg_get(grp, octstr_imm("ssl-server-cipher-list"))) != NULL) { conn_use_global_server_cipher_list(ssl_server_cipher_list); } 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_cipher_list); octstr_destroy(ssl_server_cipher_list); } SSL *conn_get_ssl(Connection *conn) { if (conn != NULL) return conn->ssl; else return NULL; } #else void conn_config_ssl (CfgGroup *grp) { info(0, "SSL not supported, no SSL initialization done."); } #endif /* HAVE_LIBSSL */ int conn_get_id(Connection *conn) { if(conn == NULL) return 0; else return conn->fd; } gateway-1.4.5/gwlib/http.c0000644000175000017500000031064013245353052014121 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * http.c - HTTP protocol server and client implementation * * Implements major parts of the Hypertext Transfer Protocol HTTP/1.1 (RFC 2616) * See http://www.w3.org/Protocols/rfc2616/rfc2616.txt * * Lars Wirzenius */ /* XXX re-implement socket pools, with idle connection killing to save sockets */ /* XXX implement http_abort */ /* XXX give maximum input size */ /* XXX kill http_get_real */ /* XXX the proxy exceptions list should be a dict, I guess */ /* XXX set maximum number of concurrent connections to same host, total? */ /* XXX 100 status codes. */ /* XXX stop destroying persistent connections when a request is redirected */ #include #include #include #include #include #include #include #include "gwlib.h" #include "gwlib/regex.h" /* comment this out if you don't want HTTP responses to be dumped */ #define DUMP_RESPONSE 1 /* define http client connections timeout in seconds (set to -1 for disable) */ static int http_client_timeout = 240; /* define http server connections timeout in seconds (set to -1 for disable) */ #define HTTP_SERVER_TIMEOUT 60 /* max accepted clients */ #define HTTP_SERVER_MAX_ACTIVE_CONNECTIONS 500 /*********************************************************************** * Stuff used in several sub-modules. */ /* * Default port to connect to for HTTP connections. */ enum { HTTP_PORT = 80, HTTPS_PORT = 443 }; /* * Status of this module. */ static enum { limbo, running, terminating } run_status = limbo; /* * Which interface to use for outgoing HTTP requests. */ static Octstr *http_interface = NULL; /* * Read some headers, i.e., until the first empty line (read and discard * the empty line as well). Return -1 for error, 0 for all headers read, * 1 for more headers to follow. */ static int read_some_headers(Connection *conn, List *headers) { Octstr *line, *prev; if (gwlist_len(headers) == 0) prev = NULL; else prev = gwlist_get(headers, gwlist_len(headers) - 1); for (;;) { line = conn_read_line(conn); if (line == NULL) { if (conn_eof(conn) || conn_error(conn)) return -1; return 1; } if (octstr_len(line) == 0) { octstr_destroy(line); break; } if (isspace(octstr_get_char(line, 0)) && prev != NULL) { octstr_append(prev, line); octstr_destroy(line); } else { gwlist_append(headers, line); prev = line; } } return 0; } /* * Check that the HTTP version string is valid. Return -1 for invalid, * 0 for version 1.0, 1 for 1.x. */ static int parse_http_version(Octstr *version) { Octstr *prefix; long prefix_len; int digit; prefix = octstr_imm("HTTP/1."); prefix_len = octstr_len(prefix); if (octstr_ncompare(version, prefix, prefix_len) != 0) return -1; if (octstr_len(version) != prefix_len + 1) return -1; digit = octstr_get_char(version, prefix_len); if (!isdigit(digit)) return -1; if (digit == '0') return 0; return 1; } /*********************************************************************** * Proxy support. */ /* * Data and functions needed to support proxy operations. If proxy_hostname * is NULL, no proxy is used. */ static Mutex *proxy_mutex = NULL; static Octstr *proxy_hostname = NULL; static int proxy_port = 0; static int proxy_ssl = 0; static Octstr *proxy_username = NULL; static Octstr *proxy_password = NULL; static List *proxy_exceptions = NULL; static regex_t *proxy_exceptions_regex = NULL; static void proxy_add_authentication(List *headers) { Octstr *os; if (proxy_username == NULL || proxy_password == NULL) return; os = octstr_format("%S:%S", proxy_username, proxy_password); octstr_binary_to_base64(os); octstr_strip_blanks(os); octstr_insert(os, octstr_imm("Basic "), 0); http_header_add(headers, "Proxy-Authorization", octstr_get_cstr(os)); octstr_destroy(os); } static void proxy_init(void) { proxy_mutex = mutex_create(); proxy_exceptions = gwlist_create(); } static void proxy_shutdown(void) { http_close_proxy(); mutex_destroy(proxy_mutex); proxy_mutex = NULL; } static int proxy_used_for_host(Octstr *host, Octstr *url) { int i; mutex_lock(proxy_mutex); if (proxy_hostname == NULL) { mutex_unlock(proxy_mutex); return 0; } for (i = 0; i < gwlist_len(proxy_exceptions); ++i) { if (octstr_compare(host, gwlist_get(proxy_exceptions, i)) == 0) { mutex_unlock(proxy_mutex); return 0; } } if (proxy_exceptions_regex != NULL && gw_regex_match_pre(proxy_exceptions_regex, url)) { mutex_unlock(proxy_mutex); return 0; } mutex_unlock(proxy_mutex); return 1; } void http_use_proxy(Octstr *hostname, int port, int ssl, List *exceptions, Octstr *username, Octstr *password, Octstr *exceptions_regex) { Octstr *e; int i; gw_assert(run_status == running); gw_assert(hostname != NULL); gw_assert(octstr_len(hostname) > 0); gw_assert(port > 0); http_close_proxy(); mutex_lock(proxy_mutex); proxy_hostname = octstr_duplicate(hostname); proxy_port = port; proxy_ssl = ssl; proxy_exceptions = gwlist_create(); for (i = 0; i < gwlist_len(exceptions); ++i) { e = gwlist_get(exceptions, i); debug("gwlib.http", 0, "HTTP: Proxy exception `%s'.", octstr_get_cstr(e)); gwlist_append(proxy_exceptions, octstr_duplicate(e)); } if (exceptions_regex != NULL && (proxy_exceptions_regex = gw_regex_comp(exceptions_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(exceptions_regex)); proxy_username = octstr_duplicate(username); proxy_password = octstr_duplicate(password); debug("gwlib.http", 0, "Using proxy <%s:%d> with %s scheme", octstr_get_cstr(proxy_hostname), proxy_port, (proxy_ssl ? "HTTPS" : "HTTP")); mutex_unlock(proxy_mutex); } void http_close_proxy(void) { gw_assert(run_status == running || run_status == terminating); mutex_lock(proxy_mutex); proxy_port = 0; octstr_destroy(proxy_hostname); octstr_destroy(proxy_username); octstr_destroy(proxy_password); proxy_hostname = NULL; proxy_username = NULL; proxy_password = NULL; gwlist_destroy(proxy_exceptions, octstr_destroy_item); gw_regex_destroy(proxy_exceptions_regex); proxy_exceptions = NULL; proxy_exceptions_regex = NULL; mutex_unlock(proxy_mutex); } /*********************************************************************** * Common functions for reading request or result entities. */ /* * Value to pass to entity_create. */ enum body_expectation { /* * Message must not have a body, even if the headers indicate one. * (i.e. response to HEAD method). */ expect_no_body, /* * Message will have a body if Content-Length or Transfer-Encoding * headers are present (i.e. most request methods). */ expect_body_if_indicated, /* * Message will have a body, possibly zero-length. * (i.e. 200 OK responses to a GET method.) */ expect_body }; enum entity_state { reading_headers, reading_chunked_body_len, reading_chunked_body_data, reading_chunked_body_crlf, reading_chunked_body_trailer, reading_body_until_eof, reading_body_with_length, body_error, entity_done }; typedef struct { List *headers; Octstr *body; enum body_expectation expect_state; enum entity_state state; long chunked_body_chunk_len; long expected_body_len; } HTTPEntity; /* * The rules for message bodies (length and presence) are defined * in RFC2616 paragraph 4.3 and 4.4. */ static void deduce_body_state(HTTPEntity *ent) { Octstr *h = NULL; if (ent->expect_state == expect_no_body) { ent->state = entity_done; return; } ent->state = body_error; /* safety net */ h = http_header_find_first(ent->headers, "Transfer-Encoding"); if (h != NULL) { octstr_strip_blanks(h); if (octstr_str_compare(h, "chunked") != 0) { error(0, "HTTP: Unknown Transfer-Encoding <%s>", octstr_get_cstr(h)); ent->state = body_error; } else { ent->state = reading_chunked_body_len; } octstr_destroy(h); return; } h = http_header_find_first(ent->headers, "Content-Length"); if (h != NULL) { if (octstr_parse_long(&ent->expected_body_len, h, 0, 10) == -1 || ent->expected_body_len < 0) { error(0, "HTTP: Content-Length header wrong: <%s>", octstr_get_cstr(h)); ent->state = body_error; } else if (ent->expected_body_len == 0) { ent->state = entity_done; } else { ent->state = reading_body_with_length; } octstr_destroy(h); return; } if (ent->expect_state == expect_body) ent->state = reading_body_until_eof; else ent->state = entity_done; } /* * Create a HTTPEntity structure suitable for reading the expected * result or request message and decoding the transferred entity (if any). * See the definition of enum body_expectation for the possible values * of exp. */ static HTTPEntity *entity_create(enum body_expectation exp) { HTTPEntity *ent; ent = gw_malloc(sizeof(*ent)); ent->headers = http_create_empty_headers(); ent->body = octstr_create(""); ent->chunked_body_chunk_len = -1; ent->expected_body_len = -1; ent->state = reading_headers; ent->expect_state = exp; return ent; } static void entity_destroy(HTTPEntity *ent) { if (ent == NULL) return; http_destroy_headers(ent->headers); octstr_destroy(ent->body); gw_free(ent); } static void read_chunked_body_len(HTTPEntity *ent, Connection *conn) { Octstr *os; long len; os = conn_read_line(conn); if (os == NULL) { if (conn_error(conn) || conn_eof(conn)) ent->state = body_error; return; } if (octstr_parse_long(&len, os, 0, 16) == -1) { octstr_destroy(os); ent->state = body_error; return; } octstr_destroy(os); if (len == 0) ent->state = reading_chunked_body_trailer; else { ent->state = reading_chunked_body_data; ent->chunked_body_chunk_len = len; } } static void read_chunked_body_data(HTTPEntity *ent, Connection *conn) { Octstr *os; os = conn_read_fixed(conn, ent->chunked_body_chunk_len); if (os == NULL) { if (conn_error(conn) || conn_eof(conn)) ent->state = body_error; } else { octstr_append(ent->body, os); octstr_destroy(os); ent->state = reading_chunked_body_crlf; } } static void read_chunked_body_crlf(HTTPEntity *ent, Connection *conn) { Octstr *os; os = conn_read_line(conn); if (os == NULL) { if (conn_error(conn) || conn_eof(conn)) ent->state = body_error; } else { octstr_destroy(os); ent->state = reading_chunked_body_len; } } static void read_chunked_body_trailer(HTTPEntity *ent, Connection *conn) { int ret; ret = read_some_headers(conn, ent->headers); if (ret == -1) ent->state = body_error; if (ret == 0) ent->state = entity_done; } static void read_body_until_eof(HTTPEntity *ent, Connection *conn) { Octstr *os; while ((os = conn_read_everything(conn)) != NULL) { octstr_append(ent->body, os); octstr_destroy(os); } if (conn_error(conn)) ent->state = body_error; if (conn_eof(conn)) ent->state = entity_done; } static void read_body_with_length(HTTPEntity *ent, Connection *conn) { Octstr *os; os = conn_read_fixed(conn, ent->expected_body_len); if (os == NULL) { if (conn_error(conn) || conn_eof(conn)) ent->state = body_error; return; } octstr_destroy(ent->body); ent->body = os; ent->state = entity_done; } /* * Read headers and body (if any) from this connection. Return 0 if it's * complete, 1 if we expect more input, and -1 if there is something wrong. */ static int entity_read(HTTPEntity *ent, Connection *conn) { int ret; enum entity_state old_state; /* * In this loop, each state will process as much input as it needs * and then switch to the next state, unless it's a final state in * which case it returns directly, or unless it needs more input. * So keep looping as long as the state changes. */ do { old_state = ent->state; switch (ent->state) { case reading_headers: ret = read_some_headers(conn, ent->headers); if (ret == 0) deduce_body_state(ent); if (ret < 0) return -1; break; case reading_chunked_body_len: read_chunked_body_len(ent, conn); break; case reading_chunked_body_data: read_chunked_body_data(ent, conn); break; case reading_chunked_body_crlf: read_chunked_body_crlf(ent, conn); break; case reading_chunked_body_trailer: read_chunked_body_trailer(ent, conn); break; case reading_body_until_eof: read_body_until_eof(ent, conn); break; case reading_body_with_length: read_body_with_length(ent, conn); break; case body_error: return -1; case entity_done: return 0; default: panic(0, "Internal error: Invalid HTTPEntity state."); } } while (ent->state != old_state); /* * If we got here, then the loop ended because a non-final state * needed more input. */ return 1; } /*********************************************************************** * HTTP client interface. */ /* * Internal lists of completely unhandled requests and requests for which * a request has been sent but response has not yet been read. */ static List *pending_requests = NULL; /* * Have background threads been started? */ static Mutex *client_thread_lock = NULL; static volatile sig_atomic_t client_threads_are_running = 0; /* * Set of all connections to all servers. Used with conn_register to * do I/O on several connections with a single thread. */ static FDSet *client_fdset = NULL; /* * Maximum number of HTTP redirections to follow. Making this infinite * could cause infinite looping if the redirections loop. */ #define HTTP_MAX_FOLLOW 5 /* * The implemented HTTP method strings * Order is sequenced by the enum in the header */ static char *http_methods[] = { "GET", "POST", "HEAD" }; /* * Information about a server we've connected to. */ typedef struct { HTTPCaller *caller; void *request_id; int method; /* uses enums from http.h for the HTTP methods */ Octstr *url; /* the full URL, including scheme, host, etc. */ Octstr *uri; /* the HTTP URI path only */ List *request_headers; Octstr *request_body; /* NULL for GET or HEAD, non-NULL for POST */ enum { connecting, request_not_sent, reading_status, reading_entity, transaction_done } state; long status; int persistent; HTTPEntity *response; /* Can only be NULL if status < 0 */ Connection *conn; Octstr *host; long port; int follow_remaining; Octstr *certkeyfile; int ssl; Octstr *username; /* For basic authentication */ Octstr *password; } HTTPServer; static int send_request(HTTPServer *trans); static Octstr *build_response(List *headers, Octstr *body); static int header_is_called(Octstr *header, char *name); static HTTPServer *server_create(HTTPCaller *caller, int method, Octstr *url, List *headers, Octstr *body, int follow_remaining, Octstr *certkeyfile) { HTTPServer *trans; trans = gw_malloc(sizeof(*trans)); trans->caller = caller; trans->request_id = NULL; trans->method = method; trans->url = octstr_duplicate(url); trans->uri = NULL; trans->request_headers = http_header_duplicate(headers); trans->request_body = octstr_duplicate(body); trans->state = request_not_sent; trans->status = -1; trans->persistent = 0; trans->response = NULL; trans->conn = NULL; trans->host = NULL; trans->port = 0; trans->username = NULL; trans->password = NULL; trans->follow_remaining = follow_remaining; trans->certkeyfile = octstr_duplicate(certkeyfile); trans->ssl = 0; return trans; } static void server_destroy(void *p) { HTTPServer *trans; trans = p; octstr_destroy(trans->url); octstr_destroy(trans->uri); http_destroy_headers(trans->request_headers); trans->request_headers = NULL; octstr_destroy(trans->request_body); entity_destroy(trans->response); octstr_destroy(trans->host); octstr_destroy(trans->certkeyfile); octstr_destroy(trans->username); octstr_destroy(trans->password); gw_free(trans); } /* * Pool of open, but unused connections to servers or proxies. Key is * "servername:port", value is List with Connection objects. */ static Dict *conn_pool; static Mutex *conn_pool_lock; static void conn_pool_item_destroy(void *item) { gwlist_destroy(item, (void(*)(void*))conn_destroy); } static void conn_pool_init(void) { conn_pool = dict_create(1024, conn_pool_item_destroy); conn_pool_lock = mutex_create(); } static void conn_pool_shutdown(void) { dict_destroy(conn_pool); mutex_destroy(conn_pool_lock); } static inline Octstr *conn_pool_key(Octstr *host, int port, int ssl, Octstr *certfile, Octstr *our_host) { return octstr_format("%S:%d:%d:%S:%S", host, port, ssl?1:0, certfile?certfile:octstr_imm(""), our_host?our_host:octstr_imm("")); } static Connection *conn_pool_get(Octstr *host, int port, int ssl, Octstr *certkeyfile, Octstr *our_host) { Octstr *key; List *list = NULL; Connection *conn = NULL; int retry; do { retry = 0; key = conn_pool_key(host, port, ssl, certkeyfile, our_host); mutex_lock(conn_pool_lock); list = dict_get(conn_pool, key); if (list != NULL) conn = gwlist_extract_first(list); mutex_unlock(conn_pool_lock); /* * Note: we don't hold conn_pool_lock when we check/destroy/unregister * connection because otherwise we can deadlock! And it's even better * not to delay other threads while we check connection. */ if (conn != NULL) { #ifdef USE_KEEPALIVE /* unregister our server disconnect callback */ conn_unregister(conn); #endif /* * Check whether the server has closed the connection while * it has been in the pool. */ conn_wait(conn, 0); if (conn_eof(conn) || conn_error(conn)) { debug("gwlib.http", 0, "HTTP:conn_pool_get: Server closed connection, destroying it <%s><%p>.", octstr_get_cstr(key), conn, conn_get_id(conn)); conn_destroy(conn); retry = 1; conn = NULL; } } octstr_destroy(key); } while(retry == 1); if (conn == NULL) { #ifdef HAVE_LIBSSL if (ssl) conn = conn_open_ssl_nb(host, port, certkeyfile, our_host); else #endif /* HAVE_LIBSSL */ conn = conn_open_tcp_nb(host, port, our_host); debug("gwlib.http", 0, "HTTP: Opening connection to `%s:%d' (fd=%d).", octstr_get_cstr(host), port, conn_get_id(conn)); } else { debug("gwlib.http", 0, "HTTP: Reusing connection to `%s:%d' (fd=%d).", octstr_get_cstr(host), port, conn_get_id(conn)); } return conn; } #ifdef USE_KEEPALIVE static void check_pool_conn(Connection *conn, void *data) { Octstr *key = data; if (run_status != running) { conn_unregister(conn); return; } /* check if connection still ok */ if (conn_error(conn) || conn_eof(conn)) { List *list; mutex_lock(conn_pool_lock); list = dict_get(conn_pool, key); if (gwlist_delete_equal(list, conn) > 0) { /* * ok, connection was still within pool. So it's * safe to destroy this connection. */ debug("gwlib.http", 0, "HTTP: Server closed connection, destroying it <%s><%p>.", octstr_get_cstr(key), conn, conn_get_id(conn)); conn_unregister(conn); conn_destroy(conn); } /* * it's perfectly valid if connection was not found in connection pool because * in 'conn_pool_get' we first removed connection from pool with conn_pool_lock locked * and then check connection for errors with conn_pool_lock unlocked. In the meantime * fdset's poller may call us. So just ignore such "dummy" call. */ mutex_unlock(conn_pool_lock); } } static void conn_pool_put(Connection *conn, Octstr *host, int port, int ssl, Octstr *certfile, Octstr *our_host) { Octstr *key; List *list; key = conn_pool_key(host, port, ssl, certfile, our_host); mutex_lock(conn_pool_lock); list = dict_get(conn_pool, key); if (list == NULL) { list = gwlist_create(); dict_put(conn_pool, key, list); } gwlist_append(list, conn); /* register connection to get server disconnect */ conn_register_real(conn, client_fdset, check_pool_conn, key, octstr_destroy_item); mutex_unlock(conn_pool_lock); } #endif HTTPCaller *http_caller_create(void) { HTTPCaller *caller; caller = gwlist_create(); gwlist_add_producer(caller); return caller; } void http_caller_destroy(HTTPCaller *caller) { gwlist_destroy(caller, server_destroy); } void http_caller_signal_shutdown(HTTPCaller *caller) { gwlist_remove_producer(caller); } static Octstr *get_redirection_location(HTTPServer *trans) { if (trans->status < 0 || trans->follow_remaining <= 0) return NULL; /* check for the redirection response codes */ if (trans->status != HTTP_MOVED_PERMANENTLY && trans->status != HTTP_FOUND && trans->status != HTTP_SEE_OTHER && trans->status != HTTP_TEMPORARY_REDIRECT) return NULL; if (trans->response == NULL) return NULL; return http_header_find_first(trans->response->headers, "Location"); } /* * Recovers a Location header value of format URI /xyz to an * absoluteURI format according to the protocol rules. * This simply implies that we re-create the prefixed scheme, * user/passwd (if any), host and port string and prepend it * to the location URI. */ static void recover_absolute_uri(HTTPServer *trans, Octstr *loc) { Octstr *os; gw_assert(loc != NULL && trans != NULL); /* we'll only accept locations with a leading / */ if (octstr_get_char(loc, 0) == '/') { /* scheme */ os = trans->ssl ? octstr_create("https://") : octstr_create("http://"); /* credentials, if any */ if (trans->username && trans->password) { octstr_append(os, trans->username); octstr_append_char(os, ':'); octstr_append(os, trans->password); octstr_append_char(os, '@'); } /* host */ octstr_append(os, trans->host); /* port, only added if literally not default. */ if (trans->port != 80 || trans->ssl) { octstr_format_append(os, ":%ld", trans->port); } /* prepend the created octstr to the loc, and destroy then. */ octstr_insert(loc, os, 0); octstr_destroy(os); } } /* * Read and parse the status response line from an HTTP server. * Fill in trans->persistent and trans->status with the findings. * Return -1 for error, 1 for status line not yet available, 0 for OK. */ static int client_read_status(HTTPServer *trans) { Octstr *line, *version; long space; int ret; line = conn_read_line(trans->conn); if (line == NULL) { if (conn_eof(trans->conn) || conn_error(trans->conn)) return -1; return 1; } debug("gwlib.http", 0, "HTTP: Status line: <%s>", octstr_get_cstr(line)); space = octstr_search_char(line, ' ', 0); if (space == -1) goto error; version = octstr_copy(line, 0, space); ret = parse_http_version(version); octstr_destroy(version); if (ret == -1) goto error; trans->persistent = ret; octstr_delete(line, 0, space + 1); space = octstr_search_char(line, ' ', 0); if (space == -1) goto error; octstr_truncate(line, space); if (octstr_parse_long(&trans->status, line, 0, 10) == -1) goto error; octstr_destroy(line); return 0; error: error(0, "HTTP: Malformed status line from HTTP server: <%s>", octstr_get_cstr(line)); octstr_destroy(line); return -1; } static int response_expectation(int method, int status) { if (status == HTTP_NO_CONTENT || status == HTTP_NOT_MODIFIED || http_status_class(status) == HTTP_STATUS_PROVISIONAL || method == HTTP_METHOD_HEAD) return expect_no_body; else return expect_body; } static void handle_transaction(Connection *conn, void *data) { HTTPServer *trans; int ret; Octstr *h; int rc; trans = data; if (run_status != running) { conn_unregister(conn); return; } while (trans->state != transaction_done) { switch (trans->state) { case connecting: debug("gwlib.http", 0, "Get info about connecting socket"); if (conn_get_connect_result(trans->conn) != 0) { debug("gwlib.http", 0, "Socket not connected"); goto error; } if ((rc = send_request(trans)) == 0) { trans->state = reading_status; } else { debug("gwlib.http", 0, "Failed while sending request"); goto error; } break; case reading_status: ret = client_read_status(trans); if (ret < 0) { /* * Couldn't read the status from the socket. This may mean * that the socket had been closed by the server after an * idle timeout. */ debug("gwlib.http",0,"Failed while reading status"); goto error; } else if (ret == 0) { /* Got the status, go read headers and body next. */ trans->state = reading_entity; trans->response = entity_create(response_expectation(trans->method, trans->status)); } else { return; } break; case reading_entity: ret = entity_read(trans->response, conn); if (ret < 0) { debug("gwlib.http",0,"Failed reading entity"); goto error; } else if (ret == 0 && http_status_class(trans->status) == HTTP_STATUS_PROVISIONAL) { /* This was a provisional reply; get the real one now. */ trans->state = reading_status; entity_destroy(trans->response); trans->response = NULL; } else if (ret == 0) { trans->state = transaction_done; #ifdef DUMP_RESPONSE /* Dump the response */ debug("gwlib.http", 0, "HTTP: Received response:"); h = build_response(trans->response->headers, trans->response->body); octstr_dump(h, 0); octstr_destroy(h); #endif } else { return; } break; default: panic(0, "Internal error: Invalid HTTPServer state."); } } conn_unregister(trans->conn); /* * Take care of persistent connection handling. * At this point we have only obeyed if server responds in HTTP/1.0 or 1.1 * and have assigned trans->persistent accordingly. This can be keept * for default usage, but if we have [Proxy-]Connection: keep-alive, then * we're still forcing persistancy of the connection. */ h = http_header_find_first(trans->response->headers, "Connection"); if (h != NULL && octstr_case_compare(h, octstr_imm("close")) == 0) trans->persistent = 0; if (h != NULL && octstr_case_compare(h, octstr_imm("keep-alive")) == 0) trans->persistent = 1; octstr_destroy(h); if (proxy_used_for_host(trans->host, trans->url)) { h = http_header_find_first(trans->response->headers, "Proxy-Connection"); if (h != NULL && octstr_case_compare(h, octstr_imm("close")) == 0) trans->persistent = 0; if (h != NULL && octstr_case_compare(h, octstr_imm("keep-alive")) == 0) trans->persistent = 1; octstr_destroy(h); } #ifdef USE_KEEPALIVE if (trans->persistent) { if (proxy_used_for_host(trans->host, trans->url)) conn_pool_put(trans->conn, proxy_hostname, proxy_port, trans->ssl, trans->certkeyfile, http_interface); else conn_pool_put(trans->conn, trans->host, trans->port, trans->ssl, trans->certkeyfile, http_interface); } else #endif conn_destroy(trans->conn); trans->conn = NULL; /* * Check if the HTTP server told us to look somewhere else, * hence if we got one of the following response codes: * HTTP_MOVED_PERMANENTLY (301) * HTTP_FOUND (302) * HTTP_SEE_OTHER (303) * HTTP_TEMPORARY_REDIRECT (307) */ if ((h = get_redirection_location(trans)) != NULL) { /* * This is a redirected response, we have to follow. * * According to HTTP/1.1 (RFC 2616), section 14.30 any Location * header value should be 'absoluteURI', which is defined in * RFC 2616, section 3.2.1 General Syntax, and specifically in * RFC 2396, section 3 URI Syntactic Components as * * absoluteURI = scheme ":" ( hier_part | opaque_part ) * * Some HTTP servers 'interpret' a leading UDI / as that kind * of absoluteURI, which is not correct, following the protocol in * detail. But we'll try to recover from that misleaded * interpreation and try to convert the partly absoluteURI to a * fully qualified absoluteURI. * * http_URL = "http:" "//" [ userid : password "@"] host * [ ":" port ] [ abs_path [ "?" query ]] * */ octstr_strip_blanks(h); recover_absolute_uri(trans, h); /* * Clean up all trans stuff for the next request we do. */ octstr_destroy(trans->url); octstr_destroy(trans->host); trans->port = 0; octstr_destroy(trans->uri); octstr_destroy(trans->username); octstr_destroy(trans->password); trans->host = NULL; trans->port = 0; trans->uri = NULL; trans->username = NULL; trans->password = NULL; trans->ssl = 0; trans->url = h; /* apply new absolute URL to next request */ trans->state = request_not_sent; trans->status = -1; entity_destroy(trans->response); trans->response = NULL; --trans->follow_remaining; conn_destroy(trans->conn); trans->conn = NULL; /* re-inject request to the front of the queue */ gwlist_insert(pending_requests, 0, trans); } else { /* handle this response as usual */ gwlist_produce(trans->caller, trans); } return; error: conn_unregister(trans->conn); conn_destroy(trans->conn); trans->conn = NULL; error(0, "Couldn't fetch <%s>", octstr_get_cstr(trans->url)); trans->status = -1; gwlist_produce(trans->caller, trans); } /* * Build a complete HTTP request given the host, port, path and headers. * Add Host: and Content-Length: headers (and others that may be necessary). * Return the request as an Octstr. */ static Octstr *build_request(char *method_name, Octstr *path_or_url, Octstr *host, long port, int ssl, List *headers, Octstr *request_body) { /* XXX headers missing */ Octstr *request; int i, host_found = 0; request = octstr_format("%s %S HTTP/1.1\r\n", method_name, path_or_url); #ifdef USE_KEEPALIVE octstr_append(request, octstr_imm("Connection: keep-alive\r\n")); #endif for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) { /* check if Host already set in the headers */ if (header_is_called(gwlist_get(headers, i), "Host")) host_found = 1; octstr_append(request, gwlist_get(headers, i)); octstr_append(request, octstr_imm("\r\n")); } if (!host_found) { octstr_format_append(request, "Host: %S", host); /* * In accordance with HTT/1.1 [RFC 2616], section 14.23 "Host" * we shall ONLY add the port number if it is not one of the * officially assigned port numbers. This means we need to obey * port 80 for non-SSL connections and port 443 for SSL-enabled. */ if ((port != HTTP_PORT && !ssl) || (port != HTTPS_PORT && ssl)) octstr_format_append(request, ":%ld", port); octstr_append(request, octstr_imm("\r\n")); } octstr_append(request, octstr_imm("\r\n")); if (request_body != NULL) octstr_append(request, request_body); return request; } /* * Re-build the HTTP response given the headers and the body. * Return the response as an Octstr. */ static Octstr *build_response(List *headers, Octstr *body) { Octstr *response; int i; response = octstr_create(""); for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) { octstr_append(response, gwlist_get(headers, i)); octstr_append(response, octstr_imm("\r\n")); } octstr_append(response, octstr_imm("\r\n")); if (body != NULL) octstr_append(response, body); return response; } HTTPURLParse *http_urlparse_create(void) { HTTPURLParse *p; p = gw_malloc(sizeof(HTTPURLParse)); p->url = NULL; p->scheme = NULL; p->host = NULL; p->port = 0; p->user = NULL; p->pass = NULL; p->path = NULL; p->query = NULL; p->fragment = NULL; return p; } void http_urlparse_destroy(HTTPURLParse *p) { gw_assert(p != NULL); octstr_destroy(p->url); octstr_destroy(p->scheme); octstr_destroy(p->host); octstr_destroy(p->user); octstr_destroy(p->pass); octstr_destroy(p->path); octstr_destroy(p->query); octstr_destroy(p->fragment); gw_free(p); } void parse_dump(HTTPURLParse *p) { if (p == NULL) return; debug("http.parse_url",0,"Parsing URL `%s':", octstr_get_cstr(p->url)); debug("http.parse_url",0," Scheme: %s", octstr_get_cstr(p->scheme)); debug("http.parse_url",0," Host: %s", octstr_get_cstr(p->host)); debug("http.parse_url",0," Port: %ld", p->port); debug("http.parse_url",0," Username: %s", octstr_get_cstr(p->user)); debug("http.parse_url",0," Password: %s", octstr_get_cstr(p->pass)); debug("http.parse_url",0," Path: %s", octstr_get_cstr(p->path)); debug("http.parse_url",0," Query: %s", octstr_get_cstr(p->query)); debug("http.parse_url",0," Fragment: %s", octstr_get_cstr(p->fragment)); } /* * Parse the URL to get all components, which are: scheme, hostname, * port, username, password, path (URI), query (the CGI parameter list), * fragment (#). * * On success return the HTTPURLParse structure, otherwise NULL if the URL * seems malformed. * * We assume HTTP URLs of the form specified in "3.2.2 http URL" in * RFC 2616: * * http_URL = "http:" "//" [ userid : password "@"] host [ ":" port ] [ abs_path [ "?" query ]] */ HTTPURLParse *parse_url(Octstr *url) { HTTPURLParse *p; Octstr *prefix, *prefix_https; long prefix_len; int host_len, colon, slash, at, auth_sep, query; host_len = colon = slash = at = auth_sep = query = 0; prefix = octstr_imm("http://"); prefix_https = octstr_imm("https://"); prefix_len = octstr_len(prefix); if (octstr_case_search(url, prefix, 0) != 0) { if (octstr_case_search(url, prefix_https, 0) == 0) { #ifdef HAVE_LIBSSL debug("gwlib.http", 0, "HTTPS URL; Using SSL for the connection"); prefix = prefix_https; prefix_len = octstr_len(prefix_https); #else error(0, "Attempt to use HTTPS <%s> but SSL not compiled in", octstr_get_cstr(url)); return NULL; #endif } else { error(0, "URL <%s> doesn't start with `%s' nor `%s'", octstr_get_cstr(url), octstr_get_cstr(prefix), octstr_get_cstr(prefix_https)); return NULL; } } /* an URL should be more (at least one charset) then the scheme itself */ if (octstr_len(url) == prefix_len) { error(0, "URL <%s> is malformed.", octstr_get_cstr(url)); return NULL; } /* check if colon and slashes are within scheme */ colon = octstr_search_char(url, ':', prefix_len); slash = octstr_search_char(url, '/', prefix_len); if (colon == prefix_len || slash == prefix_len) { error(0, "URL <%s> is malformed.", octstr_get_cstr(url)); return NULL; } /* create struct and add values succesively while parsing */ p = http_urlparse_create(); p->url = octstr_duplicate(url); p->scheme = octstr_duplicate(prefix); /* try to parse authentication separator */ at = octstr_search_char(url, '@', prefix_len); if (at != -1) { if ((slash == -1 || ( slash != -1 && at < slash))) { auth_sep = octstr_search_char(url, ':', prefix_len); if (auth_sep != -1 && (auth_sep < at)) { octstr_set_char(url, auth_sep, '@'); colon = octstr_search_char(url, ':', prefix_len); } } else { at = -1; } } /* * We have to watch out here for 4 cases: * a) hostname, no port or path * b) hostname, port, no path * c) hostname, path, no port * d) hostname, port and path */ /* we only have the hostname, no port or path. */ if (slash == -1 && colon == -1) { host_len = octstr_len(url) - prefix_len; #ifdef HAVE_LIBSSL p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ? HTTPS_PORT : HTTP_PORT; #else p->port = HTTP_PORT; #endif /* HAVE_LIBSSL */ } /* we have a port, but no path. */ else if (slash == -1) { host_len = colon - prefix_len; if (octstr_parse_long((long*) &(p->port), url, colon + 1, 10) == -1) { error(0, "URL <%s> has malformed port number.", octstr_get_cstr(url)); http_urlparse_destroy(p); return NULL; } } /* we have a path, but no port. */ else if (colon == -1 || colon > slash) { host_len = slash - prefix_len; #ifdef HAVE_LIBSSL p->port = (octstr_compare(p->scheme, octstr_imm("https://")) == 0) ? HTTPS_PORT : HTTP_PORT; #else p->port = HTTP_PORT; #endif /* HAVE_LIBSSL */ } /* we have both, path and port. */ else if (colon < slash) { host_len = colon - prefix_len; if (octstr_parse_long((long*) &(p->port), url, colon + 1, 10) == -1) { error(0, "URL <%s> has malformed port number.", octstr_get_cstr(url)); http_urlparse_destroy(p); return NULL; } /* none of the above, so there is something wrong here */ } else { error(0, "Internal error in URL parsing logic."); http_urlparse_destroy(p); return NULL; } /* there was an authenticator separator, so try to parse * the username and password credentials */ if (at != -1) { int at2; at2 = octstr_search_char(url, '@', prefix_len); p->user = octstr_copy(url, prefix_len, at2 - prefix_len); p->pass = (at2 != at) ? octstr_copy(url, at2 + 1, at - at2 - 1) : NULL; if (auth_sep != -1) octstr_set_char(url, auth_sep, ':'); host_len = host_len - at + prefix_len - 1; prefix_len = at + 1; } /* query (CGI vars) */ query = octstr_search_char(url, '?', (slash == -1) ? prefix_len : slash); if (query != -1) { p->query = octstr_copy(url, query + 1, octstr_len(url)); if (colon == -1) host_len = slash != -1 ? slash - prefix_len : query - prefix_len; } /* path */ p->path = (slash == -1) ? octstr_create("/") : ((query != -1) && (query > slash) ? octstr_copy(url, slash, query - slash) : octstr_copy(url, slash, octstr_len(url) - slash)); /* hostname */ p->host = octstr_copy(url, prefix_len, host_len); /* XXX add fragment too */ /* dump components */ parse_dump(p); return p; } /* copy all relevant parsed data to the server info struct */ static void parse2trans(HTTPURLParse *p, HTTPServer *t) { if (p == NULL || t == NULL) return; if (p->user && !t->username) t->username = octstr_duplicate(p->user); if (p->pass && !t->password) t->password = octstr_duplicate(p->pass); if (p->host && !t->host) t->host = octstr_duplicate(p->host); if (p->port && !t->port) t->port = p->port; if (p->path && !t->uri) { t->uri = octstr_duplicate(p->path); if (p->query) { /* add the query too */ octstr_append_char(t->uri, '?'); octstr_append(t->uri, p->query); } } t->ssl = (p->scheme && (octstr_compare(p->scheme, octstr_imm("https://")) == 0) && !t->ssl) ? 1 : 0; } static Connection *get_connection(HTTPServer *trans) { Connection *conn = NULL; Octstr *host; HTTPURLParse *p; int port, ssl; /* if the parsing has not yet been done, then do it now */ if (!trans->host && trans->port == 0 && trans->url != NULL) { if ((p = parse_url(trans->url)) != NULL) { parse2trans(p, trans); http_urlparse_destroy(p); } else { goto error; } } if (proxy_used_for_host(trans->host, trans->url)) { host = proxy_hostname; port = proxy_port; ssl = proxy_ssl; } else { host = trans->host; port = trans->port; ssl = trans->ssl; } conn = conn_pool_get(host, port, ssl, trans->certkeyfile, http_interface); if (conn == NULL) goto error; return conn; error: conn_destroy(conn); error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url)); return NULL; } /* * Build and send the HTTP request. Return 0 for success or -1 for error. */ static int send_request(HTTPServer *trans) { char buf[128]; Octstr *request = NULL; if (trans->method == HTTP_METHOD_POST) { /* * Add a Content-Length header. Override an existing one, if * necessary. We must have an accurate one in order to use the * connection for more than a single request. */ http_header_remove_all(trans->request_headers, "Content-Length"); snprintf(buf, sizeof(buf), "%ld", octstr_len(trans->request_body)); http_header_add(trans->request_headers, "Content-Length", buf); } /* * ok, this has to be an GET or HEAD request method then, * if it contains a body, then this is not HTTP conform, so at * least warn the user */ else if (trans->request_body != NULL) { warning(0, "HTTP: GET or HEAD method request contains body:"); octstr_dump(trans->request_body, 0); } /* * we have to assume all values in trans are already set * by parse_url() before calling this. */ if (trans->username != NULL) http_add_basic_auth(trans->request_headers, trans->username, trans->password); if (proxy_used_for_host(trans->host, trans->url)) { proxy_add_authentication(trans->request_headers); request = build_request(http_method2name(trans->method), trans->url, trans->host, trans->port, trans->ssl, trans->request_headers, trans->request_body); } else { request = build_request(http_method2name(trans->method), trans->uri, trans->host, trans->port, trans->ssl, trans->request_headers, trans->request_body); } debug("gwlib.http", 0, "HTTP: Sending request:"); octstr_dump(request, 0); if (conn_write(trans->conn, request) == -1) goto error; octstr_destroy(request); return 0; error: conn_destroy(trans->conn); trans->conn = NULL; octstr_destroy(request); error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url)); return -1; } /* * This thread starts the transaction: it connects to the server and sends * the request. It then sends the transaction to the read_response_thread * via started_requests_queue. */ static void write_request_thread(void *arg) { HTTPServer *trans; int rc; while (run_status == running) { trans = gwlist_consume(pending_requests); if (trans == NULL) break; gw_assert(trans->state == request_not_sent); debug("gwlib.http", 0, "Queue contains %ld pending requests.", gwlist_len(pending_requests)); /* * get the connection to use * also calls parse_url() to populate the trans values */ trans->conn = get_connection(trans); if (trans->conn == NULL) gwlist_produce(trans->caller, trans); else if (conn_is_connected(trans->conn) == 0) { debug("gwlib.http", 0, "Socket connected at once"); if ((rc = send_request(trans)) == 0) { trans->state = reading_status; conn_register(trans->conn, client_fdset, handle_transaction, trans); } else { gwlist_produce(trans->caller, trans); } } else { /* Socket not connected, wait for connection */ debug("gwlib.http", 0, "Socket connecting"); trans->state = connecting; conn_register(trans->conn, client_fdset, handle_transaction, trans); } } } static void start_client_threads(void) { if (!client_threads_are_running) { /* * To be really certain, we must repeat the test, but use the * lock first. If the test failed, however, we _know_ we've * already initialized. This strategy of double testing avoids * using the lock more than a few times at startup. */ mutex_lock(client_thread_lock); if (!client_threads_are_running) { client_fdset = fdset_create_real(http_client_timeout); if (gwthread_create(write_request_thread, NULL) == -1) { error(0, "HTTP: Could not start client write_request thread."); fdset_destroy(client_fdset); client_threads_are_running = 0; } else client_threads_are_running = 1; } mutex_unlock(client_thread_lock); } } void http_set_interface(const Octstr *our_host) { http_interface = octstr_duplicate(our_host); } void http_set_client_timeout(long timeout) { http_client_timeout = timeout; if (client_fdset != NULL) { /* we are already initialized set timeout in fdset */ fdset_set_timeout(client_fdset, http_client_timeout); } } void http_start_request(HTTPCaller *caller, int method, Octstr *url, List *headers, Octstr *body, int follow, void *id, Octstr *certkeyfile) { HTTPServer *trans; int follow_remaining; if (follow) follow_remaining = HTTP_MAX_FOLLOW; else follow_remaining = 0; trans = server_create(caller, method, url, headers, body, follow_remaining, certkeyfile); if (id == NULL) /* We don't leave this NULL so http_receive_result can use NULL * to signal no more requests */ trans->request_id = http_start_request; else trans->request_id = id; gwlist_produce(pending_requests, trans); start_client_threads(); } void *http_receive_result_real(HTTPCaller *caller, int *status, Octstr **final_url, List **headers, Octstr **body, int blocking) { HTTPServer *trans; void *request_id; if (blocking == 0) trans = gwlist_extract_first(caller); else trans = gwlist_consume(caller); if (trans == NULL) return NULL; request_id = trans->request_id; *status = trans->status; if (trans->status >= 0) { *final_url = trans->url; *headers = trans->response->headers; *body = trans->response->body; trans->url = NULL; trans->response->headers = NULL; trans->response->body = NULL; } else { *final_url = NULL; *headers = NULL; *body = NULL; } server_destroy(trans); return request_id; } int http_get_real(int method, Octstr *url, List *request_headers, Octstr **final_url, List **reply_headers, Octstr **reply_body) { HTTPCaller *caller; int status; void *ret; caller = http_caller_create(); http_start_request(caller, method, url, request_headers, NULL, 1, http_get_real, NULL); ret = http_receive_result(caller, &status, final_url, reply_headers, reply_body); http_caller_destroy(caller); if (ret == NULL) return -1; return status; } static void client_init(void) { pending_requests = gwlist_create(); gwlist_add_producer(pending_requests); client_thread_lock = mutex_create(); } static void client_shutdown(void) { gwlist_remove_producer(pending_requests); gwthread_join_every(write_request_thread); client_threads_are_running = 0; gwlist_destroy(pending_requests, server_destroy); mutex_destroy(client_thread_lock); fdset_destroy(client_fdset); client_fdset = NULL; octstr_destroy(http_interface); http_interface = NULL; } /*********************************************************************** * HTTP server interface. */ /* * Information about a client that has connected to the server we implement. */ struct HTTPClient { int port; Connection *conn; Octstr *ip; enum { reading_request_line, reading_request, request_is_being_handled, sending_reply } state; int method; /* HTTP_METHOD_ value */ Octstr *url; int use_version_1_0; int persistent_conn; unsigned long conn_time; /* store time for timeouting */ HTTPEntity *request; }; /* * Variables related to server side implementation. */ static Mutex *server_thread_lock = NULL; static volatile sig_atomic_t server_thread_is_running = 0; static long server_thread_id = -1; static List *new_server_sockets = NULL; static List *closed_server_sockets = NULL; static int keep_servers_open = 0; /* List with all active HTTPClient's */ static List *active_connections; static HTTPClient *client_create(int port, Connection *conn, Octstr *ip) { HTTPClient *p; #ifdef HAVE_LIBSSL if (conn_get_ssl(conn)) debug("gwlib.http", 0, "HTTP: Creating SSL-enabled HTTPClient for `%s', using cipher '%s'.", octstr_get_cstr(ip), SSL_get_cipher_version(conn_get_ssl(conn))); else #endif debug("gwlib.http", 0, "HTTP: Creating HTTPClient for `%s'.", octstr_get_cstr(ip)); p = gw_malloc(sizeof(*p)); p->port = port; p->conn = conn; p->ip = ip; p->state = reading_request_line; p->url = NULL; p->use_version_1_0 = 0; p->persistent_conn = 1; p->conn_time = time(NULL); p->request = NULL; debug("gwlib.http", 0, "HTTP: Created HTTPClient area %p.", p); /* add this client to active_connections */ gwlist_produce(active_connections, p); return p; } static void client_destroy(void *client) { HTTPClient *p; long a_len; if (client == NULL) return; p = client; /* drop this client from active_connections list */ gwlist_lock(active_connections); if (gwlist_delete_equal(active_connections, p) != 1) panic(0, "HTTP: Race condition in client_destroy(%p) detected!", client); /* signal server thread that client slot is free */ a_len = gwlist_len(active_connections); gwlist_unlock(active_connections); if (a_len >= HTTP_SERVER_MAX_ACTIVE_CONNECTIONS - 1) gwthread_wakeup(server_thread_id); debug("gwlib.http", 0, "HTTP: Destroying HTTPClient area %p.", p); gw_assert_allocated(p, __FILE__, __LINE__, __func__); debug("gwlib.http", 0, "HTTP: Destroying HTTPClient for `%s'.", octstr_get_cstr(p->ip)); conn_destroy(p->conn); octstr_destroy(p->ip); octstr_destroy(p->url); entity_destroy(p->request); gw_free(p); } static void client_reset(HTTPClient *p) { debug("gwlib.http", 0, "HTTP: Resetting HTTPClient for `%s'.", octstr_get_cstr(p->ip)); p->state = reading_request_line; p->conn_time = time(NULL); gw_assert(p->request == NULL); } /* * Checks whether the client connection is meant to be persistent or not. * Returns 1 for true, 0 for false. * Reference: RFC2616, section 8.1.2.1 Negotiation */ static int client_is_persistent(List *headers, int use_version_1_0) { Octstr *h = http_header_find_first(headers, "Connection"); if (h == NULL) { /* assumes persistent for HTTP/1.1, not for HTTP/1.0 */ return !use_version_1_0; } else { List *values = octstr_split(h, octstr_imm(",")); int ret; octstr_destroy(h); if (gwlist_search(values, octstr_imm("keep-alive"), octstr_item_case_match) != NULL) { /* Keep-Alive was requested */ ret = 1; } else if (gwlist_search(values, octstr_imm("close"), octstr_item_case_match) != NULL) { /* Close was requested */ ret = 0; } else { /* Nothing was requested, so based on HTTP version */ ret = (!use_version_1_0); } gwlist_destroy(values, octstr_destroy_item); return ret; } return 1; } /* * Port specific lists of clients with requests. */ struct port { int fd; int port; int ssl; List *clients_with_requests; Counter *active_consumers; FDSet *server_fdset; }; static Mutex *port_mutex = NULL; static Dict *port_collection = NULL; static int port_match(void *client, void *port) { return ((HTTPClient*)client)->port == *((int*)port); } static void port_init(void) { port_mutex = mutex_create(); port_collection = dict_create(1024, NULL); /* create list with all active_connections */ active_connections = gwlist_create(); } static void port_shutdown(void) { mutex_destroy(port_mutex); dict_destroy(port_collection); /* destroy active_connections list */ gwlist_destroy(active_connections, client_destroy); } static Octstr *port_key(int port) { return octstr_format("%d", port); } static struct port *port_add(int port) { Octstr *key; struct port *p; key = port_key(port); mutex_lock(port_mutex); if ((p = dict_get(port_collection, key)) == NULL) { p = gw_malloc(sizeof(*p)); p->clients_with_requests = gwlist_create(); gwlist_add_producer(p->clients_with_requests); p->active_consumers = counter_create(); p->server_fdset = fdset_create_real(HTTP_SERVER_TIMEOUT); dict_put(port_collection, key, p); } else { warning(0, "HTTP: port_add called for existing port (%d)", port); } mutex_unlock(port_mutex); octstr_destroy(key); return p; } static void port_remove(int port) { Octstr *key; struct port *p; List *l; HTTPClient *client; key = port_key(port); mutex_lock(port_mutex); p = dict_remove(port_collection, key); mutex_unlock(port_mutex); octstr_destroy(key); if (p == NULL) { error(0, "HTTP: Could not find port (%d) in port_collection.", port); return; } gwlist_remove_producer(p->clients_with_requests); while (counter_value(p->active_consumers) > 0) gwthread_sleep(0.1); /* Reasonable use of busy waiting. */ gwlist_destroy(p->clients_with_requests, client_destroy); counter_destroy(p->active_consumers); /* * In order to avoid race conditions with FDSet thread, we * destroy Clients for this port in two steps: * 1) unregister from fdset with gwlist_lock held, so client_destroy * cannot destroy our client that we currently use * 2) without gwlist_lock held destroy every client, we can do this * because we only one thread that can use this client struct */ gwlist_lock(active_connections); l = gwlist_search_all(active_connections, &port, port_match); while(l != NULL && (client = gwlist_extract_first(l)) != NULL) conn_unregister(client->conn); gwlist_unlock(active_connections); gwlist_destroy(l, NULL); while((client = gwlist_search(active_connections, &port, port_match)) != NULL) client_destroy(client); /* now destroy fdset */ fdset_destroy(p->server_fdset); gw_free(p); } static void port_put_request(HTTPClient *client) { Octstr *key; struct port *p; mutex_lock(port_mutex); key = port_key(client->port); p = dict_get(port_collection, key); octstr_destroy(key); if (p == NULL) { /* client was too slow and we closed port already */ mutex_unlock(port_mutex); client_destroy(client); return; } gwlist_produce(p->clients_with_requests, client); mutex_unlock(port_mutex); } static HTTPClient *port_get_request(int port) { Octstr *key; struct port *p; HTTPClient *client; mutex_lock(port_mutex); key = port_key(port); p = dict_get(port_collection, key); octstr_destroy(key); if (p == NULL) { client = NULL; mutex_unlock(port_mutex); } else { counter_increase(p->active_consumers); mutex_unlock(port_mutex); /* Placement of this unlock is tricky. */ client = gwlist_consume(p->clients_with_requests); counter_decrease(p->active_consumers); } return client; } static void port_set_timeout(int port, long timeout) { Octstr *key; struct port *p; mutex_lock(port_mutex); key = port_key(port); p = dict_get(port_collection, key); octstr_destroy(key); if (p != NULL) fdset_set_timeout(p->server_fdset, timeout); mutex_unlock(port_mutex); } static FDSet *port_get_fdset(int port) { Octstr *key; struct port *p; FDSet *ret = NULL; mutex_lock(port_mutex); key = port_key(port); p = dict_get(port_collection, key); octstr_destroy(key); if (p != NULL) ret = p->server_fdset; mutex_unlock(port_mutex); return ret; } static int parse_request_line(int *method, Octstr **url, int *use_version_1_0, Octstr *line) { List *words; Octstr *version; Octstr *method_str; int ret; words = octstr_split_words(line); if (gwlist_len(words) != 3) { gwlist_destroy(words, octstr_destroy_item); return -1; } method_str = gwlist_get(words, 0); *url = gwlist_get(words, 1); version = gwlist_get(words, 2); gwlist_destroy(words, NULL); if (octstr_compare(method_str, octstr_imm("GET")) == 0) *method = HTTP_METHOD_GET; else if (octstr_compare(method_str, octstr_imm("POST")) == 0) *method = HTTP_METHOD_POST; else if (octstr_compare(method_str, octstr_imm("HEAD")) == 0) *method = HTTP_METHOD_HEAD; else goto error; ret = parse_http_version(version); if (ret < 0) goto error; *use_version_1_0 = !ret; octstr_destroy(method_str); octstr_destroy(version); return 0; error: octstr_destroy(method_str); octstr_destroy(*url); octstr_destroy(version); *url = NULL; return -1; } static void receive_request(Connection *conn, void *data) { HTTPClient *client; Octstr *line; int ret; if (run_status != running) { conn_unregister(conn); return; } client = data; for (;;) { switch (client->state) { case reading_request_line: line = conn_read_line(conn); if (line == NULL) { if (conn_eof(conn) || conn_error(conn)) goto error; return; } ret = parse_request_line(&client->method, &client->url, &client->use_version_1_0, line); octstr_destroy(line); /* client sent bad request? */ if (ret == -1) { /* * mark client as not persistent in order to destroy connection * afterwards */ client->persistent_conn = 0; /* unregister connection, http_send_reply handle this */ conn_unregister(conn); http_send_reply(client, HTTP_BAD_REQUEST, NULL, NULL); return; } /* * RFC2616 (4.3) says we should read a message body if there * is one, even on GET requests. */ client->request = entity_create(expect_body_if_indicated); client->state = reading_request; break; case reading_request: ret = entity_read(client->request, conn); if (ret < 0) goto error; if (ret == 0) { client->state = request_is_being_handled; conn_unregister(conn); port_put_request(client); } return; case sending_reply: /* Implicit conn_unregister() and _destroy */ if (conn_error(conn)) goto error; if (conn_outbuf_len(conn) > 0) return; /* Reply has been sent completely */ if (!client->persistent_conn) { /* * in order to avoid race conditions while conn will be destroyed but * conn is still in use, we call conn_unregister explicit here because * conn_unregister call uses locks */ conn_unregister(conn); client_destroy(client); return; } /* Start reading another request */ client_reset(client); break; default: panic(0, "Internal error: HTTPClient state is wrong."); } } error: /* * in order to avoid race conditions while conn will be destroyed but * conn is still in use, we call conn_unregister explicit here because * conn_unregister call uses locks */ conn_unregister(conn); client_destroy(client); } static void server_thread(void *dummy) { struct pollfd *tab = NULL; struct port **ports = NULL; int tab_size = 0, n, i, fd, ret, max_clients_reached; struct sockaddr_in addr; socklen_t addrlen; HTTPClient *client; Connection *conn; int *portno; n = max_clients_reached = 0; while (run_status == running && keep_servers_open) { while (n == 0 || gwlist_len(new_server_sockets) > 0) { struct port *p = gwlist_consume(new_server_sockets); if (p == NULL) { debug("gwlib.http", 0, "HTTP: No new servers. Quitting."); break; } else { debug ("gwlib.http", 0, "HTTP: Including port %d, fd %d for polling in server thread", p->port, p->fd); } if (tab_size <= n) { tab_size++; tab = gw_realloc(tab, tab_size * sizeof(*tab)); ports = gw_realloc(ports, tab_size * sizeof(*ports)); if (tab == NULL || ports == NULL) { tab_size--; port_remove(p->port); continue; } } tab[n].fd = p->fd; tab[n].events = POLLIN; ports[n] = p; n++; } if (max_clients_reached && gwlist_len(active_connections) >= HTTP_SERVER_MAX_ACTIVE_CONNECTIONS) { /* TODO start cleanup of stale connections */ /* wait for slots to become free */ gwthread_sleep(1.0); } else if (!max_clients_reached && (ret = gwthread_poll(tab, n, -1.0)) == -1) { if (errno != EINTR) /* a signal was caught during poll() function */ warning(errno, "HTTP: gwthread_poll failed."); continue; } for (i = 0; i < n; ++i) { if (tab[i].revents & POLLIN) { /* check our limit */ if (gwlist_len(active_connections) >= HTTP_SERVER_MAX_ACTIVE_CONNECTIONS) { max_clients_reached = 1; break; } else { max_clients_reached = 0; } addrlen = sizeof(addr); fd = accept(tab[i].fd, (struct sockaddr *) &addr, &addrlen); if (fd == -1) { error(errno, "HTTP: Error accepting a client."); } else { Octstr *client_ip = host_ip(addr); /* * Be aware that conn_wrap_fd() will return NULL if SSL * handshake has failed, so we only client_create() if * there is an conn. */ if ((conn = conn_wrap_fd(fd, ports[i]->ssl))) { client = client_create(ports[i]->port, conn, client_ip); conn_register(conn, ports[i]->server_fdset, receive_request, client); } else { error(0, "HTTP: unsuccessful SSL handshake for client `%s'", octstr_get_cstr(client_ip)); octstr_destroy(client_ip); } } } } while ((portno = gwlist_extract_first(closed_server_sockets)) != NULL) { for (i = 0; i < n; ++i) { if (ports[i]->port == *portno) { (void) close(tab[i].fd); tab[i].fd = -1; tab[i].events = 0; port_remove(ports[i]->port); ports[i] = NULL; n--; /* now put the last entry on this place */ tab[i].fd = tab[n].fd; tab[i].events = tab[n].events; tab[n].fd = -1; tab[n].events = 0; ports[i] = ports[n]; } } gw_free(portno); } } /* make sure we close all ports */ for (i = 0; i < n; ++i) { (void) close(tab[i].fd); port_remove(ports[i]->port); } gw_free(tab); gw_free(ports); server_thread_id = -1; } static void start_server_thread(void) { if (!server_thread_is_running) { /* * To be really certain, we must repeat the test, but use the * lock first. If the test failed, however, we _know_ we've * already initialized. This strategy of double testing avoids * using the lock more than a few times at startup. */ mutex_lock(server_thread_lock); if (!server_thread_is_running) { server_thread_id = gwthread_create(server_thread, NULL); server_thread_is_running = 1; } mutex_unlock(server_thread_lock); } } void http_set_server_timeout(int port, long timeout) { port_set_timeout(port, timeout); } int http_open_port_if(int port, int ssl, Octstr *interface) { struct port *p; if (ssl) info(0, "HTTP: Opening SSL server at port %d.", port); else info(0, "HTTP: Opening server at port %d.", port); p = port_add(port); p->port = port; p->ssl = ssl; p->fd = make_server_socket(port, (interface ? octstr_get_cstr(interface) : NULL)); if (p->fd == -1) { port_remove(port); return -1; } gwlist_produce(new_server_sockets, p); keep_servers_open = 1; start_server_thread(); gwthread_wakeup(server_thread_id); return 0; } int http_open_port(int port, int ssl) { return http_open_port_if(port, ssl, NULL); } void http_close_port(int port) { int *p; p = gw_malloc(sizeof(*p)); *p = port; gwlist_produce(closed_server_sockets, p); gwthread_wakeup(server_thread_id); } void http_close_all_ports(void) { if (server_thread_id != -1) { keep_servers_open = 0; gwthread_wakeup(server_thread_id); gwthread_join_every(server_thread); server_thread_is_running = 0; } } /* * Parse CGI variables from the path given in a GET. Return a list * of HTTPCGIvar pointers. Modify the url so that the variables are * removed. */ static List *parse_cgivars(Octstr *url) { HTTPCGIVar *v; List *list; int query, et, equals; Octstr *arg, *args; query = octstr_search_char(url, '?', 0); if (query == -1) return gwlist_create(); args = octstr_copy(url, query + 1, octstr_len(url)); octstr_truncate(url, query); list = gwlist_create(); while (octstr_len(args) > 0) { et = octstr_search_char(args, '&', 0); if (et == -1) et = octstr_len(args); arg = octstr_copy(args, 0, et); octstr_delete(args, 0, et + 1); equals = octstr_search_char(arg, '=', 0); if (equals == -1) equals = octstr_len(arg); v = gw_malloc(sizeof(HTTPCGIVar)); v->name = octstr_copy(arg, 0, equals); v->value = octstr_copy(arg, equals + 1, octstr_len(arg)); octstr_url_decode(v->name); octstr_url_decode(v->value); octstr_destroy(arg); gwlist_append(list, v); } octstr_destroy(args); return list; } HTTPClient *http_accept_request(int port, Octstr **client_ip, Octstr **url, List **headers, Octstr **body, List **cgivars) { HTTPClient *client; do { client = port_get_request(port); if (client == NULL) { debug("gwlib.http", 0, "HTTP: No clients with requests, quitting."); return NULL; } /* check whether client connection still ok */ conn_wait(client->conn, 0); if (conn_error(client->conn) || conn_eof(client->conn)) { client_destroy(client); client = NULL; } } while(client == NULL); *client_ip = octstr_duplicate(client->ip); *url = client->url; *headers = client->request->headers; *body = client->request->body; *cgivars = parse_cgivars(client->url); if (client->method != HTTP_METHOD_POST) { octstr_destroy(*body); *body = NULL; } client->persistent_conn = client_is_persistent(client->request->headers, client->use_version_1_0); client->url = NULL; client->request->headers = NULL; client->request->body = NULL; entity_destroy(client->request); client->request = NULL; return client; } /* * The http_send_reply(...) uses this function to determinate the * reason pahrase for a status code. */ static const char *http_reason_phrase(int status) { switch (status) { case HTTP_OK: return "OK"; /* 200 */ case HTTP_CREATED: return "Created"; /* 201 */ case HTTP_ACCEPTED: return "Accepted"; /* 202 */ case HTTP_NO_CONTENT: return "No Content"; /* 204 */ case HTTP_RESET_CONTENT: return "Reset Content"; /* 205 */ case HTTP_MOVED_PERMANENTLY: return "Moved Permanently"; /* 301 */ case HTTP_FOUND: return "Found"; /* 302 */ case HTTP_SEE_OTHER: return "See Other"; /* 303 */ case HTTP_NOT_MODIFIED: return "Not Modified"; /* 304 */ case HTTP_TEMPORARY_REDIRECT: return "Temporary Redirect"; /* 307 */ case HTTP_BAD_REQUEST: return "Bad Request"; /* 400 */ case HTTP_UNAUTHORIZED: return "Unauthorized"; /* 401 */ case HTTP_FORBIDDEN: return "Forbidden"; /* 403 */ case HTTP_NOT_FOUND: return "Not Found"; /* 404 */ case HTTP_BAD_METHOD: return "Method Not Allowed"; /* 405 */ case HTTP_NOT_ACCEPTABLE: return "Not Acceptable"; /* 406 */ case HTTP_REQUEST_ENTITY_TOO_LARGE: return "Request Entity Too Large"; /* 413 */ case HTTP_UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type"; /* 415 */ case HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error"; /* 500 */ case HTTP_NOT_IMPLEMENTED: return "Not Implemented"; /* 501 */ case HTTP_BAD_GATEWAY: return "Bad Gateway"; /* 502 */ } return "Foo"; } void http_send_reply(HTTPClient *client, int status, List *headers, Octstr *body) { Octstr *response; Octstr *date; long i; int ret; if (client->use_version_1_0) response = octstr_format("HTTP/1.0 %d %s\r\n", status, http_reason_phrase(status)); else response = octstr_format("HTTP/1.1 %d %s\r\n", status, http_reason_phrase(status)); /* identify ourselfs */ octstr_format_append(response, "Server: " GW_NAME "/%s\r\n", GW_VERSION); /* let's inform the client of our time */ date = date_format_http(time(NULL)); octstr_format_append(response, "Date: %s\r\n", octstr_get_cstr(date)); octstr_destroy(date); octstr_format_append(response, "Content-Length: %ld\r\n", octstr_len(body)); /* Indicate if we're keeping the connection or closing. */ if (client->persistent_conn) octstr_format_append(response, "Connection: Keep-Alive\r\n"); else octstr_format_append(response, "Connection: Close\r\n"); for (i = 0; i < gwlist_len(headers); ++i) octstr_format_append(response, "%S\r\n", gwlist_get(headers, i)); octstr_format_append(response, "\r\n"); if (body != NULL && client->method != HTTP_METHOD_HEAD) octstr_append(response, body); ret = conn_write(client->conn, response); octstr_destroy(response); /* obey return code of conn_write() */ /* sending response was successful */ if (ret == 0) { /* HTTP/1.0 or 1.1, hence keep-alive or keep-alive */ if (!client->persistent_conn) { client_destroy(client); } else { /* XXX mark this HTTPClient in the keep-alive cleaner thread */ client_reset(client); conn_register(client->conn, port_get_fdset(client->port), receive_request, client); } } /* queued for sending, we don't want to block */ else if (ret == 1) { client->state = sending_reply; conn_register(client->conn, port_get_fdset(client->port), receive_request, client); } /* error while sending response */ else { client_destroy(client); } } void http_close_client(HTTPClient *client) { client_destroy(client); } int http_method(HTTPClient *client) { return client->method; } Octstr *http_request_url(HTTPClient *client) { return client->url; } static void server_init(void) { new_server_sockets = gwlist_create(); gwlist_add_producer(new_server_sockets); closed_server_sockets = gwlist_create(); server_thread_lock = mutex_create(); } static void destroy_struct_server(void *p) { struct port *pp; pp = p; (void) close(pp->fd); port_remove(pp->port); } static void destroy_int_pointer(void *p) { (void) close(*(int *) p); gw_free(p); } static void server_shutdown(void) { gwlist_remove_producer(new_server_sockets); if (server_thread_id != -1) { gwthread_wakeup(server_thread_id); gwthread_join_every(server_thread); server_thread_is_running = 0; } mutex_destroy(server_thread_lock); gwlist_destroy(new_server_sockets, destroy_struct_server); gwlist_destroy(closed_server_sockets, destroy_int_pointer); } /*********************************************************************** * CGI variable manipulation. */ void http_destroy_cgiargs(List *args) { HTTPCGIVar *v; gwlib_assert_init(); if (args == NULL) return ; while ((v = gwlist_extract_first(args)) != NULL) { octstr_destroy(v->name); octstr_destroy(v->value); gw_free(v); } gwlist_destroy(args, NULL); } Octstr *http_cgi_variable(List *list, char *name) { int i; HTTPCGIVar *v; gwlib_assert_init(); gw_assert(list != NULL); gw_assert(name != NULL); for (i = 0; i < gwlist_len(list); ++i) { v = gwlist_get(list, i); if (octstr_str_compare(v->name, name) == 0) return v->value; } return NULL; } /*********************************************************************** * Header manipulation. */ static int header_is_called(Octstr *header, char *name) { long colon; colon = octstr_search_char(header, ':', 0); if (colon == -1) return 0; if ((long) strlen(name) != colon) return 0; return strncasecmp(octstr_get_cstr(header), name, colon) == 0; } List *http_create_empty_headers(void) { gwlib_assert_init(); return gwlist_create(); } void http_destroy_headers(List *headers) { gwlib_assert_init(); gwlist_destroy(headers, octstr_destroy_item); } void http_header_add(List *headers, char *name, char *contents) { gwlib_assert_init(); gw_assert(headers != NULL); gw_assert(name != NULL); gw_assert(contents != NULL); gwlist_append(headers, octstr_format("%s: %s", name, contents)); } /* * Given an headers list and a position, returns its header name and value, * or (X-Unknown, header) if it doesn't exist or if it's malformed - missing * ":" for example */ void http_header_get(List *headers, long i, Octstr **name, Octstr **value) { Octstr *os; long colon; gwlib_assert_init(); gw_assert(i >= 0); gw_assert(name != NULL); gw_assert(value != NULL); os = gwlist_get(headers, i); if (os == NULL) colon = -1; else colon = octstr_search_char(os, ':', 0); if (colon == -1) { error(0, "HTTP: Header does not contain a colon. BAD."); *name = octstr_create("X-Unknown"); *value = octstr_duplicate(os); } else { *name = octstr_copy(os, 0, colon); *value = octstr_copy(os, colon + 1, octstr_len(os) - colon - 1); octstr_strip_blanks(*value); } } /* * Given an headers list and a name, returns its value or NULL if it * doesn't exist */ Octstr *http_header_value(List *headers, Octstr *name) { Octstr *value; long i; Octstr *os; long colon; Octstr *current_name; gwlib_assert_init(); gw_assert(name); value = NULL; i = 0; while (i < gwlist_len(headers)) { os = gwlist_get(headers, i); if (os == NULL) colon = -1; else colon = octstr_search_char(os, ':', 0); if (colon == -1) { return NULL; } else { current_name = octstr_copy(os, 0, colon); } if (octstr_case_compare(current_name, name) == 0) { value = octstr_copy(os, colon + 1, octstr_len(os) - colon - 1); octstr_strip_blanks(value); octstr_destroy(current_name); return value; } octstr_destroy(current_name); ++i; } return NULL; } List *http_header_duplicate(List *headers) { List *new; long i, len; gwlib_assert_init(); if (headers == NULL) return NULL; new = http_create_empty_headers(); len = gwlist_len(headers); for (i = 0; i < len; ++i) gwlist_append(new, octstr_duplicate(gwlist_get(headers, i))); return new; } #define MAX_HEADER_LENGTH 256 /* * Aggregate header in one (or more) lines with several parameters separated * by commas, instead of one header per parameter */ void http_header_pack(List *headers) { Octstr *name, *value; Octstr *name2, *value2; long i, j; gwlib_assert_init(); gw_assert(headers != NULL); /* * For each header, search forward headers for similar ones and if possible, * add it to current header and delete it */ for(i = 0; i < gwlist_len(headers); i++) { http_header_get(headers, i, &name, &value); /* debug("http_header_pack", 0, "HTTP_HEADER_PACK: Processing header %d. [%s: %s]", i, octstr_get_cstr(name), octstr_get_cstr(value)); */ for(j=i+1; j < gwlist_len(headers); j++) { http_header_get(headers, j, &name2, &value2); if(octstr_case_compare(name, name2) == 0) { if(octstr_len(value) + 2 + octstr_len(value2) > MAX_HEADER_LENGTH) { octstr_destroy(name2); octstr_destroy(value2); break; } else { Octstr *header; /* Delete old header */ header = gwlist_get(headers, i); octstr_destroy(header); gwlist_delete(headers, i, 1); /* Adds comma and new value to old header value */ octstr_append(value, octstr_imm(", ")); octstr_append(value, value2); /* Creates a new header */ header = octstr_create(""); octstr_append(header, name); octstr_append(header, octstr_imm(": ")); octstr_append(header, value); gwlist_insert(headers, i, header); /* Delete this header */ header = gwlist_get(headers, j); octstr_destroy(header); gwlist_delete(headers, j, 1); j--; } } octstr_destroy(name2); octstr_destroy(value2); } octstr_destroy(name); octstr_destroy(value); } } void http_append_headers(List *to, List *from) { Octstr *header; long i; gwlib_assert_init(); gw_assert(to != NULL); gw_assert(from != NULL); for (i = 0; i < gwlist_len(from); ++i) { header = gwlist_get(from, i); gwlist_append(to, octstr_duplicate(header)); } } void http_header_combine(List *old_headers, List *new_headers) { long i; Octstr *name; Octstr *value; /* * Avoid doing this scan if old_headers is empty anyway. */ if (gwlist_len(old_headers) > 0) { for (i = 0; i < gwlist_len(new_headers); i++) { http_header_get(new_headers, i, &name, &value); http_header_remove_all(old_headers, octstr_get_cstr(name)); octstr_destroy(name); octstr_destroy(value); } } http_append_headers(old_headers, new_headers); } Octstr *http_header_find_first_real(List *headers, char *name, const char *file, long line, const char *func) { long i, name_len; Octstr *h, *value; gwlib_assert_init(); gw_assert(headers != NULL); gw_assert(name != NULL); name_len = strlen(name); for (i = 0; i < gwlist_len(headers); ++i) { h = gwlist_get(headers, i); if (header_is_called(h, name)) { value = octstr_copy_real(h, name_len + 1, octstr_len(h), file, line, func); octstr_strip_blanks(value); return value; } } return NULL; } List *http_header_find_all(List *headers, char *name) { List *list; long i; Octstr *h; gwlib_assert_init(); gw_assert(headers != NULL); gw_assert(name != NULL); list = gwlist_create(); for (i = 0; i < gwlist_len(headers); ++i) { h = gwlist_get(headers, i); if (header_is_called(h, name)) gwlist_append(list, octstr_duplicate(h)); } return list; } long http_header_remove_all(List *headers, char *name) { long i; Octstr *h; long count; gwlib_assert_init(); gw_assert(headers != NULL); gw_assert(name != NULL); i = 0; count = 0; while (i < gwlist_len(headers)) { h = gwlist_get(headers, i); if (header_is_called(h, name)) { gwlist_delete(headers, i, 1); octstr_destroy(h); count++; } else i++; } return count; } void http_remove_hop_headers(List *headers) { Octstr *h; List *connection_headers; gwlib_assert_init(); gw_assert(headers != NULL); /* * The hop-by-hop headers are a standard list, plus those named * in the Connection header(s). */ connection_headers = http_header_find_all(headers, "Connection"); while ((h = gwlist_consume(connection_headers))) { List *hop_headers; Octstr *e; octstr_delete(h, 0, strlen("Connection:")); hop_headers = http_header_split_value(h); octstr_destroy(h); while ((e = gwlist_consume(hop_headers))) { http_header_remove_all(headers, octstr_get_cstr(e)); octstr_destroy(e); } gwlist_destroy(hop_headers, NULL); } gwlist_destroy(connection_headers, NULL); http_header_remove_all(headers, "Connection"); http_header_remove_all(headers, "Keep-Alive"); http_header_remove_all(headers, "Proxy-Authenticate"); http_header_remove_all(headers, "Proxy-Authorization"); http_header_remove_all(headers, "TE"); http_header_remove_all(headers, "Trailers"); http_header_remove_all(headers, "Transfer-Encoding"); http_header_remove_all(headers, "Upgrade"); } void http_header_mark_transformation(List *headers, Octstr *new_body, Octstr *new_type) { Octstr *new_length = NULL; /* Remove all headers that no longer apply to the new body. */ http_header_remove_all(headers, "Content-Length"); http_header_remove_all(headers, "Content-MD5"); http_header_remove_all(headers, "Content-Type"); /* Add headers that we need to describe the new body. */ new_length = octstr_format("%ld", octstr_len(new_body)); http_header_add(headers, "Content-Length", octstr_get_cstr(new_length)); if(octstr_len(new_type)) http_header_add(headers, "Content-Type", octstr_get_cstr(new_type)); /* Perhaps we should add Warning: 214 "Transformation applied" too? */ octstr_destroy(new_length); } void http_header_get_content_type(List *headers, Octstr **type, Octstr **charset) { Octstr *h; long semicolon, equals, len; gwlib_assert_init(); gw_assert(headers != NULL); gw_assert(type != NULL); gw_assert(charset != NULL); h = http_header_find_first(headers, "Content-Type"); if (h == NULL) { *type = octstr_create("application/octet-stream"); *charset = octstr_create(""); } else { octstr_strip_blanks(h); semicolon = octstr_search_char(h, ';', 0); if (semicolon == -1) { *type = h; *charset = octstr_create(""); } else { *charset = octstr_duplicate(h); octstr_delete(*charset, 0, semicolon + 1); octstr_strip_blanks(*charset); equals = octstr_search_char(*charset, '=', 0); if (equals == -1) octstr_truncate(*charset, 0); else { octstr_delete(*charset, 0, equals + 1); if (octstr_get_char(*charset, 0) == '"') octstr_delete(*charset, 0, 1); len = octstr_len(*charset); if (octstr_get_char(*charset, len - 1) == '"') octstr_truncate(*charset, len - 1); } octstr_truncate(h, semicolon); octstr_strip_blanks(h); *type = h; } /* * According to HTTP/1.1 (RFC 2616, section 3.7.1) we have to ensure * to return charset 'iso-8859-1' in case of no given encoding and * content-type is a 'text' subtype. */ if (octstr_len(*charset) == 0 && octstr_ncompare(*type, octstr_imm("text"), 4) == 0) octstr_append_cstr(*charset, "ISO-8859-1"); } } static void http_header_add_element(List *list, Octstr *value, long start, long end) { Octstr *element; element = octstr_copy(value, start, end - start); octstr_strip_blanks(element); if (octstr_len(element) == 0) octstr_destroy(element); else gwlist_append(list, element); } long http_header_quoted_string_len(Octstr *header, long start) { long len; long pos; int c; if (octstr_get_char(header, start) != '"') return -1; len = octstr_len(header); for (pos = start + 1; pos < len; pos++) { c = octstr_get_char(header, pos); if (c == '\\') /* quoted-pair */ pos++; else if (c == '"') return pos - start + 1; } warning(0, "Header contains unterminated quoted-string:"); warning(0, "%s", octstr_get_cstr(header)); return len - start; } List *http_header_split_value(Octstr *value) { long start; /* start of current element */ long pos; long len; List *result; int c; /* * According to RFC2616 section 4.2, a field-value is either *TEXT * (the caller is responsible for not feeding us one of those) or * combinations of token, separators, and quoted-string. We're * looking for commas which are separators, and have to skip * commas in quoted-strings. */ result = gwlist_create(); len = octstr_len(value); start = 0; for (pos = 0; pos < len; pos++) { c = octstr_get_char(value, pos); if (c == ',') { http_header_add_element(result, value, start, pos); start = pos + 1; } else if (c == '"') { pos += http_header_quoted_string_len(value, pos); pos--; /* compensate for the loop's pos++ */ } } http_header_add_element(result, value, start, len); return result; } List *http_header_split_auth_value(Octstr *value) { List *result; Octstr *auth_scheme; Octstr *element; long i; /* * According to RFC2617, both "challenge" and "credentials" * consist of an auth-scheme followed by a list of auth-param. * Since we have to parse a list of challenges or credentials, * we have to look for auth-scheme to signal the start of * a new element. (We can't just split on commas because * they are also used to separate the auth-params.) * * An auth-scheme is a single token, while an auth-param is * always a key=value pair. So we can recognize an auth-scheme * as a token that is not followed by a '=' sign. * * Simple approach: First split at all commas, then recombine * the elements that belong to the same challenge or credential. * This is somewhat expensive but saves programmer thinking time. * * Richard Braakman */ result = http_header_split_value(value); if (gwlist_len(result) == 0) return result; auth_scheme = gwlist_get(result, 0); i = 1; while (i < gwlist_len(result)) { int c; long pos; element = gwlist_get(result, i); /* * If the element starts with: token '=' * then it's just an auth_param; append it to the current * auth_scheme. If it starts with: token token '=' * then it's the start of a new auth scheme. * * To make the scan easier, we consider anything other * than whitespace or '=' to be part of a token. */ /* Skip first token */ for (pos = 0; pos < octstr_len(element); pos++) { c = octstr_get_char(element, pos); if (isspace(c) || c == '=') break; } /* Skip whitespace, if any */ while (isspace(octstr_get_char(element, pos))) pos++; if (octstr_get_char(element, pos) == '=') { octstr_append_char(auth_scheme, ';'); octstr_append(auth_scheme, element); gwlist_delete(result, i, 1); octstr_destroy(element); } else { char semicolon = ';'; octstr_insert_data(element, pos, &semicolon, 1); auth_scheme = element; i++; } } return result; } void http_header_dump(List *headers) { long i; gwlib_assert_init(); debug("gwlib.http", 0, "Dumping HTTP headers:"); for (i = 0; headers != NULL && i < gwlist_len(headers); ++i) octstr_dump(gwlist_get(headers, i), 1); debug("gwlib.http", 0, "End of dump."); } void http_cgivar_dump(List *cgiargs) { HTTPCGIVar *v; long i, len; gwlib_assert_init(); len = gwlist_len(cgiargs); debug("gwlib.http", 0, "Dumping %ld cgi variables:", len); for (i = 0; i < len; i++) { v = gwlist_get(cgiargs, i); octstr_dump(v->name, 0); octstr_dump(v->value, 0); } debug("gwlib.http", 0, "End of dump."); } void http_cgivar_dump_into(List *cgiargs, Octstr *os) { HTTPCGIVar *v; long i; if (os == NULL) return; gwlib_assert_init(); for (i = 0; i < gwlist_len(cgiargs); i++) { v = gwlist_get(cgiargs, i); octstr_format_append(os, "&%E=%E", v->name, v->value); } } static int http_something_accepted(List *headers, char *header_name, char *what) { int found; long i; List *accepts; Octstr *needle = octstr_create(what); gwlib_assert_init(); gw_assert(headers != NULL); gw_assert(what != NULL); /* return all headers with this name */ accepts = http_header_find_all(headers, header_name); found = 0; for (i = 0; !found && i < gwlist_len(accepts); ++i) { Octstr *header_value = gwlist_get(accepts, i); if (octstr_case_search(header_value, needle, 0) != -1) found = 1; } octstr_destroy(needle); http_destroy_headers(accepts); return found; } int http_type_accepted(List *headers, char *type) { return http_something_accepted(headers, "Accept", type); } int http_charset_accepted(List *headers, char *charset) { return http_something_accepted(headers, "Accept-Charset", charset); } void http_add_basic_auth(List *headers, Octstr *username, Octstr *password) { Octstr *os; if (password != NULL) os = octstr_format("%S:%S", username, password); else os = octstr_format("%S", username); octstr_binary_to_base64(os); octstr_strip_blanks(os); octstr_insert(os, octstr_imm("Basic "), 0); http_header_add(headers, "Authorization", octstr_get_cstr(os)); octstr_destroy(os); } Octstr *http_get_header_parameter(Octstr *value, Octstr *parameter) { long pos, len, end; int c, found = 0; Octstr *result = NULL; len = octstr_len(value); /* Find the start of the first parameter. */ for (pos = 0; pos < len; pos++) { c = octstr_get_char(value, pos); if (c == ';') break; else if (c == '"') pos += http_header_quoted_string_len(value, pos) - 1; } if (pos >= len) return NULL; /* no parameters */ for (pos++; pos > 0 && pos < len && found == 0; pos++) { Octstr *key = NULL; Octstr *val = NULL; end = octstr_search_char(value, '=', pos); if (end < 0) end = octstr_search_char(value, ';', pos); if (end < 0) end = octstr_len(value); key = octstr_copy(value, pos, end - pos); octstr_strip_blanks(key); pos = end; if (octstr_get_char(value, pos) == '=') { pos++; while (isspace(octstr_get_char(value, pos))) pos++; if (octstr_get_char(value, pos) == '"') end = pos + http_header_quoted_string_len(value, pos); else end = octstr_search_char(value, ';', pos); if (end < 0) end = octstr_len(value); val = octstr_copy(value, pos, end - pos); octstr_strip_blanks(val); pos = end; pos = octstr_search_char(value, ';', pos); } /* is this the pair we look for? bail out then*/ if (octstr_case_compare(key, parameter) == 0) { found++; result = octstr_duplicate(val); } octstr_destroy(key); octstr_destroy(val); } return result; } /*********************************************************************** * Module initialization and shutdown. */ void http_init(void) { gw_assert(run_status == limbo); #ifdef HAVE_LIBSSL conn_init_ssl(); #endif /* HAVE_LIBSSL */ proxy_init(); client_init(); conn_pool_init(); port_init(); server_init(); #ifdef HAVE_LIBSSL server_ssl_init(); #endif /* HAVE_LIBSSL */ run_status = running; } void http_shutdown(void) { gwlib_assert_init(); gw_assert(run_status == running); run_status = terminating; conn_pool_shutdown(); client_shutdown(); server_shutdown(); port_shutdown(); proxy_shutdown(); #ifdef HAVE_LIBSSL conn_shutdown_ssl(); server_shutdown_ssl(); #endif /* HAVE_LIBSSL */ run_status = limbo; } /* * This function relies on the HTTP_STATUS_* enum values being * chosen to fit this. */ int http_status_class(int code) { int sclass; if (code < 100 || code >= 600) sclass = HTTP_STATUS_UNKNOWN; else sclass = code - (code % 100); return sclass; } int http_name2method(Octstr *method) { gw_assert(method != NULL); if (octstr_str_compare(method, "GET") == 0) { return HTTP_METHOD_GET; } else if (octstr_str_compare(method, "POST") == 0) { return HTTP_METHOD_POST; } else if (octstr_str_compare(method, "HEAD") == 0) { return HTTP_METHOD_HEAD; } return -1; } char *http_method2name(int method) { gw_assert(method > 0 && method <= 3); return http_methods[method-1]; } gateway-1.4.5/gwlib/conn.h0000644000175000017500000003634113227613126014110 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * conn.h - declare Connection type to wrap a file descriptor * * This file defines operations on the Connection type, which provides * input and output buffers for a two-way file descriptor, such as a * socket or a serial device. * * The operations are designed for non-blocking use. Blocking can be * done explicitly with conn_wait() or conn_flush(). A thread that * blocks in these functions can be woken up with gwthread_wakeup. * * The write operations will queue the data for sending. They will * try to send whatever data can be sent immediately, if there's enough * of it queued. "Enough" is defined by a value which can be set with * conn_set_output_buffering. The caller must call either conn_wait * or conn_flush to actually send the data. * * The read operations will return whatever data is immediately * available. If none is, then the caller should not simply re-try * the request (that would cause a busy-loop); instead, it should * wait for more data with conn_wait(). * * The Connection structure has internal locks, so it can be shared * safely between threads. There is a race condition in the interface, * however, that can cause threads to wait unnecessarily if there are * multiple readers. But in that case there will always be at least one * thread busy reading. * * The overhead of locking can be avoided by "claiming" a Connection. * This means that only one thread will ever do operations on that * Connection; the caller must guarantee this. * * If any operation returns a code that indicates that the connection * is broken (due to an I/O error, normally), it will also have closed * the connection. Most operations work only on open connections; * not much can be done with a closed connection except destroy it. */ typedef struct Connection Connection; /* If conn_register was called for this connection, a callback function * of type conn_callback_t will be called when new input is available, * or when all data that was previously queued for output is sent. * The data pointer is the one supplied by the caller of conn_register. * NOTE: Beware of concurrency issues. The callback function will run * in the fdset's private thread, not in the caller's thread. * This also means that if the callback does a lot of work it will slow * down the polling process. This may be good or bad. */ typedef void conn_callback_t(Connection *conn, void *data); /* * If conn_register was called for this connection, a callback data destroyer * function will be called if conn_unregister, conn_destroy or conn_register * (with different data) called for this connection. * This function is responsible to destroy callback data. */ typedef void conn_callback_data_destroyer_t(void *data); #ifdef HAVE_LIBSSL /* Open an SSL connection to the given host and port. Same behavior * as conn_open_tcp() below. 'certkeyfile' specifies a PEM-encoded * file where OpenSSL looks for a private key and a certificate. */ Connection *conn_open_ssl(Octstr *host, int port, Octstr *certkeyfile, Octstr *our_host); /* Open an SSL connection to the given host and port. Same behavior * as conn_open_tcp_nb() below. 'certkeyfile' specifies a PEM-encoded * file where OpenSSL looks for a private key and a certificate. */ Connection *conn_open_ssl_nb(Octstr *host, int port, Octstr *certkeyfile, Octstr *our_host); void server_ssl_init(void); /* used by http.c */ #endif /* HAVE_LIBSSL */ /* * get the SSL config parameters from the provided Config group. * For a non-SSL system this is a no-op that does nothing. */ void conn_config_ssl (CfgGroup *grp); /* Open a TCP/IP connection to the given host and port. Return the * new Connection. If the connection can not be made, return NULL * and log the problem. */ Connection *conn_open_tcp(Octstr *host, int port, Octstr *our_host); /* As above, but binds our end to 'our_port'. If 'our_port' is 0, uses * any port like conn_open_tcp. */ Connection *conn_open_tcp_with_port(Octstr *host, int port, int our_port, Octstr *our_host); /* Open a TCP/IP connection to the given host and port. Return NULL in case of * error. Overwise return new Connection. */ Connection *conn_open_tcp_nb(Octstr *host, int port, Octstr *our_host); /* As above, but binds our end to 'our_port'. If 'our_port' is 0, uses * any port like conn_open_tcp. */ Connection *conn_open_tcp_nb_with_port(Octstr *host, int port, int our_port, Octstr *our_host); /* Returns 0 if socket is connected, -1 overwise */ int conn_is_connected(Connection *conn); /* If socket is in the 'connecting' state, it must be listen by poller. * After poller returns, connection must be checked for connection * procedure's result. Return 0 if connection done successfully */ int conn_get_connect_result(Connection *conn); /* Create a Connection structure around the given file descriptor. * The file descriptor must not be used for anything else after this; * it must always be accessed via the Connection operations. This * operation cannot fail. Second var indicates if the is a SSL enabled * connection. */ Connection *conn_wrap_fd(int fd, int ssl); /* Close and deallocate a Connection. Log any errors reported by * the close operation. */ void conn_destroy(Connection *conn); /* Assert that the calling thread will be the only one to ever * use this Connection. From now on no locking will be done * on this Connection. * It is a fatal error for two threads to try to claim one Connection, * or for another thread to try to use a Connection that has been claimed. */ void conn_claim(Connection *conn); /* Return the length of the unsent data queued for sending, in octets. */ long conn_outbuf_len(Connection *conn); /* Return the length of the unprocessed data ready for reading, in octets. */ long conn_inbuf_len(Connection *conn); /* Return 1 if there was an end-of-file indication from the last read or * wait operation. */ int conn_eof(Connection *conn); /* Return 1 if there was an error indication from the last read or wait * operation. */ int conn_error(Connection *conn); /* Try to write data in chunks of this size or more. Set it to 0 to * get an unbuffered connection. See the discussion on output buffering * at the top of this file for more information. */ void conn_set_output_buffering(Connection *conn, unsigned int size); /* Register this connection with an FDSet. This will make it unnecessary * to call conn_wait. Instead, the callback function will be called when * there is new data available, or when all data queued for output is * sent (note that small amounts are usually sent immediately without * queuing, and thus won't trigger the callback). A connection can be * registered with only one FDSet at a time. Return -1 if it was * already registered with a different FDSet, otherwise return 0. * A connection can be re-registered with the same FDSet. This will * change only the callback information, and is much more efficient * than calling conn_unregister first. * NOTE: Using conn_register will always mean that the Connection will be * used by more than one thread, so don't also call conn_claim. */ #define conn_register(conn, fdset, callback, data) \ conn_register_real(conn, fdset, callback, data, NULL) int conn_register_real(Connection *conn, FDSet *fdset, conn_callback_t callback, void *data, conn_callback_data_destroyer_t destroyer); /* * Remove the current registration and call data destroyer if not NULL. */ void conn_unregister(Connection *conn); /* Block the thread until one of the following is true: * - The timeout expires * - New data is available for reading * - Some data queued for output is sent (if there was any) * - The thread is woken up via the wakeup interface (in gwthread.h) * Return 1 if the timeout expired. Return 0 otherwise, if the * connection is okay. Return -1 if the connection is broken. * If the timeout is 0 seconds, check for the conditions above without * actually blocking. If it is negative, block indefinitely. */ int conn_wait(Connection *conn, double seconds); /* Try to send all data currently queued for output. Block until this * is done, or until the thread is interrupted or woken up. Return 0 * if it worked, 1 if there was an interruption, or -1 if the connection * is broken. */ int conn_flush(Connection *conn); /* Output functions. Each of these takes an open connection and some * data, formats the data and queues it for sending. It may also * try to send the data immediately. The current implementation always * does so. * Return 0 if the data was sent, 1 if it was queued for sending, * and -1 if the connection is broken. */ int conn_write(Connection *conn, Octstr *data); int conn_write_data(Connection *conn, unsigned char *data, long length); /* Write the length of the octstr as a standard network long, then * write the octstr itself. */ int conn_write_withlen(Connection *conn, Octstr *data); /* Input functions. Each of these takes an open connection and * returns data if it's available, or NULL if it's not. They will * not block. They will try to read in more data if there's not * enough in the buffer to fill the request. */ /* Return whatever data is available. */ Octstr *conn_read_everything(Connection *conn); /* Return exactly "length" octets of data, if at least that many * are available. Otherwise return NULL. */ Octstr *conn_read_fixed(Connection *conn, long length); /* If the input buffer starts with a full line of data (terminated by * LF or CR LF), then return that line as an Octstr and remove it * from the input buffer. Otherwise return NULL. */ Octstr *conn_read_line(Connection *conn); /* Read a standard network long giving the length of the following * data, then read the data itself, and pack it into an Octstr and * remove it from the input buffer. Otherwise return NULL. */ Octstr *conn_read_withlen(Connection *conn); /* If the input buffer contains a packet delimited by the "startmark" * and "endmark" characters, then return that packet (including the marks) * and delete everything up to the end of that packet from the input buffer. * Otherwise return NULL. * Everything up to the first startmark is discarded. */ Octstr *conn_read_packet(Connection *conn, int startmark, int endmark); #ifdef HAVE_LIBSSL #include #include /* Returns the SSL peer certificate for the given Connection or NULL * if none. */ X509 *get_peer_certificate(Connection *conn); /* These are called to initialize and shutdown the OpenSSL mutex locks. * They should be called before the _init_ssl, _shutdown_ssl functions. */ void openssl_init_locks(void); void openssl_shutdown_locks(void); /* These must be called if SSL is used. Currently http.c calls * conn_init_ssl and server_init_ssl from http_init and * conn_shutdown_ssl and server_shutdown_ssl from http_shutdown. */ void conn_init_ssl(void); void conn_shutdown_ssl(void); void server_init_ssl(void); void server_shutdown_ssl(void); /* Specifies a global PEM-encoded certificate and a private key file * to be used with SSL client connections (outgoing HTTP requests). * conn_init_ssl() must be called first. This checks that the private * key matches with the certificate and will panic if it doesn't. */ void conn_use_global_client_certkey_file(Octstr *certkeyfile); /* Specifies a global PEM-encoded certificate and a private key file * to be used with SSL server connections (incoming HTTP requests). * conn_init_ssl() must be called first. This checks that the private * key matches with the certificate and will panic if it doesn't. */ void conn_use_global_server_certkey_file(Octstr *certfile, Octstr *keyfile); /* Specifies files containing certificates Kannel is willing to trusted when * actins as https clients */ void conn_use_global_trusted_ca_file(Octstr *ssl_trusted_ca_file); /* * Specifies the encryption suites and ciphers that are allowed to be used. * Definition of the cipher string can be found at the openssl documentation * https://www.openssl.org/docs/manmaster/man1/ciphers.html */ void conn_use_global_client_cipher_list(Octstr *cipher); void conn_use_global_server_cipher_list(Octstr *cipher); /* Configures all global variables for client and server SSL mode * from the values specified within the configuration file. */ void conn_config_ssl(CfgGroup *grp); /* Returns the pointer to the SSL structure of the Connection given. * This should be used for determining if certain connections are * SSL enabled outside of the scope of conn.c. */ SSL *conn_get_ssl(Connection *conn); X509 *conn_get_peer_certificate(Connection *conn); #endif /* HAVE_LIBSSL */ int conn_get_id(Connection *conn); gateway-1.4.5/gwlib/latin1_to_gsm.h0000644000175000017500000002267311325337122015712 0ustar toljtolj#ifndef LATIN1_TO_GSM_H #define LATIN1_TO_GSM_H static const int latin1_to_gsm[256] = { /* 0x00 */ NRP, /* pc: NON PRINTABLE */ /* 0x01 */ NRP, /* pc: NON PRINTABLE */ /* 0x02 */ NRP, /* pc: NON PRINTABLE */ /* 0x03 */ NRP, /* pc: NON PRINTABLE */ /* 0x04 */ NRP, /* pc: NON PRINTABLE */ /* 0x05 */ NRP, /* pc: NON PRINTABLE */ /* 0x06 */ NRP, /* pc: NON PRINTABLE */ /* 0x07 */ NRP, /* pc: NON PRINTABLE */ /* 0x08 */ NRP, /* pc: NON PRINTABLE */ /* 0x09 */ NRP, /* pc: NON PRINTABLE */ /* 0x0a */ 0x0a, /* pc: NON PRINTABLE */ /* 0x0b */ NRP, /* pc: NON PRINTABLE */ /* 0x0c */ -0x0a, /* pc: NON PRINTABLE */ /* 0x0d */ 0x0d, /* pc: NON PRINTABLE */ /* 0x0e */ NRP, /* pc: NON PRINTABLE */ /* 0x0f */ NRP, /* pc: NON PRINTABLE */ /* 0x10 */ NRP, /* pc: NON PRINTABLE */ /* 0x11 */ NRP, /* pc: NON PRINTABLE */ /* 0x12 */ NRP, /* pc: NON PRINTABLE */ /* 0x13 */ NRP, /* pc: NON PRINTABLE */ /* 0x14 */ NRP, /* pc: NON PRINTABLE */ /* 0x15 */ NRP, /* pc: NON PRINTABLE */ /* 0x16 */ NRP, /* pc: NON PRINTABLE */ /* 0x17 */ NRP, /* pc: NON PRINTABLE */ /* 0x18 */ NRP, /* pc: NON PRINTABLE */ /* 0x19 */ NRP, /* pc: NON PRINTABLE */ /* 0x1a */ NRP, /* pc: NON PRINTABLE */ /* 0x1b */ NRP, /* pc: NON PRINTABLE */ /* 0x1c */ NRP, /* pc: NON PRINTABLE */ /* 0x1d */ NRP, /* pc: NON PRINTABLE */ /* 0x1e */ NRP, /* pc: NON PRINTABLE */ /* 0x1f */ NRP, /* pc: NON PRINTABLE */ /* 0x20 */ 0x20, /* pc: */ /* 0x21 */ 0x21, /* pc: ! */ /* 0x22 */ 0x22, /* pc: " */ /* 0x23 */ 0x23, /* pc: # */ /* 0x24 */ 0x02, /* pc: $ */ /* 0x25 */ 0x25, /* pc: % */ /* 0x26 */ 0x26, /* pc: & */ /* 0x27 */ 0x27, /* pc: ' */ /* 0x28 */ 0x28, /* pc: ( */ /* 0x29 */ 0x29, /* pc: ) */ /* 0x2a */ 0x2a, /* pc: * */ /* 0x2b */ 0x2b, /* pc: + */ /* 0x2c */ 0x2c, /* pc: , */ /* 0x2d */ 0x2d, /* pc: - */ /* 0x2e */ 0x2e, /* pc: . */ /* 0x2f */ 0x2f, /* pc: / */ /* 0x30 */ 0x30, /* pc: 0 */ /* 0x31 */ 0x31, /* pc: 1 */ /* 0x32 */ 0x32, /* pc: 2 */ /* 0x33 */ 0x33, /* pc: 3 */ /* 0x34 */ 0x34, /* pc: 4 */ /* 0x35 */ 0x35, /* pc: 5 */ /* 0x36 */ 0x36, /* pc: 6 */ /* 0x37 */ 0x37, /* pc: 7 */ /* 0x38 */ 0x38, /* pc: 8 */ /* 0x39 */ 0x39, /* pc: 9 */ /* 0x3a */ 0x3a, /* pc: : */ /* 0x3b */ 0x3b, /* pc: ; */ /* 0x3c */ 0x3c, /* pc: < */ /* 0x3d */ 0x3d, /* pc: = */ /* 0x3e */ 0x3e, /* pc: > */ /* 0x3f */ 0x3f, /* pc: ? */ /* 0x40 */ 0x00, /* pc: @ */ /* 0x41 */ 0x41, /* pc: A */ /* 0x42 */ 0x42, /* pc: B */ /* 0x43 */ 0x43, /* pc: C */ /* 0x44 */ 0x44, /* pc: D */ /* 0x45 */ 0x45, /* pc: E */ /* 0x46 */ 0x46, /* pc: F */ /* 0x47 */ 0x47, /* pc: G */ /* 0x48 */ 0x48, /* pc: H */ /* 0x49 */ 0x49, /* pc: I */ /* 0x4a */ 0x4a, /* pc: J */ /* 0x4b */ 0x4b, /* pc: K */ /* 0x4c */ 0x4c, /* pc: L */ /* 0x4d */ 0x4d, /* pc: M */ /* 0x4e */ 0x4e, /* pc: N */ /* 0x4f */ 0x4f, /* pc: O */ /* 0x50 */ 0x50, /* pc: P */ /* 0x51 */ 0x51, /* pc: Q */ /* 0x52 */ 0x52, /* pc: R */ /* 0x53 */ 0x53, /* pc: S */ /* 0x54 */ 0x54, /* pc: T */ /* 0x55 */ 0x55, /* pc: U */ /* 0x56 */ 0x56, /* pc: V */ /* 0x57 */ 0x57, /* pc: W */ /* 0x58 */ 0x58, /* pc: X */ /* 0x59 */ 0x59, /* pc: Y */ /* 0x5a */ 0x5a, /* pc: Z */ /* 0x5b */ -0x3c, /* pc: [ */ /* 0x5c */ -0x2f, /* pc: \ */ /* 0x5d */ -0x3e, /* pc: ] */ /* 0x5e */ -0x14, /* pc: ^ */ /* 0x5f */ 0x11, /* pc: _ */ /* 0x60 */ NRP, /* pc: ` */ /* 0x61 */ 0x61, /* pc: a */ /* 0x62 */ 0x62, /* pc: b */ /* 0x63 */ 0x63, /* pc: c */ /* 0x64 */ 0x64, /* pc: d */ /* 0x65 */ 0x65, /* pc: e */ /* 0x66 */ 0x66, /* pc: f */ /* 0x67 */ 0x67, /* pc: g */ /* 0x68 */ 0x68, /* pc: h */ /* 0x69 */ 0x69, /* pc: i */ /* 0x6a */ 0x6a, /* pc: j */ /* 0x6b */ 0x6b, /* pc: k */ /* 0x6c */ 0x6c, /* pc: l */ /* 0x6d */ 0x6d, /* pc: m */ /* 0x6e */ 0x6e, /* pc: n */ /* 0x6f */ 0x6f, /* pc: o */ /* 0x70 */ 0x70, /* pc: p */ /* 0x71 */ 0x71, /* pc: q */ /* 0x72 */ 0x72, /* pc: r */ /* 0x73 */ 0x73, /* pc: s */ /* 0x74 */ 0x74, /* pc: t */ /* 0x75 */ 0x75, /* pc: u */ /* 0x76 */ 0x76, /* pc: v */ /* 0x77 */ 0x77, /* pc: w */ /* 0x78 */ 0x78, /* pc: x */ /* 0x79 */ 0x79, /* pc: y */ /* 0x7a */ 0x7a, /* pc: z */ /* 0x7b */ -0x28, /* pc: { */ /* 0x7c */ -0x40, /* pc: | */ /* 0x7d */ -0x29, /* pc: } */ /* 0x7e */ -0x3d, /* pc: ~ */ /* 0x7f */ NRP, /* pc: NON PRINTABLE */ /* 0x80 */ NRP, /* pc: NON PRINTABLE */ /* 0x81 */ NRP, /* pc: NON PRINTABLE */ /* 0x82 */ NRP, /* pc: NON PRINTABLE */ /* 0x83 */ NRP, /* pc: NON PRINTABLE */ /* 0x84 */ NRP, /* pc: NON PRINTABLE */ /* 0x85 */ NRP, /* pc: NON PRINTABLE */ /* 0x86 */ NRP, /* pc: NON PRINTABLE */ /* 0x87 */ NRP, /* pc: NON PRINTABLE */ /* 0x88 */ NRP, /* pc: NON PRINTABLE */ /* 0x89 */ NRP, /* pc: NON PRINTABLE */ /* 0x8a */ NRP, /* pc: NON PRINTABLE */ /* 0x8b */ NRP, /* pc: NON PRINTABLE */ /* 0x8c */ NRP, /* pc: NON PRINTABLE */ /* 0x8d */ NRP, /* pc: NON PRINTABLE */ /* 0x8e */ NRP, /* pc: NON PRINTABLE */ /* 0x8f */ NRP, /* pc: NON PRINTABLE */ /* 0x90 */ NRP, /* pc: NON PRINTABLE */ /* 0x91 */ NRP, /* pc: NON PRINTABLE */ /* 0x92 */ NRP, /* pc: NON PRINTABLE */ /* 0x93 */ NRP, /* pc: NON PRINTABLE */ /* 0x94 */ NRP, /* pc: NON PRINTABLE */ /* 0x95 */ NRP, /* pc: NON PRINTABLE */ /* 0x96 */ NRP, /* pc: NON PRINTABLE */ /* 0x97 */ NRP, /* pc: NON PRINTABLE */ /* 0x98 */ NRP, /* pc: NON PRINTABLE */ /* 0x99 */ NRP, /* pc: NON PRINTABLE */ /* 0x9a */ NRP, /* pc: NON PRINTABLE */ /* 0x9b */ NRP, /* pc: NON PRINTABLE */ /* 0x9c */ NRP, /* pc: NON PRINTABLE */ /* 0x9d */ NRP, /* pc: NON PRINTABLE */ /* 0x9e */ NRP, /* pc: NON PRINTABLE */ /* 0x9f */ NRP, /* pc: NON PRINTABLE */ /* 0xa0 */ NRP, /* pc: NON PRINTABLE */ /* 0xa1 */ 0x40, /* pc: INVERTED EXCLAMATION MARK */ /* 0xa2 */ NRP, /* pc: NON PRINTABLE */ /* 0xa3 */ 0x01, /* pc: POUND SIGN */ /* 0xa4 */ 0x24, /* pc: CURRENCY SIGN */ /* 0xa5 */ 0x03, /* pc: YEN SIGN*/ /* 0xa6 */ NRP, /* pc: NON PRINTABLE */ /* 0xa7 */ 0x5f, /* pc: SECTION SIGN */ /* 0xa8 */ NRP, /* pc: NON PRINTABLE */ /* 0xa9 */ NRP, /* pc: NON PRINTABLE */ /* 0xaa */ NRP, /* pc: NON PRINTABLE */ /* 0xab */ NRP, /* pc: NON PRINTABLE */ /* 0xac */ NRP, /* pc: NON PRINTABLE */ /* 0xad */ NRP, /* pc: NON PRINTABLE */ /* 0xae */ NRP, /* pc: NON PRINTABLE */ /* 0xaf */ NRP, /* pc: NON PRINTABLE */ /* 0xb0 */ NRP, /* pc: NON PRINTABLE */ /* 0xb1 */ NRP, /* pc: NON PRINTABLE */ /* 0xb2 */ NRP, /* pc: NON PRINTABLE */ /* 0xb3 */ NRP, /* pc: NON PRINTABLE */ /* 0xb4 */ NRP, /* pc: NON PRINTABLE */ /* 0xb5 */ NRP, /* pc: NON PRINTABLE */ /* 0xb6 */ NRP, /* pc: NON PRINTABLE */ /* 0xb7 */ NRP, /* pc: NON PRINTABLE */ /* 0xb8 */ NRP, /* pc: NON PRINTABLE */ /* 0xb9 */ NRP, /* pc: NON PRINTABLE */ /* 0xba */ NRP, /* pc: NON PRINTABLE */ /* 0xbb */ NRP, /* pc: NON PRINTABLE */ /* 0xbc */ NRP, /* pc: NON PRINTABLE */ /* 0xbd */ NRP, /* pc: NON PRINTABLE */ /* 0xbe */ NRP, /* pc: NON PRINTABLE */ /* 0xbf */ 0x60, /* pc: INVERTED QUESTION MARK */ /* 0xc0 */ NRP, /* pc: NON PRINTABLE */ /* 0xc1 */ NRP, /* pc: NON PRINTABLE */ /* 0xc2 */ NRP, /* pc: NON PRINTABLE */ /* 0xc3 */ NRP, /* pc: NON PRINTABLE */ /* 0xc4 */ 0x5b, /* pc: LATIN CAPITAL LETTER A WITH DIAERESIS */ /* 0xc5 */ 0x0e, /* pc: LATIN CAPITAL LETTER A WITH RING ABOVE */ /* 0xc6 */ 0x1c, /* pc: LATIN CAPITAL LETTER AE */ /* 0xc7 */ 0x09, /* pc: LATIN CAPITAL LETTER C WITH CEDILLA (mapped to small) */ /* 0xc8 */ NRP, /* pc: NON PRINTABLE */ /* 0xc9 */ 0x1f, /* pc: LATIN CAPITAL LETTER E WITH ACUTE */ /* 0xca */ NRP, /* pc: NON PRINTABLE */ /* 0xcb */ NRP, /* pc: NON PRINTABLE */ /* 0xcc */ NRP, /* pc: NON PRINTABLE */ /* 0xcd */ NRP, /* pc: NON PRINTABLE */ /* 0xce */ NRP, /* pc: NON PRINTABLE */ /* 0xcf */ NRP, /* pc: NON PRINTABLE */ /* 0xd0 */ NRP, /* pc: NON PRINTABLE */ /* 0xd1 */ 0x5d, /* pc: LATIN CAPITAL LETTER N WITH TILDE */ /* 0xd2 */ NRP, /* pc: NON PRINTABLE */ /* 0xd3 */ NRP, /* pc: NON PRINTABLE */ /* 0xd4 */ NRP, /* pc: NON PRINTABLE */ /* 0xd5 */ NRP, /* pc: NON PRINTABLE */ /* 0xd6 */ 0x5c, /* pc: LATIN CAPITAL LETTER O WITH DIAEREIS */ /* 0xd7 */ NRP, /* pc: NON PRINTABLE */ /* 0xd8 */ 0x0b, /* pc: LATIN CAPITAL LETTER O WITH STROKE */ /* 0xd9 */ NRP, /* pc: NON PRINTABLE */ /* 0xda */ NRP, /* pc: NON PRINTABLE */ /* 0xdb */ NRP, /* pc: NON PRINTABLE */ /* 0xdc */ 0x5e, /* pc: LATIN CAPITAL LETTER U WITH DIAERESIS */ /* 0xdd */ NRP, /* pc: NON PRINTABLE */ /* 0xde */ NRP, /* pc: NON PRINTABLE */ /* 0xdf */ 0x1e, /* pc: LATIN SMALL LETTER SHARP S */ /* 0xe0 */ 0x7f, /* pc: LATIN SMALL LETTER A WITH GRAVE */ /* 0xe1 */ NRP, /* pc: NON PRINTABLE */ /* 0xe2 */ NRP, /* pc: NON PRINTABLE */ /* 0xe3 */ NRP, /* pc: NON PRINTABLE */ /* 0xe4 */ 0x7b, /* pc: LATIN SMALL LETTER A WITH DIAERESIS */ /* 0xe5 */ 0x0f, /* pc: LATIN SMALL LETTER A WITH RING ABOVE */ /* 0xe6 */ 0x1d, /* pc: LATIN SMALL LETTER AE */ /* 0xe7 */ 0x09, /* pc: LATIN SMALL LETTER C WITH CEDILLA */ /* 0xe8 */ 0x04, /* pc: NON PRINTABLE */ /* 0xe9 */ 0x05, /* pc: NON PRINTABLE */ /* 0xea */ NRP, /* pc: NON PRINTABLE */ /* 0xeb */ NRP, /* pc: NON PRINTABLE */ /* 0xec */ 0x07, /* pc: NON PRINTABLE */ /* 0xed */ NRP, /* pc: NON PRINTABLE */ /* 0xee */ NRP, /* pc: NON PRINTABLE */ /* 0xef */ NRP, /* pc: NON PRINTABLE */ /* 0xf0 */ NRP, /* pc: NON PRINTABLE */ /* 0xf1 */ 0x7d, /* pc: NON PRINTABLE */ /* 0xf2 */ 0x08, /* pc: NON PRINTABLE */ /* 0xf3 */ NRP, /* pc: NON PRINTABLE */ /* 0xf4 */ NRP, /* pc: NON PRINTABLE */ /* 0xf5 */ NRP, /* pc: NON PRINTABLE */ /* 0xf6 */ 0x7c, /* pc: NON PRINTABLE */ /* 0xf7 */ NRP, /* pc: NON PRINTABLE */ /* 0xf8 */ 0x0c, /* pc: NON PRINTABLE */ /* 0xf9 */ 0x06, /* pc: NON PRINTABLE */ /* 0xfa */ NRP, /* pc: NON PRINTABLE */ /* 0xfb */ NRP, /* pc: NON PRINTABLE */ /* 0xfc */ 0x7e, /* pc: NON PRINTABLE */ /* 0xfd */ NRP, /* pc: NON PRINTABLE */ /* 0xfe */ NRP, /* pc: NON PRINTABLE */ /* 0xff */ NRP, /* pc: NON PRINTABLE */ }; #endif gateway-1.4.5/gwlib/dbpool.h0000644000175000017500000001710713227613126014431 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool.h - database pool functions * * Stipe Tolj * Alexander Malysh */ #ifndef GWDBPOOL_H #define GWDBPOOL_H #if defined(HAVE_MYSQL) || defined(HAVE_SDB) || \ defined(HAVE_ORACLE) || defined(HAVE_SQLITE) || \ defined(HAVE_PGSQL) || defined(HAVE_SQLITE3) || \ defined(HAVE_MSSQL) || defined(HAVE_REDIS) || \ defined(HAVE_CASS) #define HAVE_DBPOOL 1 #endif /* supported databases for connection pools */ enum db_type { DBPOOL_MYSQL, DBPOOL_SDB, DBPOOL_ORACLE, DBPOOL_SQLITE, DBPOOL_PGSQL, DBPOOL_SQLITE3, DBPOOL_MSSQL, DBPOOL_REDIS, DBPOOL_CASS }; /* * The DBPool type. It is opaque: do not touch it except via the functions * defined in this header. */ typedef struct DBPool DBPool; /* * The DBPoolConn type. It stores the abtracted pointer to a database * specific connection and the pool pointer itself to allow easy * re-storage into the pool (also disallowing to insert the conn into an * other pool). */ typedef struct { void *conn; /* the pointer holding the database specific connection */ DBPool *pool; /* pointer of the pool where this connection belongs to */ } DBPoolConn; typedef struct { Octstr *host; long port; Octstr *username; Octstr *password; Octstr *database; } MySQLConf; /* * TODO Think how to get rid of it and have generic Conf struct */ typedef struct { Octstr *username; Octstr *password; Octstr *server; Octstr *database; } MSSQLConf; typedef struct { Octstr *username; Octstr *password; Octstr *tnsname; } OracleConf; typedef struct { Octstr *url; } SDBConf; typedef struct { Octstr *file; int lock_timeout; } SQLiteConf; typedef struct { Octstr *file; int lock_timeout; } SQLite3Conf; typedef struct { Octstr *host; long port; Octstr *username; Octstr *password; Octstr *database; Octstr *options; /* yet not used */ Octstr *tty; /* yet not used */ } PgSQLConf; typedef struct { Octstr *host; long port; Octstr *password; long database; long idle_timeout; } RedisConf; typedef struct { Octstr *host; long port; Octstr *username; Octstr *password; Octstr *database; long idle_timeout; } CassConf; typedef union { MSSQLConf *mssql; MySQLConf *mysql; SDBConf *sdb; OracleConf *oracle; SQLiteConf *sqlite; SQLite3Conf *sqlite3; PgSQLConf *pgsql; RedisConf *redis; CassConf *cass; } DBConf; /* * Create a database pool with #connections of connections. The pool * is stored within a queue list. * Returns a pointer to the pool object on success or NULL if the * creation fails. */ DBPool *dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connections); /* * Destroys the database pool. Includes also shutdowning all existing * connections within the pool queue. */ void dbpool_destroy(DBPool *p); /* * Increase the connection size of the pool by #conn connections. * Beware that you can't increase a pool size to more then the initial * dbpool_create() call defined and opened the maximum pool connections. * Returns how many connections have been additionally created and * inserted to the pool. */ unsigned int dbpool_increase(DBPool *p, unsigned int conn); /* * Decrease the connection size of the pool by #conn connections. * A pool size can only by reduced up to 0. So if the caller specifies * to close more connections then there are in the pool, all connections * are closed. * Returns how many connections have been shutdown and deleted from the * pool queue. */ unsigned int dbpool_decrease(DBPool *p, unsigned int conn); /* * Return the number of connections that are currently queued in the pool. */ long dbpool_conn_count(DBPool *p); /* * Gets and active connection from the pool and returns it. * The caller can use it then for queuery operations and has to put it * back into the pool via dbpool_conn_produce(conn). * If no connection is in pool and DBPool is not in destroying phase then * will block until connection is available otherwise returns NULL. */ DBPoolConn *dbpool_conn_consume(DBPool *p); /* * Returns a used connection to the pool again. * The connection is returned to it's domestic pool for further extraction * using dbpool_conn_consume(). */ void dbpool_conn_produce(DBPoolConn *conn); int dbpool_conn_select(DBPoolConn *conn, const Octstr *sql, List *binds, List **result); int dbpool_conn_update(DBPoolConn *conn, const Octstr *sql, List *binds); /* * Perfoms a check of all connections within the pool and tries to * re-establish the same ammount of connections if there are broken * connections within the pool. * (This operation can only be performed if the database allows such * operations by its API.) * Returns how many connections within the pool have been checked and * are still considered active. */ unsigned int dbpool_check(DBPool *p); #endif gateway-1.4.5/gwlib/dbpool_p.h0000644000175000017500000001142113227613126014741 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_p.h - Database pool private header. * * Alexander Malysh */ #ifndef DBPOOL_P_H #define DBPOOL_P_H 1 struct db_ops { /* * Open db connection with given config params. * Config params are specificaly for each database type. * return NULL if error occurs ; established connection's pointer otherwise */ void* (*open) (const DBConf *conf); /* * close given connection. */ void (*close) (void *conn); /* * check if given connection still alive, * return -1 if not or error occurs ; 0 if all was fine * NOTE: this function is optional */ int (*check) (void *conn); /* * Destroy specificaly configuration struct. */ void (*conf_destroy) (DBConf *conf); /* * Database specific select. * Note: Result will be stored as follows: * result is the list of rows each row will be stored also as list each column is stored as Octstr. * If someone has better idea please tell me ... * * @params conn - database specific connection; sql - sql statement ; * binds - list of Octstr values for binding holes in sql (NULL if no binds); * result - result will be saved here * @return 0 if all was fine ; -1 otherwise */ int (*select) (void *conn, const Octstr *sql, List *binds, List **result); /* * Database specific update/insert/delete. * @params conn - database specific connection ; sql - sql statement; * binds - list of Octstr values for binding holes in sql (NULL if no binds); * @return #rows processed ; -1 if a error occurs */ int (*update) (void *conn, const Octstr *sql, List *binds); }; struct DBPool { List *pool; /* queue representing the pool */ unsigned int max_size; /* max #connections */ unsigned int curr_size; /* current #connections */ DBConf *conf; /* the database type specific configuration block */ struct db_ops *db_ops; /* the database operations callbacks */ enum db_type db_type; /* the type of database */ }; #endif gateway-1.4.5/gwlib/protected.c0000644000175000017500000002020213227613126015124 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * protected.c - thread-safe versions of standard library functions * * Lars Wirzenius */ #include #include #include "gwlib.h" /* * Undefine the accident protectors. */ #undef localtime #undef gmtime #undef rand #undef gethostbyname #undef mktime #undef strftime enum { RAND, GETHOSTBYNAME, GWTIME, NUM_LOCKS }; static Mutex locks[NUM_LOCKS]; static void lock(int which) { mutex_lock(&locks[which]); } static void unlock(int which) { mutex_unlock(&locks[which]); } void gwlib_protected_init(void) { int i; for (i = 0; i < NUM_LOCKS; ++i) mutex_init_static(&locks[i]); } void gwlib_protected_shutdown(void) { int i; for (i = 0; i < NUM_LOCKS; ++i) mutex_destroy(&locks[i]); } struct tm gw_localtime(time_t t) { struct tm tm; #ifndef HAVE_LOCALTIME_R lock(GWTIME); tm = *localtime(&t); unlock(GWTIME); #else localtime_r(&t, &tm); #endif return tm; } struct tm gw_gmtime(time_t t) { struct tm tm; #ifndef HAVE_GMTIME_R lock(GWTIME); tm = *gmtime(&t); unlock(GWTIME); #else gmtime_r(&t, &tm); #endif return tm; } time_t gw_mktime(struct tm *tm) { time_t t; lock(GWTIME); t = mktime(tm); unlock(GWTIME); return t; } size_t gw_strftime(char *s, size_t max, const char *format, const struct tm *tm) { size_t ret; lock(GWTIME); ret = strftime(s, max, format, tm); unlock(GWTIME); return ret; } int gw_rand(void) { int ret; lock(RAND); ret = rand(); unlock(RAND); return ret; } #if HAVE_FUNC_GETHOSTBYNAME_R_6 /* linux version */ int gw_gethostbyname(struct hostent *ent, const char *name, char **buff) { struct hostent *tmphp, hp; int herr, res; size_t bufflen; tmphp = NULL; /* for compiler please */ bufflen = 1024; *buff = (char*) gw_malloc(bufflen); while ((res=gethostbyname_r(name, &hp,*buff, bufflen, &tmphp, &herr)) == ERANGE) { /* enlarge the buffer */ bufflen *= 2; *buff = (char*) gw_realloc(*buff, bufflen); } if (res != 0 || tmphp == NULL) { error(herr, "Error while gw_gethostbyname occurs."); gw_free(*buff); *buff = NULL; res = -1; } else { *ent = hp; } return res; } #elif HAVE_FUNC_GETHOSTBYNAME_R_5 /* solaris */ int gw_gethostbyname(struct hostent *ent, const char *name, char **buff) { int herr = 0; size_t bufflen = 1024; int res = 0; struct hostent *tmphp = NULL; *buff = gw_malloc(bufflen); while ((tmphp = gethostbyname_r(name, ent, *buff, bufflen, &herr)) == NULL && (errno == ERANGE)) { /* Enlarge the buffer. */ bufflen *= 2; *buff = (char *) gw_realloc(*buff, bufflen); } if (tmphp == NULL) { error(herr, "Error while gw_gethostbyname occurs."); gw_free(*buff); *buff = NULL; res = -1; } return res; } /* not yet implemented, no machine for testing (alex) */ /* #elif HAVE_FUNC_GETHOSTBYNAME_R_3 */ #else /* * Hmm, we don't have a gethostbyname_r(), this is bad... * Here we must perform a "deep-copy" of a hostent struct returned * from gethostbyname. * Note: Bellow code is based on parts from cURL. */ int gw_gethostbyname(struct hostent *ent, const char *name, char **buff) { int len, i; struct hostent *p; /* Allocate enough memory to hold the full name information structs and * everything. OSF1 is known to require at least 8872 bytes. The buffer * required for storing all possible aliases and IP numbers is according to * Stevens' Unix Network Programming 2nd editor, p. 304: 8192 bytes! */ size_t bufflen = 9000; char *bufptr, *str; lock(GETHOSTBYNAME); p = gethostbyname(name); if (p == NULL) { unlock(GETHOSTBYNAME); *buff = NULL; return -1; } *ent = *p; /* alloc mem */ bufptr = *buff = gw_malloc(bufflen); ent->h_name = bufptr; /* copy h_name into buff */ len = strlen(p->h_name) + 1; strncpy(bufptr, p->h_name, len); bufptr += len; /* we align on even 64bit boundaries for safety */ #define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7))) /* This must be aligned properly to work on many CPU architectures! */ bufptr = MEMALIGN(bufptr); ent->h_aliases = (char**)bufptr; /* Figure out how many aliases there are */ for (i = 0; p->h_aliases[i] != NULL; ++i) ; /* Reserve room for the array */ bufptr += (i + 1) * sizeof(char*); /* Clone all known aliases */ for(i = 0; (str = p->h_aliases[i]); i++) { len = strlen(str) + 1; strncpy(bufptr, str, len); ent->h_aliases[i] = bufptr; bufptr += len; } /* Terminate the alias list with a NULL */ ent->h_aliases[i] = NULL; ent->h_addrtype = p->h_addrtype; ent->h_length = p->h_length; /* align it for (at least) 32bit accesses */ bufptr = MEMALIGN(bufptr); ent->h_addr_list = (char**)bufptr; /* Figure out how many addresses there are */ for (i = 0; p->h_addr_list[i] != NULL; ++i) ; /* Reserve room for the array */ bufptr += (i + 1) * sizeof(char*); i = 0; len = p->h_length; str = p->h_addr_list[i]; while (str != NULL) { memcpy(bufptr, str, len); ent->h_addr_list[i] = bufptr; bufptr += len; str = p->h_addr_list[++i]; } ent->h_addr_list[i] = NULL; #undef MEMALIGN unlock(GETHOSTBYNAME); return 0; } #endif gateway-1.4.5/gwlib/gw-timer.h0000644000175000017500000001471413227613126014706 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw-timer.h - interface to timers and timer sets. * * Timers can be set to elapse after a specified number of seconds * (the "interval"). They can be stopped before elapsing, and the * interval can be changed. * * An "output list" is defined for each timer. When it elapses, an * event is generated on this list. The event may be removed from * the output list if the timer is destroyed or extended before the * event is consumed. * * The event to use when a timer elapses is provided by the caller. * The timer module will "own" it, and be responsible for deallocation. * This will be true until the event has been consumed from the output * list (at which point it is owned by the consuming thread). * While the event is on the output list, it is in a gray area, because * the timer module might still take it back. This won't be a problem * as long as you access the event only by consuming it. * * Timers work best if the thread that manipulates the timer (the * "calling thread") is the same thread that consumes the output list. * This way, it can be guaranteed that the calling thread will not * see a timer elapse after being destroyed, or while being extended, * because the elapse event will be deleted during such an operation. * * The timer_* functions have been renamed to gwtimer_* to avoid * a name conflict on Solaris systems. */ #ifndef GW_TIMER_H #define GW_TIMER_H #include "gwlib/gwlib.h" typedef struct Timer Timer; typedef struct Timerset Timerset; Timerset *gw_timerset_create(void); void gw_timerset_destroy(Timerset *set); /* * Create a timer and tell it to use the specified output list or * callback function when it elapses. * Do not start it yet. Return the new timer. */ Timer *gw_timer_create(Timerset *set, List *outputlist, void (*callback) (void*)); /* * Destroy this timer and free its resources. Stop it first, if needed. * * (The _elapsed_ variant assumes that there can't be any further events * within the output list for this timer, which reduces the need to * traverse the output list and delete the corresponding events.) */ void gw_timer_destroy(Timer *timer); void gw_timer_elapsed_destroy(Timer *timer); /* * Make the timer elapse after 'interval' seconds, at which time it * will push event 'event' on the output list defined for its timer set. * - If the timer was already running, these parameters will override * its old settings. * - If the timer has already elapsed, try to remove its event from * the output list. * If this is not the first time the timer was started, the event * pointer is allowed to be NULL. In that case the event pointer * from the previous call to timer_start for this timer is re-used. * NOTE: Each timer must have a unique event pointer. The caller must * create the event, and passes control of it to the timer module with * this call. * * (The _elapsed_ variant assumes that there can't be any further events * within the output list for this timer, which reduces the need to * traverse the output list and delete the corresponding events.) */ void gw_timer_start(Timer *timer, int interval, void *data); void gw_timer_elapsed_start(Timer *timer, int interval, void *data); /* * Stop this timer. If it has already elapsed, try to remove its * event from the output list. * * (The _elapsed_ variant assumes that there can't be any further events * within the output list for this timer, which reduces the need to * traverse the output list and delete the corresponding events.) */ void gw_timer_stop(Timer *timer); void gw_timer_elapsed_stop(Timer *timer); /* * Stop all active timers, elapsed or not, and return them via the * returned List result. They are not destroyed yet. */ List *gw_timer_break(Timerset *set); /* * Return the void* pointer to the associated data of the Timer. */ void *gw_timer_data(Timer *timer); #endif gateway-1.4.5/gwlib/md5.h0000644000175000017500000001033013227613126013626 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * md5.h - MD5 digest algorithm */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ #ifndef MD5_H #define MD5_H /* MD5 context. */ typedef struct { unsigned int state[4]; /* state (ABCD) */ unsigned int count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } md5_ctx; /* * Calculates the MD5 hash value, which is the raw 16 byte * data block. Returns NULL in case NULL has been given as argument. */ Octstr *md5(Octstr *data); /* * Calculates the MD5 digest key of a given Octstr. * Returns NULL in case NULL has been given as argument. */ Octstr *md5digest(Octstr *data); #endif gateway-1.4.5/gwlib/dbpool.c0000644000175000017500000002561313227613126014425 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool.c - implement generic database connection pool * * Stipe Tolj * 2003 Initial version. * Alexander Malysh * 2003 Made dbpool more generic. * Robert Ga³ach * 2004 Added support for binding variables. * Alejandro Guerrieri * 2009 Added support for MS-SQL using FreeTDS */ #include "gwlib.h" #include "dbpool.h" #include "dbpool_p.h" #ifdef HAVE_DBPOOL #include "dbpool_mysql.c" #include "dbpool_oracle.c" #include "dbpool_sqlite.c" #include "dbpool_sqlite3.c" #include "dbpool_sdb.c" #include "dbpool_pgsql.c" #include "dbpool_mssql.c" #include "dbpool_redis.c" #include "dbpool_cass.c" static void dbpool_conn_destroy(DBPoolConn *conn) { gw_assert(conn != NULL); if (conn->conn != NULL) conn->pool->db_ops->close(conn->conn); gw_free(conn); } /************************************************************************* * public functions */ DBPool *dbpool_create(enum db_type db_type, DBConf *conf, unsigned int connections) { DBPool *p; if (conf == NULL) return NULL; p = gw_malloc(sizeof(DBPool)); gw_assert(p != NULL); p->pool = gwlist_create(); gwlist_add_producer(p->pool); p->max_size = connections; p->curr_size = 0; p->conf = conf; p->db_type = db_type; switch(db_type) { #ifdef HAVE_MSSQL case DBPOOL_MSSQL: p->db_ops = &mssql_ops; break; #endif #ifdef HAVE_MYSQL case DBPOOL_MYSQL: p->db_ops = &mysql_ops; break; #endif #ifdef HAVE_ORACLE case DBPOOL_ORACLE: p->db_ops = &oracle_ops; break; #endif #ifdef HAVE_SQLITE case DBPOOL_SQLITE: p->db_ops = &sqlite_ops; break; #endif #ifdef HAVE_SQLITE3 case DBPOOL_SQLITE3: p->db_ops = &sqlite3_ops; break; #endif #ifdef HAVE_SDB case DBPOOL_SDB: p->db_ops = &sdb_ops; break; #endif #ifdef HAVE_PGSQL case DBPOOL_PGSQL: p->db_ops = &pgsql_ops; break; #endif #ifdef HAVE_REDIS case DBPOOL_REDIS: p->db_ops = &redis_ops; break; #endif #ifdef HAVE_CASS case DBPOOL_CASS: p->db_ops = &cass_ops; break; #endif default: panic(0, "Unknown dbpool type defined."); } /* * XXX what is todo here if not all connections * where established ??? */ dbpool_increase(p, connections); return p; } void dbpool_destroy(DBPool *p) { if (p == NULL) return; /* nothing todo here */ gw_assert(p->pool != NULL && p->db_ops != NULL); gwlist_remove_producer(p->pool); gwlist_destroy(p->pool, (void*) dbpool_conn_destroy); p->db_ops->conf_destroy(p->conf); gw_free(p); } unsigned int dbpool_increase(DBPool *p, unsigned int count) { unsigned int i, opened = 0; gw_assert(p != NULL && p->conf != NULL && p->db_ops != NULL && p->db_ops->open != NULL); /* lock dbpool for updates */ gwlist_lock(p->pool); /* ensure we don't increase more items than the max_size border */ for (i=0; i < count && p->curr_size < p->max_size; i++) { void *conn = p->db_ops->open(p->conf); if (conn != NULL) { DBPoolConn *pc = gw_malloc(sizeof(DBPoolConn)); gw_assert(pc != NULL); pc->conn = conn; pc->pool = p; p->curr_size++; opened++; gwlist_produce(p->pool, pc); } } /* unlock dbpool for updates */ gwlist_unlock(p->pool); return opened; } unsigned int dbpool_decrease(DBPool *p, unsigned int c) { unsigned int i; gw_assert(p != NULL && p->pool != NULL && p->db_ops != NULL && p->db_ops->close != NULL); /* lock dbpool for updates */ gwlist_lock(p->pool); /* * Ensure we don't try to decrease more then available in pool. */ for (i = 0; i < c; i++) { DBPoolConn *pc; /* gwlist_extract_first doesn't block even if no conn here */ pc = gwlist_extract_first(p->pool); /* no conn availible anymore */ if (pc == NULL) break; /* close connections and destroy pool connection */ dbpool_conn_destroy(pc); p->curr_size--; } /* unlock dbpool for updates */ gwlist_unlock(p->pool); return i; } long dbpool_conn_count(DBPool *p) { gw_assert(p != NULL && p->pool != NULL); return gwlist_len(p->pool); } DBPoolConn *dbpool_conn_consume(DBPool *p) { DBPoolConn *pc; gw_assert(p != NULL && p->pool != NULL); /* check for max connections and if 0 return NULL */ if (p->max_size < 1) return NULL; /* check if we have any connection */ while (p->curr_size < 1) { debug("dbpool", 0, "DBPool has no connections, reconnecting up to maximum..."); /* dbpool_increase ensure max_size is not exceeded so don't lock */ dbpool_increase(p, p->max_size - p->curr_size); if (p->curr_size < 1) gwthread_sleep(0.1); } /* garantee that you deliver a valid connection to the caller */ while ((pc = gwlist_consume(p->pool)) != NULL) { /* * XXX check that the connection is still existing. * Is this a performance bottle-neck?! */ if (!pc->conn || (p->db_ops->check && p->db_ops->check(pc->conn) != 0)) { /* something was wrong, reinitialize the connection */ /* lock dbpool for update */ gwlist_lock(p->pool); dbpool_conn_destroy(pc); p->curr_size--; /* unlock dbpool for update */ gwlist_unlock(p->pool); /* * maybe not needed, just try to get next connection, but it * can be dangeros if all connections where broken, then we will * block here for ever. */ while (p->curr_size < 1) { debug("dbpool", 0, "DBPool has too few connections, reconnecting up to maximum..."); /* dbpool_increase ensure max_size is not exceeded so don't lock */ dbpool_increase(p, p->max_size - p->curr_size); if (p->curr_size < 1) gwthread_sleep(0.1); } } else { break; } } return (pc->conn != NULL ? pc : NULL); } void dbpool_conn_produce(DBPoolConn *pc) { gw_assert(pc != NULL && pc->conn != NULL && pc->pool != NULL && pc->pool->pool != NULL); gwlist_produce(pc->pool->pool, pc); } unsigned int dbpool_check(DBPool *p) { long i, len, n = 0, reinit = 0; gw_assert(p != NULL && p->pool != NULL && p->db_ops != NULL); /* * First check if db_ops->check function pointer is here. * NOTE: db_ops->check is optional, so if it is not there, then * we have nothing todo and we simple return list length. */ if (p->db_ops->check == NULL) return gwlist_len(p->pool); gwlist_lock(p->pool); len = gwlist_len(p->pool); for (i = 0; i < len; i++) { DBPoolConn *pconn; pconn = gwlist_get(p->pool, i); if (p->db_ops->check(pconn->conn) != 0) { /* something was wrong, reinitialize the connection */ gwlist_delete(p->pool, i, 1); dbpool_conn_destroy(pconn); p->curr_size--; reinit++; len--; i--; } else { n++; } } gwlist_unlock(p->pool); /* reinitialize brocken connections */ if (reinit > 0) n += dbpool_increase(p, reinit); return n; } int dbpool_conn_select(DBPoolConn *conn, const Octstr *sql, List *binds, List **result) { if (sql == NULL || conn == NULL) return -1; if (conn->pool->db_ops->select == NULL) return -1; /* may be panic here ??? */ return conn->pool->db_ops->select(conn->conn, sql, binds, result); } int dbpool_conn_update(DBPoolConn *conn, const Octstr *sql, List *binds) { if (sql == NULL || conn == NULL) return -1; if (conn->pool->db_ops->update == NULL) return -1; /* may be panic here ??? */ return conn->pool->db_ops->update(conn->conn, sql, binds); } #endif /* HAVE_DBPOOL */ gateway-1.4.5/gwlib/regex.h0000644000175000017500000001734613227613126014271 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * regex.h - POSIX regular expressions (REs) * * This modules implements wrapper functions to regcomp(3), regexec(3), * et all functions from the POSIX compliance standard. Additinally * it provides subexpression substitution routines in order to easily * substitute strings arround regular expressions. * * See regex(3) man page for more details on POSIX regular expressions. * * PCRE allows wrapper functions for POSIX regex via an own API. So we * use PCRE in favor, before falling back to POSIX regex. * * Stipe Tolj */ #ifndef REGEX_H #define REGEX_H #ifdef HAVE_PCRE # include #elif HAVE_REGEX # include #endif #if defined(HAVE_REGEX) || defined(HAVE_PCRE) /* * We handle a maximum of 10 subexpression matches and * substitution escape codes $0 to $9 in gw_regex_sub(). */ #define REGEX_MAX_SUB_MATCH 10 /* * Destroy a previously compiled regular expression. */ void gw_regex_destroy(regex_t *preg); /* * Compile a regular expression provided by pattern and return * the regular expression type as function result. * If the compilation fails, return NULL. */ regex_t *gw_regex_comp_real(const Octstr *pattern, int cflags, const char *file, long line, const char *func); #define gw_regex_comp(pattern, cflags) \ gw_regex_comp_real(pattern, cflags, __FILE__, __LINE__, __func__) /* * Execute a previously compile regular expression on a given * string and provide the matches via nmatch and pmatch[]. */ int gw_regex_exec_real(const regex_t *preg, const Octstr *string, size_t nmatch, regmatch_t pmatch[], int eflags, const char *file, long line, const char *func); #define gw_regex_exec(preg, string, nmatch, pmatch, eflags) \ gw_regex_exec_real(preg, string, nmatch, pmatch, eflags, \ __FILE__, __LINE__, __func__) /* * Provide the error description string of an regex operation as * Octstr instead of a char[]. */ Octstr *gw_regex_error(int errcode, const regex_t *preg); /* This function substitutes for $0-$9, filling in regular expression * submatches. Pass it the same nmatch and pmatch arguments that you * passed gw_regexec(). pmatch should not be greater than the maximum number * of subexpressions - i.e. one more than the re_nsub member of regex_t. * * input should be the string with the $-expressions, source should be the * string that was matched against. * * It returns the substituted string, or NULL on error. * * Parts of this code are based on Henry Spencer's regsub(), from his * AT&T V8 regexp package. Function borrowed from apache-1.3/src/main/util.c */ char *gw_regex_sub(const char *input, const char *source, size_t nmatch, regmatch_t pmatch[]); /* * Match directly a given regular expression and a source string. This assumes * that the RE has not been pre-compiled and hence perform the compile and * exec step in this matching step. * Return 1 if the regular expression is successfully matching, 0 otherwise. */ int gw_regex_match_real(const Octstr *re, const Octstr *os, const char *file, long line, const char *func); #define gw_regex_match(re, os) \ gw_regex_match_real(re, os, __FILE__, __LINE__, __func__) /* * Match directly a given source string against a previously pre-compiled * regular expression. * Return 1 if the regular expression is successfully matching, 0 otherwise. */ int gw_regex_match_pre_real(const regex_t *preg, const Octstr *os, const char *file, long line, const char *func); #define gw_regex_match_pre(preg, os) \ gw_regex_match_pre_real(preg, os, __FILE__, __LINE__, __func__) /* * Match directly a given regular expression and a source string. RE has not * been precompiled. Apply substitution rule accoding to Octstr 'rule' and * return the substituted Ocstr as result. Return NULL if failed. * Use \$0 up to \$9 as escape codes for subexpression matchings in the rule. * Ie. os="+4914287756", re="^(00|\+)([0-9]{6,20})$" rule="\$2" would cause * to return "4914287756" because the rule returns only the second regular * expression atom that matched via the expression ([0-9]{6,20}). */ Octstr *gw_regex_subst_real(const Octstr *re, const Octstr *os, const Octstr *rule, const char *file, long line, const char *func); #define gw_regex_subst(re, os, rule) \ gw_regex_subst_real(re, os, rule, __FILE__, __LINE__, __func__) /* * Math directly a given source string against a previously pre-compiled * regular expression. Apply substitution rule according to Ocstr 'rule' and * return the substitued Octstr as result. Same as gw_regex_subst() but a * pre-compiled RE is passed as first argument. */ Octstr *gw_regex_subst_pre_real(const regex_t *preg, const Octstr *os, const Octstr *rule, const char *file, long line, const char *func); #define gw_regex_subst_pre(preg, os, rule) \ gw_regex_subst_pre_real(preg, os, rule, __FILE__, __LINE__, __func__) #endif #endif /* REGEX_H */ gateway-1.4.5/gwlib/gwthread-pthread.c0000644000175000017500000006164713245353052016406 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwthread-pthread.c - implementation of gwthread.h using POSIX threads. * * Richard Braakman */ #include #include #include #include #include #include "gwlib/gwlib.h" #ifdef HAVE_LIBSSL #include #endif /* HAVE_LIBSSL */ /* Maximum number of live threads we can support at once. Increasing * this will increase the size of the threadtable. Use powers of two * for efficiency. */ #define THREADTABLE_SIZE 1024 struct threadinfo { pthread_t self; const char *name; gwthread_func_t *func; long number; int wakefd_recv; int wakefd_send; /* joiners may be NULL. It is not allocated until a thread wants * to register. This is safe because the thread table is always * locked when a thread accesses this field. */ List *joiners; pid_t pid; }; struct new_thread_args { gwthread_func_t *func; void *arg; struct threadinfo *ti; /* signals already started thread to die */ int failed; }; /* The index is the external thread number modulo the table size; the * thread number allocation code makes sure that there are no collisions. */ static struct threadinfo *threadtable[THREADTABLE_SIZE]; #define THREAD(t) (threadtable[(t) % THREADTABLE_SIZE]) /* Number of threads currently in the thread table. */ static long active_threads = 0; /* Number to use for the next thread created. The actual number used * may be higher than this, in order to avoid collisions in the threadtable. * Specifically, (threadnumber % THREADTABLE_SIZE) must be unique for all * live threads. */ static long next_threadnumber; /* Info for the main thread is kept statically, because it should not * be deallocated even after the thread module shuts down -- after all, * the main thread is still running, and in practice, it can still * output debug messages which will require the thread number. */ static struct threadinfo mainthread; /* Our key for accessing the (struct gwthread *) we stash in the * thread-specific-data area. This is much more efficient than * accessing a global table, which we would have to lock. */ static pthread_key_t tsd_key; static pthread_mutex_t threadtable_lock; static void inline lock(void) { int ret; ret = pthread_mutex_lock(&threadtable_lock); if (ret != 0) { panic(ret, "gwthread-pthread: could not lock thread table"); } } static void inline unlock(void) { int ret; ret = pthread_mutex_unlock(&threadtable_lock); if (ret != 0) { panic(ret, "gwthread-pthread: could not unlock thread table"); } } /* Empty the wakeup pipe, in case we got several wakeup signals before * noticing. We want to wake up only once. */ static void flushpipe(int fd) { unsigned char buf[128]; ssize_t bytes; do { bytes = read(fd, buf, sizeof(buf)); } while (bytes > 0); } /* Allocate and fill a threadinfo structure for a new thread, and store * it in a free slot in the thread table. The thread table must already * be locked by the caller. Return the thread number chosen for this * thread. The caller must make sure that there is room in the table. */ static long fill_threadinfo(pthread_t id, const char *name, gwthread_func_t *func, struct threadinfo *ti) { int pipefds[2]; long first_try; gw_assert(active_threads < THREADTABLE_SIZE); /* initialize to default values */ ti->self = id; ti->name = name; ti->func = func; ti->pid = -1; ti->wakefd_recv = -1; ti->wakefd_send = -1; ti->joiners = NULL; ti->number = -1; if (pipe(pipefds) < 0) { error(errno, "cannot allocate wakeup pipe for new thread"); return -1; } ti->wakefd_recv = pipefds[0]; ti->wakefd_send = pipefds[1]; socket_set_blocking(ti->wakefd_recv, 0); socket_set_blocking(ti->wakefd_send, 0); /* Find a free table entry and claim it. */ first_try = next_threadnumber; do { ti->number = next_threadnumber++; /* Check if we looped all the way around the thread table. */ if (ti->number == first_try + THREADTABLE_SIZE) { error(0, "Cannot have more than %d active threads", THREADTABLE_SIZE); ti->number = -1; close(ti->wakefd_recv); ti->wakefd_recv = -1; close(ti->wakefd_send); ti->wakefd_send = -1; return -1; } } while (THREAD(ti->number) != NULL); THREAD(ti->number) = ti; active_threads++; return ti->number; } /* Look up the threadinfo pointer for the current thread */ static struct threadinfo *getthreadinfo(void) { struct threadinfo *threadinfo; threadinfo = pthread_getspecific(tsd_key); if (threadinfo == NULL) { panic(0, "gwthread-pthread: pthread_getspecific failed"); } else { gw_assert(pthread_equal(threadinfo->self, pthread_self())); } return threadinfo; } /* * Go through the list of threads waiting for us to exit, and tell * them that we're exiting. The joiner_cond entries are registered * by those threads, and will be cleaned up by them. */ static void alert_joiners(void) { struct threadinfo *threadinfo; pthread_cond_t *joiner_cond; threadinfo = getthreadinfo(); if (!threadinfo->joiners) return; while ((joiner_cond = gwlist_extract_first(threadinfo->joiners))) { pthread_cond_broadcast(joiner_cond); } } static void delete_threadinfo(void) { struct threadinfo *threadinfo; threadinfo = getthreadinfo(); gwlist_destroy(threadinfo->joiners, NULL); if (threadinfo->wakefd_recv != -1) close(threadinfo->wakefd_recv); if (threadinfo->wakefd_send != -1) close(threadinfo->wakefd_send); if (threadinfo->number != -1) { THREAD(threadinfo->number) = NULL; active_threads--; } gw_assert(threadinfo != &mainthread); gw_free(threadinfo); } void gwthread_init(void) { int ret; int i; pthread_mutex_init(&threadtable_lock, NULL); ret = pthread_key_create(&tsd_key, NULL); if (ret != 0) { panic(ret, "gwthread-pthread: pthread_key_create failed"); } for (i = 0; i < THREADTABLE_SIZE; i++) { threadtable[i] = NULL; } active_threads = 0; /* create main thread info */ if (fill_threadinfo(pthread_self(), "main", NULL, &mainthread) == -1) panic(0, "gwthread-pthread: unable to fill main threadinfo."); ret = pthread_setspecific(tsd_key, &mainthread); if (ret != 0) panic(ret, "gwthread-pthread: pthread_setspecific failed"); } /* Note that the gwthread library can't shut down completely, because * the main thread will still be running, and it may make calls to * gwthread_self(). */ void gwthread_shutdown(void) { int ret; int running; int i; /* Main thread must not have disappeared */ gw_assert(threadtable[0] != NULL); lock(); running = 0; /* Start i at 1 to skip the main thread, which is supposed to be * still running. */ for (i = 1; i < THREADTABLE_SIZE; i++) { if (threadtable[i] != NULL) { debug("gwlib", 0, "Thread %ld (%s) still running", threadtable[i]->number, threadtable[i]->name); running++; } } unlock(); /* We can't do a full cleanup this way */ if (running) return; ret = pthread_mutex_destroy(&threadtable_lock); if (ret != 0) { warning(ret, "cannot destroy threadtable lock"); } /* We can't delete the tsd_key here, because gwthread_self() * still needs it to access the main thread's info. */ } static void new_thread_cleanup(void *arg) { struct new_thread_args *p = arg; lock(); debug("gwlib.gwthread", 0, "Thread %ld (%s) terminates.", p->ti->number, p->ti->name); alert_joiners(); #ifdef HAVE_LIBSSL #if OPENSSL_VERSION_NUMBER < 0x10100000L /* Clear the OpenSSL thread-specific error queue to avoid * memory leaks. */ ERR_remove_state(gwthread_self()); #endif #endif /* HAVE_LIBSSL */ /* Must free p before signaling our exit, otherwise there is * a race with gw_check_leaks at shutdown. */ gw_free(p); delete_threadinfo(); unlock(); } static void *new_thread(void *arg) { int ret; struct new_thread_args *p = arg; /* Make sure we don't start until our parent has entered * our thread info in the thread table. */ lock(); /* check for initialization errors */ if (p->failed) { /* Must free p before signaling our exit, otherwise there is * a race with gw_check_leaks at shutdown. */ gw_free(p->ti); gw_free(p); unlock(); return NULL; } unlock(); /* This has to be done here, because pthread_setspecific cannot * be called by our parent on our behalf. That's why the ti * pointer is passed in the new_thread_args structure. */ /* Synchronization is not a problem, because the only thread * that relies on this call having been made is this one -- * no other thread can access our TSD anyway. */ ret = pthread_setspecific(tsd_key, p->ti); if (ret != 0) { panic(ret, "gwthread-pthread: pthread_setspecific failed"); } p->ti->pid = getpid(); debug("gwlib.gwthread", 0, "Thread %ld (%s) maps to pid %ld.", p->ti->number, p->ti->name, (long) p->ti->pid); /* set cancel cleanup function */ pthread_cleanup_push(new_thread_cleanup, p); (p->func)(p->arg); pthread_cleanup_pop(0); new_thread_cleanup(p); return NULL; } /* * Change this thread's signal mask to block user-visible signals * (HUP, TERM, QUIT, INT), and store the old signal mask in * *old_set_storage. * Return 0 for success, or -1 if an error occurred. */ /* * This does not work in Darwin alias MacOS X alias Mach kernel, * however. So we define a dummy function doing nothing. */ #if defined(DARWIN_OLD) static int pthread_sigmask(); #endif static int block_user_signals(sigset_t *old_set_storage) { int ret; sigset_t block_signals; ret = sigemptyset(&block_signals); if (ret != 0) { error(errno, "gwthread-pthread: Couldn't initialize signal set"); return -1; } ret = sigaddset(&block_signals, SIGHUP); ret |= sigaddset(&block_signals, SIGTERM); ret |= sigaddset(&block_signals, SIGQUIT); ret |= sigaddset(&block_signals, SIGINT); if (ret != 0) { error(0, "gwthread-pthread: Couldn't add signal to signal set"); return -1; } ret = pthread_sigmask(SIG_BLOCK, &block_signals, old_set_storage); if (ret != 0) { error(ret, "gwthread-pthread: Couldn't disable signals for thread creation"); return -1; } return 0; } static void restore_user_signals(sigset_t *old_set) { int ret; ret = pthread_sigmask(SIG_SETMASK, old_set, NULL); if (ret != 0) { panic(ret, "gwthread-pthread: Couldn't restore signal set."); } } static long spawn_thread(gwthread_func_t *func, const char *name, void *arg) { int ret; pthread_t id; struct new_thread_args *p = NULL; long new_thread_id; /* We want to pass both these arguments to our wrapper function * new_thread, but the pthread_create interface will only let * us pass one pointer. So we wrap them in a little struct. */ p = gw_malloc(sizeof(*p)); p->func = func; p->arg = arg; p->ti = gw_malloc(sizeof(*(p->ti))); p->failed = 0; /* Lock the thread table here, so that new_thread can block * on that lock. That way, the new thread won't start until * we have entered it in the thread table. */ lock(); if (active_threads >= THREADTABLE_SIZE) { unlock(); warning(0, "Too many threads, could not create new thread."); gw_free(p->ti); gw_free(p); return -1; } ret = pthread_create(&id, NULL, &new_thread, p); if (ret != 0) { unlock(); error(ret, "Could not create new thread."); gw_free(p->ti); gw_free(p); return -1; } ret = pthread_detach(id); if (ret != 0) { error(ret, "Could not detach new thread."); } new_thread_id = fill_threadinfo(id, name, func, p->ti); if (new_thread_id == -1) p->failed = 1; unlock(); if (new_thread_id != -1) debug("gwlib.gwthread", 0, "Started thread %ld (%s)", new_thread_id, name); else debug("gwlib.gwthread", 0, "Failed to start thread (%s)", name); return new_thread_id; } long gwthread_create_real(gwthread_func_t *func, const char *name, void *arg) { int sigtrick = 0; sigset_t old_signal_set; long thread_id; /* * We want to make sure that only the main thread handles signals, * so that each signal is handled exactly once. To do this, we * make sure that each new thread has all the signals that we * handle blocked. To avoid race conditions, we block them in * the spawning thread first, then create the new thread (which * inherits the settings), and then restore the old settings in * the spawning thread. This means that there is a brief period * when no signals will be processed, but during that time they * should be queued by the operating system. */ if (gwthread_self() == MAIN_THREAD_ID) sigtrick = block_user_signals(&old_signal_set) == 0; thread_id = spawn_thread(func, name, arg); /* * Restore the old signal mask. The new thread will have * inherited the resticted one, but the main thread needs * the old one back. */ if (sigtrick) restore_user_signals(&old_signal_set); return thread_id; } void gwthread_join(long thread) { struct threadinfo *threadinfo; pthread_cond_t exit_cond; int ret; gw_assert(thread >= 0); lock(); threadinfo = THREAD(thread); if (threadinfo == NULL || threadinfo->number != thread) { /* The other thread has already exited */ unlock(); return; } /* Register our desire to be alerted when that thread exits, * and wait for it. */ ret = pthread_cond_init(&exit_cond, NULL); if (ret != 0) { warning(ret, "gwthread_join: cannot create condition variable."); unlock(); return; } if (!threadinfo->joiners) threadinfo->joiners = gwlist_create(); gwlist_append(threadinfo->joiners, &exit_cond); /* The wait immediately releases the lock, and reacquires it * when the condition is satisfied. So don't worry, we're not * blocking while keeping the table locked. */ pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &threadtable_lock); ret = pthread_cond_wait(&exit_cond, &threadtable_lock); pthread_cleanup_pop(0); unlock(); if (ret != 0) warning(ret, "gwthread_join: error in pthread_cond_wait"); pthread_cond_destroy(&exit_cond); } void gwthread_join_all(void) { long i; long our_thread = gwthread_self(); for (i = 0; i < THREADTABLE_SIZE; ++i) { if (THREAD(our_thread) != THREAD(i)) gwthread_join(i); } } void gwthread_wakeup_all(void) { long i; long our_thread = gwthread_self(); for (i = 0; i < THREADTABLE_SIZE; ++i) { if (THREAD(our_thread) != THREAD(i)) gwthread_wakeup(i); } } void gwthread_join_every(gwthread_func_t *func) { struct threadinfo *ti; pthread_cond_t exit_cond; int ret; long i; ret = pthread_cond_init(&exit_cond, NULL); if (ret != 0) { warning(ret, "gwthread_join_every: cannot create condition variable."); unlock(); return; } /* * FIXME: To be really safe, this function should keep looping * over the table until it does a complete run without having * to call pthread_cond_wait. Otherwise, new threads could * start while we wait, and we'll miss them. */ lock(); for (i = 0; i < THREADTABLE_SIZE; ++i) { ti = THREAD(i); if (ti == NULL || ti->func != func) continue; debug("gwlib.gwthread", 0, "Waiting for %ld (%s) to terminate", ti->number, ti->name); if (!ti->joiners) ti->joiners = gwlist_create(); gwlist_append(ti->joiners, &exit_cond); pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, &threadtable_lock); ret = pthread_cond_wait(&exit_cond, &threadtable_lock); pthread_cleanup_pop(0); if (ret != 0) warning(ret, "gwthread_join_all: error in pthread_cond_wait"); } unlock(); pthread_cond_destroy(&exit_cond); } /* Return the thread id of this thread. */ long gwthread_self(void) { struct threadinfo *threadinfo; threadinfo = pthread_getspecific(tsd_key); if (threadinfo) return threadinfo->number; else return -1; } /* Return the thread pid of this thread. */ long gwthread_self_pid(void) { struct threadinfo *threadinfo; threadinfo = pthread_getspecific(tsd_key); if (threadinfo && threadinfo->pid != -1) return (long) threadinfo->pid; else return (long) getpid(); } void gwthread_self_ids(long *tid, long *pid) { struct threadinfo *threadinfo; threadinfo = pthread_getspecific(tsd_key); if (threadinfo) { *tid = threadinfo->number; *pid = (threadinfo->pid != -1) ? threadinfo->pid : getpid(); } else { *tid = -1; *pid = getpid(); } } void gwthread_wakeup(long thread) { unsigned char c = 0; struct threadinfo *threadinfo; int fd; gw_assert(thread >= 0); lock(); threadinfo = THREAD(thread); if (threadinfo == NULL || threadinfo->number != thread) { unlock(); return; } fd = threadinfo->wakefd_send; unlock(); write(fd, &c, 1); } int gwthread_pollfd(int fd, int events, double timeout) { struct pollfd pollfd[2]; struct threadinfo *threadinfo; int milliseconds; int ret; threadinfo = getthreadinfo(); pollfd[0].fd = threadinfo->wakefd_recv; pollfd[0].events = POLLIN; pollfd[0].revents = 0; pollfd[1].fd = fd; pollfd[1].events = events; pollfd[1].revents = 0; milliseconds = timeout * 1000; if (milliseconds < 0) milliseconds = POLL_NOTIMEOUT; ret = poll(pollfd, 2, milliseconds); if (ret < 0) { if (errno != EINTR) error(errno, "gwthread_pollfd: error in poll"); return -1; } if (pollfd[0].revents) flushpipe(pollfd[0].fd); return pollfd[1].revents; } int gwthread_poll(struct pollfd *fds, long numfds, double timeout) { struct pollfd *pollfds; struct threadinfo *threadinfo; int milliseconds; int ret; threadinfo = getthreadinfo(); /* Create a new pollfd array with an extra element for the * thread wakeup fd. */ pollfds = gw_malloc((numfds + 1) * sizeof(*pollfds)); pollfds[0].fd = threadinfo->wakefd_recv; pollfds[0].events = POLLIN; pollfds[0].revents = 0; memcpy(pollfds + 1, fds, numfds * sizeof(*pollfds)); milliseconds = timeout * 1000; if (milliseconds < 0) milliseconds = POLL_NOTIMEOUT; ret = poll(pollfds, numfds + 1, milliseconds); if (ret < 0) { if (errno != EINTR) error(errno, "gwthread_poll: error in poll"); gw_free(pollfds); return -1; } if (pollfds[0].revents) flushpipe(pollfds[0].fd); /* Copy the results back to the caller */ memcpy(fds, pollfds + 1, numfds * sizeof(*pollfds)); gw_free(pollfds); return ret; } void gwthread_sleep(double seconds) { struct pollfd pollfd; struct threadinfo *threadinfo; int milliseconds; int ret; threadinfo = getthreadinfo(); pollfd.fd = threadinfo->wakefd_recv; pollfd.events = POLLIN; milliseconds = seconds * 1000; if (milliseconds < 0) milliseconds = POLL_NOTIMEOUT; ret = poll(&pollfd, 1, milliseconds); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) { warning(errno, "gwthread_sleep: error in poll"); } } if (ret == 1) { flushpipe(pollfd.fd); } } void gwthread_sleep_micro(double dseconds) { fd_set fd_set_recv; struct threadinfo *threadinfo; int fd; int ret; threadinfo = getthreadinfo(); fd = threadinfo->wakefd_recv; FD_ZERO(&fd_set_recv); FD_SET(fd, &fd_set_recv); if (dseconds < 0) { ret = select(fd + 1, &fd_set_recv, NULL, NULL, NULL); } else { struct timeval timeout; timeout.tv_sec = dseconds; timeout.tv_usec = (dseconds - timeout.tv_sec) * 1000000; ret = select(fd + 1, &fd_set_recv, NULL, NULL, &timeout); } if (ret < 0) { if (errno != EINTR && errno != EAGAIN) { warning(errno, "gwthread_sleep_micro: error in select()"); } } if (FD_ISSET(fd, &fd_set_recv)) { flushpipe(fd); } } int gwthread_cancel(long thread) { struct threadinfo *threadinfo; int ret; gw_assert(thread >= 0); lock(); threadinfo = THREAD(thread); if (threadinfo == NULL || threadinfo->number != thread) { ret = -1; } else { ret = pthread_cancel(threadinfo->self); debug("gwlib.gwthread", 0, "Thread %ld (%s) canceled.", threadinfo->number, threadinfo->name); } unlock(); return ret; } #ifndef BROKEN_PTHREADS /* Working pthreads */ int gwthread_shouldhandlesignal(int signal){ return 1; } #else /* Somewhat broken pthreads */ int gwthread_shouldhandlesignal(int signal){ return (gwthread_self() == MAIN_THREAD_ID); } #endif int gwthread_dumpsigmask(void) { sigset_t signal_set; int signum; /* Grab the signal set data from our thread */ if (pthread_sigmask(SIG_BLOCK, NULL, &signal_set) != 0) { warning(0, "gwthread_dumpsigmask: Couldn't get signal mask."); return -1; } /* For each signal normally defined (there are usually only 32), * print a message if we don't block it. */ for (signum = 1; signum <= 32; signum++) { if (!sigismember(&signal_set, signum)) { debug("gwlib", 0, "gwthread_dumpsigmask: Signal Number %d will be caught.", signum); } } return 0; } /* DARWIN alias MacOS X doesnt have pthread_sigmask in its pthreads implementation */ #if defined(DARWIN_OLD) static int pthread_sigmask() { return 0; } #endif gateway-1.4.5/gwlib/dbpool_mssql.c0000644000175000017500000002617213227613126015645 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_mssql.c - implement MS SQL operations for generic database connection pool * * Alejandro Guerrieri * */ #ifdef HAVE_MSSQL #include static int mssql_select(void *theconn, const Octstr *sql, List *binds, List **res); static int mssql_update(void *theconn, const Octstr *sql, List *binds); /* * Macros to set the CT-Lib column format structure */ #define mssql_undef_colfmt(cols) \ for (j = 0; j < cols; j++) { gw_free(data[j].format); } #define mssql_undef_coldata(cols) \ mssql_undef_colfmt(cols); \ for (j = 0; j < cols; j++) { gw_free(data[j].data); } \ gw_free(data); struct mssql_conn { CS_CONTEXT *context; CS_CONNECTION *connection; CS_COMMAND *command; }; static void mssql_checkerr(int err) { switch (err) { case CS_CMD_SUCCEED: case CS_CMD_DONE: case CS_END_RESULTS: break; case CS_CMD_FAIL: error(0, "Command Failed"); break; default: error(0, "Unknown Command Error"); } } static void* mssql_open_conn(const DBConf *db_conf) { Octstr *sql; int ret; MSSQLConf *cfg = db_conf->mssql; struct mssql_conn *conn = gw_malloc(sizeof(struct mssql_conn)); gw_assert(conn != NULL); memset(conn, 0, sizeof(struct mssql_conn)); cs_ctx_alloc(CS_VERSION_100, &conn->context); ct_init(conn->context, CS_VERSION_100); ct_con_alloc(conn->context, &conn->connection); ct_con_props(conn->connection, CS_SET, CS_USERNAME, octstr_get_cstr(cfg->username), CS_NULLTERM, NULL); ct_con_props(conn->connection, CS_SET, CS_PASSWORD, octstr_get_cstr(cfg->password), CS_NULLTERM, NULL); ct_connect(conn->connection, octstr_get_cstr(cfg->server), CS_NULLTERM); ct_cmd_alloc(conn->connection, &conn->command); sql = octstr_format("USE %S", cfg->database); ret = mssql_update(conn, sql, NULL); octstr_destroy(sql); if (ret < 0 ) error(0, "MSSQL: DB selection failed!"); return conn; } void mssql_close_conn(void *theconn) { struct mssql_conn *conn = (struct mssql_conn*) theconn; gw_assert(conn != NULL); ct_cmd_drop(conn->command); ct_close(conn->connection, CS_UNUSED); ct_con_drop(conn->connection); ct_exit(conn->context, CS_UNUSED); cs_ctx_drop(conn->context); } static int mssql_check_conn(void *theconn) { int status; CS_INT *outlen; struct mssql_conn *conn = (struct mssql_conn*) theconn; if (ct_con_props(conn->connection, CS_GET, CS_CON_STATUS, &status, CS_UNUSED, outlen) != CS_SUCCEED) return 1; return (status & CS_CONSTAT_CONNECTED) ? 0:1; } static void mssql_conf_destroy(DBConf *theconf) { MSSQLConf *conf = theconf->mssql; octstr_destroy(conf->username); octstr_destroy(conf->password); octstr_destroy(conf->server); gw_free(conf); gw_free(theconf); } struct data_s { CS_TEXT *data; CS_DATAFMT *format; CS_INT size; CS_SMALLINT ind; }; static int mssql_select(void *theconn, const Octstr *sql, List *binds, List **res) { List *row; int columns; CS_RETCODE ret, res_type; int num_rows, count, i, j; struct data_s *data; struct mssql_conn *conn = (struct mssql_conn*) theconn; int binds_len = (binds ? gwlist_len(binds) : 0); *res = NULL; gw_assert(conn != NULL); ct_command(conn->command, CS_LANG_CMD, octstr_get_cstr(sql), CS_NULLTERM, CS_UNUSED); if ((ret = ct_send(conn->command)) != CS_SUCCEED) { error(0, "Error sending query"); return -1; } *res = gwlist_create(); while((ret = ct_results(conn->command, &res_type)) == CS_SUCCEED) { switch (res_type) { case CS_ROW_RESULT: if (ct_res_info(conn->command, CS_NUMDATA, (CS_INT *)&columns, CS_UNUSED, NULL) != CS_SUCCEED) { error(0, "Error fetching attributes"); return -1; } data = gw_malloc(sizeof(struct data_s)*columns); memset(data, 0, sizeof(struct data_s)*columns); for (i = 0; i < columns; i++) { data[i].format = gw_malloc(sizeof(CS_DATAFMT)); memset(data[i].format, 0, sizeof(CS_DATAFMT)); if (ct_describe(conn->command, i+1, data[i].format) != CS_SUCCEED) { error(0, "Error fetching column description"); mssql_undef_colfmt(i); gw_free(data); return -1; } data[i].format->maxlength++; data[i].data = gw_malloc(data[i].format->maxlength); data[i].format->datatype = CS_CHAR_TYPE; data[i].format->format = CS_FMT_NULLTERM; if (ct_bind(conn->command, i+1, data[i].format, data[i].data, &data[i].size, &data[i].ind) != CS_SUCCEED) { error(0, "Error binding column"); mssql_undef_coldata(i); return -1; } } while(((ret = ct_fetch(conn->command, CS_UNUSED, CS_UNUSED, CS_UNUSED, &count)) == CS_SUCCEED) || (ret == CS_ROW_FAIL)) { if( ret == CS_ROW_FAIL ) { error(0, "Error on row %d in this fetch batch.", count+1); mssql_undef_coldata(columns); gw_free(data); return -1; } row = gwlist_create(); for (i = 0; i < columns; i++) { if (data[i].data == NULL || data[i].ind == -1) { gwlist_insert(row, i, octstr_create("")); } else { gwlist_insert(row, i, octstr_create_from_data((char *)data[i].data, data[i].size)); } } gwlist_append(*res, row); } if( ret != CS_END_DATA ) { error(0, "ct_fetch failed"); mssql_undef_coldata(columns); while ((row = gwlist_extract_first(*res)) != NULL) gwlist_destroy(row, octstr_destroy_item); gwlist_destroy(*res, NULL); *res = NULL; return -1; } mssql_undef_coldata(columns); break; case CS_CMD_SUCCEED: case CS_CMD_DONE: case CS_STATUS_RESULT: break; case CS_CMD_FAIL: error(0, "select failed!"); return -1; break; default: error(0, "ct_result returned unexpected result type: %d", res_type); return -1; break; } } return 0; } /* Run commands from which we expect no results returned */ static int mssql_update(void *theconn, const Octstr *sql, List *binds) { CS_RETCODE status, results_ret; CS_INT result_type; struct mssql_conn *conn = (struct mssql_conn*) theconn; gw_assert(conn != NULL); if (conn->command == NULL) return -1; status = ct_command(conn->command, CS_LANG_CMD, octstr_get_cstr(sql), CS_NULLTERM, CS_UNUSED); if (status != CS_SUCCEED) { error(0, "ct_command() failed\n"); return -1; } status = ct_send(conn->command); if (status != CS_SUCCEED) { error(0, "ct_send() failed\n"); return -1; } while ((results_ret = ct_results(conn->command, &result_type)) == CS_SUCCEED) { switch ((int) result_type) { case CS_CMD_SUCCEED: case CS_CMD_DONE: case CS_STATUS_RESULT: break; default: mssql_checkerr(result_type); return -1; } } mssql_checkerr(results_ret); switch ((int) results_ret) { case CS_END_RESULTS: break; default: mssql_checkerr(result_type); return -1; } return 0; } static struct db_ops mssql_ops = { .open = mssql_open_conn, .close = mssql_close_conn, .check = mssql_check_conn, .conf_destroy = mssql_conf_destroy, .select = mssql_select, .update = mssql_update }; #endif gateway-1.4.5/gwlib/html-entities.def0000644000175000017500000001134113227613126016241 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* Please keep this file sorted alphabetically (according to current * Locale in use) */ ENTITY(198,"AElig") ENTITY(193,"Aacute") ENTITY(194,"Acirc") ENTITY(192,"Agrave") ENTITY(197,"Aring") ENTITY(195,"Atilde") ENTITY(196,"Auml") ENTITY(199,"Ccedil") ENTITY(208,"ETH") ENTITY(201,"Eacute") ENTITY(202,"Ecirc") ENTITY(200,"Egrave") ENTITY(203,"Euml") ENTITY(205,"Iacute") ENTITY(206,"Icirc") ENTITY(204,"Igrave") ENTITY(207,"Iuml") ENTITY(209,"Ntilde") ENTITY(211,"Oacute") ENTITY(212,"Ocirc") ENTITY(210,"Ograve") ENTITY(216,"Oslash") ENTITY(213,"Otilde") ENTITY(214,"Ouml") ENTITY(222,"THORN") ENTITY(218,"Uacute") ENTITY(219,"Ucirc") ENTITY(217,"Ugrave") ENTITY(220,"Uuml") ENTITY(221,"Yacute") ENTITY(225,"aacute") ENTITY(226,"acirc") ENTITY(180,"acute") ENTITY(230,"aelig") ENTITY(224,"agrave") ENTITY(38, "amp") ENTITY(229,"aring") ENTITY(227,"atilde") ENTITY(228,"auml") ENTITY(166,"brvbar") ENTITY(231,"ccedil") ENTITY(184,"cedil") ENTITY(162,"cent") ENTITY(169,"copy") ENTITY(164,"curren") ENTITY(176,"deg") ENTITY(247,"divide") ENTITY(233,"eacute") ENTITY(234,"ecirc") ENTITY(232,"egrave") ENTITY(240,"eth") ENTITY(235,"euml") ENTITY(189,"frac12") ENTITY(188,"frac14") ENTITY(190,"frac34") ENTITY(62, "gt") ENTITY(237,"iacute") ENTITY(238,"icirc") ENTITY(161,"iexcl") ENTITY(236,"igrave") ENTITY(191,"iquest") ENTITY(239,"iuml") ENTITY(171,"laquo") ENTITY(60, "lt") ENTITY(175,"macr") ENTITY(181,"micro") ENTITY(183,"middot") ENTITY(160,"nbsp") ENTITY(172,"not") ENTITY(241,"ntilde") ENTITY(243,"oacute") ENTITY(244,"ocirc") ENTITY(242,"ograve") ENTITY(170,"ordf") ENTITY(186,"ordm") ENTITY(248,"oslash") ENTITY(245,"otilde") ENTITY(246,"ouml") ENTITY(182,"para") ENTITY(177,"plusmn") ENTITY(163,"pound") ENTITY(34, "quot") ENTITY(187,"raquo") ENTITY(174,"reg") ENTITY(167,"sect") ENTITY(173,"shy") ENTITY(185,"sup1") ENTITY(178,"sup2") ENTITY(179,"sup3") ENTITY(223,"szlig") ENTITY(254,"thorn") ENTITY(215,"times") ENTITY(250,"uacute") ENTITY(251,"ucirc") ENTITY(249,"ugrave") ENTITY(168,"uml") ENTITY(252,"uuml") ENTITY(253,"yacute") ENTITY(165,"yen") gateway-1.4.5/gwlib/charset.h0000644000175000017500000001510113227613126014573 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwlib/charset.h - character set conversions * * This header defines some utility functions for converting between * character sets. Approximations are made when necessary, so avoid * needless conversions. * * Currently only GSM and Latin-1 are supported with Kannel specific * functions. This module contains also wrappers for libxml2 character * set conversion functions that work either from or to UTF-8. More * about libxml2's character set support on the header file * or the implementation file encoding.c. Short * version: it has a few basic character set supports built in; for * the rest iconv is used. * * Richard Braakman * Tuomas Luttinen */ #ifndef CHARSET_H #define CHARSET_H #include #include /* * Initialize the charset subsystem. */ void charset_init(void); /* * Shutdown the charset subsystem. */ void charset_shutdown(void); /** * Convert octet string in GSM format to UTF-8. * Every GSM character can be represented with unicode, hence nothing will * be lost. Escaped charaters will be translated into appropriate UTF-8 character. */ void charset_gsm_to_utf8(Octstr *ostr); /** * Convert octet string in UTF-8 format to GSM 03.38. * Because not all UTF-8 charater can be converted to GSM 03.38 non * convertable character replaces with NRP character (see define above). * Special characters will be formed into escape sequences. * Incomplete UTF-8 characters at the end of the string will be skipped. */ void charset_utf8_to_gsm(Octstr *ostr); /* * Convert from GSM default character set to NRC ISO 21 (German) * and vise versa. */ void charset_gsm_to_nrc_iso_21_german(Octstr *ostr); void charset_nrc_iso_21_german_to_gsm(Octstr *ostr); /* Trunctate a string of GSM characters to a maximum length. * Make sure the last remaining character is a whole character, * and not half of an escape sequence. * Return 1 if any characters were removed, otherwise 0. */ int charset_gsm_truncate(Octstr *gsm, long max); /* Convert a string in the GSM default character set (GSM 03.38) * to ISO-8859-1. A series of Greek characters (codes 16, 18-26) * are not representable and are converted to '?' characters. * GSM default is a 7-bit alphabet. Characters with the 8th bit * set are left unchanged. */ void charset_gsm_to_latin1(Octstr *gsm); /* Convert a string in the ISO-8859-1 character set to the GSM * default character set (GSM 03.38). A large number of characters * are not representable. Approximations are made in some cases * (accented characters to their unaccented versions, for example), * and the rest are converted to '?' characters. */ void charset_latin1_to_gsm(Octstr *latin1); /* Convert a string from character set specified by charset_from into * UTF-8 character set. The result is stored in the octet string *to that * is allocated by the function. The function returns the number of bytes * written for success, -1 for general error, -2 for an transcoding error * (the input string wasn't valid string in the character set it was said * to be or there was no converter found for the character set). */ int charset_to_utf8(Octstr *from, Octstr **to, Octstr *charset_from); /* Convert a string from UTF-8 character set into another character set * specified by charset_from. The result is stored in the octet string *to * that is allocated by the function. The function returns the number of * bytes written for success, -1 for general error, -2 for an transcoding * error (the input string wasn't valid string in the character set it * was said to be or there was no converter found for the character set). */ int charset_from_utf8(Octstr *utf8, Octstr **to, Octstr *charset_to); /* use iconv library to convert an Octstr in place, from source character set to * destination character set */ int charset_convert(Octstr* string, char* charset_from, char* charset_to); #endif gateway-1.4.5/gwlib/dbpool_sqlite.c0000644000175000017500000001047613227613126016007 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_sqlite.c - implement SQLite operations for generic database connection pool * * Stipe Tolj */ #ifdef HAVE_SQLITE #include static void *sqlite_open_conn(const DBConf *db_conf) { sqlite *db = NULL; SQLiteConf *conf = db_conf->sqlite; /* make compiler happy */ char *errmsg = 0; /* sanity check */ if (conf == NULL) return NULL; if ((db = sqlite_open(octstr_get_cstr(conf->file), 0, &errmsg)) == NULL) { error(0, "SQLite: can not open database file `%s'!", octstr_get_cstr(conf->file)); error(0, "SQLite: %s", errmsg); goto failed; } if (conf->lock_timeout > 0) { info(0, "SQLite: Setting lock timeout to %ld", conf->lock_timeout); sqlite_busy_timeout(db, conf->lock_timeout); } info(0, "SQLite: Opened database file `%s'.", octstr_get_cstr(conf->file)); info(0, "SQLite: library version %s.", sqlite_version); return db; failed: return NULL; } static void sqlite_close_conn(void *conn) { if (conn == NULL) return; sqlite_close((sqlite*) conn); } static int sqlite_check_conn(void *conn) { if (conn == NULL) return -1; /* XXX there is no such construct in SQLite?! */ return 0; } static void sqlite_conf_destroy(DBConf *db_conf) { SQLiteConf *conf = db_conf->sqlite; octstr_destroy(conf->file); gw_free(conf); gw_free(db_conf); } static struct db_ops sqlite_ops = { .open = sqlite_open_conn, .close = sqlite_close_conn, .check = sqlite_check_conn, .conf_destroy = sqlite_conf_destroy }; #endif /* HAVE_SQLITE */ gateway-1.4.5/gwlib/dbpool_mysql.c0000644000175000017500000003154713227613126015655 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_mysql.c - implement MySQL operations for generic database connection pool * * Stipe Tolj * 2003 Initial version. * Alexander Malysh * 2003 Made dbpool more generic. */ #ifdef HAVE_MYSQL #include #include /* * Handle temporary error codes, that will cause * mysql_stmt_execute() to be retried. * Add more error codes if applicable from mysql's * /mysq/mysqld_errno.h header file */ static inline int mysql_er_temp(const int rc) { switch (rc) { case ER_LOCK_WAIT_TIMEOUT: case ER_LOCK_DEADLOCK: case ER_GET_TEMPORARY_ERRMSG: return 1; break; default: return 0; break; } return 0; } static void *mysql_open_conn(const DBConf *db_conf) { MYSQL *mysql = NULL; MySQLConf *conf = db_conf->mysql; /* make compiler happy */ /* sanity check */ if (conf == NULL) return NULL; /* pre-allocate */ mysql = gw_malloc(sizeof(MYSQL)); gw_assert(mysql != NULL); /* initialize mysql structures */ if (!mysql_init(mysql)) { error(0, "MYSQL: init failed!"); error(0, "MYSQL: %s", mysql_error(mysql)); goto failed; } if (!mysql_real_connect(mysql, octstr_get_cstr(conf->host), octstr_get_cstr(conf->username), octstr_get_cstr(conf->password), octstr_get_cstr(conf->database), conf->port, NULL, 0)) { error(0, "MYSQL: can not connect to database!"); error(0, "MYSQL: %s", mysql_error(mysql)); goto failed; } info(0, "MYSQL: Connected to server at %s.", octstr_get_cstr(conf->host)); info(0, "MYSQL: server version %s, client version %s.", mysql_get_server_info(mysql), mysql_get_client_info()); return mysql; failed: if (mysql != NULL) gw_free(mysql); return NULL; } static void mysql_close_conn(void *conn) { if (conn == NULL) return; mysql_close((MYSQL*) conn); gw_free(conn); } static int mysql_check_conn(void *conn) { if (conn == NULL) return -1; if (mysql_ping((MYSQL*) conn)) { error(0, "MYSQL: database check failed!"); error(0, "MYSQL: %s", mysql_error(conn)); return -1; } return 0; } static int mysql_select(void *conn, const Octstr *sql, List *binds, List **res) { MYSQL_STMT *stmt; MYSQL_RES *result; MYSQL_BIND *bind = NULL; long i, binds_len; int ret; *res = NULL; /* allocate statement handle */ stmt = mysql_stmt_init((MYSQL*) conn); if (stmt == NULL) { error(0, "MYSQL: mysql_stmt_init(), out of memory."); return -1; } if (mysql_stmt_prepare(stmt, octstr_get_cstr(sql), octstr_len(sql))) { error(0, "MYSQL: Unable to prepare statement: %s", mysql_stmt_error(stmt)); mysql_stmt_close(stmt); return -1; } /* bind params if any */ binds_len = gwlist_len(binds); if (binds_len > 0) { bind = gw_malloc(sizeof(MYSQL_BIND) * binds_len); memset(bind, 0, sizeof(MYSQL_BIND) * binds_len); for (i = 0; i < binds_len; i++) { Octstr *str = gwlist_get(binds, i); bind[i].buffer_type = MYSQL_TYPE_STRING; bind[i].buffer = octstr_get_cstr(str); bind[i].buffer_length = octstr_len(str); } /* Bind the buffers */ if (mysql_stmt_bind_param(stmt, bind)) { error(0, "MYSQL: mysql_stmt_bind_param() failed: `%s'", mysql_stmt_error(stmt)); gw_free(bind); mysql_stmt_close(stmt); return -1; } } /* execute statement */ if (mysql_stmt_execute(stmt)) { error(0, "MYSQL: mysql_stmt_execute() failed: `%s'", mysql_stmt_error(stmt)); gw_free(bind); mysql_stmt_close(stmt); return -1; } gw_free(bind); #define DESTROY_BIND(bind, binds_len) \ do { \ long i; \ for (i = 0; i < binds_len; i++) { \ gw_free(bind[i].buffer); \ gw_free(bind[i].length); \ gw_free(bind[i].is_null); \ } \ gw_free(bind); \ } while(0) /* Fetch result set meta information */ result = mysql_stmt_result_metadata(stmt); if (res == NULL) { error(0, "MYSQL: mysql_stmt_result_metadata() failed: `%s'", mysql_stmt_error(stmt)); mysql_stmt_close(stmt); return -1; } /* Get total columns in the query */ binds_len = mysql_num_fields(result); bind = gw_malloc(sizeof(MYSQL_BIND) * binds_len); memset(bind, 0, sizeof(MYSQL_BIND) * binds_len); /* bind result bind */ for (i = 0; i < binds_len; i++) { MYSQL_FIELD *field = mysql_fetch_field(result); /* retrieve field metadata */ debug("gwlib.dbpool_mysql", 0, "column=%s buffer_type=%d max_length=%ld length=%ld", field->name, field->type, field->max_length, field->length); switch(field->type) { case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATE: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: bind[i].buffer_type = field->type; bind[i].buffer = (char*)gw_malloc(sizeof(MYSQL_TIME)); bind[i].is_null = gw_malloc(sizeof(my_bool)); bind[i].length = gw_malloc(sizeof(unsigned long)); break; default: bind[i].buffer_type = MYSQL_TYPE_STRING; bind[i].buffer = gw_malloc(field->length); bind[i].buffer_length = field->length; bind[i].length = gw_malloc(sizeof(unsigned long)); bind[i].is_null = gw_malloc(sizeof(my_bool)); break; } } mysql_free_result(result); if (mysql_stmt_bind_result(stmt, bind)) { error(0, "MYSQL: mysql_stmt_bind_result() failed: `%s'", mysql_stmt_error(stmt)); DESTROY_BIND(bind, binds_len); mysql_stmt_close(stmt); return -1; } *res = gwlist_create(); while(!(ret = mysql_stmt_fetch(stmt))) { List *row = gwlist_create(); for (i = 0; i < binds_len; i++) { Octstr *str = NULL; MYSQL_TIME *ts; if (*bind[i].is_null) { gwlist_produce(row, octstr_create("")); continue; } switch(bind[i].buffer_type) { case MYSQL_TYPE_DATE: ts = bind[i].buffer; str = octstr_format("%04d-%02d-%02d", ts->year, ts->month, ts->day); break; case MYSQL_TYPE_TIME: case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: ts = bind[i].buffer; str = octstr_format("%04d-%02d-%02d %02d:%02d:%02d", ts->year, ts->month, ts->day, ts->hour, ts->minute, ts->second); break; default: if (bind[i].length == 0) str= octstr_create(""); else str = octstr_create_from_data(bind[i].buffer, *bind[i].length); break; } gwlist_produce(row, str); } gwlist_produce(*res, row); } DESTROY_BIND(bind, binds_len); #undef DESTROY_BIND /* any errors by fetch? */ if (ret != MYSQL_NO_DATA) { List *row; error(0, "MYSQL: mysql_stmt_bind_result() failed: `%s'", mysql_stmt_error(stmt)); mysql_stmt_close(stmt); while((row = gwlist_extract_first(*res)) != NULL) gwlist_destroy(row, octstr_destroy_item); gwlist_destroy(*res, NULL); *res = NULL; return -1; } mysql_stmt_close(stmt); return 0; } static int mysql_update(void *conn, const Octstr *sql, List *binds) { MYSQL_STMT *stmt; MYSQL_BIND *bind = NULL; long i, binds_len; int ret; /* allocate statement handle */ stmt = mysql_stmt_init((MYSQL*) conn); if (stmt == NULL) { error(0, "MYSQL: mysql_stmt_init(), out of memory."); return -1; } if (mysql_stmt_prepare(stmt, octstr_get_cstr(sql), octstr_len(sql))) { error(0, "MYSQL: Unable to prepare statement: `%s'", mysql_stmt_error(stmt)); mysql_stmt_close(stmt); return -1; } /* bind params if any */ binds_len = gwlist_len(binds); if (binds_len > 0) { bind = gw_malloc(sizeof(MYSQL_BIND) * binds_len); memset(bind, 0, sizeof(MYSQL_BIND) * binds_len); for (i = 0; i < binds_len; i++) { Octstr *str = gwlist_get(binds, i); bind[i].buffer_type = MYSQL_TYPE_STRING; bind[i].buffer = octstr_get_cstr(str); bind[i].buffer_length = octstr_len(str); } /* Bind the buffers */ if (mysql_stmt_bind_param(stmt, bind)) { error(0, "MYSQL: mysql_stmt_bind_param() failed: `%s'", mysql_stmt_error(stmt)); gw_free(bind); mysql_stmt_close(stmt); return -1; } } /* execute statement */ retry: ret = mysql_stmt_execute(stmt); if (ret != 0) { ret = mysql_stmt_errno(stmt); if (mysql_er_temp(ret)) { warning(0, "MYSQL: mysql_stmt_execute() failed: %d: `%s'. Retrying.", ret, mysql_stmt_error(stmt)); goto retry; } else { error(0, "MYSQL: mysql_stmt_execute() failed: %d: `%s'", ret, mysql_stmt_error(stmt)); gw_free(bind); mysql_stmt_close(stmt); return -1; } } gw_free(bind); ret = mysql_stmt_affected_rows(stmt); mysql_stmt_close(stmt); return ret; } static void mysql_conf_destroy(DBConf *db_conf) { MySQLConf *conf = db_conf->mysql; octstr_destroy(conf->host); octstr_destroy(conf->username); octstr_destroy(conf->password); octstr_destroy(conf->database); gw_free(conf); gw_free(db_conf); } static struct db_ops mysql_ops = { .open = mysql_open_conn, .close = mysql_close_conn, .check = mysql_check_conn, .select = mysql_select, .update = mysql_update, .conf_destroy = mysql_conf_destroy }; #endif /* HAVE_MYSQL */ gateway-1.4.5/gwlib/gw-rwlock.h0000644000175000017500000000653413227613126015070 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw-rwlock.h: Prototypes for Reader/Writer Lock. * * Alexander Malysh , initial version 2004 */ #ifndef GW_RWLOCK_H #define GW_RWLOCK_H #include "gw-config.h" #ifndef HAVE_PTHREAD_RWLOCK #include "list.h" #else #include #endif typedef struct { #ifdef HAVE_PTHREAD_RWLOCK pthread_rwlock_t rwlock; #else List *rwlock; long writer; #endif int dynamic; } RWLock; RWLock *gw_rwlock_create(void); void gw_rwlock_init_static(RWLock *lock); void gw_rwlock_destroy(RWLock *lock); int gw_rwlock_rdlock(RWLock *lock); int gw_rwlock_unlock(RWLock *lock); int gw_rwlock_wrlock(RWLock *lock); #endif gateway-1.4.5/gwlib/gwlib.c0000644000175000017500000000707213227613126014251 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwlib.c - definition of the gwlib_init and gwlib_shutdown functions * * Lars Wirzenius */ #include "gwlib.h" /* * Has gwlib been initialized? */ static int init = 0; void (gwlib_assert_init)(void) { gw_assert(init != 0); } void gwlib_init(void) { gw_assert(!init); gw_init_mem(); uuid_init(); octstr_init(); gwlib_protected_init(); gwthread_init(); log_init(); http_init(); socket_init(); charset_init(); cfg_init(); init = 1; } void gwlib_shutdown(void) { gwlib_assert_init(); charset_shutdown(); http_shutdown(); socket_shutdown(); gwthread_shutdown(); octstr_shutdown(); gwlib_protected_shutdown(); uuid_shutdown(); cfg_shutdown(); gw_check_leaks(); log_shutdown(); gwmem_shutdown(); init = 0; } int gwlib_initialized(void) { return init; } gateway-1.4.5/gwlib/http.h0000644000175000017500000005452413227613126014135 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * http.h - HTTP protocol implementation * * This header file defines the interface to the HTTP implementation * in Kannel. * * We implement both the client and the server side of the protocol. * We don't implement HTTP completely - only those parts that Kannel needs. * You may or may not be able to use this code for other projects. It has * not been a goal, but it might be possible, though you do need other * parts of Kannel's gwlib as well. * * Initialization * ============== * * The library MUST be initialized by a call to http_init. Failure to * initialize means the library WILL NOT work. Note that the library * can't initialize itself implicitly, because it cannot reliably * create a mutex to protect the initialization. Therefore, it is the * caller's responsibility to call http_init exactly once (no more, no * less) at the beginning of the process, before any other thread makes * any calls to the library. * * Client functionality * ==================== * * The library will invisibly keep the connections to HTTP servers open, * so that it is possible to make several HTTP requests over a single * TCP connection. This makes it much more efficient in high-load situations. * On the other hand, if one request takes long, the library will still * use several connections to the same server anyway. * * The library user can specify an HTTP proxy to be used. There can be only * one proxy at a time, but it is possible to specify a list of hosts for * which the proxy is not used. The proxy can be changed at run time. * * Server functionality * ==================== * * The library allows the implementation of an HTTP server by having * functions to specify which ports should be open, and receiving requests * from those ports. * * Header manipulation * =================== * * The library additionally has some functions for manipulating lists of * headers. These take a `List' (see gwlib/list.h) of Octstr's. The list * represents a list of headers in an HTTP request or reply. The functions * manipulate the list by adding and removing headers by name. It is a * very bad idea to manipulate the list without using the header * manipulation functions, however. * * Basic Authentication * ==================== * * Basic Authentication is the standard way for a client to authenticate * itself to a server. It is done by adding an "Authorization" header * to the request. The interface in this header therefore doesn't mention * it, but the client and the server can do it by checking the headers * using the generic functions provided. * * Acknowledgements * ================ * * Design: Lars Wirzenius, Richard Braakman * Implementation: Lars Wirzenius */ #ifndef HTTP_H #define HTTP_H #include "gwlib/list.h" #include "gwlib/octstr.h" /* * Well-known return values from HTTP servers. This is a complete * list as defined by the W3C in RFC 2616, section 10.4.3. */ enum { HTTP_CONTINUE = 100, HTTP_SWITCHING_PROTOCOLS = 101, HTTP_OK = 200, HTTP_CREATED = 201, HTTP_ACCEPTED = 202, HTTP_NON_AUTHORATIVE_INFORMATION = 203, HTTP_NO_CONTENT = 204, HTTP_RESET_CONTENT = 205, HTTP_PARTIAL_CONTENT = 206, HTTP_MULTIPLE_CHOICES = 300, HTTP_MOVED_PERMANENTLY = 301, HTTP_FOUND = 302, HTTP_SEE_OTHER = 303, HTTP_NOT_MODIFIED = 304, HTTP_USE_PROXY = 305, /* HTTP 306 is not used and reserved */ HTTP_TEMPORARY_REDIRECT = 307, HTTP_BAD_REQUEST = 400, HTTP_UNAUTHORIZED = 401, HTTP_PAYMENT_REQUIRED = 402, HTTP_FORBIDDEN = 403, HTTP_NOT_FOUND = 404, HTTP_BAD_METHOD = 405, HTTP_NOT_ACCEPTABLE = 406, HTTP_PROXY_AUTHENTICATION_REQUIRED = 407, HTTP_REQUEST_TIMEOUT = 408, HTTP_CONFLICT = 409, HTTP_GONE = 410, HTTP_LENGTH_REQUIRED = 411, HTTP_PRECONDITION_FAILED = 412, HTTP_REQUEST_ENTITY_TOO_LARGE = 413, HTTP_REQUEST_URI_TOO_LARGE = 414, HTTP_UNSUPPORTED_MEDIA_TYPE = 415, HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416, HTTP_EXPECTATION_FAILED = 417, HTTP_INTERNAL_SERVER_ERROR = 500, HTTP_NOT_IMPLEMENTED = 501, HTTP_BAD_GATEWAY = 502, HTTP_SERVICE_UNAVAILABLE = 503, HTTP_GATEWAY_TIMEOUT = 504, HTTP_HTTP_VERSION_NOT_SUPPORTED = 505 }; /* * Groupings of the status codes listed above. * See the http_status_class() function. */ enum { HTTP_STATUS_PROVISIONAL = 100, HTTP_STATUS_SUCCESSFUL = 200, HTTP_STATUS_REDIRECTION = 300, HTTP_STATUS_CLIENT_ERROR = 400, HTTP_STATUS_SERVER_ERROR = 500, HTTP_STATUS_UNKNOWN = 0 }; /* * Methods supported by this HTTP library. Currently not public but * probably should be. */ enum { HTTP_METHOD_GET = 1, HTTP_METHOD_POST = 2, HTTP_METHOD_HEAD = 3 }; /* * A structure describing a CGI-BIN argument/variable. */ typedef struct { Octstr *name; Octstr *value; } HTTPCGIVar; /* * Initialization function. This MUST be called before any other function * declared in this header file. */ void http_init(void); /* * Shutdown function. This MUST be called when no other function * declared in this header file will be called anymore. */ void http_shutdown(void); /*********************************************************************** * HTTP URL parsing. */ /* * A structure describing a full URL with it's components. */ typedef struct { Octstr *url; Octstr *scheme; Octstr *host; unsigned long port; Octstr *user; Octstr *pass; Octstr *path; Octstr *query; Octstr *fragment; } HTTPURLParse; /* * Create an URL parsing structure. */ HTTPURLParse *http_urlparse_create(void); /* * Destroy an URL parsing structure. */ void http_urlparse_destroy(HTTPURLParse *p); /* * Parse the given URL and return a parsed struct containing all * parsed components. If parsing failed, returns NULL. */ HTTPURLParse *parse_url(Octstr *url); /* * Dump the parsed struct to debug log level. */ void parse_dump(HTTPURLParse *p); /*********************************************************************** * HTTP proxy interface. */ /* * Functions for controlling proxy use. http_use_proxy sets the proxy to * use; if another proxy was already in use, it is closed and forgotten * about as soon as all existing requests via it have been served. * * http_close_proxy closes the current proxy connection, after any * pending requests have been served. */ void http_use_proxy(Octstr *hostname, int port, int ssl, List *exceptions, Octstr *username, Octstr *password, Octstr *exceptions_regex); void http_close_proxy(void); /*********************************************************************** * HTTP client interface. */ /* * Define interface from which all http requestes will be served */ void http_set_interface(const Octstr *our_host); /** * Define timeout in seconds for which HTTP client will wait for * response. Set -1 to disable timeouts. */ void http_set_client_timeout(long timeout); /* * Functions for doing a GET request. The difference is that _real follows * redirections, plain http_get does not. Return value is the status * code of the request as a numeric value, or -1 if a response from the * server was not received. If return value is not -1, reply_headers and * reply_body are set and MUST be destroyed by caller. * * XXX these are going away in the future */ int http_get_real(int method, Octstr *url, List *request_headers, Octstr **final_url, List **reply_headers, Octstr **reply_body); /* * An identification for a caller of HTTP. This is used with * http_start_request, and http_receive_result to route results to the right * callers. * * Implementation note: We use a List as the type so that we can use * that list for communicating the results. This makes it unnecessary * to map the caller identifier to a List internally in the HTTP module. */ typedef List HTTPCaller; /* * Create an HTTP caller identifier. */ HTTPCaller *http_caller_create(void); /* * Destroy an HTTP caller identifier. Those that aren't destroyed * explicitly are destroyed by http_shutdown. */ void http_caller_destroy(HTTPCaller *caller); /* * Signal to a caller (presumably waiting in http_receive_result) that * we're entering shutdown phase. This will make http_receive_result * no longer block if the queue is empty. */ void http_caller_signal_shutdown(HTTPCaller *caller); /* * Start an HTTP request. It will be completed in the background, and * the result will eventually be received by http_receive_result. * http_receive_result will return the id parameter passed to this function, * and the caller can use this to keep track of which request and which * response belong together. If id is NULL, it is changed to a non-null * value (NULL replies from http_receive_result are reserved for cases * when it doesn't return a reply). * * If `body' is NULL, it is a GET request, otherwise as POST request. * If `follow' is true, HTTP redirections are followed, otherwise not. * * 'certkeyfile' defines a filename where openssl looks for a PEM-encoded * certificate and a private key, if openssl is compiled in and an https * URL is used. It can be NULL, in which case none is used and thus there * is no ssl authentication, unless you have set a global one with * use_global_certkey_file() from conn.c. */ void http_start_request(HTTPCaller *caller, int method, Octstr *url, List *headers, Octstr *body, int follow, void *id, Octstr *certkeyfile); /* * Get the result of a GET or a POST request. Returns either the id pointer * (the one passed to http_start request if non-NULL) or NULL if * http_caller_signal_shutdown has been called and there are no queued results. */ void *http_receive_result_real(HTTPCaller *caller, int *status, Octstr **final_url, List **headers, Octstr **body, int blocking); /* old compatibility mode, always blocking */ #define http_receive_result(caller, status, final_url, headers, body) \ http_receive_result_real(caller, status, final_url, headers, body, 1) /*********************************************************************** * HTTP server interface. */ /* * Data structure representing an HTTP client that has connected to * the server we implement. It is used to route responses correctly. */ typedef struct HTTPClient HTTPClient; /** * Define timeout in seconds for which HTTP server will wait for * request. Set -1 to disable timeouts. */ void http_set_server_timeout(int port, long timeout); /* * Open an HTTP server at a given port. Return -1 for errors (invalid * port number, etc), 0 for OK. This will also start a background thread * to listen for connections to that port and read the requests from them. * Second boolean variable indicates if the HTTP server should be started * for SSL-enabled connections. */ int http_open_port(int port, int ssl); /* * Same as above, but bind to a specific interface. */ int http_open_port_if(int port, int ssl, Octstr *interface); /* * Accept a request from a client to the specified open port. Return NULL * if the port is closed, otherwise a pointer to a client descriptor. * Return the IP number (as a string) and other related information about * the request via arguments if function return value is non-NULL. The * caller is responsible for destroying the values returned via arguments, * the caller descriptor is destroyed by http_send_reply. * * The requests are actually read by a background thread handled by the * HTTP implementation, so it is not necessary by the HTTP user to have * many threads to be fast. The HTTP user should use a single thread, * unless requests can block. */ HTTPClient *http_accept_request(int port, Octstr **client_ip, Octstr **url, List **headers, Octstr **body, List **cgivars); /* * Send a reply to a previously accepted request. The caller is responsible * for destroying the headers and body after the call to http_send_reply * finishes. This allows using them in several replies in an efficient way. */ void http_send_reply(HTTPClient *client, int status, List *headers, Octstr *body); /* * Don't send a reply to a previously accepted request, but only close * the connection to the client. This can be used to reject requests from * clients that are not authorized to access us. */ void http_close_client(HTTPClient *client); /* * Close a currently open port and stop corresponding background threads. */ void http_close_port(int port); /* * Close all currently open ports and stop background threads. */ void http_close_all_ports(void); /* * Destroy a list of HTTPCGIVar objects. */ void http_destroy_cgiargs(List *args); /* * Return reference to CGI argument 'name', or NULL if not matching. */ Octstr *http_cgi_variable(List *list, char *name); /* * Return METHOD used by client */ int http_method(HTTPClient *client); /* * Return URL used by client */ Octstr *http_request_url(HTTPClient *client); /*********************************************************************** * HTTP header interface. */ /* * Functions for manipulating a list of headers. You can use a list of * headers returned by one of the functions above, or create an empty * list with http_create_empty_headers. Use http_destroy_headers to * destroy a list of headers (not just the list, but the headers * themselves). You can also use http_parse_header_string to create a list: * it takes a textual representation of headers as an Octstr and returns * the corresponding List. http_generate_header_string goes the other * way. * * Once you have a list of headers, you can use http_header_add and the * other functions to manipulate it. */ List *http_create_empty_headers(void); void http_destroy_headers(List *headers); void http_header_add(List *headers, char *name, char *contents); void http_header_get(List *headers, long i, Octstr **name, Octstr **value); List *http_header_duplicate(List *headers); void http_header_pack(List *headers); void http_append_headers(List *to, List *from); Octstr *http_header_value(List *headers, Octstr *header); /* * Append all headers from new_headers to old_headers. Headers from * new_headers _replace_ the ones in old_headers if they have the same * name. For example, if you have: * old_headers * Accept: text/html * Accept: text/plain * Accept: image/jpeg * Accept-Language: en * new_headers * Accept: text/html * Accept: text/plain * then after the operation, old_headers will have * Accept-Language: en * Accept: text/html * Accept: text/plain */ void http_header_combine(List *old_headers, List *new_headers); /* * Return the length of the quoted-string (a HTTP field element) * starting at position pos in the header. Return -1 if there * is no quoted-string at that position. */ long http_header_quoted_string_len(Octstr *header, long pos); /* * Take the value part of a header that has a format that allows * multiple comma-separated elements, and split it into a list of * those elements. Note that the function may have surprising * results for values of headers that are not in this format. */ List *http_header_split_value(Octstr *value); /* * The same as http_header_split_value, except that it splits * headers containing 'credentials' or 'challenge' lists, which * have a slightly different format. It also normalizes the list * elements, so that parameters are introduced with ';'. */ List *http_header_split_auth_value(Octstr *value); /* * Remove all headers with name 'name' from the list. Return the * number of headers removed. */ long http_header_remove_all(List *headers, char *name); /* * Remove the hop-by-hop headers from a header list. These are the * headers that describe a specific connection, not anything about * the content. RFC2616 section 13.5.1 defines these. */ void http_remove_hop_headers(List *headers); /* * Update the headers to reflect that a transformation has been * applied to the entity body. */ void http_header_mark_transformation(List *headers, Octstr *new_body, Octstr *new_type); /* * Find the first header called `name' in `headers'. Returns its contents * as a new Octet string, which the caller must free. Return NULL for * not found. */ Octstr *http_header_find_first_real(List *headers, char *name, const char *file, long line, const char *func); #define http_header_find_first(headers, name) \ gw_claim_area(http_header_find_first_real((headers), (name), __FILE__, __LINE__, __func__)) List *http_header_find_all(List *headers, char *name); /* * Find the Content-Type header and returns the type and charset. */ void http_header_get_content_type(List *headers, Octstr **type, Octstr **charset); /* * Check if a specific mime-type can be handled by a client. This is * indicated via 'Accept' headers. Returns 1 if the mime-type is acceptable, * otherwise 0. */ int http_type_accepted(List *headers, char *type); /* * Dump the contents of a header list with debug. */ void http_header_dump(List *headers); /* * Ditto with cgi variables. Do not panic, when an empty are found from the * list. */ void http_cgivar_dump(List *cgiargs); /* * As above function except that dump appended to Octstr. */ void http_cgivar_dump_into(List *cgiargs, Octstr *os); /* * Check if the passed charset is in the 'Accept-Charset' header list * alues of the client. Returns 1 if the charset is acceptable, otherwise 0. */ int http_charset_accepted(List *headers, char *charset); /* * Add Basic Authentication headers headers. */ void http_add_basic_auth(List *headers, Octstr *username, Octstr *password); /* * Many HTTP field elements can take parameters in a standardized * form: parameters appear after the main value, each is introduced * by a semicolon (;), and consists of a key=value pair or just * a key, where the key is a token and the value is either a token * or a quoted-string. * The main value itself is a series of tokens, separators, and * quoted-strings. * * This function will take such a field element, and look for the * value of a specific key, which is then returned. If the key * is not found within the header value NULL is returned. * * BEWARE: value is *only* the header value, not the whole header with * field name. * * Example: * * assume to have "Content-Type: application/xml; charset=UTF-8" * * within List *headers * value = http_header_value(headers, octstr_imm("Content-Type")) * val = http_get_header_parameter(value, octstr_imm("charset")); * will return "UTF-8" to lvalue. */ Octstr *http_get_header_parameter(Octstr *value, Octstr *parameter); /* * Return the general class of a status code. For example, all * 2xx codes are HTTP_STATUS_SUCCESSFUL. See the list at the top * of this file. */ int http_status_class(int code); /* * Return the HTTP_METHOD_xxx enum code for a Octstr containing * the HTTP method name. */ int http_name2method(Octstr *method); /* * Return the char containing the HTTP method name. */ char *http_method2name(int method); #endif gateway-1.4.5/gwlib/thread.h0000644000175000017500000001171713227613126014422 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * thread.h - thread manipulation */ #ifndef GW_THREAD_H #define GW_THREAD_H #include "gw-config.h" #if !HAVE_PTHREAD_H #error "You need POSIX.1 threads and header file" #endif #include /* * Wrapper around pthread_mutex_t to avoid problems with recursive calls * to pthread_mutex_trylock on Linux (at least). */ typedef struct { pthread_mutex_t mutex; long owner; int dynamic; #ifdef MUTEX_STATS unsigned char *filename; int lineno; long locks; long collisions; #endif } Mutex; /* * Create a Mutex. */ #ifdef MUTEX_STATS #define mutex_create() gw_claim_area(mutex_create_measured(mutex_create_real(), \ __FILE__, __LINE__)) #else #define mutex_create() gw_claim_area(mutex_create_real()) #endif /* * Create a Mutex. Call these functions via the macro defined above. */ Mutex *mutex_create_measured(Mutex *mutex, char *filename, int lineno); Mutex *mutex_create_real(void); /* * Initialize a statically allocated Mutex. We need those inside gwlib * modules that are in turn used by the mutex wrapper, such as "gwmem" and * "protected". */ #ifdef MUTEX_STATS #define mutex_init_static(mutex) \ mutex_create_measured(mutex_init_static_real(mutex), __FILE__, __LINE__) #else #define mutex_init_static(mutex) \ mutex_init_static_real(mutex) #endif Mutex *mutex_init_static_real(Mutex *mutex); /* * Destroy a Mutex. */ void mutex_destroy(Mutex *mutex); /* lock given mutex. PANIC if fails (non-initialized mutex or other * coding error) */ #define mutex_lock(m) mutex_lock_real(m, __FILE__, __LINE__, __func__) void mutex_lock_real(Mutex *mutex, char *file, int line, const char *func); /* unlock given mutex, PANIC if fails (so do not call for non-locked) */ /* returns 0 if ok 1 if failure for debugging */ #define mutex_unlock(m) mutex_unlock_real(m, __FILE__, __LINE__, __func__) int mutex_unlock_real(Mutex *mutex, char *file, int line, const char *func); /* * Try to lock given mutex, returns -1 if mutex is NULL; 0 if mutex acquired; otherwise * EBUSY. PANIC if mutex was not properly initialized before. */ #define mutex_trylock(m) mutex_trylock_real(m, __FILE__, __LINE__, __func__) int mutex_trylock_real(Mutex *mutex, const char *file, int line, const char *func); #endif gateway-1.4.5/gwlib/mime.c0000644000175000017500000005330713227613126014076 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * mime.c - Implement MIME multipart/related handling * * References: * RFC 2387 (The MIME Multipart/Related Content-type) * RFC 2025 (Multipurpose Internet Mail Extensions [MIME]) * * See gwlib/mime.h for more details on the implementation. * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" #include "gwlib/mime.h" struct MIMEEntity { List *headers; List *multiparts; Octstr *body; struct MIMEEntity *start; /* in case multipart/related */ }; /******************************************************************** * Creation and destruction routines. */ MIMEEntity *mime_entity_create(void) { MIMEEntity *e; e = gw_malloc(sizeof(MIMEEntity)); e->headers = http_create_empty_headers(); e->multiparts = gwlist_create(); e->body = NULL; e->start = NULL; return e; } void static mime_entity_destroy_item(void *e) { mime_entity_destroy(e); } void mime_entity_destroy(MIMEEntity *e) { gw_assert(e != NULL); if (e->headers != NULL) gwlist_destroy(e->headers, octstr_destroy_item); if (e->multiparts != NULL) gwlist_destroy(e->multiparts, mime_entity_destroy_item); octstr_destroy(e->body); e->start = NULL; /* will be destroyed on it's own via gwlist_destroy */ gw_free(e); } /******************************************************************** * Helper routines. Some are derived from gwlib/http.[ch] */ /* * Read some headers, i.e., until the first empty line (read and discard * the empty line as well). Return -1 for error, 0 for all headers read. */ static int read_mime_headers(ParseContext *context, List *headers) { Octstr *line, *prev; if (gwlist_len(headers) == 0) prev = NULL; else prev = gwlist_get(headers, gwlist_len(headers) - 1); for (;;) { line = parse_get_line(context); if (line == NULL) { return -1; } if (octstr_len(line) == 0) { octstr_destroy(line); break; } if (isspace(octstr_get_char(line, 0)) && prev != NULL) { octstr_append(prev, line); octstr_destroy(line); } else { gwlist_append(headers, line); prev = line; } } return 0; } /* This function checks that there is a boundary parameter in the headers * for a multipart MIME object. If not, it is inserted and passed back to caller * in the variable boundary_elem. */ static void fix_boundary_element(List *headers, Octstr **boundary_elem) { Octstr *value, *boundary; long len; /* * Check if we have an boundary parameter already in the * Content-Type header. If no, add one, otherwise parse which one * we should use. * XXX this can be abstracted as function in gwlib/http.[ch]. */ value = http_header_value(headers, octstr_imm("Content-Type")); boundary = value ? http_get_header_parameter(value, octstr_imm("boundary")) : NULL; if (value == NULL) { /* we got here because it is multi-part, so... */ value = octstr_create("multipart/mixed"); http_header_add(headers, "Content-Type", "multipart/mixed"); } if (boundary == NULL) { Octstr *v; boundary = octstr_format("_boundary_%d_%ld_%c_%c_bd%d", random(), (long) time(NULL), 'A' + (random() % 26), 'a' + (random() % 26), random()); octstr_format_append(value, "; boundary=%S", boundary); http_header_remove_all(headers, "Content-Type"); http_header_add(headers, "Content-Type", octstr_get_cstr(value)); if ((v = http_header_value(headers, octstr_imm("MIME-Version"))) == NULL) http_header_add(headers, "MIME-Version", "1.0"); else octstr_destroy(v); } else if ((len = octstr_len(boundary)) > 0 && octstr_get_char(boundary, 0) == '"' && octstr_get_char(boundary, len - 1) == '"') { octstr_delete(boundary, 0, 1); octstr_delete(boundary, len - 2, 1); } octstr_destroy(value); if (boundary_elem) *boundary_elem = boundary; else octstr_destroy(boundary); } /******************************************************************** * Mapping function from other data types, mainly Octstr and HTTP. */ Octstr *mime_entity_to_octstr(MIMEEntity *m) { Octstr *mime, *boundary = NULL; List *headers; long i; gw_assert(m != NULL && m->headers != NULL); mime = octstr_create(""); /* * First of all check if we have further MIME entity dependencies, * which means we have further MIMEEntities in our m->multiparts * list. If no, then add headers and body and return. This is the * easy case. Otherwise we have to loop inside our entities. */ if (gwlist_len(m->multiparts) == 0) { for (i = 0; i < gwlist_len(m->headers); i++) { octstr_append(mime, gwlist_get(m->headers, i)); octstr_append(mime, octstr_imm("\r\n")); } octstr_append(mime, octstr_imm("\r\n")); if (m->body != NULL) octstr_append(mime, m->body); goto finished; } /* This call ensures boundary exists, and returns it */ fix_boundary_element(m->headers, &boundary); headers = http_header_duplicate(m->headers); /* headers */ for (i = 0; i < gwlist_len(headers); i++) { octstr_append(mime, gwlist_get(headers, i)); octstr_append(mime, octstr_imm("\r\n")); } http_destroy_headers(headers); octstr_append(mime, octstr_imm("\r\n")); /* Mark end of headers. */ /* loop through all MIME multipart entities of this entity */ for (i = 0; i < gwlist_len(m->multiparts); i++) { MIMEEntity *e = gwlist_get(m->multiparts, i); Octstr *body; octstr_append(mime, octstr_imm("\r\n--")); octstr_append(mime, boundary); octstr_append(mime, octstr_imm("\r\n")); /* call ourself to produce the MIME entity body */ body = mime_entity_to_octstr(e); octstr_append(mime, body); octstr_destroy(body); } octstr_append(mime, octstr_imm("\r\n--")); octstr_append(mime, boundary); octstr_append(mime, octstr_imm("--\r\n")); octstr_destroy(boundary); finished: return mime; } static Octstr *get_start_param(Octstr *content_type) { Octstr *start; int len; if (!content_type) return NULL; start = http_get_header_parameter(content_type, octstr_imm("start")); if (start && (len = octstr_len(start)) > 0 && octstr_get_char(start, 0) == '"' && octstr_get_char(start, len-1) == '"') { octstr_delete(start, 0, 1); octstr_delete(start, len-2, 1); } return start; } static int cid_matches(List *headers, Octstr *start) { Octstr *cid = http_header_value(headers, octstr_imm("Content-ID")); char *cid_str; int cid_len; int ret; if (cid == NULL) return 0; /* First, strip the <> if any. XXX some mime coders produce such messiness! */ cid_str = octstr_get_cstr(cid); cid_len = octstr_len(cid); if (cid_str[0] == '<') { cid_str+=1; cid_len-=2; } if (start != NULL && cid != NULL && (octstr_compare(start, cid) == 0 || octstr_str_ncompare(start, cid_str, cid_len) == 0)) ret = 1; else ret = 0; octstr_destroy(cid); return ret; } /* * This routine is used for mime_[http|octstr]_to_entity() in order to * reduce code duplication. Basically the only difference is how the headers * are parsed or passed to the resulting MIMEEntity representation. */ static MIMEEntity *mime_something_to_entity(Octstr *mime, List *headers) { MIMEEntity *e; ParseContext *context; Octstr *value, *boundary, *start; int len = 0; gw_assert(mime != NULL); value = boundary = start = NULL; context = parse_context_create(mime); e = mime_entity_create(); /* parse the headers up to the body. If we have headers already passed * from our caller, then duplicate them and continue */ if (headers != NULL) { /* we have some headers to duplicate, first ensure we destroy * the list from the previous creation inside mime_entity_create() */ http_destroy_headers(e->headers); e->headers = http_header_duplicate(headers); } else { /* parse the headers out of the mime block */ if ((read_mime_headers(context, e->headers) != 0) || e->headers == NULL) { debug("mime.parse",0,"Failed to read MIME headers in Octstr block:"); octstr_dump(mime, 0); mime_entity_destroy(e); parse_context_destroy(context); return NULL; } } /* * Now check if the body is a multipart. This is indicated by an 'boundary' * parameter in the 'Content-Type' value. If yes, call ourself for the * multipart entities after parsing them. */ value = http_header_value(e->headers, octstr_imm("Content-Type")); boundary = http_get_header_parameter(value, octstr_imm("boundary")); start = get_start_param(value); /* Beware that we need *unquoted* strings to compare against in the * following parsing sections. */ if (boundary && (len = octstr_len(boundary)) > 0 && octstr_get_char(boundary, 0) == '"' && octstr_get_char(boundary, len-1) == '"') { octstr_delete(boundary, 0, 1); octstr_delete(boundary, len-2, 1); } if (boundary != NULL) { /* we have a multipart block as body, parse the boundary blocks */ Octstr *entity, *seperator, *os; /* loop by all boundary blocks we have in the body */ seperator = octstr_create("--"); octstr_append(seperator, boundary); while ((entity = parse_get_seperated_block(context, seperator)) != NULL) { MIMEEntity *m; int del2 = 0; /* we have still linefeeds at the beginning and end that we * need to remove, these are from the separator. * We check if it is LF only or CRLF! */ del2 = (octstr_get_char(entity, 0) == '\r'); if (del2) octstr_delete(entity, 0, 2); else octstr_delete(entity, 0, 1); /* we assume the same mechanism applies to beginning and end -- * seems reasonable! */ if (del2) octstr_delete(entity, octstr_len(entity) - 2, 2); else octstr_delete(entity, octstr_len(entity) - 1, 1); debug("mime.parse",0,"MIME multipart: Parsing entity:"); octstr_dump(entity, 0); /* call ourself for this MIME entity and inject to list */ if ((m = mime_octstr_to_entity(entity))) { gwlist_append(e->multiparts, m); /* check if this entity is our start entity (in terms of related) * and set our start pointer to it */ if (cid_matches(m->headers, start)) { /* set only if none has been set before */ e->start = (e->start == NULL) ? m : e->start; } } octstr_destroy(entity); } /* ok, we parsed all blocks, we expect to see now the end boundary */ octstr_append_cstr(seperator, "--"); os = parse_get_line(context); if (os != NULL && octstr_compare(os, seperator) != 0) { debug("mime.parse",0,"Failed to see end boundary, parsed line is '%s'.", octstr_get_cstr(os)); } octstr_destroy(seperator); octstr_destroy(os); } else { /* we don't have boundaries, so this is no multipart block, * pass the body to the MIME entity. */ e->body = parse_get_rest(context); } parse_context_destroy(context); octstr_destroy(value); octstr_destroy(boundary); octstr_destroy(start); return e; } MIMEEntity *mime_octstr_to_entity(Octstr *mime) { gw_assert(mime != NULL); return mime_something_to_entity(mime, NULL); } MIMEEntity *mime_http_to_entity(List *headers, Octstr *body) { gw_assert(headers != NULL && body != NULL); return mime_something_to_entity(body, headers); } List *mime_entity_headers(MIMEEntity *m) { List *headers; gw_assert(m != NULL && m->headers != NULL); /* Need a fixup before hand over. */ if (mime_entity_num_parts(m) > 0) fix_boundary_element(m->headers, NULL); headers = http_header_duplicate(m->headers); return headers; } Octstr *mime_entity_body(MIMEEntity *m) { Octstr *os, *body; ParseContext *context; MIMEEntity *e; gw_assert(m != NULL && m->headers != NULL); /* For non-multipart, return body directly. */ if (mime_entity_num_parts(m) == 0) return octstr_duplicate(m->body); os = mime_entity_to_octstr(m); context = parse_context_create(os); e = mime_entity_create(); /* parse the headers up to the body */ if ((read_mime_headers(context, e->headers) != 0) || e->headers == NULL) { debug("mime.parse",0,"Failed to read MIME headers in Octstr block:"); octstr_dump(os, 0); mime_entity_destroy(e); parse_context_destroy(context); return NULL; } /* the rest is the body */ body = parse_get_rest(context); octstr_destroy(os); mime_entity_destroy(e); parse_context_destroy(context); return body; } /* Make a copy of a mime object. recursively. */ MIMEEntity *mime_entity_duplicate(MIMEEntity *e) { MIMEEntity *copy = mime_entity_create(); int i, n; mime_replace_headers(copy, e->headers); copy->body = e->body ? octstr_duplicate(e->body) : NULL; for (i = 0, n = gwlist_len(e->multiparts); i < n; i++) gwlist_append(copy->multiparts, mime_entity_duplicate(gwlist_get(e->multiparts, i))); return copy; } /* Replace top-level MIME headers: Old ones removed completetly */ void mime_replace_headers(MIMEEntity *e, List *headers) { gw_assert(e != NULL); gw_assert(headers != NULL); http_destroy_headers(e->headers); e->headers = http_header_duplicate(headers); e->start = NULL; /* clear it, since header change means it could have changed.*/ } /* Get number of body parts. Returns 0 if this is not * a multipart object. */ int mime_entity_num_parts(MIMEEntity *e) { gw_assert(e != NULL); return e->multiparts ? gwlist_len(e->multiparts) : 0; } /* Append a new part to list of body parts. Copy is made * Note that if it was not multipart, this action makes it so! */ void mime_entity_add_part(MIMEEntity *e, MIMEEntity *part) { gw_assert(e != NULL); gw_assert(part != NULL); gwlist_append(e->multiparts, mime_entity_duplicate(part)); } /* Get part i in list of body parts. Copy is made*/ MIMEEntity *mime_entity_get_part(MIMEEntity *e, int i) { MIMEEntity *m; gw_assert(e != NULL); gw_assert(i >= 0); gw_assert(i < gwlist_len(e->multiparts)); m = gwlist_get(e->multiparts, i); gw_assert(m); return mime_entity_duplicate(m); } /* Remove part i in list of body parts. */ void mime_entity_remove_part(MIMEEntity *e, int i) { MIMEEntity *m; gw_assert(e != NULL); gw_assert(i >= 0); gw_assert(i < gwlist_len(e->multiparts)); m = gwlist_get(e->multiparts, i); gwlist_delete(e->multiparts, i, 1); if (m == e->start) e->start = NULL; mime_entity_destroy(m); } /* Replace part i in list of body parts. Old one will be deleted */ void mime_entity_replace_part(MIMEEntity *e, int i, MIMEEntity *newpart) { MIMEEntity *m; gw_assert(e != NULL); gw_assert(i >= 0); gw_assert(i < gwlist_len(e->multiparts)); m = gwlist_get(e->multiparts, i); gwlist_delete(e->multiparts, i, 1); gwlist_insert(e->multiparts, i, mime_entity_duplicate(newpart)); if (m == e->start) e->start = NULL; mime_entity_destroy(m); } /* Change body element of non-multipart entity. * We don't check that object is multi part. Result is just that * body will be ignored. */ void mime_entity_set_body(MIMEEntity *e, Octstr *body) { gw_assert(e != NULL); gw_assert(body != NULL); if (e->body) octstr_destroy(e->body); e->body = octstr_duplicate(body); } /* Returns (copy of) the 'start' element of a multi-part entity. */ MIMEEntity *mime_multipart_start_elem(MIMEEntity *e) { gw_assert(e != NULL); /* If e->start element is not yet set, set it as follows: * - if content type is not set, then set it to NULL * - if the start element is not set but this is a multipart object, set * it to first multipart element, else set it to null * - if the start element of the content type is set, find a matching object * and set e->start accordingly. * Finally, return a copy of it. */ if (!e->start) { Octstr *ctype = http_header_value(e->headers, octstr_imm("Content-Type")); Octstr *start = get_start_param(ctype); int i; if (!ctype) e->start = NULL; else if (!start) { if (gwlist_len(e->multiparts) > 0) e->start = gwlist_get(e->multiparts, 0); else e->start = NULL; } else for (i = 0; i < gwlist_len(e->multiparts); i++) { MIMEEntity *x = gwlist_get(e->multiparts, i); if (cid_matches(x->headers, start)) { e->start = x; break; } } if (ctype) octstr_destroy(ctype); if (start) octstr_destroy(start); } return (e->start) ? mime_entity_duplicate(e->start) : NULL; } /******************************************************************** * Routines for debugging purposes. */ static void mime_entity_dump_real(MIMEEntity *m, unsigned int level) { long i, items; Octstr *prefix, *type, *charset; unsigned int j; gw_assert(m != NULL && m->headers != NULL); prefix = octstr_create(""); for (j = 0; j < level * 2; j++) octstr_append_cstr(prefix, " "); http_header_get_content_type(m->headers, &type, &charset); debug("mime.dump",0,"%sContent-Type `%s'", octstr_get_cstr(prefix), octstr_get_cstr(type)); if (m->start != NULL) { Octstr *cid = http_header_value(m->start->headers, octstr_imm("Content-ID")); debug("mime.dump",0,"%sRelated to Content-ID <%s> MIMEEntity at address `%p'", octstr_get_cstr(prefix), octstr_get_cstr(cid), m->start); octstr_destroy(cid); } items = gwlist_len(m->multiparts); debug("mime.dump",0,"%sBody contains %ld MIME entities, size %ld", octstr_get_cstr(prefix), items, (items == 0 && m->body) ? octstr_len(m->body) : -1); octstr_destroy(prefix); octstr_destroy(type); octstr_destroy(charset); for (i = 0; i < items; i++) { MIMEEntity *e = gwlist_get(m->multiparts, i); mime_entity_dump_real(e, level + 1); } } void mime_entity_dump(MIMEEntity *m) { gw_assert(m != NULL && m->headers != NULL); debug("mms",0,"Dumping MIMEEntity at address %p", m); mime_entity_dump_real(m, 0); } gateway-1.4.5/gwlib/socket.c0000644000175000017500000004541613227613126014441 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gwlib.h" static Octstr *official_name = NULL; static Octstr *official_ip = NULL; /* * FreeBSD is not happy with our approach of allocating a sockaddr * and then filling in the fields. It has private fields that need * to be initialized to 0. This structure is used for that. */ static const struct sockaddr_in empty_sockaddr_in; #ifndef UDP_PACKET_MAX_SIZE #define UDP_PACKET_MAX_SIZE (64*1024) #endif int make_server_socket(int port, const char *interface_name) { struct sockaddr_in addr; int s; int reuse; struct hostent hostinfo; char *buff = NULL; s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) { error(errno, "socket failed"); goto error; } addr = empty_sockaddr_in; addr.sin_family = AF_INET; addr.sin_port = htons(port); if (interface_name == NULL || strcmp(interface_name, "*") == 0) addr.sin_addr.s_addr = htonl(INADDR_ANY); else { if (gw_gethostbyname(&hostinfo, interface_name, &buff) == -1) { error(errno, "gethostbyname failed"); goto error; } addr.sin_addr = *(struct in_addr *) hostinfo.h_addr; } reuse = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) { error(errno, "setsockopt failed for server address"); goto error; } if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) == -1) { error(errno, "bind failed"); goto error; } if (listen(s, 10) == -1) { error(errno, "listen failed"); goto error; } gw_free(buff); return s; error: if (s >= 0) (void) close(s); gw_free(buff); return -1; } int tcpip_connect_to_server(char *hostname, int port, const char *source_addr) { return tcpip_connect_to_server_with_port(hostname, port, 0, source_addr); } int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr) { struct sockaddr_in addr; struct sockaddr_in o_addr; struct hostent hostinfo; struct hostent o_hostinfo; int s, rc = -1, i; char *buff, *buff1; buff = buff1 = NULL; s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) { error(errno, "Couldn't create new socket."); goto error; } if (gw_gethostbyname(&hostinfo, hostname, &buff) == -1) { error(errno, "gethostbyname failed"); goto error; } if (our_port > 0 || (source_addr != NULL && strcmp(source_addr, "*") != 0)) { int reuse; o_addr = empty_sockaddr_in; o_addr.sin_family = AF_INET; o_addr.sin_port = htons(our_port); if (source_addr == NULL || strcmp(source_addr, "*") == 0) o_addr.sin_addr.s_addr = htonl(INADDR_ANY); else { if (gw_gethostbyname(&o_hostinfo, source_addr, &buff1) == -1) { error(errno, "gethostbyname failed"); goto error; } o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; } reuse = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) { error(errno, "setsockopt failed before bind"); goto error; } if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) { error(errno, "bind to local port %d failed", our_port); goto error; } } i = 0; do { Octstr *ip2; addr = empty_sockaddr_in; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr = *(struct in_addr *) hostinfo.h_addr_list[i]; ip2 = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr); debug("gwlib.socket", 0, "Connecting to <%s>", octstr_get_cstr(ip2)); rc = connect(s, (struct sockaddr *) &addr, sizeof(addr)); if (rc == -1) { error(errno, "connect to <%s> failed", octstr_get_cstr(ip2)); } octstr_destroy(ip2); } while (rc == -1 && hostinfo.h_addr_list[++i] != NULL); if (rc == -1) goto error; gw_free(buff); gw_free(buff1); return s; error: error(0, "error connecting to server `%s' at port `%d'", hostname, port); if (s >= 0) close(s); gw_free(buff); gw_free(buff1); return -1; } int tcpip_connect_nb_to_server(char *hostname, int port, const char *source_addr, int *done) { return tcpip_connect_nb_to_server_with_port(hostname, port, 0, source_addr, done); } int tcpip_connect_nb_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr, int *done) { struct sockaddr_in addr; struct sockaddr_in o_addr; struct hostent hostinfo; struct hostent o_hostinfo; int s, flags, rc = -1, i; char *buff, *buff1; *done = 1; buff = buff1 = NULL; s = socket(PF_INET, SOCK_STREAM, 0); if (s == -1) { error(errno, "Couldn't create new socket."); goto error; } if (gw_gethostbyname(&hostinfo, hostname, &buff) == -1) { error(errno, "gethostbyname failed"); goto error; } if (our_port > 0 || (source_addr != NULL && strcmp(source_addr, "*") != 0)) { int reuse; o_addr = empty_sockaddr_in; o_addr.sin_family = AF_INET; o_addr.sin_port = htons(our_port); if (source_addr == NULL || strcmp(source_addr, "*") == 0) o_addr.sin_addr.s_addr = htonl(INADDR_ANY); else { if (gw_gethostbyname(&o_hostinfo, source_addr, &buff1) == -1) { error(errno, "gethostbyname failed"); goto error; } o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; } reuse = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) == -1) { error(errno, "setsockopt failed before bind"); goto error; } if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) { error(errno, "bind to local port %d failed", our_port); goto error; } } flags = fcntl(s, F_GETFL, 0); fcntl(s, F_SETFL, flags | O_NONBLOCK); i = 0; do { Octstr *ip2; addr = empty_sockaddr_in; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr = *(struct in_addr *) hostinfo.h_addr_list[i]; ip2 = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr); debug("gwlib.socket", 0, "Connecting nonblocking to <%s>", octstr_get_cstr(ip2)); if ((rc = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) { if (errno != EINPROGRESS) { error(errno, "nonblocking connect to <%s> failed", octstr_get_cstr(ip2)); } } octstr_destroy(ip2); } while (rc == -1 && errno != EINPROGRESS && hostinfo.h_addr_list[++i] != NULL); if (rc == -1 && errno != EINPROGRESS) goto error; /* May be connected immediatly * (if we connecting to localhost for example) */ if (rc == 0) { *done = 0; } gw_free(buff); gw_free(buff1); return s; error: error(0, "error connecting to server `%s' at port `%d'", hostname, port); if (s >= 0) close(s); gw_free(buff); gw_free(buff1); return -1; } int write_to_socket(int socket, char *str) { size_t len; int ret; len = strlen(str); while (len > 0) { ret = write(socket, str, len); if (ret == -1) { if (errno == EAGAIN) continue; if (errno == EINTR) continue; error(errno, "Writing to socket failed"); return -1; } /* ret may be less than len, if the writing was interrupted by a signal. */ len -= ret; str += ret; } return 0; } int socket_set_blocking(int fd, int blocking) { int flags, newflags; flags = fcntl(fd, F_GETFL); if (flags < 0) { error(errno, "cannot get flags for fd %d", fd); return -1; } if (blocking) newflags = flags & ~O_NONBLOCK; else newflags = flags | O_NONBLOCK; if (newflags != flags) { if (fcntl(fd, F_SETFL, newflags) < 0) { error(errno, "cannot set flags for fd %d", fd); return -1; } } return 0; } int socket_set_nodelay(int fd, int on) { int rc; rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)); if (rc == -1) error(errno, "Unable set TCP_NODELAY(%d)", on); return rc; } int read_available(int fd, long wait_usec) { fd_set rf; struct timeval to; int ret; div_t waits; gw_assert(fd >= 0); FD_ZERO(&rf); FD_SET(fd, &rf); waits = div(wait_usec, 1000000); to.tv_sec = waits.quot; to.tv_usec = waits.rem; retry: ret = select(fd + 1, &rf, NULL, NULL, &to); if (ret > 0 && FD_ISSET(fd, &rf)) return 1; if (ret < 0) { /* In most select() implementations, to will now contain the * remaining time rather than the original time. That is exactly * what we want when retrying after an interrupt. */ switch (errno) { /*The first two entries here are OK*/ case EINTR: goto retry; case EAGAIN: return 1; /* We are now sucking mud, figure things out here * as much as possible before it gets lost under * layers of abstraction. */ case EBADF: if (!FD_ISSET(fd, &rf)) { warning(0, "Tried to select on fd %d, not in the set!\n", fd); } else { warning(0, "Tried to select on invalid fd %d!\n", fd); } break; case EINVAL: /* Solaris catchall "It didn't work" error, lets apply * some tests and see if we can catch it. */ /* First up, try invalid timeout*/ if (to.tv_sec > 10000000) warning(0, "Wait more than three years for a select?\n"); if (to.tv_usec > 1000000) warning(0, "There are only 1000000 usec in a second...\n"); break; } return -1; /* some error */ } return 0; } int udp_client_socket(void) { int s; s = socket(PF_INET, SOCK_DGRAM, 0); if (s == -1) { error(errno, "Couldn't create a UDP socket"); return -1; } return s; } int udp_bind(int port, const char *source_addr) { int s; struct sockaddr_in sa; struct hostent hostinfo; char *buff = NULL; s = socket(PF_INET, SOCK_DGRAM, 0); if (s == -1) { error(errno, "Couldn't create a UDP socket"); return -1; } sa = empty_sockaddr_in; sa.sin_family = AF_INET; sa.sin_port = htons(port); if (strcmp(source_addr, "*") == 0) sa.sin_addr.s_addr = htonl(INADDR_ANY); else { if (gw_gethostbyname(&hostinfo, source_addr, &buff) == -1) { error(errno, "gethostbyname failed"); gw_free(buff); return -1; } sa.sin_addr = *(struct in_addr *) hostinfo.h_addr; } if (bind(s, (struct sockaddr *) &sa, (int) sizeof(sa)) == -1) { error(errno, "Couldn't bind a UDP socket to port %d", port); (void) close(s); return -1; } gw_free(buff); return s; } Octstr *udp_create_address(Octstr *host_or_ip, int port) { struct sockaddr_in sa; struct hostent h; char *buff = NULL; Octstr *ret; sa = empty_sockaddr_in; sa.sin_family = AF_INET; sa.sin_port = htons(port); if (strcmp(octstr_get_cstr(host_or_ip), "*") == 0) { sa.sin_addr.s_addr = INADDR_ANY; } else { if (gw_gethostbyname(&h, octstr_get_cstr(host_or_ip), &buff) == -1) { error(0, "Couldn't find the IP number of `%s'", octstr_get_cstr(host_or_ip)); gw_free(buff); return NULL; } sa.sin_addr = *(struct in_addr *) h.h_addr; } ret = octstr_create_from_data((char *) &sa, sizeof(sa)); gw_free(buff); return ret; } int udp_get_port(Octstr *addr) { struct sockaddr_in sa; gw_assert(octstr_len(addr) == sizeof(sa)); memcpy(&sa, octstr_get_cstr(addr), sizeof(sa)); return ntohs(sa.sin_port); } Octstr *udp_get_ip(Octstr *addr) { struct sockaddr_in sa; gw_assert(octstr_len(addr) == sizeof(sa)); memcpy(&sa, octstr_get_cstr(addr), sizeof(sa)); return gw_netaddr_to_octstr(AF_INET, &sa.sin_addr); } int udp_sendto(int s, Octstr *datagram, Octstr *addr) { struct sockaddr_in sa; gw_assert(octstr_len(addr) == sizeof(sa)); memcpy(&sa, octstr_get_cstr(addr), sizeof(sa)); if (sendto(s, octstr_get_cstr(datagram), octstr_len(datagram), 0, (struct sockaddr *) &sa, (int) sizeof(sa)) == -1) { error(errno, "Couldn't send UDP packet"); return -1; } return 0; } int udp_recvfrom(int s, Octstr **datagram, Octstr **addr) { return udp_recvfrom_flags(s, datagram, addr, 0); } int udp_recvfrom_flags(int s, Octstr **datagram, Octstr **addr, int sockrcvflags) { struct sockaddr_in sa; socklen_t salen; char *buf; int bytes; buf = gw_malloc(UDP_PACKET_MAX_SIZE); salen = sizeof(sa); bytes = recvfrom(s, buf, UDP_PACKET_MAX_SIZE, sockrcvflags, (struct sockaddr *) &sa, &salen); if (bytes == -1) { if (errno != EAGAIN) error(errno, "Couldn't receive UDP packet"); gw_free(buf); return -1; } *datagram = octstr_create_from_data(buf, bytes); *addr = octstr_create_from_data((char *) &sa, salen); gw_free(buf); return 0; } Octstr *host_ip(struct sockaddr_in addr) { return gw_netaddr_to_octstr(AF_INET, &addr.sin_addr); } int host_port(struct sockaddr_in addr) { return ntohs(addr.sin_port); } Octstr *get_official_name(void) { gw_assert(official_name != NULL); return official_name; } Octstr *get_official_ip(void) { gw_assert(official_ip != NULL); return official_ip; } static void setup_official_name(void) { struct utsname u; struct hostent h; char *buff = NULL; gw_assert(official_name == NULL); if (uname(&u) == -1) panic(0, "uname failed - can't happen, unless " GW_NAME " is buggy."); if (gw_gethostbyname(&h, u.nodename, &buff) == -1) { error(0, "Can't find out official hostname for this host, " "using `%s' instead.", u.nodename); official_name = octstr_create(u.nodename); official_ip = octstr_create("127.0.0.1"); } else { official_name = octstr_create(h.h_name); official_ip = gw_netaddr_to_octstr(AF_INET, h.h_addr); } gw_free(buff); } void socket_init(void) { setup_official_name(); } void socket_shutdown(void) { octstr_destroy(official_name); official_name = NULL; octstr_destroy(official_ip); official_ip = NULL; } Octstr *gw_netaddr_to_octstr(int af, void *src) { switch (af) { case AF_INET: { char straddr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, src, straddr, sizeof(straddr)); return octstr_create(straddr); } #ifdef AF_INET6 case AF_INET6: { char straddr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, src, straddr, sizeof(straddr)); return octstr_create(straddr); } #endif default: return NULL; } } int gw_accept(int fd, Octstr **client_addr) { struct sockaddr_in addr; socklen_t addrlen; int new_fd; if (gwthread_pollfd(fd, POLLIN, -1.0) != POLLIN) { debug("gwlib.socket", 0, "gwthread_pollfd interrupted or failed"); return -1; } addrlen = sizeof(addr); new_fd = accept(fd, (struct sockaddr *) &addr, &addrlen); if (new_fd == -1) { error(errno, "accept system call failed."); return -1; } *client_addr = host_ip(addr); debug("test_smsc", 0, "accept() succeeded, client from %s", octstr_get_cstr(*client_addr)); return new_fd; } gateway-1.4.5/gwlib/semaphore.h0000644000175000017500000000610613227613126015132 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * semaphore.h - declarations of semaphores * * Lars Wirzenius */ #ifndef SEMAPHORE_H #define SEMAPHORE_H typedef struct Semaphore Semaphore; Semaphore *semaphore_create(long n); void semaphore_destroy(Semaphore *semaphore); void semaphore_up(Semaphore *semaphore); void semaphore_down(Semaphore *semaphore); long semaphore_getvalue(Semaphore *semaphore); #endif gateway-1.4.5/gwlib/gwassert.h0000644000175000017500000001001713227613126015002 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwassert.h - assertions macros that report via log files * * Define our own version of assert that calls panic(), because the * normal assert() prints to stdout which no-one will see. * * We also define a gw_assert_place macro so that we can easily use it * data structure consistency checking function and report the place where * the consistency checking function was called. * * Richard Braakman * Lars Wirzenius */ #include "log.h" /* for panic() */ /* The normal assert() does nothing if NDEBUG is defined. We honor both * NDEBUG and our own NO_GWASSERT. If NDEBUG is defined, we always turn * on NO_GWASSERT, so that user code does not have to check for them * separately. */ #if defined(NDEBUG) && !defined(NO_GWASSERT) #define NO_GWASSERT #endif #ifdef NO_GWASSERT #define gw_assert(expr) ((void) 0) #define gw_assert_place(expr, file, lineno, func) ((void) 0) #else #define gw_assert(expr) \ ((void) ((expr) ? 0 : \ (panic(0, "%s:%ld: %s: Assertion `%s' failed.", \ __FILE__, (long) __LINE__, __func__, #expr), 0))) #define gw_assert_place(expr, file, lineno, func) \ ((void) ((expr) ? 0 : \ (panic(0, "%s:%ld: %s: Assertion `%s' failed. " \ "(Called from %s:%ld:%s.)", \ __FILE__, (long) __LINE__, __func__, \ #expr, (file), (long) (lineno), (func)), 0))) #endif gateway-1.4.5/gwlib/octstr.c0000644000175000017500000020415513227613126014464 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * octstr.c - implementation of Octet strings * * See octstr.h for explanations of what public functions should do. * * Lars Wirzenius */ #include #include #include #include #include #include #include #include #include #include "gwlib.h" /* * Unfortunately some platforms base va_list an an array type * which makes passing of the &args a bit tricky */ #if (defined(__linux__) && (defined(__powerpc__) || defined(__s390__) || defined(__x86_64))) || \ (defined(__FreeBSD__) && defined(__amd64__)) || \ (defined(DARWIN) && defined(__x86_64__)) #define VARGS(x) (x) #define VALPARM(y) va_list y #define VALST(z) (z) #else #define VARGS(x) (&x) #define VALPARM(y) va_list *y #define VALST(z) (*z) #endif /*********************************************************************** * Definitions of data structures. These are not visible to the external * world -- they may be accessed only via the functions declared in * octstr.h. This ensures they really are abstract. */ /* * The octet string. * * `data' is a pointer to dynamically allocated memory are where the * octets in the string. It may be bigger than the actual length of the * string. * * `len' is the length of the string. * * `size' is the size of the memory area `data' points at. * * When `size' is greater than zero, it is at least `len+1', and the * character at `len' is '\0'. This is so that octstr_get_cstr will * always work. * * `immutable' defines whether the octet string is immutable or not. */ struct Octstr { unsigned char *data; long len; long size; int immutable; }; /********************************************************************** * Hash table of immutable octet strings. */ #define MAX_IMMUTABLES 1024 static Octstr *immutables[MAX_IMMUTABLES]; static Mutex immutables_mutex; static int immutables_init = 0; static char is_safe[UCHAR_MAX + 1]; /* * Convert a pointer to a C string literal to a long that can be used * for hashing. This is done by converting the pointer into an integer * and discarding the lowest to bits to get rid of typical alignment * bits. */ #define CSTR_TO_LONG(ptr) (((unsigned long) ptr) >> 2) /* * HEX to ASCII preprocessor macro */ #define H2B(a) (a >= '0' && a <= '9' ? \ a - '0' : (a >= 'a' && a <= 'f' ? \ a - 'a' + 10 : (a >= 'A' && a <= 'F' ? a - 'A' + 10 : -1) \ ) \ ) /*********************************************************************** * Declarations of internal functions. These are defined at the end of * the file. */ static void seems_valid_real(const Octstr *ostr, const char *filename, long lineno, const char *function); #ifdef NO_GWASSERT #define seems_valid(ostr) #else #define seems_valid(ostr) \ (seems_valid_real(ostr, __FILE__, __LINE__, __func__)) #endif /*********************************************************************** * Implementations of the functions declared in octstr.h. See the * header for explanations of what they should do. */ /* Reserve space for at least 'size' octets */ static void octstr_grow(Octstr *ostr, long size) { gw_assert(!ostr->immutable); seems_valid(ostr); gw_assert(size >= 0); size++; /* make room for the invisible terminating NUL */ if (size > ostr->size) { /* always reallocate in 1kB chunks */ size += 1024 - (size % 1024); ostr->data = gw_realloc(ostr->data, size); ostr->size = size; } } /* * Fill is_safe table. is_safe[c] means that c can be left as such when * url-encoded. * RFC 2396 defines the list of characters that need to be encoded. * Space is treated as an exception by the encoding routine; * it's listed as safe here, but is actually changed to '+'. */ static void urlcode_init(void) { int i; unsigned char *safe = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz-_.!~*'()"; for (i = 0; safe[i] != '\0'; ++i) is_safe[safe[i]] = 1; } void octstr_init(void) { urlcode_init(); mutex_init_static(&immutables_mutex); immutables_init = 1; } void octstr_shutdown(void) { long i, n; n = 0; for (i = 0; i < MAX_IMMUTABLES; ++i) { if (immutables[i] != NULL) { gw_free(immutables[i]); ++n; } } if(n>0) debug("gwlib.octstr", 0, "Immutable octet strings: %ld.", n); mutex_destroy(&immutables_mutex); } Octstr *octstr_create_real(const char *cstr, const char *file, long line, const char *func) { gw_assert(cstr != NULL); return octstr_create_from_data_trace(cstr, strlen(cstr), file, line, func); } Octstr *octstr_create_from_data_real(const char *data, long len, const char *file, long line, const char *func) { Octstr *ostr; gw_assert(len >= 0); if (data == NULL) gw_assert(len == 0); /* if gw_assert is disabled just return NULL * and caller will check for NULL or just crash. */ if (len < 0 || (data == NULL && len != 0)) return NULL; ostr = gw_malloc_trace(sizeof(*ostr), file, line, func); if (len == 0) { ostr->len = 0; ostr->size = 0; ostr->data = NULL; } else { ostr->len = len; ostr->size = len + 1; ostr->data = gw_malloc_trace(ostr->size, file, line, func); memcpy(ostr->data, data, len); ostr->data[len] = '\0'; } ostr->immutable = 0; seems_valid(ostr); return ostr; } Octstr *octstr_imm(const char *cstr) { Octstr *os; long i, index; unsigned char *data; gw_assert(immutables_init); gw_assert(cstr != NULL); index = CSTR_TO_LONG(cstr) % MAX_IMMUTABLES; data = (unsigned char *) cstr; mutex_lock(&immutables_mutex); i = index; for (; ; ) { if (immutables[i] == NULL || immutables[i]->data == data) break; i = (i + 1) % MAX_IMMUTABLES; if (i == index) panic(0, "Too many immutable strings."); } os = immutables[i]; if (os == NULL) { /* * Can't use octstr_create() because it copies the string, * which would break our hashing. */ os = gw_malloc(sizeof(*os)); os->data = data; os->len = strlen(data); os->size = os->len + 1; os->immutable = 1; immutables[i] = os; seems_valid(os); } mutex_unlock(&immutables_mutex); return os; } void octstr_destroy(Octstr *ostr) { if (ostr != NULL) { seems_valid(ostr); if (!ostr->immutable) { gw_free(ostr->data); gw_free(ostr); } } } void octstr_destroy_item(void *os) { octstr_destroy(os); } long octstr_len(const Octstr *ostr) { if (ostr == NULL) return 0; seems_valid(ostr); return ostr->len; } Octstr *octstr_copy_real(const Octstr *ostr, long from, long len, const char *file, long line, const char *func) { if (ostr == NULL) return octstr_create(""); seems_valid_real(ostr, file, line, func); gw_assert(from >= 0); gw_assert(len >= 0); if (from >= ostr->len) return octstr_create(""); if (len > ostr->len - from) len = ostr->len - from; return octstr_create_from_data_trace(ostr->data + from, len, file, line, func); } Octstr *octstr_duplicate_real(const Octstr *ostr, const char *file, long line, const char *func) { if (ostr == NULL) return NULL; seems_valid_real(ostr, file, line, func); return octstr_create_from_data_trace(ostr->data, ostr->len, file, line, func); } Octstr *octstr_cat(Octstr *ostr1, Octstr *ostr2) { Octstr *ostr; seems_valid(ostr1); seems_valid(ostr2); ostr = octstr_create(""); ostr->len = ostr1->len + ostr2->len; ostr->size = ostr->len + 1; ostr->data = gw_malloc(ostr->size); if (ostr1->len > 0) memcpy(ostr->data, ostr1->data, ostr1->len); if (ostr2->len > 0) memcpy(ostr->data + ostr1->len, ostr2->data, ostr2->len); ostr->data[ostr->len] = '\0'; seems_valid(ostr); return ostr; } int octstr_get_char(const Octstr *ostr, long pos) { seems_valid(ostr); if (pos >= ostr->len || pos < 0) return -1; return ostr->data[pos]; } void octstr_set_char(Octstr *ostr, long pos, int ch) { seems_valid(ostr); gw_assert(!ostr->immutable); if (pos < ostr->len) ostr->data[pos] = ch; seems_valid(ostr); } void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len) { gw_assert(buf != NULL); seems_valid(ostr); if (pos >= ostr->len) return; if (pos + len > ostr->len) len = ostr->len - pos; if (len > 0) memcpy(buf, ostr->data + pos, len); } char *octstr_get_cstr_real(const Octstr *ostr, const char *file, long line, const char *func) { if (!ostr) return "(null)"; seems_valid_real(ostr, file, line, func); if (ostr->len == 0) return ""; return ostr->data; } void octstr_append_from_hex(Octstr *ostr, char *hex) { Octstr *output; seems_valid(ostr); gw_assert(!ostr->immutable); output = octstr_create(hex); octstr_hex_to_binary(output); octstr_append(ostr, output); octstr_destroy(output); } void octstr_binary_to_hex(Octstr *ostr, int uppercase) { unsigned char *hexits; long i, tmp; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return; hexits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef"; octstr_grow(ostr, ostr->len * 2); /* In-place modification must be done back-to-front to avoid * overwriting the data while we read it. Even the order of * the two assignments is important, to get i == 0 right. */ for (i = ostr->len - 1; i >= 0; i--) { tmp = i << 1; /* tmp = i * 2; */ ostr->data[tmp + 1] = hexits[ostr->data[i] & 0xf]; ostr->data[tmp] = hexits[ostr->data[i] >> 4]; } ostr->len = ostr->len * 2; ostr->data[ostr->len] = '\0'; seems_valid(ostr); } int octstr_hex_to_binary(Octstr *ostr) { long len, i; unsigned char *p; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return 0; /* Check if it's in the right format */ if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit)) return -1; len = ostr->len; /* Convert ascii data to binary values */ for (i = 0, p = ostr->data; i < len; i++, p++) { if (*p >= '0' && *p <= '9') *p -= '0'; else if (*p >= 'a' && *p <= 'f') *p = *p - 'a' + 10; else if (*p >= 'A' && *p <= 'F') *p = *p - 'A' + 10; else { /* isxdigit checked the whole string, so we should * not be able to get here. */ gw_assert(0); *p = 0; } } /* De-hexing will compress data by factor of 2 */ len = ostr->len / 2; for (i = 0; i < len; i++) { ostr->data[i] = ostr->data[i * 2] * 16 | ostr->data[i * 2 + 1]; } ostr->len = len; ostr->data[len] = '\0'; seems_valid(ostr); return 0; } void octstr_binary_to_base64(Octstr *ostr) { static const unsigned char base64[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; long triplets; long lines; long orig_len; unsigned char *data; long from, to; int left_on_line; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) { /* Always terminate with CR LF */ octstr_insert(ostr, octstr_imm("\015\012"), 0); return; } /* The lines must be 76 characters each (or less), and each * triplet will expand to 4 characters, so we can fit 19 * triplets on one line. We need a CR LF after each line, * which will add 2 octets per 19 triplets (rounded up). */ triplets = (ostr->len + 2) / 3; /* round up */ lines = (triplets + 18) / 19; octstr_grow(ostr, triplets * 4 + lines * 2); orig_len = ostr->len; data = ostr->data; ostr->len = triplets * 4 + lines * 2; data[ostr->len] = '\0'; /* This function works back-to-front, so that encoded data will * not overwrite source data. * from points to the start of the last triplet (which may be * an odd-sized one), and to points to the start of where the * last quad should go. */ from = (triplets - 1) * 3; to = (triplets - 1) * 4 + (lines - 1) * 2; /* First write the CR LF after the last quad */ data[to + 5] = 10; /* LF */ data[to + 4] = 13; /* CR */ left_on_line = triplets - ((lines - 1) * 19); /* base64 encoding is in 3-octet units. To handle leftover * octets, conceptually we have to zero-pad up to the next * 6-bit unit, and pad with '=' characters for missing 6-bit * units. * We do it by first completing the first triplet with * zero-octets, and after the loop replacing some of the * result characters with '=' characters. * There is enough room for this, because even with a 1 or 2 * octet source string, space for four octets of output * will be reserved. */ switch (orig_len % 3) { case 0: break; case 1: data[orig_len] = 0; data[orig_len + 1] = 0; break; case 2: data[orig_len + 1] = 0; break; } /* Now we only have perfect triplets. */ while (from >= 0) { long whole_triplet; /* Add a newline, if necessary */ if (left_on_line == 0) { to -= 2; data[to + 5] = 10; /* LF */ data[to + 4] = 13; /* CR */ left_on_line = 19; } whole_triplet = (data[from] << 16) | (data[from + 1] << 8) | data[from + 2]; data[to + 3] = base64[whole_triplet % 64]; data[to + 2] = base64[(whole_triplet >> 6) % 64]; data[to + 1] = base64[(whole_triplet >> 12) % 64]; data[to] = base64[(whole_triplet >> 18) % 64]; to -= 4; from -= 3; left_on_line--; } gw_assert(left_on_line == 0); gw_assert(from == -3); gw_assert(to == -4); /* Insert padding characters in the last quad. Remember that * there is a CR LF between the last quad and the end of the * string. */ switch (orig_len % 3) { case 0: break; case 1: gw_assert(data[ostr->len - 3] == 'A'); gw_assert(data[ostr->len - 4] == 'A'); data[ostr->len - 3] = '='; data[ostr->len - 4] = '='; break; case 2: gw_assert(data[ostr->len - 3] == 'A'); data[ostr->len - 3] = '='; break; } seems_valid(ostr); } void octstr_base64_to_binary(Octstr *ostr) { long triplet; long pos, len; long to; int quadpos = 0; int warned = 0; unsigned char *data; seems_valid(ostr); gw_assert(!ostr->immutable); len = ostr->len; data = ostr->data; if (len == 0) return; to = 0; triplet = 0; quadpos = 0; for (pos = 0; pos < len; pos++) { int c = data[pos]; int sixbits; if (c >= 'A' && c <= 'Z') { sixbits = c - 'A'; } else if (c >= 'a' && c <= 'z') { sixbits = 26 + c - 'a'; } else if (c >= '0' && c <= '9') { sixbits = 52 + c - '0'; } else if (c == '+') { sixbits = 62; } else if (c == '/') { sixbits = 63; } else if (c == '=') { /* These can only occur at the end of encoded * text. RFC 2045 says we can assume it really * is the end. */ break; } else if (isspace(c)) { /* skip whitespace */ continue; } else { if (!warned) { warning(0, "Unusual characters in base64 " "encoded text."); warned = 1; } continue; } triplet = (triplet << 6) | sixbits; quadpos++; if (quadpos == 4) { data[to++] = (triplet >> 16) & 0xff; data[to++] = (triplet >> 8) & 0xff; data[to++] = triplet & 0xff; quadpos = 0; } } /* Deal with leftover octets */ switch (quadpos) { case 0: break; case 3: /* triplet has 18 bits, we want the first 16 */ data[to++] = (triplet >> 10) & 0xff; data[to++] = (triplet >> 2) & 0xff; break; case 2: /* triplet has 12 bits, we want the first 8 */ data[to++] = (triplet >> 4) & 0xff; break; case 1: warning(0, "Bad padding in base64 encoded text."); break; } ostr->len = to; data[to] = '\0'; seems_valid(ostr); } long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base) { /* strtol wants a char *, and we have to compare the result to * an unsigned char *. The easiest way to avoid warnings without * introducing typecasts is to use two variables. */ char *endptr; unsigned char *endpos; long number; seems_valid(ostr); gw_assert(nump != NULL); gw_assert(base == 0 || (base >= 2 && base <= 36)); if (pos >= ostr->len) { errno = EINVAL; return -1; } errno = 0; number = strtol(ostr->data + pos, &endptr, base); endpos = endptr; if (errno == ERANGE) return -1; if (endpos == ostr->data + pos) { errno = EINVAL; return -1; } *nump = number; return endpos - ostr->data; } long octstr_parse_double(double *nump, Octstr *ostr, long pos) { /* strtod wants a char *, and we have to compare the result to * an unsigned char *. The easiest way to avoid warnings without * introducing typecasts is to use two variables. */ char *endptr; unsigned char *endpos; double number; seems_valid(ostr); gw_assert(nump != NULL); if (pos >= ostr->len) { errno = EINVAL; return -1; } errno = 0; number = strtod(ostr->data + pos, &endptr); endpos = endptr; if (errno == ERANGE) return -1; if (endpos == ostr->data + pos) { errno = EINVAL; return -1; } *nump = number; return endpos - ostr->data; } int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter) { long end = pos + len; seems_valid(ostr); gw_assert(len >= 0); if (pos >= ostr->len) return 1; if (end > ostr->len) end = ostr->len; for ( ; pos < end; pos++) { if (!filter(ostr->data[pos])) return 0; } return 1; } void octstr_convert_range(Octstr *ostr, long pos, long len, octstr_func_t map) { long end = pos + len; seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(len >= 0); if (pos >= ostr->len) return; if (end > ostr->len) end = ostr->len; for ( ; pos < end; pos++) { ostr->data[pos] = map(ostr->data[pos]); } seems_valid(ostr); } static int inline make_printable(int c) { return isprint(c) ? c : '.'; } void octstr_convert_printable(Octstr *ostr) { octstr_convert_range(ostr, 0, ostr->len, make_printable); } int octstr_compare(const Octstr *ostr1, const Octstr *ostr2) { int ret; long len; seems_valid(ostr1); seems_valid(ostr2); if (ostr1->len < ostr2->len) len = ostr1->len; else len = ostr2->len; if (len == 0) { if (ostr1->len == 0 && ostr2->len > 0) return -1; if (ostr1->len > 0 && ostr2->len == 0) return 1; return 0; } ret = memcmp(ostr1->data, ostr2->data, len); if (ret == 0) { if (ostr1->len < ostr2->len) ret = -1; else if (ostr1->len > ostr2->len) ret = 1; } return ret; } int octstr_case_compare(const Octstr *os1, const Octstr *os2) { int c1, c2; long i, len; seems_valid(os1); seems_valid(os2); if (os1->len < os2->len) len = os1->len; else len = os2->len; if (len == 0) { if (os1->len == 0 && os2->len > 0) return -1; if (os1->len > 0 && os2->len == 0) return 1; return 0; } c1 = c2 = 0; for (i = 0; i < len; ++i) { c1 = toupper(os1->data[i]); c2 = toupper(os2->data[i]); if (c1 != c2) break; } if (i == len) { if (i == os1->len && i == os2->len) return 0; if (i == os1->len) return -1; return 1; } else { /* c1 = toupper(os1->data[i]); c2 = toupper(os2->data[i]); */ if (c1 < c2) return -1; if (c1 == c2) return 0; return 1; } } int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n) { long len; seems_valid(ostr1); seems_valid(ostr2); if ((ostr1->len < ostr2->len) && (ostr1->len < n)) len = ostr1->len; else if ((ostr2->len < ostr1->len) && (ostr2->len < n)) len = ostr2->len; else len = n; if (len == 0) return 0; return memcmp(ostr1->data, ostr2->data, len); } int octstr_str_compare(const Octstr *ostr, const char *str) { seems_valid(ostr); if (str == NULL) return -1; if (ostr->data == NULL) return strcmp("", str); return strcmp(ostr->data, str); } int octstr_str_case_compare(const Octstr *ostr, const char *str) { seems_valid(ostr); if (str == NULL) return -1; if (ostr->data == NULL) return strcasecmp("", str); return strcasecmp(ostr->data, str); } int octstr_str_ncompare(const Octstr *ostr, const char *str, long n) { seems_valid(ostr); if (str == NULL) return -1; if (ostr->data == NULL) return 1; /* str grater */ return strncmp(ostr->data, str, n); } long octstr_search_char(const Octstr *ostr, int ch, long pos) { unsigned char *p; seems_valid(ostr); gw_assert(ch >= 0); gw_assert(ch <= UCHAR_MAX); gw_assert(pos >= 0); if (pos >= ostr->len) return -1; p = memchr(ostr->data + pos, ch, ostr->len - pos); if (!p) return -1; return p - ostr->data; } long octstr_rsearch_char(const Octstr *ostr, int ch, long pos) { long i; seems_valid(ostr); gw_assert(ch >= 0); gw_assert(ch <= UCHAR_MAX); gw_assert(pos >= 0); if (pos >= ostr->len) return -1; for (i = pos; i >= 0; i--) { if (ostr->data[i] == ch) return i; } return -1; } long octstr_search_chars(const Octstr *ostr, const Octstr *chars, long pos) { long i, j; seems_valid(ostr); seems_valid(chars); gw_assert(pos >= 0); for (i = 0; i < octstr_len(chars); i++) { j = octstr_search_char(ostr, octstr_get_char(chars, i), pos); if (j != -1) return j; } return -1; } long octstr_search(const Octstr *haystack, const Octstr *needle, long pos) { int first; seems_valid(haystack); seems_valid(needle); gw_assert(pos >= 0); /* Always "find" an empty string */ if (needle->len == 0) return 0; if (needle->len == 1) return octstr_search_char(haystack, needle->data[0], pos); /* For each occurrence of needle's first character in ostr, * check if the rest of needle follows. Stop if there are no * more occurrences, or if the rest of needle can't possibly * fit in the haystack. */ first = needle->data[0]; pos = octstr_search_char(haystack, first, pos); while (pos >= 0 && haystack->len - pos >= needle->len) { if (memcmp(haystack->data + pos, needle->data, needle->len) == 0) return pos; pos = octstr_search_char(haystack, first, pos + 1); } return -1; } long octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos) { long i, j; int c1, c2; seems_valid(haystack); seems_valid(needle); gw_assert(pos >= 0); /* Always "find" an empty string */ if (needle->len == 0) return 0; for (i = pos; i <= haystack->len - needle->len; ++i) { for (j = 0; j < needle->len; ++j) { c1 = toupper(haystack->data[i + j]); c2 = toupper(needle->data[j]); if (c1 != c2) break; } if (j == needle->len) return i; } return -1; } long octstr_case_nsearch(const Octstr *haystack, const Octstr *needle, long pos, long n) { long i, j; int c1, c2; seems_valid(haystack); seems_valid(needle); gw_assert(pos >= 0); /* Always "find" an empty string */ if (needle->len == 0) return 0; for (i = pos; i <= haystack->len - needle->len && i < n; ++i) { for (j = 0; j < needle->len && j < n; ++j) { c1 = toupper(haystack->data[i + j]); c2 = toupper(needle->data[j]); if (c1 != c2) break; } if (j == needle->len) return i; } return -1; } long octstr_str_search(const Octstr *haystack, const char *needle, long pos) { int first; int needle_len; seems_valid(haystack); gw_assert(pos >= 0); /* Always "find" an empty string */ if (needle == NULL || needle[0] == '\0') return 0; needle_len = strlen(needle); if (needle_len == 1) return octstr_search_char(haystack, needle[0], pos); /* For each occurrence of needle's first character in ostr, * check if the rest of needle follows. Stop if there are no * more occurrences, or if the rest of needle can't possibly * fit in the haystack. */ first = needle[0]; pos = octstr_search_char(haystack, first, pos); while (pos >= 0 && haystack->len - pos >= needle_len) { if (memcmp(haystack->data + pos, needle, needle_len) == 0) return pos; pos = octstr_search_char(haystack, first, pos + 1); } return -1; } int octstr_print(FILE *f, Octstr *ostr) { gw_assert(f != NULL); seems_valid(ostr); if (ostr->len == 0) return 0; if (fwrite(ostr->data, ostr->len, 1, f) != 1) { error(errno, "Couldn't write all of octet string to file."); return -1; } return 0; } int octstr_pretty_print(FILE *f, Octstr *ostr) { unsigned char *p; long i; gw_assert(f != NULL); seems_valid(ostr); p = ostr->data; for (i = 0; i < ostr->len; ++i, ++p) { if (isprint(*p)) fprintf(f, "%c", *p); else fprintf(f, "\\x%02x", *p); } if (ferror(f)) return -1; return 0; } int octstr_write_to_socket(int socket, Octstr *ostr) { long len; unsigned char *data; int ret; gw_assert(socket >= 0); seems_valid(ostr); data = ostr->data; len = ostr->len; while (len > 0) { ret = write(socket, data, len); if (ret == -1) { if (errno != EINTR) { error(errno, "Writing to socket failed"); return -1; } } else { /* ret may be less than len */ len -= ret; data += ret; } } return 0; } long octstr_write_data(Octstr *ostr, int fd, long from) { long ret; gw_assert(fd >= 0); gw_assert(from >= 0); seems_valid(ostr); if (from >= ostr->len) return 0; ret = write(fd, ostr->data + from, ostr->len - from); if (ret < 0) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) return 0; error(errno, "Error writing %ld octets to fd %d:", ostr->len - from, fd); return -1; } return ret; } int octstr_append_from_socket(Octstr *ostr, int socket) { unsigned char buf[4096]; int len; seems_valid(ostr); gw_assert(!ostr->immutable); again: len = recv(socket, buf, sizeof(buf), 0); if (len < 0 && errno == EINTR) goto again; if (len < 0) { error(errno, "Could not read from socket %d", socket); return -1; } octstr_append_data(ostr, buf, len); return len; } void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos) { if (ostr2 == NULL) return; seems_valid(ostr1); seems_valid(ostr2); gw_assert(pos <= ostr1->len); gw_assert(!ostr1->immutable); if (ostr2->len == 0) return; octstr_grow(ostr1, ostr1->len + ostr2->len); memmove(ostr1->data + pos + ostr2->len, ostr1->data + pos, ostr1->len - pos); memcpy(ostr1->data + pos, ostr2->data, ostr2->len); ostr1->len += ostr2->len; ostr1->data[ostr1->len] = '\0'; seems_valid(ostr1); } void octstr_truncate(Octstr *ostr, int new_len) { if (ostr == NULL) return; seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(new_len >= 0); if (new_len >= ostr->len) return; ostr->len = new_len; ostr->data[new_len] = '\0'; seems_valid(ostr); } void octstr_strip_blanks(Octstr *text) { int start = 0, end, len = 0; seems_valid(text); gw_assert(!text->immutable); /* Remove white space from the beginning of the text */ while (isspace(octstr_get_char(text, start)) && start <= octstr_len(text)) start ++; if (start > 0) octstr_delete(text, 0, start); /* and from the end. */ if ((len = octstr_len(text)) > 0) { end = len = len - 1; while (isspace(octstr_get_char(text, end)) && end >= 0) end--; octstr_delete(text, end + 1, len - end); } seems_valid(text); } static int iscrlf(unsigned char c) { return c == '\n' || c == '\r'; } void octstr_strip_crlfs(Octstr *text) { int start = 0, end, len = 0; seems_valid(text); gw_assert(!text->immutable); /* Remove white space from the beginning of the text */ while (iscrlf(octstr_get_char(text, start)) && start <= octstr_len(text)) start ++; if (start > 0) octstr_delete(text, 0, start); /* and from the end. */ if ((len = octstr_len(text)) > 0) { end = len = len - 1; while (iscrlf(octstr_get_char(text, end)) && end >= 0) end--; octstr_delete(text, end + 1, len - end); } seems_valid(text); } void octstr_strip_nonalphanums(Octstr *text) { int start = 0, end, len = 0; seems_valid(text); gw_assert(!text->immutable); /* Remove white space from the beginning of the text */ while (!isalnum(octstr_get_char(text, start)) && start <= octstr_len(text)) start ++; if (start > 0) octstr_delete(text, 0, start); /* and from the end. */ if ((len = octstr_len(text)) > 0) { end = len = len - 1; while (!isalnum(octstr_get_char(text, end)) && end >= 0) end--; octstr_delete(text, end + 1, len - end); } seems_valid(text); } void octstr_shrink_blanks(Octstr *text) { int i, j, end; seems_valid(text); gw_assert(!text->immutable); end = octstr_len(text); /* Shrink white spaces to one */ for (i = 0; i < end; i++) { if (isspace(octstr_get_char(text, i))) { /* Change the remaining space into single space. */ if (octstr_get_char(text, i) != ' ') octstr_set_char(text, i, ' '); j = i = i + 1; while (isspace(octstr_get_char(text, j))) j ++; if (j - i > 1) octstr_delete(text, i, j - i); } } seems_valid(text); } void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len) { seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(pos <= ostr->len); if (len == 0) return; octstr_grow(ostr, ostr->len + len); if (ostr->len > pos) { /* only if neccessary*/ memmove(ostr->data + pos + len, ostr->data + pos, ostr->len - pos); } memcpy(ostr->data + pos, data, len); ostr->len += len; ostr->data[ostr->len] = '\0'; seems_valid(ostr); } void octstr_insert_char(Octstr *ostr, long pos, const char c) { seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(pos <= ostr->len); octstr_grow(ostr, ostr->len + 1); if (ostr->len > pos) memmove(ostr->data + pos + 1, ostr->data + pos, ostr->len - pos); memcpy(ostr->data + pos, &c, 1); ostr->len += 1; ostr->data[ostr->len] = '\0'; seems_valid(ostr); } void octstr_append_data(Octstr *ostr, const char *data, long len) { gw_assert(ostr != NULL); octstr_insert_data(ostr, ostr->len, data, len); } void octstr_append(Octstr *ostr1, const Octstr *ostr2) { gw_assert(ostr1 != NULL); octstr_insert(ostr1, ostr2, ostr1->len); } void octstr_append_cstr(Octstr *ostr, const char *cstr) { octstr_insert_data(ostr, ostr->len, cstr, strlen(cstr)); } void octstr_append_char(Octstr *ostr, int ch) { unsigned char c = ch; gw_assert(ch >= 0); gw_assert(ch <= UCHAR_MAX); octstr_insert_data(ostr, ostr->len, &c, 1); } void octstr_delete(Octstr *ostr1, long pos, long len) { seems_valid(ostr1); gw_assert(!ostr1->immutable); if (pos > ostr1->len) pos = ostr1->len; if (pos + len > ostr1->len) len = ostr1->len - pos; if (len > 0) { memmove(ostr1->data + pos, ostr1->data + pos + len, ostr1->len - pos - len); ostr1->len -= len; ostr1->data[ostr1->len] = '\0'; } seems_valid(ostr1); } Octstr *octstr_read_file(const char *filename) { FILE *f; Octstr *os; char buf[4096]; long n; gw_assert(filename != NULL); f = fopen(filename, "r"); if (f == NULL) { error(errno, "fopen failed: couldn't open `%s'", filename); return NULL; } os = octstr_create(""); if (os == NULL) goto error; while ((n = fread(buf, 1, sizeof(buf), f)) > 0) octstr_insert_data(os, octstr_len(os), buf, n); (void) fclose(f); return os; error: (void) fclose(f); octstr_destroy(os); return NULL; } Octstr *octstr_read_pipe(FILE *f) { Octstr *os; char buf[4096]; gw_assert(f != NULL); os = octstr_create(""); if (os == NULL) goto error; while (fgets(buf, sizeof(buf), f) != NULL) octstr_append_data(os, buf, strlen(buf)); return os; error: octstr_destroy(os); return NULL; } List *octstr_split_words(const Octstr *ostr) { unsigned char *p; List *list; Octstr *word; long i, start, end; seems_valid(ostr); list = gwlist_create(); p = ostr->data; i = 0; for (; ; ) { while (i < ostr->len && isspace(*p)) { ++p; ++i; } start = i; while (i < ostr->len && !isspace(*p)) { ++p; ++i; } end = i; if (start == end) break; word = octstr_create_from_data(ostr->data + start, end - start); gwlist_append(list, word); } return list; } List *octstr_split(const Octstr *os, const Octstr *sep) { List *list; long next, pos, seplen; list = gwlist_create(); pos = 0; seplen = octstr_len(sep); while ((next = octstr_search(os, sep, pos)) >= 0) { gwlist_append(list, octstr_copy(os, pos, next - pos)); pos = next + seplen; } if (pos < octstr_len(os)) gwlist_append(list, octstr_copy(os, pos, octstr_len(os))); return list; } int octstr_item_match(void *item, void *pattern) { return octstr_compare(item, pattern) == 0; } int octstr_item_case_match(void *item, void *pattern) { return octstr_case_compare(item, pattern) == 0; } void octstr_url_encode(Octstr *ostr) { long i, n, len = 0; int all_safe; unsigned char c, *str, *str2, *res, *hexits; if (ostr == NULL) return; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return; /* calculate new length */ for (i = n = 0, str = ostr->data, all_safe = 1; i < ostr->len; i++) { c = *str++; if (c == ' ') { all_safe = 0; continue; } if (!is_safe[c]) { n++; all_safe = 0; } } if (all_safe) /* we are done, all chars are safe */ return; hexits = "0123456789ABCDEF"; /* * no need to reallocate if n == 0, so we make replace in place. * NOTE: we don't do if (xxx) ... else ... because conditional jump * is not so fast as just compare (alex). */ res = str2 = (n ? gw_malloc((len = ostr->len + 2 * n + 1)) : ostr->data); for (i = 0, str = ostr->data; i < ostr->len; i++) { c = *str++; if (c == ' ') { *str2++ = '+'; continue; } if (!is_safe[c]) { *str2++ = '%'; *str2++ = hexits[c >> 4 & 0xf]; *str2++ = hexits[c & 0xf]; continue; } *str2++ = c; } *str2 = 0; /* we made replace in place */ if (n) { gw_free(ostr->data); ostr->data = res; ostr->size = len; ostr->len = len - 1; } seems_valid(ostr); } int octstr_url_decode(Octstr *ostr) { unsigned char *string; unsigned char *dptr; int code, code2, ret = 0; if (ostr == NULL) return 0; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return 0; string = ostr->data; dptr = ostr->data; do { if (*string == '%') { if (*(string + 1) == '\0' || *(string + 2) == '\0') { warning(0, "octstr_url_decode: corrupted end-of-string <%s>", string); ret = -1; break; } code = H2B(*(string + 1)); code2 = H2B(*(string + 2)); if (code == -1 || code2 == -1) { warning(0, "octstr_url_decode: garbage detected (%c%c%c) skipping.", *string, *(string + 1), *(string + 2)); *dptr++ = *string++; *dptr++ = *string++; *dptr++ = *string++; ret = -1; continue; } *dptr++ = code << 4 | code2; string += 3; } else if (*string == '+') { *dptr++ = ' '; string++; } else *dptr++ = *string++; } while (*string); /* we stop here because it terimates encoded string */ *dptr = '\0'; ostr->len = (dptr - ostr->data); seems_valid(ostr); return ret; } long octstr_get_bits(Octstr *ostr, long bitpos, int numbits) { long pos; long result; int mask; int shiftwidth; seems_valid(ostr); gw_assert(bitpos >= 0); gw_assert(numbits <= 32); gw_assert(numbits >= 0); pos = bitpos / 8; bitpos = bitpos % 8; /* This also takes care of the len == 0 case */ if (pos >= ostr->len) return 0; mask = (1 << numbits) - 1; /* It's easy if the range fits in one octet */ if (bitpos + numbits <= 8) { /* shiftwidth is the number of bits to ignore on the right. * bitpos 0 is the leftmost bit. */ shiftwidth = 8 - (bitpos + numbits); return (ostr->data[pos] >> shiftwidth) & mask; } /* Otherwise... */ result = 0; while (bitpos + numbits > 8) { result = (result << 8) | ostr->data[pos]; numbits -= (8 - bitpos); bitpos = 0; pos++; if (pos >= ostr->len) return (result << numbits) & mask; } gw_assert(bitpos == 0); result <<= numbits; result |= ostr->data[pos] >> (8 - numbits); return result & mask; } void octstr_set_bits(Octstr *ostr, long bitpos, int numbits, unsigned long value) { long pos; unsigned long mask; int shiftwidth; int bits; int maxlen; int c; seems_valid(ostr); gw_assert(!ostr->immutable); gw_assert(bitpos >= 0); gw_assert(numbits <= 32); gw_assert(numbits >= 0); maxlen = (bitpos + numbits + 7) / 8; if (maxlen > ostr->len) { octstr_grow(ostr, maxlen); /* Make sure the new octets start out with value 0 */ for (pos = ostr->len; pos < maxlen; pos++) { ostr->data[pos] = 0; } ostr->len = maxlen; ostr->data[maxlen] = 0; } mask = (1 << numbits) - 1; /* mask is also the largest value that fits */ gw_assert(value <= mask); pos = bitpos / 8; bitpos = bitpos % 8; /* Does the range fit in one octet? */ if (bitpos + numbits <= 8) { /* shiftwidth is the number of bits to ignore on the right. * bitpos 0 is the leftmost bit. */ shiftwidth = 8 - (bitpos + numbits); /* Extract the bits we don't want to affect */ c = ostr->data[pos] & ~(mask << shiftwidth); c |= value << shiftwidth; gw_assert(pos < ostr->len); ostr->data[pos] = c; return; } /* Otherwise... */ /* If speed is a problem here, we could have separate cases for * the first octet (which may have bitpos > 0), and the rest, * which don't. */ while (bitpos + numbits > 8) { /* We want this many bits from the value */ bits = 8 - bitpos; /* There are this many bits to their right in the value */ shiftwidth = numbits - bits; /* Construct a mask for "bits" bits on the far right */ mask = (1 << bits) - 1; /* Get the bits we want */ c = (value >> shiftwidth) & mask; /* Merge them with the bits that are already there */ gw_assert(pos < ostr->len); ostr->data[pos] = (ostr->data[pos] & ~mask) | c; numbits -= (8 - bitpos); bitpos = 0; pos++; } gw_assert(bitpos == 0); gw_assert(pos < ostr->len); /* Set remaining bits. This is just like the single-octet case * before the loop, except that we know bitpos is 0. */ mask = (1 << numbits) - 1; shiftwidth = 8 - numbits; c = ostr->data[pos] & ~(mask << shiftwidth); c |= value << shiftwidth; ostr->data[pos] = c; seems_valid(ostr); } void octstr_append_uintvar(Octstr *ostr, unsigned long value) { /* A uintvar is defined to be up to 32 bits large, so it will * fit in 5 octets. */ unsigned char octets[5]; int i; int start; /* Handle last byte separately; it has no continuation bit, * and must be encoded even if value is 0. */ octets[4] = value & 0x7f; value >>= 7; for (i = 3; value > 0 && i >= 0; i--) { octets[i] = 0x80 | (value & 0x7f); value >>= 7; } start = i + 1; octstr_append_data(ostr, octets + start, 5 - start); } long octstr_extract_uintvar(Octstr *ostr, unsigned long *value, long pos) { int c; int count; unsigned long ui; ui = 0; for (count = 0; count < 5; count++) { c = octstr_get_char(ostr, pos + count); if (c < 0) return -1; ui = (ui << 7) | (c & 0x7f); if (!(c & 0x80)) { *value = ui; return pos + count + 1; } } return -1; } void octstr_append_decimal(Octstr *ostr, long value) { char tmp[128]; sprintf(tmp, "%ld", value); octstr_append_cstr(ostr, tmp); } /********************************************************************** * octstr_dump... and related private functions */ static void octstr_dump_debug(const Octstr *ostr, int level) { unsigned char *p, *d, buf[1024], charbuf[256]; long pos; const int octets_per_line = 16; int c, this_line_begins_at; if (ostr == NULL) return; seems_valid(ostr); debug("gwlib.octstr", 0, "%*sOctet string at %p:", level, "", (void *) ostr); debug("gwlib.octstr", 0, "%*s len: %lu", level, "", (unsigned long) ostr->len); debug("gwlib.octstr", 0, "%*s size: %lu", level, "", (unsigned long) ostr->size); debug("gwlib.octstr", 0, "%*s immutable: %d", level, "", ostr->immutable); buf[0] = '\0'; p = buf; d = charbuf; this_line_begins_at = 0; for (pos = 0; pos < octstr_len(ostr); ) { c = octstr_get_char(ostr, pos); sprintf(p, "%02x ", c); p = strchr(p, '\0'); if (isprint(c)) *d++ = c; else *d++ = '.'; ++pos; if (pos - this_line_begins_at == octets_per_line) { *d = '\0'; debug("gwlib.octstr", 0, "%*s data: %s %s", level, "", buf, charbuf); buf[0] = '\0'; charbuf[0] = '\0'; p = buf; d = charbuf; this_line_begins_at = pos; } } if (pos - this_line_begins_at > 0) { *d = '\0'; debug("gwlib.octstr", 0, "%*s data: %-*.*s %s", level, "", octets_per_line*3, octets_per_line*3, buf, charbuf); } debug("gwlib.octstr", 0, "%*sOctet string dump ends.", level, ""); } /* * We do some pre-processor mangling here in order to reduce code for * the 3 log levels info(), warning() and error() that have the same * argument list. * We need to map the function calls via ## concatenation and revert * to the original function call by a define. * The do-while loop emulates a function call. */ #define LLinfo info #define LLwarning warning #define LLerror error #define octstr_dump_LOGLEVEL(loglevel, ostr, level) \ do { \ unsigned char *p, *d, buf[1024], charbuf[256]; \ long pos; \ const int octets_per_line = 16; \ int c, this_line_begins_at; \ \ if (ostr == NULL) \ return; \ \ seems_valid(ostr); \ \ LL##loglevel(0, "%*sOctet string at %p:", level, "", \ (void *) ostr); \ LL##loglevel(0, "%*s len: %lu", level, "", \ (unsigned long) ostr->len); \ LL##loglevel(0, "%*s size: %lu", level, "", \ (unsigned long) ostr->size); \ LL##loglevel(0, "%*s immutable: %d", level, "", \ ostr->immutable); \ \ buf[0] = '\0'; \ p = buf; \ d = charbuf; \ this_line_begins_at = 0; \ for (pos = 0; pos < octstr_len(ostr); ) { \ c = octstr_get_char(ostr, pos); \ sprintf(p, "%02x ", c); \ p = strchr(p, '\0'); \ if (isprint(c)) \ *d++ = c; \ else \ *d++ = '.'; \ ++pos; \ if (pos - this_line_begins_at == octets_per_line) { \ *d = '\0'; \ LL##loglevel(0, "%*s data: %s %s", level, "", \ buf, charbuf); \ buf[0] = '\0'; \ charbuf[0] = '\0'; \ p = buf; \ d = charbuf; \ this_line_begins_at = pos; \ } \ } \ if (pos - this_line_begins_at > 0) { \ *d = '\0'; \ LL##loglevel(0, "%*s data: %-*.*s %s", level, "", \ octets_per_line*3, \ octets_per_line*3, buf, charbuf); \ } \ \ LL##loglevel(0, "%*sOctet string dump ends.", level, ""); \ } while (0) void octstr_dump_real(const Octstr *ostr, int level, ...) { va_list p; unsigned int loglevel; va_start(p, level); loglevel = va_arg(p, unsigned int); va_end(p); switch (loglevel) { case GW_DEBUG: octstr_dump_debug(ostr, level); break; case GW_INFO: octstr_dump_LOGLEVEL(info, ostr, level); break; case GW_WARNING: octstr_dump_LOGLEVEL(warning, ostr, level); break; case GW_ERROR: octstr_dump_LOGLEVEL(error, ostr, level); break; default: octstr_dump_debug(ostr, level); break; } } void octstr_dump_short(Octstr *ostr, int level, const char *name) { char buf[100]; char *p; long i; int c; if (ostr == NULL) { debug("gwlib.octstr", 0, "%*s%s: NULL", level, "", name); return; } seems_valid(ostr); if (ostr->len < 20) { p = buf; for (i = 0; i < ostr->len; i++) { c = ostr->data[i]; if (c == '\n') { *p++ = '\\'; *p++ = 'n'; } else if (!isprint(c)) { break; } else if (c == '"') { *p++ = '\\'; *p++ = '"'; } else if (c == '\\') { *p++ = '\\'; *p++ = '\\'; } else { *p++ = c; } } if (i == ostr->len) { *p++ = 0; /* We got through the loop without hitting nonprintable * characters. */ debug("gwlib.octstr", 0, "%*s%s: \"%s\"", level, "", name, buf); return; } } debug("gwlib.octstr", 0, "%*s%s:", level, "", name); octstr_dump(ostr, level + 1); } /********************************************************************** * octstr_format and related private functions */ /* * A parsed form of the format string. This struct has been carefully * defined so that it can be initialized with {0} and it will have * the correct defaults. */ struct format { int minus; int zero; long min_width; int has_prec; long prec; long type; }; static void format_flags(struct format *format, const char **fmt) { int done; done = 0; do { switch (**fmt) { case '-': format->minus = 1; break; case '0': format->zero = 1; break; default: done = 1; } if (!done) ++(*fmt); } while (!done); } static void format_width(struct format *format, const char **fmt, VALPARM(args)) { char *end; if (**fmt == '*') { format->min_width = va_arg(VALST(args), int); ++(*fmt); } else if (isdigit(**(const unsigned char **) fmt)) { format->min_width = strtol(*fmt, &end, 10); *fmt = end; /* XXX error checking is missing from here */ } } static void format_prec(struct format *format, const char **fmt, VALPARM(args)) { char *end; if (**fmt != '.') return; ++(*fmt); if (**fmt == '*') { format->has_prec = 1; format->prec = va_arg(VALST(args), int); ++(*fmt); } else if (isdigit(**(const unsigned char **) fmt)) { format->has_prec = 1; format->prec = strtol(*fmt, &end, 10); *fmt = end; /* XXX error checking is missing from here */ } } static void format_type(struct format *format, const char **fmt) { switch (**fmt) { case 'h': format->type = **fmt; ++(*fmt); break; case 'l': if (*(*fmt + 1) == 'l'){ format->type = 'L'; ++(*fmt); } else format->type = **fmt; ++(*fmt); break; } } static void convert(Octstr *os, struct format *format, const char **fmt, VALPARM(args)) { Octstr *new; char *s, *pad; long long n; unsigned long long u; char tmpfmt[1024]; char tmpbuf[1024]; char c; void *p; new = NULL; switch (**fmt) { case 'c': c = va_arg(VALST(args), int); new = octstr_create_from_data(&c, 1); break; case 'd': case 'i': switch (format->type) { case 'L': n = va_arg(VALST(args), long long); break; case 'l': n = va_arg(VALST(args), long); break; case 'h': n = (short) va_arg(VALST(args), int); break; default: n = va_arg(VALST(args), int); break; } new = octstr_create(""); octstr_append_decimal(new, n); break; case 'o': case 'u': case 'x': case 'X': switch (format->type) { case 'l': u = va_arg(VALST(args), unsigned long); break; case 'L': u = va_arg(VALST(args), unsigned long long); break; case 'h': u = (unsigned short) va_arg(VALST(args), unsigned int); break; default: u = va_arg(VALST(args), unsigned int); break; } tmpfmt[0] = '%'; tmpfmt[1] = 'l'; tmpfmt[2] = **fmt; tmpfmt[3] = '\0'; sprintf(tmpbuf, tmpfmt, u); new = octstr_create(tmpbuf); break; case 'e': case 'f': case 'g': sprintf(tmpfmt, "%%"); if (format->minus) strcat(tmpfmt, "-"); if (format->zero) strcat(tmpfmt, "0"); if (format->min_width > 0) sprintf(strchr(tmpfmt, '\0'), "%ld", format->min_width); if (format->has_prec) sprintf(strchr(tmpfmt, '\0'), ".%ld", format->prec); if (format->type != '\0') sprintf(strchr(tmpfmt, '\0'), "%c", (int) format->type); sprintf(strchr(tmpfmt, '\0'), "%c", **fmt); snprintf(tmpbuf, sizeof(tmpbuf), tmpfmt, va_arg(VALST(args), double)); new = octstr_create(tmpbuf); break; case 's': s = va_arg(VALST(args), char *); if (format->has_prec && format->prec < (long) strlen(s)) n = format->prec; else n = (long) strlen(s); new = octstr_create_from_data(s, n); break; case 'p': p = va_arg(VALST(args), void *); sprintf(tmpfmt, "%p", p); new = octstr_create(tmpfmt); break; case 'S': new = octstr_duplicate(va_arg(VALST(args), Octstr *)); if (!new) new = octstr_create("(null)"); if (format->has_prec) octstr_truncate(new, format->prec); break; case 'E': new = octstr_duplicate(va_arg(VALST(args), Octstr *)); if (!new) new = octstr_create("(null)"); octstr_url_encode(new); /* * note: we use blind truncate - encoded character can get cut half-way. */ if (format->has_prec) octstr_truncate(new, format->prec); break; case 'H': new = octstr_duplicate(va_arg(VALST(args), Octstr *)); if (!new) new = octstr_create("(null)"); /* upper case */ octstr_binary_to_hex(new, 1); if (format->has_prec) octstr_truncate(new, (format->prec % 2 ? format->prec - 1 : format->prec)); break; case '%': new = octstr_create("%"); break; default: panic(0, "octstr_format format string syntax error."); } if (format->zero) pad = "0"; else pad = " "; if (format->minus) { while (format->min_width > octstr_len(new)) octstr_append_data(new, pad, 1); } else { while (format->min_width > octstr_len(new)) octstr_insert_data(new, 0, pad, 1); } octstr_append(os, new); octstr_destroy(new); if (**fmt != '\0') ++(*fmt); } Octstr *octstr_format(const char *fmt, ...) { Octstr *os; va_list args; va_start(args, fmt); os = octstr_format_valist(fmt, args); va_end(args); return os; } Octstr *octstr_format_valist_real(const char *fmt, va_list args) { Octstr *os; size_t n; os = octstr_create(""); while (*fmt != '\0') { struct format format = { 0, }; n = strcspn(fmt, "%"); octstr_append_data(os, fmt, n); fmt += n; gw_assert(*fmt == '%' || *fmt == '\0'); if (*fmt == '\0') continue; ++fmt; format_flags(&format, &fmt); format_width(&format, &fmt, VARGS(args)); format_prec(&format, &fmt, VARGS(args)); format_type(&format, &fmt); convert(os, &format, &fmt, VARGS(args)); } seems_valid(os); return os; } void octstr_format_append(Octstr *os, const char *fmt, ...) { Octstr *temp; va_list args; va_start(args, fmt); temp = octstr_format_valist(fmt, args); va_end(args); octstr_append(os, temp); octstr_destroy(temp); } /* * Hash implementation ala Robert Sedgewick. */ unsigned long octstr_hash_key(Octstr *ostr) { unsigned long b = 378551; unsigned long a = 63689; unsigned long hash = 0; unsigned long i = 0; unsigned long len = octstr_len(ostr); const char *str = octstr_get_cstr(ostr); for(i = 0; i < len; str++, i++) { hash = hash*a+(*str); a = a*b; } return (hash & 0x7FFFFFFF); } /********************************************************************** * Local functions. */ static void seems_valid_real(const Octstr *ostr, const char *filename, long lineno, const char *function) { gw_assert(immutables_init); gw_assert_place(ostr != NULL, filename, lineno, function); gw_assert_allocated(ostr, filename, lineno, function); gw_assert_place(ostr->len >= 0, filename, lineno, function); gw_assert_place(ostr->size >= 0, filename, lineno, function); if (ostr->size == 0) { gw_assert_place(ostr->len == 0, filename, lineno, function); gw_assert_place(ostr->data == NULL, filename, lineno, function); } else { gw_assert_place(ostr->len + 1 <= ostr->size, filename, lineno, function); gw_assert_place(ostr->data != NULL, filename, lineno, function); if (!ostr->immutable) gw_assert_allocated(ostr->data, filename, lineno, function); gw_assert_place(ostr->data[ostr->len] == '\0', filename, lineno, function); } } int octstr_recode (Octstr *tocode, Octstr *fromcode, Octstr *orig) { Octstr *octstr_utf8 = NULL; Octstr *octstr_final = NULL; int resultcode = 0; if (octstr_case_compare(tocode, fromcode) == 0) { goto cleanup_and_exit; } if ((octstr_case_compare(fromcode, octstr_imm ("UTF-8")) != 0) && (octstr_case_compare(fromcode, octstr_imm ("UTF8")) != 0)) { if (charset_to_utf8(orig, &octstr_utf8, fromcode) < 0) { resultcode = -1; goto cleanup_and_exit; } } else { octstr_utf8 = octstr_duplicate(orig); } if ((octstr_case_compare(tocode, octstr_imm ("UTF-8")) != 0) && (octstr_case_compare(tocode, octstr_imm ("UTF8")) != 0)) { if (charset_from_utf8(octstr_utf8, &octstr_final, tocode) < 0) { resultcode = -1; goto cleanup_and_exit; } } else { octstr_final = octstr_duplicate(octstr_utf8); } octstr_truncate(orig, 0); octstr_append(orig, octstr_final); cleanup_and_exit: octstr_destroy (octstr_utf8); octstr_destroy (octstr_final); return resultcode; } void octstr_strip_char(Octstr *text, char ch) { int start = 0; seems_valid(text); gw_assert(!text->immutable); /* Remove char from the beginning of the text */ while ((ch == octstr_get_char(text, start)) && start <= octstr_len(text)) start ++; if (start > 0) octstr_delete(text, 0, start); seems_valid(text); } int octstr_isnum(Octstr *ostr1) { int start = 0; char c; seems_valid(ostr1); while (start < octstr_len(ostr1)) { c = octstr_get_char(ostr1, start); if (!isdigit(c) && (c!='+')) return 0; start++; } return 1; } void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl) { int p = 0; long len, repl_len; len = octstr_len(needle); repl_len = octstr_len(repl); while ((p = octstr_search(haystack, needle, p)) != -1) { octstr_delete(haystack, p, len); octstr_insert(haystack, repl, p); p += repl_len; } } void octstr_replace_first(Octstr *haystack, Octstr *needle, Octstr *repl) { int p = 0; long len, repl_len; len = octstr_len(needle); repl_len = octstr_len(repl); p = octstr_search(haystack, needle, p); if (p != -1) { octstr_delete(haystack, p, len); octstr_insert(haystack, repl, p); } } int octstr_symbolize(Octstr *ostr) { long len, i; seems_valid(ostr); gw_assert(!ostr->immutable); if (ostr->len == 0) return 0; /* Check if it's in the right format */ if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit)) return -1; len = ostr->len + (ostr->len/2); octstr_grow(ostr, ostr->len * 2); for (i = 0; i < len; i += 3) octstr_insert_data(ostr, i, "%", 1); return 1; } void octstr_delete_matching(Octstr *haystack, Octstr *needle) { int p = 0; long len; seems_valid(haystack); seems_valid(needle); gw_assert(!haystack->immutable); len = octstr_len(needle); while ((p = octstr_search(haystack, needle, p)) != -1) { octstr_delete(haystack, p, len); } } int octstr_is_all_hex(Octstr *os) { long len, i; int ch; seems_valid(os); len = octstr_len(os); for (i = 0; i < len; ++i) { ch = octstr_get_char(os, i); if (!gw_isxdigit(ch)) return 0; } return 1; } /* * function octstr_convert_to_html_entities() * make data HTML safe by converting appropriate characters to HTML entities * Input: data to be inserted in HTML **/ void octstr_convert_to_html_entities(Octstr* input) { int i; for (i = 0; i < octstr_len(input); ++i) { switch (octstr_get_char(input, i)) { #define ENTITY(a,b) \ case a: \ octstr_delete(input, i, 1); \ octstr_insert(input, octstr_imm("&" b ";"), i); \ i += sizeof(b); break; #include "gwlib/html-entities.def" #undef ENTITY } } } /* * This function is meant to find html entities in an octstr. * The html-entities.def file must be sorted alphabetically for * this function to work (according to current Locale in use). */ static int octstr_find_entity(Octstr* input, int startfind, int endfind) { #define ENTITY(a,b) { a, b }, struct entity_struct { int entity; char *entity_str; }; const struct entity_struct entities[] = { #include "html-entities.def" { -1, "" } /* pivot */ }; #undef ENTITY int center; /* position in table that we are about to compare */ int matchresult; /* result of match agains found entity name. indicates less, equal or greater */ if (endfind == 0) { /* when calling this function we do not (nor even want to) know the * sizeof(entities). Hence this check. */ endfind = (sizeof(entities) / sizeof(struct entity_struct)) - 1; } center = startfind + ((endfind - startfind) / 2); matchresult = octstr_str_compare(input, entities[center].entity_str); if (matchresult == 0) { return entities[center].entity; } if (endfind - startfind <= 1) { /* we are at the end of our results */ return -1; } if (matchresult < 0) { /* keep searching in first part of the table */ return octstr_find_entity(input, startfind, center); } else { /* keep searching in last part of the table */ return octstr_find_entity(input, center, endfind); } } /* * function octstr_convert_from_html_entities() * convert HTML safe data back to binary data by replacing HTML entities with their * respective character values * Input: data to be inserted in HTML **/ void octstr_convert_from_html_entities(Octstr* input) { int startpos = 0, endpos; int entity; Octstr *match; while ((startpos = octstr_search_char(input, '&', startpos)) != -1) { endpos = octstr_search_char(input, ';', startpos + 1); if (endpos >= 0) { match = octstr_copy(input, startpos + 1, endpos - startpos - 1); entity = octstr_find_entity(match, 0, 0); if (entity >= 0) { octstr_delete(input, startpos, endpos - startpos + 1); octstr_insert_char(input, startpos, entity); } octstr_destroy(match); } startpos++; } } gateway-1.4.5/gwlib/dict.c0000644000175000017500000002426313227613126014071 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dict.c - lookup data structure using octet strings as keys * * The Dict is implemented as a simple hash table. In the future, it * might be interesting to use a trie instead. * * Lars Wirzenius, based on code by Tuomas Luttinen */ #include "gwlib.h" /* * The hash table stores key/value -pairs in a List. */ typedef struct Item Item; struct Item { Octstr *key; void *value; }; static Item *item_create(Octstr *key, void *value) { Item *item; item = gw_malloc(sizeof(*item)); item->key = octstr_duplicate(key); item->value = value; return item; } static void item_destroy(void *item) { Item *p; p = item; octstr_destroy(p->key); gw_free(p); } static int item_has_key(void *item, void *key) { return octstr_compare(key, ((Item *) item)->key) == 0; } /* * The dictionary itself is a very simple hash table. * `tab' is an array of Lists of Items, in which empty Lists may be * represented as NULL. `size' is the number of elements allocated * for the array, and `key_count' is the number of Items currently * in the table. `key_count' is kept up to date by the put and remove * functions, and is used to make dict_key_count() faster. */ struct Dict { List **tab; long size; long key_count; void (*destroy_value)(void *); Mutex *lock; }; static void lock(Dict *dict) { mutex_lock(dict->lock); } static void unlock(Dict *dict) { mutex_unlock(dict->lock); } static long key_to_index(Dict *dict, Octstr *key) { return octstr_hash_key(key) % dict->size; } static int handle_null_value(Dict *dict, Octstr *key, void *value) { if (value == NULL) { value = dict_remove(dict, key); if (dict->destroy_value != NULL) dict->destroy_value(value); return 1; } return 0; } static int dict_put_true(Dict *dict, Octstr *key, void *value) { Item *p; long i; int item_unique; item_unique = 0; lock(dict); i = key_to_index(dict, key); if (dict->tab[i] == NULL) { dict->tab[i] = gwlist_create(); p = NULL; } else { p = gwlist_search(dict->tab[i], key, item_has_key); } if (p == NULL) { p = item_create(key, value); gwlist_append(dict->tab[i], p); dict->key_count++; item_unique = 1; } else { if (dict->destroy_value != NULL) dict->destroy_value(value); item_unique = 0; } unlock(dict); return item_unique; } /* * And finally, the public functions. */ Dict *dict_create(long size_hint, void (*destroy_value)(void *)) { Dict *dict; long i; dict = gw_malloc(sizeof(*dict)); /* * Hash tables tend to work well until they are fill to about 50%. */ dict->size = size_hint * 2; dict->tab = gw_malloc(sizeof(dict->tab[0]) * dict->size); for (i = 0; i < dict->size; ++i) dict->tab[i] = NULL; dict->lock = mutex_create(); dict->destroy_value = destroy_value; dict->key_count = 0; return dict; } void dict_destroy(Dict *dict) { long i; Item *p; if (dict == NULL) return; for (i = 0; i < dict->size; ++i) { if (dict->tab[i] == NULL) continue; while ((p = gwlist_extract_first(dict->tab[i])) != NULL) { if (dict->destroy_value != NULL) dict->destroy_value(p->value); item_destroy(p); } gwlist_destroy(dict->tab[i], NULL); } mutex_destroy(dict->lock); gw_free(dict->tab); gw_free(dict); } void dict_put(Dict *dict, Octstr *key, void *value) { long i; Item *p; if (value == NULL) { value = dict_remove(dict, key); if (dict->destroy_value != NULL) dict->destroy_value(value); return; } lock(dict); i = key_to_index(dict, key); if (dict->tab[i] == NULL) { dict->tab[i] = gwlist_create(); p = NULL; } else p = gwlist_search(dict->tab[i], key, item_has_key); if (p == NULL) { p = item_create(key, value); gwlist_append(dict->tab[i], p); dict->key_count++; } else { if (dict->destroy_value != NULL) dict->destroy_value(p->value); p->value = value; } unlock(dict); } int dict_put_once(Dict *dict, Octstr *key, void *value) { int ret; ret = 1; if (handle_null_value(dict, key, value)) return 1; if (dict_put_true(dict, key, value)) { ret = 1; } else { ret = 0; } return ret; } void *dict_get(Dict *dict, Octstr *key) { long i; Item *p; void *value; lock(dict); i = key_to_index(dict, key); if (dict->tab[i] == NULL) p = NULL; else p = gwlist_search(dict->tab[i], key, item_has_key); if (p == NULL) value = NULL; else value = p->value; unlock(dict); return value; } void *dict_remove(Dict *dict, Octstr *key) { long i; Item *p; void *value; List *list; lock(dict); i = key_to_index(dict, key); if (dict->tab[i] == NULL) list = NULL; else list = gwlist_extract_matching(dict->tab[i], key, item_has_key); gw_assert(list == NULL || gwlist_len(list) == 1); if (list == NULL) value = NULL; else { p = gwlist_get(list, 0); gwlist_destroy(list, NULL); value = p->value; item_destroy(p); dict->key_count--; } unlock(dict); return value; } long dict_key_count(Dict *dict) { long result; lock(dict); result = dict->key_count; unlock(dict); return result; } List *dict_keys(Dict *dict) { List *list; Item *item; long i, j; list = gwlist_create(); lock(dict); for (i = 0; i < dict->size; ++i) { if (dict->tab[i] == NULL) continue; for (j = 0; j < gwlist_len(dict->tab[i]); ++j) { item = gwlist_get(dict->tab[i], j); gwlist_append(list, octstr_duplicate(item->key)); } } unlock(dict); return list; } Dict *dict_duplicate(Dict *dict, void *(*duplicate_value)(void *)) { Item *item; long i, j; Dict *dup; lock(dict); dup = dict_create(dict->size, dict->destroy_value); for (i = 0; i < dict->size; ++i) { if (dict->tab[i] == NULL) continue; for (j = 0; j < gwlist_len(dict->tab[i]); ++j) { item = gwlist_get(dict->tab[i], j); dict_put(dup, item->key, duplicate_value(item->value)); } } unlock(dict); return dup; } long dict_traverse(Dict *dict, void (*func)(Octstr *, void *, void *), void *data) { Item *item; long i, j, r = 0; lock(dict); for (i = 0; i < dict->size; ++i) { if (dict->tab[i] == NULL) continue; for (j = 0; j < gwlist_len(dict->tab[i]); ++j) { item = gwlist_get(dict->tab[i], j); func(item->key, item->value, data); r++; } } unlock(dict); return r; } long dict_traverse_sorted(Dict *dict, int (*cmp)(const void *, const void *), void (*func)(Octstr *, void *, void *), void *data) { Item *item; long i, j, r = 0; List *l; l = gwlist_create(); lock(dict); /* We need to aggregate a list of all item elements first. */ for (i = 0; i < dict->size; ++i) { if (dict->tab[i] == NULL) continue; for (j = 0; j < gwlist_len(dict->tab[i]); ++j) { gwlist_append(l, gwlist_get(dict->tab[i], j)); } } /* Now we can sort the list. */ gwlist_sort(l, cmp); /* And traverse the list. */ r = gwlist_len(l); while ((item = gwlist_consume(l)) != NULL) { func(item->key, item->value, data); } unlock(dict); gwlist_destroy(l, NULL); return r; } gateway-1.4.5/gwlib/gw-getopt.h0000644000175000017500000000643713227613126015073 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwlib/getopt.h - define a prototype for the getopt function * * Some systems have a which defines the getopt stuff. On * those systems, we include that. On other systems, we provide our own * definitions. */ #ifndef GWLIB_GETOPT_H #define GWLIB_GETOPT_H #if HAVE_GETOPT_H #include #elif HAVE_GETOPT_IN_STDIO_H #include #elif HAVE_GETOPT_IN_UNISTD_H #include #else int getopt(int argc, char **argv, char *opts); extern int opterr; extern int optind; extern int optopt; extern char *optarg; #endif #endif gateway-1.4.5/gwlib/charset.c0000644000175000017500000005425313227613126014601 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwlib/charset.c - character set conversions * * This file implements the character set conversions declared in charset.h. * * Richard Braakman */ #include "gwlib/gwlib.h" #if HAVE_ICONV #include #include #endif /* Code used for non-representable characters */ #define NRP '?' #include "gwlib/latin1_to_gsm.h" /* This is the extension table defined in GSM 03.38. It is the mapping * used for the character after a GSM 27 (Escape) character. All characters * not in the table, as well as characters we can't represent, will map * to themselves. We cannot represent the euro symbol, which is an escaped * 'e', so we left it out of this table. */ static const struct { int gsmesc; int latin1; } gsm_esctolatin1[] = { { 10, 12 }, /* ASCII page break */ { 20, '^' }, { 40, '{' }, { 41, '}' }, { 47, '\\' }, { 60, '[' }, { 61, '~' }, { 62, ']' }, { 64, '|' }, { 101, 128 }, { -1, -1 } }; /** * Struct maps escaped GSM chars to unicode codeposition. */ static const struct { int gsmesc; int unichar; } gsm_esctouni[] = { { 10, 12 }, /* ASCII page break */ { 20, '^' }, { 40, '{' }, { 41, '}' }, { 47, '\\' }, { 60, '[' }, { 61, '~' }, { 62, ']' }, { 64, '|' }, { 'e', 0x20AC }, /* euro symbol */ { -1, -1 } }; /* Map GSM default alphabet characters to ISO-Latin-1 characters. * The greek characters at positions 16 and 18 through 26 are not * mappable. They are mapped to '?' characters. * The escape character, at position 27, is mapped to a space, * though normally the function that indexes into this table will * treat it specially. */ static const unsigned char gsm_to_latin1[128] = { '@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, /* 0 - 7 */ 0xf2, 0xc7, 10, 0xd8, 0xf8, 13, 0xc5, 0xe5, /* 8 - 15 */ '?', '_', '?', '?', '?', '?', '?', '?', /* 16 - 23 */ '?', '?', '?', ' ', 0xc6, 0xe6, 0xdf, 0xc9, /* 24 - 31 */ ' ', '!', '"', '#', 0xa4, '%', '&', '\'', /* 32 - 39 */ '(', ')', '*', '+', ',', '-', '.', '/', /* 40 - 47 */ '0', '1', '2', '3', '4', '5', '6', '7', /* 48 - 55 */ '8', '9', ':', ';', '<', '=', '>', '?', /* 56 - 63 */ 0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 64 - 71 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 73 - 79 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 80 - 87 */ 'X', 'Y', 'Z', 0xc4, 0xd6, 0xd1, 0xdc, 0xa7, /* 88 - 95 */ 0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 96 - 103 */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 104 - 111 */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 112 - 119 */ 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0 /* 120 - 127 */ }; /** * Map GSM default alphabet characters to unicode codeposition. * The escape character, at position 27, is mapped to a NRP, * though normally the function that indexes into this table will * treat it specially. */ static const int gsm_to_unicode[128] = { '@', 0xA3, '$', 0xA5, 0xE8, 0xE9, 0xF9, 0xEC, /* 0 - 7 */ 0xF2, 0xC7, 10, 0xd8, 0xF8, 13, 0xC5, 0xE5, /* 8 - 15 */ 0x394, '_', 0x3A6, 0x393, 0x39B, 0x3A9, 0x3A0, 0x3A8, /* 16 - 23 */ 0x3A3, 0x398, 0x39E, NRP, 0xC6, 0xE6, 0xDF, 0xC9, /* 24 - 31 */ ' ', '!', '"', '#', 0xA4, '%', '&', '\'', /* 32 - 39 */ '(', ')', '*', '+', ',', '-', '.', '/', /* 40 - 47 */ '0', '1', '2', '3', '4', '5', '6', '7', /* 48 - 55 */ '8', '9', ':', ';', '<', '=', '>', '?', /* 56 - 63 */ 0xA1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 64 - 71 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 73 - 79 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 80 - 87 */ 'X', 'Y', 'Z', 0xC4, 0xD6, 0xD1, 0xDC, 0xA7, /* 88 - 95 */ 0xBF, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 96 - 103 */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 104 - 111 */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 112 - 119 */ 'x', 'y', 'z', 0xE4, 0xF6, 0xF1, 0xFC, 0xE0 /* 120 - 127 */ }; /* * Register alises for Windows character sets that the libxml/libiconv can * recoqnise them. */ struct alias_t { char *real; char *alias; }; typedef struct alias_t alias_t; alias_t chars_aliases[] = { { "CP1250", "WIN-1250" }, { "CP1250", "WINDOWS-1250" }, { "CP1251", "WIN-1251" }, { "CP1251", "WINDOWS-1251" }, { "CP1252", "WIN-1252" }, { "CP1252", "WINDOWS-1252" }, { "CP1253", "WIN-1253" }, { "CP1253", "WINDOWS-1253" }, { "CP1254", "WIN-1254" }, { "CP1254", "WINDOWS-1254" }, { "CP1257", "WIN-1257" }, { "CP1257", "WINDOWS-1257" }, { NULL } }; void charset_init() { int i; for (i = 0; chars_aliases[i].real != NULL; i++) { xmlAddEncodingAlias(chars_aliases[i].real,chars_aliases[i].alias); /*debug("encoding",0,"Add encoding for %s",chars_aliases[i].alias);*/ } } void charset_shutdown() { xmlCleanupEncodingAliases(); } /** * Convert octet string in GSM format to UTF-8. * Every GSM character can be represented with unicode, hence nothing will * be lost. Escaped charaters will be translated into appropriate UTF-8 character. */ void charset_gsm_to_utf8(Octstr *ostr) { long pos, len; Octstr *newostr; if (ostr == NULL) return; newostr = octstr_create(""); len = octstr_len(ostr); for (pos = 0; pos < len; pos++) { int c, i; c = octstr_get_char(ostr, pos); if (c > 127) { warning(0, "Could not convert GSM (0x%02x) to Unicode.", c); continue; } if(c == 27 && pos + 1 < len) { c = octstr_get_char(ostr, ++pos); for (i = 0; gsm_esctouni[i].gsmesc >= 0; i++) { if (gsm_esctouni[i].gsmesc == c) break; } if (gsm_esctouni[i].gsmesc == c) { /* found a value for escaped char */ c = gsm_esctouni[i].unichar; } else { /* nothing found, look esc in our table */ c = gsm_to_unicode[27]; pos--; } } else if (c < 128) { c = gsm_to_unicode[c]; } /* unicode to utf-8 */ if(c < 128) { /* 0-127 are ASCII chars that need no conversion */ octstr_append_char(newostr, c); } else { /* test if it can be converterd into a two byte char */ if(c < 0x0800) { octstr_append_char(newostr, ((c >> 6) | 0xC0) & 0xFF); /* add 110xxxxx */ octstr_append_char(newostr, (c & 0x3F) | 0x80); /* add 10xxxxxx */ } else { /* else we encode with 3 bytes. This only happens in case of euro symbol */ octstr_append_char(newostr, ((c >> 12) | 0xE0) & 0xFF); /* add 1110xxxx */ octstr_append_char(newostr, (((c >> 6) & 0x3F) | 0x80) & 0xFF); /* add 10xxxxxx */ octstr_append_char(newostr, ((c & 0x3F) | 0x80) & 0xFF); /* add 10xxxxxx */ } /* There are no 4 bytes encoded characters in GSM charset */ } } octstr_truncate(ostr, 0); octstr_append(ostr, newostr); octstr_destroy(newostr); } /** * Convert octet string in UTF-8 format to GSM 03.38. * Because not all UTF-8 charater can be converted to GSM 03.38 non * convertable character replaces with NRP character (see define above). * Special characters will be formed into escape sequences. * Incomplete UTF-8 characters at the end of the string will be skipped. */ void charset_utf8_to_gsm(Octstr *ostr) { long pos, len; int val1, val2; Octstr *newostr; if (ostr == NULL) return; newostr = octstr_create(""); len = octstr_len(ostr); for (pos = 0; pos < len; pos++) { val1 = octstr_get_char(ostr, pos); /* check range */ if (val1 < 0 || val1 > 255) { warning(0, "Char (0x%02x) in UTF-8 string not in the range (0, 255). Skipped.", val1); continue; } /* Convert UTF-8 to unicode code */ /* test if two byte utf8 char */ if ((val1 & 0xE0) == 0xC0) { /* test if incomplete utf char */ if(pos + 1 < len) { val2 = octstr_get_char(ostr, ++pos); val1 = (((val1 & ~0xC0) << 6) | (val2 & 0x3F)); } else { /* incomplete, ignore it */ warning(0, "Incomplete UTF-8 char discovered, skipped. 1"); pos += 1; continue; } } else if ((val1 & 0xF0) == 0xE0) { /* test for three byte utf8 char */ if(pos + 2 < len) { val2 = octstr_get_char(ostr, ++pos); val1 = (((val1 & ~0xE0) << 6) | (val2 & 0x3F)); val2 = octstr_get_char(ostr, ++pos); val1 = (val1 << 6) | (val2 & 0x3F); } else { /* incomplete, ignore it */ warning(0, "Incomplete UTF-8 char discovered, skipped. 2"); pos += 2; continue; } } /* test Latin code page 1 char */ if(val1 <= 255) { val1 = latin1_to_gsm[val1]; /* needs to be escaped ? */ if(val1 < 0) { octstr_append_char(newostr, 27); val1 *= -1; } } else { /* Its not a Latin1 char, test for allowed GSM chars */ switch(val1) { case 0x394: val1 = 0x10; /* GREEK CAPITAL LETTER DELTA */ break; case 0x3A6: val1 = 0x12; /* GREEK CAPITAL LETTER PHI */ break; case 0x393: val1 = 0x13; /* GREEK CAPITAL LETTER GAMMA */ break; case 0x39B: val1 = 0x14; /* GREEK CAPITAL LETTER LAMBDA */ break; case 0x3A9: val1 = 0x15; /* GREEK CAPITAL LETTER OMEGA */ break; case 0x3A0: val1 = 0x16; /* GREEK CAPITAL LETTER PI */ break; case 0x3A8: val1 = 0x17; /* GREEK CAPITAL LETTER PSI */ break; case 0x3A3: val1 = 0x18; /* GREEK CAPITAL LETTER SIGMA */ break; case 0x398: val1 = 0x19; /* GREEK CAPITAL LETTER THETA */ break; case 0x39E: val1 = 0x1A; /* GREEK CAPITAL LETTER XI */ break; case 0x20AC: val1 = 'e'; /* EURO SIGN */ octstr_append_char(newostr, 27); break; default: val1 = NRP; /* character cannot be represented in GSM 03.38 */ } } octstr_append_char(newostr, val1); } octstr_truncate(ostr, 0); octstr_append(ostr, newostr); octstr_destroy(newostr); } void charset_gsm_to_latin1(Octstr *ostr) { long pos, len; len = octstr_len(ostr); for (pos = 0; pos < len; pos++) { int c, new, i; c = octstr_get_char(ostr, pos); if (c == 27 && pos + 1 < len) { /* GSM escape code. Delete it, then process the next * character specially. */ octstr_delete(ostr, pos, 1); len--; c = octstr_get_char(ostr, pos); for (i = 0; gsm_esctolatin1[i].gsmesc >= 0; i++) { if (gsm_esctolatin1[i].gsmesc == c) break; } if (gsm_esctolatin1[i].gsmesc == c) new = gsm_esctolatin1[i].latin1; else if (c < 128) new = gsm_to_latin1[c]; else continue; } else if (c < 128) { new = gsm_to_latin1[c]; } else { continue; } if (new != c) octstr_set_char(ostr, pos, new); } } void charset_latin1_to_gsm(Octstr *ostr) { long pos, len; int c, new; unsigned char esc = 27; len = octstr_len(ostr); for (pos = 0; pos < len; pos++) { c = octstr_get_char(ostr, pos); gw_assert(c >= 0); gw_assert(c <= 256); new = latin1_to_gsm[c]; if (new < 0) { /* Escaped GSM code */ octstr_insert_data(ostr, pos, (char*) &esc, 1); pos++; len++; new = -new; } if (new != c) octstr_set_char(ostr, pos, new); } } /* * This function is a wrapper arround charset_latin1_to_gsm() * which implements the mapping of a NRCs (national reprentation codes) * ISO 21 German. */ void charset_gsm_to_nrc_iso_21_german(Octstr *ostr) { long pos, len; int c, new; len = octstr_len(ostr); for (pos = 0; pos < len; pos++) { c = octstr_get_char(ostr, pos); switch (c) { /* GSM value; NRC value */ case 0x5b: new = 0x5b; break; /* Ä */ case 0x5c: new = 0x5c; break; /* Ö */ case 0x5e: new = 0x5d; break; /* Ü */ case 0x7b: new = 0x7b; break; /* ä */ case 0x7c: new = 0x7c; break; /* ö */ case 0x7e: new = 0x7d; break; /* ü */ case 0x1e: new = 0x7e; break; /* ß */ case 0x5f: new = 0x5e; break; /* § */ default: new = c; } if (new != c) octstr_set_char(ostr, pos, new); } } void charset_nrc_iso_21_german_to_gsm(Octstr *ostr) { long pos, len; int c, new; len = octstr_len(ostr); for (pos = 0; pos < len; pos++) { c = octstr_get_char(ostr, pos); switch (c) { /* NRC value; GSM value */ case 0x5b: new = 0x5b; break; /* Ä */ case 0x5c: new = 0x5c; break; /* Ö */ case 0x5d: new = 0x5e; break; /* Ü */ case 0x7b: new = 0x7b; break; /* ä */ case 0x7c: new = 0x7c; break; /* ö */ case 0x7d: new = 0x7e; break; /* ü */ case 0x7e: new = 0x1e; break; /* ß */ case 0x5e: new = 0x5f; break; /* § */ default: new = c; } if (new != c) octstr_set_char(ostr, pos, new); } } int charset_gsm_truncate(Octstr *gsm, long max) { if (octstr_len(gsm) > max) { /* If the last GSM character was an escaped character, * then chop off the escape as well as the character. */ if (octstr_get_char(gsm, max - 1) == 27) octstr_truncate(gsm, max - 1); else octstr_truncate(gsm, max); return 1; } return 0; } int charset_to_utf8(Octstr *from, Octstr **to, Octstr *charset_from) { int ret; xmlCharEncodingHandlerPtr handler = NULL; xmlBufferPtr frombuffer = NULL; xmlBufferPtr tobuffer = NULL; if (octstr_compare(charset_from, octstr_imm("UTF-8")) == 0) { *to = octstr_duplicate(from); return 0; } handler = xmlFindCharEncodingHandler(octstr_get_cstr(charset_from)); if (handler == NULL) return -2; /* Build the libxml buffers for the transcoding. */ tobuffer = xmlBufferCreate(); frombuffer = xmlBufferCreate(); xmlBufferAdd(frombuffer, (unsigned char*)octstr_get_cstr(from), octstr_len(from)); ret = xmlCharEncInFunc(handler, tobuffer, frombuffer); *to = octstr_create_from_data((char*)tobuffer->content, tobuffer->use); /* Memory cleanup. */ xmlBufferFree(tobuffer); xmlBufferFree(frombuffer); return ret; } int charset_from_utf8(Octstr *utf8, Octstr **to, Octstr *charset_to) { int ret; xmlCharEncodingHandlerPtr handler = NULL; xmlBufferPtr frombuffer = NULL; xmlBufferPtr tobuffer = NULL; handler = xmlFindCharEncodingHandler(octstr_get_cstr(charset_to)); if (handler == NULL) return -2; /* Build the libxml buffers for the transcoding. */ tobuffer = xmlBufferCreate(); frombuffer = xmlBufferCreate(); xmlBufferAdd(frombuffer, (unsigned char*)octstr_get_cstr(utf8), octstr_len(utf8)); ret = xmlCharEncOutFunc(handler, tobuffer, frombuffer); if (ret < -2) /* Libxml seems to be here a little uncertain what would be the * return code -3, so let's make it -1. Ugly thing, indeed. --tuo */ ret = -1; *to = octstr_create_from_data((char*)tobuffer->content, tobuffer->use); /* Memory cleanup. */ xmlBufferFree(tobuffer); xmlBufferFree(frombuffer); return ret; } int charset_convert(Octstr* string, char* charset_from, char* charset_to) { #if HAVE_ICONV char *from_buf, *to_buf, *pointer; size_t inbytesleft, outbytesleft, ret; iconv_t cd; if (!charset_from || !charset_to || !string) /* sanity check */ return -1; if (octstr_len(string) < 1 || strcasecmp(charset_from, charset_to) == 0) return 0; /* we are done, nothing to convert */ cd = iconv_open(charset_to, charset_from); /* Did I succeed in getting a conversion descriptor ? */ if (cd == (iconv_t)(-1)) { /* I guess not */ error(0,"Failed to convert string from <%s> to <%s> - probably broken type names.", charset_from, charset_to); return -1; } from_buf = octstr_get_cstr(string); inbytesleft = octstr_len(string); /* allocate max sized buffer, assuming target encoding may be 4 byte unicode */ outbytesleft = inbytesleft * 4; pointer = to_buf = gw_malloc(outbytesleft); do { ret = iconv(cd, (ICONV_CONST char**) &from_buf, &inbytesleft, &pointer, &outbytesleft); if(ret == -1) { long tmp; /* the conversion failed somewhere */ switch(errno) { case E2BIG: /* no space in output buffer */ debug("charset", 0, "outbuf to small, realloc."); tmp = pointer - to_buf; to_buf = gw_realloc(to_buf, tmp + inbytesleft * 4); outbytesleft += inbytesleft * 4; pointer = to_buf + tmp; ret = 0; break; case EILSEQ: /* invalid multibyte sequence */ case EINVAL: /* incomplete multibyte sequence */ warning(0, "Invalid/Incomplete multibyte sequence at position %d, skeep it.", (int)(from_buf - octstr_get_cstr(string))); /* skeep char and try next */ if (outbytesleft == 0) { /* buffer to small */ tmp = pointer - to_buf; to_buf = gw_realloc(to_buf, tmp + inbytesleft * 4); outbytesleft += inbytesleft * 4; pointer = to_buf + tmp; } pointer[0] = from_buf[0]; pointer++; from_buf++; inbytesleft--; outbytesleft--; ret = 0; break; } } } while(inbytesleft && ret == 0); /* stop if error occurs and not handled above */ iconv_close(cd); if (ret != -1) { /* conversion succeeded */ octstr_truncate(string, 0); octstr_append_data(string, to_buf, pointer - to_buf); if (ret) debug("charset", 0, "charset_convert did %ld non-reversible conversions", (long) ret); ret = 0; } else error(errno,"Failed to convert string from <%s> to <%s>.", charset_from, charset_to); if (errno == EILSEQ) { debug("charset_convert", 0, "Found an invalid multibyte sequence at position <%d>", (int)(from_buf - octstr_get_cstr(string))); } gw_free(to_buf); return ret; #endif /* no convertion done due to not having iconv */ return -1; } gateway-1.4.5/gwlib/mime.h0000644000175000017500000001562213227613126014101 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * mime.h - Implement MIME multipart/related handling * * References: * RFC 2387 (The MIME Multipart/Related Content-type) * RFC 2025 (Multipurpose Internet Mail Extensions [MIME]) * * Here we implement generic parsing functions to handle MIME multipart/related * messages. Our representation is made by the struct MIMEEntity where each * entity of the MIME scope is hold. Every entity should at least have headers. * If the body is a "normal" content-type, then it is stored in Octstr *body. * if the body is a sub-MIME multipart/related again, then it's single entities * are parsed and chained into the List *multiparts. Hence items in the list * are of type MIMEEntity again. We result in a recursive linked represenation * of the MIME multipart/related structure. * * We know about two various multipart types: * multipart/mixed - where no "order" is associated among the entities * multipart/related - where the "start" parameter in the Content-Type defines * the semantically main processing entitiy in the set. * * In order to provide a mapping facility between the MIMEEntity representation * and an Octstr that holds the MIME document we have the two major functions * mime_octstr_to_entity() and mime_entity_to_octstr() that act as converters. * * Using the MIMEEntity representation structure it is easier to handle the * subsequent MIME entities in case we have a cubed structure in the document. * * Stipe Tolj */ #ifndef MIME_H #define MIME_H #include "gwlib/gwlib.h" /* Define an generic MIME entity structure to be * used for MIME multipart parsing. */ typedef struct MIMEEntity MIMEEntity; /* create and destroy MIME multipart entity */ MIMEEntity *mime_entity_create(void); void mime_entity_destroy(MIMEEntity *e); /* make a copy of a MIME object. */ MIMEEntity *mime_entity_duplicate(MIMEEntity *e); /* Replace top-level MIME headers: Old ones removed completetly */ void mime_replace_headers(MIMEEntity *e, List *headers); /* Get number of body parts. Returns 0 if this is not * a multipart object. */ int mime_entity_num_parts(MIMEEntity *e); /* Append a new part to list of body parts. Copy is made*/ void mime_entity_add_part(MIMEEntity *e, MIMEEntity *part); /* Get part i in list of body parts. Copy is made*/ MIMEEntity *mime_entity_get_part(MIMEEntity *e, int i); /* Replace part i in list of body parts. Old one will be deleted */ void mime_entity_replace_part(MIMEEntity *e, int i, MIMEEntity *newpart); /* Remove part i in list of body parts. */ void mime_entity_remove_part(MIMEEntity *e, int i); /* Change body element of non-multipart entity. */ void mime_entity_set_body(MIMEEntity *e, Octstr *body); /* Returns (copy of) the 'start' element of a multi-part entity. */ MIMEEntity *mime_multipart_start_elem(MIMEEntity *e); /* * Parse the given Octstr that contains a normative text representation * of the MIME multipart document into our representation strucuture. * Will return parts of it in case an error occures in the recursive * call, otherwise will return NULL in case of a fatal error while parsing. */ MIMEEntity *mime_octstr_to_entity(Octstr *mime); /* * Parse the given List (HTTP hedaer) and Octstr (HTTP body) and create * a MIME multipart representatin if possible. Return NULL if parsing fails. */ MIMEEntity *mime_http_to_entity(List *headers, Octstr *body); /* * Convert a given MIME multipart representation structure to * it's Octstr counterpart and return it. Will return parts of it, * in case an error occures in a deeper level, otherwise a NULL * is return in case of a fatal error while convertion. */ Octstr *mime_entity_to_octstr(MIMEEntity *m); /* * Take a MIME multipart representation and return the global header * for it. Return a pointer to a HTTP header List. */ List *mime_entity_headers(MIMEEntity *m); /* * Take a MIME multipart representation and return the highest level * body encoded to an Octstr to tbe used as HTTP POST body. * Rerturns an Octstr with the body. */ Octstr *mime_entity_body(MIMEEntity *m); /* * Dump the structure (hicharchical view) of the MIME representation * structure into our DEBUG log level facility. */ void mime_entity_dump(MIMEEntity *m); #endif gateway-1.4.5/gwlib/gw_uuid.h0000644000175000017500000000301310253521766014610 0ustar toljtolj/* * Public include file for the UUID library * * Copyright (C) 1996, 1997, 1998 Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU * Library General Public License. * %End-Header% */ #ifndef _UUID_UUID_H #define _UUID_UUID_H #include #include #include #define UUID_STR_LEN 36 #ifdef DARWIN #ifndef _POSIX_C_SOURCE #ifndef _UUID_T #define _UUID_T typedef __darwin_uuid_t uuid_t; #endif /* _UUID_T */ #endif /* _POSIX_C_SOURCE */ #else typedef unsigned char uuid_t[16]; #endif /* UUID Variant definitions */ #define UUID_VARIANT_NCS 0 #define UUID_VARIANT_DCE 1 #define UUID_VARIANT_MICROSOFT 2 #define UUID_VARIANT_OTHER 3 #ifdef __cplusplus extern "C" { #endif /* initialize uuid library */ void uuid_init(void); /* shutdown uuid library */ void uuid_shutdown(void); /* clear.c */ void uuid_clear(uuid_t uu); /* compare.c */ int uuid_compare(const uuid_t uu1, const uuid_t uu2); /* copy.c */ void uuid_copy(uuid_t dst, const uuid_t src); /* gen_uuid.c */ void uuid_generate(uuid_t out); void uuid_generate_random(uuid_t out); void uuid_generate_time(uuid_t out); /* isnull.c */ int uuid_is_null(const uuid_t uu); /* parse.c */ int uuid_parse(const char *in, uuid_t uu); /* unparse.c */ void uuid_unparse(const uuid_t uu, char *out); /* uuid_time.c */ time_t uuid_time(const uuid_t uu, struct timeval *ret_tv); int uuid_type(const uuid_t uu); int uuid_variant(const uuid_t uu); #ifdef __cplusplus } #endif #endif /* _UUID_UUID_H */ gateway-1.4.5/gwlib/cfg.c0000644000175000017500000006066413227613126013712 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * cfg.c - configuration file handling * * Lars Wirzenius */ #include "gwlib/gwlib.h" /* for include dir */ #include #include #include #include #include struct CfgGroup { Octstr *name; Dict *vars; Octstr *configfile; long line; }; static CfgGroup *create_group(void) { CfgGroup *grp; grp = gw_malloc(sizeof(*grp)); grp->name = NULL; grp->vars = dict_create(64, octstr_destroy_item); grp->configfile = NULL; grp->line = 0; return grp; } static void destroy_group(void *arg) { CfgGroup *grp; if (arg != NULL) { grp = arg; octstr_destroy(grp->name); octstr_destroy(grp->configfile); dict_destroy(grp->vars); gw_free(grp); } } struct CfgLoc { Octstr *filename; long line_no; Octstr *line; }; static CfgLoc *cfgloc_create(Octstr *filename) { CfgLoc *cfgloc; cfgloc = gw_malloc(sizeof(*cfgloc)); cfgloc->filename = octstr_duplicate(filename); cfgloc->line_no = 0; cfgloc->line = NULL; return cfgloc; } static void cfgloc_destroy(CfgLoc *cfgloc) { if (cfgloc != NULL) { octstr_destroy(cfgloc->filename); octstr_destroy(cfgloc->line); gw_free(cfgloc); } } static void destroy_group_list(void *arg) { gwlist_destroy(arg, destroy_group); } static void set_group_name(CfgGroup *grp, Octstr *name) { octstr_destroy(grp->name); grp->name = octstr_duplicate(name); } static int octstr_sort_cb(const void *a, const void *b) { const Octstr *fa = a; const Octstr *fb = b; return octstr_compare(fa, fb); } static int octstr_cmp_cb(void *a, void *b) { return (octstr_compare((Octstr*)a, (Octstr*)b) == 0); } struct Cfg { Octstr *filename; Dict *single_groups; Dict *multi_groups; }; /******************************************************************** * Section providing hooks to external modules to apply their specific * is_allowed_in_group() and is_single_group() with their own * foobar-cfg.def. */ static List *allowed_hooks; static List *single_hooks; static int core_is_allowed_in_group(Octstr *group, Octstr *variable) { Octstr *groupstr; groupstr = octstr_imm("group"); #define OCTSTR(name) \ if (octstr_compare(octstr_imm(#name), variable) == 0) \ return 1; #define SINGLE_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), group) == 0) { \ if (octstr_compare(groupstr, variable) == 0) \ return 1; \ fields \ return 0; \ } #define MULTI_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), group) == 0) { \ if (octstr_compare(groupstr, variable) == 0) \ return 1; \ fields \ return 0; \ } #include "cfg.def" /* unknown group identifier */ return -1; } static int core_is_single_group(Octstr *query) { #define OCTSTR(name) #define SINGLE_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), query) == 0) \ return 1; #define MULTI_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), query) == 0) \ return 0; #include "cfg.def" return 0; } static int is_allowed_in_group(Octstr *group, Octstr *variable) { long i; int x, r = -1; for (i = 0; i < gwlist_len(allowed_hooks); ++i) { x = ((int(*)(Octstr *, Octstr *)) gwlist_get(allowed_hooks, i))(group, variable); r = (x == -1 ? (r == -1 ? x : r) : (r == -1 ? x : r + x)); } return r; } static int is_single_group(Octstr *query) { long i; int r = 0; for (i = 0; i < gwlist_len(single_hooks); ++i) { r += ((int(*)(Octstr *)) gwlist_get(single_hooks, i))(query); } return (r > 0); } void cfg_add_hooks(void *allowed, void *single) { gwlist_append(allowed_hooks, allowed); gwlist_append(single_hooks, single); } static int add_group(Cfg *cfg, CfgGroup *grp) { Octstr *groupname; Octstr *name; List *names; List *list; groupname = cfg_get(grp, octstr_imm("group")); if (groupname == NULL) { error(0, "Group does not contain variable 'group'."); return -1; } set_group_name(grp, groupname); names = dict_keys(grp->vars); while ((name = gwlist_extract_first(names)) != NULL) { int a = is_allowed_in_group(groupname, name); switch (a) { case 0: error(0, "Group '%s' may not contain field '%s'.", octstr_get_cstr(groupname), octstr_get_cstr(name)); octstr_destroy(name); octstr_destroy(groupname); gwlist_destroy(names, octstr_destroy_item); return -1; break; case -1: error(0, "Group '%s' is no valid group identifier.", octstr_get_cstr(groupname)); octstr_destroy(name); octstr_destroy(groupname); gwlist_destroy(names, octstr_destroy_item); return -1; break; default: octstr_destroy(name); break; } } gwlist_destroy(names, NULL); if (is_single_group(groupname)) { dict_put(cfg->single_groups, groupname, grp); } else { list = dict_get(cfg->multi_groups, groupname); if (list == NULL) { list = gwlist_create(); dict_put(cfg->multi_groups, groupname, list); } gwlist_append(list, grp); } octstr_destroy(groupname); return 0; } Cfg *cfg_create(Octstr *filename) { Cfg *cfg; cfg = gw_malloc(sizeof(*cfg)); cfg->filename = octstr_duplicate(filename); cfg->single_groups = dict_create(64, destroy_group); cfg->multi_groups = dict_create(64, destroy_group_list); return cfg; } void cfg_destroy(Cfg *cfg) { if (cfg != NULL) { octstr_destroy(cfg->filename); dict_destroy(cfg->single_groups); dict_destroy(cfg->multi_groups); gw_free(cfg); } } static void parse_value(Octstr *value) { Octstr *temp; long len; int c; octstr_strip_blanks(value); len = octstr_len(value); if (octstr_get_char(value, 0) != '"' || octstr_get_char(value, len - 1) != '"') return; octstr_delete(value, len - 1, 1); octstr_delete(value, 0, 1); temp = octstr_duplicate(value); octstr_truncate(value, 0); while (octstr_len(temp) > 0) { c = octstr_get_char(temp, 0); octstr_delete(temp, 0, 1); if (c != '\\' || octstr_len(temp) == 0) octstr_append_char(value, c); else { c = octstr_get_char(temp, 0); octstr_delete(temp, 0, 1); switch (c) { case '\\': case '"': octstr_append_char(value, c); break; default: octstr_append_char(value, '\\'); octstr_append_char(value, c); break; } } } octstr_destroy(temp); } static List *expand_file(Octstr *file, int forward) { Octstr *os; Octstr *line; List *lines; List *expand; long lineno; CfgLoc *loc = NULL; os = octstr_read_file(octstr_get_cstr(file)); if (os == NULL) return NULL; lines = octstr_split(os, octstr_imm("\n")); lineno = 0; expand = gwlist_create(); while ((line = gwlist_extract_first(lines)) != NULL) { if (loc == NULL) { ++lineno; loc = cfgloc_create(file); loc->line_no = lineno; loc->line = octstr_create(""); if (forward) gwlist_append(expand, loc); else gwlist_insert(expand, 0, loc); } /* check for escape and then add to existing loc */ if (octstr_get_char(line, octstr_len(line) - 1) == '\\') { octstr_delete(line, octstr_len(line) - 1, 1); octstr_append(loc->line, line); /* check for second escape */ if (octstr_get_char(line, octstr_len(line) - 1) == '\\') loc = NULL; } else { octstr_append(loc->line, line); loc = NULL; } octstr_destroy(line); } /* * add newline at each end of included files to avoid * concatenating different groups by mistake */ if (lineno > 0) { loc = cfgloc_create(file); loc->line_no = lineno; loc->line = octstr_create("\n"); if (forward) gwlist_append(expand, loc); else gwlist_insert(expand, 0, loc); } gwlist_destroy(lines, octstr_destroy_item); octstr_destroy(os); return expand; } int cfg_read(Cfg *cfg) { CfgLoc *loc; CfgLoc *loc_inc; List *lines; List *expand; List *stack; Octstr *name; Octstr *value; Octstr *filename; CfgGroup *grp; long equals; long error_lineno; loc = loc_inc = NULL; /* * expand initial main config file and add it to the recursion * stack to protect against cycling */ if ((lines = expand_file(cfg->filename, 1)) == NULL) { panic(0, "Failed to load main configuration file `%s'. Aborting!", octstr_get_cstr(cfg->filename)); } stack = gwlist_create(); gwlist_insert(stack, 0, octstr_duplicate(cfg->filename)); grp = NULL; error_lineno = 0; while (error_lineno == 0 && (loc = gwlist_extract_first(lines)) != NULL) { octstr_strip_blanks(loc->line); if (octstr_len(loc->line) == 0) { if (grp != NULL && add_group(cfg, grp) == -1) { error_lineno = loc->line_no; destroy_group(grp); } grp = NULL; } else if (octstr_get_char(loc->line, 0) != '#') { equals = octstr_search_char(loc->line, '=', 0); if (equals == -1) { error(0, "An equals sign ('=') is missing on line %ld of file %s.", loc->line_no, octstr_get_cstr(loc->filename)); error_lineno = loc->line_no; } else /* * check for special config directives, like include or conditional * directives here */ if (octstr_search(loc->line, octstr_imm("include"), 0) != -1) { filename = octstr_copy(loc->line, equals + 1, octstr_len(loc->line)); parse_value(filename); /* check if we are cycling */ if (gwlist_search(stack, filename, octstr_item_match) != NULL) { panic(0, "Recursive include for config file `%s' detected " "(on line %ld of file %s).", octstr_get_cstr(filename), loc->line_no, octstr_get_cstr(loc->filename)); } else { List *files = gwlist_create(); Octstr *file; struct stat filestat; /* check if included file is a directory */ if (lstat(octstr_get_cstr(filename), &filestat) != 0) { error(errno, "lstat failed: couldn't stat `%s'", octstr_get_cstr(filename)); panic(0, "Failed to include `%s' " "(on line %ld of file %s). Aborting!", octstr_get_cstr(filename), loc->line_no, octstr_get_cstr(loc->filename)); } /* * is a directory, create a list with files of * this directory and load all as part of the * whole configuration. */ if (S_ISDIR(filestat.st_mode)) { DIR *dh; struct dirent *diritem; debug("gwlib.cfg", 0, "Loading include dir `%s' " "(on line %ld of file %s).", octstr_get_cstr(filename), loc->line_no, octstr_get_cstr(loc->filename)); dh = opendir(octstr_get_cstr(filename)); while ((diritem = readdir(dh))) { Octstr *fileitem; fileitem = octstr_duplicate(filename); octstr_append_cstr(fileitem, "/"); octstr_append_cstr(fileitem, diritem->d_name); lstat(octstr_get_cstr(fileitem), &filestat); if (!S_ISDIR(filestat.st_mode)) { gwlist_insert(files, 0, fileitem); } else { octstr_destroy(fileitem); } } closedir(dh); } /* is a file, create a list with it */ else { gwlist_insert(files, 0, octstr_duplicate(filename)); } /* include files */ while ((file = gwlist_extract_first(files)) != NULL) { gwlist_insert(stack, 0, octstr_duplicate(file)); debug("gwlib.cfg", 0, "Loading include file `%s' (on line %ld of file %s).", octstr_get_cstr(file), loc->line_no, octstr_get_cstr(loc->filename)); /* * expand the given include file and add it to the current * processed main while loop */ if ((expand = expand_file(file, 0)) != NULL) { while ((loc_inc = gwlist_extract_first(expand)) != NULL) gwlist_insert(lines, 0, loc_inc); } else { panic(0, "Failed to load whole configuration. Aborting!"); } gwlist_destroy(expand, NULL); cfgloc_destroy(loc_inc); octstr_destroy(file); } gwlist_destroy(files, octstr_destroy_item); } octstr_destroy(filename); } /* * this is a "normal" line, so process it accodingly */ else { name = octstr_copy(loc->line, 0, equals); octstr_strip_blanks(name); value = octstr_copy(loc->line, equals + 1, octstr_len(loc->line)); parse_value(value); if (grp == NULL) grp = create_group(); if (grp->configfile != NULL) { octstr_destroy(grp->configfile); grp->configfile = NULL; } grp->configfile = octstr_duplicate(cfg->filename); cfg_set(grp, name, value); octstr_destroy(name); octstr_destroy(value); } } cfgloc_destroy(loc); } if (grp != NULL && add_group(cfg, grp) == -1) { error_lineno = 1; destroy_group(grp); } gwlist_destroy(lines, NULL); gwlist_destroy(stack, octstr_destroy_item); if (error_lineno != 0) { error(0, "Error found on line %ld of file `%s'.", error_lineno, octstr_get_cstr(cfg->filename)); return -1; } return 0; } CfgGroup *cfg_get_single_group(Cfg *cfg, Octstr *name) { return dict_get(cfg->single_groups, name); } List *cfg_get_multi_group(Cfg *cfg, Octstr *name) { List *list, *copy; long i; list = dict_get(cfg->multi_groups, name); if (list == NULL) return NULL; copy = gwlist_create(); for (i = 0; i < gwlist_len(list); ++i) gwlist_append(copy, gwlist_get(list, i)); return copy; } Octstr *cfg_get_group_name(CfgGroup *grp) { return octstr_duplicate(grp->name); } Octstr *cfg_get_group_checksum(CfgGroup *grp, ...) { va_list args; Octstr *ret, *os, *key, *val; List *exclude, *keys; exclude = gwlist_create(); /* * Variadic Octstr* arguments may contain the * config key names that DO NOT go into the * checksum computation. This allows differential * compares and detection of single changes. */ va_start(args, grp); while ((os = va_arg(args, Octstr*)) != NULL) { gwlist_append(exclude, os); } va_end(args); /* all configured config names of this group */ keys = dict_keys(grp->vars); /* remove all excluded configs names */ while ((os = gwlist_extract_first(exclude)) != NULL) { if ((key = gwlist_search(keys, os, octstr_cmp_cb)) != NULL) { if (gwlist_delete_equal(keys, key) != 1) panic(0, "%s: multiple config variables with same name `%s'?!", __func__, octstr_get_cstr(key)); octstr_destroy(key); } } gwlist_destroy(exclude, NULL); os = octstr_duplicate(grp->name); gwlist_sort(keys, octstr_sort_cb); while ((key = gwlist_extract_first(keys)) != NULL) { octstr_append(os, key); if ((val = dict_get(grp->vars, key)) != NULL) octstr_append(os, val); octstr_destroy(key); } gwlist_destroy(keys, NULL); ret = md5(os); octstr_destroy(os); return ret; } Octstr *cfg_get_configfile(CfgGroup *grp) { return octstr_duplicate(grp->configfile); } Octstr *cfg_get_real(CfgGroup *grp, Octstr *varname, const char *file, long line, const char *func) { Octstr *os; if(grp == NULL) panic(0, "Trying to fetch variable `%s' in non-existing group", octstr_get_cstr(varname)); if (grp->name != NULL && !is_allowed_in_group(grp->name, varname)) panic(0, "Trying to fetch variable `%s' in group `%s', not allowed.", octstr_get_cstr(varname), octstr_get_cstr(grp->name)); os = dict_get(grp->vars, varname); if (os == NULL) return NULL; return gw_claim_area_for(octstr_duplicate(os), file, line, func); } int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname) { Octstr *os; int ret; os = cfg_get(grp, varname); if (os == NULL) return -1; if (octstr_parse_long(n, os, 0, 0) == -1) ret = -1; else ret = 0; octstr_destroy(os); return ret; } int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname) { Octstr *os; os = cfg_get(grp, varname); if (os == NULL) { *n = 0; return -1; } if (octstr_case_compare(os, octstr_imm("true")) == 0 || octstr_case_compare(os, octstr_imm("yes")) == 0 || octstr_case_compare(os, octstr_imm("on")) == 0 || octstr_case_compare(os, octstr_imm("1")) == 0) { *n = 1; } else if (octstr_case_compare(os, octstr_imm("false")) == 0 || octstr_case_compare(os, octstr_imm("no")) == 0 || octstr_case_compare(os, octstr_imm("off")) == 0 || octstr_case_compare(os, octstr_imm("0")) == 0) { *n = 0; } else { *n = 1; warning(0, "bool variable set to strange value, assuming 'true'"); } octstr_destroy(os); return 0; } List *cfg_get_list(CfgGroup *grp, Octstr *varname) { Octstr *os; List *list; os = cfg_get(grp, varname); if (os == NULL) return NULL; list = octstr_split_words(os); octstr_destroy(os); return list; } void cfg_set(CfgGroup *grp, Octstr *varname, Octstr *value) { dict_put(grp->vars, varname, octstr_duplicate(value)); } void grp_dump(CfgGroup *grp) { List *names; Octstr *name; Octstr *value; if (grp->name == NULL) debug("gwlib.cfg", 0, " dumping group (name not set):"); else debug("gwlib.cfg", 0, " dumping group (%s):", octstr_get_cstr(grp->name)); names = dict_keys(grp->vars); while ((name = gwlist_extract_first(names)) != NULL) { value = cfg_get(grp, name); debug("gwlib.cfg", 0, " <%s> = <%s>", octstr_get_cstr(name), octstr_get_cstr(value)); octstr_destroy(value); octstr_destroy(name); } gwlist_destroy(names, NULL); } void cfg_dump(Cfg *cfg) { CfgGroup *grp; List *list; List *names; Octstr *name; debug("gwlib.cfg", 0, "Dumping Cfg %p", (void *) cfg); debug("gwlib.cfg", 0, " filename = <%s>", octstr_get_cstr(cfg->filename)); names = dict_keys(cfg->single_groups); while ((name = gwlist_extract_first(names)) != NULL) { grp = cfg_get_single_group(cfg, name); if (grp != NULL) grp_dump(grp); octstr_destroy(name); } gwlist_destroy(names, NULL); names = dict_keys(cfg->multi_groups); while ((name = gwlist_extract_first(names)) != NULL) { list = cfg_get_multi_group(cfg, name); while ((grp = gwlist_extract_first(list)) != NULL) grp_dump(grp); gwlist_destroy(list, NULL); octstr_destroy(name); } gwlist_destroy(names, NULL); debug("gwlib.cfg", 0, "Dump ends."); } void cfg_dump_all(void) { #define OCTSTR(name) \ printf("%s = \n", #name); #define SINGLE_GROUP(name, fields) \ printf("#\n# Single Group\n#\n"); \ printf("group = %s\n", #name); \ fields; \ printf("\n\n"); #define MULTI_GROUP(name, fields) \ printf("#\n# Multi Group\n#\n"); \ printf("group = %s\n", #name); \ fields; \ printf("\n\n"); #include "cfg.def" } void cfg_init(void) { /* make sure we put our own core hooks into the lists */ allowed_hooks = gwlist_create(); single_hooks = gwlist_create(); gwlist_append(allowed_hooks, &core_is_allowed_in_group); gwlist_append(single_hooks, &core_is_single_group); } void cfg_shutdown(void) { gwlist_destroy(allowed_hooks, NULL); gwlist_destroy(single_hooks, NULL); allowed_hooks = single_hooks = NULL; } gateway-1.4.5/gwlib/gwthread.h0000644000175000017500000001631113227613126014753 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwthread.h - threads wrapper with interruptible sleep and poll operations. * * This is a (partial) encapsulation of threads. It provides functions * to create new threads and to manipulate threads. It will eventually * be extended to encapsulate all pthread functions we use, so that * non-POSIX platforms can plug in their own versions. * * Richard Braakman */ #ifndef GWTHREAD_H #define GWTHREAD_H #include "gw-config.h" #ifdef HAVE_SYS_POLL_H #include #endif /* gwthread_self() must return this value for the main thread. */ #define MAIN_THREAD_ID 0 typedef void gwthread_func_t(void *arg); /* Called by the gwlib init code */ void gwthread_init(void); void gwthread_shutdown(void); /* Start a new thread, running func(arg). Return the new thread ID * on success, or -1 on failure. Thread IDs are unique during the lifetime * of the entire process, unless you use more than LONG_MAX threads. */ long gwthread_create_real(gwthread_func_t *func, const char *funcname, void *arg); #define gwthread_create(func, arg) \ (gwthread_create_real(func, __FILE__ ":" #func, arg)) /* Wait for the other thread to terminate. Return immediately if it * has already terminated. */ void gwthread_join(long thread); /* Wait for all threads whose main function is `func' to terminate. * Return immediately if none are running. */ void gwthread_join_every(gwthread_func_t *func); /* Wait for all threads to terminate. Return immediately if none * are running. This function is not intended to be called if new * threads are still being created, and it may not notice such threads. */ void gwthread_join_all(void); /* Return the thread id of this thread. Note that it may be called for * the main thread even before the gwthread library has been initialized * and after it had been shut down. */ long gwthread_self(void); /* Same as above, but returns the process id (pid) of the thread. */ long gwthread_self_pid(void); /* Same as gwthread_self() and gwthread_self_pid() combined to one void * call. Returns the internal thread id and the process id. */ void gwthread_self_ids(long *tid, long *pid); /* If the other thread is currently in gwthread_pollfd or gwthread_sleep, * make it return immediately. Otherwise, make it return immediately, the * next time it calls one of those functions. */ void gwthread_wakeup(long thread); /* Wake up all threads */ void gwthread_wakeup_all(void); /* Wrapper around the poll() system call, for one file descriptor. * "events" is a set of the flags defined in , usually * POLLIN, POLLOUT, or (POLLIN|POLLOUT). Return when one of the * events is true, or when another thread calls gwthread_wakeup on us, or * when the timeout expires. The timeout is specified in seconds, * and a negative value means do not time out. Return the revents * structure filled in by poll() for this fd. Return -1 if something * went wrong. */ int gwthread_pollfd(int fd, int events, double timeout); /* Wrapper around the poll() system call, for an array of file * descriptors. The difference with normal poll is that the * thread can be woken up with gwthread_wakeup. timeout is in seconds. */ /* NOTE: This interface will probably change in the future, because currently * it is hard to implement efficiently. */ int gwthread_poll(struct pollfd *fds, long numfds, double timeout); /* Sleep until "seconds" seconds have elapsed, or until another thread * calls gwthread_wakeup on us. Fractional seconds are allowed. */ void gwthread_sleep(double seconds); /* Sleep until "seconds" seconds have elapsed, or until another thread * calls gwthread_wakeup on us. Fractional seconds are allowed. */ void gwthread_sleep_micro(double dseconds); /* Force a specific thread to terminate. Returns 0 on success, -1 if the * thread has been terminated while calling and non-zero for the pthread * specific error code. */ int gwthread_cancel(long thread); /* * Check wheather this thread should handle the given signal. * Since signals are thread specific, this needs to be handled * by the thread code here. This is mostly to cope with * "interesting" implementations of "pthreads" */ int gwthread_shouldhandlesignal(int signal); /* Dump the current signal mask for this thread. This will print out a * set of debug messages that state the signal handling status for the * first 32 signals on the current system. Return -1 if something goes * wrong. * * Debugging purposes mostly so it can be ignored on platforms * where this isn't applicable. */ int gwthread_dumpsigmask(void); #endif gateway-1.4.5/gwlib/counter.h0000644000175000017500000001007213227613126014623 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwlib/counter.h - a counter object * * Kannel has monotonously growing counters in some places, and these need * to work even when several threads use them. This header defines the * type Counter that provides such a counter. The counter is a long, and * if it reaches LONG_MAX, it wraps around to zero (_NOT_ LONG_MIN). * * Lars Wirzenius. * * Changed the counter type 'long' into 'unsigned long' so it wraps * by itself. Just keep increasing it. * Also added a counter_increase_with function. * harrie@lisanza.net */ #ifndef COUNTER_H #define COUNTER_H typedef struct Counter Counter; /* create a new counter object. PANIC if fails */ Counter *counter_create(void); /* destroy it */ void counter_destroy(Counter *counter); /* return the current value of the counter and increase counter by one */ unsigned long counter_increase(Counter *counter); /* return the current value of the counter and increase counter by value */ unsigned long counter_increase_with(Counter *counter, unsigned long value); /* return the current value of the counter */ unsigned long counter_value(Counter *counter); /* return the current value of the counter and decrease counter by one */ unsigned long counter_decrease(Counter *counter); /* return the current value of the counter and set it to the supplied value */ unsigned long counter_set(Counter *, unsigned long); #endif gateway-1.4.5/gwlib/gwlib.h0000644000175000017500000000765513227613126014265 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwlib.h - public interface to gwlib * * This is general header file to include all gwlib subparts. * As they are usually all needed, this eases the need of * lots of includes in modules * * Kalle Marjola for WapIT Ltd 1999 */ #ifndef GWLIB_H #define GWLIB_H #include #include #include #include "gw-config.h" #include "gw-getopt.h" #include "gwpoll.h" #include "utils.h" #include "log.h" #include "thread.h" #include "gwthread.h" #include "gwmem.h" #include "socket.h" #include "cfg.h" #include "date.h" #include "http.h" #include "octstr.h" #include "list.h" #include "fdset.h" #include "gwassert.h" #include "counter.h" #include "charset.h" #include "conn.h" #include "ssl.h" #include "parse.h" #include "protected.h" #include "accesslog.h" #include "dict.h" #include "semaphore.h" #include "xmlrpc.h" #include "md5.h" #include "gw_uuid.h" #include "gw-rwlock.h" #include "gw-prioqueue.h" void gwlib_assert_init(void); void gwlib_init(void); void gwlib_shutdown(void); int gwlib_initialized(void); #ifdef NO_GWASSERT #define gwlib_assert_init() ((void) 0) #endif #ifndef HAVE_STRTOLL #undef strtoll #ifdef HAVE_STRTOQ #define strtoll(A,B,C) strtoq((A),(B),(C)) #endif #endif #endif gateway-1.4.5/gwlib/gwmem.h0000644000175000017500000001513313227613126014263 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gwmem.h * * This is a simple malloc()-wrapper. It does not return NULLs but * instead panics. * * We have two wrappers. One that just checks for allocation failures and * panics if they happen and one that tries to find allocation problems, * such as using an area after it has been freed. * * Kalle Marjola * Lars Wirzenius */ #ifndef GWMEM_H #define GWMEM_H void *gw_native_noop(void *ptr); void gw_native_init(void); void gw_native_check_leaks(void); void *gw_native_malloc(size_t size); void *gw_native_calloc(int nmemb, size_t size); void *gw_native_realloc(void *ptr, size_t size); void gw_native_free(void *ptr); char *gw_native_strdup(const char *str); void gw_native_shutdown(void); void gw_check_init_mem(int slow_flag); void gw_check_check_leaks(void); void *gw_check_malloc(size_t size, const char *filename, long line, const char *function); void *gw_check_calloc(int nmemb, size_t size, const char *filename, long line, const char *function); void *gw_check_realloc(void *p, size_t size, const char *filename, long line, const char *function); void gw_check_free(void *p, const char *filename, long line, const char *function); char *gw_check_strdup(const char *str, const char *filename, long line, const char *function); int gw_check_is_allocated(void *p); long gw_check_area_size(void *p); void *gw_check_claim_area(void *p, const char *filename, long line, const char *function); void gw_check_shutdown(void); /* * "slow" == "checking" with a small variation. */ #if USE_GWMEM_SLOW #define USE_GWMEM_CHECK 1 #endif #if USE_GWMEM_NATIVE /* * The `native' wrapper. */ #define gw_init_mem() #define gw_check_leaks() #define gw_malloc(size) (gw_native_malloc(size)) #define gw_malloc_trace(size, file, line, func) (gw_native_malloc(size)) #define gw_calloc(nmemb, size) (gw_native_calloc(nmemb, size)) #define gw_realloc(ptr, size) (gw_native_realloc(ptr, size)) #define gw_free(ptr) (gw_native_free(ptr)) #define gw_strdup(str) (gw_native_strdup(str)) #define gw_assert_allocated(ptr, file, line, function) #define gw_claim_area(ptr) (gw_native_noop(ptr)) #define gw_claim_area_for(ptr, file, line, func) (gw_native_noop(ptr)) #define gwmem_shutdown() #define gwmem_type() (octstr_imm("native")) #elif USE_GWMEM_CHECK /* * The `check' wrapper. */ #ifdef USE_GWMEM_SLOW #define gw_init_mem() (gw_check_init_mem(1)) #define gwmem_type() (octstr_imm("slow")) #else #define gw_init_mem() (gw_check_init_mem(0)) #define gwmem_type() (octstr_imm("checking")) #endif #define gw_check_leaks() (gw_check_check_leaks()) #define gw_malloc_trace(size, file, line, func) \ (gw_check_malloc(size, file, line, func)) #define gw_malloc(size) \ (gw_check_malloc(size, __FILE__, __LINE__, __func__)) #define gw_calloc(nmemb, size) \ (gw_check_calloc(nmemb, size, __FILE__, __LINE__, __func__)) #define gw_realloc(ptr, size) \ (gw_check_realloc(ptr, size, __FILE__, __LINE__, __func__)) #define gw_free(ptr) \ (gw_check_free(ptr, __FILE__, __LINE__, __func__)) #define gw_strdup(str) \ (gw_check_strdup(str, __FILE__, __LINE__, __func__)) #define gw_assert_allocated(ptr, file, line, function) \ (gw_assert_place(gw_check_is_allocated(ptr), file, line, function)) #define gw_claim_area(ptr) \ (gw_check_claim_area(ptr, __FILE__, __LINE__, __func__)) #define gw_claim_area_for(ptr, file, line, func) \ (gw_check_claim_area(ptr, file, line, func)) #define gwmem_shutdown() (gw_check_shutdown()) #else /* * Unknown wrapper. Oops. */ #error "Unknown malloc wrapper." #endif /* * Make sure no-one uses the unwrapped functions by mistake. */ /* undefine first to avoid compiler warnings about redefines */ #undef malloc #undef calloc #undef realloc #undef free #undef strdup #define malloc(n) do_not_call_malloc_directly #define calloc(a, b) do_not_use_calloc #define realloc(p, n) do_not_call_realloc_directly #define free(p) do_not_call_free_directly #define strdup(p) do_not_call_strdup_directly #endif gateway-1.4.5/gwlib/thread.c0000644000175000017500000001413113227613126014406 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #ifdef MUTEX_STATS Mutex *mutex_create_measured(Mutex *mutex, char *filename, int lineno) { mutex->filename = filename; mutex->lineno = lineno; mutex->locks = 0; mutex->collisions = 0; return mutex; } #endif Mutex *mutex_create_real(void) { Mutex *mutex; mutex = gw_malloc(sizeof(Mutex)); pthread_mutex_init(&mutex->mutex, NULL); mutex->owner = -1; mutex->dynamic = 1; return mutex; } Mutex *mutex_init_static_real(Mutex *mutex) { pthread_mutex_init(&mutex->mutex, NULL); mutex->owner = -1; mutex->dynamic = 0; return mutex; } void mutex_destroy(Mutex *mutex) { int ret; if (mutex == NULL) return; #ifdef MUTEX_STATS if (mutex->locks > 0 || mutex->collisions > 0) { info(0, "Mutex %s:%d: %ld locks, %ld collisions.", mutex->filename, mutex->lineno, mutex->locks, mutex->collisions); } #endif if ((ret = pthread_mutex_destroy(&mutex->mutex)) != 0) panic(ret, "Attempt to destroy locked mutex!"); if (mutex->dynamic == 0) return; gw_free(mutex); } void mutex_lock_real(Mutex *mutex, char *file, int line, const char *func) { int ret; gw_assert(mutex != NULL); #ifdef MUTEX_STATS ret = pthread_mutex_trylock(&mutex->mutex); if (ret != 0) { ret = pthread_mutex_lock(&mutex->mutex); mutex->collisions++; } mutex->locks++; #else ret = pthread_mutex_lock(&mutex->mutex); #endif if (ret != 0) panic(0, "%s:%ld: %s: Mutex failure! (Called from %s:%ld:%s.)", \ __FILE__, (long) __LINE__, __func__, file, (long) line, func); if (mutex->owner == gwthread_self()) panic(0, "%s:%ld: %s: Managed to lock the mutex twice! (Called from %s:%ld:%s.)", \ __FILE__, (long) __LINE__, __func__, file, (long) line, func); mutex->owner = gwthread_self(); } int mutex_unlock_real(Mutex *mutex, char *file, int line, const char *func) { int ret; if (mutex == NULL) { error(0, "%s:%ld: %s: Trying to unlock a NULL mutex! (Called from %s:%ld:%s.)", \ __FILE__, (long) __LINE__, __func__, file, (long) line, func); return -1; } gw_assert(mutex != NULL); mutex->owner = -1; ret = pthread_mutex_unlock(&mutex->mutex); if (ret != 0) panic(0, "%s:%ld: %s: Mutex failure! (Called from %s:%ld:%s.)", \ __FILE__, (long) __LINE__, __func__, file, (long) line, func); return ret; } int mutex_trylock_real(Mutex *mutex, const char *file, int line, const char *func) { int ret; if (mutex == NULL) { error(0, "%s:%ld: %s: Trying to lock a NULL mutex! (Called from %s:%ld:%s.)", \ __FILE__, (long) __LINE__, __func__, file, (long) line, func); return -1; } ret = pthread_mutex_trylock(&mutex->mutex); if (ret == 0) { if (mutex->owner == gwthread_self()) panic(0, "%s:%ld: %s: Managed to lock the mutex twice! (Called from %s:%ld:%s.)", \ __FILE__, (long) __LINE__, __func__, file, (long) line, func); mutex->owner = gwthread_self(); } else if (ret == EINVAL) panic(0, "%s:%ld: %s: Mutex failure! (Called from %s:%ld:%s.)", \ __FILE__, (long) __LINE__, __func__, file, (long) line, func); return ret; } gateway-1.4.5/gwlib/dbpool_sqlite3.c0000644000175000017500000002041213227613126016061 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dbpool_sqlite3.c - implement SQLite3 operations for generic database connection pool * * Stipe Tolj * David Butler - modeled select and update from dbpool_oracle.c */ #ifdef HAVE_SQLITE3 #include static void *sqlite3_open_conn(const DBConf *db_conf) { sqlite3 *db = NULL; SQLite3Conf *conf = db_conf->sqlite3; /* make compiler happy */ /* sanity check */ if (conf == NULL) return NULL; if (sqlite3_open(octstr_get_cstr(conf->file), &db) != SQLITE_OK) { error(0, "SQLite3: can not open or create database file `%s'!", octstr_get_cstr(conf->file)); error(0, "SQLite3: %s", sqlite3_errmsg(db)); sqlite3_close(db); goto failed; } if (conf->lock_timeout > 0) { info(0, "SQLite3: Setting lock timeout to %d", conf->lock_timeout); sqlite3_busy_timeout(db, conf->lock_timeout); } info(0, "SQLite3: Opened or created database file `%s'.", octstr_get_cstr(conf->file)); info(0, "SQLite3: library version %s.", sqlite3_version); return db; failed: return NULL; } static void sqlite3_close_conn(void *conn) { int rc; if (conn == NULL) return; /* in case we are busy, loop until we can close */ do { rc = sqlite3_close((sqlite3*) conn); } while (rc == SQLITE_BUSY); if (rc == SQLITE_ERROR) { error(0, "SQLite3: error while closing database file."); } } static int sqlite3_check_conn(void *conn) { if (conn == NULL) return -1; /* There is no such construct in SQLite3, * so return a valid connection indication */ return 0; } static void sqlite3_conf_destroy(DBConf *db_conf) { SQLite3Conf *conf = db_conf->sqlite3; octstr_destroy(conf->file); gw_free(conf); gw_free(db_conf); } static int sqlite3_select(void *theconn, const Octstr *sql, List *binds, List **res) { sqlite3 *db = theconn; sqlite3_stmt *stmt; const char *rem; List *row; int status; int columns; int i; int binds_len = (binds ? gwlist_len(binds) : 0); *res = NULL; /* prepare statement */ #if SQLITE_VERSION_NUMBER >= 3003009 status = sqlite3_prepare_v2(db, octstr_get_cstr(sql), octstr_len(sql) + 1, &stmt, &rem); #else status = sqlite3_prepare(db, octstr_get_cstr(sql), octstr_len(sql) + 1, &stmt, &rem); #endif if (SQLITE_OK != status) { error(0, "SQLite3: %s", sqlite3_errmsg(db)); return -1; } /* bind variables */ for (i = 0; i < binds_len; i++) { Octstr *bind = gwlist_get(binds, i); status = sqlite3_bind_text(stmt, i + 1, octstr_get_cstr(bind), octstr_len(bind), SQLITE_STATIC); if (SQLITE_OK != status) { error(0, "SQLite3: %s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return -1; } } /* execute our statement */ *res = gwlist_create(); while ((status = sqlite3_step(stmt)) == SQLITE_ROW) { columns = sqlite3_data_count(stmt); debug("dbpool.sqlite3",0,"SQL has %d columns", columns); row = gwlist_create(); for (i = 0; i < columns; i++) { if (sqlite3_column_type(stmt, i) == SQLITE_NULL) { gwlist_insert(row, i, octstr_create("")); } else { gwlist_insert(row, i, octstr_create(sqlite3_column_text(stmt, i))); } /* debug("dbpool.sqlite3",0,"inserted value = '%s'", octstr_get_cstr(gwlist_get(row,i))); */ } gwlist_append(*res, row); } if (SQLITE_DONE != status) { error(0, "SQLite3: %s", sqlite3_errmsg(db)); while ((row = gwlist_extract_first(*res)) != NULL) gwlist_destroy(row, octstr_destroy_item); gwlist_destroy(*res, NULL); *res = NULL; sqlite3_finalize(stmt); return -1; } sqlite3_finalize(stmt); return 0; } static int sqlite3_update(void *theconn, const Octstr *sql, List *binds) { sqlite3 *db = theconn; sqlite3_stmt *stmt; const char *rem; int status; int rows; int i; int binds_len = (binds ? gwlist_len(binds) : 0); /* prepare statement */ #if SQLITE_VERSION_NUMBER >= 3003009 status = sqlite3_prepare_v2(db, octstr_get_cstr(sql), octstr_len(sql) + 1, &stmt, &rem); #else status = sqlite3_prepare(db, octstr_get_cstr(sql), octstr_len(sql) + 1, &stmt, &rem); #endif if (SQLITE_OK != status) { error(0, "SQLite3: %s", sqlite3_errmsg(db)); return -1; } debug("dbpool.sqlite3",0,"sqlite3_prepare done"); /* bind variables */ for (i = 0; i < binds_len; i++) { Octstr *bind = gwlist_get(binds, i); status = sqlite3_bind_text(stmt, i + 1, octstr_get_cstr(bind), octstr_len(bind), SQLITE_STATIC); if (SQLITE_OK != status) { error(0, "SQLite3: %s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return -1; } } /* execute our statement */ if ((status = sqlite3_step(stmt)) != SQLITE_DONE) { error(0, "SQLite3: %s", sqlite3_errmsg(db)); sqlite3_finalize(stmt); return -1; } debug("dbpool.sqlite3",0,"sqlite3_step done"); rows = sqlite3_changes(db); debug("dbpool.sqlite3",0,"rows processed = %d", rows); sqlite3_finalize(stmt); return rows; } static struct db_ops sqlite3_ops = { .open = sqlite3_open_conn, .close = sqlite3_close_conn, .check = sqlite3_check_conn, .conf_destroy = sqlite3_conf_destroy, .select = sqlite3_select, .update = sqlite3_update }; #endif /* HAVE_SQLITE3 */ gateway-1.4.5/gwlib/gw-timer.c0000644000175000017500000004401413227613126014675 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw-timer.c - timers and set of timers. * * See gw-timer.h for a description of the interface. */ #include #include "gwlib/gwlib.h" #include "gw-timer.h" /* * Active timers are stored in a TimerHeap. It is a partially ordered * array. Each element i is the child of element i/2 (rounded down), * and a child never elapses before its parent. The result is that * element 0, the top of the heap, is always the first timer to * elapse. The heap is kept in this partial order by all operations on * it. Maintaining a partial order is much cheaper than maintaining * a sorted list. * The array will be resized as needed. The size field is the number * of elements for which space is reserved, and the len field is the * number of elements actually used. The elements used will always be * at tab[0] through tab[len-1]. */ struct TimerHeap { Timer **tab; long len; long size; }; typedef struct TimerHeap TimerHeap; struct Timerset { /* * This field is set to true when the timer thread should shut down. */ volatile sig_atomic_t stopping; /* * The entire set is locked for any operation on it. This is * not as expensive as it sounds because usually each set is * used by one caller thread and one (internal) timer thread, * and the timer thread does not wake up very often. */ Mutex *mutex; /* * Active timers are stored here in a partially ordered structure. * See the definition of TimerHeap, above, for an explanation. */ TimerHeap *heap; /* * The thread that watches the top of the heap, and processes * timers that have elapsed. */ long thread; }; struct Timer { /* * The timer set this timer belongs to. */ Timerset *timerset; /* * An event is produced on the output list when the * timer elapses. The timer is not considered to have * elapsed completely until that pointer has also been * consumed from this list (by the caller, presumably). * That is why the timer code sometimes goes back and * removes a pointer from the output list. */ List *output; /* * A call back function is called when the timer elapses. */ void (*callback) (void* data); /* * The timer is set to elapse at this time, expressed in * Unix time format. This field is set to -1 if the timer * is not active (i.e. in the timer set's heap). */ long elapses; /* * A duplicate of this event will be put on the output list * when the timer elapses. It can be NULL if the timer has * not been started yet. */ void *data; /* * This field is normally NULL, but after the timer elapses * it points to the event that was put on the output list. * It is set back to NULL if the event was taken back from * the list, or if it's confirmed that the event was consumed. */ void *elapsed_data; /* * The index in the timer set's heap. This field is managed by * the heap operations, and is used to make them faster. * If this timer is not in the heap, this field is -1. */ long index; }; /* * Internal functions */ static void abort_elapsed(Timer *timer); static TimerHeap *heap_create(void); static void heap_destroy(TimerHeap *heap); static void heap_delete(TimerHeap *heap, long index); static int heap_adjust(TimerHeap *heap, long index); static void heap_insert(TimerHeap *heap, Timer *timer); static void heap_swap(TimerHeap *heap, long index1, long index2); static void lock(Timerset *set); static void unlock(Timerset *set); static void watch_timers(void *arg); /* The timer thread */ static void elapse_timer(Timer *timer); Timerset *gw_timerset_create(void) { Timerset *set; set = gw_malloc(sizeof(Timerset)); set->mutex = mutex_create(); set->heap = heap_create(); set->stopping = 0; set->thread = gwthread_create(watch_timers, set); return set; } void gw_timerset_destroy(Timerset *set) { if (set == NULL) return; /* Stop all timers. */ while (set->heap->len > 0) gw_timer_stop(set->heap->tab[0]); /* Kill timer thread */ set->stopping = 1; gwthread_wakeup(set->thread); gwthread_join(set->thread); /* Free resources */ heap_destroy(set->heap); mutex_destroy(set->mutex); gw_free(set); } Timer *gw_timer_create(Timerset *set, List *outputlist, void (*callback) (void*)) { Timer *t; t = gw_malloc(sizeof(*t)); t->timerset = set; t->elapses = -1; t->data = NULL; t->elapsed_data = NULL; t->index = -1; t->output = outputlist; if (t->output != NULL) gwlist_add_producer(outputlist); t->callback = callback; return t; } void gw_timer_destroy(Timer *timer) { if (timer == NULL) return; gw_timer_stop(timer); if (timer->output != NULL) gwlist_remove_producer(timer->output); gw_free(timer); } void gw_timer_elapsed_destroy(Timer *timer) { if (timer == NULL) return; gw_timer_elapsed_stop(timer); if (timer->output != NULL) gwlist_remove_producer(timer->output); gw_free(timer); } void gw_timer_start(Timer *timer, int interval, void *data) { int wakeup = 0; gw_assert(timer != NULL); if (timer == NULL) return; lock(timer->timerset); /* Convert to absolute time */ interval += time(NULL); if (timer->elapses > 0) { /* Resetting an existing timer. Move it to its new * position in the heap. */ if (interval < timer->elapses && timer->index == 0) wakeup = 1; timer->elapses = interval; gw_assert(timer->index >= 0); gw_assert(timer->timerset->heap->tab[timer->index] == timer); wakeup |= heap_adjust(timer->timerset->heap, timer->index); } else { /* Setting a new timer, or resetting an elapsed one. * First deal with a possible elapse event that may * still be on the output list. */ abort_elapsed(timer); /* Then activate the timer. */ timer->elapses = interval; gw_assert(timer->index < 0); heap_insert(timer->timerset->heap, timer); wakeup = timer->index == 0; /* Do we have a new top? */ } if (data != NULL) { timer->data = data; } unlock(timer->timerset); if (wakeup) gwthread_wakeup(timer->timerset->thread); } void gw_timer_elapsed_start(Timer *timer, int interval, void *data) { int wakeup = 0; gw_assert(timer != NULL); if (timer == NULL) return; lock(timer->timerset); /* Convert to absolute time */ interval += time(NULL); if (timer->elapses > 0) { /* Resetting an existing timer. Move it to its new * position in the heap. */ if (interval < timer->elapses && timer->index == 0) wakeup = 1; timer->elapses = interval; gw_assert(timer->index >= 0); gw_assert(timer->timerset->heap->tab[timer->index] == timer); wakeup |= heap_adjust(timer->timerset->heap, timer->index); } else { /* Setting a new timer, or resetting an elapsed one. * There should be no further elapse event on the * output list here. */ /* abort_elapsed(timer); */ timer->elapsed_data = NULL; /* Then activate the timer. */ timer->elapses = interval; gw_assert(timer->index < 0); heap_insert(timer->timerset->heap, timer); wakeup = timer->index == 0; /* Do we have a new top? */ } if (data != NULL) { timer->data = data; } unlock(timer->timerset); if (wakeup) gwthread_wakeup(timer->timerset->thread); } void gw_timer_stop(Timer *timer) { gw_assert(timer != NULL); lock(timer->timerset); /* * If the timer is active, make it inactive and remove it from * the heap. */ if (timer->elapses > 0) { timer->elapses = -1; gw_assert(timer->timerset->heap->tab[timer->index] == timer); heap_delete(timer->timerset->heap, timer->index); } abort_elapsed(timer); unlock(timer->timerset); } void gw_timer_elapsed_stop(Timer *timer) { gw_assert(timer != NULL); lock(timer->timerset); /* * If the timer is active, make it inactive and remove it from * the heap. */ if (timer->elapses > 0) { timer->elapses = -1; gw_assert(timer->timerset->heap->tab[timer->index] == timer); heap_delete(timer->timerset->heap, timer->index); } /* abort_elapsed(timer); */ timer->elapsed_data = NULL; unlock(timer->timerset); } List *gw_timer_break(Timerset *set) { List *ret = NULL; lock(set); if (set->heap->len == 0) { unlock(set); return NULL; } ret = gwlist_create(); /* Stop all timers. */ while (set->heap->len > 0) { Timer *timer = set->heap->tab[0]; gwlist_append(ret, timer); /* * If the timer is active, make it inactive and remove it from * the heap. */ if (timer->elapses > 0) { timer->elapses = -1; gw_assert(set->heap->tab[timer->index] == timer); heap_delete(set->heap, timer->index); } abort_elapsed(timer); } unlock(set); return ret; } void *gw_timer_data(Timer *timer) { gw_assert(timer != NULL); return timer->data; } static void lock(Timerset *set) { gw_assert(set != NULL); mutex_lock(set->mutex); } static void unlock(Timerset *set) { gw_assert(set != NULL); mutex_unlock(set->mutex); } /* * Go back and remove this timer's elapse event from the output list, * to pretend that it didn't elapse after all. This is necessary * to deal with some races between the timer thread and the caller's * start/stop actions. */ static void abort_elapsed(Timer *timer) { if (timer->elapsed_data == NULL) return; if (timer->output != NULL) gwlist_delete_equal(timer->output, timer->elapsed_data); timer->elapsed_data = NULL; } /* * Create a new timer heap. */ static TimerHeap *heap_create(void) { TimerHeap *heap; heap = gw_malloc(sizeof(*heap)); heap->tab = gw_malloc(sizeof(heap->tab[0])); heap->size = 1; heap->len = 0; return heap; } static void heap_destroy(TimerHeap *heap) { if (heap == NULL) return; gw_free(heap->tab); gw_free(heap); } /* * Remove a timer from the heap. Do this by swapping it with the element * in the last position, then shortening the heap, then moving the * swapped element up or down to maintain the partial ordering. */ static void heap_delete(TimerHeap *heap, long index) { long last; gw_assert(index >= 0); gw_assert(index < heap->len); gw_assert(heap->tab[index]->index == index); last = heap->len - 1; heap_swap(heap, index, last); heap->tab[last]->index = -1; heap->len--; if (index != last) heap_adjust(heap, index); } /* * Add a timer to the heap. Do this by adding it at the end, then * moving it up or down as necessary to achieve partial ordering. */ static void heap_insert(TimerHeap *heap, Timer *timer) { heap->len++; if (heap->len > heap->size) { heap->tab = gw_realloc(heap->tab, heap->len * sizeof(heap->tab[0])); heap->size = heap->len; } heap->tab[heap->len - 1] = timer; timer->index = heap->len - 1; heap_adjust(heap, timer->index); } /* * Swap two elements of the heap, and update their index fields. * This is the basic heap operation. */ static void heap_swap(TimerHeap *heap, long index1, long index2) { Timer *t; gw_assert(index1 >= 0); gw_assert(index1 < heap->len); gw_assert(index2 >= 0); gw_assert(index2 < heap->len); if (index1 == index2) return; t = heap->tab[index1]; heap->tab[index1] = heap->tab[index2]; heap->tab[index2] = t; heap->tab[index1]->index = index1; heap->tab[index2]->index = index2; } /* * The current element has broken the partial ordering of the * heap (see explanation in the definition of Timerset), and * it has to be moved up or down until the ordering is restored. * Return 1 if the timer at the heap's top is now earlier than * before this operation, otherwise 0. */ static int heap_adjust(TimerHeap *heap, long index) { Timer *t; Timer *parent; long child_index; /* * We can assume that the heap was fine before this element's * elapse time was changed. There are three cases to deal * with: * - Element's new elapse time is too small; it should be * moved toward the top. * - Element's new elapse time is too large; it should be * moved toward the bottom. * - Element's new elapse time still fits here, we don't * have to do anything. */ gw_assert(index >= 0); gw_assert(index < heap->len); /* Move to top? */ t = heap->tab[index]; parent = heap->tab[index / 2]; if (t->elapses < parent->elapses) { /* This will automatically terminate when it reaches * the top, because in that t == parent. */ do { heap_swap(heap, index, index / 2); index = index / 2; parent = heap->tab[index / 2]; } while (t->elapses < parent->elapses); /* We're done. Return 1 if we changed the top. */ return index == 0; } /* Move to bottom? */ for (; ; ) { child_index = index * 2; if (child_index >= heap->len) return 0; /* Already at bottom */ if (child_index == heap->len - 1) { /* Only one child */ if (heap->tab[child_index]->elapses < t->elapses) heap_swap(heap, index, child_index); break; } /* Find out which child elapses first */ if (heap->tab[child_index + 1]->elapses < heap->tab[child_index]->elapses) { child_index++; } if (heap->tab[child_index]->elapses < t->elapses) { heap_swap(heap, index, child_index); index = child_index; } else { break; } } return 0; } /* * This timer has elapsed. Do the housekeeping. We have its set locked. */ static void elapse_timer(Timer *timer) { gw_assert(timer != NULL); gw_assert(timer->timerset != NULL); /* This must be true because abort_elapsed is always called * before a timer is activated. */ gw_assert(timer->elapsed_data == NULL); timer->elapsed_data = timer->data; timer->elapses = -1; if (timer->output != NULL) gwlist_produce(timer->output, timer->elapsed_data); if (timer->callback != NULL) timer->callback(timer->elapsed_data); } /* * Main function for timer thread. */ static void watch_timers(void *arg) { Timerset *set; long top_time; long now; set = arg; while (!set->stopping) { lock(set); now = time(NULL); while (set->heap->len > 0 && set->heap->tab[0]->elapses <= now) { Timer *timer = set->heap->tab[0]; heap_delete(set->heap, 0); elapse_timer(timer); } /* * Now sleep until the next timer elapses. If there isn't one, * then just sleep very long. We will get woken up if the * top of the heap changes before we wake. */ if (set->heap->len == 0) { unlock(set); gwthread_sleep(1000000.0); } else { top_time = set->heap->tab[0]->elapses; unlock(set); gwthread_sleep(top_time - now); } } } gateway-1.4.5/gwlib/fdset.h0000644000175000017500000001231313227613126014251 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * fdset.h - module for managing a large collection of file descriptors */ typedef struct FDSet FDSet; /* * A function of this type will be called to indicate that a file descriptor * has shown activity. The revents parameter is in the same format as * returned by poll(). The data pointer was supplied by the caller who * registered the fd with us in the first place. * NOTE: Beware of concurrency issues. The callback function will run * in the fdset's private thread, not in the caller's thread. * This also means that if the callback does a lot of work it will slow * down the polling process. This may be good or bad. */ typedef void fdset_callback_t(int fd, int revents, void *data); /* * Create a new, empty file descriptor set and start its thread. * @timeout - idle timeout for any filedescriptor in this fdset after which * callback function will be called with POLLERR as event. */ #define fdset_create() fdset_create_real(-1) FDSet *fdset_create_real(long timeout); /* * Destroy a file descriptor set. Will emit a warning if any file * descriptors are still registered with it. */ void fdset_destroy(FDSet *set); /* * Register a file descriptor with this set, and listen for the specified * events (see fdset_listen() for details on that). Record the callback * function which will be used to notify the caller about events. */ void fdset_register(FDSet *set, int fd, int events, fdset_callback_t callback, void *data); /* * Change the set of events to listen for for this file descriptor. * Events is in the same format as the events field in poll() -- in * practice, use POLLIN for "input available", POLLOUT for "ready to * accept more output", and POLLIN|POLLOUT for both. * * The mask field indicates which event flags can be affected. For * example, if events is POLLIN and mask is POLLIN, then the POLLOUT * setting will not be changed by this. If mask were POLLIN|POLLOUT, * then the POLLOUT setting would be turned off. * * The fd must first have been registered. Locks are used to * guarantee that the callback function will not be called for * the old events after this function returns. */ void fdset_listen(FDSet *set, int fd, int mask, int events); /* * Forget about this fd. Locks are used to guarantee that the callback * function will not be called for this fd after this function returns. */ void fdset_unregister(FDSet *set, int fd); /** * Set timeout in seconds for this FDSet. */ void fdset_set_timeout(FDSet *set, long timeout); gateway-1.4.5/compile0000755000175000017500000001624513312227404013250 0ustar toljtolj#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gateway-1.4.5/NEWS0000644000175000017500000015632513310761405012377 0ustar toljtoljNEWS about Kannel: Open Source WAP and SMS Gateway version 1.4.5 This is a STABLE version. It should be usable for production systems. Please do report problems to the Kannel bug tracking system available at https://redmine.kannel.org/issues or send a mail to (the development mailing list, see https://www.kannel.org/lists.shtml). Changes since version 1.4.4 stable: [*** Beware that the version move from 1.4.4 stable to 1.4.5 stable contains numerous change sets, with major bug fixes and improvements. Following is a summary of the main issues. For a complete and detailed set of changes please refer to the specific ChangeLog in the doc/ directory of the distribution. ***] Compatibility breakers: New features: * Added graceful-restarting of bearerbox via the SIGHUP signal, which can be used to softly restart bearerbox on config changes allowing existing SMSC connections to keep on running. * Added redis support as message store and DLR storage. * Added Apache Cassandra 2.1, 2.2 and 3.0 support as DLR storage. * Added OpenSSL 1.1.x support. * Added support for chained certificate files. * Added support to define which SSL/TLS chipher suites to use. * Added UCS-2 (Unicode) support for FAKE SMSC MOs. * Allow override of specific SMPP values via meta-data forwarding, i.e. for TON/NPI, DCS. * Splitting white/black-list into per direction (sender/receiver) allowing a more fine grained control. * Added 'instances' directive for 'group = smsc' contexts to duplicate the configuration group into any number of instances, so there is no need to duplicate the configuration in the config files, reducing the potential for errors and redundancy. * Added per line PDU dump function for SMPP. * Added support for constant SMPP TLVs. Bugfixes: * Fixed various SMPP module issues. * Better handling of MySQL DBPool temporary error codes. * Various fixes in the routing abstraction layer. * Fixed segfault in logging module for permission errors. * Fixed smsbox's XML MT and XML POST processing. * Fixed HTTP SMSC queue counter. * Fixed waiting time when in bearerbox shutdown phase. * Fixed missing character set processing in HTTP SMSC (type kannel). * Fixed MO concatenation handling for re-routing cases. * Fixed various memory leaks. * Fixing asymmetric load distribution for this HTTP SMSC type. * Fixing HTTP Keep-Alive indication as HTTP server. * Fixed HTTP UCS-2 payload forwarding. * Fixed HTTP admin command /reload-lists. Changes since version 1.4.3: [*** Beware that the version move from 1.4.3 to 1.5.0 contains numerous change sets, with major bug fixes and improvements. Following is a summary of the main issues. For a complete and detailed set of changes please refer to the specific ChangeLog in the doc/ directory of the distribution. ***] Compatibility breakers: * Internal message structure has changed, so older smsbox connection daemons won't be able to communicate with this bearerbox. Please ensure that you use boxes from releases greater or equal 1.5.0 for correct communication. * DLR storage via MySQL requires now MySQL 4.1 or higher, due that we use now prepared statements in the SQL calls. New features: * Added 'meta-data' support, which provides a mechanism to pass SMSC protocol specific optional data to the lower SMSC module layer. Ie. optional TLVs for SMPP. * Added better serial speed support for the AT modem on MacOS systems. * Added cleaner iconv() support for character re-encoding. * Added SMPP v3.4 DLR support via optional TLV values. * Added DLR support for the MT batch processing program. * Added Microsoft SQL server support as DLR storage backend. * Extended the HTTP admin interface. * Added SMPP v3.4 intermediate notification support. * Added MT module handling of +CME ERROR cases. * Added better result parsing generic HTTP SMSC module. * Added better throughput handling in SMPP module. * Added SMSC module 'loopback' as the MT counterpart of the 're-route' directive in the 'group = smsc' for MO messages. MT messages are bounced back as MOs into the incoming queue. * Added separate DLR message counters on the HTTP admin status. * Added 'http-timeout' config directive to allow setting of a timeout value for outgoing HTTP calls. * Added WTLS provisioning support. * Added add-on packages sqlbox and opensmppbox to the main distribution, where sqlbox provides abstraction from bearerbox towards SQL RDBMS and opensmppbox provides abstraction from bearerbox towards SMPP clients. Bugfixes: * Fixed various bugs in AT module. * Fixed various memory leaks. * Fixed ISO date parsing. * Fixed HTTP cookie parsing in WAP module. * Fixed WAP-WSP quoted text parsing. * Fixed various WAP module bugs. * Fixed MT batch processing program. * Fixed FreeBSD build procedure. * Fixed OMA OTA compiler output. * Fixed weak DLR resolving for some SMSC types. Changes since version 1.4.1: [*** Beware that the version move from 1.4.1 to 1.4.2 contains numerous change sets, with major bug fixes and improvements. Following is a summary of the main issues. For a complete and detailed set of changes please refer to the specific ChangeLog in the doc/ directory of the distribution. ***] Compatibility breakers: * Internal message payload encoding changed from LATIN1 to UTF-8, which means any 1.4.2 boxes are unable to communicate with older versions. * Re-defined logic for the 'smsbox-route' group that is used for MO routing to different (identified) smsbox connections. * Changed main message structure to include foreign (SMSC) ID to it, breaking the access-log format and communication to older box versions. New features: * Added service routing based on account field, which allows routing of MO messages depending on the account set by an aggregating SMSC provider. * Added the new 'generic' system-type for HTTP SMSC, which allows the usage of the escape code sequenced in send-url and regex parsing of HTTP response. * Added 'interactive' mode via stdin and stdout to allow a more human like interaction with the fake smsc module. * Added support to pass the 'from' source addr via 'X-Kannel-From' HTTP header in the PPG request. * Added generic DLR handling for type 'kannel' (HTTP SMSC), which allows point-to-point DLR forwarding though the whole kannel instance chain. * Added support for store spool directory. * Added concatenation MO support. * Added AT SMSC support for protocol 'type = telnet', which interprets telnet escape sequenced compared to rawtcp. * Added REGEX support for keyword matching. * Added support for IBM AIX 64bit builds. * Added SSL support for HTTP SMSC module server. * Added bearerbox HTTP admin command 'reload-lists' to allow re-loading of the '[white|black]-list' on the fly. * Added support of concatenated, 8bit and Unicode messages over HTTP via Clickatell. Bugfixes: * Fixed alias support for sms-service in smsbox scope. * Fixed various MIME type handling bugs. * Fixed security and race condition issue in HTTP module for keep-alive connections. * Fixed wrong length calculation for concatenated messages. * Fixed bug that AT SMSC put UDH without UDH len. * Fixed various memleaks, reported by valgrind. * Fixed HTTP proxy scheme interpretation for SSL-enabled connections. * Fixed OTA compiler, within WBXML compilation. * Fixed encoding of 'Content-Id' WSP header. * Fixed various segfaults in SMPP, logging modules. * Fixed various AT command handling in AT module. * Fixed 7bit encoding in AT SMSC. Changes since version 1.4.0: [*** Beware that the version move from 1.4.0 to 1.4.1 contains more then 200 change sets, with major bug fixes and improvements. Following is a summary of the main issues. For a complete and detailed set of changes please refer to the specific ChangeLog in the doc/ directory of the distribution. ***] Compatibility breakers: * Format for wapbox's access-log format changed to include the MSISDN of a client as second argument after client IP and before method. * fakesmsc uses now -r to specify the remote port on bearerbox side. Option -p is generally reserved for pid file creation. * sendsms now obeys bearerbox's reply before indicating result to HTTP caller. This breaks any application layer clients that rely on the HTTP body response of sendsms. To enforce the old behaviour use config directive 'immediate-sendsms-reply = true' in smsbox group. * DLR via MySQL uses now also 'username' and 'password' for the mysql-connection group in order to harmonize the config names. New features: * Added config directive 'store-dump-freq' to core group to define the fequency of the store-file dumping mechanism. * Added backtrace support for Linux. In case of PANIC, we get a backtrace of the called routines to make debugging easier. * Added some new modem groups to doc/examples/modems.conf. * Added more WTAI functions to support. * Added RAW TCP support for remote termnial servers for AT modem devices. * Added 'config.nice' support while configure time, to allow "remembering" the used configure flags and options. * Added OMA ProvCont support via OTA messages. * Added SyncML support via OTA messages. * Added directive 'wml-strict' to wapbox group. * SMPP data_sm PDUs are supported now for MO messages. * SMPP added config directives 'bind-addr-ton' and 'bind-addr-npi' to allow setting values for bind_receiver and/or bind_transmitter PDUs. * Added support for WSP 1.6 headers. * Added automatic support for large files, via compiler directives. * Added config line delimiter via \ (backslash). This allows wrapping config lines to several lines. * Added support for hooking config group definition files as our own gwlib/cfg.def from external add-on modules to the core. Main intention is to provide a installed Kannel without the need of patching the source for any modules that use Kannel's gwlib and gw libs. * Added config directives 'bearerbox-port' and 'bearerbox-port-ssl' to smsbox group, in order to not need any core group reading of external modules, ie. sqlbox. * Added config directive 'max-pending-requests' for smsbox group to control the outbound requests stream generated from smsbox towards HTTP application servers. Bugfixes: * Fixed several bugs in TCP connection handling. * Fixed several bugs in HTTP communication layer. * Fixed segfaults on x86_64 (Intel Xeon) platforms. * SMPP validity and defer time are set in UTC, several improvements and error checks added. * Fixed several 'make check' issues. * MySQL support fixed, where certain function prototype names clashed with our own gwlist structure. * DLR support for PostgreSQL fixed for LIMIT clause usage. * WSP empty header values fixed. * WDP fix to discard truncated datagrams without PANIC. * WAP Cookie handling fixed, charset handling generalized. * AT driver fixes and improvements. * RADIUS bug fixed in MD5 computing for authentication towards NAS. * MacOS X support improved for configure process. * store-file fixes and improvements. * WML compiler fix, causing sefault. * Fixed memory leaks for concat message handling. * MIME parsing and handling fixed. * FreeBSD AMD64 architecture support fixed. * Fixed wapbox signal handling for shutdown. * WTP SAR race condition and handling fixed. * Fixed memory leaks in smsbox. * sendsms POST XML handling fixed, where sender address was not parsed. * smsbox reply handling fixed, to copy the originating smsc-id value in the reply messages. Changes since version 1.3.2: Compatibility breakers: * fakesmsc switching from -p to -r for port, since -p is used for pid-file creation. This broke fakesmsc to use an other port then the default 10000 to connect to the smsc_fake module of bearerbox. New features: * Added ability to start/stop/restart of all smscconn's that have equal smsc-id's instead of only one. * Implemented very simple priority queue ala Robert Sedgewick for gwlib. * Implemented concatenation of large sms inside bearerbox and does care of sending all message parts over one smsc link. Now we have a problem with concatenated large sms that bearerbox will try to load balance those over different smsc links and such messages arrive as junk (all parts of concatenated large sms must go through the same smsc). * SMPP added ESME dlr bit to DLR processing, added setting of sms priority flag in smsbox and smpp module. * bruNET upgrading response parsing to comply with more recent interface version (v2.0+) where bruNET delivers 'MessageId' in the HTTP response body. * AT, EMI usage of the of priority queue and priority flag. * URLTranslation added '%o' as escape code for MO msgs representing the msg->sms.account field. Which is interpreted as the operator ID for aggregator specific MO messages. ie. Xidris HTTP SMSC module. * test_ppg added support for X-WAP-Initiator-URI, use -I option. Bugfixes: * SMPP fixed panic on NULLed source_addr/destination_addr, for nulterminated string length checking of PDU elements, bug that dlr lookup was made with source instead of destination address (in dlr source and destination switched), fixed incorrect handling of GSM_ADDR_TON_ALPHANUMERIC for destination address, * AT fixed segfault when modemtype is set to 'auto' or 'autodetect', fixed '+CPIN', some modem needs '"'. * HTTP fixed a binary MT bug (when DC_8BIT has been set) and various improvements for passing parameters to the HTTP request, fixing 3united (formerly Xidris) HTTP interface for binary MT messages. We passed URL-encoded binary string, but server side expected HEX encoded (2 char per byte) version. * WSP string coding bug fixed. * WML compiler fixed panic for certain DOCTYPE definitions, memory leak fixed. * XMLRPC fixed memory leak. * Fixed ISO date handling. * Fixed double encoding in smsbox when trans coding from UCS2 to UTF-8 or ISO-8859-1. * Improved pthread reader/writer-locks. * Fixed usage of native semaphores on MacOS X to avoid a "not implemented" error. * Fixed pthread lib settings for FreeBSD 5.2.1. * Added check for 'sem_init' in librt. This needs on Solaris & HP-UX. * Fixed Linux version of gw_gethostbyname when gethostbyname_r failed. Also free buffer on error. * Fixed daemon mode (make sure stdin/stdout/sdterr are opened and do chdir("/")) and change user code (set supplementary group id's and don't destroy passwd struct). * Bug work-around causing segfault on cygwin while using uninited rwlock functions. * Various memory leak and double free fixes. Changes since version 1.3.1: [*** Beware that the version move from 1.3.1 to 1.3.2 contains more then 400 changesets, with major bugfixes and improvemnts. Following is a summary of the main issues. For a complete and detailed set of changes please refer to the specific ChangeLog in the doc/ directory of the distribution. ***] Compatibility breakers: * LICENSE changed to Kannel Software License v1.0. BSD-style as before with some more restrictions to the name "Kannel" and usage of it. * SMPP changed recoding of source_addr and destination_addr on the MO side. We will pass a prefixed '+' to the smsbox side. Otherwise there is no chance for backend applicatins, like smsbox to decide what type of number it is. * EMI2 login operation 60 had a hard timeout of 30 sec. Some SMSC may need longer to ACK the login, so use the 'wait-ack' time value here too in case it's larger then 30 sec. * CIMD2 harmonized 'my-number' directive, this makes 'sender-prefix' absolete, interpretation of 'keepalive' is now in seconds instead of minutes. * HTTP SMSC changed 'dlrurl' to 'dlr-url', 'dlrmask' to 'dlr-mask' in order to reflect changes within smsbox's sendsms interface. * Removed no more needed 'retry' smsc group directive. This is now handled via the more abstracted 'reconnect-delay' value. * WAP access.log file of wapbox has now some more elements, ie. remote IP of client, HTTP method, length of content body, user agent string, HTTP server string, cookie support is enabled now by default, added new 'wap-url-map' and 'wap-user-map groups to replace deprecated 'map-url' map. * Renamed internal SMSC module identifiers for the smsc group directive 'smsc', which identifies which SMSC module is to be used for the specific link, according to these: to , to , to . * The configure option switch --with-defaults default value is now "speed". * (!!!) smsbox's sendsms interface changed for values passed to various variables, according to this: pid=0 says that you want a pid value in pdu, with value 0; mclass is now 0-3; coding is 0-2; alt-dcs is 0-1; mwi is 0-7 to comply with ETSI values; dlrmask and dlrurl query parameters are deprecated, but still functional; please use dlr-mask and dlr-url; flash was removed. * Changed core group config option 'maximum-queue-length' to 'sms-incoming-queue-limit' for the sake of semantics. * Added 'binfo' billing identifier/information element to bearerbox's access.log log format. * Changed the way how DLR storage is "defined" while configure time, according to this: removes '--with-dlr', --with-mysql to --with-mysql-dir, --enable-[mysql|oracle|sdb|sqlite] to --with-[mysql|oracle|sdb|sqlite]. * Account field is required in DLR tablespace and dlr config sections too. New features: * SMPP added facility to specify SMSC service type with 'service-type = foo', adding handling of invaid userid and/or passwd to shutdown SMSC connection rather than retrying to reconnect, a set of optional parameters (SMPP v3.4) have been added, UDH support for MOs, handling of intermediately delivery notifications, added 'message_payload' handling, added enhanced DLR parsing and handling of DLR's optional parameters, added "more messages to send" support. * EMI added XSer $0c and $0d handling, OP/31 handling for the sake of EMI implementations that use this construct as server-side initiated keep-alive mechanism. * CIMD2 has been rewriten to the new SMSCConn API layer, added additional support features 'our-host', 'our-port' and parameter 069 (service center address), harmonized log message formating, new 'no-dlr' config directive to indicate if DLR requests should be proceeded, added RPI (return-path-indication) support and binfo support via tariff class, allows setting PID for MT messages, adds "more messages to send" support. * HTTP SMSC added 'system-type = brunet' for an implemenation of bruNET's specific HTTP interface (bruHTP 2.1), harmonized debug output, added 'system-type = xidris' for an implementation of Xidris, 'dlrurl' and 'dlrmask' handling for Kannel message proxying, added 'system-type = wapme' for the Wapme SMS Proxy gateway interface. * SOAP/XML over HTTP module added. Yet not bound to abstraction layer. Hence this is yet experimental. * FAKE added DLR handling for fake smsc type. Now you can test DLR handling even while unattached to real SMSC. * AT added +CMTI support for MO messages, 2 new config options 'max-error-count' and 'reset-string' for hard reset of the modem when modem crashes. * OISD has been rewriten to SMSCConn API, added validity support. * HTTP admin command 'restart' added to restart bearerbox, 'loglevel' to change log-level of log-files while bearerbox is running. * Added 'our-host' interface support for binding to an explicit interface on SMSC connections. * Added smsc specific logging capability by handling open log files in exclusive or non-explusive mode, using 'log-file' and 'log-level' as smsc config directives. * Added --disable-wap and --disable-sms configure switches to disable parts in bearerbox. * Moved smsc group config directive 'reconnect-delay' into higher abstraction layer to provide this for all SMSC modules. Reconnect delay is defaulting to 10 sec. * Added internal restarting msg command among boxes. * Added new command line option ("-g" or "--generate") to bearerbox. This option just dumps all known config groups and options to stdout. * WAP added support for EFI inside WMLScript, added new application ids from OMNA web page, WSP encoding-version handling, logging of upstream HTTP server failures with HTTP response code 502 (bad gateway), new config option 'http-interface-name' to wapbox configuration and allow selecting of interface for outgoing HTTP requests, allows to put semicolon-separated list of IP addresses in 'wdp-interfaces' statement in config file and kannel send responses from proper addresses. * WAP Push added missing official WINA URIs, 'concatenation' and 'max-messages' config directive support for wapbox group, handling of PPG related DLR reports. PPG sends SMS with DLR, but smsbox has to do the DLR signalization to the specified DLR-URL. The stored service name is read from PPG core group, added 'default-dlr-url', 'ppg-smsbox-id', 'service-name' to ppg core group and 'dlr-url', 'smsbox-id' to wap-push-user group. * RADIUS accounting proxy implemenation added for MSISDN provisioning within WAP operations. * Added 'throughput' smsc group config directive for MT message per sec. limitation. * Added bearerbox internal re-routing via config directives 'reroute', 'reroute-smsc-id' and 'reroute-receiver' to multi-group 'smsc'. This allows MOs to be directly turned into MTs within bearerbox. * ORACLE 8i/9i support added for database polls and DLR handling. * PostgrSQL support added for database polls. * SQLITE added SQLite support for database polls. * Added new escape code '%I' for URL translations to allow inclusion of the internal SMS ID into the processing, new escape code '%T' for sending the UNIX epoch timestamp in favor of '%t'. * Added shell script 'gw-config' to allow 3rd party software to check for CFLAGS, LIBS and version of the installed Kannel instance. * Added 'binfo' to smsbox's sendsms interface to pass relevant billing identifier/information to smsc modules. * Added POSIX regular expression support. * Added Perl compatible regular expression (PCRE) library support via --enable-pcre configure option. * Added backtrace support for specific architectures for better debugging information on panics. Hint: use address within [] with addr2line or add -rdynamic to CFLAGS. * Added new config directives 'access-log-clean' and 'access-log-format' to allow custom core access.log formatting, 'access-log-time' to indicate if localtime or gmt should be used within access.log. * Added new command line parameters for daemons (all boxes): -P/--parachute : start watcher father process that catch and restart crashed child process -X/--panic-script : execute this script if child process crashed -u/--user : change process user-id (security) -p/--pid-file : write PID into the given file -d/--daemonize : daemonize the process * Added new config directive 'smsbox-max-pending'. Bugfixes: * SM/ASI fixed TON and NPI values, PDU decoding, decoding of binary MOs, enquire link pdu's were not sent within regular timeframe. * SMPP fixed generic_nack definition, sequence incrementation, charset encoding misbehaviour when msgs get split into multiple sms chunks, checking of esm_class for DLRs (only bits 2-5), PDU decoding bug for UDH sequence, wrong esm_class checking for deliver_sm PDU, improved error handling for wrong MO PDUs, shutdown sequence improvements, bug for re-encoding character set, bug that source-autodetect was 'false' if not defined in the config although userguide mentioned 'true', race conditions amonst status and connect_time while set in various threads, optional parameters handling improved. * CIMD2 fixed for CPU load consume while idle, wrong time for messages, wrong parameter length for "service description" field. * AT fixed panic if UDHI in PDU is set but user data length = 0, bug in non-blocking write to modem device, few race conditions. * HTTP SMSC fixed a number of bugs. Including bearerbox crash if smsc-id is stopped and /status page is called, don't 'fail' a MT message when the HTTP server can not be triggered, instead use 'reconnect-delay' to try again, expected MO parameters to 'username' and 'password' instead of 'user' and 'pass'. * SSL fixed a serious pthread_mutex bug for call-back function to the openssl thread locking, non-blocking write mode, memory leak in SSL handshake sequence, various improvements. * Fixed generic alt_dcs re-coding misbehaviour. * HTTP fixed basic auth problem with the passwd, redirecting, serious bug in the HTTP client code causing smsbox to crash if the connection is closed directly by the HTTP server. * Fixed bearerbox behaviour while receiving SIGHUP (restart) signal, signal handling that may have caused deadlock. * Fixed ACK/NACK handling beween bearerbox and smsbox. * WAP fixed and improved XML charset encoding handling, WSP header 'Encoding-Version' handling, HTTP referer header removed due to breaking specific WAP Forum certification tests, various fixes in WML compiler character encoding handling, DOS bug within WML compiler, possible segfault if WML document doesn't contain DTD section, crashing wapbox while comparing empty cookie strings, various memory leaks, WTP bug for abort PDU in speficic timeout events, fixed variable substitution within WML compiler. * WAP Push fixed malformed xml reponses for the PAP document, none accepted attribute 'product-name', case insesitive handling of constants "WAPPUSH" and "TYPE" for sake of interopertibility with existing PIs, handling of Push flag, PPG specifier and prologue parsing to support other PIs, including delimiter parsing, PAP MIME parsing, various memory leaks. * Fixed partially panics caused by too long UDH sequences. * DLR smsc-id is added now to DLR MOs from the temporary DB tablespace. * Queue policies have been improved for internal bearerbox to smsbox message transmission. * Fixed race conditions within store-file handling. * Fixed serious poll() handling of POLLHUP and POLLERR. * Fixed bug that config directive 'sendsms-chars' was not used at all in the logic, only the default remained. * Fixed bug in smsbox that crashed if %A is used in get-url. Changes since version 1.3.0: Compatibility breakers: * SMPP changed default behaviour of the 'source-addr-autodetect' to yes. Now the module will try to set TON and NPI automatically by scanning the given source adddress. * Added proxying of the smsc-id value to attached smsbox instances via the HTTP SMSC module. This allows spreading load from one smsbox to several bearerbox instances. New features: * Additional debian packaging files. * Documentation section about log file rotation. * PPG now allows routing to explicite smsc-id's. New config directives 'default-smsc' for ppg group and 'forced-smsc' and 'default-smsc' for wap-push-user group have been added. * Added debug info about ammount of outstanding HTTP reqeusts in the smsbox retry queue. * OIS added direct module. * CIMD2 added validity setting. Bugfixes: * CIMD2 various fixes for correct urltrans()ing. * AT2 fixed double-increment bug for outgoing messages counter. * Fixed a keep-alive lookup problem when using a HTTP proxy. * HTTP SMSC various fixes. * Fixed infinite loop bug if /TYPE=xxx is missing in the PAP document. * Fixed a bug in the smsbox routing behaviour of bearerbox. * SMPP various fixes for the optional fields decoding. * EMI2 fixed MO counter bug and assignmend of non-existing fields bug. * Various fixes in the WAP application layer. Changes since version 1.2.1: Compatibility breakers: * Added initial SMPP v3.4 optional fields support. Still very experimental. Use the 'interface-version = 33' config directive if you don't want to rely on this new code. * HTTP servers can bind to specific interfaces now. * WTP timer frequence can be set now manually with 'timer-freq' value. * EMI2 handling of un-acked msg can be configured via 'wait-ack-expire' directive. See User Guide for more details. New features: * WTP-SAR (segmentation and re-assembly) is now available for the WAP gateway part. This enables Kannel to function as MMS proxy. This has been tested with several new MMS capable phones. * smsbox inbound routing has been added. It allows routing based upon smsc-id or receiver number rules to specific smsbox instances. This may be several real smsboxes or even own boxes that act to bearerbox as if they are smsboxes by using the same message communication interface. This is useful for implementing own boxes that act as EMI/UCP or SMPP proxies. * iconv support has been added for character encoding. Adds 'alt-charset' directive for the SMPP smsc group. Use iconv's type representation to define which charset is used by a specific smsc. * HTTP connections are now established in non-blocking mode. * Added speed 115200 for AT2 connections if system supports. * Protection against malformed PDUs for AT2 has been increased. * Added detection of invalid TP-OA address length and logging for AT2. * Added National Replacement Codes (NCR) ISO 21 German for german umlauts to be used with 'alt-charset' directive. * Added Siemens SL45 init strings for AT2. * Added a WAP packet proxy application, test/wapproxy.c. This may be used to act as a WDP, WTP proxy between WAP client and WAP gateway for packet analyzation purposes. * Allows returning to the 'device-home' URL if 'smart-errors' are activated. This can be used to let the phone go back to a pre-defined URL in case an serious error happens, i.e. HTTP lookup of an URI fails. Bugfixes: * SMPP thread handling bug fixed. * AT2 date encoding bug fixed. * HTTP basic auth userid and password handling bug fixed. * Fixed WAP smart-error message bug, when HTTP lookup failed. * AT2 init string in Siemens TC35 configuration fixed. * Fixed various SSL connection related bugs. * DLR race condition due to unlocked list fixed. * Fixed memory leak in smsc abstraction layer for restarting smscs. * Fixed initial approach for client SDU size to solve the problem with concatenated WSP requests. * SMPP throttling problem fixed. * Fixed HTTP queueing bug. * Various improvements and fixes in the HTTP routine library. * Fixed panics for /store-status calls if no store-file is used. * Fixed difftime calculation to make heartbeat work again. * Fixed possible race condition in store file saving. Development news: * We need to think about and rewrite the iconv() character encoding layer. The character encoding should be done in the smsc module abstracted layer and not in the smsc specific module layer. As a base encoding we are going to use latin1. Changes since version 1.2.0: Compatibility breakers: * SMPP module users should note that the 'msg-id-type' default behaviour has changed. The SMPP spec says that msg ids should be C strings and hence we treat them as such per default. If your SMSC gives msg ids in submit_sm and deliver_dm PDUs in different numbering basing, then please use the 'msg-id-type' config directive to set it accordingly. New features: * SMPP priority flag is now supported. * SMPP unbind PDU handling added. * SMPP throttling error code support added. * MacOS X support has been improved. * Added 'allowed-receiver-prefix' and 'denied-receiver-prefix' for sms-service groups. This is used to restrict access to service requests coming in on certain receiver numbers, i.e. shortcut numbers. * Added directives 'http-request-retry' and 'http-queue-delay' for HTTP request queueing for sms-service 'get-url' and 'post-url' services. This way a non reachable HTTP server will not cause to drop the request. Instead smsbox will hold a queue and retry the HTTP request via the configurable settings 'http-request-retry' and 'http-queue-delay'. * Added 'store-status' HTTP admin command to retrieve the messages currently in the main queue. * Added a '--with-cflags=CFLAGS' and '--with-libs=LIBS' configuration options. These are useful when Kannel is linked against additional proprietary modules. * Improvements in the Siemens M20 GSM modem support. * Added EMI2 specific configuration directives 'notification-pid' and 'notification-addr'. * Added Return Path Indicator (RPI) support for SMPP and EMI2 via boolean sendsms interface parameter 'rpi' * LibSDB support for external storage has been added. libSDB is an abstraction library for various DB system, including MySQL, PostgreSQL, Oracle, gdbm and some others. * wapbox has an own access.log facility now. * Added the new 'smasi' SMSC type for connecting to SM/ASI protocol SMSC, like the CriticalPath InVoke SMS Center. * Added HEAD method support for HTTP client module. * DLR support for the AT2 module has been added. * Slight re-organization of the DLR module to make it easier in supporting other SMSC modules too. * Added 'unified-prefix' configuration directive on a smsc basis to set number normalization rules. This may be used it SMSC connections handle prefix normalization differently. * Added 'source-addr-autodetect' to smsc group for auto-detecting source addr in smpp module, if desired. Bugfixes: * Timezone issue fixed in SMPP module. * Output of fakewap has been made more human-readable. * Various fixes and improments in the wmlscript parsing routines. * Fixed various other possible segmentation faulting bugs in handling null'ed Octstr vars. * Fixed various mutex problems that caused errors while accessing lists. * Some fixes in HTTP keep-alive handling logic that causes our client to keep the connection up, even while the server has asked to drop it. * Various fixes and improvements in the PPG (push proxy gateway) module. * Fixed a bug in the prefix-match routine that caused to tread an number match not to be a prefix match. Changes since version 1.1.6: Compatibility breakers: * configure now uses the --enable-localtime as default. This will log file stamps in local time, not GMT. Beware if you need other timezone date logging to switch this off. * configure now uses the --with-malloc=native as default. This is more suitable for production environments then the limited malloc checking counterpart. * Use the 'to' HTTP GET variable to specify the destination MSISDN of outbound messages for both sendsms and sendota HTTP interfaces. * wapbox does not any longer start a PPG HTTP server thread if no ppg group is specified in the configuration file. New features: * Harmonized logging output for EMI2 and SMPP module. * Added on-the-fly shutdown and re-start for specific smsc-ids via the administrative HTTP interface URIs 'stop-smsc' and 'start-smsc'. * Added traffic statistics of inbound and output SMS on the status page. * Added 'interface-version' config directive for SMPP module. * Added timing configuration directives for SMPP module to specify reconnect delays and timeout values. * Added alternative DCS support for SMPP module to define alternative DCS value via sendsms's alt-dcs flag. * Added support for XML POSTs of SMS messages on the basis of the IETF draft http://search.ietf.org/internet-drafts/draft-koponen-sms-xml-03.txt. * Added transceiver mode for SMPP links. * Added wapbox directive 'smart-errors' for smarter WSP error messages to the handset device. * Added wapbox directive 'force-sar' for forced processing of segmentation and reassembly (WTP-SAR) packages. Bugfixes: * Fixed compiler warning for gcc 3.x for compiler macros. * Fixed a couple of memory leaks in various modules. * Improved the output of the status page and fixed the status condition if an SMPP link is only used as receiver. * Fixed validity issues in the SMPP module. * Fixed a possible segv bug in SSL connection opening call. * Fixed handling of application ids in the PPG module. * Implemented a queue limit for outbound messages. This should hold up the situation that there are infinitely more messages injected to the queue then there are outflowing to the SMSC connections. * Further improvements in the AT2 module. * Fixed some MySQL related problems while processing DLRs to databases. Changes since version 1.1.6: Compatibility breakers: * GET method variable 'phonenumber' will be replaced by 'to' for the sendota HTTP interface. Currently we run both, to allow users to switch seamlessly. New features: * sendota HTTP interface requests can be send in POST method mode containing special X-Kannel HTTP headers for the control information and the OTA XML document as body content. Changes since version 1.1.5: Compatibility breakers: * Major restructuring of the AT2 module has been done. See the ChangeLog for more details. New features: * PPG module has been introduced and works for both IPv4 and SMS based bearers. Supported document types are SL and SI. The PPG is an essential item of the WAP Push architecture. * WTLS support has been included, but yet not finished. Development in this area is still needed. * Flash SMS support added. Messages that arrive at mobile terminals are displayed directly to the user interface and usually they can not be saved to the inbox. * 3G Lab contributed the XML files for their Alligata. * Added "keepalive" feature for EMI2 module. * MWI (message waiting indicator) message support added. These messages do cause the mobile terminal to indicate special events on the user interface, i.e. showing that a new E-Mail has arrived. * AT2 now supports Siemens TC35 * Added DLR (delivery report) support for SMSC modules. Delivery reports are returned by SMSCs and can trigger a defined URL in order to inform the pushing application of a successful transmission of the message. URLs can be set on a per-message request basis and hence semantics of the message ID is kept by the requesting application. * AT2 now support autodetection of modem devices. * HTTP basic authentication can be used now for sms-service groups. This allows SMS services to access HTTP resources that need explicit user authentication using the HTTP basic authentication scheme (RFC 2617). * EMI2 windowing control has been added. * DLRs may be stored to external storage. Using the --with-dlr configure flag external storage spaces may be used for the DLRs. This is useful in cases you take your boxes down and do not want to loose all pending DLR messages. Currently MySQL is supported as external storage. * SSL-enabled HTTP servers are now available for any HTTP interface. Users may rely now on secured HTTPS scheme communication between HTTP clients and Kannel's HTTP servers. This is used for the sendsms and the administration HTTP interface. * Cygwin platform is now supported out-of-the-box without additional pthreads libraries from 1.3.9. * WAP OTA (over-the-air) has been improved. OTA settings and bookmarks may be send via SMS bearer to capable mobile terminals. Pre-defined sets from the configuration may be send or individual sets using a GET request parameter. This will change to allow POST of the OTA XML document. * Several new phones are supported for the AT2 module. See the doc/modems.conf file for their definitions. * New sendsms HTTP interface field 'account' has been introduced. This is mainly for accounting purposes. * SSL-enabled inter-box TCP communication can be used. In case boxes are running on different machines in different unreliable networks this may be used to secure the TCP connection between them, i.e. smsbox talking to a remote bearerbox and communication is SSL-enabled. * URIs for the HTTP interfaces configurable. The HTTP interface default URIs for the sendsms and sendota functions may be defined in the configuration to individual URIs. * Added SMSC interface implementation to Sonera ContentGateway. * Solaris packaging added. * Added 'exec' translation type to sms-service. This allows to execute arbitrary external code and pass the output as reply to the message sender. * Include within configuration files added. This makes 'include = "foobar.conf"' possible and hence segmenting the groups to their own config files to make the setup more clean. * Improved HTTP SMSC behaviour. * SIM buffering for AT2 has been included. This is a fail-safe mechanism to handle messages that pass the regular line of processing to the SIM card. Bugfixes: * Various fixes in all major SMSC modules. * Fixed bugs in text concatenation. * Fixed make process bug for Solaris 2.6 * Various memory leaks have been fixed. * Fixed default DocBook detection for FreeBSD platform. * Fixed forced-smsc bug for sendota HTTP interface. * Fixed issues to support Linux on PowerPC and S390 again. Development news: * WTLS is the next major challenge. At least --with-wtls=openssl configure leads to a clean make process. 3ui's kwtls package seems to be good enough as sample for the missing WTLS parts. * Added general MySQL connection support. This may be extended to have several groups reside in corresponding MySQL tables and hence operation of highly dynamical environments gets easier, because there is no need to restart or -HUP the boxes. Changes since version 1.1.4: Compatibility breakers: * sendsms service now uses the HTTP status code in replies, instead of always using 200. Valid requests get 202 (Accepted), invalid requests get an error code. New features: * fakewap is better at testing high loads. * Added sender-prefix configuration variable for CIMD2. * A new sms-service escape sequence, %i, which expands to the smsc-id of the message. * Added a status.xml service to the administration interface. Bugfixes: * Minor bugfix to emi2. * Fixed handling of accept-x-kannel-headers and assume-plain-text configuration fields. * Phone-as-SMSC driver can handle text messages with UDH. * Fixed a rare case that could cause a deadlock between the bearerbox and smsbox. * Fixed a bug that prevented having many smsc configuration blocks. * HTTP: Correctly handle redirections to invalid URLs. * Don't panic if there is no "default" sms-service. Development news: * Beginnings of https support. Not secure yet. Changes since version 1.1.3: Security: * smsbox: X-Kannel-UDH headers in HTTP responses are no longer accepted, unless accept-x-kannel-headers is configured for the service. This prevents possibly untrusted sites from setting strange UDH values. * Bugfix: An empty POST request from a client could crash the wapbox. Compatibility breakers: * smsbox: HTTP responses with content-type application/octet-stream (or no content-type at all) will be sent as "octet data" instead of assumed to be text/plain. This makes it possible to send for example ring tones in response to user messages. * smsbox: The "user" field is now required in all sendsms services. * Kannel now uses the same "data coding scheme" values in all SMSC protocols that use them. It is now used only to set the alphabet, and leaves the message class alone. This affects the Phone-as-SMSC, CIMD2, OIS, and SMPP modules. * Compiling Kannel now requires libxml 2.2.5 or later. New features: * New sms-service type "posturl", which makes a POST request containing the message in the body and other information in X-Kannel- headers. The sendsms interface also accepts POST requests in this format. Not documented yet. * Sendsms services also accept POST requests. * smsbox: X-Kannel-From and X-Kannel-To headers can be used in HTTP responses to set the sender and receiver numbers, if accept-x-kannel-headers is configured for the service. * New, improved module for UCP/EMI SMSC protocol, called "emi2". It will replace the emi and emi_ip modules in the future, but coexists with them in this release. * New configuration variable catch-all in sms-service configuration groups. If this is set, the service will be used for all messages that match its keyword, instead of only messages that have the right number of words. Useful for defining service-specific error replies. * Configuration variables such as "concatenation" can now be set to yes/no or true/false instead of just 0 or 1. * Kannel can be configured to store incoming SMS messages in a file until they have been processed, so that they can not be lost in a crash. * Improved portability to MacOS X. * SMPP SMSC module will send enquire_link packets at regular intervals. This is needed to stay connected with some SMSCs. * Significant improvements to the SMPP SMSC module. It should now be ready for serious use. * Phone-as-SMSC module will retry a few times if sending a message fails. This works around many temporary problems. Bugfixes: * Support libxml versions that install xml2-config instead of xml-config. * Several memory leaks fixed. * Fixed panic if faked-sender configuration variable is used in a sendsms service. * Sendsms replies now have no-cache headers to prevent proxies from trying to cache sendsms queries. * Some PDU encoding errors in the Phone-as-SMSC module were fixed. * CIMD2 SMSC module works around a bug in some SMSCs that could cause messages to be received multiple times. * HTTP module can (again) handle "100 Continue" responses from servers. * Lots of minor bugfixes. Development news: * More work on WAP Push. Known problems: * New POST-based interface for SMS is not documented. * The CIMD2 SMSC module can sometimes send multiple "alive" requests at a time, which breaks the protocol and confuses the SMSC. * Concatenated text messages don't work with all protocols. Changes since version 1.1.2: Security: * A bug in the error handling code would make Kannel crash if a HTTP request (for example to sendsms) contained literal spaces in the URL. This has been fixed. The problem was not present in the 1.0 series. New features: * New "http" SMSC which allows Kannel to be used with HTTP-based SMS interfaces (such as Kannel itself, so that you can chain them). * WML compiler produces slightly smaller output. Bugfixes: * Phone-as-SMSC module made more reliable under high load. In particular, reopening a broken connection works again. * Bearerbox no longer treats any UDP errors as fatal, they are just warnings now. * Several memory leaks fixed. Development news: * Started a benchmarking framework, activated with "make bench". * Bearerbox now uses the conn module for box connections. * octstr_format takes a new %E format which does http-url encoding. Changes since version 1.1.1: Compatibility breakers: * Format of access log output has changed. New features: * Support for Ericsson GSM modems. * smsbox: HTTP responses can now send UDH messages by sending an X-Kannel_UDH header in the reply. * smsbox: Added "%b" translation for receiving binary data. * Updated and expanded User's Guide. * SMPP driver now responds to Enquire Link packets, which will help keep Kannel connected to an SMS center when the connection is idle. * Small perl script to read and summarize access log output. * wapbox is better at dealing with HTTP responses that are too large for the client, or in the wrong format. Bugfixes: * WMLScript compiler avoids generating zero-length functions, so that the result works on more clients. * smsbox: Numerous fixes to the message splitting functions. * smsbox: OTA configuration works again. * WML compiler: Corrected encodings for "ordered true" and "ordered false". Development news: * WML decompiler improved. Changes since version 1.1: Compatibility breakers: * Kannel now complains about unknown configuration settings, rather than silently ignoring them. New features: * The SMS testing tool (fakesmsc) has been replaced with a better one. It can be started and stopped while Kannel is running, which makes it easier to use. It also supports udh. * validityperiod option for phone-as-SMSC, see user guide for details. * User's Guide has section on how to use pre-compiled Kannel packages. * Improved portability to FreeBSD. * Updated CIMD2 code to version "2-0 en" of the specification. Bugfixes: * http-proxy-exceptions works again. * SMS service keywords are case-insensitive again. * If SMS request has unknown keyword, and no default is specified, reply "Request failed" instead of logging a confusing error message. * Fixed possible deadlock in bearerbox startup. * Fixed a number of memory leaks. * Fixed some errors that only showed up with --with-malloc=native. Development news: * All boxes now use the new configuration file interface. Changes since version 0.13.1: Compatibility breakers: * Replies from the bearerbox admin interface are now formatted according to the Accept: headers sent by the client, preferring WML over HTML over plain text. They used to always be plain text. * Filling in admin-password is now mandatory in the configuration file. * In the configuration for UCP/EMI SMSCs, username and password are now used if they are set, and not used if they are not. They used to be mandatory even though they were never used, so in existing configurations they are likely to contain dummy values that will not work. (This was actually changed before 0.13.1, we forgot to note it then.) New features: * New SMPP module. Written for SMPP 3.4 but should support 3.3 as well. * smsbox reports load to the bearerbox. * Added status.wml, status.html, and status.txt commands to the bearerbox admin interface, to return status in a specific format. * If admin commands are tried with the wrong password, the response is delayed, in order to limit brute force password cracking. * New configuration variable status-password, which protects the status admin command if it is set. * Admin commands can be used without a /cgi-bin part in the URL. So http://localhost:13000/cgi-bin/status can now become just http://localhost:13000/status. * New smsc configuration group variable 'allowed-smsc-id', which lets you limit which messages can be sent to a specific SMSC. * New architecture documentation. * New SMS testing tool called fake2. It works like the old fakesmsc, but can be started and stopped while Kannel is running, which makes it easier to use. * New URL translation %k in smsbox, which is replaced with the keyword of the SMS request. * Improved portability to FreeBSD by using less stack space per thread. Bugfixes: * The u-dieresis (u with two dots) was translated incorrectly to the GSM character set, in the AT, CIMD2, and SMPP drivers. Fixed. * The EMI used to crash if username was not set. Fixed. * WML compiler can handle a libxml that was compiled with the -DXML_USE_BUFFER_CONTENT flag. * WML compiler: If charset is not supplied in a WML file, the one from the HTTP content-type header is used instead, if available. * Fixed signal handling on Solaris and other systems with POSIX threads. Development news: * New SMSC interface in the bearerbox, which should allow much faster implementations and better error handling. There is a wrapper for the old interface, because no SMSC drivers have been converted yet. * New configuration file interface that uses Octstrs. * Work started on WAP Push. Changes since version 0.13: New features: * WTP and WSP protocol stacks are now separate, so that other projects than Kannel can make use of them. * Redesigned smsbox to have a stable number of threads. It is much more stable now, handles more requests at a time, and shuts down more cleanly. * sendota interface accepts more than one OTA configuration. * Driver for UCP/EMI SMSCs supports authenticated sessions. * smsbox accepts WML responses as well as plain text and HTML responses. Bugfixes: * Improved HTTP module's support for HTTP/1.0 clients and servers. * Fixed UDH encoding in Phone-as-SMSC module. * Fixed splitting of SMS messages that have UDH. * HTML to SMS conversion now deals with entities like Ӓ correctly. (Also fixed in 0.12.3) * Several bugs and memory leaks fixed in SMPP module. * Bearerbox detection of inactive SMSCs is less trigger-happy. This greatly improves throughput if the roundtrip to the SMSC is slower than 10 milliseconds. (Also fixed in 0.12.3) * Detect libxml 2.2.10 and above as part of the 2.2.x series. (Also fixed in 0.12.3) * Fixed some memory leaks. Development news: * Checking malloc now displays some of the contents of the memory leaks it finds, which makes it much easier to track them down. * Started building support for WAP Push. Changes compared to version 0.12.3: New features: * HTTP module restructured to use a fixed number of threads. This makes it able to handle many more requests at a time. * Kannel boxes report version numbers of themselves and their components (such as libxml) when starting up. * Support for proxies that require basic authorization. * Bearerbox "status" command reports lengths of internal queues. * Phone-as-SMSC module now also supports Falcom A2D modem and Nokia 7110. * Added configure option --with-defaults=speed for production systems. * Updated documentation. * Bearerbox starts up faster. * sendsms interface can handle multiple requests over one HTTP/1.1 connection. * Improved portability to HP/UX, FreeBSD and Cygwin, possibly others. * Support magic URL "kannel:alive", to check if the gateway is still running. * Support for PAM authentication of sendsms interface. * Sendsms interface checks that UDH messages have a correct length indicator. Bugfixes: * Fixed several bugs in Phone-as-SMSC module. * Fixed the problem that switching malloc wrappers required a "make clean" when recompiling. Development news: * Many files have been reformatted to our new coding style. * Renamed Msg type smart_sms to just sms. * New Dict module in gwlib, for Octstr -> value hash tables. * New FDSet module in gwlib, for efficient polling of large sets of file descriptors. Used by HTTP module. Connection module has extensions for it. See ChangeLog for detailed information. gateway-1.4.5/mkinstalldirs0000644000175000017500000000132107032671456014476 0ustar toljtolj#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Public domain # $Id: mkinstalldirs,v 1.1 1999-12-30 14:58:54 liw Exp $ errstatus=0 for file do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr fi fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here gateway-1.4.5/doc/0000755000175000017500000000000013312227711012430 5ustar toljtoljgateway-1.4.5/doc/ChangeLog-1.3.00000644000175000017500000002777610203150325014652 0ustar toljtolj2003-01-05 Stipe Tolj * doc/userguide/userguide.xml: some credits for Aarno and me. 2003-01-04 Stipe Tolj * gw/bb_store.c: fixed possible race conditioning in store_save(). Thanks to Alexander for pointing this out and providing a patch. [Msg-ID: <200301040008.44151.a.malysh@centrium.de>] * gw/wapbox.c, gw/wap-appl.c: added device_home global to allow returning to the device-home URL if smart-errors are activated. 2003-01-02 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed typo from last commit. * gwlib/charset.c: fixed compiler warning. 2003-01-01 Stipe Tolj * gw/bb_store.c: fixed a if statement clause. Thanks to Alexander. * gw/smsc/smsc_smpp.c: applied Nisan's generick_nack changes. [Msg-ID: <5.1.0.14.0.20021211132822.00ab3da0@amagoblin.ialien.co.za>] 2003-01-01 Stipe Tolj * gw/smsc/smsc_smpp.c: Added Alexander's patch to support clean suspend mode for the SMPP module. [Msg-ID: <200212111207.23455.a.malysh@centrium.de>] * doc/userguide/userguide.xml: added 'wait-ack-expire' documentation for the UCP/EMI section. * gw/smsc/smsc_emi2.c: Added Nisan's wait-ack-expire patch to handle msg was not acked event. 2002-12-31 Stipe Tolj * gw/smsbox.c: added account to fill_message(). Thanks to Paul. [Msg-ID: <005701c2b0c0$4140cb50$0300a8c0@anam.com>] * gw/heartbeat.c: fixed difftime calculation to make heartbeat work again. Patch provided by Alexander Malysh [Msg-ID: <200212262253.18847.a.malysh@centrium.de>] 2002-12-27 Stipe Tolj * gw/bb_store.c: fixed assertion panic when admin URI /store-status is called while there is *no* store-file used. Bug has been reported by Mauricio Ramos . Patch based on submission by Alexander Malysh . [Msg-ID: <200212261844.46127.a.malysh@centrium.de>] 2002-12-26 Stipe Tolj * gwlib/http.c: added some more debugging output and fixed missing NULLing of reused trans->host for parse_url(). * gw/smsbox.c: fixed missing destruction of structures in http client retry thread http_queue_thread(). * gw/wapkannel.conf: roll-back to previous revision. Veto against commited changes from igor that don't make any sense here. * test/test_http.c: made the whole thing more cleaner, in means of requesting and getting responses. Will now spread the load (-n switch) accross all threads that are defined with -t switch. 2002-12-23 Aarno Syvänen * timer-freq patch: * gw/wapbox.c: added reading of timer-freq values * wap/wap.h: wtp_initiator_init and wtp_responder_init passes timer-freq values * wap/wtp_resp.c, wap/wtp_init.c: use timer-freq configuration variable as a 'timer tick'. 2002-12-13 Igor Ivoiov * wap/wtp_pack.c: fixed a bug in wtp_pack_sar_ack() with sprintf into char that could cause a segfault. Thanks to Aarno Syvanen [Message-Id: ] 2002-12-10 Stipe Tolj * gw/smsbox.c: fixed a bug in url_result_thread() which caused no reply if HTTP request queueing was used. Thanks to Paul for this. 2002-12-07 Stipe Tolj * config.h.in, configure[.in]: added iconv support and detection * gwlib/charset.[ch]: added charset_convert() routine as wrapper for iconv calls to convert from a known charset encoding to an other. * gw/smsc_smpp.c: uses iconv library to convert character encodings. Orginal patch from Alan. Adds 'alt-charset' directive for the smpp smsc group. Use iconv's type representation to define which charset is used by a specific smsc. * doc/userguide/userguide.xml: added 'alt-charset' documentation. 2002-12-07 Stipe Tolj * gwlib/conn.c: fixed reentrant bugs in conn_shutdown_ssl() and server_shutdown_ssl(). Thanks to Paul for pointing this out. * test/wapproxy.c: fixed a couple of compiler warnings. * gw/sms.c, gw/smsbox.c: only minor coding style changes. 2002-12-05 Andreas Fink * gw/smsc/smsc_smpp.c: fixed throttling problem in SMPP which was triggered by getting back a generic error instead of a submit_response error. For incoming messages the original ID is set (my-number problem) as a temporary fix and if coding is not 1, then conversion to latin1 is not done to allow incoming unicode and binary to work properly. 2002-12-03 Igor Ivoilov * wap/wsp_server_session_states.def: fixed initial approach for client SDU size to solve the problem with concatenated WSP requests. Thanks to Vjacheslav Chekushin for pointing out the problem with nokia 7210 [Message-ID: <3DD34FED.5010305@lmt.lv>] 2002-12-03 Stipe Tolj * gw/bb_smscconn.c: fixed memory leak in smsc2_restart_smsc(), thanks to Nisan for spotting this. 2002-12-02 Stipe Tolj * gw/dlr.c: fixed race condition due to unlocked list. Thanks to Alexander Malysh for this patch [Msg-ID: <200212021737.55308.a.malysh@centrium.de>] 2002-12-02 Stipe Tolj * gwlib/conn.c: added openssl free'ing stuff reported by Paul in conn_shutdown_ssl() and server_shutdown_ssl(). 2002-12-02 Stipe Tolj * test/wapproxy.c: added our wap packet proxy debugging tool to kannel 2002-12-02 Stipe Tolj * gw/smsc/smsc_emi2.c, gwlib/http.h, gwlib/charset.h: fixed some minor compiler warnings. 2002-11-26 Oded Arbel * doc/examples/modems.conf: Fixed init string in Siemens TC35 configuration, thanks to Fogarasi Andras . added Siemens SL45 configurations, don't remember who gave it to me, sorry. 2002-11-25 Oded Arbel * gw/smsc/smsc_at2.c, gw/smsc/smsc_at2.h: patch to fix swap_nibbles to use unsigned char. Patch provided by Sindunata Sudarmaji . 2002-11-20 Stipe Tolj * gw/bb_http.c, gw/smsbox.c, gwlib/cfg.def: patch to allow to bind to a specific interface for smsbox's sendsms interface and bearerbox's admin HTTP server. Patch provided by Nisan Bloch . [Msg-ID: <5.1.0.14.0.20021118225946.024d51a0@amagoblin.ialien.co.za>] 2002-11-20 Stipe Tolj * gwlib/charset.c: fixing a compiler warning, thanks to Ignat Vassilev for providing patch 2002-11-18 Stipe Tolj * gwlib/cfg.def: added missing 'field-boxc-id' field in 'dlr-db' grou. Thanks to Ignat Vassilev for pointing this out. 2002-11-18 Stipe Tolj * gwlib/http.c: added http_open_port_if() to bind to specific interface. Thanks to Nisan for this patch. 2002-11-18 Stipe Tolj * gw/bb_smscconn.c: processing now number normalization on smsc basis first and for the global define rules. * gwlib/http.c: HTTP basic auth is supported, so fixed the comments. * gw/alt_charsets.h, gw/smsc/smsc_emi2.c, gwlib/charset.c: added NCR ISO 21 German for german umlauts to be used with 'alt-charset' directive. 2002-11-15 Stipe Tolj * doc/userguide/userguide.xml: added explanation about 'field-boxc-id' directive in 'dlr-db' group. * gw/wap-appl.c: fixed a bug if 'smart-errors' was on in wapbox group and the HTTP lookup failed, reported by Peter Löfman . 2002-11-14 Stipe Tolj * gw/shared.[ch]: added wrapper for connecting to bearerbox from external boxes and return the connection itself if successfull. 2002-11-14 Stipe Tolj * gw/smsc/smpp_pdu.c, wap/wtp_resp.c: fixed compiler warnings. 2002-11-14 Stipe Tolj * doc/userguide/userguide.xml: added 'smsbox-id' directive and 'smsbox-route' group documentation * gw/bb_boxc.c, gw/bb_smscconn.c: added smsbox specific identified handling * gw/dlr.[ch]: added smsbox instance identifier handling in DLR code. This is necessary if you want to route the DLR message the same logical channel back to the sending smsbox instance entity, like in EMI/UCP and SMPP proxying cases. * gw/msg-dec.h, gw/msg.h: added admin message field that is used to transport the identified while an smsbox instance is identifying itself at startup. * gw/smsbox.c: added handling of 'smsbox-id' directive that allows an smsbox instance to identify itself to bearerbox for routing purposes. * gw/smsc/smsc_*.c: changed function calling to dlr routines to fit new way. * gwlib/cfg.def: added directive 'smsbox-id' to smsbox group and 'smsbox-route' for setting routing rules for smsbox instances. * test/fakesmsc.c: added 'route' message type to simulate an inbound message that should be routed to an specific smsbox instance. The whole block is mainly what we called the "smsbox routing patch". It allows routing based upon smsc-id or receiver number rules to specific smsbox instances. This may be several real smsboxes or even own boxes that act to bearerbox as if they are smsboxes by using the same message communication interface. This is useful for implementing own boxes that act as EMI/UCP or SMPP proxies. [Msg-ID: <3D790901.B126AAC9@wapme-systems.de>] 2002-11-14 Stipe Tolj * gw/smsc/smpp_pdu[ch,def], gw/smsc/smpp_pdu_opt.def, gw/smsc/smsc_smpp.c: Added SMPP v3.4 optional field support. This is a first prelimiary version, but has been proven at Wapme to work in production. 2002-11-13 Stipe Tolj * gwlib/conn.[ch], gwlib/http.c, gwlib/socket.[ch]: applied non-blocking patch for http connections, submited by Vjacheslav Chekushin [Msg-ID: <3DD1103B.7000405@lmt.lv>] 2002-11-13 Stipe Tolj * wap/wtp_resp_states.def: fixed compiler warning 2002-11-12 Stipe Tolj * gwlib/http.c: fixed a bug in basic auth userid and password handling, reported by Vjacheslav Chekushin 2002-11-12 Stipe Tolj * gw/smsc/smsc_at2.c: fixed a bug in date pdu deocding, patch submited by Sindunata Sudarmaji [Msg-ID: <20021023132104.A4594@top4>] 2002-11-12 Stipe Tolj * gw/wapbox.c, gwlib/cfg.def, wap/wap_events.def, wap/wtp.[ch], wap/wtp_pack.[ch], wap/wtp_pdu.c, wap/wtp_resp.[ch], wap/wtp_resp_machine.def, wap/wtp_resp_states.def: long awaited WTP-SAR support, a huge special thanks goes out to Igor Ivoilov for this. [Msg-ID: <7AAE7951AE8F1C41902D5BBC4129D42701E5FD39@limex2k.francoudi.com>] 2002-11-11 Stipe Tolj * gw/smsc/smsc_smpp.c: fixing a thread handling bug, reported by Paul. 2002-11-07 Oded Arbel * gw/smsc/smsc_at2.c: fixed compilation warning from last commit 2002-11-06 Oded Arbel * gw/smsc/smsc_at2.c: added detection of invalid TP-OA address length in decode_deliver_sm(); added logging in case of decode_deliver_sm() failure. 2002-11-06 Oded Arbel * gw/smsc/smsc_at2.c: added speed 115200 if system supports; added simple protection against malformed PDUs in decode_deliver_sm. 2002-10-22 Stipe Tolj * Re-creating stable release 1.2.1. 2002-10-22 Stipe Tolj * gw/smsc/smsc_at2.c: fixed a major bug in 7bit encoding. Thanks a lot to "Rodrigo Sousa Coutinho" for patch. [Msg-ID: <004c01c279da$5d6a3c70$ca00a8c0@domain.outsystems.com>] 2002-10-20 Stipe Tolj * Making stable release 1.2.1. gateway-1.4.5/doc/ChangeLog-1.10000644000175000017500000005710407525470177014525 0ustar toljtolj2001-01-22 Richard Braakman * Making release 1.1. 2001-01-22 Kalle Marjola * gw/wapbox.c: fixed read-config and map_url_max which caused wapbox to stuck and never start * gw/smsc_wrapper.c: added one debug message 2001-01-22 Richard Braakman * gwlib/gwthread-pthread.c: Split gwthread_create_real() into four functions to separate the signal handling code from the thread code. This way the sigmask will also be restored if thread creation fails. (Spotted by Uoti) * gw/smsbox.c: In obey_request(), handle TRANSTYPE_SENDSMS as well, to avoid the rather cryptic default error message if this error occurs. Still investigating why it occurs at all. 2001-01-22 Kalle Marjola * gw/smsc_wrapper.c: fixed startup-order, to avoid segmentation fault if smsc startup fails 2001-01-22 Lars Wirzenius * gw/wap-appl.c: Fixed memory leak (a Mutex was not being destroyed) and related whitespace usage and made the Mutex static. Also removed a spurious editorial comment with an "I" referring to me, even though I didn't write it. * gw/wapbox.c: Made some global-but-static variables with configuration information local to the function that reads and processes the config. 2001-01-22 Richard Braakman * gwlib/gwthread-pthread.c: In function gwthread_create_real(), applied Nick Clarey's patch to fix signal handling and restyled. Then fixed signal handling some more by using pthread_sigmask instead of sigprocmask, and SIG_BLOCK instead of SIG_SETMASK. This way we won't interfere with signals used by the pthread implementation. * gw/bearerbox.c, gw/smsbox.c, gw/wapbox.c: Updated comment in signal_handler() to reflect the new situation, and made them all use gwthread_shouldhandlesignal(). 2001-01-22 Lars Wirzenius * gw/wapbox.c: Converted to use new config file module in gwlib. 2001-01-22 Lars Wirzenius * gwlib/accesslog.c: Made the output buffer be allocated via dynamic memory to avoid overflowing the stack with large local variables. * gwlib/log.c: Made output buffer smaller, again because of stack limitations. The new limit is one kilobyte, but since it is used only for certain parts of the output (the prefix with dates etc, and the format string), it should be plenty. 2001-01-21 Lars Wirzenius * doc/userguide/userguide.xml: Changed SMPP version to 3.4. * gw/smsc_smpp.h: Removed. I thought I had removed it earlier already. * test/fakewap.c: Fixed memory leaks. 2001-01-19 Tuomas Luttinen * gw/wml_compiler.c: Added function set_charset to fix bug with the character set read from the http-headers. 2001-01-18 Lars Wirzenius * gwlib/octstr.[ch]: Renamed the horribly long name octstr_create_immutable to octstr_imm. This should make it a bit more palatable. * gw/html.c, gw/smsbox.c, gw/smsc_at.c, gw/smscconn.c, gw/urltrans.c, gw/wap-appl.c, gw/wap_push_ota.c, gw/wml_compiler.c, gwlib/cfg.c, gwlib/http.c, test/test_dict.c, test/test_headers.c, test/test_http_server.c, test/test_octstr_immutables.c, test/wml_tester.c, wap/wsp_headers.c, wap/wsp_strings.c: Related changes. 2001-01-18 Lars Wirzenius * gwlib/cfg.[ch]: Wrote functions cfg_get_integer and cfg_get_list to allow easier access to non-octet-string variables. No explicit typing in cfg.def, though. That may come later. 2001-01-18 Kalle Marjola * gw/bb_boxc.c: the current smsbox closes the connection properly, so wait until that before exiting with boxc_receiver, thus eliminating lost messages * gw/bb_boxc.c: added alive-check to boxc_sender after list_consume() as octstr_send does not notice that socket has been closed 2001-01-18 Lars Wirzenius * gw/smsbox.c, gw/urltrans.[ch]: Converted to use cfg.c instead of conffile.c. This revealed a need to simplify things so that the caller does not have to manually check quite as many things. Will update cfg.c accordingly before continuing with the other programs. 2001-01-18 Kalle Marjola * gw/smsbox.c: fixed 3 memory leaks some pointed out by Uoti, and one logical error in failed requests 2001-01-18 Lars Wirzenius * Wrote a replacement for the conffile.[ch] stuff. It does pretty much the same thing as the old stuff, but does it with a better interface and uses Octstr instead of C strings. It does not (yet?) support reloading and automatic notification of changes to the configuration. * gwlib/cfg.[ch], gwlib/cfg.def, test/test_cfg.c: Wrote. * gwlib/gwlib.h: Include cfg.h. * test/.cvsignore: Ignore test_cfg. * test/fake.conf: Removed, since it was unused and followed an ancient syntax. 2001-01-17 Lars Wirzenius * gwlib/dict.[ch]: Wrote function dict_keys. * gwlib/socket.c: Bugfix. Destroy the official_ip octet string at shutdown. 2001-01-17 Derry Hamilton * gwlib/socket.c: Removed the ugly loop from gw_netaddr_to_octstr6 since octstr_format does support hex format after all. 2001-01-17 Lars Wirzenius * configure.in, configure: Remove checking for -lz. Richard is right: if libxml needs it, then xml-config --libs must report -lz, so there is no point in checking for it for ourselves. 2001-01-17 Lars Wirzenius * configure.in, configure, config.h.in: check for syslog.h. * gwlib/log.c: Use the result from configure (HAVE_SYSLOG_H) to exclude the syslog stuff from compilation on platforms on which it is not available, such as Windows when not using Cygwin. * gwlib/socket.[ch]: Wrote get_official_ip, so that other modules don't have to do it themselves. * gw/wap_push_ota.c: Rewrote the static name() function. The old code was buggy (had a memory leak) and called non-portable functions (inet_ntop, uname). The new one uses get_official_ip. * gw/shared.c: Use get_official_name and get_official_ip to report the host, in addition to what uname() returns. 2001-01-17 Uoti Urpala * gw/smsc_fake2.c: Added missing #include, minor fixes. * gw/smscconn.c: Added missing #include. 2001-01-16 Uoti Urpala * gw/smsc_fake2.c: new fake SMSC connection module. * test/fakesmsc2.c: client to use with the new module. * gw/smscconn.c, gw/smscconn_p.h: Added references to the new module. 2001-01-15 Lars Wirzenius * wap/wtp_pdu.c: Bugfix from Aymerick Jéhanne. When unpacking TPIs, append the correct data to the PDU. 2001-01-15 Lars Wirzenius * gwlib/gw_inet.c: Added an include for to allow compilation on FreeBSD. Thanks to vlm@smarts-gsm.ru for pointing this out. 2001-01-15 Kalle Marjola * gw/smscconn_p.h: modified so that 'start as stopped' is done in protocol specific creator * gw/smscconn.c: added missing settings to NULL, and removed call for conn_stop (see above) * gw/smsc_wrapper.c: added one protection mutex and fixed startup to follow above interface 2001-01-15 Lars Wirzenius * gw/urltrans.c: Implemented %k in URL translations, based on suggestion from steveu@infowebtelecom.com. * doc/userguide/userguide.xml: Updated docs. 2001-01-15 Aarno Syvänen * gw/wap-appl.c: Wrote conformations and indications part of Push OTA protocol. * gw/wap_push_ppg.[ch]: Started writing test version of PPG main module * gw/wap_push_ota.c: Still streamlining and fixing bugs * wap/wap_events.def: Added new push related events * wap/wsp.h: Added push related error codes 2001-01-12 Tuomas Luttinen * gw/wml_compiler.c: Now compiler can handle a libxml compiled with -DXML_USE_BUFFER_CONTENT. The content of the node is converted into an octet string with a macro. 2001-01-12 Richard Braakman * Updated NEWS file to prepare for 1.1. 2001-01-12 Richard Braakman * gwlib/charset.c: Translate u-dieresis correctly from latin1 to GSM. (It does exist in GSM Default, so it doesn't have to be approximated.) 2001-01-12 Kalle Marjola * gw/smscconn.h, gw/smscconn_p.h, gw/bb_smscconn_cb.h: updated API description 2001-01-12 Kalle Marjola * gw/smsc_wrapper.c: fixed deadlock in message sending * gw/smsc_wrapper.c: modified reconnect so that it does not cause bearerbox to wait in various functions, by adding new mutex instead of using old flow_mutex 2001-01-11 Derry Hamilton * gwlib/gw_inet.c: Fixed off by one errors. * gwlib/socket.c, gwlib/socket.h: Implemnted a basic inet_ntop using Octstrs. IPv6 handling is basic, but appears to work. 2001-01-11 Lars Wirzenius * gwlib/octstr.c: octstr_copy_real: Changed the code that checks whether the length of the part to be copied is too long so that it can deal with integer overflows (assuming they wrap around). 2001-01-11 Kalle Marjola * gw/smscconn.c: modified so that flow_mutex is always locked in functions using function pointers * gw/smscconn_p.h: added notes about mutex 2001-01-11 Kalle Marjola * gw/bearerbox.c|h: added suspend for SMSCConn * gw/smscconn*.c: fixed suspend in various parts 2001-01-11 Kalle Marjola * gw/*smscconn*.*: changed SMSCCONN_KILLED to SMSCCONN_DEAD, and clarified some callbacks * gw/smsc_wrapper.c: fixed so that _sender does not suspend 2001-01-11 Lars Wirzenius * utils/chlog-stats: Wrote. 2001-01-10 Lars Wirzenius * gwlib/gwassert.h, gwlib/gwmem-check.c, gwlib/gwmem-native.c, gwlib/log.[ch], gwlib/octstr.c: Undid changes to make logging functions use octstr_format instead of fprintf. The interactions between debug(), gwmem, gwthread, and other low-level parts of gwlib are too intricate and error prone. It is better to suffer the use of octstr_get_cstr when logging things instead of making logging error prone. 2001-01-10 Lars Wirzenius * gwlib/octstr.c: Implemented %p in octstr_format. * test/test_octstr_format.c: Related changes. 2001-01-10 Lars Wirzenius * gwlib/log.c: Made info() use octstr_format as well. All places that call info() have been checked manually. In the process, found a couple of bugs, see below. * gw/bb_smscconn.c: Bugfix. octstr_get_cstr was called with a NULL argument, reversed the test so that it is called only when the argument will be non-NULL. * gwlib/log.c: Bugfix. Output needs to be flushed as soon as it has been written. * gwlib/octstr.[ch]: Implemented %i for octstr_format, and made octstr_get_cstr report the place it has been called from. * test/drive_smpp.c: Bugfix. Remember to quit from a loop within the main loop of a thread, if the quitting signal has been given. 2001-01-09 Kalle Marjola * gw/smscconn*.*, gw/smsc_wrapper.c: updated start/stop interface, moving list trick into wrapper, so that each connection implementation can do it any way they like. 2001-01-09 Lars Wirzenius * doc/CodingStyle: Add note that one should never include anything except gwlib.h from gwlib.h 2001-01-09 Derry Hamilton * gwlib/gw_inet.c: Included string.h to declare strncpy. 2001-01-08 Derry Hamilton * gwlib/gw_inet.[ch]: Added initial implementation of gw_inet_ntop and supporting code. * gw/wap_push_ota.c: included gwlib/gw_inet.h. 2001-01-08 Lars Wirzenius * gwlib/log.c: Made warning() use octstr_format. All usages have been checked and should work. 2001-01-08 Kalle Marjola * gw/*smscconn*.*: removed reason from killed-callback, instead it is used in why_killed field (previous is_killed) * gw/smscconn.*: infotable now has killing reason included 2001-01-08 Aarno Syvänen * gw/wap_push_ota.c: Streamlined the code somewhat 2001-01-08 Kalle Marjola * utils/kannel-init.d: changed binary names into variables so that it is easier to change script to work with different versions 2001-01-06 Lars Wirzenius * gwlib/log.c: Added a missing include for so that CHAR_BIT is defined. The over-eagerness of Linux headers to define everything strikes again. 2001-01-05 Lars Wirzenius * Started to convert logging functions to use octstr_format instead sprintf, to make them more powerful. Now, panic() and error() use octstr_format, the others do not yet (each call needs to be checked to make sure that octstr_format can deal with the format string and I didn't have the time to do that yet). Also added the function panic_hard for those cases where calling panic would call eternal recursion - panic uses octstr_format, which can call panic itself (via gw_assert or gw_malloc, for example). * gwlib/log.[ch]: Implemented panic_hard and made panic and error use octstr_format. * gwlib/gwassert.h, gwlib/gwmem-check.c, gwlib/gwmem-native.c, gwlib/octstr.c: Changed to use panic_hard instead of panic. * gw/wap-appl.c: Indentation fix. 2000-01-04 Derry Hamilton * configure.in,configure: Added tests for the definition of INET_ADDRSTRLEN and finding libraries for inet_ntop. Allows gw/wap_push_ota.c to compile and link under Solaris 7. 2001-01-04 Lars Wirzenius * configure.in, Makefile.in: Added PDF conversion of docs. * doc/arch/*: Replaced the architecture document with a modified version of the draft for my MSc thesis. The old document was horribly out of date, the thesis draft is at least mostly current, even if it is still missing a few bits. 2000-01-04 Aarno Syvänen * wap/wap_events.def: Added Push OTA events * wap/wsp_pdu.def: Added sia, a spesific content type for trans- mitting data bearerbox addresses, etc. * gw/wap_push_ppg.c|h: Added module to implement PPG main logic. It does not do anything, yet. * gw/wap_push_ota.c|h: Wrote requirements part of Push OTA protocol. * gw/wapbox.c: Send bearerbox address to OTA module. Initialize and shutdown ppg. * wap/wsp_strings.def: Added conversion tables for bearer types and push application ids. * wap/wsp_headers.c: Added packing and unpacking of OTA headers 2001-01-03 Lars Wirzenius * checks/check_fakesmsc.sh, checks/check_fakewap.sh: Modified to work without network access to facilitate development on a laptop. * test/test_http_server.c: Added option -f, to allow a WML file to be returned instead of a text/plain response. This is used by check_fakewap.sh above. * gw/bb_smscconn.c: Initialized some local variables so that the compiler won't warn that they are used before they are initialized. * gwlib/octstr.[ch]: Removed octstr_search_cstr, which was no longer used. 2000-12-29 Tuomas Luttinen * gw/wml_definitions.h: Added WBXML_ to every defined constant, so that there wouldn't be any more mixups with constants defined elsewhere. * gw/wml_compiler.c: The code modified to use the new definitions. 2000-12-29 Tuomas Luttinen * gw/wml_compiler.c: The own hash table code is deleted and dict implementation is used instead. The wml_init builds up the dicts for the WML binary bytecode and wml_shutdown frees those dicts. Also a bit of code renewing by deleting all octstr_*_cstr-functions. * gw/wapbox.c: Added calls to wml_init and wml_shutdown when starting and shutting down the wapbox. * gwlib/octstr.c (octstr_hash_key): Now hash key for a NULL octet string is 0. * test/wml_tester.c: The test program now has a command line argument -n number that does the compiling n times. Also all the wml files written in sequence in the command line will be compiled. Some other modifications to get rid of the octstr_*_cstr-functions. 2000-12-29 Kalle Marjola * gw/bb_smscconn.c: shortened SMSCConn status output * gw/bb_http.c: added full HTML header to HTML replies 2000-12-29 Kalle Marjola * gw/bb_smscconn.c: added load-based routing to outgoing SMS messages, which takes into account reconnecting connections, preferrations etc. (note that currently as all SMSC Connections are used via smsc_wrapper their load is equal to internal queue length, which is usually 0) * gw/smsc_wrapper.c: a bit update to startup 2000-12-28 Kalle Marjola * gw/bb_http.c: added that HTTP admin commands can be used without cgi-bin/ in the URL, too. * doc/userguide/userguide.xml: documentation updated to reflect that 2000-12-28 Kalle Marjola * gw/bb_http.c, gw/bearerbox.c: modified so that every reply to HTTP admin is formatted according to client Accept: -header, with preference as WML > HTML > plain text. 2000-12-28 Kalle Marjola * gw/bb_http.c: modified so that cgi-bin/status returns the reply in format accepted by the client, preferring WML over HTML over plain text. * gw/bb_http.c: made admin-password mandatory in code, too. Set that wrong password in admin commands causes delayed answer to delay brute force password cracking * gw/bb_http.c: added new configuration variable status-password - if set, status inquiry must be supplied with either this or general admin-password * gw/*kannel.conf, doc/userguide/userguide.xml: updated to reflect status-password 2000-12-28 Kalle Marjola * gw/bearerbox.c, gw/bearerbox.h, gw/bb_boxc.c, gw/bb_smscconn.c: updated to format status inquiry into HTML, WML or plain text. * gw/bb_http.c: added new HTTP admin functions cgi-bin/status.wml, cgi-bin/status.html and cgi-bin/status.txt if the client wants a specific type. Plain cgi-bin/status returns HTML currently, updated to return whatever client requests via Accept -header in near future (as would all other commands, too) * gw/bb_http.c: removed cgi-bin/xmlstatus, replaced with cgi-bin/status.xml which still does not return anything sensible. 2000-12-27 Kalle Marjola * gw/smscconn.c, gw/smscconn_p.h: added new smsc configuration group variable allowed-smsc-id * doc/userguide/userguide.xml: added description 2000-12-27 Kalle Marjola * gw/smscconn_p.h, gw/smsc_wrapper.c: a bit more commented code 2000-12-22 Derry Hamilton * config.sub,config.guess,configure.in,configure: added the host determination files and removed the dependancy on /usr/share/autoconf. 2000-12-22 Derry Hamilton * config.h.in,configure,configure.in,gwlib/gwthread-pthread.c: Cleaned up host system determination and tests for broken pthreads. 2000-12-21 Lars Wirzenius * test/drive_smpp.c: Added includes for accept(2). 2000-12-21 Lars Wirzenius * Rewrote the SMPP protocol implementation. The old one was excessively verbose (lots of repetitive code), did not use Octstr, or Connection, and needed much attention in order to fit into the new SMSC interface anyway. The new code is about half the length and much cleaner and should be functionally about as concrete (but see comments at the top of gw/smsc_smpp.c), and happens to be somewhat faster. * gw/smsc_smpp.h: Removed. It was only included by the old version of gw/smsc_smpp.c anyway, and shouldn't have existed at all. * gw/smpp_pdu.[ch] and gw/smpp_pdu.def: Wrote. These parse and generate the binary and struct versions of the SMPP PDUs. The C preprocessor trick the WAP stack uses is used here as well to keep code clean and short. They're used by drive_smpp as well, so they're not made part of smsc_smpp.c itself. * test/drive_smpp.c: Wrote. This is a server end implementation of the SMPP protocol and is used to verify that the client end works. * checks/check_smpp.sh, test/drive_smpp.conf: Wrote. * gwlib/semaphore.[ch]: Wrote. These are used by the SMPP code to make sure not too many pending submit_sm requests are open. The current implementation of Semaphore is quite simplistic and wraps around List; native semaphores should probably be used instead, but this is good enough for now. * gwlib/gwlib.h: Added include for semaphore.h. * gwlib/octstr.c: Ignore NULL arguments before calling seems_valid, instead of afterwards, since seems_valid asserts that the argument is not NULL. * utils/source-stats: Cound the `wap' subdirectory as well. 2000-12-21 Kalle Marjola * gw/smsc_wrapper.c: added some mutex operations so that reconnect should now work without segfault 2000-12-21 Kalle Marjola * gw/bearerbox.c, gw/bb_smscconn.c, gw/smsc_wrapper.c: updated status output information 2000-12-21 Kalle Marjola * gw/smsc_wrapper.c: moved logistics of reconnect to this module, instead than in smsc.c * gw/smsc.*: removed lots of public functions (the old interface) * gw/bb_smsc.c: remove depricated code 2000-12-21 Kalle Marjola * gw/bearerbox.*: use smsc2_ functions for new bb_smscconn, renaming in a near future * gw/smsc.c: modified to use gwthread_sleep instead of plain sleep, so that no need for 'semi-busy sleep' during reconnect * gw/smscconn*.*: added missing functions, these should now work * gw/smsc_wrapper.c: finished, including program flow etc. 2000-12-21 Kalle Marjola * gw/smsc.c: added missing breaks to _reopen 2000-12-21 Derry Hamilton * gw/wap-appl.c: Fixed race condition, between updating and deleting stuff in id_to_request_data and caller simultaneously 2000-12-20 Kalle Marjola * gw/bb_smscconn_cb.c: renamed as bb_smscconn.c and includes all code in old bb_smsc.c - will replace the old system as soon as I get last missing functions ready and the system tested * gw/smscconn.* added that shutdown can either empty the internal queue first or do a quick shutdown, putting all messages into failed list 2000-12-20 Derry Hamilton * gwlib/gwthread.h, gwlib/gwthread-pthread.c, gw/bearerbox.c, config.h.in: Combined patches from Nick Clarey and myself that cope with POSIX-but-not-quite threads. My head hurts. 2000-12-19 Richard Braakman * gwlib/dict.c: Improve description of Dict fields. 2000-12-19 Kalle Marjola * gw/smsc_wrapper.c: it is ready - to be tested out. Next: new bb_smsc.c, so the wrapper can be checked out 2000-12-19 Kalle Marjola * gw/smsc_emi.c: fixed that NULL pointer is not tried to be printed 2000-12-18 Kalle Marjola * gw/bb_smscconn_cb.*, gw/smscconn*, gw/smsc_wrapper.c: updated, almost ready now. 2000-12-18 Peter Grönholm * gw/wml_definitions.h, fixed attribute name, "accept_charset" is now "accept-charset". 2000-12-15 Lars Wirzenius * gw/bb_smscconn_cb.c, gw/smsc_wrapper.c, gw/smscconn.c: Rudely commented out things to shut compiler warnings off. 2000-12-15 Kalle Marjola * gw/smscconn.c|h|_p.h, gw/smsc_wrapper.c: continued the work * gw/bb_smscconn_cb.h|c: added. Callbacks to synchronize things 2000-12-15 Richard Braakman * gwlib/dict.[ch]: Implement dict_key_count(). Implement behaviour of dict_put when value is NULL. * gw/smsbox.c: dict_key_count() now exists, so use it in outstanding_requests(). 2000-12-15 Richard Braakman * gw/smsbox.c: smsbox_req_sendsms and smsbox_req_sendota made static, they're not called from anywhere else. 2000-12-13 Richard Braakman * test/fakewap.c: Indented gwlib_shutdown() call according to our coding style. 2000-12-13 Paul Keogh * test/fakewap.c: Added gwlib_shutdown() call. gateway-1.4.5/doc/ChangeLog-1.5.00000644000175000017500000010660511457445760014667 0ustar toljtolj2010-10-20 Stipe Tolj * configure[.in]: make sure we use the packaged install script rather then the system own install on Interix 3. The system own version has no option -d support. * gwlib/counter.c: Interix 3 has pthread spinlocks, but they seem to be experimental and block the system. We'll use mutex locks instead. * gwlib/gwlib.h: Interix 3 has no strtoll(), but strtoq() provides the equivalent functionality. * gwlib/gwthread.h: Interix 3 has no sys/poll.h, so ignore the inclusion for this platform. * gwlib/socket.c: use gw_netaddr_to_octstr() instead of inet_ntop(), due to the fact that the later is not provided in Interix 3. * gwlib/utils.c: there is no initgroups() in Interix 3, so avoid the call for this specific platform. 2010-10-12 Vincent CHAVANIS * test/test_list.c: fixed compiler warnings. 2010-10-12 Vincent CHAVANIS * gw/dlr_mysql.c: Fixed broken DLR when state is intermediate when using Mysql 2010-10-11 Stipe Tolj * doc/userguide/userguide.xml: add reference to new '%R' escape code for the DLR-URL value. * gw/bb_alog.c: add '%R' handling to get_pattern() for the 'access-log-format' custom access logging. * gw/urltrans.c: add '%R' handling to the escape code handling. 2010-10-07 Stipe Tolj * */*: updating the LICENSE preamble to reflect the correct year. 2010-10-07 Stipe Tolj * utils/makedist: addopt for our SVN repository. 2010-09-27 Alexander Malysh * gw/bb_smscconn.c, gw/msg.h, gw/smscconn.c: applied patch that fixes sms-resend-* handling for concatenated messages. 2010-09-24 Alexander Malysh * gwlib/list.[ch]: added function to search for the equal item on the list, this is usefull to lookup for one element if it's still present. 2010-09-24 Alexander Malysh * gwlib/list.[ch]: added new function gwlist_consumer_count to receive count consumers for this list. Fixed comment for gwlist_sort function. 2010-09-24 Alexander Malysh * gwlib/list.c, test/test_list.c: fixed gwlist_sort if list get fragmented by usage. 2010-09-21 Alexander Malysh * wap/wtls-secmgr.c, wap/wtls.c, wap/wtls_pdu.c, wap/wtls_pdusupport.c, wap/wtls_statesupport.c: Fixed WTLS branch warnings. Thanks to Nikos Balkanas for this patch. 2010-09-21 Alexander Malysh * gw/smsc/smsc_smpp.c: handle “Invalid system_type" as fatal and don't retry login. Thanks to Roy Walker for this patch. 2010-09-13 Alexander Malysh * gwlib/pki.c, wmlscript/wsgram.[chy]: fixed some warnings. Thanks to Nikos Balkanas for this patch. 2010-09-12 Alexander Malysh * gwlib/http.c: fixed issue that new servers were added every time gwthread_poll returns as well as on startup. This fixes #525. 2010-09-12 Alexander Malysh * merged wtls_provision branch. Thanks to Nikos Balkanas for this patch. 2010-09-01 Alexander Malysh * doc/userguide/userguide.xml, gw/urltrans.c: Fixed bug that keyword-regex was case insensitive. Thanks to Nikos Balkanas for this patch. 2010-08-06 Alexander Malysh * gw/bb_boxc.c: fixed security issue that box-[allow|deny]-ip options were ignored for smsbox. This fixes #188. Thanks to Roland Discein for patch. 2010-08-05 Alexander Malysh * bootstrap.sh: changed to /bin/sh bacase e.g. FreeBSD has bash in /usr/local/bin. Thanks to Victor Luchitz for the hint. 2010-07-28 Alexander Malysh * gw/dlr.[ch], gw/dlr_mem.c, gw/dlr_mssql.c, gw/dlr_mysql.c, gw/dlr_oracle.c, gw/dlr_p.h gw/dlr_pgsql.c, gw/dlr_sdb.c, gw/smsc/smsc_at.c, gw/smsc/smsc_cgw.c, gw/smsc/smsc_cimd2.c, gw/smsc/smsc_emi.c, gw/smsc/smsc_fake.c, gw/smsc/smsc_http.c, gw/smsc/smsc_oisd.c, gw/smsc/smsc_smpp.c, gw/smsc/smsc_soap.c: applied patch that adds last 7 digits from destination to DB queries for DLR support. It reduces possibility to get wrong DLR for e.g. EMI. Thanks to Nikos Balkanas for this patch. 2010-06-04 Alexander Malysh * gw/smsc/smsc_at.c: clear privdata afetr read error to get clean status for reconnect.This fixes #544. Thanks to for patch and bugreport. 2010-05-31 Alexander Malysh * gw/smsc/smsc_oisd.c: applied patch that allows empty MOs. Thanks to Michael Zervakis for this patch. 2010-05-14 Stipe Tolj * gw/dlr.c: fixed missing foreign ID (FID) escape codes handling for DLR SMSC SUCCESS|FAIL events, due that we handle the last chunk here, we didn't get hold of the FID. We need to duplicate it to the split list original too, in order to have it available later, when the last chunk us handled for the DLR events. Thanks to Gianluca Moretti for report. 2010-05-06 Alexander Malysh * gw/smsc/smsc_smpp.c: ignore receive_port for transceiver mode. Thanks to Juan Nin for report. 2010-04-27 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_at.[ch], gwlib/cfg.def: Aplied patch that adds configuration option to at smsc, message-start (in group modems). In case of sim-buffering it will set the starting buffer index in the sim. For some modems such as the UMG181 this needs to be set to 0. Defaults to 1, and doesn't need changing for most others. Thanks to to Nikos Balkanas for this patch. 2010-04-12 Alexander Malysh * gw/smsc/smsc_at.c: applied patch that fixes issue when error received during handshake. Thanks to hisham malik for this patch. 2010-04-01 Alexander Malysh * gwlib/http.c: fixed memory leak. 2010-03-24 Stipe Tolj * doc/userguide/userguide.xml: fixed Alex's missing paragraph closing tag. 2010-03-22 Stipe Tolj * VERSION: fix typo and make the rXXXX tag more clean here. 2010-03-22 Alexander Malysh * configure, VERSION, configure.in, acinclude.m4, aclocal.m4: switched CVS -> SVN 2010-03-20 Alexander Malysh * userguide/userguide.xml: applied patch that should clarify modem initialization. Thanks to Nikos Balkanas for this patch. 2010-03-20 Alexander Malysh * gw/smsbox.c: rewrite of XML POST to use libxml/xpath. This should handle all of escaping, namespacing etc. issues. 2010-03-18 Andreas Fink * doc/examples/modems.conf, modems.conf fixed default settings for Siemens TC35 this should make hanging TC35's a thing of the past 2010-03-09 Stipe Tolj * doc/userguide/userguide.xml: we use UTF-8 as default encoding for the payload and not WINDOWS-1252. This caused a lot of mis-understanding. * gw/smsbox.c: fix also the comment. NLC. 2010-02-28 Alexander Malysh * gw/bearerbox.c: don't ignore errors on startup. This fixes #536. 2010-01-21 Stipe Tolj * gw/bb_boxc.c: fix a duplicate store_save_ack() call in case we get SMSCCONN_FAILED_DISCARDED as result of our smsc routing call. In this case we HAVE already called the store_save_ack(), and hence yield an ERROR line that we're unable to unlink the file from a spool directory. 2010-01-20 Stipe Tolj * utils/start-stop-daemon.c: fix FreeBSD build, removed the redundant command here that breaks the build. NLC. 2010-01-19 Andreas Fink * gwlib/charset.c partially revert last change. GSM charset character 09 is encoded differently by various vendors. Nokia and Apple show a small c cedille. Ericcson and Android show a capital C cedile The standard GSM ETSI TS 123 038 V8.2.0 (2008-10) shows a capital, even though french speakers who have invented GSM will agree that it most likely was meant as small (in french you dont write capital C cedille but you use small c cedille often). Capital and small c cedile get encoded into 09. 09 gets decoded to capital c cedille as it is in the standard. 2010-01-19 Andreas Fink * gwlib/charset.c Fixed french character c cedille. In GSM 23.38-700 it looks like a capital C cedille for code point 0x09. Real life phones however display a small c cedille for code 0x09. The change does encode capital and small C cedille into 0x09 and decodes to small C on incoming. Before a small c cedille resulted in a questionmark. 2010-01-11 Alexander Malysh * gwlib/octstr.[ch]: the search functions should return long #526 Thanks to Stepan Seycek for this patch. 2010-01-11 Alexander Malysh * gwlib/octstr.c: fixed #527 Thanks to Stepan Seycek for this patch. 2010-01-03 Stipe Tolj * gw/smsc/smsc_loopback.c: make sure we create an new UUID for the MO we are about to loopback via this smsc. This is more realistic by means that other smsc modules also create an own UUID for a logical MO. 2009-12-23 Alexander Malysh * gwlib/log.c, gw/wap_push_ppg.c: fixed some compiler warnings and typos. Thanks to Nikos Balkanas for this patch. 2009-12-22 Alexander Malysh * gwlib/octstr.c: fixed crash in octstr_decode_url() when called with octstr=NULL. Bug #528. Thanks to Stepan Seycek for this patch. 2009-12-07 Stipe Tolj * gw/smsc/smsc_emi.c: fix segmentation fault in case we jump via goto error in smsc_emi2_create(), but have yet no privdata created. 2009-12-06 Alexander Malysh * doc/userguide/userguide.xml, gw/bearerbox.c, gw/smsbox.c, gw/wapbox.c, gwlib/cfg.def: Applied patch that adds configurable http-timeout support for outgoing http client connections. Thanks to Nikos Balkanas for this patch. 2009-12-03 Alexander Malysh * gw/meta_data.c: fixed memory leak. Thanks to Nikos Balkanas for hint. 2009-11-24 Alejandro Guerrieri * contrib/kannel-monitor/*: rewrite of the code to support separate dlr counters. Interface cleanup and php code updates. 2009-11-23 Alexander Malysh * gw/dlr_pgsql.c: applied patch that escapes table name and fields. Quoting an identifier also makes it case-sensitive, whereas unquoted names are always folded to lower case. CB. See http://www.postgresql.org/docs/8.0/static/sql-syntax.html#SQL-SYNTAX-IDENTIFIERS Thanks to Vincent CHAVANIS for this patch. 2009-11-15 Alexander Malysh * gw/wap_push_ppg.c: allow requesting DLRs without dlr-url. Thanks to Nikos Balkanas for this patch. 2009-11-15 Alexander Malysh * gw/bb_smscconn.c: applied patch that minimize possibility of wrong re-assembling of concatenated MO messages. 2009-11-11 Alexander Malysh * gw/bb_smscconn.c, gw/bearerbox.c, gw/smscconn.[ch], gw/smscconn_p.h: applied patch that adds separate dlr counters on the status page. Thanks to Alejandro Guerrieri fir this patch. 2009-11-09 Alexander Malysh * gwlib/octstr.c: fixed crashes on Snow Leopard 64Bit. Thanks to Paul Bagyenda for this patch 2009-11-01 Alexander Malysh * gw/numhash.c, gw/bb_smscconn.c: fixed possible crash by reloading white/blask lists via HTTP interface. 2009-10-22 Alexander Malysh * gw/dlr_mssql.c, gw/dlr_mysql.c, gw/dlr_oracle.c, gw/dlr_pgsql.c, gw/dlr_sdb.c: added warnings if DLR was not inserted/updated/deleted but no error occurs e.g. row to update not found. Thanks to Nikos Balkanas for this patch. [Msg-Id: <001801ca530c$43c24ac0$02b2a8c0@tardis> 2009-10-13 Alexander Malysh * gw/dlr_mysql.c: applied patch that fixes table name and field names that use reserved keywords. See http://dev.mysql.com/doc/refman/5.0/en/identifiers.html for details. Thanks to Vincent CHAVANIS for this patch. 2009-09-20 Alexander Malysh * gw/msg.c: fixed crash when wrong packet received on bearerbox port. Thanks to Michael Zervakis for report. [Msg-Id: <4AB3A08C.3050408@zervakis.com>] 2009-09-17 Stipe Tolj * doc/userguide.xml: document the 'smsc = loopback' type. * gw/smscconn[_p].[ch]: add the loopback SMSC type to the internal structures. * gw/smsc/smsc_loopback.c: add loopback SMSC type module. [Msg-Id: <4A4B9245.1030705@tolj.org>] 2009-09-04 Alexander Malysh * aclocal.m4, configure, configure.in, gw/dlr_mysql.c, gwlib/dbpool_mysql.c, test/test_dbpool.c: implemented select/update function calls for dbpool_mysql. This require mysql prepared statement support and therefore mysql version >= 4.1. Changed dlr_mysql to use these new function calls. This fixes #258. 2009-09-03 Alexander Malysh * gw/smsc/smpp_pdu.c: fixed memory leak. 2009-09-02 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smpp_pdu.[ch], gw/smsc/smsc_smpp.c, test/drive_smpp.c, test/drive_smpp.conf, test/test_smsc.c: implemented smsc-id config option for smpp-tlv group. 2009-09-01 Alexander Malysh * gw/bearerbox.c: fixed memory leak 2009-08-31 Alejandro Guerrieri * gw/bb_smscconn.c, gw/bearerbox.c, gw/bearerbox.h, doc/userguide/userguide.xml: limit of 1M messages on outgoing queue limit documented. Small code cleanup. 2009-08-28 Andreas Fink * util/start-stop-daemon.c: fix compilation under MacOS X 10.6 2009-08-28 Alexander Malysh * gw/bb_smscconn.c: always initialize msgdata because too many parts in kannel expect msgdata non NULL. 2009-08-24 Alexander Malysh * gw/smsc/smsc_at.c: fixed timeout value passed to select. This should fix #514. 2009-08-12 Alexander Malysh * gw/smsc/smsc_at.[ch]: changes as follows: - changed at2_read_line to first try buffer and only then try to read from device. This should give us some speedup. - populate timeout to select. This fixes to high CPU usage. - more error handling. - variuos fixes. 2009-08-07 Alexander Malysh * gw/dlr_oracle.c: fixed table name in dlr_flush_oracle. 2009-07-28 Alexander Malysh * gw/numhash.[ch]: increase numhash precision from 9,18 to 19,38 on 32,64bit respectively. This is possible by using C99 standard type long long. 2009-07-21 Stipe Tolj * gw/smsc/smsc_smpp.c: fix compile error for --disable-ssl builds. NLC. Thanks to Gottfried Huber for reporting. 2009-07-08 Alejandro Guerrieri * gw/bb_smscconn.c: fixed warnings on unused variables 2009-07-08 Alejandro Guerrieri * doc/userguide/userguide.xml, gw/bearerbox.c, gw/bearerbox.h, gw/bb_smscconn.c, gw/bb_http.c: improvements and bug fixes for the http admin interface: - added add-smsc and remove-smsc commands to dinamically add and remove smsc without restarting bearerbox - start-smsc reloads the configuration from disk - fixes bug on stop-smsc and start-smsc to properly report an error when a non-existing smsc name is stopped/started - fixes a bug when starting a group with 2 or more entries with the same id and different admin-id's 2009-07-07 Alexander Malysh * gw/smsc/smsc_smpp.c: merged smpp throttling branch that adds throughput handling without sleep for better ACK/DLR performance. Also changed: - added return codes to all sending and processing PDU functions - added extra error code when we receive malformed PDU - inlined smpp_msg_[create|destroy] - check validity against SMS_PARAM_UNDEFINED instead of hardcoded >= 0 - added function to send generic NACK - check bind_xxx_resp for error 'already bound' and don't handle it as error - re-wrote io_thread function (this is the main loop) to take into accounts all possible conditions and throughput - implemented async shutdown sequence 2009-06-29 Alexander Malysh * gw/smsc/smsc_at.c: optimizing detection process on CME/CMS Errors (avoid to check if CMS when CME was detected). Renaming param value code -> errcode to make it more clean. Thanks to Vincent CHAVANIS for this patch. 2009-06-29 Alexander Malysh * gwlib/regex.c: fixed memory leak. Thanks to "Franck LAMASUTA" for patch. 2009-06-24 Stipe Tolj * acinclude.m4: fix unquoted definition warnings from bootstrap.sh run. * aclocal.m4: outcome of aclocal * configure[.in]: fix Fedora Core 11 (x86 and amd64) build for openssl detection. The static libssl.a library has been extracted from the openssl-devel package and is usually now not installed on a base system resulting in a failing build environment. 2009-06-23 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_http.c, gwlib/cfg.def: added generic-foreign-id-regex config option that allows us to substract message id from body content by successful submission. Thanks to "Franck LAMASUTA" for this patch. 2009-06-22 Alejandro Guerrieri * gwlib/dbpool_mssql.c: various fixes: - allows execution of stored procedures on mssql_select - fixed memory leak on mssql_select - fixed double free on data deallocation 2009-06-22 Alexander Malysh * gw/smsc/smsc_at.c: applied patch that adds handling of +CME ERROR. Thanks to Vincent CHAVANIS for this patch. 2009-06-19 Alexander Malysh * gw/smsc/smsc_smpp.c: following changes: - added retrurn codes to all sending and processing PDU functions - dded extra errorcode when we receive malformed PDU - indents fixes 2009-06-19 Alexander Malysh * gw/smsc/smsc_smpp.c, doc/userguide/userguide.xml: added possibility to bind with SSL. 2009-06-18 Alexander Malysh * gw/smsc/smsc_at.c: applied patch that adds more error descriptions. Thanks to Vincent CHAVANIS for this patch. 2009-06-18 Alexander Malysh * gwlib/http.c: removed max http server limit. 2009-06-16 Alexander Malysh * gwlib/http.c: increase max http servers from 32 to 100 and return error if max servers reached. 2009-06-16 Alexander Malysh * gwlib/http.c: indent fixes. 2009-06-15 Alexander Malysh * gwlib/http.c: fixed last commit that broke urls with port and query. 2009-06-11 Alexander Malysh * gwlib/http.c: fixed #503. we didn't handle right urls like http://host:port?query. 2009-06-10 Alexander Malysh * gw/smsc/smsc_http.c: fixed compiler warnings. 2009-06-10 Alejandro Guerrieri * test/.cvsignore utils/.cvsignore: ignoring test_date and decode_emimsg 2009-06-10 Alejandro Guerrieri * gw/smsc/smsc_http.c: removed the dlr-url field as a requirement for incoming dlrs on kannel smsc-type 2009-06-09 Alejandro Guerrieri * gw/smsc/smsc_http.c gwlib/cfg.def doc/userguide/userguide.xml: added support for mo parameters, return messages and codes configuration. 2009-06-09 Alexander Malysh * gw/ota_compiler.c: fixed #484 and reordered syncsettings to be in line with OTA spec. 2009-06-09 Alexander Malysh * gw/ota_compiler.c: revert of re-order INLINE attributs in oma_ota_attributes because code assume VALUE INLINE to be last in table. Thanks to "Nikos Balkanas" for this patch. 2008-10-22 Stipe Tolj * gw/ota_compiler.c: re-order INLINE attributs in oma_ota_attributes struct to fit the order in the spec tables. NLC. 2009-06-04 Stipe Tolj * gw/smsc/smsc_smpp.c: add the SMPP username as msg->sms.account value, so we can use it in the urltrans layer with escape code '%o'. This makes the semantics for MT/MO direction similar. 2009-05-25 Stipe Tolj * doc/userguide/userguide.xml: fixing bug 'document type does not allow element "PARA" here; missing one of "FOOTNOTE", "MSGTEXT", "CAUTION", "IMPORTANT", "NOTE", "TIP", "WARNING", "BLOCKQUOTE", "INFORMALEXAMPLE" start-tag'. 2009-05-20 Alexander Malysh * gw/smsc/smsc_smpp.c: some SMSCs have submit/done date with seconds. Now we can parse it sscanf way. 2009-05-20 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_smpp.c, gw/smsbox.c, gw/dlr.h: added support for intermediate notification. Thanks to Alejandro Guerrieri for this patch. 2009-05-20 Alexander Malysh * doc/userguide/userguide.xml: adding clarification that user can provide own message id's to the dlr-url. Thanks to "Arne K. Haaje" for this patch. 2009-05-20 Alexander Malysh * gwlib/octstr.c: fixed PANIC when we try to send empty message body. 2009-05-06 Alexander Malysh * gwlib/dbpool_oracle.c: fixed compiler warnings. 2009-05-06 Alexander Malysh * doc/userguide/userguide.xml, gw/bb_smscconn.c, gw/smscconn.[ch], gw/smscconn_p.h gwlib/cfg.def: added new config option to smsc group 'smsc-admin-id'. This is used in admin interface to shutdown/start/restart smsc links when smsc-id is equal due to loadbalancing. Thanks to Alejandro Guerrieri for this patch. 2009-05-05 Stipe Tolj * gw/msg.[ch], gw/msg-decl.h: remove the semicolon references from the macro definition file for the sake or usability of the macro in other places. NLC. 2009-05-04 Alexander Malysh * aclocal.m4, configure, configure.in, gw-config.h.in, gw/dlr.c, gw/dlr_p.h, gwlib/cfg.def, gwlib/dbpool.[ch], doc/userguide/userguide.xml: added MSSQL support to DBPool and DLR. Thanks to Alejandro Guerrieri for this patch. 2009-05-04 Alexander Malysh * gw/meta_data.[ch]: Extends meta_data_set_values function to be able to add new values without replacing the whole dict. * gw/smsc/smsc_smpp.c: return DLR error in dlr_err metadata parameter. Thanks to Alejandro Guerrieri for this patch. 2009-04-30 Alexander Malysh * utils/mtbatch.c: fixed freeze at the shutdown. 2009-04-30 Alexander Malysh * utils/mtbatch.c: send the whole message to bearerbox instead of splitted parts. Splitting is done in bearerbox. 2009-04-17 Alexander Malysh * aclocal.m4, configure, configure.in: fixed FeeBSD compilation options. Use -lpthread instead of -lkse. See http://www.FreeBSD.org/kse/. 2009-04-17 Alexander Malysh * gwlib/charset.c, gwlib/date.c: fixed compiler warnings. Thanks to Vincent CHAVANIS for pointing to it and partially fix. 2009-04-16 Stipe Tolj * utils/mtbatch.c: changed email reference. NLC. * gwlib/socket.c: re-inforced preamble, which was changed acidently in the previous patchset. NLC. 2009-04-15 Alexander Malysh * gwlib/socket.c: implemented support for multi-IP. 2009-04-15 Alexander Malysh * gw/smsc/smsc_at.c: fixed error path that we didn't close device. 2009-04-15 Alexander Malysh * utils/mtbatch.c: applied patch that add DLR support for mtbatch. Thanks to Vincent CHAVANIS for this patch. 2009-04-14 Alexander Malysh * test/decode_emimsg.c: moved to utils. Thanks to Vincent CHAVANIS for this patch. 2009-04-07 Alexander Malysh * gwlib/gwmem.h: fixed compiler warnings about strdup redefine. 2009-04-06 Stipe Tolj * gwlib/gwmem.h: fixed typo from previous commit set. NLC. 2009-04-06 Alexander Malysh * gwlib/gwmem-check.c, gwlib/gwmem-native.c, gwlib/gwmem.h: applied patch that adds gw_calloc function and speedup a gw_strdup. Thanks to "Nikos Balkanas" for this patch. 2009-04-03 Alexander Malysh * utils/mtbatch.c: applied patch that fixes #495. Thanks to Vincent CHAVANIS for this patch. 2009-04-02 Alexander Malysh * gwlib/thread.[ch]: fixed compilation failure if compiled with '--enable-mutex-stats'. Thanks to "Nikos Balkanas" for report. 2009-04-02 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed issue that return code 1 of conn_write that indicated still data buffered but no error was interpreted as error. Thanks to "Raf Coremans" who spotted and reported this issue. 2009-04-01 Alexander Malysh * gw/smsc/smsc_smpp.c: handle partial SMPP v3.4 DLR support, when receipted_message_id received but not the dlrstat. 2009-03-30 Alexander Malysh * gwlib/http.c: applied patch that fixes octsr_copy length. Thanks to Vincent CHAVANIS for this patch. 2009-03-30 Alexander Malysh * gw/wap-appl.c: applied patch that fixes possible infinite loop. Thanks to "Nikos Balkanas" for this patch. 2009-03-29 Alexander Malysh * gwlib/http.c: applied patch that fixes octsr_copy length. Thanks to "Nikos Balkanas" for this patch. [Msg-Id: <002b01c9af01$c06655d0$02b2a8c0@tardis>] 2009-03-15 Alexander Malysh * gwlib/cfg.c: fixed compilation error introduced by Stipe. 2009-03-14 Stipe Tolj * gwlib/cfg.c: fix segfault on sparc-solaris10 and possibly various other systems in case of a failing lstat() call and further undefined processing of the variable outcome. 2009-03-14 Stipe Tolj * config.rpath: touched file to surpress the configure error. * configure[.in], aclocal.m4: added '--enable-auto-import' linker option for the Cygwin 1.x platform to avoid warnings at link time. 2009-03-14 Stipe Tolj * Makefile.in: fix missing -liconv flag for gw-config's --libs output. We rather use the Makefile variable then the configure substitution, so we get all library flags handled. 2009-03-13 Stipe Tolj * gwlib/date.c, gwlib/dbpool_sqlite3.c, test/test_store_dump.c: fixed minor compiler warnings. NLC. * acinclude.m4: changed header to reflect the correct file name. NLC. 2009-03-13 Alexander Malysh * .cvsignore, Makefile.in, acinclude.m4, aclocal.m4, bootstrap.sh, configure, configure.in, gw-config.h.in, gwlib/charset.c: Use already defined in gettext AM_ICONV macro to detect and declare iconv. This fixes warning about const declaration. This macro defined in aclocal and therefore I renamed aclocal.m4 to acinclude.m4 and added bootstrap.sh. Please always use bootstrap.sh to create new configure script! 2009-03-08 Stipe Tolj * install-sh: use a more recent version taken from automake-1.10, in order to support wildcard filenames to install. This script is used in case the configure run finds no other BSD-compatible install program, i.e. required for Solaris 10 that has no such thing. 2009-03-02 Stipe Tolj * gw/bb_boxc.c: minor source re-formatting. NLC. 2009-03-02 Alexander Malysh * gwlib/charset.c: try to convert with iconv harder. 2009-03-01 Alexander Malysh * configure.in, configure: added openjade to search. Added /sw /opt/local to search path for docbook. 2009-03-01 Alexander Malysh * gw/bb_boxc.c: applied patch that fixes handling of multiple boxes with equal name. Thanks to Ben Suffolk for the initial patch. [Msg-ID: ] 2009-02-16 Stipe Tolj * doc/userguide/userguide.xml: adding documetation section for the command line switch for showing the version. * gw/shared.[ch]: moved the version printing related public functions. * gwlib/utils.[ch]: places the printing functions here and adding the --version command line switch to the general command line intrpreting function. [Msg-Id: <4996DF94.5010505@tolj.org>] 2009-02-15 Alexander Malysh * test/test_octstr_format.c: fixed compiler warnings. Thanks to Vincent CHAVANIS for patch. 2009-02-15 Alexander Malysh * gw/meta_data.c: fixed compiler warnings. Thanks to Vincent CHAVANIS for patch and to "Nikos Balkanas" . 2009-02-15 Alexander Malysh * gw/smsc/smsc_at.c: applied patch that includes more speed cases, and allows the default to be any speed (rather than 9600) *if* the OS behaves like OSX where B9600 == 9600 (not so under Linux). Thanks to Paul Bagyenda for this patch. [Msg-ID: <48DB2FB0-2D8B-4FC0-A00B-A33E36DAA45D@dsmagic.com>] 2009-02-10 Alexander Malysh * checks, gw/pushkannel.conf, gw/smskannel.conf, gw/wapkannel.conf: fixes for make check. It works now. Thanks to Vincent CHAVANIS for patch. 2009-02-10 Alexander Malysh * wap/wsp_headers.c: fixes wsp_pack_text -> wsp_pack_quoted_text. Thanks to Vincent CHAVANIS for patch. 2009-02-10 Alexander Malysh * test/*: various fixes. Thanks to Vincent CHAVANIS for patch. 2009-02-10 Alexander Malysh * wap/cookies.c: applied patch that fixes cookies parsing. Thanks to "Nikos Balkanas" for this patch. [Msig-ID: <006201c9865e$bd574230$02b2a8c0@tardis>] 2009-02-10 Alexander Malysh * test/test_date.c: added test to test gwlib/date. 2009-02-10 Alexander Malysh * gwlib/date.c: applied patch that corrects parsing of iso date for YYYMMDDTHHMMSS format. Thanks to Paul Bagyenda for this patch. [Msg-ID: ] 2009-02-06 Alexander Malysh * test/test_hmac.c, test/test_md5.c, test/test_octstr_dump.c, test/test_regex.c: applied patch that fixes segfaults. Thanks to Vincent CHAVANIS for patch. [Msg-ID: <498C3EE0.4030408@telemaque.fr>] 2009-02-06 Alexander Malysh * gw/smsc/smsc_at.c: fixed some memory leaks. 2009-02-04 Stipe Tolj * README: add the documentation requirement packages for Fedora Core too. 2009-02-04 Stipe Tolj * test/test_octstr_format.c: fix intendion according to our CodingStyle policy. NLC. 2009-01-29 Alexander Malysh * gw/smsc/smsc_smpp.c: this patch should fix #460. Changed %lu -> %llu in octstr_format call when strtoll is used. 2009-01-29 Alexander Malysh * gwlib/octstr.c, test/test_octstr_format.c: applied patch that adds support for %llu, %llx etc. to octstr_format. Also added test. Thanks to Nikos Balkanas for patch. [Msg-Id: <7f4386bc0901290255y3f8f44feya6132b138b0b6003@mail.gmail.com>] 2009-01-26 Stipe Tolj * gwlib/http.c: fix the recover_absolute_uri() to handle HTTPS connections to port 80 too, via applying the port 80 to the URL scheme if the connection IS SSL-enabled. Thanks to Martin for the vetoing. [Msg-Id: <92cf04420901251835k5f0636acueafdfd17f8147355@mail.gmail.com>] 2009-01-25 Stipe Tolj * gwlib/http.c: add function recover_absolute_uri() to handle partly incomplete absoluteURI values in redirect HTTP headers. [Msg-Id: <4979FB14.2000600@tolj.org>] 2009-01-21 Alexander Malysh * utils/makedist: added sha1 digest for packages. 2009-01-21 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed panic due to the unsupported %llu format in octstr_format. 2009-01-14 Alexander Malysh * doc/userguide/userguide.xml, gw/bb_alog.c, gw/bb_smscconn.c, gw/meta_data.[ch],gw/msg-decl.h,gw/smsbox.c,gw/smsc/smpp_pdu.[ch], gw/smsc/smsc_http.c,gw/smsc/smsc_smpp.c,gw/urltrans.c,gwlib/cfg.def, test/drive_smpp.c,test/drive_smpp.conf: merged meta-data branch. 2009-01-13 Stipe Tolj * test/test_http_server.c: fixing Alex's previous committ clash. NLC. 2009-01-13 Alexander Malysh * test/test_http_server.c: fixed memleak. 2009-01-12 Stipe Tolj * Making stable release 1.4.2. gateway-1.4.5/doc/ChangeLog-1.1.40000644000175000017500000004763307525470177014675 0ustar toljtolj2001-05-07 Richard Braakman * Making release 1.1.4. 2001-05-07 Richard Braakman * gwlib/list.h: list_len(NULL) returns 0. This has been true for some time now. Make it part of the documented interface. 2001-05-07 Richard Braakman * gwlib/octstr.[ch]: Added octstr_dump_short() for dumping octstrs that are expected to be short printable strings. The output is much shorter for such strings, but the function can still handle any kind of octstr. * gwlib/smpp_pdu.c: Made smpp_pdu_dump() use octstr_dump_short(). 2001-05-07 Richard Braakman * Updated NEWS file. 2001-05-07 Uoti Urpala * gw/smsc_emi2.c: Changed error handling for (re)opening connections, reorganized some code. 2001-05-07 Richard Braakman * gw/smsc_smpp.c: Use system-type for receiver as well as transmitter. 2001-05-06 Richard Braakman * gwlib/octstr.c: Fix edge cases in octstr_get_bits and octstr_set_bits. 2001-05-04 Richard Braakman * gw/smsc_cimd2.c: Made packet_encode_message() cope if the sender field is not set. 2001-05-04 Richard Braakman * configure.in, configure: Made libxml version check require 2.2.5 again, and added some output about the check. 2001-05-04 Aarno Syvänen * gw/wap_push_pap_compiler.c: Fixed an uninitialised variable 2001-05-03 Tuomas Luttinen * gw/wml_compiler.c (parse_text): A bug fix: added a check that around text emphasis the white space is not removed. 2001-05-03 Lars Wirzenius * Makefile.in, configure.in: applied patch from Craig Emery to slightly improve (and simplify!) building and configuring. 2001-05-03 Lars Wirzenius * gw/smsbox.c: Log username (at info level) whenever someone uses the sendsms service. Based on request from Johan du Buson. * gw/smsc_smpp.c: The transmitter thread is woken up as soon as there is something to send. Previously it woke up only when it was time to send the next enquire_link PDU. This was slighly slow. * test/drive_smpp.c: Deal with enquire_link PDUs. 2001-05-03 Lars Wirzenius * gw/smsc_smpp.c: Implemented system-type and address-range variables from the config file. In the I/O thread, timeouts are calculated to the next time when enquire_link needs to be sent, instead of using 1.0 seconds always. Configuration file is checked that it specifies smsc-username and smsc-password. * test/drive_smpp.conf: Added missing smsc-username and smsc-password. 2001-05-03 Lars Wirzenius * gw/smsc_smpp.c: Partly rewritten to use a simpler thread structure and to deal with I/O errors (such as broken connections). Most of the code is the same, but it has been rearranged. * test/test_smsc.c, gwlib/date.[ch]: Moved function date_universal_now from test_smsc.c to date.c. 2001-05-03 Aarno Syvänen * gw/wap_push_pap_compiler.[ch]: A compiler for compiling pap control messages to wap events. * gw/wap_push_ppg.c: Do not panic, when pi message does not not have any headers (a warning instead). Corrected a misspelling. Use prefix PAP in all enumerations defined by pap protocol. * gw/wap_push_ppg.h: Another misspelling corrected. Hnadle default values of pap attributes (by reordering, so that the numeric equi- valent of an attribute has value 0). * gw/wap_push_pap.c: A new test version of pap module. *wap/wap_events.def: Corrected a typo. 2001-05-03 Nick Clarey * gw/smsc_at.c: Applied patch from Alex Judd (ajudd@snaz.com), adding an automatic retry to message sending should it fail. 2001-05-02 Richard Braakman * gw/smsc_cimd2.c: Fix encoding of text messages that have UDH. (It got the length wrong due to a _probable_ misreading of the spec. If SMSCs implement what we thought it had said, then we have a problem.) 2001-05-02 Richard Braakman * gwlib/octstr.c: Made octstr_get_char() not crash if pos < 0. It now returns -1 instead. 2001-05-02 Richard Braakman * gw/wap_push_ppg.h, wap_push_pap.c: Renamed TRUE and FALSE to PAP_TRUE and PAP_FALSE. (These are enumerated protocol values.) Needed for portability to systems that predefine TRUE and FALSE macros. 2001-04-30 Richard Braakman * gw/smsc_{at,cimd2,ois,smpp}.c, gw/sms.h, gw/smpp_pdu.h: Standardized on two data coding scheme values, called DCS_GSM_TEXT and DCS_OCTET_DATA. Not all protocols can use these, but at least the ones that do will all use the same values. Both have now been chosen to set only the alphabet, and leave message class alone. 2001-04-29 Derry Hamilton * configure.in,configure: Allow libxml versions between 2.2.10 and 2.2.19. 2001-04-26 Lars Wirzenius * gw/smsc.c, gw/smsc_p.h, gw/smsc_smpp.c, gw/smscconn.c, gw/smscconn_p.h: Converted SMPP driver to use the SMSCConn interface. This is needed to improve reliablity of the driver, which will happen next. 2001-04-26 Richard Braakman * gw/smsc_cimd2.c: Reopen connection if SMSC does not respond to "alive" request. 2001-04-26 Richard Braakman * gwlib/http.c: Handle 100-Continue responses. 2001-04-26 Richard Braakman * gw/smsc_cimd2.c: Stopped sending "delivery request" when logging in. It is not needed in the normal configuration, and it confuses some SMSCs. Thanks to Antti Valtokari for tracking this down. (If it _is_ needed in your configuration, then you will not get messages that arrived while Kannel wasn't connected.) * doc/userguide/userguide.xml: Explain what configuration the cimd2 driver expects from the SMSC. 2001-04-25 Tuomas Luttinen * configure[.in] : Kannel now requires libxml 2.2.5 or newer. Reasons for this are: *encondingAliases functions that were included in 2.2.3 *a bug that affects XML attributes in 2.2.3 and 2.2.4 2001-04-25 Uoti Urpala * gw/smsc_emi2.c, gw/emimsg.c: Changed debugging output, made reconnections more robust. 2001-04-25 Richard Braakman * gw/smsc_at.c: In pdu_encode(), revert to using a Protocol-ID of 0 (implicit) rather than 0x1F (which doesn't seem to be defined). This might be the key to the problems people have had with this module. Please let us know. 2001-04-25 Richard Braakman * doc/TESTCASES: Removed, we have "make check" now. 2001-04-24 Uoti Urpala * doc/userguide/userguide.xml: Added information about emi2. 2001-04-24 Lars Wirzenius * gw/smsc_smpp.c, test/test_smsc.c: Implemented sending of enquire_link packets and handling of their responses. This is very simplistic, still: It doesn't check that the responses are actually received. That will have to be implemented later. 2001-04-24 Richard Braakman * gw/smsc_wrapper.c: Produce an info log when a reconnection attempt succeeds. 2001-04-23 Lars Wirzenius * gwlib/octstr.c, test/fakesmsc.c, utils/start-stop-daemon.c, wap/wsp_push_client_machine.def, wap/wsp_session.c: Applied manually parts of patch send by Dirk-Willem van Gulik as improvements for MacOS X. Mainly this included renaming of some local variables (uint -> ui), presumably because MacOS X defines uint as a macro. Also reformatted fakesmsc and start-stop-daemon output and corrected preprocessor syntax. 2001-04-23 Richard Braakman * gwlib/http.[ch]: Added support for HEAD method, supplied by Jarkko Kovala. 2001-04-23 Richard Braakman * gwlib/socket.c: Clear sockaddr_in structure before using it, to make FreeBSD happier. 2001-04-21 Uoti Urpala * gw/smsc_emi2.c: Fixed a stupid bug in the previous fix. 2001-04-20 Uoti Urpala * gw/smsc_emi2.c: Fixed a bug in SMSC time stamp parsing. 2001-04-19 Richard Braakman * gw/smsbox.c: Fixed bad assertion in prepend_catenation_udh(). 2001-04-18 Richard Braakman * gwlib/gwthread-pthread.c: Made gwthread_join safe. 2001-04-18 Kalle Marjola * gw/bb_store.c: updated writing to file a bit. Still problem if messages arrive faster than store_cleanup works, needs to modify to use hash at some point * gw/bb_smscconn.c: changed so that when shutting down, ignores messages that cannot be routed. So if you have not enabled SMS-store, some messages can be lost. 2001-04-18 Kalle Marjola * doc/userguide/userguide.xml: fixed some typos 2001-04-17 Uoti Urpala * gw/smsc_emi2.c, gw/emimsg.[ch]: Added support for operation type 01, other changes to work with different SMSC setups. 2001-04-17 Richard Braakman * gw/urltrans.c: In strip_keyword(), use the right test for end of octstr. This fixes handling of messages that only have the keyword. 2001-04-17 Lars Wirzenius * gwlib/http.c: When the http module is shut down, set run_status to limbo so it can be restarted. Paul Keogh wanted this so that (parts of) Kannel can run as a COM object. 2001-04-17 Lars Wirzenius * doc/CodingStyle: Added a paragraph about CVS tags. 2001-04-16 Richard Braakman * gw/wap_push_ota.c: Removed and includes. They are not used by anything and cause portability problems. 2001-04-13 Uoti Urpala * gw/smsbox.c: Bugfix, messages sent with sendsms GET requests were always marked as binary (this bug was created when sendsms POST was added). 2001-04-12 Lars Wirzenius * gw/smsc_smpp.c: Make it optional to dump or not dump SMPP pdus that are received or sent. Not dumping them reduces "make bench" log file sizes by about half a gigabyte. 2001-04-12 Kalle Marjola * gw/urltrans.c (urltrans_get_pattern): fixed that %s cannot cause overflow if there is catch-all argument 2001-04-11 Richard Braakman * gw/urltrans.c: Slight simplification of strip_keyword(). 2001-04-11 Kalle Marjola * README: changed smsc interface guidelines to point to smscconn_p.h * gw/smsc_interface.def: removed as depricated * doc/userguide/userguide.xml: fixed typo, it is strip-keyword, not split-keyword * gw/urltrans.c: modified strip-keyword function * gw/bearerbox.c: changed shutdown message a bit when killedby signal 2001-04-10 Kalle Marjola * gw/bb_store.c: some little fixes, dumps acks to file, too, if any in memory * gw/bb_boxc.c: added some comments for possible future updates 2001-04-10 Kalle Marjola * gw/bb_store.c: Bugfix: comprasion was wrong way around... 2001-04-10 Kalle Marjola * gw/bb_store.c: Updated to use double-memory buffering and to do frequent dumps out of that data. Now it is fast and does not take much disk space. Interval is currently fixed (5 secs), and there is still no message queue limitations, and sendsms (push9 messages are not yet supported. But otherwise it should work. * gw/bearerbox.c|h: required little modifications * doc/userguide/userguide.xml: added notes of store-file variable 2001-04-10 Richard Braakman * gw/smsbox.c: Add no-cache headers to sendsms replies. 2001-04-05 Uoti Urpala * gwlib/http.c: Fixed a bug in the sending of HTTP replies. It was unlikely to be triggered with replies as short as Kannel normally uses, though. * gwlib/conn.[ch]: The callback function of registered connections is called when all queued output is sent. This was required for the above fix. 2001-04-04 Kalle Marjola * gw/smsbox.c: Bugfix. Fixed memory leak in header parsing 2001-04-03 Richard Braakman * gwlib/fdset.c: When destroying an fdset with active fd's, simply ignore those fd's and make it the caller's responsibility to deal with them. This reverses a change from 2000-11-22, which was made at the time to fix the http shutdown sequence. It didn't, and now it's in the way of a better solution. 2001-03-30 Uoti Urpala * gwlib/http.c: Enabled keepalive connections again. 2001-03-29 Uoti Urpala * gw/urltrans.c: Test in find_translation() was the wrong way around, 'accepted-smsc' actually worked like denied-smsc. Fixed. Also enabled using 'accepted-smsc' in default SMS-service groups. 2001-03-29 Uoti Urpala * gw/smsc_emi2.c: Added support for the "our-port" parameter. * gwlib/conn.[ch]: Added function conn_open_tcp_with_port, which allows specifying the local port number. 2001-03-29 Uoti Urpala * gwlib/http.c: Added a test that checks whether connections in the connection pool have been closed before trying to reuse them. 2001-03-28 Uoti Urpala * gw/smsc_emi2.c: Wrote. New implementation of the emi_ip protocol. * gw/emimsg.c, gw/emimsg.h: Wrote. Functions for working with EMI messages. Used by smsc_emi2.c and testing programs which I didn't add to CVS yet. * gw/smscconn.c, gw/smscconn_p.h: Modified to recognize the new smsc type. 2001-03-28 Kalle Marjola * gw/smsbox.c: added content-type checking in sendsms POST, and set binary of sms.msgdata accordingly (note: UDH+7bit msgdata might not work with some SMSC center protocols currently) 2001-03-27 Aarno Syvänen * gw/wap_push_ppg.c: Fixed a compiler warning 2001-03-27 Kalle Marjola * gw/smsbox.c: combatibility breaker: do not allow default sendsms user anymore (guess I thought that that has been disabled years ago...) * gw/smsbox.c: added POST support for send-sms, too. Hopefully works. Use is automatic, if request to Kannel is POST, body is used as message text, otherwise cgi-args are parsed. Username, password, receiver number etc. are taken from X-Kannel headers (like X-Kannel-Password) and are documented real soon... 2001-03-27 Kalle Marjola * doc/userguide/userguide.txt: added new configuration variables, but missing X-Kannel header definations. Will add these later. * gw/smskannel.conf: changed 'url' to 'get-url' (althought plain url still works, for backward compability) 2001-03-27 Kalle Marjola * gw/smsbox.c: added post-url support for sms-service group. Documentation in User's Guide RSN (hopefully) * gw/urltrans.c: added that strip-keyword with POST is done here, althougt that is ugly (but easier to do that way) 2001-03-27 Kalle Marjola * gwlib/cfg.h|c: added new function cfg_get_bool, taking true/false, on/off, yes/no or 0/1 * urltrans.c: modified to use new bool type with concatenation, omit-empty and some new variables (theoretical compatibility breaker) * urltrans.c|h: added new variables for sms-service group: catch-all (should work as %a or %r in pattern), accept-x-kannel-headers (see below) and some variables for POST use * smsbox.c: Compatibility breaker: modified to allow from, to and UDH field set by SMS service, as X-Kannel- header, if accept-x-kannel-headers set for sms-service. The compatibility breaker is that X-Kannel-UDH does not work anymore unless accept-x-kannel-headers is set * smsbox.c: Compatibility breaker: if sms-service HTTP fetch reply is of content-type application/octet-stream set flag 8bit on. This can be prevented by setting assume-plain-text on for the service. 2001-03-27 Tuomas Luttinen * configure.in: Removed the earlier patch, the test was just on the old implementation, I didn't run autoconf... 2001-03-27 Aarno Syvänen * gw/wap_push_pap.c|h. Testing version of the pap module * gw/wap_ppg_push_machine.def, gw/wap_ppg_session_machine.def: Machines to store push data. * gw/wap_push_ppg.c|h: push proxy gateway main module * gw/wap_push_ota.c: Lots of bugfixes. Courtesy to Peter Galluc, Derry Hamilton and Uoti. (There were other bugs, too.) Trans- ferred handling of header X-Wap-Application-Id to module ppg. Fixing memory leaks. * wap/wap_events.def: push_id removed from Pom-Connect.req. * gw/wapbox.c: Initing and shutdown of new modules, include new headers. * gw/wap-appl.c: Added handling of the event Pom-Connect.req * wap/wsp_server_session_states.def: Corrected a typo spotted by Aymerick Jehanne. * wap/wsp_session.c: Added functions to create events for push abort and confirmation, fixed bugs in functions make_confirmed_push pdu and make_push_pdu. Fixed memory leaks. 2001-03-27 Tuomas Luttinen * configure.in: Replaced the earlier way to detect xml2-config with patch provided by Craig Emery that is shorter and as effective. Both were tested with different libxml versions, also with both xml-config and xml2-config. 2001-03-27 Richard Braakman * gw/smsbox.c: Fix bad memory management of faked_sender string. 2001-03-26 Richard Braakman * gw/smsbox.c: Converted some char * to Octstr *. * gw/smsc_cimd2.c: Changed "const static" to "static const" in variable declarations (ansification). * utils/run_kannel_box.c: In print_usage(), actually use the stream argument instead of always printing to stderr. 2001-03-26 Uoti Urpala * gw/msg.c: Fixed bug when sizeof(long) != 4, removed unneeded code. 2001-03-23 Richard Braakman * gw/smsbox.c: Fix call to alog (urltrans_username returns Octstr *, not char *). Spotted by Paul Keogh and Gildas PERROT. 2001-03-23 Kalle Marjola * gw/smscconn_p.h: made interface a bit more clarified and moved counters to callback * gw/bb_smscconn.c: added counter increases * gw/smsc_wrapper.c, gw/smsc_fake.c: removed counter increases 2001-03-23 Kalle Marjola * gw/smsc_http.c: various little fixes 2001-03-23 Tuomas Luttinen * utils/kannel-stable-rh*.spec (Requires): Now requires libxml2 >= libxml2-2.2.0. 2001-03-22 Kalle Marjola * gw/smsc_http.c: put smsc-id to correct place 2001-03-22 Kalle Marjola * gw/smsc_http.c: fixed several memory leaks 2001-03-22 Uoti Urpala * gwlib/http.c: Fixed memory leak. 2001-03-21 Lars Wirzenius * gwlib/cfg.h: Commented return value policy for octet strings. 2001-03-21 Tuomas Luttinen * configure.in, configure: Added the xml2-config that libxml-2.3.* and newer want instead of xml-config. Tested with libxml-2.2.11 and 2.3.4. Yet to be tested with both libxml1 and libxml2 installed. 2001-03-21 Kalle Marjola * gwlib/xmlrpc.h|c: Updated, still missing many things 2001-03-21 Kalle Marjola * gwlib/xmlrpc.h|c: Added. Initial code to implement XML-RPC specification. 2001-03-21 Lars Wirzenius * checks/check_http.sh: Kill server via HTTP, instead of via a signal. This way, if the server has trouble dying properly, it will be quite visible, instead of possibly hidden by signal handling. 2001-03-21 Uoti Urpala * gwlib/http.c: Fixed memory leaks, updated keepalive connections to work again after Richard's changes (still left them disabled by default though). 2001-03-21 Uoti Urpala * gw/bb_smscconn.c: Fixed incorrect test in sms_router, the smsc_id of a discarded message was logged only if it _was_ NULL. 2001-03-20 Richard Braakman * gwlib/http.c: Server side now accepts POST requests. This involved separating the header and body reading code into a section shared by server and client side. * Fixed a bug along the way which would cause busy-waiting in the client code when waiting for a result to arrive. Also made return codes consistent for the state functions, so that 0 means completion and 1 means waiting for more input. gateway-1.4.5/doc/ChangeLog-1.4.50000644000175000017500000005445313310761405014661 0ustar toljtolj2018-06-15 Stipe Tolj * gw/bb_smscconn.c: fix copy and paste typo, causing memory corruption and hence PANIC/segfault while using HTTP admin command /reload-lists. 2018-06-15 Stipe Tolj * test/test_http.c: add URL escape codes for %r for random number and $I for UUID string representation. Escape pattern scaning is activate via option switch -V. 2018-06-11 Stipe Tolj * gwlib/gw_uuid.c: ensure we handle SunOS (Solaris) for SIOCGIFHWADDR. * gwlib/log.c: define syslog facility names for SunOS (Solaris). Minor patchset to support Solaris 11 (SunOS 5.11) builds again. 2018-03-23 Stipe Tolj * configure.in: fixing r5201, which breaks openssl function testing for any older openssl versions, i.e. 0.9.8f, since the version checking doesn't handle 0.x correct. We rather use the AC_CHECK_VERSION() construct for this and remove all characters from the version string first. 2018-03-22 Stipe Tolj * gw/dlr_cass.c: fix obvious copy-and-paste typo. NLC. 2018-03-08 Stipe Tolj * gw/smsc/smsc_smpp.c: fix enforced meta-data data_coding handling when getting coding = DC_7BIT (hence UTF-8), but want to enforce to Unicode. In this case we would have sticked to UTF-8 in the payload, but declared it as data_coding = 0x00 (indicating GSM 03.38), which is wrong of course. 2018-02-28 Alexander Malysh * added support for openssl version > 1.1 2018-02-14 Alexander Malysh * test/test_http.c: fixed compilation error. 2018-02-14 Alexander Malysh * configure.in: fixed deprecation warnings. 2018-01-17 Alexander Malysh * updated Copyright year. 2018-01-17 Alexander Malysh * gw/bb_smscconn.c: fixed copy & paste error. This fixes #773. 2017-11-29 Alexander Malysh * configure: moved utils compile to extra Makefile.am and fixed conditional make for start-stop-daemon. 2017-11-21 Alexander Malysh * gw/bb_smscconn.c: fixed copy & paste error. This fixes #772. 2017-11-21 Stipe Tolj * doc/userguide/userguide.xml: document hard-coded 'data_coding' value for SMPP's meta-data group. 2017-10-13 Stipe Tolj * doc/userguide/userguide.xml: document 'const' directive in context group 'smpp-tlv'. * gw/smsc/smpp_pdu.[ch]: implement smpp_tlv_add_constant() to add any configured constant values if the corresponding TLV values have not been set via the meta-data part. * gw/smsc/smsc_smpp.c: call smpp_tlv_add_constant() to set contant values. * gwlib/cfg.def: add 'const' to 'group = smpp-tlv'. 2017-09-26 Stipe Tolj * gwlib/dbpool_redis.c: fix segfaulting when under high load and stopping redis-server connections. 2017-07-19 Alexander Malysh * gw/smsc/smsc_smpp.c: Fixed sending of long messages. This fixes #769. 2017-06-16 Stipe Tolj * doc/userguide/userguide.xml: add documentation for config directives 'ssl-[client|server]-cipher-list'. * gwlib/cfg.def: add above config directives to 'group = core'. * gwlib/conn.[ch]: ensure openssl engine cleanup is performed more cleanly, this avoids various static memory leaks reported by valgrind, and add encryption suite and cipher select/de-select configuration. This patchset allows configuring the SSL/TLS client/server side connection by defining which suites and ciphers should be used. The corresponding cipher stings are defined in the openssl documentation part. 2017-04-11 Stipe Tolj * gw/smsc/http/generic.c: provides the missing MO part for the generic type from the patchset dated 2017-03-14, allowing to send UTF-8 data, which can then be forwarded as UCS-2 towards the smsbox connection. We transcode ONLY if an alt-charset is set and a coding value has been provided. 2017-04-10 Stipe Tolj * gw/smsc/smsc_http.c: fix transcoding by using UTF-16BE as UCS-2 encoding indication. 2017-03-14 Stipe Tolj * doc/userguide/userguide.xml: remove 'wapme' reference for HTTP SMSC type. * gw/smsc/smsc_http.c: re-considering an older issue, when having UCS2 payload from the smsbox connection side. All major HTTP API will NEED a unique encoding that is injected, and we will use 'alt-charset = UTF-8' to allow setting a config diretive to convert ANY encoding to UTF-8 towards the upstream, which reflects an unique input encoding, otherwise there is no way to distinguish this. This allows keeping the currentlogic if no 'alt-charset' is set. * gw/smsc/http/wapme.c: removed the 'wapme' type as it is dead for quite some time now. This patchset ensures that we have a construct (via setting a config directive, alt-charset) to uniquely provision MTs to the upstream SMSC. [Msg-Id: <4D76BF9C.7070700@tolj.org>] 2017-02-22 Stipe Tolj * gwlib/http.c: fix missing keep-alive indication when we DO keep the connection persistent as a server, cleaned up the corresponding negotiation constraint to fit the RFC2616 requirement. 2017-01-04 Stipe Tolj * gw/msg.h: add msg admin 'cmd_feature' to allow passing feature on/off commands within the inter-box communication. NLC. 2017-01-10 Alexander Malysh * gwlib/octstr.c: deleted immutable assert from octstr_cat. 2016-12-13 Stipe Tolj * gw/smsc/smsc_http.c: fixing asymetric load distribution for this SMSC type if there is a large set of non-relevant SMSCs groups and a set of relevant groups, the first group would be systematically prefered, which leads to an un-even distribution. The load is now set as with the other SMSC types based on the queue size. 2016-12-06 Stipe Tolj * doc/userguide/userguide.xml: indicate the terminus SSMPP for secure SMPP. * gw/smsc/smsc_smpp.c: indicate 'SSMPP' for secure SMPP connections. 2016-11-14 Alexander Malysh * gw/smsbox.c, gw/smsc/smsc_cimd2.c, gw/smsc/smsc_smpp.c: applied patch to support DLR_EXPIRED. Thanks to Iwan Iwanowicz for the patch. 2016-10-26 Alexander Malysh * gw/smsc/smpp_pdu.c: applied patch that fixes memory leak if TLV is sent twice. Thanks to Donald for this patch. 2016-08-22 Alexander Malysh * gw/load.c: fixed load calculation 2016-08-04 Alexander Malysh * gwlib/xmlrpc.c: fixed crash if wrong formated xml given 2016-08-04 Alexander Malysh * gw/dlr.[ch]: added DLR_EXPIRED and DLR_UNKNOWN dlr mask 2016-08-04 Alexander Malysh * gwlib/gwthread-pthread.c: fixed memory leak and panic if new thread could not be created 2016-07-14 Alexander Malysh * gw/load.[ch]: Changed precision timing to microsec. Thanks to kneodev at gmail.com for initial patch. 2016-07-13 Stipe Tolj * gwlib/dbpool_mysql.c: fix error code handling for mysql_stmt_execute(). The function returns CR_ error codes, we need to call _stmt_errno() to get the server side ER_ error codes and retry on temporary ones. 2016-05-26 Stipe Tolj * gwlib/dbpool.h: add missing define for Cassandra. 2016-05-09 Stipe Tolj * gw/smsc/smsc_smpp.c: relax SMPP DLR scanning for a better pattern match. [Msg-Id: <5720AAD1.2000500@kannel.org>] 2016-04-14 Stipe Tolj * doc/userguide/userguide.xml: add documentation for escape code '%e'. * gw/urltrans.c: add escape code '%e' for printable hexadecimal byte codes. 2016-02-15 Stipe Tolj * gw/dlr.c: add missing original DLR bit-mask forwarding in case of DLR SMSC[SUCCESS|FAIL] events. 2015-12-22 Alexander Malysh * gwlib/conn.[ch]: renamed some ssl init functions to be in conn_XXX namespace. test/test_http.c: implemented cmd line option to provide CA file. 2015-12-21 Alexander Malysh * gw/bb_smscconn.c: fixed MO concatenation handling for rerouting cases. 2015-12-17 Stipe Tolj * doc/examples/dlr-mysql.conf: add comment block describing an advanced configuraiton for MySQL with scheduled events for DLR table clean-up. 2015-12-17 Stipe Tolj * doc/examples/dlr-cassandra.conf: example for Cassandra. * doc/userguide/userguide.xml: documentation for Cassandra support. * gw/dlr_cass.c: adding DLR handling via Cassandra. * gw/dlr_p.h: adding dlr_init_cass() prototype. * gw/dlr.c: add 'spool = cassandra'. * gwlib/cfg.def: adding 'group = cassandra-connection' context. * gwlib/dbpool_cass.c: adding Cassandra DBPool support via DataStax C/C++ Cassandra driver library. * gwlib/dbpool.[ch]: include Cassandra handling. * test/test_dbpool.c: add Cassandra testing capabilities. * configure[.in]: adding --with-cassandra and --with-cassandra-dir * gw-config.h.in: define HAVE_CASS This patchset adds support for the Apache Cassandra 2.1, 2.2 and 3.0 database engine. Initially DLRs can be stored in the database. 2015-12-14 Stipe Tolj * doc/examples/store-redis.conf: add documentation for the 'hash' config directive in the 'group = store-db' context. * gw/bb_store_redis.c: use redis with binds list and implement an 'hash' mode that allows for readable object in the redis store, rather then the string blobs as sinle key/value pair. * gw/dlr_redis.c: use the binds list values. * gwlib/cfg.def: add 'hash' config directive to 'group = store-db' context. * gwlib/dbpool_redis.c: implement the usage of redisCommandArgv() with the binds values via the list. This patchset re-writes some parts of the redis support modules, mainly to support the more generic redisCommandArgv() API call that makes things more robust internally. 2015-11-16 Alexander Malysh * gw/bb_smscconn.c: fixed crash in smsc2_find if id or admin_id is NULL. 2015-10-23 Alexander Malysh * gw/smsbox.c: fixed xml post parsing. Check ud type and if not binary don't try to hex decode. 2015-10-01 Stipe Tolj * gw/sms.[ch]: incubate function sms_charset_processing() into module. * gw/smsbox.c: removed charset_processing(). * gw/smsc/smsc_http.c: fix missing 'charset' processing for type kannel when receiving MOs. 2015-09-25 Stipe Tolj * utils/mtbatch.c: add option -x to disallow injection of smsbox-id to MT messages, in order to let normal smsbox connection handle DLRs. 2015-08-04 Alexander Malysh * gwlib/conn.c: added support for chained certificates. 2015-07-20 Stipe Tolj * gw/dlr.c: add the original msg DLR bitmask to the meta-data of the DLR, allowing smsbox applications to retrieve this information on-the-fly without the need to do local storage/retrieval. * gw/meta_data.h: define the macros for the DLR bitmask of the orig msg. 2015-07-13 Alexander Malysh * gw/bb_store.[ch], gw/bb_store_file.c, gw/bb_store_redis.c, gw/bb_store_spool.c: Applied patch that fixes store file race condition by status request. Additionally this patch removes status from each of store and add it to bb_store to abstract and simplify status handling in store. 2015-07-01 Stipe Tolj * doc/userguide/userguide.xml: add documentation for escape code %N for DLR notification text. * gw/bb_alog.c: implement %N escape code for 'access-log-format' pattern. 2015-06-24 Alexander Malysh * configure.in, configure: fixed library search path order issue on OSX with MacPorts installed where iconv library was not found for linking. 2015-06-24 Alexander Malysh * utils/mtbatch.1: fixed bad formatting. This fixes #728. Thanks to Kalle Niemitalo. 2015-05-18 Stipe Tolj * gw/smsc/smsc_smpp.c: harmonize the [data|deliver]_sm handling where we don't find a DLR in our storage. Make sure we log a FAILED event in the access-log for both PDU types. 2015-05-17 Stipe Tolj * gw/bb_boxc.c: ensure we get a wakeup call while being in gwthread_sleep() in sms_to_smsboxes(), which reduces the shutdown waiting time. Ensure we don't re-loop if we're in shutdown phase. * gw/bearerbox.c: issue gwthread_wakeup_all() after bb_shutdown() in order to wakeup all pending sleepers. [Msg-Id: <55364459.7030503@kannel.org>] 2015-03-19 Stipe Tolj * gw/bb_store_redis.c: fix memory leak when the result set is empty, we still get a single row entry from the redis side, which needs to be destroyed. 2015-03-18 Stipe Tolj * config.guess: update to latest version to support various more platforms. [http://savannah.gnu.org/projects/config] 2015-03-12 Alexander Malysh * Makefile.in: fixed make invocation for subfolders 2015-03-12 Alexander Malysh * Makefile.in: addeed possibility to easy add subdirectories to build process 2015-03-12 Alexander Malysh * Makefile.in, aclocal.m4, bootstrap.sh, configure, configure.in, soap/Makefile.in: first step in automake direction. 2015-02-23 Stipe Tolj * gw/smsc/smsc_http.c: the queued callback function should return the number of messages in queue, and not the open requests that we are pending. 2015-02-20 Stipe Tolj * doc/examples/store-redis.conf: configuration example for redis msg store. * doc/userguide/userguide.xml: document 'store-type = redis' option. * gw/bb_store_redis.c: backend implementation of the message store in a redis key store. * gw/bb_store.[ch]: adding Cfg* passing in store_init() prototype. * gw/bearerbox.c: changed to do store_init() prototype change. * gwlib/cfg.def: adding 'group = store-db' as group for message backends as databases or key stores. * test/test_store_dump.c: changed to do store_init() prototype change. This patchset implements the redis key store backend as a message store for bearerbox. This allows to have persistancy on a remote system without using the local file system. Thanks to Alejandro Guerrieri for the patch. [Msg-Id: ] 2015-02-20 Stipe Tolj * gwlib/utils.c: removing info() calls after gwlib_shutdown() calls for the parent process exiting. This results in a 0 exit code on MacOS. 2015-02-19 Alexander Malysh * gw/smsbox.c: fixed issue with XML MT request, was not decided anymore. 2015-02-04 Stipe Tolj * gwlib/log.c: don't dump the WARNING in log_thread_to() if there was no attempt to open an SMSC specific log, i.e. no 'log-file' was set. 2015-01-29 Alexander Malysh * doc/userguide/userguide.xml: added description for new log-format config option. 2015-01-29 Stipe Tolj * gw/ota_compiler.c, gw/smsbox.c, gw/wap_push_[pap|si|sl]_compiler.c, gw/wml_compiler.c, gwlib/xmlrpc.c: FreeBSD CURRENT messes up with __wchar_t typedef used heavily by libxml2, so we need to make sure the internal types are included to fix the building on FreeBSD CURRENT. 2015-01-29 Stipe Tolj * configure[.in]: fix openssl library detection via GCC's print-file-name argument. We need to obey what $CC is set, not call the binary name directly. This broke the configure on FreeBSD CURRENT. 2015-01-28 Stipe Tolj * gwlib/log.[ch]: fix segfault when calling log_thread_to() with -1 argument, due to a failed log_open() call, i.e. permission denied. Since the unsigned int type wrapps arround the if statement in the function yields and we address a random memory segment via the logfiles[] array, resulting in possible segfaults. Now we also log a WARNING statement in case the thread specific log file could not be opened to inform the user in the general/stdout log abou the fact. 2015-01-28 Stipe Tolj * gw/smscconn.c: fixing bug #708 in function c:smscconn_usable(). We need to bail out for connectioks with status SMSCCONN_ACTIVE_RECV, since those can't be used for routing. Some source code reformating, NLC. 2015-01-19 Alexander Malysh * gw/smsc/smpp_pdu.[ch], gw/smsc/smsc_smpp.c, gwlib/cfg.def: added new PDU dump function that allow to dump in one line instead of multiline, for better parsing. It can be switched with new log-format configuration option. 2015-01-02 Stipe Tolj * gw/smsc/http/generic.c: fix segfault when starting without specific configuration directives for this type. 2014-12-19 Stipe Tolj * gw/sms.c: add a TODO note in function extract_msgdata_part_by_coding() that yields a GSM centric limitation in regards of character encoding support. NLC. * gw/smsc/smsc_smpp.c: use DCS handling functions to reduce code redundancy on the MO side, and also support individual data_coding setting via meta-data value. 2014-12-18 Stipe Tolj * doc/userguide.xml: cleaning section "Fake messages" to include all types. * gw/smsc/smsc_fake.c: add support for UDH + 7bit text, using types udh-data and udh-text now. * test/fakesmsc.c: adding reference for udh-data and udh-text types. 2014-12-18 Stipe Tolj * test/fakesmsc.c: add missing usage output for type 'dlr-mask'. 2014-11-17 Stipe Tolj * doc/userguide/userguide.xml: document the new graceful restarting. * gw/bb_http.c: add new HTTP admin URI /graceful-restart. * gw/bb_smscconn.c: implements graceful restarting of bearerbox. * gw/bearebox.[ch]: signal SIGHUP handling for graceful restarting, and SIGUSR2 for pure log re-opening. * gw/smscconn_p.h: add MD5 checksum variable for graceful restarting. * gw/smscconn.[ch]: do MD5 calculation on parts of the config for change detection. * gwlib/cfg.[ch]: additions for MD5 calculation of the config parts. This patchset 'gateway-graceful-restart.v5.diff' implements the soft/graceful restarting of bearerbox. Where the process can be signaled via SIGHUP and re-loads the SMSC configurations. Any config parts that are not modified keep on running, and either SMSCs are re-connected or shutdown. In addition re-configuration of routing config directives will cause NO re-connecting of the corresponding SMSC groups. [Msg-Id: <50822776.7040809@kannel.org>] 2014-11-12 Stipe Tolj * gw/smsc/smsc_smpp.c: extend Alex's patchset to also support destination TON/NPI setting via meta-data values. 2014-11-12 Stipe Tolj * doc/userguide.xml: added 'instances' to 'group = smsc' context. * gw/[bb_]smscconn.[ch]: allow multiple instances to be created via the corresponding config directive. * gwlib/cfg.def: added 'instances' to 'group = smsc' context. [Msg-Id: <5452797C.2020207@kannel.org>] 2014-11-12 Stipe Tolj * doc/userguide.xml: document new config directives and declare deprecates. * gw/bb_boxc.c: handle SMSCCONN_FAILED_REJECTED response for routing. * gw/bb_smscconn.c: crean the white/black listing handling to support sender/receiver side testing. * gwlib/cfg.def: add new white/black listing config directives. [Msg-Id: <54525E66.1020308@kannel.org>] 2014-11-11 Alexander Malysh * gw/smsc/smsc_smpp.c: allow overwrite of source_addr ton/npi on message basis via meta_data 2014-11-06 Alexander Malysh * gw/smsc/smpp_pdu.c: added check fo defined fields and print error only if it's unknown TLV 2014-11-06 Stipe Tolj * gwlib/dbpool_mysql.c: handle temporary error codes, mainly for InnoDB's lock handling for mysql_stmt_execute() calls, which are rolled back and then need to be retried by the application side, according to error code references at http://dev.mysql.com/doc/refman/5.0/en/innodb-error-codes.html. 2014-10-22 Alexander Malysh * gw/smsc/smsc_smpp.c, gw/dlr.h: dropped SMPP specific intermediate dlr mask and replaced it with abstracted buffered. 2014-10-13 Stipe Tolj * gw/smsc/smsc_fake.c, test/fakesmsc.c: add UCS-2 (Unicode) support for MO messages withing FAKE SMSC type. 2014-10-13 Alexander Malysh * gw/meta_data.h: added SMPP group 2014-10-13 Alexander Malysh * gw/smsc/smpp_pdu.[ch], gw/smsc/smsc_smpp.c: fixed error code SMPP_ESME_RALYNBD -> SMPP_ESME_RALYBND. 2014-10-13 Alexander Malysh * gwlib/conn.c: added more vorvose SSL error. Thanks to Artem Pylypchuk for this patch. 2014-09-25 Stipe Tolj * test/test_regex.c: fix substring dumping, upper limit caused PANIC. NLC. 2014-09-08 Alexander Malysh * gw/dlr_sqlite3.c: fixed DLR status update, see #705. Thanks to Filippo Natali for this patch. 2014-08-01 Stipe Tolj * Making stable release 1.4.4. gateway-1.4.5/doc/fakewap-packets.txt0000644000175000017500000001737407035334776016272 0ustar toljtoljPackages sent and received by the fakewap program This file documents the packages sent and received by the fakewap program. Fakewap tests a WAP gateway by sending UDP packages to make simple requests for WML pages. It is meant for stress testing the gateway. The basic session looks like this (WTP is the transaction and WSP is the session protocol layer): A) Fakewap -> Gateway WTP: Invoke PDU WSP: Connect PDU B) Gateway -> Fakewap WTP: Result PDU WSP: ConnectReply PDU C) Fakewap -> Gateway WTP: Ack PDU D) Fakewap -> Gateway WTP: Invoke PDU WSP: Get PDU E) Gateway -> Fakewap WTP: Result PDU WSP: Reply PDU F) Fakewap -> Gateway WTP: Ack PDU G) Fakewap -> Gateway WTP: Invoke PDU WSP: Disconnect PDU Packets A-C open a WAP session. Packets D-F fetch a WML page. Packet G closes the session. The fakewap program does not need to understand the WAP protocols as such, it just needs to generate packets in the right order with a little variation, and keep track of which packets have received and which have not received responses. The detailed formats of the packets are listed below. Note that bits are numbered in the WAP specification with the most significant bit being 0, not 7. Unspecified bits are filled in fakewap or the gateway. Packet A) bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ------------+---+---+---+---+---+---+---+---| octet 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | ------------+---+---+---+---+---+---+---+---| octet 2 | 0 | | | | | | | | \ TID, fakewap ------------+---+---+---+---+---+---+---+---| |-- generates octet 3 | | | | | | | | | / linearly ------------+---+---+---+---+---+---+---+---| octet 4 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ------------+---+---+---+---+---+---+---+---| octet 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ------------+---+---+---+---+---+---+---+---| octet 6 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet 7 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| Fakewap generates a new TID (transaction ID) for each A) packet is generates. TIDs are generated linearly. If a 15 bit counter overflows, fakewap can, for now, stop sending anything. Packet B) bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ------------+---+---+---+---+---+---+---+---| octet 1 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | ------------+---+---+---+---+---+---+---+---| octet 2 | 1 | | | | | | | | \ TID, gateway ------------+---+---+---+---+---+---+---+---| | copies from octet 3 | | | | | | | | | / A) packet ------------+---+---+---+---+---+---+---+---| octet 4 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ------------+---+---+---+---+---+---+---+---| octet 5 | | | | | | | | | \ ------------+---+---+---+---+---+---+---+---| | Session ID, ... | | | | | | | | | | generated by ------------+---+---+---+---+---+---+---+---| | gateway octet n | | | | | | | | | / ------------+---+---+---+---+---+---+---+---| octet n+1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet n+2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| Fakewap needs to extract the TID and match it to the list of A) packets it has sent that have not yet received a B) packet in response. It also needs to extract and store the Session ID because that is needed by G). The Session ID is encoded in the uintvar format specified by the WSP specification, section 8.1.2 in the WAP 1.1 version. Code for decoding it is in gw/wsp.c (should be moved elsewhere). Packet C) and F) bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ------------+---+---+---+---+---+---+---+---| octet 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet 2 | 0 | | | | | | | | \ TID, must be ------------+---+---+---+---+---+---+---+---| | same as in octet 3 | | | | | | | | | / A) or D) packet. ------------+---+---+---+---+---+---+---+---| Packets C) and F) are identical, except C) gets its TID from an A) packet, and F) from a D) packet. Packet D) bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ------------+---+---+---+---+---+---+---+---| octet 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | ------------+---+---+---+---+---+---+---+---| octet 2 | 0 | | | | | | | | \ TID, fakewap ------------+---+---+---+---+---+---+---+---| | generates a octet 3 | | | | | | | | | / new one ------------+---+---+---+---+---+---+---+---| octet 4 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | ------------+---+---+---+---+---+---+---+---| octet 5 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet 6 | | | | | | | | | \ ------------+---+---+---+---+---+---+---+---| | ... | | | | | | | | | | URI length ------------+---+---+---+---+---+---+---+---| | octet n | | | | | | | | | / ------------+---+---+---+---+---+---+---+---| octet n+1 | | | | | | | | | \ ------------+---+---+---+---+---+---+---+---| | ... | | | | | | | | | | URI ------------+---+---+---+---+---+---+---+---| | octet n+m | | | | | | | | | / ------------+---+---+---+---+---+---+---+---| The URI (or URL) length is specified with uintvar (code to generate them also in gw/wsp.c). The URL itself is just the octets of the string copied as is. Packet E) bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ------------+---+---+---+---+---+---+---+---| octet 1 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 | ------------+---+---+---+---+---+---+---+---| octet 2 | 1 | | | | | | | | \ TID, gateway ------------+---+---+---+---+---+---+---+---| | copies from octet 3 | | | | | | | | | / D) packet ------------+---+---+---+---+---+---+---+---| octet 4 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet 5 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | ------------+---+---+---+---+---+---+---+---| octet 7 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet 8 | | | | | | | | | \ ------------+---+---+---+---+---+---+---+---| | Compiled WML ... | | | | | | | | | | page. ------------+---+---+---+---+---+---+---+---| | octet n | | | | | | | | | / ------------+---+---+---+---+---+---+---+---| Fakewap needs to extract the TID so it can match it to the D) packet it sent. It can ignore the WML page for now. Packet G) bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ------------+---+---+---+---+---+---+---+---| octet 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | ------------+---+---+---+---+---+---+---+---| octet 2 | 0 | | | | | | | | \ TID, fakewap ------------+---+---+---+---+---+---+---+---| | generates a octet 3 | | | | | | | | | / new one ------------+---+---+---+---+---+---+---+---| octet 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ------------+---+---+---+---+---+---+---+---| octet 5 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | ------------+---+---+---+---+---+---+---+---| octet 6 | | | | | | | | | \ ------------+---+---+---+---+---+---+---+---| | Session ID, ... | | | | | | | | | | copied from ------------+---+---+---+---+---+---+---+---| | B) packet. octet n | | | | | | | | | / ------------+---+---+---+---+---+---+---+---| gateway-1.4.5/doc/ChangeLog-1.2.00000644000175000017500000007020110203150325014626 0ustar toljtolj2002-07-02 Stipe Tolj * Re-Making stable release 1.2.0. 2002-07-04 Aarno SyvŠnen * "Test_http_server reads black and white lists from files" patch: * test/test_http_server.c: Doing this * checks/check_ppg.sh: Use lists when starting http server responsible for distributing these * test/whitelist.txt, test/blacklist.txt: Added required files. * test/smstestppg.txt: Changed MSISDN. * gw/pushkannel.conf: Changed send-url. * checks/check_fakewap.sh: Killing only bearerbox. * test/iptestppg.txt: Changed ip. 2002-07-03 Stipe Tolj * test/*testppg.txt: fixed the "make check" failure report for ppg module due to not-whitelisted receiver MSISDN. 2002-07-02 Stipe Tolj * Making stable release 1.2.0. 2002-06-28 Stipe Tolj * gw/wap_push_pap_compiler.c: fixing a compiler warning 2002-06-28 Aarno Syvdnen * checks/check_sendsms.sh: Better debugging for failure cases * checks/check_smpp.sh: Do test only 10 times, to save nerves * checks/check_fakewap.sh: Use name SIGINT * checks/check_http.sh: Do not test https part when --disable-ssl option is used. * gw/wap_push_pap_compiler.c: Better debugging * gw/wap_push_ppg.c: Ip tests work again, do not destroy pap event too early. Another bugfix. * gw/wap_push_ppg_pushuser.c: Added some comments * checks/check_fakesmsc.sh: Better debugging. * checks/check_ppg.sh: Minor corrections 2002-06-28 Stipe Tolj * gw/smsc_emi2.c: fixing an assertion checking bug 2002-06-27 Stipe Tolj * doc/userguide/userguide.xml: added documentation about SMPP related configuration directives. Patch submitted by Alan. 2002-06-25 Stipe Tolj * gw/wap_push_ppg.c: fixed a bug when service not found and username is not initialized octstr_destroy() will cause segmentation fault. 2002-06-25 Stipe Tolj * gw/wap_push_ppg.c: allow to start PPG module without SSL enabled HTTP server support. 2002-06-25 Stipe Tolj * gw/wap_push_ppg.c, gwlib/cfg.def: back to previous revision, due to misunderstanding of the 'ppg-ssl-port' directive. This is not a boolean like to 'sendsms-port-ssl' et al, but a real port number to open up a SSL enabled HTTP server. * gw/pushkannel.conf: changed this example config to fit the semantic of the ppg-ssl-port directive 2002-06-25 Stipe Tolj * gw/wap_push_ppg.c, gwlib/cfg.def: harmonized ssl indicator directive name to match those used in core group 2002-06-21 Stipe Tolj * gw/smsc_smpp.c: fixed a bug in transmitter/receiver routing handling for the SMPP module, patch provided by Nisan Bloch [Msg-ID: <5.1.0.14.0.20020620231315.025997f0@amagoblin.ialien.co.za>] 2002-06-17 Bruno Rodrigues * gwlib/gwmem.h, gwlib/gwmem-native.h: forgot gw_claim_area_for 2002-06-15 Bruno Rodrigues * configure.in: Added --enable-warnings that enables -Wall -O2 -g to gcc * gwlib/gwmem.h, gwlib/gwmem-native.h: fix compilation warnings 2002-06-12 Bruno Rodrigues * configure.in: WARNING: defaults to localtime * gw/smsc_emi2.c: some cleaning * utils/find-long-lines: added rtf, pdf and html to ignored files 2002-06-12 Stipe Tolj * gw/smsbox.c: fixing inline comments to fit CodingStyle rules 2002-06-11 Bruno Rodrigues * aclocal.m4: fix date function, for days lesser than 10 * configure.in: defaults to native malloc but still with assertions * configure.in, Makefile.in: use pdfjadetex to convert from xml->tex->pdf instead of xml->tex->ps->pdf * debian/*: some fixes * gw/ota_prov_attr.h: Added MMSURL comments * gw/smsbox.c: removed from xml-post; fix setting msg->sms.service on MO messages * gw/smsc_emi2.c: removed NACK code. It didn't work either way. * gwlib/conn.c, gwlib/conn.h, gwlib/http.c: Reenabled HTTP Keepalive and added extra debug: http connections now print the fd used, so we can try to find the bug. It looks like a reused connection that didn't timeout. 2002-06-11 Stipe Tolj * gwlib/thread.[ch], gwlib/conn.c: applied Oded's patch to make gcc 3.x not complain about it's __FUNC__ macros. [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296D8D@exchange.m-wise.com>] 2002-06-03 Stipe Tolj * gw/smsc_smpp.c: fixed memory bug in msg_to_pdu(), patch by Oded [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296D6F@exchange.m-wise.com>] 2002-06-02 Stipe Tolj * gw/smsbox.c: memory leak fixes, provided by Angel [Msg-ID: ] 2002-06-02 Stipe Tolj * wap/wsp_strings.def: added required MIME types for the content type assignment table 40. Thanks to Paul for indicating this. 2002-05-30 Stipe Tolj * aclocal.m4, configure[.in]: fixed Bruno's date extraction using 'cut' and defined it as external function in aclocal.m4. 2002-05-30 Stipe Tolj * gwlib/cfg.c: added more verbosity for 'include = "foobar.conf"' config file inclusion that avoids to concatenate groups by mistake. 2002-05-30 Harrie Hazewinkel * Moved heartbeat related code into the heartbeat.[c,h] files. Added a heartbeat_stop all functionality by means of the parameter ALL_HEARTBEATS in the heartbeat_stop function. This affected gw/bb.h, gw/smsbox.c and gw/wapbox.c. 2002-05-29 Stipe Tolj * gw/smscconn.h, gw/smsc_smpp.c, gw/bb_smscconn.c: added new SMSCCONN_ACTIVE_RECV state to provide online status information and exclude the smsc from routing within smsc2_rout() 2002-05-29 Stipe Tolj * gw/smsc_emi2.c: fixed octstr in octstr_format() call. 2002-05-29 Stipe Tolj * gw/smsc_emi2.c: changed conn->name string to be same as smpp for conformance of debug output on the admin status page * gw/smsc_smpp.c: set smsc status to 'online' in case we use only receive bind. 2002-05-28 Stipe Tolj * gw/smsc_smpp.c: added more smsc-id output to debug information 2002-05-28 Stipe Tolj * gw/bb_smscconn.c: fixing compiler warning 2002-05-27 Stipe Tolj * gw/bb_http.c, gw/bearerbox.h: some declaration fixups * gw/bb_smscconn.c: use smscconn_shutdown() instead of _stop and added global list to hold all smsc groups for later re-start lookups 2002-05-25 Stipe Tolj * gw/bb_smscconn.c: deleted unnecessary debug lines 2002-05-25 Stipe Tolj * gw/bb_http.c, gw/bb_smscconn.c, gw/bearerbox.c: added HTTP admin commands 'stop-smsc' and 'start-smsc' to stop and start single smsc connections without interfearing other connected smscs. 2002-05-24 Stipe Tolj * gw/ota_prov.c: excluded not needed include of urltrans.h * gw/dlr.h: fixed header comment path 2002-05-23 Stipe Tolj * gw/smsc_smpp.c: fixed another ocstr bug in msg_to_pdu(), thanks Oded 2002-05-23 Stipe Tolj * gw/smsc_smpp.c: fixed the smsc-id definition, provided by Oded [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296D40@exchange.m-wise.com>] * doc/userguide/userguide.xml: added documentation to timing directives of the smpp module, provided by Alan McNatty 2002-05-22 Stipe Tolj * gw/smsc_smpp.c: fixed destruction of a octstr in msg_to_pdu() 2002-05-22 Stipe Tolj * gw/smsc_smpp.c: added 'smsc-id' output at debug lines, reformat source to be CodingStyle compliant * gw/smsc_fake.c: reformat source to be CodingStyle compliant * gw/bearerbox.c: added traffic statistic to admin status page 2002-05-21 Stipe Tolj * gw/smsc_smpp.c: fixed a octstr_destroy() bug in msg_to_pdu() 2002-05-21 Stipe Tolj * gw/smsc_smpp.c: applied validity and deferred patch by Alex [Msg-ID: ] 2002-05-21 Stipe Tolj * doc/userguide/userguide.xml, gw/smsc_smpp.c, gwlib/cfg.def: applied interface version configuration patch from Oded [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B167F6B@exchange.m-wise.com>] 2002-05-21 Stipe Tolj * gw/smsc_smpp.c, gwlib/cfg.def: applied timing configuration patch provided by Alan McNatty [Msg-ID: <1021942284.3140.207.camel@euclid>] 2002-05-21 Stipe Tolj * gw/smsc_smpp.c: added Alt-DCS support for SMPP module 2002-05-20 Stipe Tolj * gwlib/conn.c: fixing a compiler warning 2002-05-20 Stipe Tolj * gwlib/xmlrpc.h, test/drive_smpp.conf: typo fixes 2002-05-20 Stipe Tolj * gw/smsc_smpp.c: added 'smsc-id' processing patch supplied by Dima Milentiev [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B05AB42@exchange.m-wise.com>] 2002-05-20 Stipe Tolj * configure[.in]: fixed Bruno's cvs checkout date extraction 2002-05-20 Stipe Tolj * gwlib/conn.c: fixed a possible segmentaion bug in conn_open_ssl() reported by Oded. [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B167F67@exchange.m-wise.com>] 2002-05-20 Stipe Tolj * doc/userguide/userguide.xml: some changes and extensions to sendota documentation * test/test_http.c: fixed a bug for POST method and changed -b flag to -B for the POST body content. Excluded -x flag. If -B is set this indicates a POST request to be issues to the HTTP server. * gw/smsbox.c: fixed segmentation fault bug in sendsms_thread() caused by using args in smsbox_sendota_post(). 2002-05-17 Stipe Tolj * doc/userguide/userguide.xml, gw/smsbox.c: added 'to' GET variable to sendota request. The old parameter 'phonenumber' is yet still supported but must be removed for the upcoming next stable release. 2002-05-17 Stipe Tolj * gw/bb_boxc.c: fixed a misbehaviour in accept_boxc() which didn't close new socket descriptors if the remote IP is banned. Thanks to Paul. [Msg-ID: ] 2002-05-16 Stipe Tolj * gwlib/conn.c: added Oded's non-blocking SSL_connect() patch. [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B167F62@exchange.m-wise.com>] 2002-05-16 Stipe Tolj * configure[.in]: fixed --disable-ssl bug reported by Aarno. 2002-05-15 Aarno Syvänen * doc/userguide/userguide.xml: some clarifications in ppg documentation 2002-05-14 Stipe Tolj * gw/shared.[ch], gw/smsbox.c, gw/smscconn.h, gw/wapbox.c, gwlib/counter.[ch], test/drive_smpp.c, test/test_http.c, test/test_ppg.c, wap/wsp_session.c, wap/wtls.h, wap/wtp_init.h, wap/wtp_resp.h: applied long vs. unsigned long patch from Harrie Hazewinkel [Msg-ID: <10110987.1021046787@localhost>] 2002-05-13 Bruno Rodrigues * : The "Why don't you love me anymore?" patch * gw/smsc_emi2.c: if SMSC reply with a NACK and error 04, we should resend authentication. I couldn't do it (When I send the login packet, socket gets eof and disconnects), so kannel just reconnects for now * gw/smsbox.c: remove information if a tag is not present on xml-post; If we know that there will be more than one "to", pass the to list instead of joining and spliting it in "to" string; moved checking illegal chars in "to" below, checking one by one instead of the full multi-to string, that could even not exists if the list is received * gw/wap-appl.c: fix a warning * gw/smsc_at2.c: applied patch from Oded Arbel to fix debugging messages * Makefile.in: applied patch from Benjamin Lee to add DESTDIR in two missing spots 2002-05-13 Stipe Tolj * gw/wap-appl.c: fixed a minor assertion bug in return_reply() 2002-05-06 Stipe Tolj * checks/check_http.sh: added SSL-enabled HTTP server and client checks * gwlib/gwlib.h: fixed Aarno's redefinition of GW_NAME 2002-05-03 Aarno Syvänen * checks/check_fakewap.sh: Do the test may times * gw/wap-appl.c: Fixing no ppg configuration option: No references to ppg lists. * gw/wap-appl.h: Passing configuration data to the init function. * gw/wap_push_ppg.c: Do not start anything when no ppg is configured * gw/wapbox.c: Do not start any push threads, or set push variables when no ppg option is set. * gw/wap_push_ppg.c: Going down gracefully when HTTPClient is NULL. This was noticed by Paul Keogh. 2002-05-03 Bruno Rodrigues * : The "where do you want me to post this?" patch * doc/userguide/userguide.xml: added kannel post headers (kannel->appl); added glossary and bibliography * gw/other_smskannel.conf, gw/smscconn_p.h, gw/smskannel-ssl.conf, gw/smskannel.conf: fixed typo * gw/smsbox.c: fixed ucs2 content-type and added X-Kannel-Service to kannel post-url 2002-05-03 Bruno Rodrigues * : The "I don't like empty variables" patch * gw/smsbox.c: fixed empty text messages panic in post-xml code * gw/smsc_emi2.c: fixed deliver reports with undefined smsc-id. It uses smsc "name" field if smsc-id is not present 2002-05-03 Bruno Rodrigues * : The "I want my cvs date" patch * configure.in, Makefile.in: configure now creates a VERSION var with cvs-20020501 based on ChangeLog date on cvs (or simply first line of VERSION file, if not cvs); Makefile now uses it on documentation headers; added --enable-suffix (default: disabled) and --with-suffix= to enable and define the suffix name to binaries; tweaked some messages * gw/wapkannel.conf: default to aarno dirs ?? changed back to tmp * gwlib/http.c: removed hard-coded User-Agent. It should be defined on the module using it and passed through headers list. Fixes Wapbox sending "kannel/$version" instead of mobile user-agent 2002-05-03 Bruno Rodrigues * : The "where was my head at that day" patch * gw/smsbox.c: reverted octstr_destroy(udh) but replaced original one with O_DESTROY; 2002-05-01 Bruno Rodrigues * configure.in: configure now defaults to --disable-mysql * gw/smsbox.c: http reply, when text/plain, doesn't strip_blanks. Needed to be able to send smscards with spaces in first line 2002-05-02 Stipe Tolj * configure[.in], config.h.in: changed VERSION definition to have a more readable date format and added GW_NAME define to allow vendor specific naming. * gw/bb_http.c, gw/bearerbox.c, gw/shared.c, gw/smsbox.c, gw/wap-appl.c, gw/wap-error, gw/wap_push_ppg.c, gw/wapbox.c, gwlib/http.c, gwlib/socket.c: added GW_NAME macro 2002-05-02: Aarno Syvänen * gw/bb_smscconn.c: Dropped outgoing sms queue test when handling para- meter maximum-queue-length. * doc/userguide/userguide.xml: Documented the change. 2002-05-01 Bruno Rodrigues * configure.in: added --enable-mysql besides --with-mysql; added date to VERSION, read from CVS/Entries instead of newest file in .; fixed openssl command detection * gw/smsc_smpp.c: added PID and DCS/* MO support 2002-04-30 Aarno Syvänen * wap/wsp_server_session_machine.def: Fixed a compiler warning 2002-04-29 Bruno Rodrigues * gw/smsbox.c: xml-post: moved auth tag to from tag * doc/userguide/userguide.xml: updated 2002-04-29 Bruno Rodrigues * gwlib/cfg.c: Yet another fix to grp->cfgfilename. Hopefully, the last * gw/smsbox.c: Finished post-xml code. Someday the code will be changed to libxml functions, but until then, this "works for me". XML format could and WILL be changed later, as IETF's document is still a draft, and there's some tags that it doesn't have. Works for service (post-xml field), accepts xml in service reply and in sendsms-user. Sendsms-user support multiple recipient addresses. * doc/userguide/userguide.xml: Completed post-xml documentation. * gw/smsbox.c: Fixed a bug when receiving reply from service and accept-x-kannel-headers is disabled. udh was destroyed and later was used to define coding * doc/userguide/userguide.xml: fixed ">Date" in log format appendix * gw/smsbox.c: fixed some tab/space * gw/smsbox.c: destroy sendsms_url, sendota_url and xmlrpc_url at the end 2002-04-29 Bruno Rodrigues * doc/userguide/userguide.xml: Added UDH example to set number of messages in MWI * Changelog: Fixed ^M. Please cvs up -d and cvs diff before commiting 2002-04-29 Bruno Rodrigues * gw/otacompiler.c, gw/shared.c, gw/wap_push_pap_compiler.c, gw/wap_push_si_compiler.c, gwlib/xmlrpc.c: Fix xml includes to be #include 2002-04-27 Aarno Syvänen * gw/wap_push_ppg.c: Corrected handling of puah.soa application id. Thanks to Michael Mulcahy for correction. * gw/wapbox.c: Dropped an useless (and dangerous) dump. * wap/wsp_unit.c: Better debugging. 2002-04-27 Aarno Syvänen * gw/wap_push_ppg.c: Fixed HTTP return statuses. 2002-04-26 Bruno Rodrigues * debian/*: fixed some issues, add mysql and ssl support to debian packages (not that crypto is not an issue and ssl has moved from non-us to main, there's no need to have a kannel and kannel-ssl package) * utils/kannel-stable-rh7.spec: added ssl and mysql, altough I still haven't built the RPM * doc/userguide/userguide.xml: Added "can use DLR" checkbox to table SMSC Driver Features 2002-04-26 Aarno Syvänen * gwlib/cfg.def: Added new configuration variables. * checks/check_sendsms.sh: Added tsting for empty cgi vars. * gw/wap_push_ppg.c: Use variable global-sender. HTTPS support added. Changed push-url default. * gwlib/octstr.[ch]: Added function octstr_strip_crlfs. * gw/smsc_cimd2.c: Fixed a memory leak. * gw/smsbox.c: Fixed a memory leak happening with stranger return types. Kannel accepts 202 return code. * gw/bb_smscconn.c: Logsms works without sender/receiver. Implement queue limit. * test/test_http_server: Response body changed to "Sent". * gw/wap_push_si_compiler.c: Fixed a memory leak. * gwlib/http.[ch]: Library function http_cgiargs_dump. * gw/bearerbox.c: A minor memory leak fixed. * doc/userguide/userguide.xml: Documented PPG HTTPS support. Added docu- mentation for global-sender. Changed default push URL, previous one caused lot questions. * doc/arch/arch.xml: Documented architecture change caused by HTTPS support. * gw/wap_push_pap_compiler.c: Values of reserved words case-insensitive. * checks/chech_ppg.sh: Better debugging for failed cases. 2002-04-25 Stipe Tolj * gw/wap_push_ppg.c: fix in coriented_deliverable() to return the right boolean, thanks to Paul 2002-04-24 Stipe Tolj * gw/smsbox.c: fixed typo in init_smsbox() 2002-04-24 Stipe Tolj * gw/smsc_smpp.c: fixed debug output to be hex, thanks to Simon 2002-04-24 Stipe Tolj * doc/userguide/userguide.xml: added 'transceiver-mode' section * gw/smpp_pdu.def, gw/smsc_smpp.c, gwlib/cfg.def: added SMPP transceiver mode patch submited by Simon Beale [Msg-ID: <004201c1e0b3$c9490c20$c80a0a0a@ngame.com>] 2002-04-23 Stipe Tolj * gwlib/cfg.def: added missing 'xmlrpc-url' for XML-RPC URI trigger to be used. 2002-04-22 Stipe Tolj * doc/userguide/userguide.xml: added 'smart-errors' section * gw/wap-appl.c, wap/wsp.h, wap/wsp_server_session_machine.def, wap/wsp_session.c: added HTTP Referer header and smart WSP error messaging * gw/wapbox.c, gwlib/cfg.def: added 'smart-errors' directive for smart WSP error messages via returned WML decks * gw/wap-error.[ch]: added files to handle the smart errors * wap/cookies.h: find_session_machine_by_id() is now declared in wap/wsp.h 2002-04-19 Stipe Tolj * doc/userguide/userguide.xml: added 'force-sar' section * gw/wap-appl.c: some source reformating * wap/wtp_resp.c, gw/wapbox.c, gwlib/cfg.def: added 'force-sar' indicator to allow forced WTP connections, even if the phone requests SAR. Some source reformating. 2002-04-19 Stipe Tolj * gw/wap-appl.c: reformated return_reply() to CodingStyle rules 2002-04-18 Stipe Tolj * gw/numhash.c: fixed a bug inside numhash_create(), reported from Paul. 2002-04-17 Stipe Tolj * gw/wap_push_ppg.c: turned default PPG HTTP instance off if no 'ppg' group is in config file, for security reasons 2002-04-17 Stipe Tolj * gw/bb_smscconn.c: added smsc id information to status.xml patch provided by Angel. [Msg-ID: ] 2002-04-17 Stipe Tolj * gw/wapbox.c, gwlib/pki.c: more work on WTLS configuration checking 2002-04-17 Stipe Tolj * wap/wap_events.c: minor style correction 2002-04-17 Stipe Tolj * gw/bb_udp.c: added checking if WTLS support should be used, even while compiled in * gwlib/cfg.h: introduce new 'wtls' group to specify all required arguments 2002-04-16 Stipe Tolj * gw/smsbox.c: added preliminary function smsbox_xmlrpc_post() to handle the XML-RPC calls and replies. * gwlib/gwlib.h: added inclusion of xmlrpc.h to make the structures public * gwlib/xmlrpc.[ch]: further improvements in the parsing, but yet not finished for that. 2002-04-16 Stipe Tolj * gw/smsbox.c: changed return value semantic of send_message() to return the number of splits that have been send to bearerbox, otherwise return -1 in case of an error. Patch submitted by Oded. [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296CA6@exchange.m-wise.com>] 2002-04-15 Stipe Tolj * gw/wap_push_pph_pushuser.c: fixed memory leaks in xxx_list_add() and xxx_authenticate() reported by Paul. [Msg-ID: <000001c1e214$2ef53650$0300a8c0@anam.com>] 2002-04-10 Bruno Rodrigues * doc/modems.conf: added enable-mms info and enabled it on nokiaphone * doc/smsc_at2.[ch], gwlib/cfg.def, doc/userguide/userguide.xml: added enable-mms variable and only send +MMS if it's enabled * gwlib/cfg.c: removed assignation of included filename to group structure. If we want filename and line number for each line read, we need a different approach. With it, group would have the last file included and at2 won't know anymore where the modem definitions are. It's better to have the original kannel.conf in group struct so at2 could reread everything and find the group it wants 2002-04-10 Bruno Rodrigues * gw/smsbox.c: Changed XML Post format (smsbox->application) to conform to IETF sms-xml-02 draft. 2002-04-10 Bruno Rodrigues * gw/urltrans.c: Added white/black list and allowed/denied prefix implementation to default service. * doc/userguide/userguide.xml: added --enable-drafts information 2002-04-09 Bruno Rodrigues * doc/userguide/userguide.xml: fixed a link reference that fails with --disable-drafts 2002-04-10 Andreas Fink * doc/userguide/userguide.xml: corrected a typo. Added section about DLR 2002-04-09 Bruno Rodrigues * gw/smsc_smpp.c, doc/userguide/userguide.xml: Added my-number to SMPP * doc/userguide/userguide.xml: changed at2 my-number description * gw/smsbox.c, gw/urltrans.[ch]: Added preliminary XML Post to smsbox. * Makefile.in: when building ps from xml, only echo "check log" if jadetex fail, cleaning "make -s" * Makefile.in, configure.in, configure : added --enable-drafts to enable/disable draft blocks being included in documentation * doc/userguide/userguide.xml: added draft conditional includes, defined with --enable-drafts to be able to write text without being displayed on snapshot documentation until it's almost final 2002-04-08 Andreas Fink * gw/dlr.c: fixed mysql_close issue pointed out by "Dima Milentiev" partially fixed a mysql problem when multiple messages where sent using the same timestamp 2002-04-06 Bruno Rodrigues * test/.cvsignore: sorry, two last lines got concatenated * doc/userguide/userguide.xml: moved "account" information from send-smsuser group to send-sms cgi variables 2002-04-06 Bruno Rodrigues * test/.cvsignore: added test_xmlrpc to cvsignore 2002-04-06 Bruno Rodrigues * gw/smsc_emi2.c: Fixed (I hope) a bug when smsc disconnects us and kannel tries to connect to primary and alternate smsc (it's hard to duplicate the error) * gw/urltrans.c: some identation cleaning 2002-04-04 Stipe Tolj * test/test_xmlrpc.c: fixed some memory leaks 2002-04-04 Stipe Tolj * gwlib/xmlrpc.[ch]: additional parsing improvements, error handling * test/test_xmlrpc.c: added call to xmlrpc_call_send() in thread to test sending XMP-RPC requests via HTTP POST to servers. 2002-04-04 Stipe Tolj * gwlib/http.c: changed the server side Server HTTP header, to look the same as the client side. 2002-04-04 Stipe Tolj * gwlib/http.c: added User-Agent HTTP header to HTTP client requests to identify itself by the string 'Kannel/', where is the version string from VERSION. 2002-04-04 Stipe Tolj * test/test_http.c: fixed unitialized var usage for the POST content 2002-04-04 Stipe Tolj * gwlib/xmlrpc.[ch]: added parsing of XML document * test/test_xmlrpc.c: some minor changes 2002-04-03 Stipe Tolj * test/test_http.c: fixed a missing int declaration 2002-04-03 Stipe Tolj * gwlib/xmlrpc.[ch]: some minor improvements and parsing routines * test/test_xmlrpc.c: added testing application for the xmlrpc calls 2002-04-03 Stipe Tolj * gw/ota_prov.c: make output a bit more semantical * gw/smsbox.c: bug fixing of destroyed variables * test/test_http.c: fixed typo and minor bug when sending non-POST request, which of course does not have any content. 2002-04-02 Stipe Tolj * gw/smsbox.c: added new smsbox_sendota_post() to handke POST method of sendota function. Now you can use the same POST semantic as for sendsms. 2002-04-02 Stipe Tolj * test/test_http.c: added POST method support for the HTTP client test program. Mainly this may be used to test POST enabled HTTP servers within the single boxes, like PPG, sendsms, sendota. 2002-04-01 Stipe Tolj * gw/smsc_at2.c, gwlib/http.c: fixed minor kannel-nag warnings 2002-03-28 Bruno Rodrigues * gw/smsbox.c: Added X-Kannel-SMSC on smsbox->application. It was missing gateway-1.4.5/doc/ChangeLog-1.3.20000644000175000017500000041360110203150325014636 0ustar toljtolj2004-07-14 Stipe Tolj The 'make check' happy again commits. BEWARE! You need to run 'make check' _before_ commiting changes to cvs to ensure we don't break any check scripts or test programs. * checks/check_[http|ppg].sh: bash doesn't like Aarno's if statements, therefore reverting this to the simple ones. * checks/check_sendsms.sh: harcoded error message changed in gw/smsbox.c. * test/test_http.c: fixing segmentation fault while using global client cert for https calls. This broke checks/check_http.sh. * test/test_http_server.c: fixing segmentation fault while using predefined reply body file. Fixing starvation while client_thread is down and http ports are still open. Thread joining at termination fixed. 2004-07-09 Stipe Tolj * gw/smsc/smsc_soap.c: changing #ifdef #warning's to commented blocks to get rid of the compiler warnings in the nightly build tests. This module still _needs_ revision for the new UUIDs that are used. * wap/wsp_headers.c: Bruno moved packing/unpacking of PROXY_AUTHxxx away by commenting them out. This was in revision 1.10. And there is no reason for this in the ChangeLog entry??? BTW, this makes the checks/check_headers.sh test fail for the relevant Proxy-Authxxx headers. That is why I put things in again, as long as noone complains and tells us why they have been commented in rev 1.10. Along with this Aarno did break the quoted parameter parsing within revision 1.17. Reverting this back to the previous behaviour to make test/test_headers.c happy again. * test/test_header.c: fixing trivial compiler warning * test/header_test: changing the expected values to have quoted parameter values to make the test program happy again. 2004-07-09 Stipe Tolj * test/test_headers.c: fixing command line options and argument handling which breaks "make check" target. * checks/check_headers.sh: needs to pass the test/headers_test input file since change of test/test_headers.c from rev 1.7 makes this necessary. 2004-07-08 Stipe Tolj * Making development release 1.3.2rc1. 2004-07-07 Stipe Tolj * doc/userguide/userguide.xml: trivial fixes see bug #141 and #84. 2004-07-07 Alexander Malysh * doc/userguide/userguide.xml: trivial fixes see #140. 2004-06-29 Stipe Tolj * gw/smsc/smsc_http.c: fixed type in setting 'dlr-mask' and changed the urlencoding of 'dlr-url'. Thanks to Rene for spotting this. 2004-06-29 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed compilation failure. 2004-06-28 Alexander Malysh * gw/bearerbox.c: got rid of unused 'boxid' mutex. * gw/msg.h: introduced 'ack_status_t' typedef instead of anonymous enum. * gw/shared.[ch], gw/sms.[ch]: moved sms splitting code from shared.[ch] to sms.[ch]. That's IMO approriate place for it. 2004-06-28 Alexander Malysh * gw/smscconn.c, gw/smscconn_p.h, gwlib/cfg.def, doc/userguide/userguide.xml, gw/bb_smscconn.c: made rerouting between SMSC's working properly. 2004-06-28 Alexander Malysh * gw/bb_store.c, gw/bearerbox.h: added 'store_save_ack' in order to avoid code duplication. 2004-06-28 Alexander Malysh * gw/dlr_mem.c: fixed locking issues. Don't use 'list_[lock|unlock]', use rwlock instead. 2004-06-28 Alexander Malysh * gw/bearerbox.h, gw/bb_boxc.c: moved declaration for 'route_incoming_to_boxc' from gw/bb_boxc.c to gw/bearerbox.h. 2004-06-28 Alexander Malysh * gw/smsc/smsc_smpp.c: commited patch #3 and #4 (in a slightly modified version) from bug #129. Thanks to joergent. 2004-06-28 Alexander Malysh * gw/smsbox.c: commited patch #1 from bug #129. Thanks to joergent. 2004-06-28 Alexander Malysh * gwlib/list.[ch]: added 'list_sort' function that sorts the list with qsort. * gwlib/octstr.[ch]: added '%H' modifier to 'octstr_format' that converts Octstr to hex-encoded in uppercase. * gwlib/semaphore.[ch]: added 'semaphore_getvalue' function. 2004-06-25 Alexander Malysh * gwlib/log.c: fixed (workarounded) endless panic loop if memcheck was enabled. 2004-06-22 Alexander Malysh * doc/userguide/userguide.xml: fixed typo bug#133. additionaly reviewed and fixed deprecated 'dlrurl' and 'dlrmask' params. 2004-06-21 Alexander Malysh * gw/smsc/smsc_smpp.c: added "more messages to send" support. 2004-06-21 Alexander Malysh * gw/msg-decl.h, gw/shared.c, gw/smsc/smsc_cimd2.c: applied patch that adds "more messages to send" support (only CIMD2 supported yet). Thanks to "Arne K. Haaje" for the patch. [Msg-Id: <200406111342.30696.haaje@eurobate.com>]. 2004-06-20 Alexander Malysh * gw/smscconn.c, gw/smscconn_p.h: more speedup. Changed [allowed|denied|preferred]_smsc_id from 'Octstr' to 'List'. So we have no need to always parse the whole string and split it into the list. Now we just split it while starting only once. 2004-06-20 Alexander Malysh * gw/smscconn.[ch], gw/smscconn_p.h: made status/killed enums named. Taught 'struct StatusInfo' to use named enums for status/killed. Changed return value to 'const Octstr* for 'smscconn_name' and 'smscconn_id' functions, so the caller see that those _may_ _not_ be freed. * gw/bb_alog.c gw/bb_smscconn.c: fixed const identifier warnings. 2004-06-20 Alexander Malysh * gw/wap_push_ota.c: fixed attempt to destroy locked mutex. 2004-06-20 Alexander Malysh * gw/wap_push_ppg.c: fixed typo, see bug#114. 2004-06-20 Alexander Malysh * test/test_ppg.c: fixed bug #131. 2004-06-16 Alexander Malysh * configure.in, configure: added "format warnings" if --enable-warnings defined. 2004-06-15 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_oisd.c: added validity support. See #124. Thanks to "Dariusz Markowicz" for provided patch. 2004-06-14 Alexander Malysh * configure.in, configure, gw-config.h.in: added check for pthread_rwlock. Fixed MySQL detection when no reentrant client libs are installed. Added '-rdynamic' to LDFLAGS on Linux for better panic/backtrace support. 2004-06-14 Alexander Malysh * gwlib/protected.[ch]: added 'gw_strftime()' function. Fixed macro for 'gethostbyname'. * gwlib/thread.c: added panic for attempt to destroy locked mutex. so we can at least try to catch such cases. * gwlib/utils.c: fixes for parachuting code. These bugs can only be triggered with NPTL. 2004-06-14 Alexander Malysh * configure, configure.in, gw-config.h.in: added check for * gwlib/semaphore.c: added support for native semaphore. 2004-06-14 Alexander Malysh * gw/bb_boxc.c: added tracking of pending messages between smsbox <-> bearerbox. * gwlib/cfg.def doc/userguide/userguide.xml: added new config option 'smsbox-max-pending'. See userguide for description. 2004-06-14 Alexander Malysh * gwlib/gwlib.h: added "gw-rwlock.h". * gw/bb_boxc.c: changed 'boxc' to 'Counter'. Switched 'list_[lock|unlock](smsbox_list)' to rwlock's. Added panic if multiple equal smsbox routes defined. 2004-06-10 Alexander Malysh * gwlib/gw-rwlock.[ch]: initial version of the wrapper for reader/writer lock. For now only pthread_rw_lock is supported. 2004-06-10 Alexander Malysh * gwlib/regex.c: fixed memleak. 2004-06-10 Alexander Malysh * gw/dlr_mem.c: fixed race condition. 2004-06-10 Alexander Malysh * gw/bb_alog.c, gw/bearerbox.[ch]: added const identifier. Rewrite of costom log format handling (performance). Fixed memleak. 2004-06-10 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_cimd2.c: added ability to set PID for MT messages in CIMD2. Thanks to "Arne K. Haaje" for the patch. [Msg-Id: <200406101430.29450.haaje@eurobate.com>]. 2004-06-09 Alexander Malysh * gwlib/counter.c: cleanup. Got rid of #ifdef's. 2004-06-09 Alexander Malysh * gw/dlr_pgsql.c, gw/dlr.c, gw/dlr_p.h, gwlib/cfg.def, doc/userguide/userguide.xml: added PostgreSQL native DLR support. This is not tested yet. Code partially picked from SQLBox patch. 2004-06-08 Alexander Malysh * wmlscript/wsgram.[ch]: new bison-generated source/header files. 2004-06-08 Alexander Malysh * gwlib/dbpool_pgsql.c: added pgsql_[update|select] functions. Those were partially picked from below named SQLBox patch. Thanks a lot to "Rene Kluwen" . 2004-06-08 Alexander Malysh * configure, configure.in, gw-config.h.in, gwlib/dbpool_pgsql.c, gwlib/dbpool.[ch]: added PostgreSQL dbpool support. Patch picked from sqlbox.patch posted by "Rene Kluwen" . Thanks a lot for the patch! [Msg-Id: ]. 2004-06-07 Alexander Malysh * gw/smsc/smsc_smasi.c: fixed bug that enquire link pdu's were not sent within regular timeframe. 2004-06-03 Alexander Malysh * gwlib/http.c: applied patch that adds real reason phrases for http reply line instead of just 'Foo'. Thanks to Zoltán Dudás for provided patch. [Msg-Id: <200406031200.28195.zoltan.dudas@sei.hu>]. 2004-05-18 Alexander Malysh * doc/userguide/userguide.xml, doc/examples/dlr-sdb.conf: userguide documentation for LibSDB dbpool support. Thanks to Guillaume Cottenceau for the patch. [Msg-Id: <878yfpx3rs.fsf@meuh.mnc.ch>]. 2004-05-18 Alexander Malysh * gwlib/dbpool_sdb.c, gwlib/dbpool.c, gwlib/cfg.def, gw/dlr_sdb.c: applied patch, in a slightly modified version, that adds dbpool support for LibSDB. Thanks to Guillaume Cottenceau for the patch. [Msg-Id: <87ad07o0ie.fsf@meuh.mnc.ch>]. 2004-05-18 Alexander Malysh * gw/dlr_sdb.c: applied patch that adds "limit" support for Postrgesql into SDB DLR storage. Thanks to Guillaume Cottenceau for the patch. [Msg-Id: <84u0yse0dv.fsf@frozen.mnc.ch>]. 2004-05-15 Alexander Malysh * wmlscript/wsgram.y: fixed bison's file generation. Thanks to Paul P Komkoff Jr for pointing to this. 2004-05-15 Alexander Malysh * gw/bb_udp.c: applied slightly modified patch that allows to put semicolon-separated list of ip addresses in wdp-interfaces statement in config file and kannel send responses from proper addresses. Thanks to Paul P Komkoff Jr for provided patch. [Msg-Id: <20040506114255.GF13255@stingr.net>]. 2004-04-27 Alexander Malysh * doc/userguide/userguide.xml: applied patch that corrects libSDB section. Thanks to Guillaume Cottenceau. [Msg-Id: <84llkivnye.fsf@frozen.mnc.ch>]. 2004-04-27 Alexander Malysh * doc/examples/dlr-sdb.conf: applied patch that addds sql code to create a correct Postgres table. Thanks to Guillaume Cottenceau. [Msg-Id: <84smeuy9rn.fsf@frozen.mnc.ch>]. 2004-04-21 Alexander Malysh * doc/userguide/userguide.xml: applied patch adds, in "Extended headers" description, that they need a configuration parameter to be accepted. Thanks to Guillaume Cottenceau . [Msg-Id: <84r7uj0z8n.fsf@frozen.mnc.ch>]. 2004-04-21 Alexander Malysh * gw/wml_compiler.c: applied patch that fixes variable substitution. Thanks to Joerg Pommnitz . [Msg-Id: <4D93AAF95CB5A64E8F622EC796ECF5AC3FC0EB@exil.condat.de>]. 2004-04-19 Alexander Malysh * gw/smsc/smsc_smpp.c: added 'message_payload' handling. Added enhanced DLR parsing and handling of DLR's optional parameters. 2004-04-19 Alexander Malysh * gw/smsbox.c, gwlib/xmlrpc.[ch], gwlib/cfg.def, gwlib/octstr.[ch], test/test_xmlrpc.c: applied patch from bug #120. Thanks to Robert Galach . 2004-04-19 Alexander Malysh * test/dlr-receiver.py: added simple ready-to-go server for receiving DLRs. Thanks to Guillaume Cottenceau . [Msg-Id: <84fzb4uu2s.fsf@frozen.mnc.ch>]. 2004-04-19 Alexander Malysh * gwlib/octstr.c: applied patch that allows octstr_search_chars to not ignore its `pos' parameter. Thanks to Guillaume Cottenceau . [Msg-Id: <84d6642ok9.fsf@frozen.mnc.ch>]. 2004-04-18 Alexander Malysh * README: adds docbook entries for Gentoo and Mandrake. * doc/userguide/userguide.xml: replaces `README.docbook' with `README'. Thanks to Guillaume Cottenceau . [Msg-Id: <84brluwris.fsf@frozen.mnc.ch>]. 2004-04-18 Alexander Malysh * gw/smsbox.c: applied patch enhances the log and output messages when gw/smsbox.c encounters a message without a recipient field. Thanks to Guillaume Cottenceau . [Msg-Id: <84k70guv6v.fsf@frozen.mnc.ch>]. 2004-03-28 Alexander Malysh * gw/smsc/smsc_cimd2.c: applied in a slightly modified version that set the DLR Msg's sms->msgdata value to the statuscode if there is no USER_DATA available. Thanks to Nicholas Rahn . [Msg-Id: <1080286173.6498.46.camel@frisbee.mnc.ch>]. 2004-03-27 Alexander Malysh * gw/smsc/smpp_pdu.[ch], gw/smsc/smpp_pdu.def, gw/smsc/smpp_pdu_opt.def: applied patch with new version of optional params handling in smpp pdu. With this version Dict* is killed and all opt. params are treated the same as mandatory and could be easier accessed. Now pack/unpack for int values works too. Note: not available in pdu opt. params are initialized with '-1' for int, NULL for nulterminated/octet strings. [Msg-Id: <200403231506.31479.a.malysh@centrium.de>]. 2004-03-22 Alexander Malysh * test/test_dbpool.c: applied missind part of last commit. Thanks again to "Robert Galach" . 2004-03-20 Alexander Malysh * gw/dlr_oracle.c, gwlib/dbpool.[ch], gwlib/dbpool_oracle.c, gwlib/dbpool_p.h: applied db_pool_binding_variables_2.patch provided by "Robert Galach" that enables binding variable in sql statements and contains implementation for oracle. [Msg-Id: <01bb01c407a7$26623640$320da8c0@tenbit.com>]. 2004-03-17 Alexander Malysh * gw/smsc/smsc_sema.[ch]: fixed annoying compiler warning. Changed msgbody from (void**) to (void*). I don't know why in hell (void**) was needed? 2004-03-10 Alexander Malysh * gw/smsc/smsc_smpp.c: applied patch that removes unneeded setting of online time to -1. Thanks to Nisan Bloch . [Msg-Id: <6.0.0.22.0.20040311193716.03189a90@amagoblin.ialien.co.za>] 2004-03-11 Stipe Tolj * wap/cookies.c: source beauty, no logic change. 2004-03-11 Stipe Tolj * wap/wsp_server_method_states.def: fixing bug where WSP 1.2 is simply assumed while entering the WSP header packing, instead of using the "detected" WSP Encoding-Version that is available in the state machine. Thanks to "Vjacheslav Chekushin" for this. 2004-03-11 Stipe Tolj * gw/smsc/smsc_cimd2.c: fixing wrong parameter length for "service description" field according to Nokia CIMD spec. Thanks to for pointing to this. 2004-03-11 Stipe Tolj * gw/smsc/smsc_smpp.c: fixing race conditions amonst status and connect_time while set in various threads. Thanks to Nisan for pointing to this. [Msg-ID: <6.0.0.22.0.20040305000910.02f37008@amagoblin.ialien.co.za>] 2004-03-11 Stipe Tolj * gw/smsc/smsc_cimd2.c: added more codes that return DLR_FAIL. Thanks to "Arne K. Haaje" for this patch. [Msg-ID: <200403101401.42854.haaje@eurobate.com>] 2004-03-10 Alexander Malysh * gw/shared.c: fixed bug that every part of splitted message has the same UUID. Thanks a lot to "Robert Galach" . Msg-Id: <00f701c40696$8168da10$320da8c0@tenbit.com>. 2004-03-10 Alexander Malysh * wap/cookies.c: applied patch from "Mindaugas Riauba" that fixed segfault. Thanks a lot to him. Msg-Id: <02c601c40691$c9750310$f20214ac@bite.lt>. 2004-03-10 Alexander Malysh * gw/bb_alog.c: fixed bug introduced by last change that "%s" was not passed to alog(...) call. Thanks to "Robert Galach" for catching it. Msg-Id: <004d01c4068d$d6058d60$320da8c0@tenbit.com>. 2004-03-09 Alexander Malysh * gw/urltrans.c: applied patch from "Angel Fradejas" that fixes the bug #117. Msg-Id: <200403031228.i23CSkP16905@int-mail01.mediafusion.es>. 2004-03-09 Alexander Malysh * gwlib/octstr.c: applied patch from "Angel Fradejas" in slighly modified version that checks for NULL pointers. Msg-Id: <200403031228.i23CSkP16905@int-mail01.mediafusion.es>. 2004-03-08 Alexander Malysh * gw/bb_alog.c: fixed custom & default access_log. Now we try to determine SMSC-ID as follows: 1) smscconn_id(conn); 2) smscconn_name(conn); 3) msg->sms.smsc_id. Made functions conn NULL pointer aware. * gw/bb_smscconn.c: made bb_smscconn_failed(...) SMSCConn NULL pointer aware. 2004-03-06 Alexander Malysh * gwlib/protected.c: restored GETHOSTBYNAME mutex, that was accidental removed by last commit. 2004-03-05 Alexander Malysh * gwlib/octstr.c: don't allocate temporarely Octstr in 'octstr_append_decimal'. 2004-03-05 Alexander Malysh * gwlib/protected.[ch]: fixed non reentrant time functions, those _must_ use only one mutex instead of mutex per time function. Quote from man page: The return value points to a statically allocated struct which might be overwritten by subsequent calls to any of the date and time functions. Added 'gw_mktime' function. * wap/cookies.c: changed 'mktime' call to 'gw_mktime'. 2004-02-26 Stipe Tolj * doc/userguide/userguide.xml: update of OISD section. * gw/smscconn[_p].[ch], gw/smsc/smsc.c, gw/smsc_oisd.c, gw/smsc/smsc_p,h: Rewrite of OISD module to smscconn API. Thankt a lot to "Dariusz Markowicz" for this patch. [see Mantis BUG#59 for the diff file] 2004-02-24 Stipe Tolj * gw/smsbox.c: fixed bug that config directive 'sendsms-chars' was not used at all in the logic, only the default remained. Thanks to "francesco emmi" for submitting this report and Edwin for acknoledging it. [Msg-ID: <1077126696.1011.49.camel@verne>] 2004-02-19 Stipe Tolj * wap/wsp_server_method_states.def: removed the ambicious 0x00 byte removal that was device specific for the Siemens S35. Thanks to Paul and Vjacheslav for pointing this out. Sorry for the delay removal. 2004-02-19 Stipe Tolj * gw/dlr.c: fixed MO boxc routing in case we have an directly received NACK from SMSC. The DLR message wouldn't be returned to the same smsbox-id connection. 2004-02-19 Igor Ivoilov * test/fakewap.c: added header "Accept: */*" to connect request to make wapgateway happy and reply with status of 200. 2004-02-18 Alexander Malysh * gwlib/conn.c: fixed possible race condition. also set io_error for failed write operations. 2004-02-18 Stipe Tolj * doc/userguide/userguide.xml: added Arne's patch to document binfo and tariff support within CIMD2 module. Thanks Arne. 2004-02-18 Alexander Malysh * doc/userguide/userguide.xml: moved 'External DLR' section to sect1, because DLR support doesn't belong to SMSbox configuration. Moved 'Mysql connection' section to sect3 and made it belongs to mysql dlr config. 2004-02-16 Stipe Tolj * gw/smsc/smsc_cimd2.c: added RPI (return-path-indication) support and binfo support via tariff class in CIMD protocol. Thanks to "Arne K. Haaje" for the patch. [Msg-ID: <200402160909.47610.haaje@eurobate.com>] 2004-02-16 Stipe Tolj * gw/bb_boxc.c, gw/shared.c, gw/smsc/smsc_[cgw|emi|fake|smasi|smpp].c, gwlib/conn.[ch], gwlib/http.c, test/drive_smpp.c, test/fakesmsc.c, test/test_smsc.c: renamed conn_read_error() to conn_error() to imply that this is a generical IO error condition we use for abortion. Also within gwlib/conn.c fixes handling of POLLHUP and POLLERR according to BUG#107. 2004-02-16 Stipe Tolj * gw/wml_compiler.c: fixed compiler warnings. 2004-02-10 Alexander Malysh * gw/bb_smscconn.c: got rid of 'List *incoming_wdp'. No sense to be there. 2004-02-10 Alexander Malysh * gw/wml_compiler.c: applied patch that prevent segfaults on solaris while printing debug msgs. Thanks a lot to: Paul P Komkoff Jr . Msg-Id: <20040209125602.GK12061@stingr.net>. 2004-02-04 Alexander Malysh * gwlib/utils.c: don't free 'struct passwd*' because it's allocated staticaly within glibc. 2004-02-02 Stipe Tolj * gw/shared.c: changed connect_to_bearerbox_real() to not drop panic in case we couldn't connect to bearerbox. This allows the caller to deside if a panic is applicable or a loop will be entered to try to re-connect. Whereas connect_to_bearerbox() keeps to throw panic on unsuccessful connect. 2004-01-29 Aarno Syv\132nen * gw/wap_push_ppg_pushuser.c: Fixed a fatal bug appearing when no blacklist is defined 2004-01-27 Stipe Tolj * gwlib/gwthread[-pthread].[ch], gwlib/log.c: added pid output to default log-file format. * test/test_wakeup.c: added getpid() calls to show whic OS process id we get for a thread. 2004-01-26 Aarno Syv\132nen Committed bugfixes by Paul Bagyenda. * gwlib/date.c: Bugfix in function making ISO dates * gwlib/mime.c: Add random characters to the boundary. Safer way to detect "non-standard" mime entity ending (\n, not \r\n). Correct a misspelling. * wap/wsp_headers.[c|h] More public functions. Accept '"' in addi- tion of WSP_QUOTE. Correct handling of quoted parameters. Thanks a lot to Paul ! 2004-01-26 Stipe Tolj * gwlib/dbpool_mysq.c, gwlib/utils.c: some source code beautifying. No logic change. 2004-01-23 Alexander Malysh * gw/wap_push_ppg_pushuser.c: forgot this one by last commit. 2004-01-23 Alexander Malysh * doc/userguide/userguide.xml, gw/bb_smscconn.c, gw/smsbox.c, gw/smscconn.c, gw/smscconn_p.h, gw/urltrans.[ch], gwlib/cfg.def, gwlib/regex.[ch]: Applied a "big" regexp patch from "David Schmitz" . This patch breaks currently kannel build when no 'regexp.h' found. David is working on resolution and most modern OSs has regexp support anyway. Msg-Id: <400D4417.9010306@wapme-systems.de>. 2004-01-23 Alexander Malysh * gw/bb_boxc.c: fixed double free. Thanks to Benjamin Lee for pointing this. Msg-Id: <20040123123650.GA22906@xaos.realthought.net>. 2004-01-23 Alexander Malysh * gwlib/octstr.c: fixed bug that space was not replaced when all chars were safe except a space. 2004-01-22 Stipe Tolj * LICENSE, *.[c|h|h.in|def]: moved copyright to 2004. Even while I realize this makes me one year older too ;) - no logic change. 2004-01-22 Stipe Tolj * gw/smsc/smsc_http.c: bugfix of brunet MT interface. The new UUIDs have broke the TransactionID syntax. Brunet expects 32 bytes hex value and the parsed UUID Octstr representation contained dashes that have to be removed. * test/test_uuid.c: added simple testing app. 2004-01-20 Alexander Malysh * configure.in, configure: applied mysql-configure-rewrite.patch that does: 1) remove code duplication 2) bug-fix for CFLAGS/LIBS 3) adds using of reentrant counterpart of libmysqlclient Msg-Id: <200401191528.57104.a.malysh@centrium.de>. 2004-01-20 Alexander Malysh * gw/shared.c: added more info to 'version_report_string'. Compiler,Build time, Mysql build with version, running with. 2004-01-20 Alexander Malysh * gw/bearerbox.[ch], gw/bb_store.c: applied bb-store-fixes.patch that: 1) remove check for report while loading of store-file (this check has no sense to me because if bearerbox crashed or was down, we want deliver DLR's to smsbox instead of silently deleting) 2) improve store status query 3) fixes some race conditions Msg-Id: <200401151937.35566.a.malysh@centrium.de>. 2004-01-20 Alexander Malysh * gw/bb_smscconn.c, gw/bb_store.c, gw/dlr.c, gw/msg.h, * gw/smsbox.c, gw/urltrans.c, gw/smsc/smsc_emi.c, gw/smsc/smsc_fake.c, * gw/smsc/smsc_oisd.c, gw/smsc/smsc_smpp.c: applied add-report-mt.patch that change 'report' to 'report_mo' and adds 'report_mt' sms type (similar to 'mo','mt_reply','mt_push'). Msg-Id: <200401151859.02886.a.malysh@centrium.de>. 2004-01-20 Alexander Malysh * gw/bearerbox.c, gw/smsbox.c, gwlib/utils.c, doc/userguide/userguide.xml: applied parachute-daemon.patch that adds some useful command line parameters for all boxes: 1) -P/--parachute : start watcher father process that catch and restart crashed child process 2) -X/--panic-script : execute this script if child process crashed 3) -u/--user : change process user-id (security) 4) -p/--pid-file : write PID into the given file 5) -d/--daemonize : daemonize the process Msg-Id: <200401151456.52069.a.malysh@centrium.de>. 2004-01-20 Stipe Tolj * gwlib/octstr.[ch]: applied Alex's performance gain patch. Thanks. [Msg-ID: <200401191255.42340.a.malysh@centrium.de>] 2004-01-20 Stipe Tolj * gw/smsc/smsc_smasi.c: fixed decode_binary_data() which now behaves the way expected according to the specs. Binary MOs are *NOT* encoded the same way like MTs. The SM/ASI SMSC sends raw data bytes in the body and udh fields and only escapes specific bytes that are reserved as protocol delimiters. This fixes binary MO receives. 2004-01-18 Alexander Malysh * doc/userguide/userguide.xml: added missing 'field-source' and 'field-boxc-id' in examples within DLR database field configuration section. 2004-01-15 Alexander Malysh * gw/bb_store.c: got rid of unused 'Counter *msg_id'. We use UUID's now. 2004-01-15 Alexander Malysh * gwlib/log.c: close syslog when exit. removed 'inline' from declaration of 'gw_panic_output' because va_args functions can't be inlined. 2004-01-14 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_at.[ch], gwlib/cfg.def: applied at-merging.patch. This patch adds propperly reconnect for modem device. Fixes a few race conditions and adds 2 new config options 'max-error-count', 'reset-string'. These options adds facility for hard reset of the modem when modem crashed. Additionaly a few fixes here and there. Msg-Id: <200401121508.00508.a.malysh@centrium.de>. 2004-01-12 Alexander Malysh * gwlib/http.c: fixed memory and mutex leak. Thanks a lot to: Nuno Ferreira for provided patch. Msg-Id: <1073928970.2849.4.camel@taz.graycell.biz> 2004-01-10 Alexander Malysh * gw-config.h.in, configure[.in], gw/dlr_[mysql|sdb].c, doc/userguide/userguide.xml: Applied patch that removes '--with-dlr' configure option and replace: --with-mysql --> --with-mysql-dir --enable-[mysql|oracle|sdb|sqlite] --> --with-[mysql|oracle|sdb|sqlite] Added documentation for those. Msg-Id: <200401091444.52832.a.malysh@centrium.de> and <200401091517.54703.a.malysh@centrium.de> 2004-01-08 Alexander Malysh * gwlib/http.[ch], gwlib/cfg.def, gw/wapbox.c, doc/userguide/userguide.xml: Applied patch from Vjacheslav Chekushin that adds new config option 'http-interface-name' to wapbox configuration and allow selecting of interface for outgoing HTTP requests. Thanks Slava! See Msg-Id: <3FE1AE9C.3020008@lmt.lv> 2004-01-06 Alexander Malysh * configure.in, configure: fixed CFLAGS for pthread_spinlock support. 2004-01-05 Alexander Malysh * gwlib/gw_uuid.c: trivial change, don't define _SVID_SOURCE if it's already defined. 2004-01-05 Alexander Malysh * configure, configure.in, gw-config.h.in, gwlib/counter.c: added pthread_spinlock support. Here some benchmarks (factor 6 faster): Counter benchmark (loop 10000000 with counter_[in|de]crease): w/ spinlock support: real 0m1.665s user 0m1.340s sys 0m0.035s real 0m1.513s user 0m1.365s sys 0m0.000s real 0m1.501s user 0m1.360s sys 0m0.005s w/o spinlock support (mutex based): real 0m6.685s user 0m6.255s sys 0m0.010s real 0m6.687s user 0m6.230s sys 0m0.030s real 0m6.703s user 0m6.270s sys 0m0.010s 2003-12-18 Stipe Tolj * contrib/kannel-monitor/index.php: fixed fread() problem if XML output is too big. Thanks to Angel for this quick patch. [Msg-ID: <200312181230.hBICUvh16011@int-mail01.mediafusion.es>] 2003-12-17 Stipe Tolj * gw/bb_boxc.c, gwlib/gw_uuid.[ch], gwlib/utils.[ch], radius/radius_pdu.c, test/wapproxy.c: fixed strict compiler warnings. 2003-12-17 Stipe Tolj * gw/smsc/smpp_pdu.c: making compiler and Alex happy again ;) 2003-12-16 Stipe Tolj * gw/smsc/smpp_pdu.c: removed debug output while packing optional v3.4 parameters and added better debug output for dumping of the PDU. No logic change. 2003-12-16 Stipe Tolj * gw/wap-appl.c: added access-log logging of upstream HTTP server failures with HTTP response code 502 (bad gateway). So even in case the HTTP server can not be resolved or is not reachable, user's will be logged with a request access entry in wapbox's access-log. [Msg-ID: <3FDDB666.F31F5648@wapme-systems.de>] 2003-12-11 Stipe Tolj * test/fakesmsc.c: changed randomization behaviour to allow adding randomized numbers as last message word. Use the -r switch as bitmask. 2003-12-09 Stipe Tolj * wap/wsp_headers.[ch]: fixing prototype declarations of depending routines for external applications using WSP header functions. 2003-12-09 Alexander Malysh * gw/dlr.[ch], gw/dlr_p.h, gwlib/cfg.[ch], gwlib/log.[ch], gwlib/mime.h, radius/radius_acct.c, wap/wsp_headers.c: fixed compiler warnings. 2003-12-08 Alexander Malysh * configure.in, configure: changed 'head -1' call to propperly 'head -n 1'. * gwlib/gw_uuid.[ch], gwlib/gwlib.c: added uuid_init() and uuid_shutdown() functions. uuid_init() just open the random device (if any) because otherwise it's possible that we open device twice (race condition). 2003-12-08 Stipe Tolj Universal Unique Identifier (UUID) Patch by Alexander. * configure[.in]: adding word size, srandom() and various header checks needed for gwlib/gw_uuid.[ch]. * gw-config.h.in: some additional #undef's * gw/bb_[alog|smscconn|store].c, gw/smsbox.c, gw/urltrans.c, gw/smsc/smsc_[fake|http|soap].c: changing ID handling to UUID routines. * gw/msg-decl.h, gw/msg.[ch]: exchanged INTEGER(id) to UUID(id) and added adequate handling of UUID in msg_foobar() routines. * gw/smsc/smsc_fake.c: added 'dlr-mask' msg type handling. * gwlib/gw_uuid.[ch]: UIID implementation (taken from libuuid), see prefix comment block for author information and acknowledgement. * gwlib/gw_uuid_types.h.in: autoconf header file for handling UUID required types that have been detected while configure run. * gwlib/gwlib.h: added "gw_uuid.h" header inclusion. * test/test_dict.c: using UUID as unique key for the "huge" test. Thanks a lot to Alexander for working this out. [Msg-ID: <200311302210.18110.a.malysh@centrium.de>] 2003-12-08 Stipe Tolj * gwlib/conn.c: fixed compiler warning, commenting out function tmp_rsa_callback(). 2003-12-05 Alexander Malysh * gw/dlr.c: fixed bug that dlr's were not routed correctly to smsbox within bb_boxc, due to last changes in dlr.c (now we do not duplicate dlr_entry values in order to avoid not needed memory allocations, but bb_boxc await e.g. boxc_id as NULL and not as ""). 2003-12-05 Stipe Tolj * wap/wtp_resp_states.def: fixing BUG#102. In RESULT_RESP_WAIT state, when TimerTO_R occures and MAX_RCR, we should send Abort PDU with type PROVIDER instead of USER. According to WAP-224-WTP-20010710, sec 8.3.4.1, p.43. Thanks to "Noritoshi Demizu" for providing patch and the bug report. 2003-12-04 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed bug that source-autodetect was 'false' if not defined in the config although userguide mentioned 'true'. 2003-12-03 Stipe Tolj * gw/smsc/smsc_emi.c: added OP/31 handling for the sake of EMI/UCP implementations that use this construct as server-side initiated keep-alive mechanism. 2003-12-03 Stipe Tolj * doc/userguide/userguide.xml: adding a bit more explanation about the effect of EMI's 'my-number' config directive for keep-alive (OP/31) PDUs. * gw/smsc/smsc_http.c: removed additional body checking for type 'wapme' and added username and password requirement for the MO side to act as sendsms HTTP interface transparently. 2003-12-02 Aarno Syvanen * wap/wtp.c: Better debugging in the case of truncated pdu * wap/wap_events.[c|h]: Wrapper for checking wap event allocation * wap/wap.c: Fixed a memory leak * gwlib/octstr.[c|h]: Wrapper for checking ocstr_copy allocation * gwlib/http.[c|h]: Wrapper for octstr_find_first allocation * gw/wap_push_ppg.c: Fixed memory leaks * gw/wap-appl.c: Fixed a memory leak * gw/msg.[c|h]: Wrappers for msg_create and msg_unpack. Fixed a leak. * gw/bb_store.c: Fixed a memory leak 2003-11-30 Alexander Malysh * gw/dlr.c: don't duplicate values from dlr_entry struct, just reuse these. This give us a bit speedup. 2003-11-30 Alexander Malysh * gwlib/conn.[ch]: applied conn-ssl-cleanup.patch. This patch does: 1) removes ssl_mutex 2) corrects SSL_[read|write] operations 3) removes SSL_connect and SSL_accept because these handled by openssl library trasparent while SSL_[read|write] operations. See Msg-Id: <200311261813.34824.a.malysh@centrium.de>. 2003-11-27 Alexander Malysh * gwlib/accesslog.c: fixed compiler warning about zero-length format string. Got rid of buffer allocation, just allocate on the stack. 2003-11-26 Alexander Malysh * gwlib/http.c: fixed memory leak if conn_wrap_fd(...) failed due to unsuccessful SSL handshake. 2003-11-26 Stipe Tolj * gw/smsc/smpp_pdu.def: added missing esm_class values for deliver_sm PDU. 2003-11-26 Stipe Tolj * doc/userguide/userguide.xml: added HTTP SMSC type 'wapme'. * gw/smsc/smsc_http.c: harmonizing kannel_receive_sms() to behave the same way as smsbox's sendsms interface. We run into code duplication here. Have to think on how this can be done better, in sense of modularization. Added Wapme SMS Proxy type 'wapme' as HTTP content/SMS gateway interface. 2003-11-26 Stipe Tolj * gwlib/cfg.def: added 'access-log-time' and 'access-log-clean' directives to smsbox and wapbox groups. Thanks to Alex Kinch for reporting this. 2003-11-24 Stipe Tolj * doc/userguide/userguide.xml: added new config directives 'access-log-clean' and 'access-log-format'. * gw/bb_alog.c: handles the custom bearerbox access-log formating * gw/bb_smscconn.c: moved log_sms() to gw/bb_alog.c:bb_alog_sms() * gw/bearerbox.h: added bb_alog_ prototypes * gw/[sms|wap]box.c: harmonized access-log config directive reading * gwlib/accesslog.[ch]: alog_open() changed to indicate if markers should be written to access-log file. If no markers are set, then the default timestamp prefix is not written, allowing users to individually set the timestamp in their custom access-log format. * gwlib/cfg.def: added config directives 'access-log-time' to indicate if localtime or gmt should be used within access-log, 'access-log-format' holding the escape code formated line to log, 'access-log-clean' (boolean) indicating if standard markers shoould be avoided and hence the access-log should be "clean". 2003-11-22 Alexander Malysh * gwlib/log.c: don't add timestamp if syslog used. Improved backtrace support. 2003-11-22 Alexander Malysh * configure, configure.in, gw-config.h.in, gwlib/log.c: added backtrace support for supported archs to gw_panic call. Backtrace information allows better way to trace a panic cause because now panic give us really meaningless info. Tip: use address within [] with addr2line or add -rdynamic to CFLAGS. 2003-11-21 Stipe Tolj * gw/bb_smscconn.c: adding logging of msg->sms.binfo field to access-log. 2003-11-21 Stipe Tolj * wap/wtp_resp_states.def: fixing PANIC output in case object is larger then maximum SAR limit of 256 packets. Thanks to "Vjacheslav Chekushin" for providing patch. [Msg-ID: <3FBDC5BF.2000702@lmt.lv>] 2003-11-20 Aarno Syvanen * gw/wap_push_pap_mime.c: Fixed parsing. Now there must be empty line between headers and message. * gw/wap_push_pap_mime.c: Fixed memory leaks. And bug reported by Paul. 2003-11-20 Stipe Tolj * doc/userguide/userguide.xml: fixing typo 2003-11-19 Stipe Tolj * doc/userguide/userguide.xml, gw/bearerbox.c, gwlib/cfg.def: changed config directive 'sms-incoming-queue-length' to 'sms-incoming-queue-limit' for the sake of semantics. 2003-11-15 Stipe Tolj * LICENSE: changed to Kannel Software License v1.0. BSD-style as before with some more restrictions to the name "Kannel" and usage of it. Changed in consensus with all other Kannel developers and members of the Kannel group. * COPYING: removed "old" license text and add reference to LICENSE file. * README: intent line fix. * configure[.in]: added license information notice in end of output to inform the user that he/she is bound to the license agreement terms when proceeding with instllation. * utils/update-license.sh: added simple shell script to prefix the source files with the license text. Needs to be modified to be able to really "update" in terms of exchanging old against new. * */*.[c|h|def|h.in]: added LICENSE file as comment prefix block. 2003-11-13 Stipe Tolj * test/fakesmsc.c: don't dump msg line in debug, because this takes speed away and the EOL is anyway annoying. 2003-11-13 Stipe Tolj * gw/bb_smscconn.c: typo fix. no logic change. * test/fakesmsc.c: added -r option to allow randomization of source and/or receiver numbers while passing MO messages to smsc_fake. 2003-11-12 Alexander Malysh * gw/smsc/smsc_at.c: applied (in slightly modified version) patch that fixes non-blocking write to modem device. Thanks a lot to: Yulianto Z for provided patch. Msg-Id: <1068643285.4052.58.camel@pandora.daehsan.com> 2003-11-12 Stipe Tolj * gwlib/http.c: fixes partially BUG#99 when the HTTP servers sends an 'Authorization' header without real values in it. This would cause previously a PANIC while accessing list_get() on an empty list. Thanks to the bug reported for pointing this out. * wap/wsp_strings.c: making the WSP mapping output a bit more compacter. 2003-11-12 Alexander Malysh * gwlib/protected.c: do not double check errors from reentrant gethostbyname functions. This breaks resolution of the hostname for old glibc (e.g. Redhat 7.2). 2003-11-11 Stipe Tolj * gwlib/conn.c: enable non-blocking mode for SSL connections via read/write BIO and partial writing and buffer moving in ssl context. this is needed if we use non-blocking mode otherwise openssl doesn't simulate write(2) behaviour. Thanks to Alex for providing the patch [Msg-ID: <200311071927.27616.a.malysh@centrium.de>] 2003-11-11 Stipe Tolj * gw/bearerbox.c: remove "no-op" debug output. * gw/wap_push_[ppg|pap_mime].c: various Ocstr call improvements for the PPG handling, MIME parsing routines. * gwlib/octstr.[ch]: added function octstr_case_nsearch() to allow searching for octstr in a specific range. Patch posted by Aarno. Thanks a lot. [Msg-ID: <76D52118-0ED8-11D8-B1D6-0003937AE746@gni.ch>] 2003-11-10 Stipe Tolj * Makefile.in: adding gw-config to be removed when target clean is called. 2003-11-10 Igor Ivoilov * gwlib/http.c: Fix for the BUG#95. Problem caused by octsrt_imm() on non-constant c-string in http_something_accepted() 2003-11-07 Stipe Tolj * doc/userguide/userguide.xml: BUG#98 indicated that the user's guide does not indicate that the keyword in a sms-service group matches in non-case sensitive manner. This is a crutiual information for users, so addiong this. 2003-11-07 Stipe Tolj * contrib/kannel-monitor/*: changed the monitor to allow non persistance of the admin password. Instead, if no admin password is configured, a dialog box will ask you for it whenever you try to issue HTTP admin commands to bearerbox. Added Alex's smsbox queue output. 2003-11-06 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed another issue resulting from the previous revision commit. We want to convert the charset *only* if data_coding is 0x00 and hence the default smsc alphabet is addressed. Thanks again to Alexander for this quick spot. 2003-11-05 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed bug for re-encoding character set. Accoding SMPP spec v3.4 if mclass is set, then data_coding is within 0xF0 range. Which means a normal 7bit text message will be data_coding 0xF1 (241). Thanks a lot to Alexander for preparing this fix and the patch. 2003-11-03 Alexander Malysh * gw/smsc/smsc_smpp.c: applied yet another workaround for BUFFERED DLR's. Thanks to: "Alex Kinch" for patch. 2003-11-03 Alexander Malysh * configure.in, configure: applied patch with better gethostbyname_r/gethostbyname detection. 2003-11-01 Stipe Tolj * wap/cookies.c: fixed annoying compiler warning 2003-11-01 Alexander Malysh * doc/userguide/userguide.xml: documentations about deprecated 'maximum-queue-length' option and new 'sms-incoming-queue-length'. 2003-11-01 Stipe Tolj * test/test_[regex|pcre].c: make test programs compile only if gw-config.h #defines are set. 2003-10-30 Alexander Malysh * gw/bb_boxc.c: applied bb_boxc patch. This patch solve major problems within bearerbox<->smsbox routing: 1) When an smsbox passes an MT message bearerbox will send an ACK for it, that is passed to the "global" incoming queue. From this global incoming queue all smsboxes are reading. Hence there is no garantee that ACKs are delivered to the right smsbox. 2) smsbox routing doesn't work if bearerbox started after shutdown and messages were stored in store-file. (see bug #83) 3) mantis #80 3) shutdown can block for ever if incoming queue is not empty and no smsboxes will connect to bearerbox. Now we have timeout for this (it's hardcoded to 10sec). This patch split bearerbox incoming queue on per smsbox connection basis and makes smsbox routing more restrictive. In order to reflect new smsbox connections behavior, new incoming queuing policy was introduced. Incoming queue is now per smsbox connection and only if no appropriate smsbox connection was found (e.g. smsbox routing is set but smsbox is gone), messages will be queued within global incoming queue. And as a bonus, allows clean shutdown on cygwin. * gw/bb_smscconn.c, gw/bearerbox.c, gwlib/cfg.def: new config option 'sms-incoming-queue-length' instead of the old 'maximum-queue-length'. Old option still supported but marked as deprecated. 2003-10-30 Stipe Tolj * configure[.in]: added Perl compatible regular expression (PCRE) library support via --enable-pcre configure option. * gw-config.h.in: added HAVE_REGEX and HAVE_PCRE to indicate availablity within the gwlib code itself. * gwlib/gwlib.h remvoed #include "regex.h" to avoid preprocessor conflicts with system regex.h header file. Inclussion has to be performed within the sources directly. * gwlib/pcre.[ch]: added wrapper functions to PCRE library functions. * gwlib/regex.[ch]: added compilation if PCRE library provides POSIX compliant regex if no system own implementation exists. * test/test_pcre.c: added test program for PCRE function calls. * test/test_regex.c: added #include "gwlib/regex.h" 2003-10-30 Stipe Tolj * gwlib/regex.c: fixed compiler warning and deallocation of memory after gw_regex_sub() call. * wap/cookies.c: fixed compiler warning * test/test_regex.c: fixed missing deallocation. 2003-10-30 Stipe Tolj * gwlib/regex.[ch]: made regex functions display calling function in case of error. This is useful for later debugging purposes. Added functions gw_regex_[match|subst]_[pre]() for simple matchin and substituion operations on Octstr. Either passing the RE in plain text or as pre-compiled structure. * test/test_regex.c: added wrapper functions testing. 2003-10-29 Stipe Tolj * configure[.in]: added checking of POSIX.1 regex functions and header files availibility on the system. * gwlib/gwlib.h: added inclusion of gwlib/regex.h * gwlib/regex.[ch]: added POSIX regular expression support, including substitution routine for passing subexpression matches to the result. This needs some more improvement, but looks good now. * test/test_regex.c: test program for the gwlib/regex.[ch] module. Try $ ./test/test_regex "+4914287756" "^(00|\+)([0-9]{6,20})$" "\$2" for a quick test on how to substitute an prefixed + MSISDN with the regex into the subexpression part two. 2003-10-28 Stipe Tolj * gw/smsc/smsc_emi.c: fixed billing identifier handling. We have to convert the binary information received from smsbox to hex for the EMI XSer 0c representation. 2003-10-27 Stipe Tolj * wap/cookies.c: fixed BUG#95 causing wapbox to crash while comparing cookies octstr_compare(). 2003-10-27 Alexander Malysh * gw/bb_http.c: small bug fix. Allow http admin commands w/o /cgi-bin/ prefix (e.g. /status). 2003-10-26 Alexander Malysh * gw/bearerbox.c: applied patch that should fix bearerbox signal handling. Otherwise is a deadlock possible while signal arrived. For more details see Msg-Id: <200310130000.34055.a.malysh@centrium.de> 2003-10-26 Alexander Malysh * gw/bb_http.c: cleanup and harmonization of http admin commands. 2003-10-24 Alexander Malysh * gwlib/conn.c: added check for NULL pointer callback function. * gwlib/http.c: call conn_unregister(conn) before destroing HTTPClient. 2003-10-22 Alexander Malysh * gw/wml_compiler.c: fixed possible segfault if wml document doesn't contain DTD section. Thanks to Vjacheslav Chekushin for patch. Msg-Id: <3F95203C.60402@lmt.lv> 2003-10-22 Alexander Malysh * gwlib/http.c: applied patch from bug #78. 2003-10-20 Alexander Malysh * gwlib/accesslog.c, gwlib/gwlib.c, gwlib/log.[ch]: applied alog-log-rc-reopen.diff patch. This patch should fix race conditions in the accesslog and log module while reopening of log files. Patch just add reader/writer lock and make sure that writer are locked while reopening of log files, plus adds log_shutdown(..) function in order to proper close log files. 2003-10-20 Stipe Tolj * gw/smsc/smsc_http.c: added forwarding of 'binfo' CGI variable in Kannel type. * gw/smsbox.c: added X-Kannel-BInfo header for sms-service. Thanks to Adi Prasaja for this patch. [Msg-ID: <20031019021038.GA18965@imt.co.id>] 2003-10-17 Alexander Malysh * gw/smsc/smsc_smpp.c: applied smsc_smpp.c-allow-plus.diff. This patch implements workaround for buggy SMSC's that send '+' in front of source address and ton/npi set to 1/1 (means international/isdn). 2003-10-17 Stipe Tolj * gw/smsbox.c: fixed missing assignment of msg->sms.binfo. Thanks to Paul for spotting my looseliness ;) 2003-10-17 Stipe Tolj * gw/smsc/smsc_at.[ch]: adding +CMTI, MO support. Original patch submited by "Rene Kluwen" and revised by Alexander to fit current cvs head tree. Thanks a lot for submission. [Msg-ID: <031c01c29faf$5cb51660$1401a8c0@helena>] [Msg-ID: <200310162237.01081.a.malysh@centrium.de>] 2003-10-16 Stipe Tolj * doc/userguide/userguide.xml: added sections about new sendsms CGI parameter 'binfo' and sms-service escape code '%B' used for proxying billing identifier/information from/to HTTP application into SMSC modules. * gw/msg-decl.h: removed 'hplmn' parameter added by Bruno; by veto of Alex and Stipe. This is a good thing to have, but has to be more generic and not specific to EMI. This has to be re-done cleanly. * gw/smsbox.c: removed 'auth_code' and 'hplmn' processing. 'auth_code' was nowhere used, even not in the smsc_emi.c module?! Bruno, this is overhead. Added 'binfo' processing for billing identifier/information proxying. * gw/urltrans.c: removed '%h' escape code for hplmn forwarding. Added '%B' escape code for billing identifier/information passing. * gw/smsc/smsc_emi.c: rewrote the XSer handling sections to be more generic. Added XSer 0c and 0d handling. * gw/smsc/smsc_http.c: changed bruNET interface to use binfo field instead of account field. This was miss-used for some time and should be cleaner now. * gw/smsc/smsc_smpp.c: added 'service_type' handling of deliver_sm and submit_sm PDUs to pass information via the binfo billing identifier/ information field of the Msg struct. 2003-10-15 Alexander Malysh * gw/smsbox.c: trivial changes. 2003-10-15 Alexander Malysh * gw/smsc/smsc_at.c: fixed bug #92. * gw/smsc/smsc_at.h: made all functions static. 2003-10-15 Stipe Tolj * gwlib/mime.[ch]: abstracted mime_[octstr|http]_to_entity() to use the same base routine for the transcoding. Added mime_http_to_entity(). Added MIMEEntity *start to the MIMEEntity struct to reference the multipart/related start elmement. 2003-10-15 Stipe Tolj * gwlib/http.c: applied Alex's patch for Vjacheslav report on a failing http_something_accepted() routine if we have multi-valued parameter. 2003-10-15 Alexander Malysh * Makefile.in: fixed 'make install' errors. 2003-10-14 Alexander Malysh * radius/radius_acct.c, radius/radius_pdu.c: applied Vjacheslav's memleak patch. Thanks to Vjacheslav Chekushin . For more details see: Message-ID: <3F854566.4020704@lmt.lv> 2003-10-13 Alexander Malysh * gw/msg.h: defined MSG_PARAM_UNDEFINED as -1 for init. values of all messages. * gw/msg.c: got rid of ugly sms initializing.Added using of MSG_PARAM_UNDEFINED. * gw/sms.h: added using of MSG_PARAM_UNDEFINED that now equal to SMS_PARAM_UNDEFINED. 2003-10-13 Alexander Malysh * gwlib/http.c: fixed panic in http_something_accepted(...) that NULL was passed to octstr_case_compare(...). 2003-10-13 Alexander Malysh * gw/sms.c: restore old DCS behaviour. 2003-10-13 Alexander Malysh * gw/smsc/smsc_http.c: changed 'dlrurl' -> 'dlr-url' , 'dlrmask' -> 'dlr-mask' in order to reflect changes made by Bruno for smsbox. Thanks to adi for patch. 2003-10-13 Alexander Malysh * .cvsignore: added gw-config.h, gw-config. 2003-10-12 Alexander Malysh * gw/smsbox.c: various fixes/cleanups here and there. 2003-10-12 Alexander Malysh * gw/bb_boxc.c: don't remove producer of incoming list if that is a global incoming list. Otherwise we have panic. * gw/urltrans.c: don't panic if msgdata == NULL in urltrans_find(...). * gw/shared.[ch]: made program_status var. volatile, because changed in the signal handler and should not be cashed. 2003-10-12 Alexander Malysh * gwlib/thread.[ch]: added mutex_try_lock(...) function. 2003-10-12 Alexander Malysh * gwlib/http.c: make compiler happy. 2003-10-11 Alexander Malysh * gw/sms.c: hmm, seems some of us don't know, what a pointers are for :) 2003-10-11 Alexander Malysh * gw/dlr_sdb.c: fixed bug #87. 2003-10-10 Stipe Tolj * gwlib/http.c: removed unncessary convertion to upper case in function http_something_accepted(). That's why we have octstr_case_compare() for. 2003-10-09 Alexander Malysh * gwlib/http.c: fixed bug, that octstr was double freed. 2003-10-09 Stipe Tolj * gwlib/http.[ch]: changed http_something_accepted() routine in order to use Octstr compare and upcase functions rather then istrdup() which is deprecated now. 2003-10-08 Stipe Tolj * utils/foobar-config.sh: added generic foobar-config shell script generator script to generate gw-config which may be used by 3rd party configure processes to determine Kannel's gwlib dependencies. * Makefile.in: added gw-config rule to create our gwlib dependency description shell script. This shell script goes into $bindir when installing. Install gwlib headers and libgwlib.a itself to the installation directory to allow 3rd party software to use it. 2003-10-08 Stipe Tolj Kannel's gwlib as 3rd party library harmonization commit. This will resolve the global config.h issue, which breaks in case we use gwlib code in other GNU autoconf generated projects. Therefore we move to gw-config.h for our specific config header file. In addition all name conflicts should be resolved. We use GW_VERSION instead of VERSION which is more common to non-dependent source projects. * [gw-]config.h.in: removed config.h.in and added gw-config.h.in. Changed #undef VERSION to #undef GW_VERSION to avoid naming clashes. * configure[.in]: move from config.h to gw-config.h and add GW_VERSION to the substitution rules. VERSION is keept, because it is needed to set the same env variable in Makefile. * Makefile.in, gwlib/gwlib.h, gwlib/list.h, gwlib/socket.h, gwlib/thread.h, utils/attgetopt.c, wmlscript/wsint.h: moved or changed inclusion from config.h to gw-config.h * gw/bearerbox.c, gw/shared.c, gw/smsbox.c, gw/wap-appl.c, gw/wap-error.c, gw/wap_push_ppg.c, gw/wapbox.c, gw/smsc/smsc_soap.c, gwlib/http.c, utils/start-stop-daemon.c: changed usage of version #define VERSION to #define GW_VERSION defined within gw-config.h * gw/mime_decompiler.c, gw/wml_compiler.c, gw/smsc/smsc_emi_x25.c, wmlscript/wmlsc.c, : removed duplicate #include "config.h". We include our specific config header gw-config.h within gwlib/gwlib.h anyway. 2003-10-07 Stipe Tolj * wap/wsp_unit.c: fixing DOS attack bug is datagram unpacking failed. This fixes BUG#33. Thanks again to Vjachelsav. [Msg-ID: <3F828204.3070209@lmt.lv>] 2003-10-07 Stipe Tolj * radius/radius_acct.c, wap/wsp_session.c: fixing compiler warnings. 2003-10-07 Stipe Tolj * gw/wml_compiler.c: fixed DOS bug within wml deck as described in the mailing list post. Thanks to Vjacheslav for providing this fix. [Msg-ID: <3F7BCE92.9080401@lmt.lv>] 2003-10-07 Stipe Tolj * doc/userguide/userguide.xml: changed example and behaviour description according to the following patch. * radius/radius_acct.c: Vjacheslav's patch to allow running RADIUS acct proxy in "single-end-point" mode. Which means our RADIUS acct proxy is not forwarding any packets to a remote RADIUS server. Thanks a lot to "Vjacheslav Chekushin" for the patch. [Msg-ID: <3F81522B.40409@lmt.lv>] 2003-10-01 Stipe Tolj * configure[.in]: fixing BUG#88 which was caused by Alex's gethostbyname() patch. Cygwin does not have a re-entrant version, but seems to compile silcently for it. This results in a undefined reference while linking. * gwlib/protected.c: some typo fixes, no code change. 2003-09-26 Alexander Malysh * gwlib/protected.c: bugfix prov prev. commit for gethostbyname_r() Linux version. 2003-09-26 Alexander Malysh * aclocal.m4, config.h.in, configure, configure.in, gwlib/protected.[ch], gwlib/socket.c: Added using of reentrant gethostbyname_r(..) functions. If none is found then needed values will be copied into supplied buffer. Otherwise we have segfault, because gethostbyname(...) uses static buffers which will be overwritten by next call. 2003-09-26 Alexander Malysh * gw/dlr_mysql.c, gw/dlr_oracle.c, gw/dlr_sdb.c: fixed bug, that smsc-id was not copied to dlr message. Thanks to: Adi Prasaja for pointing this. 2003-09-25 Stipe Tolj * gw/mime.[ch]: added function mime_entity_header() and mime_entity_body() to return HTTP header and HTTP POST body of e MIMEEntity type. 2003-09-25 Stipe Tolj * gw/shared.[ch]: implemented _real() functions to have boxc connections handled directly if desired by an box. This does not change current behaviour and gives more flexibility for other boxes. * gwlib/parse.c: fixed pasing issues in parse_get_line() and parse_get_seperated_block() * gwlib/mime.c: fixed CRLF handling for headers and boundary separators. 2003-09-15 Stipe Tolj * wap/wsp_headers.[ch]: relabeled strip_parameters() and pack_integeer_value() to have "wsp_" prefix. for cleaner prototypes. 2003-09-15 Stipe Tolj * gw/wap-appl.c: veto against Bruno's changes for WAP URL mapping added in revision 1.89. This needs to be more abstracted and cleanly bound with HTTP and RADIUS acct proxy lookups before commited as change. 2003-09-11 Alexander Malysh * doc/userguide/userguide.xml: fixed values for mwi/mclass/coding. Need more review. Examples should be fixed too. 2003-09-11 Alexander Malysh * gw/smsc/smsc_smpp.c,gw/smscconn.c: applied smpp properly shutdown sequence patch. For details see: Message-Id: <200309021706.51057.a.malysh@centrium.de> 2003-09-11 Stipe Tolj * gwlib/mime.c, test/test_mime_multipart.c: fixed compiler warnings. 2003-09-10 Alexander Malysh * gwlib/utils.[ch]: added gw_isalnum(int) wrapper for isalnum(int) function. 2003-09-10 Stipe Tolj * gwlib/parse.[ch]: added routines parse_get_line() to get the Octstr stream up to an EOL and parse_get_seperated_block() to get an next Octstr block between two separators. * gwlib/mime.[ch]: added MIME multipart/related parsing routines. This allows to parse an MIME document given as Octstr into our own MIMEEntity representation which is a hierarchical linked structure. * test/test_mime_multipart.c: added simple testing instance for the MIME parsing and transcoding routines. 2003-09-10 Alexander Malysh * gwlib/octstr.c: fixed bug in octstr_replace(...). We should not replace in replacement, so just skip replacement length. Otherwise here follow simple OOM: Octsr *str = octstr_create("abacd"), *needle = octstr_imm("a"), *repl = octstr_imm("aa"); octstr_replace(str, needle, repl); and wait for... 2003-09-05 Stipe Tolj * gw/smsc/smsc_smpp.c: changed pdu_to_msg() to recode source_addr and destination_addr on the MO side. We will pass an prefixed '+' to the smsbox side. Otherwise there is no chance for backend applicatins, like smsbox to decide what type of number it is. BEWARE: this may be a behaviour change for your individual setup, if you rely that the number is transmitted in pure TON=1 notation to the smsbox. In this case please use unified-prefix on the smsc group level to get rid of the prefixed '+'. Thanks to Alex for providing the patch. 2003-09-04 Stipe Tolj * wap/wsp_[strings.[ch]|session.c]: fixed compiler warnings. 2003-09-03 Alexander Malysh * doc/userguide/userguide.xml: spelling fix. Thanks again to "Bill Brigden" for pointing this. 2003-09-02 Stipe Tolj * gw/shared.c: added SQLite version in version_report_string(). 2003-09-02 Alexander Malysh * doc/userguide/userguide.xml,doc/examples/dlr-*.conf: added required 'field-source' to the documentation. Thanks to "Bill Brigden" for pointing this. 2003-09-02 Alexander Malysh * doc/userguide/userguide.xml,gwlib/cfg.def,gw/smsc/smsc_smpp.c: applied SMPP inactivity+transaction timeouts patch. For description see: Message-Id: <200308202001.50721.a.malysh@centrium.de> 2003-09-02 Stipe Tolj * gwlib/socket.c: fixed a segmentation bug. If setup_official_name() did not have a successful gw_gethostbyname() call, then gw_netaddr_to_octstr4() would cause to cause segmentation fault. 2003-09-01 Stipe Tolj * configure[.in], config.h.in: added --enable-sqlite switch to enable SQLite support and #defines. * gwlib/dbpool[_sqlite].[ch], test/test_dbpool.c: addd SQLite support for database pools. 2003-08-29 Alexander Malysh * gwlib/log.c: fixed bug indroduced by Stipe that no system error strings were shown in the logs. 2003-08-28 Stipe Tolj * wap/wsp.h: added WSP_1_x enumeration values to identify which WSP Encoding-Version is used within a session. * wap/wsp_headers.[ch]: re-declare wsp_headers_pack() function to add required WSP version. * wap/wsp_server_session_machine.def: added INTEGER(encoding_version) to hold the version within the WSPMachine. * wap/wsp_server_session_states.def: populates the above sm->encoding_version with the appropriate version parsed our of the request WSP headers. * wap/wsp_session.c: added WSP encoding-version mapping functions wsp_encoding_string_to_version(Octstr *enc) and wsp_encoding_version_to_string(int version) * wap/wsp_strings.[ch]: added VSTRING() define for "versioned STRING" and VASSIGN() for "versioned ASSIGN" of the .def values. * wap/wsp_strings.def: added WSP enumeration values to the definition tables * wap/wsp_server_method_states.def, test/test_headers.c: addopted calling to wsp_headers_pack() with the version. 2003-08-27 Alexander Malysh * gw/smsc/smsc_smpp.c: added handling of intermediately delivery notifications (although we doesn't requested these). 2003-08-24 Stipe Tolj * gw/shared.[ch]: changed read_from_bearerbox() to pass double value that is passed to conn_wait() to have the call unblocked on pending connection timeout. This can be used for smsbox connections that only temporarly read messages from bearerbox. Added INFINITE_TIME define. * gw/smsbox.c, gw/wapbox.c, utils/mtbatch.c: added INFINITE_TIME to read_from_bearerbox() calls. No behaviour change. 2003-08-23 Alexander Malysh * gw/smsc/smsc_smpp.c: changed SMSC_FAIL dlr string to the form 'NACK/error_code/human_readable_string' 2003-08-23 Stipe Tolj * gw/smsbox.c: fixed segmentation fault bug in remember_receiver() when trans == NULL and urltrans_name() is called. 2003-08-23 Stipe Tolj * doc/userguide/userguide.xml, gw/smsc/smsc_fake.c: added DLR handling for fake smsc type. Now you can test DLR handling even while unattached to a real SMSC. At least in some extend. 2003-08-22 Stipe Tolj * doc/userguide/userguide.xml, gw/urltrans.c: added new escape code '%T' for sending the UNIX epoch timestamp in favor of '%t'. 2003-08-22 Stipe Tolj * doc/userguide/userguide.xml, gw/urltrans.c: added new escape code '%I' to allow inclussion of the internal SMS ID into the processing. This is a preliminary support in having unique IDs sometime of all messages entering and leaving the system. Mainly for tracing reasons accross all attached backend (application server) systems. 2003-08-22 Stipe Tolj * test/test_[dict|boxc].c: fixed compiler warnings. 2003-08-21 Stipe Tolj * gw/bb_boxc.c: fixing BUG#80, see Mantis for more detailed information on the impact of the bug and why things have to be resolved here. 2003-08-21 Stipe Tolj * test/test_boxc.c: added smsbox connection testing for BUG#80. 2003-08-14 Alexander Malysh * gw/dlr_oracle.c: fixed update statement. 2003-08-11 Alexander Malysh * doc/userguide/userguide.xml: added info for Oracle support and new config params for MySQL connection group. 2003-08-11 Stipe Tolj * test/test_dict.c: added extended huge Dict test. 2003-08-11 Stipe Tolj * gwlib/dbpool[_oracle|_p][.ch]: some source code reformating. No logic changes. 2003-08-11 Stipe Tolj * gw/wapbox.c: added re-opening of access-log file when SIGHUP is received by wapbox. 2003-08-10 Aarno Syvänen * doc/userguide/userguide.xml: Now userguide even compiles! 2003-08-08 Stipe Tolj * gw/wap-appl.c: some debug output harmonization. No logic change. 2003-08-08 Alexander Malysh * gw/smsbox.c: more info about deprecated fields in the warning strings. 2003-08-08 Stipe Tolj * gw/wap-appl.c: major bug fixing BUG#76. We *only* pass the original client request headers to the convert_content() routine, not the once passed to the HTTP server. This broke connection-less mode. 2003-08-08 Alexander Malysh * gw/dlr_mysql.c,doc/examples/dlr-mysql.conf,doc/userguide/userguide.xml: teached mysql dlr to use dbpool. * gw/dlr.c,gw/dlr_oracle.c,gw/dlr_p.h,gwlib/cfg.def,doc/examples/dlr-oracle.conf: added dlr oracle storage support. 2003-08-08 Alexander Malysh * gwlib/dbpool.[ch],gwlib/dbpool_mysql.c,gwlib/dbpool_oracle.c,gwlib/dbpool_p.h,test/test_dbpool.c, config.h.in,configure,configure.in: dbpool cleanup/rewrite. Added oracle 8i/9i support. Some parts still not ideal, but I hope that others will help me/itself to get it cleaner:) 2003-08-08 Bruno Rodrigues * utils/vimrc: example vim configuration to have 4 space tabs and no tab characters * gw/wap-map.c: removed \r chars (no DOS text files please) * gw/wap-map.c: added missing .h 2003-08-07 Alexander Malysh * gw/bearerbox.c: store_shutdown() _must_ be called after all services that make use of it are down. 2003-08-07 Alexander Malysh * gw/bb_boxc.c: do not use NULL values in debug log. * gw/bb_store.c: Fixed segfault if bearerbox going down. 2003-08-07 Aarno Syvänen * gw/smsc/smsc_http.c: Dont add drlmsk to urls when dlrs are not asked for 2003-08-06 Stipe Tolj * test/test_ocstr_dump.c: added automatic convertion from hex values in text/plain files to be converted to binary before cumping the content. 2003-08-06 Stipe Tolj * doc/userguide/userguide.xml, gw/wap_push_pap_mime.c: fixed compiler warnings. 2003-08-05 Aarno Syvänen * gw/wap_push_ppg.c: Fixed a compiler warning (a serious one). 2003-08-05 Aarno Syvänen * doc/userguide/userguide.xml: Documented last commit 2003-08-04 Aarno Syvänen * wap/wsp_strings.def: Added new application ids from OMNA web page. * test/test_ppg.c: New command line option for adding a multipart part header (for testing Content-*-headers in the content part). * gw/wapbox.c: Added default validity for wap push sms binary messages (yes we fetch this data from push control document). * gw/wap_push_ppg.c: Fixed bug reported my Juan Enriquez. Use Kannel headers to control ppg sms level. Added new application ids from OMNA page. * gw/wap_push_pap_mime.c: Removed an unused function. 2003-08-04 Stipe Tolj * gw/smsbox.c: fixed assertion bug, while having double octstr_destroy() for charet. Thanks to Aarno for pointing out to delete this. 2003-08-03 Alexander Malysh * gw/bb_smscconn_cb.h: added new enum types (SMSCCONN_SUCCESS,SMSCCONN_FAILED_QFULL) * gw/bb_smscconn.c: changed return code for bb_smscconn_receive(...) now we use enum types, so we can react with error codes in low level drivers appropriately. * gw/smsc/smsc_smpp.c: added requeuing if tcp connection was closed. As per smpp spec. required send gnack if command not supported/handled. Added more check-code for MO traffic (pdu_to_msg) so if smsc send "shit" to us, we set appropriate error code and discard such sms's. Corrected msg->sms.coding behaviour for MO messages (for LATIN-1/ASCII we set DC_7BIT instead of DC_8BIT, because DC_8BIT == BINARY DATA).Added handling of error codes if bb_smscconn_receive(...) failed. 2003-08-01 Stipe Tolj * gwlib/http.c, gw/wap-[maps|appl].c: fixed some compiler warnings. 2003-08-01 Stipe Tolj * gwlib/http.[ch]: rewrote parse_url() to parse the URL into an HTTPURLParse struct that holds all relevant components of an URL, ie. scheme, hostname, port, etc. Added therefore http_urlparse_create() and http_urlparse_destroy(). Now parse_url() is not populating given variables, but does return an HTTPURLParse pointer to the caller, so the caller can grep for the required information. Routine parse2trans() has also been added to allow internal mapping of the HTTPURLParse struct to the HTTPServer struct and the corresponding URL components. This rewrite *should* not change HTTP client behaviour. Removed unused parse_url_path() because this can be done now via parse_url() and the resulting struct. Added 'conn_time' to HTTPClient struct. This will be our future timeout reference for letting the keep-alive sessions die if a certain timeout is reached. Currently we *never* destroy reseted HTTPClient's, which is a possible security consideration. We need to implement an cleaner_thread() that drops all idle keep-alive connections. 2003-07-31 Stipe Tolj * gw/wap-maps.[ch]: removed wap_map_[url|user]_config_info(). This is done directly in the wapbox.c:config_reload() section. Reorganized user_map to be a Dict instead of a List with the userid as the hash key. This makes lookups way more faster. This should also be done with url mapping lookups, even while this is more complicated because of wildcards etc. We will implement an URLDict for this. * gw/wapbox.c: changed the wap-[url|user]-map group parsing a bit and added information output of what has been added. Fixed missing update of 'logfilelevel' while not reloaded to the given parameter in wapbox group. 2003-07-31 Stipe Tolj * gw/wap-appl.c, gw/wml_compiler.c: minor code cosmetics 2003-07-28 Stipe Tolj * test/test_http_server.c: fixed memory leak and made shutdown process now multi-thread safe via gwthread_join_all(). 2003-07-27 Stipe Tolj This is the new "rerouting feature" for bearerbox: * gw/sms.[ch]: added sms_swap() routine to swap receiver/sender number in bearerbox scope internally. Yet not used, but may be for internal rerouting of messages. * gw/bb_boxc.c: renamed route_incoming_sms() to route_incoming_to_boxc() to be more semantic in terms of the new internal rerouting abilities. * gw/bb_smscconn.c: added route_incoming_to_smsc() routine that allows to reroute MO messages to MT without leaving bearerbox scope. This is intended to "connect" SMSCs that can not pass SMS via the lower network layers, ie. SS7. By this mechanism SMPP or EMI/UCP is used to exchange messages within physically uncompatible networks. * gw/smscconn_p.h: added data structures needed to 'hold' the rerouting configuration information, where the int is a flag indicating if all MO'ed msgs from this smsc-id are passed to MT routing, the Dict holds the receiver number <-> smsc-id mapping and the Octstr holds the specific smsc-id rerouting information where all MOs are passed to. * gw/smscconn.c: added init_reroute() to pupulate smsc-id connection data for rerouting. * gwlib/cfg.def: added rerouting config directives 'reroute', 'reroute-smsc-id' and 'reroute-receiver' to multi-group 'smsc'. * doc/userguide/userguide.xml: added reroute documentation to smsc group. 2003-07-27 Stipe Tolj * gw/wapbox.c, gw/wap-appl.c: re-organized Burno's 'wap-url-map' and 'wap-user-map' mapping functions to be more modularic in the new gw/wap-maps.[ch] files. Renamed also function calls, because they are not wsp specific. * gw/wap-maps.[ch]: moved Bruno's mapping function in here to have a cleaner modularization. Don't code everything to gw/wap-appl.c. 2003-07-27 Stipe Tolj * gw/wap-appl.c: general source code cleanup, no logic change. * gw/wapbox.c: cleaned up config_reload() to use reload_foobar() wrapper functions for various types. * radius/radius_acct.c: fixed source code styling. Bruno: *grr* 2003-07-24 Bruno Rodrigues * gw/dlr.c, gwlib/cfg.def: panic if group is undefined, instead of segfaulting, for example, running "bearerbox /tmp/" * gw/wap-appl.c, gw/wapbox.c, gwlib/http.c: fixed lots of memory leaks ;) * gwlib/http.c: removed "clear values" from use_proxy as close_proxy already does that * gwlib/http.[ch]: refactored parse_url to be able to "ask" only some values, setting the others to NULL; made it public instead of static to be used by cookies.c * gwlib/http.[ch]: added parse_url_path to split rul path into base_dir, page, query_string and anchor. This will be used in cookies.c * radius/radius_acct.c: don't destroy if not init'ed, fixes a mutex panic on wapbox shutdown 2003-07-23 Bruno Rodrigues * gwlib/cfg.def, gw/wapbox.c, gw/wap-appl.[ch]: added new wap-url-map and wap-user-map groups to replace (to be) deprecated map-url map. This allows url transformation, msisdn sending and cokie handling per url * gwlib/http.c: destroy proxy values to be able reloading them; only re-set content-type if not empty on mark_transformation * gw/wapbox.c: added configuration reloading through SIGHUP (I'll implement later the same functionality in bearerbox and smsbox) for some "safe" configuration parameters: http-proxy-*, log-level, smart-errors, concatenation and max-messages (what are these?), old map-url and new url-map groups * gw/wapbox.c: defaulted sms parameters to UNDEF * gw/wap-appl.c: if device requests an HEAD, process it as usual and trim content on the end; if content is already 0 bytes, accept it and also return 0 byte "converted" content * gw/wap-appl.c: if device accepts */*, add kannel's accepts anyway; ................ * gw/wap-appl.c, wap/wsp_headers.c: added msisdn provisioning based on proxy authentication, unfortunately only supported by some devices, but it's better than nothing. Device's user and pass is matched against "wap-user-map" configuration group (later an alternative like pam) and if this fails, previous radius provisioning is tried * gw/wap-appl.c: if msisdn is discovered, new wap-url-map groups defines if it's to be sent through query_string or header, and which format to use. * gw/wap-appl.c: added info() debug for requested URL (too many debug and not one line with it ;) ) * gw/wap-appl.c: moved http_headers_remove_hop lower 2003-07-23 Alexander Malysh * gw/bb_store.c,gw/bearerbox.c: fixed segfault if no store-file is configured. 2003-07-21 Bruno Rodrigues * contrib/web/sendsms.php: removed hardcoded -way in the past- date from Wap PUSH SI 2003-07-21 Bruno Rodrigues * configure{,.in}: enabled wap cookies by default 2003-07-20 Bruno Rodrigues * : The "breaking smsbox interface compatibility" patch * WARNING: changes are: - internal values are -1 for UNDEF and 0-x, enabling 0 as an accepted value - UNDEF says that you don't care what Kannel uses, other values askes Kannel to respect your choice. for example, no "pid" argument (pid=-1) says that you don't want to include pid in pdu (unless it's required). pid=0 says that you want a pid value in pdu, with value 0 - mclass is now 0-3; coding is 0-2; alt-dcs is 0-1; mwi is 0-7 to comply with ETSI values - dlrmask and dlrurl query parameters are deprecated, but still functional; please use dlr-mask and dlr-url; flash was removed - documentation in next commit ;) * gw/msg.c: numeric sms.parameters are now defaulted to -1 (SMS_PARAM_UNDEFINED) * gw/sms.c, gw/sms.h: build fields_to_dcs and dcs_to_fields with sms parameters values in range UNDEF (-1) and 0-n * gw/smsc/smsc_smasi.c: fix (sms.parameter-1) * gw/urltrans.c: added %h for hplmn and fixed charset values * gw/smsbox.c: - as we now have msg sanitizing in msg.c, removed extra cleaning in here; - added auth-code and hplmn parameters; - now strips blanks from account parameter; - send charset in content-type; send server's date (HTTP 14.18, to be able to compare against X-Kannel-Time sms's date) when doing a POST or POST XML; - do some aditional checks on sms parameters, like rejecting some chars on account, or greater than 32 chars, checking dlr-url for http/https, dlr-mask for [-1...31]; - X-Kannel-UDH and XML's are now sent and received as url-encoded to be consistent with query-string; is also url-encoded (for binary content, for example). A test for hex is still done, so be carefull with hexadecimal strings (like "313233"); - Standardized content-type behaviour between application POST and application response. Kannel now also accepts html, wml and binary in a POST against smsbox, like it did in an application response - post-xml: fixed vp tag, added right charset to headers and * configure, configure.in: added search for stylesheets version 1.77. userguide.xml: fixed unclosed tags. 2003-07-20 Bruno Rodrigues * userguide.xml: removed chapter "Setting up wap&sms gateway" because it is redundant (and didn't say almost nothing at all), added note in "Using the gateway"; pulled sms-centers to sect1 to enable smsc sections to be available on TOC 2003-07-20 Bruno Rodrigues * configure{,.in}: --with-defaults default value is "speed" * userguide.xml: changed some strings, added others, added some features, fixed duplicate software requirements, fixed ./configure defaults (still missing some options), fixed redhat and some debian strings, Capitalized every "Kannel" reference, removed aarno hardcoded directories in examples. 2003-07-20 Alexander Malysh * gw/bb_smscconn{.c,_cb.h}, gw/dlr.[ch], gw/smsc/smsc_{at,cgw,cimd2,emi, fake,http,smasi,smpp,soap,wrapper}.c: added generic DLR_SMSC_[SUCCESS|FAIL] code. All smscs benefit from it. Advantages follow: 1) no code duplication in every smsc. 2) even fake/old smscs have now DLR_SMSC_[SUCCESS|FAIL] support for free. 3) always the same format for dlr messages e.g. "ACK/some_driver_message", "NACK/some_driver_message_or_error_code". 2003-07-20 Alexander Malysh * gw/bb_store.c: always set message id and timestamp. 2003-07-20 Bruno Rodrigues * gw/smscconn{.c,_p.h}: renamed to and to * gw/smsc/smsc.c: removed and ( alias); renamed to * gw/smsc/smsc_at.c: change comment and include directive * gw/smsc/smsc_p.h: renamed EMI to EMI_X25 and removed EMI_IP and non existant EMI_X31 * gw/smsc/smsc_emi_x25.c: removed emi_ip code * doc/userguide/userguide.xml: changed emi/emi2 and at/at2 sections and added a new appendix to include important information for upgrades 2003-07-20 Bruno Rodrigues * : The "clean up old modules and break everything" patch ;) * gw/smsc: removed smsc_at, moved smsc_at2 to smsc_at; moved smsc_emi to smsc_emi_x25 and smsc_emi2 to smsc_emi. No changes were made to these files. Kannel should be broken now until I commit other changes 2003-07-20 Alexander Malysh * gw/dlr.c: changed ugly Octstr* cast. * gw/msg-decl.h: added new fields: auth_code,hplmn. These where missed from Bruno's last commit. * gwlib/octstr.[ch]: added more const identifiers. 2003-07-20 Oded Arbel * gwlib/charset.c: fixed return value as per Bruno's suggestion * gwlib/date.{c,h}: added ISO-8601 date functions used by SOAP driver * gwlib/http.h: added "bad method" HTTP status code * gwlib/octstr.{c,h}, gwlib/html-entities.def: added HTML entities conversion functions * gwlib/utils.{c,h}: added 64 bit random generator used by SOAP driver * gw/smsc/soap.c: changed error codes to use HTTP status enum removed stubs for commited gwlib functions 2003-07-19 Bruno Rodrigues * gwlib/octstr.{c,h}: added octstr_search_chars similar to its singular cousin, but enabling to do 'error if o_s_c(string, "/\n\r\0")' * userguide.xml: added information about requiring defined smsc-id if you want to use delivery reports * gw/dlr.c: dlr_add and dlr_find returns nothing if smsc-id is empty, logging an warning asking for "smsc-id" * gw/dlr.h: added some macros to test dlr_mask values, specially now that it could have the value "-1" ;) * gw/dlr.c, gw/shared.c: now uses dlr.h macros to test dlr_mask * gw/msg.c: reset structure on msg_create(sms) to make sure that every value is in a sane state * gw/wap_push_ppg.c: accept dlr_mask=-1 and 0 * gw/sms.h, gw/smsc/smsc_*.c: uses dlr.h macros and checks for sms parameters with values -1 or 0 2003-07-18 Bruno Rodrigues * gw/wap-appl.c: Set encoding version in Via: header; also change content.charset variable if kannel does transcoding; reset map-url variables when destroying them * gwlib/charset.c: added comment 2003-07-18 Bruno Rodrigues * STATUS: moved issues to http://bugs.kannel.org to concentrate them in one unique place, where everyone (I mean, whoever is registered) can add comments, open new bugs and specially, fix them. * gw/msg-decl.h, gw/xml_shared.c: space/tabs and other cleaning up * gw/smsbox.c, userguide.xml: mo-recode now also tries to recode to utf-8 if iso-8859-1 fails * gw/smsbox.c: sanitize message for request-failed replies. This message should be a clean text message and shouldn't inherit from original message parameters like coding, pid or others. * gw/wml_compiler.c: don't even try to transcode from utf-8 to itself ;) 2003-07-18 Stipe Tolj * gw/mime_decompiler.c: fixed header comment section * gw/bb_smscconn.c: fixed an assertion while cleaning up smscconn of connections that are not present. * wap/wsp_header.h: strip_parameters() needs also to be declared 2003-07-18 Stipe Tolj * gw/wap_push_pap_compiler.[ch]: Redeclared parse_address() to make it publically available for other modules, ie. MMS encoder/decoder. * wap/wsp.h: added enum type for WSP Encoding-Version * wap/wsp_headers.[ch]: moved type definitions and declarations from .c to .h file. Redeclared some (un)pack funcitons to be publically available as wsp_(un)pack_foobar(). These are used in the MMS encode/decode module. 2003-07-17 Alexander Malysh * gw/dlr_mem.c: memory leak. 2003-07-17 Alexander Malysh * gwlib/conn.c: SSL_set_fd(...) can fail, so check return code and handle error gracefully. 2003-07-17 Alexander Malysh * gw/bb_smscconn.c: memory leak. 2003-07-17 Bruno Rodrigues * gwlib/octstr.c: octstr_dump 16 chars per line. It's impossible to decode 8 chars per line and we already have most of the other lines with more than 80 chars * gw/wml_compiler.c: encode LITERAL attribute names if there's no opcode defined. For example, multiple="true" and multiple="false" are each one encoded as one byte, but there's no multiple="" opcode. This fix encodes multiple and something as a LITERAL string correctly * gw/{wml_compiler,wap-appl}.c: changed some debug strings and removed two debugs. In wap-appl, there's no need to test body!=NULL again, and if it's tested, it should be an error, not an warning. In wml_compiler, there's no need to that debug because that value doesn't make any sense. WML is probably recoded before by my patch and will be recoded again in the end. In practice, this value was never in sync with real results and as I don't know why, it's better to not be there confusing ;) 2003-07-17 Stipe Tolj * configure[.in]: relabeled default settings to [foobar] style. * gwlib/gwmem.h: added #define gw_malloc_trace() macros to trace the caller from higher level. * gwlib/gwmem-check.c: some source beautification. * gwlib/cfg.c: fixed memory leak. octstr_destroy(file) was missing and hence for each included file we had two allocations left over in heap. * gwlib/octstr.[ch]: added #define octstr_create_from_data_trace() macro to trace caller from higher level. When running in assertion check mode this helps a lot in determining memory leak positions. This needs to be sync'ed with the octstr.[ch].debug versions. Are they still necessary? 2003-07-16 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed wrong esm_class checking for deliver_sm. 0x02 is not known value, I have not found any reference for this value. 2003-07-16 Stipe Tolj * gw/wap-appl.c, gw/wap_compiler.c: some source beautification. 2003-07-14 Bruno Rodrigues * gw/wap-appl.c: if devices doesn't support requested content-type, return 406 Not Accepted instead. This is configurable through a #define but it should be configurable in config file to be disabled by whoever wants * gw/http.h: added 406 and cleaned up 2003-07-14 Alexander Malysh * gw/sms.c: fixed active/inactive flag in dcs_to_fields. 2003-07-14 Bruno Rodrigues * gw/wap-appl.c: added multipart/form-data decompiler * gw/wap-appl.c: added preliminary and comment mms decompiler, which will require Stipe's code * gw/wap-appl.c, gw/wml-compiler.c: cleanup warnings * gw/wml-compiler.c: fix attribute values charset encoding (Closes: #37). * gw/smsc/smsc_soap.c: fix warnings by creating dummy function that would panic on call. Stipe, would you please fix this ? * gwlib/list.c: fix warning * wap/wsp_headers.c: added support for new Cache-Control wsp value; added support of well-known values to Bearer-Indication and Accept-Application * wap/wsp_strings.def: added some new wsp well-known values * wap/wsp_headers.c: added quoting to parameters, like name="foo" 2003-07-14 Bruno Rodrigues * *: fix comment style from "//" to "/* */" 2003-07-13 Bruno Rodrigues * Every comment with DAVI is a mental note for me to finish or fix that * code * gw/wap-appl.c, gw/wml_compiler.c: set wbxml version related to device's supported version * gw/wap-appl.c: added support for deconvertion, similar to existing convertion (ex: wml to wmlc), for device's POST content * gw/wap-appl.c: added preliminary application/vnd.wap.multipart.form-data to multipart/form-data; deconversion code is just waiting until I understand Stipe's mms decoding code ;) * gw/wap-appl.c: added preliminary multipart/mixed to application/vnd.wap. multipart.mixed; it's on hold because there's some other priority issues * gw/wap-appl.c: in convert_content, don't convert from x to y if x is supported by device * gw/wap-appl.c: added some debugging and body dump to debug content encoding and decoding * gw/wap-appl.c: adapts content charset to device supported charsets. For now, it only tries to convert content to UTF-8 if device doesn't support original charset but supports utf-8. This works for wml and xhtml content * gw/wap_push_ppg.c, test/wml_tester.c: fix change to wml_compile call * gw/wml_compiler.{h,c}: like wbxml version change, also send right wml version by looking at replied wml's external ID (Note: SE-T610 and others looks at wml version and if 1.1, it would ignore enctype attribute with multipart/form-data and do a POST with appl/x-www-urlencode because that attribute is wml 1.3 only) * gw/xml_shared.c: rewrote a comment to be more explicit * wap/cookies.c: removed "too verbose" debug line; removed "Version" text in cookie when its value is 0 (default) 2003-07-13 Alexander Malysh * gwlib/list.c: fixed panic about: Managed to lock the mutex twice. It occurs if list_lock(..) follows pthread_cond_wait(...) called. We lock list->single_operation_lock first (through our mutex wrapper which set mutex owner to gwthread_self()) and then pthread_cond_wait(...) unlock this mutex, but do not set mutex owner. So now we set it self. 2003-07-12 Bruno Rodrigues * gwlib/http.c: moved new variable declaration to function begining. Strange, it worked with my Debian's gcc-3.3; changed comment style 2003-07-11 Bruno Rodrigues * gwlib/http.c: added some comments * gwlib/http.c[http_header_pack]: implemented header_pack functionality to aggregate similar headers without exceed a string limit - this is required because if you have one header with all, it's too long, and if you have one header for each value it's too many headers 2003-07-07 Bruno Rodrigues * debian/kannel-cvs.docs: don't include deleted TODO * debian/rules: enabled cookies - hope they don't crash in version 1.2.x ;) * {test,utils}/.cvsignore: ignore new binaries 2003-07-02 Alexander Malysh * gw/dlr.c: fixed debug message if dlr_url was not set. gw/dlr_mysql.c: fixed a bug in missing '%s' for select statement. Thanks to John.Vandenberg@callista.com.au for pointing this. gw/dlr_sdb.c: fixed varios bugs introduced by me while rewriting of DLR code. Added workaround for Oracle (oracle doesn't like LIMIT 1). Thanks to John.Vandenberg@callista.com.au. doc/examples/dlr-[mysql|sdb].conf: added missing boxc field And again thanks to John.Vandenberg@callista.com.au. 2003-07-02 Alexander Malysh * configure.in,configure: added ability to biuld in more as one DLR storage type. Just call: ./configure --enable-mysql --enable-sdb --with-dlr="mysql sdb" in this case we have mysql and sdb support build in. 2003-07-02 Stipe Tolj * wmscript/wsstdlib.c: added support for EFI inside WMLScript. Thanks to "Guido Meyer" for this patch. 2003-06-30 Bruno Rodrigues * userguide.xml: added missing already implemented tags for XML Post - vp/delay and timing/delay 2003-06-27 Stipe Tolj * gw/wap-appl.c: enhanced the 'access-log' logging of wapbox group to have more information stored to the log entries. 2003-06-25 Alexander Malysh * gwlib/conn.c: fixed not critical memory leak. 2003-06-24 Stipe Tolj * radius/radius_acct.c: fixing mutex_lock() PANIC inside radius_acct_get_msisdn() when gw/wap-appl.c is calling the function without having the proxy thread running. This broke wapbox. 2003-06-24 Stipe Tolj * gw/wap-appl.c: removing HTTP referer inclusion by Kannel again. This has caused WAP certification tests to fail in the REFPOOL. There is a magic WML attribute which forbids to send the referer, but as Kannel does it on it's own, the tests are failing and handset manufacturers complain. * gw/wml_definitions.h: updating the tables to the latest official WAP spec. * wap/wsp_strings.def: fixing macro naming. I don't know if this matters really, but I thought of changing to lower case would be better. 2003-06-24 Alexander Malysh * gw/bb_boxc.c: fixed boxc mutex handling. We lock in box_sender but never unlock.This confuse valgrind as example and is a bug while destroying locked mutex. 2003-06-24 Stipe Tolj * gw/wap_push_pap_mime.c, gw/smsc/smsc_fake.c: some code styling * gwlib/dlr.c: fixed a output typo * gw/smsc/smsc_http.c: fixed PANIC'ing while previously destroying cgivars that are afterwards destroyed anyway in the calling function. This was for system-type 'brunet' and 'xidris'. * gw/smsbox.c: fixing bug when new 'ppg_service_name' variable is NULLed and passed to octstr_compare() causing PANIC. 2003-06-23 Stipe Tolj * gw/wap_push_pap_mime.c: fixing compiler warning, commenting routine parse_short_tail() while unused in code. 2003-06-23 Stipe Tolj * gw/smsc/smsc_[fake|http|smasi].c: added 'throughput' delaying feature. 2003-06-23 Stipe Tolj * gw/smscconn[_p].[ch]: added 'throughput' MT message per sec. limitation to abstraction layer. * gw/smsc/smsc_emi2.c: moved 'throughput' from EMI2 specific directive to abstracted directive to provide it to other SMSC client modules too. * gw/smsc/smsc_smpp.c: added 'throughput' feature to SMPP client module. * gwlib/cfg.def: moved all abstracted directives to the top of 'smsc' group 2003-06-20 Stipe Tolj * doc/userguide/userguide.xml: fixing jade compiler warnings?! 2003-06-20 Stipe Tolj * radius/radius_acct.c: fixed a bug when NAS does not provide framed IP address or caller ID (MSISDN), then discard the packet for the mapping, but do forward to the remote server. Thanks to "David Chkhartishvili" for spotting this. 2003-06-20 Stipe Tolj * Makefile.in: added compilation of RADIUS related files inside radius/. * doc/userguide/userguide.xml: new MSISDN provisioning section describing the use of the RADIUS accounting proxy thread. * gwlib/cfg.def: removed properietary groups that are *not* used inside Kannel's tree and added 'radius-acct' group configuration directives. * gw/wap-appl.c, gw/wapbox.c: added RADIUS accounting proxy related calls. * radius/*: added RADIUS accounting proxy implemenation. * test/test_radius_*.c: added some testing applications for the RADIUS routines. 2003-06-19 Stipe Tolj * gw/dlr*.[ch], gw/smsc_[soap|smpp|oisd|emi2|cimd2|cgw|at2].c, gw/bearerbox.c: Alexander's major DLR rewrite to support callbacks for the various storage types. [Msg-ID: <200306192033.01855.a.malysh@centrium.de>] 2003-06-19 Stipe Tolj * gwlib/gwthread.h, gwlib/gwthread-pthread.c: bouncing back to previous revision. Doing the required mapping inside log.c itself via #define. * gwlib/log.c: fixed Michael's reported bug for the logging functions. (this one uses a simple #define mapping for getting the table slot). 2003-06-19 Stipe Tolj * gwlib/gwthread.h, gwlib/gwthread-pthread.c: added function gwthread_table_slot() to provide the slot integer of threadtable the thread is using. * gwlib/log.c: fixed Michael's reported bug for the logging functions. 2003-06-19 Stipe Tolj * gw/smsc/smsc_emi2.c: added initialization of privdata->check_time. * gwlib/gwthread-pthread.c: added cleaner initalization of pollfds. Thanks to "Nuno Ferreira" for these. [Msg-ID: <005601c314a1$005b00c0$0b01010a@GRAYCELL.BIZ>] 2003-06-19 Stipe Tolj * gw/smsc/smsc_cimd2.c: fixed a bug inside CIMD2 module. Thanks to Per Skaglund for the patch. [Msg-ID: <1383.62.61.70.221.1054632009.squirrel@mail.dialtone.fi>] 2003-06-19 Alexander Malysh * test/test_dbpool.c, gwlib/http.c: fixed compiler warning 2003-06-19 Stipe Tolj * gwlib/octstr.c[.debug]: fixed a possible segmenation fault in octstr_url_encode() when passing an immutable Octstr. Thanks to Paul for spotting this. 2003-06-19 Stipe Tolj * doc/userguide/userguide.xml: added documentation sections for PPG DLR. Thanks to Aarno for providing the sections. [Msg-ID: ] 2003-06-19 Stipe Tolj * gw/smsbox.c: added handling of PPG related DLR reports. PPG sends SMS with DLR, but smsbox has to do the DLR signalization to the specified DLR-URL. The stored service name is read from PPG core group. * gw/urltrans.c: allow handling of NULLed URLTranslation in case it's a PPGed DLR response. * gw/wap_ppg_push_machine.def: added PPG DLR related variables. * gw/wap_push_[ota|ppg|ppg_pushuser].[ch], gw/wapbox.c, wap/wap_events.def, wap/wsp_unit.c: added PPG DLR support. * gw/smsc/smsc_http.c: added 'dlrurl' and 'dlrmask' handling for Kannel message proxying. * gwlib/cfg.def: added 'default-dlr-url', 'ppg-smsbox-id', 'service-name' to ppg core group and 'dlr-url', 'smsbox-id' to wap-push-user group. See new documentation sections for explanations. * gwlib/http.c: changed http_cgivar_dump() slightly. Again a patch by Aarno. Many thanks to the PPG maintainer ;) [Msg-ID: ] 2003-06-19 Stipe Tolj * gw/wap_push_ota.c: fixed handling of Push flag. * gw/wap_push_pap_[compiler|mime].c: fixed PPG specifier and prologue parsing to support other PIs, including delimiter parsing. * gw/wap_push_ppg.c: added missing official WINA URIs * gw/wapbox.c, gwlib/cfg.def: added 'concatenation' and 'max-messages' config directive support for wapbox group. * gwlib/http.c: fixed missing octstr_destroy()s. * test/test_ppg.c: major rewrites to support also binary content, etc. * wap/wsp_headers.c, wap/wsp_session.c, wap/wsp_strings.def, wap/wsp_unit.c: added proper WSP 'Encoding-Version' handling. Patch made by Aarno. Thanks a lot. [Msg-ID: ] 2003-06-18 Alexander Malysh * gwlib/dbpool.c: fixed compiler warning 2003-06-15 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed compiler warning 2003-06-03 Bruno Rodrigues * userguide.xml: added information about libxml2-dev packages; replace kannel.3glab.org to kannel.org 2003-06-02 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed a bug in pdu_to_msg() while extracting the UDH sequence. If the UDH length indicator was > then the message itself the octstr_copy() calls would cause PANICs to stop bearerbox. Now we discard any binary messages that don't have at least length valid UDH length indicators. Thanks to Alexander's broken SMPP server for spotting this ;)) 2003-05-29 Bruno Rodrigues * config.{guess,sub}: updated from autotools-dev 20030519.1 * userguide.xml: added missing documentation for notification-pid and notification-addr for UCP/EMI. Code patched on Aug 05 2002 * userguide.xml: added frames to y/n tables; updated at2 capabilities 2003-05-28 Stipe Tolj * gw/smsc/smsc_http.c: some fixes for system-types 'brunet' and 'xidris'. 2003-05-28 Stipe Tolj * gw/smsc/smsc_soap.c: adding new SMSC module for SOAP over HTTP from Oded and Dima from m-Wise. Yet not bound to the smsc abstraction layer. Thanks a lot! 2003-05-27 Bruno Rodrigues * doc/userguide/userguide.xml: fixes in post-xml section 2003-05-27 Stipe Tolj * gw/smsc/smsc_cimd2.c: Fixing wrong time for messages. Thanks again to Angel for this fix. 2003-05-27 Stipe Tolj * gw/smscconn_p.h, gw/smscconn.c, gw/smsc/smsc_at2.h, gw/smsc/smsc_[at2|cimd2|smpp].c: Angel's alt-dcs abstraction layer patch for at2, cimd2 and smpp. Thanks a lot. [Msg-ID: ] 2003-05-27 Stipe Tolj * gw/shared.c, gw/smsbox.c: fixing mainly BUG#24 for sending too long UDH indicator sequences. This does not cover the effect, when UDH is pretty long and Msg body is getting split and hence the UDH gets prepended with the UDH sequence numbers. At least this fix ensures that octstr_copy() inside sms_split() does not panic. Patch based on post by "Oleg Titov" . [Msg-ID: <198463211.20030505104734@aleph-tec.com>] 2003-05-26 Alexander Malysh * gw/bearerbox.c: bugfix from previous commit. 2003-05-26 Alexander Malysh * gwlib/cfg.[ch], gw/bearerbox.c, doc/userguide/userguide.xml: added new command line option ("-g" or "--generate") to bearebox. This option just dump all known config groups and options to stdout. Later (if we have module API) we can dump default values also. 2003-05-24 Alexander Malysh * gwlib/octstr.[ch]: Made functions arguments const, then it's clear for caller whether we manipulate arguments. 2003-05-24 Bruno Rodrigues * contrib/mon/kannel.monitor: applied fix from Dariusz Markowicz <00a301c321fa$08edab00$d4e34cd5@oem> 2003-05-19 Stipe Tolj * gw/smsc/smsc_http.c: fixed compiler warning 2003-05-16 Stipe Tolj * gw/smsc/smsc_http.c: fixed parse_xml_tag() function. This may be of abstractive use inside gwlib/octstr.[ch]?! 2003-05-16 Stipe Tolj * doc/userguide/userguide.xml: added 'xidris' to HTTP SMSC system-type values. * gw/smsc/smsc_http.c: added Xidris HTTP interface as system-type 'xidris'. Yet not tested against server. 2003-05-15 Stipe Tolj * gwlib/md5.[ch]: added md5digest() function to return the raw 16 bytes of the hashed value. * gw/smsc/smsc_http.c: bruNET MT needs a 32 byte transaction id. Hence we use MD5 to generate an transaction id. * gw/smsc/smpp_pdu.c: removed assetion checking inside parsing function. bearerbox should not panic on malformed PDU packets. 2003-05-04 Bruno Rodrigues * debian/*.init: fix bug (Closes: #25) 2003-04-29 Stipe Tolj * gw/smsc/smsc_emi2.c: login operation 60 had a hard timeout of 30 sec. Some SMSC may need longer to ACK the login, so use the 'wait-ack' time value here too in case it's larger then 30 sec. 2003-04-25 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed cheking of esm_class for DLR's. Following SMPP v.3.4. spec., we should check only bits 2-5. 2003-04-24 Alexander Malysh * gw/smsc/smsc_smpp.c: added using of smpp_error_to_string function for error log entries. 2003-04-24 Alexander Malysh * gwlib/md5.[ch]: fixed compiler warnings about static functions. 2003-04-24 Alexander Malysh * gw/smsc/smpp_pdu.c: fixed typo in error message. 2003-04-24 Alexander Malysh * gw/smsc/smpp_pdu.[ch],gw/smsc/smsc_smpp.c: Moved SMPP error codes enum to smpp_pdu.h. Added additional error codes. Added new function smpp_error_to_string(...), so if error occurs we can log fully error string and we have no need to looking in SMPP spec. 2003-04-22 Stipe Tolj * gwlib/gwlib.h: added md5 header inclusion. * gwlib/md5.[ch]: added MD5 message digest algorithm. This may be used in various places, including computation of unique IDs etc. * test/test_md5.c: added simple testing program. 2003-04-17 Stipe Tolj * configure[.in]: removed checking of libiconv.a. Some systems, like Linux contains iconv functions inside glibc. We check the for the header only. * configure[.in]: seems I'm wacky today. Of course we need the checking still, otherwise systems that need linking against the lib will fail the build process, ie. Cygwin. So I'm adding this again, but without explicite warning message. 2003-04-17 Stipe Tolj * gw/smsc/smsc_http.c: fixing a missing urldecode in brunet_send_sms(). * gw/smsc/smsc_http.c: fixed minor issue in brunet_send_sms(). 2003-04-16 Stipe Tolj * utils/mtbatch.c: added MT batch utility. This application connects to bearerbox via smsbox interface and sequentially sends a pulk of MT messages to a speficied range of receiver numbers. Currently 7-bit only. * Makefile.in: added utils/mtbatch.c to the make process. 2003-04-15 Stipe Tolj * gw/smsc/smsc_http.c: harmonized smsc output to be in same style as others. Fixed expected MO parameters to 'username' and 'password' instead of 'user' and 'pass'. Now you can use the smsc_http module to loop messages from MT to MO direction. See new user's guide section. * doc/userguide/userguide.xml: added new 'MT to MO direction switching' section to illustrate how to use HTTP SMSC module to achive this. 2003-04-14 Alexander Malysh * gw/smsc/smsc_emi2.c: fixed c&p typo. 2003-04-14 Stipe Tolj * gw/smsc/smsc_http.c: added new bruHTP 2.1 version and using account field for cgi var proxying inside the module. 2003-04-14 Stipe Tolj * gw/smsc/smpp_pdu.c: removed gw_assert() checking within smpp_pdu_pack() in order not to crash bearerbox. Thanks to for point this out again. * gwlib/octstr.[ch][.debug]: added two new functions: octstr_is_all_hex() to check if given Octstr* is in hex notation and octstr_delete_matching() to delete matching segments within an Octstr*. Thanks to Aarno for providing these implementations. 2003-04-08 Bruno Rodrigues * debian/*: more updates - update Standards to 3.5.9; build "-docs" packages as arch independent to have debian build system generate only one -docs package and kannel* and kannel-extra* packages for every architecture; updated conflicts - kannel, kannel-devel and kannel-cvs conflicts but -docs and -extras don't :) You can have all documentation installed at the same time, but only one kannel instance 2003-04-08 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed some more typos. Thanks again to "Rachman Chavik" for this. * contrib/mon/kannel.monitor: fixing problems for perl 5.8.0 release with reference hashes. Thanks to "Dariusz Markowicz" . 2003-04-07 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed an obivious typo. Patch provided by "Rachman Chavik" . Thanks a lot. 2003-04-06 Stipe Tolj * configure[.in]: fixed a bug from previous commit. 2003-04-06 Stipe Tolj * configure[.in]: fixing BUG#18, which caused to break the build process if mysql had library dependencies (ie. -lz) because they where not included in the last stage linking process. Now we try to detect via mysql_config which libraries should be added. 2003-04-05 Bruno Rodrigues * debian/*: syncronized with .diff files * debian: now defaults to generating a kannel-cvs package for building daily snapshots. To build stable or devel, rename {changelog,control}.{stable,devel} to {changelog,control} * debian/.cvsignore: also ignore kannel-cvs temporary directories * debian/*.postinst: fixed chown /var/run bug * config.{guess,sub}: updated to new files - hope it won't break anything * gw/sms.c: also set alt_dcs=0, improvement to Alexander patch at Mar 04 * Note: kannel 1.2.1 and 1.3.1 are about to enter debian :))))) 2003-04-05 Stipe Tolj * gw/smsc/smsc_http.c: fixed compiler warning. 2003-04-04 Stipe Tolj * test/test_headers.c: changed to take an argument as filename instead of the hard-coded filename. * test/test_http_server.c: more -? output added and added a -r option to define which static reply text should be in response. * gw/smsc/smsc_http.c: fixed a number of bugs. Including bearerbox crash if smsc-id is stopped and /status page is called. Restructured IO threads to work cleanly now, which means don't 'fail' a MT message when the HTTP server can not be triggered. Instead use 'reconnect-delay' to try again. Aded also another 'system-type = brunet' for an implemenation of Brunet's HTTP interface. 2003-04-03 Stipe Tolj * test/test_octstr_dump.c: added a simple tester for octstr_dump(). Takes one argument, opens the file, reads the content and dumps the content using octstr_dump(). 2003-04-03 Stipe Tolj * gwlib/http.[ch]: added http_get_header_parameter() function to return a specific parameter value for multi-parameter headers. * doc/userguide/userguide.xml: added section about new 'no-dlr' for CIMD2. * gwlib/cfg.def, gw/smsc/smsc_cimd2.c: added new 'no-dlr' config directive to indicate if DLR requests should be proceeeded for a CIMD2 connection. This *should* be abstracted for all SMSC types in the next future! Thanks to "Dziugas Baltrunas" for the patch. [Msg-ID: ] 2003-04-01 Alexander Malysh * configure.in, config.h.in, gwlib/protected.c: added check and using for reentrant functions (localtime_r,gmtime_r) in gw_localtime,gw_gmtime. In case of existing and using this functions, we avoid locking. 2003-03-31 Stipe Tolj * gw/smsc/smsc_cimd2.c: re-patching Angel's fix from 2003-03-27. 2003-03-31 Stipe Tolj * gwlib/http.c: fixing a serious bug in the HTTP client code causing smsbox to crash if the connection is closed directly by the HTTP server. Thanks to "Michael Mulcahy" for a fix! [Msg-ID: <000a01c2f555$6c920790$6100a8c0@synge.anam.com>] 2003-03-29 Stipe Tolj * gw/smsc/smsc_emi2.c: fixed a typo for 'wait-ack-expire' handling. Thanks to Angel who reported this. 2003-03-28 Stipe Tolj * gwlib/http.c: fixed a bug while HTTP redirecting (BUG#12). Also added HTTP response code 307 for redirection. Some source code formating. Thanks to Angel for reporting and providing a fix ;) * test/test_http.c: allow client to follow HTTP redirects. * test/test_http_server.c: added a special URI /redirect/ that can be used to test the redirection handling and reorganized the thread to be more clean. 2003-03-28 Stipe Tolj * gw/wap_push_pap_compile.c: fixing a *possible* inconsistence with PAP and PPG specs. The constants "WAPPUSH" and "TYPE" should?! be in upper case as defined in specs. But the specs also use examples with lower case, so we'll handle both for the sake of interopertibility with existing PI vendors. Thanks to "Ritesh Shah" for reporting this. [Msg-ID: <094b01c2f516$175e3210$6b0110ac@ritesh>] 2003-03-27 Alexander Malysh * gw/smsbox.c: added temporarily fix to smsbox that "handle" ack messages from bearerbox, so user will not be confused with warning about not handled messages. 2003-03-27 Stipe Tolj * gwlib/log.c: fixing possible seg fault bug while re-opening "shared" log files. Thanks to Alexander for this patch. 2003-03-27 Stipe Tolj * doc/userguide/userguide.xml: added CIMD2 specific documentation for Angel's latest CIMD2 re-design patch. * gw/smsc/smsc_cimd2.c: Angel's fix for CPU load consume while idle and minor changes. [Msg-ID: ] 2003-03-27 Stipe Tolj * gw/smsc/smsc_at2.c: added an 'error' warning in case we can't decode the PDU sequence. Thanks to "Bas A. Schulte" for giving us a hint here. 2003-03-27 Stipe Tolj * gw/msg.h, gw/bb_boxc.c, gw/[bearer|sms|wap]box.c: added Alexander's restarting patch to allow sending restart command within Kannel's internal communication. [Msg-ID: <200303222057.12928.a.malysh@centrium.de>] 2003-03-25 Stipe Tolj * gw/smscconn[.c|_p.h], gw/smsc/smsc[.c|_p.h]: this is a rewrite of the CIMD2 module to be addopted to the new SMSCConn API layer. Thanks to Angel for sending this patch. * gw/smsc/smsc_cimd2.c: Added additional support features: 'our-host', 'our-port' and parameter 069 (service center address) have been added. Harmonzied log message formating. BEWARE: there are also COMPATIBILITY BREAKERS: Harmonized 'my-number' directive, this makes 'sender-prefix' absolete. Interpretation of 'keepalive' is now in seconds instead of minutes. [Msg-ID: ] 2003-03-25 Stipe Tolj * Makefile.in: fixing Bruno's delete commit that caused config.sub and config.guess to dissapear after a 'make distclean'. They are part of configure and have been produced while autoconf did all it's magic. Thanks to Alan for this hint. 2003-03-21 Stipe Tolj * gw/smsc/smsc_emi2.c: fixed a re-connection bug cause by last commit. Thanks to Angel for this one. [Msg-ID: ] * utils/makedist: added creation of bzip2 tarball and md5 sums. 2003-03-21 Stipe Tolj * gwlib/log.c: fixed a possible bug, when a logging file is opened twice. Now we search for the filename in the open table and simply pass the file descriptor of that already opened log file to the new logger. Thanks to Alexander for this patch. 2003-03-20 Stipe Tolj * gw/wap_push_ppg[_pushuser].c: fixed BUG#8. Reported by Bas A. Schulte. 2003-03-20 Stipe Tolj * gw/wap_push_pap_compiler.c, wap/wap_events.def: fixed none accepted attribute 'product-name'. Thanks to "Bas A. Schulte" . [Msg-ID: ] * test/test_pap.c: added return code output in case pap_compile() fails. 2003-03-20 Stipe Tolj * doc/userguide/userguide.xml: added 'reconnect-delay' to the higher smsc group abstraction documentation and deleted 'retry' from emi2 and at2. 2003-03-20 Stipe Tolj * gw/wap_push_ppg.c: fixed malformed xml reponses for the PAP document. Thanks to "Bas A. Schulte" for this patch. [Msg-ID: <98D28678-5A1E-11D7-8DAC-000393059670@zeelandnet.nl>] 2003-03-19 Stipe Tolj * gw/smsc/smsc_smpp.c: moved 'reconnect-delay' also to the higher layer. 2003-03-19 Stipe Tolj * gw/smsc/smsc_smpp.c: added UDH support for MOs. Thanks to David White for this patch. [Msg-ID: <3E770BA2.5030701@i-one.at>] * gw/smscconn[.c|_p.h]: moved smsc group config directive 'reconnect-delay' into higher abstraction layer to provide this for all SMSC modules. Reconnect delay is defaulting to 10 sec. * gw/smsc/smsc_[at2|emi2|smasi].c: changed reconnecting behaviour to use value in the abstraction layer. Thanks to Angel for his patch here! * gwlib/cfg.def: removed no more needed 'retry' smsc group directive. This is now handled via the more abstracted 'reconnect-delay' value. 2003-03-19 Stipe Tolj * gw/wml_compiler.c: fixed compiler warning. 2003-03-18 Stipe Tolj * test/test_http_server.c: added a special URI /save which causes to save the received body of a POST request to a temporary /tmp/body.. file. This may be used for analyzing MMS related POST requests. 2003-03-17 Stipe Tolj * gw/wap-error.[ch]: added error_converting() for reporting smart error messages if the converter failed, ie. libxml2 parser failed because of non-indicated encoding in the xml source. * gw/xml_shared.[ch]: added find_charset_encoding() to scan the xml preamble line, ie. and extract a given charset encoding definition if available. * gwlib/octstr.h, gwlib/dbpool.c: cosmetic fixes * gw/wml_compiler.c: make wml_compile() more "inteligent" concerning the encapsulated charset encoding in the xml source. This also fixes BUG#6. The problem was/is that the HTTP reponse header can deliver a charset definition and the xml preamble. So we cascade now as follows: If xml preample has an encoding specified, this overrides the HTTP reponse header, if not we take the HTTP reponse header if available. If both are not available, we assume UTF-8 as default encoding charset. The charset information is stored in the libxml2 document tree and re-used afterwards while text elements are parsed and transcoding to the targeted charset has to be done. * gw/wap-appl.c: added smart error messaging if converters failed while converting or compile a supported content-type, ie. a WML compilation failed. 2003-03-13 Stipe Tolj * gw/smsc/smpp_pdu.c: Alexander's patch for fixing optional SMPP 3.4 parameter parsing. Thanks a lot. [Msg-ID: <200303121404.42328.a.malysh@centrium.de>] 2003-03-13 Stipe Tolj * doc/userguide/userguide.xml: removed no-longer necessary 'force-sar' diretive, fixing BUG#7. 2003-03-11 Stipe Tolj * gwlib/dbpool.[ch], test/test_dbpool.c: implements database connection pools for further use within Kannel. Currently MySQL is supported. More abstraction for various other DBMS is needed. 2003-03-11 Stipe Tolj * gw/bb_boxc.c, gw/bb_smscconn.c, gw/msg.h, gw/smsbox.c: added Alexander's ACK/NACK patch to provide smsbox connections with accurate ACK'ing data. [Msg-ID: <200303092018.30806.a.malysh@centrium.de>] We'll have to decide now on how to react on inbound ACK messages within smsbox. 2003-03-09 Stipe Tolj * gw/bearerbox.c: while we receive SIGHUP we shouldn't re-load the store file, because we'd duplicate currently stored messages. Patch provided by Alexander. * contrib/kannel-monitor/index.php: some date calc fixed. Thanks to Alex. * gwlib/octstr[.ch|.debug]: added Alex's octstr_item_case_match() function. 2003-03-09 Stipe Tolj * configure[.in], config.h.in, gw/bearerbox.c: added --disable-wap and --disable-sms configure switches to disable parts in bearerbox.c. In an extended step these could be used to make a conditional compile process, where the whole WAP gateway libs don't need to be generated. * gwlib/conn.c, gw_bb_store.c: minor debug message beauty. * gwlib/http.c: opening an HTTP server should be 'info' log level. 2003-03-07 Stipe Tolj * gwlib/http.c: fixed the previous kludge by a clean solution. We call parse_url() only once to populate the trans values. Added also dumping of the HTTP response. Can be turned of by switching of an #define. 2003-03-07 Bruno Rodrigues * Makefile.in: re-added make tests (closes: #3) * Makefile.in: clean automatic generated config.sub and config.guess in make distclean 2003-03-07 Stipe Tolj * contrib/kannel-monitor/index.php: some minor changes contributed by Alexander. * gwlib/http.c: fixed (kludge?!) a HTTP basic auth problem with the passwd. Bruno substitues this with stars, I don't know why. 2003-03-06 Stipe Tolj * contrib/kannel-monitor/*: a simple php application to summerize sms traffic accross several bearerbox instances, including automatic refresh and admin command support. 2003-03-06 Stipe Tolj * gwlib/log.c: fixed compiler warning. * gw/smsc/smsc_smpp.c: fixed a charset encoding misbehaviour when msgs get split into multiple sms chunks. Now also the chunked, single msgs get passed to the charset encoding. Thanks to "Benjamin Lee" for this. 2003-03-05 Stipe Tolj * gwlib/octstr.c[.debug], gwlib/log.c: fixed some compiler warnings. 2003-03-04 Stipe Tolj * gw/smsc/smsc_smasi.c: some minor cosmetic changes. 2003-03-04 Stipe Tolj * doc/userguide/userguide.xml: added smsc based logging directives * gw/wapbox.c, gw/smsbox.c, gw/bearerbox.c, test/drive_smpp.c, test/test_http_server.c, test/test_pap.c, test/wml_tester.c, gwlibs/utils.c: added the GW_NON_EXCL flag to the new log_open() call. * gw/smscconn.c, gw/smscconn_p.h, gwlib/cfg.def : added 'log-file' and 'log-level' as smsc global config directives. * gwlib/gwlib.c: gwlib_init() calls now log_init() too, in order to initialize the index mapping array. * gwlib/log.[ch]: added smsc specific logging capability by handling open log files in exclusive or non-explusive mode within the open log file array. Added log_thread_to() function to allow a working thread to register to a specific exlusive log file. * gw/smsc/smsc_[at2|cgw|emi2|fake|http|smasi|smpp|wrapper].c: added register calls log_thread_to() within the working threads in case the smsc-id should be logged to a separate, exlucive log-file. 2003-03-04 Stipe Tolj * gw/smsc/smsc_smasi.c: fixed bugs in pdu_to_msg(), including the setting of 7bit coding to have normal text logged in access.log. * gw/bb_boxc.c: added missing smsbox-id output to XML tree of /status.xml. * gw/sms.c: fixed alt_dcs re-coding misbehaviour. Reported by Alexander. * gwlib/conn.c: cosmetic changes 2003-03-04 Stipe Tolj * gwlib/octstr.[ch|debug]: added some more functions provided by Nisan. [Msg-ID: <5.1.0.14.0.20030304085848.026b6020@amagoblin.ialien.co.za>] * gwlib/conn.[ch], gwlib/http.c: fixed a serious pthread_mutex bug for the call-back function to the openssl thread locking. We used two separate lock array, one for the client and one for the server side. But openssl does not know about those, and you can't register two different call-backs for client/server side. This should make now a lot of ssl related things more cleaner. 2003-02-28 Stipe Tolj * gwlib/log.c: fixed minor problems from last commit. Thanks to Angel. 2003-02-27 Stipe Tolj * doc/userguide/userguide.xml: move 'our-host' from SMSC specific config sections to global SMSC section and added HTTP admin command 'loglevel'. * gwlib/log.[ch], gw/bb_http.c: added HTTP admin command 'loglevel' to change log-level of log-files while bearerbox is running. Patched submited by Angel. Slightly modified by me. [Msg-ID: ] 2003-02-27 Stipe Tolj * gw/smsc/smsc_smpp.c: adding handling of invaid userid and/or passwd to shutdown SMSC connection rather then retrying to reconnect. Thanks to Alexander for this patch. [Msg-ID: <200302271127.55572.a.malysh@centrium.de>] 2003-02-27 Stipe Tolj * configure[.in]: added checking of --[enable|disable]-docs switch. Thanks to Alan for the reminder and the patch. * gw/smscconn_p.h, gw/smscconn.c, gw/smsc_[smpp|smasi|http|fake|emi2|cgw].c: Added 'our-host' interface support for binding to an explicite interface on SMSC connections. Patch provided by Angel. [Msg-ID: ] * gw/dlr.c: memory leak fix. Thanks to Alexander for pointing to this. 2003-02-24 Stipe Tolj * doc/userguide/userguide.xml: entry about 'restart' command * gw/bearerbox.c, gw/bb_boxc.c, gw/bb_http.c: admin HTTP command 'restart' added to restart bearerbox. Patch by Alexander. [Msg-ID: <200302222202.55347.a.malysh@centrium.de>] 2003-02-23 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed a mistakely deleted increament of msg_id_counter in smpp_create() for sequence_numbers starting 0x0000001. 2003-02-21 David Holland * gw/smsc/smpp_pdu.def: fixed generic_nack definition (thanks to Alexander Malysh) 2003-02-18 David Holland * gw/smsc/smsc_smpp.c, gwlib/cfg.def, doc/userguide/userguide.xml: added facility to specify SMPP SMSC service type with 'service-type = "foo"' syntax (thanks to Nick Clarey) 2003-02-18 Stipe Tolj * gw/smsc/smsc_smasi.c: fixed typo bug in reading the TON and NPI config directives for the SM/ASI module. 2003-02-17 Stipe Tolj * Making development release 1.3.1. gateway-1.4.5/doc/release.txt0000644000175000017500000000416513312227265014623 0ustar toljtoljSteps to follow when making a release of the gateway; if there is a problem, fix it, and re-start from beginning: * Decide on the version number. * Prepare the software for release. * Make sure everything is committed to SVN trunk. * Make sure everything is working. * Run "make -s check" * Test with a real phone. * Make sure documentation is up to date. * Make sure NEWS is up to date. * Add an entry to ChangeLog that says you're making release such and such. * Branch SVN trunk to branches/stable_X_Y_Z for packaging. * Update in branches/stable_X_Y_Z file VERSION to have the version number you want. * Bootstrap a checkout of branches/stable_X_Y_Z on dedicated distro. Currently we're using Debian 8 (amd64). * Add file compile, depcomp, ltmain.sh and missing. * Commit VERSION, and all modified/added files after bootstrapping. * Tag the release from branches/stable_X_Y_Z to tags/version_X_Y_Z. * Use tag/version_X_Y_Z is used for distribution tarball packaging. * Make distribution files. * Use "makedist" script, with the version number as argument. Run it in an empty directory, not directly from the SVN checkout directory. * Put new files on www.kannel.org, and otherwise update the site to reflect the new release. * makedist output goes in ~kannel/public_html/download/$V, where $V is the new version number. * Use the www.kannel.org SVN repository to change the html files, and checkout in the corresponding htdocs directory after committing. * Announce new version on index.shtml, and describe it on news.html. Include an extract from the NEWS file. * Change the links in download.shtml, and update the "Old versions" section. * Check changes locally before committing. Note, this will not work for the links on the download page. * Send out the announce to appropriate places. Remember to set Reply-To to the devel list. Include an extract from the NEWS file. * announce@kannel.org * linux-announce@news.ornl.gov (not for all versions) * Freshmeat (not for all versions) gateway-1.4.5/doc/ChangeLog-1.4.10000644000175000017500000020574410505736755014673 0ustar toljtolj2006-09-25 Stipe Tolj * gw/ota_prov.c, gw/ota_compiler: adding support for SyncML settings via OTA provisioning according to Nokia/Ericsson OTA spec. * doc/userguide/userguide.xml: adding section about SyncML OTA. Patch provided by Adrian Silva , thanks a lot. [Msg-Id: ] 2006-09-24 Stipe Tolj * test/test_http_server.c: fix compiler error for gcc 2.95.x due to a non first declaration of variables inside a if block. Thanks to Ben Suffolk for reporting and patching. [Msg-Id: <9D37D8D9-ABA6-45B9-AB54-F687A46952BA@vanilla.net>] 2006-09-24 Stipe Tolj * gw/bb_store.c: fix the "never dump store" behaviour in store_dumper(). The if condition garantees that we don't need to dump the store if nothing happened while we have been sleeping, but it arrises a problem when we are under constant high load: we would never dump the store. In case the difference between now and last dict operation is constantly lower then the dump frequency, then we never enter the if conditioned block and hence never dump, resulting in the effect that we never remove "old" messages from the store that have been ACKed and are removed while the new dump is generated. Now we introduce a busy flag that garantees that we do dump in case we're under constant load, but not if we really haven't done anything. 2006-09-19 Stipe Tolj * gw/smsbox.c: make sure we duplicate the smsc-id value for any reply msg struct passing back to bearerbox for MT transport. This would otherwise break certain routing setups where smsc-ids are needed. 2006-09-14 Stipe Tolj * test/test_store_dump.c: adding a simple test tool to msg_dump() the contents of a store-file. * test/test_list.c: adding a simple List object tester. * test/test_http_server.c: add a URI /mmsc to act as a MM1 interface HTTP server and reply with a M-Send.conf PDU when MMS client is sending a HTTP POST with the M-Send.req PDU. Only for testing and capturing purposes. * test/test_conn.c: add generic connection type tester. 2006-09-09 Stipe Tolj * gw/smsbox.c: fixing POST XML handling, where sender address was not parsed from the XML. Thanks to Francesco Emmi for the patch. [Msg-Id: <44FCB05F.9010004@tolj.org>] 2006-09-03 Stipe Tolj * gw/other_smskannel.conf: fixed deprecated option for fakesmsc's port to -r instead of old -p. Thanks to Tiago PC for reporting this. [Msg-Id: <2055f52c0609041159w72da5467g23ca3bb1da6f17dd@mail.gmail.com>] 2006-08-28 Stipe Tolj * gwlib/semaphore.c: type fixes. NLC. Thanks to Vincent for the catch. [Msg-Id: <02c201c6ca8f$ce465e10$9600a8c0@vince>] 2006-08-28 Stipe Tolj * gwlib/cfg.def, doc/userguide/userguide.xml, gw/smsbox.c: adding config directive 'max-pending-requests' for smsbox group to control the outbound requests stream generated from smsbox towards HTTP application servers. Thanks to Giulio Harding for doing detailed analysis and problem report. Patch provided by Alex. [Msg-Id: ] 2006-07-23 Stipe Tolj * gwlib/dbpool.h, gwlib/dbpool_sqlite3.c: fixing naming scheme to reflect the sqlite3 version. 2006-07-23 Stipe Tolj * gwlib/cfg.def: add multi-group 'sqlite3-connection' to be used for various usage of sqlite3 support of dbpool. 2006-07-12 Alexander Malysh * doc/userguide/userguide.xml, gw/smsbox.c, gwlib/cfg.def: applied patch that adds two new config options to smsbox group: bearerbox-port and bearerbox-port-ssl. This patch should help external modules at least sqlbox now. 2006-07-07 Stipe Tolj * gw/smsc/smpp_pdu.c: added a new string for smpp_error_to_string() indicating that we have a value in the vendor-specific range. NLC. * gw/smsc/smsc_http.c: changed email reference. NLC. 2006-07-05 Stipe Tolj * gwlib/cfg.[ch]: adding support for hooking config group definition files as our own gwlib/cfg.def from external add-on modules to the core via cfg_add_hooks(), taking two function arguments within the local scope of the external module, representing the is_allowed_in_group() and is_single_group() from the core. In the local scope the external .def file is included as we do in the core. The purpose of this cfg_add_hooks() function is to allow add-on modules to use seamlessly the core's cfg.c code for semantical config checks at startup. 2006-07-05 Stipe Tolj * gwlib/http.c: fixing bug #326, which causes panic in check_pool_conn() when using HTTP/1.1 keep-alive connections, hence the dict_get() lookup returned a NULL and we pass this list untested to gwlib_delete_equal() which causes the panic. Thanks a lot to Vincent and Martin on solving. 2006-06-13 Stipe Tolj * gw/smsc/smsc_smpp.c: fixing bug report #334, actually this is a feature to auto-detect if we have hex values for the message id in submit_sm_resp vs. DLR messages via a if OR statement. Thanks to Martin Conte for this patch. [Msg-Id: <92cf04420606040932k3ae8b166of0d111f9e825f4ca@mail.gmail.com>] 2006-06-12 Stipe Tolj * doc/userguide/userguide.xml: adding a paragraph descibing the new line wrap delimiter '\' (backslash). * gwlib/cfg.c: adding support for a line wrapping delimiter '\' to allow multiple lines for a single config directive. Alex suggested this via a patch to the list. [Msg-Id: ] 2006-06-11 Stipe Tolj * wap/wtp_init.c: fixing bug #350, typo which may cause a segfault. Thanks to for bug report and patch. 2006-06-06 Alexander Malysh * configure, configure.in: fixed net/if.h detection on Mac OSX. 2006-06-03 Alexander Malysh * gwlib/xmlrpc.c: various fixes: - write tags for empty string - extra chars in string should be replaced with http entities - don't panic if i in xmlrpc_get_param bigger as count of method call params 2006-06-03 Alexander Malysh * configure, configure.in: switched to autoconf 2.5 and added check for large file support. 2006-06-01 Stipe Tolj * gw/smsc/smsc_smpp.c: fixing bug #345, causing long overflow on 32 bit systems while processing message id values from submit_sm_resp PDU that are in hex representation. Thanks a lot to Ady Wicalsono for report and provided solution via patch in bug database. [Msg-Id: <446C4175.6090802@infokom.net>] 2006-06-01 Stipe Tolj * gw/smsc/smsc_smpp.c: adding possible alternative for DLR message state string for state 'buffered'. Thanks to Tom Sommer for providing a patch. [Msg-Id: <20558.62.242.67.218.1148906304.squirrel@webmail.dreamcoder.dk>] 2006-05-23 Alexander Malysh * gwlib/gwthread-pthread.c: don't panic if new thread could not be started. This bug easy triggered when process runs out of file descriptors. 2006-05-23 Alexander Malysh * gw/smsc/smsc_at.c: fixed wrong condition for octstr_len(temp). Thanks to Andrija Petrovic for patch. [Msg-Id: <446B1C5B.50500@software888.com>] 2006-05-15 Alexander Malysh * doc/userguide/userguide.xml, gw/smsbox.c, gw/smsc/smsc_smpp.c: applied patch that changes internal charset from iso-8859-1 to windows-1252. This patch changes not the whole kannel to use windows-1252 but we want to change to UTF-8 as internal charset anyway and this patch could be seen as a temporarely workaround that allows sending/receiving of euro sign. Thanks to Peter Christensen for the patch. [Msg-Id: <4461EA8F.5040806@coolsystems.dk>] 2006-05-14 Stipe Tolj * gw/bb_smscconn.c: fixing bug #341, causing not to obey 'sms-resend-retry' for messages that are temporary failing. Thanks to Martin Conte for provided patch. [Msg-Id: <92cf04420605130116h7ea562aew7c2ec7ded92dfb1e@mail.gmail.com>] 2006-05-11 Alexander Malysh * gw/smsc/smsc_at.c: Added sanity check on digits before calling the octstr_append_char. smsc_at does not check the digits of the address field in the function at2_format_address_field. So, if the recipient's address contains a non-numeric string (e.g. 'Info Service'), and that's quite possible, the octstr assertion crashes the bearerbox during octstr_append_char. Thanks to Andrija Petrovic for provided patch. 2006-05-11 Alexander Malysh * gw/smsc/smsc_http.c: - Returning HTTP_OK status code 200 when receiving an MO from clickatell - Returning HTTP_BAD_REQUEST status code 400 is sent when "Insufficient arguments, rejected" - fixed compiler warnings about unused variables - changed info to debug about "received mo" Thanks to Vincent CHAVANIS for patch. 2006-05-09 Alexander Malysh * gw/smsbox.c: applied patch which resolved a number of memory leaks and potential segmentation faults in the smsbox_req_handle. Thanks to Peter Christensen for provided patch. [Msg-Id: <445DFAFC.6030807@coolsystems.dk>] 2006-05-09 Alexander Malysh * doc/userguide/userguide.xml,gw/smsc/smsc_smpp.c,gwlib/cfg.def: added new SMPP config options 'bind-addr-ton' and 'bind-addr-npi' in order to be able to define bind settings that some SMSCs require. 2006-05-09 Stipe Tolj * Makefile.in: make sure we do NOT link in object files from the progs itself, they contain int/void main(), and we don't want that inside the libgw.a in order to allow users re-usage of the code inside the lib. Otherwise we would get a 'duplicate define main()' link error, if an external module tries to link against libgw.a after a successfull install. 2006-05-09 Stipe Tolj * gw/bb_store.c, gw/bearerbox.[ch]: detach the two queues 'incoming_sms' and 'outgoing_sms' from the binding of bb_store.c. Now we pass a dispatcher function as argument to store_load() in order to let it access local scoped variables in the callers space. 2006-05-08 Stipe Tolj * Makefile.in: adding installing of all .h and .def files in the install target, including the gw directory. This is required if external modules implementing own functionality will use gwlib and gw functions that are installed to the system. 2006-05-05 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed #337. We must set RECONNECT status on connection before we put local queued messages into global queue. Thanks to for patch. 2006-04-28 Alexander Malysh * gwlib/list.h: added example to the comment how to use gwlist_sort function. Thanks to Wilfried Goesgens for patch. 2006-04-28 Alexander Malysh * gw/smsbox.c: fixed memory leak. Thanks to Rafael for patch. [Msg-Id: <44510365.8070000@atgcaribbean.com>] 2006-04-24 Andreas Fink * gw/smsc/smsc_at.c, gw/msg.h, gw/smsbox.c, gw/urltrans.c added new parameter %f to show the SMSC number from which an incoming sms is arriving. Only valid for AT. 2006-04-19 Alexander Malysh * gw/smsc/smsc_http.c: We need to refresh the connect time when status is changing to SMSCCONN_ACTIVE otherwise connect time has no sense. Thanks to Vincent Chavanis for provided patch. [Msg-Id: <0eda01c66398$5bc7fe10$9600a8c0@vince>] 2006-04-07 Alexander Malysh * gw/smscconn.c: fix for prev. patch that throughput was not set. Thanks to Vincent Chavanis for pointing to this. 2006-04-07 Alexander Malysh * gw/smscconn.c, gw/smscconn_p.h, gw/smsc/smsc_emi.c, gw/smsc/smsc_fake.c, gw/smsc/smsc_http.c, gw/smsc/smsc_smasi.c, gw/smsc/smsc_smpp.c: applied patch that changes throughput from integer to double for more precise throughput configuration. Thanks to Vincent Chavanis for provided patch. [Msg-Id: <1e2901c659a5$09339850$9600a8c0@vince>] 2006-04-07 Alexander Malysh * gw/ota_prov.c: fixed memory leaks. Thanks to Rene Kluwen for provided patch. [Msg-Id: ] 2006-04-01 Alexander Malysh * gw/bb_smscconn.c, gw/smsbox.c, gw/smscconn.c, gw/urltrans.c, * gw/wap_push_ppg_pushuser.c gwlib/http.c gwlib/regex.[ch]: get rid of gw_regex_matches function because we already have gw_regex_match_pre with the same functionality. Additionally fixed coding style mess in gw/urltrans.c. 2006-04-01 Alexander Malysh * gwlib/octstr.c: fixed octstr_delete_matching. Don't know how it worked before?!? 2006-03-28 Alexander Malysh * gw/smsbox.c: applied patch fixes race condition for the case when immediate-sendsms-reply=false (which is default). In this case we put uuid into store dictionary after we sent message to bearerbox. Then another thread which does read_from_bearerbox tried to delete not yet existant uuid from store dirctionary which leads to stale sendsms clients. Thanks to Dziugas Baltrunas for patch. [Msg-Id: <943470880603231203hd97b1e5nffff4c8b2c455358@mail.gmail.com>] 2006-03-28 Alexander Malysh * gw/smsc/smsc_http.c: patch sets the smsc_id in incoming messages. Otherwise, they are unable to be routed (smsbox_list empty). Thanks to Rene Kluwen . [Msg-Id: ] 2006-03-28 Alexander Malysh * gw/shared.[ch], gw/smsbox.c, gw/wapbox.c, utils/mtbatch.c: changed call interface to read_from_box so that we can set timeout and differentiate error from timeout. See #321. 2006-03-24 Stipe Tolj * wap/wsp.h, wap/wsp_strings.def: adding new WSP 1.6 headers. NLC. 2006-03-23 Alexander Malysh * gwlib/http.c: fixed non conformance to RFC when client sends wrong request we just closed socket. With this change we return HTTP 400 Bad request error. Thanks to Dziugas Baltrunas for pointing to this. 2006-03-23 Alexander Malysh * gw/bb_boxc.c: fixed compiler warning in function when using 64bit system. Thanks to Vincent CHAVANIS for pointing to this. 2006-03-23 Alexander Malysh * configure.in: added AC_C_INLINE check again. That was wrongly reverted with a last commit from Stipe. 2006-03-22 Stipe Tolj * configure[.in], gwlib/charset.h: reverting Andreas commit regarding libxml2 header due to -1 veto vote by Alex and Stipe. 2006-03-17 Alexander Malysh * gw/smsc/smsc_http.c: Feature add #322. Added Clickatell HTTP interface. Thanks to Rene Kluwen for provided patch. 2006-03-17 Alexander Malysh * gwlib/octstr.c: Fixed #323. Thanks to Rene Kluwen for provided patch. 2006-03-14 Alexander Malysh * gw/heartbeat.c: fixed #320 that heartbeat_stop crashed when no heartbeat at all is activated. Thanks to Rene Kluwen for provided patch. 2006-03-14 Alexander Malysh * gw/smsc/smpp_pdu.def: fixed #317. SMPP v3.4 defines that validity_period and schedule_delivery_time unused in deliver_sm but SMPP v3.3 states that parameters for the deliver_sm are the same as for submit_sm. So make length of validity_period and schedule_delivery_time 17 as for submit_sm. It doesn't break SMPP v3.4 clients because these values are NULTERMINATED. 2006-03-14 Alexander Malysh * gwlib/mime.[ch]: minimal additional patch for the mime module, to allow client/user access to the start element. Thanks to Paul Bagyenda for provided patch. 2006-03-05 Alexander Malysh * gwlib/conn.[ch]: added new function 'use_global_trusted_ca_file' that allow setting of global trusted ca w/o a need to call conn_config_ssl. * gwlib/mime.[ch]: hide MIMEEntity struct and don't allow direct values manipulation. Manipulation allowed only through access functions. Thanks to Paul Bagyenda for provided patch. [Msg-Id: <963281CE-055B-4254-96D6-9DDE6FAC8F30@dsmagic.com>] 2006-03-05 Alexander Malysh * gwlib/http.[ch]: allows http_receive_result to be non blocking if requested. This allow us to start only one thread for http client side. 2006-03-05 Alexander Malysh * configure, configure.in, gw-config.h.in, gwlib/conn.c, gwlib/gw-prioqueue.c, gwlib/gwmem-check.c, gwlib/http.c: replaced '__inline' which is GCC extention with 'inline' and added configure check whether compiler supports inline. This should fix #307. 2006-03-01 Stipe Tolj * gwlib/conn.c: fixing compiler issues from Alex's previous commit. Thanks to Rene for pointing out the CVS HEAD didn't compile. 2006-02-28 Alexander Malysh * gwlib/conn.c: fixed deadlock when first thread made conn_unregister call and the FDSet thread at the same time called conn_callback function. Then the first thread locked [in|out] lock and wait for unregister completion but the fdset thread tried to lock [in|out]. Also fixed some gcc4 warnings. This commit should fix #302 and some others http client related. 2006-02-23 Stipe Tolj * gw/wap-appl.c: apply higher log-level usage for octstr_dump() in decode_bearer_indication() and check_application_headers(). NLC. 2006-02-23 Stipe Tolj * gw/wap-appl.c: fixing a bug causing wapbox to panic while we handle PPG related S_Suspend_Ind type PDU but no PPG is used at all. 2006-02-23 Stipe Tolj * wap/wtp.c: fixing bug #310, causing wapbox to panic while gwlist_append() produces an assertion error if a malformed WTP datagram is tried to be processes and we try to send an RcvError PDU deducing the TID value from the WTP datagram, causing us to push the WAPEvent into a wrong list. 2006-02-23 Stipe Tolj * gwlib/octstr.[ch]: adding a more flexible octstr_dump() call via a variadic macro call. Allowing a third argument specifying the log-level of the Octstr dump. Ie. octstr_dump(ost, 0, GW_ERROR) will dump in ERROR log level. The variadic macro will allow the current usage without a third parameter and hence doesn't require mass patching of existing code. This more flexible octstr_dump() is intended to be used for higher log level runs, where we still want to dump particular data in case we run into warnings or errors. Running in debug log level for real-life production systems in order to get full data dumps is not suitable for a long period, so this allows a shorted log level with reduced log sizes, but octstr_dumps where we need. 2006-02-21 Stipe Tolj * test/fakesmsc.c: fixing option switches '-r' to '-z' for number randomization, which clashed with the '-r' for port specify'ing. Thanks to Ngurah Bagus for the report. [Msg-Id: <9100e92b0602202241we1e9facr94e9ed1d349e5046@mail.gmail.com>] 2006-02-21 Alexander Malysh * gwlib/http.c: remove retry within http.c in client code. That is a bad idea to do any retries in http.c module because it's just library that should just give error to the caller back and not decide to do any retries. The caller is then responsible to do retry. [Msg-Id: ] 2006-02-20 Stipe Tolj * wap/cookies.c: reverting to previous revision, the new locking seems to cause a deadlock situation. Need to resolve this seperately. 2006-02-19 Stipe Tolj * doc/userguide/userguide.xml: added missing 'access-log-' config directives to wapbox group. Thanks to Roberto Carlos Navas for the hint. 2006-02-10 Alexander Malysh * gwlib/http.c: replaced not needed enums with defines. Some whitespaces fixes. Fixes for GCC4 warnings. Fixed function conn_pool_get where retry was not reseted. Fixed check_pool_conn where we now do explicit conn_unregister (it could be a cause for dealocks). Fixed start_client_threads where no error handling was present when create of write_request_thread fail. 2006-02-09 Stipe Tolj * gw/wapbox.c: fixing bug #305, where wapbox did not react on SIGTERM. Now SIGINT and SIGTERM will cause wapbox to shutdown. 2006-02-09 Stipe Tolj * wap/cookies.c: fixing bug #304, which caused segfault via octstr_append() called from set_cookies(), which should be a race-condition. Now the cookies list is protected via a permanent lock before we either cycle in the list or delete/append items. Thanks to Mindaugas for reporting. 2006-02-07 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed typo deliver_sm -> data_sm. Thanks to Stipe for pointing to this. 2006-02-04 Stipe Tolj * gw/pushkannel.conf: remove trailing newlines. NLC. 2006-02-04 Stipe Tolj * gw/ota_compiler.c: fixed OMA compilation, due to mis-ordered array of parameter attributes which caused all attributes to be inlined. Thanks to Tomas Varaneckas for report. [Msg-Id: <43E071A8.40302@metasite.net>] 2006-01-29 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_smpp.c, gwlib/cfg.def: applied patch from Peter Christensen that adds new config option 'alt-addr-charset' which make it possible to define charset for the alphanumeric source address. Patch was modified by me to match Kannel coding style. [Msg-Id: <43D0C806.2020907@coolsystems.dk>] 2006-01-19 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed bug that SMSCConn status was not set to DEAD when io_thread terminates. Thanks to Peter Christensen for pointing to this and partially patch. 2006-01-13 Stipe Tolj * configure[.in]: reverting changes from Andreas in rev 1.154 for setting both (i386 and ppc) architecture flags for darwin (MacOS X). This causes errors with -MM cfalgs and we should build for the architecture we run. Thanks to Cesar Gutierrez Corea for his reporting and Aarno for investigating this issue further on. [Msg-Id: <60387C21-74FA-4E5F-B61A-AA6C3D963BDA@gmail.com>] 2006-01-12 Stipe Tolj * utils/run-checks: use /bin/sh instead of /bin/bash for the sake of platforms that don't come with a standard bash, ie. FreeBSD. 2006-01-12 Stipe Tolj * gwlib/octstr.c: adding support for the va_list handling on FreeBSD AMD64. Thanks to Cesar Gutierrez Corea for provided support. [Msg-Id: ] 2006-01-12 Stipe Tolj * checks/check_http.sh: use /bin/sh instead of /bin/bash for the sake of platforms that don't come with a standard bash, ie. FreeBSD. * checks/check_sendsms.sh: add sleep time after URL calls in order to give the boxes chance to write to the log before our tests run. 2006-01-10 Alexander Malysh * gw/smsc/smpp_pdu.[ch]: commited patch that add all known error codes up to SMPPv5. Thanks to Peter Christensen for provided patch. 2006-01-10 Stipe Tolj * gw/dlr_[mysql|pgsql].c: reverting to previous revisions due to Alex's veto for breaking existing installations with behaviour change in last commits. We need to resolve this in a different way. 2006-01-10 Stipe Tolj * gw/dlr_[mysql|pgsql].c: adding 'field_dst' to the the DLR manipluation and selection crieria for MySQL and PostgreSQL support. Thanks to Vincent Chavanis for a patch. [Msg-Id: <0fb901c61531$cac92b00$9600a8c0@vince>] 2006-01-09 Stipe Tolj * checks/check_[fakesmsc,fakewap,http,httpsmsc_kannel,ppg,sendsms].sh, gw/[other_sms,push,sms,wap]kannel.conf, test/drive_smpp.[c,conf]: use loopback interface IP 127.0.0.1 rather than 'localhost' for the same of 'make check' and various oeprating systems or distros. NLC. 2006-01-09 Aarno Syvanen * test/iptestppg.txt, test/smstestppg.txt: Removed deiiver-before-timestamp * field from push control document used by check_ppg.sh. Checks should * certainly work without editing. 2006-01-07 Stipe Tolj * checks/check_http.sh: fixing this check, shell variable assignment * gwlib/http.c: server_create() needs to duplicate the certkeyfile Octstr, otherwise our server will respond one time and the next request is causing a PANIC due to a octstr_destroy() on a non-present variable. * test/test_http.c: need to destroy the global ssl_client_certkey_file Octstr after we did all requests. 2006-01-04 Stipe Tolj * utils/start-stop-daemon.c: fixing bug #287 for Solaris platform. Thanks to aivars.kalvans@tietoenator.com for the report and patch. 2005-12-29 Stipe Tolj * gwlib/conn.c: fixing bug #284 which causes core dump while NULL is passed for conn in conn_unregsiter(). This "may" be a more general problem as it seems that this may be a racecondition. Need to observe more. * gw/wapbox.c: fixing bug #284 which causes wapbox to core dump in dispatch_datagram while a NULL value is given. We need to react smoothly by discarding the "failing" WDP/UDP datagram and continue operations. Thanks to Mindaugas for reporting the bugs. 2005-12-26 Stipe Tolj * doc/userguide/userguide.xml: fixing documentation references for the change from 'mysql-[username|password]' to '[username|password]' in the 'mysql-connection' group. Thanks to Hillel for pointing to this missed issue. [Msg-Id: ] 2005-12-26 Stipe Tolj * gw/wml_compiler.c, gw/wbxml_tokens.def: added registered public IDs for external WML IDs as defined by OMA. Moved array to .def file to use pre-processor macro magic. We would need to re-write the WML definition from gw/wml_compiler.c and gw/wml_definitions.h to use the more generic pre-processor magic as for wap/wsp_strings.[ch|def]. 2005-12-22 Stipe Tolj * gw/wml_compiler.c: fixing bug #282, which caused a segfault while trying to access the xmlErrorPtr type, but libxml2's xmlGetLastError() didn't provide any data for it. Which means the libxml2 parsing broke, but we don't get any valid xmlGetError() values?! Thanks to Mindaugas again for reporting this issue and provide also the fix. 2005-12-22 Stipe Tolj * gw/wml_compiler.c: fixing bug #283, which caused a segfault while passing NULL'ed arguments to strcmp(). Thanks to Mindaugas for report. 2005-12-18 Alexander Malysh * gw/smsc/smsc_smpp.c: Implemented data_sm handling for MO. Also rearranged code to avoid code duplication. Replaced dump_pdu with macros in order to save function call. With this commit #216 fixed. 2005-12-14 Stipe Tolj * doc/userguide/userguide.xml: added 'validityperiod' to SMPP section. * gw/smsc/smsc_smpp.c: added 'validityperiod' handling inside smsc group. This now allows general validity period setting inside the smpp smsc group. Priority order is: message specific value given via sendsms interface and then smsc config value. Thanks to Hillel for this idea. [Msg-Id: ] 2005-12-13 Stipe Tolj * gw/wml_compiler.[ch], gw/wapbox.c, test/wml_tester.c: fixing major showstopperlong bug #260, causing wapbox to block under the following condition: user request a text/vnd.wap.wml document of considerable size with bogus XML content in it. The wml_compiler() call used to handle the XML parsing in relaxed style, which means passing XML_PARSE_RECOVER as bit mask to libxml2's parsing function would let the bogus XML content pass and afterwards our whole arsenal of WML mangling would hit that XML tree, obviously causing CPU to hit 99% and block other incoming requests. Actually this bug was introduced by revision 1.120, which applied Paul P Komkoff's charset-NG patch. The behaviour can be configured via the 'wml-strict' boolean config directive of 'wapbox' group. Default is yes. * gwlib/cfg.def: adding 'wml-strict' to 'wapbox' group. Setting to 'yes' enables the strict XML pendantic parsing, setting to 'no' will have libxml2 to parse more relaxing and try to recover from errors, but(!) also possibly block on too large bogus input. * doc/userguide/userguide.xml: adding 'wml-strict' section to 'wapbox' group documentation. 2005-12-09 Stipe Tolj * gw/ota_prov.c, radius/radius_acct.c, wap/wap_addr.c: fixing compiler warnings. NLC. 2005-12-09 Stipe Tolj * gwlib/mime.c: fixing MIME boundary parsing. Thanks to Paul Bagyenda for reviewing and resolving this. 2005-12-09 Stipe Tolj Patchset to include OMA ProvCont OTA provisioning support. * configure[.in]: adding scan required for OMA ProvCont HMAC computing. * gw/ota_[compiler|prov].[ch], gw/smsbox.c: adding OMA ProvCont support. * gw/xml_shared.[ch]: adding specific charset MIB enum codes used widely, adding code_page integer to handle while WBXML compilation. Thanks to Paul Bagyenda, Paul P Komkoff Jr and Edward C.A. Tromp for development of OMA ProvCont OTA support. [URL: http://www.mbuni.org/downloads/1.0.0/mbuni-kannel-patch-full] 2005-12-08 Stipe Tolj * wap/wap_addr.[ch]: performance gain by using int compare rather then Octstr compare within wap_addr_same(). We need to call this at various places within the WAP layers and this will increase peformance on significantly on production high-load systems. 2005-12-07 Stipe Tolj * doc/userguide/userguide.xml: add new 'remote-timeout' directive to RADIUS accounting proxy section. * gwlib/cfg.def: adding 'remote-timout' to 'radius-acct' group. * radius/radius_acct.c: fixing blocking state if remote RADIUS does not answer within pre-defined timeout. This ensures that the proxy operation continues. Thanks to Deon van der Merwe for this fix and included patch. [Msg-Id: * Makefile.in: adding 'install' target components for wap library, including heaeders. Mainly this is a sync towards compatibility needs from Mbuni MMS gateway project. 2005-11-11 Alexander Malysh * gwlib/counter.c: allow calling counter_destroy with a NULL just for convenience. 2005-11-11 Alexander Malysh * gw/bb_store.c: fixed race condition when dumping into the new file but in the meantime some messages will be already stored in the Dictionary. Generally means: synchronize file and Dictionary contents. Fixed bug #248. * gw/bearerbox.c: added panic for the case store_init call fail. 2005-11-10 Stipe Tolj * doc/userguide/userguide.xml, gw/bb_smscconn.c, gwlib/cfg.def: veto'ed against naming convention for the 2 new config directives and changed them to 'sms-resend-freq' and 'sms-resend-retry'. 2005-11-09 Stipe Tolj * doc/userguide/userguide.xml: fixing default values for parameters within the user's guide. Thanks to Dziugas Baltrunas for this. [Msg-Id: <943470880511081236t74d1556me79aa8611611115b@mail.gmail.com>] 2005-11-08 Alexander Malysh * doc/userguide/userguide.xml, gw/bb_smscconn.c, gw/msg-decl.h, gwlib/cfg.def: Applied patch that adds configurable max retries and resend frequency for the temporarily failed messages to the core. 2005-11-04 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed memory leak in SMPP DLR handling. Bug #265. Thanks to "ungod" for reporting this. 2005-11-03 Stipe Tolj * configure[.in]: fixing mysql section for the sake of sparc-solaris-10. Thanks to David Chkhartishvili for reporting this. [Msg-Id: <4365C800.4080402@magtigsm.ge>] 2005-11-03 Stipe Tolj * wap/wsp_strings.def: added additional charset code for UTF-16, since this is widely used in production environments. 2005-10-30 Stipe Tolj * wap/wsp_strings.def: added missing byte code for Content-disposition value 'inline'. 2005-10-26 Alexander Malysh * gw/bb_smscconn.c: fixed memory leak when concatenated messages was sent through kannel and one of splits failed due to broken connection to SMSC. In this case we looped for ever consuming 100% CPU time and all available memory because message was duplicated in SMSC module and not destroyed in core. Now we check whether link is OK and only then resend via the same SMSC otherwise fail as usual. Thanks to Wilfried Goesgens for debug help. 2005-10-25 Stipe Tolj * wap/cookies.c: added TODO to reflect the need to unify the functions wap/cookies.c:parse_http_date() and gwlib/date.c:date_http_parse(), these are obviously doing "the same", except the return value, source code indenting. NLC. 2005-10-24 Stipe Tolj * wap/wsp_headers.c, check/check_date.c: re-interpretation of return value for gwlib/date.c:date_parse_http(), we assume that the signed long is negative only for those values beyond epoch time border, hence wrap to unsigned for further processing. 2005-10-24 Stipe Tolj * gw/wml_compiler.c: updating well known WBXML public identifier IDs and WBXML token array up to current Encoding-Version 1.5. NLC. * wap/wsp_strings.def: updating well known content type tokens, added registerd tokens now too for future use, updating push application IDs. 2005-10-21 Stipe Tolj * doc/examples/dlr-mysql.conf: fixed the naming change from change set 2005-09-21, where the 'mysql-connection' group changed to use 'username' and 'password' as login credentials instead of the mysql prefixes. Thanks to Mike Harris who pointed this out. [Msg-Id: <200510201656.j9KGuqch027946@outmail.freedom2surf.net>] 2005-10-10 Stipe Tolj * test/test_regex.c: added output of the sub-strings matching a regular expression, just for the sake of readability. 2005-10-07 Stipe Tolj * doc/examples/modems.conf: added modems group for Sony Ericsson T63x, found at Heny Junior's blog describing the use on a MacOS X system. [URL: http://henryjunior.com/blog/?p=12] 2005-10-06 Stipe Tolj * gwlib/octstr.c: fixed a critical bug in octstr_split() where we would loop infinetly inside the while clause cuasing octstr_search() to allocate memory. If a needle has len 0, then we obviously have an exit condition for the loop. 2005-10-05 Stipe Tolj * gw/wap_push_ppg.c: possibly fixing bug #144, initializing Octstr vars that are destroyed afterwards in case of a failed URL compare, waiting on Jonathan for feedback. 2005-10-05 Stipe Tolj * gw/wml_compiler.c: fixing bug #255 where we pass a NULL result from xmlDocGetRootElement() within parse_document() to the next functions and hence causing an segfault. Thanks a lot to Mindaugas Riauba for the bug report and the fix suggestion. [Msg-Id: <01ad01c5c807$8bca3ba0$f20214ac@bite.lt>] 2005-10-04 Stipe Tolj * doc/examples/modems.conf: commenting 'no-smsc' value for Falcom GSM modems, this breaks the PDU string acceptance as far as we tested. Should be 'false' for the Falcom modem type. 2005-09-27 Stipe Tolj * gwlib/dlrpool_sqlite3.c, gwlib/dbpool.[ch]: added SQLite3 support for database pool constructs. This can be used to implement a DLR storage type for SQLite3. * gw-config.h.in, configure[.in]: added SQLite3 support, this is only the configuration part, yet no DLR storage implemenation for this. 2005-09-27 Stipe Tolj * gw/dlr_pgsql.c: fixed a typo from previous commit on this that broke compilation. No logic change. 2005-09-27 Alexander Malysh * gw/bb_store.c: fixed start sequence of store file. Now we don't allow using of store until store file was not loaded (all attempts to use store will block). Also fixed some memory leaks. 2005-09-26 Stipe Tolj * configure[.in]: changed --with-sdb handling in order to break configure process if the libSDB client library is not found. 2005-09-26 Stipe Tolj * Makefile.in: added removal of 'config.nice' for distclean target. 2005-09-22 Alexander Malysh * gw/bb_store.c: changed writing to/from store file. Now we don't URL encode the packed message that should give us a bit speedup. Fixed races while loading of store file. We must read the whole store file into private dictionary and then populate to the queues because at the same time SMSCConns may run. * gw/bearerbox.c: Fixed store file shutdown phase. It is wrong to shutdown store file asynchronously while some SMSCConns or boxc connections still running. We must shutdown store file only when we made sure all producers are down. 2005-09-21 Stipe Tolj * configure[.in], aclocal.m4, .cvsignore: added config.nice support to the autoconf build system. This is taken from PHP5 to ease the handling of configure option switches while doing re-configure calls, also fixed sqlite client library handling. We now stop if the lib is not present, otherwise we will run into linking stage errors afterwards. 2005-09-21 Stipe Tolj Feature request #254 in order to set port values for mysql and pgsql database connection types. Used as DLR storage space. * gwlib/cfg.def: added config directive 'port' to 'myqsl|pgsql-connection' groups, changed mysql config directive names to 'username' and 'password' to reflect the harmonization to others. (COMPATIBILITY BREAKER) * gwlib/dbpool.[ch]: added port value to mysql and pgsql confs, also renamed internal pgsql variables to be more harmonized. * gwlib/dbpool_[pgsql|myqsl].c: added port variable support and changed internal variable naming. * gw/dlr_[sdb|oracle].c: source code layout fixes. No logic change. * gw/dlr_[pgsql|mysql].c: added port variable support and minor source layout changes. 2005-09-20 Stipe Tolj * doc/userguide/userguide.xml, gw/sms.[ch], gw/smsbox.c, gw/xml_shared.c, gw/smsc/smsc_[cimd2|ois|oisd|soap].c, gwlib/http.h, gwlib/octstr.c, wmlscript/wsbc.c: fixing bug #252 where references to UTF-16[BE] and UCS-2 have been mis-spelled. No logic change. 2005-09-15 Stipe Tolj * gw/smsc/smsc_at.[ch]: applied RAW TCP patch to support remote termnial server connections for devices. Also some inlined source code beauty. * doc/userguide/userguide.xml: added variables for the RAW TCP mode. Thanks to Stanislav Sinyagin for the patch. [Msg-Id: <20050914152140.76555.qmail@web51904.mail.yahoo.com>] 2005-09-15 Stipe Tolj * gw/smsc/smsc_at.c: fixing compiler warning. No logic change. 2005-09-14 Stipe Tolj * gw/smsc/smsc_at.c: fixing a bug for 'nokiaphone' GSM modem types, where PDUs longer then 18 bytes get truncated by the device if passed too fast. We pass the PDU now in 18 byte chunks and delay to smoothly allow the device to parse this. This is know for the Nokia phone GSM types. Thanks to Ulrich Petri for the fix and patch. [Msg-Id: <4326E76A.3040902@upcd.de>] 2005-09-14 Stipe Tolj * gw/smsc/smsc_at.c: minor change in at_wait_modem_command to display the sscanf() parsed error code string lateral only if we really found a int in the string returned from the device. No logic change. Thanks to Alex Judd for this hint. [Msg-Id: <4326F4EB.5070302@skywire.co.uk>] 2005-09-08 Stipe Tolj * gw/wml_compiler.c: source styling, no logic change. * configure[.in]: changed required version of libxml2 to 2.6.0 due to applied Paul's patch to gw/wml_compiler.c. Solves compiler warnings and errors. Fixing build bug reported by Jarrod Hermer . [Msg-Id: <20050908093728.B109C5A44@ctb-mesg1.saix.net>] 2005-09-02 Alexander Malysh * gw/smsc/smpp_pdu.c: fixed length for the NULterminated TLV. 2005-09-01 Alexander Malysh * gw/wap-appl.c: fixed compiler warning. * gw/wml_compiler.c: added 'libxml/parser.h' to includes because it cause build to fail. 2005-08-20 Andreas Fink * gwlib/soket.h fixed socklen_t double definition on MacOS X 10.4 * configure.in fixed incorrect brackets 2005-08-12 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed bug #242 that case statement because of missing break for requeue action triggered error condition. Thanks to srivest for report. 2005-08-12 Alexander Malysh * gw/wap-appl.c, gw/wml_compiler.c: applied charset-NG patch that generalize charset handling in the WAP stack. Thanks to Paul P Komkoff. [Msg-Id: <20050602143346.GA28202@stingr.stingr.net>] 2005-07-26 Aarno Syvanen * doc/userguide/userguide.xml: Removed a duplicate 2005-06-10 Andreas Fink * gwlib/gw_uuid.h: uuid_t doesnt need to be defined on MacOS X. New compiler dislikes it configure, configure.in: Build changes to correctly build on XCode 2.1 including dual build for ppc and i386 architecture if possible 2005-06-02 Stipe Tolj * gwlib/http.c, gwlib/fdset.c: some code styling within handle_transaction and poller. No logic change. 2005-05-28 Alexander Malysh * gw/bb_store.c: fixed bug tthat caused bearerbox to consume 100% cpu time. Hopefully fixed #230 (see Mantis). 2005-05-10 Alexander Malysh * gw/smsc/smsc_ois.c, gwlib/gwmem-check.c, test/test_regex.c: fixed coompiler warnings. * gwlib/conn.c: fixed typo '___inline' that cause build to fail. 2005-05-09 Alexander Malysh * gwlib/conn.c, gwlib/dbpool.c, gwlib/gw-prioqueue.c, gwlib/gwmem-check.c, gwlib/http.c, wap/wtls_pdu.h: changes that to make ISO strict compilers happy. Mostly: 'inline' -> '__inline'. 2005-05-09 Alexander Malysh * test/test_ppg.c: killled wait variable and use wait_seconds instead. 2005-05-09 Alexander Malysh * test/test_hmac.c: fixed build error when no openssl available. 2005-05-06 Alexander Malysh * gw/smsc/smsc_at.c: build fixes for strict compillers. 2005-05-06 Alexander Malysh * gwlib/octstr.h: fixed compiler warnings for strict compilers (e.g. HP-UX). 2005-05-05 Alexander Malysh * gwlib/gwlib.c: fixed segfault while shutdown when memcheck used. 2005-05-05 Alexander Malysh * gwlib/dbpool.c: drop 'inline' from function declaration. They can't inlined anyway but produce errors with strict ansi compilers. 2005-05-05 Alexander Malysh * configure.in, configure: fixed openssl detection for Mac OS X. 2005-04-22 Stipe Tolj * test/test_hmac.c: fixed compiler error of the automatic compilation test, due to usage of HMAC_CTX_cleanup, whereas geodude still runs an openssl version with the deprecated "old" HMAC_cleanup. 2005-04-21 Stipe Tolj * test/test_octstr_dump.c: added binary dump to file for files that contain hex values. Can be used to convert hex value blocks to binary files. * test/test_hmac.c: added file that implements HMAC calculation via openssl library. HMAC is used in authentication for OMA Prov documents. 2005-04-14 Alexander Malysh * gw/smsbox.c, gw/wapbox.c, gwlib/cfg.def, gwlib/http.[ch], test/test_http.c, test/test_xmlrpc.c, doc/userguide/userguide.xml: applied patch that adds the 'http-proxy-exceptions-regex' option to the wapbox and smsbox config files. This added to allow a regex like "^https" to skip the HTTP proxy for SSL connections. Obviously it can also be used for more than just that. Thanks to Jonathan Houser . [Msg-Id: <425D26A4.80401@wirelessonenet.com>] 2005-04-08 Stipe Tolj * gwlib/md5.c: fixing bug #207, causing md5() to return corrupted values since we assumed digest is a NULL-terminated C string, which is of course not the case in gernal. Thanks to Vincenzo for reporting this. 2005-04-07 Stipe Tolj * radius/radius_[acct|pdu].c: fixing bug #208, which caused a wrong computing of the MD5 authenticator of the NAS acct packet. Thanks a lot to Vincenzo for bug report and also fix. This was a very stupid interpretation of the RFC2866 by me. 2005-04-07 Stipe Tolj * gwlib/http.c: fixing bug #213 breaking HTTP response handling when there has been a response header 'Content-Length: 0' given. Thanks to Jonathan for this report and provding also a patch for the problem. [Msg-Id: <42541321.2080102@wirelessonenet.com>] 2005-04-01 Stipe Tolj * test/wapproxy.c: added option -p for UDP port of wapproxy to list to. Can be used to proxy WDP packets on the same machine/interface. 2005-03-29 Alexander Malysh * gwlib/http.c: fixed horrible bug in 'http_cgivar_dump' that used 'gwlist_extract_first' instead of 'gwlist_get'. 2005-03-28 Alexander Malysh * gwlib/dbpool.h: fixed compiler warnings. 2005-03-22 Stipe Tolj * wmlscript/wsstdlib.[ch]: updated and added latest WTAI functions as defined in WAP-268-WTAI, WAP-269-WTAIIS136, WAP-270-WTAIPDC, WAP-228-WTAIIS95-20010908 and WAP-255-WTAIGSM. Thanks to Dermot Wrycraft for providing the hint for update. 2005-03-21 Stipe Tolj * gwlib/octstr.{ch]: adding octstr_str_case_compare() to allow insensitive string compare with const char. Patch by Fred . [Msg-Id: <020f01c51acf$98f1c0e0$0401a8c0@FRED4>] 2005-03-21 Stipe Tolj * gwlib/http.c: fixing server and client thread state variables in order to make modules usable in other code where http_init() and http_shutdown() is called several times. Thanks to Paul for pointing to this. [Msg-Id: ] 2005-03-17 Alexander Malysh * gw/smsc/smsc_smpp.c: applied patch that implements relaxed source_addr checks in SMPP and adds additionally error reporting why kannel rejected this MO. [Msg-Id: ] 2005-03-15 Stipe Tolj * configure[.in]: moved required libxml2 version check from 2.2.5 to 2.2.7, since we use the macro LIBXML_DOTTED_VERSION in gw/shared.c and this is available since 2.2.7. 2005-03-09 Alexander Malysh * gw/bb_smscconn.c, gw/smscconn.c: fixed memleaks in handling of splitted messages. 2005-03-08 Stipe Tolj * wap/wtp_resp.h: adding patch from Igor to support larger objects via WTP SAR segments. Thanks to Igor for providing the patch and production environment tests and Mindaugas Riauba for picking this item up again for discussion. [Msg-ID: <8BCBF9DB739F034B87FE7C7D30EAE55C01A0F34B@hqex2k.francoudi.com>] 2005-03-07 Alexander Malysh * gwlib/http.c: (Client Part) fixed race condition while destroing Connection. In order to not trigger RC we must first explicit unregister connection from FDSet (because this operation is locked) and then destroy Connection. (Server Part) fixed race condition that caused double free of a HTTPClient struct while closing specified listen port. 2005-03-07 Alexander Malysh * gw/dlr_pgsql.c: attached patch adds again 'LIMIT 1' to dlr_pgsql because after fix for #190 we will delete and update to much rows in postgresql. [Msg-Id: ] 2005-03-07 Alexander Malysh * gw/wap-appl.c: added call to 'radius_acct_get_msisdn' back. Thanks to Jonathan for reporting this. 2005-03-07 Aarno Syvanen * doc/userguide/userguide.xml:File schemes in settings and bookmark examples were wrong. Fixed this. Thanks to Davy for reporting. 2005-03-06 Alexander Malysh * gw/bb_store.c, gw/wap-appl.c: fixed compiler warnings. 2005-03-06 Alexander Malysh * gw/wap-appl.c: Fix empty device_headers with request_headers == NULL and session_headers != NULL and small memory leak with connection-oriented wap Thanks to "Paul P Komkoff Jr " for the patch. [Msg-Id: <20050306212423.GA26532@stingr.stingr.net>] 2005-03-04 Stipe Tolj * gw/wap-appl.c: adding a NULL check causing a PANIC while dumping the IP in the fetch info() statement. How can this be NULL, since we pass it the same way to alog()?. Tbanks again to Jonathan for this. 2005-03-04 Stipe Tolj * gwlib/http.c: fixing bug #205 (leaking FDs). Due to an unhandled error state we would not change the HTTPEntity state and the conn ist not closed. Thanks to Jonathan for reporting this and Alex for the fix. 2005-03-04 Stipe Tolj * gw/wap-appl.c: added output in info() log line for fetching the requested client URL. Thanks to Jonathan for this. [Msg-ID: <422880B3.90805@wirelessonenet.com>] 2005-03-02 Stipe Tolj * doc/userguide/userguide.xml: fixed some typos and added sections for URL escape codes %m and %M for sms-service group. * gw/urltrans.c: adding URL escape codes %m for mclass and %M for mwi parameters of our Msg structure. Generally this shall allow to use smsc_http (kannel mode) interface to have MO transported transparently up via sms-service to an upstream smsbox instance for further processing. 2005-03-01 Andreas Fink * gw/smsc/smsc_at.c: be more friendly to modems which are not ready after opening serial port or after AT&F. Helps Ericsson T300 2005-03-01 Aarno Syvanen * gw/smsc/smsc_at.c: Fixed error messages in "slow modem start patch" 2005-03-01 Stipe Tolj * configure[.in], gw-config.h.in, gwlib/http.c: added option to make HTTP/1.1 keep-alive support disabled via optional configure switch --disable-keepalive. Thanks to Jonathan Hauser for this patch. [Msg-ID: <421B8103.7070301@wirelessonenet.com>] 2005-03-01 Stipe Tolj Portability enhancement for non-gcc compilers, no logic change. * gw/smsc/smsc_smpp.c: changed gcc specific magic macro __PRETTY_FUNCTION_ to __func__ that is more generic, because of gw-config.h.in macro rule used. * readius/radius_pdu.c: remove void NULL void call and enclose into an if statement. Thanks to Mike Bristrow for the patch. [Msg-ID: <20050218120010.GA17561@urgle.com>] 2005-03-01 Stipe Tolj * configure[.in]: added support to find docbook.dsl file on Debian unstable. Thanks to Benjamin for this patch. [Msg-ID: <20050219161644.GA938@xaos.realthought.net>] 2003-02-23 Aarno Syvanen * doc/userguide/userguide.xml: changed the added si doc to minimum one, so that users can minimize the generated si message. 2005-02-20 Aarno Syvanen * doc/userguide/userguide.xml: added an example si document * gw/smsbox.c: ppg dlr-url should work now when it is a configuration variable. Fix suggested by Davy Chan * gw/wapbox.c: reload (SIGHUP) does not change value of configuration variable concatenation * gw/smsc/smsc_at.c: Handle a very slow initialisation. This is a patch by Andreas. * test/test_ppg.c: Added two new push header, used to ask * delivery reports 2005-02-18 Stipe Tolj * gw/wap-appl.c, wap/cookies.c, wap/wsp_session.c: fixing an assertion PANIC, while passing a NULLed List* to cookies.c:add_cookie_to_cache(). We now gwlist_create() the cookies list inside machine_create(). Thanks to Jacob Dalsgaard for reporting this and Davy for pushing the "recalling"-button. [Msg-ID: <4018EB52.306@cybercomgroup.com>] 2005-02-18 Stipe Tolj * wap/wtp.c: fixing bug #197, causing wapbox to PANIC on truncated WDP datagrams. Thanks to Jonathan Houser for reporing this bug in ML users@kannel.org. [Msg-ID: <4214F128.4090007@wirelessonenet.com>] 2005-02-17 Stipe Tolj * test/test_radius_pdu.c: some minor issues, like usage display etc. 2005-02-17 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed typo while setting submit_sm.data_coding. Thanks to Davy Chan for the patch. [Msg-Id: <20050217104340.GF6920@exras.cs.ust.hk>] 2005-02-15 Stipe Tolj * configure[.in]: fixing bug #191. Thanks to Sefan Cars and Noritoshi Demizu for reporting and resolving this issue for the FreeBSD platform. 2005-02-15 Stipe Tolj * gwlib/http.c: fixing bug #68 reported by Aarno. Thanks to Rune Saetre for providing a patch. Applied in variation of the Rune's patch, in order to reduce code. [Msg-ID: ] 2005-02-11 Stipe Tolj * wap/wsp_headers.c: fixing a generic problem for empty WSP header values. This was initially reported by Paul for the Siemens SX1 device. [Msg-ID: <20050118210227.GA12497@stingr.sgu.ru>] Patch applied is more generic then the one from Paul. [Msg-ID: <41F8D8E5.10400@tolj.org>] 2005-02-11 Stipe Tolj * */*: update LICENSE preamble block to 2005. * [various]: update personal email reference to latest address 2005-02-11 Stipe Tolj * gw/wap-appl.c: added support to log MSISDN of a calling client device provided via our RADIUS acct proxy. Thanks to Paul for this. [Msg-ID: <20050211123830.GW14917@stingr.sgu.ru>] 2005-02-10 Stipe Tolj * gw/dlr_pgsql.c: fixing bug #190, where PostgreSQL does not take LIMIT for DELETE and UPDATE operations. WARNING: This causes a possible loose of uniqueness, since only timestamp and smsc-id is used as unique id. Which means we will drop *all* messages of a particular second, then at least one of them get's a DLR. This needs a fix in the semantical issue on how DLR resolving is done. Reported by Johann du Preez . [Msg-ID: <000b01c509bd$92e1aee0$bf00a8c0@Pinotage>] 2005-02-10 Stipe Tolj * doc/examples/modems.conf: added modemds group for SonyEricsson GR47 GSM modem module. Thanks to Matti Ärmänen for this. [Msg-ID: <421C8F56.2050502@sci.fi>] 2005-02-10 Stipe Tolj * doc/userguide/userguide.xml: minor typo fix. 2005-02-01 Alexander Malysh * checks/check_list.c, gw/bb_alog.c, gw/bb_boxc.c, gw/bb_http.c, gw/bb_smscconn.c, gw/bb_store.c, gw/bb_udp.c, gw/bearerbox.c, gw/dlr_mem.c, gw/dlr_mysql.c, gw/dlr_oracle.c, gw/dlr_pgsql.c, gw/dlr_sdb.c, gw/heartbeat.c, gw/mime_decompiler.c, gw/msg.h, gw/numhash.c, gw/sms.c, gw/smsbox.c, gw/smscconn.c, gw/urltrans.c, gw/wap-appl.c, gw/wap-maps.c, gw/wap_push_ota.c, gw/wap_push_pap_mime.c, gw/wap_push_ppg.c, gw/wap_push_ppg_pushuser.c, gw/wap_push_ppg_pushuser.h, gw/wapbox.c, gw/wml_compiler.c, gw/xml_shared.c, gw/smsc/smsc_at.c, gw/smsc/smsc_cgw.c, gw/smsc/smsc_cimd2.c, gw/smsc/smsc_fake.c, gw/smsc/smsc_http.c, gw/smsc/smsc_oisd.c, gw/smsc/smsc_smasi.c, gw/smsc/smsc_smpp.c, gw/smsc/smsc_soap.c, gw/smsc/smsc_wrapper.c, gwlib/accesslog.c, gwlib/cfg.c, gwlib/dbpool.c, gwlib/dbpool_oracle.c, gwlib/dbpool_pgsql.c, gwlib/dict.c, gwlib/fdset.c, gwlib/gw-rwlock.c, gwlib/gwthread-pthread.c, gwlib/http.c, gwlib/list.c, gwlib/list.h, gwlib/log.c, gwlib/mime.c, gwlib/octstr.c, gwlib/octstr.c.debug, gwlib/octstr.h, gwlib/octstr.h.debug, gwlib/parse.c, gwlib/semaphore.c, gwlib/utils.c, gwlib/xmlrpc.c, test/drive_wapbox.c, test/fakesmsc.c, test/test_cimd2.c, test/test_dbpool.c, test/test_headers.c, test/test_http.c, test/test_http_server.c, test/test_mime.c, test/test_ppg.c, test/test_smsc.c, test/test_xmlrpc.c, test/wapproxy.c, utils/mtbatch.c, wap/cookies.c, wap/timers.c, wap/wap.c, wap/wsp_caps.c, wap/wsp_headers.c, wap/wsp_push_client.c, wap/wsp_push_client_states.def, wap/wsp_server_method_states.def, wap/wsp_server_push_states.def, wap/wsp_server_session_states.def, wap/wsp_session.c, wap/wsp_unit.c, wap/wtls-secmgr.c, wap/wtls.c, wap/wtls_pdu.c, wap/wtls_pdusupport.c, wap/wtls_state-decl.h, wap/wtls_statesupport.c, wap/wtp.c, wap/wtp_init.c, wap/wtp_pdu.c, wap/wtp_resp.c, wap/wtp_tid.c: renamed all occurence of 'list_XXX' to 'gwlist_XXX' thus fixed bug #32. 2005-02-01 Alexander Malysh * gwlib/fdset.[ch]: In order to efficient handle timeouts and don't start "yet another thread" we use already available fdset's threads. With this patch applied we will have a possibility to set timeout for all filedescriptors in fdset and after timeout elapsed registered callback function with POLLERR as event will be called. * gwlib/http.c: changes related to server/client idle timeout and removed some code duplcation. [Msg-Id: ] 2005-01-28 Stipe Tolj * doc/userguide/userguide.xml: fixed personal reference for Kalle. 2005-01-28 Kalle Marjola * doc/userguide/userguide.xml: added HTTP status codes and contents to sendsms entry 2005-01-28 Kalle Marjola * gw/smsbox.c: in sendsms, wait for bearerbox reply before replying to HTTP client. NOTE: compatbility breaker if the HTTP client is reading the reply content, plus Kannel can now return new HTTP status codes. Use 'immediate-sendsms-reply = true' in the smsbox group to enable old behaviour. * gwlib/http.h, gwlib/cfg.def, doc/userguide/userguide.xml: relevant changes 2005-01-28 Stipe Tolj * doc/userguide/userguide.xml: fixed personal email reference. 2005-01-28 Stipe Tolj * test/hello.wml: fixed obviously wml compiling break for checks/check_fakewap.sh. 2005-01-28 Stipe Tolj * checks/check_http.sh, utils/run-checks: moving shell from /bin/sh to /bin/bash. * checks/check_ppg.sh: moving file condition check from -e (exists) to -f (file exists and is regular). Fixing bug #168. Thanks to Stefan Radman . [Msg-ID: <20050120.152742.094138.593FCF86BC282B0082761599C0E8DE79@CTBTO.ORG>] 2005-01-24 Alexander Malysh * gw/urltrans.c: fixed bug #174. Thanks to chandave for provided patch. 2005-01-23 Alexander Malysh * gwlib/http.c: apllied patch that includes some http server fixes: - don't close listen filedescriptor when accept failed (that can be caused bei client just now disconnected or network error) - added 'active_list' that saves all active http clients and so while shutdown all active clients can be disconnected gracefully (w/o fdset warning about active entries) and when listen port removed all active clients for this port could be disconnected. [Msg-Id: ] 2005-01-23 Alexander Malysh * gw/bb_boxc.c: applied patch that change behaviour in communication thread creation. With this patch threads are created only after successful accept and so eliminate possible DOS. 2005-01-21 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed bug #165. we now always send validity & deferred time in UTC. 2005-01-21 Alexander Malysh * gwlib/gwmem-check.c: added backtrace support. w/o backtrace is this module really hard to use. [Msg-Id: csodge$rfm$1@sea.gmane.org>] 2005-01-20 Alexander Malysh * gwlib/octstr.c: fixed segfault and compiler warnings on a x86_64 (Intel Xeon). * gw/smsc/smsc_at.c: fixed compiler warnings on a 64bite OS. Thanks to Ilan Aelion . [Msg-Id: <200412311337.12104.ilan.aelion@dimoco.at>] 2005-01-19 Alexander Malysh * configure.in, configure: fixed bug #178 and similar bugs. Additionaly fixed indentation. Thanks to sradman for bug report. 2005-01-19 Alexander Malysh * Makefile.in: fixed bug #173. Thanks to joergent. 2004-12-23 Alexander Malysh * contrib/kannel-monitor/index.php: and yet another one-liner. Fixed a case when there is a bearerbox attached and no smsbox's attached to it, the bearerbox doesn't appear in the Box Connections. This is due to the test being an empty() test with a few spaces in the variable $x... Doing a trim solved this.. Thanks to Bill Brigden . [Msg-Id: <200412231224.iBNCOU008238@bill.aqvs.co.uk>] 2004-12-23 Alexander Malysh * gwlib/http.c: applied 'http client timeouts part1 (v4)' patch. This patch fixes a problem with dead connections in http client connection pool. It's only a first part of fixes that we need (we still need to kill inactive connection after timeout expired). How it works: 1) before putting connection into connection pool register dummy callback 2) if dummy callback called (we will receive error poll event) check if connection still ok and if not destroy it 3) before return connection from pool, unregister dummy callback 2004-12-23 Alexander Malysh * gwlib/conn.[ch]: added 'conn_register_real' that takes callback data and data-destroyer function pointer. When conn_destroy/conn_unregister called and Connection has data_destroyer fn-pointer that will be called in order to destroy callback data. When conn_register on already registered data called that if old-data != new-data then data-destroyer function called in order to destroy previous callback data. Additionaly some locking fixes. 2004-12-23 Alexander Malysh * contrib/kannel-monitor/index.php: applied patch that should fix a bug when dead bearerbox causes monitor to freeze. Thanks to Agastiya S. Mohammad . [Msg-Id: <1103539890.3803.309.camel@localhost.localdomain>] 2004-12-15 * gw/bb_store.c: removed -Wall warnings * gw/smskannel.conf: resumed global-sender, otherwise make check does not work 2004-12-13 * gw/bb_store.c: use Dict to make things much more faster. Also introduce 'store-dump-freq' to set up how often the situation is stored to file * gw/bearerbox.*, gwlib/cfg.def, doc/userguide/userguide.xml: relevant changes * test/fakesmsc.c: update usage to reflect changed command line argument (-p to -r) * gw/smskannel.conf: updated to include much more explanations and fixed above thing 2004-11-30 * gwlib/conn.c: Bug fix: try not to read negative number of bytes * gwlib/http.c: Bug fix: close connection with bad content-length 2004-11-29 Alexander Malysh * gwlib/charset.c: fixed bug in 'charset_convert' that could cause converted string to be truncated. Thanks to "Pommnitz Joerg" for the patch. [Msg-Id: 4D93AAF95CB5A64E8F622EC796ECF5AC3FC3DF@exil.condat.de] 2004-11-23 Stipe Tolj * Making stable release 1.4.0. gateway-1.4.5/doc/ChangeLog-1.2.10000644000175000017500000006152410203150325014637 0ustar toljtolj2002-10-19 Stipe Tolj * wap/wsp_headers.c: roll-back to previous revision. We have to resolve this issue more carefully. 2002-10-17 Stipe Tolj * gw/smsc/smsc_smasi.c: added enquire_link facility to sm/asi protocol. Can be configured via 'enquire-link-interval' directive. 2002-10-17 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed a typo in DLR error handling. Thanks to Alexander Malysh for spotting this. [Msg-ID: <200210161940.36328.a.malysh@centrium.de>] 2002-10-16 Stipe Tolj * test/test_octstr_immutable.c: minor change to make dumping of arguments possible to. 2002-10-16 Stipe Tolj * wap/wsp_headers.c: fixed a bug in WSP header packing that breaked MMS notification sending via PPG. 2002-10-16 Stipe Tolj * doc/userguide/userguide.xml: added documentation to SMPP's directives [source|dest]-addr-[ton|npi] and source-addr-autodetect. * gw/smsc/smsc_smpp.c: changed DLR msg_id behaviour. SMPP spec says msg ids should be C string, this is default now. Via msg-id-type users may configure for smpp connections that use dec and hex values or mixes of those. * gwlib/cfg.def: added 'source-addr-autodetect' to smsc group for auto-detecting source addr in smpp module. 2002-10-16 Stipe Tolj * gw/bb_smscconn.c: fixed a bug in http admin /status page routine if smsc groups did not have any smsc-id declared. Patch has been submited by Rene Kluwen [Msg-ID: <006501c2708f$52284400$1401a8c0@helena>] 2002-10-16 Stipe Tolj * gw/smsc/smsc_smpp.c: roll-back to previous revision. Veto'ed Andreas commit because it took out the new msg-id-type feature, which is required by certain SMSC vendors. 2002-10-16 Andreas Fink * gwlib/http.c: fixed http basic authentication for DLRs a dlrurl containing username and password was crashing kannel before because http headers where not initialized. also potentially a problem in other places. 2002-10-15 Stipe Tolj * gwlib/utils.c: fixed a bug in does_prefix_match(), when a number gets not recognized if it has the same length as in prefix list. Now prefix = number does get matched. 2002-10-15 Andreas Fink * gw/dlr.c gw/smsc/smsc_smpp.c: fixed DLR reports if message ID was hex or alpha 2002-10-15 Stipe Tolj * gw/smsc/smsc_smasi.c: added enquire_link feature to pass a newline throught this connection to keep the TCP session up. 2002-09-23 Oded Arbel * gwlib/octstr.c: Fixed bug in octstr_insert_char(), patch by Rene Kluwen [Msg-Id: <75184712412.20020923031314@chimit.nl>] 2002-09-23 Andreas Fink * gwlib/octstr.c: fixed memory leak in octstr_url_encode 2002-09-19 Oded Arbel * gw/smsc/smsc_at.c: Fixed a bug in at_receive(), reported by Rene Kluwen [Msg-ID: <200209191406.g8JE6L8H017962@ns.nesscis.com>] 2002-09-18 Oded Arbel * gw/wap_push_ppg.c: Fixed a bug in get_mime_boundary that would cause it to get into an endless loop if the boundary was not ; terminated. changed the HTML entity name of a double quote from &qt; to " and added ';' at the end of HTML entity, fixed endless loop bug in escape_fragment(). 2002-09-09 Stipe Tolj * config.h.in, configure[.in], gwlib/cfg.c: veto against #define WIN32. This shoould be only used for Win32 native support, *not* for Cygwin support. 2002-09-08 Bruno Rodrigues * doc/userguide/userguide.xml: fix 2002-09-06 Bruno Rodrigues * gwlib/cfg.c, doc/userguide/userguide.xml: added directory include to configuration. If "include" argument is a directory, include the files * configure.in, config.h.in: Added #define WIN32 awareness * doc/userguide/userguide.xml: "un-drafted" post-xml * utils/build-cygwin-package: added first alpha version to a script to build some package for windows. Now, it creates a zip file with the executables, docs (if generated) and example configuration files 2002-09-06 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed a problem with the range of sequence_number. Reported by Angel. [Msg-ID: ] 2002-09-06 Stipe Tolj * gw/bb_boxc.c, gw/bearerbox.c: made boxid++ thead-safe via mutex * docs/userguide/userguide.xml: documented the smsc specific 'unified-prefix' directive for number normalization * gw/bb_smscconn.c, gw/smscconn.c, gw/smscconn_p.h: added 'unified-prefix' function on a smsc basis to set number normalization rules. * gwlib/cfg.def: added 'unified-prefix' to multi-group 'smsc'. 2002-09-06 Andreas Fink * gw/dlr.c: fixed a crash when migrating from MySQL database without source field to one which has. 2002-09-06 Andreas Fink * gw/dlr.c: fixed Stipe's modifications so it at least compiles! 2002-09-06 Stipe Tolj * gw/dlr.c: fixing dlr_add_() routines for the new DLR handling way. Thanks to Oded for reporting this. * gw/smsc/smsc_smpp.c, gw/smsc/smsc_at2.c: another fixes for the new DLR handling way. And again, reported by Oded :) 2002-09-06 Andreas Fink * gw/dlr.c: added Oded's patch to fix a missing parameter in mysql DLR. 2002-09-05 Stipe Tolj * gwlib/utils.[ch], gw/urltrans.c, gw/smscconn.c: moved the identical routine does_prefix_match() from urltrans.c and smsccon.c to the higher abtraction layer to utils.c and made it publically available. 2002-09-05 Stipe Tolj * gw/dlr.c: fixed a bug caused by a typo * gwlib/http.c, gwlib/parse.c: fixed minor compiler warnings 2002-09-04 Stipe Tolj * gw/dlr.[ch], gw/urltrans.c: added a 'source' field to the DLR storage space, hence modified the dlr_add() call parameters. Re-organized how the DLR msg structs are transfered to smsbox and the msg->sms.dlr_url is now used to get the DLR URL. This is more clean and makes DLR proxying accross different SMSC modules posible. * gwlib/cfg.def: added 'field-source' for the mysql dlr definition * gw/smsc/smsc_*.c: added source parameter to call dlr_add() and changed msg->sms.msgdata handling after dlr_find() * gw/smsc/smpp_pdu.h: added submit_sm and deliver_sm esm_class defines 2002-09-04 Aarno Syv\212nen * STATUS: updated * TODO: typo fix * checks/check_ppg.sh: typo fix * gw/bb_boxc.c: Reformatted. Store wap push messages to the store file. * gw/pushkannel.conf: Added country-prefix to the example file. * gw/wap_push_ota.c: Minor formatting change. * gw/wap_push_ppg_pap_compiler.c: Ditto * gw/wap_push_mime.c: Better public function comment * gw/wap_push_ppg.c: Reformatted. Handling missing denied and allowed lists. Remove X-WAP-Application-Id header, when user agent is wml.ua. If there is none, assume wml.ua. Removed push.sia requirement, when push is confirmed. Use 'any' as default bearer and network. Do not add Content- Type header to responses. Use xml escapes when sending message fragment to pi. * gw/wap_push_ppg_pushuser.c: Reformatted. Use country-prefix. Handle missing allowed and denied lists. Do not add Content-Length to the responses. Edited function compare_octstr_sequence. * gwlib/cfg.def: Added country prefix. * gwlib/gwthread_pthread.c: Reformatted. Dummu function for older MacOSXs returns a value. * gwlib/http.[ch]: Added function http_header_value. * gwlib/octstr.[ch]: Added function octstr_insert_char. Memory leak wrapper around function octstr_format_valist. * gwlib/parse.[ch]: Added function parse_get_rest. * test/test_ppg.c: Removed content type sia. Use mms.ua as X-WAP-Applica- tion-Id value. Reformatted. Do not add Content-Length header. Use HTTP POST in test_ppg requests. * wap/wsp_strings.def: Added new content types and headers from newer wap specs. 2002-09-04 Stipe Tolj * gw/smsc/smasi_pdu.c, test/test_cfg.c: fixed compiler warnings 2002-09-03 Stipe Tolj * gw/smsc/smpp_pdu.c: fixed a bug in copy_until_nul() which caused to return octstr "" when the null-terminated string contained "\0". The return value in such a case should be NULL. 2002-09-03 Stipe Tolj * doc/userguide/userguide.xml: documentation for the new 'msg-id-type' directive for the SMPP module * gw/smsc/smsc_smpp.c, gwlib/cfg.def: adding the 'msg-id-type' directive to indicate in which number base the SMSC is returning msg ids. Patch provided by Nisan Bloch . [Msg-ID: <5.1.0.14.0.20020819203925.020675c0@amagoblin.ialien.co.za>] 2002-09-02 Stipe Tolj * gw/shared.[ch]: added deliver_to_bearerbox() which is identical to write_xxx but returns an error code which can be used for errror handling. * gwlib/cfg.[ch]: switched from static void dump_group() to void grp_dump() to make this function publically available and usable in the code. 2002-08-26 Stipe Tolj * gw/bb_store.c: obey if we log in localtime for the store-status 2002-08-26 Stipe Tolj * test/test_cfg.c: added error code return for int main() to indicate if a configuration syntax was ok or not. This can be used in control shell scripts to check Kannel's configuration files. 2002-08-23 Stipe Tolj * gwlib/http.c: fixed HTTP persistent connection misbehaviour in http_send_reply() which caused to do keep-alives, even while the client requested to close the connection. 2002-08-23 Stipe Tolj * gw/smsc/smsc_at2.c, gwlib/http.c: fixed a minor compiler warnings * gw/smsc/smsc_smpp.c: fixed a type in handle_pdu(), reported by Vibhu Mohindra [Msg-ID: <20020822214514.GA4279@lfs.localdomain>] 2002-08-22 Stipe Tolj * wap/wap_events.def, wap/wtp.c: added a RcvResult event and a coresponding unpack_result() function. This is necessary for an upcoming wap proxy. 2002-08-22 Stipe Tolj * doc/userguide/userguide.xml, gw/smsc/smsc_at.[ch], gw/sms.h: Oded's patch for full DLR support in AT2 module. Some further improvements and fixes included. [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296F5A@exchange.m-wise.com>] 2002-08-20 Stipe Tolj * gwlib/http.[ch]: added HEAD method support for HTTP client module functions, this modifies the http_start_request() prototype. * gw/numhash.c, test/test_smsc.c: changed calls to http_get_real() * gw/smsbox.c: added method to remember_receiver() and get_receiver() and changed calls to http_start_request() * gw/wap-app.c, gw/smsc/smsc_http.c, gwlib/xmlrpc.c, test/test_ppg.c: changed calls to http_start_request() * test/test_http.c: added -m option so select HTTP method type for request and changed calls to http_start_request() 2002-08-19 Stipe Tolj * wap/wtp_pdu.def: changed the TPI documentation string to make them more specification conform. 2002-08-19 Stipe Tolj * gw/smsc/smsc_smpp.c: fixed a bit calculus typo, reported by Nisan. [Msg-ID: <5.1.0.14.0.20020819154851.02066060@amagoblin.ialien.co.za>] 2002-08-19 Stipe Tolj * gw/smsc/smasi_pdu.c: fixed a parsing bug in decode_type() and switched some error levels from error to warning for the sake of the logs. 2002-08-15 Stipe Tolj * doc/userguide/userguide.xml: added new SMSC type section for the SM/ASI protocol. * gw/smsc/smasi_pdu.[chdef], gw/smsc/smsc_smasi.c, gw/smscconn.c, gw/smscconn_p.h: added the new 'smasi' SMSC type for connecting to SM/ASI protocol SMSC, like the CriticalPath InVoke SMS Center. 2002-08-15 Stipe Tolj * gw/bb_smscconn.c: removing debug line from previous testing and commented out lines and added 're-connecting' state to smsc2_status(). * gw/smsc/smsc_smpp.c: fixed a bug with possible segfault when acessing the smpp->msgs_to_send in queued_cb() while the connection has been shutdown and the status page queueries all available connections. 2002-08-13 Harrie Hazewinkel * Changed the '' into '(null)' since the former is to close to XML and may cause confusion. 2002-08-13 Stipe Tolj * test/test_http_server.c: allow to use multi-threaded HTTP server tests 2002-08-12 Stipe Tolj * gw/smsc/smpp_pdu.c: fixing a compiler warning * gwlib/octstr.[ch].debug: added missing octstr_recode() and _read_pip() functions in the debug version of the octstr module 2002-08-11 Stipe Tolj * gw/smsc/smpp_pdu.[chdef], gw/smsc/smsc_smpp.c: rollback to previous revision and adding a silent fix to SMPP PDU elements that are too long. * Makefile.in: fixing missing dependency generation in file .depend for all modules in the 'new' gw/smsc sub-directory. This has caused to keep make quite, even while source files changed in gw/smsc. 2002-08-11 Harrie Hazewinkel * Moved more smsc related code into gw/smsc/ gw/smsc.h -> gw/smsc/smsc.h gw/smsc_p.h -> gw/smsc/smsc_p.h * gwlib.octstr.c: graceful handling of the Octstr* when it is NULL, instead of panicing. Oded Arbel [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296EEF@exchange.m-wise.com>] * Converted all doc/ChangeLog-* file to have a UNIX line ending and not the '^M'. * gw/smsc/smsc_smpp.c, gw/smsc/smpp_pdu.h, gw/smsc/smpp_pdu.def: Make sure that the address length going into the PDU is not longer then the maximum length. If the address is longer it causes a panic. Oded Arbel [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296EEF@exchange.m-wise.com>] 2002-08-10 Stipe Tolj * gwlib/list.c: fixed a mutex_destroy() problem, because list is still locked while mutex is destroyed. 2002-08-09 Harrie Hazewinkel * Moving the smsc code into a subdiretory gw/smsc. files moved (into gw/smsc): emimsg.c emimsg.h smpp_pdu.c smpp_pdu.def smpp_pdu.h files changed: test/drive_smpp.c test/test_smsc.c 2002-08-08 Stipe Tolj * gw/smsc/smsc_http.c: fixed the "failed" logging to access.log, which was caused because the relayed smsbox instance send HTTP_ACCEPT and the module did only like HTTP_OK. * ChangeLog: reorganized the huge ChangeLog to version specific chunks into doc/. Only changes since the last stable release are inside the current ChangeLog in the top level directory from now on. 2002-08-08 Harrie Hazewinkel * Moving the smsc code into a subdiretory gw/smsc. Only the smsc.h, smsc_p.h smscconn.h and smscconn.c are as API still in the gw directory. files moved (into gw/smsc): smsc_at2.h, smsc_cimd2.c, smsc_fake.c, smsc_sema.c, smsc.c, smsc_sema.h, smsc_cgw.c, smsc_emi.c, smsc_http.c, smsc_at.c, smsc_smpp.c, smsc_cimd.c, smsc_emi2.c, smsc_ois.c, smsc_at2.c, smsc_wrapper.c files changed: Makefile.in gw/smscconn.c, gw/smscconn_p.h 2002-08-08 Harrie Hazewinkel * configure.in: Be a little less strict for the '--enable-warnings' * gwlib/conn.h: fixed 3 warnings. 2002-08-08 Stipe Tolj * gw/smsc_http.c: typo fix. * gw/wap-appl.c: added HTTP HEAD method for WSP->HTTP requests 2002-08-07 Stipe Tolj * gw/bb_store.c: fixed a segfault bug in store_status() 2002-08-07 Stipe Tolj * gw/bb_http.c, gw/bearerbox.[ch] : renaming start operation to 'restart' to indicate that this is used after bearerbox has started and individual smsc have been shutdown previously. * gw/bb_smscconn.c: fixed serious problems in /stop-smsc, /start-smsc admin commands and /status page retrieval * gw/smsc_emi2.c, gw/smsc_fake.c: fixed a segmenation fault bug, which was caused by /status page lookup when a specific conn was already shutdown 2002-08-07 Harrie Hazewinkel * Fix/partial rollback of the access log facility for the wapbox. 2002-08-06 Stipe Tolj * gw/bb_store.c: fixed possible race conditioning for sms_store list in store_status() causing segfault. 2002-08-06 Harrie Hazewinkel * Added an access log facility to the wapbox. 2002-08-06 Stipe Tolj * doc/userguide/userguide.xml: fixed typos from last commit. * contrib/mon/kannel.monitor: some slight changes to the monitor module * gw/bb_smscconn.c: fixed a possible critical race condition causing segfaulting bearerbox if the admin status page is called to often. 2002-08-05 Stipe Tolj * doc/examples/dlr-*.conf: fixed a typo in the 'dlr-db' group for the id variable 2002-08-05 Stipe Tolj * doc/userguide/userguide.xml: added documentation about libSDB support as DLR storage space type * doc/*.conf, doc/examples/dlr-sdb.conf: moved the .conf files to doc/examples and added a dlr-sdb.conf example configuration file * config.h.in, configure[.in], gw/dlr.[ch], gw/shared.c, gwlib/cfg.def: added libSDB support as DLR storage type. libSDB is an abstraction library for various DB system, including MySQL, PostgreSQL, Oracle, gdbm and some others. 2002-08-05 Stipe Tolj * gw/smsbox.c: fixed a bug for an uninitialized rpi value inside smsbox_req_sendsms() 2002-08-05 Stipe Tolj * doc/userguide/userguide.xml: added documentation about RPI support * gw/smsc_smpp.c, gw/smsc_emi2.c, gw/smsbox.c, gw/smpp_pdu.h, gw/msg-decl.h: added Return Path Indicator (RPI) support for SMPP and EMI2 via boolean sendsms interface parameter 'rpi' 2002-08-05 Stipe Tolj * gw/smsc_emi2.c, gwlib/cfg.def: added EMI2 specific configuration directives 'notification-pid' and 'notification-addr'. Patch submitted by "Dima Milentiev" [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296EB9@exchange.m-wise.com>] 2002-08-05 Bruno Rodrigues * doc/modems.conf: added keepalive command to M20: signal and battery level * gw/smsc_emi2.c, doc/userguide/userguide.xml: Added keepalive support when there's no username and password. "my-number" should be set. 2002-08-04 Stipe Tolj * gw/wml_compiler.c: fixed a segmentation fault bug in check_if_emphasis() which was caused while a nulled node->name gets into strcmp(). Thanks to Peter Bieringer for reporting this. 2002-08-03 Stipe Tolj * gw/bb_store.c: fixed a minor compiler warning * gw/bb_smscconn.c: fixed a possible segmentation fault bug in smsc2_status while accessing the SMSCConn structure. * gw/smsc_smpp.c: disallow start if no system-type is specified 2002-08-02 Harrie Hazewinkel * Added a '--with-cflags=CFLAGS' and '--with-libs=LIBS' configuration options. These are useful when Kannel is linked again additional proprietary modules, such as an SNMP module. 2002-08-02 Stipe Tolj * doc/userguide/userguide.xml: updated documentation about HTTP admin commands for 'status', 'store-status', 'start-smsc' and 'stop-smsc' * gw/bb_http.c, gw/bb_store.c, gw/bearerbox.h: implemented 'store-status' HTTP admin command to retrieve the messages currently in the main queue 2002-08-01 Stipe Tolj * doc/userguide/userguide.xml: documentation for new smsbox group directives 'http-request-retry' and 'http-queue-delay' * gw/smsbox.c, gwlib/cfg.def: added HTTP request queueing for sms-service 'get-url' and 'post-url' services. 2002-08-01 Harrie Hazewinkel * Adding more warnings to the '--enable-warnings' and deleted the duplicate '-g -O2' options when '--enable-warnings'. Only the following warnings cannot be avoided, since these depend on the lex/flex and yacc/bison plus the system. - wmlscript/wsint.h:217: warning: function declaration isn't a prototype - wmlscript/wslexer.c:166: warning: no previous prototype for `ws_yy_lex' - wmlscript/wsint.h:237: warning: previous declaration of `ws_yy_parse' 2002-07-31 Stipe Tolj * gw/smsc_emi2.c: fixed a bug when using /status.xml for an EMI2 link that does not set any username. is interpresed as XML start tag and hence we don't produce a valid XML file. 2002-07-31 Stipe Tolj * gw/smsbox.c: changed formating of HTTP User-Agent headers to be in "foobar/1.2" style. 2002-07-29 Stipe Tolj * test/fakewap.c: fixed compiler warnings from previous commit. 2002-07-23 Harrie Hazewinkel * Adding an extra option to the fakewap test which can print out the complete message in human-readable format. The characters/bytes of the message that are not printable are printed as '_'. This is to facilitate debugging of the content part. 2002-07-15 Stipe Tolj * doc/userguide/userguide.xml: added documentation about the 'allowed|denied-receiver-prefix' directives for sms-service groups. 2002-07-15 Stipe Tolj * gw/urltrans.[ch], gw/smsbox.c, gwlib/cfg.def, test/test_urltrans.c: added 'allowed-receiver-prefix' and 'denied-receiver-prefix' for sms-service groups. This is used to restrict access to service requests coming in on certain receiver numbers, i.e. shortcut numbers. 2002-07-09 Stipe Tolj * configure[.in]: correcting a type and a match pattern from the previous commit. 2002-07-09 Stipe Tolj * configure[.in]: fixing the hardcoded way Andreas did in the previous patch. configure should *only* be auto-generated by autoconf. 2002-07-09 Andreas Fink * changed dlr.c and STATUS to not contain any ^M at end of line Makefile.in and configure to properly deal with MacOS X (darvin) panic replaced with gw_panic, done as a #define now (MacOS X has panic already defined) gwlib/gwthread-pthread.c: added empty pthread_sigmask() if its MacOS X. added file README.MACOSX 2002-07-08 Harrie Hazewinkel * Making the init phase and the initialization of the smsbox, wapbox and bearerbox equal in approach. All three had the same thing done differently. 2002-07-08 Stipe Tolj * gw/smsc_smpp.c: fixing an obvious bug and compiler warning due to typo in smsc_smpp_create(). 2002-07-05 Aarno SyvŠnen * TODO: Added file for larger projects. Now it is about making WAP 1.2.1 gateway and PPG to support working with MMS centers. 2002-07-05 Stipe Tolj * gw/smsc_smpp.c: added throttleing error code support, patch provided by Oded. [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B296D6C@exchange.m-wise.com>] 2002-07-05 Stipe Tolj * gw/smsc_smpp.c: fixing timezone issue for sms time validity, patch made by Alan [Msg-ID: <1024987558.1209.472.camel@euclid>] 2002-07-05 Stipe Tolj * gw/smpp_pdu.def, gw/smsc_smpp.c: added unbind PDU support, patch submitted by Ignat Vassilev [Msg-ID: <3D17E046.1060806@declera.com>] 2002-07-05 Stipe Tolj * gw/smsc_smpp.c, gwlib/cfg.def: added SMPP priority flag support using configuration directive 'priority', patch submitted by Ignat Vassilev [Msg-ID: <3D1A586B.3070308@declera.com>] gateway-1.4.5/doc/arch/0000755000175000017500000000000013312227707013352 5ustar toljtoljgateway-1.4.5/doc/arch/external-interfaces.fig0000644000175000017500000000270507361052630020006 0ustar toljtolj#FIG 3.2 Landscape Center Metric A4 100.00 Single -2 1200 2 6 360 810 1305 1620 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 1305 1620 1305 810 360 810 360 1620 1305 1620 4 0 0 50 0 0 12 0.0000 4 135 375 585 1170 SMS\001 4 0 0 50 0 0 12 0.0000 4 105 480 585 1395 center\001 -6 6 405 1755 1305 2520 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 1305 2520 1305 1755 405 1755 405 2520 1305 2520 4 0 0 50 0 0 12 0.0000 4 135 420 585 2070 WAP\001 4 0 0 50 0 0 12 0.0000 4 180 450 585 2295 phone\001 -6 6 5130 1035 6165 2115 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 6165 2115 6165 1035 5130 1035 5130 2115 6165 2115 4 0 0 50 0 0 12 0.0000 4 135 450 5355 1440 HTTP\001 4 0 0 50 0 0 12 0.0000 4 90 480 5355 1665 server\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2475 1260 3870 1260 3870 1935 2475 1935 2475 1260 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 1395 1125 2115 1080 2430 1395 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 1350 2115 2160 2115 2430 1665 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 3915 1575 4545 1530 5085 1485 0.000 -1.000 0.000 4 0 0 50 0 0 12 0.0000 4 180 1035 2070 990 SMS protocol\001 4 0 0 50 0 0 12 0.0000 4 135 930 2025 2385 WAP stack\001 4 0 0 50 0 0 12 0.0000 4 135 540 2745 1620 Kannel\001 4 0 0 50 0 0 12 0.0000 4 135 450 4320 1395 HTTP\001 4 0 0 50 0 0 12 0.0000 4 135 345 4275 1755 PAP\001 gateway-1.4.5/doc/arch/arch.xml0000644000175000017500000030336413312154361015015 0ustar toljtolj Kannel Architecture and Design $Revision: 1.20 $ Lars Wirzenius Gateway architect Wapit Ltd
liw@wapit.com
This document examines the purpose of a gateway in the Wireless Application Protocol (WAP) architecture. WAP is a technology for implementing services on moible phones using hypertext similar to the World WideWeb (WWW). We examine a particular WAP gateway, called Kannel and will discuss its design and look how well it works.
Introduction It has been a long-time dream of science fiction authors and fans to have a computation device with you at all times. This dream device would allow you to do many of the same things a full-size device would, whenever and whereever you would need it. In addition, just by always being with you, it allows you to do things a static device won't. For example, in Arthur C. Clarke's novel everyone has a small device that works as a notebook, dictionary, encyclopedia, and recording device. This itself is nothing special: real-life computers have been doing such things for decades by now. However, by virtue of being small enough for its user to always carry it, it suddenly becomes much more powerful. You have instant access to all the information you need, when you need it. You always have all your notes with you, allowing you to get things done wherever you are, and not just in the office. A lone computer is nice, but quite boring compared to a networked one. Instant communication with anyone, anywhere, at anytime is another science fiction dream. The communication device worn by characters in the television series is an example: just by tapping the device once, you can talk to anyone. The real world has been catching up with science fiction. Mobile phones have allowed near-instant communication with anyone else for several years. They aren't as small as the Star Trek devices, nor as fast, but they are small enough to be carried at all times, and they're extremely popular. Mobile computers are also reality. The first portable computer, the Osborne-1, was produced in 1981. It was the size of a suitcase and weighed more than ten kilograms, so it wasn't particularly easy to carry, but its descendants have evolved into smaller and smaller versions each year. Current technology allows laptops that are small enough to be carried in a bag to most places. Even smaller devices, palmtops, really are small enough to be taken everywhere, in a pocket, just like modern mobile phones are. Palmtops aren't as powerful as laptops, or desk computers, but powerful enough to do many useful things. We now have mobile phones, providing connectivity, and laptops and palmtops, providing processing power. Combining them is a natural next step, and actually one that has, to some extent, already been taken. Mobile phones can function as wireless modems to mobile computers, providing network access anywhere. This has some technical problems, however, due to the limited bandwidth and high error rates in mobile networks. It also requires carrying two devices, and connecting them in some way. Having a single device capable of both communication and data processing is likely irresistible to the mass market. Some such devices already exist, such as the Nokia Communicator and the Ericsson R380, but they have so far been priced out of reach for most consumers. With hundreds of millions of mobile phones in use all over the world, the market for services targeted at mobile users is already immense. Even simple services find plenty of users, as long as they're useful or fun. Being able to get news, send e-mail or just be entertained wherever you are is extremely attractive to a large number of people. More sophisticated services make things even more attractive to even more people. One technology for implementing mobile services is WAP, short for Wireless Application Protocol. It lets the phone act as a simple hypertext browser, but optimizes the markup language, scripting language, and the transmission protocols for wireless use. The optimized protocols are translated to normal Internet protocols by a WAP gateway. Designing and implementing a WAP gateway is a straightforward excercise in well-established software engineering practices. However, when the system has to work efficiently and reliably for a huge number of concurrent users, some special problems arise. This Master's thesis discusses the problems and the design decisions of a particular WAP gateway, called Kannel. We also provide benchmark results to justify the design. We do not only discuss technical issues, but touch some project management issues as well, since the Open Source nature of the gateway affects the way development has been and is being done. Kannel is an Open Source project by the Wapit Ltd company launched in June, 1999. I was employed by Wapit to head the project. It is not the first Open Source project with which I am involved, but it is the first one where I am getting paid for the work. Kannel is an important and necessary part of Wapit's approach to implementing mobile services, but not one from which the company expects to make money directly. The reasons for making Kannel Open Source are discussed. This document was originally written to be a Master's thesis for Lars Wirzenius. The thesis has not (as of this writing) been finished, but a work-in-progress version has been converted to be the Kannel architecture document, since the old architecture document had not been updated for a year. The thesis version and the architecture document version of the text will evolve in parallel. Problems in implementing services for mobile phones This chapter explains the problems in designing and implementing services for mobile phones. There are both technical problems (how to do it at all) and business problems (how to make money doing it, in the short and the long term). There are various approaches to solving these problems; we will briefly summarize the important ones. Technical problems In order to be usable to their users, mobile phones have to be small in size and light in weight. This puts rather severe limits on their design, which results on several problems: The battery has a fairly low capacity, resulting in more limitations due to having to keep power consumption down for every part. Small screen and keyboard, resulting in very limited input and output possibilities and making user interfaces awkward. Slow processor and little memory, resulting in little computation being possible on the phone itself. Some of these limitations apply only to phones and other mobile devices do better. For example, the screen size of a Palm or Psion device is large enough that simple text processing is doable. For every device meant to be mobile, however, the limitations will apply to some extent. It is not really possible to comfortably carry around a full size keyboard, mouse, and screen. The wireless mobile network also has severe limitations, compared to a wired local area network. The total amount of bandwidth that all mobile users in a geographical area can share is limited. With cables it is always possible to expand the bandhwidth by installing more cables, but the total spectrum of radio waves available for mobile networking is limited, both by physics and by the way it has been allocated to various purposes by governments. Radio waves are also inherently error prone, since they are affected by many sources of disturbances: other devices and the Sun cause intereferences by sending their own signals, and buildings, mountains and other parts of the landscape distort and in some cases prevent the radio signals from reaching their destination. Even if nothing else is a problem, the distance to the nearest base station for the mobile network may be too large. This results in a network with limited bandwidth and a high error rate. Normal networking protocols, such as TCP/IP, have been designed for an environment with low error rates, which makes them partly unsuitable for a mobile network. Additionally, the various protocols used in the Internet (and that's about the only interesting global network for mobile users as well) on top of TCP/IP are textual, meaning that the messages they send are plain text. This makes them easier to specify and understand, and much easier to implement them and debug the implementations, but when bandwidth is very limited, they do waste it. Business problems The technical problems outlined in the previous section are fairly straightforward to solve in isolation. However, in order to be viable from a business point of view, the choice of technical solutions needs to be guided by business needs. The basic business requirement for a mobile network operator is that building a system for mobile services needs to be profitable: the cost of building the system must be less, in the long run, than the income generated from its users. Mobile phone networks already support data connections, so the basic problem of getting data from and to the mobile devices is already solved. The current solutions are not optimal, but they are good enough for now. The shortcomings of data connections in current networks will be solved by next generation mobile network technology, such as GPRS and UMTS. This, however, results in a new problem: the work done for implementing services in today's networks must not be wasted when newer networks are employed. Thus, today's solutions must be designed so that they will work tomorrow as well. Telecommunications equipment needs to be interoperable: devices from different manufacturers must be able to talk to each other without problems. The interoperability requirement results in the need for a standard for the way mobile services are implemented. This standard may be a formal international standard, or an industry de facto standard, as long as it is open and adhered. The standard should also be as broadly applicable worldwide as possible. This makes it easier to reach a critical mass of users: when there are enough users, it becomes easier to mass produce devices and that keeps the cost of the devices low, thus allowing even more users to buy one. Also, a mobile device is more attractive, if it allows interaction with many other users. Reaching critical mass is impossible, if the devices or services are hard to use. Thus, whatever solution is chosen, it must allow user interfaces that are easy to learn and use. Business requires that service users can be billed. For real mass market use, billing needs to be efficient and simple, both for the service provider and the user. Billing can be arranged in various ways: pre-paid, paid with phone bill, or via credit card, for example. In summary, the way mobile services are implemented must fill the following requirements: Leverages on existing mobile phone networks. Must be adaptable to future mobile networks. Standardized, for interoperability and mass market. Allows easy user interfaces. Allows billing. We will next look at how current solutions work. Pre-WAP solutions Current (GSM) networks have two ways of implementing services for mobile phones: normal voice calls and short textual messages (SMS messages). A mobile phone can be used to make a normal voice call to a service number, which is typically answered by a computer. The computer plays recorded voice messages, and the user can interact by pressing the number buttons on his phone. This is awkward and slow, and if there is any information that needs to be saved, the user needs to make notes with a pen and paper. This is uncomfortable enough that it is not a viable solution except in very rare cases. SMS messages are short textual messages (up to 160 characters) that are sent from or to GSM phones. Similar functionality exists in alphanumeric pagers in the US, and elsewhere. The messages are sent to a particular phone number, and can be processed by a computer. The computer can then send a reply message. This allows many simple services. For example, one could implement a service where by sending the words WEATHER HELSINKI to a given number, one could get the current weather forecast for Helsinki in reply. SMS based services fill most business requirements given in the previous section. They work in current networks, and a billing infrastructure already exists. They are not, however, very user friendly, since the messages are short, and it is difficult to memorize long lists of service keywords and arguments. An additional current option is to run a dial-up Internet connection over a GSM data call. The phone would then use normal HTTP to fetch normal HTML pages. This is doable immediately, and requires modification to the phone only. The mobile network and the services can exist as they already do. The main problem is that existing HTML pages are written in such a way as to require fast connections, fast processors, large memories, big screens, audio output, and may require fairly efficient input mechanisms. That means they can be made attractive for users of traditional computers and networks. However, portable phones have very slow processors, very little memory, abysmal and intermittent bandwidth, and extremely awkward input mechanisms. Most existing HTML pages simply will not work on them, nor will they ever do that. Even simple HTML pages with minimal markup will be hard to use on a display with only a few lines of text with a few words each. Content needs to be specially tailored for such small screens. Even if content were tailored, normal HTTP is fairly verbose for use in a mobile network with slow bandwidth. An HTTP request constists of up to dozens of lines of text, or up to a couple of hundred of bytes. This can be made much more efficient by using a special protocol. The Wireless Application Protocol This chapter explains the goals of WAP, and summarizes its history so far. It introduces WML and WMLScript, and explains why they are used instead of the normal Internet languages (HTML, Java, JavaScript, and other formats). It explains shortly the on-the-air protocols of WAP, and why the normal TCP/IP or other existing protocols weren't chosen, and the role of the gateway in translating between air and Internet protocols. It covers features such as sessions. This section also covers the current status of WAP (what is implemented and in use, and market penetration), and the expected future, with GPRS (and wouldn't it be sensible to use HTTP with GPRS?), UMTS, and 3G coming (and I need to look up what those acronyms mean). XXX does it? Goals and history of WAP and the WAP Forum The WAP Forum, which creates and maintains the WAP specifications, was founded in June, 1997 by Ericsson, Nokia, Motorola, and Unwired Planet (later Phone.com, later Openwave Systems). The 1.0 specification was published in April, 1998, but wasn't implemented in phones. The 1.1 specification came out in July, 1999, and was the first one implemented in publically available phones. 1.2.1 came out in June 2000, and phones implementing it (and specially push) are now available, too. Work on WAP 2.0 is closing. It will converge WAP with Internet protocols and W3C markup languages. The goal of the WAP Forum is to develop an open, freely licensed specification that is not tied to any network technology, nor to any specific device. They want to do this in a way that is as compatible as possible with existing Internet technologies, to allow existing content providers to use existing content when creating mobile services. The WAP architecture WAP is a collection of languages and tools and an infrastructure for implementing services for mobile phones. WAP makes it possible to implement services using hyper-text, similar to the World Wide Web. Here WAP Push and Pull are handled separately, because they are, indeed, very different services. Meaning of these terms will, hopefully, come clear later. WAP pull does not bring the existing content of the Internet directly to the phone. As discussed in , existing content is unlikely to display properly on a phone anyway. Instead, WAP defines a completely new markup language, the Wireless Markup Language (WML), which is simpler and much more strictly defined than HTML, making it easier for the hypertext browser in the phone to interpret and display it. WAP also defines a scripting language, WMLScript, which all browsers are required to support. To make things even simpler for the phones, WAP even defines its own bitmap format (Wireless Bitmap, or WBMP).
WAP architecture
WAP defines a protocol semantically equivalent to HTTP, but being in a binary and compressed format it reduces the protocol overhead to a few bytes per request, instead of up to hundreds of bytes. However, to make things simpler also for the people actually implementing the services, WAP introduces a gateway between the phones and the servers providing content to the phones. The WAP gateway talks to the phone using the WAP protocol stack, and translates the requests it receives to normal HTTP. Thus, the content providers can use any HTTP servers, and can utilize existing know-how about HTTP service implementation and administration. In addition to protocol translations, the gateway also compresses the WML pages into a more compact form, to save bandwidth on the air and to further reduce the phone's processing requirements. It also compiles WMLScript programs into a bytecode format.
WML and WMLScript Content and services in WAP are presented to the phone using the Wireless Markup Language (WML) and the WMLScript programming language. WML is a simple markup language defined with XML and is used to mark the contents of the file as actual text, title, hyperlinks, etc. Using XML gives some syntactical benefits, such as fairly simple rules for parsing, which means that the parser in the WAP browser in the phone can be kept simple. It is also likely that the WAP gateways and the browsers in the phones will not tolerate syntactic and semantic errors in WML pages very well. Much of the complexity in WWW browsers is a result of having to cope with numerous versions of HTML, some of which conflict with each other, and accomodating for bad HTML in a heroic attempt to present the user with at least something interesting from the web page. Since WAP browsers are embedded into phones, and phones won't be upgraded as easily or as often as WWW browsers, WML needs to evolve much more carefully than HTML has done and WML pages need to follow the specifications. A WML page is a deck of cards. One card at a time is displayed by the phone. It is possible to switch between cards on the same deck quickly, since the whole deck is downloaded at once. A WAP application might fit onto one card, or be divided into several, depending on its size and how big decks the phone accepts. WMLScript is a simple programming language based on ECMAScript and JavaScript, which are usually but not always implemented in WWW browsers. A WAP browser is required to implement WMLScript. WMLScript is used to make WAP pages more dynamic. It is not always enough to provide only a static page. The application might, for example, use WMLScript to let the user only fill in valid values into a form. The validation can be done on the content server as well, but then it will need to be sent there and the result needs to be fetched back. This is both slow and potentially expensive, if a new connection to the gateway needs to be established. WMLScript also defines a number of libraries for controlling phone functionality. This could, for example, be used to implement better phone book browsers than what is implemented in the phone itself. A WML page is typically provided by the content server in its textual form, and the WMLScript code as source code. The gateway will then translate WML into a binary format, which is more compact, and WMLScript into bytecode, which is simple for the phone to execute and requires no CPU intensive parsing on the phone. The phones typically can't handle textual WML or WMLScript source code, but rely on the gateway to do the translations. The WAP protocol stack The WAP protocol stack takes care of transporting requests for pages from the phone to the gateway, and transporting the pages (possibly converted to a binary form) back to the phone. The protocol stack consists of three core layers: Wireless Datagram Protocol (WDP): Moves single packets to and from the phone. This is the lowest level layer defined by WAP. It is implemented on whatever suitable mechanism is available on the underlying network. For TCP/IP networks, it maps directly to UDP packets. Wireless Transaction Protocol (WTP): Implements a single request-response pair between phone and gateway. The request may be for a new page, or it may be something related to the higher level protocols. Wireless Session Protocool (WSP): Takes care of handling actual requests for pages. Sessions are used to optimize bandwidth usage. A representative use case for the protocol is shown in . Phone opens session, using WSP. Phone and gateway negotiate protocol features and HTTP headers to be used in requests gateway makes on behalf of the phone. Phone sends URL for the page the user has configured as his home page. Gateway makes HTTP request, with negotiated headers. Gateway encodes page in a binary form and sends it to the phone. User shuts down the browser and the phone terminates the session.
A representative WAP session
The behavior of each end of the WAP connection is defined by a set of layer-specific state machines, which define the handling of timeouts and other errors. We shall not discuss these at any length, since the details are not relevant this document. The WAP protocol stack contains several additional optional layers and optional features of the layers we have mentioned. These are not interesting for the discussion of the design of Kannel.
The duties of a WAP gateway This section summarizes the duties of the WAP gateway. The basic duty is to implement the WAP protocol stack, as outlined in the previous section, so that the user can actually use WAP services. Additional duties may include, depending on how the gateway is used, user authentication and billing. The gateway can often identify the actual user. For example, if the bearer used is GSM SMS messages, the user's phone number is known to the gateway. The gateway can then pass on this information to the content services. This is useful when the service can use this information to provide personalized service: it might remember the user's preferred settings, for example, or let him access e-mail without filling in a separate login form. An identified user can also be billed. WAP content can be priced in various ways, and if it is to be billed to the user, the user needs to be identified. In addition, something in the WAP system needs to keep track of what billable items the user actually uses, and the gateway is one good place to do this. The gateway doesn't actually include a billing system itself, but it provides user and usage data to the billing system of the operator. From the user's point of view, the gateway is also responsible for optimizing WAP usage as far as possible: the gateway should keep the number of packets small, to keep costs down and make best use of available bandwidth. WAP Push Architecture Previous chapters defined pull mode of operation: a phone starts everything and a content server acts passively. It is, however, sometimes useful that the server can start a transaction. Email notifications, news services and stock quotes are some examples of this mode of service. However, simple pushing a content to the phone causes problems. User experience is badly detoriated, if incoming push messages can interrupt ongoing tasks. So instead an actual content, one pushes Service Indication, which tells that a service has become available and contains an URL telling where the user can found it. Then the user can accept or reject the service. The phone may confirm that is has received the push content. In addition of this basic service, PAP document defines way to control the push operation. A push initiator can select network and bearer used, set delivery time restrictions and define quality of service. SI document contains, too, some additional attributes defining more complex services than one defined before. For instance, a push initiator can force a SI content to appear on the screen of a phone immediately the phone receives it, or instruct the phone to put it into box, so that the user can read it later. It is possible, too, to define a expiring time for a content. WAP Push uses established document defining standards, like XML and MIME and its protocols operates over well establised ones like HTTP and WSP (well, you can argue with that). This shortens the development cycle and reduces errors. WAP Push is an application layer protocol, and so in principle totally independent the transport layer used. So WAP 1 uses WSP/WTP and WAP 2 HTTP/TCP. WAP Push Protocols WAP Push suite defines protocols for sending content from server to a push capable phone. Confirmed push includes sending a confirmation from the phone to the gateway, and, if this is asked for, from the gateway to the initiator. There are two protocols: Push Over the Air Protocol and Push Access Protocol. OTA (Over The Air) protocol. Lightweight protocol used for sending content from gateway to the phone. It maps quite directly to WSP, but it is possible to use it with other protocols. PAP (Push Access Protocol) used for communications between a push initiator and a gateway. Protocol headers and protocol data are packed into XML documents, and, if necessary, MIME multipart messages and these documents or messages are exchanged over HTTP. Push can be unconfirmed or confirmed. Unconfirmed one goes following way (fetching the user may ask for is omitted): A push initiator send PAP message to a gateway, requesting a unconfirmed push of a content to the phone. The gateway makes an OTA request for pushing the data to the phone. It is delivered using WSP sessionless services. and confirmed (and session-oriented) one, see : A push initiator send PAP message to a gateway, requesting a confirmed push of a content to a phone. The gateway sends an OTA request to the phone, asking it to establish a session with it (a gateway cannot do this by itself), if there is no session already open. The phone establish a session using WAP protocol stack mechanisms. The gateway sends the content to the phone. The phone sends a confirmation to the gateway. The gateway sends a result notification, meaning a confirmation to the push initiator.
A confirmed WAP push
WAP Push XML languages PAP protocol data is packed into a XML document. Language used for this is called PAP. User data can be of any MIME type, however, there are specific contents expressed with specific languages: Service Indication and Service Loading. Service Indication (SI). A gateway sends this type of a document to a phone for a push initiator. It tells to the user that a service has come available. He can reject, accept or postpone pulling of it. The indication may not interrupt the currently running task of the phone. Service Loading (SL). This is for a quite similar service, except now pulling in principle starts without an user intervention. However, the phone may implement a security mechanism suggested by SL specification and ask the user does he want to start pulling. Duties of Push Proxy Gateway These are similar to WAP Gateway, because when pushing, the push application forms the external interface of a gateway. However, there is a possibility that PPG works very closely with PI, which does storing, billing and other similar services for it. This is a quite realistic alternative, because PI has the content and so it, not a "simple" gateway, provides visible services to the user. Of course, PPG must spare bandwith, too. Even though SI and SL documents are small (url being their main content) they must be delivered to the phone overs SMS. Difference between one and two SMS messages can be truly great indeed.
The Kannel Open Source WAP Gateway This chapter is the most important part of the thesis. It covers the design and implementation of the Kannel Open Source WAP Gateway. Introduction to and status of the project (1 p) This section describes the Kannel project at Wapit: why it was started, and when, and what its goals are. It gives general, very high level requirements for the gateway, from Wapit's point of view, and explains why the project is open source and not a proprietary thing. It gives the current status of the project and its product. It probably even covers why we use C and not Java. Wapit Ltd was founded in the fall of 1998 to develop services for mobile phone users, originally based on SMS. During the spring of 1999, when the company started growing and became more amibitious, it decided to start developing services and authoring tools for the upcoming WAP platform as well. As part of its strategy, it decided that it made sense to develop its own WAP gateway, and to make it as open source. There were few existing commercial gateways on the market, and all of them were quite expensive. Since Wapit intended to deliver its service platform to many customers all around the world, it would have been quite expensive to buy a new gateway for each customer. So expensive, in fact, that it was cheaper to develop a new one. On the other hand, since Wapit had no interest in making money directly from the gateway, it made sense to create an open source project to develop the gateway. This way, it would be possible to get help from other companies, and to some extent individuals, in developing the gateway, and specially in testing the gateway in various environment. The gateway project was launched in July, 1999, at the WAP Forum meeting in San Fransisco. The goal was to produce a gateway that was technically good enough at least for small operators and corporate level service providers. The author was hired at the end of June, 1999, to lead the project. By that time, there existed a very primitive proof of concept level prototype for an SMS gateway, which did not yet do anything for WAP. This was demonstrated in San Fransisco and it seemed that there was a huge interest in an open source WAP gateway. Wapit decided that it made sense to make a gateway that was both a WAP gateway and an SMS gateway, because there was already a huge existing user base of SMS capable users, and few or no WAP users. Also, WAP itself can benefit from SMS, for example via over-the-air configuration messages (OTA) for phones, to make it easier to configure the WAP phone for a particular operator or service. Initially, there was no formal requirements specification for the gateway - indeed, it did not even have a name. The gateway was just supposed to be `fast enough', but a more strict formulation was not even possible, since it was unclear what kinds of usage levels the intended customers would have. During the fall of 1999, the following formulation emerged:
Kannel Architecture and Design document The gateway needs to be able to serve thousands of concurrent users on reasonably priced hardware: less than ten PCs with high-end Intel CPUs, 128 MB of memory, fast network interfaces. It needs to be scalable to even higher levels of perfomance by adding more hardware (meaning that there can't be a single bottleneck that prevents more users from being served).
For reliability, the requirement was that when the gateway was being run on several hosts (the architecture allowed this), crash or failure of one node should not affect the others.
The gateway was finally named Kannel in January, 2000. A kannel is a traditional Finnish musical instrument, but the name has no meaning for the gateway; it is just a nice name. In the summer and fall of 2000, when this is being written, the gateway has been in light production use for several months, both as an SMS gateway and a WAP gateway.
Requirements This section lists the requirements of the gateway and its design. The gateway must be able to share load between several hosts. This is also necessary for fault tolerance. The gateway needs to be able to serve hundreds of concurrent users on a PC with a 400 MHz Pentium CPU, 128 MB of memory, 10 Mbit/s network interface. The gateway needs to be able to serve thousands of concurrent users on reasonably priced hardware: less than ten PCs with high-end Intel CPUs, 128 MB of memory, fast network interfaces. It needs to be scalable to even higher levels of performance by adding more hardware (meaning that there can't be a single bottleneck that prevents more users from being served). If one of the hosts running the gateway crashes (or the gateway component running on that host crashes), the rest of the gateway must continue to work. If the crashed component recovers, the rest of the gateway needs to start using it again. Likewise, for load balancing, new components must be able to connect to the rest of the gateway while running. Sessions and transactions that were running on the crashed component may be terminated, i.e., it is not necessary to migrate them to another component. The architecture design needs to be simple. We have limited resources, and it is simply not realistic to assume that a complicated design is implementable quickly. We can assume that performance is adequate as long as no single bottleneck exists in the design. The gateway needs to support both WAP and SMS services. New bearers and transport protocols must be simple to add. Gateway architecture This section explains the gateway architecture. It gives requirements in more detail for perfomance, scalability, reliability, and simplicity of implementation and adding new boxes at run time. It covers the division of gateway duties to processes (bearer, wap, and sms boxes), and explains the duties of each process. It covers interprocess communication between the different boxes, and covers gateway-level communication issues such as heartbeats. It should probably cover the different approaches to the design that were considered, and give the reasons for major (and some minor) design decisions. External interfaces of the gateway The gateway has interfaces to three external agents: SMS centers, using various protocols. HTTP servers, to fetch WAP and SMS content and to push WAP Content. The pull protocol is HTTP, push PAP. WAP phones, implementing the WAP protocol stack and (for push) WAP Push client.
External interfaces of Kannel
There are several vendors of SMS centers and most of them use a vendor specific protocol. The protocols are fairly similar in spirit, but the details of course differ. The differences are not relevant to this document, though. The protocols essentially follow the following pattern: Client logs into the SMS center. When an SMS message from a phone arrives, the SMS center sends it. The client is expected to acknowledge it. When the client wants to send an SMS message, it sends a request, and the SMS center acknowledges it. When the client is done, it logs out. The various SMS center protocols are implemented using somewhat different approaches within Kannel, but each implementation uses the same interface towards the rest of Kannel. This simplifies the rest of Kannel. Each SMS center account is bought from a mobile operator. Each account is assigned a number to which SMS messages are sent, and which typically also appears as the sender number for messages sent via that account. (Some connections will allow the account user to set the sender number, though.) There can usually be only one connection to an account at a time. This restricts Kannel's design somewhat. Multiple concurrent connections would allow for higher performance and reliability. The HTTP protocol is a fairly pure request-response protocol. The client connects to the server, sends a request, and then the server responds and this completes the transaction. Multiple requests may be done over the same connection, for performance, but the basic flavor of the protocol is still the same. The WAP protocol stack and WAP Push have already been briefly described above. In order to achieve maximum throughput, Kannel needs to be able to communicate with each external agent independently from each other, i.e, by multitasking internally. For example, it is not good enough to read one request via SMS or WAP, fetch the requested content via HTTP, send the content to whoever requested it, and only then read the next request. This might be fast enough, if the HTTP servers were extremely fast, but they are not. Each HTTP transaction can potentially take an indeterminate time, without failing, and Kannel must not let one slow request prevent every other client from getting service. What Kannel needs to do, then, is read requests from each external interface as fast as possible, and keep them in an internal queue. Then it needs to make the HTTP requests for the contents as fast as possible, and then send the responses back to the requesters. Depending on how fast the HTTP requests take, the responses will be sent to the requesters in different orders. Things needs to be designed so that this works. There is a potential reliability problem in this kind of design: if Kannel reads many requests into an internal queue, and crashes, the requests will be lost. This can be expensive to the clients, if they use SMS (whether for SMS based services or for WAP), because each SMS message costs money when it is received by Kannel, not when Kannel sends the response. Ideally, Kannel should keep the list in persistent memory (on disk), but it does not do so at the moment, because of implementation complexities.
Division of duties to processes: the boxes Kannel divides its various duties into three different kinds of processes, called boxes, Box seemed like a nice, non-technical term that should be understandable for marketing people, specially if each box is run on its own host. In this case, each Kannel box corresponds to a physical box, which should be clear enough. mostly based on what kinds of external agents it needs to interact with: The bearerbox implements the bearer level of WAP (the WDP layer). As part of this, it connects to the SMS centers. Kannel currently implements SMS only as a WAP push bearer. When it does this fully, its SMS gateway functionality will have to interact with the WDP layer: it needs to be possible to use a single SMS center connection for both textual SMS based services and as a WAP bearer. The smsbox implements the rest of the SMS gateway functionality. It receives textual SMS messages from the bearerbox, and interprets them as service requests, and responds to them in the appropriate way. The wapbox implements WAP protocol stack and WAP Push (an application level protocol). If wapbox is used for pushing, it is called Push Proxy Gateway or PPG Another term for fetching data is pulling For Kannel box structure for pulling, see , and for pushing, see .
Boxes of pull Kannel
There can be only one bearerbox, but any number of smsboxes and wapboxes. Duplicating the bearerbox is troublesome. If there were multiple bearerboxes, they would still have to be known by the same IP number for WAP phones, which needs help from network routers. Also, each SMS center can only be connected to by one client. While it would be possible to have each SMS center served by a different process, this has been deemed not to give enough extra reliability or scalability to warrant the complexity. Having multiple smsboxes or wapboxes can be beneficial when the load is very high. Although the processing requirements as such are fairly low per request, network bandwidth from a single machine, or at least operating system limits regarding the number of concurrent network connections are easier to work around with multiple processes, which can, if necessary, be spread over several hosts. Each box is internally multithreaded. For example, in the bearerbox, each SMS center connection is handled by a separate thread. The thread structures in each box are fairly static: the threads are mostly spawned at startup, instead of spawning a new one for each message.
Boxes of push Kannel
Making sure things are working: heartbeats In addition to shuffling packets between the phones (directly or via SMS centers) and the other boxes, also keeps track of the heartbeat of each box. Each box sends a heartbeat message, essentially saying `I am still alive', and the bearerbox will keep track of when each box has sent it last. If a box stops sending heartbeat messages for too long a time, the bearerbox will close the connection to it. A parameter to the hearbeat message is the load factor of the box. The bearerbox uses this to decide which box it should send each package to. If all boxes were alike, a simple round-robin system would usually work, but this is not something the bearerbox can assume.
The Bearer Box This section explain how the bearer box works: its internal architecture with messages, message queues, thread structure, heartbeats inside the box, and how communication between internal and external modules happens. At the moment, the bearerbox implements only UDP as a bearer for the WAP protocol stack. In the future, it will support SMS messages as well. The bearerbox already implements the necessary SMS center connections, but they are used for SMS gateway functionality only, and are thus ignored for this thesis. (This is true in spite of an implemented WAP Push. Using SMS as a pull bearer requires reassembly of SMS messages and routing them to one of wapboxes.) Once the thesis is submitted to the university, descriptions of the SMS gateway functionality will be added. The bearerbox receives UDP messages from the phones, sends them to wapboxes, receives reply messages from the wapboxes, and sends the corresponding UDP messages to the phones. Since there can be several wapboxes connected to a single bearerbox, the bearerbox needs to route the UDP packets so that all packets from the same phone are sent to the same wapbox. In practice, the routing problem is simplified so that all packets from the same IP number go to the same wapbox, even though it is not guaranteed that the IP number hasn't been assigned to a new phone. Phones are allocated IP numbers dynamically - when they make the data call, they get an IP number, and when they terminate the call, the IP number is released and can be allocated to the next caller. Thus, it might make sense for the bearerbox to know when a WAP session or transaction is finished so that when the new phone uses the same IP number, it can be assigned to a different wapbox with a lower load. In practice, however, this is unlikely to have much benefit, so the added complexity is useless. It will be added, of course, if benchmarks later show it to be useful. The bearerbox uses several internal threads and message queues. shows their structure. There can be multiple UDP sockets open, since the WAP protocol uses different UDP port numbers to identify the type of message: whether the message is for a session mode transaction or a sessionless transaction, whether it uses the security layer, etc. The bearerbox has a separate thread of type udp_receiver for each such UDP socket. That thread reads the UDP packets, converts them to message objects used internally within Kannel, and puts those into the incoming_wdp queue. All udp_receiver threads use the same queue. The wdp_to_wapboxes thread removes the messages from the incoming_wdp queue and routes them to the correct wapbox. Each wapbox is represented inside the bearerbox by a separate message queue and two threads: boxc_sender and boxc_reader. The wdp_to_wapboxes thread thus moves messages from the incoming_wdp queue to the wapbox specific queues. The boxc_sender thread removes the messages from the wapbox specific queue and sends them to the wapbox proper via a network connection. The message traffic in the other direction is a mirror image. The boxc_reader thread reads messages from the wapbox, via the network connection, and puts them in the outgoing_wdp queue. The wdp_router thread removes the messages from that queue and puts them in the queue specific for the socket, so that they will be sent from the correct port. The udp_sender thread then removes messages from the socket specific queue, converts them into UDP packets, and sends those to the phones. Multiple queues within the bearerbox were used because routing can change at any time. If a wapbox disappears, all messages waiting to be sent to it should be sent to other wapboxes instead, so that they can be dealt with in a useful manner. The bearerbox tries to balance the load between different wapboxes. This is implemented using heartbeat messages sent by the wapboxes to the bearerbox. Each wapbox computes its own load factor. In the current implementation, this is the number of open and pending HTTP transactions it has. Periodically, the wapboxes send a heartbeat message containing their load factor to the bearerbox. The bearerbox remembers the latest load factor it got from each wapbox and assigns each new phone to the wapbox with the lowest load factor. This keeps the wapboxes balanced approximately evenly in the long run. To make sure a sudden surge of new phones won't all be assigned to the same wapbox, the bearerbox increments the load factor it stores for each wapbox when it assigns a new phone to it.
Bearerbox architecture
The WAP Box This section explains how the WAP box works. It lists the features of WTP, WSP and WAP Push that are implemented. It covers internal architecture: data structures (state machines, events), thread structure, code modules, inter-module and inter-state machine communication, and probably explains the preprocessor trick used to ease the implementation immensely. When pulling, wapbox reads messages from the bearerbox, maintains internal state for each client and makes HTTP requests on behalf of clients. It responds to messages according to WAP specs. The basic duties are pretty simple, but things become somewhat more complex when need to deal with large loads. Only WTP and WSP are implemented. WTLS exists as a patch, but is not covered by this thesis. Only the UDP bearer for WDP is supported at the moment, which means that the Wireless Control Message Protocol (WCMP) is not implemented. Push can be confirmed or unconfirmed. Unconfirmed is simple: PPG sends the push content to the bearerbox (essentially asks it to do a sms push). If confirmed push is session-oriented, the gateway first asks the phone to establish a session with it. PPG maintains session and push data for initiators and send confirmations (result notifications) to them, if they have asked it. After both kind of pushes, Kannel can work as a pull gateway. Both unconfirmed and confirmed push are implemented, but only unconfirmed one is tested with a real phone. Wapbox does push over SMS, but resulting fetch uses an IP bearer. Thread structure Each WAP protocol stack layer has its own thread. Push OTA protocol implementation is divided between OTA layer (requests) and application (indications and confirmations) layer. There are two threads corresponding PAP protocol, one communicating with OTA layer and other accepting push requests from a push initiator (Session- oriented WSP and confirmed push, these are treated concurrently, because, as mentioned before, WAP Push is followed by a pull.): Bearerbox communication layer. This layer corresponds to the WDP layer inside the wapbox; network related parts of WDP are implemented in the bearerbox. Wapbox segmentates the push content before it sends it to the bearerbox, and selects the bearer. This layer is used for both pushing and pulling. WTP responder layer. This layer exchanges messages with the bearerbox communication thread and the session mode WSP thread, and manages WTP responder state machines. Messages coming from the phone are routed to this layer. This layer is used for pulling. WTP initiator layer. This is similar to WTP responder, but now the gateway starts the transaction. This layer is used for pushing. Session mode WSP layer. This layer exchanges messages with the WTP responder, WTP initiator, the application layer and OTA layer, and manages the WSP session, method and push state machines. This is used for both push and pull. Application layer. This layer exchanges messages with two WSP layers and makes HTTP requests on their behalf. In addition, it implements indications and confirmations of push OTA protocol for confirmed push, sending them to OTA layer. So it is used btoh for pushing and pulling. HTTP client layer. This layer implements the actual HTTP requests. It is independent of WAP protocol stack, and only implements the HTTP protocol. This layer is used for pulling, and it belongs to the application layer. OTA layer. This layer receives messages from PAP layer and makes OTA requests to sessionless and session mode WSP layers. It is used for pushing. PAP layer. This layer accepts HTTP or HTTPS requests from PI and it is used for pushing. If PPG is not configured for HTTPS, there are three threads: ota_read_thread, http_read_thread and pap_request_thread.If it is, there are three or four threads: https_read_thread is now mandatory, and http_read_thread is optional. ota_read_thread communicates with application layer. It sends push confirmations (called result notifications) to the push initiator. http_read_thread and https_read_threadaccept pushes from the push initiator. pap_request_threadparses MIME content sent, compiles pap control document, implements required PPG services and converts push content to the tokenized form. It informs push iniatiator, by sending relevant PAP messages to it, errors happened during these processess and communicates with OTA layer. Push application (PAP and OTA layers) layer are in principle independent of WAP protocol stack, but they do use WTP initiator and WSP pushing facitilies. This means that only WSP session facilities are common with push and pull. For usage of threads when pulling, see and when pushing, see . Here arrows marked with '1' refer session establishment, ones marked with '2' content pushing and ones marked with '3' push confirmation.
Wapbox thread structure for pulling
Sessionless WSP and unconfirmed push services use only a part of whole stack: Bearerbox communication layer. This layer is always the same. Sessionless WSP layer. This layer exchanges messages with the bearerbox communication layer, the application layer and OTA layer. It has no state machines as such, so it is very simple. It is completely independent of the WTP and session mode WSP layers, despite the name similarity. It can do both push and pull. Application layer. In this case, this layer is used only for pull: the phone sends no confirmation messages to the server. OTA layer. This is similar for confirmed and unconfirmed pushes. PAP layer. Now ota_read_thread is missing; it is used for receiving phone confirmations. All communication between internal (ones communicating with other Kannel layers) threads is via message queues. These layers (and therefore the threads) send events to each other, no other form of communication is used. Only the event data structures are exposed by each layer: all other data is internal to the layer, and is only manipulated by the single thread that implements that layer. This reduces the need for locking datastructures, which both simplifies the program code and makes execution faster. One layer of WAP Push (PAP) forms the external interface to the push initiator. Therefore it includes a HTTP server thread, which has an external originator for its events. In addition, Push implementation has an internal layer (OTA). The events used correspond to the ones used in the WAP protocol specification. Events related PAP protocol correspond attributes of XML document.There are minor differences due to implementation details, but it has been a goal to make the implementation follow the specification as closely as possible to reduce errors. However, making push over SMS requires adding quite many additional fields, but these are well separated from ones corresponding protocol primitives. An earlier design for the gateway spawned a new thread for each incoming WDP packet, had all data structures available to all threads, and had elaborate locking to get things to work. This proved too hard to get working in the everyone-hacks-everything style of program development adopted by the project because of its open source nature. Experiments also showed that it would have been too expensive, computation wise, at high levels of usage. The current design has a static thread structure. All threads are started when at program startup, and remain running until the program stops. There is a potential scalability problem on machines with a larger number of processors than the wapbox uses: many of the processors will be completely idle. It is, however, possible to run multiple wapboxes, so it should be easy to utilize them anyway. The implementation of each layer is basically the same: each has a queue of incoming events, to which other layers append events. The layer extracts an event from the queue, handles it, and possibly sends other events to other layers. The only locking needed is when accessing the event queue for each layer. The queue operations are very fast (constant time), so the time spent waiting for a lock is short.
Wapbox thread structure for pushing.
Implementation of protocol state machines The WTP and connection mode WSP layers are implemented in terms of state machines, as described in the WAP protocol specification. At the source code level, there are a number of various options for implementing state machines. To ensure the correctness, however, it is necessary to keep the source code easy to compare to the actual specification, and most options would obscure the actual protocol related parts of the implementation with unnecessary detail of state machine implementation. We have therefore taken an approach where we describe the state machine in the source code using a macro language (the C preprocessor) and use that to transform the description into compilable and efficient C code. See for more information. Implementation of push sessions WAP Push architecture makes possible for a push initiator to establish a connected session with a phone, so that it is unnecessary to reconnect every time. This session data is stored in a data structure similar to protocol state machines. Currently connectionless pushes are, too, implemented using a push machine. This will, however, change. Efficient implementation of HTTP requests It is necessary for a WAP gateway to implement HTTP requests at high usage levels efficiently. This is the only useful thing the WAP pull gateway does on behalf of the client, and there are potentially a very large number of clients, so the quality of the HTTP implementation affects gateway performance a lot. The straightforward solution would be to implement each HTTP request in a separate thread. This keeps the implementation simple, but is somewhat expensive in computation resources. For example, if there are ten thousand concurrent users, each making a new request every fifteen seconds, on average, and each request taking one second, on average, there are about 670 concurrent requests at any one time. On Linux, each thread uses 8 kilobytes of kernel memory, minimum, so 670 threads would use over 5 meagbytes of extra memory, in addition to userspace memory requirements such as stack. In addition, starting and stopping threads has a cost, and having lots of threads will cause more context switches, an additional CPU cost. Thus, while it works well at low usage levels, the straightforward solution will cause too much overhead at high usage levels. It is thus necessary to implement HTTP as a static number of threads, for performance reasons, even if it somewhat complicates the implementation. This is similar to the `C10K' problem () known to implementors of HTTP servers. Even though the hardware is more than fast enough to handle ten thousand simultaneous clients (ten thousand concurrent HTTP requests), the operating system and HTTP server software have designs and implementations that won't scale up to that high loads. A WAP gateway is very much similar to HTTP servers in this regard. The basic steps in making an HTTP request are, expressed in network operations, are: Look up the IP number for the HTTP server. This involves making a Domain Name Service (DNS) query, which can take up to several minutes, if the name server is slow or does not respond at all. Due to stupidities in C library interfaces, only one thread in a process can do a name lookup at a time. This will be discussed in more detail in . Open a TCP connection to the HTTP server. This can take some time, if the server is slow or the network is congested. Write the request. If the request is very large, this can again take quite a while, but for typical requests, it will be a single TCP packet. For the writer, the operation finishes when the data has been copied from the writer's buffers to the operating system network buffers, so typically this is very fast. Read the reply. Even if the reply is fairly short (and for WAP pages it almost always is only a few kilobytes), it can take several seconds for the reply to arrive from the HTTP server to the client. Close the connection. This should be very fast, since the client can continue processing immediatly and leave it to the operating system to negotiate closing with the HTTP server. Between these network operations, the HTTP client only waits. It has no other processing to do (the gateway as a whole might have other processing to do, but we're talking about the HTTP client thread). Thus, it won't even help to add more processors to the machine: even a single processor can execute quickly any number of idle threads. What does cost, however, is that every time one thread wakes up, it needs to be scheduled, and all its registers and possibly other data needs to be loaded to the processor. This takes processing time, and the more threads we have, the more often this will happen. If we only have one thread, it will be running all the time, since at any one time presumably at least some of the HTTP connections will be active, so it does have something to do. This will mostly eliminate context switch overhead on a multi-processor machine, which can allocate a processor for HTTP only. A single thread might, however, be too little at very large loads. If there are very many HTTP responses coming, more than a single processor can deal with, then it would make sense to have more threads, one per processor. This may happen in the future. To implement the single thread model, we need to wait for input from several sources at the same time. This is accomplished with one of the Unix system calls select and poll. These do essentially the same thing, but have different interfaces. They both get a list of network connections and wait until at least one of those has data waiting to be read in the operating system's buffers (meaning that the read operation can be done without the thread blocking). Thus, the thread essentially does this: Wait until there is something to read. Read it into a connection specific buffer. If the buffer has a complete HTTP reply, return it to whoever made the request. Repeat forever. Further details can be found in the source code. XXX explains how threads are really used in http Making concurrent domain name lookups The Domain Name Service (DNS) is an integral part of the Internet and implements a directory service that maps textual domain names into IP numbers, which are used in actually routing packages between hosts. It is implemented as a custom distributed database system, and has caching and other features to make it quite efficient. Unfortunately, the portable C library interface to it, the gethostbyname function, does not support concurrency. It is not thread safe, and even its thread-safe and somewhat portable version, gethostbyname_r, only protects against multiple concurrent calls, but often does not implement queries concurrently. This is a large efficiency problem, because it can take several minutes for a single request. It is also a security problem, because a malicious user could have the gateway to fetch large numbers of pages with domain names that take the maximum time each to look up. If the gateway can only do one request at a time, this will efficiently prevent any real users from using the gateway. There are several possible solutions to this. One would be to implement the DNS protocol within the gateway. This is problematic, because gethostbyname does more than DNS lookups: depending on how the host the program runs on has been configured, it can also look names up in files in various formats, and it can be quite important for a system administrator that the gateway follows this logic. It is therefore simpler to run sub-processes to do gethostbyname calls. Each sub-process does a single call at a time, but since there can be multiple sub-processes, concurrency is achieved. This does not, however, completely eliminate the security risk. An attacker could use the feature to cause the gateway to start huge numbers of sub-processes, each taking several minutes to do the host name lookups, and thus making the gateway host run slower because of the increased load. The sub-process implementation needs to deal with this in some way.
Converting XML languages and WMLScript to binary The conversion of WML and WMLScript to their binary forms is done by two fairly independent conversion modules. They are fairly simple applications of compiler theory. The WML compiler gets as its input the WML source code, plus whatever character set information that may have been present in the HTTP headers. It returns the binary form of the WML deck, or an error indication, if the page was faulty. The character set information is needed because the services and phones may generate and accept different character sets. XML, which is used to define WML, specifies Unicode, encoded with UTF-8, as the default, but this is not always practical to use in real life. In principle, the WML compilation process is very simple. The WML language is very easy to parse and the binary format follows closely the textual one, merely encoding start and end tags, attributes, and other parts of the language in a more compact form. There is, however, a feature that can be used to minimize the size of the output: string tables. When the textual content of the WML page is converted to binary form, it can contain references to a table of strings. As a simplification, think of this as each binary byte either being a character or an index to the string table. The WML compiler decides what goes into the string table. This allows the output text to be compressed: the WML compiler can fill the string table so that the total output of the binary form is minimized. The decision as to how the string table is filled needs to string compression techniques, which complicate the WML compiler somewhat. Push XML languages (SI, SL, CO) are similar to WML, but their compilation is even simpler (no variables here, for instance). They do not use a string table either, because push documents, which are sent over SMS, must be small. The WMLScript compiler is a more traditional programming language compiler. The binary output format is a bytecode, for which it is easy to write a small interpreter, suitable for a phone. Thus, the WMLScript compiler needs to parse the input file, form a parse tree of it, optimize the tree, then generate bytecode, and further optimize the bytecode. The output is a binary string, which can be sent to the phone as is. The WML compiler does some simple basic optimizations, such as constant expression elimination, but does not otherwise work very hard to keep the size of the output small. This could be improved, but since WMLScript programs have so far rarely been large, it has not been sensible to put the effort into this.
Experiences From Implementing and Using the Gateway This chapter discusses the experiences of the project, in a wholly subjective manner. It is divided into four parts. Part 1: Discussion of what was done right and what was done wrong in the project, with regard to architecture, implementation, and project management. Part 2: Discussion of how the open source development model has affected the project. Part 3: Benchmarks on how the gateway performas at various load levels, and how it recovers from crashing wap and bearer boxes. Experiment designs are explained and results presented and discussed. Part 4: Discussion of feedback from people using the gateway. Subjective evaluation In this section I try to evaluate the Kannel project and describe things we've done right and things we've done badly. Most of the problems have been in general project management issues, such as making up and keeping time schedules, and building up the development team at Wapit and the open source development community. During the first year of the project, approximately from June 1999 to August 2000, there was intensive pressure, from Wapit, as far as the development speed was concerned. At first, there was pressure to get at least something to work, to get something to sell. When the SMS gateway was ready for production use, in September 1999, the pressure switched to getting WAP working. When this happened, in January 2000, the pressure switched to implementing the whole specification and ensuring compatibility. These needs were mostly filled by the end of August 2000, or at least the features were there, even if the software still had some bugs. As soon as the first production installation was made, in September 1999, it was also necessary to fix bugs and implement missing things that the production installations needed. This slowed actual development down somewhat, but in general the quality of the software is higher because of early production use. We have been able to concentrate on things that are actually needed, instead of following a feature checklist made up by marketing or by users who hadn't ever used a gateway before. It has not, however, made it easy to predict development speed, since at any time it may become necessary to throw aside the current development task and fix a customer problem, and the Kannel team has often failed to accurately predict when a version with a desired feature set would be available. In hindsight, the intense pressure for development speed was probably too intense, and resulted in slower development speed. Although some amount of pressure is good for getting people to work faster, the Kannel team had too much stress, and this resulted in overly optimistic time schedules and when they slipped, in further stress. From a software engineering and management point of view, the only redeeming feature of Kannel's project management is that the software made it to the market sufficiently early and with sufficient quality in order to succeed. Building the Kannel development team at Wapit has been fairly straightforward. In June 1999 there were three people, including myself, and every couple months until March 2000 the team acquired a new member, and in December 2000 we were six people. Two people have left the team, one to another department inside Wapit, the other to another company. This slow growth of the team has worked out well, even though the almost constant need to train new people has cost somewhat in development speed. Building an open source development community around Kannel has proved to be a much harder task. Partly this is because Kannel is of interest to a fairly small group of people, but mostly it is because specially at the beginning the development discussions were not open, in practice, to people outside Wapit. Many of the discussions were held face to face between Wapit developers, or on internal Wapit mailing lists, and this effectively shut out outside developers. The situation has since changed, and the development community is now slowly growing. Our choice of open source license, which essentially allows anyone to do anything, as long as they credit Wapit in their documentation, may have had a negative impact on the growth on the development community, but this has not been investigated. Our license does not require other developers to publish their changes, and there are several other companies working on their own versions of Kannel, without submitting back any changes to the Kannel project. This is acceptable, according to the license, but may have cause the development community to grow slower. On the other hand, if a more forceful license, such as the (GPL), had been chosen, the other developers might not have wanted to use Kannel at all, since it is often perceived that the GPL makes it impossible to build a profitable business. It would be interesting to investigate this in the Kannel context, but we have not had sufficient time for this yet. The software development process itself has been loosely based on the spiral model although adapted to an open source development model, with rather fuzzy goals for each iteration. In short, the philosophy has been to get at least something working, so that people can try it out and even use it in production, and then improve and possibly rewrite it to make it better. Unlike many projects with this approach, the Kannel project has actually spent much time on the rewriting: code gets rewritten once it gets too buggy or it fits too badly with the parts around it that have changed. We have tried to keep the general architecture and internal interfaces clean, and thus rewrites have mostly been local. An excellent example of this is our HTTP implementation: the first one was made quickly, and served well for almost a year, and once its bugs and limitations in speed and features became problematic, it was rewritten completely from scratch without affecting the code calling more than by trivial calling convention changes. A small, but very important things we did correctly was to set up a `nag' script: a simple script to compile the current version, directly from the version control system, and mail the developers any error and warning messages. In principle, this script does what every developer should do, but it is hard to force developers to use a particular set of compilation options, and even if they are willing, it is easy to forget one. The script helps by doing it automatically for all developers, and by doing it systematically every night. Additionally, when the script was run on multiple platforms, every night, it helped find several portability problems. Later, we added some automatic test cases, which can be run by each developer. Even though the tests are simple, they do check for all the basic features of Kannel, and make sure that a change won't break those. As time goes by, we add more tests, making it easier to catch more and more mistakes. We recommend the nightly automatic compilation test and the automatic testing for all projects. Like most open source projects, we have been using a bug tracking system that anyone can browse. Our use of it has been unsystematic, though, with most bugs reported via email on the development mailing list. This has, at times, caused bugs to be ignored or forgotten. As Kannel gains users, bug tracking will have to become more systematic. Quality control in general has received rather little attenation from Kannel developers. Except for the simple automatic test suite described above, the general approach of the developers has been to make their code or changes available, via the version control system, as soon as possible, so that others can participate in the testing. This is partly good, because the developers do not even have access to all mobile devices to do a complete test, and partly bad, because those areas of Kannel that are hard to test or require specialized hardware, such as the SMS center protocol implementations, have been tested fairly lightly. On the whole, things have worked out, though. Effects of choosing to be open source An open source project, with an ever changing group of developers, each with their own goals for the software, is by necessity different from a traditional software project. The major effects of being open source for the Kannel project have been more varied testing, more people doing debugging, and a need to keep the source code simple. WAP is being used all around the world, and implemented on many phones that only work in certain parts of the world. Thus, for Kannel to be compatible with all phones, it needs to be tested by people around the world, and in a traditional software project this would be quite hard to do. As an open source project, Kannel has users from around the world, and they have helped in testing Kannel against almost all WAP capable phones in the world. Even though the testing is informal, i.e., there is no specific set of tests run by the users for each new Kannel version, it is quite effective: as soon as a new and incompatible phone becomes available, or if the developers break Kannel for some phone, the development mailing list gets bug reports. This informal and distributed approach to testing has been applied to most parts of Kannel development. The assumption is that if we have enough users, with different usage patterns, all or most code paths are exercised and if there are problems, we will hear about it. This, of course, flies in the face of conventional software engineering, but seems to work for us as it does for many open source projects. The distributed approach also applies to debugging. One of the popular slogans for open source development is when you have enough eyes, all bugs are shallow (see ). This does not mean that all bugs are easy to solve, but if there is an urgent problem with Kannel, there will usually be many people working on finding it. They all work independently, but communicate about theirs findings and share theories. The end result is that the process of finding a particular bug is sped up significantly compared to having only one or two people working on it. With many people working on same parts of the code together, communicating only over e-mail, it is important for the source code and program structure to be simple, so that everyone can understand it and so that fewer mistakes are made because of, for example, complicated interfaces or arcane programming tricks. Those parts that are complicated or tricky also tend cause more questions and more bugs. The major impact of being open source, however, is more time spent communicating over e-mail. In a traditional project, much information is shared only orally, but since e-mail is the only common communication medium for the Kannel project, more time is spent reading and writing e-mail. On the other hand, much less time is spent sitting in meetings, and on the average the communication cost is probably about the same for Kannel as it would be if the project wasn't open source. Benchmarks XXX This section will be written after I have some time to do some benchmarking. It will probably be the last one I write. User feedback and experiences XXX I will have to send out some questions to users@kannel.org, devel@kannel.org and talk to our sales and marketing people at Wapit. Time enough to do that later. Plans for the Future This chapter discusses the plans for the future of the gateway: implementation of missing features (specially WTLS and WCMP), more bearers, updates to new versions of WAP. It also outlines needs and plans for higher reliability (keeping transactions and sessions alive over box crashes) and load balancing (migrating jobs between boxes according to load). New features The Kannel gateway has been ready for production use since September, 1999 as an SMS gateway, and June, 2000 as a WAP gateway. This does not mean that it is finished. On the contrary, it is only the beginning, and many important features are missing. Being merely important, they are not necessary for all production use, and thus they can be implemented even after the software is being employed. Among the missing features are the WAP security layer (WTLS), features from new versions of the WAP specification (WAP 1.2 and the June 2000 versions), and using other WAP bearers than UDP, specially SMS messages. Some of the work for these is already going on. There is an implementation of WTLS for Kannel, provided by 3UI.COM, but this has not been integrated into Kannel source code, because of legal and technical issues. The legal ones, involving patents and usage and export restrictions on cryptographic software in USA and other countries, are solved, or can easily be solved, and WTLS is now being added to the Kannel source repository. Using SMS messages as a bearer for WAP, i.e., implementing WDP over SMS, will require implementing the Wireless Control Message Protocol (WCMP) as well. Since SMS messages are so small compared to UDP messages, it is then also necessary to implement segmentation and reassembly of WDP packets into multiple SMS messages, and this will result in a substantial WDP layer. Wapbox does segmentation for WAP Push, but reassembly of received SMS remains to be implemented. Better quality In addition to new features, Kannel can be improved as regards to security, reliability and speed. At the moment, Kannel is open to several forms of denial-of-service attacks. This is a security problem. The most common form of these potential attacks is feeding it too much data, causing it to run out of memory, and crash. Kannel design needs to be adapted so that it won't try to buffer too much data read from the network. This will require changes in several parts of Kannel, but they will be small and mostly local. Many Internet server programs written in C suffer from a 'buffer overrun' type of security problem: the program has a bug that allows an attacker to feed it enough data so that it overruns the bounds for an array. The C language design is such that this kind of programming mistake is easy to make. Kannel uses an internal abstraction, called the octet string, which reduces the risk for this problem to the level of any programming language with array bounds checking. The main reliability problem Kannel has is that it will lose SMS messages it has received from an SMS center if it crashes. Kannel should store the messages in persistent memory so that it can recover from a crash without losing messages. This is important for SMS use, because each message potentially costs money to the end user. WAP session data will also be lost, but this is unimportant, and will easily be re-established by the phone, in some cases invisibly to the user. Of course, when WAP uses SMS as a bearer, it should not lose the SMS messages related to WAP, either, even if the session data itself is lost. There are several possibilities for a persistent storage for SMS messages, but this issue has not yet been studied by the Kannel developers. To improve application reliability, Kannel should allow users using its SMS push feature ("sendsms") to track which messages have been delivered, and which have not. This will require bookkeeping by both the bearerbox and the smsbox, and the design will have to be done carefully to avoid bottlenecks and keep performance up. It is not a good idea, for example, to respond to the sendsms HTTP request only after the message has actually been sent to the phone, since this will require keeping so many more HTTP connections open that socket port numbers will run out at high load. Kannel is about as fast as the speed requirements made for it in the fall of 1999 dictate: at least a hundred SMS messages per second and a hundred WAP requests per second. In some installations, this is not quite enough at peak traffic levels, and thus Kannel performance will require some attention in the future. It may be necessary to change the architecture somewhat, to require less message passing and less locking, but no benchmarking or profiling has been done yet to warrant changes. It should be possible, however, to speed Kannel up by an order of magnitude, if it becomes necessary. The current design and implementation stress simplicity, not performance. Migrating jobs between smsboxes or wapbox might improve performance as well. Then if one box becomes loaded much more than the other ones, it could move some of its load to the other boxes, and thus even the load. However, since the transactions tend to be very small, spreading the load only at the start of the transactions is probably enough. This needs benchmarking and profiling. Bibliography Imperial Earth Arthur C. Clarke 1975 Science fiction novel featuring mobile computing devices. Star Trek Gene Roddenberry Popular science fiction TV series shown since 1966. Has mobile communication devices. The Cathedral and the Bazaar Eric S. Raymond Essay on how open source development paradigms work. See http://www.catb.org/~esr/writings/cathedral-bazaar/ GNU GENERAL PUBLIC LICENSE Free Software Foundation License used by the Free Software Foundation for the GNU Project. See http://www.fsf.org/copyleft/gpl.html. Wireless Application Protocol White Paper WAP Forum Overview document about WAP. See http://www.wapforum.org/what/WAP_white_pages.pdf. Wireless Application Protocol Architecture Specification WAP Forum Describes the general architecture of WAP, the place of the gateway in it, and the various layers of the WAP protocol stack. See http://www.wapforum.org. C Preprocessor Trick For Implementing Similar Data Types Lars Wirzenius A C preprocessor trick for handling many similar structured data types, such as packets in a communication protocol, is described and justified. See http://liw.iki.fi/liw/texts/cpp-trick.html. The C10K problem Dan Kegel A few notes on how to configure operating systems and write code to support thousands of clients. See http://www.kegel.com/c10k.html.
gateway-1.4.5/doc/arch/kannel-boxes.fig0000644000175000017500000000447507225127421016437 0ustar toljtolj#FIG 3.2 Landscape Center Metric A4 100.00 Single -2 1200 2 6 45 810 990 1620 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 990 1620 990 810 45 810 45 1620 990 1620 4 0 0 50 0 0 12 0.0000 4 135 375 270 1170 SMS\001 4 0 0 50 0 0 12 0.0000 4 105 480 270 1395 center\001 -6 6 90 1755 990 2520 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 990 2520 990 1755 90 1755 90 2520 990 2520 4 0 0 50 0 0 12 0.0000 4 135 420 270 2070 WAP\001 4 0 0 50 0 0 12 0.0000 4 180 450 270 2295 phone\001 -6 6 5760 1125 6795 2205 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 6795 2205 6795 1125 5760 1125 5760 2205 6795 2205 4 0 0 50 0 0 12 0.0000 4 135 450 5985 1530 HTTP\001 4 0 0 50 0 0 12 0.0000 4 90 480 5985 1755 server\001 -6 6 1665 1260 3060 1935 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 1665 1260 3060 1260 3060 1935 1665 1935 1665 1260 4 0 0 50 0 0 12 0.0000 4 135 780 1935 1620 Bearerbox\001 -6 6 3780 720 4860 1305 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 3780 720 4860 720 4860 1305 3780 1305 3780 720 4 0 0 50 0 0 12 0.0000 4 135 600 3915 1035 Smsbox\001 -6 6 3870 2070 4905 2700 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 3870 2070 4905 2070 4905 2700 3870 2700 3870 2070 4 0 0 50 0 0 12 0.0000 4 180 630 4050 2385 Wapbox\001 -6 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 5265 3285 5265 180 1395 180 1395 3285 5265 3285 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 1080 1125 1575 990 1800 1215 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 3060 1485 3330 1125 3735 1035 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 3060 1710 3420 2160 3780 2205 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 4905 2430 5400 2430 5670 1980 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 4905 990 5400 900 5715 1395 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 1035 2115 1530 2340 1800 2025 0.000 -1.000 0.000 4 0 0 50 0 0 12 0.0000 4 135 540 1710 3240 Kannel\001 4 0 0 50 0 0 12 0.0000 4 180 1035 1755 990 SMS protocol\001 4 0 0 50 0 0 12 0.0000 4 135 930 1710 2385 WAP stack\001 4 0 0 50 0 0 12 0.0000 4 135 450 5400 855 HTTP\001 4 0 0 50 0 0 12 0.0000 4 135 450 5400 2655 HTTP\001 gateway-1.4.5/doc/arch/wapbox-threads.fig0000644000175000017500000000617107225127421016774 0ustar toljtolj#FIG 3.2 Landscape Center Metric A4 100.00 Single -2 1200 2 6 135 1035 6705 8505 6 2700 7155 4275 8055 6 2925 7290 4050 7875 4 0 0 50 0 0 12 0.0000 4 135 780 2925 7425 Bearerbox\001 4 0 0 50 0 0 12 0.0000 4 135 1095 2925 7650 communcation\001 4 0 0 50 0 0 12 0.0000 4 135 480 2925 7875 thread\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2700 7155 4275 7155 4275 8055 2700 8055 2700 7155 -6 6 1395 4230 2970 5130 6 1620 4410 2475 4995 4 0 0 50 0 0 12 0.0000 4 135 855 1620 4545 Connection\001 4 0 0 50 0 0 12 0.0000 4 135 840 1620 4770 mode WSP\001 4 0 0 50 0 0 12 0.0000 4 135 480 1620 4995 thread\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 1395 4230 2970 4230 2970 5130 1395 5130 1395 4230 -6 6 2655 2835 4230 3735 6 2880 3105 3780 3465 4 0 0 50 0 0 12 0.0000 4 180 870 2880 3240 Application\001 4 0 0 50 0 0 12 0.0000 4 135 480 2880 3465 thread\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2655 2835 4230 2835 4230 3735 2655 3735 2655 2835 -6 6 2655 1530 4230 2430 6 2880 1800 3375 2160 4 0 0 50 0 0 12 0.0000 4 135 450 2880 1935 HTTP\001 4 0 0 50 0 0 12 0.0000 4 135 480 2880 2160 thread\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2655 1530 4230 1530 4230 2430 2655 2430 2655 1530 -6 6 1395 5625 2970 6525 6 1620 5850 2115 6210 4 0 0 50 0 0 12 0.0000 4 135 390 1620 5985 WTP\001 4 0 0 50 0 0 12 0.0000 4 135 480 1620 6210 thread\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 1395 5625 2970 5625 2970 6525 1395 6525 1395 5625 -6 6 3870 4860 5445 5760 6 4095 5220 5265 5580 4 0 0 50 0 0 12 0.0000 4 135 1170 4095 5355 Connectionless\001 4 0 0 50 0 0 12 0.0000 4 135 915 4095 5580 WSP thread\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 3870 4860 5445 4860 5445 5760 3870 5760 3870 4860 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 135 1035 6705 1035 6705 8505 135 8505 135 1035 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 2655 7380 2025 7155 1935 6615 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 4320 7560 4770 6840 4815 5805 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 2115 5625 2115 5130 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 2115 4185 2115 3645 2655 3240 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 3 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 4725 4815 4770 3555 4275 3240 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 3375 2835 3375 2430 0.000 0.000 -6 6 2655 45 4185 810 2 2 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 2655 45 4185 45 4185 810 2655 810 2655 45 4 0 0 50 0 0 12 0.0000 4 135 975 2925 405 HTTP server\001 -6 6 2835 8820 4185 9630 2 2 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 2835 8820 4185 8820 4185 9630 2835 9630 2835 8820 4 0 0 50 0 0 12 0.0000 4 135 780 3150 9270 Bearerbox\001 -6 3 2 0 1 0 7 50 0 -1 4.000 0 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 3465 8055 3465 8820 0.000 0.000 3 2 0 1 0 7 50 0 -1 4.000 0 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 3330 855 3330 1530 0.000 0.000 4 0 0 50 0 0 12 0.0000 4 180 630 315 1305 Wapbox\001 gateway-1.4.5/doc/arch/wap-session.fig0000644000175000017500000000423507225127421016313 0ustar toljtolj#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 6 135 495 810 1755 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 135 720 810 720 810 1755 135 1755 135 720 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 225 810 720 810 720 1170 225 1170 225 810 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 720 720 585 720 585 495 720 495 720 720 -6 6 5040 495 6300 2025 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5040 990 5625 990 5625 2025 5040 2025 5040 990 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5040 990 5670 495 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5633 990 6263 495 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5659 1995 6289 1500 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5670 495 6300 495 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 6300 495 6300 1485 -6 6 2655 495 3915 2025 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2655 990 3240 990 3240 2025 2655 2025 2655 990 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 2655 990 3285 495 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 3248 990 3878 495 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 3274 1995 3904 1500 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 3285 495 3915 495 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 3915 495 3915 1485 -6 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 3 1 1 1.00 60.00 120.00 810 810 1980 495 2835 810 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 3 1 1 1.00 60.00 120.00 810 990 2025 1035 2565 1080 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 5 1 1 1.00 60.00 120.00 3960 1035 4590 1035 5040 1215 4635 1395 3915 1260 0.000 -1.000 -1.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 3 1 1 1.00 60.00 120.00 2565 1575 2025 1665 855 1485 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 3 1 1 1.00 60.00 120.00 855 1620 1890 1980 2610 1845 0.000 -1.000 0.000 4 0 0 50 0 0 10 0.0000 4 135 870 990 1440 page to phone.\001 4 0 0 50 0 0 10 0.0000 4 105 1830 900 2205 5. Phone closes WAP session.\001 4 0 0 50 0 0 10 0.0000 4 135 1755 1035 900 2. Phone sends URL request.\001 4 0 0 50 0 0 10 0.0000 4 135 1800 1080 405 1. Phone opens WAP session.\001 4 0 0 50 0 0 10 0.0000 4 135 690 4050 720 3. Gateway\001 4 0 0 50 0 0 10 0.0000 4 105 825 4050 900 fetches URL.\001 4 0 0 50 0 0 10 0.0000 4 135 1560 990 1260 4. Gateway sends encoded\001 gateway-1.4.5/doc/arch/conf-push-session.fig0000644000175000017500000000370207361052630017424 0ustar toljtolj#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 270 585 855 585 855 2025 270 2025 270 585 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 720 225 810 225 810 585 720 585 720 225 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 360 765 765 765 765 1170 360 1170 360 765 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 4545 45 5625 45 5625 2385 4545 2385 4545 45 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 4680 1980 5535 1980 5535 2160 4680 2160 4680 1980 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 4680 1710 5535 1710 5535 1890 4680 1890 4680 1710 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 4680 1395 5535 1395 5535 1575 4680 1575 4680 1395 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 4680 1080 5535 1080 5535 1260 4680 1260 4680 1080 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 4680 720 5535 720 5535 900 4680 900 4680 720 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2250 315 2925 315 2925 2070 2250 2070 2250 315 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2340 990 2835 990 2835 1125 2340 1125 2340 990 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2340 1395 2610 1395 2610 1485 2340 1485 2340 1395 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 4410 585 3015 585 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 2115 630 900 630 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 945 1125 2160 1125 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 2160 1620 945 1620 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 3060 1530 4410 1530 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 990 1890 2160 1890 4 0 0 50 0 0 10 0.0000 4 135 765 3240 450 push request\001 4 0 0 50 0 0 10 0.0000 4 135 915 1080 495 session request\001 4 0 0 50 0 0 10 0.0000 4 105 1335 945 945 session establishment\001 4 0 0 50 0 0 10 0.0000 4 135 825 990 1485 push delivery\001 4 0 0 50 0 0 10 0.0000 4 105 810 990 1800 confirmation\001 4 0 0 50 0 0 10 0.0000 4 105 1140 3060 1350 result notification\001 gateway-1.4.5/doc/arch/kannel-push-boxes.fig0000644000175000017500000000246607361052630017412 0ustar toljtolj#FIG 3.2 Landscape Center Metric A4 100.00 Single -2 1200 2 6 5760 1125 6795 2205 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 6795 2205 6795 1125 5760 1125 5760 2205 6795 2205 4 0 0 50 0 0 12 0.0000 4 135 450 5985 1530 HTTP\001 4 0 0 50 0 0 12 0.0000 4 90 480 5985 1755 server\001 -6 6 1665 1260 3060 1935 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 1665 1260 3060 1260 3060 1935 1665 1935 1665 1260 4 0 0 50 0 0 12 0.0000 4 135 780 1935 1620 Bearerbox\001 -6 6 3825 1260 4860 1890 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 3825 1260 4860 1260 4860 1890 3825 1890 3825 1260 4 0 0 50 0 0 12 0.0000 4 180 630 4005 1575 Wapbox\001 -6 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 5265 3285 5265 180 1395 180 1395 3285 5265 3285 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 135 810 720 810 720 2790 135 2790 135 810 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 1350 1485 720 1485 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 3780 1530 3060 1530 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 5715 1530 4905 1530 4 0 0 50 0 0 12 0.0000 4 135 540 1710 3240 Kannel\001 4 0 0 50 0 0 12 0.0000 4 135 930 1710 2385 WAP stack\001 4 0 0 50 0 0 10 0.0000 4 105 360 225 1305 WAP\001 4 0 0 50 0 0 10 0.0000 4 135 360 225 1755 phone\001 gateway-1.4.5/doc/arch/pushbox-threads.fig0000644000175000017500000000721107361052630017160 0ustar toljtolj#FIG 3.2 Landscape Center Metric A4 100.00 Single -2 1200 2 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 7290 2970 9090 2970 9090 3510 7290 3510 7290 2970 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 4 4050 2790 6435 2790 6435 3690 9405 3690 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 4230 3015 6120 3015 6120 3555 4230 3555 4230 3015 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5715 2025 7920 2025 7920 2565 5715 2565 5715 2025 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 7335 3870 9090 3870 9090 4365 7335 4365 7335 3870 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 7335 4590 9090 4590 9090 4995 7335 4995 7335 4590 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 4050 990 9405 990 9405 5175 4050 5175 4050 990 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5715 1215 7920 1215 7920 1755 5715 1755 5715 1215 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 7155 540 7155 180 6435 180 6435 540 7155 540 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 7200 5895 7200 5400 6435 5400 6435 5895 7200 5895 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 6795 540 6795 1215 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 6795 1755 6795 2025 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 6750 2565 5085 3015 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 5130 3555 5130 5400 6435 5535 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 7200 5580 8190 5355 8190 4995 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 8145 4635 8145 4365 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 8145 3870 8145 3465 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 8280 2925 8280 1440 7920 1440 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 7200 1755 7200 2025 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 7020 2565 7020 4185 7335 4185 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 7875 4365 7875 4590 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 0 0 1.00 60.00 120.00 7875 4995 7875 5310 7200 5490 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 7020 1170 7020 540 4 0 0 50 0 0 14 0.0000 4 150 915 4275 1440 KANNEL\001 4 0 0 50 0 0 14 0.0000 4 195 900 4230 1890 Push layer\001 4 0 0 50 0 0 14 0.0000 4 150 480 4410 4050 WAP\001 4 0 0 50 0 0 14 0.0000 4 150 465 4500 4410 stack\001 4 0 0 50 0 0 12 0.0000 4 180 765 5850 1530 PAP layer\001 4 0 0 50 0 0 12 0.0000 4 135 1350 4275 3285 Sessionless WSP\001 4 0 0 50 0 0 12 0.0000 4 135 1320 7425 4095 Session-oriented\001 4 0 0 50 0 0 12 0.0000 4 135 900 5850 2385 OTA thread\001 4 0 0 50 0 0 12 0.0000 4 135 480 4635 3510 thread\001 4 0 0 50 0 0 12 0.0000 4 180 1395 7380 3330 Application thread\001 4 0 0 50 0 0 12 0.0000 4 135 915 7605 4320 WSP thread\001 4 0 0 50 0 0 12 0.0000 4 135 1650 7380 4860 WTP Iniatiator thread\001 4 0 0 50 0 0 12 0.0000 4 135 165 6660 405 PI\001 4 0 0 50 0 0 12 0.0000 4 135 465 6570 5670 Phone\001 4 0 0 50 0 0 12 0.0000 4 135 90 6615 855 1\001 4 0 0 50 0 0 12 0.0000 4 135 90 6660 1980 1\001 4 0 0 50 0 0 12 0.0000 4 135 90 6570 2880 1\001 4 0 0 50 0 0 12 0.0000 4 135 90 5310 4230 1\001 4 0 0 50 0 0 12 0.0000 4 135 90 7650 5715 1\001 4 0 0 50 0 0 12 0.0000 4 135 90 8280 4545 1\001 4 0 0 50 0 0 12 0.0000 4 135 90 8370 3780 1\001 4 0 0 50 0 0 12 0.0000 4 135 90 8460 2070 1\001 4 0 0 50 0 0 12 0.0000 4 135 90 7425 1980 2\001 4 0 0 50 0 0 12 0.0000 4 135 90 6885 3240 2\001 4 0 0 50 0 0 12 0.0000 4 135 90 7740 4545 2\001 4 0 0 50 0 0 12 0.0000 4 135 90 7380 5355 2\001 4 0 0 50 0 0 12 0.0000 4 135 90 8550 4545 3\001 4 0 0 50 0 0 12 0.0000 4 135 90 8550 3780 3\001 4 0 0 50 0 0 12 0.0000 4 135 90 7920 5760 3\001 4 0 0 50 0 0 12 0.0000 4 135 90 8685 2115 3\001 4 0 0 50 0 0 12 0.0000 4 135 90 7200 945 3\001 gateway-1.4.5/doc/arch/bearerbox-arch.fig0000644000175000017500000001107307225127421016725 0ustar toljtolj#FIG 3.2 Landscape Center Metric A4 100.00 Single -2 1200 2 6 2520 270 3285 900 6 2655 405 3195 765 4 0 0 50 0 0 12 0.0000 4 135 375 2655 540 UDP\001 4 0 0 50 0 0 12 0.0000 4 135 510 2655 765 socket\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 2520 270 3285 270 3285 900 2520 900 2520 270 -6 6 495 2565 1980 3015 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 495 2565 1980 2565 1980 3015 495 3015 495 2565 4 0 0 50 0 0 12 0.0000 4 180 1080 675 2835 incoming_wdp\001 -6 6 1710 7110 3195 7695 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 1710 7110 3195 7110 3195 7695 1710 7695 1710 7110 4 0 0 50 0 0 12 0.0000 4 180 1140 1845 7380 wapbox socket\001 -6 6 360 1575 2070 2025 1 1 0 1 0 7 50 0 -1 0.000 1 0.0000 1215 1800 855 225 1215 1800 2070 2025 4 0 0 50 0 0 12 0.0000 4 180 975 675 1845 udp_receiver\001 -6 6 2745 1530 4365 1980 1 1 0 1 0 7 50 0 -1 0.000 1 0.0000 3555 1755 810 225 3555 1755 4365 1980 4 0 0 50 0 0 12 0.0000 4 180 870 3105 1800 udp_sender\001 -6 6 315 6255 2025 6705 1 1 0 1 0 7 50 0 -1 0.000 1 0.0000 1170 6480 855 225 1170 6480 2025 6705 4 0 0 50 0 0 12 0.0000 4 180 960 675 6525 boxc_sender\001 -6 6 3105 6390 4815 6750 1 1 0 1 0 7 50 0 -1 0.000 1 0.0000 3960 6570 855 180 3960 6570 4815 6750 4 0 0 50 0 0 12 0.0000 4 180 930 3510 6615 boxc_reader\001 -6 6 3330 5175 4725 5670 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 3330 5175 4725 5175 4725 5670 3330 5670 3330 5175 4 0 0 50 0 0 12 0.0000 4 180 1050 3420 5445 outgoing_wdp\001 -6 6 540 4995 1935 5580 6 675 5085 1620 5445 4 0 0 50 0 0 12 0.0000 4 180 915 675 5220 box specific\001 4 0 0 50 0 0 12 0.0000 4 135 240 675 5445 list\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 540 4995 1935 4995 1935 5580 540 5580 540 4995 -6 6 270 3600 2160 4230 1 1 0 1 0 7 50 0 -1 0.000 1 0.0000 1215 3915 945 315 1215 3915 2160 4230 4 0 0 50 0 0 12 0.0000 4 180 1410 630 4005 wdp_to_wapboxes\001 -6 6 3150 3735 4770 4185 1 1 0 1 0 7 50 0 -1 0.000 1 0.0000 3960 3960 810 225 3960 3960 4770 4185 4 0 0 50 0 0 12 0.0000 4 180 855 3510 4050 wdp_router\001 -6 6 3375 2610 4860 3285 6 3465 2745 4635 3105 4 0 0 50 0 0 12 0.0000 4 180 1155 3465 2880 socket specific\001 4 0 0 50 0 0 12 0.0000 4 135 240 3465 3105 list\001 -6 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 3375 2610 4860 2610 4860 3285 3375 3285 3375 2610 -6 6 540 7290 1350 7875 4 0 0 50 0 0 12 0.0000 4 135 390 540 7425 write\001 4 0 0 50 0 0 12 0.0000 4 135 675 540 7650 message\001 4 0 0 50 0 0 12 0.0000 4 135 780 540 7875 via socket\001 -6 6 3960 7110 4860 7695 4 0 0 50 0 0 12 0.0000 4 135 330 3960 7245 read\001 4 0 0 50 0 0 12 0.0000 4 135 675 3960 7470 message\001 4 0 0 50 0 0 12 0.0000 4 135 900 3960 7695 from socket\001 -6 6 5355 6300 7110 7875 1 1 0 1 0 7 50 0 -1 0.000 1 0.0000 5940 6570 585 270 5940 6570 6525 6840 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5490 7290 7110 7290 7110 7875 5490 7875 5490 7290 4 0 0 50 0 0 12 0.0000 4 135 525 5670 6660 Thread\001 4 0 0 50 0 0 12 0.0000 4 135 1110 5670 7560 Data structure\001 -6 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 2475 765 1485 1485 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 1215 2070 1215 2520 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 3870 1440 3330 765 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 3915 2565 3825 1980 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 1215 3060 1215 3555 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 1260 4275 1215 4995 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 1215 5580 1170 6255 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 3 1 1 1.00 60.00 120.00 1170 6750 1215 7425 1665 7560 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 3 1 1 1.00 60.00 120.00 3240 7515 3735 7335 3915 6795 0.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 4005 6390 4050 5715 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 4050 5085 4050 4230 0.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 0 2 1 1 1.00 60.00 120.00 4050 3645 4050 3330 0.000 0.000 4 0 0 50 0 0 12 0.0000 4 180 1305 585 1080 read UDP packet\001 4 0 0 50 0 0 12 0.0000 4 180 1365 4050 1215 write UDP packet\001 4 0 0 50 0 0 12 0.0000 4 135 630 450 2295 enqueue\001 4 0 0 50 0 0 12 0.0000 4 135 630 450 4635 enqueue\001 4 0 0 50 0 0 12 0.0000 4 135 630 4140 6120 enqueue\001 4 0 0 50 0 0 12 0.0000 4 180 630 4095 4725 dequeue\001 4 0 0 50 0 0 12 0.0000 4 180 630 450 3285 dequeue\001 4 0 0 50 0 0 12 0.0000 4 180 630 405 5985 dequeue\001 4 0 0 50 0 0 12 0.0000 4 135 630 4140 3555 enqueue\001 4 0 0 50 0 0 12 0.0000 4 180 630 4005 2340 dequeue\001 gateway-1.4.5/doc/arch/wap-arch.fig0000644000175000017500000000367607225127421015555 0ustar toljtolj#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 6 225 900 765 2205 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 225 1080 765 1080 765 1890 225 1890 225 1080 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 315 1170 675 1170 675 1395 315 1395 315 1170 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 675 1080 585 1080 585 900 675 900 675 1080 4 0 0 50 0 0 10 0.0000 4 105 375 315 2205 Phone\001 -6 6 1755 315 3690 2880 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 1755 1215 2745 1215 2745 2835 1755 2835 1755 1215 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 1755 1215 2700 315 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 2732 1215 3677 315 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 2732 2853 3677 1953 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 2700 315 3690 315 3690 1980 -6 6 5400 225 7335 2790 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5400 1125 6390 1125 6390 2745 5400 2745 5400 1125 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5400 1125 6345 225 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 6377 1125 7322 225 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 6377 2763 7322 1863 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 6345 225 7335 225 7335 1890 -6 6 1890 1620 2565 2385 4 0 0 50 0 0 10 0.0000 4 105 390 1890 1755 WML\001 4 0 0 50 0 0 10 0.0000 4 105 660 1890 1950 conversion\001 4 0 0 50 0 0 10 0.0000 4 105 615 1890 2145 from text\001 4 0 0 50 0 0 10 0.0000 4 135 555 1890 2340 to binary\001 -6 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 3825 990 5265 990 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 810 1395 1665 1395 4 0 0 50 0 0 10 0.0000 4 105 915 5490 3105 Content server\001 4 0 0 50 0 0 10 0.0000 4 135 930 2025 3150 WAP Gateway\001 4 0 0 50 0 0 10 0.0000 4 105 390 5715 1890 WML\001 4 0 0 50 0 0 10 0.0000 4 105 330 5715 2085 pages\001 4 0 0 50 0 0 10 0.0000 4 135 390 5715 2280 (text)\001 4 0 0 50 0 0 10 0.0000 4 105 705 945 1215 WAP stack\001 4 0 0 50 0 0 10 0.0000 4 105 1140 4140 855 HTTP and TCP/IP\001 gateway-1.4.5/doc/wtls/0000755000175000017500000000000013312227710013420 5ustar toljtoljgateway-1.4.5/doc/wtls/fig8o.png0000644000175000017500000006764207374232663015177 0ustar toljtolj‰PNG  IHDReÛÅzètIMEÑ :g’î pHYsÊ&ó?gAMA± üao1IDATxÚì}P]ç߯dKB²#d+±-9ö ÙSж¶4Ù¶¡?"o›™í$0qF8; šf!“,$üQ£$5d;F3Pã,¬ÛvZHwG(JwÁœÒDÙÖ‹-d[‚Xè~|~«ÇÇçÞ{îû=çžûûüqçÜsžóœç<çyžïó{^W­¬¬„<âÒ¥KEEEû÷ï—3íí탃ƒÓÓÓvg###•••1}›œœÜ¶mÛ–-[V­Z555UZZêpP\\<>>ŽûIžµsçN"Àœ={v×®]‰¾¯€·Û·o÷*EQ”,°ÚÃg÷ôôð{øða7sssUUUüÆô­¦¦¦­­-ÚU”-tˆ¥ãöúúúø¿¸¸hÞ¢¶¶6ë‘§(Š¢d/õ¥¬««›´p\2j„ݶ°°Íz3Î`vv¶··7¢3lÇŽŽ‘gayyÙáfllÌ »Ïá· ß{÷î•cŒc SÌbcRQEÉ4žé%ƒuuuaóó+7ò8Ãߢ¢"ÎÂÒÒRÄ•óÒê‹ÏÝÝÝ^Ť¢(Š’<Ó˶¶¶²²2”³o||\46n܈©7??Fvvv÷555§Nâ–ì¿“'ONMMq`7#bï_ä¡Ü‚1ÊSxV¸ãÚÚÚÊÊÊ¥¥¥˜†Ö­[·rk¸¡¡»¸„‡<}xx8d™˜xèUL*Š¢(YÀ½Ä8ÃJCÆ0ÑD“šššär(ü:9‘(ì¹mÛ¶!¥­­­88qâDÈ2U݇ª­[·.dµ©ò\ô¯¸ýs¸¼dÿ\1*þÌ3Ïà2Éí[,øK`D†1FqÞÆ«(Š¢oôòàÁƒbŸ ˆ’æÐLLûß¾¾>T¶  €WÜsüì³Ïº á1ˆXšÇø[;bqbDbÂb˶x^gaaÁþEQ%xÜ›ýGbŠaY"HfÊG{{{ww·´¾r•¿ŽXr(–¹kvv–K(“Èz)6¨¨løˆ!;û÷ï7£p¹…ã™™™’’îu˜˜x^]]ÝÕÕµ´´´¸¸ÈS"6´òŽŽÞÓǸÔù$Š¢(ÁÆûA«ÌœË¥R8uêT…űcÇÐEÄéˆÄ1¿2`UÝ cˆë¶mÛêëëEð¸Z\\Ì%ŽÅ½ý‰•••ÆxÃ[ôIÆñ?dM£ÄrÃÈȈH8Ägãš››Mï&.“˜¸©(Š¢ä«<\¯ ~deL=Ì8”¬¡¡û/¡öO$ñ³‹tÆîž={6ž–aEQ%GɽD“0Ÿyæ™7Þx{Î4ÌÆÉÜÜ\YY™£O4-`ebtF›Ê¢(Š"åCaaá¾}û—K‹ÿ™.‚úûû)Bó¼ã)7ô2dI&lzzÕ¬¨¨H˜;|øð³Ï>˽i ÕââbUUÕØØ˜×Ñ£(ŠYµj•9Þµk×ÄÄ„ÃÁòò2çûúú’è٥̴^NNNbäùĹœÑKEQ”½>^^^Ž^†ëbCCCggg¢–2†‡‰¶·%z¹qãÆh˨å^®‡§(Š’WˆªÉ/ò)“d}ì­[·†,CS¶0‹fó÷ܹsÆ™ƒúúúêêj3SÎ>k¯¸‹Ûe´ãèè¨<7œ9|ø°,·GŽéïïYýV<Ú¬V†{î2Fò;–×ÍWEQ”L²Vb)))‘åÉÌIÓ#(C+¦¦¦dÕ39¹´´dî=pà¢ØÕÕåð™“ÈÒ+Ä#8ƒ?³³³òD¼â ^á,dM1缌ðç€åÑÜÞØØˆKñAü%0ØÄ&^G§g¨^*Š¢dd¦¢¢Ú¿?väÐМä/ ò)êìì4·ˆ:‰Bá.»·Fê8F†Ñ¹¾¾>ŽQGy,²¦É‰^¢£â@î•ó'gøËÓ% xµrWÑMåŒHi~âÁzŠ¢(ùÆž={ÌÀœÚÚZY Ý]VLà d+qcÀ™£IV4OnÇdlmmmhhéíí•=*dŽ86¢i¤c9D#e!Y©[òp#ŠkœÁ¾}ûì!äàܹs^Ç¥ghÿ¥¢(J–@·Þxãååeéq ßòaïÞ½ýýýqÎ|“%VfffBVçe[[ÛÙ³gû-*++CÖh ÎŽŽ>ûì³á·£¯²2Zcc£xUWW7mmPÏââb&æÃä ª—Š¢(§££cÕªU²<úÍÙÖ­[Ñ$± O:qŒAÌDY[–Ô.++ Y¶&&#^"o<ôµ×^ ¿}—… ’¶\) ¥ÕÔÔ„»—ÀàÞë¸ô mM†ÁÁAÒ¨,BKŠ$åù4^EQ\¾Ãµ6'‚$“F8) m7üõ5¼…… ã,âÜq Ÿ'NÈzMMMØ‹83Ãeggge­Pž(»ù:x饗Œ½ˆq‰Ür B+'y´ý¡X½f,R~¢ó/ƒ4GÕÏtH $ñÖÖÖ|®|)Š’e–——e‹Ã,¬Ç¹{÷î£GæóZÙª— 077GµË}ú‘ 3±D1CIÍÜ+Kxäy‚S%½ ;v̾›S& (ëïïÏôS|Žêe¼(±,Ó2W½Èçf EQÒ5òLáƿuëÖ<ßåWõò#PÁÙÙÙ'NÈnRžl &’véÒ¥žžžŽŽŽô>ôÀx›çéOQ%WÈk½”•Ÿd'jO€X"™§×1¡(Š¢Ä OõòرcMMM>Yq×®]cccjh*Š¢ø™|ÔËþþþúúz¯Cñ ¶oßžçå(Š¢øœ|ÔË¢¢"¯`]ˆ¸Å¢(Šâòq}ŠeÈëuEQ”¨ä£}YZZ*+.úŠuëÖ©‰©(ŠâOòѾô'ËËË»-ÆÇǽ‹¢(Šâ$ïìKd©°°Ð'#c£±eË–ÞÞ^]Z/™››[ZZ2ËBÉÉÅÅEÙÈ¢²²RöïߟÏÛD(Š'ä^bÀÉ6þ§®®ÕÔy&ùÀøøxww÷ÈÈ*¸oß>ÑÅpEEJTqÜÜÜ\QQ‘…µC•ÙŒ)~0FûúúHÒ………º.±’"²ÌYÈZÈ…_Yïì’E´[¨¨Q]Û¿žTÚòE/ùäFî›Éù“C‡ɶìJv ‘ôôô`½…lµéUš„¬aY²ž~}}}Š+Ë¢(%K±¬™œœ¬­­UÕTâ‡t><<,ûB»‹bœí” 5½~¿Ì°’ åô÷ó:þòjÖXxäyêUKKKq~jj 8Ã1µ™ùùùDŸ511ÖR²$q¯ „Š ¥Ý[%H6ì(eÙ¶3xé0øe±Ù©5' 9¬ h¯c1È«e£y™ŒŽ»ºº¶[POó®PÏ\Q"}ÞÔ3oJnArÍ‚R:à‰Ô½~õ´d½$}äÖSŠ])¯ùµK¦êe† žQ/¢=Å,m×]¹*õîL¿¯ƒdfáAJ®àm›)ÙrÀê%Ÿ'ç6˜œ5áçØ¤oÕËLÐ××·uëVlÊtyH‘„‡Ñ M>èÆ³V×m¦¾ŒrJI@]]×e[(mÁÔË\Ëýû÷;Þ‚].ÙuTI Ø^˜ƒi×1XÃ}±Ìþw¬³ÈòCÿ@ýÌWÃVs½L½Ì~3}êPÿ /O¥bèut i¥Ï¨ŠPѱ7@ISW½8ˆ·6Ìæ!RuóºT‹\БA¼Žž$ fYœ££a#–ªccc^Ggp†‡,dW#™òD‡´¯Ú`£!›þz[‰Ìõ Š‹‹sqiE­ºè†lnz…³@ÿäädWW—ׯþÑät¾›£M/Jœ ×ÖÖú|}l©‘Úd.•u^ vF°.ÍQÔÊL/Ž>Å<„‚)|L™$²YL#9Ô6Lû2dU¨ËÊÊü¹5tœèJxé‚d°mÛ¶³gÏæD;Uæ(**:~ü¸.˜Hêëëskql;ÔeGFF|Þç ðþ—DýüüüÀÀ@î–Ò„¨¤HUUUï<K@,kkk½…’f–——kjjrW,C–ySZZêÿW¬}igrr²¼¼<ímúf}á7nݺÕqU¶0äÑ)ö¤8p@ÖDV’CÖ"—”Ý»w766ús¦’k(MN×°CYçëÄéuƒp–Hcq‰åÚÕÕ•ÐúŸ²ì5ì|u±¦¦¦äî¥X¡ iïQ¿}ûö•+W®^½ºfÍš{ï½7â]ŸúԧIJDPûÛß^¸p‚û­·ÞB팛ºººDsÕI^’ºLR4ˆ–¤›[ò*ÁYˆdùªª*‡I688èu4dƒÎÎN¯ƒà$øz‰X&×pibËëׯ¿ýöÛÈ^aaáý÷ßï~ïƒ>è8ƒXr/‰‚ÊʬC‡%$òÉää¤'ј‹]¾›î•••333^‡"'Ér¤ìr \õ:²„§c\/ImÉÕ£‘Éññq~±Á/_¾L’E,9~â‰'¢õJÚyà"žÇ<sóÃ?äo{{{¢Î7¾~AAסð#7nÌhß[€ñ<Þòĸ Y–´ßæ•\/9’„q‰L’+¶oߎªñÁæççѹ5kÖ|ö³ŸG,áž{îùÔ§>í*¾?þÝwß•¾„$“ðäO†IâÊÿ+lyBii©Ú—9JþØ—ÐÓÓãu>AÀõ2‰è6bùÎ;ï jh›œf2F#¼IÖÁ™3gnÞ¼ÙÛÛ›P±®½˜JêlÙ²%Ø,É% ¯C‘=üÖ$d½LΜ±\\\´Ÿß°aCBþ`’º»A,‘ÌÕ«W‹BÇé3Åœš˜1QãÒ–––]»vmÛ¶ [³¶¶¶½½}||\ÔçäÛ, Êp_ز^&1¼êÀ"‹© ži+++"™Ò]§Ïmmm鎭 !›${ ÿÒÚÚJ-íìÙ³ü’S*++©„!Ÿåååä•£ø_™˜AÖËD#s¤··{÷Ýwï޹s'ј‰%îˆdnÚ´É1wÅŒ'_U»|H¡Î4¤ü²²2Y¹¯¯tÈßÝ»wkS<ÇWŸ«—”•‰Ö‘Å}ÿý÷W"­ydæ$DÌ^LA$ó±Ç‹Óg_%#¢­‹I€v¶··ÏÎÎ?~¼££CUSñ_Õz«—‰ŽôÙ²eËþýûoß¾ýÁDt 3@%þQB"™¿û»¿çjD'NœHg|)Ê'!G =zô…^Ø»w¯×ÁQ>B.xK`õ2ÑÆØÆÆF~/^¼¸eAÝ›7oš±²ñã>±ÄHæóÏ?Ï “………´GZÀ())ñ|¶\®³k×®‰‰ ŒÎââbµ×•$X·n]`p¦^&ÑÛÔÔ$Ë×¹¸AM“ÌC=¿c$ó­·Þ¢R¯c;S§²²R­ð´ÐÛÛÛÞÞ^XX¨m³ÞâÿôLÁå„!ÃÊì’‰ƒ©©©œ‘L½L´1¶¬¬ŒÏyáÂwg¨ir&æÃ?¿{d›Œ¹'& ¯tFYÙ¿¿¶_¥‹ºº: ¾òòòÇ{–ü%Ó­J¨ÝÉ“'] \puvvÖ^×?tè(¨ÙßI&¸“7KKKÝŸåC‚©—‰Ž…y饗–,bº|ÿý÷“ÏÆçw~ç@;ãqd^¿~Ý}ìϾ}ûÒeA„,:>>îu(‚†B__Ÿ¯†`äiiÇ6 ¬ _¼Z¶—¨¨¨ˆ¶ÿ НƒêêêˆdSÕÊÊJó ³¡Y×¾< †JL³¤¤$ãÑ7ÔK’TBù™Êg‹i\ W¯^M.TkÖ¬)***..~Êâ±ÇsŸmB‚ÆM¢ ²+Ò€ÌRÕ©„i„Ì2::J¹©±ê ñ—l²kïÀÀ@¸ 566rÒÑôbß‹)šD™ )#zº;ãó@þ𡋦LFhƒ3bv<ùª!-òŽTÔʉ͑‘¯ƒ÷1ÔY¨õQcÖGËùǤ§§ç·¿ý-&]<Ž7oÞœ–×Yo²Úx/_¾Œ5î[ö[ßúÖáÇ#V*ód¼$8vìJIÕ¤¹¹¹³³3çúH|e"FUÌø§ +ÙQäq°uëÖòòrû%ÙßÐ^ãql\XZZîጶIûª£ñÆôPRVwttàÀ˜¡ÒíÍíá[@ÇÜ*ÇW iN½äŪªª|Xy$N»»»ùNäUw©H¨K\¦‘D“Ø{,8¸ï¾û· 6ÄÙ ?Ÿ²XYY¹rå Ñî‹R¶¶¶’ø2«ƒJeAEE™?0Cò|å ¥j¢uS%E(ãl’5K€™ŽCAÆj„lz¾Ëo¸}É-ŽA!TF£é¥Ø—Ç7—Ä–Å ¯`c4¦u×|¢=“y÷îÝ>Ki¥¶¶Ö½{2¡.q1.í£xV­Z…ùøã?õÔSØ(OX¡jiKûCxà;v8vÖDD£-}±˜·0jjj°ÅÉùÔaU,3ôKépª,ç°y#Š¡°ö6Ç6õŽ]~£¾Z'fF´»(-)WíyÍŠø˜åXLAÍ&Ÿ°/Ý•œ÷G?²3íÏ}~$“`DûZñ _‘¯þ›ßüÆœA·Pǘë¤gžþè£Ú—zGÈyMª{áM¤r•L¤BAÅBw‡Î&ÔKªªª´_À‡¼ôÒKæØ^§A,¢qÙjGÁ"c\ÃŸÒØØØÝÝmþ644ÈJ!ÓÙ .ÊcçñU)÷±^RþFìL®®®~ñÅ·mÛvöìÙl†¬°°Qä{;vÌq c¢³³ÓŒ¼rÿxª£G.--™žKoÅÒððÃoذAÖ°×")¼I6-+€áááúúúÉÉI±še¨nRM¡8VÉÌ‹èŸô\ F/ë,ì.›››£å΋ÈúˆÝPCµëeBûø0FÝß%SQ™ëeĦŒhÙîÇ“yÊÔSŽ?NU%¼KõĉѾ"Fp<žS ÿõÖ[ò×],¥Ï í)“XÎ;·uëÖÐÝÊuƒ¡)Ž˜IFFFì¹"?!Y’8³¡•¬ÑÛÛKMš¬ä·r-Ë *MMM©LÁ6°+P8ñ µÛvf`*bæh‰­¬¬tÙæˆ²Qn ¡c ÓYÅM.ºßå·JðÇz>LF&3Ä)?™Ü½{7¦$Ù²¦¦Æ~ÉE¿ã̺ø‰õfæ\†‹%IíÈ‘#<ÝþE6Ò'Sü„ÿ…^  ·'î™™TðÀ]]]7n¼víö7"~—Cž@FÝ»w¯íñb±$›`©xÏ@ŠÈ°Pq®üìBKKËìì,•æhƒzâ‘dþ* ã%yxYaNkk+”}ˆHaKa˜ÊƒFtÃñUcìG¬ÜÅÑŒÉ;øgAÒP¸±¿˜†ÎÿŸ… L5ÌÏÏ“ÿñdll,Üs*\»,&&&VÏ]n'ÎñŸoÁ/ea?Â?n’xz` ‰†×ÉwÈ#ä¯C‘=§D“gÓh 9*SSSæé1$Sƒ±‡–B³2¹7Å«˜… D)R‰R—ö|b;;Ÿ5N¢ê%5&ÿÔÉá Åå­bîŠ%åì[o½…Xž>}úÎ;r£,{±uëÖ˜ZˆƒžžžD£Ï1e—MÆÉ“'9¸uëÖ›o¾þuBy¯—˜51£QÉ!K3¼E–×Ë•(;4$Ç! û»^Æ|åvß4f!C6L½ÎêR\;ÞÝs¢®ïCDøg½‚ñññ„jpîË,I³{ÈÊäünذÁ¬³#ÝgÏžuo…YíûŽ1`ñ€EKòŠ9Œ“ÀWTT„¬  ŸùÌg"ºñ]KE>w†õ d·|Þuyy9ö%‹ûP>÷6¿äÝD¤­­-æö>Ñf‰$úÊÑ^ª   ]¯“îvXp_v!ËÌÍÍEœV ÒMøÀZA¤(t·bhßok~~>£Ó}d}Å„”ÞÏŸèšò⩾¾^gÊû‡æææ|%[[[K…¾¦¦&õ¹v---Ôƒc5¸”Ì\Jc_~Ö:ãxæYħþïãsâY ÝrM/¥mÓô¨c_šKË›7o&=Yeß¾}öÕ4H^y;ÈåÈ‘#•••yûú>„ ¨}ŒI¾m…ÝÙÙ™âÊà˜•h†™Å —!²i4.³ ±®—>Ìã9£—‰å(s«öع}ûö»ï¾»mÛ¶´ø–úH¼Ü…¬¥»@û Ê5?/ –æææ°2³ó,GÕÙNßná%ëC½ àþ$1ÑZ»v­ùÍ4+ÖØ¢M›6¥Å·]»vù0%e*¡|>?¼>fn>w!;ðÉ@ú<'§wó޹̲^F+U)éBÖ¡XÆ%鯼¼œÏV\\\UUUSSÃ_jp‰îBwæÌ™[·nIG)÷âÃ*‹Ã‡×××—Zà³Kr·7Vän«Kêu/¿ü²×¡øˆùùy_uð{‹¬Ùíu(ò—Ñ@‰neès|µó¥|½Zššš²o.c”ÉÞyigxxx·Åøø8Å¢Œ6šåoGGGaaaüe³0é¹ä¹˜Gf±ž®®.B%þã³<1¦Ïù¬—ÄUÌ¡Ë~ ¿¿?½úA ¡våõk)^B¢¢bí¾»‰yéÒ%é"m·ABMË6Ô)>^ÌW;“AÖKAæ–Ά††ŒÉÿ /ÈÁ}÷Ý~ ¢…)‰ã„V™Ù5ÍÍÍ[·nÅÁèèh<¸|ù²<÷øŒŠ›õ‹I¾Ò¨c¯piÇç–––h¾¥w\nAƦÖâ·¦?¾WUUUyyymm­Ôî)×êëë9/ Jœ”&Ê!INü¥ð’uó9ÆÓŠ@ù% r é„cjWüúÓ€ xîÜ9¯CpHT”!îË#D¬¥‘~ÐEjù¤IP‚ýÑýÑ~ RÔ±cǨƒIãYå¦ï’D·¯v&;ÞGpXôfÔ²˜˜|ˆý—/½ô’}'É‹ª=IŠƒÅÅÅŠŠ J.Ùÿ/ž0È^ЫW¯æF³dR[[[gg§´ 766ŠÍ$Õ½k“K>—þœ´0;;‹†µ¶¶R:$¨÷HHñÊIŽq°wï^ÒÕ³Ï>‹•ÜÔÔDjäsS'ã/nH](®,—Ã_H–D2I9¤UNîٳLJ…HÈš², +…uûöm Ÿgžyƾ±’ ÔÞHB$?Ræ;w®^½zóæM™JG¡Dš¤¶Gùvï½÷ž9sŸ‘Oiâ"}RL%Z;'/p;Y€ú“™`Ãã¤ÿKÊF¹ea¿ÜdV.pHËJZ­Hì¼ðºƒ¹&ëÞìÓ)•Þ~ûí,, !KŠ}7»,„ÙŸD[¡Ðd–+ãÈ2(2åiÊ"twiY®šÒ ÷ÔŠp)We½C¿rÌUR¬œ¡Å-(%,¹ä·µÁìÈ{yŠl¾¾Oо+ÉHÝ¢Å{ï½Qɉ”<(å‡~¸è ‚zñâE¨ä]»v'r&Îh¡\’Œð½ï}ï—¿ü%ž –øöÎ; ±2ûÛßrŒç޼±>LQùe_ÚW+¦&•®«Y@Z3(:ý67›ýi] Š¥•R.}á _0»EËàhOÛcáõ›ÅÙÃò³ùàÚµkö³Ÿ=ýôÓ1ÛN%íaÞEì{²#¯_¿þþûï£ ›7ovl_ïVãk¯½†ñŠ0‡¬AòÐ{î¹ËU°~ýz~ù‹·<òHL?u|¬ÇØ?é̾²[·nQ}#ÝÈö“Ò'?øàƒDOˆwùòe¬Þhy ŸÅ2‡Q¤Š=77'U4δµµUWWdz‰,ƒé€ÐrK}}½iœG“H¾3à·~å@"j$<öØcáó°ãï° qJÏ¢tP#¯ªªêîî¾páÉ©ãYG˜˜ˆŸt*EcÅÚ»gܲzõjÊÕÏ|æ3(âÃ?LÊÿô§?ý)‹{-bÌT%}ØUdû²°°0¼xrÙ;ÆÀG¥`¢’å8¿fÍRÒƒ>˜–àI“Ú,o[P+((ˆ¸‰ôry™~€—F ‰¤²²²¼¼œ £¾¾>d¯©©‰ÏO‡ θ‹o-‹gJ Èí---œéééñÛa¾KÞŽAË&JM7nÜ¿_þò—Q¸„ªP¢‹Ž[ÆÆÆÈY#$3 IYý–…‹ØŽ(_D?)ÇÄðÅpDÑZB%—è%ŠKYWVVç>©RM %¾¦[60-³Áë¿”['íõ/÷Û¯]»& îÀ÷6{˜$Šô_âU´§à¿Ø¬.w÷sV PŽ¿CÅs=Ö‰ú~‹?·éêêr 0^õ_®ÜÝÆÞ㈂NLLØ»g“'OÊ––² Ši¯’ÞtÙˆ¥”Aøœ¡\2½ØýD¶ÅÁ;ï¼Ãßææf#Šxb¯Ûq~hhÈ=bew°ø³G<ïôҞܳÅ¿úÕ¯ÐKêà©x’ý\êO|˜…Î+v½ÄÚ³ëå‡~Èy»&¹)¤È¾S¡™š‚’!¥f'K~ñSD6£u"úI_œ9sð É”†b†lEÌù³gÏJ!m?N¹Ê½&Qù0³¹=¶   ¼#а, åúõëÒ 9Ö¬YsãÆ Ãm6Kÿìàí yÞíOÈb333ù“2ÛÛÛÍz#Ù'bRWW'í«1?—ö¿ÓÓÓä,ûÜGV¥ã|Ó¦M2Ø0ÚÒ¡W¯^•ƒÍ›7÷ôô˜EHŒ’O<~ü8¶&Q×ÔÔä¾[™'ŒÙ ²^¢ˆçÎãƒÙ“‘ ('©==öØc)ÊXœPŒ6Â(Ü7õÌÈKƒƒƒªš¾‚’Ú‡‹H•Õ«#ŒÐ¬®®–Nĸ|ù2"g™æÒ§.cÑ©î#„2Ì5¢33 öy"z»ÅÂ%<~ë›wðñ±$ ÇF‰|-{Þ&U]¼x1£a0ø¥Û<9 Ÿ}öÙŒ†Óÿ ºd«ß8xð`__Ÿ×¡ÈSD>M7$Êëé)Cé2®UF,R¦¾·³4çf:ÒR!àz)‰ã¤}VƆ °ü2ÓÞ›ÊSöíÛgäË[êêêâ\ƒPÉ—gÏžõ¹M$–——í&¦Ù.BÊ´õ¯þ•¬¾™^½”®SûTƒÞ¿E¢¢¢˜{zNÀõ²²²2â¶Ý¡O6”_¸pÁ1Õ2Üÿý’’V¬é›^GI#-9>œ••·¼ð ===^‡"_-즞Ù³ŒÚä“O>))gVÒ1`\\\õ5ý”áP¾¥> ¤±±±µµÕü½té’é;ó×Kj¾ÑŠWÇÄ’·Þz+ÎæÞ_‰é‰'žÉLz[ÝÒÒRmŠ Y&fü;Ã(…œ…qéóAÂÑ¡iLºéééÞÞ^»¤¥bbJÍþ=‹ 6ˆF¬ëË´K÷]“ƒ¢Ò‡“z®—T»6nÜ.™| ǰ><ÎÌrSÑ %1f‡j ’É/i.æ#ÐK5h|BeeåñãǽE±oß>ûr‰è%ÂvñâEéèA´ì5þ$z°&oܸqùòåwÞyçÊ•+žXxÆœ½}û¶i}5ˆ~>Ed'¢,Ek"\/CV ëP\\¾ŽTÈJgΜ‰¦gÔ×Î;·yóæäšéIX¿ó;¿óÔSO‘"Óž¼ò‡]»vQËöíšpùC}}=9K{.³ Uü'N˜¿è¥, víÚµpÇ”c{C–¥xËÑÈw-°–——ï¿ÿþ‡zÈnÈR*Y[pÇŸ;…‚=ŸDhkk#Ù7 ™ãûî»Ï¾îiâ7¿ùÍf ÑE’Ij~~žtišUS'FKÇîÈJ~º„ìÑ£G«ªªø"^$éïï—uþ¼H~ɵ°°`?)—0#Î0püÀ„Ÿ_¿~=÷~ðÁ!ÛN[2Œ#γ”*¾KÛâY6NÐKÙØÇo¸½!qç‡}·SdË–-7nÄ"‰XŽ˜ÚÞ·°Ÿ‘UIXŽ Ià’Ä]à¡~\P1ëð·mÛæÛhà¡ÒÖÔÔ䘦¥dâââ™™GéA±MÆ0 #–6h[B£iD„?”Ši[dÇ·keG-¸§§§}eʤ2ॳ³óðáÃI?Ú.–õõõ¬ˆqwwwÌq›Iö1·ûpÀ˜'P÷¤È@e.ç ‘S_!Áûp,FàA‰ö3gÎHY$ÍTØ…f”l8fÇæ‘Á>;’\žžãã㲊ž‰ª—'NœðOýèsì ˜ÕÕÕÃÃÃɯ$ÍÏ~ö³ür{MM gì›N œoii¡ö·wïÞˆžÈƨ†Q¢Ãk þ0æ ÔäËË˽H~aÄÒW5é¼BƇ›&SdŒcQ¬ˆÍ¡8H®÷Ç>¥ ÷M–)HãL¹o|ãÍÍÍ™ŠÁÔˆª—Ødh€OV[èëëÀKúvÞ¢µµUöˆI™ "2—6bŸ %ˆ,V7::Q×±‡¦¦¦Îž=ëçsˆööö­[·ú‚s` Ko‘XŒ^"c7oÞt_X'uÓîC¸^nذ!/ˆU@ó©æàã*Iaa¡#ÜRbTyÊ;vÌ~2Q!okkö3½˜yë,ÜïzðÁ¥îÆÓGFF¢mö‹Ù'ÛÅΈÍîöy¸v¨‘ðvñ¼ U{°ö'±ÝßßO¥Ûë°™ååej{³³³ÚÂá-²*:ßâþûï›oii ½”­s11ÛL]z1ãáÚµkî¶#>§qËŠžžžÆÆÆŒÇc²|‰²¼ŽŽf~~Þ«QãdΉ‰ ̈ÚÚZÇ¥D+¹hÒñãÇñg||Ó¤Ô"æ]›7o–Ê nŒ)l‰öQŸ;wŸãq©#}‘ÝøšjefJ€âââêêê¡¡!K?€œPÉF#EW[¸7º¾÷Þ{É= ¥¼råŠù‹]±ÕñNW{ì‘#Gˆø‡_Þlte‡3?ùÉOþâ/þ‚JººŽãs{îðáÃáW“0ØQ}lÄáááúúz Ù¢¢"ªi.­£X–Ò¯>88Hy‘‰f¨¾¾>"– ³F¢ÃA#"’I5…oªÓÒ Äo|ãÔV1h|Ò/£„¬¦2 êÙöÉ}…ŒÎßþö·‰.´"ó2å˜ÂpÓ¦Mцöp>-­²”rû~®–}¬—:Ò?ápÁ™;w†¬²)k]ËËË.ÃM IruÂoz’+**FGGÂhŽÍTKd5ZƒªÊ—îîn$™"†²›È”32Ü ÂEQŠûxº…|;!És$111ƒˆ|í]K²uü®®.êgjSúÙÛ™âÚ>…¯Æß;vDÛ‰óëׯŠäÊÊŠ±,Qʘrˆ‰™ú«Q ðùŠQŸˆ>мGG*Ãzà@9R¯ð–””Âþèþ(šSe‹Ùž.ÃyÌtbi÷îÝ€.=zÔ¡š¤ø‹ða·vð=Èl´æ,$*(²5¦,˜§öPBNœ8AÅŽ$‰RªMég¨÷öö’Ú)š6nÜHá ‹*s0"PŸùÌgâ\qåöíÛ2«òHc÷¤ b\ú|ŨOt“U|¾;!$'»…ñSYYI±Ê"¢ƒxv,‘ÞÚÚÚxæVâx·…ȧˆwK±Pµür‡R^º Èu˜õ:;3N˪ªª5°n~~^º„5±ù R»ÌS3± ‰¬JÄú {ú—2Ê!° KJJþìÏþìí·ß¿JZÙ±cGÄ„uìØ1³¾ÌöíÛ‹ŠŠöíÛ‡Á*£‡\7·`J †rÌ^I$½Ôñ±I@Ô>|˜ÊŸ,õ@}‹÷só‰'hm,!|«—²DvcccÌíâ—Lxçwd‰ MÌMû !éã”}K 6mÚ”Ü ò¹¹¹œ¯üõÖ]èéé¡^S__¿fÍšð¥%5D\°xttTFô$1­Å>•%žµ~õœHI>„dª#Hæøø8ß:•…¢‰ô)x %U¨¯744|ýë_©—8dLɼsçŽi{»~ý:å¤ÑKÙ͉_ÑKQ¾{÷nŠ¥‰¸âOÒ v˜˜X®ÑdZ˜CGÛÚÚ¨—a©¤´¥¥%žHÃ}{{»4›„¬á¾.æ)Ö§ŒìÏJ¤æ ©ì <¨SçÓ Y`¨¬¬D~Ú·ɼ|ùòÅ‹c6¨â`ÖâÌ]NŸ>¢q ”½9Ôßô±^RšçÊ9T*½¢.‹ìÙ³ÇaGÞzë-{[?ÊŠ{9&Þº»»‹ŠŠdqZ{ÀdÑ åÃs3²N¦ØG 4Øê‚>iG¶wð:~áàÁƒñ,\¥ä ’¼Ý·+‰È† b.È.ÆåíÛ·oÜEšdS ³o·†ŽÈÇqDeÓç–¥91r•.êêê***¾óïDl” •\¸pÁ.™29ÁZ^^Žp®º wç]PJû zÊ)—V\Ä’ðäP³~®ÊN¨CöÉ¡ª½J ä'Ñ œ)©â\ÍnãÆ›7o~òÉ'¥ÛÒlG‘4¹µíÒÇz™½[¶lYI‰‰‰pNœ8‘ö°õööž:uêÿüŸÿ±‘áÃ?|öìÙlÇf^‚¹_UUElçU?12Œˆè”À@]):vìX´½£ «W¯vLÖ”EÆÇÇQJôÒœÿàƒ"pµ@5Ÿ{Tťš[—!Çú>T·‡††jkkýÜ»“öõ}"B1J:¨¬¬¤EZAQMÙàFˆ’E4ˆ(%FçÜÜ\¸j&©¼ººZËì@R§¾LœçϘ—~ ]^1ðPŒÔ×ׯ]»9¼s王K3çRLIdk2‰'Š­ùàƒbkþÓúOãΞžž\ža?/4€rÄŸû_¦}ýXÔ˰9̲®ÔÑd+ÙÔæ‘G±og“Fd3N-Å™.陈sêÅ^íºG‹ÄL‘‘§744 ç›= |»Ÿ—Ù©ð;ßùŽ{ÿÆeQQ‘ùë¾´2RJé4;;+Î\¶"F/üq÷ª?ÏÅ·œ3"¬œD,´[x6 Š {X ²”2”k²‰/CzI…r“Ôƒ<‡T/³‚¬ƒ(†f–¿(ùè---„!£ûµñ,^Ç©Xæ²SaSSå•K«ì­[·®]»&–(¸'­ih988¸mÛ¶œËPžïçF¤cI¼ññq ͇~xýúõ™Ø·S»V‡Åfdrrr-Éæ07Yx²···¹¹ #É™%…Óµ= ¦¶¶6÷YLJÀ EQ#™¡…îÓE®\¹žöVVV®^½JB½}ûvÌgá,ÑR!?zô¨×‘” y½_t8Tö«¶RÊÈ00T“2Žä•ÄòŒ. –˜8”ÚZœy’Ég¥dq_D"]8y"JFm UkmmEØÒÙ NVíש#yŸžTÔØØ8??_^^þúë¯_¼xÑe«ËM›69¥'³â=~â‰'âž—9:4]íËO@R —C‘Ì7Þxc÷îݘ˜i|%éËÒ”h9·àE@º¨$ehÑ(ƒìÞczàÀJ¨™™™ÂÂB®¦8ÚŽ4\[[‹*“¨ø«X棣£Ø—!««µ¤¤ä+_ùŠË_wáeÚƒ>ç³î¿ÿ~Ä2¡å„r׸ ©^: ¬‰X¾ ™Ï<ó %aZ„ú9rdvvÖ“ñ&Šj-|d†L&ü— gd¥ÃˆŸ{Ë–-h¶QÍ–––D²òˆññqž‚$WVVb[hÅ+?!˜%ûúúøû—ù—ÑæYFl-CŸ|òIj›-Ôµ÷Þ{ïÚ»pU~ôÑG]E–Dž£ÆåG$ºúy€™ššB,ÝÝH?Pss3åQrO¡ÊßÛÛ»qãF~ïR$^ÇDþ‚˜UWW'ýq#"i#’O{žŽvÊö¨¤‡C‡MY8B…ÀsrllŒÔ¸Ý‚ÎÄù%9øY.¢-eé„ôñï¼óÎù0¼ŽÑ\Bû/?AÌÞ# SRXgg'µxŽ{zzâå599yøðá‘‘ŠN »\x¨ó™0eKÔ¿Ñ¥K—°QµøëÔ<Ô¬…£££2U\~Í ÿÒÒRY|—$HíÿV*âöù'²-Éïç?ÿ9Õô•Ovd¢¦öJ ¼l†Å´/íÈ~^”VD³HHŽÔõ¨øã²¬¬ŒrÓÝOµ/}‚ù¸¤Šän—i*]]]^¿Š’NÈžY.¢ÓÒÚ111p^¿~ýâÅ‹óÎ;^GjÎa½‚|fÕªU(\BUu¬‡A‹ðÙ¾‹‹‹ÔÝ(s ãñ–Š!Emn­ÙTø GŽáËÊiÙ!Ü}ø æ ¦·´´´È„Z¯_BI?»wïÎôÐ0Inhh(-^õ÷÷···“˜oܸaŸ”ùÀ¤wc€Q½ü².FŠk5¸/“á‚­_ćÌÍÍ #„ .‹éga *ÅsdC´ÑÑÑŒNÛ%UTTôöö¦Ñφ†Œߺuëƒ>à7d­Š'›Fd:Þ€–Ο€Ä422âá€Uì]á3W µÌÏÏ˱6 (9lP#KJae~øá‡HÀ§,¼Z z©(Š’GØ%óÎ; ׯ_×VÙxP½TEÉ/¤av``@ºPM ÍÛ·ooÚ´If]P½TEÉ;†‡‡›ššFGGíÝí7oÞt_o6ÏÑõ}EQòŽêêjÙâ×¾¦•Š¥;ª—Š¢(ù–åôôôøøx6gÈä4Ú«(Š’×ÌÍÍÕÖÖ¦eM«`£z©(Š¢|´àb}}}uuukk«}ùF3ojffFf»-..¶µµå¡²ª^*Š¢(ÿÈøøø7¾ñ……dR±°°Ðlxb6½)..ÎÃ%‹U/EQ%6:ÞGQ2ÂòòòôôtZvKUŨ^*JF˜Ý¹sguuµ×Q%=¨^*Š¢(JlT/EQ%6ª—Š¢(ŠÕKEQE‰ê¥¢(Š¢ÄFç_*JFX^^ž-((°ïÿ (Jî¢z©(Š¢(±ÑöXEQE‰ê¥¢(Š¢ÄFõRQEQb£z©(Š¢(±Q½T”Œ077WZZZSSãu@EI÷zE &KKK333^‡BQ”´¡ö¥¢(Š¢ÄFõRQEQb£z©(Š¢(±Q½TEQ”ب^*JF(((()))..ö: Š¢¤]?VQEQb£ö¥¢(Š¢ÄFõRQEQbã¥^ÎÍ͵´´­R²ÑNäó ¼NŠ—Œ×ÖÖxó‘âââîîîK—.y ”¸Yñ‚¥¥¥êêj¯_]ù>ŸÃ“d xÈììì®]»¼N}ÊG:tÈëä Ä…z944´nÝ:¯“¨ò1|>Š×I1hP ™ššB–¼H( ½NtÊ'ؾ}»?“Šb'ÛzYWWçuÊT"çñ:5 Ä’X-))ñ: NÔ¬ô-}}}^§Ŭ®·ÞoáušLžMr¼eË–+W®Ü¼yÓ\}óÍ7½`Jði*++µBlêëë'''½…¾NYY¶¦×Q"“½ù——.]***òú}“áÑG-//î¹çüqûùÑÑÑŠŠ ó÷üùócccý×ÓÂ9??OUÀëPééé;wb_ràuXþ‘ÁÁÁÚÚZ¯C¡¸Aî#z %2ÙÓK2*ÙÕë÷M€5kÖ|éK_zþùç£9@ j@8_yå•Ó§O{ý S]]=44äu(‚€õ’ «ŽÆô?‡joo÷:J²¤—¹e\nÚ´éë_ÿºÝvŒÈ•+WLólDÐËïÿû9§šjb¦¿é¥—¹‚š˜¾%Ký—9ÔmùùÏþÛßþv<.ÝÅvìØñÃþð§?ý)ªiï録Mccc&ÞñÔ©S£££Ñ®ò±š››3ñ\ÅCr«uÇ?dh,1&Ä‘#G¢]š››Ó^L’%û²¼¼|||Üë— J‰^¦Ý[,уž?>¡»2gš´··wttdÿ¹yÅòòòììlAAO >BB¼Eî‘¡Rš¢]Õ&Y’¥õ}¼~Ó¬Y³[0b²,QŒ¶äË¥ß^!WÑ<¨YÒKŸ¯»†X ìØ±#£OÁxÅÎöú]c333ãu”4£Ã|r m<÷'YÒK?×mËýèG1;#ÓõÊG}Ôë7Vò?¢(©“ïû“ˆXfMòü8EQ%]du}ò¥/})NõºråÊOúÓˆËÈ‚ŸÿüçãiÑE2_~ùå/~ñ‹q†°¸¸8½¯\TT¤Ö†¢ÄO&ò ×ï¤$C^ëå¦M›\–#0 ”þçî2ãüùóƒèå7¿ù͘ªÉsŸ{î9¤7ž@fbõnæææª««)juý‡\'_P‡ ç"yÝ‹¶Åt366V[[ë"–vNŸ>ýµ¯}íûßÿ~L—ú§Š¡éu(diiifffvvÖë€(Š’òW/Ë-ÜÝ |ßùÎw]jñ®®Îý.ÄÉô:EQ”xÉ_½üò—¿ì³É4œóçÏõ«_u—Ìçž{NMLEQ”\!Oõ¡*))qq C{Ry„H¦»›ßÿýß÷:&EQ”¸ÈS½t’ƒ]OdLd‡/{öìñ:&EQ”¸ÈS½ljjr¹úƒü ‰åÑ#ÒÞÞîâUEEEÌ&Y]‹+G)((())IûT%ûhT„<ÕËGy$Ú%ä-Å–X‡o÷wçâ@×.*Û·oŸžžÖÉ$ŠòT/]V¿s—·$p_ rÆ ^G†¢(Š›<ÕK—ïI‘ .¸\ýÜç>çõ+Š¢(±ÉÇõ}üq—«o½õVzwåÊ•TnojjJïòuq.¿ (J(3yÐëwR’!õÒ´Û—îs~üã»8hllLûCU/%~2‘u=¼\DõÒ¿ÌÍÍ•––fÂgÝ 1 ,//ÏÎÎøgËh% 2”ý¼Å¡ ÕKqKŽÒ­›sÄrçÎ%%%jIä4šC^èåþýû7lØPQQ±ÉÂÝñ~ô£l†mÍš5'Ož¼yóæùóç_ýõ«W¯¾úê«éšý©(Š¢¤‹€ë%ÖÛw¿û]ÿÏqD5·Y Ûþà?HãPEQ%u‚<ŸäóŸÿ|¿ÿÅÒÚùÍo~³»»Ûë€(Š¢(X½D&¿ýío{Šäyúé§¿ò•¯x EQ”@qçΤï f{,&ÚË/¿ìu(RåùçŸÿßÿûŸ?Þë€(Š¢ä*ׯ_¿xñ¢L ¸zõª9ß}÷ñûðÃoÞ¼yýúõñxL½Ü±cGÌq=9ACCCGG‡×¡P’¡¸¸xjjª  Àë€(J>róæÍ_ÿú×ï¿ÿ~4ƒR´sÖ ÉxòÉ'Ý7À¦^f‘9÷}Ç?³nݺ MÝSÅò—¿üeB³Ì×K?þøc=¶zuäžÊ`êe`–›zôÑG©ïèôEQ”xøðÃ'''“î¤|óÍ7ß~ûm,®ˆ-´ÁïsíÚ5¯ƒ6T,EQâáâÅ‹ÿ÷ŸÊˆžež¾þúëx~)˜zùóŸÿÜë ¤‡,/f«(Š’£ p¿üå/Óâ•´è†Kf0õòÔ©S^!=PÍñ:Š¢(~'biÀÃ÷Þ{Ï~&˜z‰Yvúôi¯C‘*7oÞ¼ÿþžžž-[¶xœ ²}ûöéé鈗fggëëëwíÚuôèQ~½©XPÊ·-8íèSÇLä_½z5&×C=þÐ_üâ·oßæøž{îyúé§Ã—c=wîÜ­[·Ì_#&2ù½ï}ï¾ûîûÁ~è»ôöö~þóŸ///óY¾³/‡††(h丱±qÊ‚“r†KSw1·˜3æÆ€a5¢‚h‘_Ki&–äók¿ÑëWùG¨nÛ¶­½½}yyÙë°x&æn‹¹¹9¯Ãò ÉF2—=½Å“+4Z÷’b¹XÎ8’zøÑÂóÆ8ŸîyÒAxcv>¢Ø”û·Ëoº†âÏÿý¿ÿ׬z#‹à8lAÔn|||qqñªü}ó“Tígðög?ûõË„Äø}ä‘GJJJ~øÃšóW®\±±oã²-2ÚÐÐÀ·°;¾|ù²¿ìKR[YY 9Æþ `帴´”¿ctË8tèPGG¿§NšŸŸYÃJ9õú=Ò ¯/q²ò!Ñ"¿rFþâÀžeg ûþö[üJÉçÃÖlmmmkk3/˜o šÅÅÅþ1¸ÉP&Ùp~ñ‹_ Y ú£ýèÚµkMMM>ú(WOž<ùïþݿ۳g7¾òÊ+¯¾ú*A]³fÍ7¿ùMîânðœÄü‡ø‡_ÿú×oܸquü ½‰x6q$§aSÿÞïýA'ˆ¼ÛÌÌ 7"D ¯ôãÿøñÇÿÿá?œ²@¹Ê/—þÛûoœ¡Äák9ÃãU#î…IÔÜsÏ=Yx÷$àMgöîÝKbåMIy¼ ¿ÄÕªU«ˆ?øƒ? ´â*gÈ\â{-”qD£ýÆx¹Tá(Loß¾M¨þÓúO¼Hþì~e¾ŽoôýïŸ_¾—lc›^ˆó˜½;”ø¤œ•f$ÃN É\œä½eAúä ~~ï{ßûë¿þk2,éÓäJÉ¿Ï%­Jú$5âRRìç>÷9ŽÉû'ä_ÜHŠå*æqá7F <7ÆóĈy$þ Ê›>÷ÜsÑžÏn| b>ѯL™væÌ¬4,¡••ÇÕTÚc±)ñ‹_„û)ܺuëæ]’~DÒü›óo(FH“.\ø—ÿò_Rù~ì±Çþãü¼ïw¿ûÝ/|á \ú×ÿú_S¦ü×ÿú_ù¾/¿ürUUÕæÍ›‡††p¶víÚ_|‘º;úú©O} ‰A/ÿæoþfýúõÿå¿üüçÿüŸëëë©+¬Šé…4äî€ÄTTTÄ+¡ùµµµ¤B±/å*y•ã;wÚ݇,–ž$…!™mFwí åôéÓßúÖ·dt”z=“´¼#ù']%¥OxüÈÑℚQÈVEDšÄ†‰?kýѰ·Q¤—¹¹¹hm°[,2ô\_!;íE»š‰È'ÎÝ[}‰yrŸ¤Êɰ&Õ…¬ô&5TãžÄÆ[PW“å<Ç¢"áÀn¡4w¤X¹j|6ß´…ß‘xnŒó‰ã'Π’+‰þº<1&¤ª‰~e t—öÌTJ'¼Íèš©C½g]]ý<‚òÓŸþ9D‘CYdžäŠ.`er,¥(Õÿõ¿þ—ÜBñKÅQšLp†¾â Bþ™OB6#yIqìVù+IÍ(bènúCçD>I‚¦‡`ãÆîOûÎw¾C4ɪžT.ˆÊ´è¥ 0ËPUVV¾öÚkö3bÙsxaa!Îúúú7'ô¬hUR'baº}ûöÎÎÎÌE' Q³³³TiÛIíáEçºuëZ[[Iü™¨4ðAíÕÍp$[0ÑHiV%f<yФ4T¡ººšó’ººº¢u+: ‡’)Ôì'ùî¦9WOêo 'ÎãybD⹑ŽÚ9t7üƘ$]m¢r±16•zؽ÷Þ‹}™hçbxõÕW<Štä½\XXà5EéËÄ:Â4¾ÿÿã`†í°@ÿê¯þ Y=qâ„x‚A…µƒK,(™gùÏþÙ?‹ø½ü¢—ägÑyIßü• “1±%ÓR¦”••±ä—î&êÈ/µ I:_þò—MÄÑàkQ ‰sœU¢Úúúz¢…‚i×®]“““ÄÑ%y’?22rîÜ9. 8£ðâ½%n$®ì7úm.G€Çˆ"–¤L>AÌʇh•·¸¨;á4UÐR‹("éŠd&‰‡ÐÚÅ2dµHäe"¶p)–K¤dò©¤X“—©ò’bñoñ7¤X$ê7F4”ytÌã|bx±;1ƒ:jÁ™hOŒsŒ[Òæ 7>öØcá]˜)¶~¡:)Žý:KèîîÆ:DP9~úé§14qIåÇkÖ¬7ÔÿÐ]nA8)Æ)ÌÅ}8~i5ª¤=6t·ŽÔFyJæ$ÕŠ˜Ž.q&âGª¥nž—ìí±¨/Iƒò…^ô‹k×®a¥Ùã‹“T:ˆk¿!«3Yê2ö{7Y8|ã‹Ú„ùøÃîRß±{+8ÚcùFÆ,“\'ÕU±Q0øK¤QT™j„4©™†5scœ-B™KæE¬”‚˜tõÒØ—$oŠò,Ö1íK;öd#ƒVz{{‘O©¼x²!zºÛÌk†áØS Óº+«¤XBe$‰œ3ޤ.Wí7F|Dx ¿1Î'†çùˆI5â#6VG|bŠÝ1ðG†k¥Hø®=ôÐ?ù'ÿÄþP‡¬®_¿Þ1ç„Iø° ¤Áš”²Ô^_¸pÁ¼8À8¦¤•ÂÇ\Eþ9þŸÿó↲ݜä‘G¤ðçRÈþ‚o?ÿüóÔ~±/ öúåõnr©Ôd·nÝJí€dDB’sä/nbŽËG&11©JH÷;1h.qò•W^1ýÕÏ=÷œŒ} ZmÆ%”DÙ@\ƒÄû¿ÿ÷ÿžýñü•¯|EÆhIcºñœïôòË/Ëg ²Ã_êzâ->þˆ#’ ¼²‰Þ‘Ô&¿rFþ::¨$³Ù³œýoá³vvvuòOœPQ I`|xØ“ ÕP¾”´ô„¬o‡ µ´´$™ŽDE¾#cÊ_I¶§=I«bÑÚ*gIÝî‰K/l<7&ñDs{rAxcÖ¾ãêÕ«ck¦ÅO¤ý3C¢b)%E¤  ï_ T»Z©v$ÑäKêÊd·[BwKió÷Q 9F#ž·_Â+)Õ×®]ë;û2í8Æû s?øÁг%ŠïÄ&Ò…."Ÿ2ï•ôØØØøCb i¤öQ™e…¬"¨)·S“ú»¿û;dXNŠ^J÷ryy9þàùèè(yÜ_ýÕ_ñÛÑ Y–þTªEö0‡÷É2™K‹‹‹1»™ƒ‹}™ýHHȾT<'-ö¥ô)|Ñ"Ó1½Ed¨æ@ ¦Ñ*,BPM´-ýšÈ*fâ_þå_ñ!¤f„dbËc,rRI½CD—dÞ´KMÏå!«„[Ði<Ò;ÍôwÆ3¾<0ä‰Xj$(¾"'Ä2dÂÿüŸÿs2È}q€¥›Í°Qnû®=6; TX{ØŽ§OŸÆp”¶ŒE²>Û… BVcïW¿úU¤ñþá¾ûÝïe(h?'Q$PŒH»çW®\q´`‰ú¶Þ¤(ŠâPÁø‡5üìg?ËÎD y–_ziËû?ýôÓ£££X~Ò¾cÇû„3iÇꈎʒ¾'Nœà >p ”œ·¯Ã²Ú»‘FY*BÎÈú¿÷{¿çu(Ù£¸¸xjjª  Àë€(J`Ù¼ysv†e|úÓŸ~ÿK7nÜÀ.|å•WÐ3 >ÄRúŠ¿üå/s€±(—àk_ûšX„È¡8“FÚùùyD·££ƒKÜÈùp«Q ñ V®¢©ø€ÄfnŇÈZhy>¬IQ2Ê“O>™…§¬^½Z‡æ—}ù‡ø‡²š—|Æ Dözzz¾õ­o™Kh›L ¹víš Çj|î¹ç½ 6`n"‡!«Eû+_ùŠã)åååxûçþçfE«ŠŠŠ¯ýë^¿½¢(J ƒ'Ó]]=ö˜tçÝøXÁÞXê â²v1O†Ï¿Œö ™i.;þ «x‚ŽÍ-Ò>>6Àܹsçoÿöo3׋Iù\VV&z™_ö¥= ¢]Џ FÌ“áJíAñNצtŠ¢(yJ¶k×®¿ÿû¿ÏÿxnFçWÿ¥¢(Š0î¿ÿþ O=õ”}֊ꥢd„¹¹¹ÒÒR³Èª¢(™½t¬º—:xøðÃÛÏäi{¬¢d𥥥xV U%-8ÖêK,K‡X†T/EQ”`€•yÿý÷SOMeøtˆâO„K^¿ ¢(Š¢¤‡OúÓÿâ_ü‹¤7‘Eq¹=¢X†o_®±ð: ó裚MQEQ”øÁ@,--½yóæ¯ýë÷ß?[™Ø´iÓ“O>é®AÖKTçå—_vß*ËŸô÷÷=zôÕW_õ: Š¢(9 Ê';%_¿~ýâÅ‹²lž}ßM™øðÃoÞ¼9Î¥Û«—DÖ~ô£\4.…^xáÍ7ßó: J’”””{EÉkÐÂÇ-äo*[›v}Ÿþð‡öí s‘›7oþÁüÙÂ:›èú>C×÷É-t}Ìñ>T%r],C–‰¾¹¦¢(Šâ ÁÔË={öx„ôð¹Ï}Îë (Š¢(L½ ÌN“ºº¬¢(ŠO¦^nذÁë ¤Ü²¤(Š$‚©—£££^!=œ?Þ“ñ>Š¢(Šƒ`êå믿îuÒÃéÓ§½‚’$ÓÓÓ«V­’`Š¢€`ê%2såʯC‘z{{½‚¢(ŠòÁÔË›7o–b‹¬2n쪄âC(£kkk)¦ëêê¼KžB P^^¾°°0==ÔbQIšöööþþþ ªCÂz‰X¾ñÆcccšUO ¼Æâ$[ªdzÂîÝ»KJJ¤ÃRQ­ªª¢F1d˰™û'] í°/e©ÀD‘DÖÚÚÓ%I ±$«ØMx*›T¸$Ò8YjA‡«d0²YÈj‰èmMMÜŽcü_¶à˜“ö»dàøø¸Tô¤ª+Ç8÷¯LðÌ-à†‡‡Læ—“” â&d÷â§N.I#äØä@û³¸Dxð?d5ݘ— Y«lpWĆJBÂ%y)‰»Ÿ²_£Dæ ñ¶¾¾^>"Û»w/wZ.É#È{8à îåÉ[à•|G<ç ¼¼\Ü$ŸT#¡»eeä*C’¨.Ç©µÆ •ô) iiiI²‰=G8’™Iç§N2!7S®JÆ—t.Y OHÛáég’ÎIäbù ¥„ý¡”]”r²8œ9™Pñ%ÙY(**zñÅ£•<I^ߤp3Yž§Û+ü5Ea{íµ×ìÖþqåAœ4ñ#wá’;üóëc2¬-³û“ˆå]»vÅìù ññ9›››©XÙëq[·n•†ŽU?"çTUUQÙ$=UTTðí+++ù*ßøÆ7B–}‰‡Ïóóóx޳Ÿüä'„ÿ›šš%8Ǥ SóåAe8+((à*÷’8x Iœ¿½½½vŸIÄ„ù7Þ›˜ú †äH0-ÙÀ^LÈIŠxÂi#sÀy¼â•‰4<áv"äìÙ³æYZ’2ÞòúÒ+ŒKbãœáìèèà.bÉQIçï¶mÛ¸ÄSpÆ«‘ ìáçjÈ*Úð‡«ò¢Ž[$Ïó8¾£D>—xÑ(¥‘Ã{™·èéé!*ˆg‚M$ÌÏ<ó ÏÒÕ_óré„TÓñªU«°H±G%}b‰ÉE¢’å„HBdI{Oº•df—.ò)™óÒŒKɘx(aàª,â/éO$óÜ®®®ÕëÆ±¤sþ’Î;¶ÑB0¨««³ë"•ê&7Ú-éðâ y#_ã3…  á¥$#Û‹/b€ .rî(yxeùoÉSÜ…3„rž«¸—'R5çùWJ¡y {†5~r#áä$¥ ïËÅ+Á¦@Æ¢k÷îÝ„ùÀ^'+ÓÔÔT´«áãcWî¨ÌÉhÃä³Hâ§ø²>6¿œ$%?~\–Þ&;á’4*.%‡,ŒÏ˰=ûpïÄÄ÷ÊÉ%ƒc² ÁæüöíÛ%ër@±Þá-A Yæ.¹WïxYóF’+¤‰IbU¸Ä-ðæFy–r‚$#9Ù××G~à—c’5À ·óö§ã^^Š7â×þ±±1ÎÛ½æ/—ˆp -÷rR–Ø6/e q øÃ½ÄÝÿtáøÖ¾BbÆ>d4§q/ÂÇÇšÄ/Å+)Sþ’z£Å•Ü%•Z<$%›«øÌ%’½HZx23^í·X±eL{^Ž™ÎIÕ2 ØžÎ)L”7Â7“=ÁÑßDÁ-³s#âgŠ/Þ(¼ø2ŠVò؇…›pJ[«d ƒt7+ñKJæ½(ÇL/ a–â‹ÒãàÁƒæv Œ)¾†††H¦ø"ú_¦ä 7'ÂóôoÉã”ì -,cú5(‰„gŸ}ÖîsÈ2yu}ö¿ŒÅ·´¹“2dDÅ4éUú´ùµG= ˆaêhGÅð—j— è è7îQi!Ë2iŒM´oñÉ$¹Ë½ÔãL¿ž#2…†-mý4ßHLÜN~–ùÚÑ\Êá˜[x/ÊŽˆÉš×'Z¤!Ô±ŠD¬ÄT,P2Éó»,ð_ˆÀùjxxXr—ô!QZñ8<óÌ3ŽPá€W&üáMgòR¦è'6ˆ1¾£D”Ü­ÁM>wȵ¶Hˆç$ÆiÒŒìÊ Q!iXf\Dër–¥8FÂ+‹’Œ¥³&| ­¹"SÂÑÅ-ÔM^æÑä—tŽSY—^|ü‘&ÀíAb­J¡„Dq’§È]è O7Ü%™]®¢¾"?Ry ¹_x^ò €ddG9ƒûÚÚZ) Èøü%ÕÞýÉ‚ͯl$"NADå—â­ÔxqG¨ø.¦ˆËSâ´CÝ[c°f¤neÎHƒª1ä±ôíͳƱã$î¥}€óöfI ™e–Vî6ïȯtH3½ñÊø`?ö{Íg-äïhÿî­xbÇkJK¿ö–ûÓÃãA®Ê%û=䎰Ù=Á[{Ó=TÃo¼rÄ¡iã’”€–›èry 9 wá^¦"¤}ò²ŸÛc†{ À‡v$l9)V—ý$etx§Œ)@Lª³'K{ú7¿Žd枈™1b:—¦`ó¾ÑÒùÊ'[•#_rÆQ8Hc•)¾ð9bñåˆÆˆ}Xæ¤ãéâ‰#0òö—Ø*îx;GÁîaìD¸öØôèeÖ 5Hï l’[‹†„÷dj'©G‘½ßb%¬»Èž.ýÍÒñLxÒû‚ª—YÃ'%@æH%ÇÿˆÜ-¾’#`z™©öØ !óÓ{zz¶mÛ–së>dyú´¬­ÚÕÕUYYi”Š‹‹eÜ`YË1dö^ùäÔ]Y rÅšWk|M7+**8ƒjvYHZ´g•Hó«p)³ûe~´Yþ˜ÑKy–Y¿Ñ¾Ò#(Å LÈZÅ‘‘ó¡»‹.ÊZ¯²Hf¸^’З,ì‘oÏóä ÉióRœ! ²²%Eî‰{V1v¸_±Éá‚Ìv%´<ȼX!™Y–ð5ÎÌë…“JÎË,rû#äÅe¥=®òAÉí¸¡|!*$JMĆ£z™52Z˜„gO?öiž.倬éºòI½”Z¬YÀÛQ×Ä )Í‘w$e’Ìd1KÑ3`zé£öX¾«¬b*qŒŒŒ S’J;ƒì&fjy²3ŽÌ/”©Žq<88(»êˆ¥8>>ç¾ð½½½æ)ÜK Tº©‰Yøâĉˆ[›$û|GY¾‹W¥âioK‘í"vÔ‹êlÛ¶Íe#O´¤°°7Ž5ÃÄž›››ÛW6&sYÃϸ—¦fá&¨²6t}}}[[›Ùrˆ‡R‘K555\²;“e‰Ni0Ë›8 o¹:rävW ƒìÿeÖÝYÛ,ij{¢’»H¢µÿµ'H{Nyæ™gHاN2«4È;EEEáùÂN{{; 2ܤL$6®ìØìRn÷¦°"Ñ¢©&¨8 < MMM²$$¤(Ê¥\g---öQ8–†Ìkzš¤…,<$Ü(†¸lÆS(y¸]Ö¿¬ªªr,û¬¤‚ôÒÀg¦¬œ™™‘â2b«=V©‡’tzzZŠrÃK/½ÄIY öìÙ³¨K?ÊáÐ'$G–I4gHaÜ$8™bìØ1i¶uÿqî!*BH¸Ýli)+1òø «!“Ϲ‘`#0f¿!»'äg©0Ú7ãªûÆo˜'âæå—_...vY2—$CÊò:öW–ŽGÈ¥9H"\‚*çñ—„‡¨­ÊdÓYXR²=—ìÎÌä¹ädž…ŽÆ\p’z7%.¹EåçqR ÊÆã”2òÇÔ]|;#€Q!Õí9ãe"ù™¼cO¡»Pr1‰ÛKVÏ;äM¢Ýž/ðá'?ù‰É;T¼HKfEèˆHE¼cO·&ïíŽí…nLY!Ý¥ˆd ©¿šüuÉB.Ù?qðàAžEæF÷ìCÞ¡”#ZL¥œ¼#äxe"D»0ÓB¼zÉ7 lÊP ÌÂ7æ€D-IŠi¤‘“\rÜEz¢þÕÝÝMBäªÙöÙCº8OµŽ'Ö3ܘG¼øâ‹ÄÓÆC JRªŠøŒÅÙææfrõV»ÿvÍíÒ>LÎ$Ê#8Æ o!Ù^V‘Æ2<À½ØaâXÞ‘š/—x´,7/ "¼Åk¯½FΔ4n¨B’$`Ž”~*­³]cê,X–ö'Táö݈yD‹W>"Ç Áã’ÔT¸dwf<U&¼&ñþ‰ ü¥ ‘aðÝ%¢xYÙrM*È|ñÜ,/™”·È>ò\ZíyÇ$H)ȉbqâ@òÙô Ž% H¾Ø³gìç*w¾ð…/p£É;KWeļÃSH·‡Þ½{·Ý%?JÞ1ÖÜH®— ¢â²ý@ÈÒQ'ùE†Ðój&Ù/É1z&ΤÀ±„Dê[&‘»äJ$ò1À J¯ß>!Ošd•´099ù /LLLxt’ØâñÚ]¤øÿ—ÝTðwîÜYRR˜þê(………gÏžÕF&%&ˆÅñãÇÓ²¥ HlÿK™Ï'óÓ½¹’¿ô[¾/ÍoÈüwYNKÅ™ß0± %:ÿË’=uLÍ£xűcÇìg•¬A H9Újв¼¼ŒXÎÌÌø¹í'i^¯àÀ½½½dû„zEÉ’;;;uÜ™‡ýëêê¶mÛ¦•fŵ¨ÿßÞÛÆ„aåÎX"’ ¨…ÊÔ„"U@*Sbê@*BÙ¨ 6q†¸ö =öúy‚á»ï5;{ìîi»/÷ÿvì™ß“y[Óz8NǼ¾¾~||üöt°‹ô¿zùÕñŽðùùyÁo üzÇ˯ù×È~ξ&~yyÙ‡ÿöhÃKu¼ðßßßÿÜqøQ_¾|9Î…ÿ/I_˜:½€Ëö;þ> ünô2½€L/ ÓK8ÅñÑu][Ôa,œâoøþ%üU¬/ ÓKÈô2½€L/ ³?2ëKÈô2½€L/ ÓKÈôNQJéºnÇÖƒuè%dz ™^@¦—é%dW­€ËÔ÷ý<Ïûµõ @Î[€ÌóXÈô2½€L/ ÓK8Ŷm˲¬ëÚz ûcᥔiš†aØoZÏT`} ™^@¦—é%dz ™ý±Y_@¦—é%dz ™^@¦—pŠRJ×uã8¶¨C/ ÓKÈô2½€L/ »j=\¦¾ïçyÞ¯­êpÞ:džÇ@¦—é%dz ™^Â)¶m[–e]×ÖƒuØ §(¥LÓ4 Ã~Óz ëKÈô2½€L/ ÓKÈì€Ìú2½€L/ ÓKÈô2½„S”Rº®DZõ @z ™^@¦—é%dz ÙUëà2õ}?Ïó~m=P‡óÖ ó<2½€L/ ÓKÈôN±mÛ²,뺶¨ÃþX8E)eš¦aö›Ö³X_@¦—é%dz ™^@f,dÖ—é%dz ™^@¦—é%œ¢”ÒuÝ8Ž­êÐKÈô2½€L/ ÓKÈ®Z—©ïûyž÷këA€:œ·™ç±é%dz ™^@¦—pŠmÛ–eY×µõ @öÇÂ)J)Ó4 ðߴž¨Àú2½€L/ ÓKÈô2ûc ³¾€L/ ÓKÈô2½€L/ᥔ®ëÆql=P‡^@¦—é%dz ™^@vÕz¸L}ßÏó¼_[Ôá¼uÈ<€L/ ÓKÈô2½„SlÛ¶,˺®­ê°?NQJ™¦i†ý¦õ,@Ö—é%dz ™^@¦—Ù ™õ%dz ™^@¦—é%dz §(¥t]7ŽcëA€:þCZóÇyÀ <IEND®B`‚gateway-1.4.5/doc/wtls/fig6out1.png0000644000175000017500000013401007374232663015607 0ustar toljtolj‰PNG  IHDRŒ©¹0êtIMEÑ 8aâ¹ pHYsÊ&ó?gAMA± üa·—IDATxÚì½}tWÇ}çÿŃ6¶äØF6²ÓHÞt8k”¤i‚´I6h›cÈÉD#zvEväž³ÀöÄR’"m¤vˆIß§Ïëé~ï;wîܹóžÏܙτ®D¢µµuùòåÚÞæáê¡´óÖètÊ?oAÈÓo½)¼˜2Êõp;ym]<ÄÉYzïÜ)ŠÓoÙFöC!—(PùKA(ÉëÖ­“L¨xc²M±¯®®æ¨¿xK¤8—ð’!b«ªªÒ›ÂQ¶Ù¿aÃIoQ?/»"Ðh–â¤ùîÂw‘Ò¤&‡hp¢ì:ÞSòË<Ô„ Œ‹B yYÔõ»jÕ*¶9…ö® €­èi#`YFMcÈë§ÛÉ$S߆±nÙ¯£:7YæÆ bøºýÚ&°„*?ÕcÑêõ8åá®â6´_)Tx¢ºâ&°A°Fü”_1SJ^J¦þÆ–ÿrîñ¿Müdxœ¼eˆ7—Û°aƒÂ»¨´¡Ó…×qÁãÊÕ·[/²›ˆa¹Â1W˜]Q×ëã/Þ:Ð}<ºâ“¹+¾7ÈÅ,ü'†¿\¼†®#=]̺ruüzüÐ$§ÉåÊ_}¥Ž­lî@ïÜŒAR1ú©¹2ru#™5k–>ka›bÂN9‚:"4Ï)óê²f{ºÓ¼bÅ ÞGÞµeË–ÉìNÎÉÔÛjk³8ð5ƒñHF¤]‚âì£îtA̼´‘£øEºªªêøñã¨lCC¥]3 .\ÈÆúõëyi§†¼Ï.•••=öX__ß‚ ºéP"ïc x_/^l}ÝF¡1>>®¹©À;ˆM˜z<®IúÌøßä ʤ)´‘u===˜•üä/Ò…Z×Ö֢ܧNêêêâ…ÞîÁ?wìØ±råJdÛØIÒ¢¬¼/¦ÐF’eåÝI»B‡Âކkà Yã1wî\MÃ(++ÛºukMMMii)GÙÐôB[3Œ3}†aä &Ò†/è4ó²eËø«oMŽbƒŸ(zEEÅÐÐÐáÇ3RÃ0ò„¢T†™F^RUUØÖ_Ö®®®~Ï{ÞS\\üö·¿ýÃþ0ÂÌ5écûÛ‹-zç;ß9þ|ýÍô †‘«$?pl†Áv‘g•µk×–••Ù—3Ã0 #ïÉ ‘®¬¬ô;sÑ—÷¡ž£X9“““Høt|½7 Ã0 ?ccc.\8pàÀÄÄDÈóîç<9gA)’"Ý××WWWÍݚܻpÔ?¤k»½½Ý¤z†Qy yÓÓù{øðáx@‡***Ö¬YcýF"û Uåþz<ä h°I(9õbÄÔsäg>ΣI}J­1ÑÜÜœèSΰHëKsKKË4-ùŒ`R›Ç±®IòõÏÈ­zBž7T|UÅSÅp]öêÕ«­ýddjnº x'Ož\¼x±”µ¤¤$!Ké¥f+--ÅTЛ5åu9… -Tšéœ0^‡ÇQ__ŸöEÙy¾Ô~ ¬(‘A‡«SºM­­­¼Íì;%ƒ"¢•@ùÐz…Ô&Z×!ž¸»ººÜÙÙ™DJ¸º[¡Ü02Ë… ¨"Pb^ ^c¿‹ÖÆÕ‚ÁþåA£¡¥{׬Y“„ tNÑâKæ>=ãh÷éS% IœŽý3)Òiù¨Z쳡fÁØ%â©ePh©u4OñÄ@´|ùò«’X}= Ѳ.™N…1]PÈçÌ™CQœ²0@m\ÞŽh…V-×ÞÞÞT’¤5¿ù›é¼)\´zò ¡’Éî ¹]œx§ìtÊWº»»ëëëýB¯/?þx ÿmll¬ªª Ë#-ùÙ×××ÐÐ000_ãÆÇÇ)¥Ü¾ëÍ iLÃ̸Ïr(á•••!¯rH¨ø ×ÖÖ†¿ëׯŸœœ”ê§ž6žÑºuëÌÅ £œŸIϾ*ØE±ÊL!´VDœvdž¡žº¤M^ŒHNÇ>p?iã§×²œŽ8Ó…jáŒwËc™¥·çØ<˜éÜÍ$*uI[«T#(¨¿hGz9q1 Tdd  Ñû’1‘–ä™ÏŽø¿äiyÉ©†¤ÓÓ§¦Y«Ó*3ÑDZ3ý¦; Zã9í/B!¢BLKyã¥àÕ`O‡šºW/3ÙT`ÐbËìPÖ 6DLXfDZ…/ƒÙ‘…zvÒXqèyQ‚§¯¾P}7s¹šÛŠ"ÒZ56í ¼‡£u3§bÎtg€ô¶õzúì]½z)~ä6¦„ç˜A=r¨ÍH[D:S] ~–/_žéR1½¸6~ãœî§4$3Þ±ìViÁb?ªaNç(ÕÓÔl"FÔ-‘Þ1YÓý^P´ ¹Ûc˜á¯± ¯·# ;~ü8VÂ+¯¼âŸ»|îܹ%K–Üxãïz×»Rù<¶gÏžúúúŒÜ<Éžœœt7u%;¼¸Lccco %fáÂ…'NœÈ’y¢CCCXqõÉY³fñ—7Ej½bÅŠááajÚéMïã}÷Ý77ˆHÚ2Ó¦M›rÎqB]]]yyy¡ "£KÝÀÒ×áúõëÓ>:EÐi*W þv©Jr¤³³³´´ô®»îºöÚkŸzê)„9ä pu¡ÿý¿ÿ÷xúé§QëGy$Q XµjÕÀÀ@Fn›¤RÙ!Ò<3étÀ9_>Á+½uëÖÜRèÐUÏ3555H]¦Óò:®xP`h\úkv 6ZZZz{{©=Qè÷ÂgÃ8p#"}}}4sN¡­¢ýZPDy§vìØ‘®Ø"ìÐð~½¹YZì¯ß°¤Ùûo|ã¶Ûnû³?û3š¢€ZK›OŸ>½hÑ¢×¢G°¯¹æš;ï¼sãÆýýýý×ÿ…3Û`Ñ(åÐU+“Ç“¯–4eŽò‘ðsóæÍôGô•¯|%Îëµµµe¶KahhHH5æZS2ÝðhrúB­IšqäþÝýäÕðÏžt_¬ýL“w[#u¨0ûüóÏ¿ôÒK—/_Ö}ÿާÙQWW—Îì̸÷|úÜÎCÄŒ¦•688(+b†çN:±CÞ‡¢ŽŽ6ôWDüÔ¹ÓÑÉŒ >ï36¼ùê_¯á5ç½À¤nmm=qâ"½qãF}yÌtÒrƒÌvwS­ùG˜{ÄÿÆt`(š2rôéßþíß"šœœ¼é¦›¾þõ¯üãvº¦Ùäh«+çMÑ!ßrô’†ûåå¡è':YJÒûÕ€Òe>(fj9ZÇô)yvP'ÔÖÖNS?ÓL‚á‘„È}ûö­Y³&Ú[Œ"F»ã|õ „¼æŽ2píÚµÔ´Î`gm#äúÇÍxŒø½9¼¢Žæ{C¤¯\¹‚¡ø¸›³gÏ&”kñôuÆ?™J°çúë¯}"°§':^}õÕ÷¾÷½1†>RËçâÚº LIä9?ºë“€ ±±Ñ¿FzêLÇ÷<¤"׫Ë‚'XUUE}’ë‹j¤5UCCCÁVш1QF&% í^•••…>`'{h‚‡„vVâìڌ؂×åù• SöuS’>úÑ>ýôÓý˜ÂñøÝ½õÖ[ŸþùhG_~ùå|àdzö,ƒ˜"šÞóÐC¹÷ oHGGÇððpº ¦ð9NáŦ$ÐTÌr4¦ÞqM(pqâö±ðéœÑÚÚJ—=}ýŒ1ªK:â<#Ìe½æ¨8M.íEtÄ«5ub|ûO¨»+À:r'ZþyãyaÃá*‰®mšÇPöíÛ·xñb*ÒŸÿüçþCþ\¢}FVéK_úÀ>ðÊ+¯h02¦£æ;v eéïï_¸pá®]»b4èQdˆ\—'>oÞò‘ Ê‹-ÒªÏl\ï±bÅŠÿù?ÿç¡C‡x.o{ÛÛb\‹¶þÿý¿ÿ·ººúÛßþ6W<èñÃþððáÃ?ùÉOþßÿûè}ÄÏ4®æ™½dÉ’äLˆ;wF\XwëÖ­d–ô 7Ü F¥–6Z·nä ·rHmmí”sa‘vº±±ÑÍ«ãeР_ÞÉ/ùË7nÔbj_wÝunØ“ãµ×^£üáþáܹs Àßk<Á"v¨8ù›¡yÒê€ ¯n(…êaP*É^’hN.×zLy­Qˆ1¬ô`#Üj® Ñ?¦?Y“¼Ì¼ç¼™Ü5’¬ŸTþ7\Mr·tšk©˜šhÖ¬YTCÔbˆ.mFb&$•ˆøϾ}ûˆVý9w§ø]D €³‡ýä<Í&¢¢4Óà' %åþô§?MsŠêÏEX__Í{>õfÚUgŽGFžµ'¨ …$¡S(öÈžFrPí"ŠÎK³Œ]Êj WF£:(“„…À;;˜ÀœEé¥ SƒQ˜ý5•Ê?U|ìòÏ«§òOVåŸØüåŸ0H>al"xŠ8GCwÝuÏ1¢÷1Ž:Ç/^<U˜œø­o}ëþà.x Éúu»téÚü³ŸýŒÇª S½”*؈õ%“’æšoˆôM7Ýô{¿÷{O<ñ„~FTû×.pË]üË¿üË>ðøó…¦‡õ.Aýë_‡¼YÚ!ߺå©ðØcE[|Úqýõ×ûífD('\ðótc›ûþ¾YÞv^rZâ7IŸ¢Fmâïê×Ëq`Àý*…ÅŽðìç/Q>p9êJ°LÞpT ¹#*RËÛB«–ÀþÍ›7S`hP”)èþ4tvvRˆ£Íkšs!éÅ6Ò’Ri¿©×ËþÞ£xˆ?Ÿ5L— Ú²cu2S˜|ðÁºº:^4øÑG¥EK‘ c, Þ£À~Š4¦ð׿þõ×NQ!ªhã\ùW±üÓ2 £üwuuÅ(ÿ¡ÞàY§Å…ÀŒ[8SÄÙǘԟùÌghWéYDüŠ‘£žEž»V=æ)Ë¢ÀüùŸÿ9Rmð<6¹„j-„ÜŠQ¯jáԈϑ‡µÿ~7søõ´Òœ{ýõ“7Þxc@ÞÝ|ó³Ï>{gié™3gÜNÂ<÷Üs¿ÿû¿O}zÇw°O¾„7uý‰K×Xî_þò—S®?-üË…¦×MFðßO—ÒF9à}¦f¡XÈ*¥VRï9Ox‚ñ—vµmyÞQmm-µ gQ4UvùË)”êrŒB¦xBWÕjeÕªUúæíšÑhå.Úmì¤SúI0•£ »víRÊeXûoSžö¨R…¦ÃŒ6ò !%V 8RºÔ/ MA¢äð²Èi¯o eïèÑ£*ó:‚‡¢»ý*Ò”óeË–¡(”Lé{³_¤#–N§"/ÿòLË¿^Øhå?¤jÛ¶m™Îþl½ó7³ä”M.ØÆðu.ÜHCuUÊc’vR‰Qft¾üòËþAapéêêÏ<ò”Èõ()óÌ3ŸøÄ'¦Ìnï¾ûîóï!4_ò¸ûî»áilêsº¾³Â”­þ^xDÞ~ûíZ–„»àePŸe=`+óTdÙ“õ¹2‰'Ã/[!«±­sËÌâb‘Äéqwr#]+üÅ9vìutBC¨Ü¹…ðxrëGC–´}sˆúóãtÚ˜=LÙš´Q\ñÐÆ§?ýiýœ?þßþíßòB¡š4¿PÖ›nº)-Ei áñ,åÒÖÑÑñÖ“$õú¼Þ§B:tèÞ{ïEí?ö±ýæÕW48X4{6f~ee¥ýÓÌdÏg?ûÙ7-Xðþ÷½oppm–-Ÿˆ%•…ô’ÒCK66S…ý´7¹±\½¦¦†ú…æBŒA4¯¾úª–ަµB¡¤Êæ\Z=Š„slÿÀc7Ú>!è‰B.“’tý¡ªo ~"W I—[z†1Äžb\sÍ5êíøÔ§>…¹˜\kæµ×^»|ù²¦)ùwò#;þx°¡5ž÷wR¨´&®»î:šçÏ[ð¦7¡vDý­oû=ï~wÿþýeK—^?o^QQÑé3gŠo¹åío;šGšÞóž÷Äyu™¢ˆÔ¤n„¶>pé@ÈeË–F]4(61-‰zD$ºHµÜ}ÈW­úÈwNw_û¤·f—*Óâ.h Ò¶ Í9× ÛÛÛ›[S($—é„€W8éqyu¬5^ý¨»[ƒ®ôƒi”µvåÊ•ßüæ7qF¥À¿þõ¯Q1ô1p¢ô> n±A¤Ã5îÎ÷w¼ãßùÎw^xá…w¬XñƒþðÏþìϰªiYœ?ž£ü]÷ðßÿ¾úÕ¯~âŸø“i2TTThZsœÇd.Ë™†¾eŽŒŒpo¾ŸùÌgü!ÝÔ)ê\Âs!ÂkÏñ+ƒæú®ˆJŽPbœ›bÍŽ*8p`hh3=âÜÊ4º*äe#»¦£G7×áYGtÄfT²ù±þlÚ¡R¢4‘ö³zõjŒ¨¿ø‹¿y#Èв믿¾³³ÓME>wî\@Yc÷;?`‚!:ˆàÍ7ß,±w¡SMÑê¯'Ò}6«­­}üñÇï¹÷Þ<ÑB>ï¸ãŽ—&'_øå/ßzï½!Ï¥6Iÿæ7¿ùÌ3Ï<=:zÏ=÷èÄ„œæ8›’r£ñ{±]DIÔÅk¯½cé­ð•‚á߃¼UœL©Ê~´*x¢—ˆ†æx˜HÐ][iª`¡VY¼xqN¯šwîÜh#bƒA¸`Á‚ÈǾ÷½ïq Ò/]ÿîßý;÷WüøÇ?¦Z\±bÅ’%K’Î&¿wx/4ªÿ°u¡¯/½ô’ߢŠ1DYó¶ýÝéyvDòÏÕÇ=Â÷Ǹ Ò»w®¯¯/<€¼š[e$hcFÛ↦û[ûÕQYY©Á¶™NH6‚è|ñ‹_üò—¿Œ*#yê²Ft\Ï+û'<Ç!qFȉásPôßgcðéOÚÿ‘âwDšDKê>ÿùÏ#ÕÏä‘GT'bõ'*ÒØÐrÔ¬Ÿni¬³gÏbצş -—[n¹%ÎÀ5x“GB¥ÑJ+>ѤrVøTWò„ü¡‘D"Ú#hjjª©©IÝ5[®ƒB/_¾Ž vTÂrÛîÒàüùóÓñôTsîéÓ§µ?þ|¿m`ÃÃÃþëßÑùÍ›7cø£[1œvñÜ|óÍDñþ÷¿?Ѭ¡ýâ_ÓÂ}Æ’Æ4O1ßÉŽ×ç§ L¢ë$F#þå¹ð"‘'Û¶m;vìØ©S§H9’ƒ)ÐØØ¨1íÏâ('ò¦%ñ9м9Rš­F6ïËàà 7f:-ƒŠhÅŠ!Ï{h¦Ó’½ q”²Sá@YgÍšÞíŠôN©& Ïe‚#ÆH}æñ€ Xý·²ÿÜsÏaÿå_þelÿ¿ÿ÷ÿžtÖP«ú¿ÑJ#eX_¸pAŸ’ŽœÜÑG…_|1cšÊ=-Ó6º»»µ:J3«PÐÚ :øú׿žÁU 0(y´<23ÿú¸¸5}z¯®®Ö²n™JImmmÞ7ƒò ^LÊŒz£­Ú›»hz•¶©K÷ïߟg78óÈ YÀ÷¥C³i"ê4;_}õÕŸÿüç!oÂ0ʨÏÒìÂ4:,†N#ï¼ò ¯¼ †%²ÍÏ;ï¼3Înp =ŽXu¿qIlè¯|å+!ÏEÏ~øá×lšóçÏW/ôÈÈÈ_ýÕ_iŽ6&ï£>šhvlÚ´©¹¹9ß–RhîVãxÝþŽŽ‰ûA¹ýÛÝÝV¹AžSÆÏ]äM ´³³‹A#G^w>sñbIIÉÁƒsºVⵉáôfÆÈ›FORUUE%FAâíØ¾};ûÅ‹ëË_¦“–<ýýýæŽ;í`³9s&šÕ‹NSnºé¦ë¯¿>pÆ€öïA1‘geŽóê´&£Õuoˆô=÷Ü#§£4üñ~ðƒ¨2jzîÜ9pߤ¿ýío;/*÷Þ{oy!ß@MMM±’æ ýë_ÿ¹Etý% £˜"Û¨²å ^¿#GŽp«N™Ô 1þüóÂ]¯õÐO +˸š4T¬<МndL”jkBëI>9çGùµ‡³ zzzZZZrZ¤¹óÙ’vŽçŸ>özQ¨¸f!…K5üêW¿Ò¸.ýÄÈŒß!(Ï4ZÃëè–,Y²sçÎêêê›o¾ù“Ÿü¤:·ý+¸E¸8J`ÿñ?þÇÿú_ÿky!ß@uuu4lQë={öD vë­·rõµµ4£?¨¸÷ïßO»&°¶•[2K?i›Ä6Âéy&Òä:&Ó©Hž®®®¼õ“h ¶à•Dضm¯R¦ž”——ç´‹:¬ Ú¯¹ÛøÎZÐÈÞÞÞ)ƒÉùIÄC²Å_ô…96‰ j­áøF,úôM¤$ôþàB^+u|æ™g~úÓŸ®\¹Ò Ý®ÿ‹¿ø š !oxzrÙ< a £µ¨uÄɾ4(ŽØ‚ÑÆCií#7`بÓýº‹f/\¸p»Gøé1Z.ùA®WF)–ÍôyP#²qœ4L uBdTˉºD4â)ÁLýÌg>{Üq ÿ$˜×ozÓ›0/ñ‹_Äž]-ã]ŽöYí ‘¦Büñ¬ío}ë[ü y—ÿéŸþ‰¦¥ìÈéG¸B‡¼Qfùí®KŸ!S\Å+SlÞ¼y×®]™N…‘Ÿ`‰æè*ËÔoñ¯úc$ Jù÷ÿ÷1Ä^3£È#tu‰Åø‰Ý­ûº%<£ÿÈ0Š‹`ß}÷Ý*h°æIÓ¸xÛÛÞ¦¨=¿óï°gñâÅ>øà“O>™b¾  $ñ¿ü—ÿ˜å>7¼¯¯…vŽy1 #Fˆf£Ðè49maj´BâHŸUìÙ³gbbÂ<3ÓDCCMØœ{/¨úÖ¯_ofôôR¢2ï{ßû¢ˆèzìܹsçÏŸ—'Mi ¦? §O-.£Õøº³ë/|á üýÜç>G¤¨õ'?ùÉ{î¹G‡_}õÕ^xá¶Ûnó{Ã>ûþ÷¿ÏÆ»ßýîû·ÃàN%_4Yè©§žrcÓÄM7Ýä_ç‘`¼Wè.u÷š5k¦ìª"‘(±[Ã#Öö¾}ûò~\e…LÓ<º\4ótÌ»¡ƒJù¾û˜;V°ã(c]]]¹Õ¬­­]¶lYŽ~ÀJ”ôúuÞ¶m[<ù†Ê`ÿ⿈öY)TÂ.]ºô³Ÿý ‰9s挛ïׇ>ô¡Ø#ȰQÛÚÚbÌzãäý×¥€ñúüóÏ£ÖìüùÏþÄO`˜Þÿýïÿû5—Éͨyúaböq]Þâ?pà€ÖÍgÏž½ùæ›ýÆ4mh¢ÎÀÀf7–tx_7Ok¹GŠ)Ï~Ð9ª¡hCç²^œ.¢Œlƒ6zMMMµ_÷ìÙCs-žáÇFÒ F[·nýë¿þëGy$¢NK¡ÿñÿñ™gžAý3›±.(Nh¶ß &îÿù?ÿgþüù˜ÔååågB·´´Lñi¤|þóŸG ÿóþÏo~ó›i)|ðƒµwïÞo~ó›ZŒ’3ÿðÿPîMøëýc“}Ðc÷îÝüÇœ®L¤>|ø?ø'ÙñË_þÒýÄÀ¢µ‚}Lë¡§§'⪱ìç¨æ^Ó& w…-ŽÌŽ‹ žckk+™6‘ ¤e¹ÏÐÕ!˜Ñù=šÏȨ0b¦cd%/¯Fºbëîî¦Ö-¨E½2QQQñ‰O|"¢»’óçÏû?Ëž={+è×Qxþùç§œ‚±qãÆ)Ç0¾ñMC9ZˆØž¹ž|òÉ¿Iû/TVVö½ï}/°àV»óF§ Y÷eÚMÁræ'NŠ5eýèÑ£ØeT[[K¦wyGêŽ-[¶P ;;;STVž©Þ|4Sbߤ§éÐ? ³6·)Ú´\úúúHa¡}ÊÔ7é¹s碉T˜døc=på={ölÿH)lȾ(.\øæ7¿9Æå(*˜%S~s ~ÐÆxýéOèmxúé§Ýö7ÞmXuŠ)¨È‡>ô¡C‡ù‡¹¿ð 4^¤Üýýý}ÙÐü1Ç:|õFr$âB`…€–©Hã¬3Õn4ƒNž<‰¾ÊOarõÑž={¨‰RWzÃH¹4.>-_`rÏ ÿÇû÷ïOnøËððp]]ñ„…ê544”®Øâô;::*uS…‰Ü¼ï}ïó«aÀ¼Fƒo½õVäéµ×^;wî¥\<¯>O±§;^iÿà´¾Þ^ÊVÄžä7N¸öÚÿý¿ÿ·Và€Ó§O§+••ð™Ï|æ/ÿò/ýYóâ‹/Òz G´¨Óéˆ ö<ÝðáßMMM4 °¸‡®Î'ß4*0üö‡žHss3 LÔ:¡1_H;…­ªªŠrÔ³DNcët…<¦¡©9ÅB8>>Î+Àû%Uf#XKìÞ½;~©–³&´™·)¿½"Æ€ºzýúõ©ë4Õ8ÎÌç jySU˜˜Â?üá/^ìÄÝ ¬ÀKS"vOI´¥%~ç\þ«_ýê’%KøñÿðýÈGüC¬#ò«S§®õyŽP>ñ‰O¤˜~P‘ÚÚÚÇ{,|²ZQQù¥šEæW@ªyÇ´¾M¸ÇÙ±÷¨ÜV‹}9¦ø†ÇÀ!2¿¥¥…÷¡±±év ÎmkkãAÆrÇe>F«49Èv{Z>ŽÒ˜tw5Ò–-[°¶nÝ8$ј˜ r®­)@åæËò*¬þøãЛ6m²ÚÄ(ü=Ï4dKKKy;thdd„j„¿ýýýXÞþå|Œ|E_C¨-1_zé%T{:†ïô2ëJº§§FïƒsâM¾„¼éÑìñ|O´¥9r䈓#j%2ùÀú¬€á+Áž;w®ÕAFÁBCCYÂ|øðáx`á…쟽VhPCj ŠS[^{íµ©˜Žñ“]ºÅ› qIntº££#0¦.NüãM¤ Ã0ŒäpëGÌð,¡2Øã¤§§'à[AiÂ$:º•ðõõõ[¶l Ÿ0m†a ¡yYåååΩåÌ0;õ(ÒKø#­‡A¾466655Å£¸CCC(ôÚµkm°˜a†‘Pô¨¡¡¡¦¦1Z·nÝÊ•+]ׯÆñ„¼q ÍÍÍéºhÖ‰tD¸gäV3bHµ&àj@G__Ÿÿcª¢4 Ã0R§¸¸øÈ‘#!ïCõè訛Ù§ ™(Ùõ™‰Eh÷íÛ-€[ö< ºúYQQmBQø×nÃ0 ÃÈr²K¤ÑZleŒæ8Û#úPO`iÃ0 #çÈ.‘M›ã äüäÉ“6›È0 ÃÈ!²N¤ Ã0 ÃÙ5Ë0 Ã0 GnŒî6²}ã7×K†áçÒ¥KgΜ)**Z´hQ¦Óbä<ÖÝm$¼Ì[2 ?Z“¦¸¸X‹F*Xw·a†ad)&Ò†a†‘¥˜H†aF–b"m†aYЉ´a†ad)6ºÛH›‚eáØ,#˜H†aF–bÝ݆a†‘¥˜H†aF–b"m†aYЉ´a†ad)&ÒFòTxd:†‘]œ>}º½½}ïÞ½™Nˆ‘Ø*XFòŒŒŒd: †‘u\¾|y||<Ó©0ò³¤ Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRlà˜‘<ååå™N‚adEEEÅÅÅæ¸ÛH æ»Û0 Ã0²ëî6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRL¤ Ã0 #K±ÑÝFò?~<äyðÎtB #‹¸téÒ™3gŠŠŠl€·‘:6ºÛHžY³fñ׊aøooo/..nhhÈtZŒœÇº» Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRL¤ Ã0 #K±ÑÝFòØ,ÃǦ`iÄDÚ0 Ã0²sf YŠ¢§§'ÓÉ1rƒÉÉÉ•+Wºu<ËÊÊæÌ™“éD†‘“˜%¡¡¡¶¶¶þþþêêj[2ÙH»»»nll\³f©µa a"ý;ìÙ³§¡¡Ê”*c(ÓÉ1ò„±±±öövÔºªªª««Ë¤Ú0Œ81‘~ƒžžä™:Tþü2#?Þ¼yóêÕ«›ššLª Øû&ºxñbeeeÈëå^ºti¦“cä3Ë—/Ĥ.--µò–¯œ>}zïÞ½‹-úØÇ>–é´9O¡Ï“£ºÜ´iÓ‘#G¬Æ4f†uëÖ¡Ð6jé´éçòåËãããHu¦bämIcCWTTtvvRif:-FaA‹pxx˜âdž~0 #…kI'¤ÐÇŸå។e©€Ä†G0eà+Vøï1ù$,¶X*w—FO¨ØÓ›6mÒÐEÃ0Œ…(ÒÔ³mmmû÷ïOcœ˜DkÖ¬iiiÑϦ¦¦ 477ëgGGG{{û1UÊÚD‚´rttt×®]'OžÌt>M CS“Üò¤úúú⌙‹x؃gM‰¹hìl'åÓñ½ƒvÃÄÄ„ká¹NQQQqq±9î6ÒB!Š4ÚY]]öÉЈ c‘«hì.ÛìY»vm…rÎ¥µˆañâÅ“““„_¾|yx?¼â¢Õ:?%6l#-ýýýÎBårèý¡C‡BžÎqYO0«ÆŠÿ`§K9‘G”4â'1s®lS·!hm yjvÉÓUh»p›l³_)Ñ~b#°¶¹z]]±Ñ^!|Ä{TÚÀ%žeee ÌN`A´¢å×rnÚ&º§“âáü ›ôHo±”–7NGÌÆÌƒ<744Øü+#=\)0N:Å]ó7¡³œÕËFŒ`¨ï¾}û¶mÛ†Ê^¸p=\ëá”——À­?±§³³3°“˜1ýùK„Ä@ƒ ªªJÑ#žS¸?I À‰­­­ ð“C„Äšg?9³žŸ.aÀO/‹Ø¸MâÔ%ãnÁm(—8‹ÔêvPem­.A¥„DúSÂ)Ø”ìÔ¹tq’¥„×OnœðUîQê¢ ¼aÆ­[·ê¾„{ÊLí$$²-oÊ"QªØÉµ¡„¹,rJ/¤–g—öh ÃÈi N¤©ý’'qŠ4êEUK¯Ú– QÑó‹Ð…‰-Ò@`N!*·GÂÆ†ô ;r䈓O—*m«³IlØåÚ£S´A<(ñ( ìQjÑ35eÊ=$®þ"lNNbˆ´Òì6”0'ÒJ‰ÚJ‰„ÜŸÎ@œþ{äDÒ@JüÏÈeÈO•ýyK`Ý‘fÓ-.$H¿%ÒÄI:y ´- ›V‘N®d†‘ß\ww[[UaêñÈ JÀ‚Çþ èíííÃÃÃÔõqºI!¶ññq™°ÝRg,‡6nÜí.JJJü?ËÊÊNœ8144T__‰q þx$Éį ‘~”= y=½.ºå¾ÝÎ;7ÎCѼˆwtñâER‚ÍgT]]]•••---=öXŒËù644èvz{{1²Ãû–•E¾}ûöêêjÂ'š°TÀjÿ¼aB®Š4â·bÅŠ$ND®ÒRç677#TMMMþš'ÛŠ‹‹±MÝð±hT\…›BSÙèèèÀh޾¿¿EчÒp—U(Wܲe‹¾IcÖÔÔ 4´!  xBÞH·7ÒøøñãëׯçÖP©:ò™û¾$U:‘8‘1.Á!Ná6‘ÀU«V%™¤DEJx@´u¸´ˆ€4“±»víBØâ‰ŸŒ¥‘±aÃå3)g>3s#Ü…ˆmš'Õ$#°¤o0ÈFžQrÓ¸wfyIîy£2 J®J¢ÄXLbaÌSõy:;3+©âF M;wî ø“BÏÜò—.ZwˆÓÈ?®ÍI‘6Æí»ï¦Ä Ti±á6o’¡¯¶ˆ.&,!‰Y!ÙÉ¢¥.n¥ê ÆÖD÷ïßOlÑÕLa"m¤‘lï¬©© —g‘¨Ü:tèÁÌô=©2­Ú¹Æ#S·˜nž4=&Õ†‘ëäêÀ1Ã0¦d``@ãà ÃÈQ²Ý’^¾|ù©S§¢uw'jsdCGwGGGyyyø°du‘eC Øð±P§É<%Ú$ÊÀŽ;Âã¡8¥e¶¡a$7,iê¤:õá0ÄsàÀÌÞ UgÄu ¸Áðª6?X±bÅ4yÓÌHòx‚rö’v(œÕÕÕ)F"Ïe¤ÐÚ0ò€ÜiA¥3::zäÈ‘T܆ûÓÈ,/^¬­­MWlÝÝÝY8výàÁƒþiiÙFö$™JJx/x;xGLž3ËM7Ýd¾»t‘K"-T%'Õeee ­“˜õõõ³fÍ’O’7à¶®®®´´TŒõÌϹs玌Œ¸SPhÂ÷õõXûuŠœx°¿²²’C1¢mmm܈»$r]TŽMÖ¯_ß}÷ñSÎ@¸fbOO&“0öh ÎÚ¾};‰Š ¹5åÀD"G9E )râ–-[ˆÊÛÔÔDj;<¸({”òÀÏ… jyG®BxÍv)Tllk)®(#þÉñÄìïÏ’ê.È@ÿ!9xѶ’Gz”«$I.bØ&? FàðÇMxBò—›Õ‰Ñ²1~’¶¤Sy)Œ´3{öl[ËH™öK:Ó¬\¹rppp:bnnn¾páBcc£[÷bÔC‹7pÝ­[·^ù]ßÝWÂüTŸ:uŠäi9þvuuÉù¶ O„:ºtéR)*®¨ÐU×ìY·nÛ‹/æ¯Vþ[ùˆÒC‚ùI´,‡¹%+¸Voo¯RB$6làî8E ynP ¬{<è¡CŸ¡«Þ¼ ¯Ø¸G9g]qwÇÏçX[³Ÿå«\ ~Ö)ñ'ÞíT7É ‡.DúI†óHª+ú·]òHÆš5kˆ“S” üÝ¿¿|€ûWdኄ!NžŽŽ’`¶õD\6ú¶Çƒ–™Ž’iFî’íÇÒ=–hÀ XZ@ÈùСCª¸CÞ×Ág€†Ã¾S ÃÈ~ N¤©¸Ñé)½HÄ Eœôp‹D9¨»±hߤCž½ˆd¢µ(kà¬4Ϊ­­•w-í¤Þ'ÔE1º‹EÈÙÃEQ ~¢mÜ âŒõ)sQ–"W”ƒOÌÑ={öètdl¹‡?¯°_+++Q, mã\—Û ´Böï߯¤Füî—ØˆÖoËs8I•C´‰×N­¹j¸d†Lp‡h¾øƒé\Ìki3bIVÄvðÎQÂp ¤yÞ²e WQT.eëÇYxÈÛ‰‰ ðeF€Üp š^˜’’ÌÁ$VÚÈ8h0Ú‰Ðv{¤ËUy‚M¯/ÄÑÂÐÂ@ö¸:‚„T§böÉE¶>ÃËXO}êQ6 lÄÎNô{ ™`kcä §OŸÞ»wï¢E‹l€·‘:÷M:ä™A 2£U›r ìK åt.n«±ù°5c‹:Ê¥É=,`’‘ÊåPzŒfÄ^í¤8WœÌ~´Z¢ ­ê¦ÐyÃåË—úÒa1(DK:tuîÓöíÛS›L199™Þ©½cccD-}ùN×uÓ[Ɖ?ý§ ÏÃÃönUÞ` li¤-égL÷÷÷S9bôäbå˜vçñgBz55Ÿ:”H6 Ú(ÕÕÕTè¹X Ø nà˜ƒjóE~?2£QwNSSSŽvç†1®H‡<>~üxUUUÄÉQ†1}ÈÁÙöíÛ7lØé´†‘½´H‡<mkk‹1%×0ÒËž={h ˜ —™[P#]èÀ±pêêê¨4mu?cZÞ¸qcÈ›J>M‹]†‘O˜Hÿ–ñññššš'Nè3¡Õ¡Fº hÑlii™˜˜Ø·oŸÍ¶2 #NL¤ƒŒõõõõôôŒŽŽVUU•——Çðmi1 MNNj4;µk×jÝ-Ã0Œ81‘Ž…Öf¦ªÉÂuš¬E ;ý-++˳™f†aÌ&Ò†a†‘¥¨3#-¨wÁºp ÃÏ¥K—Μ9STTd¼Ô1KÚHžY³fñ׊aø1· F)ôyÒ†a†‘µ˜H†aF–b"m†aYЉ´a†ad)&Ò†a†‘¥Øèn#yl –a„cS°Œ4b"m†aYŠuw†aF–b"m†aYЉ´a†ad)&Ò†a†‘¥˜HÉSá‘éTFvqúôéööö½{÷f:!F>`«`É322’é$FÖqùòåñññL§ÂÈÌ’6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRL¤ Ã0 #K±cFò”——g: †‘u›ãn#-˜ïnÃ0 ÃÈR¬»Û0 Ã0²iÃ0 ÃÈRL¤ Ã0 #K1‘6 Ã0Œ,ÅFwÉsüøñçÁ;Ó 1Œ,âÒ¥KgΜ)**²ÞFêØèn#yfÍšÅ_+B†ág||¼½½½¸¸¸¡¡!Ói1rëî6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRL¤ Ã0 #K1‘6 Ã0Œ,ÅFwÉcS° #›‚e¤iÃ0 ÃÈR¬»Û0 Ã0²iÃ0 ÃÈRL¤ Ã0 #K1‘6 Ã0Œ,ÅDÚHž L§Â0²‹Ó§O···ïÝ»7Ó 1ò[ËHž‘‘‘L'Á0²ŽË—/g:Fž`–´a†ad)&Ò†a†‘¥˜H†aF–b"m†aYŠ 3’§¼¼<ÓI0Œ¬£¨¨¨¸¸ØwiÁ|w†aF–bÝ݆a†‘¥˜H†aF–b"m†aYЉ´a†ad)6ºÛHžãLJ<Þ™Nˆad—.]:sæLQQ‘ ð6RÇFwÉ3kÖ,þZ2 ?ãããíííÅÅÅ ™N‹‘óXw·a†ad)&Ò†a†‘¥˜H†aF–b"m†aYЉ´a†ad)6ºÛH›‚eáØ,#˜H†aF–bÝ݆a†‘¥˜H†aF–b"m†aYЉ´a†ad)&ÒFòTxd:†‘]œ>}º½½}ïÞ½™Nˆ‘Ø*XFòŒŒŒd: †‘u\¾|y||<Ó©0ò³¤ Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRlà˜‘<ååå™N‚adEEEÅÅÅæ¸ÛH æ»{j´ŒDOOO¦bä ®SVV6gΜL§È0ŒœÄD:ccc}}}ÝÝÝK—.5cÑH…ÉÉI :ÝØØ¸fÍSkÃ0ÂDúwسgOCC•)UêÊ•+3#O Ù×ÞÞÞÑÑAÑêêê2©6 #NlàØôôô”””ô÷÷Ÿ8qbß¾}¦ÐFYºtikkëÄÄDyy9Ålûöí/^Ìt¢ ÃÈÌ’Q]Ö×× ¡ÐT¦™NŽ‘ç¸òÅÅÅ™NŽaYM¡[ÒÔ˜ò>=::j mÌsæÌéêê˜.--Ëtr ÃÈj Ú’F¡©([[[×­[—é´ ½|ùòƒò7Ói1ÒÉøøx{{{qqqCCC¦Óbä<…kIˆ6…62ÅÒ¥K‡‡‡W­Zeö´aÑ(\‘®¯¯_¹reœ M5ÚÓÓcã}Œô‚NcrUWW[¹2 #"êq ¹9räH<ËÊÊœ­ÓÒÒrâÄ ïc¤ š‰£££•••q–FÃ0 ŠB´¤±ZÐÚýû÷Ç…^»víàààœ9s87öw&´µµ¹ŸI$²££#Å%i9H¢¢™’R&Æ7-é0¹ÛI=‡)ffSS-¿ááá´$Æ0Œ|¢Eº¹¹yÍš5ñ[Ø8š9ÍYü’Ç­ñ—mEKHµ‡¸– ¦Ýé„W]‚áw¡<Œ‘Ô’Kl.fw!ò3ä}ïà*ÄéQbÔ QCD•râRgs¥Â0 ÃQpÝÝCCC²«¢¾¾~llŒýS¶úûûý3gÆÇLJ=êêêÐÅŽŽ¥æ¥îæ\.­ˆëäääöíÛOžú¨Žax¡ ú´¬ïÓœÕÖÖÆž@0I>ï»ï¾gµ·´´ .îÛjD*¬aÏ~ŒN¢Òuý‡Öx!›7oV 1L‘½À˜çÇ{ ­•­,ˆp¹§,ð Cø_ÆQò9I ÊUÿ˜AdXö÷áÇyŃ>tè1 Å¡ ¡À†a…å»[–Mº¦Sé'W«¢ê>E0@±§31FV@ë‡Â€qŸé„)qîܹ'Ÿ|rþüù÷ߦÓbä<êq,-$m÷`“aÚ"ϘÑHu¦ïÃÈV¯^±ÛÆÈ-Ο?ÏÛMCÜDÚHé °fÍšS§N%mˆ†a‚}“ΦІaFlL¤ Ã0 #K1‘ÎCbLçAEEEì!u-++s?KJJü3ÐæÎ«‰àìôXÕ¤5³3•?N<áûg…ÑÓÓ1¤aFÎa"=C8O&Ó B¸cÇŽøå0~ïò¸¢ðòmÂMiš2º¸`Á‚•+Wjg__Ÿ?½½½ä”‹b%½Ô1M›6-]ºTÛÎa§aF®c"N¨¶¶6,Î6.IZwwwmm-û%iÈÛZ1SP5yÑjŒüätlG¤ËMJæ§dnJ·A` hb›3gÎêÕ«ù«¥ýnÑüÉÓÂË€v{á¹ç’E~W´6ISSÛìáÖBÞÜ! S×Äe9\sÙ‚jrþ›?¯¸É–£±OúÓÊþ:íWÌ.]šý…‡Üºi[ÎjˆÊߣ ³”]º£À—Pž»CJ¡Ž’¤ÀìpÈ¥‘ò{M[Èé´–ÔÕÕŽŽ"###Z¤Åšœœ”Ã2QRR‚°=zT³P»7s• ]B½eË–‰‰‰ûî»À "¢;וnJm 'FQäKN?Ø_SSÉsçÎÕ*×DN’üqšý&/)wáÙàrˆ–\¢*ÀÎ;åîÛµkiC•e=S%±Ÿ£„Ñ~- EÅ)n'{¼qãFÒàŒpÙŪ‚#Ø£4(€Zþ^÷hp ñ«Cž¿D¥E*É^õÆs “?=äùªU«¸­}I²}ôQ~Κ5‹¼å–g`nÃ0Œß!ÓÎÃg”mÓ9zÜÙÙyâÄ ìH-«ÐÛÛòúcÝb ZJK«nhqˆ§¦r@ÝÕÕÅÎ ZnA –[.ÊÝjZÚ <Ý2M¡ß]¢CýÀüÜ·oßàààâÅ‹ýÉveÀ-€ÁFkk«ü@z”ð÷ĉþr¢›éÅDÚ0Œ¶ÀFz˜œœ,))‘áXYY‰fø;iSA£œd”'ÖÚR§4É.ØyJ/^\¸p!Y‘®”F´,·F˜¹ ¯›šØo#uì›tzX°`:ÚÓÓƒZÓH—Uv`ýæ$ ¾hnnvÉ+X…yÚ«ªª²P¡ Ã0Â1‘NZV9½q¢ý鲫l¹-±Î#Ó©ˆÊÈÈÈ”îÒÊËË.\ØØØ¨ˆ™N²aӈ͓6Œ,"žoÒ´ÛvïÞ=44„T;W3†aä%&Òù€óe–Sv¤'ótOj§;Y’!ÏõJkkëÄÄÄž={êëëSqŠnF6c"ìØ±CƒÀc€Â­X±Â¿§½½}JÙ‹'æä 1 ùëŽ'µÓŠÉg0áhÚ˜ó¡fFþa"í`$ÕÖÖ¦OUUÕîÝ»Cž›‘Øß¹ÓuÅØ½•ä9ÕïzÖÈ,óæÍãu{ç;ß™é„ù€‰tÚß²eKIIIYY™Vh`{+Gݤ(߬Y³***ä€zýúõ¥¥¥ü%Œf…ÕypHÁ¨vÑK6úúúØCEÜÑÑ¡£òAÆþÊÊÊÀ8£žž®òÖ•’n®N~r-š¿÷ÝwŸÜ€“¥Ðõ—®È®E:µ`¶,W$Z"ñ_´¦¦†0ŠSa8]·ý‡üÛ\—ø57ŒÀÄ©›ÒÝ,âL9LHîÂeÛº…×9ïï- fLw§§£¼…¦¦&®Âµ\6jÂLà§»e¿£ïlÃùNÏtBŒ×™?>"}ÿý÷g:!F^é‰Ú3Ê´:3imm•¬µkײͅ–.]záÂ~²-§c§®"¿"”Ó.9#˜„ÉÅô¾}ûü¾´ƒÜz_¹ê$ëŠ7ÓÝïjC'’˜7ÁZ®=£ ˜Ÿ›6m"…„$Áît¿KçûŒ‹Ê-!åÉD)Q¥¼³³SZ¸º¼‚¨tùi[®¾” ¶fÍ“ºýç14p ¥vëÖ­Îw·?+\Ê™;…k¹ÜP>p!ݱ麊ÁŸ`Eèÿ)7)΃Ûô‘Š3•ºiMža3MÁJ˜°Ôø2Q4X^£©vµDcÀ…õºuë,X@‹;äMµÂÊ\¾|¹›ÁLH`L?ðÀÚ£Už£XÆüŒ8é éÅLÄèD]0°°VI˜T'€Vx\½zµsÖÎâÅ‹ ƵˆD+Di¦5éq‰GV±eÑ nŸËagëÆIƒ;„À»mç?\«v˜¨´0‰2JÕRq)Áz&$ÙÈ ,f®Kò×ß…NÙ—„g?61ÙÂU4m ÉgƒÓý &Wõ3ä ´ÖÏœpÙÝÜÜ\]]ÝØØ˜é„†‘N¬»;m¨~D P ­ÊàýA´¨ôÃL¡¦È•¾ ‚uww#’½‹òaÄér©Íψc©¢“'O"Ѝõää¤_ûCžª±3ö -]1< q’ö£¬Z,$äuAA%ÁœÈµHºHtÝÒJÕÚvk_¢+Zû’á¯:êcä0 @Aµh´Ë tWS’äô[¨ßž¬àY°Í…Èöœ8qB´~ •`ÝÔÂ… ù©˜ÝOÿºÔY éä±úÞ6 #0‘Nrf‚lÞ¼Ù ˜@c ̻ÇŽÊÔsV`mm­$V½Á29kÿþýÈ9JCuò:¢‘“pßgiñf"ñKWÈû4‹9ø¨ìG‹.ëŠC˜ÂúŠÜÓÓ#‘ y:§Å§I³$íСCä;Hwˆ»óÓ¹ÜβeˈðÑG _,+À¾}û´\ýY8i‰&pEò‡0Z²šµÐuàÛ­L0p/üTÌîgKK ™œÍߤźuëâYâÌ0ŒÂ|wgž€7iä)R·¹'˜à(«_¤ÃðÜ|ðÁüã4 :;;3ä¤è»;;‹wrîܹ'Ÿ|rþüù6vÌH³¤3¶›ÍGJ}ò¡Ð!¯Ÿ£µµU˜¯R«««8éT¡óçÏ üä'?ÉtBŒ|ÀŽežõë×ûWËéëë ÿ¤mÄ€ö͔֧LçÉÉI×KŸpk1†‘‹˜HgžÀšT…¼DUrÄŸcy¬Ð iñ™N…aéĺ» #O ±b£» #Ï(,‘®®®Ö÷Ëé`»Ç ßWœ¦!f1bvÎÈ¢QWWWYYé~bá9çÒ˜zœ.-)++óçØ,’’’‚]1B#Õ Ã0…%Ò™ííÌu+'þô777 Ihi±áVTìèèXê1<6N:Å6GŽaÜGóW‘;v,ðSžÀ‰D!ý]°`ö|Só“‹ò—Cž›°åË—;§Öœ")ì¼â¹¤Ö…ÉéòƒMbðû‘vé—“mÅOÈ+žÓrÒÆ!¿·mÝ”Övä/¹œ˜síç§öë”'ÒJßk76mÚ$?©ÕÝq¹®®.vrá÷gÛ\eÐ#äù?ÑMmݺ•»&¦ôE:3ðˆiÓd:†ad'Ò˜VZ^b:<|:thË–-(2Ì…ªüãZ0 ´&ªƒ@²“YÒ…Véú„´ (=ôPàgüwç.ÚÓÓ#ó7â„æð^UU¡ÿèPÁo•®-,´/¢ì©¸ánc~~ÞÖZȼ¡bdd$›Í"Õ vߺ$¤Óiâò0(tÌ›ûÅî}íˆ"tTn¿{pp¯=ë+DP,,,ÌÍÍmmm•Äš"é0 HZ”ÊšÌÄÁôááaÎŒWB<$ÛÛÛ“““z^Lq:ÜmpqL&“Á>Ù+*“¥¥¥ÁÁÁƒƒÝsB\EåFÒ1ï]^.‘'''ýýý•¹¢ƒŠ……›ßT·¢…¨h‘Žy:ýñãG›2:JK5ˆÐ²½½ÝÔÔ´²²‚BkíðHòèÑ£T*õ÷¿ÿ=hGDÐc&‚BÛSöÄGÐ<¿zõŠÄ‡Jõ`y:vˀ泵µ’'Ø…Å!‘þ \F_¿~óÞü¡/,µw‡þßÒÒ’MG:==m3•«æk³UU‚n½âNH¤/ÁæÊž™™±5:::wvv‚öK”ö¬Ãðððý½ }U0­0Zˆ ‘¾\j3™L‹OˆÊ¤©©é!ŸÙΦF  $ÒB”=ùÁôÞÞžžJ"H¤EñØ‚WnÙ+ þ`º§§§„S¨ŠÛrzzº¹¹Y[[ûìÙ³ }eDZOUUUÌ[v)hGÄ_‚飣#=ó šT”JOZˆh@ôlÂìBˆ ‘""Ø[^ö)„ˆi!"14Ÿ £…ˆi!„"¤H¤…Bˆ¢§»…ˆUUúG )I !„!E"-„B„‰´BR$ÒB!DH‘H !„!E"-ЧÊ#h/„ÇÇÇšúM”‰´BR$ÒB!DH‘H !„!E"-„B„‰´BRþ´¢ŒyûömÐ.:=z”J¥jkkƒvDDMÇ/DtÐBD w !„!E"-„B„‰´BRtKˆ?Y]]µôùùùþþ~ÐU ÕÕÕ–ìë뫯¯Ú)!BžîÅ311á>ËÄxrr2NÇãñ‘‘‘íím§âáá똛›kkk#=<<<44TŽ_Çéééææfmmí³gÏ‚öE”=îÅóÎ#h/Š= {‘H$H£Íëëë===å( Q‚óOWiooocc#›ÍÒs*Ç.à÷ïß3™Ìׯ_ƒvDD‰´¨D–––€ÃÃã£#d@Ú6êëëù^vwwéH­¬¬í‘Á ánQqô÷÷¯®®îìì466í‹(R½¼¼|||ÜÖÖ¶½½]ŽQµwD"-*‹¦¦&bhB4EÏåRMª½½ý·ß~ûøñcÐîñ h¸[TÄÐÄd[[[Rèò‚ï‹oíððPÁ´¨4I‹Jaaaacccooïªçççï0³¾¾ÞÒÒÒÔÔÔ××´/B<zOZT+++£££;;;ù2¼¿¿ßÑÑÁ'»ººº&''u¯:´'“I=O *‰´ˆ>„Èñxœ8¬µµ5/WüÞÞÞ˜'€TŸí²¸’t:=<<|tt´#B<º'-¢Á1±ò¥ ---;öPŠ~i1 Týœð(PõÆÆFMMÛ¤7`ofOŸ>uÂö»„}loo§ßìÙ³†냟žž‚i¤:hG„x$Ò"â ºSSSóóó…‹e2™Ÿþ™ÄÀÀÀ¥ššš¾yFÎIÜäåݶ¶¶ºº:S|èï↑;%D”H‹ˆ377×ÕÕuí\ÐuvvöÒÕÕÕ-1o®iî¶(êH¸iiSâ™™w r‹›'¸A h›Ä÷H89”§^òÇÇÇÝQäÛCR~7vŒyã- ª¶P{ii©»»Û…õä³×fU³ÔnêHß‚Â|R/9fÇŽr…Øá@ÿ&eL͸9€ŠY?ƒ„u_È7?]±˜§Ð6A>9öÂúmå¶µµ#Ö×"â\iš››××ׯ-¶¶¶†–Ç<1>;;+P’2„Ñ–~ûö-j:22Â'µq8™©TjyyÙÊØÝS>)3==M|Ì&UPÒCì9Äò)f>S˜Ï††: ®j³ŒŸ¨”%èpx6›e“C(@1›\“½|öxXu$lïüü¼UJÖ  vÆ‚«ËÜæª° {‡<è[˜Û¸Aô60eöqxqqÑΡUm>SÌÎ ¬‘à„c'±æÎçÍÁ[kŽÑF"-Š'üý<{솅]ÌZX3rDÚtí!#E&±¦dië˜ü[4zØKáè¨% ù$Ì v‘¦-8ƒÜÚô^®.ÚB& á7?›=¬3ášsñ£³âŽ59·bîaÌš³Ž–‹ûfi×}ýnúýû÷A;"¢€Þ“QfeeÅ–T*€ÝæªúåË~gg'ún]õÄ™Ÿºº:>ÑN“ºØ_@û÷¿ÿÝÞÞîðµ@–4úý¯ý+æ ÷ööÚu½G~sLM‰Vñ ›9ƒá1o$œ”Ç+j!gfffxx±dWMMͧOŸœr' ë:8;åÊÝhQ2f­Þ““ç¤ß[ ÒsÕeæÏò†KKK---ìºíÚ”˜Âû!DTÑ=ie¸ˆ¿xñ¢p¤(N?~üØžá°ë~&“Ù÷¸yuÈíññ1úÔÝÝÝßßïòé( *ccc¶iQ&ÕÙ lTÓîvs¸{ÊìR3O&¥Káî £ÁV5!xÝöÄ8a´EÛ‘ öÃÃCª¶»ÂôQ(OŒk^ùÛb»'M*íõÀ,L´‹ÞÆóçÏóÏCÌ{¼Ë6q•b xB31EÛ9*»{ùE@-zÆ[DEÒ"ÊêYX"WDŽ`š’PZ>úqtt”F»×¨Ð- Ìf³˜¢@ÎlDΔEºTDIvÅÈßÝÝEÃlT9’£Úű”±›ÓÉd#8LxÝÔÔDšc½ ÁSØä)¼¾¾Ž“˜¢BadÛÿØš¿-«««ô¯­­a™ª­!´§F¼¥÷ൠ1nõ°MüDѱoç–Âôm:$¬QÄ—{í7+DÐd&¢xìõÙ0ÿ„P)d/#¢6Ù–=_ÖÞÞŽ:Þvˆø*ˆŒ_¾|Yªi±s¦Žq/‚—ü„¤=l`?TðMÙ½›â.(’¢<°‡Ã‘%bY4¯T M M0Fß<$¸wa´?Â.-èw-¢,H‹â±QPñ`äÜ6. öøU öyÜ«Ï!çÑ£GtSjkkƒvDD‰´(­(D>ȳ{XAˆ;¢§»…¸67™ÛÌŸ¥ë&Øl\1ï®y óÏVò–ú/¢¢âN”ŽDZˆÛa¯!¹ÍwïÞùWd½TØö`3‡p ›»»»¥r ˳³³;;;þµ:îhðÒ¶àüU“§æsrrbþäœ(!ÄMH q 666N<®ZÍbrr²ðP'{)ã6Kõü—ƒÐ|mm-æÍæýÀÏU]Zc]]ù#„(‰´·àÍ›7CCC]]]¯_¿v™ÝÝÝÉd’ø8潋lãºDÛ555UUUÃÃÃ$‰„­gÅ^ÿ»×\¶··c!gè{jjŠÃ›ššæææ8Š!)%mŽl’s~~N]T} Í‘Éx<Ž^ö÷÷?~üØo“’ã@2 ‘Í+{Mû”Ç –ÍygÐQ³¶‰clâ¤-ÚájÄO«Sæ¿Q®»¯…%D% ‘ÅsíjÊÉ!€&F§···ÝÖÙÙY6Ý2S1o °††›ía[__'½ººzéMY‹Ë———sÖÓäÜÚü!?ýôSÌ{WêÓ§Oÿú׿¨®ººÚ^˜¦^6¿|ù‚}ÿÃöö|õ·oßü¡­­»•Íf±f«h»»Ë¶ M£ É1óÞ­B‰qտߦ€Àã6Öh£¿Æ—/_Ú”¢”Ïi,…ñÁ úû¼/NOOiàææfÐŽˆ( ‘ÅóÎ#h/[¦FœüSUØ”Ý(å+\¢²H‘M(f…/½)K¤îùóç .©C‰éði‘7vlnÎU›ô·ß~C;QÖ›LÚEÉ®®.3ˆ¦"ðþ¹Kɱ1~©Aòý‹~Ú’XÈŸ2l؃ ‚#œdÞ–Ùúû¼/¾ÿŽHýú5hGDH q# :?~üh(A-šçVÑ@vwwmÎj°™´<”Œë5lQò¥ '[üMIDš¨Ú2‰„M¯mŸþòƒƒƒÉd]·N›(_¾eÔ—ü‹.#4’¶ê3½ ZóBù˜o–Í«  Øtß¶ÙÒÒ‚6OOOã íy3‰Ú¨î!ó&ç9vèÇPÀNfÐ_©e€DZˆn!cnM-‚QB[‚Èæææîînôýv7›‰˜‘+¢I»—Œ\µ··#áþÈÕa‹j`©sJi Tc-œ™™ñ—·5¤;;;9Š Þä]ÌÕ@;‘aä“'OðO,¾·µªr¼²0:ß mã»'M£££4ßÜfƒhÒÓÓÓV ž£åÖÀ[ÔÔ•Ïf³Î, Ž¥›vΜç8œ¿iŸïϵ„V¤9ᜫ÷ïß툈zKˆ›’óJÁ1ŠØÛÛ‹8]ZIK&“5556‘gË6­¦}...R‘¸›M±³³óùóçÿþ÷¿Ù4i´÷°Ý®OŸ>Yº½½ý?ÿù3xrrbÓh_ûJzlï¶dˆ«…†`êÝ»wöþ·A>­£b›¶FHSS§År¬É˜ò;l>û7ƒþV…5i!nŠ-#ít%Û íUK#£Fvƒ™˜ÛŸ?88ˆ’íîîæ”G‘ÃW¯^ýãÿ˜››³‘a ®ýå—_P»ÃÃCt³ÿüç?‘Àt:MÄæv¹bÎ UÛœÛKKK9KaæCÿ ¿¿¿¥¥Åât T¾|ùâ_ ÛÿXYY‰yKsvttP5á#Õù§êÌqøÂßöo"ÿttÜâZBˆ¿t(/ʘðÿ„J;Ü}áKÛ`¦!³iöÝ5»÷l [Ú%Ò~;„¤Hìk屿nZ“Ùœz÷öö(l•"Þ®Þœ].mNæpùþ†ÛDìQk«Å†¬IÛ ÖþòV;Ök©­§ikQç”t_ºi7 nõ]h¸[TZ`CØ(L{{;111(.±©ñ–#ötú¥‹aûûûœd §ÕHûDÆZ`CTzKˆûÂî.ÏÌÌ,º;µåÈ—/_ •@/,,¤Ói?Úe!"‚îI‹â±—‹ÄU ]јÃÙ^©*ŒÝžðèÑ£T*U[[´#" H¤EñDCD™²»»ǃöâgD:h/DDÐp·ˆ2---ùQ›q¬Œ°IÐòâžQ¿´ÀMÈ™}ìáÙÙÙyñâE€ñH¤E”inn.áƒEïÞ½+ððÔ=ÑÛÛ{-äØœÛá4Ä^Ê/prrrísv G+ÒBTi!J±iwwwÉÍNNN¦R©ýúuCCÃU×ÕÕ]ûŒlš”`ùüù³›Ÿ\ˆ¨"‘Q†‹øÒÒR ¢”Édrtt4æ½wD˜[SSóôéSD”ø’𴪪*ÛÝú^˜7¼ÜÞÞÎ^>)`™³I¢¿¿ãþ»ºº¶··q70À&U755Ùáxþü9‡“°™¼p2‘HØ„$Žããc¬L[Â2ivp†ÈûØñ»gòi“œ°‹axñiooí…÷LÐ/j‹2¦ˆ (žêêj›Çãîð±YA°¹¾¾N ¯¯ïÛ·o¦|º‰¸m¡‹l6k16H}}ýâ⢽L|áMèíß4ã6˘ßa›Åwp,*Å.›å›½CCCfÖæÐ&a³jøÄçÆÆFŽ":·‰¸m ê³]Îg2))¢yÒ###¶&GÌ›ÜÍ@ö*vPµæ÷ß_[[ûúõkÐŽˆ( §»EñX”òg¼‰D K5.j“Z#f«««6Í5Áe]]Ý—/_\›éš€Ø&Ñ$Á&¡ª-iËKؼ›nÓ&µi®cžH_ûª1ýƒ´‡{Ìáß>þlëSù±Y„ÿž4’Lpì6é@ Ûöª1%ÑZ<±]H/Níå“ Í>ñȹÇÏ!~›¾ÙÝ÷®Wˆ‡Gsw‹â ÿÜÝ×tôéáßž*_fffÐï÷ïßÓ'àÔ¹õ¸Â:ëëëþ%¹B…æî%D‘´ˆ>6.TíHÙ@èOˆÜÛÛ;99iÃá—:::B«ÐB”=8&*‚åååVÿmWqö¼÷ÉÉIÞ‡ö³½½=55žçׄ¸o4Ü-*®ïíííörQоˆb°çõøÕÓ•ƒ†»E¥Àõ}~~ÞæúÚqkøÖÚÚڥТ¢H‹ ¢¯¯/•JI§Ëbèx<ÂäBÜ7iQYLOLL$ ·Â„9étºµµu}}]/F‹ D÷¤E%bÓnǼ™8¯ÛK…½;—J¥ì¦ Ý"$Ò¢rÙÞÞîïïoii±Y©ƒvGü‰M_jóÄ}øðAo[‰JF"-Ч\&3)ÌÆÆÆÌÌÌêêjGGj¶—Ž*Š“““7oÞìííõõõC—é3bšÌD”½'-*6˜§ÖHµeîîîg—ÝËZ¸ÝÜÜ´·†î‘ëéùm!üH¤…ø§Öå‹Ái!DÐÓÝB!DH‘H !„!E"-„B„Ý“ÅóöíÛ ]"t>ž˜˜˜ Úþ´BˆâÉxøsüë’uuuµ¶¶í£¢xôV¥(­‚8m‰DâÒ]ÕÕÕÙl–Ï }¬8´ –(!A zzz.Ý566&…¢Ü‘H QÞ\zïyÚ5!Ä]‘H QÞ\L+Œ"èž´({FÉÿ¤’„œ;ÓÈöÑÑQÐNU.§§§›››µµµÏž= ÚQöH¤…ˆ½½½étÚÒËËËWݨB”i!¢€ ¦F %tOZˆ(àîLk !¢„"i!"‚ÓúG %$ÒBD‡ª*ý£…ˆîÅ3á´B„‹ÓÓÓL&³¹¹´#" ¨ß-ŠGÓ‚† EÒa@Ó‚Š¢HZ!„)êw‹âQ$6 ’&L<::ÚÝÝÝÙٱϠ:þßÿûÿ÷ÿ÷·¿ýíþç‚ö%\ttt$“É/^ÔÔÔ466íNy ‘Å#‘÷$ÒçççÛÛÛétziiÉÞõŠÇã\jƒn®(?¬c÷ùó烃~HÃÃÃRëÂH¤EñH¤ÃÆ}ˆ4òÜÙÙ™J¥FFFZ[[5%¸(ûûû‹‹‹ ÓÓÓš#ï*$Ò¢x$Òa£´"}||<88Hb~~ž:èÆ‰hr~~>99Ilýþý{zA»:$ÒBD‡ŠôÊÊJÿÚÚš®›â@ªÛÛÛ›››‰­ƒö%\èén!D.£££GGGRhñ0TWWomm‘hjjB°ƒv'DH¤…zooO·ŸÅCÝ××Ç¥ÓŽ¿í€"D,--mll ÐA;"*”‰‰‰d2ÙÒÒ¢¡¡HZñ'Ѓƒƒˆô­Žšššâ’ʱA»/"ÂÀÀ@[[›=´(ôà˜Ñá.ŽŸŸÁ|úôéV÷¡···Ÿ>}JâÛ·oHuÐ'@D~üœ–——õT„†»Eñè¬(199™J¥nuM´'r Èxøs‰ŸÍÍÍÔUà¨ÝÝÝ¡¡!Û\YY9<ß¾}[À¬ÝŒäêl›ÕæŸì¢ézwfÙä“Â…í‡ Î[oÍÚÛÖÖvUa¾‚Kϼcdddmm™¡$Ÿ¥òܾGŒSÅ=œžž¤úžŒ— º'-Dt@¥Š»7L=00p«Ç¹‰ç¶··ÇÆÆ ”!üÝñ MGÂ…q9ï»t£ÇÒÒé:â阽Ù^ª>ñH§Ó9ÕáÒÂÂB¯\Õœ«©©©üüøý,lüÒò9{ ¶ï…Ærˆ¡/=¼ô.ƒ+`$–¶aŒ )à^Ny·‰qªˆy/\{ön ¼û0[fÝKeŒ~Ba£èÈu·ðô†Ø+­}}}ÛÅ®ˆ¤þD`Äh•žyØ”lºè™VX”LI¸6==Í!lr”5|8v¹`Ú†^É¡Œ?¶³hÞœDN¬#BÂÿŽ™º˜7ÊúéÓ'{g×N‹U‡M´ß¦]£çÅ\”tA,î§Òœv™«è›qrü˜”R‘ÿ¼Ù¨/mÇÔÅH;äÓwb©×,ûÛH—åâG¼k‘´ÙÄ1kHWW—¿.»q`ÎÛ˜› ôüå9onÅY¦‡çrJû“æ„þiE]aEñH¤ÃPÿð ABn{”“=GáqÔ‘65Å”€½H>bleÓ˘7îm7&×××Mm²8Þ4φ»­›â·Ç8’É®ÅÅEŽ5;?ÌÎÁ:> p#¢˜©¦)1{I¸ñvÓoŠù;¤)pp@ÉœvYïáÂë PÌš€5Ó]3;??O¥ÎLö°à/ìNˆeƒØëøCqÏ Œç‹´5ŸOÔ×ÿ˱s‚eœ§0Þf³YÊÐâ´`SÄ^6íkʱ|O—꺿áô²@Ž ¸°r%ÝØØàJzó£–––nûøOSS“%ÎÏÏm€=™LƼd»Ž>'c^ж³³sxxˆ‘ÞÞÞ˜7ˆÊÙv·‘‰) ãH´··£pì&ÓI#ñêÕ+‹ì‘íü‡ªZZZ¦¦¦°üäÉïïï?>>Î×]YYq>$ ì¿{÷Ž’tfff:;;q;ýúuÌSG‰å(ëIˆg€“C»VWWýí¢v p‘´t:ÝÑÑáb_k/Ñ0…ñнññq¾PÏ·ÐÙ…ævÝ›ÄòóÏ?“Cyׯ«N>…i'Ó?'i{6ÍîôǼa òÃØÞÞæ;¥}ÚÅæ‡ŠùugÞºVc躗 ÊëGí…ø ÞÝê‹ÃŠ«Î?Üm]Ì ysŠÅþIÛÏÆF؋爇;ÄÈÞ[\k±¬1¾ð"¿˜Ú^õ<êÂ.+ϵu4Ÿ Ñ34à›‡¹ æƒÉ!Æ]¢mk‹YcÓF¡KÉœv¹ˆÓ.¶›ô§.‘&¿øqCÁ °×MœÉQ6&omgÓ† ]QVׯüHšBI, ºÎsgÙ ü'Ó%,S›4‡MDÝo9?:/þû ˆDZˆHÁe«'â›bÏýW]Î=i‚jÏ¿¤R…»çÍŸ0ÔŸ@Ò ޵MÿQù›4Í=ílظ·³–ƒ=Öd£Óø@EÈ ¦È· ‡ÉŸŸŸ·çÏÍBel˜Û‰%Ay*bWÎ#è†ÝÍ¥˜5Öß.°{º.a½;###vÒH k7•Ø¡ VŒ´ä§.‹‰­˜"ÓµÑN‹«ÐQöb„þß>›î øO¦%;o6ÒΦ¹Ó.ÊäÜç. wù}FMf"DÔØßßG'¶··oøºpMM Ñ[$£ÜÙÙioo' ¼í9¹Ç¶ÛÆÁbM³¨:‘HÎFlVšCêVwp¢„DZˆ’Édº»»o¸ÐdiW¡&ÒçççMMMþûÇwáøø9$„ ɬ)Ù›HíN‰±ç Š˜Â%èÁ1!"H*•"´BŸ^¾|9>>^ÉëY!Z(tÉπݔ ºqBçã>Ú(€DZˆhbÏŽŽ]uttÌÎÎFr@û†§¢´Ý#Ðá!Ú ýå˗‘t<ñâEMMMxzN¥B"-Š§Â‡¡Ê‚éééÉÉÉ••{ÉêääÄ^"Jd³Ùt:ýË/¿ŒÛ‹|!è'×D£ŸP™b“]8Bõ%^õ(ïµ3~û9;;óOèqgb^ÜlÓäì-ÕëFعù¬é±¿Nîf›ùv{s̽+óbî¶¶¶ûxWêž°©ånXØ^ëêêºíDô¡Esw Qq466¶øÚ;qéêׇ‡‡×®Š}~~^`ÆÇÐÐz¶´´4;;›³Ë¦@¹{l™¯»X°Î®Ú$šöN³{ Ûr†‡‡­9[[[Ož<ùùçŸïîùðººÚÑÑqÃÂô¨æççÑéD"5Î%ÒBT:X¶Æ}€ŒÍÌÌŒŽŽrÅ$M‚MÓ¶‰‰ ¤tppÐÄ2N»´Ÿíím> 6m.vuwwc‡LÌ’o×僃ÿ‚fÁ/Û¶\1ÎÍÍÅ<™¤€sÌ}JÚ|jæ³ùIɺº:j1ãænغ#4ÓßË÷'ðÓÕÔÔ„©L&ƒ™};Š/…499Ë}æc-›ÓÛÒ |Ú Z·×5Ǧ¹§oü>¸í="i{Ÿ¾$½¨`‘H !î‘çÏŸÛt"h’½†"Ž“°©7Ñ9‚ÔÞÞ^¢U¤%çp„“].mC/ÙÄ¢k+eÅ<=#Í¥ÜP5øbÿéÓ§È’=%ÄÏ…Y ø†Í½½=Œç\Öq²ªªêììÌ"Q6I`“êHÛ#ôK&þ°I& Ä8½gÄòý üDPm .\%Ÿñ]1SxˆœœsòøñãªÜöë°æÐ5¡ôOã¦ØL«·=ªËƒo6h÷ïLÐãí¢ŒÑO(Üߪ½6ù¥»››Íf·¶¶R©”[’Áêõ˹'íÖ¡²{Ò###h›[KÃ-l«iÙ Ïdºå“í÷i+nå,óûqs—½na›ÛÒ•ÁÈÐÐÅæççmm˜oÒÓØÉPmQ,*u5æÜÏÏç$`Ð\2WÝ$»v –O›á+æ=åwûãÇþç ÜéòÏý™S¯¿9å5Ŧó¢·ÉSƒnÄP$-D¥ƒä‡k%Ä<£…¯^½úé§ŸÜ.÷(\ºÂ±gv›6;æÚÚZÎRÖñxüÿøG¾"c´q"x½t𓪬¤ bû÷Úø01»ìÎqN"éíííÂodùr6>}úDåüá}³?>>NIŠåÔè¤à¶ßE_+ çö.sñ½ç?LP^H¤EñXG/h/Ä]A®}̪8п.²ÈÉóçÏwwwÑ›_ýer#ÕF___GGÅrö!:vùÃÕÞÞÞîîîþþþ¦¦&l²×†²WVVø´1d FZÀÿ21]\ÂÂâââ‚inŽòÍÍÍ‘ƒ[;¿vÿ›}ùòåª'•ÐEŽ¥!Ôh9t)ì9€«î¶ZœÆ¸¥šKÓݹ´W6è>æ?©~s8çöØAt(/„ž»,„u-ˆ £ í’8;;ãóÂŒõ¿'ã^ ËyyÆåÛ¸%ŸÎÚ…7ʦ­‚¼ça‹@°˜Ý!ùïäé/3~ñ×wÕ,ÇSǧ­Ðe%]"§ºl6ë 8—ÌUsÛœº tžè£ ânɯü“æß´VûkÌqÃNŽ¥ïïë.-w¯¶T‚nGñDyÎ^!Ä I§Ó ¶^¡„øããã?ýôSww·[IºÒ(Éϲ··wdd¤|×çÐp·â±ßƒƒ.a`ccãäädaaaqq±2úüü¼¿¿ÿÇw´ÓÜܼººtkŠGÓ‚ !þ`~~~pp°¼^Ÿ06ÍYÐ^ÉäädGGÇM–q‹6Ф…ÐÕÕ•L& Ý‚vDˆ?Þž™™¡ãxwS(ýçÏŸƒnPñ(’Åcs)豆Ȱ¾¾n“lôõõ틨\ÎÏÏÛÚÚKò¶X]]]6› ºMÅ£HZñ'Èóêêêððp4&=åˆÍØ:==ÝÕÕ´/¡@"-„ø/kkkùï+ ñ ÐíííÉdRc9‰´â/´¶¶®¯¯ó©‡½ÅCb1ô“'Oè&íKˆH !rA¡÷ööFGG»»»o²ž£wyž˜˜H$ÓÓÓ%yX,JH¤…—`+Rôõõ!Ø XòO„ä9ǼVt:‰´([·'h/Ä=b“œ@2™looO§ÓRkQlv~W»»»üÀjÿÌê¡iA…7bvvvii©¼–Q!ääädtt´¯¯ï~K;;;ôl9“rD"-„(’íímE?âæ±¶æÝ)w‘Öd&Bˆ"Ñ”BÜ7º'-„B„‰´BR$Ò¢x&<‚öBˆpqzzšÉd677ƒvDD‰´(žwA{!D¸øþý;"ýõë× Q@"-„B„‰´BRô –BˆHq~~¾··géýý}6ýïI×ÔÔ466íãM‘H !„ˆOŸ>õOaûøñc—^^^.#‘Öp·BˆHQ]]=66vé®úúúžžž ¼šT!DÔ ŒŽÇãùëÁF——H+’B5. ¦Ë.ŒŽ)’BI£kjjü9eFÇI !„ˆ$Ó~I.Ç0:&‘BUfgg/M—i!„ÑÄEÏeFÇ$Òâ.Tyí…áâøøxbb¢Lã¶èñöíÛXÙ†Ñ1‰´BˆhÓØØX¦atL"-„"ÚTWWíBñH¤…Bˆ"‘B!BŠDZ!„)ZK=6)„ðóèÑ£T*U[[´#" hZP!„‘egg§··×¿žty¡án!„"¤H¤…Bˆ"‘B!BŠDZ!„)iQ<A{!D¸8==Íd2›››A;"¢€DZÏ; ½"\|ÿþ‘þúõkÐŽˆ( ‘B!BŠDZ!„)i!„"¤H¤…Bˆ"‘B!BŠØÅ£‰ß…ȧ¾¾^¯&ŠR!‘BˆŠ£|œ¸-ûûûçççÁ¶·¥¥¥ècµ –BD„jee%Ng³Ù“““ººº =ª8ì´£Ö###mmm7?P"-„Ñ„²¿¿?“É455õôôtuu566íTEC@Ÿö@­ÇÆÆZ[[¯=D"-„%$nÓ òr||<<|ø€RèC ½µµóž,ãgsi‰´BD„¹··w{{û&7;EH˜ŸŸç‹K&“ûûûù{õ –BD%l6«ºìèëë³g¿rnQ+’Bˆ²‡ lxxxccC ]¦tuuRç¿%‘Bˆòæüüœ‹ûâââ¥Ï OLLTùÐÃÞ¡…xšïqppП)‘BˆòfrrrhhˆP,hG"ÂÎÎýž@ª&˜^YYÙÞÞv9iQ>žšš/\Œ¿ê…ÇU‘4Êd¡v{{;:‘³Ѻô±¦Ò’ÉdŠ;pff&‘H¸Í––3oâ¼UMó9?ÞÛÛ+I‹°fs‚®®®Þ¤|uuõ§OŸ^½zår$Ò¢x&<‚öBˆpQ[[‹H?{öìaª^\\¼öV4Z~“ù«¿}ûÖ×××ÛÛ›JnllÜkC¨1¿spC&''iàU^ë<Çú«nnn®©©)mÓÒé´R”|)öd¾+&‘BˆrÅ„­§§çÚ’sssˆ„›W½köÙmT?ã1::ŠÀœœœP1+9f›ˆƒƒƒ9ÈQäÛ1Oo(ãTǦB³C0HG›$lvkŽÅ¬ÛE&A0åMD]y+0E±·oß¾~ýÚeÚQV©9û1+'¨ƒ~Ï›ššÜ±ô{©‚N\Ý §vò±o/ÄcŠÏcòÙk%Ý^;™ |ö÷÷¿yóæÚØfllì¿m¹BQž,//·µµ.³¶¶fw¦,Ú¾ª<1´‰ÙÙYr8Õ´!H_òis€íQ€ÄìÓ§OrttäLùœžž¦ŒÕ~vvÆf*•b“LJ’I1 bÖÀŽ}Ò4º ëëë|RžO PŒªù$tvÕ‘C;pkkËsGaÁœßÛÛ£:»CG­9‚e \xóo’6³°'¹\Pµùϧ9ÜêAÚŒÓ.<7gØr–©›vxᯌåÔY"-„å š$ܰðÀÀ@Ì˽t¯IÎ7´5EKœ¢›Îe³Yäá1 1Ù¶å)ÿ˜B·(€†™â:‡Ù4(`lf9–vYIK˜è"ç6Ûâ⢫+çæ1åýŽq9æ¼ëÐà G!„Ö`ï¥"ÝÑÑa%]]âÏ1‡É´ŠØe~R#gÃêò[ö;v-”äüÐp·B”++++Df…ËŒŽŽnllìììØˆq<·“ÉäððpNᦦ&©~ñâ…/úÄQ—Ž®£ßþMw !õàà rHiÏvÚ.ÛDq?~ühá¸ñþý{j?99!ÂnhhÀ_[[ëóÀ-r#ÆãããÈF8Ð?þ믿º4ÖÐÑššš±±1º4„’·À+úwõ~~~nQ²ÃÆ'°f½ üÄ>nçœÛòß‘ó‡îø‰achA{!D¸øý÷ß¹Rýúõ¾+²ÀîÚbþK?BbãÒU£%®˜Å… Ú °ÿnÁ¨][$ù#iÿ¥À -a‘4™H2²mÑ3{=ØŒy!¬“$!¿ðe¡š.Ⱦø1,lC܆ †[y« n€MöžyØH;ÅLãó#i+ûëH>m7Ëxèw˜2æ§5Çì»Í‹‘4'ÐòýCè—ò_—îûg$"ŒýíƒöBˆpÁõU ¼ïŠÜuüZ*¾¶±Ù OÞˆ;ýòCηXþ‘‡k” óÒÿ Í'åɱ.á û7Ùë¯Ëªv*µ¾¾nisÀ2­gòn™ò.í?$ÇOò)iíµLú%v?™¤ë@&ênŸÖ;ªÀ)ò7ÇJúkg3ß7p–-ßn»Z®ýrµT¥([K?!!üÛsIùƒÉ¥egg§··÷&/V èîîFöúúú~þùç'Ož„üõÑóóóšš®®Z`C!Ê’t:meˆ›°¼¼¼²²233366þUÂÜ‹ïi!„(Wìn®¸ vCú& =Ý-„B„‰´Bˆ[ã¦ËÁfÚº­5L=q·³Px2µ2E"-ŠÇžB Ú !ÂE}}=*ußOšjS‹äpttôîÝ»999yúô)Ÿ˜º£HÛÛAŸ•Ò#‘Bñ'þ`ÔÍ:bœ{仪ŒË±ÄÒÒ’{Ý^WW·¶¶Æg —Vgsq_µy…›àÏÉÙëw©@±ûå%ÒB!þÐ!‚ÚD"ÑÒÒ²±±A¢©©©½½=æ­wG:³‰ŽŽR&?\ž™™!#¶¹²²Bº¦¦fxxØV³xüø1H˜q›É ³N¼)fSžùÒ»»»Í«ýý}[O³¿¿ŸM« þÆ+Œìîîú¡€­¼‰¶,F¬ ÔKílâ]3B:™LRWÌ›£ÃÉ!ŸJ)l»h;ivåËÙUB$ÒB!þH›šÛfŸŸ?;;C­m%f>þõ¯!H° [ü‡£Rããã{{{n¡Äxdddkkkaa¡««Ë¦èBe3,“355•ãƒxóùÓO?¹Ì'Ož\\\ ‹‹‹–3==½¼¼ŒYWË…7ëYŽ5[uƒFÙbÛxhMxýúµ-‚3è½­—…¼â“M,ßÛV(úáá!›ìÂ1—Î)æßUÚïE"-„âpá´õ0ÚÚÚ' £mêM›h³££cuuµ¯¯/ÿpBRt›'''ˆâää$*H¾)½?þüË—/ùÓ°PÞf· ÆT*E ë·€'uuu6M>Þ^Õ(JÒ(|ö7©6)Å1ìÐ@ŒX\N]t°ÜÛÛK‚&p8í%§¤?MOÅãp·ë†ï7G"-„âÔnôÌÌ qa쯷ca``ÀŠåÜE¢vwwÉ75EÆ@”ÏV²²23–‘mŒ¼|ù2ß8"xL¡Ö.“òd^Z>æ­¼‰^Rï¥w²ÉÇ[š–sA<»oŽJ$¸:;;k Çg2ç=èO¤Óé¡¡!ëm¸tww7Nºb/^¼p»JþÀ &3Å£iA…ÈçÁ¦--—Ùlù©®®¶ÅµˆwmPš4Ñ­CáØ$‚$í2c^ÌŠ\Y¾<#>==Í'šÍ9A,1Ž’ÑžxP¸¦¦ÆnǼX–Mÿ¢XœFDé1ÈQfœ2– E>m2ý-B89í¤isssÎ[Áfgg'º­ž‰6Ópä?‘j‚M R¬¡¡áõë×GGGdr¬¥±`íÍ/æÆäK…æîÅ#‘"Ÿi{9äsPEKK º^Ö'‡ ì…Ö“B!B‹†»…BD••ÿë×å‹DZ!DÔð?j^Öh¸[!„)ФEñäÌf „€G¥R©ÚÚÚ )žªªªoß¾…d±êL&Ãù Ú‹ÀP$-ŠgÂ#h/„È3¢òìÙ³û®(.Ì;²±±qÛCljÏûÀœ9??·iCî©–ð#‘Bˆ²äÅ‹ù“vÍÒÒRww7Ýn›¥ä·ß~tó|¥Óiÿ¦ÑßßÿæÍ±e+gffl¢lg‡Nr¬É¹Mý5ŠÙ|œ¤Íš­qi:göööêêꪫ«cÞÜ஼Æ&9‘\¡’“S__“H !„899É £ÑÂÖÖV›qYEƒü³— 6ÝfÌ‘¦ Le±öåË{MüÝ»wÿüç?±c ]Ø2G}[ZZ°I1«:™LþòË/»»»ÓÓÓ6/wÌc[Ƀ ©)'¤mALÒØ,0-hùrvvf"ýç’ÀB!Ê»š—ÄÔ·oßš››Y6-šÚ„Þì%¢µ|ƒœ·oß’à“2–™Íf9dhh(öc¦#gŠ„=Ȳ¸¸Hž///§R)2mæ/g™sÆ–ë°ùÃfr¶¶¶Ì”Ùw‰ˆAO¥§§çB“™!Dùb+aÜkd]]Ýàà ‚Š@ú—¾ðógØçÍŠWn¾îÆÇÇ?~üˆ5Âb[5òÿø‡í*°4… w[ ¹?N§m‰´(=8&D>§§§™Lfssóêâ:>33SS‰Dbwwwtt4I2ù§÷öö>}ú”@Ùåwtt,--¡µþç×666u»sl«5ûAãmŠì†††ƒƒj·áô––èêêÚßß÷;ChŽöãFww·ù ¾ÙJ—€Ž§±µµ5¦¹»Å]ÐÜÝBäó lPW2™D8-Ö¼»5B[´áèè½Ä¦-ÿLÉÜÛÛc—‹˜ ʳéEWÜü!Ó©T ÉDÅ—@~H`‡C¬:v™ ‘@¶m/ÎP£µÎ^óûÀ±vWÛ%¢ô¦]ú^ëëë1‰´¸ i!òyàU°ˆ,Ÿy¤_u“B‘´BD¤º»»{``@óœ„äyxxØV+<æ¡HZ!"HkkëÁÁAKKK»ÇÌÌŒîUÎÎÎÎèèhSSS[[[GGôµw%I‹âÑ´ BäóÀÓ‚Þ„óóó••t:›Í&‰ºººœ÷|Ä}srrÂi§ÏÔÓÓÓÕÕuó'ðõž´BD$¡ÇÃ6mQŠ z è3¥Ói[ß:èÝååu‰´BTh¶­+U ìììd2™ÙÙÙ )Ý“B!BŠDZ!„)i!„"¤èž´(ž·oßí‚¡ãÑ£G©Tª¶¶6hGDÐ+XB!"ËÎÎŽM‹´#E¢án!„"¤H¤…Bˆ"‘B!BŠDZ!„)iQ<A{!D¸8==Íd2›››A;"¢€DZÏ; ½"\|ÿþ‘þúõkÐŽˆ( ‘B!BŠDZ!„)i!„"¤H¤…Bˆ"‘B!BŠØÅ£‰ß…ȧ¾¾^¯&ŠR¡HZ!„)i!„"¤H¤…Bˆ"‘B!BŠDZ!„)iQ>ž˜˜˜ Ú$ÒB!DH‘H !„!E“™!„ˆÇÇÇîvñ‡z™¦¦¦¾¾¾ }¼)i!„‘¢¾¾~nnmv9þ•ï·¶¶‚vðh¸[!DÔ¸êÁ½V ½»ФEñ¼}û6h„=J¥RµµµA;RÑôôôOûƒiãÇA»v;ª´F‚Bˆè‘N§{{{ý9ÄÐå5Ö“H !„ˆ*‰DÂL£Ðå5ÖÓ=i!„QÅgºìîFФ…BDLÕ××íέQ$-„"²X0mÏ‘íK1(’Åcóøg BœžžnnnÖÖÖ>{ö,h_DlggçéÓ§e*ÒzëJö÷÷ÏÎÎ,ýùóçl6´G¡Ã??€ðC·Ý‰D¢L/ ¢h¾ÿžÉdøÞ%Ò!¡±±±|ÿ†é\Ž'''—––ššš^¼x´;¡FïI_E:v‰óóóááá¾¾¾ò½L!‚B"ý_¶··{{{ãñøØØ:]]]´G¢ì±{ü¢¾|ùòáÇr|¾Té?@ž_½zEbyyY×PQrÚ<Ž ©cÞ“,Šª…7AOwÿëtvv=—ã{@˜éRó3[ZZ Ú!DPÑ‘ôùùyooo]]ÝÁÁ·ÅÃÐØØ¸··×ÒÒ’ÉdæççƒvGj*ú¬îînzqq1hGDÅA±½½Á&¶Ú!¢ÌÎÎÁŸA;R$•;ÜÝßß___/…P]]½µµ…TkÜ[ˆ{åää$íEñTèp7WÆÝÝÝk—Cá:99I¢««K·«EÉ!ŒN&“ÍÍÍúu qO¬®®–õË´•(Òûûûƒƒƒ7™œ…~÷îAÏøøxÐ^‹ÂOkcc£¥¥…_£žŠBäS‰Ãݽ½½ccc×^mF­ÅÅÅ« £÷;…£ø$º•Å@srÖH§!dú ×´«nå×XxußUÜKÏ^cccWW— Ø!JÎçÏŸ;::‚öâ\T[[[õõõ7)i3;¶¶¶(ÓÜÜœs>m®oß¾ÝÐb 9øŸsè ø ø›¶··G¦€A ˜Á«~iVãÇ Û¹¼*\EïXõÍÉ9{Ž£££˜·DÏø!DEÁ¿¬ÿ\I¿zõÊ¿ÂèU{ÙÌŽÛÛÛ‰DbeeåÒbDoUˆ’¬6’ç‰pÃî&¹Ì¡¡¡¡­­­€ &^[‘ÍõQZç÷=®-vmJX×Up¡aóœˆÀÕƒëÀM®3â¾áYWWWÖsU–HÛX´[ü îŠÉ·ËQ½½½·2ýå—_’ɤ 6RG‚ÍÁÁÁgfffZcž@rl{{;åÉ17Ø4Uèìì\XX`“2sssãããäļ¾…ONN¬.›ŠÜµ‚]æ’i°]SØÌQšÉÉI4lll̯SSS®iTŸ1oÚKŒc¶»»›fRÀò/]„ƒ)àj¤œ{m?iˆ'MÓ8'æ{cÞ¿ŽŠh§ ;´”õúí[™ŽŽËg“2n£Íéš@yΟî$˜«šC(?8cù®Fy« Ï­FKXûZ¯ý½]ÕB —ÄrïþV–Hse¿I`óD.æ­etttT]]Í…øÚ묟l6‹ô ázýÛo¿}úô‰«°_QÓææf{n‘›ŸŸñâÅ›7oLY©zyy™òüÂ8öÉ“'tÌãñ8ŸX¦ö¢mì 0bCar(ðúõkä.¤Õ…Æ|üø‘VXï~ww—J©Ñú õåËjA’ý­Às à!­ FËÄ&u±‹NÎÞÞžUG,ˆ?ÓÓÓÔ‚) vvFüóƒ€Ù9±<øvp¯¨‘ªé%ŒŒŒ ôV˜¯€†`ÿél½|ù’£À¾¾>êÍ©7¦=b^_ammÃù ðÊN)Ý/œ´&Ø9Á¸ ¶aq±Àã _ÊÏ?ÿlù®ßçÄêrÖ,A4žo'§–Îp*îŽ !òá/Ïÿ7h/îFÐãí ÏúúúMJÚÍf®ËÞ- Ò\‚Is]Î/œsC4ö㞴݃ôß·ößmllD8‡††¸ôcûöÎ…ï6ª™)2·¶¶è1P̺|r,ÅPÍT*eõ’ƒåØ_ïq’¦-äcäÂw‡Ø|¢‹½}›3ɆݛwwUM±(L%±l'Šp’]è{­ùy÷¤sj48¶ÑÃΆèü÷ÛŒyI>Å(qÙ=iÿ·`²’é?¥Ö+ŸsãÊÙÌIäç»Óâ¬Y'ÝlðWß“6F<îþ#§R®Jw·#І?€÷ïßq ê ÝüÙ %‘–aæÂG¢¦¦¦ªªêVO8wtt˜”Ú?Ðå£ÐX6¡Š-ŽùŸÿüÇv¹Wï‘^{Ì+/A0Î#TÄ‚„›¤é$r ›ýýý„†v֩ц¨¯êQ¢sHfNæÔÔ”û}ãù¶‡ÛKÕîV.u%“ÉwïÞ!ÏÔÒÞÞ>66–”ߤFrˆ9]MMMþ°’P•o!Ǧ=oÏù¤±—Vaò¿)ìûO©× o\% ³ìî&˜“vŸÂ6í7÷Ãit_ka¸ ¬®®Þ¤äUØ}~¢K¼Ê©Í£Šü™†ÐõœSz[8tžø6þùgËÁaSGòíÑû¢s¾ÖÂfi{ѯŠqNpÀÎ^™¾þW±ØCàî(‰»Ã…‚莽ްt(ÿpÐEµ¡Ñ[‘Ífý›—wag}}ký·oßl‰ÌZWÌ_QN¥nTÖ%¬€}"o—¾6–cÿ.äøÃY¥ë@[HØ€­ßŸ»ÏOßÊfÆý=^eü*·ouÚ‹ø?^µtÛ['îÂï¿ÿ¾¶¶öõë×ÂÅ–——óoüwyDpU¤O_üîÿñPA3Žñ1©“{öÊ(zZ¨;\X‰5‰{øDÛª=üÅüåTêþØ.aì7l^:Ý©YÎq£8rüá/A•ÿm±[ãΟ;ÏOßÊfÆÞ}z¯? ú¶§ýV£sDçWßå‹ÿû¿ÿ{Õ®«¾;{Õ"hÇË•_~ù…Ï÷ïß—ü•Ω ‘\Çé4lll$‰ü'“‹fggÇ=€ö`pM±W¡ÆÇÇ5·¥âá‰Çã/^¼èïï·Çf£D-U¹¿¿ßÑÑ¡ç2Dh©ªºõÿÑnáçÇd•ó¿._.ýîš››ËwQEqTЃcô°ôª-\¬‹˜É^åw/z‰2Â}we=–¸o*H¤Ãíy“aÝS÷ÂfÅ*PoIª(ü`sþÓÈöΕ‹0lö4WÌæËÇMæ "™™¹ûðÈ4×ë¢/Ö\î·<$Õe‡¤Z¦²Dš`:ð÷Ln¥Ó»»»ggg÷áÌÞÞ^Ëþ÷£ŠÀ„*l‰KÉd2ùË€ÖÕÕÕÔÔ¸·È¦¦¦ðÄ)=ºk³¸ê›H$,í&3ìÍ–l6»°°p—†\êdÉùüùó{E(´IuônË•§§§üf677o~ˆ“j~ùA»/BFЗ?(ÓÓÓ6¯H A>}úä÷çéf•òïò§]þ–dº7©È·b9UÄ~LžÅ§¦ÄÏb¦,ÇU½¾¾n…Iç[¶M›)Ì_—¹d6ÝÏË~? 4ÙÑ××÷ñãG±Y½ÖÖÖüóy9kæ¶óSV€«•­¾e}¬Ù $9 Fù§HË™tÌB“K_ÃpgϵÅôïriÿ¹¥N¬ÿœS¬$kìð]Üp:¼k‰ÌË'eJÑ3Ž]”è%I%*K¤mD±´Ñ’f6S©—Z[ÔÈ¿ËÞþrÅLK,R´ICI[>›ÄCmmmþZL¤ mÊLìSŒÏÙÙYrL¥ØD–Ü!X  •rÝ7õb“ÂfÙUM¿¾"«1o¼!öãÉ£|?M5sš ¸çìØ!öþ´¹j“qšª544I¸l YÚd™ÎäÜŒ˜óô«l¥9 ‡###þ“S@¤3ɱþ¾Ë…7ag½ vá†9cV·+'m_¢}¹†•y1¹z÷R ™"@î"ÒBäPY"}á]¸]¸vwL<ˆóèÿZš?çÐÐÓÿ.K_øfÌ6YµY²]¾ö×ÂæØØ˜Å…ˆMa5äÊ"ÎÅÅÅœK¼E{V&®i§è9³IÛtÜ?B±KýÌoטGNï'–7u6 ‡T–¯€ûô‹´…Ô΂é1fmÖtÒùrXX¤Á抡óáo#F¨ ÿmâsÆFYü»\Úœ´î‚ûáž›©Ûf2¿Ë‰3Sò1iQB*ëž4|øðáÕ«W¥²ÆUÉ_]]v·™É4fׯÆ»,ž³´ÿp{ÌÇ>Ý£I—>?òåË›ÃMUæ½xñ–èïïG&sÊÛ N4&ßšMDšŸo+fÆ|Óq˜W~?ým±&ÛL,4¹ðvÊììì8ÿ_¾|i“`;lR·9>>N-Ø´ùG¹ä¥Ói{Ãi lšR"x›ÐÔå#‡œ+{0ÍïŒu\Ü.—v3–s&Ýœ$¸êŸ3œü»¼6ÃIæÔòÃBˆ|*N¤MiJµvï”áòfc¡ö ñÒÒWmv~±‹4’ciwlWW×àà »l9ÈÂӀз@œz{{)yò”8æ As,ö¹Ð;5"Ó¦¼FòŸmÆÈèè¨MBâÏ'"ÄùnÅF,çøim¹´ÉþyµÈßßßÏÞŠ*LÏliÈMÆ‚­÷egÆÆ®Ý„áW1ñ[Žš*ë_AüùóçH/'“߀ßD׿˥ûí7;N eÒÈéżñý+]Þ¾,Š(âX!D´©8‘Žy‚wíú¾7Ä5.Ùv­ç“K-òùñãGÂíò§c?îïRš™™áÓn»E-ý«[ÚfMM ºˆRÞæcAm,×ä@ɨڅ}\÷m!UŒÛ=l21b‰ÅÅÅT*õùógvùŸ&EÒ8)2¹ÍñtíB’í9y×dlú}f/$“IÊ[Äl ¢§ øOùαÞ¾}ë_)÷r†"œq׺ôÐK« ~i§R|ò°E»Í¾Jÿ.KÓpÒæ$Í´uºÈç“NƒåǼµ1lå®"&\£Ź}€§Ç…åHÍ8æ‡0+“ÉäèJ9b+Üe³Yäá´uƒvJÜ[ÝRS‘!®¢BE:æM²AœdO—/OŸ>µ²‚vDƒM5¬„WQ¹"mA ×Ǿ¾¾ }• mwF‚vD^*W¤cžN···?yòÄnî ñ0ðÃëíí­¯¯×OQ˜J|pÌQ]]½µµÕÐÐðôéÓ»Oï,ÄMØßß·‡ï¤ÐBˆk©h‘6&&&¸bÚë:°Ž‚¨Xè@·µµ-..ê&‹â&H¤ÿ`llìèèèðð0ŽŽj=WQZ666çd2ÙÑÑÁ/-•J푸GèÑã×ì4¢$Tô=é|øwe2™t:mso½xñ‚ÏK_á¢0Ÿ?Îf³ü–øQ7Û¤E¼H-ʾqº¾¾>çµ~!Š@"}%ûûûggg\jü3… ‡- ©NLñxÜuÞ\¯4$Ò¢„ü-h‹-uÇ%~£MUUUÌ›t,hG„"šèž´BR$ÒB!DHÑp·(ž·oßí‚¡ãÑ£G©Tª¶¶6hGDЃcB!DHÑp·BR$ÒB!DH‘H !„!E"-„B„‰´(ž  ½"\œžžf2™ÍÍÍ Q@Ow‹â±Çô¦%D‘´BR$ÒB!DH‘H !„!E"-„B„‰´BRôt·BRI !„!E"-„B„‰´BR$ÒB!DH‘H !„!E"-ЧÊ#h/„ÇÇdz³³A;"¢€DZ!„)i!„"¤H¤…Bˆ"‘B!BÊÿ–-ñ&s~òIEND®B`‚gateway-1.4.5/doc/wtls/wtls.xml0000644000175000017500000015342013312154361015141 0ustar toljtolj ]> Guide to Mobile Internet Security 1 Introduction Welcome to the Alligata Server Guide to Mobile Internet Security. This guide is part of the Alligata Server Secure package. It supplements the Alligata Server User Manual, and explains how you can use Alligata Server Secure's encryption features to set up secure Wireless Application Protocol (WAP) services such as credit card transactions and exchange of private information across the Mobile Internet or a mobile intranet. This guide covers the following subjects: How security is implemented on the Internet using cryptography, message hashing, digital certificates and digital signatures. How the Wireless Transport Layer Security (WTLS) component of the WAP stack extends security to the Mobile Internet. How to obtain the data items items you need to set up secure Mobile Internet services: asymmetric key pairs and digital certificates. How to configure Alligata Server Secure to offer secure WAP services. 2 Internet Security Overview For an understanding of security on the Mobile Internet, some knowledge is required of how security works on the terrestrial Internet. This section explains the ways in which confidential information sent across the Internet can be protected against interception, alteration and forgery by third parties.
2.1 Aspects of Internet Security To be considered entirely secure, any method of communication must offer the following features: Privacy. A message must not be readable by third parties between its source and its destination. Integrity protection. A message must reach its destination in the same form as it left its source, or else the fact that it has been altered in transit must be obvious to its recipient. Authentication. Means must exist for the recipient of a message to verify that its sender is trustworthy and genuine (that is, not impersonating a third party). Non-repudiation. The sender of a message must not be able to deny, at a later time, having sent it. All these features are available on the Internet through the use of encryption, hashing, digital certificates, digital signatures and password protection. These techniques are discussed in detail later in this section. Firstly, it is important to know why they are necessary to begin with.
2.2 Insecurity of the Internet The Internet is not an inherently secure medium. A message sent across the Internet from one computer to another typically travels via several intermediate computers, called routers. Anyone with access to a router can inspect or modify data packets as they pass through it. Furthermore, before and after its journey across the Internet, data will often pass through a local area network (LAN). The architecture of most LANs is such that data packets from and to one computer on the network can freely be read by any other computer on it. All this means that a message transmitted across the Internet can potentially be seen, and even altered, by hundreds of people (some known to the sender, others unknown) on its way to its destination.
2.3 Secure Sockets Layer (SSL) A solution to the problem of secure Internet communication was first developed by the software company Netscape in 1994. Netscape added a protocol layer, the Secure Sockets Layer (SSL), on top of the Internet's TCP/IP protocol suite in its Navigator Web browser. SSL employs a collection of mathematical and computational techniques to allow data to be sent securely across the Internet in ways that meet all the criteria of privacy, integrity protection, authentication and non-repudiation. By 1998, SSL was firmly integrated into the infrastructure of the Internet as a whole, and was the main catalyst behind the e-commerce boom of the late 1990s. As Figure 1 shows, it can be used in conjunction with any of the higher-level Internet protocols, such as HTTP, File Transfer Protocol (FTP) and Internet Message Access Protocol (IMAP). Figure 1: SSL's position among the Internet's protocols SSL uses the following methods to provide security across the Internet: Cryptography. This is the science of scrambling messages so that they cannot easily be understood by anyone other than their sender and their intended recipient. It enables privacy in Internet communications. Message hashing. A message is run through a computational algorithm to produce a message 'fingerprint', which can be used to verify that the message has not been altered in transit. Digital certificates. A digital certificate is a short electronic document that vouches for the authenticity of its holder. It is issued by an organisation called a certificate authority (CA) and is formatted in such a way that it is practically impossible to counterfeit. Digital signatures. A digital signature is a way of formatting a message so that it is traceable to one source, and one source only. Digital signatures enable non-repudiation in Internet transactions. The methods used by SSL are generic mathematical and procedural ones, which can be applied to any secure means of communication. As we shall see in Section 3, they have already been adopted by the Mobile Internet's Wireless Transport Layer Security (WTLS) protocol (see Section 3), and they are likely to form the basis of any future developments in Internet security. Sections 2.4 to 2.8 examine the elements of Internet security as they are implemented in SSL.
2.4 Privacy The fundamental requirement of any method of secure communication is privacy. In inherently transparent media such as the Internet, this means finding ways of ensuring that even if a third party can see a message, they cannot understand it. The best way to achieve this is to scramble the message in a way that is systematic whilst being all but impossible to deduce from the scrambled message alone.
2.4.1 Symmetric Key Cryptography SSL uses techniques of cryptography to scramble and unscramble data. Cryptography is the art of rendering information opaque by passing it through mathematical scrambling algorithms. The scrambling of information using cryptography is called encryption; its unscrambling is called decryption. In encryption, message data is passed through a mathematical algorithm involving a particular numeric value. This numeric value is called the key. In basic cryptography, a message can only easily be decrypted by someone with access to the key with which it was encrypted. Other important cryptographic terms are: Plaintext: unencrypted data. Despite its name, the term usually refers to any kind of unencrypted data, whether textual, graphical, audio or binary. Ciphertext: data that has been encrypted. Cryptanalysis: the study of methods to 'break' ciphertext (that is, deduce its original plaintext form) without direct access to its encryption key, encryption algorithm, or both. An example of a very simple cryptographic algorithm is to add a value x (the key) to the code of each character in a message. To decrypt an encrypted message, its recipient must know both its encryption algorithm and the algorithm's key. They can then use the key to perform the inverse of the encryption operation on each character of the message. For example, if a message were encrypted by adding 6 to the code of each character in it, it would be decrypted by subtracting 6 from each code. Because the decryption operation is the exact inverse of the encryption operation, this type of cryptography is called symmetric key cryptography. The algorithms that are actually used in symmetric key cryptography on the Internet are much more complex than this example, in order to be able to withstand attempts to crack them by trial-and-error (known as 'brute force attacks'). Most symmetric agorithms encrypt messages not a character at a time, but a block of bits at a time (typically 64) ( a method called block cipher encryption). In block cipher encryption, a complicated series of transformations is applied to each block in turn, using a very long key (ideally at least 112 bits). In addition, a technique called cipher block chaining is often applied, whereby the result of the encryption of each block is used as a filter for the encryption of the next block (see Figure 2). Cipher block chaining hides any repeated patterns of data that occur in the plaintext message. (Such patterns are always a useful 'handle' for malicious cryptanalysts.) Figure 2: Cipher block chaining
2.4.2 Public Key Cryptography Advanced symmetric key cryptography offers very effective security for most purposes. (According to one estimate, there is not enough energy available in the solar system to perform a computational brute force attack against a 256-bit key.) However, symmetric key cryptography has an important limitation: before any encrypted communication can take place, the encryption key itself must be securely conveyed from the sender to the recipient. Symmetric key cryptography only allows this to be done by extraneous means. For example, the sender could send the key in an armoured van to the recipient (this is how banks install keys in their cash machines). Of course, this undermines the main advantage of the Internet over other forms of communication, namely its practicality. To circumvent this limitation of symmetric key cryptography, another type of cryptography, called public key cryptography ( also known as asymmetric key cryptography ) is employed for the exchange of symmetric keys. Public key cryptography exploits the existence of a type of mathematical operation called a one-way function. A one-way function is one that is much easier to perform in one direction than in the other. A simple example of a one-way function is the multiplication of prime numbers: for instance, it is much easier to multiply 4253 by 5521 than it is to find the two prime factors of 23480813. (The multiplication of prime numbers plays a significant role in many cryptographic algorithms.) Public key cryptography uses advanced one-way functions, consisting of a mathematical algorithm and a numerical key, to encrypt data. Unlike in symmetric key cryptography, however, the key used to encrypt a message cannot be used to decrypt it. Decrypting the message requires a different key that is mathematically related to the encryption key, but for all practical purposes impossible to derive from it. Even knowing the encryption algorithm is no help in calculating the encryption key, for which reason the best-known encryption algorithms are kept in the public domain. (The thinking is that submitting encryption algorithms to the scrutiny of the world's cryptanalysts is the best way of testing their robustness. For example, the RSA algorithm used by Alligata Secure has so far yielded no significant weaknesses.) Note that deriving a decryption key from an encryption key is always hypothetically possible; in fact, mathematically it is many times quicker to work out a private asymmetric key than it is to work out a symmetric key of the same length. Still, calculating a private assymetric key of 1792 bits should ( for the next few years, at least ) be all but computationally infeasible even using hundreds of thousands of computers working in parallel. Certainly, for almost every organisation in the world, it will be financially infeasible.
2.4.3 Cryptography in Practice Let us suppose Brian wants to set up a secure Internet connection. He first uses an appropriate software tool to create an asymmetric key pair, consisting of one public and one private key. Others can then use his public key to encrypt messages to him, which he ( and no one else ) can read using his private key. In this way, anyone can send Brian a private message without going through the risk or inconvenience of exchanging symmetric keys beforehand. Conversely, if Brian wants to send a message that others can be sure originated with him, he encrypts it using his private key, and others use his public key to read it. (This is the process of creating a digital signature, and is elaborated in Section 2.7.) In practice, the complex mathematical processes used by public key cryptography make it rather slow for use with long messages. SSL therefore restricts its use of public key cryptography to the exchange of a symmetric key (see Section 2.3.1) between the client and the server at the start of a secure Internet session. This symmetric key is agreed on-the-fly between the client and the server and it is called the session key. After the session is over, it is discarded by both the client and the server. The ways in which symmetric and asymmetric cryptography are combined in real Internet transactions are illustrated in Section 2.8.
2.5 Integrity Protection We have seen how cryptography can be used to send messages across the Internet that are unreadable by third parties. However, this does not prevent third parties from blindly altering messages between their source and their destination. Depending on the content of the message, such alterations may be apparent to the recipient of the message or not. (For example, indiscriminate interference with a text message is usually easier to spot than with a block of binary data.) Integrity protection is the term applied to techniques for verifying that a message reaches its intended recipient in exactly the same form as it leaves its sender. While integrity protection does not guarantee that a message will reach its desination unchanged, it does (virtually) guarantee that any change is obvious to the recipient.
2.5.1 Hash Functions Integrity protection uses computational algorithms called hash functions. A hash function is a one-way function (see Section 2.3.2) into which data ( such as an Internet message ) is fed, and whose result is a value of a fixed length in bits. Passing a message through a hash function produces a hash value that is effectively a 'fingerprint' of the message. This fingerprint is called the message digest. It is usually much shorter than the message itself. The sender of a message computes its digest, encrypts the digest using their private key and sends it appended to the message. The recipient verifies the integrity of the message by decrypting the digest using the sender's public key, then running the message through the same hashing algorithm that produced the digest. If the message has been interfered with on its journey, the hash value calculated by the recipient will not match the value of the digest. In fact, a matching hash value is not an absolute guarantee of integrity: a collision is theoretically possible, whereby the modified message happens to produce exactly the same hash value as the original message. However, collisions in good-quality hash functions are so rare that their calculation may be considered computationally intractable.
2.6 Authentication SSL allows privacy and integrity in Internet communications. However, without further measures, the anonymity of the Internet makes it easy for a user to impersonate another user. For example, a malicious party could create a Web site on which they masquerade as a respected organisation, set up a private connection for transactions, and begin obtaining money and credit card details from unsuspecting 'customers'. Figure 3: Creation of a message digest using a hash function
2.6.1 Digital Certificates This problem is addressed by the use of digital certificates. A digital certificate is a message sent by one party to another at the beginning of a secure Internet session, verifying the sender's identity and vouching for their integrity. The certificate is obtained from an organisation called a certificate authority (CA). The certificate is virtually impossible to forge, for reasons that are explained later. Once a secure session has been requested by an Internet client such as a Web browser, it typically continues with the server sending the client its digital certificate. The server's digital certificate contains the following information: The server's public key The certificate's serial number The certificate's validity period The server's domain name The domain name of the CA that issued the certificate The certificate is supplied with its hashed digest (see Section 2.5.1). The digest is encrypted using the private key of the CA that issued the certificate; this encrypted digest constitutes the CA's digital signature. If the digital signature can be decrypted using the CA's public key, then the certificate must have originated with the CA. (See Section 2.7 for more on digital signatures.) Upon receiving the server's certificate, the client validates it by checking the following criteria: That it is valid for the current date. That it applies to the server that sent it. That the CA that issued it is known and trusted. (To do this, the client checks the CA's own certificate, which is signed by the CA itself.) That the CA's digital signature can be decrypted using the CA's public key. (Most Web clients contain a list of the public keys of the best known CAs, so they do not need to search the Internet for them.) The client warns the user if the certificate fails any of these tests. The user may continue with the session at their own risk, if they wish. Digital certificates can be issued in chains. For example, a large CA might issue a certificate to a smaller CA, which issues a certificate to a still smaller CA, which issues end-entity certificates to Internet traders. This helps distribute the task of administering digital certificates. When an Internet client receives a certificate from a chain, it checks the certificate of every CA in the chain as described above, until it reaches the self-signed certificate of a top-level CA. Digital certificates are not only used by Internet servers: they can also be obtained for Internet clients. In practice, though, demand for client certificates has proved minimal. Authentication of a client by a server, where it is implemented at all, is usually through use of a user name and a password. While this method is not infallible, it nevertheless adds a layer of security to Internet transactions that is absent from many non-Internet confidential transactions ( for example, ordering goods by credit card over the telephone).
2.7 Non-repudiation The final requirement of secure communications is non-repudiation: a message's source must be provable upon demand. Non-repudiation is normally achieved using digital signatures.
2.7.1 Digital Signatures A digital signature is simply a way of encoding data so that its source and its integrity are verifiable. Digital signatures use the same techniques of cryptography and hashing that are used to provide privacy and integrity protection (see Sections 2.3 and 2.4). The difference is that the roles of public and private keys are reversed. Let us suppose that Abigail wants to stamp a message with her digital signature. First she passes the message through a hash function to create a message digest. She then uses her private key to encrypt the digest, and attaches the encrypted digest to the message. This encrypted digest constitutes her digital signature. (Of course, Abigail could encrypt the entire message using her private key; however, encrypting the digest is sufficient and much quicker.) If Brian is the recipient of Abigail's message and wants to verify that it originated with her, he uses Abigail's public key to decrypt her signature. He then runs the message through the same hash function that Abigail used to create the digest, and compares it with the value of Abigail's decrypted signature. The main users of digital signatures on the Internet at present are CAs, who stamp them on every certificate they issue (see Section 2.6). Although client-side digital signatures are an effective means of non-repudiation, demand for them has so far been minimal. This suggests that businesses and customers are happy to carry out transactions without them. Instead, client-side non-repudiation is normally implemented using password protection, which is regarded as an acceptable compromise between practicality and guaranteed security.
2.8 Example Secure Transaction Secure Internet transactions rely on quite complex combinations of public key cryptography, symmetric key cryptography, hash functions, digital certificates and digital signatures. The following example illustrates the sequence of steps involved in a typical SSL session. Note that by far the most complex part of a secure Internet session is the initial handshake, whereby the parties agree on a secure data format for the rest of the session and, if necessary, establish each other's credentials. This example demonstrates the most usual type of SSL handshake, with the client authenticating the server, but without the server authenticating the client. The transaction is summarised graphically in Figures 4, 5 and 6.
Part One: SSL Handshake Abigail, a Web surfer, sees an item she would like to buy on Brian's Web site. Abigail clicks a button on Brian's Web site that sends a request for a secure Internet session to Brian. The following items are appended to the request: - Various information about what versions of SSL Abigail's Web browser supports, what encryption algorithms it supports, and so on. - Some randomly generated data. This will be used, along with other data, to generate the session key (see step X). Brian receives Abigail's request for a secure session and sends her the following items: - His digital certificate, including his public key. The certificate is signed by a trusted CA using its private key. - Information about what versions of SSL Brian's Web server supports, what encryption algorithms it supports, and so on. - Some randomly generated data which will be used in the generation of the session key. Brian could also request Abigail's digital certificate. However, in practice it is very rare for a server to require a certificate from a client. Abigail validates Brian's certificate as outlined in Section 2.6.1. If the validation is successful, she is happy that Brian is who he says he is, and that he is a reputable trader. Abigail performs a series of operations on the random data she sent to Brian, and the random data Brian sent to her, to produce a piece of data called the premaster secret. Abigail encrypts the premaster secret using Brian's public key and sends it to Brian. (If Brian had requested her digital certificate, she would also send her certificate for Brian to validate.) Brian receives the premaster secret from Abigail. Brian decrypts the premaster secret. He and Abigail simultaneously perform a series of operations on it, to arrive at a piece of data called the master secret. Abigail and Brian simultaneously perform a series of operations on the master secret to arrive at the session key (see Section 2.4.3), which will be used to encrypt the information they want to send to each other. Abigail sends Brian two messages. The first confirms that all further messages from her will be encrypted using the session key. The second is an encrypted message that formally ends the handshake from her side. Brian sends Abigail two messages. The first confirms that all further messages from him will be encrypted using the session key. The second is an encrypted message that formally ends the handshake from his side. Figure 4: SSL handshake. Step numbers correspond to those in the textual account
Part Two: Transfer of Confidential Information Abigail fills in the relevant form on Brian's Web site, including her credit card details. She presses a button which sends the form to Brian, encrypted using the session key. Brian receives Abigail's credit card details and decrypts them using the session key. Figure 5: Transfer of confidential information using SSL. Step numbers correspond to those in the textual account
Part Three: Secure Session Closure Abigail and Brian both discard their session keys. Brian closes the secure session. Finally, Brian sends Abigail her item and her credit card company the bill. Figure 6: SSL session closure. Step numbers correspond to those in the textual account
3 Mobile Internet Security
3.1 Wireless Transport Layer Security (WTLS) Mobile Internet security uses the same methods of encryption, hashing, digital certificates and digital signatures that SSL provides for the terrestrial Internet. However, instead of SSL, the Mobile Internet is served by a streamlined protocol called Wireless Transport Layer Security (WTLS). WTLS is an optional component of the Mobile Internet's Wireless Application Protocol (WAP) stack. It resides between the Wireless Datagram Protocol (WDP) and the Wireless Transaction Protocol (WTP) layers of the WAP stack. The structure of the WAP stack is shown in Figure 7. Figure 7: The WAP stack Like any Mobile Internet transaction, a secure Mobile Internet transaction extends across both the mobile telephone network and the Internet, using WAP for the wireless part of the journey, the Hypertext Transfer Protocol (HTTP) suite for the Internet part, and a WAP gateway in the middle to translate between the two. Figure 8 shows an overview of Mobile Internet communication, from the mobile device at one end to the HTTP server at the other. If security is required across the whole communication channel, SSL can be used between the WAP gateway and the HTTP server. Alternatively, the content provider can host the gateway themselves. (As will be seen later, this arrangement provides optimum security.) Figure 8: WAP communication overview Like WAP as a whole, WTLS uses the Internet as a model for its procedures and is very similar, in outline, to SSL. However, it has a number of additional characteristics: Compact coding. WTLS employs more compact coding than SSL, in order to keep messages as short as possible and to minimise the time and processing power required by the client device to interpret and transmit them. These measures help to offset the speed limitations imposed by the high latency and low bandwidth of wireless networks. They also compensate for the low power and computational resources of mobile devices. Datagram support. WTLS operates directly above WAP's Wireless Datagram Protocol (WDP), and therefore needs to accommodate the unreliability and unpredictability of connectionless datagram communication. Rigorous confirmation and retransmission procedures are rendered doubly important by the intermittency and variable quality of radio transmission. Optimised handshakes. WTLS allows the WAP gateway, acting as a server to the mobile WAP client, to authenticate the client by obtaining the client's digital certificate from an external source, rather than the client itself. This reduces the processing and memory burden on the client. Dynamic key refreshing. Communication via radio signals is particularly vulnerable to 'tapping' by third parties. As an extra security measure against eavesdropping, WTLS allows for the symmetric session key to be changed regularly over the course of the session, without the need for a clean handshake. Fast encryption and hashing algorithms. WTLS uses the quickest, most efficient algorithms available for hashing and encryption (see Section 2), so that client processing time and power consumption are kept within reasonable limits. Client-gateway rather than client-server coverage. Unlike SSL, WTLS does not span the whole of the communication channel from the client to the content provider's HTTP server, but only communication over the mobile telephone network between the client and the WAP gateway. If security is also required between the gateway and the HTTP server, it must be implemented using SSL. The complete WTLS specification can be found on the WAP Forum's Web site at www.wapforum.org.
3.1.1 WTLS Implementation Classes The WTLS specification allows for three classes (levels) of WTLS implementation: Class 1: Anonymous encryption. Data is encrypted, but certificates are not exchanged between the client and the gateway. Class 2: Encryption with server authentication. Data is encrypted and the client requires a digital certificate from the server. Class 3: Encryption with client and server authentication. Data is encrypted and the client and the server exchange digital certificates.
3.1.2 WTLS Handshake The WTLS handshake is very similar to the SSL handshake. The following example illustrates the most common form of the WTLS handshake, that for WTLS class 2 (see Section 3.1.1). This involves the client authenticating the gateway, but not vice versa. It is illustrated in Figure 9. This example shows the full handshake. WTLS also uses an abbreviated handshake for resumption of a previously established session. This involves re-exchanging a session identification code agreed when the session was first established. Bollocks! Abigail, a WAP phone user user, sees an item she would like to buy on a WAP site. Abigail activates a link on her WAP phone that sends a request for a secure Internet session to the WAP gateway. The following information is appended to the request: - Various information about what versions of WTLS Abigail's WAP browser supports, what encryption algorithms it supports, and so on. - Some randomly generated data. This will be used, along with other data, to generate the session key (see steps 5 onward). The gateway receives Abigail's request for a secure session and sends her the following items: - Its digital certificate, including its public key. The certificate is signed by a trusted CA using its private key. - Information about what versions of WTLS, encryption algorithms and so on are supported by the WAP gateway. - Some randomly generated data which will be used in the generation of the session key. In WTLS class 3 (see Section 3.1.1) the gateway would also request Abigail's digital certificate at this point. Alternatively, it could obtain Abigail's certificate from an external source on the Internet - a procedure which characterises the optimised WTLS handshake. Abigail validates the gateway's certificate as outlined in Section 2.6.1. If the validation is successful, she is happy that the gateway's proprietor is genuine and trustworthy. Abigail performs a series of operations on the random data she sent to the gateway, and the random data the gateway sent to her, to produce the premaster secret. Abigail encrypts the premaster secret using the gateway's public key and sends it to the gateway. (In WTLS class 3, she would also send her digital certificate for the gateway to validate.) The gateway receives the premaster secret from Abigail. The gateway decrypts the premaster secret. The gateway and Abigail simultaneously perform a series of operations on it, to arrive at the master secret. Abigail and the gateway simultaneously perform a series of operations on the master secret to arrive at the session key (see Section 2.4.3), which will be used to encrypt the information they want to send to each other. Abigail sends the gateway two messages. The first confirms that all further messages from her will be encrypted using the session key. The second is an encrypted message that formally ends the handshake from her side. The gateway sends Abigail two messages. The first confirms that all further messages from it will be encrypted using the session key. The second is an encrypted message that formally ends the handshake from the gateway's side. Figure 9: WTLS handshake
3.1.3 Digital Certificate Formats WTLS specifies two possible formats for digital certificates: X.509. This is the standard format for digital certificates in SSL, and is optional in implementations of WTLS. However, it is not supported by the current generation of WAP client devices. The principal information contained in an X.509 certificate is: The subject's name The issuing CA's name The certificate's validity period The asymmetric and symmetric algorithms used for key exchange The subject's public key The digital signature of the issuing CA Alternative names for the subject (optional) Allowed key usage - for example, whether the subject's public key may be used for encryption, server authentication, signing other certificates, and so on (optional) WTLS. WTLS certificates are similar to X.509 certificates but more compactly coded, so as to suit the high latencies and low bandwidth of wireless networks, and the limited processing reources of WAP client devices. WTLS certificates also omit some of X.509's non-essential fields, such as alternative subject names and key usage options. A WTLS certificate includes the following information: The subject's name The issuing CA's name The certificate's validity period The asymmetric and symmetric algorithms used for key exchange The subject's public key The digital signature of the issuing CA
3.1.4 Certificate Revocation in WTLS On the terrestrial Internet, a CA can revoke a certificate it has issued before the end of the certificate's validity period, if the security of the owner's private key has been compromised or if there is new reason to doubt the owner's identity or integrity. Certificate revocation on the terrestrial Internet is implemented by means of certificate revocation lists issued by CAs. When an Internet client receives a certificate from a secure server, it retrieves the signing CA's certificate revocation list from the Internet, checks that the certificate does not appear it, and if not, accepts the certificate. On the Mobile Internet, it is impracticable for a small client device to check a revocation list every time it downloads a gateway's certificate. The problem of revocation is therefore addressed by the use of short-lived certificates. The CA, instead of issuing the secure WAP gateway with a single certificate valid for a long period, sends it a fresh certificate at short intervals throughout that period - for example every 25 hours. Each certificate is only valid until the next one arrives. If the CA needs to revoke its endorsement of a gateway (for example, because the security of the gateway's private key has been compromised), it simply stops sending the gateway certificates. Clients of the gateway will begin receiving expired certificates, and therefore will know that its security can no longer be relied on.
3.2 WTLS in Alligata Secure NOTE: THIS SECTION WILL NEED UPDATING.
3.2.1 Supported WTLS Implementation Classes Alligata Secure supports all three WTLS implementation classes.
3.2.2 Supported Digital Certificate Formats Alligata Secure supports both X.509 and WTLS certificates. Note, however, that X.509 certificates are not currently supported by WAP client devices.
3.2.3 Supported Encryption Algorithms Alligata Secure supports asymmetric keys generated by the RSA alogorithm and symmetric keys generated by the MC5 algorithm. [check]
3.3 End-to-End Mobile Internet Security As we have seen, WTLS provides security between the client device and the WAP gateway. Most secure Mobile Internet transactions will also require security between the WAP gateway and the HTTP server. This can be implemented using one of two arrangements: SSL can be used between the gateway and the HTTP server. This method presents a very slight security risk, because data is momentarily held unencrypted inside the gateway (a phenonmenon known as the 'WAP Gap'). It is therefore important that administrative access to the gateway is strictly limited, that the relationship between the gateway host and the content provider is strong and trusting, and that the decrypted data is never stored outside the gateway's memory. This set-up is not recommended for operations requiring guaranteed security, such as online banking. The gateway can be hosted by the content provider and placed behind the content provider's firewall. This set-up obviates both the 'WAP Gap' and the need for SSL between the gateway and the HTTP server. The content provider can, if they want, act as an Internet service provider (ISP) to the whole of the Mobile Internet, once the secure transaction is over. Alternatively, the content provider can close the secure WAP connection after the secure transaction has taken place, in which case the client user must dial in to their usual gateway in order to view other WAP sites. Figure 10 outlines a secure Mobile Internet transaction of the second type, with the WAP gateway behind the content provider's firewall. Abigail is now the user of a WAP client device, communicating with Brian via the WAP gateway. Figure 10: WTLS transaction, with the WAP gateway hosted by the content provider
4 Using Alligata Secure with OpenSSL NOTE: THIS SECTION IS INCOMPLETE AND IN PLACES INACCURATE. IT MAY, HOWEVER, BE USABLE AS THE BASIS FOR THE DOCUMENTATION FOR THE SECURE VERSION OF [KANNEL], WHEN THE LATTER IS RELEASED. Alligata Secure is supplied with the OpenSSL open source software toolkit. OpenSSL includes a library of general purpose security functions that you can use in conjunction with Alligata Secure to implement secure Mobile Internet services. OpenSSL enables you to: create symmetric or asymmetric keys create [digital certificates] encrypt messages calculate message digests Of OpenSSL's features, creation of symmetric keys, message encryption and digest calculation are incorporated into the Alligata Secure software. You can customise them by changing the configuration variables described in Section 4.X. Before you do anything else, however, you must create an asymmetric key pair.
4.1 Creating an Asymmetric Key Pair An asymmetric key pair is required for WTLS connections between a WAP gateway and client devices (see Section 3). Alligata Secure supports keys generated by the RSA algorithm. The following instructions show you how to create an RSA key pair using OpenSSL. Many additional options are also available: see the OpenSSL man pages (in particular openssl and genrsa) for details. To create an asymmetric key pair: Create three or four files containing random data. You can do this by using the command echo random_string > file_name for each file. For example: echo ;st509tjjm[4t#~{sa{)8EHjhjOSFOhoij > rand1.txt These files will be used, together with the random data file $HOME/.rnd, to generate the key pair. Type openssl genrsa -rand random_data_files -out output_file -storage_encryption_algorithm -passout password_source Notes: random_data_file: the file names should be separated by colons :. output_file: the name of the file to which the public and private keys will be output. Conventionally, the file name should have a .pem extension. -storage_encryption_algorithm: the symmetric algorithm used to encrypt the key file. Possible values are -des, -des3 and -idea. This parameter is nominally optional, but should always be used except for testing. password_source: the source of the password that will be used to decrypt the key file. This parameter is formatted as follows: pass:password password is the password. Avoid except for testing, as Linux utilities such as ps can see the password. env:environment_variable The denoted environment variable's value is the password. file:file_name The first line of the denoted file is the password. Ensure that the file's read permissions are limited to those who will need the password. fd:file_descriptor_number The password is read from the denoted file descriptor. stdin The password is read from the standard input. Example key generation command: openssl genrsa -rand rand1:rand2:rand3 -out abigailskeys.pem -des3 -passout file:/var/keypass Delete the files of random data that you created in Step 1. To generate a file containing just the public key, type openssl rsa -in source_file -out output_file -pubout For example: openssl rsa -in abigailskeys.pem -out abipub.pem -pubout
gateway-1.4.5/doc/wtls/fig7o.png0000644000175000017500000007001707374232663015164 0ustar toljtolj‰PNG  IHDR‡Û6Ò§¤tIMEÑ 85û\u‘ pHYsÊ&ó?gAMA± üaožIDATxÚì½mP_çyçÿCÖzÛ’eƒ’ZÄÞ€¦‰!í’£+4ÍÚéˆNHÚ€ú<ÛB¦3ÙЋ-ÚÝ1ô…ag"˜v»3…é4™Ž 3™Ù·.$Ùù;?bY`ÙÛ2H–õÿø\ÑéÉïñüžÎÓïú¼çwŸûÜçœû\ßûºÏ}_wÞýû÷CJ(4>>ÞÐа±±qâÄ ÙS^^~ñâÅžž3ÍîîîÒÒREEEÂܦ¦¦jjjVVVΞ=y‡777Édmm-l?碜baa¡¤¤Ä,‰M(G‘íܾТ(J*ìq»^áÊ•+üÛÛÛ'Íàà`uuu¬¶··/\¸033+¿vttÄÉ¡¾¾¾««Ë~á9#ÿ"Æ4ÚÚÚœ¾wŠ¢(J†PUþ”ÕÕUÜÓÆÆFt3ìWsO{{ûÖÖV¬LÌd$«­­šlrro¸µµÕÜ#šj'{hh(Nk!Éðܹs²=000<<Ìå¸}GEQ”TPUþÓ'Nôõõ¡v³¹Ÿí|ƒ†††ÑÃÌvÈPqöåàgó/?™žtaa!Òõ\£££gΜ‘Nfòá(“•UJ+**¤çœœ%Aiiéææ&yr"ÎÂÎÊÊJöŽ5M ösWAÎ###nßQEQ%T•?õ;ÇÇÇE˜/^¼híÄ.//_[[»~ýú¸u?Ê:11ÁöÆÆÆÜÜÜ¢düÓ‘€ÃCÆ×e6ªªªvvvðq#S’€RÑV š]ÓÏ>ûìŽEåð3œ]°===íöMUEQRAUù—ß’;::p7‘^´Ð`ô©®©©Áµú¾¸³("û‘mägWŽšœœŒ:|â²²²!ç4†††È„Öj–ree%dtJs®íímSïå©©)q»—ÑalÈŠ¢(ŠïPUþ´›º®®nñH`ØH«]뤴©© %nmm%}KK ZȞΎ6Çú íª<66†¿.®yBÖ××å@EQÅwìu».#Î1*kNCºzõjee¥8¦?üá{zzFGGqFÛÚÚÌ~fbÒ›S›æææð§E 7 âœG™“’mii)™Ô××ãûr,†¥÷÷òå˸ìËËËdû /DfX[[K )¥ÂïßÚÚ²3wKQEñ ¹î+£d¨šuf0’Æžþþ~dyxxŸxii‰4l ©ìDAqIóòòÐïÕÕUÔQä_|ñÅC†ôÊ01鬶rñâEñ¼¥Wœ¬iD·¸¸˜üE›ù—í¡÷RN÷üóÏK†2âÌLŒgO›O½¤¤„?ÉŠS¸}_EQ”TÈÓ("É‚ˆ"¸¤È*SSSqz¡#Ae ggg³áÑR6HDQŧ亯œÊЇÚÓÓƒ/+jR‡ãUKÐ’Œƒ$_»vM%YQüÎææfMílD ›š%¢F€P⣪œ4uuu+++ˆñöööÈÈ^o²9477od¶`ëëë/^ÔÊŠ666.444”––¶´´D¦‘i–©É^uuu²1}S€SH°Å>Úƒ­(Šâ9–––Ξ=»¸¸ˆîvttàtÊW3k i`h“ááa2œŸŸwàBŠŠŠúúú»u~G}eEQOSPP€CŒ$K·öúúúÔÔ”Ìõ(..Q䃚ì”dük& Ï[dRVÜ‘Q¥òéù“ÃeÏ ù“Õöö6ûÍît¶%Ú?9ô÷÷›¡¤„faZ[[ã‡ýW¹¯(Š¢x ¼äª¯¬¬ =Ư5w"Òì?qâ„8»ì'ì3‚-Ó1øÓš³D’ÝÝÝ+SEøsbbBþ$ŸŠŠ öȶ„ò%±DOb¿|¹ÛØØ`¿Z É~‰9ÈžIɆÛwÔ7¨¯¬(ŠâQjkke°ˆu:œÑ³C{hhˆ?¯_¿Ž{jú²kkkccc¨ãðð°5O Æ s/———ùwddDÂúâÔ"¨c$“¬Èõ%AWW× /¼ NðsÏ=GJö“LÒó';å_þò—)¿RB ä í“ëQDEQ.rŽ;[[[2T–¬øS"óKüÿÈÃq¯%}Èèïìì\__'½,|g-aÈpÇÅWl¢ó•}ÌèèhKKKd T™7„·%ruHEQé¬v 4/Ö …FæÕU°ª²_A’ã¯Éû†0›#5¶··§¦¦¦§§q¬y'y[x-_xá¦(9HOOùoVÏRRR"ƒ¿›¨*û’ááá¨øR ®®Îº¥¢(9­ólw§9pŠà¡ªì9ðbWVVÆÇÇåÏòòrüÝ¢¢"NjyGG‡F'#àUwvvf»Õ¬(Š¢$DUÙÈ -|Vé[v¥ 2³B;´EQ\DUÙeÐàÞÞÞË—/»]_ÒØØ822âv)EQrUe—ijju»¿ÂÅ‹ÇÆÆÜ.…¢(J.¢ªì&8Êùùùn—" ;;;Ùž2¡(Š¢D¢±½Ü$jè/ uEQ‡Q_ÙeòòòÜ.BΜ9377§Ó¥EQF}e% «««EEE ê4+Š¢8‰úÊn‚ø™kŸyüæ©©)  d­\ ñfΉßÞÞ–Õdr¼lÈ"n—WQrUeרÝÝ-,,tkvr²Èò«n—BIÚ“““íÅ‹E}eù°d²”Ððð°$niiAžµM¦¤†¬å¼¾¾^\\Ò•£ì¡ªìˆ1T–8õ :c*{˜ÞjÆYXX¸téɺ¿8Ö£££¸Ôd222"ëò*Šé}‘0ûü)0ñ£!ÑÈ£*R***´?&UeÀÆUWWûÅK¶‚inllt»þÆ”º­­-ê€Õ*ñÓ‰'jkkQhþMsý;ªYCCCaaáÕ«WÓ ÙFÁÚÚÚfffp¸U›s|ßqƒP"éµ “¢ ý+ÜWœehhÈígž:4rݾ~¢¯¯ïŒü+åâââìì,v mæ_¶“=×Îξfn~~>ƒ—°²²Bž˜Ñ‰‰ Wî¡âTWZceee¼Ô^·/×eT•ƒÚæ/G“ÒÒ†kÀº}ýϽ¹¹1‹/ÆQyæXr°i­FFFŠ‹‹3«ÇVÈ™*ÑÝÝåÛ¦xšbiöÙ$‹ }HöM jd‚Jæ¯!38[Rr^K«0»}#}ÆØØ./›t21u=¡Ö’Œ—moƒü©ÌøÍêÖÚ^.š šššÜ¬`jd Lؼ¥µ¾æOnßKßÀC/++îeʲHr,§Y”2MùO i(P*ÇΨ8^„–³Ó jd³Žï$ðð®,?¹};ýí\äl(¦¸¸8,gç%Yá¼¹éИÈïVîbÿóM0P#›uü·2ª©•‘JnßN€Q˪V!Éa’[ÓØØèÊŪ0 'è¶ù‰BN9Í:3*»lnn¹]ŠTˆ éµ»»»´´ä…~-/ÓÔÔ2¦eõ,«««<ˆ……gÄ{îíí ö%+Ù†JU^^îå›9ËHU9»ÌÍÍUWW»]Š9pà2ì¯Ajî‚ÉøÁ~@£Þs‰0sÆÑÑQg·úúz¼_ÏúËq&''¼,Éu~vvÖSìGW§È.¾ö,ý€ÌE°kƒƒƒ˜ gNGk _™f“cgŒÃØØØÌÌŒX[ñ4ìhWy_’CFlœÂ€¯šãvzð @Ï—àö]ô:‘ßzs°¡ûŠ/ðW“Ϙ×l' )ÚÒÒ⋦h,4Öf|ŠŠŠ†††¼9RÆ1¨äü«ýØ~‹ÔÐÐ099évAR$¨½ÙªÊÁ @íokkÛÜÜt»,)¢Â ‰ ¬KwÈ2h:ÁãûT Ǿ¨*;Íðð0Úœq¿Ù\†…í°Õ‡d9—ééé•••4Û9îF£,))Á4øq \Æ¡zº>úL‰÷‡[Ûa ”Ãàvz.Ò××—©Ç'Ñ•íÌ#ewwwÊ}>˜ËŸN£Âýlnnv»‚:™ËAŒ½mëàõúiì‹úÊ.@5???ÍLðYу”Çx§ÖŽSŽ_¼·:5¤ÏvkkKoˆIGGÿf°é©dÑÑQ™_lnnÆú: ÔÕÕ •–––——WWW÷ôô`+µOÛr­yä÷NlUe‡H¡ù666vâÄ ¼XsL–I²Cÿ‘ä‡~8a2´a~òÉ'å3¶Mººº²rË<Ïöö¶ÀŽEMM µ/'&&¤«¿ªª F¡s¶%ç 5ó¾îÄVUv‚º¯±bxÈdÔ7êÞ½{É–áØ±cv’qF,æéÓ§í‡÷uË4eÌQxJ|h»à1···#Ò¼l755!Ϲ30Xq_W-Ue'H¡á6002b€DýõöíÛÉfuŠTTüµµµ¯ýëöÊÍå1_JR Ð´8ggg— JJJ|m@o233ãvRGUÙ ’í¾®ªªÂxíDM ẒÅþGPéÊþÖ·¾es>nn†Œ(,,ÜÞÞv»~åÀ===xϨr.„r‘œ;îëꤪœuRè¾~þùçùw}}=V‚>ø …P©ñ§H…!Â|õêUf `•>hóØØØµk×JKKµÇ%Køñ; n‰ßg¦ŒªrÖL*=Õ_o8ÎÇc$aN¡0 §HYA˜oÞ¼)ãÀº[~B'ÿdŠŠŠ $¹¡¡!K xïû¨©©±þ‰ÁY[[ kL`g ìdèk“¥ªœuìZ[[]ä0~²„ ¢rôèÑ‚‚ûéwvv>þøc›oB®–¤0]‰Š ­¯¯w»,A#Û#Þ›››eL,FFFº»»cýŠ…¼~ýºu:ÃØØ²zÆ@öð+:]e'+_÷ð©*gZ©É~Ôikk»uëVÂQÖ$Híëò©S§NŸ><'œÁ,loo?þøãñÛx¾q~@ ‡»½ ÷see…V£zÌ„6(ÞBYYYØþÆÆFŒ¾D¬Y‚²ø Ï4j: B†îš'ª««“m³=aí±³è·¼¼Üí–:ªÊÙ%ÙOe/^<~üø;ï¼c'qÊSDhŸzê©§ ØŽ?<{kkë÷ÿ÷ã,¨œ”ÿ 677ûûûi²äàPš¬‚_õ£ýȱ–OR­F¤qqqg4²ø…^E¸ÝÖ…ìb‰®éF_»v-2éÔ†%3KNy¬¾/Û ãD¶|Ä^· Y™k||ÜSÉE;ͱdGQƒoܸag$ž®YÓä¨|«~÷Ýw?úè£È4o¾ùæÕ«Wc­š^ZZš‘’øZZ´ÖQå®®.ª¥É8ccc¼\UUU¾î‡ô#ØŸr¶/_¾lî—Á.»æÎ°µe1‰ÖCÌ M§YgÍ’óçÏã#Àæ %Sæð›#ûN®}âëõžVåááao.xÙ€šA³.ŽJrN5éÑG´vß¾}Ò猂>|xÿþýöTÛÌEžïÝ»‡6ã¯[lþóŸ—Q9‘Çúzl…}¸öK—.q±£øÏ]I‰5KSwA=ib¿Å,SÉe;Lbe†¤Õ4!Ÿ ?4p”ôN[÷„Mµú6À(ptt”=4Ñ"sNèäççgù¾fïö`ã"·´´xP’Mh¬UWWÇo²%åâ÷öö"‡Ö=èîã?þÙÏ~öIƒ_38~üøÁƒ3+Éa'å§OŸ¦`Ýÿá‡â.gënzÚˆ.\èììœUIÎ6˜ãöövånÄ÷Øo1·¶¶šÛÖÉä€i²¦¤þGJrXß!Gõõõ…¥‰Œ`v5×ÔÔ YK‹BÇš‚cÿZ|ÝËâQ_1nhhˆ“€j+ÂFÆY]]Õ8`?–z~~>Ö±µµµ6Ýe§èî+¯¼bîAÑ`›c²2MÎþæ›ošS°nß¾¿*¨ð”i ²±¶¶–#½^£\RRBeSw9M¨´vÜkÈp-l¹¶£NÊû”KšÈ‡A/­§Í¢a“£BÆ0±Ô®×ïÆ£ªLÓ,j5êîîF½ŠŠŠ^ºµ°°pkkëßøFdÿ-{¨µ±¾1Û%¢ÖµÝ•d³?ñÄ7nÜVüqÈè‹Te^3_7NãÀ¥a8Pˆ”m„’2P(~«W±ïfBß@ÜæŸ¦¡Ã.™¯¶t ³'jÛÔjyYbõ'aÛM‹|ªªªR¸¢¨ß°MT•³Bdh\nôÜÜúwîÜ9W|5*Ùµk×fff"xJK•ãדÎÎÎýû÷›C¯ãKr–¼äGºÐ`¼ò6ž:uJvÊj’2(#ìXÇú-†¦!V£¯¯ÏfäQ%³ðú\¹r…Þ'ƒºº:*UšC…y+¹? Ãìcª2&ÈÜ6{QPkÍÇ ÐB3ÊìH‹3}ÙzxÔoÆvˆÿÙØï5=ªÊ‘ÓÞQDªÈðð°[EÂ4”””ÌÎÎ⯇ íôôt:3,eŒÂ&ŽòC=)ÉÔu´ù·¶RÙÉ;ñiŠ4Ù’Iaaáoÿöo[/jee¥££ƒ×a¾sç%D˜£¶3â´Kü †‰‹RIv—^x¡©©ÉSS0Òw=¶3ïÖNV¼’ñ³J¨ýXsŠpÈøvÀž¡¡¡Èšuv“õ@,§³ó¡§¦¦ÆzÒ¤ˆß3çû‰š÷=IX!›››=Ò‹%‹F„Õ jaœkIXAi0’ì¿øÅÿgðþûï[çÂe"–3%‘5˜ñ$H–Â}æ¨8‡“?MœE~ýä“O^~ùåÛ·oGu‹Iæv•É<}ƒ¤Íê_¬á¨¨W™ @>ä©RÖ³'tI1/Öô(}¤µ±ƒ‡„Ö@nBš·4Ž0/..:ðL³‡?T™*âÏ–}Ö=ñU¹½½=~†’ì•W^A’_ýuó@^6Þ$“ø·‹·nbb"©;ÌûC[INx )E³?úè#¼óûÑæRO•Ñc f¤¸íBi¹ú«*c. Z$r‹ô†­gOxºÙÙÙL]©DÄŒŸ9ýfVœ¸› ¦Çñ*Ó¼ŸüúHÙ#ò¥Š¯Êñ¦Q‰IsçÎq”e–0¬­­dÕÑ\HöÝ0»ÙÃð»Ñ ƒGÆÍ÷»¨]aΜïp×WŽo‚ÄÀfŠ­­-gni¬¸!¯vÛǣߕ­x-ÔðêêjRßPñGÃ&XOú“O>‘?9"ÅÅÅ|u£9›0!RZ!aƒGRþ>äMZZZ¦N*.BíÊÈ'X€)˜œœÄ=ÍÔwer‹¿þDüq'™}yû¦+kWD^¸wzUSƪì5Rl›S]]õ'ézº}ûvȘ‰d Ü‘UUøè£âǾ¶OÀŒ÷|nnnbbÂí‚(¿„ÚE#5ÎüCßA³ïŸ'M £q|ùòå„c°CqCTú7d´u’•Il‘ª²$|÷öîýôA„ÅÒÊwïÞýàƒ2¢Ê¼í›ÈÛÕÕY:Åy`jÃ7pìt þuŽ–¯#` Þ¸™Sìß¿Ÿ>ìÀ¹ä×^{íÑGÍHn›5$«¡x¡C^>”d{e\¿€©µÆ€T2ˆ“ŪÊN§çÍúJÄ÷•eN0”––ö÷÷³Q]]ÍFR=ê÷îÝC’qÍ%Œ¶D6ÍËËËÏÏ_XX8w‚6[Ö‹T<88ØÚÚêÏlgggyy9¨áYR`kkËí"ø˜8VÂ×K‘F~EV_YIŽ ƒÙÙY³2]¹rÅ|a:õ(¤·¨¨¥\6À*..fcnn®££µ¿Š³õ”õÑÑÑÂÂBiPJòÌ3Ïíúú:;9ceeeT_Í|Q¯Œ­°Â…ûâ­æ¹ð¼2˜! ¾¾ÞíËŠ‰èTJTZZZhÇÇïtIø+&èÂ… =àOŒÀõB:ã¨*;‡,Ö-+•šë.c {{{÷ìùôAÈ×e+8¬¨cWWWMM Z>66&µPb^²ÝÝݽ½½Ó,¡ªòÞ{ï…ŒðaäÙÔÔTQQa.hŠ ñú‘çÊÊÊüü¼Ì›â}ž™™‰•›zz3‹ƒ;JW6¶•§,M(ÙÓ××']ÜT!~’¾iᡯ8ýb@©BüD}ã_Œ©ÙB†rˆXdÚ|’†ݾâ(”••yDü…Œ÷æÖñRǰ¨]2TjE~~¾Œþùç/> d¬f[j@šÌŠ4ç]z@ Ck°Ö»Žör”ϪaÖaý8=hd^^^äâŒåÃÀ}xxëIÍC¡‘j`yi;ƒ9ïÞ½{ߘmŒSÎQæêlœW‹w€"I°0 ø%¿Æy1¸¢ ÙJYcÃk­oéÊF/i'ñ˜hœýèG?’h Ï>û,ÏeÝÚÚùÎw¾C* &˜¶Tmm-WÔÖÖÆáü444„y¥ªðˆ‘dŒõÀÀÀèè(µ‹C$ø9×›#r§§§©þ­ln´¢òð.S¥?ó™ÏH‹Ó¦ÎuttP7¨!ó7óá‡Þ¾}[§ Ή*$ëÉR»x:ˆ4UNVhæØdÇ–ódÉDæ§ Œ•–Èÿ………çÏŸ§•` Ù‰×ÞßPUvjUII‰uoˆ¨²¸Ëò'õÀ°5U¢Æ¡µ¹îŠ9+zÿþýÖ8ÛÔã8âÔò°UWýŽÄw»Ñ‘ ‰4h“Ñ¢Bk‘d6¨ó!ÒX䢢"·¯,\fkk«÷P,(¹µã2­41“?ñ˜¿ûÝï~ó›ßLx (+ŠhÆ5ŠÏûï¿/Ĩ„ȪÍIžßúÖ·h)∋“ ÿî1àÔÔvˆ*%ùwÿîß9]A¿+»F˜ÝŒµ6Ù|ðöÛocFïÿj¨KÞ4*ñ;ï¼cö,Ù羦¼Zœ÷ÕW_ ÛoÊ€/FEÔ”A­X[[“ÕsÛ l/àÙÑ¢"½¬&G‰g‹à(k}KÓï„ßÿýß 0`¿Yf~ñ•¡-òí§wü‘GAD1G›X'Yû5X!*öâ!º´N:õøã?öØc”çøñãG¥M°× aÁü¾¦²õ•¢¶¶vzzÚ:EÊf ¢Ã‡Ó½uëVØþƒRw©¸)æÎ;V¯‹×ã½÷Þã 1ß^ùMƒ7r ujh[Â¥D<¾WGGÇàà`__ŸŒÒÃjSºFFFÌC***ðWPhrêRQkjjܾ¾phÄ_RW‰ õÕüó?ÿsë«-ã ¬ýØ _ê……… .„õ£Ä4 Íp(´ò“Ÿ Æœë®Ûhm,o›F¿x?üð¡C‡(t'HµÄèñ>šƒËâCù©Ãýýýnßï áv îèXK˜ñ%V2rÓÂJ˜ðŠº Âvš/Cü¨åHæ7¤zûöíÔî*o‘¬59 ùãÇ_˜AŠí÷åÒ"A’9·K‘Öǔª‘OÙ±¥’B»]Š´ˆ³ÀQölÔ}cµ(lˇ~¸máÞ½{Öò$¼·êNƒ2§l„Œ¥ü¤×E”é!´ð0#7oÞüÅØŽš', d²(Òkú uuuÖVbgYIœ( ÝJ“ÚíG´ÛMlâǃÁ'~ì±Çޤ)Ó¬÷ï¾ûn¬³ÿ#<£¼3˜íz…ª°>¦"*G>eo.?33¼9xN6¹/¶««Ë|ú C yeAæÚÍÍÍɱµµµøÜ(ñÈÈiäÝÁÆÙ5G®ÈœÏHh(ÈqII ¸··WÆÖ<óÌ3ba{´–ü¹ãì\E ËíxíÁv*Vdd»óçÏËçÁþ(‰4‘Å0ÒÁƒ3ˆÒ§°°Ð_ªœ#ô÷÷ûåË‚7‰ÝÉËKCÇf¬Í°þmYÄ%Æ{F˜ÍGCžóóóÒ1~äȺ«ûÚì?ÿÒ—¾„ÞËú(”‰[VÄ#:oÓ”ÿôW®+-- ^¿ª²sÐ&ÕAjŽþ§*¿ñÆ÷mÌ'N ³«ggg'eùðR´»ÍðXŠëð¾HXY· â{ÌQW(´u-sVq¦T%¦Õ.æ%jçŸtfÄQž˜˜Þ× Ue稭­¥Êֹ˼$o½õ–a&M²/Ò¾}ûN:%ÛQGbÛ!xQ½LÚÛÛ‡††Ü.…òKÔQNÚ4ÖÌÖñ¤4Í¿ùÍošªü±AÊ'Âásoll`X DqïÜ¹ãØ•b”¼Å=YT•à |Fä4ùííí×^{-¾0óë­[·b-þ‰¡ÃËùÎ;ï¤æ”øûkUU•¬ÂävA”Œ'RG9M¸Ö%¡$üÖÍ›7ã„}KNÁ]&Äøí·ß¾qã.òÑ£G9£ô™óS:2Ÿ,ËËËQ ùUeçàÀ'¶N… ~§é X‡´ðÎÄæ÷ß]<~üxj%A˜Ÿ|òɧžzJâH${ø™3g‚ªÊÐÙÙ‰‹æv)r………ÑÑÑ‘‘· â{ºèdîò½{÷DªÃ qTéýØ‚DF‰ßzë-œcö`UNžUǺēµ+xÿþýÖÄó+¯¼‚_k†ÕäºsçíÜÇ›ÑéÀ+D{6Å*‚‡„†îííU/Í-hó;wο+Dy Är{{{ïÞ½Ò™ŒFÆ Š ŽoÔ8Eìä'™…|ßXcqÏž=2™Ÿ¢~!ÉGþÃf-K⌫µGO ¨r`BàÖÕÕ555QYmÎô öGNb–.èQéÓŸ1+øNÎÂ-À]¶®„¨8µšf+ aÌ)Å [VðdE¦Xé·¶¶bE Pš>6ËØ2âfÈ­î¶Û >4RKKKÇÆÆT’³­ðÑÑчzÈ×yûömþD;c}`–5=S>#’¿wš&ž={2Õ¾ÿö·¿-ëMªrä‡äêêjZ|óóón5ˆpžÖÖÖein+çÏŸO*+.:ÔÐЀ|ò/.BBÓ£,CÞpLXB7WfaÙ/é僴ÄSSSÉ^²O‘šÊÊJõ˜³õ™ÛK’5ûÜ.N0ÁàÐèáí>tè3bü‰A¬Cø)å~ìwß}×êjÇr‹iÙg$ˆ!ïæÂÂB0æD yÙ î˜8‚‘â2Üeü<çWÜ“3Ö××G„Wš” sss8b‰JJJh6¾ýöÛ·nÝŠšøèÑ£øÊl â8pÙXØŽK£0Ç„íZHÏ?ÿ¼u~W°ijjš3L™@{{{_|ñÅ^x!ðzË e0ÃŽn]¸p¿"òƒî[o½Kž©ðÉ®-k•d‰‡~8Î,Œ^úók0‰ü¤Ueš?aÅÉÕ»6 býŠAÁƒOó´d'&&Nž<K•;&1C:::°eñÇJpßp|ûûû‘XÉ™{EKYö466vuuE½{£££˜<øøùó"ÑF Æ$›pgZZZxó3ÎÓE¨Š2ñêÕ«×cÁuU†ááaL‡õí¦!^PP@ÊX½Í8Ö=ö˜ýxä³±±!>òÈ#ÌhÅÖqN¤³GU9d|KÆ7u»  ~ÓüL¿BàjcñQÐ×_=jS•ãCåÅÃä%ìq½xñâÀÀ@dÉÑž:ƒXò&ã%Ë»—Spᲄåµkׂd€FíÌÌÌÜÜÜÔÔ5%ŽZ÷ŒT9d¼ÝØÕÖÖV¶§§§y"eeeügÙ½{÷š4ò¾‰9$ý•'ì Ãkb ²ñ)ý®2Æ ºøÙ\ÆŒ”P–“J3 9”””ðòÛùJ⢢¢†††°n€¡¡¡øîàÈÈHnÉ‘…8±hÜ䎎ŽÇÍ8Ü1\´æææ……î! P/¿×†·›QhÀ‹LÛš¶f|³ƒû4µ•ƒ:)É$0¢L¼ë+  ¯q óˆ² uúüùó)|KޝJ}}ýŠAÔãûÊòÑ(eˆå7G-§´¹lU娂ÞÞ^19Õ™Ÿ,9Û¹bÅ#¾r$ùùù¯¾újÂdÈí#‚x=⦌%Πþy.p{{q=}útÔOËüU•©šmmmÃÃÃògYYYñ¯ŒHä•‹ §0555==ÖÚq‚9Qæ¦uò¢ŒWÂய¯×ÖÖ"?A š¨Õ‘±n€}xã7>ó™ÏÄO&¸ì32Œ0¿öÚkÒëèÑ£>ú¨õ3^‡¬!ûÉ'Ÿ°?êìM;œ;w_"x’ò¾¯œ;à~µ´´üÜ êCá͉:z¢¡¡%Hqø„Qµ¥qŠ£ì©¨A:uΞ=«/TÙ›5à#<ë+ËÙÖÖV;Á/mzÌ·oß^[[3ÿÄh<öØc²½³³#öMzÇ ¥ìL‹ügý>ºw¿+ç2ÆêÒ¥K±ƒºyófÔýCCC¨r:’Œ¢455%1Aœi•ä¨H§7G£g‡¯œ#³ÛýHmmíôô´Í-xÌ››› µðСC¥¥¥Ç ŠŠŠLI†7nˆ$?ùä“ò:µbã8è¯×{°eP±7¿+wuueöƒâÀÀ–}bbâ?ü‡ÿõF&4Göcóà‹Œ¥VZÌ¿ñçwa[ñæž&î;°AÚp1Áˆ¯¯¯þ ”¡Æ®¬¬`:dDŽܽ{—gšpTöC=õ‹ÛéÓ§···~øá4‹"øS‘§Uyxx¸­­Í›a•æææ®\¹’Ù±¼SSSdøÏÿüÏQûgnݺuäÈ‘°~ìššê¨ ªL¶¦Ê4\î0¯Yœ !Á… RþܶO0wâ«$„†fB!Z¨lR³?>þøã›7oâãò~òÉ'ñ½}û6F‘–?Ùxä‘GîÝ»gîI üûçŸÞí›—-¼Ûƒ$‹`¸]˜P¶êêêÌöXò’ ®_ûÚ×b5'#¿:ËRF–Šêïï·sÓHÃí5ÃqÇ_o£··¥Ñ Á)Lg=±àAË5åÒg(++‹&!ˆ±ÄVJØ-ã-^}õÕ×ÀŸiJrÈèº ä8/Á£ªŒÔùbUê\mmmf›ˆîï·¿ýí¨c»d„Ùº7×t‘yO:::ð›%ȶµ`ü´ô~%9rÛšC$2)0Hí²{áv)¼Âøø8•9ÇGì{ – ã#GŽ$Teb}÷îÝ;(..N³ÀX$2 p¿GU9¥†*Bë/³y ÍÍÍÍÌÌD­ô;;;aS“q¯­ß2c^³³gÏÊG7úìøÕ*Øñï6Íòð;AP ìÏÎí‚x¼dí¾ö>¢ÊÉFÇÜ·oŸ¬ÐÜbR>ñÄ¥¥¥lðgúa8'''ƒÝoçQUžššrà,TÇûIÒÝÝ™O6£áÑþ§ÿôŸdÎ_$ï¼óŽŒf”?åƒtj'jllŒã(÷ôôàUx`EÆéíííïïw»î#SÛÜÍÊËË———“Ke›)o£Ç´YOž<™~ƒ=Ô+äYU¦–¸]„$ÈÆ§D„öúõëõõõ±jÿööök¯½f 3¾òüü|²- Y¬0*xäW®\¹víZï]à O[ÞËã!@–ëÖšãÊÊÊ^z饤±¯âæZìøÊGM¿´Áþ¨ò¬*;36W^’D ¥é˜Ô<ÙÎÎÎXÂŒ'ýÊ+¯˜‘åeh›­Hô{bb"þå¶¶64[¿ &7–0»]7ihhèëëÓšã0û·kÿÓrR¡4:$YBJÖ¹ ö5ªrmm­ÛEp¿´Xö¦¦&|âüÇŒµÊ)¾ò/ $z6vplllgg'˜–MÔ‰³¼³³³¤‰ÿmFÖù vOQ– )ãÙ}0::º¾¾ÞÜÜìvA»ðšcmì«æáÇÝ*j.¬ŽãÑ e4ˆJKKÝ.…-¨k‰§8²]]]ÜŠééé‡zÈ|X4?<ˆ`›žiºžkγ ɼ HrN5DCgggCCßþéŸÒ²ïg›:*nñK/½ÄF²§C¼g ð¤qý×ÝN¯x.̵óh¶ ¯:Ö-Gâ`‡!í³/¤¦¦æ[ßú–siiiú!r¢‚£Ì{²±±188˜æº9,d| sëìÔÏ¡¡!Î%¡[ÇÆÆ‚=‘4e¼ßƒ •••W¯^ýÜç>GË>N²£æŸq>‰½¼¼Œ1‘(›q"¢ãH<ýôÓq,ª¬Y·µµøž¯«r.C ÆÌ™õ˜JYRR‚Óüõ¯aÎÏÏüñdzqÞúúz™ÄV%h<Ñzs~è“4¶··—––æææ²Ú´B'''9‹zɱð…*/,,\¸pammÍ:`%’¼¼¼cÇŽíÙ³•M¹7.¼”ãÝl% Zˆ>4²¬¬ì™gžA˜Óò‰  ÕA^™Qä‘ñìœ8jõÑ%šG–¼ØÍÍͪª*.P‡wù%ÍñÚÚZÚXßûÞ÷Þzë­XºÎþ·ß~{ïÞ½aM=ÌÑÎÎÎ^ƒøvI>·Qa쯊OÒßßÏíö}rUeï²¼¼æ§â‹`å+**ð˜?üðCûvì ýº\c1×£-åL胰nsÜôšš*ªLµÉ”Ó,K¬^¹r…æ(ÿüç?·¹dÈ öÄOØ/•­½½=GZ~¯¬ÄšíŠ0/,,ôôô|ãßÈ $ËR€êçHÕw ÙÊÊJCCƒ¹H–ÀŒVVV†"¾dS\ù$A1â[Û„PU$+­F\d•ä`077'ÑÆÆÆPè¿ù›¿‰‡ëᇎ;m?n•')IG¹««Ëí›äªÊ;+À™xÌÛÛÛ¥¥¥iZX™§™LVxÉÖOƒìñˬqƒ‡ÊÅØáˆd)º’ÏÃjmm5¸ UÞØØ¨­­åY£ÍXádKB­“ÉD1ß:00LMMÉw+åe;)×g||¼ºº·‰³p.Ðâ W®\©¬¬L%féLæ!â"£ô6=Waååå4û°¼xEh-~õ¡«««Ü‡kjjÆ ØÆËGŒ‘d)H¨HaK‰Ð\£ùÕ¯~õСC‘­iع]ä@ãv³@‰ŽX@›‰%ð5ú*~O,×Y¼²%%ÿ†ùF‘hõÈÜ|qpy^©Î,..扫óê}ö•ixe¤Ø²pû|æ1Ë2²J–ÐùÊeuuµªª*©™4xq¿pn&''#¿Áð+.õùóçq}lN|¢¬Õ#«ð¤FGGñD¥XdÅIÏCäüc’õööêü`¿ 0[°dhh(S£ðdHÿ÷¾÷½wß}×ê"?öØcöç5)I¡f×»TVVÒÄN§o9µu)LT•CÓ¢’¸Áüµ£¸¶¶妹ævy•¤1ƒ„gU›i¨e@UYQEQ¼‚ÎŒR¿²dàv)EÉ$ê++Š_‘%öôV” ¡¾²¢(Š¢xUeEQEñ ªÊŠ¢(ŠâT•EQÅ+¨*+Š¢(ŠWÐØ^ŠâWÝ.‚¢(FgF)Š¢(ŠWÐlEQEñ ªÊŠ¢(ŠâT•EQÅ+¨*+Š¢(ŠWPUV¿Rnàv)EÉ$:Û÷ܽ{÷Î;²¬éž={<èv‰‡ÐÕ)%xè|e_òá‡Þ¸qãÖ­[}ôQä¯hó±cÇŠŠŠø—m· «(Š’[|òÉ')Û^õ•ýOúçlØ<äÈ‘#åååê@õ•Å#à ݼysss3dxMæþÇóï©S§ð‘lÚaUeßðúë¯'¥ÇVNœ8ñÔSOíÛ·Ïí‹P2‰ª²¢¸ËÝ»wö³ŸÝºuËŽeÆ?üðà M±ª²ày¿ôÒKQ;«í³gÏž²²²ãÇ»}5JÆPUV·À,ÿô§?ç8Y>ûÙÏž>}:V·ª²×AŒ‘äÔ\äH>kàö5)™A`/--¹]EÉ-nÞ¼ùòË/§c–‘䊊Š#GŽDþ¤ªìiäú§Êlž§Nzúé§Ý¾2EQ_‚߸q##YaŠ1Èa;u€®w‘ŽëŒgK}zûí·Ý¾8EQÿñãÿ8S’2þ§?ýiØNUeï²°°©Žë0–——ÓüJ­(Š’k¼þúëï½÷^fó¼yóf˜Ì«*{ÿ|¥Ì{ý©(ŠbŸ·ß~³œœñ˜­n’ª²‘yÉY=’¯ýØŠ¢(vÀ&///g/kϨª²Iy^rRÐ@sûB•´X2p»Š|^y啬Úä»wïšž˜FÜt|S›ÒÙv”êÁæææ‰'\¾/Jªœ={6¤ó•%Ë`*38Â+˜}™Ä¬ªì}ôÑââbR‡Ð:C2~øáì•jmmMUYQ”ß׿ ××^{Í™ò`óŸ~úiUå_"+/±±ÿþXáÐÌè¦L*ò8™/,,ØOÿ‹_üâ¹çž“íÏ}îsÿí¿ý·¤Îõ—ù—ögf'¾æööv:QÔEQ|Êòòr²ck°®Y[LyT•‰5P Å}9yò¤5|ê7!ª\QQöxnܸaýRK>§OŸ>|øðo¼‘ìhê¿ø‹¿øìg?ÛßßO%OêXJÅIíWÊVPPàÐVEñɆmøë¿þ뉉‰÷Þ{ï‰'žMê\xYEEEvl2÷=×U¹EJQe랟þô§ï¼óš*{îÝ»÷¯ÿú¯Ü/3 7nnn.l°ÎòIy}MMÍÕ«Wy–Ô€?üÃ? Oëûßÿ>~å+_©®®fÏÌÌÌK/½ôµ¯}­¬¬ŒºÂ¯ˆ1?qÈ¡C‡ØóðÓÃ?üÃ?ܾ}û‹_ü¢EÝúÍßüMŽ5÷p¥ªÊŠ¢x«ÕM î„9nSüë¿þëa™Ÿ~üãc½Í=¸:ÇŽ»uëÖ«¯¾šTÀ ó?ÿçÿü»¿û;lìÿïÿ=ÙËáXLºØÛ„`´s:â&æÿý¿ÿçÁxhpOOÏììì7¿ùÍ?ú£?bÏŸüÉŸP!¾ð…/Ð^ûÓ?ýÓáOÿÎïüih¸ñ+Òû¹Ï}1ÆÃ>wîÜ_ýÕ_Ñ4ûã?þcTüĉh6êNVüÄ~D­É‡ºÂ¯NYñº:…<0ÈÈ­Õ Tm6¿µ½n`M }“Ö=ïd¤H¯¼ò 6ö»ßý.6Öš?ûüq!Ùƒ›D įo¾ù&boZ¬·ìg›ýæQü)Çnmmá_…Œ•Ý÷•777WVVÆÇǧ¦¦²:!, nŠH—Û7 ”ê¿ü—ÿò÷ÿ÷ù—ÉýAPyüHiÈX“‘–ןÿùŸSkyðÒ—Búîînk¥‘npvÊQƒƒƒ"ðÔ-Y ‚{Ž*#çn_®’"ÉŽTûìî˜e Åêê*:pÒßú­ß¸Eî¿içÀtú&‚]ÅÓmkk߆=¸C8NˆFøâÅ‹ìÿÝßýÝ1öKI._¾Œ™eãúõëÿù?ÿçgŸ}–‘v,¹ìÿÿñ?~ç;ßá'ÑlŽý⿈¹¾s玛ªÌ#î¹çæææ\9;÷‚[c•1ïÀ£å9QAÙF˜/]ºdþDå ÍE«Šgσoll¤m100ð×ý×T¼ôxrk.%Þ°µùyèÐ!Õc¿£J6@ƒ»ºº’Ñ’>¸"6»y‡²acñˆðtQSœ\Œ-òÌ~l5ò,M ÌìÌÌ žɬ ô±Iþ»¿û; ¸8ßßüæ7Ù_TT„s…Gúgög!ÃJ»6ø–†Fee¥H2m ® oï¾³477‡}Šð4Vp”i4˜]ÒÝñõ¯ý+_ù Þó?üÃ?ðg? ¸oT gÙç7)r¾rÈèrO Í‹êÜG©‰ä{ͷµ8§Êfß5^©G¼“عJKʜĖmh—}å+_qó¾(i ó••ŒPTT„ÂMLLÔÕÕ¹]'àbÑfÖåKââbçF{ÑC’+**rP’CƧè°Ä±à©8¦ÊQ[ Š¢ä ²v\ŽHrȈßpìØ1üŸ?þ8abé[v¬lO<ñ„sªÜÕÕÅ¿ŽÑ§æôéÓ‡JÓ Ò+ðXÝ&@cê«_ý*~s ž.Ç~å+_QI:ÚKQœ‹Šš¦9y•Ã1éQ× P_Ù7 Ç¨2-µ7ß|óÆæV±Ø·oNöc=–í©ÏŠ[œ={6¤QDÅqPÓ/}éK›››?ûÙÏ’]vËü…/|!ŽYVUö(>ùä“>øàwÞAžoß¾ýñÇïÝ»÷¡‡zôÑGÙ@㬩¬(Š¢¤É ´ù7Þ°#¹   ¤¤$aÀUe¿‚<¸]EQ”ÜE´ùæÍ›7nÜxMÖ¯§NzüñÇm~TUVEQ”´Ø·oŸôb¦Ÿ•ŽöREQ¯ ª¬(Š¢(^A{°ů,..º]EQ2Œª²¢ø ”¨(ÁC{°EQÅ+¨*+Š¢(ŠWPUVEQ¯™ïÊ»»»+++llooOMM…ýº¾¾¾¹¹ÉÆàà Ö¤¼¼\*)**JëDQEIŠ„f¹¸¸8Ì2«YöyÉÑ]]]ÝØØàOOOóÈÍ'wñâEÙ¨­­ 8U__ÏgΜ‘=.‹.›RK8¼ªªŠš¡#Y%>òŽèŠi–ÇÇÇÚH³ln„f™9\ö‡™eÁV³ì¶T™×~Ü€Æm¨óçÏ£¥¥¥öS<ËåååÅÅÅøUwTˆ¹¹9NJõª©©ioo¯¨¨8pà€Û÷JQ¼E^^^HW§ÈU°ÃÃÓ““!õÅ,£Éú¸v,³˜eì?)9)ÖÕÕq.5ËY"¦*£ˆ£££CCC"<žDÊÏÀ¦*GbmP€¶¶6ÓÛV”GU9×0Ír¦¤15ˌׄM–šåÌsÿWÙÙÙ«ªª¢ÁÕÝݽ±±q?È· ž}Ê9HÁ¨‚<þ¾¾¾LLQüKÔWX ¦õÃ,gÖú¥i™¥`g Ô,gŠ_y¥¹¿Fu—©d™ÊŸÊJ­qò–)ŠG(3p»JV³œ¾ŒpTG9S%W³œ!„gŸAÙJTw9³õŒÖ5@›fŠ¢†¬šåû1Üå4e+j–Ó!¯»»»°°°½½=K£ÉŠŠŠd¢ºé(Çé?IÕÕÕÚÚZ™/¯(Šâw:::JJJ²g–¡²²raaÁüG™¦@ó_ZZºtéÒììlö.!¨äñ0æææ²7®}||¼¡¡ÁüIŽÚy’&h?•@ƒÑ(Š0hH2Âlþ‰£+ÒHÊäççomméœædÙcud³|ü—mP–¥e¶¡§(ŠâÙ6Ë¡_µÆ2õƧ<ö”•• dõ­­­²qõêÕläO£g_ZZšÕ«PEq†3gÎdÛ,Cgg§ldã\sss»»»ÅÅÅÙ¾Šà‘×ÞÞÞßß?22ÒØØ˜¥sðl ËËË3þE9d|T&ç‚‚õ••\C"`khâàÑÐÐ0>>žU³,…²ÐÑ(fIÖá>)°G:.šššFGG³tŽ\»v-Îô唑gê×ÔÔdó.)Š9kàv)”Ìã€Y®d6OÓ,Ç W¢ÄaùiPYYÉ ÍÆiPÍÌ(ã‘·´´”––²ÁŸUUUÙ¿WŠ¢(Nf–³÷u6³c}°Æxù¦YÎÒ·êÀ³GÖµ°°À å¶fI›3´§§§°°pxxØÜ©2EQ>Œ9t³\TTä³l® :Ö'5>]3J¾a„ý€T·¶¶¶µµydº¯ÉÉÉ+W®XçØ Tß· ¨(N£kFYÍ)l'Ö¸«««±±ÑSf™"E¶2>:wØŠÑýKÛçòåËE"ÛÒ)á0KKK4Á¨ ùùù#R’CF»Òù‚)Š¢d¨Ý¿˜åŽŽl2n(2ÎÙù²q^ÎNÄ,GuâÕQN™O}eî©Í;ˆþÉòÚµµµ’ñöš,¯===ÍSG#›ŠQéîîF¹¿uŠâ2ê+  Í¡|¦YFÈÙÈ’YÆ1à Û7Ë}}}YM`òä•–×;dyÎ¥e‡`$<éÝÚÚ²nÐ8H­Ý—ì’ÝŠ tfT°É Y¶9ðÊü”™¾Y–5*œ½aá—ªõ†_ØÙÙÑ nŠ¢ŒÒÒR/ðŠvá¤Ì^ù–ÔåË—Ý.L*X+*®C[[¸ÈñƒŠâ_Ä×Ä{©««sÌàp®þþ~·/=Lg]Iß«rök+öYXXxî¹çÖÖÖ¨HÍÍÍ!ª¨‘ááá¶¶6\Ø^xÁËSUUåSUÖ×?~Ùƒ½»»›ŸŸïvaR!K(öÙÜܼpáz<00 BÉVWWe<ŒOV?òrIDLß1;;«‘RfüwàÀŸ~™×X›.‚y*))ùíßþí •d%GÀTÎÏÏ·¶¶–——G«™)N¸}¹© ]˜é°ÇÜòã}´&S††{ÂþöQ·°gò(³•DbÍÍÍÙÔ¶¶¶®®.ŽbÃÜIƒ’ú á ±bR0åçççåå;wŽ¢¢"9„‘Ý›ˆ=iÈäÊ•+’!òƒÐJS‘um£¦%7r¦a$³M&•••ÕÕÕ\çBþ­g'CÊC6Âtkpp3š ÖÖ××ç°‡”¤§ü) ɰ“ÄÖ› WÁyÍñAr¥´`äþH_4e#{(ž,‘Ë!òdù“mÈ:¾ü¶˜ ÷dtt”Ãår¯Ì[$­+Yú—Ò’a&O·´´§pƒ”R.PeýɺM>………$æìòLeåÉŸóšWéùi{{[È!FŽsÉæU¤ zœ¥!þŠÊà/×Σ„ùÎ~Y“jêv7CŽ‚éIçæ‡õ`Gýh§_t~~žü+îÚÎÎÎ}£óRÉOlHÏ*²=666;;‹2‘xeeEŒ¦”Aº‹­}³¤!é1‚’¯” þdg__¢K‚X=Ø =ç$b\»vMº#ÏÞÚÚÊRB3+d?WTWW‡ÃÁ9õ†üižZNj-­ f``àþƒl¹ÒææfnÂÚÚ·ˆCD?(ÛrìY4h¹ 3Yd¶i4Ân'ª©©!=ÿr]r‡%O2äÔfüŠïKyØÏéØ&.WmþdMf^2ÿrR¹K\”¹_‚_†=î¼ÜC~¥ÁÄÎÆÆFNÁ‰8–\#"!÷"~~šøÅµ>%eÂ}e¿<~u”ÝBzê2•ÎJÙÄW&vrŠ©©©Èᜑ #Ά9O”mì¬ôlË2Äy"=–‚ZÆc‹SÒ gxÛ¦ÿ*êüKIð¨0è±\–%ƒ/ùËßþö·åÔ¤¬­­•_9³Sfë= >¬¯eÝÏNô/–Ÿ7‰¹È†,v–˜ëµzÛøŽÜ±Èye\šÄ+ƒ»9<#‡%—f~DÀ½–³G=‘)l'H+»Íéâë7„§Œ^rvš,œzÈàüùóÖŸ¬Ûr Ö‰ŠÓÞJhx(T®WÖ1“²I›‰c)-ÿ¢ålà(K£{Jž,}Q6ñ‹Úù¥õàqÂUÙ/ñÐýRM 7?{ó@ô÷Îê_† Ÿq2ë§el7v{힟Ÿ7żâ’ ¤¶à*‘2,Oi\¾|9jrxæ™gJJJ¢~W>{öì¹sçÈ!ê0(i(Ä?;QT.„‘gäz1sÜ ùSúlå{p¬Lø©££#,îÅ®¯¯_[[£"ÝÒâጠ7‘“†Œó¢—œ+ì»rÈÆE1"WDAÉ“œùÉ:ä-~}î¹ç¸:Ï =æìˆ"å´þdÝ–¥w=¦À˜pЙø=Ò-©MxÅÊ¥K—:;;3%ɸڼÙî¼õ¾YöË×OïÅWÆòøýíîîö²$äT’ŠŠ |‡òÙÝÝõEןâ$2,#ƒ VXX(Cý³]æÈ¯ ž¢¯¯Ï/SxgY]]õÅ|wEIÍÍM”Xbž»rvÚ¾n߃èÌÎÎz¹Ñà/òbMü•àïn/ +++Þ–ãЪ“ðŠ <òÑgÉ›ÝQ²¾ªÛ¥{cýPQQáAU–!n—BIÉ#VLQ‚fÙƒ!ž$~»Û¥{býàÍ^bý¨¬(JÎâÍÙG¥'³ÄTeoêŸ7+¥¢(ŠxÓYÒ/Ê™%/N@i~ÃX\\Ô®QE$ÂÆ¹Ë)–ñ:Ö'³ÄSe.S¡‹R(Љh})r ¯-SqàÀ·K(öÄùÍkÝÅÚS%ÇñÚÌ`5Ë'ž*{톗CÛ(Š¢8€×̲×Ê⩲׾àê˜EQr¯-S¡ªœqòâ”òT,‘ ¥(&ú]97)**ÚÜÜt»¿Dã‡dœ=ñöN§±¬cïv)EQ\Æ;óƒu­ l@•½Óiìµ~Eqûn—Bqï˜eo†µð; TÙ;2ýz¡(ŠòR¦šål—°­í‘o?DQEðH,ë“ ö$Lá‘®c•dEQ¡¬¬Ìí"|?D%9$Ve/ôQx¡ *Š¢x/˜eý¨œ%«²"|y¡ *Š¢x/˜D/HC Iü]9äo³³³Þv¨(Aç+ç,»»»ùùùî–AÇúd [ªìzoEIù¼§ù”8XÍòòòòÒÒ’l[Íryy¹«KͲëdR•Eqƒ­(Á#‰Ñ^Š¢(Š¢dUeEQEñ ªÊŠ¢(ŠâT•EQÅ+¨*+Š¢(ŠWÐ1ØŠ¢(ŠâÔWVEQ¯ ª¬(Š¢(^AUYQEQ¼‚ª²¢(Š¢xUeEQEñ ªÊŠâWò Ü.…¢(™DUYQEQ¼‚ª²¢(Š¢xUeEQEñ ªÊŠ¢(ŠâT•EQÅ+ìu»Š¢¤Hww·ÛEP%Ãèꊢ(Šâ´[QEQ¼‚ª²¢(Š¢xý®œ€ÕÕÕ·K‘EEE'Nœp»Š¢(JbT•ÿÝÝÝÉÉÉþþþ­­-¶8àv‰2ÉöövAA---ªÓŠ¢(DUùßÄxee¹9sæŒÛ…Ê›››£££UUUl·µµ©<ûšžžó_EQ‚A®Áîè設­ííí °G"òÌU×ÕÕ ¬c G¥)rüV”€‘»£½JJJÖÖÖ666ÆÆÆrJ’¹½½k§ERZZªþ–¢(ŠÈE_yww·¡¡YRÑd||¼££cff&×Z'¾F}eE 9ç+onn–——_¼xqhhH%Ù„‚$WTTLNNº]EQ”Ü%·F{­®®"<ׯ_ç_·Ëâ9ð’766h²loo766º]EQ”\$‡TIFr–––´“6àþp—VVVôK³¢(ŠóäŠ*KǵJrBLa.--UÙãèeE 9ñ]yww·ªªjhhH%ÙóÔÔT[[ÛêêªÛeQEÉ-rb v}}ý‰'Pe· â'.\¸°¶¶¦câEQ#øª<99ÙÒÒ²±±ùj½²²¶±µµÕfæ’CiiéÄÄ„ý"mnn Œ'u.çihhàß±±1· ¢ ¢·´´2fâ¹]%ÔÖÖ455©4øß•‘äX^2‚º¼¼¶3ª~Ç"jñÁ­¬¬Lá\Î322RXXHB£r*é@ÇnR‘›››CÆL<· ¥œœ©©)ŒÞQŒUÀU™&yIII]]]œ4±ÁOâAFª²tÖI͸~ýº2??‘’CÈå¶"i†††ä,¤”s!™ì!Ÿl˜#ËÈ}%µ0¡*‹Š³GÔ]KÅå2ÙVia¸ý0•(xV•©WÔ³©(ƒÑû]Š ò|åÉÉI;‰‘ÉE mmmæOÈreªòÒÒ’ŒÅâ ù"“Qó\XXî5 (ƒ$£<œK¶OX‘ñ/---•••Ô'Ršýêååå"ó»»»¨õèè¨ìÇ‹•˜Þvz9ýæPYÉ’­„Øä×™™™¨RNœ»¬Ø§©©‰·&þxEÉb<}:Ô?°ß•Q‘ââb;ãñ§°ï»qX__ýjÏv$æÇæÂÂBëÄ/ÎQø»8²W®\AÑKKKÍáÙ(¢uÀêææ¦”!N› *Ò’ ͬ9ǹ(YƒY†T(J|¨¢4@©ÏnDÉipBªªªü8Ú?°¾2FÁæŒH…ÁÁÁ8‰ÛÛÛùwyyÕß5ˆL#>hèAKMüæá:ÇÉ™d¸é[[[¨fȺ%õ‰â±_ʆ:–””È~NÝÕÕÅ¿$ÀÍ5ÓÓÓ!cXYXþVÑ•h%Xs©ŽJssóÔÔ”íÁ­0ûƒ÷/*S%ì5°ßd¤êæååYG\²gÁïCjW8sæ îÝåÀª²}PµËd$s,Ð3ù0ÌóÎÏÏÕ¯K3 «477G2™Œ$ÇŸR]]]TTDžˆ%Ç¢—ˆ®Â~ LMšÑ2žykÒó«ôºK‡aGG†,þàp3kÎq\yÎ?ÃL!“¹!2º‹ÉÞEux­„H»ºV¼†®¿¿ßíR$M`{°i"% J…˜EÆñYFò“)]bûä§¥¥%ÃíáfÙ¢¬¬LF#+!{U…–Gd/BØ´1ßEŽT&O]T–n;/]䔄øÈ|ë©¥,S 2Ú£¤¤YÉEYÚÙÙ¡-ks† ÉÈêÚµk±&#؇ò‹ý±ÿÖ„ÌžH®BÊ/ý(égè0´«2;›ÎX_yssÓ㑳üV·£¸¸8ƒynoo?÷ÜsQ5ŸLöËËËmmm+Æ›•ÕÛþÃþ°¤¤$#å4 q“p‰ù‚200À#àñ’ÏŸ?ϱ“““üÄ6Î(ÞÏëO¶Öv ®¶äÀQÒAUXX(ãHð8[ZZØ#AQ$s9VÎ2fXp,ÎYX¼üon8-ŒÝÝ]Žíèè#æ!”J oî”P?Ò}e,7š?GFF$RPØO!c¬ Û”ÇÜCVÜi Jòõõu¹(ó‰\$¡„$MèÁÐ~âJ åÂ%æÜ"™fÉOì¤æp¥a—µðÒqhýɺÍ–ûvä¤ì1§´Ø„BJ¿fFê¤3V•¥ëØíR ÞŠŒ‡Ë‰Õ1Î;k¦–ÇÙ4ðøEeï¶cÖÓ¯$Ò‡É+,±ðø×*$‘Ô××#6È$Z‚ ¾|ùòôô4%A-ØÆ £…gÏžÅäûûû‘ì>U:2gdƒ(b€¡4øßdÂùs¶*l='ÅÖùË_&œu9…uö„@ÊÊÊJ F[á?øÙ¥L98Ë¥K—®^½*;ùõÊ•+ìät¤9áOŠJ«««¹"$4)¬?™Ïúd¥AÀ¿‚É—8 z0j5d´EäÒäî‘ggg'7$½”œl)!ζÜR¹ 2L‡›ð£ýèÙgŸå,÷-=öäFŠÄ=äbIÿÌ3ÏTUUq‹¬?Y·É–|äÑpuÜ1JÈÅÊmçpn»ôjدùùùiVH§qÛYÏÚƒY²TUxÁ¢N]ðcç›IÔîkO]f1K·=#=Øa?ÅÏ0ô 9‘Ø!cÝó×ûF5ÃâóP$ª]Çš³ÙáÌ¿³³³÷ðd¡KÈÈžû–®fÙ…Nò°S˜"xì ë`GyÖ« =‡Kà#9){ÎP9B%Ýû$0 »f!¹¥œˆ¾¾>2gƒ¦ƒ5â¡2SJQiQ¶¨%47¸@óWr&[Ä2oX /¤ðLÉ,¼„gm¹oüIï?ˆž$wÒzvûµË§c°7á•à Å ŸÂµpE\W¶ƒ‡Ë¬¶ëŸÛŽƒ•þÀ@üι¹9\4YM ‰YRRu⢸§–©a­¢ .àÌÙï<³Î”£b+ü‹[‰/5™8šxŸÖó_|12¥KÀ­BD¥–³È\Q)ó§øó#¤Hœ]âÐvyþùçÍ_`òáÞR‘¸½á…^ ÙºAØ•Z1c#Jè~D’ÍïòÈ,<˜…—P¬Ù®Ü¦HiY!·uPU¦¹|).·]_ÉT‘ÈHS˜ûûû«««eyoÊÖÕÕ2>4"QgTKgò¹sçš››#u»?33C©Ø@~ž]>Ü¢RHEü¹ &\¯|z .Ÿä»µ ²G³£ÁÀü–ƒÈÅÒ(áÔ2»ÌüÜKÎìá'ŽâJe†…ù“™-µî¹çž3׊5©««ã-¾t馥¥ÅÜω8£Üò§1D’555QBþ4KHä,“3àTÜ®ááa ¶µµ%;©Wñ ÏÓ”¯Úùùù’ÌúÈôœŽvCäWaNggn=i²½`VpÛYÏ>‚èMRè–L‘±€=»,]T_á –i±ö|&d``€ó^¿~ݺ“*wíÚ5k÷,¶¨¤åM礒˜aù%7.Ÿpæ8‘¬@cn˜ù›ʹ̳³ß<¯¹mÝ0OÁ!lHÎf†òE#òÂwvv8‹tƒ›¹…ZÒ˜²Á%H‡yØO&$2È-57HÏO‘éIlæyvÉM~e[.й@ë#ãȧYxþŒ,¼u[î[œG ì·3TþÌ™3aÃò}AÞ}¯.—&´òhÙùqa`4NiK&\ƒÒ1ð]¸Ÿ çg@ÖËøEe|%ÇŒ”§§¤¤ïʇـwÙ Õ§8~ù•+Wü(íÁ¦áïÓ«ž*<õ;þ ØŒ}Úü½|ùr"‘à×fiiicccרnÞ¼IH.jøœsà¿OŠÜçõ™™™ ²011ÑÞÞq9ZXD‡„ƒ}ûö544¨ ú‘YãÚqš?½D¾³ªs°ˆ‰¨(k¬­­©mNÊÐUUUaÏÀÀ}ÄN †& žBÃþÅÐJ‘ÂË¯Øø%æT“EÁ044Äwç7jAÊ4œ¦¦&¿‡òPKO«q 4."ÌàÅ ¢ !‹´pOÂ":ôöö>|˜†Ñßßïy´½½m®i6}}}Ic¸uë–¹îêêÚÚÚJ•Ö‰'Ξ=KZIßuuu¼Ž>~äÈÂð÷ôéÓôJä(êBµ°ˆTþÅÅEÚ­U„JÓ ÐdhMÓÒvi™åps>d“E¾ë‚5 ‹´‹wttfô¶-õÂ"&°£ÜEƒŠŠ Y½¬˜Úž…f»-Åyyy<·‚çúúzoooÔ%daQjhiiihhÀìÎ÷àóæææüü¼f¸-â;Ê]4XXXÀn†ž«««×ÖÖRM`vvvpp0ç‚Ñ}ÌÌ̤«1XXX„F­ä¶Çv”ÛÂÂÂÂÂ"ް6´…E‰`ssseeÅzv³°(X†¶°( 9rÄn^·°(X†¶°°°°°ˆ#,C[XXXXXÄ–¡-,,,,,âËÐq„õXb‘ ®\¹"¤ÛÛÛlnn®¯¯·›)-,,,r»Ú"m´¶¶šÓ{Ü8|øpKK‹ÿ(‹Â`ssscc£²²ÒsÆ‘…E0P¸å”[ ·­Bñeh‹ôÐÖÖfŽÜH HúÕW_5WWWWVVtÚ&vvOOOoo¯5¸-, À177·µµ¥V©&™*ü!§OŸ®««3dY–¡-‚öL[ hÒá!ž¶'mXXä4ÒééiÔbÈ8˜†Ã¶>sæ „í>3×"ß° mñÿA3^^^–¢¸sLlMMŒÝÅÅÅcÇŽÑÚs˜"m~ff&ç'yXX”'hžýýý.\Èm;õ€¡¥¥…„¬U]X†.kÀʽ½½°òêêjT2ÐÚGFFì¼—…EÆ( 7{€nÝÓÓ“ïC·Ê–¡ËpssssN†¿²ZùÄÄD§uYXXDÛ–Ñ­QÚÛÛ£.†Ò„Ý]Ž@Ñnhhˆ =KžS§N-//G-Hqcxx¸®®®'ZÄ}}}555¶åÍÍÍŽŽÚo!Í÷òeèr:o O@zùå—£¡¸±±±±ººÊoÔ‚X4a¸ùüùóQ ò-¦§§+**¬’sX†¶ˆ £Á¢80::Z]]Ÿa°„3vôèQìé¨))X†¶ˆN:CãÞÂ"Vhkkƒã9ªŒêí¨{‰Á2´EŒ0==]YYÙÚÚjyÚÂÂXþ v9 çºº:¨:jAJ–¡Ë—.]ŠZ„ LNNЧãi%XXD˜/n#Û©@˵ËÇrËÐepLÕ¨¥Øð´]{’PkjkkùZ‹Üƒ†€aZ\cKvùXö°û¡Ë ´™¢³M×ÖÖ¬÷"‹rZu[[[ÔRdŽööö¡¡!ëŠ?X†.#tttãä {kkË6o‹òD‘6[Μ9£ój-Ò‚å. hI‘¶sy4ŒZ ‹Bƒšé\¤ÍÖƒññq;-¬ ]úÐÒÊ"j### Çt0wjkkÍ‘å€%>|˜†lÇÃÂÃÚÐ%TW¬ç"¢ç±±±ö;ˆZ ‹hPD˶ÓÍWkkkÔR,C—2Šnɺƒ¶gi¤…ÍÍM ”âZîkᇬçRýŽÓÓÓö`øð°£Ü%‹¢£gÿŠ03Ð×ÕÕ500µ€qßùóçÏ;ÐÒïË}7\~íÚµªª*n677“¦^&«¨>õw.ØyèÒÄÛo¿µ¿´­©©©TMºÅÅÅÖÖÖºº:²\çzàW3>ïktt”שSSSKKKØ+!»~¸y``ž–T˜tE´Ì0{lnnÆ¥ê·Ô±žË¤´Éi©N´ç–¡KE=‚TtÛÃÒÅäädccceeåàà +=õÚÚÚŠ [[[üBPluu5,~ä“r;uêÔÎëDž±rCBª„3[[rà ÚÓµ‹Âo®044µÅ€¨x‹¼àæÍ›Åî)ùKo”‹Êù…KF0/òz@0rŒð9”Òâ[øgJ—/_.X '-Oê Q7»ÂŠõ×.Xº4±oß>Œ°¢nð%fI“£Gž?~fffbb"-ýIÉëëëØXD’tx‚zë­·àQ‚åv&•žTÆtqm¬/F”Õ!Tã’_—D­"Xä@E=â “¥enÆcccä7û¨(ÚÚZ÷r0VößÌy.ªªªJ{Õ^´6tÔ­­ÐèêêŠúƒÇv?tY@ǵæãàwØâ´ÿ£ÕÕÕÅÅÅÙÙY.²I¢ØOÎíïï§r8ï ­tæ(Ïßü*Ô××WÂŽÉÚ‘#G “ ]WWç¾³gÏž¨   8tèP´ÿE€¨U‹Â!‡+¢Â'å—)uáeˆ3gδ´´äcB]þ×Ü…ÁÈÈH o•‰Ð†.O®*½µ&¹…‡.#ôööf–Ó¹sçèJ´Ñ6ü‹ôérÏÀüZ^^.FOXœ‹‹‹SSSù°8e1766’D!ÏõkooçÓ?œø£<ZK,R"jÁ¢p0.¯3C®¦„µ68‚W2Ç ”•¼æ5•ð®Hr‹––’.|ºùF„6t!“ŽJ²åÖ†.Œ;Èøu,'('$³~ýõ×·nݺ}ûvÒ§‡ZYYÉ€¤;::Še-ñææf]]]æk3“È###Åò9ŠY.׈ Y®®°§ÊÃ2tYàÊ•+Ù K޹Ýe ôΟþyÒð÷Þ{ïÕ«Wß}÷ÝÿóþÏûï¿ÿñÇ{ºrmK·mC{ýýýÑ”`š@™*ö-é@Í:{öl±|Ž¢@ü¹Šî©Òt (îž3èÐæ·¶¶Bnù󬕳ð"j#Þ¢Ȇ*ü{„¶··oܸñÍ7ߤ›þåÝxçw¸é~+3·*ñßí³´´TÞø|Z‹µ ¹D„£Ü¹Ú¹ÏAÒûÁ{"hŒˆ”*€VkÊ+ŽûŽç¦é.Bž^åßrfᆵ¡KËËË{ ½™Ù믿þk˜¨î¿ÿþ‡~8xgÈ#<â¹Ãëׯ_‡§‰dÇÙã§£«Ò¤Å<ª$C⥗^*†|¸ÞÞÞÎÎΨ)äʆ&tDÏMZW° ]âØÜÜô4×:Œáû‹_üâêÕ«_~ù%7«««¡Þ1<ú裩ÁÍ7nÜÀ¿}û6í|aa!-ÙNœ8Q¸L£££Y®™/":tˆ~9³ f‘1(sþóÛʯ½öZÂ9êÛÜñ¬ùHª^¡{.9é¸Heeeâδ1qSûÖ­[4dîÌÌÌx^9~üxpFjkk£.˸Ã2t‰#³õÛp ê0ôIÛ3ËÁîw>ú‚àðÐÿ»ï¾ûñÇÓA¤µ£7cµ£ ÀËjà·««kpp0j)Ê o¼ñFÒû(LXÞÚÚÒÿ’L¿}L3^-$U1ÝþŽ gcûʀƦÏÀ!’]&¶+,C—82˜E›†/¡ç÷Þ{oÇå6—„aíõë×?øà:ÿrñÄ“u¦E /áöK.ãC¬-ܨ¨¨Lãºöl‘ð[±avLø7¦OŠ……,x󷦦æâÅ‹II}W¶6ô®° ]ÊÈàô§|xè938p ̨øöö6$M³?>LÖb8]>CÜÔ™¤ÇmY¤…]Ç„…³gÏškw ây¦¥åŸÕƒû&긛n 4Znà&lyóõ›šš2Ërsss΋±Ä`º”‘Á7öо}ûàËìéYxøá‡ÃI»—ŽïŠ—^z)wE•lmmyÔ”ìù9AÈ!_÷èÑìì¬.h5žy"ÍU'Á¹|Ûv€uuue–©` ¾ Kº¸/j,òˆt‡¸iº´¨¯¿þú³Ï>ó?ýꫯ2á±Ç»~ýz˜tÂY@Ž–Æô¡ =77ç1>ʧOŸžœœ,É9EZÄÉ“'³_™Où\¸p!Ø[˜!_š§›8¥‚û鯪ªJ‰¾ýýýK©‰V+ °³3.à¥Ú%Ygr ËÐ%‹ †¸µåñÚµk©ÐŤ»;bÏž=HJù~ˆ¤WVVª««Ã œ’ÁXMú–§ ]QQ1??ÏWÛ¿¬>G–€žÚÚÚZ[[³Œ †[__§Vt˜Án'nWøé9q÷H¸fÙvðx•jr€2ãçÏŸOúÈî³ ËÐ%‹t‡¸é[n:Hkøé§ŸNW´þ pHú¡‡ÂŒF¿ÞÕísH¿ECyNǨ&˜esss\P|ñŽŽ ‡ž0ScccN†j`)ô˜žžžTt•ÇXî=Q0hWW×ÀÀ@ºÂÌè]¿Ž–‚gC¥ÍÍÍ©²\JÊ\þ`ç¡KéúLÖüV€ >ÿüó æ§ï¿ÿþ0NN >øàúŽt7IÇEMHƒ¼ÏŸŒ}cc“šûMMM•••Ü/Ò6 ΤŒŒŒì:V<Ðí9%…Ê–= aæ•i³è(Yòh€wn»L, ,C—&®\¹’®='Kè믿#`ÈSUU•Ö^jHº¦¦f×MÒò¢`7@p€Ü«%œñÛØî_ôòø‡0@Í&†Œ—kù¡Ñ²à0Xüž#12*Eª2,Ãù  °'WKv-b…ÁÁÁîîîðái±ÿóþÏwÞyg×ú°gÏžüàˆD̘à7nÜ{²0øþ÷¿ÿwÿîß ð+·ÚÛÚÚzÚAÔ‚Ä ØÐmmmhÙÛdùZÅ‘#Gt µLMM¥µM?ˆªÎ{8áòåËž¥R´ÙTî_tÖxÔÅ“ PÎ’Näû³oᇵ¡Kéš,¯¿þúG}†ð2&E-{æ™g~è»ê‘G Þ-ýþûï§rŸ”ˆåJ“ÚÚÚøŸ!XxhµhjjÊæòZ«·ª««³‰g{{»··—¨ví0+c®Ù…5éìOZ3_e kC'úþØØX܆暛›;;;ôմü¡àÿ¯ÿõ¿ÖÖÖ¦yê©§r˜©Û·ocXÓ‹%`‡Å‡‡‡“.6‰!...vttÄMªøŠÂl’OÙ¨eI· oøHêOcccÒÀE½é<騀¥ž0° íÅæææ‰'b¸×Ö ½½Ýí7)Òb襥¥'Ÿ|2érkâÑü±ÎªzðÁóg¹Þ¼yóúõëÆ ¸àûßÿ~EE…ßþˆ!CK`Û¦‚ÑÖÖ–p6¾G-HDËÐÁ©£C©%BæQ²‹Zá($ì(÷]ŽgzN8§'¥R´í*‰Ó§O?ÿüó^|àžy晚ššüàÏ9à/æl^–÷ïßÿ½ï}Ý­^|{†ù=÷ôôô$•<ÂdÔ;§µ ±†¸Y€ðèn¯àß|óMR¿sssñ,t°¸¸ˆ¨výË®¡”ÊÓyRÐØiÎÁ.†‚{z º*¡qšpú«†††¦¦¦hÑ¿‹Ì¶‘° ý¨âIç;©ÜSSSÚØSÈ唨”$·ººŠµáãíîîØ ò0è›Ï= ù.ˆûï¿«ýêÕ«š™þì³Ï’¶ç˜Œ’Ñ«¶¶¶VUU é dá±oß>ˆ„ÏJßÃMÅ Ú2Z EA]Je+»©×€žð4yšs{{û?ü‡ÿÐ= gÂî´k©¤•“Á03V”/9{ªUHX†þI—Jõôôôööž8q"’#ötRúÖÖÈ „Äàƒ3 C+røÏ,Ñ:èÀ’„(œk×®ÕÔÔä–„3Ö0ÅK£Eå' „‡¤IKúöíÛ_|ñEÂYËê±0Òõišttt\ºté7Þ°4“.ø  /½ôÒÒÒRÔ²DqŒÝo¾ùfbbâüƒð'ò'aÞ¢ Pñh5åÃ?LGñë_ÿšHÎzˆ{ï½÷øgÿìŸýÁüÁ}÷ݧ¶6:: ÓÊ^}õմΤ’Ù“]ßï·|É%îL?Iiˆº\‹–¡¿ƒå6µŸ.ë9*§H¤‹ýýý´ ¿´·TƒE4ZÚ|pä(4¡÷ß_ý‹´irP8m’ÖH„ y£(м»ºº²ÔÄÉ ù"r´~ú¦sçÎmooc%œ:uJñÓΫ««!i:} ?%›N!’OÓØØxòäÉœì—-OH­É­câÌú«_ýŠ‹?ú£?ºçž{þÓúO»¾‚–³±±A3äÅ›7oîsà ókT×Ô¿úWÿêÿð¯^½š–lÚuö£ýèå—_þ«õ¯’–Z¥{÷îEøÅ/~uY–v,î’p— uÚ“¾:ô›—/_N•—]ÝË!ÿÒÁ;ï¼Cá) È_sÍ…°“> YÔ¯?ù%u²ŒY€xþ¯³k äHˆüSSS‘¤^J $ùÐQKñ¨QkÔîÚ›pfжï€kÿ`:k–¹»}ûö|ƒþò—¿üä“OøòÅ7n|ôÑG¿px¸ƒ¨Ÿ}öñxz]K•æñ—.صÜ)IÐ}Äd]÷ôô4úoøf ߤ¹#€qïõÄO˜¹+Ùë g¢·¯¯Ïb d6 ŒŒ>þæ›oR¶I#WüßÌÌL]]Þéâ³r[C‹”Rö>-øÖMMMqs<9¾úê+ÿ¬sȹ[Ìeʳï6775Ç5¦3-3—®Ÿ¶O†zwu¶—ñÅͼHc¤sxúé§Ÿ|òI.8ð¿ñܹ½ÓúâNv”;%’.͈ PZÒ‘ÞT8{öl*‚‰;>~ÍhZš.º»»ßzë­•••0çÞd°”š˜a÷0ÜfF/è 4µæGáýrÓß¡7,,,ØEa¹U±­­->XTðø×{öÙgÍAή;,Rùr ¢âóôüùó:oãG?ú‘–w|é€~ •"žjyìÞ½{{ì1T‡÷ïþÝÖÖVÂY­Åbršf¾ Óy~~¾HOR‰Qñ1‚gõòå˱ZpxÎG€ìÛ¸ óî»ïþå_þ%¿æ­ÌF­ ÿ@Yöƒ~½add$êÂ(5hF)j)¾E„£Ü_ýõ¶ 0¨§ ·wXޤ~ª£0J°š ÷)d4Ë3gÎ`£îC½¿üå/ͨuªoŠÄ#Z÷ —çê€kSªt/CCC¼hG¹CÂŽr—,h®©4 ÏØ²1 ùwvñv5ÏùöÈYx§T:›¨½½½Àé–< ÏV…rõÙ³ùâ›o¾Ñª1ˆw—––4¸=55¥½æXá+wÐÐÐ0æ-sÿþýî†ß}IÆSÍÊð{î¹ç¯ü•¿2>>λëëëê%Ô$>L£ž˜˜öBCH^„žíïð° ]ÊHµÒÛ3B[°#(ÐÇÓ:ƒ2@HÚyOθuëVggç®Kð,2@WWWÀŒL9€&ùñÇ»ïˆÝÃfjÎ;©çŒ=[%aSŒWjlee¥{éúPoo/=ôæSbaôizqq ¡ªª ²Gû'9¸vvv––È}˜;Xyµë62€‡.e„¥ß»wo„¡úòË/ƒ³ €Ç€, ³ýýýt1…™~–æò9žk,&K2£…ß©;þC;”Ýùé§Ÿ>øàƒá¬Ž¼ôß—“Ü“O>°ÈëöíÛº@±vÓ¿qmë¦dä Þ`m—dkC—<¼²ººê&¼c”`ÝÝÝjçÓÓÓt¦ÜI×Eðöööõë×yäýÕ¹~t üÒÔëS9ZqÏÉÑ[~¡Ö… ’ºi¹^ƒhïðAíê¡ÄÝÞ`¶êBU–‚EûÅ_äÖ­aðlÃпñ¿‘}Z1Ù¹Z\° ]ú@u][[ƒáܾ5dƒ8p •Q S¶¶¶VVV®:€䨋;§Nêèèß«Š_Qÿyå¨-Jç—hI‹ø¯]»F̤xìØ±à˜ ïÌyqq¢ð] å€ï›’ÇÇÇ{{{¹o´÷Ó+wH—kó©û¯Œ!ÂhÝ´Y’vO†ºººnܸÁ…Ö`çZ‘”t»„¼ >ðÀON 4jäáîñ‡eèR†vjp 3¥½½]›¬ÎúuÜIzxx¸ººKWûž 3]ºt)á$qŽŽŽ†d¬/¿üRM&ªÕ%çÎ3-öĉLKKËÖÖÖÄÄ1CÁ§»~¸ŒâŠäŒT«#GŽPh0(Ý =·µµñ¸?44ÄîWTTPbv¯C/áÚ3Ùlžb^{†Ü³6´gó¤E*X†.qøÏªrõßþÛ ÞÂCôôôx…sk‚ÎÝì i¢å7ï:Â$êL|«544Ĺœó lYÿ·ûÆ?ðŽã³3©Õ+6äzûöm™Ë á>o8pÀ³û™·““å`»B;µ",)X†.eÀdþE¿nסÓ½ô˜šËt/¡‘‡^î?ôÐC!5ëð;¬4wãÆ¯¿þººº:i˜X9z‹ÍÍÍ.\H8ŸãܹsçÏŸÇüJ8Öp˜“ûúúßØØˆi>>>~ñâE´4"‘…íž/,$"<¦,ð®šp¦¢µšÚ?ñ¼µµ•”¡i­þôÓOÝÔ®}ϰ²x^Ñ2±¤sÛÚý•[òžœœ´Û®ÂÃ2tÙKÅ –°íߊ-üÑGMwìÁ4Gt¸A§@¿ì²ûꫯÎ ó'Ÿ|ÒZ‚E>çb@áûÊ™O#ýÉ\TVV*|ÄÅÅEþž={=ŒëÙÙÙžžžî¨ø«‰ Å™plnˆnæ^'€üAŽŽŽúý- ì*î„3mtýúu}kñ+̪5~‡_HeFøñÇŸ®”Ùë¾§Iævojjª0EZ° ]v8~üx˜`hÍôݘà4`Ú-vðÁƒ3ö7’¸Ã¾nЕ<õÔS˜ËÚFB„Ñ* ×'=·ôàžø7g¨ÜKê<Ëë<ÝŸù뎳Þ;Xƒƒ¨ò»¼¼aê1_d~~þw÷wµñ_ØÚœmãG*3:]ÙÏÐào¶Ùœ.¥Lüðäv·U‰ãСC á›d‰¹Œ†JÎE6ô,$µ¤‰öqt7I'À.ÀD²0¹Åàà ùÔIVF…85m¬¿þ%™ÑÙ§k6Xÿ$f¥w®òØßßï9oÃ"–¡K0´½´{ÂOgÚäUÓé!#‰¤×N˜Â§[>Àv´N›u|Jª¦Š!`÷pÒ5Ÿ~úi–ö53Öþ©èûî»/·«¸ÇÇÇ ï¯·¨aºÄ‘Ôþs34íóúõëy•Áø^øüóϳŒ*’•çI×ÙZä òÈù>«ÈA TWW/..šö‚öLÅÓ wR¦”בŒSÔªLó7é6­º!kd°œ×fËÐ%ŒN†ÿ¦.4ŠõÉ'Ÿ¨ÈLç’½½I?N¢×®]³$'¼üòËväSxýõ×) ú Õp+7Õò‹Ï>û,3c¼å¦gíÎðã~®:‡W^y%>ží‹–¡K555þ“wÍT´Ö¼zõjþd¸ÿþûzžÊ_[[Ò‹YÎQ__Ï¥„ÍÍ͵µ5†h¡årããã3| +s±«Ol4ìtÒ6 ©Ë¨ص>úhRš›û/sCÚ®6H–¡KSòØÚuã¶G±n=ÇÓæ´]¤:º*æèêêòûó²ÈCCCå°>?$fffŽ?žÔþóÖôÁìzð°œlg°Âó™gž©¨¨Ø³gÏG}”q^¢ZSM¿‰BcÍèÓ°¾¾ë0jAb¸vmmm~~¾¹¹ž¾xñâáÇÿïÿý¿Áoݸq#ü„4\þÈ#†žÎùu===v¤$X†.}tvvê\BךôÜ H: îìì|üñÇ÷Þ{¯ßÃQÀÍO>ùä~ð¨:¯#êy‚N…ŠZŠÒAcccŽÊˆ-P £rŒiT™]Û¦jH’†žepýõ×þmйEGGGUU•Žb³H–¡K4ríâpß p¿üᇢÂöÙgÆ·æœúÎ;ïìÝ»7ûI)¨ú±Ç‹ºTÒ…ÖÔÔd;šœ ­­­¶¶¶½½=jAŠÓ“““».Ó‰¢á-éíímZú»0Á=û,èhõ¿üå/³9wuyyy~~ÞNdd ;„X3Ž0ñöôô¼òÊ+ !ÃÃÊ´LÏͧžzJ³Ô4ì0ÓÕHºj4þ«©©]¬å— 4£og%ÃZõÂлº÷I£M†è2¾Œ0£ah3èM$ï½÷žlëÇd,¹\”ØñíŒamè”@i éº0H5§OŸF™ÍfG¯¡gšœÑ1îj_ÞrPÈBË-èh0È~Qç"ZXzÎòÝR¯ oICüO?ý4ª?üÜsÏ™ø¿úê+虿¿ù›¿ùøãg£OOOOǪ-:X†N‰¹¹¹XíÞ«««óŸO---ì¦ghXN Üîîî>þ|eeeÒ}ÃPZGGG…ƒ¢^„õL1666F-HñÚ %P€–ž3@mmí®‹Å DÒîSãRAçÈyhM´ººš/µë¸z0hõ|t{NF6° ‹‹‹Ô°˜¸ >wîÔ˜é¯\¸p!ƒhÀ¢gˆ–¥XücV]]]H(M_Gû±½½}ñâÅõõõæææÌ²@ q˜whoo?yò$dc-éð廣œÙ‰üÌ ©èð{( éO>ùä³Ï> ãTkMÜKÆhãÙ¯ £Ç°§¹g ËÐßÁßû·¶¶NLL$]ó\Hœ9s¦­­M§#g 4âžžrdî„qrï½÷ªXŒá822’Ê­.=¤‡¿Òà)I³6Õ;¼¯.ú÷˜Œ˜õ9À8°$ Ê^¡ ÐÌÖÖÖìü}Æ íÌÍÍ¥;¡ CôÑG»®î¤™_½zõÝwßýùð±²—™«aÈb„eèïàïýáhiaa1‘hcccX¨IOÏMwø¨·· ¸»»ž®®®Öò“àWžxâ ] ÑØü[¨=8ä -©&$Ï,'îrŠ’¦ í&i?øR+++|Yʇ l)k:g‰¦¦&Š1ƒú/ס»3‡h ûd)3MÃ2t–ؓ I×DPÅ/^¼XYYf^'‡ …"µ<©õœ™“j(y~~žwé:‡‡‡±lP™S…öÙgÉ>®V’çcM&}÷¥K—’ZÞðuâV])xèÚµko¼ñFäc-‘CNH´Ô¿¹¹µ²è:hÚÔ‘#G “ÖåË—ÓR²é‚þüÏÿüÀi¥‚Æf:ù3O?ý4ÍüÃ?üþ÷¿Ÿ“}•qk°E»Ûê.`+ûé~Ǭ *ä´ |€q™Ù²/š«é4?®Aopª9'ißt[Øñ»Òóàà 6:š>’÷ôô@½kkksssˆŠB@ºgÏžõGB°S§NuttŒŒŒDŽ 1œÓ";èdY%ÙÙÙ‰m]¶çëMOOC9vókž@ÕúéOú÷þÞß O{aÞöîÝ«3éâÙÓs<lÑÁê8^À%Ù,™. h«Ù/ˆÅž¦?ÝØØxï½÷¾úꫤa~øÃ†‰ Š:qâÄ®cæðÌÝÛÛëáiÙ^°{À6k “Æy°”ì %œ•óXôPeµµ»»»ººe.jA2GœmhÈ+¯¼ò_þË ï“„å¾N…Ï?ÿÜ„t_g šêööv€g$‹0° íl%4::µ )­™+gLhÊëëë{öì¹~ýzÒ»24´„ù›ÖÉŒ©x:•••ôPŲԈŽ^ƒ/^,’F»-–o”qfhM6}üñÇ»:Ï7xê©§¢òDÖè©’. ±ËÐÉ¡Sw¢:8š››és8ˆÚØØˆÅsòäÉTçCÿæoþfÀ(jrÆ+ÌÓâi¸¹­­-'ëK ‰°)ÓB Ì;Æ™¡ŽôÓŸþ4¤»wïÞǼ0yñ ¯+WÊ v:9;(ºu.éâõ×_?qâDKK˽÷Þ+/Üܼy3)C£Á .h:@ë·ù ?~|×N‡Npuu•ß·ß~›f¼±±±«Ñ—_~9cw+‚|eãÓ¸¸€e ¦|ƒ¦úïÿý¿Gµ 3ÐýÐC¥zôÉ'Ÿüìg?“ÊKÃÇÔ®­­­¬¬ä/7i›_|ñÅøÃßú­ßâQrÒZÕÒsö(z×"K=z;ïÃ?ô?…¹QÛý÷———§§§Ñ`²•áà0“““˜ÚEg@']¤µµ5n#1y æ(v¥6æ64í=øÓO?…bƒCîÙ³ÇO®¼NËý‹¿ø !DצËÓÅ5'gXºÜ±°°@7A#|ì±ÇüÛÉЯ“ž“Q__sgy~&xSS-¹ªª*U˜[·nµµµ)ÉÑOÅÕaN@6××׋žãÔYZë¥K—0pCnþÄÚþùϾººÊoø%f|ðÁýÑaŽcOÿöoÿö£>ºë+Zòié9'° Ú87bÈÇÓ}ûöÍÎΔ4àk×®ùÇT°­xàÏX÷üüü‰'†††2^³6>>ÞÑÑAK ç„³ ˬH[;ý)¹+‡áßÞÞÞ³gÏF-EY€æðòË/ÿìg?ûè£F@Í£ûî»RGŸsÖ. º;.666Ð,ÍÈ–ûEôuÜ{ï½Á|~011FµùM†Ên5ˆ'._¾\°†LZ™ I£ûòË/¾Èm…,@õ 9ï ÊÖëç]¸uëV–GHò ‘Û8aýçŸþ_ÿët™(Ü3KŠ.Ÿp&¤Ñ¸=Š¥&!Â#<tÂ1ß±½c¦õAX §`ù^¥í¾»¹¹E¤lý´4Ÿ7Þx£»»{uuõÁ I³•Úä¾Éß?þØsN†„ÑA±„ÜuÂÛ zÙ5b¹‚])vN:•ÖÖÞ¡Ó®rgMMÍŸþéŸ8p i­øÞ÷¾çæom¨ps}ôÐÐPRGBr^ 1»µŸàÝñwQÚÒVªs´á¶b¾R,qÇ0íK}—Ö0»üðÃ{XÒMåüÀûï¿¿ºº:ü”ZÈf7Yå–¡¿C¬f؇Îùòf$MÇñÅ_øŸîÙ³ç¹çžs7W:¬ç|ÈOÔÐЀ—²+,(%Hº$»-þ[JY‹9Ck—£¶–ôÿþßÿûÓO?MÚßsÏ=O>ù¤ç&!××׿üòËà„hì|â‰'ÒrxÒÚÚŠ‚^Zu|`G¹¿CÁöóPZS¨Ìþ!Ä`¯Ý™TÆÆÆŽ;öØcùŸ"É»ï¾ëög„ŸÙ6e-O @7433“ÛÜEJéÌ™3ŸŸ;2ã ´’¡çømÏÐÒÒÒÒÛÛû;¿ó;<òHÒÀIm_÷™gžAöÙgŸ~úiZ:VøÞ½{ï»ï>~¹æ~ðƒÀîéú#›˜˜ž·²H–¡¿CÑ#˜•‚fßÔÔÔÕÕ•j8áƒ>øøãÍßžžžt=„£Э,ÇC¯w¯‚+8†††.\¸óõ ií°¡¡Oóe•%ÏyŽíííØ¬/½ôRÒ é¤>ˆ„{ï½½ >~üñÇáéçž{ŽïÈ/×Üyà2–Ъk¹…eèïP°™BØ=é²Lz(ER_"Ùcdddqqñ¿ÿ÷ÿžJƒ¾~ýúÕ«WMûÇ@ÔRð0‘£¬¯¯tëtý™ÎŸ(Ðma^@i[2†–ƒ½•§ÈQ5ª««øš…ÉŽ… _]î;(I´Öÿú_ÿ«ŸV3Øýl7X†þy"¼<’Ë“ºÚÝÝMçþòË/LVi­Š1¦é5–è@'¿`ØÍØåýpy°ØêƒJoa0™‚Òêêê @Òmmm—.]jllÌÇŒàøø8ÚjœÙ2WJÞ7œ[ÈËfZHÚêWVVh³ï½÷ž%éÒƒ])vèÚ´(þÈá Wèˆ_ˆ¤µµõܽÝâá‡ưþüóÏÍVûï¿ÿé§ŸN:$žÔY0H”n "/=†¨` Çî)@æ\ó™™™œ”§Ž}›ŸŸ§V”êJ8s½¨§[[[yM¥··7‡*ŽYÚý½ï}ïÆ¦W‡³SÍR[,Cßú êêê]Ï9ŽdùÛßbN(ÒFúú>ø@ž}öY©ð_ýõ_|A_ ;†~â‰'²_ ßÑÑQUUUÚkAÅ (Xù°Õü…988ØÕÕ•îqŸnÐ.úûûOiâÅôô4Íg}}}ïÞ½4LãôÉ'Ÿ¼ç;VZ´ˆÚeJì°±±óÙ5L缺ìq× gbOȹf±'ð7ß|ÃÍ_üâhñï¼óŽ?@Z%_&ÞˆÎ;§Íf9Œ“ÒÓR€¡¡!Ï#Š”<ÈoÅË[|—|×:‹ì¡…{úL_}õUBžÅ¢–Ë"sX¿Ü^:tó…t||}æÌ™B0.,,nSSÓSO=…%½¹¹yàÀw î²OËx#êsP°<䮦¦BÈÉTÅèèhww·Rø7‘«H;TWW S˜oP‘øÐóóóͨ„Ä2+áaí’†Íëêê4 `ëÏ>û “ÚŽu)ì(·…f”[à ”•gžyæ½÷Þã7~]ܾ/<”*Èrkk+Yž˜˜Èxk™\X EÍÌÌ`=Ÿ?~Wgs¼‚ªÕòIǽµ–î¾­­Ín¦*:èL÷R¾Û·oóM|ðA;Ü]|ˆÚˆ·ˆ._¾\[[ë¹966¦£¾úê««W¯æE˪Z.--ió÷ÂÂBø·(1xý°.tnNìvI*`%G]9ƒÖZ¶··»o~ã jÑ,ÒƒU©,îÂöö6™ç&Ê8ôÙÐÐðþûï?õÔS9ßÂÊOäïÅXOêÙ»T7CÒÐêàà %ߨØ899™jG…ÃSÂTWW/..ÎÎÎÒçdð Åô6T.9ñ5ë^å\!jÑ,Òƒ‡¶¸ túÇ÷߇¤!Ѧ¦¦¡¡¡®¤Ó -‘—öÄó®hq ¡„Uîíjº¦¬ø}ýõ×KÉášE>°oß¾©©)ô9-;(óöU¼° mq`˜8é#-?Æ€[^^ÎIƒ'’ááalA;Ùi@Q ¸ï\»v-¤[YYY[[› ‹RÅéÓ§Ñüúûû«««Ã;þ³ˆÊbIŽExÈ]Ið‘;mmm«««o¼ñFÆ ŽommUZžÅJ+++<ŠÕ*z ‹bÇææfgg'Ú^{{û /¼à€jn³¡]Ç|ÇiùÀÚÐicll Š}饗¶¶¶PÏÃσÒMŒóJMMMZ/ZXXdƒC‡ÉQàôôôäääÛo¿íçiÍ¡$2rGj‘'X†¶ÈZß$ÿˆèæ½½½(Ý©«1ˆ±¹µ¹–üµ›k-, }ûövµ aaÚâ. G£b‡Ú¢`ØÜܬ««ÃZ¥D-Ë·@cH„룷··íêÅÒÃðððÀÀÀÚÚZÔ‚XJy”¥µ¡¡!$=ïqîþ‹˜ãСC‹‹‹ÇŽƒª£–%1::ºººLϲ´¨Šû÷ïÇàŽZj‹\âìÙ³tJ2¦-,vE)ÛЧN:}útÈÁmúD~/_¾\;k-Ü@KkmmÖp¹råJss3*`ðà6Ž9R[[KxM¢#¶*1=z´««ËλY슒µ¡1>è sÞ0ÅàrzO“ЇÑçççƒcPÞ*¼y´«lá‘äU•ñŒgô9È8¶úúzjB„†‹†s°æÃÌ=cd“÷­­-3$~Áù˧1UT©‡‘W¬zZ,,,tvvÆa\Ç"æ(M†¦»ÌÇŠŒ¡¡!~{{{S¥;==¢Z`l’ƦŒD€Á'#ûQõ‰ýýý---a–mÑR+¡g},M]€` fuuõæÍ›î¼+g<% ¯ðbJc{{»©Ä|ÜH:jA,âŽÒdh:Ä®®®œ¯•¥+ÄRø'''M_¯þQCÍêžb©ß亻»A.ü=”"!Œ¢•gCöÖIHîæ!‘4wèñ_yåuè LlºÖfb$”ðne‚k=5Ñòׄ1<á~…â’17ï@¤" Ý2»/ ”‘·Þz+ËoGe@»Š¤OTf¥Û…‡>7¤¾ë7!:ð¸­5ÕŒ\ã˜ÏAͤœ¹0ß‘§IK†oâáÚ³PcÅ é¾PZæÚD2>>Ž6`âñk«î’fÇó¿¢|™ #°; îÑ…ÑÞÞN[°f´Å.Ø)9` Ðó›Ö[*Ë—/„™˜˜ Ç䢾¾ €‹sçÎq‡ß¦¦¦Ó§O󺊔› o…Î l(!‚ÕÖÖrÓÄLs%ñ~aa×gffø]pàþëi^'!IÂ}É@0(¡¡¡Á“Gn69 ¼Ì,^‘O+^¤ÜFFF°ö¸à>’£é›×¹†¤Mà³gϪ(TØîD¹C$zŠ*:âášTxÊ¢šr3*%9yP鹋+c ÆÚÚZN«Ûî8ç ­Wø42¸—––ÂdŠ"UЄ£‘˜2We#ªªª*îðHú+×z…§„1…oÀ_î•—ϪðÊ Z1¸¿—¹˜šš"-½ËM½« #·á<âC(®MŠÍÍÍîT I0¥E•SF¼ã´î+eÄ“#.xýâÅ‹ Cä´‚פ z{Z¨……%ÈÐÔ{qaz‚¡Ý£”RL ÆR æÛØØ@ º­­-:G9ßIÁÐôhܧÿâš·Ô…ÉK³ç¯;¤)Šh‰ÓÏvîh‰¤WVV¸¥yþºCš×ÛÚÚ¦§§ƒ“pCƒ~ÄL.ˆ™.,ÌÌ4ùZ__ç]÷’+êë—HˆŠŽÒ<•VqêÔ)úS:wl¡’®]»Æ»û÷ïOš"=)²ü”ntvvîºP ·Ð˜jZŽÃPΧæççëpMU¬®®ö¦ .P%¤qñòË/»Ÿò‰ß~ûm]ó ¨‡%ÄO™­j¸g¬ýåjF‰É ‡Ä0‹dÂÓ777aGdC~÷H5Õ*ÑÝÝmn-ÕÃóÑUñhbÈlbà&t»¸¸H»sWB?¤5š85~“ãÏœŠBÈ_…e>€£U ùªÇ0£¯éBƒof4RÃbî9KböŒGé¯ÌÌÌèEû---i˜âòÔ@ÊSs±T9Ô^¡ë7õ™›°²9G] ¦$€f¯‡†$¯3êaöCKHò󯯆ÛÑ×f%Kö2ç¯@´¢Ç,ðÉL<ÿÔþÒÒ’{.“¢pÎÔÔ”{Q˜"ÉÕR¯,‘ý<´€õÆHÎsÒ‚Éay¿ª1]ðz$†Gþ:áÒX)ÖÞÞN[+Û¹óRcèü­31S]¶¶¶<.G²A^õ$ãVÉãKÄ<•ϯM¿¹"1Ý™ÆèÔŠä_baaÁ“Ç]UT«\)=ÁÙ)¥•b9¬‡1õ‡šV,Kû&2†á3*3*¦çéÈÈHžV€ç›¡‹—› ŒkÂ2D©í‡N„;É'À"I§º“¦ÛÑÑá^,pf@fbûßJ2,//{ü*ó·®®Žì$•ÍÄÓÜÜl:/s“fßÐÐ g΋‹‹¼‹ ­Ïr­ix0I³onò:,¯xvEçöƒNNNjp7Ëùkø·"9(Bú³Œ$ÕöýsD´À}ù÷†·†‡‡WVVøå¦Û«v™'îëëã]"!äøø¸™tÑA–ÄéžLÂî$Z²É‹Þuž‰`îïïOêacvvvrrR&QªIÓÞÞ^zdÒmkksßLÜñ¼pØ”ß×^{-áð´d®¨¨PœL*«««n0§dê¹] ë cúhò^]]­Ü‰¦Ò3þ^¼Ká»å/ ´¿¥À‰jÚ‚,âdØEN:ý®¦ÍþÊ&EÇ™¸Ï‡Ö̈ns“:lj)|è`‘ôÝ¥i]¼x±²²rÓb3¯+9Í)-~CNK›õÈ677—¸s tZGeH!ŠàYqrâÄ î¤r´žî‚é™Ö+å êm:€*A†ÖÐYÒé³–œCQQtM366ÖÔÔÔÚÚŠ®M/üû¿ÿûž&‡òŽ$o¿ý6]-BõÔ3øÔ©S°×ÒÒ]Ì«¯¾JçráÂ%”¸sè½û-7íèèàEú Øa$ž¹0b˜G0¢;€ž’n"'}(iU:PTæ*˜ò•W^!#Z/fº?Í^«öÖ[oép°ªª*¾Hww·Nwðt—„iv "¥o%7éï°º˜"$6njÜE•DGŒ‹DmA*óºâ§V?i&TcŠˆ:`Ly¾>ꔎWqÛßa@õƒ›‰ÐP˜·ÎŸ?0GÕtÍSJ¤ç)¥áV4ƒx´q©Å)µŸhN4>þñ³Nq.Û퀹‚æ±¢Ú:œ¿í"Úô ÷l‹¹Þp`®ýG¤xjš;’¤7ÝáMäw°küž;ºv>›´Ü'Á$=ÆwÌZ*á¾ðœ…£ýÐî˜ÝÌ[’G¿y’–U* Ø5bi!>.î ‰=;%ê´síÍ7ßÔùöE ìYÉQ RÜÀdž‰$u ¦êêj ÁìÏEµ(èÈÚõõuëì3<(1ÌÏü`É£d½~êðZ›µ,Yajj*&G//FGGWVV´ö'hJz6Û,ʨkÚobéÙbW”à<´“{ÉU‘ÑöéÙ€:Ðßßù“Ç •›`áu@K"¢Ä¢P²6tÂ1\è—+** êTË/-Jègrë-‡J¨åK1‘Ç¢ÀàëSahãËÈÂ"¥lC'îtww÷èèhÔ²XXÏT€ø`§kôÑ^Úm9äd7ᬇZ‹¢A)Ûнóúú:=õüü<Æ´µ]Êð_gg'ôÖÖVܾx___}}=–ôÅ‹í±2Áää$R›Ê¢–Å¢˜Pâ6´@-Ϻtˆ4•¨Å±È#°TZ[[åçDî©£–( ääùÂ… ˆjéÒÆôôtee¥¼ Xz¶HeÁÐ]öŠƒŠŠ zF¹+²(ðAù¬ô†µµµ˜Î1?ÏGg 8q{zppÐRu)¯É7åËž?~fffjjʮܶÈ%»:ôæ´ŸÙÙY÷ÑŠEŠíííÑÑQ>¥ñ.^\ 7ÇÆÒ$ÖÌ*ÌÍÍmlltvvò5-1ç 幺LÚÀlÂQ/Ÿ#`-ò(Ù¸M.v UëØ†„3sµ8i ¢¢âøñãºÞ¿|'– ,C[XXXXXÄåÉÐe4maaaaaQD° maaaa;ܺukÿþý{î`uuõÈ‘#æokkkÔ–¡-,,,,b‡}ûöéÈù¤ÐÊÊ’‡‡¶°°°°ˆ#0£+**øõÜ?}út™¸f³6´…E‰`xx¸®®Žß¨±°È ’šÑÜ,:aÚ¢d°±±±ººjökYX”z{{=žáìòÙenÚÂÂÂÂ"¦ð˜Ñü…³£ªp° maaaa_¸ÍhØ:žÎöóËÐñ”ÜÒÒ¢‹ÎÎΨÅ)(,C[XXXXÄcccî.ŸhÁ2´…E‰@çzñµ 9ô|øðá˜X—ØýÐq‡õËmaaaaaaX†¶°°°°°ˆ#,C[XXXXXäÛÛÛ™½hç¡-,,,Ê›››ããã###ú{ëÖ­+W®D-TY ¶¶Vuuu§OŸnii ³±û¾¨Å¶°°È è|766*++ËmGŠÅ®€‰ûûû‡‡‡©óóó¶’D…•••ÑÑÑÎÎN>E[½SÁŽr[X”†††Ž9R>‡ X„Äääduuõµk×Ö×ס‡®®.KÏz``ezllìüùóGE·NØÚÐ¥ Lgø ¢¢bqqñðáÃQ‹cqêëë—–––——z{{ÛÛÛýa¬ maaaQ‚¸rå ôÜ×× XzŽ-àéµµµùùù¶¶6ÿSËХ虮vvöÌ™3QËb±;ÆÆÆªªªŽ=zëÖ-÷}ËÐ%…ÍÍM¬çååek:úûûkkk;::Ü7-C[XX”,<I9€,744ŒŒŒXz.:`Iooo»‡»í~h ‹A™ï¶ºråÊôôôäääÊÊJUUUÒ0°WKK ÖÔÔTª¥ÔÚÚzðàA³ãÙ¢¸@­®®¦«~挡i7oÞŒ:wi£l)­@w+®­­Aº§OŸ®¯¯¶éû& Ðœ9s†W ì¨ó‘3)ú÷­­­0Þ0,â Õω‰‰Df M%˜ŸŸ§UPh!¶*X”¶··±<¸hnn.±^»$AÖÛÛË6qggg#ºô]ËËËôc³³³|ô¡¡¡PÔŽ=zòäɾ¾¾¨±È ˜ 333¨›‰ÐØØØÐV÷ÚÚÚ”ÖðïZXnÞ¼¹°°CSÏ!izí¨%²ðÛ‚¯Ã7¢GŠsœ…µ{‰ß¤OÕ£ÊП;w®¨sZò BÒÿpŠ¡ùä|Ѫª*:¯TŸß¢ĀÚÞÞ.¯QËbñ-øðhþ¾ˆxš^¤½œéÖ“âòåËð7ô¬QÏ€‘CSÆßþîn>xð ß>j™-,"¦FKK‹åéhAGqBŸùþ êñ P>étÔFí ƒôþðtªè¦µ°¹“Ž•nmmå5#$ð”ö855å5-ÙTCCCÄãÉr!ó¸+ô5ƒšœÐ1¯Fia‘+È+Ó™3g¢$t:ô2¥72Oák`¶`)¢–c×'«+8Œñ/FîR…ÁÚ&~öìYœP…“zħá)*”[Twd»xñb@ä¨ wnJNO´$­‘”NélT ‹2ý”ŒéØöÚ² Éd€öõF2iª¤‹eÁÆEw ¦3ù ¨Æ†®'¹XsÁs͇#fffôʆžú¿”Þ2yEaø]»wà……“:=ršs§DUÒ&ó ×PBDknr')CsßS®ÝðíÇJú, jJû°« ,ÊÆ®(1†¦<ã B•ˆ>°ªªª( uè»3KÖ©ÆQ‰Å͸wx‹¿P#ÀSJFwdÎj2TK‰Åß÷ ­ö÷÷ÓjxJñ+¸ÐªL Îk§œtþjíž[N-…ã]"‘ﵩ©iÇQA¸©©  =x‡èÇ$ehm”'üŽcÇs“W´Þ©‚}PdNr¶Õèè(¥¹²²âßFµ¹¹yâĉ[·n©X£^‘naQh´··Ó.êêêÖ××í>ÃüáÊ•+ÍÍÍ©ü)d¨466.//—Ʀ³gÏÒu·¶¶RÂôçÝ8<¿ããã.\8yòäöö6Ë/5Ÿûð1×®]«©©,¸kRDÜ™œœ¤(Ž×à¹ÁÁA½á-/ÜÌ[<"$ñÈjß³gB"¤"†‡‡aŸ¶¶6~¯8Ð}ÂpgÿþýæGd@¯"ëµ×^#r¾àÑ£Gƒ š¨Ž;fî<ÿüóóóó‹‹‹…ç;Ê z½~’ ZERzN8*FH/z””;¤»”ÃCŸ!dȤI FÈ‚cÎL~áÔ©ST¬ldH…ìs—Ô ü÷ÕÔ &Æ®òÀáÍM®ùX»F‚U kú ‹œÃÊ”==Ã(YÆ £ ‘’=@Á E9\£“×9€­“Vû>ÐN×ìµ^ÑßhllÌó–,`ˆydd„$¦§§EíàÅ_„×ÝÁ¶¶¶ ¹ ^—TL ¥Ý¡a :БGâ øRš¥<"Q¸¶³³³ÚAø®ÒÝ›!ht‘ ÂP¾ªUD«µ…Ê‹bæÙ!6y@Ó^7­Âç‘V7(f#iî#Ö¸ë+f~©ŽZ`ÔN³üA)wŒðdœhµâ€heœ!€ª¦{áa©‚¢p#µ¢ºÅSåÔ3îdvõiGŠ„—š%IæÛÌxžñl´ÐMIKx¹½4›L±x¾»>/?DNƒQä7Hx‰¡OÌ_Š‘k­´’«ÅÚ;Ð2Q“SŽòhU/iJ€ò'N­2¹ó,•ҶΤUKTÌBó±üé¦jfׇEöÐ×ç§ àéŒmç_¸göÉx6Ì,: ¹µ†vA{Œº¨’N˜•bå ˜«â¢XVãûqCÓפZ¡*3QËáÔ$è[SEªqBñ„qA§F¥eôÜÑr;ý5ý ñÓÕòtffFûèÕ¡{ê!b@¶ÖÚqmZ1ÓáJŸ8{ö,w¹1’GqŸ§êa¹Ã_’#ÓPÝ{L§ %C4€Ü—6j⇞ð¢C÷²FJ ­Â½+"ò«dø«u’@ËI‘ò!/ËY—¨Kâ—ÍŠDÞ%O‰ŸÔ¹àõ9É…ÖkAŽC%)mZ‹6‰„Àò:Ä_^7šŠy‹È%/"†4<í•$;æh·CÂY¢ÂM¢:í€$<Qü&§ôƒ´."të4„T0½Hùç;|Sìî6IÉ$íR†ø‰Šì»‰–bô§› dÄ:óÉø|›tw\‘j@SwdÖúj“*!sGm?qgq»Ûü2:¢Pôˆw]¥¯ C&–¡Ýê/¦ˆZ–ÌñCS‰eB%…gò_U\ü:©gÒBÍÃ$„‰Cèahµ1uñ†hý ½ã°¯ˆ§m§n††Z”®L&µ'ò;»SLŽÄýÀ)÷Nv ¸—é›ë¤ñ»Ý,È–õ¸¼}ìNÈÀìD4 )*#žJ. ­Û¯ éùŽnCS%I î2WB"xS]Ü -5ÅdÓ=Ú¯“'ÜI$œu’&9u¬î] \¨9™œšÏáî4ݟü¨ ÷솻Y"IRÚ3›cÄÛqTͧ²xB.+À¯µYÀl† €§ÆæVõ6«øèn†Ö ÉêzÇÕ"ø«±Ù0¾0å+"›Ìšq²Â2té ùín«[·n]¸p£!ÕH¸YÉÌ…dAH¼UQQÁ¯Æf€¿“““æ×f—Âòò²Vçë/ä¤Ýf‹‹‹<"äúúúþýûÆä¡óÖÖVí¨“åí×ÎÔï›o¾iVúìÒ¥K?ùÉO$¼™k¤MÓÉ"62;~;::Ž;&sß Í©#¿?E²I<&þ¤ k$DÌÄoŽn­®®žÕ‚U®ŽMI’t±ž¦À“®^¦Ðxª½\œ8q‚ND³¤ŠŠ±ãëêêøv„t/|à&öbÒõêÚ9??ïŸíæ­ññq³Ì ºUePäÔ¨¹¹9}zÉlºNmsD6²ibÓº}*ƒ&~T[@ Tÿ2 ÿ]ꃎÅõäîõ×_?zô(ÒRÎ:¬˜€äTÚ gÆË/¿,³ž§Èò®ËC¤2R¥±'@9«««¿NI†ß1¡j©:ÓÖÖ¦O¦GT 1(×4.·x¼E¢g †¸ÑŸð:Ýu2 u:¢,'¤íY½¡°³›¿u7<ó@êúÝÊ ö§»_Ñ$Ÿ±WŒqi½5OIçHlô‰24SÙÐÚ±.£ŠÀDkf¯.ZCÙJ‘;†ŸÇë/ÐÜpÂéèdy¤ûnnµ]öœß†Fxmòs ¿s· ­å]ÆŽ  lS¤b;íâß¹ÛfUùH¶„φÞq9"Ð쵎fRåºOãùÆY{W¦*/ª$Ý64†ƒwÛÐÄ`Ô9±1£Žšï7£)IGÈ͘‰\#œ&§ÒÃŽ‚å®úd*O· ­QŠ„3Vé &NSÎúÖnvî˜õú4ªþtSÁÎF IuåðcSú×Áˆ‰©·F÷x‰Û†ÖÒe­iJÜt0‘‡Ìo–›Drî#6´q–™<9[Òº¥Üæ.s›©]ñÿ«c°¿u7ôÁÜR†×R*ä‚ñ–ì!f¹ÖâŽ02(¤Y â~Å/XEé‰?L xÞ #À®²™yÜI$2dá‡,‡à´D‡¦G6Ô˜4#IE (ç€Giå.-—¼!‡Äó Vêi$©gÃÐ!ý ÕÂÈXe`¸éÖ-wÌ&:­#Có‰³ahMH—6C5¢ö÷“©` Ù瑯¦) ùÃÄ XE˜=<“–¿QçãËôí(÷òòrH}PÞ”S¿Œ¿”*÷+&òð’ëü«¨Ë//L㣉‚‚8çççå( ðÕä„kúpBÂŽ555©|Èp³±±±ººZî°ÍˆŸ;rŒH$ÜÑwE8::ÚÝÝ-øF é]Þ"N9qB€¶¶6^Gã’Ìã>Ž'€$J6]I”S $äžQªuý‰VÑÕÕU›2PT‰Ä½ *3ø…1Ÿ, k “qBÙŸ5þ|‹#û¬•ä²&j)rƒ¤4S¼ÐÂil\ƒÙ ´ewUïìì¤?¯®®Ö>ƹ¹9ú.ÿq>333X´{öìG?¼å?uÃD˜T6:ógÏò.Qa™ÀÍèëȃQ§#¢y„®022ÒÖÖFm['¤{‚Ï!ð믿.W9©Š‚ñT'µDÖíä|ô~å{$îìR5Û?Ìní×’ûh]Ì8uro#–––´ð]Ž¦Ý±­9 R4[†ˆJ‰rMùjVÃH¢ EÌVbðìTñ¼¢ …×ëÚ~¦Ôݳ8š·0w´ÉX.9ǸÃ{f5Ð1Sy@”Ç3¿BœÚÀí΋»ˆÌî8•³¹03Iæ­ÄYSzæÙ˜¸3½dÊÄ|Òý™v\{6È‘ žÜÃG ïloWܺukttT4Ý÷‡‡‡{zz¸¹¹¹©ÑxTÄÌM¨Qç:$='Ž×®]£ÿ5³²PòF¯Ý××'Çó ŠééiÍ—L9H*0áùx“““:”߀½•Ä$°¾gÞ‚H^}õU„ßÞÞ¾rå y‘cg#¿É©æ«^³2ˆ¨Ï?ÿ<¯›™’€Í¸.\І„3dîÃ@Ie#i¹Kå¤PÇ2Rbži'J1ôÔ3‹<>>ÞÑÑ1;;KŠˆð|>±Nlå>¯øÇÉuè:’¸ëÉ—ÆÏ¯öÇ# yTÒäËD¥EÁj&GÚ æÉ¸ÙNÝP…ÔÑ“ˆš‘\UÑ" JosšFM£–"Р•œn'‡Þi¹7ˆr?Mwé/zg˜[Ýü¯T;H5A ‡Ñùò®™Ï–oî@¨î5j!ô•!}(<ÒÊÛ6Lù“ŸüÄÝ}{N ÆXÄhkmmMz&¼2N¤‚¥ÂÐÀ-:íQ§_è>ÿû¿ÿûîÀÖ²JCçJqǸ&]âL*Å»ëd¼§ÕAf©K~ë­·ªè”7 #×ë'Nèt“0Ÿö%!Hš‚%;”-}7ŸÃ…ô3÷ÇJÜ™ñU]Ò,•ijñQê¢R&o¿ý¶;ÂôÙ x{Ã8»(1”žÚᇎÙZŠ2Â}ðÔ˜«¥¶:Ђ>úäÉ“îût£0½°›¡µµ\}kee¥:¸¤ËʰÒèX/]ºdRÁT¥=$uÐïÀXcôÔ¤Â+ôÔ$”t)rWW©Pó( ·5߸_‘$d›©ÆôäëÛ³H•\CBäÔC“*®ÁÁÁ_|qnnî7Þ0ºå-Èå©(XP[ãܘÌy’MzŒ»ûƒ¢O P&21À[nîçé›o¾I)™M4ŒóçÏ+-‰a!§  #"çuÊ„¼S’:.…¿ÒWÜqòŠä!rµsuÖóU󆹕´–\zWHŽ;Ê,²éš&…¦DÅ}>òPUˆ°»»‘Ìœ\’CPÓ‚}±0¯À´:$>›M,J÷R«ÌÈsN@W.Ó8¡‡zè·û·ÿóþÏô¿?ýéOÿãüçïü|G¿õ[¿E÷JêÿößþÛ>øà‡?ü!4Là§Ÿ~šßgŸ}Vþõ¿þ×ö³Ÿý¿ñ7 ¨ûî»ï¹çžûÿãýïøÿ·¸ó×þÚ_#¡={öpñ·ÿöߦ³þ'ÿäŸ'oi<©èúÕx¸©øy‘‹„cb" ©ÄïýÞH±À^GfBÂ+~øá“O>900 IH޼S’æ‚xþäOþ„ýóþϹó;¿ó;ЇûÈ Íÿý¿ÿ÷å»_á¹@0'aLÒ>úè?þÇÿ˜DÑK(–?øƒ? ur o‘S…°b’~RúùÏN¦€l ]½z•¿”ùâE Gÿáþ!lM9üÍ¿ù7¡L.[¦>ñhx™¢æ&…c>‡Âüîïþ.wÐ* ?>±ýñÿ1 ý­¿õ·È5Ùüõ¯M®ÉáMfùü _FH-¿ä-îcµóþÑ?úG|Jæßü›£Êi>±€¼æ/þâ/¸Éë<òˆ¦9~üãSV£0 F™üÙŸýĬÀDHÞsXÛ þé?ý§ˆšóh‹rä&$:“©Ã%†O>ùÄ¿89)èjrëJ—rœ“Øh)ÁZ]}N@r§Nºqã†Úl0¨9ÿò_þKwÇ»kê!51DèO=W_©€ôí"©œ*jΦsÌþHmK Aá›à#ß ²†H;βð8,¦(ðò%ã'ªüNMMùá(äÕ(ª\hÕ$¿‘¤r¥Ø®‡@5ÂOÐÆy¥ØÖÖVȳºø·ä¤‚û´À©‡LT1GèI=‡_©@ ߃-²«“Šìc½ôÒKXÌÏ?ÿ|ö `b¢©?Ê«äi½‘ltt´Ä¶H† µñÎ ´$¾ðéò¹se»dèauu5æ«x¼CÄrÔç ££Cئ!{Hmˆ:Ùƒê'?ùIÂYŒ‚õévœYð×]„Ñ_sÁ¯' Íø 1$]l–ÊšÔýñÈÛ03•aR7ù“æZŽÉÜ1Èg¸'!aqqÑýÈSJ~2ÇN:§OZXXø“Ó'ãï—Ûï$9>‡©áåÌy×xÂt¼q¶¡}œp¶ªj+ÊÎCèµ?ÓÆ}LûÔÔÔÁƒµORn´ÿJϽaÕ$§z+å^ŽÓí–tN™ ¢ïyßçÉj:h©ã>¡(AoèsÈk&˜.æÊ¯)±ne©VX Wš`««<¡2 v===N‰ôœpÐÌcQøÎÎÎÚÚZÖuÂZÏÙÞÞž9¼JÝàðOÚõ_¥ááa¶Ý8#¿Uh®WÀ„? …ÈsΈa”:ô»Ë¬Q.±‡ÐΤ··ÑÍßÕ¼Â2ö÷÷çÊ ßDqŸV”H,±†¹JdžL&›?Rªk×®Ñ Ò‚U-«ÉÜWÜW¶é3Ö˜¸œþºe%0š­ùËY\ÐoМCSžUTìîÝ»ãããZ]âò“ÞØØðòë®é–~MES›¨Ü84x¤ÓiÍÓüJÿ"Ï®ÙòÏœ?*6Ú2Š…'œŽy©h*±ÌÈMAfüà<™››C§sµNeão<@__ß{gáèoB1޵„R_=È Æ_1¤Sžò---µµµ)ÒTV· ~g$ EG;×YÐQž(î *•áWÊD.“ Í-H€|'¨ß€­¡”û÷ï?zôˆ]è Öò§b¤S±ÌJèêêâ(‘˜©¯¹sÎô*uj4øžÊ¶„?ÿa.­”|L¬\½%±@”œMt‹±Þ¢]Ã!ò>w-þ–––“FióCӜ˒.„ÓºbÂ#äæ4èqÒæïÀÀ€ ¹<.8´ò`ìÑ쓜­­­Üôdz ªüàÁJ¨­­Åžö»n$›&ZjC%£¾…®¯¯¯ÑT¬sÒ9º\ ê賚wöbÃ_ ‰Ôäý÷ß÷;Dr•ÏGN)ä+y>üðC„™»Lù.¸´%f_N'p•&''•_Wà¬7ý”^\\Œd!„jöôéS]¾#o Ý yTÖ |½?òü'ËŸG'ƒ+Géšžà2;HäþÉu³Þ䓇.ÛüÄÓ Ñ»»»|åVi6\±|r)ÙKsØQµªpïÊFþð,%aM]B8vh7Qÿ,¿³#¥Ð¦ÚS…?)$'kùÇöE’3Ýì///çúI³LÄ®2y »âÈ»­ò¥öDç¢i+4†Ô&›^…ꥯ+!ë àp•*Å÷к þ[Ã5ÉÌ“uJ 9ó™ä„èd–yº+pÒ ’ÿKnM+ÖÂw9)sZ©Á˜¨þƒ© ÉyÛÙ'ŽþÏ\®t`Ž·aþ–‰íº%Ùëgˆ ¹wºBóïžzÂ˪5›Kã›››¥îšjªÃaRóÙÞÞ.¯X­­­2²•nê„ÏQ(…F‡2­¸\ MÎ|t‹?ש-ÃS+´–óä¯Ð<–˜ˆ®ðŸ%º•*¥Â+ÄåY4MUºwï^2M£ü Sȯ§§'‘d…ÎÚ†¨Ó•ÐÆK®ÛQŠ MGD¶…JCÃxøÝºY-@šö8z5æªÏä!gÖõ±@‹M:™ý kµîF«mÝâØÉÉI­§U·˜m- Õ.Z^ËW=W|½äPhzQ*™CP+)1§æ_W¬ùÂn™ÉT=Pµ ¬$Jyë­3¯›üxóS*"3ú…>zeÎÓ)°ÐFeÂ?M!³b‰ky"’¬ÐYwÉ3ÈDI©¸áÑí’¬Ðz¨E­ö—ðP¾V¨òUn-ô~A§z[¡q&åñ— ÜqÔdßÿoÂ$¥O°³³C¢ÖÄj”TKù®L…Ö6Ô½ã"»Ìz!â¿ ŠðêKeCã¯ÊÃWE¼PýSÞº_ÊT9ä|àáw{bj#眢ò«‘ ¬¶Ê„SãmmmÕÖÖnll:N¥a$„çÏŸ÷÷÷wttðgã›(•¥E®iFq×.giñÝ×¹E+]ïÜ###ò‚Y__pp0<<Œ¬jÐ^'×A¦dÊ›%Ç™Ö{èn^¹rEyüŽÃÜeÔ*sÿ\*yFÛ\¢»È®L-…››ÛÛÛ»páÂÊÊÊÒÒÒÌÌ µbßÌÇL3óéð_F¿Ønkkó;ÙV™Ê¦êÆéloo+ F›Çž‡2h`æÂ`2P™µµµ†††/^ܹs'­|-ŸLÒéÍÍMj óœšš:û²iÃHü©øïuww§ÓéÞÞ^™Î‰U‘R!DÕ¸¼4¯ÌnþWŒ‘6Åäb•Ê!sòvÖ %\##½·=híC<ÏsAœ„¯hM½ †ÑÞÞŽì¹DRɧRØFËoݺ…ýš©»ì®ajLG²ñ©qY¢K‰ï޽˱N¶AUoL¶¾ìfwq|­Ùã¸\®ÕÄÄ„ðœ>Vùž‘7òÏÊNzP'*D÷÷÷mѰQ¸…üá5³7î•\Ò_±´È _Ö4&°}è·~Ò¢dkCkëw.ôäÉ“cã1e|ÿþýÙÙYÌ&ŒfÅT`C½4š;ŽâŠå ¡ª´ø´Ñ®ÎlK: )—š³Ö°-æ`Hô6òpË莠á¯ÞáÑ£G---)on¿KDátùÓ¹¥êÜ”gϞɩF.>=·¼½¤†ZLë· JHÙ¸5îïÌv ·ÁÓÅM$sæ_žÂ›šštŽþ<-<…øÇ È?88xö.æ¹£ˆ\´äé~Ä(2jA,xð@?É%Ú)^îEuf5ØÖdg³ÍŽÊ6??O9nYš|‡ñé¦ëonnrt2¨L~Êô æ?²é\”â/ù¬7#?®Fb‘o¦¸kñ{<~ü83ìO¡ÃòT©åé—;W”Æ3=ÄÉeä>¨#ätÓ°3CaF{M\|ÃüïQ„~¹]QÚà¡&<3thŽ<ÿJG#呃Ú"¥Zì§*G3³È9==ÈIØsùô»ïæï£°™D¾Áå3Ü¥«?Ê.Ë_ÿÔ+ï%Šv“òfŠQ›7o*HÛ‹‹‹*– …MãsggG~@SRþËÀÇkîÎÎNÊ'[MMÎ…Ÿä‰L;cç”ÙÐF1¡sÚä‘«OZº”Ä©9ã~jjª2íæL·8ÿñRšoÚßc­çS“À± MÅçáAoüé(1ÂŒl¯¬¬pA¸’¤ LnÊ´Ì_lJ²ÓåG³ëêê6>ý®¸ö÷÷³úc®Fÿ¦‡«÷Žº9SÛÁq©0ùeÈ¢¦Ô͋ʌŒŒP,%(n‡\‡R9`gw~Â2¾îA9ò{{{©*ÊwÎennîöíÛ·nÝD×ÏîWÎærW<Ù<ˆÛÛÛJHTéܹsq×¢NmÜã;–ëõ?ÚnÚeÍB –”—«¨¦kn–Sø=Š0V‡¿eçyfÍ †¡_Q;ys“ÛÔ”m£¶7=ü̹¼…»àæßÉow‡ÛtåÊ•”çsæÎ;r ^7õ-ôR•MùÜPa Ñ^dkii¹qãF`wíH Ù‹[p.F_\fœ‹bBë\jJ¦¥¥'wöa ]) ÇÊ™9ézÒØ@oúlÐKðw,4E‹ ¨l.?­Ï!} Jvò,HW°cv$3]^š/'Ï©W1œTW·Ì·KÎüuVº«ùôô4×™b1Á©ùuÁù#Óá+éz-úýp“쮜Šò¢7Ùäç4‘gNÉ¿{÷®®äYÝõD2³ÀH,(W±ž‘­W¸‘GÒÚÚÚ@°¿¿ŸÄ€71åTâææfKK _åwÌå¡i"½©©IÁ¦ä«„òÌÌÌttttwwó«*@!|­««Ó¾d s¦“–?þ˜ô;wîø+<77—òLêÃ×ÞÞ^—Ÿ<¢ãRŽR__ßÞÞNfýJô“jè¾*%gDJ¦Ÿ¢ÈˆkјQP²Ú+çϟךE£,É3rFw9ÙÜÜ÷å)*ÇF‹<šH´‘3²*ÅÐÐPgg'm͋߿&‹E¡jh íõõuÞ¸wï_!(xVɼ¿¿/W?”@f199©UÅ$yh5Š QeøJ6vô×<å$¹õÙ7oÞ¤nªŸ ˘*‘Çí“900@±$’#’gyy™ ÕÉñ\9·oߦdÕ„*‘­@íjÊlèr%ë‚<,›jÄB„oK‚ŲúÈ“¿³€×³@Î\Îõü{È·]žÞúòÉÈR³{ßËó)Væ83Ú èJa¦ÑOì¢¦Ìø€åJfœ¥r"«Ú©y 42œ¹dҿ׉š©<—¥ä“-'¤EnHM¡Ë½¶7ÐFп¸kQ ÊrˆÛˆóXRæhÖ¢ÐFX[[Kr°¯¨XYY‰» F™`6´aEbjj*î*œ$8s6ÊShÃ0ŠÄÆÆFÙtOLLÄ]…È:óYî·¢à¦bO·#=!yþ:ËqgffTH$çEQáÅ1…6Œ2¦V&Ú"rÊ~¾Xœ òÜÖÖ–™>22‚(...Fu””÷âãÔ³dÏâ ‡ãrôÝÝ]¾!O(*Zg5¦Ð†Q&Ð4ÐÊ$Ü›Uy˜˜¹ØÜÜ,ƒA‚óçÏÿìg?Ky+¸ÐQyãÂâ\YY¹zõª|zðÓÆÆ†ÌP ìsî|j´îË?j"o$ÚîííE I¡O988è2Ê”£ì@õHôÏ–äa;°äLå¤|såþŒã†ØÍ dɹ;ÿD_£ÂfІQ<Ôò.p…cZ¥^M¨¦Ë"gR´ÅÚ@` 7qRJ…›<::âSn:3äçÅ‹\Õ®®.]C<žžæÄÉÉÅšššêì씳°+W®,,,,//ïìì_ŽG(§ªªJ3åL´©©I>8Š›P&å°M¯ÎM0T yï½÷>üðCŽØÑÑAQhrrÓ_¦9_gggµ‹ltLr²ñøñcEÎà !óݹ“™^/½6úúú8w0} üZSSCå#¾…ð÷m$‡Q¸kaƒ$GÎðC³ùÑi4i‚)ùXõ¥ÙEEü"¬Cþ oò#gyάØÖy)ò„Ú®¡r666úSXÃ8òÂlhƒ›Bâúú:å »JTQG¯‚gð+7Ne’¿¹¹Ù•Æ?ì úJe(ÇÊìΆFn{¸ÒŽ^E1qÞŵÁàNG…ÔÐÝ#eæL{zzKƒÃÉñ8_éð•_éøÏ+RfC†Qd°™°¥"ñ¬¢0…è†=Õt¦|F³¸ÿ>úIÝ6åAZ[[É,Ëg§\ðÕéñ¿=I§ÓÚàjk”Byü~?ܶîwÓÙ hÀôtù±DÃÔÜ8·b‘www³Ë7üÇ’õ¬^·Õ9ÿâF£ñØÄ²˜1Á)äD£8ô-vvvØ#òÉés,0÷•úÝ’Gˆ)´aÅfzz:cø¤Ðþ¢ˆwîÜÑ›?š`ÅFÌeCûß8>þœ ¬¬¬,yÐ^ß½{—Ï3žTy qKooïøø¸n× 2Ÿõß²Fɸ_ŠÁüðáÃááa‰+?Q¬¾.,,ÌÎÎæòâN9üÔÞÞÎs -]ÄxnnŽO ñO"ûðÃ›šš°­«««Ù‘¯'=k$ŸZ!Õtõ¨màë ‹Èg!˜B—!òÏì¶SÞ}Ëi³Q¸¹Ø+ξI2´³###§{ì×fJ=iQ4å“´õ·nÝâ“æûŒ:M»_6Á»x„Ü=NÚ@„b™æ….v$ _ÙpO]kk«¶ý|²/· 1£Eª­­ö“Z²)p€PÞ»w»€TÊ}}}dÆ¢Õkf媤k$#àx•uÝ\¢k_Ù÷îý»Χ…js¾¨»Ê |•é?00 ó ‹œQ&h.%ÍÄÚÚ}®ôøxˆy¶ÈÀ¿¥pvŒJãØÈôÚø¤GQ¬CušiL¢S˼§Ó)ï§ÉOŠ‹R“'¥9Ã(¿¿ÝL#øŸ éE ½¼<ç¿Ìì"-___û<Œ’'ÿ™be=<<<Ñ!xn5$3.Úú+ò`ÊÏQ€ÊœÂŽ7…6Ž%eKJŽ—/_ŽUWW¿xñ‚F$Ï&!`ISˆÞ[§Ói /›×iFÂÏsdxnnNkXûúúœ±›É·ß~»²²òÓŸþtmm?ÈW_}ņ\¬®®NMM}ñÅ!GA˜wvv´®·¾¾>Ï?ÂÄÄ„ýeŒa ]JÐú ÍÛÛÛš(¡ãŠB›¥Ó¢ <%Aÿ±yÐKeC›ŠL>ÿüsMôÍ•á›o¾A¼þóŸ#ä¹ò\¼xqkk«±±]Ïç=1ÙègÄ}JE½—²È‹5…. ¸÷ZäÀs€É[ ùØÒiäk£««Ë,ƒÒBžJËëäŠGøII)Ãçp!ÏáÒëÏ\RÐ3á‚ÜT•üñ‡‡‡Ï^NCCCܧò[°7"6–Y&'{'á¹0….0 êêêZ[[?~\„Ù×È?êëëã é¶„˜žž¦™à3Œîîî\}AÒ›››ùäi ‘g„Y>>o¼ñÿ,ïÁÁÁöööwÞyÇÿ«F¿Cª„HÓ×Ѳڹ¹¹\Ùø)Äd/]8ý¨¼¸ä ·8òq;Ú.‰(PäîD\™g\Ö,¦ÐI‡'€&ŒÞT1Ë_”ƒÒå3i§F1 ³þ„ K#Ë£2¸ ÿ÷ï·ž¿ûÝï ¡Ð´¡Zæð§ú§‚l»<(ô7ß|R&*µ±±Á'ÏÖa *–ËCV©ãN­¾¾žö§¶¶60êÀiii!Ýõ®ÈyçÎR¸°ôZHW€ eÖWipWWÝ)r:/®ºº«]ƒ%´9df;ÐëÒsÂŽÊ&·'ä”FRÃŽŽ2455Q Çâ@tÎø¤dÊôgsxtZO™~㸭­MVÊ”'ü®Lkº]>þøcÿyE‚)trá‰äQàÞ»)¦E†ƒ.//ÓÌñàÚˆ·Q8hõ2M(šQÚhÂpyF›ýï;‘çýèGo¾ùf [ccc ûé§Ÿ†×êÒ¥K·oßNåʦõ/×?Åáá¡–¶ó™N§ÝÀ 7šÔÓÓsïÞ=:@ÒKrVUU!–H&âÍ¥¦éPf1®$ÝôŒ+Fkƽ^\\t“ÿÙ‘FFËRxè°/Ûä÷ጌ°;åyàÙ Qbƒœ”F/jwwW16®]»6==-Ÿ$òK£ˆÊÀOT†l.r¥Û Ú|ðù¹³î 2QÆòéÂÓÿ={O_1à°BL¤\ð@žeé'†ˆ^9«4‰"íݱ‰zΛ!™ý‹¶¿úꫯ¿þ:¼pZ^½×÷›ÑÈ«3:ˆ½ç}j%.‹´óþýûnxOÈ*æWVòËg5ê+ÙöØÕÕÕELp·/¤»<ü$W¯@‹D[¤§…:ø³pZ›‰Z3ŋԘ<5¤ž˜æþÒ-˜ššñ`CÃ*ù匘B'ŽyNy3 jB ·<Õür' Ð\òœ’§VïyR«¡9,?ÎêñMíêêR¼¶HªGóDik½ˆ"¦”tpWÌÚt΂ ØÁ\ ân&W«Gx~–Ö6Ÿk…6ÓÐóÇD jkkÚ!îK¤ø~¹13­áSgvÁ"Ûáå„äÌç ™²HÏ@ošÝÆ©¯Ã‰øm?Å:9„[ÏB }ùòeþŠtäesȳ˜hu0õÐh^†RR¯Zpú‰îôïþ¬;VVVúûûwvv*Ù†0 „þ|ÒjêP®œ_}õÕ/~ñ‹¯¿þ:|Jö±èõg¸®Sþ#)o$)üï#9£ü µ·QîòÑOÏçÿ²ÒR¼÷Þ{)¯ÕМ -‡e»©©©ºº+yVJÊ›™B÷_cãÜxYÚ¥½½]Ã;pì’Àh¤aDˆ"ë­ž„3òü“Ÿü?£<§¼¿ÒÚÚÚOúÓðZin°Ç}‘Œ Â:2мsg›8Ïù#ò5(¯ ˆ±¿ã¼½½­Qh·QPòíÛ·Ÿ>}ª™þ©¤ÏŸ?Y^^ÆV˜™™9Ö)gZSSsÆ“-ôJ£D9ðp¢˜¬çhúÅ_ ú!Ô]xôèQܗǨ,Þ8{F$ÈzÈ3óÅ‹1dSžÐ¢Çr©-ôZšfnggÇ%"ÿrÜ£ /þ Þ—/_ö/¥¨c_Î-..–öF$hÒM¸O+Í¿–_ýêW!cݪVõFÑ0:) yù¿ÙEAµ‚^m V¯k³[Mc L^ÐìlåH|„QÕÌ5…†qv4;,<–å[o½ùqÃ{¥š›™òþk1_ â"§I…(¹\ý½D‹)t"èéé9‘#\½‡îîî–LÒ|ëxVx–——¯\¹¢”3þñ´à!Þëfø™™™©¯¯ ‘|4ÆãœBdåûßÿ~´}óÍ7¾»3QÚ?XUÆ8ù|öìÙááa!µîÝH™B':ïá~ 3Ñ{hµeì2åÕ!ú££ÃÍ ¼¨>ôlÙUr@<¶··+ABx˜ÿãüQ•†< ø½vg%Ä-F™¡xbþ8iXN³ÙàkæX‚?QyÜ.î'·MC$W d#1à³lss³Ò†+²bï¡ãçÞ½{ùo?}úÔm»eT‚'ËCËBL~¥<~ü˜¿A:VX=Úñææfþþ]Tø‰”›ÿáÙ•Þ0j—yPóe:'ùꫯ¾üòK­ä‘þ“?ù¿è~ûí·rÄÍOW¯^õïøï|'Ü™¸~ýºXFâ(r8¯¨$­µµ•&¢»»[½ù¶¶6z0tN¾Òh(œ{5ÐÔÔTSSCîÞ½«¨}}}]]]ûûû---î'-?Ñ6%PŽtZåÈ·hggç‹/Ø}ff†¯kp9wSè˜áq<‘÷ƒÖA^gý)4Uþünr¬sWØåMåð_ ‰Ðg'B2s"§+ß|óÍ'Ÿ|¢`Žø‡@Sß}÷]}ý§ú§‡jûþèNá\,áÈ…Q$E-..644Ȩžž~ðàÞžrçÎzä(.mË‚[wåÊ•µµ59ľuëmšY£èþŸ¸­n[;NLLPàúúzÊë–é ÅŽ‘mee%dÑ]ysxxÈE¶Qî˜9éøvÉÇ5£aŽ>úHòŒî^ó¸|ù2F³µ´?’rw• Eá¦_©Ï„u˵ÅöE¶ýSghÇñBNÚÛÛ•õõÿäßÖŽ~/]™^äòq*W®TWW› '£££¥ë Ñ¡èFÚˆ'EGȳۇ6k)3‚áfA¦<ÃÚÅ3p¾MPòëk>#Û¥Ess36kÈ:ò<‘ÛAEy ü„E;88ˆÌeÄPva$Ø¥§§‰}öìÞQyPe÷“<2i[;RBSSSww7·†ûÒÛÛ ýüùsÌî@äÐJ`jjŠ«m6tlðôGI4Føÿ”AW£ÔI§Ó4sǾÁM8ÿôG¬ Góßxã ¿<§¼ù_n([KHùÁ~ —Ó§0£ïß¿ŸòÂBÇ}…rBƒˆúp:hšÖ××f¹Õ¥ RèŽ#¥Ëåi~~žü ÌÌO´lä¹íáÿiyyÙmS ö4ν–½³³£@XZDê6*sˆnee…N§ù厌±±1­hÊ“ÉÉÉrzÅ¢èùç5·bF&õõõØ^OŸ> Ÿ±··§¸hþ[o½õßþÛËšsùþÏÿ™òÂ÷Òâó jHü¯þꯤÖt.uv›ÅbDs°+a2Ùóüùsú‚ô]̆Ž…3‹»QBçÚÌhãìÈH u† Ï<_}õU.ÝŸ}ö™6þùŸÿyffæË/¿ÔWÿ›é|Ð+^ÿZ‰¤Á«‘ÿ¥3‹›Ho  5w-"¦lí‘âºWÈÇâ¼—|ôÑG_|ñ…¶QëÕÕUið?ýÓ?)ÇÊtþ·ÿñÿ1ÿZ!Ïòð“ðÅ?‹‹‹´ì殫¤ÙÜÜÜÙÙ‘ g3Åâ¡,ÅŒGŠó²ÖÁ8 ½½½ããã “““ùäçwÞ}÷] e¤÷oþæoü?]»vm{{[¶õøÿÁ-¡þõ¯ýÉ'Ÿ|ûí·üî^ÔA£™:Îihll¬­­˜˜°WH¥Ë­[·Ü³¡c \„ËoèÞ(>Z5‹±›¿WZÔ÷ÏÿüÏkjjœ‹6®^½ŠrËŒÖ<²‹¯ ]¹óŸ/¦X%±`3šÚZT›…®Õþþ¾ózk6t øç@–ØÐ‘Ì&5N–¢¦ÓéRïÿõôôðaFäiF§¼•ÐZX¦…rgÍÿßÿû?Q•VVVT±¸¯ÍñÐÅÁâ×éR*C³¡‹ Íljœˆ•™~ÍŒ¢¤544h†sI#Ba(sñë_ÿ:kú)¦wüæ7¿É5ËL x =Ûˆ4AGG‡½r*!xÌúûûWWWýϰ)t±)ûqà²|Ån“ææf©½½½\Ó’?ÿüó_þò—QyvëÖ­T©=ؘû7nܨ­­µáî’€þhKKËúúz`*¢)t±ÉgåeISö]£ÌÏϧrÿY"MŽH»ëVVV0nJqŽÅØØØ½{÷5ÍÍH&/_¾ÄtžššÚßßÏ^5….*.dEC[vv¿ƒF…£Ù”¹Ìh·b*Bry1Óì°u>¯·Ñ·nÝjjj2Nh3½¨êêꃃƒÇg}ÀL¡‹Šß×|ã&"Æ©ÁþKyftæËÔB¼ÎD•þ½Wº~¡©<­ÿÝ»wÑiÎI°qïØá¡F›···wvvså´¹ÜE¥tÿç'¢§§‡ç/îZ¥M£‡¦ÏhÐÛñÃþð§?ýi„Çúîw¿ë",9ç8õª¯PÒp%Ñiú:+++œªPUUÕÞÞ.ÿ0Fq¸ÿ¾¢uÕ×× å³TÁürGF>~¹+çj§Óéðhµæ—;rÊfµ•¤-CWfgg½Û¯¾úê¿øÅ×_> ûX¸VBüpPÒ©ÝÍ@ÿ lØÚÚ†ó¯í1 ÇÍ›7/\¸pÒ·œfCŠz;«q×¢²(¡å@yBs¶¾¾ÞÔÔ„}åÊÿ<š·Þz« þCº»»‘g*PÜsQïa裸Œ½‡.õO(§°]FŒ Ê2a[ZZŠöudddeeåüùóØ—¥8AÌ(L¡‹Çõë×ã®BñÈ:ïÆ0NA‡†åÛ« ôööÞ¹sÇäÙH%6Êýí·ß~þùçÛÛÛŠê<üi…ÏÛo¿-w»É$±ae ÁÅ‹¹)æÒȈ 5/,,tuuaRÈû¦{÷Ì£»¸¸Xö #äS2 ýÍ7ßðÿtÑå2Ñ[Ï·ÞzëæÍ›ßýîwã®o2{A˜4pô¥â®…Q ™skkk?6.v4Zwss³££cooçvuuÕäÙH¥1ʽ¶¶ö×ý×!òìøê«¯~úÓŸòÆÚŽ»Ö¿GŽú¶··Ç]…Êbff0ÜeIÓ××÷ìÙ3„yee¥ºº:ªµ¨r“Xç[[[&ÏFBHºB#´?ùÉOPèíÅŒvªއNME½„5w= ìîîº@å Ú¹³³ÓØØøòåËñññt:}–7Ór¸H!òë9::Š¥nïžäh…þæ›o¦¦¦N'´ì•(‘.‰‰Ü4XÃÃÃZ†Q[[«–––SDœM~¸{£‘“,@§±z»ººêêêx>Ã×ßÐsŽ!>77'mÞßß·úFÒHô{hþ<¹Ü`[»hí)OËù›ùS”‡†††éF&h³^ïåÊ Æqvv6Oߥ53Î(2r’…íûãÿ˜Ïa,lNù6 xn¡yxx¸½½ÍCŽÙ­9Œd ‰úÜ6*äJÿ¢L øóÏ?ÿøãù;½þúëÿú¯ÿúŸÿó~ë­·Hÿè£þðÿ0ÓNE¹éýèGqŸM¢åŠK”Õûq&2Yh×××­Q3bGbÊëAbF¯­­My„ï…óÀ÷ôôTàüM£´H¨B£Í™‘XÛ¿û»¿û/ÿ忼ýöÛJÑt°/¾øu¡w0¬¿¢ëï¼óNÜç”DônaaáD{qkª««ó™PCsÓof”7]Noâ5 ¤¸)¯‹¬×.h³ ³Q*$T¡³·þó?ÿ3-'Ï¿­½§ÇŸ~úé÷¿ÿý62ý릜Nÿ§ÿôŸª««seûÍo~ã5ñ³°°€]’!óÝ02¼¸¸ˆ }õêU®!’ÜØØˆl÷ôô ½üŠ$onn’‚rÿÅ_üÅêêêûï¿ßÒÒ’ò,rúpnÒ0 #ZŽQhß³¿xNˆÊ믿~º}é üÁü%„äÙÚÚ:KõäQ <ãÄoÊÁº=é^hsCCf4}Lg¾úUœÇ`vvÖYÉ;;;|ºw À.¦Ð±³···»»ðÔaFérŒB÷»ßýáø‹_ü"îzf9y÷Ýw5v­IÝ|u!)üéŸþi>-Wà•*Úœç7íã'Ÿ|rº™››ëïï×v ¸1?é¤Ö××1mÝO¤»Á lÜ›7obÝžnxƒf}tt”Â¥¾~ª««±È1—9z®‰ct ÜÂS?Ti||üt×Ä8)ô“¸ÚÜG›`åÁñ/Vÿøÿ¸¦¦fffÆMl~ë­·P;m£?ÿùÏX~ç;ßqû~ýõ×ýðáÃúúz)ôo~ó›Ï>ûŒÚþíßþíŸÿùŸGpiòÖæ3‚Éë÷"ï›W®\aûÉ“'.0—º©©)W!ôNŽu¥rµ1<<ŒÖ"Ãn:=÷{š®ÀÕ«W)ÿàà€Ö_¿b(a½e*ôýû÷ zé Ã0ʘ¼´IB‰5½èG?ú‘_´øéÓO?My–‘gDÚ} Èyž`(cáýÑýJ¬¥Vo¿ý6b¬éW_}õźµÎQÚÆÆÿù?ÿ§ªªÊÉFþCEÓæ\>CV< zèÀöÏãó• câ»_¯·€B#Æ™SÖ÷÷÷‹v†aeF¾ „:ºaØ`o¼‘kð3s&—äüDóº±ð®]»öÉ'Ÿ ™‡‡‡©W -çbüŠ<¯®®Ê¹•,iDúüÿÁ^ÿò/ÿ"{:ÿ9bœK´Y`’¾xñ¢*&ƆaÑRlŸb’óp?[[[¯Ÿä¯««ûû¿ÿûï}ï{Ì?øÁþàþ=ö'~ùå—šìôî»ïæYÃðº”8k:•\__oiiÉ'jEñY^^Ö¸·¾>}ú´¡¡ëÉÂ9Ã0 #œ$Ƈ~çw2MXDîÿðÓéôÞÞÞ·ß~û¯ÿú¯î§ÌeTßùÎw¾þúëo¾ùƽÿã?þãÏ(dxcccÀq¦f„=}…ÿ'ý²B/AæÐþCÔ××ó5—#î’€m†QB$1r†^û µ©©©šššÿïÿ}UUzöÑG¹ð®÷w‡߸qÃ_‚Mf²½þúën6Y2A9©¶¶6 ¯¬¬øUùÙ³gœ>?UWWg®hò/ñ¢ÓÛÛ{RWÛtØQ“À9îäädWWÖ³zt 0£'&&T,—ýúõë©Wñû¨ÕÌÌLˆõ\ƒF!àŽÐOªðȆQN$Q¡SÞPógŸ}ææ”ù•Éo«âè«>¯z¤<½ÿÁ~÷ ƒìæ\¿†,5LÎBÎóöìJ@’±Œ9ÊØØ˜:ÎS¿¢Üô.\¸à?")¥Ê…¦þY=›†¯ 7¢å¢Gܵ0 #2’8Ê-úúú")í)δ¯Š߉ëvxxx”T<° )hsÖáëùùy$½÷›õ—/_&…tŒ{ÙÖá1( Ã0ŒS\…~ë­·ÔžºÆÆÆxß@'¿'sQWW‡®onnb §Óéææf7RÊO|Eýƒçt80šI—#tRnß¾õXzÒ0 ãÔ$W¡Sž¾žÅ8C›“cÛ1s´Ü»wÏÿõæÍ›(nWW ­w™Rë™™™ÖÖÖ«W¯"Æ©Wï¼õY__Ó#åÝ&¿§3Ã0 #úÚAÓÿæ›o.--Ô7ÙøÃDYÏZɤ©Î÷ÈÄÄ„3v—<²îÕÐÐà>ép += ÷ŽDuJ Ã0JŽDÛÐâwÞ¹}û6Æ\ž¯“1ïþò/ÿ2QòœJžÿKdU+©°‰Ï²[Þ¼³þ´»»÷YV333<ü_o†a”.I·¡WKÏÏÉ÷¿ÿýÏ?ÿüþá\°j?o½õֻヒ0'saÕÆÆF¢¢?ÉYJSS“lâÓÑÙÙ¤Á&rºDÛÛÛÖ12Œ²¡4úwu}ãzo¾ùFÁ˜µJ˜×_ýt±Ÿ‹†RNؾóóó œuŠÝ‘çÅÅÅ ¹FË Ã0Œ|(QîL°’µô³®®N —çTR_Êöôôlmmbíèèèòòr¸S³O&†aƱ”¤B—(ÉéK—.íîîb ç©Ó7oÞ$ÿ±ˆ±ËM¡ Ã0΂)tñHà@·Cº‹NkaU&è7vsþZžéÅ0 Ã8¥ôºÔYZZJxx -qÆü•¾¾xñB·/\¸à÷)–þÒFqH§Ó—/_6¿Ü†Q6˜B•••¸«ÎÉvVWÛev²åÄ€Gܵ0 #2l”»x|g–1•s¦†a…ú¨TˆeY!§i†QPL¡‹ÊììlÜU(¶Ú0 ãì˜B•íííJXƒd6´aÆÙ1….6 qW¡°`@ŸÅÑ·qjèümmmUBÐ0*Sèb3==w ËÔÔTÜU¨Px´Êþ3ŒÊÁºØ<÷ˆ»…ncc#îZ†a”¦Ð1PÆVNÙá†a S蘙™)×7µqWÁ0 £L0…Žä‘Ž»ѳ´´dÓ” Ã0¢Â:ÊÒÖ¼sçNÜU0 Ã(L¡ã[³ÌÜzlzÄ]‹ŠfppðéÓ§|Æ]Ã0¢Á:6FFFâ®B”ܺu+î*T:/^¬¯¯Ï3ηaÉÇ:6ž?^6f´Іa‘c '½½½å1©»££#î*†a”¦Ðq‚<—Á”±¹¹9›Âm†9oÄ]Jg|||pp°tßÒɰ©I†áØÚÚŠ» ÆéI§Ó‰jM¡ã§££ãñãÇq×â”tww—Ç@}0333==M‡i`` îºT<ù+++SSSûûûlŸ?>îÑpppPUUÅFOOOŒšm ?›››sss}}}qWäĬxÄ] ãwìîînooówEÊ'ÌÏž=£ùžŸŸ¿téRÜ•2¢goooaa¡¹¹9å-eŒEªí=t" §Vrá4h§0 ã®…a•¥¥¥ººº „™ÎÐää¤És¹‚ ÑS4 úúúâšB'…ööö¸«p2l|Û¨(677kkkvvvL˜+ I5²›7oÒ?+ZÓg£Ü‘‘N§/_¾|êݹ彽½tÌã>¼à¥_y–óíììŒû$ #/4\TUU…9e/›+™›KKK´öôØŠÐK3…ŽŒSïN+P__¿°°ÐÓÓ÷©ÃÊÊÊÌÌ –„µVFÙóüùóææfŒæäÿ1â€H766Ò\ÏÎÎú©°QÚa•&ÿ…4ÕÃÖ§ª&ÏIC£8|Æ]‘ò3mqb£´ÀzÞßß+´×©sGGGqŸ¬ñolnn¶µµgüäÈÐç¹´Ë({茶¶¶®­­%óÏhÄíaKKË7h tSèÄA»@·="mòlT<íuuu&ÏF8…nm”;qÐ" ψt¢†»MžŠ‚§}bbÂäÙçüùó«««ƒƒƒj®Í†N(‰²¤÷ööš››Mž ¡··—–wvv6 uKKËÎÎNä.M̆N(²¤[[[â­ Õ¨««[\\4y6*øíím“g#°¦äp7ò’͆N4š‰påÊ•¸Ú‹¹¹¹‰‰‰­­-›¹|ööövww“æú¿ähjjº{÷.mnÜ1J þz4•Ñþû̆N4èâãÇkjjh5ŠüZ𿾫«kccü4” ôâøŒ»"%ÌÒÒRÊ3‰â®ˆQzð×ëè舶LSè`lllqq±½½½hÞæ8Ôèè¨õÅààà½{÷â®…Q’ܼysss3Â2M¡KƒK—.mmm½xñ¢¶¶VÝüÁã•N§±×1Í’0* þbUUUöŽÀ85ôðîܹaæõ³dÐäRôÖ­[<lGëÚZ%³ aÚlT sssùL‡DÈ)uuuö&ÈžŸ‘‘‘ 4….1ÐÎÇKMÇÇÇoß¾ÝÚÚz–^¿‚ݪßgdŒJfaaAqÃihh¤ìîîšåm¤¼(X555ÏŸ?j•¬r—$ÒéÅÅEºóÍÍÍt᧦¦N4•ŒÌìR___[[K«DQhòl”:§ž¨±··—ò^'›óò+d7ó4y6ÎÖ´ÕV勺ÿPUU¥iYsÞ¿ii ]G›ÉÓÓÓcKÙ`«­RÞt[[Md®¿@.è°ª«šÿ..\ CÀ.!Ç¢+|xxHÎ]Q&†ZñÇÕ¹¶6ž,\¥îîîÌW!§ÃºÜ ™^[[sÏÇÇù¼víš¾"Ìg7Œ$Ó¯QhòͨPðƒüC ç---l À!¢Å?Ž¿$•988 ß˜;Òßß?00pÒ±+ʤ[Àg±.êï8wîÜÓ§O‹ÜÒBáJé+GSÜ‘QÖŒzÄ] Ã(Hˆ¿}Óû |v:Ñ?Ev3ŸáÙ._¾¬b)ŸíÀ¯Ïž=CàOzŽ”ÃiFuŨÃÄÄD®_©½ ms¾÷tôôô$ÿˆ «½‡6 £lÙÜÜlò8v–Æêêjþãš_ɺ{lflh,{òk–/6è;wjkkùDüPG6êêêH×RZLULy2ÌÌÌøËY[[Ãj']çB”­»»û¥|•K!ޝSSSlk— .° _Ù (G:ùÉ©ýõ<ç¡SÞ°Äàà ÅR=vQµ‹»ýlh CÅò+`Õª«««··— èúŽN~å«*5ÇU9œZàÐ|ÕÅäWN2•™k²´´Äï\pÿãx~m.·aåŽ|Ë#ÀXŸ¹òh¦Xž =ˆÇùóç›››]âÁÁAUUUffZ|ÚzÊw³ØäªïÅ‹óóóJA$äJ/‘ vás``À•ƒ†q (º4˜íííIû£GäÆÀÿT’Ïá(œ}5Ie||üñãÇ’ËÂööv$Ae q%LNN"iËËË\@¾JÃø¼}û6’ÆéSt:Mùþwgä¿téRCCåë P&;úw‘kî_é1°Ëôô4¤sFW}ªGUÉÃî½ÄŽ×î*Š]¤Ê\ ÎÝ_yΈÊÓ âćf—+W®¬¯¯»ÙûdëëëãW.Ëáá!uæèÐîˆù?r_ÉëShÃ0Œ“aʧ_>Qѿ̹fd“7ÀêêjTä uwsÇöňw»Èš÷ÏKGþ`l$Dö%ÛOž<™¥ëÞj»y (ƒä;û²ÞC¯Ïù$›ìTŽu5Q%ùtbsíÚ52S1 Ÿã’Â.þ¥äìÅ.¨¯TŸŸÐÈÖÖÖŽŽ·‹¤QO7÷mww±äL9»ýý}®WƒZ¹WïútG—’rãÆ Žâ©êsD áÄýµåÐ|UïÙÖîtSÜÕ!Üü¾_½›BF™@—_vüÊQ9 1¤ÓîsAF^&'rÕ§y@~½ÄÎË•Y£ÜH¬D𔀩ŠH‡Bê íAcP2¥`RcÞaR2¦!Û²ù8ßÀ’3NœÂÑ$ŽâLL›!䇔g=c¹R,é7Ä5º <~Ȧ©ìœ{æà{aÔj ÙýêßáÌu² †)otÛÊÙuuuqš*™s ?º{$d4#ÃCsß{ï½ÌîŽÎüü|™®^½J” y_Náô?ÐTîrÊ3Í9"’OGùÄ^ÄÀÕûìÌîÅÊp×W²µµµqŨš„x³§™+Et;’Î¥«­­Í ƒK6LçÀ«_š¢m}}}Wûþ]2%ßAõ¸\Ü‘û÷ïs\jåb;’HO¥··7äè ¡(ʇf›«Á¯‰ôœ,¤©©‰t®3_ÝA†¢RäyqF‘±¹Ü•7šteÞn½ø—¢¾¾Þb†Qd~o¦ÍPOOMd5P¦êêꪪªÄ> è%½I©&ò¬0JwýKmïííuttd¾QÖ„2NP¶2z¯Ñr-’f/NŸÝI¬­­¥(Òõ–:îS7~Çýû÷yâ®…aSh,Ú \Syé¹²QÈêê*¹ Fsgg‡öŽæ5î‹`A±id/™ªÖÖÖ0‚Q”ž"º²²"W—¤«ÎüJý1¬I £fGJ@zçææ0—Ù‹G—?{}øá‡lLNN =yò„œzhmÍtBØßß/lÃH îtøì°\{ùñÓŠ…”F»©l´­q¿‰7r‚Vq§â®EPÍ”ç(íðððòåˇNÈtüÕÑÿ"&ëãêăÑ3Žz <Àq_ìg]9¢e m”=¿Õ˜ü 5‘à7[|NÜšT}f6ŽjDd–i;ü±£”ˆê5ù‘ïI¥J‘RrDlMrÒ'xðàÁ‘§ÁÊ™U¡%Ü{Ñ.S>yØ¡¡!~ÒŽlSìrmp,ùÇø½Ké)4û¢¬”¦™Î®’: çˆîD\=ýE¹iJª3ÂL6ê£zbd­mÒ)α‘4ª2®Oý&Å}Õ†?l°¤”t7@âÏÏî3Ú¥ûóë ÚÖ;ou³â¾$¿G¥)´|µÆ]‹"a ]™¼¦¸Uá H677³Ÿ‹Ü;ltkkkK«K•(Y3­ô¶OŸÕÕÕ)oÖêêjàÅ!_—––ô²ðÚµkäwARÞ›]­ÈF >55EÊOkkk!'566†µÚÒÒB¶Nc-Uî49Y®îDØ ?{e.åÐKëϯš¦$ãÛe ´þþ~ªº»Ä|¢Ðë%(eªžÔ§hî—“ང³æ9äq…gff4YLÕKy‹¦f<”î÷.B;ÎWÒõF_Ó é*‘™ôîîn:=þ¹tåwóÂØQÛn>Zà¸QdøGäóß1ŒÒå5tñصË4èâÚÔÔ”òZ(¿Œ¥^µ’@:šä„6s&0ö%»“xîÜ9Ô””?ü0å)7š˜”ÄW¤sSÓÓnß¾}çΔ§Üü9i.ýI£ÉW”O~ºzõ*Ç"g®àmmm0µE~¨'*Ô¦¿ ȃ4’®vŸœäŸ}îáÏIãN=ù•s¬©© ”ƒ¸Òî“ãîyäºàœËÇGFF阳ªgê•Ã"  ÌÅ9VzZ4Q™ž€¦æ!¨.ÝÿÔш뭇¾ò„ É\=u¼Ø%àõÂ¥ë+½1òß¿QwÛº¹þ—I€KËýËK b”7¯moo‡¬ ´Jh‘fŠÉJögÐp±´YƒÒZñ,[ÄŸS(9iã(½¤²´’¤¦£RZù*hz9æò­[·Ø¸wï^Êk‚Q;—.\@ßÿ}4!¤æ¤“tzþÿ35äD®\¹¢~Àââ"¥“M]·A766LŠ"…«®S7¿Nð¦3Í7e’?õûƱæxs,öÒШpÕÍâäArjkk]µ¡Ô“ž„[S^biî5×?•mC;%¨ló$´´´ø3`ûÊg§ÛÐ3IwНêTùókª¶¿ÿă§I‚n›{'/f¹–Æ=ΨB<êËé[…œ¬Q±œC9hôé„377G«Š."ºúãÆáñˆ÷!‘KmDQ3 åSŒ;Ž0S+z=¢+& Çdïèè¸zõjÊ[‹EGÁmÓMôWÉ(2Ü}¬ ˸+R$hÙxÞÂ=ÉåÇkg/" Ð\Ò¡ÆÐä!îëë‹»:eÈé<®D…†ôý¯cÜ(´Æ½±­#å,_1nަ³[o¯K+€t9Áݹ}ûvܵ0ŒÂr.åM^»F¢Ñ8p\n:°\«««ùÔ¢»¬y°-"?ô³gÏBÜÞÑ#|þü96´‹Ûazl###~ÏEeÙЕI™ØÐFijjŠÄĤ!FžµÀ=WçÒ.Z2§ûùÑ*M_ˆ¨®[© í ™8@QG+g|Û¨dL¡+¿cËB€Ì4yD¢7ɉÎ7»&| G’9¨œ±ë¼;×ÍÍ}+hõ 6q:ÎG§‘gÎqvvÖ€•€)tå2==]„ðÏÒ›Iä ݯ‹ˆ³\9 Œ0ÍØvfïÏ~ö³”÷†[ë먀;õê½x–½éºÑÉÿºíîîr­’04¸’µµµccc¹Ö°©‡D†€CuÃ(W*Z¡µºº\˜¹\;Fò7’2Ñ»7ÿÒµÀzhÙÓþEÌÑB‡À½òôo¹"8Kÿ¦´@›ÇÇÇ«««:Íé+þ=3“g£rH´B«ËLó$o)Ïâ/Úßß/ùÖ WåÄì …üZÒªÕ±” u«kkkdÐO½½½l¸ÝI'§+Šürþå*CfR4„è?tÊkF5ÐJùd@0ØF“´D›bå|ÊÄÀiúÓu":Ç”×6éäëJu£|ÎQ 5îÇ¡ý×J9ÛÛÛ©Œ\³¹jhm± ,ò =ÖHÊJø4rÎtrròÚµk…«6œ[—ïßÖRõ"tƒÎÒ¿)EœNÏÍÍéÑÕË…“Æü6Œ’'nÏ£9yúô)H>;;;5çœ~ôâââãÇÏŸ?ïÞ½éééææfyÌ&] 0ØÀœºyóæÄÄÄìì¬\Lyîšé€Ë'¶ì06ä€s}}Ý_”_»ˆ$VUU=xð€ò<à.¿¾’™”ùùyùF–m æŠá?bÀW9¿r"TR•RžÇ¾Êë8g!_ÜZucC¯T ¶¹8k%;O²(ÍŸºQ2;*ÖH>7"kDð"ã÷ÀÌ•WÐI¶é…(ö”t;¯Ô»»»œxæ¸7ONž«tt;ä¤=Úmë(q_•2‡ÿ—þ­q7Eñc~¹+“ßþ â®CNÜCébW¤^…”pÞÄÔ§–t½Š|åßWÑ”(g^ ·åÂcø‹âW•ŠÀ¡`ŠšÔ!Þ.§+jjj½Šbihü?9tjj÷Ý9º{säÉ?¦ƒ» þû%m–C·k¥´ú¤ÓÀŸª†sº B™ .µU¬°‘@WOÔšÞÉ‘ö#PEa9Vò9œ ³vÒ3*Ðu+ÑȺŒB¢ÜV&¦Ð•I¢G¹ èŸÍ«™œkkk’‹¸•‰›Z¢¯<â¨ÝÊÊŠvµDÕ¿!sY\!YwlärIˆŠµ(Íá{ííí)øUÖÒÜÑýÕP!º Ê+u®cù¿~R¤‚ÎŒjL[þÂüÓ˜[[[ÝèË—/;::T‡‘Sv­ý¹S^ÌSJxôèQÊ{Y^ááa·ŽË¿] _åÅ/ŠËbcÚ†‘ÉqW Œt:]–Án#iŒP,ÍW××r½V)oüŸ+&h™] dr~~ÞõT>|è¦,--i:)¤+QÛ333+++tz6kkkÜ}Pœ>|¨ÒäoR#çþmuï¿ãezzº¡¡!05Á0ŒÒ¥fŠå¢®®.‘ÞÞÞÆ"ÿ… ÒHbmmmøîg gÄ¡å?DÐÚÝÝEó\t¦L”§×°„P½kG‡‡‡•þÞ{ï!“<vk~yŠííí¥üÆÆFî—ÛV¯‹NƒE†6 £p¼ÖÞÞ~ÿþý¸«‘¤TÖ§ÛHùì]ùò”]j3‡û´ò˜Æ—5†É†¼‡¦< Éí¢yINËõ¦ÓÕÊ_l`hÑ_²?Üz †´ò|ð¶ÉÌǸJsvd ü‚ÂAå×%Ftï–––4EÎMÛßßÇÞ}ñâEäþ±åÆ|gg‡#nnnÒmrÛ ·•§÷PÃ0ŒÓñæcæÊŸ„@›(ËIh0ÚvîÜ9[ZZ”ŽAƒ)# ¡õÔ×¶¶¶@X@ ,véééÁ˜fdž††êêêt:½°° ˜\ ~ÒÚùÜæXäQ™“““lpè@„`r655±#EQˆJVµd¨óðïÕÝÝòFøUñ$§OÅt ¬7²ñÙÑÑ122ÂgʳíÆÇÇ‹pÔ!(¨ç¬|@’5¤˜²® ÞŠœ¡>fº[‘ŶîãÅ‹]¦e†q^C±Üœ„ƒŠHSaÿ qÊ7©IþñŒ”>xðEÉŒExãÆ 7@ªÁä«W¯¦¼åÂôTdΪ4š`6úúú\ÈH lR¾Üp:PrÒ^çó|üø1ÂÎ ìˆø‘ˆȯ®VîXHÅÖÔÔ¬¬¬,..ÎÎÎbý#ítØ‹“-ÎGZ„0Òù €K\:isñ¹ªZÙ9ôè<]¿~ aÖ¶î”*÷%1 £œyC3`³®4M \A£ùäÉÍãõCs‰ž¡Êýýý¨l@ðRž+ #æµÄÛ?û—m¬ØÌÛ(·LƆã(ؾäÌáDéÃg*¡µ!Az)?àSElookè[UB“ÈÆAù¤œˆbfá²OMMeÆŸˆΗ+0>>Î-¦¦éåt èßôööÒC ŒšœÍÓV|°”7[PÞQ¸Ë\üDÍ3 £,ùíL1Z"-Iét¡B ÿìÏþ,å 9Ò ß»wOSx²‚ ²Mj¦‚brÑȾ÷Þ{Y-Bú(H‘^vÒÈZ8Æ4ö+…ŒW·Ð”%,-9Áà«¿pöâ3°8‡šhz0ù#˜û…þ„<~sØþøãùŠlß½{—‹0þAÝbC§<ÿ_è4§ÏÍRŸÒõlx†#¬'Eéap†2wyuu•Û\ü¸¯DäI­\×Fò[…æ/ÌnÅU¤-þðÃõ ¤ªÈË—/_¸pDóÑm("Šu…¥ëŸ~EfÚVtŽ–wqq‘‹"å9•TD¾¾>T|vv§(½nt@JÆb thŒ¹¹9ìrE·\__ç+]btt”CcÞ)ä³ê©b5*òLd¹ÊÃáZ[[9º&W®\!×_©a£GÀ“e!@žµÒ)Þ'Á¡ÞŸ ¤hÂ×\¡¹Î•FY2·¹ÑŠ™ÁFfº |ÂQ¸Î)o€ÆÕ[ZZ4u€»œL¯œòäjî3 £|ã’òpÖ¯)o Ai…µ]„ƒæe98;ô©h7+™†‹7JÿF¾èßp#¸8H¯ ’u›üô±è,3îˆî&éra¦lN’{zzâ>{£1Ÿb•ÉïÖCß½{W3„KšiìNSlP½rŽ»FÑ311ÁidžÓkÝÚ‹TIÃZ—<88¨¯ô]œ™k;å¹ “ÐÌô÷ß_Ûþt޲¹¹é?®aFøBÓôе=å½6κ][[K/çàà€nœ?¯ Å­—nq|uuµ2ð)ÚCe†‘òû›žžîíí5݆˜››óyL }}}tV°ƒgffèLðݥ²wsmcoz,//ûÓùʆ¦ ¤<¸Z 744´¸¸˜œ÷ñ†aTþ!oìÅ 2*”¯ªªŠÏ¸+’WU] p¬ê¨Š}üø±+Qû,óB!¿øŒ»"FôØ{èÊä÷ür뛜ËË—/ëëëo¾k½)m4:­õ Få€88hF³a ᬩò‰166†Ù±µµe"]ö g###Ø‘å¡Oô2‡~ü¸üä¹ÒPÖÌ «†a”(¯å“ kssniiYZZ2©.]¸wÜÁîîn´™Öm.¡iÛ†a•ù£££íðüùóééé………ºººëׯ§<ýŽû,ŒcPÏ”÷¾9N uvvšÑl¥ÿ_…¹‹»"FQ9±B;êÃÃÃÕÕU}Æ}.FêëëS)…¯Ž»R†aœ SèÊäSïé&ý677Ç}†a†QnœÞ†6 #QÈK:¶•cåA[[›óáúòåË/^8»èÂ… .JºQÆä5SÌ0Œä3==ÝÐÐÀgÜ1¢a```ûÏŸ?G¤Ý×7nÄ];£˜B†a$‘›7of9þüÈÈHܵ3Š)´aFBÉ:"rûöm›ïY!˜B†a$”L3Ú èŠÂÚ0 #¹ôØ èŠÂÚ0 #¹ 8I6ºÒ0…6Œ2appðéÓ§|Æ]#JPeìfm›]iØzhÃ0ŒDóòåËêêj6ö÷÷M¡+ŠÓû3 Ã0Šª<99©¸ëb³¡ Ã0 #‰Ø{hÃ0 ÃH"6Êm†aAž?¾²²²¿¿Ïö‹/jjjØhoooll,Úëå6Œ2afffzzzppp`` îºF©²··ÇŸm~ùòe®<—.]š˜˜PHß‚b£Ü†Q&ìîînoo»hH†aœ”±±±ÚÚÚ¥¥¥yNyæuwwwSS­)´a†Qé É(îøøx¸6ûÙÜܬ««[XX(\­L¡ Ã0ŒŠSÓÅ=ž½ª˜)´a†Q¹`4···ïííºÌè¹¹¹BÔÍÚ0 è\º»»Ýëä#õõõÎÎNžóçÏ£â!…ô÷÷ŸÎÇV[F™N§/_¾ÌgÜ1Œ’aiiieeÅŸR___]]ýàÁƒ .¸Ä—áEuttD>OÓV[†aÃÞÞÞôôôØØ˜KYóж?œ4úoäÜÞÞ>6qffFM<ݬ@:}¯ÖÖV—âŽØêáÏ)™Sç¢ÄÁÁÁ@üéJƒKíßF»ººjjjúúúšššž>}úäÉ®ÛÈÈÈíÛ·üãðÁØÓäáS«¥5¯[»ÏÎβc„Õ3Ú0 # Œ§ññq§v´éè+J¬¯ˆb]]M6éäDÿüú*Í&¿?‘f=¸µµE‹¿³³Ãvmmíµk×0æ”srr²§§Ç)19Ý¡•ùÒ¥KJ'';Jt©ö³gÏü9)°ªªjssÓ%677766S¤9e—¢ÐLMMÉåHVö<‰\ÃÃÃÃ]®!…Â6ÊÓ­ávè¶´´pÙ¹þ'ç§húwÃî†aFV0¤­å¨‡ÿW>•Î6ö®÷¬‰| $ºB0£———Ýá”ÓN9µANÞ¢JªW1m#3ä¤]~‘ÉeqqÍ \‡‚‚E{ AÔ¿wïž»\ºSlSÒ)6w›E£ªªêàààD»D{¯ÛŸÙ0ʃµµµ‡–ßgQùë¿þëÏ>û,噤o¾ù¦õ«_iͼ­­t¶ÿöoÿ–œß|ó» Jüõ¯íOD>ùäÙëÝwßUâ_|Á¾Z…åî£rþÆÃå$çŸ~ªå^Zé4æ<d£Ì·ß~ûܹsßùÎwÈé†Qà¿ûwÿNoR•ÈéHf¦ä3kâ/ùËÿý¿ÿw.¡uP&G¡2tÿùú!ñÅ‹_ýuÜwûß@ž}9CˆØ …"&4xDm…"4t—[!„¨D¤ÐB!D%"…B!*)´BQ‰H¡…ˆ SSSmmmüFmˆ"¤ÐBÄ„íííõõu~£6DRh!„¢‘B !„•ˆZ!„¨D¤ÐB!D%"…"&$“ÉÖÖV­Ë-Dl8ñäÉ“¨mB‘T*ÕßßÏoÔ†ˆ²"Z!„¨D¤ÐB!D%"…B!*)´BQ‰H¡…ˆ ét:•Jñµ!BˆpB &''ÛÛÛùÚ!D8H¡…BˆJD -„BT"Rh!„¢‘B !„•ˆZ!„¨DÞµBˆpîëëÓ—3„ˆ Rh!bBƒGÔV!BCw¹…BˆJD -„BT"Rh!„¢‘B !„•ˆZˆ˜055ÕÖÖÆoÔ†!ÂA -DLØÞÞ^__ç7jC„á …B!*)´BQ‰H¡…BˆJD -„BT"Rh!bB2™lmmÕºÜBĆOž<‰Ú!„ùH¥RýýýüFmˆ(+ò¡…BˆJD -„BT"Rh!„¢‘B !„•ˆZˆ˜N§S©¿Q"„)´1arr²½½ß¨ B„ƒZ!„¨DÞµ¢*ØßßüøqÔVÄ»¿m÷º£¶%ælmmõôôDm…ˆ?RhQ*–——¯_¿¾°°ÐØØµ-ÕBkkë¢GÔ†T Éd²¡¡¡»»{hh(j[D ‘B‹Á]žŸŸ¿téÒµk×&''é¿¢¶Hˆ²±±ÁÕ>==}óæÍŽŽŽ¨Í±B -ÂynóxüøqMMMÔæQrš››çææVWWÏž=;11qþüù¨-ñA3ÅDhàL$“I\g:,ɳ¨*ðž···£¶EÄ)´¼çÎÎÎÛ·oŸ;w.j[„ˆ®ÿõõõñññ¨ 1A -¡««khhHò,ªœ¥¥¥©©©ÕÕÕ¨ q@ -B`cccss3«ëJ¥–——µÐ•¨jjj&''/^¼µ!"H¡E¡àœ®ˆNCŠX²#ó¨”ÇñêU©=¿0N!UMœ£Ü )î¼SücÖ½½½+W®Ô××K§Å¡B‹|¨Í Ož;;;3'oommñûüóÏÛêKtL»»»ù³CÔÛÚÚÜ_Tß¿^øüü|žÃ‘âpŽûaKšyT»Gmmm 2e)dÀQ~P…⦪:Wœ£,ú]Üy9¦p%gÞ4â‚1žÚ@q˜ñV4Ì&ÜÌ Œlp”U©egãÿ)sY™ÿépñ‰ìªÅ_ÿ»»»þÒùsÌsIçi#„8¶84YQuhM±ê‚errrzz°¾¾>«ï›ŸL \__?uêTfLœf²¢kii¡SëììDêr¥L‡ˆmD¦ÿ2‡·˜Ó§O¯¬¬loo'éq²îeÔràü5ó“Ìž@Õ555™Öæ9œ©F´oÒ¦qáìR"›ânlnnZLŠ“õ+IxÃ8©þ{f6gðêHÁhòLÙT?ægÛiüì@^;;;n€•7óö¬Ýgv–¸ ¡tœ_³$PÛYkØD¡åêç@¯Ñ®aqsGFFÂ}„tõêÕ½½=Û¾~ýº½æö–èq•¨(4S,ž˜í÷e'''Ëó¥TmfˆÐÝݽµµÕÖÖVÄÚ¢BT>»»» õõõh3ÃßÐÓ·oVúCÜßcý ƒ(ùбÅïF#ØQ½{ƒ3MGC_f‹G]+qæáÇ‹‹‹ Œ².“.BÄ­ißÒÒRº¯­1—õ#§4gÍö¨äCÇ¿}”Ïúw£;°H“ññqyÖýÏx`«·Üè„ç@Kž«Í‹3&̹&Ž !*÷å+?¸E™‘BÇÓæ¬_bBT>æFûCä@Wzs솧n{Vétz{{;™Lª÷2ôºª-DL ã¶OZEmˆÿS*9ÐÕ†Z!*÷àYO « )´BT4æF·¶¶Ê®6¤ÐBQé\¾|9jDè}è˜ÓÝݵ Bˆ£R¢•Š Gs¹…ˆ SSS“““ôãz¿Nˆx »ÜBÄ„íííõõõ¨–wB„ŽZ!„¨D¤ÐB!D%"…B!*)´BQ‰H¡…ˆ Éd²µµÕ¿†³âX£·­„BˆJD+–„@:¶÷Pýkò-zØv·Gf8îNàÕÕññqd—x®øSSS¸M™Ë’ä ç73Ó·³–NŸÌq"ëKÖR‡le ¯5­¯¯g¾Åž«•e 'S÷¢¿¹Â9:.QY<Gƒ«nnŽš\[[s?¾|ùrëSض½ðžžwÔÞÞÛ oy?:÷îÝ Ä'¦‹ßÜÜìŸ',œt‘[}ð—e†cáÎ*ëM¢®{!Â!këã‚÷·>kÄ$<³ÕX«|r˜VæâÓšüñ\­,k8‰Ð9¸ôGFFˆfáþŽÈŸäè¸D¥¡Nö¨¸õrýº5†@œÌpëüÛ>ÂÚU ¾e”5~žð'Ogd&ˆcã‰@¸ßr¶5¼q"k«±Á´?šµ>לán»ÀV–+¾‘«•e Ïì,Á<%ÊÚq‰JC3ÅŽÊøø¸kÞYikk»råJÖðöövÿß'yçQf|×\ O<"äJ?•J8q"Wøúúº?Dëø‹8QHëËÚ:2ÃÛÊžøÄ2óPáŽ@kõ‡û;¢;.Q H¡KH:¦ôõõe>¶ðÂ×O¶gN¥[oyjjjvv6³å/..Z¸žTU>\otßüFmHܰçÊ™­#Wx.\k*‘Öád¶V®ïè;¤Ð¥‚V±¼¼Lƒýä'?ù¹Ï}Ží·¿ýíï{ßûÞ¤ ~×××ÝÛÏö&b œ ÷†b:þã?þã‡ç{ßûÞG?úQK‡>"ÿôéÓdäâùµ×^sO˜r…'¼6fáßýîw-œôßö¶·‘,ö[fÏûßÿþ@8jJ¸•ŽQùßÿýß“xÂSYŒ±ô ·‡ ™oj*\§‰óxçUBÖÖuuu´‚Ï|æ3®uXë£!d O¦•Yk²ø´&âZS®V–5ü›ßüæ—¾ô%KŸûûû­_ûÚרå:"ì´ð¬WâéU”ð¤Ý¿>]®pªÎžÇëÂ+ZSì¨puº'Œ‘Ý£âBƒ»»^çÎ+.<Ở+<áµç¢Ã†3V°íÞÞÞÇç Œ².Šƒ¾þÊ•+YXˆü¶•%ŽÖšBieyÂýN®ð;(âyÂ]ùa!…"&H¡…ˆRh!bB:ÞÞÞN&“šx/D´BQ‰H¡…BˆJD -„BT"ú>t I&“¹Þ°êèèXYY‰Ú@!ÄÁœt<ÉêFGâ@ollìíííîî.,,D]+1çáÇ‹‹‹ÝÝݧNŠÚ–øÓÓÓSWW×ÒÒRSSSº\²ºÑr «)t<™íïï"ψty `|011133CvæÌ™¨ëCˆ’ÀÎh¸¯¯odd¤é#ψt ðÎ;äuÑE9BÇ–€]6zmžšššœœ>>n²Î.Ã8[Tò¡cntwww6ÃüçŸ>ô¾IˆãCÕ¦¦¦{÷î…;T¥}íììÈ®6äCÇœ¡¡¡ÖÖÖR粺ºº¹¹)y¢¦¦frròâÅ‹á&{ãÆ Íê¨B¤Ð" ¼‘žN§»ººp2ÚÚÚôEzKúúú°¦R©Ó¬««‹ºX"¤Ð"ÐÚB^д™ÞËËË[[[ëëë---iKÆÆÆJ1¯[TRhqTPܹMMMáC744ììì477'¼Ž,ÿ!&êüºz{{ývwwó§`8Šc[4Žò!Hcºººfgg3—lsFVØÍE˜YÕÅÅÉOén¥ötLy„•ûÀÀÀÌÌL)Ê%ª )´8* ®†0'¼%êêêÎ;Çöw'&&ð¶]×¹½½íŸ,ƒúž>}: D G±ÎGííí¹¿¤€0SXÃÃÃÈ...–ª– ë`û©À"R Tõ¡â8lrò‰mþ‘ÞŽm°rç"×éâèH¡Eù0gŸi||Ü<Œžžžü‡ Í}}}è´?¯Ýº¿šššO}êSH§Ÿò`ÃE"dN±ñDZùõ¯n3ý0z^Œgxaï§RA ˆ‰f[IÙù….å̤tF²ÁQ'õ¿%SM{ÈÅÙÌvgg§íMxs÷ü£Ÿ ¿In)»ôm;ÓTW"+¯Ã¥Oœ€%öK^²Ýñäß©¿¼¹ª+P¥þ]nÛ;×γ«r)(áf°;)®°Vÿ‰‚©ÌÛ*â8ñDÄšËYw­­­±«µµÕ9âU”+‹Lº»»ý®¬¬ä‰¼´´„¸âcñ{çÎ+NÂ[·!á½äMìFé $¿ÈƒmÛ!D ÅôI‘ !YX"üµcÙk‹À^eBxcc£YÞêÁ_´,,wÒ¿víšåÎ_Ñš=HͲ3{q‡4xPvg*Þª3Õ& ³ËÒÙÙÙÁ³hT²¥€=vUa5Ɇß¼F«4~çææ,‹`׆™J¸¥æªÑ6,ÄYBÙý–­££Ã_† ËìÀ„7è±åçØE­ÖÕÕY±ÖâÎ)ÅÁN‹cvúwù·ÍB+ 1­˜¤iž?>áùÍ–Bí3ì¤pEp•Fþx©ªYŒŒpAú îo­V¥¢ª]u0®Ç L&“W®\ÁÉÀ™ð÷SE`ªY < ¤'MxK…ç€ý /`!}%¿W¯^µ@¡k²µµ…çDàÀÀžÓ+¯¼‚£C|ýúõ\)ß»w7ap>(‡Ðõ›#HÊtÊ„ØPÀÚÐçqöìYó«°mssÓ-ªúòË/s nݺe!$Kji—ŽÝ¶Ûªd‡hqˆóÕ8ÄvQvgª[©j~~!´ ÃÄ´£(/Ö’5Ÿª ‚{:À6á¤FýøgÝÏÌÌp ìf>$KâöK‹@âT/áØséÒ¥¬•ùÜsÏa‰­|I.ÎŽåê2K\m'È*|hhÈ. Žå@B8˘aÖb‰ÿ¢MxOIZZZ0ƒqÜva»üÛv yÒO)ˆUùbRàQ±=³g6pRÈã)‚ +‰Œy£££…_í…7"̳Ëfvv–¶Ùß߯›ä"¡»ÜÕ}u^tö…œ£¿d‰ºÜ¿¿ðøô³&„n¤”n7pKÐnE>ÿüóló»êáö¢ t¸¶ÓF—M¹[ºT[| ´ÇÞYÁ`%d…cs ì.7Ý7õfý»½nî^†áX, <ˆµJö?æDEr¡ÔD¶ÃëîâXàôô4ýµÿes ijj¢COx›Ý^÷`SM „™1yùgÝ£FÔž«Æ®®.¿”bOFf?õõõ™uÒä‘9á‹òšÙæ%ç¿*ìFŽ;ÅXƒg‰L’û®‡âqr‘Ø. Ü¿mq¸HÜ0‹.‰À_{`Ï…ÁIqiPì´ñY¢8¼ˆ–EÖ\Z¶¦=—‡æš )tAƒGMésј£ßÙv 3™Ÿ°ÍÞgÂóê¬ë¤3Ežé@„÷C‡5þâ›MßÇß—^z 1v‘‘%Dy£\cccÖ™úûÙx“t…Ä ¸¶Ia¹dî²ÜQ2º~¿›Df¹ç©RÀCÕ(>Ù™60n°np¤—_ ‚Ûg_6 ˜JuÙãÕW_åÌÚsSŽrÓ”üUjŽiÀ¤pU­†Ù°û„?zôÈ"ð×NM ‘»wïšm.´ßn;'‚¤q= ‹%œD›¥OõÚo“[6°ÄÁ¬¬¬P|ý¤@)¨ ŠfŠ]uQ4wÿ™‰Cdâøwù·ít°A%c ¥°œ;eKŠCé8¼¿¿ƒý'…«ÅîP îz(Å¿M-qaPíZª¯ª‰úA¸(-6ÿÅ&[Ñã—(:ÜÂgЄŽ=ÇeãÞ½{6áèX“𦶅ž,'¨ð }"òl !Äæ`S.h¦Xuò–¨G¢œ>}šA}è޳ÞÚâg½ñ[jÌïÁ!ÃW“Ñ{ù o2jCŽ%øåö0¢Èûûû¸àa}«†çòòr[[ªu5ˆз­bŽ=LžžÞÙÙ)éÊûöIz“Ò„¨|z{{Ñrÿ-ú£ÓÕÕuæÌ á®õ-*=‡Ž?6i¥ÔÆqƒ}ÿK2BT RmbW¸òœðf­çyuPÄ)tüÙÝÝ=⤕Á{^ZZêïï×7Dµ‘N§žÚ:9¡'Î[Ë“U'Rèª Ï»¿áÒÑÑ‘J¥’Éäì쬺{666•655]¸pÁ¦Á‡•òÉ“'OxÔÖÖÒ”Ö××O<Å? ]ÄÍ‹?eþð;ž´-¡e+Xµ´´ø] !Žöž7WøÈÈH)\ç›7o"ÒYwø9vqÜÑL±˜3>>í<Œ½½={_9êʈ9>\\\ìîî>uêTÔ¶ÄœúúzwÚ+ã¥Ë…Î\÷¦¡¡!ÄÏp‰JF>t I&“ŰNœ8ae~mÃMí.Ûöª…Ñ <땳ØÕ–]=è9t ÉÓ€iðQ['„(”̯˲ȹˆ RèBκìöß’BTQµèªB O²6c9ÐB;üëææf9ÐU…:žd.Q"ZˆcŠ[—bƸ¨d4—;¶Œ_¹rÅýµÕü£6J”t:½½½màŠÚ2'OžÜÙÙqÿU‚:¶ìïï×××Ûš!åŸÂ-„‘ååeûzlÔ†ˆ²"…Ž3Î.ÐþÑ~ôíoûµ×^sßô¦ÿ}òÓ?ýÓÏ>ûìOüÄOD] !ª†Ú[[[~–ÆšðæææøÃ„šðñG gÌ.äÓuÿýßÿýïÿþï»»»yâм?ðèªÈ~ðšp`!„o}ë[ögVMø!…Ž9‹‹‹MMMy†Þo¼ñF*•B¡ LFþ¡}è]ïzWÔ%Bü/…h³éô1B ]Õ|ë[ßZ__ÿÑ~tØßýîw£ÓQ›/DµÃØzuuµˆ&üÌ3ÏüüÏÿ|Ôæ‹ÐÛVÕË믿¾¶¶VDÛ†o~ó›_øÂ¢.ø1¦¦¦ÚÚÚøÚQ&hŸÿüç‹kÂûÙÏ~¶¸cEÙBW)o¼ñÆ—¿ü壤ðï|ç+_ùJÔåÿíííõõu}S¡J  ±=Qj¤ÐÕçÏ}îsGOOú[ßúVÔ¥¢ê  ws;ž4­8êÒˆœH¡«¼ç°în1×2!ÊÌ׿þõüà¡$õÕ¯~UM¸b‘BW4ì§}’EÔe¢Š@PCltá¦&ÂE߇Ž´·/|á ¶^AV¾ÿý#Íû}ï{_Ôå"&Ò„Ãõz_{í55áÊD 7VWW|¹ùÓŸþô_ýÕ_}ðƒüßùw¼ãù#ã%ooo?ûì³¹"ÐY¼ñÆZ®(r’Édkk+¿Q"ŽÄW¾ò•ük%ž6áúúú?ú£?:zr¬««‹ºè"ˆÞ‡Žn}}ݦ\½ûÝïF8m¡¾„×´P\ô/὿ø¡}Èí"pmmͶßüæ7·´´üçþç7¾ñŸN}ç;ßøÛ¿ýÛÅÅEòÊßn41ï—ù—óÄillÄ€¨+Rˆh  #«¯¿þ:Ûïz×»'¹vjSºlÐØhÂMMMûûû_ûÚ×lÂDøÕ_ýÕ¿û»¿ûÜç>÷Þ÷¾÷À&L“'fþ&ÜÐÐÐÖÖuEŠ ò¡#†VJvmÒfG»&÷õ¯ÝÝÎzÝ#W:$R`ŽoûÛ¿ÿýïâŸø­ßú­·¾õ­´Þø‡øîw¿ûk¿ökìý‹¿ø‹·½íml£ß_ýêW‘ð~ô£lÓ¼Ñi:þ~øÃ&þŸþ韾ï}ï#òÇ?þñÿú¯ÿŠº"…ˆšð—¾ô%F'¼U€>ó™Ï¼ç=ﱿþ&Ì®þçΕNá_Å ÙÒŠiÂ4½"š0Í–mkÂŒ8„®à{ßû^Ô)² ™bQb‹†Ìü}í)¥˜cI“þó?ÿó¹¹¹ßþíß&¯ßÿýßÇ;ÞÁÍõÓŸþ4Mº»»›hüeœNcf×üÇþòË/÷õõѰ‹@B~ó7óÿñiöQW¤Ñ@Æ=uòlÐlKÚ„áÆäÛßßoíñ´e¤š†IËMx+Ø Í® ãß M˜à÷~ï÷¬ #Õ¤ó/ÿò/"ˆ A %´®ògJËÄGÿ›¿ùÚ´LZé'?ùÉ¥¥%Œa(ÍÈúþà¡¿ôÒK¿û»¿ëf}³««‹ÖþK¿ôKlb­ý_ÿõ_9*êº"¶ò¿ªdMøÏþìÏð€‘dÚ#M˜17á¸Î´ë‘‘šðøø8£jׄiãÖ„ÑoZ}Âk¤ƒŠ—n$!Žˆ:J>øÁ–ÿ ¥i·8¾4Ýd2‰â¾÷½ï½|ù2­ýŸøªŒTá _ ÚÇ?þñ›7oÚQ´|úŽú“?ù»™æÇ=Z¢ªxÏ{ÞóÌ3Ï”9SkÂÈê×¾öµ††š0¿4áøÃ‹‹‹Œ³­ ÃÐÐ[w™&LBì>™¨|ÞÌ8+jª—'N ‘ûûûþÙ×4xÄòYŸú©Ÿúö·¿ív1.þÿžò–·¼åþçŠÈ”ó>ð¿þë¿þõ_ÿu†Ï4o› öüóÏ3bXXXèíí%Fþoÿöo\µ4þ³gÏþå_þåoüÆoüʯü éøs?÷slðK‚NW¥†!½6×IÔ¶T Ô¶}$Ê?¬ Mø~ánß¾M›Eki­ßýîw¿øÅ/Ò0›››ÿéŸþ‰ ÉëÕW_ýÃ?üCׄ‰÷îÝŽŽß _þ™Ÿù™÷¿ÿýQW§¢¹ÜÁ믿n‹ÔÕÕ¾…xÛ4oš}à¦üàþ—›­ƒŽÄ~̦ÙG’µp0œºrå ¾”†Ýå'O~ã7Ü4ïŸüÉŸô煮&Œœ3^$k‘Í实ñȺë'=²îz«‡ûK#ÿ´Ò²ÑÔÔTæ…¨(ò4aÖ¹ÖÉÚ„õ½ö°x÷»ß]æE!H¡c}¾lþUÃÖÖÖB—ð×LB‚5áü-ôË_þrèþÎw¾3ꢋ,H¡ãF`TžÉ>ðÂß¼,\üü9 ! çMozSþ™xän©“Pø ¨Ë-² )¸UGCCC¸‚j“M„å!óyöÑjb‹º Ìd9 è}¸…â@Bç™é""Gs¹«”/ùËyÖ-|ñÎÎN½ ]!¤Óéíííd2iïÿˆxó•¯|å›ßüæ¡ñÒ„õ”ªb‘BW/Ÿýìg2eŒ¶ýÑ~T¯„ˆŠÏþóGœ2ö‹¿ø‹r +y?ÕËQôyîèè< !´Á¢õ•&ÜÞÞ.y®päCW;EÜî¶BtgLˆJ ˆÛÝ4^°Rhñ¿Ë–}ñ‹_<ð«´ oÜýž÷¼'×ò BˆH  §R©ZÑ~iÅš>r,B‹ÿckkk{{›¦žõ+7 ·Ÿyæ™gŸ}V®³•I:ÞÜÜÌÓ„ßùÎw¾÷½ïU>FH¡cHže™kkkGGGóî>%ùÃþðÍo~sÂkÛqW>SSS“““ÃÃÃCCCQÛ"¢Ä}SMø¸£5ÅbÈúúúììlÖ]—/_>ðp}防½½Í©ç7jCDøàÓ¨ {éslШ*†àHe ¯©©‹Ú:!Ä¡aà•«]‹#…Ž! }}}™á£££ˆtÔÖ !„()t<ÉnËBˆã…:ždºÑr …âx!…Ž-~7Zt5L&[[[ùÚ!D8H¡c‹ß–] ¥R)½j%DlBÇs£å@ !ÄqDïCÇs£å@ !ıC sZ[[£6A!D1è.·BQ‰DàCïïï?~ü˜û÷ïïììD]1çálj¼+u‹°hkk³;lDb@:ÞÞÞN&“ QW†"ÊêCÏÎÎvuu555MOO³-y.§<¢¶¢*H¥R\ÕW®\©¯¯ïïï_]]-³“““íííZRˆØP&šžkxx¸»»ûöíÛÍÍÍQ—ZˆÒÂöìY£wîÜÑ/„(ŽrøÐƒƒƒcccËËËê­D•Ð××·½½=44ÔÖÖ633µ9BˆcIÉ}èþþþT*¥~DµqþüùîînDº³³ScS!Äa)­÷€<¯¬¬HžEu‚0onnvtt¤Óé¨mB3JèCÓ%]¸pAÓÁD•ÓÐÐpûömÜh{…A! ¤„>4òLÇT¸÷œòØßß÷â‚/,,ÈÿÇšsçÎáFÏÎÎ~HSÁ‡‡‡×ÖÖøº¸QRþ)ôÇÕÕ1àIiÀ]Àu8Ô!f]Œ Aà%2Uˆ2pØÁ5¨¯¬¬Dmø1#®õFÇØÚÚnšq­«H@­JQ“¥ò¡çççÑÔ£¤€3ÎÆÈÈŽøÌÌÌòòòGá…»m}ú•W^á æ@’Å$÷º0åMxÓ 9Š˜T#µÍᔈ!Z}}ýÜÜœ3 Ìvapà’ãt“ø9wÒ9)œ rá@"ðK¡,>§˜¦e5ÀÀ6!þÚ&£ééiί™q¨ ˜­tE3ëÁyÑ'Ë•Æ5ƹ>Ê )ZÒe¶ê+û‚ÎÃz ú:óâ¼ãôm«ük>ÐA¡ÓÃ?•KÆIϸ···¾¾N§o_8ÀI¢âèm鵩J;„D ¤lŸX¦—çÀS§NŸþÁ°ÑKš=ɲðfí2D >!¤Iúç=8UdGFFL2Ñ3¿xcZróæMÃ?~̹'òÕ«WÑB²CÞú<ˆŒ HJæR°nèÎ;‡C8üÊ•+¤Fš¤Câ!pOû-[_šb"íÔªí²á¦&¼9äC"æe‡˜Tqø‹*“ïÝ»w)…¥SSSóâ‹/Z.®þÑEN ¨Lµð{íÚ5ÜhÉxÍt$å/‘ÿæ*:clƒJ°§éfb<éøšúMu~mÃßðüOå¹Xµ0âqÕâοVvÐ_çnÃÌ{¶øæj³}ïÞ=g‰å€ñ¤àfÂÄ*3ñô HÖjϬßaõÀ¸„hHXrûömW]Ô¶Õ†ÇæF‡}UÁ)ú94ç"ÓàÌôG{~õ¦¹ÊyP]…ˆÿ9´¿—ð7[zHþÒUþÈ¿T>4ƒëL‹†2Ð]âr‘n"!¯¼ò ¿Éd²¶¶6p7Ë\jæü÷ïß÷?]F_qC‘FƤxT¸ƒÏ?ÿüöØcu»¯KîÎÙÊÿÂ÷êê*>_à~²crrŸÕDÚ:Uàtf~– Y}õÕWÝ_†c¯ÎïAR? Ï[¥N‡÷ôô˜ì‘xžÉö8ŽyfãSv¿ë™ð$K쮾Ÿéééþþþ7n¸ô“…{mh—)EÈš‘OP?6“½/d>A⻦bßgô'î8sæ ¥À)wÏS¨+IiZn8577—ðnn‘ëëëeyâi¿IÁÍbõfãï¨m©tTW¡CMÒ­ÑÛø›-½é:èZÑúÆßm)•B#$ôÎGLÄVó¶î’"ùE(0‹ç…^ðßBóÐÝ„'¨Tjí÷Ø8ÜÝ’EŠpb"–yŒ±•¡ìÞ,‡øßÕ΃ÉäÙ³g)ÂÀ^#†µXB.MMM~16 Î:{­€D`›ªæ×Ÿ¬[:p8y-.."QÄÏLÜa÷ÃïÞ½kkªö¾üòËöÝN ã'L¥>3³£ìø¾v‹ÛªÛHgb‰ÿ.wV8}ÃÃÃäHÚ͕Âûk6cd.Y¥Á0‚ጸ«‹«Ž1–«mŒ'*KRÒÁþÂEšqÉ¡^AT¿Yª·ÂQ]…Ž«ÒÌþÐA7NÇHW“9í)H‰\~TIËz;:k™‡àŸB2ãdèBÜáü%о¯…“JÙJ‹`¿vþŠÿÛþ{ÈÛþ ;Ḛ̂_KÙí²G>YkÃåâŒñ[Ź8«2«ÈÚóTÿFÖø™¹ªÅÕªÿþZd—²«+·áOÇÙ`ög=•®·=r] ™µí·Íÿ×î¯Õ¬gÖÚö˜µæ³bO Œlñ lè.÷“¢ê­jQ]…í®ˆÇy"”J¡ ¬ÀΦàb^>¡%œËÄÓÛ¼"öp±ø ùˆH¡…ˆŠÂë¸OLLäÚ{âIÆ|°H§ÓMMMøò¡¿vuDR©”½¼”L&#´mfffww·<ó3E´LOOÓKý匩©©ÉÉÉááa]TBʶ¶¶\Ó¶J¨Ð O„ÆÇÇõqhQÍØdˆ ª !*þþ~÷m€Ò*tÂ{wvaaA"-ªä¹££cuu5ÿÛüBˆª…þáìÙ³YÝè’¯X299‰íæý Q=LOOwwwKž…y`_WW—u%“r¬)600°¼¼Üï!Õ€-qÌeÿøñcɳ"?¹î1—j]î +++t[ƒƒƒôYhö±^Oˆ\¬¯¯ÛšÞȳ´YQôècæÚÝeRhÆïïïÛ¤Ö£÷CˆÊÁÖOx+¢Gb@:¶Ó4%MˆãE.—µä3Å„åa||üÊ•+—/_ŽöÃBˆÃ’J¥úûû3E§o[ !„ÕƒZ!„¨D¤ÐB!D%"…B!*)´BQ‰”õm+!DéîëëK&“Q"„)´1¡Á#j+„¡¡»ÜB!D%"…B!*)´BQ‰H¡…BˆJD -DL˜ššjkkã7jC„á …"&loo¯¯¯óµ!BˆpB !„•ˆZ!„¨D¤ÐB!D%"…B!*)´1!™L¶¶¶j]n!bÉ'OžDmƒBQ½¤R©þþ~~áò¡…BˆJD -„BT"ºË-„B”›ÁÁÁÕÕUÛÞßßßÚÚjnnv{———ëêê¤ÐB!D¹AžOž<™uW__ß;wò¡…ˆ étz{{;™L644Dm‹â`PhçFû¡![+Ösh!bÂääd{{;¿Q"„(ˆÑÑÑÌ@h7È–B !„àc‡-…B!¢!pÓ+ ÙRh!„"’l)´BN•3ozK¡…BˆÈpœ9ÍSo[ ô¶•Ç”ëׯߺuKër [æ¶¶6ɳÇŽ3gÎd —B !„•ˆZ!„¨D¤ÐB!D%ò–¨ Aö÷÷?~µÙÙÑѵB[¤Ð³±±qûöíÙÙY¶wwwëêꢶèp Ó555l´µµõõõ;wÎþŠò3555999<<<44µ-BˆBG’|ýúõT*…°ŒŒÐ«÷)¸”ezzzllŒí”èØ±½½½¾¾ÎoÔ†!ÂAÏ¡ËÍüü|2™D¡qwvv–––².ž~ì`¨qíÚµÇÛ°£©©éÂ… xØQÛ%„Ç)tù°ïu_¹råÞ½{wîÜinnŽÚ¢’PSS؃ÁGcc#c‘ññqé´BºLÌÌÌtuu]¾|yee¥&X¡Óh3.õ£Gp©%ÒBqXôº .//onnÆànö¡ ¼sssÓÓÓõõõ©T*®· „¢ȇ.-øŽ'Oždo²ÚäÙqþüù¥¥¥ŽŽŽùùù¨m‰3Éd²µµ•ߨ B„ƒ¾œQZZZZÆÆÆ¨¨ ‰+xÒ&ÕQÛ"„D*•êïï×—3ÊÊàà`gg§äÙ¨©©áú;}úôÆÆFÔ¶!Ä1@Ï¡KÅôôôòòr®ÕÁ=ؼ7<>>žðnW}Ñ Ë"WRÎËñ@Òé´}»ô(/:777“HOOR­…M„➈°²²‚ŒíííåŠpùòe«ÿµµ5¸¶¶¶ÝË"WR΀SÃάgXGGÇÑ („ñ€~5k_-º$\¼xgQnbVðÚ§¦¦VWWõ@ú¸“N§gffvvvvww¢6GˆÐèëëKx 1E»’±:|Ðú,;ÁGľ¢Q[[ëOiccïܳ.åíÖÊ.:ܲhiiÉuiÒ5Ûê’.ΡgøÂ fee%¼ZÿwR’ÉdÞ˜µ^‡‡‡íR×| ?¸Îñ(êëëoܸQRb}}Ñ@–Q;÷1„þíÉÇÝdºìÃívǃü]-Bh·ÍÙ›ð^5¶½„“ˆ%;11ÐTKêöíÛ~_[[sy¹Ë®³³ÓÒŒ-ˆùäÇïrͲ&M‹ï2e¼™çÞ¾ò=°–Ä¡°sjç«tÌÍÍqöÉ…Ñ@Ô%¢p©wx”îš·þ?3\ 2wîÜ)ä!«Ȭ˜¬Á[ó°ðk×®=yªÐpëÖ-›½•ð¾šà>™€`/--uww»¤,&)[=Û@´‘‘ÛÆx"#·lÓ¦˜ñ÷É+´‰º,¶ ¿wïž“íAž Œ) ¤ Í%‡´¨.Ìo®¯¯¿råʱ»Ëj~sþɃ¡c7]")o[[Û‰'jkk)uæ­ò™™™Â‘ÌÏÏsÒ ¿»“L2ÛŽþ0’D|ñ–c(Ñ 9Š\V˜ ç…Ú.Â?ãî/­µ@·5p^B9S:;;×××óDX^^>é‘§©&¼{æyÒ‘B‡×nàu)q ===î]²R#m.rä4EUp¼p¼±ÄÓî,@ž‰“ÆÆÆ®]»VÈ{€—hžÎää¤- bšœëB‹Po[[[åiàYs¡½ÐN»ººì­Ô¬Ðœ{{{kjjòËsB«~Šh©««£Õ…>ÂÍ„o.m{øða (‘ñx¥^ã“úñ¿[ ô¹¶A¿644DmØ/½ösÏ=‡’q!ÙW×p˜èõ¨$Ù¹þüÅG6ì‰8.> vwwonnâÑoÒçîìì0Œ#&Ñìë룫õgá·Šì <{ö¬Ý±´]¤311‘ð&`$©™UZ øXÓÓÓv€pñé“2ßRhÊ"PvR ~àö¦Z.¤Æ! ¤322B Û˜AšTÚ`º›¶T~cc£µÂ/\¸@L„ÖLu» *äúõë+++–#c8÷ä…ª6g—_êðÒ¥K¤€å˜Ä_  –H–½XÈ飶Ϝ9CVÛþâØ¨ÚÇvk¿“/#­€=ls:H›ÉÎ`™m®Œl`¦†²Ô6þ}—»+cõéÏ.[MÙæðÚâ?æ"ZQ¹ÐÙM×›7o&¼[î/½ôÒùóçµ°½½½MºõG™"~õêUº`ÿ[t¦È]³u©ìBšššèL á@vÑ­“šÁ6!è¹à¸Ó«ZwïÞµ,ˆDmm-(òéW'|)FtÊXEß~˜Uýýý”á´÷ÙÆ“d;œ¿¤@ˆK“,›h‹á÷xªËåB¹Ð3²@ mÁvþ’ÊJä„Hx7±ž{Jʧ3¤øöF%õiÔõÃЋ/²峕Þ°Û^ë Ú)89ZÍS"2Å6’%L¢PìB¶_xáJŠ ‘(²M:$N|«Fd˜ùMMxʇÁ2Ò²k€_¢½øâ‹”Â*óÈS)N(Ë0P«ííí'žÂ•Àu’KžOž²B%bkÓöâ»n]¤ÈÎúh ¡µr8áî tó]Êy²°]¶ÆÿelËßÁ\[1÷ÉÓ¥sme@[<Ò¬zðà‰àTªÎ¿$¾mت“‰§opXXü@.V¥×®]K<]‡ß­%luˆBø#£dn=Wwj܆ÅçX‹o«üN}N‚üºŠõïRà¯ë‰É~“µH„_â;SmUÄÀÙþ@‹†‘\º.Y¿©¡ô9™ê韚§ ùСÁõ¡5,K9ÞÓ2ÇÇÇésµ¢Jãé%ó¼7™ð:k¼‡_F/<¶R¿…c¯ì犀ÿá'ÿ.üQ\¢ïÃ?÷Üsβ{Ô™ f’' Va¯í{q¯ÚÞE ‚Kg÷Çç²ÄÁÂôÇÌ|ÊŽïK?cÏ/i;ôà¹V"&õ™ëåOFþÄ‰Ìø€ ,°à ÿG¦~Ÿott´··—£¨O’®ºüŠð•Ý£Š‡r`!çËá<&Ó¹¹9ò¢tî1°R¸éþZu9&¼å"Øk¦ÚŠ…ObÈ„®>sú$çÅõ0E§@ ]½ÐÆè\ «/ø[Q,uº™&2–w OÀîr£ßY—ëÁ0zü»wï"-I'N^tî–`ÕH²=ºÿ~Ö,è©IÇ/`lã’Úmê¬Ë¼ vÛÓR£\v‹Û?°7n Ïœ3ŒîÚáj®ª³uõmA…Ì7þÍ´›ð Ï¡§B†‡‡i™’oë &¦› {oϽ½çîxT÷~îQþo$ó@øæš¨TnݺÅåÝÙÙÉnKODm‘¥Âfö www3*-ÿû™Rèð¹yófÿ¡¦œ;wÎk½páÂèèèÖÖ -á›N§‘|ÄÌÖ¤åiii)bU ÒÙÜÜ´woò‘‹-·²¾¾n/P’; ê– `W*•ºÿ¾-Ü“'fØÚ~!bD9±¯zÛ%Á¥žkÑ !Ž;(4ò¼¼¼ÕçÝN< õó#ÂèííEÌ“¿òƒv"Ïn•œÖÖVz@´Ðô·@[Ð^½oooOx÷®Þ¤è\ÑNÓ~—HÊC¸|ù2qȈ®Öÿ1¢Ñ N4gÕÚÚZmmmOOÝ‹YxIIÍ÷Ñ,îØ`+?Gm…¡ʇJŽ|è’€Žâévww>òBwûúú:h޵m¥YÄ )µ…xì6K2™ôOÒÎÿ×°uêÝ•ÇØ@Œ´ŒVVVÈÂ> ÃðÂ\Â÷öö,WÉ–ì7ÿ)³p p”ä9tL&9ûå¯Û¨+@ˆ¸!ºT ‡gÏžÝÜÜŒviIçCWȉžžžžŸŸÏ|K;×vS$j[„! u¹Kžåµk×ð£6¤‚ØØØpß»B‘)t ¨««ŒÐ†d2é>T-6¿Ý}\]!D~¤Ð¥åÖ­[»»»---n²U™JyD[333]]]<ÐÓJ!„(Í+-ø‹sssÓÓÓmmm QMÙ– .,..nnnJž…¢päC—ƒóçÏÛZcöpõN§íKïz·J!‹ær—„jbbâþýû7n܈ýbUUØ !·­„¥@ ]nèF‡‡‡ùµį3µuò.]º499X¼L!Dáè.w¹A’ïx$¼¯Bµ´´\¿~Ý­v|I¥R¨r[[Ûàà`ccãææ¦äY!Ž‚|èˆA›gffìË’¶nWÔûì³Ïþîß~Ö¹víšOQEQ/QÏí(Š¢(‰æóÏ?¿páBeeå©S§._¾Ì±Ÿ‡n¸¡Q£Frܾ}ûÖ­[›ŸJb¨£Ö³¢(J-áüùó'Nœ8yòd ×Hýúõ[´h‘‘‘T#Þn?Jê£ò¬(Š’âœ={öÈ‘#¨2F³#6oÞ¼GM›6uûÉR•gEQ”¸ ƧNª¬¬ ê¡eË–õê}ÑÃÈßvíÚaž:n}ðàAb$ˆ´Óq¢.ÿ333[µj%¿y—‹/îÓ§O“&MÄ¥¬¬ì׿þuvvvÆ ßxãšëçÍ›WhѶmÛôôtÉj!À?»téâöƒ§ò Þ}÷]ê³nGGQj5˜§Ÿ|òIiié¡C‡>|âĉ3gÎ\®ŒÚ3H8Öí±cǸ6-- Ù«S§NŒ1¡0ß»wïßÿþw§,æ Ë]ˆ9fåOìqVìÔéÖ­eúŽ;ä÷¬Y³rssgΜ¹téRqÉÉÉ)**"·qœ••…Z_¼x©þÇõ¶÷ã0ÔýêÔyòÉ'E¤G°¿_ÞTâ:tèĉ§M›ævz(Š;Hru†r¤4jÔ¨k׮ѦçΣ(Ž¢w9¨Rôë×O›»䆅 îܹÓd©+V˜¿péÒ¥õë×ã‡cDmæ@~[ªN¨žçÌ™ãöÕFäìß¿ŸÄÛt6ðµk×VwŠ7nÎŽ5ªwïÞn§„¢¸&ò_þòJH§´W$vÛ¶m˜à᛿ø,))Ù½{w‚µÙgµäs_î?c½¶qÃØ±c±z¥¥d§ÀÅ’UöY:ÍYüp¼hÑ¢¶mÛN˜0Áˆ·ì6|=zÔ¸SçYÉÐî²²ùÉY\üj ………~bƒ7~ _hŠ`O–üüüÜÜ\“ò$¬¤°ñ€ ¯?à³  @.$cLš4‰4çàÂH-Ÿ}úôÉËËÃѯTÂ!޹—øÁÑÁòKQ\‡ü¼}ûöøiÁ"ψ4_SýÇHò®]»¨+¸˜ Ü"óÝÅ8¤ _ ËÉÉA +**†Ê_ìà[o½•s{öìÉÈÈ>|øºuë(‹ÓÒÒ8à'Ž Ó>«eµ­(”7nÜ(Zî³4¸oß¾ÈöY .á”´ÄrÀ+”¹ŠR¾¹ǘæ³gÏÆ¥ÏÊʪªªÂ?QâÔ!CäFœÂÝ4°×rÌ+ ¤=zôÊ•+I”—ôœ9s¦¼bRX: ¨i¡—xàÞ—˜ÐÐlô˜SÅÅÅGŽÉÎÎÆf1‡ÏRß‹/N:ñ–[SÀƒt[Œ1‚{q !·ãõ‘¸;Ñ#|~†îQïãJr‹êâƒÍã˵W¯^íÚµs;Éͽ”àbÙ ™Òp@ò¦ÅœÓ¾½|ùrÊY¿Fìôôô‰'Rìm6 ؔ鸣â‚ZàH8”éüD ЩP¾²ØmHýŸˆÑÀiAÎqÁƒ\«Ø™ƒø€…‘^Ò·&¯˜Ÿ$&µ+séÒ¥˜¿ö@Ääåu#À;v”¾d¥âÅ;ÓkÖ¬áö„6‹7Bྦ­GîˆO^½ÛI¥(у$ï¶H|2–4÷ 4£ÅÝ;Ú ï¿ÿ>±r;ÉÍòÜÍùDÿÄ&æ/ÇÓrÊw½7«kþüù˜Â»¦ušzÇŽbUw$MåBŸ5aŽ¿XW"Ãèwß}·xà óYå¸Ïs9âMqHçXp­¶‘ÚÒY^Ç(¥xØ´iS ô[ÞÉNJ"Ã$¦½Kå¦rÆ©éÓ§ûÝ…ÀyATÅ8–V@¨ð~%'…ܘæòBqÄÛ ¦(Q‚‘ºk×.o¹5oyy¹qñ¬+âæv,’˜Œ ¤˜¦Ô¶»•c1šÅŒF5¯]‡¢©ÿ6˜t”Ë"Ì~ 2Ä /’¢<+++ÐÛèÑ£}–ùŽð :·Ýv›ÛIç9xGï¾û.•ôoܸq¼5óByw˜¿èî¤I“¤‰;;;[#+ÙÂU(4õ-¬jÂ1öY=Í#FŒ |lbãÙô/ˆäû¬×$µ7¹¤¸¸Xª\Š’ Š^0R‰²·ÿ~ÌhìRí5ˆ›*tÔüCže€˜½ÉZ“¥±zÆŒ”ævãxùòåëׯÇ„E'0ãð¼nݺ –-[†õ†TÓœ AÐNeÜQÔÏýë_ÝN:AºÕ©S‡dÁ8ž2eŠØ©¼£+Vðލý :”³üä=rŠwÏ ‹1cÆØƒÂh&‘¥)eøðá"ð¼‘[Œfé¤xë­·Ð`²µ4ΚixT¶¸ ^SZZ1Ñ©VJjð¾…Û±ø?>þøãíÛ·{Y›Uè¨ùÇ*"”ÅX®öödŽq¥¼ûî»)sí—Q.?ùä“GŽá¯ß)?(¸ ŠòZ7þŽ9@0(ô1ï°ºŒ7DBféˆ7þʘ&?oŠÏJR9Àr%¡¤%}ù$cQQÑ„ &NœHê‘tȧÏz}¼;NQãAGí¡á ÝåZ^“¼}ÌåÂÂBñ‰=Íûâ÷âF2²{Iƒ‡¼Ù­[·J&pó®}Ö›u;Á%2°VùXt4rÔ Ð-Z´hß¾½ÛI2⸨§ŒÜÞ¿¿Ÿ(Š¢$ .\Ø·o_âG¥ƒÖ=¯"BJUE v³j³SxjÞWRGëùÒ¥K¥¥¥YYY:AYQ”dd÷îÝÚ¦í mÚ´éÛ·¯Û±HtÇ*EQ” ”””IJ׆ Μ9ôÔøñã 9{ß}÷EòªU«Z´hA n§P4ôéÓGG…I½ØƒPEI1ÊËËc\sãÆÕMG>|¸œNžW¯^Ý¥K—$•ç÷ß_7  •gEñ—/_þì³Ï8¸zõjݺuÅ‘²LÇÔ$’ .`:Çȯ~õ+YÞëøñãO<ñD‡p‘S'à)¸{<6Žñ.ŸþùG}¤{ ‡ƒÊ³¢¸ JPnzü%`‹-233ƒ®í£8ËbÄä§Á¼ÁDjÒ‚ ¾ÿýïÇûŽÑÝyîÔ©“Ð5¢ò¬(5ãgÔ6hÐ F»1þàƒΜ9Sã6D&•>kM‚=z$À0ªÈ ¶xñâ÷Þ{W9wîÜîÝ»‹ãªU«Þzë-Þx¿~ý{ì±—oذaãÆ“'O^½z5þÿéŸþIZËQÍ-[¶ò¸qãÆìØ1y´&Mš`ÄKÕáþûï¿ñÆïºë®gŸ}öÎ;ïÄÛÌ™3e“›]»vñ—X‰OÇDu„ xÆeÞ¼y;vì°ß%̧–UÏtÂmÄ*Ï2<ûwÞ‘­¨>Ìë?þ¼©OõìÙSWñ&+V¬pjw ^1Å„Ûä$”>ÒûHfáÜ.Åa†LÙtèСXú5E§1£é¦M›ºTÎPhA‰o\òóóËÊÊ ã"+ÿË:tC‡={¶Ùƒ‡1™9==?QO9xð`žšúšúç?ÿyúôéëÖ­kÑ¢ÅO<æÉ ?Hì§Ÿ~j–ô z9E®˜°UUUˆ4ù@L?o(1§FŽIà'N|íµ×ðÆµœÂsÿþý_yåôõ°i‹óEϘ1Ÿ>KÈ+**n¿ývŸU¥à£ ûÝ%"x_‰i{Oj¢‘gÙâtïÞ½¾ëœÝtÓMr*°•ýÞ¼y3ï²U«VÌÎÎÖyVZðwÜÚïzĈû÷ïí---Íí§q髱©ÙpÞBF¡”7ß|sh½üøã)Ô™ýyöìÙÝ»w·iÓ¦wïÞ)ÐNˆ-ENã¯ìÊã³6È!û‘Ee%ZJÑ0Ÿ5ƒvçγfÍ2òŒxÌŸ?_v'….\(›ŸF Õ¦0Û3á©§žòYÅ&‘—aÞ¢Í"É8Re !Ïv­¬±ˆ1ª)â*V²ÈTkx¨§Ÿ~w„üž{îÁ§ØÙÜT¤šl,ULÌe‰5ƒõë×cvs-±Ñå s´œ«°ò©˜»Dʇ~t{ű<¿ôÒK|3·Þz«Ôï(˜¤)Æx0¯7nŒ7êb♌wIMíÞ{ïuûÁŸ˜}¡ýÈö‘µ¡ýƒÌŒ6G­çÎC/«é8- ‰ÞoÛ¶Òv%Ñœ‚ 6dÈE‹‰<Ë6<²õŽH2cßÀgm“J’Šx |<×RæðW–° iØHü³y…–†si =”ŒbÖ£©víÚÅß|иPb‹Ö2Úì³Úä”±h%X´Y._máàSS VyMdòŒ6·oß¾S§Nä^ßOçÎù¾ýío›·K¥ÞŒ^Aª©"-X°àøñãd‚xà›ßü&Yðw¿ûÝw¾ó·Ÿ]©i¿ÂImyFäJJJ1›D¤ýŒÚ¸. ‰¨ìß¿¿]»v½zõJd¢9Î’%KUQeÙ†Gö6¥Z0cËÎ=x@zÑlŒi#ÞvdƒÔ(ÆÐÅR9s‘Fc=;òOÕS¬ä w tO›6Í4l8Ÿ_D¦$`Rr”ü$‘Î’©Ä…ªÞ¤I“ ì;øI X)‰'‚61ž‡ï„×ùÄO<ÿüóHò¿üË¿ðÀCF›)ÍsssÍvR¸s??üð¨Q£øüÞxã ²ßnØœH¾Ü¼y³Û‰¢m²7ŸƒÁ¢÷HˆØÊ²Cp¼†ôÈ^‡±€±‹0#º”•Ë–-=¦ˆä'޲¿-Å¥ìL¸o^ß¾}ëÔ©ƒ¢SòF:òHú5ÜM±e·oߎÅ쳌Â6ŠpDtÉu„°wï^éà2íçöýéÞ½;¾òÊ++C|РA>«ÍIîE<%ÀÄ@"˜õ|Öˆ¨Õ¬Y³Œ 5BήÍ>Ë2‰¥‹=F"°ž1©€,^¼øoûÛC=äw6//¯gÏž_ûÚ×øÀZ¶lÉOìì;ï¼ÓxàçOúÓgŸ}–üG™Ð}ôQ·[ ÉšUUUnG$.ÄÕ¨¥ÌB/Éö1®n>R8p`òvEc¢aK·‹Ù]’”ºN7 \d§y£¾œ5Å.—#Ì~»ß†ÉÉ“'½P¹Án~üñÇ'Nœ(?íÝp™_aéüâ‹/nÙ²eƒ…x ?4´ù±Ç£ä7±’Ævéðž?¾Ï2йK¤ñLdûöœ9s0M—)Ãã¬]»¶¬¬ŒÜbšd™0‰@žeb 5¯©S§ž=}úô[o½uÛm·Q«åÓzýõ×q±Ëó7«Wï»ßýîªU«ÈšâqŒõlR›P4”””Ä»DN˜6 T504 È›:¦3Å=E§iÝE})Á͆ñ`âˆ0ø¬k<‹Uí³ä9êé:~øaœ ¥œî… )¶.19zô(0·“mÉÏÜhÊ”)᮹Mµ«I“&¼‰_ýêWö!†+W®pƒæççóR@ Ç>Ÿyæê,2ÿ*I×¥«=dddP¯ä w«÷%N¤öñ2ŸÂíXD‰Œê²w@ž)Ūªª()Ôp¡\“SdN²(EY4–íkщíÛ·»ý赑 +âµlÙí þ”ÅAzZ²Ö˜1cÈK˜šØÓ³fͺxñ"‚:Ñ‚ ¶iÓ¦Ž;r€ÄRîQ_”ª!Ò;vìX»…M^Eƒ©2b/™ó¥—^Bàòòò¸¹‘¬»råJÂár”a.--%H;7"÷Úo'Ùxøðá , ÌpåYæ0P·å~¦êŠûÆoPÏ Q:rö¾ûîCÈ튑éìJ[§`b¾ýöÛnÇ"¾$ïÞºhó£>JÑi\(§p¤¬ DCª9e’MIG‘²uëÖXä™2”BÓíGW‚€~c^#cíÚµ‹}žtZZÖ#Ò#¹“1šQSlVÄXŽÌ†äqŒ‹”~’Óìö°w9+šÞSZJ¿ Ár9>Úôôt“™Åh様Ѣýæv÷/¼ðÙØäð°·e&Õ™3g0Ž«¼Ç·oßaülÕªÕ°aÃ}â‡ÚòL˜2J3Ñ/\ r o'Åñ¡Í2Q$µ¡ E$’ &¿%nÆZø¬Á،Ͳbýp*êŽÌè&I+ àóÏ??kÁ[¦ÆÙ¡C‡XtK‹ÙŒl0 ÚH£(yÌØÇ(7¹Ë~¹ßtä™ ‘í©S§ŠO´ß Ï£F2þ³-°Ý¹÷•&I.”sn‡o¿KXCH¶oßN¢lÙ²%DŸʽyóæ'N<õÔS%%%ü|óÍ7ƒúlÒ¤ ©\\\L˜üããòJ' ¯H–íÖ­[j4nó©ïÛ·Ï #€âÍåË—Üíí ~Uö†âhs GJ4þF½ä‘nêœP·F¤Ñ#Š£è¦ZÌ™3ÇüDMå/µ@ê²8]^^²-~¸ÇØœfpœ@uCksíÚµ\ˆôâ­Øâ‡?üaÐÜÈð)+ßMš4Éw}l· Ô–õŒÝÜ¢E ìzY]$(?ýéO/Yø¬ab<ò‘¨Îs=ÞyçŒúø ÇPb‡úEY|âm&}ôQ¼'8y‡C‡ag$ï(î„A–¨ 5¶TBÖµ¥ºÖ«W¯ˆr¸ uøÙ±cGiôåÓ›…Æ'Ç”~èÔ¸qã(QV»®ƒ¶qãF*ˆ›6mš>}:~ÊÊʪkf–¡Ófr,ÖÃoÃê{æ2„ùž{îAÞé¨'eßxã_|qÛ¶m¿øÅ/œycŠÓHv¡r'Ãh“}ð6Õí;wÖª‚8©Çˆ% ªžEEEnÇB‰´¹“EJVCÃz$*2Þ©At-[¶” é~sÀO!Ö³§€õ|ðàÁZ¥Í>«µÀí(ÄŠÌrŽ+§Nrû)ãºE¹M-o»-I V_ôáÇ1óÊËËÝŽ‹óÔܸ¥KÝ5ES»k½z 48sæL‡8 ;‹y“ªª*U8a„œœ·£²!£Û±H42¬ÆË[D_ºt)??_F6L:uýúõO™2EFÕ:ôÈ‘#/^nÏÂÂBgΜ9ø4}x¸ã(]oÒÔÇ».((=zôرcsss9+>í{^BoJ–Ô4mÚ´_¿~6lX¼x1 K‚LŸ>===Ý©}Y<‚ìPI5+Ù×µõ£fë¹¢¢ݵkW ñ„ qãÆÈsýúõßyç·A ŽÌcñYC “]Û¹K §@ÞÜŽBµ ÇH::þ|Y³õíØ±#ª\TTÄY –á6è.uD„öÝwßÍÌÌlذ¡,ÿ‰ŠçXø¬IY2Ðý&<¦Y(8œ*t‰@p¤ô&q$ ©©ðEÏž={ذa©×œëÚúQ³õŒ|ÞtÓMT0ݱGò»tébfÖ*^C¶"ðY/+ÙåùäÉ“nGAÜÔ©@w9@6dïHrÝÚµk1ˆ×¬Y#]ÂfÛ´ bF÷îÝ[tWfÈÈ2ݲ‘FŸ>}¸D6ÏsµÆ§Ïê§3[ ¤6¨o×®];wîøåæååQwùñ\RRâv4FÖµ½å–[R£ ¿fyS>O:E%´´´Ô4¦I“µ¬ÿèŸïDÚ”R/‹¤jöö)ì’t’:9-•êÔÁƒËî„2p¤qãÆrÀ«tp=¦è˜4iÚ|ôèQ ;´™;ŸA:H{µ6Úœ––6Ç‚§CqËÊÊÆŒƒŸ;vðh‹0›mÈ—/_NÈ2ø6ÐÌHɆ;uêô›ßü¦ºZõüùóI:$<õ¾ YØ€ZZbÖ +ï÷lÍ"9rðàAô¸uëÖ|`>úh³fÍ8ûÉ'ŸH¡ÀGòñÇõ«_¥FÓªU«Àp‚:*^À^!ÕÉ»­dòÎv© óWŠìÇS:óÙfffºÕ9=eÊJ TùâÅ‹d¶Y³fÉ’‡f0ŠØÁ>kd¢ôFËrž8Jw2Ãã ¾„ƒËrÒÄ-‹@ÉÔU™ÍB ~cg7+ó<¯™¶Yå#%ûÝ©sìÞ½»W¯^íÚµs;.1±<ó:·mÛÆÃwíÚõ[ßú_H=‚ú”¹\²-Î÷ó§?ýéܹs|?:`Ûûðm=Úü” ÐI:ˆ/%GuÆ¥˜ôÈú¬ åºwïžàþHôƒS8??¥¢€,˯X±Â¬¶˜••…xã‡SÒ˜ÇO»YÖ`â/z쳋ðY«¥§§svĈ›6m’qdÎöÐyž4ôFs$ì}÷Ý—’ò,È¢úI­ÐÈ3¶òóÏ?Ï[§úÊ+¯\ûüóËW®|~õjR tîÜùG?úу>øÙgŸmÞ¼9//¯+##ÃíÇWBa7ªdW g÷cO d¿”4œåĉTb9…SE2e$ö¢E‹°Œï¸ãDÚghËÎÎöYCS1©¥¦ˆ#6þE°}V«µYÏnåÊ•â æ*<#粘bÏ킚΀™z‹ÕÈÖR!<ð-'û€’)))!·$o?tÍË’¬ZµªK—.s³fÍ&Ožü•ví¨pÙ{k.\¼btèáÇ©á^´r?Ÿ=9&ÍJ,Bxýõ׿úÕ¯îÚµë±Çs;(Ú(ï(@±WÈ$Ôµsssí$ d×ڰȶSð‘öìÙ36‡ì'=&²¢¡4qÇã^Xˆtu»ù’=R̈ä%RŸÞºukuó!Ŷ~ûí·S¯ïÙúõëSˆ%é0õp­gžðž{î©(/?}ú´ß)¤÷{ßû^u¾úê«W®Û.d.¯ûÉ'| 4pûÙ•ð³žC·•)©A¦bKƒ6v-ÂÂ… ã¤ÍÔ,¥:®ãP£=z´nÝú£>?~|·nÝÊÊʽ‘'NœHymöY ¨~ <8´7Ù­   ñ1=z4uÇ  "hܦ‚ÔÔÎêÞ]F¥sçÎ ÓÒ®ØVœ¿zåÊ©“'[·i“ø„PÂǯ§™Â4èwî}+”J”——_½z•:YüÌÄXÌÙx/œBÙWZZbT#§RÀznÚ´)…m‹-<( þü1’3fÌ¿%KW®\ùÃþ°öìo}áÂ…’’’ž={=+«ß¸¸ª«ÌGÏÎÎ6»˜"g¬äºõêñúý¾ØzõêU7:L@Ôýfg%og@-A¶6±Caè˜\¹rÅí($%wÃ`¼Ç˼q½…»€Røá‡öåÎ;‡Ë_ÿú× 6Èüo³j²ív¬ʉ':tètª â§Í’aH¥Q£Fñ×ñVÃÍ›7&ÖŽ½D%ó,ì>#¹}áÓOgÍš%S§bšÂ<àì3+‚µ!ËyÚ‘m%“tð¶SPÒ9sæ¾ûî³;îµ?~<•Wãxùòå—_~™BaäÈ‘QÜ…¿èîÃÊÒ“  3$¨ÂL)ÿ·¿ý-螘8¢Ä]ºtyúé§›4iRQQqÓM7mÛ¶­64kûAnˆ\YY™——gw;vìÊ•+ãZŸ æÖ~ óçÏIž1DÐf{öúxí™êD]Bß?~CäöÛoïÞ½»q|æ™gŽ;†¥"[{ HìêÕ«—/_ŽroÙ²%¢ñ7nôy@ž}–B¿ÿþû)¶”±íÚµ‹w u5ÙÈd›&j~ÔßyçÐPâóò333³uëÖ)?f;s~4vˆý'‰ðÊ+¯%>fÁÁöíÛ)(ëׯ/îø¡"Û»wïÅ‹¿ñÆÓ¦Ms}•®è(//çAÚ·oïvD"`ÅŠq-^#"##còäÉŽÈ3¹ UîØ±ãßÿþ÷…9(ÚP åÞ{ï=*ÖvûX°ììlÑæµk×Nš4)®1A›© `©#ÏÜÎ ë±oè Gž T;ߥ—.]***ÊÍÍåÛXºt©Ûщ/ÕÖIÆm%Üi ªîÖXȹsçŠó™ñwäÈ‘˜È(´ì›tèÐ!, eޱ›“W›…’’’fÍš%Ñ*‰Ë—//..v;ÿ€*šä„X!Ùd?d~ÇŽQ·Nó ó ­. ÛÖU×p-óóóã­Í>Ë:7nU¥nݺmܸ±oß¾âî×Ïá :Îï‡wê5Tp¨oR©áµ¡Ð .t;Rq§:ëÙ•‰^Úw½{ØgÍš²G¡HµÏ2}×[§ñ9cÆ q¿ÿþû7X`R#á>«ÈÀÇÚãx;ñ0þ|<È%€öËUˆÇvªââ,ö1GJ"AM1ì0“***Èl‡ޱçøäÉ“I½–V,T·é{Æ e‹êÖ®‰r/Ù‡;¨‡Èäe¥ÚÕ f<®Ð²ÑÍСCÓÓÓIA’O¦ÄÉ¢üµ¡ öÒ¥Kf;.É8xÛñiØÇ|Ò=Œ"Ÿ¶´cKC7.£ü”Qˆ%Eª\ËÁ®]»Q Ùå0''ç…^ðYæÑ‚ Œ u×]w!ö|ÀxxðÁEz‘j‰ÀOjÆ…U'ÏÉ:d1 Á¨r~~>Œ¥¸fÍóÎ%DÚî’d§úÜÜÜ'Ÿ|Ò¾üu >iuKxœn¸ÁñU1‹É*(±ÝJžn}ÇwP T·*ò¼yóf<`Š¥Ëû•&ñQ£F=ûì³ö4^~ùe|>ýôÓÝ»wç¨ïܹs¹ªI“&<ðVûùóç9åç”Äòhݺu’.À”\Èl2muC²c`ëÕ«—’K™†ŸmˆMiÔXœÖö/Bÿ0”3228 H=`1oÞ<»>¡Í .LÌN±Ô‘%J™™™˜Va Öf"P] l+™ÈÈ8‚ãMyÒ¾ýÌ3Ï`ìŠ1í³º1—±rPh\Dq‘Á)xèß¿¿$æüùóGX ²~Oo½õ1š9‹6û,û›k‘aJ,fþ¢ÊÆ… #.ñHF¢÷ÑGÅ#dE êÓ¥K—o|ãGï¼óÖ•ãÚ,Ij­}ÁÂíX„Em´žÅ*•UÜ@$yãÆ!&ºMš4iÈ!2¨/~PR¯]»V,'Œ0¢4kÖ,Ÿ­;3aTTTT×H¤ÛJ"ϦyÙaJ·½{÷ú®Kµ0nܸիWSö…Ø;¤sçÎæ¸qãÆü¥6VÝdE kbn÷ UnŠþóŸÿ…~ñʼnŒÝkíGJ–——¥x„\Ëáµ’1¾ò•¯=z4ó’É¢ƒ ò›VT{àñe[3™<7¨_=‹Ýq¥ï›IF}ÖÜó'Ÿ|2œ9BøGÅã7.ÆO•¹—ˆ_¼ï‚âââêöºIÒm%5jäøPÕ©S§bõÊ@nã8~üxäÙ÷eÍ–4þÉ–=öAÉ(0»þ¡¸………v«V­ºóÎ;±Ú¹aƤ~å•W¸ŸKœä³Ã>yL‰2g×®]y¹~øa,C²#‚—xåÊ•æÍ›'ã\ŒØ9yòd ÊsnhРAìc£6¦ñ£tÃøí¤í:üøQ WUU9>¬¬¬ >P•NÍ›7/¢¨:÷•vÔ@’w[É=z8[×A Q)?–bdï0—îAÚeFÖ=÷Ü#.´‡9|øpŠl?„OÍ€»Ë–¬Ô ü\âº$ß™3g’®ùÄ›4mÚôæ›oæ7«d'’>ø[+‘÷•Q dY¿ìܹsn52s_ªAÞE‘‚Û2AY e²úÝ.¤}èСÎj$ªŒ$1ên3gÎôSeãGfp¹5Dû¸:Æn¦®ã·ò\R cš4Mлîº+pa¯Gyį{ÞnÈNž<ÙÏ®;w."Í%7Æn–ëqãÆõ@%ƒ<‰ãk¯½†f>|xÙ²eRt‰GŽQyŽ‹ùêÕ«ñù&X½zõrö£A›6m¨¹>÷Üs”Ì<”0˜%Xð‡re…QÚûK¤Ž<‹=ºråJ ²‰'òúcÙ¢NöŠ'4G†jû©rˆˆÉqê‰"îw·/Ni'y·•”uí~øá‡»[Ø]ú[ȱßbÝB`eÈOõ= À~Ž.q¢v6‡:™j"u¬3gÎð•¹%Ì¢H³À'Õ‘ŒŒ ÜŒUž?þ¢E‹(¿óïìÞ½ÛÅtð2‘Ésݺu)x£1ÞÕ© ay j(_aa¡#Uûœœìd>–@ÂWeó8<…Su‚¨áíHi ¸'ãÜ*y–IÉnG$éÑîçH‘!Ù;v<}útt‹qƃÄ,ðɳc¦å+_ñ»ÅÝÔ©S)®{öìyâÄ ·ËD&Ï-ÒÓï¾ûîØGýö·¿år*žyyy3Ç((¦ž¬ÇæÒxõé;wæææRcÞîðxêsæÌ‰±N;!Ö½Ã=W&(&úõë§UõØùì³ÏTž#BJ€„ü “Ä,ðÙµk×çž{®ºJ ]QQ¡ò÷·ÃÜrCF8c(9rdÈ!1¶]‡`­E#&쪌­iaÒ¤IÍ›7÷ô­Á8Ýü ‹“¸kßG …‘LUr;"ÉÍÕ«WÝŽB’qáÂoæ:YàóèÑ£ñ»EË–-C˜:ì”'Mš4‰ÓZ:Iûò¸å–[â*ÏHoèð)Oúöí›àvÇ×ú5ËsFF†,¿à8ÇŽûêW¿ŽÏ ñN ¶uëÖkf¹M1å£VeÁL£Š1þÒÕ-‹’N:5ºnx¿Í¡Ŷ’ó,b|@§ ú•2ã›6lØ@­îÅ_LäMy•«V­rûÑHÀŸ˜Å;v ±XZZeW‚'YQ!ð¾B×,Ïñ—/_.//oÖ¼9éXQYù׿þ5Æ»fffò·ºµ/ÜBVîÌÎή΃QåÒÒÒ‰':bÊË4ªŠŠŠ¨êÅ|—ÐÂ€šªªªÞ½{‡ðìûsSIOmö}y¿ E‰Yà3~+ˆ>}㪺Æ3Ù* ["ÁOí©AÕî¼ì&Mš Í×®]ãoýzõìÿ¥¥5iܸeË–mZ·îtln\š5kÆÙ´† ùkÿ׫W/_b¯‘+wOÙÀ ýCQeÔtéÒ¥±k3!Sˆbг=Jh3ªŒ¿cÇ>ƒû㱞C/ñÍ-¸uŒî"A÷«I~[Q%5ÞŸ0ª„ò×ý%©>Ι3§ºriùòå%%%n§G ·ïY,]Ìè 6 ½Cn»ÍÔ>®\¹â³sÖ©S§^ýú=ôÐŒ3nlß¿@n¸á†ß­[GMmøðá­[·öÎâ½²‚¦_ýÑôàÊDjÇ»½eU8mé ‹’ϲžk´=U¯Š #C«nŠ‘ÝãÅ‹ßxãQtx‡~â‘¥Â•Ô ® |ÊfÕ”WÒhŸ–‰`ë¼çЄ+Ï.T‚þøÇ?~ï{ßóY“ʱÛ~8i’½‰ q“&^ÿñÿ±lÙ2 »;¾ñ sªÎ 7¬[·îüùó>øàž={0ÑZµjbW¯DbV~‹`;5‘:œœœyóæ…hK7˜NåxGIîz5ZªÉ;õ™’È‘.®ûï¿_梈Ø?ðÀ²'޼ 1”©†þÛ¿ýuYÙW —Õ«WãÈ1ÕSYø¥¸¸ÿ¼\éPà³âå¾öÚkdÂÇ\¶vF†yä‘;3ãU«VÈóÏ?ÏUüœ6mš=V[¶lY°`ÁÈ‘#çÎëvJ+ÉDœøÄ#Ã˾[mÚ´9xð`àªafÏc%p·[´hÁÇ߬Y3ŸµÊ …Ë~ô£§,Àø“ý-ÒÒÒ~ñ‹_ Í”SÏ<ó "S¾ù替ÿýïò“Ÿ íU”M'Ož$+xaê$åàˆ#ˆ 5ÇÜÜ\”‰*žÏêÐŘž9sfœ„pÒ¤I_ûÚ×BOq&H8å»4¼ɸFIÀ2®±yIj@———;*KVñÅ©‰¾ð "À¢Í¨&•Qä–·6pà@ŸµvØäÉ“¿ýío“ÿe›gŸÕ²ÇßgŸ}Ögõ"ã.‹zõ%|Ê8Œï;v˜[?ñÄ\‚»}€^"µÙûcj”ˆ @vv'oÊöÁƒc:SˆÉâhüñ¶mÛ† öÊ+¯Ï‘gê%%%IÑ켫W¯¢¯Ð3fÌ@0êÕ­»pÁ‚k>_Ýzõš7o~ôØ1$›˜tßµk%Å/~ùKÜ/\¼x¨´ô{ßý.¥Ï¿ÿú ^ýõQ£FõìÙÓígÿÇPm$£?1ª,È®YAG2›NåôôtéT®¨¨p¤S9Â\L?IºtÄ8êˆEËßüà>«k™Î_d=–Õ³ùÉ, Ý¯_¿ûî»oüøñ²è† ð/ÃYåZ\|Ö* ”_XáO=õ/Ë‘p*Ç+V¬0·&ç`mÛ§‡_Ù&ÚLÉëý½”ˆ0 |:Z»víÐæÃ‡ï߿߮¾SgÅr»(Y6]v‘æ=ýë__³fÍ7¿ùÍO>ùäw¿ûݹO>ÁnÆz–â‰ýþð‡S'OþpÒ$ÜyFù¯¿Ž¢ÿå/Á±qãÆóæÏ§šÖ£G|Þ{ï½¾n]lSTpöìÙcÇŽMØþ2*ÁýÜáN:hɸ­¤Ï¹ÕdíHG,…ŽŒ¥Ø»wïý÷ßoΊ•lGö Dƒ¥?ûÿüDžqïСµ[Ÿµ¼¹øG¹Ä><;ph=Úì‹óFU†¸#RÜ‘>©·awa•½ýöÛY¸4R0̰¹¹—T×–K•QVÙ+ÚgmW…1ý /H3ø–-[(òÄgup ±ÂþóŸs¿ïK¶ì_:…ß ¹H9cá`|ô?bYà³}ûö]»v}ï½÷Ü݆+|D¹ Î;wî2döRè±±‚Õê³zT«óñ¢žXW”˜¼˜PÆñÆoôÕ©Ó¤iÓÓ§OSpßj{Ey¹¬ FZP-Z´i÷‚6'™F•e!Ë.]ºÔíHùû gù3T$ñ»Ç;B¼Ç¡<ýôÓ?þøj ŸUEtÉðܵkò‰ŽŠr ½Ï=÷œtK›öÔ©S%.A× Gɹm–‘Û!0 ñSh§º'=ΡC‡jáÐÑ-ðI «ãâÅ‹ÈLóºråŠß72nÜ¸ŠŠ ̶7æääÄuôkÛ¶megBî2iÒ¤ê¼Õ gGŠÅ‹ËèSÙ÷ý÷ßÿö·¿-ýmT»òòòþ߈:w~fñâ‡zˆ`7lÜ8bđ炂 tdÉ/E°­ƒî€›bðxß¼ŒéÓ§{y3 *ËtשãŸI*++333£XyÛ]ø ·mÛæHP2N[ÌâË—/ó³……Ýîö™ýduüÛó?ö™¹„ã&Mšjªßüf±êìÁú¹ÈO¿È8Èí·ß^ª×‰_ÄÊ#ð~‹ŠŠÂodjÚ´iÿþý‘ƒ¤h°CE¤U«VT)†jgÏž-­ÏjpŽS—‘‘a:1ÑféÜöïßo/~£”g‚`ÇŽ½zõºé¦›¤€øŸÿùY"ŽZv³fÍíÿþïÿ®W¯Þ€‚~ÕµDž“…@%ŽÈÑûÔÚb׺X¸‹¸C•hûöínÇÂx¿×aÎËèÙ³'µ@ä<GIE3poûììlD-½Ü:p–ªª*û­cÚ±ŠwcÚܤàCn ýôéÓíÛ·çáÑé¯ýëñ~NÅ"jÌIÒm%o¸á†$jó$]§NÜŽE"¨Í~0® T£<7jÔë‹ùí·ßv;ÊÑPßÂg52?ùä“öõÀ©mXëP7D§í¸Î²hÑ¢Àòvùòå~Õ‚häù…^8tèoèþûï7µi9]¹æ]=z” kìHSßdèÍ0ìD·­¤ë÷jaŸ¢# Íµdºó©S§ÜŽ‚k„³Àg»víºwï¾wïÞdôÌñ¼yó°4ì-̾ë#ÅB ÚrŠÓÙ³gîøJ=x;áï!ݶ’J’Ò´iÓÚЬ­ø,ºk×®— 48sæLUU•,FýLjð”çIÝ å79pÍš5&L(,,,((H|d(KçÌ™tJmXòìgpÈ*Þ÷íÛŽ}úÜrË-{÷îMvmö%ÕäÀh·e"fD— µpûa•P`=‡3é9©Áè×ÑaѳgϤX‡D‰‘6mÚTUUƒ[VVöÐCýû¿ÿ{j šëÑ£‡ÛQ—ÈäyÉ’%………2«ò®»î3fLD————›‰§cÇŽ­ (“êËiiiaz¦6-Û9$M›6Ǿ¶)I¯^½t…íZ/ZöI J^^ÞÊ•+S jÛ¶mÛ$ÒäùèÑ£{öìiÖ¬ÙÕ«WOž<¹zõê—_~ù·¿ý­<-5¯?ÿùÏûöí£†Õ¡C‡;ï¼Ó¾ù<â¢E‹ì=Íø´gW\'Ò‰R²­¤w–# “xìk›zP8PíæÚÕÖÐ[/óÕ$ûÄr55N·cÈsóæÍí ¦×©SÆ îØ±£ÏÚ-§^½„†¿ýöÛ$Ä/ùKqÁìö–¤§*•••‘ ­l+™tƒ·e_Ûd7â ¥pmëoV(½C·*q6éêâ~$ÝäÀâŠ<¯\¹òÞ{ï5¦íËh³A>4ךcJF¾ÿ‡zÈígWþYl6¢KÒÓÓ“±•¸ö,¯$õ­Áƒ'W)æ,îîç.\½g“ºï9?üÈúžæ{-|Vk¶} ïŒ3^}õÕ'NÔ­[«º}ûösæÌ1gö³ŸåççËBXÛwÜq‡Û®|‰(öo5jTAAÁ!CÜŽ{Äð•ÊšØnGÄ[ðÍvïÞ½6 sm† úìÙ³ÇôlvvvëÖ­“ú“ ‘·e_Š¢¢¢ê6vŒ+ØEÇ\2̦<]^ßoŽ›mö¥·#ºHR÷d¤É0!y·•ä+íÑ£‡ö@ |›íÚµëܹs ™‰+­Zµª…ë1=ztäÈ‘'Nô[?Ëg2Ù´iSèžiÓ¨Q#jŸAOÉ?.v¶–Yì~ nû”gê<U§Ç{ìøñãâH}ê'?ùI rW·ºÐÙ³g_|ñE³Fë°aæM›¦Ky¬ç &DtIòn+é³0ùb“º±.Fx|ì¡:èø/?êÖ­ëvÜaß¾}Ï?ÿ< ‘——g±íþô§?}òÉ'É»„'Õñ[n¹¥º³cÆŒñÂ@(ÙÕpãÆvǰö¢Fž©^=þøãv÷Ï>ûì¹çž“ÒJKKwìØÁ F†©§ö©SÔFçÎk¿–û¾ú꫺c•Gº•¤PÝæTd üWTT¸÷(ùüóÏ·mÛV{ƈQŸFx‚.™¤øQ›w6ëÚµ+–˜YQ¿Gï¼óNR7k÷íÛ·M›6AOa¶†îqO0${”;Vµk×c×ÞìÓ Aòñ~ð^ÞOóÌ3öŠ9UÎÇS.Õ˵„`LøXwP\‰ ¿AÆNóæÍ«ªªÜ޾]y–”쇾å–[t*s¤bÉ>´¢6Cí*;;;œl6¯[·®ºÙÞ fÓ¦M~.a}·Èð±cdž fw¬S§Ù÷å—_–ŸË–-ûþ÷¿ÿøãSw˜9s&Lj±ñŒl£ÇöÎ ÊÁ«W¯º Ê ±ÑBÔ“tês T·‡ ³‰0ݪûMEMff¦ÛQP¢ªö€¯’Ž;vÍš5î®WÚ­[·={öõLEeíСÃo~óÔ÷½÷ÞC›}Vcõí·ß.~þò—¿ø­ë‰› ®?ûì3û©+W®Œ?þÆoìsçΑÃ#KðKÇ'¸‡»Æq1Jü¶P’‚èöX›8q"–FiiiAAAâãÌ­«[{1²¡adÙÙ³gË‚ˆ=ü4Ë’Üzë­è¿Qh,ã{î¹Ç\صk×|PVáNKK3S¢µWÌ Dm='ï¶’!ÀØ¥ÒYYYyðàÁ¨Kg²wçΩ€šZ|‚Ç q»äڜǃ`ÔÂåÃ’”FQEÝúÕÖÂkK‡µ, ¬ZµªK—.Û¶mûðÃùÙ¸qão}ë[~ÃAQ_* Ç'[ßrË-A— L”dX”Pa \OÎPݲ$æ¬ßTúTâÂ… 'Ož$c‡9 1–¦ìêª;ååå PhÕf§Ø¾}»ÐÇÞF•bD Ï”,Ï=÷œÝqܸqßùÎw¼“ߢž#FŒxàTž½@âlˆåÆR Êhòÿ•+W|ÖqŸÕAcÚŠêÖ­›‘‘Ѻuëp:zl<Jtí{JPx×É»rmm µ÷q‰ q;°ŒÞ°aðaÃdQO̯?ÿùÏûöíÃΠò[ÔsÏž=~½›ÿõ_ÿ…<»ýøÊócYW$I·•Œr²Y (Æ ˜×C† 9tèЉ'dvv¶Žs]›Ý³ðõë×/µ'ôG Ï·Ýv†ÔŠ+LÅ¿AƒMš4‘ãŸþô§vÏ”>[¶lùÍo~#?ýºp>ÿüóH÷GRâG,MÓÉ»­¤‹PÙïÙ³'Övqq±#S¹R¸}Ïuúôé³{÷n·c¡üé?êÔ©SmX:²¡aƒ¦z.K‹`Lýë_7Ìö¶>¡U«Væ¸ÿþ¯¾úª4A ?þñuËg°~ýúH÷ª²ƒõ|äÈ·")¡|6lØ|P^^Ë´:PZ¥jûžë4µHÞýšR²7ÕÙÌÌÌ›-špåÙìâLqpçwzÈÍÍ]¼xñéÓ§/^¼Ø¬Y3êòS§N5g»uëöûßÿÞí‡UœëÙ¬»®D …N–ÅÙ³g©åœѽuH¤Àz^·n]Ô—gddèâJ±ƒM€ Í(ôùóçqáï§Ÿ~êûr»TãÆÓÓÓ)°jgiå5ÂÞHí…Ù]§]»v:u’cT9µ;•Ã$â-1䨱c#GŽt;”˜ÐµDÖ’TƒØƒ gΜq|4Ÿ"Èh í ñ#ú䨽{÷öíÛ«ªª®Ö~þô§?:tÈí‡U‚P\\ã´(Uh¥6€~èVqBO%Jëm4h5Ê‹aL9hÓºõÍ7ß\^^¾uëVæ).]ºûŠ"ÈsEE…Ú|JÊ“½k×.gå,³iÖVìDSa¹|ùr½zõZ¤§Ÿûä“+áÏæÍšiÝÓk”––Æ2éYm%Ý~E‰;‰îæ8½zõÒ$ J¸‰"ÃULç{ï½7Ò]W¯^%gÛ¯ÒŽ×9{ölzzzŒ¤Ì¶’ŠR#an$¬„Iýúõµá­:ÂÍdýû÷7Dz͔ß,çÁÿÍ7ß,»bµaµ)SPP0jÔ¨QëY©U ÐÆ Ó¶ÀØ¡–¸‹¢bWžo¿ýö7ß|SŽeÏ-[6mÖ¬^xàÿöÑéo|ãn?¾âj=+µ ѕڰpU\éÔ©“®A‚p·ÄðYÈþõ_ÿµE‹Û·oÿÖ·¾Ýýþ÷ÿ÷òåË7|øÂ… Qëe“&MÚ·oß®]»ð7qò`?´ÚÍQ ò¬(Šw._¾Œjž:uª²²²FµF’eﲨw%üâââ?þØíçþ‚dé÷*ÏŠ¢(©É‰':ä®ݯ›EF‡Ê³¢(JÊ‚¥¾oß>WvÙB’»wïÞ¾}{·Ó YQyVEIq>œàiÙ¨2Ú¬Fs,¨<+Š¢¤>—/_.))I@otÓ¦Mûõëþ@6¥:TžEQj ˆô‡~X^^UHÙú¥„ʳ¢(J­ãìÙ³GŽ9sæLì:ݨQ£®]»¶nÝZ›²EåYQ¥öráÂŒép¦{ÙA’±’322ø«³™ã„Ãò|àÀœœþºý\Š¢Ô^ÂÙ)54µs6ä‘>}úô•+WªóÓªU+$9õ eŠ—.ê©(Š¢|¢ÛÄÂíˆ(_j5 EQEITžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQÅŸ† ^ºtÉíX(µ‡å9--­²²Òí‡R¥VC)”‘‘Kݺu+--uû9”ıyóæÑ£G»‹/á°<“§UžEqJ¡¶mÛº %™¨ªªjÞ¼¹Û±øÎ7nóU¨B+Š’Ô`H­_¿ÞíX(µçåyøðá………n?—¢(µ”²²²ØMç &¨<×*R¿qÛ§ÙZQWÉÏÏÇHˆ1ìììââb·EI¥¥¥YYYnÇâKÄÅzæópû¹E©¥ìܹ#!Æ@6lˆB”ÛO£$‚ÊÊʳgÏzm¼B\úžÇŽ«´¢(®àˆõ Ë–-›1c†ÛO£$‚µk×"[nÇŸ:×®]s<Т¢¢1cÆTTT¸ýtŠ¢Ô.0 rsswìØáHhðšQ¥8NVVÖš5k† âvD¾D\–%ÉÎÎÎÌÌD¤Ý~:EQjsæÌY²d‰ƒ¡MŸ>ÝígRâ RuöìY¯i³/~«†­[·nܸqºìŽ¢( cÞ¼yééé–³Ó¦M+²pûÉ”8’““³råJ·c„¸4n yyyùùù7ntûEI}*++3339âl[4Áfee•––jwJ‚N­X±bÏž=nG$q\s{Ê”)>«>ëö3*Š’â\ºt £Èq%À¥K—z°åS‰µk×.\¸Ð©‘ ŽGëÙg}3Ôg§M›¦"­(Jœ œéÓ§…Ìĉãt‹#Fœ={–r¼aÆn?®â eeedÇ›[$¾;V‘•yxRAû¡E‰/éééÇŸ6ÃÖ­[gΜIiÎíÜ~bÅòóó³³³=>,?îJ¢ÐkÖ¬iÞ¼99[×âVÅ)¨ñO:UÚ´0´ùÇ@§L×e—’dsqÖ¬YEEEݺus;:¡HÐ~Ï(49;++‹¿jF+Š#RžŒ=º¢¢"®v³nD™N€ò]d$//lóµ¯}­´´ÔãÚìK˜<û¬œ- •¤§§:týúõš¿E J ÊœœJX¤ûâ‘B™.‚>}úÜÜ\mîö>TªÈ6HOAAœ,c¡â;4¬:ÈÐË—/'¥d28Œ5Êí¤PÅs Ç””2ojöìÙÇ÷H!QZ»víÊ•+‰!q£K|uA©ŽÍ›7WUU‘›ììì%K–$Ýð{wäÙi—ŸŸO:ÊO]¬[Q£sX<ÈvªÇ‡L#Õ………Ÿ¢ nGª6Ò§OŸÞ½{û’'ç„À}yVEQÅÄõ=+Š¢(Š&*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ê³¢(Š¢x•gEQEñ*ÏŠ¢(Šâ9TžEQÅs¨<+Š¢(ŠçPyVEQÏ¡ò¬(Š¢(žCåYQEQ<‡Ês¬”••õ±ÈÌÌ:thnn®Ù’Ý#\ºtÉ•k£¶²²²N:óæÍ³;Κ5 Çõë×ÛIð´´4ûU~¤ŽÞxGyyy·«s¬¬,ŒÓ#‡1!ª)ƳàN$Éc] ë+V 0”ªPàòmWVVâ-33“ŒEÖ)´àÔúõë ŸrÕ‘#GæÌ™C ø§¶nœ7oÞp 9x÷Ýw80Ö‚³Âí0:íñéÓ§ÌåœÝ¹s'·–Ÿø™4iÒÚµk¥ "Àüü| Üg51q_yb"æ,óYÒ‚‚y{RÈ%„)Ê£s<‚-**âgÏžÅQüDžð}ôQføÉUD•Gå ›…Dƒ©1bÆŒ¨WÐW†~‡näÑä@^Ó JÞ©$ž’¼ÒµÁY”Ò$Tnn./ oø‘”¤ãÿ¸K´Íã›·_]ÄðÏãs;ðF°«Ø ì’œOsJÚ´ÅEz¸ø”(šÌ7â]Ü®$1>ëˬî,…»”¶’¥8櫾fÕmå§P Ë1)@¯ÙšÎÄ‘ËÉFòW*}R4Lßõ[Ÿõô¶ð]7åøšei™ŒK°\‚ÈÉ­M‹.6_Þ0óõú=Ž˜­>ŽrØdMà¦EÚ4YK°„ )aúYù¢ôHâHä%>>›™+IÄÁÌ™3}×Mêk_nÜ Œ¡ÏÖ¸ÝЂ¤0Ï%‚ÍíDz%­|V«‰yÅ‚$”<‹ñÆ­å.vw1¶FIIy/ü•Ö?_0ë™'o¦YÛ^TáßïmŠs ñLž1Ö3ŠÌ»ý%’%Bxàã•¿&?£åÔ\Éx¸KMŽ—%ÇÒDÿTôå;âÕ¯Æ"$Wó×s@¦•;šŒ!Us9ær9ËçCå•[sS¹µG’ $çÈU˜¶z¢$—ãß|S¸ð8å×dÍ]ìÏNZ2³ –Kä1ƒÓ¡­gã"e`Ð.žê<ùŽÜíÀ •ç(±kFPD]$›J9.…¦”û’9Ä&“OÿâA²—´ÐŠ™¸iÓ¦k×Û{M[MPy6±FŒ<Ûƒ’ÖQ¾ùä$d Ðø÷ \*U‘F©šˆ¸ŠgÑ¿tÇ)µð]oà’`¹#úaÓïc3þM&ªü•ä’d ›Ç!@Jû{1uIB ü,í"Ç…òÊ$(ž®Y%ŽÜWÊiR6Q²Ç\Ùx“ Þü.—‚RÔQâcvPy– ¥þD‚Ë‹ª˜œ5oSâ oS´_nÁY®’‘ºá$E!å$C†èõ—†4¾ üHþ‘ì-Ç|›’øÔ¡¥:èW#'SÉÀ)+8–Jùµ/KŽýó—ŒMþŸ={¶½F.¹B¾S‘ dàYN~JiC¶‘OGÉŸæÉlCñoÏðòiH®Q#—Lnrµ|òr/ûdÇÞ¯ïGŒò,u©4Ë{ñ>*ÏÑ#FIˆ³vÛÚhŒ]ÿì&WU÷)šãòlò«ùDÍí$kÆ“oLT$„<ʧT,®}Y!‚ökò‰ŠðØÕ…ˆ÷äw­i30élTÍ|ö×,£<ðc Z÷#¨ú¥ƒÄЈ™½¤öKv{"K½›Þ®…òíÜæ1«“gA4@žÝžøæmCÙ^òˇR:ÇcTA #¯ÌÔ€ñ+L3†ý5Ùó•_\í9ÖÔÈCȳÉ{¹Ân \³:€QëW#·ç"û'o>1ùŠÅ›=Šæù¥ƒbâoVâ´F~Í–?{Û{7vy–šS,ãæŒN¬Šj¬eeesu¤ã‡:²dAAz§Lצ+\²0?‰|FFÆÚµk—,YúBé4*..¶¢£ÔŽèèz éQ¶rë­·æääHÝ?ªö•2B^B#¢¢"éG÷YÝÛü$36DDSÀÁ¤“ç×Řžžîç {"=zT®•ƒÀJq·§UuàeÉÆ ¥Uàó6ýCìܹ304Ê)"YPPà`¥<}úôá‘ÂAÏòrIÒ‰'ŽC÷#<5zðYúf ýrQ2ö¢ÏúŠ©Èò½ðÅÍš5+tPfZ„ü”Æ'“ As¬Œ¢˜3gÎôéÓ¹£½Æ — =ÜaãÆöÉQ2Ú+F“’¡Æ[{ •çè‘ZS§N%»›œD¾—R›,En&7Èt=¾j±ùb¿¯Ìôݼy3óóóüŠxò—¨ŠàŠøQÃ5C$ˆêèÑ£å€8›Éµb°r/™UL‰"ÚK¢Ð¥ô“Lâ@8kÖ¬1ŒŸ€I ˜H²qU6ƒÂ(|Ö0½>×A{pÑ¢EÎ`–‡% %õ¸±GRO*.$‹Ô3xéâ8HÒ‰OI|bŃO.äYHNÉX¿©Þv²²²¨Ê{!•$ˆ¼#‰Ç”AæmR-àØ¼5û %͉’ t*‰j¼_ÒßÏ] r`OORÞ‘ïÝg½è(®"J2ë×%êp<ŦM›B_‹7Ÿ5˜Q~JÆó™U<5· בVË–-³ŸÂ…¬›™™yäÈGR&ÅqÛ|OnL7¤i2]9Û>–J.®q›c¦ä»>P+œÆíkÖŒ)ÜÅÊ4£ŸøKàÔšMùnoA"òöÓtšÖظ-d[˜Ÿ¬˜ÜŽ[K/i`k•´Šû9i–¶îÀz¦UÙ©Æík×ç¸ ÜÔt_ÙݯY=vvof†¥Ý]nÇ){ñm†óøªŸ÷l‚5ƒL¦UP^E³´oÛ‡§Ú‡†™ü,ýp^À|Ô¦+×¾Ô¤-oJf[™o§ºÆmó.ªkÜ6Ÿ¼Ø²ÒDd:/®4n›O^¤…¾^´YA&&Éè01‘ péÒ¥ö^1'8æryjñoÏŸÝ+‚DØ>E‚5íÞr#žÈ¯‡%CÃ’•ggàÝS!•)¨»q‘±]rŒg¿c¾spÍ*‚KÈ|6â(7µß]>¿ÛÉOâcFd˜YÑ~‘ñ¦Ü+ðqì¡U÷ ؽك%L­VÝZ 2 ÉÏQ†V™(íCq²'fˆw8DÅ/ÝŒ# xG~Ê»ðóæw_q·ßKâïç4>Õ+ (ñ1ih›æ¦ÏϯäJÆbË]dä—Y Ã^Yäw™@Áq`6:y¾v½zǽ¤:Ž<›Ð¤izùòåè«TàD’¥âK–à@âl—g"/O*K¯˜qáÈó5«BiZá»Þ÷,Ê, T_å9ÿáø¶¯?­—IEND®B`‚gateway-1.4.5/doc/wtls/fig2o.png0000644000175000017500000002262507374232663015161 0ustar toljtolj‰PNG  IHDRŠå[+A}tIMEÑ :3 ²& pHYsÊ&ó?gAMA± üa%$IDATxÚíÝHçýÿñc—Vi@ްÖÐ MÖLɨöX«´Ää…-‘e$ÝÀØ’­m*[cX!iY=lÄÐv&Ä¢¥e6e1ŒÆÐX”ï¨gthÊP=Ž”œõ¿¯Þ¹{çxŽ9ž¯ëÜ>n¯sŸÛ뾯ïû}ŸûœS´°°Y«._¾|ãÆ Ûµp¶mÛÖ¯_o»_£i|¶«ð55ŠšÆv-œ°Éc»·ùÔc»NpmBËÏ}¶+Òžpáçžpáçžpáçžpáçžpáçžpáçžpκx<>;;«¥ÖÖÖªªªâââÑÑÑÉÉÉŽŽÛu`º¯¯¯OzpppÇŽeee‰DBáY…‹W®««³]aw={öÇOÃ`á²¶°Ä ׯ_× z´½¯&[Ó¼ôÒKËÚB¶gÏ;·wï^­ðÞ{ïÙÞ×cÚ%‹½ùæ›_~ù¥_˜{'_båÏ?ÿ¼§§§­­Mײí}-0f¶CÓ:¦pY[¸cSjøä¾Í5å«‹ÛJ”'&&”C—––¶··g[µ¦¦FsP¶gO:µ¬œJ¥–ûÇiüúé§Û·oŸ››;räˆf¿pY[Xb­àÏbÈQ°i4×øMóÙgŸ-k ŸRù+¯¼òýïÿþûïׂþ‘ ½ 6lÛ¶mhhHqÔ/̽“/±ò7yä‘§Ÿ~Z?xð í}-0f¶Ùºuk4=qâ„N¡üÂemaé¦TðÖ¨±½¯ŽZç/)^ÎÏÏŸSº¬¹fãÆŠÊj¡éééd2©r¥ •••cccZ_m¦eZÅõ©©©òòr{M‚Ê¿õ¬^XUUuìØ±ÚÚÚ––³Íññq­ÜÔÔ¤-ë%Ú‚6nû8¬˜}ûöéñùçŸ×Œ`–áÓš²•ã®`Ó(*¿ñÆ?ü°¶ùÔSO)Ïhll´½¯…ä±ÇÓ¡ÓAS ¥Ù|Ó¦M+µeÓ(fù­·Þ²½£i×®]›< ¢;+»qEn5:ùF6_eÏ ·ÊŒËÊÊ´<00`žP>­“YåÓ ´æ¼I¡Z™‡TÒÜÜ<99ùñÇ+ÊÎÌÌtww«\ÓÈȈb³‚´õÚºº:`Ehµñ)•µåD"¡¡—¤ºO=W¯^ݼys°\]PI›¹ê_Ç3ßT¨#¬—ø+ëŒR½Iò°Rü¦I K4:jƦ ^Ä~Øc–ׯ_¯¡d{G ŒNúÕ.çÎÓ‰Ž2éàSŸ|ò‰Å´‚–M¡&"ª½ÒÈ‘#GT¸x®×Æ/^¼è·–å³Ï>Ó<{ö¬ ºwð)¿!4RÌ{Á¡¤—økª\…iï%™Ø¼mÛ¶ؼy³J8æ]jsU<íÌÉ\/1›5%¿þõ¯Í…/ë瞉ÄáÇuLwîÜ™ã¶4µ¥R)L) ×××+ä755™PÝÐРx_[[«gµNäVz-!»¸mÞ§Ñ$®,Mg$× ¾×¾ø}wÓ­¹={Å-Ñ4~~|Ǧ¹|ùrÆ{€ÍôÜsÏÙÞËÂSVVfšF³„’c¿<íø›É]É@Ú%Öˆ7½èŒ*øÚ myÏž=/$ØÞ×£ØlZgëÖ­& j?1 ¶ˆÉÇ‚ôÂÅwVê,ö[ÌÛC¿ýíomï«sÖe{¢¢¢"âÝ`þܱc‡’ìl++è*ôš†YXXÐ)Uss³yJçÂíííÓÓÓ Õ5ý©Ø¯øÝÓÓc®“Û>+ÆôÂ÷Þ{O“µfsÿf Í :ß43Îk¯½¦?Õ¿Õ)µñfÒ7É™R1uÜÅWê·`Ó¨3ûóÅ›Æ;SM£×*‡NkåßÚ¬RçÓ§OG¼t0c‡ŒÌ{Ï244qH„^AÁ¦Ñäž{ÓßNÖ³iM£iȼÄÏ-´qÂsîÌUkµ‹Ò,s€¡¶xùå—5õ+ÊF¼#¯£ªc«@þÖ[o}ðÁæžy³²‰ÊiZqBqÝ\>åÂi~Ì{Ï?üá÷ìÙã_ÕÓäöàƒª!âñ¸Úåõ×_Wshdé\V%jÍGyÄ¿Écß¾} ófÔ†sW¤l»Öè”pÅ?*P Ì%_ÛµøMãsêcZj5íZ8Á\òµ]‹Û˜‹¶ká×&´üðÛ8‡ð €sÏ8‡ð €sÏ8‡ð €sÏ8‡ð €sÏ8‡ð €sÏ8‡ð €sÏ8‡ð €sÏ8gí ØôÐC}ùå—y¿<·¶¶F£QÛû±xàÛU¸Í]6ÌÍÍ vttØÞ•PQ?Y©9.ôá³aÃÛUÈP¥•jB>®Mhù)ZXX°]‡BUSSsæÌ=Ú®2˜˜˜hkkÓ£íŠ 3†Ë>.àâ6Î!<àÂ3Î!<àÂ3Î!<àÂ3Î!<àÂ3Î!<àÂ3Î!<àÂ3Î!<àÂ3Î!<àÂ3Î Ox¬««+º¥»»ÛvÈÓ:ÛXãããííí;wî4%¶+@žBž‡‡‡ɘá’ð|àÀžžž‘‘‘ŠŠ SR^^Fm× €|„ä½çþþ~=677o¹¥¯¯Ïv¥ÈSH²çníZ°2B’=K"‘hhhظq£çæælW€ü…$<+×ÔÔÌÎÎîß¿_ Ò©TÊv¥ÈSH³y§yjjª»»{bbBËñxÜv¥ÈSH³ø÷l—––&“IÛ5 O! Ïííí‰DbddDËzœ››S‰íJ§Ü¹]YYÙÕÕµk×®T*¥ì¹··W%¶+@žB’=G¼ÏVݼy3™Lê±³³ÓvuÈ_ÁgϧN*--™™Iû’X,ÖÑÑa»vä#<Ù3¡QðÙóÞ½{õ8::ê§ËóóóõõõMMM¶«@žB’=+<û·KKKS©ÔÀÀ€íJ…ÊœÇv- £VVhØ®BÁÔjõ¹ÙQݬÕÚÙÇ;Ö- áYS@<O$5·h™V­¬ÙÙÙòòò¶¶6§úº›µ²"‹éP Ú®HÔjõ¹ÙQݬÕÚÙÇ;Ö- á¹±±1x)»¬¬ìÌ™3|°ê^Ð<«þÔÝÝíÔw¦ºY«Õ§A®¡^UU5>>n».®×Ê 7;ª›µZ;ûhê¦1²¸naÏ200`¾ÎsllìâÅ‹­­­¶kf===:r­¯»Y«Õ—H$ê†õ}têȧÕíë ½ 7oÞ,..îèè¸víš¹{jjê^ÿSèßÙÝqÛ=Êij »­ÓÕÕeû8áã2†]Éd2$Ù³¹bÖ××WSS£Çh4ºvîÜ^¡¢™4ãommµ5€—¨Õùóçm·ÌW4ŬΡÐdºø¿k œ9sÆVë,]«ŒO­¾Õ9 ŸüÜýðqóÈçR·ÒÒÒ„ç‘‘‘ŠŠŠ‰[TRRRb–|›!LÒ<«ÙÖv]\¯Õê3!P‡Â©û0ܬ•nvT7kµvö1­nÿµ$¾D"±eËÿÏ<ïšRjÛµ õ!s‰ÂvE  V«OG@ÇÁµøçf­¬p³£ºY«µ³ë’ðÜÞÞžmäWUUÙ®]x¸Ù¿Ý¬Õês3ºY++Üì¨nÖjíìãu Ixxçw:;;™î‘òòòÙÙY×ú·›µ²B#¼±±Ñv- £V«ÏÍŽêf­ÖÎ>Þ±n! ϱXÌ< §ê÷‚›ýÛÍZYáft³V«ÏÍŽêf­ÖÎ>Þ±n!¹5LûÙÝÝ===­é ­­Mg%Çç¦0@ IxŽÜúÖ•ááá®®.%н½½Î~A K IxVnooïììL&“Z6·§ Äãñ©©)Ûµ`yBòÞsKKKSSS}}}°°ÕCö (8!Éž‰DCCCÆ/ò-..N+QÀÔúþPÚ®>· IöñîËñ&½öööÑÑQóÕÜ8($áYyãÆuuu;wî4%žŒ++6 "§„$pà€¢õâo#ñ™›È”a››½pMHÂsċЊ»æ¶õ¨L:Û·”ŒŽŽþâ¿÷K¸; à”„çT*USS£„Ø/éêêêîîθ²ÒëÖÖÖ?ýéO¶k @f! Ïñx<²œ$¸¶¶6¯"™™™ ~טÎvíÚå_Eoiiéííµ}$Ö´öövÿ¢ˆÎØÔ^ÁV+--µ]ǵ‹á㸥‡ÏÈÈxYe! ÏÁÛ°³QŸÕB}}}, Þ­-ÏN£ÞYRR¼*Ì×GGGm†µîСCuuuÁ’ÉÉI³ÐÚÚJl¶‹á㸥‡±yõ…$<ëDOC½ªªÊ?WNû1ýù¿ýFƒŒÎ1<ˉ'Òz°¡î›ãràÞ©õ€¯¯¯ÏvíÀðqÃÇ5! ÏR]]½ô CCCfA\‰”™”R+lçþ_²õ`º¯#2fG0|ÇðqJH¾5L‰òÄÄÄðð°Æùè訖ø î––:ؾ}{ðË·s¡œVB÷u‡ i…Ìþî`ø¸Œá㔄çT*¥“¾ªªªX,6??¯óýÛ‹=zTO]¸p¡Û£ìy¹SÃâL÷uJZ`öw ÃÇq w„$<+ÊNOO_»v-âÝ&¦þ”mÌ«·)~+Õôçñž¯¿þzpƒt_§höÞ*Èìï†ËÒΟ>…$<'“Éà}¹ Àeee×ÔÄ­x¬¼yÂsìØ±|X“BM@ÿÑL+t_7ùíÂìï&†Ë>ŽIxVgºråŠp±GiñâïÜ^â[¸ó`zpWW—í]GfšYª««™ýÝÄðqÃÇáù`UmmíÅ‹—^§¿¿_û÷ïW ×q—ÿ‘¾ë²;~Ðv1|\ÆðqAH²çeIûÊ0\³Fóÿeu8(<·s766622üÅI’i€SBž‰DKK‹ùM•T*URRríÚµl·d755}÷»ßµ]e² Ixž››3¿©R\\\YY988˜-½Äú‡Rª=66–H$âñ¸ó‘#G†‡‡mï_ IxîïïW¬mnnÞrË?$ÞÔÔôñǧR©¶¶6Ègff–x»€ÕTðï=±XÌÿýfó­aõõõK¬¬T[¶’æ›7oê…*™ŸŸçâ6À! σƒƒ###CCCæÏ†††óçÏ›¯à^¬²²RQ9X²sçÎ÷ßÿСC¶÷€¯„$<ÏÎΚŸ¸0˜/]º”–@ïÚµ+¸N2él¿ŸÀê CxN$GM¥REEE¦$.þ²~GP(ž+++•þ¶´´œ9sF–””˜C§éèèX\8??ßÖÖf{¸MHîÜV<}ÿý÷/\¸L&?¾ÄÊsss ÉEž²²²‘‘ÛÕà6aÈž#^ÄݸqcqqqEEEkkëáÇ·oß^[[›qåæææÒÒÒÆÆF­¬…ÉÉIÛÕà6!ÉžûúúhÍ/VE£Q%ÓK|ÇÈÄÄÄÞ½{ûûû˜{{{ÇÆÆlW€Û„$<™Ï=—••e[¡¥¥EQÙ¼?­ÕÌ/jàŽ„gó½" &0+ôf¼ÌRW¶=555;;k»úÜ&$ï=G£Ñd2ÇÍ'˜›ƒ?.™FOùŸrÎx7v…$???;;KÆ dÏ?þxÄ{ÚvEX! Ïõõõ555UUU5·(Ÿ¶]©{n||<âýZ—íŠ ³wÞyg-ôÃÅðqÃ'$áY#mttt‰»µCéÙgŸx*³]d0î™››#¸‰áã2†O$4áùÂ… ÕÕÕK|î9L÷x_hº–{°³Ìì!8‰áã8†O$4á¹µµ5•JóFíJÝ[~÷¬íì&öœÄðqÃÇIxîïïO$[ÂýÁª`÷x=8ø'¬ Îþò /Ø®¾¶xøðÅûNI>köü)$¬Rû)–”——Û®Ô=”Ö}MÉ•+Wl× _I›ýEçŽ*ÉöjXe‹‡ÏÁƒ>ŽX<|ÌùS}}½íª­¶dÏÑh´ªªj~~~𖉉 Û•ºWwßl…°bñ쟭«á㸌#EçO¶ëeAH²g^)]®®®öKôgcc£ízÝmmmËI ]0<<œq¢7€ÚºlçI d;OZ›Ã'$ṯ¯¯²²2ijopp0‘Hd|jmö`×8p ÛSë4|²eÉ dË="krø„$<Çb±ãǧR©Ðô¹µµuaaÁÿ³¨¨(ø'¬ þ>iww·ÿ0|g~ÓÈ`ø„ä½çÒÒÒh4ZRRRtËZnT@¡ Iöl~ãÚµk~I¸ïÜ„[HÂóöíÛûûûkjjlW€’ð¬ÔyffæðáÃ¥¥¥¦¤Ñc»^ä#$áyrr²¢¢bddÄ/ ñ«¡’ð¬¤y``€EÂ!$wnÏÏÏ×ÕÕ)c^³_ž“„玎ŽÙÙY=¶··¤….$á9â}ívKKKMM2éX,VRRÒÝÝJ¥l× €e IxUÒÜÐаsçÎd2©Lz`` —••eû Lœ’ð|éÒ¥ŽŽfeÌæ{=[[[M¶]5–­àïÜ>~üx4íììŒx¿[uêÔ©þþþÇïß¿?âiÛ`Ù ;<++›oQO$æ[Úšš8ÐÒÒ¢°m»‚䣰/në±²²2âEe=&“É¡¡¡ââb¥Ñ¶k@ž ;{VŠ¬Ç±±1ÅieÏ&0«„¶­°Ãs4Ý»woCCƒ¢rGG‡‰Ö'Ož4Ú®y*ìð,ýýý&i6üñ‰‰‰` …¥àó¤Eb~VPè ûÖ0B‰ð €sÏ8‡ð €sÏ8‡ð €sÏ8‡ð €sÏ8‡ð €sÏ8‡ð €sÏ8‡ð €sÂðƒ’y;{öì矞÷ËõZmáòåËv÷âÍ7ß¼ûìÞ½{Æ vw$è.›F®_¿®-¬ÈÁÉÛÕ«W#wÝ@ûöí³¸ iLŸ_ÁMîðÙê±[ù4W=+²©B>®Mhù)ZXX°]k4ñ}úé§¶káM›6Ù®Å×hßèè¨í*|MâÔé‚Eû<¶kq›7=¶ká×&´üpqçžpáçžpáçžpáçžpáçžpáçžpáçžpÎmáy~~>—פR©‰‰ =Ú®¼[6lذÉsÿý÷§.k K¬ -§m¹ÈÖ4?üð²¶°Ä 4J~L»¤5IJ:ùW^¿~½í½,Hf¶‘à'›Âem!—¦Ì}$®)_…ç¹¹¹ººº¢¢¢²²²’’’†††x<®òîîn=µø5SSS[¶lÑ£íÊ»e÷îÝæ÷VÏ;wöìYÓáLá²¶°Ä Ú¦V +/W¶¦yùå——µ…ŒOiò:qâ„¶<::ª §—Å´ËéÓ§uôöìÙãæÞÉ—XY±A›}÷ÝwÕèþÆ‘#3ÛˆŽžº÷“O>é.k wlÊçž{.÷‘¸¦Ü§¼qãF-ÍÎÎ.,,ܼyóСCƒƒƒJŽOž<9==½‚ÿllllYë«Ï\f~¤ýÆ/¾ø¢íºà6¦i´°²M£ðüàƒj˱Xì‰'žP ·½£F³¿ŽÞ«¯¾úì³Ïµ»÷ù矛F×4¢ÛÞÑ‚ôÒK/é~ôÑGÏ?ÿü½Ø¾¢þ3ωxÇ<íÙܯ~/¾”j¶,W¯^µ½—…J]ÚÀû=iÏæ~õ;ãD§fUøW3ÙÞKG­S¢ÜÕÕ¥`¼ø¹-[¶\»vM+ôôô˜Eî³¼cÇÅuÑþþþ–––ÑÑÑæææŠŠ W­³wï^ÖÖÖšD\/Ô‚Ùfuuõøø¸Bï¼Çls×®]zVÜÌÌŒžêììT8צL¹ÒzÛ*W&?{ôÑG;::‚åêˆ}}}¦ùå—ZMý~ëÖ­¯¼òŠéôÁKF:£|É£ulïPx,Ñ4:ø¦rlš`*¦—˜­lZÙöŽjs=¾ûÁ§t¨Í5Uѳj-œ>}ÚÖfA_Í499¹ø2iww÷O<ÁåÓüìÞ½[áÓ¼äwõÈ­nBå¿ûÝïÎ;§ùM…f–SSêÈ›•ÍSÇ’YY›å}‡lr½s[rvvV1XQÙ”œ9sfzzºªªJqT*6+OMM©üÀf…d­såÊê$@YÛQ V­À¬ &“I½\«™Y/¬¯¯WÀV»š÷¶u~P@±9âÍ¢¾«<ÙTGœ››ÛíQÇ5ÝT»ùÑGiRá‡~hÖ4g”êµ~ VÄM£É¥i6oÞlšÆ¤zižzê)=j’²½£FI•ÚEŠÐÁ,Y󀎿΄ô¬û3Ï<£ã¯B­c c±˜YÓ„ -(H,Þ¾6«¾÷½ïÙÞÑ‚´mÛ6êõë×·µµ³äW_}µ¼¼\‘Um¤é] ¤vùùÏñ"º µ‚YÓ´ŽbG06«P'²ÿûßÿôª ÞZì>åÍ:åÌeÕh4ªœØ7Z‰rÄ›’Yk•"+Ê©ý÷Œ°õ*åÐi›ÒK´‚V.))1ªCCC Õ&·}XògÞëRWÓlìpêŽ:yüܣޫ?M§|ûí·uî©BÆW'¾|ù2³üŠ 6Ò)¿\m¡É¥iâñ¸r¸ŒM£Yæ¹çžSzÇ•ºå2ï=«]tœƒ×®_¿n¾Înܸ¡VS¡%ÜÛKQAí¥Ó;Ÿ¹­Oƒ»öò`Þ{ÖÑÓLn¢¯¡Ø¬†S阛¸«Ã«3! úo(˜Á•võB/×:Š&ö‹Îlï«sîÓxPXñ‹ u¦“qíáááÒÒÒÅå*T|U~¼à¹yó¦y'[érp5ÿÝåšš­°pËáÇ#Þ ;•••Z§··×öa¹[šJÔùü+oþ^›Snæñ´u"^ žê_ÓÃÊÊØ4þŸwl…öÅMcRÅ oÛûWØ‚ù™NR5‰ûåšÁÕvšÐß`@wwwZö?Re®™û[Ctä}ý?Õ fùÑG5 j¿ÐwäÈ5ŸÂ|°Pq}ß-×=i+@Öíß¿_ qsssÔ£"%Ó «i7d©ë¿ÿþû‰DB9nÆ uvv=zÔ$âŠâŠÐi+(“îééQ$Ö³ccc7n¬««Û¾}»2掎mY§Ó•WUU)SW}<¨G~?¶9ΜHnÚ´I1@ýÒŸÊU¾gÏs„•˜Õ4›ëÔ^…êú›7o6ç›&93•z›æÄ‰96–ýì9[ÓhthÒ„e^ËMË¢ã¬3!sÅ"xTͧ¡ÔRJÕXšúUrñâE­ìš·-ÍæS@ÁºµµU+˜›Õˆ4JÌ[Î:%Ò©O0Ö²ZAg¥šóÕ:¼:R‰ÊM¡&4s}ÛDb34¸`Y¾¡™Å¼‹£ø§Ìµ¾¾^ËÇŽ[·n]Ä»ÿKç°.\¨­­UÌV¹V.**zðÁõ”99ýÖ·¾eÞŸøÎw¾£Rüç?ÿYOi5•ûwë}ó›ßljjºtéÒo~ó›oûÛ?øÁÂõúÓŸ¶··ÿãÿøãÿXQQ¡Õô¿tr G­£h­Šé…¦>+K£}e/EþûßÿöïÕ±2Ó ¯z´ïÚ;Eâ?üáýë_õ”æí I þŸÇ¬üÏþSÝ]‡Ni×ëtдÂⳟ»¤)re?Ór—V­itÌ—nþýïÿ·'cÓè¸)-3O™¡õW°ÌmŽ01re·©&ÐAÓãàààéÓ§M¡Ž§þ×;ï¼£&ÐI’™7tÀÿûßÿªær¨i;³ò_|aVþ¿ÿû?5„Ùˆ¹ ®¸ò·¿ýMÉÃÊV{«çžñå0óÌ nPÝØôjui]łȭ)è?ÿù¢´´ôБÿýﯧ4dtÚôo|C…z‰Ȭ¬A¤a¥vÔD§.þGfö[Áš»6¡å§èŽ7^)~+ë-¬û³r¤‰/íNÑ5Kç¶¹Ð* i|ÙÞi²BâÔé‚EþÇèÝa®Ø®…\›ÐòÃwnàœ;_1^|ƒ ¸§r ÏDhV·páçžpáçžpáçžpáçžpáçžpáçüÔÆ…ÏN jôIEND®B`‚gateway-1.4.5/doc/wtls/fig5out.png0000644000175000017500000022515507374232663015540 0ustar toljtolj‰PNG  IHDR‹k¡»EvtIMEÑ 9#“ñ pHYsÊ&ó?gAMA± üa)üIDATxÚì_LSçÿÇ«‚‚BùŠÂdÂÔQ]¾eñ‚ª³¸Äîb€&âvKØMñbT³ávKÊ.„d ²Ä’¸Á¶„&ËhvÞ€ûË ]2…du†úgÔ9鿤äûþÏ<;¿Rj{ZzNO?¯‹“ÃésžóœÃù<ïÏçùsݳˆ5kÖ455‰^¼xQ§Ó¤˜}lVÓÓÓcccØ1ÒÒJûÈŠ*Š  ÂÏŠQ'+uŒ·Û}ùòåS§NÁÆl6›ô§ÜÜܬ¬,l‘b||Üï÷ÛívƒÁ°B§ˆÉ’áW˜PÐk!¯×Km\ȧ¦¦&-- ™>|XLƒÓ‘vW¡­­­8RTT„«ààrÀäI%Ñ fN§Sé'Ê0~6lü­·ÞÂ~gg'4¸§§ÛÆÆFÁ ½Øoii©¨¨èèèp ˆ9ÀºQ™ŒŽŽÂ~aÅÒÌÛÛÛKJJȨñ“ÉdJMù<ûì³dò¨.°ƒ_‘Ìãñ`ŸjäŒ}\ûUUU¨7PSQÊòòrä€}—Ë…_‘^Lɨ¥]ua¦«±±1Ý#¿˜"Úþþ~8Ȱ4³Ù¼ ´rã8œ_¤Ç ¯¾¾;0Nʇ’!ÁR­ÜÔœNûV«ùL 444ˆ145|-Mg”```G°ƒ éõ{!ÔF é,ò©)rÞ†Y>È–aŒbƒ6jˆ4¬[„Î ú§ÉÅd ’~h¥—ƵdÂ8u…ÝÕÕÕ8ˆ?‘R’Éc‹ƒ¬£~‹!Öf$ HÔÌŽÒ¢¾Â)b‘ð'¥Ä–*.F%°Bÿ µPI!«öC‹’©{ÔOL Ëxûé͆ À, s…Æ)b¶ÈDÚ"½X¡aW0£ýDû”^f©ËE»xÃ0±…”OÚ¸-mî&Ñ]Ü–FÃDB #‹ÆéR±«ûuuudéÒî0ª+¨Z@a°5;BÚÅ6ø•NÁéTZª‘hd+£¸•û_¨…êâ#à™R£·4ÍÄÄLEü¦’••µbŠǃèÙëõâOŸÏ·ÿþÇ^N¯×‹û¸nÀ…ÈÏÏ/**ê@Ù Ãcó‡Ò‰J?W†Ñ8°_„¡N§³P@÷¨éG Òø5*Ô0bõ‚ƒ---¡³…ÉCYÓÒÒŽ=êp8p†ßÕÕeµZ'¦î0ÔB¨" ².— %AÊËËQœî÷û[[[QeáÒµµµˆ(ÄŽ<йÛÛÛ©\éÇÉHPÚEPxqáEJЋKŽ*üMòˆÉáÕ ¾çÔԔ𨱠 `CCC!bhjb"?v…}Ø ÒmåÇyR†Achr„Q ²‡ƒLùó`†‰‹›¬¨6 Tlp!S8z’üxj$_ I£°Õ‹ÔäIõá(PMe±XU2”U_TáÀqG]G§Sÿ¥äZm°Bÿ^w˜JÀô$¼»ÔX„·™†YŠ“Œé8M—Ò N4~‚½Á à„Â$`°™aÞ3ö¥™SŒ+ª;Dyâ*H†œ)ì‹2 Ç™Ê Ä¹ÒÂ,ƒEq]”7B}äJ?W†I`†1Œ‘vP' b–þDÚ «_\3ˆÀŠÅˆæS`ÔÈU ¶”!ÎMžê ü __ÔZê±^|±Õ’!7äOçb‡« ²bAˆÀy¤¥¥ÁÆðŠ»Ýn“É«ˆ¨¨¶¶Öçó‘¯srssa½ä83 “p”””@GQ?x½Þ‚‚H2uÇäêâêBm¤(]€„§««k||œæ'PWPø@Aq ΕömÇ§Ó “f{c˜„fxxØn·ë„ ™Ëw›ÍF=zJß.‹Š™™™ºº:Çc0&''iHøÐÌúpXlß@U Ã$(CCCýýý>ŸO't‡-SücÐH4Fmp+7Ã0 莡†aF°B3 Ã0Œa…f†a5 Í0 Ã0j„ša†aÔ+4Ã0 èþb‰vp»Ý.—‹fOêõúÊÊÊ€µf†a˜‚çCk¯×K+±/þÉh4ÖÖÖ.Ó·†a˜åƒ:áñûýˆ•C/^YQQqâÄ ñϳgÏNMM zrrrø ÞŒÈr|†–a°B'6æ²²²Ðò&kÖ¬¡U@”¾'&N@‰á™ù|>òÕT™>·[¼555‘~Ô–a˜(a…V5ãããØê„e9JKKuºî:¡íííµÙl±ý¤~qqq__×Å/ŒËåjmm¥ÑF£Á` % Ä{xx¸½½ï!ÜAœ‚—$Dz†ab+´êp»Ý¨=±Id,«ÕŠèŠkaE¯±oTcc£Çã9uê”<•…Hwww÷Ýw-´Ê0Œ X¡UT¹¼¼œ²TœœœœÑÑQ¦—}:ze…QSSƒÀš‡/0Ìò²À¨ƒÉÉIƬÓÓÓJ?mÒÔÔd4!ÀÞ‘‘‘ÙÙÙ‰ñn ›Íæ¾¾¾Ð‰@b\ ¯–Ãáˆí-àÝ€<£Tü’0Ì2Á_,Q ˺H»<$)]­ár¹ °ƒÚÖÖÖÝ íœ"÷ôô æÆéÈ$œk]¾|¹¨¨è‡~˜™™±Z­±½h3Ü…ƒÁt¦Ã0Q ­h8˜ÚèííUºÚ2VRR‚-bb»Ý.cFIõÔÔ21™L¡;Dð¿ƒ<Ãóëïï_¾æ™ââb¸UUU¸£¸Q¤uBǰ¨ÖŠÀ"¼ñôÅiªžÒ7ÍÈEéÁäÌB"F¥MøIN&''õz=¶ñ¼âæ±±1eoïü(´²ÅP'ýýýñ·V«Õªô}32áZIü~UUU˜3gTª`¥ÚQZÎÄn·WWWÇí¢ˆ¤§¦¦,‹Òwÿ·Ð-Îá AIIÉèèhœ/ ;…Û¤ô­3rà‘bÿÿOlÒ\ÕD”g*¼Ê{Í•ŽWµ@é„Qåg˜%fyh¤bšwß}÷àÁƒÐf7&“©¨¨hÓ¦M))ÿz'wîÜùñÇŸþù€ƒ—.]úæ›oöïßÿæ›oê„ð×^{-šÂ$œ<ÓºÒ#^¯ „§ÚÔÔÄz €FHMMMñ'Ø8sf³9àJfPùLLLÄÿºš¯çµŠöGŠutt@ž¯_¿^WW÷Æo”••åçç‹J|ïÞ=l!ÏçλpáTynnŽ~ÊÎÎÞ»wïÛo¿íñxÞÿýÔÔTÔ¿Ñ, ét:Kžu‚”™ÖKÀž¤Ò¥S 5²<‹êõzntayh_¡ÿþûol=úú믯[·NúôøäÉ“NDϨX¡Ü|ðÁG}ÃË/¿|ñâÅ‘‘‘íÛ·üñDzK¢ÎÏn?Äý±2žÕ²~$+q7ÓÔÔ¤t)Ô…ÍfkllTº “h\¡¿øâ‹]»vMLL¤§§#&øG Êmš;´víZ£ÑHcÄ@~æÌÝ#½—Çää¤ÒÏC&ÍÍÍô¡(‹ÅÂÃðz½g™ÿ'.ÕÕÕ :¥aGã ýÕW_¥¦¦vvv"JšÀjµB}ÿýwÔ­×®]«¬¬Ü¹sçâdò7nܽ{zÕ—W˜8ÏŽ-ˆDš `xx¸¢¢BéR¨Žœœœââb§Ó©tA&ñвB#¦1™LÕK—.!8‘rï޽ǎCê– ´ùÓO?…ÞCõå•§±±1¡?±‘>|øp¢ÌáŽ?íííßÉ“'—ZÁb÷îÝ=CõåC0z*¡»oñ¬xyÁ¥p»ÝƒAéR¨‘²²²³gÏ*] †I<´¬ÐW®\ÁöܹsK‰âºuë²³³!ÌçÏŸ§ï@åçççåå-•833ó—_~êËîQ¦… @â~‹>VÊ"½<Ž^Ï®FZþb ܆¦†¨7;†-ͰڲeKèÆðM›6AË·nÝúÓO?E#±ðFFFˆ#“˜OD€ü+++KKKÿŠPfjjjpp0šI™$Ò‰;ðm9`—%x[xÂÃÈ@Ë €øúõë3¬‚?…””p–((( aƒêG_€Ûxê©§bDÙúG æÑx x>}}}òz—F›Íæ„ ÎćñOZb®¹¹yppR ?5™Ø€›ÛÖÖ“ú~3¬Rébb†fzÅŠ:a˜ØÁƒc˜mvv6TëÖ­ÓÓÓÑ[lIö*Ë´/¢0Ó?xðàáÇ)))«V­Zü+Tv||&ÙÀÛkÐ Í]¤+P©ðßgÍ`±X¼äÙÙÙh²2 x€pzxö¹fЬB“ŽÆ<[QÞ¹FÙ@×ÛÛ»ÔÌ®Ç{¦!ŽC†±MMM]|ÊÊ•+ip;naõêÕ™™™Ò”Èmff&+++"‘†‡ár¹øKiiiÑ|³=™A›[rsszFb¤ìß¿æ<::ZRReVõõõx’MMM¬ÐšA³ z€ØÜÜÜ¥K—h þ‚,­ Ùƒ7°þUAU0"d7F-–ç………{÷îᦠ¯Ôx°3Tù?þ˜ŸŸ¿/€ÛÇÁ'žxÇ¥9GIãF¦¦¦’¶‰’À¿ƒ:ðþØív›¢É(ûn¾*É„QšUè Ð*“.\Ðëõ¥¥¥uuu8ˆP1%%øM2öå—_~òÉ'>Ÿ: ÅÚ±cGµ–œ\yc:äA3„Yåçç#&}nvv6nMzj}ãÆ ˆ:~Ú°av¨¹;¢/o ˆ~x%Jükx¸r”ÐÊin·Á4¶<ÄIr’B¡_ž?þêÕ«ûöí{õÕWÍf3Ô(hÊ :áÃa´HBíÏ>ûìÃ?LOOlj´˜Iöj?‡ƒª-h-ô ½víZ8K…ÎRÒÒÒúSK¸„àðKà¾@§7n܈ü{zz"ú wss3BŸ$§âââáááÊÊJ¥ ’ðàIBž- ß–-[¨ZŒH¤ËËË“|ÈX}}½Óéd…Ž p'''éÃ8Ü<Ã$-WèãÇ:tÈï÷ÿuïžWòÝÁ¹¹¹[·n…øJ âæuk×Î ÜözznÞ¼¹I`ñÒ‘ÒÚÚ*ã,’g(èÍ›7ŃáË3ÈÌÌDzˆñR ÿð6mÚ„k!" ,›[ ©Æø€×‰—ÿŠ!⨃ÁÀ‘4“œh\¡ÁÃùù?ÿç«N=ÓÒÒBŒxDÕ`üïÅ?¡[¿Ý¾½1''&½Ñ2–Ë…g°XžuB¬iVÙÙÙˆ•C$€~ÓUœ›ÞÞÞ0s>zôèÈÈHôÏ'áðz½xJ---‰û¹uuB"••e4“Ùùc’í+ô‹äY'[ö† ¹¹¹Kµoß>œ(•vèÖ܃Ñ+ôèèh¤cÄP7Ùívx ò,õëׇVh‚®…À}bb"ÌIÛ¸µd*…û-//Ÿ™™±ÙlÐ’¤º÷ø@"M=ÓÀ ÊÊÊxR“lhy}h"£‰»³³Û[·nýõÁƒ!†}-M» 31DeFÉà _’a‘Áîîn¨…ÛíæaÛñÄáp´¶¶òÊLRÁ W"mâ†äääܾ};Ä%¯ç¤^jjj†‡‡¹Ë9þà#’¶ÙlJ„aâ+t\‰´‰»¾¾!²Ø§”_ýUFI233ƒ.¡±éôôôÄå9©šL…‡À½¡ŠÐÙÙÙÛÛË_We’‡¤Pè•+W®ŽÒi8 é3g΄˜™ªÕù0N§·ó+ŽÍf“ñ9†IP4;–[… G”¾±±Ñãñ„“rñ§¶ÃdÕªUëèO8ôáÏ¥º½!Ò×®];}ú´Éd š@“Í¿~¿ôøø¸&ï.±€ ˆ÷3Ù¦Ý3IKRÄÐjµ|D‘neeefff˜+ºëõú˜‚Ú`0<ýôÓí màð¶oß¾TåšÙꤪªª³³S«Í ‡Åb ÿ;w “Ð$E ½råJÅ£Ÿˆ&d£´===KͰ‚pR»4’¥§§gddD¿XuÈ0Wàþýû7oÞ ˆÑáj,FÆå~’qÆív{<«ÕªtA˜¨¯¯¯­­ÅVé‚0̲“ K¬¨¡¡aaa! €FH½aÆիWG4¼+Jà ž¾}û¶ôC¡ìb0¿šÐ9r¤££CéR0ÿ‚obbBéR0L<àVnÕÈØf³̰ÊËË{òÉ'ñS<åYdãÆ(€ôÈüü|2 êöz½ãã㼆ªP¼=Œaâ+tœ¿ƒ4Qú¨c¬zšeƒHggÍÍÍýõÙ³g•-gl«„Çâãm<Š€¥9M&Sÿ /@À+ý~?}‚­H Ò²Q”~BÑ‚g"ã. Ò<+šI4®ÐJá_ÂñýÿÇÞµEq­Û!(BPQy ¢9˜G)âbdˆ¥Œ¹”IA¢õ DIŒàCÊ£– L<Ô‰@’s¥Š{$× ˜cÀ¤ RF7¢ÆF-Q@ò â]·¿rŸ¾=ÃLÏ‹ž½~tõtïÞ½{wÏ^ßÚïóôôD›ÕÖÖÆÖ@GÏhßÑF[ÜÑ&åŒb$$$`‹}ZÆíììHíiww·Î9kÃÆJKKõ8±Bý°~~ñ¾LäææŽé‰u]]]¶º5¾=îàðqh0ŠJpͱpÑ"ósûå—_̹ÍŠÁñ3òÂÝÑÑA?½½½%ô éÎ(//÷õõ%¿ÐæêÕ«ÁÁÁ™™™föÇRæ ¥ÄÄDd…üQ`(ňˆ¨Éùóçûûû߸q£¯¯O%Ì “<‘’aú ’õ¬êÁ㇇‡744àu –Œ˜OII»ÐðIà«ãq,88¬ Åjhñôc'''wKÀÌ" ´ G”œ–#C³º¹¹±³²‘‘‘P]HA2¨ªªÂÏììlPµ——Tµ eCæP~~~ fèବ,Ü…îEœ@'›6m ½ÿ>ªbppW©Õê‘zŸ6,ýa%> G¡êâââV­ZÅNá½ ö`6ÅÆÆ²þØ~øŒŽƒôŽFü~U‚…„Î$]#ÔŒ÷‹lů˜Þ» ¶ØÇ–Œ:ÃÓÒÒÄ…¡dÈm¸Q&©©©t– ™àS=ÇÇÇgdd %nÄ¢«á,]‚üqªººš.DVØ’ùBåATlv_ùˤ|ÜTaã):¡X a´TAž¢QÓŸ@%Š„1cÆ v ­-ÚâüüüáhîÈ‘#xä}ûös Mgtt4ØHOü]ðP]]]ee%iúÞÞ^•åÖaN Î333õ$@]A=ƒ-ÀÓ`kÆ.ØÙ¿?ñ7˜ UÇÖÚ!C?˜©¤¤D;CŒÔszz:Ò`G|®3Ñå4Ê€ô999`zÜV iãK¨©©A2|0‹õá-ã#¡ÞHŒK***À”Ø×î1Æ'„lA½Øïâß„«òòòbbbØ–(ù ØÄ¾`ÙÜÜ\¤Äµžžž¸§6n܈ q枈>°‚‚’yëSŸL†¦È%cQÁ¶F‰c”C±špîÜ9[á_ ?ÛzÐìhêâvttd«œÑ>¢%E3jzq Â3766–••¡578RA;þþþCCC: 0RÕiuÀ^1h‚€&Qu ñA°Ì¼,¼nðx‹,[¶ GÈ­´v8÷c f%õ)I€·ö 㦰è î‚ã8{ׂð‰­qй°Æ§…gÁ&…J Ò††ÜWámwñT-$$éa^ H黺ºð)Òð9uâONNF‘È òÄ>T; ÙàƒD2âlVl*$+ xÜç9‡ŠÕÐðœã¸qÎÎÎ’6ÔVÈÎÎÎ_&Y¢7š#öøã³S૪Uý}¹:AŽÊÑŽKz ª¬WÎÆÅ‹åÌäbV ƒøe±Ivâ:-!J]8oÞ<ýwM²Že6G–Ék^zL®ÔÔTq·¼ÐãÅêL€¯F$vªªª4 ˆ÷¥îÓŽdš!Øšæ<Êô[€”°`Æâ²+2‰l] Ž1…khmÙ¿Múÿÿaëææ6U(«««äªÙ³gSžMMMÚM¤@d ×±æ†FÐq;vʪô ƒ@Oði£0F;-HÕÒÒR ¶‘žž$@õhuuRRxK{Š8%C‚€aÄÄÄH°9öÈGç0Øx¸#î ¦Äv¸NØd¶¼ñÆú©.88ÙÂCÁNœ8¹L¥={ö,ž‘úÉ=`‡t3ò§eý*Á §F±‡[CõLód.L@UŒEzæà0 ×Ð7nÜÀvhh¨¯¯¯¿¯OgÇìÿÍ#óðhnnöññþx Ì’€„8X³½½Ýßß$jrw®Ì–EìÒzhhhðóó³HVÔ:s™‚-ˆ„樄I ³èèhÔv]]ÎïL ›L;Æ"41hß2êì".¤ ´§3N!¸É U¸#È>>>ž¦‘‡µüü|˜iii45 ¯žn„çÂ#Ó—€}<)Oa§†ëÍIã.jµÚ`„ùR›ƒc¬ÃÁ„8Çc4&WYY¹yóæC‡uwwƒƒ—.Y²déÒþ~qʉ“&mÛ¶ÍÝݽ­­-+3Sâk³·¯ïøñã½½½QQQÈaüøñõõõëׯ7­` :—$¥¤¤ÐòÕ«W!jçÌ™3µ„' ž’fl%?õÔSì'ªNIÊÆÁaý;À£4Òlë‚ØÔÍ`Â|‹Ñí¿ÿîÝ»iQ†þi¤rò«ñ¿’0z¾d£ ð^î'žx¼ ÚðððØ»wïó‹üñLJ  eˆcð7¤j ¿ €y8êèè8ø—¿\ºt üM>±U'™Y$Z`ƒ"ITTnn. Ú9 Г-•¡Y»^^^†üUëºäöíÛhé¦M›F?AÈ WZZ:÷¿öL"m„……)‰žUÂ;’óà#ŒÂ±»ŽœƒÃ((œ¡gΜyôèщ'¾òÊ+´ŽåÏþ3þÞŸîìâB" :R{Ë–-===¾¾¾¿·µáx?ÒìÙ³gÅŠÏ?ÿ¼t3¶æK[˜*Áµg«XÐtdÀ:6‡chppxx8-z¦AD°Hgg'v`€Ë†L§¹EÎÎθuhh([,‹Ú àîÃi¢££µ3/̵a¬!”ß1<‚‚‚ŒŠHfUPTP[—ÂöÀ»nllÓ¾Ø88äC± R¡eKNNN«V­‚Pþꫯ [o77þñ¨hêÔ©Þ>> pök¯½ö?µµÏ>û,v@“8~ñŸÿ\³fÍÖÖö¶¶ÿüÛß´xyy9D¹EŠGSxhj[‚µÿ~mâib IIIh£AêäB„†â˜çEòžf^&ôƒ.„)€Èz0=lƲ4?GÈ{ rê®ÖžÒl=àõUWW“Wòï1b·¶ð~u.¡¶7”––›œƒCyPìL1ØÉ“'§L™vùä“OÞ{ï½cÇŽ½ð ýýß}ÿ=væ›o¾Ù±cGÇÝ»4ƒ¬³£ãÞÀÔ-ã°]ÈŸþ´xñâYD»ðâ‹/Zªxb^ߨÉè·ÞzKgw1¤?8‰õçç烳Áš «W¯¦f Ô%Ó[2[u=yòdð=›.¢GnØ!Ež"À`m[u%4ž r­É‘t>ãîÖhµÕj5nÇåÚ¨¾ù²²2[—‚ƒc„ X†ÌZWWçîîÎnnnFË ºswíÚ%ž86000ÃLJæQCAByÿ×ßÿîúøã¯¿þzQQÑË/¿l~aÐâKf¢ŠÙ2:99YgÀ AÙ 8[fJ‹^ä†Äºx5y3ö¡,‰R?%K =íÙ"àSáëÇFð1À$åšÃ~` %ÝÔÔÔÓÓ#qͱyófPÔ¸qÿªˆWü¤¡bJ€mEEÔ¶˜žAó&&$$D"‘Å„ *BQ=<¼vÚ´i“&Mêììzì±Ç@Ø N¶€ÛP˜g1 àaÇ€•i4ÚÕÕfÊp«¿hm·¸@Œ_ý•Lá“­7š¼KZ#g–?š¢BYï.®Ç18‡RaG iâ™,Ħ½:ˆZá§Ÿ~ÚªÅÐéCLrú—½Ž?Þ"£Ô ^å´ Xæ]hÀ^%:&&Ül¬ûÓ ÇøÜ¹s‡3TÂòb™ÍýÎ;7mÚ$ É1’HHHÀ«´ølDŽÑ%3tss3ÍÙÚÛÛÙ’¡… &&&²ØŽzF/€¨m92W´eŸxg»ºº¬zœv £u.¿–I'pVV–Äsª9€xÒ³~,77וCŽÙÓ%%%ó¾n› °°°²²’»;å°O(™¡ÅS®ÐʃŠ(¤cmmmddä3Ïlçåÿ04§g;‡]0ô•+WN:åêêúÜsÏŵãÇ×™ÞÌV<1\¤qqWW¨Z§1óáèèV¦ãööv“P’ô·ø$[гiÜ/æcùÓÁä ??Ÿbˆq/cVŵk×V¯^ššÊ{,88”ÏÐuuu™™™´Oq®vìØ! €Až7ÀÇÓ§O—\^__èÐ!lé'´odd¤™Ó¸@ð¾¾¾:ÑK<`ߺu+00PΤ¶ÞÞ^6ÿKüýý¯_¿þÇtwwCI›Ö£ lmmµ,CÈŒU…  GEE©ÕjìXp\xkt±±±\I[°~Ž;VYYÉVqp¨ì¡[ZZØ>HL–žžNaANŸ}öYUUK.ü+³²²xƒòzÅŠW®\©­­eGhF7ÐÔÔ$¦g•ÀÙ¹¹¹ôóôéÓbe‰³5ÐÊÉÉÉâ<`íF$rúøøèî<¹‚ºäèlm°IsÈÚ‚µk×J€ØòòòêëëO:…öbñâÅ`;Ð6Kð¬T¼¸¸¸œœ}z:w``àæÍ›â#ÔMM‰Íwrb½•]ò1_€­K! AAAÐÓ°êvîÜ9VJn[œ9söMyyùÈRppŒ9(™¡Ž?Þ/vrrŠŽŽ–ð_€=—·´´üøã´מMf in°i—‹é¹°°pß¾}¿Kè°ÜÜÜ$³Ï$ )Ó|HÕ4lP]]œœ †ՅŸ&¯é²£–8=spÈòô c?‹ŠŠ xÖ­[ÇŽttt\¸pÁËËËÛÛ["C!L÷ïßÏ&r«d°HÁ<==!¿Ð¸³‘W£àïïOôœ Ó-",òøAä­ÝKñ‚P__ß²²2Ó:–Ñà9rÄ"2v7XUU…ú,---@]¨y>P-Ô3ÿ`88dBù ­>á믿^²d EpzçwîÞ½ËNó¶mÛJ?333Åô¬z4Bl©0Ì»w‰imm5öB6†ñACzÚ¢ [œ%1­-Ö-Z„gœ?>×|æuøï¨ªÁÓ0ï8CKpñâEý±a888Œ[Ÿ3˜˜èêêÊŽŒ7Ž~655‰éYõ(Tû)–ÔCCCäûsÁ‚)šoÈ/ÆarÜPƒ›©`×®]‹‡Öɯ8˜ŸŸú¿zõjRR’v‚   ¬¬,@r9j@ærd*³———EjCa€ih‚í¥lnrpÈ„ò5´J<^¸paKKËO?ý400°råJ l òF3zþüyrIA—AçìBèiÐ9ÞòõõµFÄè#GŽPa -*++ÁÐÄúç3F=ƒƒ é™0æ+Ó£Ú\>“Y'æÎ;2!8Ç>̃HJ@F9E"73«á pŒ]8XªÃvâË/¿¤)`Z%¬ú5k–$YGGǹsçnÞ¼¹téR™>AÁI–õÑn^´hò5ROéåË—‡K?{öl‡;wî ½•TZhhè¼yó@ÿK®V«¹wÆá[Jç »…³³³ATÙ ?â#&LèììÄÿ&s¶¢nÉÇŸW»LÁí¼²¡d Me^^^EE;âêêúÁˆ½~N™2…-DÖØýàÁƒl4¾wï^Ë–3H퇅…UWWëwBË¢ÐôôðpïÞ½ÜÜ\d ŒÆ…‚¡5BÅÅÅ~~~))):ïUUU…¦¤°°P¿â)--åã¬z*BmÛ3!‰O_ ¯ ð'…]Žÿ²ùóÛ)+ùCT£JÖÐà0ÐÒ ïë냼&ß#555´ûnnn .\±b[ŽbNOO_‹ê***²¬†–”ÿ1lѲCñk'ptt”9Ñ b||¼Áøx–œœmžFÕÁpÑž".FxxøpÏh4˜G|ê2ÁËË«¬¬ÌÎWkkhyÐ33s¨ðáþï nç• %khÂÚµk¯\¹òóÏ?3...ƒÛO?ý”9ðjmm½"`ûöítDâ”›&‹Yµ´`_úƒ‰u2´Îƒà*ß”#±6Oãˆ~zF[€[p ­‰‰‰iii¶.Ũ>•É“'Û9=ëÁ¶.Ǩƒòçr;wîܳg¿¿¿»»; ù•+W²ñfmÂóõõeûaaaÐÓƒ@H[·nÍÎζjQ'L˜jDsfš)€B&$$è‰n9ˆ§Q9SDh±/Ÿ—«¨pd´­ b{DGGó¾c¡ü^n•°† úXìΓŠ Ç¥K—º»»ÁÍË—/_³fþl‘ÛŒ3¬ç8šÖÑž>}ú·ß~Ó™`Ö¬Y:}hƒ•ÑÒ#‹ÃN€$ q¡®Nœ8ÑÐÐPSSÓ @z˜än…;‡Ò¼MF# Ðboøðà N<´ ×Ëmm(¸W6”ÏÐõõõ»ví¢¹ÜãÆ{饗֭[gT¨‰ÚÚZ ­nõ÷÷¯_¿Þª%‡ÎÊÊZ°`Agg§öY H%Ann.ˆÓü°r\|£Í={ölII‰UëAÀqss£Éº¶.‹mpíÚ5Šc·5 gh£ üqh°¾NZñ |ûí·§d @Þׯ_W 3Å$>·[ZZ gŦϟ?¿aÃk—Ú$ }¯s4&ÂÀÀ€¶ŒNLL˜ÙBˆÇÄÄè×а{` ÔÙ*¡£;'''>>Þ>ûxñAªÕê²²2NÏ&@ùãÐPÌà9ññŒ °Ú›o¾ù¡€””ì‹g‡‡Äô¬zgÂÚðôô¬¨¨×^½M€¦×6Š5ŸŸŸ9k-P ¡¡¡ÈD²èèhÞæÊÇÆÏ°uAFø³Pl>AŒƒÃ4(™¡¡2;:: ‹?ÿüsèB_`ë­[·R‚úúzý^?ÙþÐÐÐÔ©SÉëçZ\\Šêîî®}ÂúÖ­[’ƒ«W¯†ñŠMHH0v^(S\H^ôÇÂ*((@5ò6×(@@ÇÆÆÚº# çlŸ÷½Ï9ë’eí³÷Úë}¯kÝkÝë¾þçe1ÔÀDÄfçÎËÓi±{rZns…„øÛÚÚ=zäèB]:t¨q´¥èQ©ÀÌgÜIü>´GAht†Nnõ³š -¿÷ïß·CÛ!üÒ/ý’«õƒ†üXÀÐðt¦ƒ¯ÝÝÝ¥¥%þÏÍ͹÷ÚÚZ©38þ¼?]lÉ7™’Vb~P…¶Ó‘¿”§çlð íQê_Sl_D[ýŒˆªëëëÝÝÝ+++¡yá[ßú½m´>|˜QØ5 Ïëù¯¯멤sOÏŦܨØhmme¶Tå=è™™ÁÇ»ººfffæçç+·¢#£££ÌäªYFºDÃ1ô~ðƒ¯ýëùÌ(¿ÿýïüãÏzŠºš8räÈðððk¯½666ö½ï}/ôôG?úÑÖÖ$m’4#ãòò2ƒr¡ 1jGè#õ÷÷{'¥€^]]…ž¡±ª#=39 õµµ5®›šš˜ðUb–@ä²ïOÉ{x”ÅÐÿú¯ÿúøñã¾¾>W,8ðÝï~wrròÓŸþ´{ß¼hT .òëW¿úUdýÌÃWÌ6þùŸÿùÅ_´CÌZ],ˆ¤R—––"Vèy||Ü»=(ÔðÝ»w«FÒt›ѳî@¢gΜAÌEš_\\,WƒÞ¼ysppþéÏ={x”õ¬ËÒ3Ãâ'ÿÏÿyôÿñη¿½ïß·ÿó?Óÿó?ÿßïüÎßþíߺñ<ÿüóÕÏ<Òíg?ûÙ¬úbÂÛo¿ýoÿöo¶6IçO¨W®\A8Ž ¦5Èå~ݲ,=www±Î‘?´,/,¡–%=¢Ñåí´DsÐp³ŒÅ’PE×Ï=<uÎЮ¼ûõ¯ýw~çw¾ÿýïçÿúÿüÏÿ@б:Œ¶ÃÃë««§NúéŸþé\Áþë¿þëŸþéŸl%üòåË Ä+++'Nœ8zôhf)àoXœ0£££Ñ`¬ŸœœŒ·ê P&|¶´´”ó±"À @‡ÚŸüáëÿý?÷Pë¾”Vv8ð~KÍÌÌLMMýÕ_ýÕîî®=ú™Ÿùfܱðƒêäwf<L…ޤÒýa4¯r‘4(]”ÙO¹ôïàÎÁÁÁ………‚üyÿýÖ(꜡aåwÞyGÚ^o¾ùæ§>õ©'ßýnþRˇ>ô¡çŸ~{gÇØî»ßý.Âè¯þê¯V¹ bèTpÞ騱cŸùÌgŒ¤_zé%]ÀÐÜüÎw¾£ÅðŸüÉŸDÄÉêc£ ttt\¹rÅ;®¤‚·µµ5==]ŠöñÀDÕ××å½ð[k4‘˜‘vÈXgö ðØW•j445YÓ„†ÙÙYo7¦FQç Þxã ø®º{÷î'?ùIÝüQšb°¢ˆù[ßú–Ž#¿÷Þ{ÿñÿ!Ã[U†1´œJݸqãÔ©SÿþïÿžÊæêJTýßÿýßdø'~â'~îç~®hžötu/RÏ©@' PŸž úÚA¨…¡½uÂas ê€oßw‰ÚEý3tjï“ÈÇI¾ýíogõ(UlllHåG?5 —ÒìÛo¿ýS?õS¿ð ¿P¡¤%@wvv"Q]¼x1–â7hYä`ªúÉ“'ȬòVZL¶!~sssbbâ•W^ô£°‡Gý¡!ºÖbè”sÈ‘Iúãÿ8BvÙÓ…-†††>|˜™JƒÚ¶u楥¥”³àÜÔÔ¤­b.¢¨{xxÔ4ë¬<<<<âBŸ‡®dÊÐ$=>>.gSeLn}}8ãòñàáááá!x†®@™™2´pæÌ™ååår¨2CT¤èÒóÍ›7ýi+*Ã3t @ÊÛ¹žÊ@$zöìY˜µèTVWWeˆêáÇÞ>”‡‡‡Gìð ]xî¹çnݺ…ÔÛÓÓÓÑÑQO?~üxhh¨¹¹ybbbqqñÆq—ÆÃÃÃÃã}x†®@Àù¸7¥åééé .ÀÓ0.Âw®À»ÛÚÚNØÞÞžŸŸ÷zaÉ×å®9r$ÿ•gXvmmM¶/úûû¡^׺rjïX­¬.¯®®úmdÂ[,©¬¯¯#û¥Dbö.ŠÀÐÐPkk«7ŽááááQMøUîbñ믿^b$EÓs*PU+—ó%<áeh$ÂËÐu‚ååå‘‘þÇòÀ3´‡Gn¾víšghºgh$Â3´‡‡‡‡‡GáÚÃÃÃÃÃ#‰ð íááááá‘Dx†öðððððH"üyh$ÂËÐI„gh$Â3´‡‡‡‡‡GáÚÃÃÃÃÃ#‰ð íááááá‘Dx†ö𨌌Œ8p€ÿqgÄÃã<ð íááááá‘Dx†öðððððH"ÝbÉÆÆÿoÞ¼iÿ=jíííG=wãÎNðøñãGmnnÒ-õ¿Ð×ÁáqÅ# šššNŸ>ÝÝÝ}èСææfßLû¢zkkkaa>~øðagg'£¼¾™¸óåQ0vww—–– ³ååeÆ»3gÎ9r$î|€gÏž­¯¯Óçææ(ãqçË£R$@sóŸîzþüùú˜_zTÅÐH â«««ÃÃÃ57”{DƒÆeÔ›œœd¼›ŸŸî¹çâÎÑþ˜™™¤+^¾|ùøñã5‘grA“³‰‰ æ—‹‹‹t€¸sä‘84C÷ööò%0‚k]Ô£^Œ244422‚tw^r‚®H‡ììì¤CúÕÎÇÖÖÁw‚¡™«òÐõù¼˜Ò €¡oß¾½²²’ÀGÖ†¤ý*އyº««ëîÝ»^˜ö0Ô?C3?ERíëë‹;/UÅÂÂB?_¢ˆp``àÁƒÉœ:xÄ d‰öövfoI^þñ¨&꜡¡gzüÆÆF¢ÆhªA:Lˆ\röìÙC‡ÍÎÎFc¤öüݰ`ZÉÿ};‰G# žÏC3Ì8q"Oz> Ðó- MO›vuuÑâÎËû ïÑôüøñc(œ~xðàÁæææ………¸³ìè!«««RööhpÔ3CŸzô(4lÝÛÛ›„‰…GõÁ´rtttkk+îŒxÄŒºeh䆿²ï=3n"âØ—C*¡¡yy9:à­êÛOÞ7où#³àåEh=£Äê:sæ =!FƒÕ-r<%Š^»Ft~øð!ÁVVVô?÷¼§§ú×µVõݧ»»»ûæÿSSSˆïqÕOÒ°o¥QÉ¥Oú sµ'NÄ]1£>šAgbb¢9Llù?<<œ+Ý}W& ‹`¤¼)iÐ4]‚ V,©Óm._¾¼ïÖò•+W´äÓÔÔ” †é}§AðÄÒÒÒ… ôóéÓ§›››nfÑ|#­òGå3(É_ ºö­4*™ª®h6è 333qׇGœ¨O†Îs@, .ˆ7nܸyó¦õÜD8“ ¾jÙ&ã)’ÐH®‡†† MÈüø‰QÃîÀÀ€‘½û3Ò  2€JH7³&çFBn©4>•ÎýZ³fÏ­ÌP>óoñ¬˜œœäsKþœÆ£‚H×’˜áô–jã­·ÞŠ3??øða.Ž?ÎpÏÅÕ«W¹ÃFÉsçÎñºª”›Ð(-€"ØÑ£G¹i1óˆÄOø••^_\\äÿJ÷§Ò^'!å„ûÊ?ÈNœ8*ãÝ»w F À+üçõÆüƒ +*¢å¾½Î5Ù&$me‹§üäf__ŸŠ)ðHy B¢Õ…b¾xñ"á•s«7»P-YUré}ƒxèeínûƒ )(ó’eóéÃjÁµµ5*YÕ® ¤˜¼NÓXMÒd´LvSóºÐ+ꊀ ‹Yñp¢¢ÏÐ Ú'-å'¯ëffÛKK O­é – æÍÄÀ}2F_RÜšQH¥âÖ†ÞRöˆS©«grÍSÅcß”•ˆûäDr¡â¡ÕøI— {tl]P^„ðJŽŠ JµzëÖ-E«Æ"˜òÃ#÷º”ÎÃT–žïQ£¨C††\’È·"ò`h×ܾI×xQ_c*XiÔ ÍOžÃ…ÒÒ'¦9Ñ}Ÿ¤H`·­Õ[˜ ê;‚byJüD%òV0žf2´žòHFU¹Ã·œÛÑZ+ñhö).·BY­R™úè4{ÖÔ–\À½.¥óƒjÛ£1Q‡«Ü|W%F²¾¾ÞÖÖÖÓÓcwVWWwwwßÚŸôÔÔ”=ÝÜÜ´Å(>fôàÁƒ©` ‘,½òÊ+Éñó)ja™Á”ŸŒV LîOžº!íõ“'O’áS§NTFb¦ÄL„¹v¦ÝìšrmooS ¡`ÍÍÍ<%¢r_apa£Ýœz{{¹Ð&«wvv"|–Ð(±)]03](c„û‚nC=çoÊ‘fÕÚìððp{{»´·¸ *2—ú‘J©ÏT°g ¤$!¨Vmk™&èêê¢áà¿Ö¡íê¬Ð¼Êš€F÷£DüÏõʳJêâš>CZ¡ó蓆 ßºÚ‹wîÜÉÔâEˆ™Ú²ÅmM^¬ódíEšëðÈŠðꫯº›_äáfæ.ôÞ±±±ëׯ»1˜å·P¶î­i IÓÉi,’s¯ é/Ù‹PœV-îýõÕ:ê¡ùNAJ×¼wï_…;|\ºt‰ï°}|Û¥= ÷¸ã#/2²\¹r…¡„q‡¯T[×¹Î8’áîîn‚ƒ)CÐáC?Ýöºˆ“ƒ²]4GF"^×Ç߀üï['$Í[¢œÐ#¢â¦UŽûHC#¬)ÙIÇ^±‘f!\0nÂFŒ)î»T ãrõfI”ª+tW›I õSÜ^8ížÿæ7żvíš®7@±¤Ë…öGÝÀš2Ò5]£zmÊÈOêz¶¶€Khe B段òœz?¥²“Å¡QäNBT´™ùìg?› ¦qT²èŸ0ÄOñ?÷¹ÏQí|›LÎèÃd††ðéN )ÓYî»ÆôU’£8<€ó´1 ˆ‡Œq!ìüdþqûöm˘ ¦ìÚB&cn5jóEk×’¤³n¡øœ˜)šE{ÿþ}&0:‘P(÷ºˆnªÿâNÆ“Oú-ã†çéFÜB|™¡•·"^Ô²˜­F>}ú”Y°mY)æÐ‚•îð p½¨eFíNiÅ iƒûàÿí-í~¹±¹É¹qÚOK=”1Ë-ÿµM¨…D»p3¬ ^×R§^TBÒæÍza°³†É̘`kòîâ(ªÐ¡Êºž¦dµTÚ”yÀU•*=ÚØ¿µF@Ñõì2´çéÅGâ–áËŒ›7oÆî\’©7_ÂÄĄք㮀akcc£”N¢Kmiï»Á¼µµ»U;Û}Ðjmìùñ(Ì<…˜2÷ed¨Núüq+;ø¬´owF’‚zcè„àD€¸sá‘÷îÝ+h¼Ëºm<)©$R¶//ä“&î’Õ?˜QÅei§úÐgµ³³ÓÒÒ"ÅÆw˜íÚÃÃÃ#é(B†v + °Ýääd쫌ù”TzµR&M¬Ä_ ĽÌ^fHý¤1?zôHj;×wïÞ-K´U¶H0::êîD†ôãt€[÷M‹Ç|¤ãSÍÜ–EôÐ>´çntý}bù S²h< À퓹~J©ÓÍ!ÍZ¹è#Ñõ¡)Ö Äc嵋z>*§½¢˜a¯ãÇ»æJ¶Êƒ¸L4èš6œEÑOÙðJ°š…)}óY¿ꤥ¥Å5@‘L4 ¦X)îtA¯0ž>÷Üs!=ó¢±ïŒJg¾­Eø<]slÆL²üco{¸,SíÊ¡DM±ÚåfCÈRaCÁ3tÁ1›u¤ÐÀ‘•·dËI`ÆÐÅMCoåŠÄ½ïŽh²hh#š}Ì'Nœ-ÃP&Á¡C‡Bf¹¬Pº ~wtNg'ù´Ur@ÐÑ8. %°T`)¥Ä < ÎoÍÃÌÓꤲ¬×¥ƒ‰¦ú¶¬€Ùýô-ëå/¡–kÚQVVVŠ;m%óÀÕÏpÙAóÉ@[܉õÆÐéÀè`%–DŒ¡SŽÙNÙ¼uëŸ.Ô%kböŠ$RH©<(¼mjÏx“¾ÿÔžñÑÔž‰`_$€{(Ö"GhÐê´Œƒ’ ׬±ì„„•O£j3‘«ê4ÌÙ}ˤ΃ºòŠL4ƒîîneX¶$mE‚‹¬ÇÝ/~Œ\kÑM_7 ª´ •…†–eJ–åN pæÌÖé°µ«dæÑ_?Í´õöö¶l_ÛYj¥¥yê@?½)uË’^Œä 3ÁÌÒ¤RG ªF®y—Ÿ|/îqgÁlq›l|*Û ÊvÚ1˜/cø²ñ™v–‹ä'Þ& »™Þ3 «’Êê­Lí¦÷Ö4hi§\ÈꙢRHe˜BÉH*eÅê 5Õ[P++’ u¡ZAq¶œëuÈвÛPöh3šïP”¬:ãßgh>n¢§Ùú7"´hSÙ )[BeDÀ­Ts‰ÜxØ5×nWëS!îÒ‚ä sé=ÿæ}A´*;ÌfYîYŠ”gj@‚rêƒv¿É$ÓÂSQ ùºÌªFÕÀ^¹3ñt¤+W®È— | ëвGMÓPRžÂjÕ ´ù¡?hʨֱéÚ|"‘kÙŠ!™dWZ¼EZ²šÎ[¡ÆU<òz’ tÈÅ‹$-C˜êQ©À`œæs¤»µ¤Hxºo¶^óWhRsJuK nSC÷¾îØ 0™wgü$cä‡DÉù7ä´†$HQvô‘Ri]‰ª9”µˆÌõ+'2&ãÎòoåê»{Iöð}2t…f[™ ýð›»Ó¥r×u¡w]Ng, ë§ËС…;Áõs`¢OÈï…ÀëÝ›æÚVB¹Y1”¡s%¤…nÂDl–31~iå ÄÐæ“ IJ<˜‰XÄ‘ °4Æ~RíЉ®å ÍØuaËÅÖQmµCM¦…‹MÍ=†¥%[ñö9dên?´žfßíäé^^ÌÇFD¶Ý–u÷eèóòã’ޛκjéܾXàZ1´¨TiB%¢n-65n*°Í©-p]¤ƒUÞÕG­o!ä¶+ÏVöV„ÆTº¬7»Ü©À Eæ1ƒJ€¹³ŒQëˆ=Ÿ%¿¹ˆ¸¿´´$3ÝSSS333|«!ãÕÜ~öìYss3cù7s¾fè$N÷ŒDÿæææFY$ΕÉÁÁÁcÇŽ1è¤7½äJ‚²m›ub@&evJ‘#7\ºt)WärÄË(æf€¢=xð€wÉ6OIˆ ¹Ó **Ý( z䪚@p,È9tþ AÍbvSS“ªWF­é“ÑïÒ(gaM‰×­Ë)6«´T`4ÃÒ"•ÖÖÖ‚òIB÷ïßOiR)ï}_¡‹’b¦käP¶í>S@¾;–C‡ç§¶xèÀ¶Ñ@ÇŽ`_>™¤•Muí4¹ímoË+œÏpzzš¶æ‚ÔI¢££ƒOCFìéøÐ2ÝÃG€«ßc=„¸§3Ö²‹Ñ¶!g›s:|uþüyí?qŸÏ/´ÀN>QF 9£äÚ¶â®Åô¶}(w¼Dk¶³jc*Eí(+!e/dŽ˜Øˆ\I¸«y¤åÊZÞLÚ%Ky1ëOU(U…mÑQ*¦ÖÞ #ƒáˆñÔ„«Ä^Mh‰¸b´5ÓB´¦YrÔv”Ô²ÊÐé@ÐL\¨#ÁT°D€NÔñÔ¬æÝÈuþ2´–¦•7[n‰–¡INBç¾Ù6(cöS†NM©ÂîËËd.ZËø|/¼¢ )¾ý§rSFn5Í2¹æ ÒÞHï­VK€ôÞWÌT•Œå©>©ýø†=hB½²Õ>¥Ž;–jëcóF”ãÎEÍ£r4™*1e4¸#xHiß¼ˆ«ÌEŠ«ë•”Â2ØýP€ôžƒ–L·+.-™g”\^^,­|²-„W YšL„‚IQ<³3ˆVM#R®TC9wk kꮳ ûoºléBN7h2‘gàºGc2ô•¼þ022rûömë­i477_¼x±‹B.Ξ={ìØ±¸ªQŽ766¼Mì$CÍÄ熘;66Ç—Ëä$_q¡Æ¼LGÄãÀºe«¨R×q™ûûûkÛÖ½)ù‘„éÚÖÖÖ‰'¤Öw}xä̈́Ի»» §–k:õøñc¹ñ.(Ðëëë~Jgð ]o`FÜÞÞ>??¯+ÆÄÜ܃#Ø©‘œLLLÔÁºŽGEÁÀÕÚÚ*G×qç%AhL†®C]n#2ãòÉ“'ã΋G< éûûûWWWc§çTp ‘¨££#SEÙÃC\1::êéÙ#Uß Ú#é¡¡!OÒ ¦7knIÀüüü±cÇ‚=I{dbkk é™™œY ôhp4ĺ£!’ôÑ£Ggggã΋G5ðøñãÁÁAÆ;˜‰;;a0u {~—ÑÃÀ…Ü<11Áå¥ç¬ð«Üu ™ò¡ß#»Ü¼y3îìxTpsoo/ ­CØ ¤çT°Üd?<èùøñãr²ið2´‡‡‡G]afffuuõáÇqgÄ£ =ONNž8qÂ]îö2´‡‡GÝbww7î,Tˆbƒƒƒ5tÊÙÀ$ CkýCð2´‡‡G=Nºyóæ;w¶··:”àÙ³gü?sæÌ¹sçŽ?^¯Ë¿===+++õZººÇììl[[›V¼Sedè­­­§OŸÆ]:‚Q‰DáñãÇsssóÇ;;;uÞ7¢5!iB1…wYêì|0EkmmÕàîQ£˜ŸŸ¿páÂÚÚZª¸ÓVôìåå剉‰'OžÐãýdÍ£°»»+Á«»»›þĉqçÈ# PÑðð0P,bq,+«Œcß4úäädLÔ˜n...æbh†n&(ˆhuPÒúFGGÇÕ«W騩tÞxôèÑåË—iÚ£GŽÓÒù¿ëáQxúôéÊÊ M?‡¤µãΑGH´mĈ”ä8«º.3•\Oñæð$ƒIoä"/šÉæèèèÌÌ ¯Õñþ‡‡‹­­-ºýƒ¦§§ý²a°¾¾ÞÓÓÓÙÙY yW£ÜØØX__ñ×â(744ÔÚÚŠ•õéÜÜœ´»§¦¦¦´ri“eÞ'Úíííööö¸‹X*(øîînÄŠ e·bî8::TJ¥7655½¿qÍä„`æEbpsܳ €PuæÌzmm-î¼4.ˆÎŸ?ÏXYéVPBŒ­µ(bæ™mQø‰'rÈ$ ÆþÇ]¾2:cj’ë©¶~­…Ó7¨ºèø @0Þâ]»yëÖ­ÙÙÙB³J$´æ‡¢iüäÉ“;;; Ræ9Ëã¡À¨Ç†ôæž‚ð¨ÛÚÚ`¬J/f :߸qcuuµ»»{ddDêß5YºØWà;{ö,2´ìXå “ÉOeq„µ îzŠÂ¥K—ø?66–õés¢c@šÍ ƒP® œ››Ë?3p.m”“¡©Êææf‰þZ‹ >eݽ½Í ÈWC£všìíí…¤m«–¨¶i[[[[C6ž ä¨|–U)¸¥¥%ë´h˜|*˜LLLP?!Ö8†††Úðˆÿ´ ¹Ï5ó}AD…øGlËËË\(B-/ó” î󟨸èêêbV‘ Öç¹¶´äDñÅ933“ &"Ê­\J'³.:’âá'÷‰\?b ÌÊÊ /Z£sA0Jª"bDUE™³¥¥¥û÷ﲿ¿ŸÀ$êæ<ºÎ³34…¤*ù*Þ×%û ¨¯|âõð¨30OE˜>vìXbGm>ÌÔ´—{ £Œ³;;;J,ºÇÌ æççu85îÊ(àFuX¤ˆÓ ´ïŠGi­7¸ K"WêíàÁƒÃÃÃÐxûöíÉÉI=EAWÓÓÓ° -»€0›››¼ÂSBBi_{íµ‹/ªWóŸkKÆ¥ušššvww‰„8¹Ð™:"¿|ùòµk×Ĭd˜ŸZ ÖY$®™v[l£££LÄ©þsm÷ ÆëDûôéSr¨2rÓÊH> ‰„£'tÄrÅF[h‰O‚^Ë­jƒQ¨chµXª:Ï&¦º˜ÞzűJ@ôœé†/F0Ö IG ­­ fÒª/5Ì8ï>-Ô€9,¥]UF ÷]Q]* "Y|»sç)RçÏŸ‡¼›šša–——Û@~’¹I=óáÃ|ʹ}íµ×RêAB¶›Æ+(–„ˆçõ×_'d)³,òÅS 6$ʬ‚Ùƒ)’º»~q0oH½‘™p8TF&*#qÞ¾}[eŒ¨1ŠÀÔA5f9ß_À«Éî­[·²JÜÜO³0½½ÊÍÜJoÇÿC ­­­E/2J@b~:ØÂÝ»ws-Ôˆ¹ 5+šÇJQâòþÃ¥Ä ÐSKßh°zàB T@~î›Ér$•ã‡-R•û¶xMLœU8üSê`•›NŘ•Ì“Njñ7nÄ‘ìÐRê¾Ál­Û-WÖŒÞÖuí~ ¡ØÈ$$cX²¢Ì ï^? à^„Þ59º8öS â^¨DdÞ-”½¨qÏÍݱ8u“© ESµêîæÓÆO×ôö¡C9ÌlˆDÿ;>ÊIÖ ¤ã’-á¾£˜j“ÿ¶/’ ÖìP©$$2M0X_«ö\´´´hŠ@f1!†f¤‘”0ô>­*Nc½Îq‡âðTд§Eêð·>3ÝW© FÒÜס2žº4O¢”]‘ó;Â+2²ÆÏÐGKö43\¡ŠX5R:’£¥y—y¥SéÔ-x…hùOx" •¤ F>¥ÚàöîS bVåSá £~IüLyº¸¸hõ µ -6È×JK™'!·¶­ „Ôn ÜïG‡J-Óº9Q6È•ª:ÄÐj^Ô®ENl™E#çJ…šqëÍ*ŸkÍ­¤ù41?‰SÖÄ,?YÇeÕm:1¨u†Ö.f¢&=™9Lìžtž ]QH‡‰l0Èh», Khc8ÞÒ P†•±¢Ÿ˜¡ÂrY¼“謭u14n®x5Ì1Ò­ZEê+++©`§]MáÉ#&ƒ,O¡ ^Iƒ¯¶Ö]†–h®¬rÍHJêª3†VBªD.¨DbPä²C$îk2¥;ü”’!™ÚØAVÅRb ­~ˆŸÒ Kþ¥=g½G£ ÉArdƒÿÊyQtË…æC¤Å«Dd@#¬l*ÛòÁn}”ûöRoT‚;AKGæU:ÞUžyWd¯ú¡ª[«Õ³Φ¦ÁSbpkÛBjŽ¢ ‡ÛIŠüW¹ˆP¶¤K™”2hkWuB ~ÍÌTç¤EäÔ’^ç'T4•…ú'~1¥4oUWê<5½•´,MìB­\¹¯´ ðÑQÕ¡e¤˜X Õ Î@)? ¾}}Úe$T¨$×ân¼e¬¨Ø04M1åÉ<®nę٠¡­uˆ:DÙB ­™ˆHËDáL†Nܬa×y]5¹ÔUéŒl4¸»‘§?h¨VÁ4 ­~Xlñ@în½8ÂIÓD%š¦Ÿ-ÞºG(…(Ùô Ï»¡:‘(ìR…ˆît«Hó]SÕ–Š(G3$kVÕƒ•QåR¥i–cѪ¶í« S ÐÖ”…‡É-Í­Cñë‚M)ÃehˆÓ²§`!Ï,ë®åˆ•5}q‰Ÿ„ÜþP®&v«%¤_Ú°`²r´Ð(¡žœXhº\Ja5!.o®ÂÐ傯¥hKllLãcVØ8Ríaø–áPþK‚QE·;\ÚÍõõõÝÝݶ¶6ýd´%6D"¯ãÛÛÛRxË…ááá¡¡!D1¾öövØ=«±Dü˜v¢¬+¿ñÆÊ<ÙÖýÎÎΩ©)Yg§tüèêê’¸o…JeÓ¤ ó§OŸ–Ö›»áÏ»ýýý$JѸ¤KUè)ñ!l§ª{üø± ÞJ±ŽŠmnnÞÙÙAæÓÑ@Ëöôô´žmh£ˆlLLL˜1^hŒ¥u¯V‹˜bˆ½nõU“w¥PMxòœµ¶¹¯M U‚u!Y££>³ªéÑxÑ dÉviiÉÞ¢I—:Q-ݹs‡§²\ʳ:Oé!¦ê%³ºô(+érzZ‰Ml Ãô"·þT»«.[(´Åw!ò‚VzJÔô¾z=òB:Ô"l´†X]oIÎÐXïN%/º¯FÒ˜^Ô,O’†Hù“Ñ´”ÁNBa.ZkÈZ[ °vIµ{rdh-e+Eb|)Ö3 hÝXKU" -)+˜ S¸)êX‚ý]ëîÝ»ªÐN0 qŸüó.D+/I:Ýoç,‡¶'Êo’½Ö3Ȭ w©És…?ñeh{µŒÈOñ/jï6åȬV\dÊÐʉ («mÓ±§¤’ãSÁ°å®¯jß—ÀZäpeh.\µI·}µ3b}ÌÌ$©–HËÕUL}PÂô¬—¦‚É™•TY*K»ÐæEå¦Òµ‚ C&pÝ8%Ú-»I‰JÈÐÒàIçPkŠÐu²K„†;Ø¡¼ª£ùd8kéÊR¨<ñ¿«ÜŒ>yî¥I'ËÝcȳ!R‡…Vhï0¤8— ÈR¡8óÉCH¥0¤¶‘O÷õˆ˜ ¶WªÍ×è¤ ÕfÌ´H«ì¡˜ól”è0¡ÚÎ¥–YDëD#—º¦ ­r‹DͰ@®’–ØÄ™°Yc#£†m?K‡0¿ä?ßT«WÒB}3´>%)‚„¾&¯{™*&…Öm:ZäˆBRÁ¾j E6™¦t™[¥ªˆ,ý˜¡ãR“Còà˜=½Ò!™RºøÒˆ. \òȳLS¤(qt($íîÁ7&ŠfèB¬»S¥U_eOKwõÊÐR¢Ô§är•„4S·ìëë“ökèDVæ7è|J;§¹ìx§žZ„@SøišYnB¡#aRùtUV3 e7íE.˜p(Ã6‘¦m(‰P˜ŠâÇ M>ª)¹‡@ɳ*àÔ4h×ÅÅÅò®ÚÑtþÇ#+›ì³”VÍÔéÃyîUñêrÇСåã<‰MbmôDSÚììl,ãXÑ‘’ÌÐ:n#•ÕÔÞîa:ØœÒ>‘Τè˜L*Ø„Òá`=…¹3ZÛmÒ™•ºyWÎ<´ÿ¥U"åAzˆÚ:ÔŽ•öªxEñp_û˜ÚÖÔ™RÞ ÍÿìDŸq™ÕI!@O¥¶c/:Æ¢ò𦭢­ÂÆÖÚkzx”Ž*KíYïyèâ:”[IÏY3Ù¦Éøø¸ÈÛHNë4ùm®ÆØ*SÕ’­5}±¥ŽÉv­™Mfä0Mzt.à ¦WõÄÐ:Z’vDaûP{ãÆ ×Šƒ•ÅDêÐy kY@UüÒn‘ñ¥T°-%ÙÔ" ™³C»gLÈŒ,CÀš’ì-Q’ƒ¤õE„hi_8˜ÿ°»™î°wCǂ쀨NïmÑ–·ù2ñc]îÍÍ͸|?Ë™™Ö Ɖ‰ ÂRŽ ¹fh–MG }ºæ(rï\ÌÍÍñuLMMqʳÎ*ݺÁÎÎŽ¸qA»À©ÔsVßÒ¼uéÒ¥¬¶Ze ³µµ5Ù°s%§N’MoSáÜ7o®©Nˆ™¶ØÝÝ ½ø,€_ЈpY†ŽA¢ëëëL¼tä$ÂU6ÉIißM¢šœõ!òWïÜ¡ â« )¿ëkS~»ìœŒ¦±ÑQñUœ={6•Ãll„µwÙSÍõ´P#´•Cq9)ÈsÆÂÂCŸÇÐÐk!É|•›aóÒ3Ýd¡0u>¢âÜÃ42BÇ«ŒŒíËe|xy+%Š\‰áRZ¶ÊÍøË(Ì¡D`‚båAqZwåZ¦¶‰–xB‘ë°h*L€Vt3‡,Mâ®ËrBV¬3]ÃRÔ-’®»¶%S‡0e?“xQޚݡRꪣ9¨.jUÞ Cu#¼wï^.'ª:†*,//37ÒúùƒDöp*ïÒè÷ïßïîîF¥M™±X1h[Çdhh."dTÆLÚŽ£•Ñ SþøPéQ„@1šššh‰[·n]¾|™‚É¥v*8úB}¹®7÷…véùº\ÇÝ5®ï0+OË—gÖ8uº·Pj¬©S®‚bVaó÷œAütbBÖKì'ñ0NÉŠY*8£\tB™‰h²P˜JÔ§G­@GØÝ;FÌæVˆ17$?ÐáºkæÈn°ÞH°Hb#N¹d ÛÛd×ÓÓÓY#—¡T° ©ÈµC(9nî+iÔ(õÊÊ õÆ«úç?Ň8¹yðàA(ÿ4¸#>¦&ååIFB '»„Т‚ Úó"²5s,‹Jà¾r7à©¢" ?5‹Ú@‡AD¦±dAÙæ'I # sÍÐÇ‹v½ž\¿~]³Cò §ÇSJÅ.øÏ5ôÏ»Póíy+†²‹µQ(ïê9m#+Ê™Pw7ÍmIÇR©Ü¬Æxù`¤›à*àÙ‰/ò®þàEž¹".{ê.÷ƒíím1åÄÕb›•ÙHˉ]H­Ñb–âC(ÝÐ+¡œ˜¥uzUèd³«—H0¹6ÑÑ=º¦ôÜê ){CÀ¹ôäµûb®XÓÁ1îPÞBn[ƒvÜNd†±ÏÞ2;n®ÎdHuÎFË–½›®«9Y^ÛEÔ¹kk:ë'o^ü¤”Þ³"lw$­2¼ª°êEúØm{ÒÄóA½µu*[ •…>#¤ôž&pjÏ,®EîÎ>#ê¶PO\IއΠÙÜN»¿©àVåÒ*; je$1ü¯QÅ2F*½¸¬/dUÛîK[Îü ¥ƒ¯¢¥¥Ešu:«®|J‰Î´x$W Òß3½>ûnÑô™1Ÿ"|zoÃ_~)d„5A–ÅM90‘* =RZnN\…9fâÃñî%ôŠïSwOí™)%Ù¥"«Ò¤Pꦚ«ÁKZŽ¡ð²ì!Sk.ºgBp-f»ÍçæÍÍ¿*ÖjÏ5ëaÍ$¯DfÚS¥Vj)·ÑÅâÄÉìG&ÓeñÔ,›ºJMÀ3tA ár —%ÊelÍÔY>]…Á×(YJ@²Äž Œʰ¼yF¢SY ZO ½ig*Š<½·è}(Ôb®W†¦ì0å}§r y?fè²ÛjÉÕùøH´ô!¶³û²÷2Œ~.@Ú±äœ ÔS{v² M3&–$²Ô-ˆ Ìð¯‘+3A3ŒàÚ½ÒߎZïÏÊе•=>i‘½[Ñ¡Wd‚Øõ)b†£¹ hrlE„n>.}cÉ%Æf¶iÄ:ÉQM$'f ‘ …7?Õ7smz=µ‚„XýŒyîCï»›[ÓÈÜÊ…$ïC3GÄŠ“éx0SOɧҤª²o¢ùß²‘‡}‹PJfJYÙû#‹ÜWb*Q^èä¢ó»B5'3ÁHÑ××‡ÔØÛÛ+y=îòýä„üœ={–¼1 -t×=´í—§@B011—a¾šC};ÒÖ Æ¸sQ*`e®DE$ãrçäÉ“ ˜®…"ÛÜÑÅãÇy…`²ï¡eK^!®¹É˜622böCRòÊÒÒ’t?‘L |Èh ˆVÎÚSŽ¡$»Ð^©»t¦‚Èc=ÙÈj…¤»ºº£œ“4Ùã"µgeËl•¨NHEù·úap ›¿9©}ñ¾ÅzUé‹ U’%b4"/¦5ÞAkéÐsÒ֦ȹ"oIÎè…é@m»:Ð9œÚæd¨!î\¼ßŸ8ËS Åì¸sQYÔÐ~.˜© }b8’¥#TgF´)&˜a(]0·†Ÿ¦§§¥í˧qéÒ%^yðàfÞ\0¤ììì¸ÉÉHŒíLv¡ÀÌCwÄåÊ•¦¦&Dæf(ɵ˜tþüùáî[„;ÚRÌ4=KO™lsMÎa_ŠI´°/ù'-ÛQæ!‰êµ×^SäŠDÉ0Ád*Q¦¼ËÕï3´,ÅÖ<N;’RÜ]”Žò6t‚iyy9 ›59–´]³ra~~^[Å®Ñ ‹ÔhŽpdËÁöná?(Y¶'@Ÿ;;;™›2¡ˆÜÌ£ÞÞ^Øb Æ ˆ™yg‰WlázjjŠ×‘ƒ3}UAÛ·oßæ©xÝIÑv—Û %ëihˆƒ€‰JKÜævÈÀ´CvÝ˸ý¿:ºLýBV‹ƒ©ðÉ\T‰H•Uéña€t™ô]3¥± -k+xþØW¯2]Í:D´y¬j"áV?GÝ}eeeß7ɺܶr( èØ‹¼ ¸wÜ0!ŸîI™L˩ڇ…Ì<\“ʰån–Û3_·ì¹¶ýCqºE°ÜZ™ά°"» ¬8®ƒ¢ñc]në1LzzzÊEüL£¤˜gó -2ÇÑ„k}}½££ãÙ³gòhgykdd„;ö®4ñ˜¼p‡ûrë‚8u_û%¡»HÂ솘™š)u‘:!µî!(¼â.ƒ9á&/2_ãB¹"ŒNQkª¨‚身«KjwÒ˜HS-Õ†ü?Êþ‰gd§Å’›™™!ZUšj@%•!פâ†È÷µ/B† ¦‰dÖ‚3­, v2¦ª‚ƒêM@rbz•ª©Ð«-ô3_l‰‚êÜkqç‰Æ©¨\¦ÅkZ¨‡Ÿ´æa‚Tº¸i‹ùºã†á‘v”ÝB¦y×nŒ…Ìz¸&ô®~ÊTTè-ËžíˆgÆéÁrka.\¸õ¼X‘¹› ñð³l;.iËuR‰Ì/ÑJ&÷Üi”«å )ì«3§¾|ù2?å6Jf44W⢉j_¾(¨DóL¯8---ãããšLí™3g¡; RäJ&¬å—‰„乌wI×µkÍu__ßââ¢Üg‘´fÇÛÛÛr2¯©©%“Ë ÝTq¸à-â!°üUH2ä¬^yj“‚IVæ¦Lv»“,½"#-éÀÀ5™¤8篘íôÞé=òO·cn(@Ö| ¬ôT.tJ›Ÿª^Ù?/±·Ô.ä )«ƒ¦¸@ÃÑ"æj¥ÊØW†.]ª¨!ì[I–¡“ ׸z¥! ñºÃú±ç ÷ŸÜ•¯:ë,d¬C)²<•Úóäjk)©:fHlM–Ì-’62`ÅIrùÚse‘ÎX$·ŸÖ›¯îA^=y³ðÐLlügNoˆÄèÍ\? æ¢C3; Tå-\^#Åßî)ìër*|¦ï kBû) wsâ¶£[pK%ÄÐéÀ}–ޤ$ši*Nj^Î-Ò ¿Ê-‹ªqç"Aˆæ¤¬ †u × ¡gh"^åNËÚ6/£ú´{þ Qlnnâ¡'-//K+ܹs'¬ògjØ“%dVùß–x*?b°|ÂgÜ_ @íókÖøÉOf麻»!ž òàjýHqŸ¤õèìÙ³šzÔÔÔ¤xdòsaa0:*©ó ïr!ïâZÐæŽ˜©hEÈ]÷㑭˵”ÕƒH&´ôÝÚÚªƒ ä„ü„V–2 ®Åvk# È,Ö±³æ².Kn¥íOœôê*tz¾&ÌÝ”:s,'ðù .Õ›#Ðh††<*…Lê–§î¢|­´šíФé@M"š­j…9°ˆÖØS”¡µ’,…úÎ¥¾ïÊpº¯•j7´­c|Zdveè´ãÕÎÕÿÒš6´~.9›ÿ|~rÉœ öïuŠ€ûRÖWÈôžËKÕ¤œ-šç;å!TuåS²Ï‘=@Òæ3$C“+ÜJjJŒäÄ]r n243/Ôr°­ÔUâiJz÷î]Ý—³j-W(b£·4Ž@%—òÔ+¢ehwó¨°ï ”Z”¡C+sY?ü¬«°ù/EY²†ëç¾™î<3ºšÛbWM R“iêÒ‘e•Û ’.}Ñ?SÏâ Ež¿Yl ¹»€¡vÍaDB¡įÍr#ÁpƒåºFè]XþÏÏÏçòŸá¾ý5³DY_ÉUðˆzËuOrõ Mžª¶VCˆfèäh¼ç;vý1t(ÛðSæ\ŽÒ œ‹",zó(d ;ãØ¦˜gx‰LRåѱ1+²~–E=%Š¡•‰C‡•®8V9T¤Å&ѶŒƒrÍy†ðHýMŠ 5#ÉÑ |51éQf-…–ë -Bt…$™¡M(Ô™«ôÞù+eÛ&ë¦ìÇCgNè]­áÌ/(tTɽÖIQ„âtY)°7¸"Å P¡Ü$ÒÁ’˜T•¡CbR¨¥$¹…Vg-æTฯ,ËŠû0tzOý*v•¶x!ÃÝeŒ0 Z‚…‚IñáÇ®–d]î¸ë& ¬yž"Xþ3õh;6Ifh!ä~WrV¤­7íâiâbçV€H¥¥¥E»nœ ¬åÃПD Û|­J55ì“Zœ©à4£~"Cjê`{ˆ!†V†‰|ttô\€t 暃5­êE2/)üçiww·bv?ü+¤¨-ÑT Ub+dÑ œA'©@*ÓÒiƒ€J(¯­zÕÈȈ÷y\+xüøqGGÇ… ®¶¼¼|íÚµÌó±#ÉFËgffßÌÌr4Fà<}“$Ç]^¡¸råÊÔÔcþîî.«««\ÈPšmÊô¦/,,Àj²:"µ\¾” éÞ†bÖ} ÙÍÍÍMb »977×ÚÚªÀ²¤­8¥Æ466F+À²$GoŸœœ/fZ}ׯ9ò.‘ŒÉ(˜Y clg„çEe•ëíímžò¥óá/--õõõ…tc3}oÈÖ—rYþPôcˆ„îHÕSªŒ²5 â®Gc‚1¨···§§gzzši{­›¡ˆÉdh†2™*ôE¦A²ð¬vÕ¹uÆ„šª!>8,$Tèpl*°w­ó,©ZÉÚè° âìÉ“'Ýy$‚5Dèšob6SrvO(ÎÍ~^}õUZŸÑë7<…nuöõå—_Ö Øèð)‡‰ ìr?Y¢˜:[dçJruêÔ©T`R/ W~(Ÿ@âiæ2¼%[Þ¤”GýA_šlÒ1|wvvzn.™Æc‡@†ÆÙüÁøk‡s¡veèT`3 ŠF ÔEDH$·›ö­Ï®®.ªÉÕ ÉM*“›&ªÂ8ð ¤#!\¾|‰QV¡g~JÐÏtä#ßB—.]Ò€Äñ©mûöíÛr#íÞײ¹È«W¯6ˆ‡êàôéÓqg! &a%ÊZb‘ZoV˜dY‹€oçÛá6ˆGB'Â¥|fèi’2jo^´ÇŒ–› c‚ËÃã±cÇÜE`nò:Ò'7aJ3ZLõÊHb(N8•Œi’$#K„Ah„Œ]ë:/Ê}ò¯U К|ð.¾^WÑtSkão¼ñ†ûŠ´‡‡Gòü”N§ëCŠª©mÿX‡ˆåžÇÂäϸD¡µ›L¹äCf†···¥¿]–8síj'ž¡=<<êsss"á®o#«MLLôôôÈ î¹sç:;;ûúúÆÇÇ[ZZtG.¥Ì|ùòenÊ^*8•¤seÆ3´G‰(Û*·‡‡‡GqXXXЉäÌãååå¬;5ªÙ¾>xð TÊäã‚6˜¡Ûþþþ‹nÞ¼ùàÁƒëׯ߻wOae >þ¼,ÛËÏÒ¹jnnVVu8¸Ñ\ƒ ©q´©†L=3sÒÍÇÓd±hØèˆWuZÜËÐñƒ-â8GM£&ŠÆˆãÚøÀÀÀÙ³g¯€†]kuuu½1wÃAooïË{h Oªÿ…¬yò¤Ì›?~\–R{VÕ`/MXWWWa;ÂSuSSSˆ×ÓÓÓHÆîú²Êè¤Å#i ˜ò<-âæÍ“I²s“„¼*[®»»»ŸþgŽ}IÀ©S§šÍp#ÄÀøKí WzMæKŽY ƒ½à33Ç šOê{òiù7¡_üd*~Ô!×È…?ÒðÎÎŽ¶*DmZ Ãe­^-;ÛÊ6šN6»ysÓÒB°nmmU„ׯ_w• ©dZóöíÛWðihª!WWzú'$“TÆÚ8qÒoseõ ÖWYø¸HTsˆâ¶ÉÃ(˪ˆGbZûZ[[ã'CÜÃUû[÷hHD¯èºjVôIwaðÖ­[ÖK‘ÏÞr Ó%fLÞßm-Zþ å)A¡‘º´š­%G³)—w¶Ðky9Ú£CÙQ®UnÄG ˜hR m Ë¿d*` kV]Èu#p½.JO.w-¼ü<š/Hy“t¨TÀÙz´²²}Êï²Å¬eg O0Â7‹ÄV¡åìÒÍ­{­æ#ZíYh’‘Þs,mùWºn&?j‰·ÈO¨,¢y¼èVØß?´GÀZ½žM§/»oÚü‘ËE27kk«h"˜èašáÆÝ#wQbê¥ì¹jâ(RḬ̀`ß h8.ˆÒˆVNµÅé`ø…è¦þ›çcýGþcêÀ#­¤ð¬YŠÈOD‰2·Ÿói£2îC“Š ýПµ‹,¯ÉüÌÅÐÚ!†«B~‘y…xÔ7\†¦¡•1»[ÈéNËÃÌL~—Ý.aÄÉ»‡ÒÈf4]"wéYZ²JzÏK4â¸þ+oòW­=éçi›ˆ¤···CeÑf9ôÌ»E“´g膀 |ôãRÔÊ‹L2«†Ž½hù0´•§KL½D­¨²jÑúPBS¥ñiHjtZlÄP«kchj϶Z…-¢'û–%“§#—]'jÑ>´ýT®”sþKÓÊ eÈ%TzÑÂkIÜ}Qºà•Pœ¡;¡xÔLîMKݽ~ÀMË}%ô(”1«bSNì]F îû0^S¬QðìÙ38c}}=9FÈý8Bž«]ÔDÑ4ÇÕÊ‹ªí|Sʵ‰Ì¯@Ðî·¶¶º"TݹsÇ Ì¤ã°Òi’¼U‰²ŒŒŒ0ÄW§2!ÙÔªK…Õm*Ø]V®¸hnnÖ®ù¡=„âqá'úà–»ŸªáЬñ¸7-u÷ú¹nZî+¡G¡ŒYµ›rbï^¸pAÆæö-`>ð ]ÿ˜ššbn›z6ˆ'Nf5T4¸„Ñ\N÷òAì Ìä…088¸ººÊèy``€‰¬Ö®¥ª £ÏÍÍ…´^{í5 E)d(BC‰Þ-…šh#)0wwwÓÛ©ÀØóÉŒ!ÂXzEÁ<ïÕW_-£‘¢²yŸôH&ähi)öÏ&òcw.·h¥;zð>yôèÑDy§e¿õÖ[È÷¥Xœ´-š ŠüòË/çz±ï“ÑmTOÞ'=R{Þ'½ ]ÿp—•‹äsX}-ù=¤Œ(ã9숨rÍWŠFCµ‘‡àºþá?lxQ–õÞ2âÌ™32ÁŒ[ŠÝ××aŸ9QË¡=KKK ÷1O3 Þ•«–ˆGêäÞbIý£þvy=j É1¾a@ö]^^.eT=räH´ÃŒ²ËÐUƒFŒ{÷î1Éa5fùe)Né›)¹ ýêŠVKD ðȵåRFxºÑÕÕe“ß©ö³££#îÜy4"(P’%;Ð\(÷-Q ÌE`$À©S§>¬kSœü¢2§_ܑڼ.ì~?²¸ÍЏxÀîX`{W‘s!½þ»ºïºp3I{=3Ÿ™QÙE¨\nº¹ŒÊ…î"QI‹4EW–“s‰Âüü|®æN¦ ²@Æ7d¢¡úˆ¶Ÿ•˦Gì@˜.HªÓÁß|bŽŽ§ìgÄË~ÚLk¥ƒ³¹ä¹¥¥EÆÔ¸3::ªŸ®-ÐÝÝ-S! ©ë••i¼s“ÉÍÚÚïòèСCŠYæÃR{¾x…ð:R%‹]J…ÿ²1"ðºzNiˆ…"€ŒHÇ5 ¦’û”‘WdSEa¤3¯Ÿê´”Hw§re'ž­­)1¹äúÉ…Ì•dÁ[,©gd= I¯Ê<}ïQ7ÈßbI%ÍÐîÀš4äy.\Üœç$â©3†NïÙóJ#Œl£¦%ÛÛÛ°f:`5è ÒM†·DêVj:ƒNêP"ì%«a¼{n"TÙ‰S¢¢ÕUQšæ#-3&£O@œmáe¾Ô^”4’xòä‰3ÈA!–çT»›ÐÑÈ\îI %<×ÞÞ®„gÏžõôôp_v¹ ;;;ºóëׯ­¯¯SÉ r>ÑÚÚÚÕÕ¥…b‘boo/ÿ]Ùƒƒƒƒ²¬iÙƒ¶çææœ ZVáiAwÕÂFF?yòäòò²õÌS§N…l ­,€ºÎ,D6 2—÷ †¶Ê!!-°Ÿ>}:UÔ±ÏÐõ‰PWN½§Œçè=< Bò‹„¯FbŸ`â27 uÔ2rR8sæŒÚôÎ;î‰p™.‘©êþþ~xZ‚ÌäŠñÞ½{Ìrà-ñ"1Ü¿ú”ôÌ‹p<äÇ» VZN;úH½© ° a¤ÈæîdsóÆ0}[[ÑòSi\¸Ÿ×ÏŸ?ÏÌ@Æja¦ñ;ÍØ&&&ŒÈáuDR´yF&HK€Ê¡€¥Ô³gèºEHŒö´G¼H²¥|/òEXÓhnn†ät}ðàAÛÅÐÅìì,$ K}îsŸ³`ˆ¤°|Æ»Cw +ɦrÆœ äñ.:ö§ÊR&L<==ÍÌ* ˜p'ÄÜ–=ØñzFæ>9l @œÈÐÄÏëLÈÉÌÌ ¯»¶\tŠ”BËÝ$ÔÎ}+µ]Ðo¦ÊUp$~"$Ÿ®•FÉ3¦.x ñS@æ"äŸxˆ­Èf(ï^ˆG¢`Úï@7’¼cƪ\VÆ\$ºÀFpR:Xu@.W´ÒÿrU½~ºþab4SE/@{Ä $›¸³P% 8Æ…x€8»´´„0:00U¦èhÛÛÛ³ºv­{x»Üu­®ä3©÷ð(v¹ É·_ôööîëΫ»ÜÑðv¹ë ²ËímŠÕ9¤Iáᑬ¯¯gU–®34¬ íQvøUn*abb"î,T2 w.*…™°Ò‘Õ*Y\(KfT?åêž¡=<<ª„›7o&g8®êûLãÇ#\jæÂÐÐPVã mmmÄVF{ÚÄ900Pt+%3P2ÅT$©à4ZYvâ=C{xxTup ©1 866Vô»ÐU¦þ\¸³³“N§Ë²¯ìéP{,º---ŽÎІghê¡”>ù¨›E‚™™ùÚÑ„£¿¿ddÄ|,RLDUm·ë´…”«JžºŽCå’H4¥Î&g‘üçÑÉ“'y±··—Úã§b#"çšä077GBºI0î~jj*”= ²„á©âÔj³âáõЊ¸iv<à§¢%%MmXx²!CiDË#“µJlâx†öð¨0Ê8p áÚ¼ Üݦ•/# §L к`¨5‡K•K½>6ÚeM“Jƒ«`P~:tq~~žÿ süøqž¦«[Ȭ7nÜÐÏÍÍM&aÝÝÝ®É-9gDh¾wïÞùóçá¿ÕÕÕññq™Ô&†Ã‡}Î#$á  ´¸&ª¾¾>h˜;„$KDuúôéË—/“ÏÝÝ]7{:P@œt3îð_ʉŠ1Wùx—¸iv:é!HáܤŸ"t>==mvÇR¹¦&d•›«FGGó}†éX”Åò±úéb~~>W/€ôféípó•+Wä©Äœóáôöö*Î7n¸n óÏUkkkApÞê§G4¼ÕÏz­833377'·k£££Ñ¤«˜Áhaa¡¿¿Ÿ‰ãQÅj<ªùø y¡O, ehéúB‡È»+++å:öJl||G|Ìqå0ðÝÕ±18Q†ÕªC }r{ÎPUô*/Ê;½œ­z•E£ Un¡ UYcMæ”Ñ!ÿñÿñîÝ»ÓÓÓüÇüñׯ__\\¤Ÿÿà?ˆ~qmmM¬gçÿ-ÒÙÙ ¿vww¿øâ‹îÓ·ß~;zZ {ü—f®`:nwý•?V¹Üv‘Åì\?S{^]¼ñÆÔ¡ü0fåNîó–Å“’;n°†º wè-fØUö_35øB4Ý`öÈò@ëCÌÜloo×vF(€EгlâMÜÛáûàêÕ«°r,:\$züøñóçÏÇ]yáîÝ»ôþÇ’zšb†\Ê_RöÞW5ìOÿôO¯:øó?ÿóL¥0&n˜?øƒ?øÞ÷¾­™YÎz°•Kx“¬)¦ãæ4(ÿÇÇÇÓPF!æîJ"ô“9‡%µgì“zêÖ¤ôòˆ‡ÿL§ÒA:tèwˆprrRoéÈ;mÑÒÒ¢\s‡§-t^™ÿ\+ B‹Ü=æÎ˜&ã$ü'o£££äJyãZ&E‰‡)£Î (2,ª*ÒŽ Q]må“Jl¯)–the{gg‡‹?5un.:::üŠwò±¼¼|íÚ5yª- ©d®Öh‹Wg”#ÞE€võ¿^zé¥ÿûÿ/2t(sMîÛÏþð‡ÿ÷+Ym{gšóäsƒ£zeG(¼rå M€D¸ººªc™´Tè'ÒçÒÒ™)C.^¼¨wA¢¿¿ÿÌ™3 nÛÛÛtZ½7sg~~~dd¶Ó[©ÀÐfss3)¶µµYWáE˜©QKÙ††‰§DE®®ƒ¬uÊÌQ!“–¶m›åCeÞ-?™g]†!ÛLȧ­C”ÏÐ ­ÛÚÚJKz4³ì ÌéÍu¹ ç‘˜—@Ã… RÁÐ==ýÎw¾ãþŒ8cýRû™'"¥.–rïËbÜuV @½¶ Œà1‡~RI÷Š0®§ ma({]â,t»»»ë®Ê˜§¬W_}UZ8úŸËà¶YñÔ.‰Ýg2¡ƒ0• Y3ÍGÑ'«Ðb«ß—/_¹)ž¡“yH/¼Q%À<”9)Ø“´G. X”²¦ÇDÐL¥AÆ@¡¼-¸Dû /dJÏ.Ü éµg…,—¥>¨633ƒ€Uâfy ŠU:Ï© BpæOhibb"B†Î dÖÑÑQj’ ˆV.4 Œ9ŸýìgmSÂSür"™5B^‘|ÿþ}"$Z¹†t5¼ˆ¹y3€9£$fþgUt ™tÙÀ·q 4¬®®&ŸžSv÷ÎÎN‰…õC‰GVHÑ6BT-»¡MFÃwÞy'"€öÅ£‘yx”ž¡“ÙŒ;ùbee¥B–G=rŒ½ÄͦÅáßøFÄS)úÖâYóÊ!dœ++Ì ˜Gqð dõw›X;!d5=[BqçÎT䱿T`Ô³ìéFkÞJ op²rkàáÇ/¿ürô+“*‘™­­­ƒ¬uÏЉÀùóçÝ#óò«ÓÜÜ|ðàA­ ŸÛÕÕÅhvìØ1y­ôhXvggz†Ú C$d€G” q™Gî5£"#$™d>Aüt{2)'÷Œ¢¯¼ò i¹IÔ( Ùà•1[.ø©x |uÞz‰G\@Vþüç?/MlëSŽ=ÊýýèGìë_ÿº]å+_‰;×å³çr-êŠá ¿ééi‰¿2N.h-!¹œÀ€ÀÓLEW(‡ÈåÒ=Y*»¡©`|# …yýõ×ÝGîµ^”-n%¥YÞ\$vÙ#Z®ð 'è÷¡3K™ 2›{ ÃèkkktP-1©kÚÂ&Ü)÷g"]XœY¤B"ký¢å“Ó‹vÍœ€¯"3róðÚk¯‰Îùâc ãáQ} K&þÔ§>õ[¿õ[2ü ¯üîïþîG?úQ…áóÑ¢÷/ÿò/»? o¥>hÙ;QÐHR.’f¾N„Œ £££\¸ëdHäÒÖÖæ®¥…À(„D‘É—kkëxä¾Î5÷âˆÒ…œ,ŒûˆkÒÕµ^dàB¢ $Æ+-4ºØÙÙáõZ$iFæ÷Íã”è¡ÅÃ@G)¨è÷LsEb^Çßzë--!¤¯òæó\!L׿Þ’8ºú}:p½žÚ›˜£·T`ð=WäòynÙÎêÍz<º\Þæ= ê<µ^±êH¹º™±øj…þùç¯æ†6­_xáh[Ý9ÛžÂFùdLß‹}b ÄåË—ÇÇÇË›5]Pv²žPmØ… …|À½°G™pïCÒ¹Y̦©ã°ûvŠª&@æu¹ð2tlÈêø1W|ÜÑÑÑÛÛËT1×2«ÚÚÚâ]†Ýq—’ÉôVN¨øÉäQ^\¸£ñEoŒqMj“\“ Í‘3#Ì/Ár1q…N=z4Œ¡ó /©ÑÄåL¼óÎ;o¿ý6Ÿüä'!r}÷wW„pðy–ñ3´/ÝÝq³!ë¹ZQ°  y8€{a2áÞ­&º,fWÐØ}»ˆ>¹—L08kÔõž3âý)«;Réˆ ʃ©{_[/Z8‚ȶ›››™$J§ãäÉ“©@ŠB&æ›áÎÁƒé¦ð®Äbi|ˆ†µÛDr¶F9wVVV˜›+3º‘Œd2±&Vjâh'µ‚ü—%éÆôw¾ó7뉩¿ù›¿± ¾÷Þ{/ì^ó›ß yKŒFÂW¹SÁr*P&u•O=jP€LBy†Ž/^Ì5‘dÄ_!Q¾4è“ ä×ÖÖ¦ð4ä qöõõÍÍÍmooKü…Gå{9˜1šH í©©)ƒëeo||Ö[Ò3çY#'iMLŸ3`úk×®Å]µ‹}}/Öèrô"zržö(>ñ‰Oüå_þ%Œûgög§OŸÖ‚ö»ï¾û•¯|…ëW^y&VÈ­PäÏÐ’Ô“¯ÉÐqáÂ…µµµ¸3âQ<‡ø5Íò¾­ÊyçÍ3ð£GjÅ®5c“N[I-<"¤y%Ê5íÆØ£r`VzòäIÙˆæ:š„¡ß|óÍÌ0§N’ñ®ý×ý…^Ð}ík_K¶üZZZøå#æ" Œ»†öAGGÇåË—ëÁÖ#Œ¢ÚAø}è±››@hgKKâÑ!m?ÛãhÐÍèH[[[ù«%K‹›.j«ÜÏ?ÿ<ôü+¿ò+ZâæçK/½txœÿ’{BÀ”bqq±½½]Fû=’ ùæJ«•™‹4ž¡«ŠFXÎG§ÌÃ#LdéH ^YÕŠs}¬ªã7šq†ÖkÇßÞÞ^ZZjnnε áè]½½½LCgd 㺪¨­…²¢Q*¯I†9•ɺ$“³ÈBÑÖÖ–ysttž« ±¬}…k׮ɘvxM®iHñnîéé¹rå ¢s„Hãu¹«Š¡.†³¿XB!ǬH~ýýý! ƒöÅ/~±Œié,VèæÖÖ–,LOOÇ]¥‚Òݺu nž››ëììÔº}Ü™jPPùÃÃòê¸o`ÏÐÕCVëµu ¹ßðz¤%BÆkåäÇ]‚P?ó™Ï|ùË_ÞW {_0J’D¦-6z¯$Ò­­ÃÑ…½ÀîÀù›@÷(²¾\Ä‹ž¡«‡ºùÎóŽ´Æ ÚƒÚ7¡àKwŒ{ñÅ+ª“xòäI­oçÚ ¬¸-<¿]=4Èw6!I§ÓufKöêÕ«’h«vpˆ9Áúú:‚•••¸+À£¡áºz8}útÜY¨jÁÀ£¢`ÎO#Ѷ··W𤙠œ={vnnî¹çž[ZZª%õŠ[åþáøo|cssS{'fáÿL±?ö±UBɳ\hMh¡¸M¬¸qãÆîîîÂÂB[[Ûììl…ÎD0žhÀx‚ôìû°G쨆–ÝŸ\¦þR{¦í_xá…sçÎÉ]¢Ð€_ûÑ£GåR×ãD@™·nÝ’û¸þþþ‡—WÀ…þ{{{!iÙµöÒ³GP«ÜËËËôGAφwÞyç _øl´w®?€ZYõe„¢ö &Z[[ù?44411QÄêbwwwÜ¥ñ¨+Ð-ew žnjj*—©,úvGGÇÙ³géüHçп§g„ é24D;55r½¾/˜CççÏŸO΢wþ¾âccÓèèèÜÜ\&K†§>ÜÙÙ™ç1>ÁÇ],z3]¾n„Ýõõõ$éÅÅÅ¢§¿²‡¬å7X™@mùó¨{$Z†~÷ÝwÇÆÆ ¥g·üŠ{·H²n3 rI´ üøñcƲææf-îmCiÆ%´ãêL—;GŽY 1Ó';j*KFèöti¸ùêÕ«Ož<ñôì‘4$—¡‘žgffr-V‡îÃå™!£c¨2<w²@2Ü\u5†¶}×½áò¸ËçQ·€žÅÓGEž¢¿µµµ1AÙêÒºI×=yò$#ÿ¹nii7ó–_ÙöH ’»Êý•¯|%SþÆ7¾qûöm¾¥øÃ?úÑ>ýéO¿ð Üÿüç?ÿ‹¿ø‹™r*Ì Iæ3Ÿ‰»4IÔ3ÍբߟŸ°Wì-!xTZôN21bôµÑoAê}}}¾‹z$ eè·ß~;Ó tû¥/}é7ó7?ö±éŽäcimnnòó#ùHfTðúK/½w™‡ÞÞÞRN—Ê1ËöövÄ0Ç#o¦ß£ 8€ x™8µw¸Ã P3¡”.HÙ•À=<*‡„24sáÌ›ÿðÿÀÇfôü~î>FÚþµ_û5¦Ò_ûÚ×2íë*¶ßû½ßË3é¬4_"¨&622’µ’ ‚,=euÛ'x†ö¨2ÌètÝïÇ{4âaè¿þë¿þ—ù—ˆY‡õ§OŸfÞD°ÞÙÙ‘G÷o~ó›YZaZZZòÉÛØØØ'”§“ª—b–%*¤ð™™™óçÏg}ÚÔÔwY=<<þñ£¬ o`©ó¿Ö]ðHxÛªcKÙÔ-cllÌ)Ammmyy9Ê—ËÂ#i!üßû½ßûЇ>TZZj.oûÛQå?øƒ?°H‘™O~ò“iúsŸûÜ‘âʯNø»£ÉÉÉÁÁÁ,üK}---á~~¾ªª …¦lwwwQ\9k—¹Å£££þ-íD(4z„ !DÞ8\xk†ð÷£ýh}}½ÙL(ŸS\ŒÚ¿ü˿̎©ø yýë_ÿ¾÷½Ï½*æàÝï~·ë Í™f-ý¯ÇQ…ö4ìéÓ•íèèÈÑ3Ö3öýðððÍ›7)::X¨/YFà{{{ïÝ»g¬Ë—/ߺu‹žÙÊÊ BέG¡Ÿ~úi)óºbRh!„È/‡HÂ<>>žºGz¸C—N)9Hr–yÅH—߾ϧӘìYÆ«¿óï;GnM`Äôš…-ÛÙÙi§îß¿ï_> ww#Ϧ¦¦çž{îH·Æ6 °ÎV2™¼rå º‹H¯­­]¼xqcccgggÝ Æ‘žVZOOš!Ž£}ô̱ÛÅD!D^8D¡ivSå9:loo¿îu¯sö4†] žŸŸÅ+^qÌbzüq""„,~ì»Ìc€Ðº†í;c,ZÉðà›qÍ©K—.e $—Ï@ÓÒÕÕ577GÑ‘~džÎQc=Óà–1…ŒI½¹¹iÚO?»ùüùóÓÓÓþu!Ðï¢Ú¼K!N›Cúõ¯ý³Ï>ûñ<ìt¦gttÔ†g9þÆ7¾f¼ûÝïþÔ§>•vφw¼ã¹,PøHmÎqˆ%ûä'?y¤ô#o /¿q.XÎzd9kØÍΑbçwkkK+o !Äéqø‹Õ_ø…_¨¬¬¤QvËgb§¢vvŒœ|ô£uvök^óšW¿úÕîZTóä‹n¢|n¹EÄñ׿þu7_,ð‚™»´ùÇ]j@ç®ÍÇË5ua–è€=éì¬dÿn’>]ÿ„pºG²¡ÃÅælj¾˜±!'íA’»»»Qbk‘ÿ÷ß/Zœú§ú§„÷8ÐF£ˆ´ûó¡s@ÈÄø›¿ù›6Ÿœècû˜}=õ‘|„`Ÿ|òɧžz*áõ >ñ‰O`X#ÿýßÿÍ©÷½ï}.¹Êék³A¾&&&ì5ó©FtDzgg#5ðE g÷×ìÚ£šã¦»\»µµ555uñâŇb='¼÷Д-v³³˜ïÞ½[RRBŸ Kzoo¯¥¥¥ð!„(¢øï[ßúV”ÕÿÛäáWõWQè}èCH‘<ÿØÇ>† ýôÓOûC¨¬¬´Ï¸ðƒüáþaÂ÷r:ü+„¤‘N»¦iÂëdúÔ˜«óÚók×®uˆâüùóØñˆ}jÏ ˜´¹Ùæ Ï”²ý4­oį^B !D~‰¢BÛk`ÿ 'oûÛÝ0µ]#ÒXÉýýýþÕKð†#¿ o`ÜB[˜!îd2™iÍ1‹Q[xüIåhhhX[[³ùhuUUÕÎÎŽíVQQáNÙ×Vî›+ìf2eKyc‚§¥Ïô–šnöBˆ,DW¡ayyù„{£"Ùg¥å‘, ð„°0ÉÈ bdØt—„•””œ$4ŒéL£ÜYB–B !Dv ;Ù Ý?ÉÌêBÊó¡¤Ýñ:,°éçææìø„2ÙÞÞžIž£ù‘·Bœ"­Ð ïÛ§w¼ãÇø:ùÙgŸŽ<'¼©Xa'áe «ö¥ÖñVó’–µµµ°s)„g˜¨+tÂûøª··©ÎQ§kkkßûÞ÷†ûyU*/¼ðBØI‚ù›E_y¾ÿ~šÈ-„'!¢s¹ƒ©ô–-û•_ù•Ï}îsŸúÔ§ÜfÕ~~â'~â©§žB˜Ãý°*a'! ¶4JîûIû/‰njjª¨¨8jÊ Ds¹…â$H¡ Fj”Úa;hpmMäBˆrærdž¢z/[T™BˆÓ@ ]8ü{ÄžÉÉɰ“ „grŽíí툿ŠÎcN#µ†Z‘` ð~ƒs!Ä)!….(³³³™¶ŠE5Z=ÂN…"oh”» ÉÛÙ"ɦBœ*R育¸¸ûoÈà w$B‘BžÑÑѰ“pº ϱï…!DBš‘‘‘°“pºÜºu+ì$!DBšu°SqZloo績·È; ÉdRÓô„ˆ R舱ã¬E´y``@ -DlB‡Àèèh\ßÔjˆ[!ò…:çXΛžžŽkÏC! :ÃNBþéêê ; B¤Ðá°½½½¸¸v*òÉòò²VúBˆ<"…÷¼ç=a'!ŸÜ¸q#ì$!D¬B‡FglVÇœÕGV¡“L&ø ;!Bˆü …“®®®xL­êìì ; B7¤Ða²½½ƒ)cmz-„yG»O†Ì­[·°¤ËËËÃNÈ1Ùßß×7ÐB8VVVÂN‚ŸêêêsçÎ<)tÈ p×®][ZZ ;!Ǥ­­-õBÛÆmxxxgg‡ã¼´È"NØSQVVÖÝÝÝÜÜ|Œ'D >ËËËãããׯ_;!G†dk£IQl8a^[[kooŸ˜˜¸páB؉Ñe}}}dd¤«« Ãú¨R­÷Б€›wæ^å’`-Q)’ÉdII‰ærŸ*o]]Ýââ"¼µµ544$yÙá á9áiá™áÉ©¨¨È½’J¡#½òúúú°Sq4®]»¦ñmQ<`7WUUÕÖÖ®¬¬H˜Å1pRÍ1ÏR._Ûj”;oÐ3ª©©9öå¨]GG¬°ó‘'Éï;wzzzJKKÃΊ‡@ÝD˜ÛÛÛ×ÖÖô²Yœ!lè¾¾¾ÁÁA~éðey¨¤Ðyã¦Ç±/·V`rr’† 쬉\XX@¡ÕZ‰Ø³¾¾NÅ‹~ÅgÓéêêjL»»wïÖÕÕ¥õ¦Qî¨À [\\ìêê¢E;-Ù y$r~~^ò,bÏøø¸ kKžÅiÀsµ¼¼ÜÐÐÀ“–Öƒ:B”——Ó™¢Eˆ¬Hcè755iòª(h:‘g=íâôàéÚØØèëëK»p²F¹£E]]ÝØØ˜uÛ£Ö.Ø8|2™lnn;-" îWœííí+W®¬­­ÝÕ„ÄYglqq‘Æ‘4û%a'O™œœìì쌔H;yÖpŸˆ=ö´OMMez;(DÞ¡Ù§ L“ EL£cIcOÔ××KžE‘ÐÖÖÆ£.y…Ä> Ùç×9ê=tDán!Ï¡/ÚEª««ççç%Ï¢àßÜÜÔÂ/¢ððÔ¡Ðþï¤5Êiö÷÷ž|òɱ±±PÀ399™ý‹=!âDEEÅââbÆ®D²½½HÛª& ÙÐ]´M5.]ºTàeA‰ŽH1&´Jƒ(0_%Ï",ÊËËyÝŽlè³Áòòòµk×nÞ¼Ù××W½äù››Ó«¸3Ä‚G£GØi9“ìïï—••mllhþ¶žÃŠŠ ÌhšzÙÐg”’†‹6ÇÕ\ ]"":ÉóÙyà7서Uxøyæ%Ï"\æÚÚZ›¤¹ÜgnÛØØÈ7°¤óþ)ˆ…ÌLgQœ wwwg:‹eãŸdkTWWëÈ;<‡<­­­Rè3Ú¹´´äÔ´··÷xƒ;l³Û[·nq|ûömi³(Z¨###™Î"Ï/^ô»PïöööÂNµˆ!´ê Í;£˜NcF¯¬¬ÔÖÖÒ‘§Ãu¤µBñÌ%\Èå‹‹‹E€’gqÖÙÝÝ=Þ…T¥ÊÊÊ,CÜçÏŸ¯y„¹œd§!²@çïÂ… ´Ì²¡Ï0ܤÇöööääd__w´´´´Õ#í%/¼ðÂôôôÆÆFUU~ð¯·n"N ݹsç£AÔ‹ì_üSÝPñ„÷™CEE]]]™<ãÇ}0c ðüR=£Yãl Ÿþz㥠èTiò|*´ÏóóóRè8@ïöHxOü‚›MvïÞ=~/_¾l©333Ñl#„È ËËË—.]B¡¤ÓèDŽ»•ÓNx•.‹®PmÀ|uuo˜DÕÕÕH Ín4×B±1üÂÚC)QVÖõ~~´tɈ5ýa§BˆÁÓîoæš››±es¹°¦¦æáǹø4aÆXÏÅ3>]°DqÂʸ··GŽN£ÜH$IÍc€íííYÎÒ!<ðîÅr9ÊÓ+ÕC³Ÿî%£÷ÐBˆØ2;;[QQÑÖÖ–¯Ö=Ï?ÆåØ÷¤g?á™ÚUUUäqŒËùóçKJJ®\¹ÒÐЀŸ®®.ÛσáŽÑiCœ]XX 6l†‹Ùè„ÐÑÑÁ/×âÏHÎåþèð}ßÒÒbñÉU¸ŒŽŽÚ_›é‚ói‘öôôp`Y vN,g;;;‰…¨'''qÁ”“ÿ¦º𷯯 o€Ý¢Lþ|ù‰gÿ­äï­[·oþK(N‘ 3>>Ž#§l©Žq´w\k³pl*•j vPnkH» Äk%H­­‘ŒJ4“GþÚíæ/WQnìg᥇$Ì®‹8}dC‹¢"`CûimmíÏ̹sçr±¶í]R]]ßqgg'“ÿÄËmèÆÆF,6¬ðû÷ïÛ“¦ß"'œÂg'&&Ö<‡ o޼ɵHŒæ‚7‚Å?îö滼¼Üf˜sjff†É—àN,ÄU__ïâ²% ¹ÐÙÐxã¯m»içææðîÝ»V¶œ5[ñx­I`Œ’~ _[vƒx Ð/\eþ¹Ðb´÷tæŸÀÉ‘?x³Œ÷öör`;66F°¢°¨ ‡H­L¸– ¬$9Kø\^YYi©ÚØØp¥ˆÝ‚"³dGK KKK‰”qþ‰ÿVìxÆ_Ëš={Vžx¾éqè˜MBßC !Š|}µl/¡Ñ ç‚ý´¸¸hâwèå—/_>ç1??oëÙä,,-w9€Æ/²¥Ž‘j‘rí»-gÁå ¯£`—ØÇ9X{(ÆõXx˜z–÷‘‘ÌÇÝÝ]Â¥›U3LxÖ-ª­I‡#—ó·©©)áí;NÈæÙ\И7n ÌÁÁÁAÜI%ƒÝÂ%¼7© ¯£@!ix³H-æŸÜ•{_Ž-ä´³,ãdÁ> MxÃV’©—àÕ«W‘p(›È/Vµ^â"ƒæÇç¬ Êfö%ÉÁ_îÖ<ù2ÃÚEMarËì/aò×RHÑqwðl™}ðàÍÊe^žZhyÑ ×|;h"‘C—Ë¥õD¥²O¢DD EôÇ˯YrGâúõë4âHa¢ñΤ"Ø|&±üÅÔ³Ѳ²2‹ÎdÑ¥õçZËãÀÀ> ³§§ÎöÝ!aæ¡BÞP¿˜¡ôÜ 7C à õ%تªª„'<ä7õ36fk¼¸‚%FÊß…O°œÂ‘4 idÇ©±-;²ƒ y'n`ÙYvÑÙõ'\Qd¹¿$xffÆ{½²²Bª¬÷c¼ì±'¼amʇôÓ!óO–‰šÐèâØÊt–;7÷Âç!Jƒ"]]]µìsaÚezmëa½‡BÄÚMA¿!‹ØÐ&Ò &“ɼØÐ•••6¬ê -´(Ž𙹍 m½µ×ÆÞÞA;Ýd ãËØ–'ÂàæÂÀ…ΞÆÂ`£Ç¤Ód’¿öRù¹çžC ¿õoèÖ ·ËÐÐAY ’f¯lm ?&BÎ2FéÑ-ô†„%<µ# fÙs9IòëÉ@¥H<Šå“Üõ÷÷ÛT|Ë—ƒ2AéÌÍÍ. EZl~‰´’ü“*·6‰¤ˆ°zÓÆîxñÅÉ¥dö1&8þ-j¢ ×Å_‚ò ¿•¸×PnĈãBÈòÍÞKY¸/Äi£÷Ðѽ&,ÎÛmvŒ+ÚJ´ùH! íQ(:m¾ÿ¾½1å _!S öj9_غ v|ÚíL¦|î—VýBœy°®0‰lœ»äx«ãåø1ôicŸYc¿Zzò¸Ì¶Z–5MÊöö6‰L]¨\ä Œl:%Rh!ÄÙ¦¯¯ÚFž÷TÂ{Sh…›—¡Ï1ÇÄ ¨7oÞô¿>?!è‡M–¶¿§½á)áÛ:nÅ ±±1ís¬’G¡Ý§ wy`` ¿¿¿¨n·mêx7|<Ο?¯Í¡E°§zooO3Å„g˜ÑÑQ¬Ã¼LÃÄÔîÚ" ÌÎÎÚ )´â 3==]__Ÿ— º»»S?Ö¢ð¸­Êõ:†ø—¡·/ý.…ß¾F{xÚo£ÆÚÚZ¾¦SŽ­¦©mXEˆØGÕ6i@ï¡cH[[›û’2€m,v…ÈûûûçÏŸÏc#FÅÁŒV!réÒ¥gžyÆf“H¡cˆÛ¿6•ã}ˆ"D4Áä¥?šß½ ©;sssª&"°ž¯]»æ6×{èbKѦº×y„:!ò&oÚGý$ŒÝ¸q#윉"…§ÿ³u)tlnn.íªéRè8cf4h©a!Ž"½¶¶ÖÔÔ¤wÒâ4H&“YÉÑšb1§¦¦&ì$qZ`ÝVWWŸj6ÜÝÐÐ0<<|ûöm½-yG·­­mgggcc#˪ò²¡…g•ýýý¼ì™‘¢XZZêïï¿ví­ª­¤+Äñà¡å)ª¯¯ïíí][[ËþK¡…âpš››·¶¶šššªªªzzzôrZ•••žœŠŠŠššLç\ÛѪŸ1GûC‹SRB † ´¼¼<<99I®éM&Rú‘å ¯ãÂÃl³s…""ä¤Ðhóàààðððõë×é¡K’ÏNŠ¡¡¡!Ó­¶¶¶„·nütz}}}bb‚<–• §þñÎÚúP(77§èµtwwk˜AWhì®®®ÆÆFŒ05[ñµîöàæ¢ÙÜ\ô,7×V»]^^v9moo§g™¥[éììÅÅÅiŠ¢··WcÅBˆpÉ6S Ó¹ººúÖ­[´\XZñhÁ…ŸÖÖÖ û¦þ¬ïÞc«ÝòÄ"ÏØÊýýýkkkt+‡††²úXåþýû{{{<ç” A TTTÌÎΆ-!Dñ’Q¡±Eªªª°?–––â7 *t¼0mÁسk5’r:˜¿È-*‹6ãrÔç–¢@ž¹]çÛº¥¥åÒ¥KZ9š¬®®ê›ˆ7éÚ¶«;»M¶8ˆÆôƒ:::ÂNËÑÀÞ%͘¼c7ç¸}vLæé›R ¨ ÈÀ™鯯FJ€ß°R ¢°¦˜§Jš÷г³³X!±ü"Ed rffµÃjDœÂNNN Ï&Ÿô0³?±4èöq`}}=žmÉÜ,FòL9Ø'LÕÕÕíííaç8a§B‘7‚ McGÝ y.NСÂNË!𬢵ÛÛÛHéýû÷³Ì“ÀgSS“³ƒKKKwwwíiÇ\&„L×¢ÐÈ3}VÊdaaall,ì| !Š…—rc‘Ð{!L̈OCn1‘çÖÖÖË—/#± Ûªù±cÄ•_ÿ0µ“g çÒ¥K---ö¹?aâ™ ùÛÕÕe«ñÐ[µÏ´ÆÇÇ -ì¬ !Š…—)4ÍS{{{sssØ©a‚¡LHQdg2[W’_„¹¿¿~~ž“ì‘‘œsŒ#«‡HN«ªªÐiÛñ—pÄ-oÒÓÓƒ»Õ B‹xßEþO¡§§§)»›­¼œL¡ÐÒJÒbßðð0Q¨‹8¨ÝÔÔTdíŶ¶6³‰ïß¿ŸðûÚµk6i¨±±Ñ½ YXX\È)lîÒÒÒ þS¶t §½™Æ'¦¹;‹H»W¼gbâ˜â¬ó ÝÕÕE£8}ñå¤ âÊ•+ÕÕÕ4‘çÏŸÏÞ¦c©ÐÒ hyÅèƒÉˆYiý¶Hˆò ч@DíÝ3öîÄÄD`æÄòò²MðvàùîÝ»öeÿØØØÌÌLêëg²ìfO8îtl²*žK´ÀÐ#¡pRû%Bˆ³ÊG?­ÕA æ§æ©̈¡É#k.×ÖÖ2`mèõë×rãáÇîxkk+KÈY°e+Žq¡cooÏŸ’Ó‹èT! däH—,--qOzÕ©Bbì1³1gžI\nÞ¼™ðæ|Qþ<‡æè¢ÇæN vlþí€;Åå*ÈÜÜœÛhºNDaFË{vzùUfE¼y©²V/­þùU<-Îì¦E3ΤRÖ|äÞâ[Ó‰H¸Ëý]éîîÎr¹yà—«Nød[c}¨·“GtªØ=:êUa¤2eß:ó›K~Ù³`Of Ïšžp'äa—GšŒDê~*tÂh%ÂNEB'/rÏÎÎbd™¿L&3vÒ‚›MsñâÅííí±±±´ŸiíïïߺuËÊÊÊì8;ïyÏ{JKKùM{Ö69Èr¹y(ÀJ¥”^¾ÞJR8}}}ùM^.ó¤²0444::šß$ÊٞÑ‘ÊÊÞ›ûÊÊŠ ;ó»îá¿Ð–aqŽæß]ÞÔÔä÷ì¦b¸‰øtþm—0{'ÝÕÕv‘5;;;4a§BˆSä%…ÆÜÌâi`` ­­­¥¥%õÔææ¦«$4[ׯ_Ÿœœ¬­­ x¦•·´²²Òt(û9eã¶è#»W’ä(á ûÖÌqff†®"j.G?î{X‚-mþ¬Qžˆ ƒx›››³[@Ö¸Ä^Û{‡±±1ü[:-.·QÖ»wïrÏæÓª´M»]\öÂ?v ‘Ú½p©Íþ‚Ÿ$ ìÁž-»g•¬Ùmå—;E"9uà½3¶;îžp{9b7èàÑh¡•9%cîÅ#]‰YÀ?ÑY ÛµÛcœËx{Á(¶QîD¯$bƒF¹‹“Ç1R›æú1Ó°½½Ý /š-ÿ ¶ 6r9R”bjÛÝyòÉ'mŽ1IzñÅwwwmV»Å¢KKKW=l‹Crg nr2ÉãòÄ£ÉPǤÙ,f±ùðÖƒ±·&ZdóÎÆ`És [’;»}È’í±Hòp±g S‰ÑýÂÐÌ>ÊRì =÷æ‚;û•äQ>ÎÜ7 Ø]h ß"'ÛóÌ…„–:B`-þ¿¸ÍGã˜ÛÊ1åÕÙOÆcÕS +‰Øó8bi§Z1 «W¯Þ»w/áYoEŒ«ªª^×L&Ýòi¡9¶½h¬A´¯VÄ ;Ò?óÖìK·44¢hã™ OÎi"ÝG2¶/“ 3!à³Ý#Ë7BmmmدdüÎ;˜D¨š-)å÷ÙÑÑažö—–½×ƒþÁo"’ Fj+°!„tYhЉѹ£%$•D’lÒÉ_Ú£vy´yHl(žI'Ö=! ‡ô_´Ùn yA¡Mq]P,A¹þƒ4àN,ïYî]Dö°gÀuH’½§¨¨¨  é|P\H¦õÝ8¿eß=œ§4S¾œÀeHÙr7ívp̽£»ÀÃOQÛ —ˆì°”ô;b||<âˤ qr£Í*++K{ÎäÁ,cDÂ}sâÀ’0±Ämüg£ÜX{5IlJ0XÉ1.™„öÑ«ǸÐÓžÒ\‘ߊ¥ÝDQ BÄEw_xá…Ô¹B: eKD!ih'±¥ü+Af4755™)€ãÀÄ"ópL<ð'p´Ð/ (¢%Ø¢ ‰'XJ†Iâ/·ƒ¼5fœû"™B(÷ ÍüRìÜíï|§+«@ðI¡ùß3’ǵ©y`Rtì‡ìäØü¯„·›…¹ØÒñfÎ&¼´3ïŸÓ-  mè‚Ê]¶cn îv‹#øÉx1@ £™z"þ`“eÿǾÎò‰ÔÃG8Ïîo*;;;©áç>(¸Ü>ã&.ôŒöÚyH%KŒÙ=šþì!N!ÏöâÜvz ”š`—¼@:Ý$÷ÚØ<Ø/½+“$/‡>$§õÉlC&N¾édÚÚ‘%Fû 0S±‹ÓƒŠOÇ7ìT:Ëz]„ˆ \ŽÑ‰Œƒ-eyÈþ F Æ#}°‘Ös–§hÍq™öHx¯äSì’H§¾v¯ß̃ýbO¸wÇN^ެ¬¬¸ ó…Á>|Ê>ªióòK¦á%Ã^Í䥮\¹R´¶øQ'|ÞºuËfA o³wÃa'ã˜`@£Ð4”ccc©K–FLáëׯcð¹å±Nm–Mq?¥4r@?ø[QQQ0¶ØýôOkiiá¶YNø½¬½ö&"·èìØ}€—¯¯Ñx*(L÷Y]±á§C? ²é~™Ö]"fnCGD®©©élUWš˜ü®LNöC™"d|uá¿Lå¦Û¬ub§Ç322244488hgy*°±¼a|¼¥µ·r™gäfõOLL,,,_;¶í¿0èlå%StwP©K—.çgÖoYYY–Ç y¦S¾¸¸¨9b¢H8ó -Â…Æt`` {ÃzrÌRÇÌr.Ñíêê"v7QÎ6‘Díè qÊÍÔs&u? vŸAg7µé¹ÑŽŸþy7r`Ãà‡Nµ;¶XÍ1tš¹ÕiÎ(™' ܶ£Lô‘•(¤ÐEGKKKÞò´†õôöÂrê˜ö,m÷ìì¬;Ë8.¶p2¼±±aKÁ¬­­aïrÜ××WYY955åöϰU_Ò†oË–ÙžWwww»ý¯®^½šð¾ÈÏ{–N‡;‹>üÓððpCCC½‡ÝǰS'Da {¶Z¡9Òäí3ã¡sã±ÃG`o‰(<¨´Ô¶ÚÝ»wi»É”­R—ðFž¼¹ž©mߨB4¶‹MM·¥âl¹4ûZÁ‹³­m6.ÄÅV²³c°©õ)™¸ÂåoS»˜¡¹ÜÅÉKÕ ì4¡ÍåYĬ±FжäwnnÎ<ÐÎZ¥ÅÑÚP[‰“Ôí…å?¶k-´±±1ì*÷¬›ñäbáØ]åÂñ/óé¢>ð´S¶B$É Ù.‹ÑÄ2£Fð`¢6"|KÛÄÄÇî[üÒ••ˆ¸p‰ýuÉpÍÑîH up;3úAºNo¯'‹"p_ÜG€”Œ;6Ÿ”’Ý\{rLY¼#ùmjj²‚EÌÝtã¬åÔŒi»³VÔc÷ äk¡ÍÀ²£ o$À¿XlŽ·)/‰)0…œÎ"Rèâ$Š mk›ÐfÑHÑÔZ¦1EZ(mï„Êl£ææfNÙ Þ¸yØJœÖþâˆBèííµ¶Ø¾suA¡s î\åÚ_šHücœ!±~ÿ¦‘ Zjm[bΚO‚²YE.F?襜üº<‘¥ùúõ뜲¥ÂM38&ö!µ|¦(þ²²OÎø;âáÊäÀ[Ⱥ´´”¼ð7¿ ]€Æ4ûƦ~\ª(@Ò¹±±a˶Û(77{–,#¤GN¹UåS;™°'ßѯÐÇÐf# -mN‹º8‰¨B›ž™@Z¶JKSˆÌࡽ½ÝÆ*Ývþ³ƒm2ѧ…¶‰ÅoŒ—À]P´³n+Jl¤Ôdþ¨ùë_ªÂFAíwüàÓeK;ªlÛ`àîvËH<Ú§Ëmn°k§L¡ÝµdǺ$Ï_VæÇÝP[Í’aÛx؈îñF¹Ó*tÁS0ÿª)nç `ï&mòv~GY¼[¶Œß;ö?N‰cm¼6ƒÇÖfw›Î´BK›³ ….NÏo‹vz˜e›]æòáoUU•[}êëë+++s;þf *ð2ZH»ßÓÓ399‰Mæ÷Ÿ:%Ê™A»»»MMMO>ù$ž3M¦%r¡Y£ïØÞÞN]FÛ?‰éöíÛ—.]²QYÿZâÅü­­­}æ™gˆÅfAçqM´¡‚|˜Ô•Cæçç-v’Á=²ï”ü»†ä ›Afß+[¤vŒ»-Ÿžx´þùIà%“É~Ñnc‘€3A'!Î Uhû¸] |øØÜÜLã8>>Îñƒ>øÁ¦½ÜÖñÆâIxsb¹ÄÂÁ…¶ÀÖ GDB[,SP·nÝârb|¢ÆÖálCCÃÕ«Wýû Y"im‰ñ…^@M‰Èb¤Ó@ÂÌ.·+økÛj¾²!zâE¼S÷þ²E¹Ý bVVeyÄ3]<Øæ˜z$Ã!ú('ŸL ¼> …¼¸¸ÈÍr«ëP2®“D).N’JŒÇÉ:R¶š[†ÝÖ*9ùã»wïž<§T§Gá'!Î ÑýÚ á¤ÙEchÝŒY[Ë:á)ÜÜܧÌP¦aòp!&,J†á‹ù511Äò‹ Æ´ù´—‰Å•:/—Ëíý·m'ìšþ>zr>í5aºÆ‘憿#­Ïàà b‰7[þÂn»d"Û¸ØÝq‘ éììt¹3lãH¿½E.ˆ‹²Jxˆºí*mÉ óÑÛÛÛÝÝÈ‘ Û91ìÛ{4LÛ±8Ö<Ò.Ðfoè9Ø'ÔäÜÞîûÒ²ººêö]å˜b´cùg!„ÈHØ#íAܻ՘¡˜(~<üS½ SVQxfìÞSº¯­pA¿)›êx¶ñ@‡É>ά¬ÜÛÛãØýÀ›Ô}àm¹±ä‘Z5è$Ù¤<{yOŸÌŽé¥án${»/Ä©…:( ÏKViÔfgÄU¡óBbs¹íoaÊ A:É ¦|¥!áOd÷X›¾gOøÆÆ†­…Ž£i¶}¨fjºë¡I t„8=¤ÐÅÉc¶¦RØfüËH&“þÑ`á§®®Î¿åFaÊ Û1Ë pa°M,†‡‡íïöö¶Û ztt”rÀ%uÙÑééiÜm_mlèÙÙÙÒÒÒ‰‰ [´¢¢â¹çž³]ºmÈÚ[>“ˆ8¶èì˜××׉Î6í·d„q%ºï¡Et@ŠN>]ù„477'¼W¿6Ó “×$±´ù---i··A§ÇÇÇÉ:½»»»¹¹‰9b …ÚtBÿk~ÇÀÀ—¸M´øŸŸ·c®mkkKä¶ýFÁð÷$„1౦¦¦bØðC³ðû/¥eÔã’þ€¹œK¦ò’qT*ôùPnrœ©©›ý¾µµ…x¿øâ‹ËËËi§©#´¶­! ³³«««PtÜ;;;qñ´ægpppoo¯¦¦ÆLvÔÝÆ–=8èëë ·XüB2+…"6<†Ù‘ßyNÓžžžc\xñâE³´BgËã’~r‘š©ÉÉÉ,ûŸ<ãˆS¾ö±>!öÊ@~;::lu¶c„yùòå,»rYçÕzTöµÇÔ3ÖÝú Bq<ÖÞÞžé#–bk|æî?YC¨òZêú'¡¾¾>K‘¤B®T槇MbçÛ¥¼wïž}©lkQo¨àÒ¥K·nÝÊt¶¶¶Ë»±±‘¨WWWKKKíC5 hÅHÐBˆøñ˜YŒ°ÂƒMc SØ-/¿¶ÜÇÊÊÊ•+W8URRBÊ£5¯ %n(¸ÃÃí˜{çÎüÛ1aràþ:üá LÄK Ž#åƒg -á™VüÅçææ&.6¸JSn#ŸhI嬥™(Ä®ÂOWWÖØì쬵úÇ$‰ŽÐp7«.Pæ‡K;#Ÿƒƒƒækñ™z7ñOÔ¸/..r9˜¶™ˆK–‘ üØ,­(€("dCÖ¶€¤0mÅ[=¿ÑÑÅ4w«~655ñk«ÖØÂ«a—‡"μ´¦Í­[d7~GÃÂÀ†ö;;;kkkúñÜsÏ]¿~&rbfˇ=|ø)pþÑH“4þšîºRŒ3Š‚«pA™¦¦¦0ÔðO°S­&èéiiiÁ±š­FwÄìz|àHx‚ŠO[›Œ_šuë¡ÐDm9ø3uÓãï|'YNkÏÌÌÔµk×Cå8Ò°¥©«k!ÆøÃÂÙÛÛ³e[FFFl¡®››K[ød QOý),E2Â-£äéŠYar_Èwùþýûä4/*·Õ(4"²¹rÈ37×v˜»0„1ç%…¦™¦ ެBÓþÒPZûëw§caFŒ­'E{½ººê/hºëÛùGÛlY.[f™_·26ª‰v¢Ž¶‡m4–wÂ_µ-ª­³³.Øþþ~d!7Á£‹ÐëAfßÛv (-»Ëí»e 9,ŠgžyÆ´?µ4ð@ BYcÈs]]K•zÈ0Ù·O•ÌzC©"u¶›V¦÷©tV¢#Ïî>rÇérQò^SSÃÝçð Ù<2›}mÇÖÓ¢»FÑQ¶ä—2ÎUÜ î‹sðàíõIw͸ÐÂç,b› h!Ä©cŸEÓ¸#aœý#Ü6M›mT…¦ÚVTn¨Ä£ …ìÀ¶„²-–]86C û¢ÆïŸ–×­eá_çË¡‰·•¤Ð0·}–Û ;Õ’‡Û†Ùä¿cÂëØ.™¶E•m-œð¾èuq!gQGLçhQX8è¢Û>ËÊÁåÝì]¸]EšÝâ3ä×…™ðÌnNMLLX2ö¼ÎË:hyÇ>sr;:› ÛÎÍn ÿ±åÝn±ß¿måÜ­lýîv_Ül;[ü5ìÜ‹¢C+–'?úúöíÛ ùɆ1ò^|ñEøÅ´u»_¤Å¦ÀÊñÏK§…¥'ûtÕÆñòòrII‰™¶þpøkŠŽÕŽƵ˜Åããã\‚MŒ#‰ÁzãZlá L.ôž¶ÓeEVËÊʇØqÄÚ³Àý㢘³$ û/°±žq'Hˆé=Y9àNŽø‹MœúΕp(7’„·ÀŒ6®ÂæÃ^';”!Hž½¶D’`ÂLD±a^KFÔ CI¾¸‰”$öñææ¦}åŸÑí?öàŸ¢°Þ‰Ž8wîHª»íMb-Þ°s/„(œV£1‘ê£ù ÁÔ¿~l”»ÇFŒ«0f¹0pÊlV ÇVÖ4ΛßÐ »HÝy°ßV@ì©f«[üùxå6Ì,~ü&rê…d$‚+ÂRhºkƒ+¶Í6ƒ-“wà=îØlh~ñc qÓ§q¶2>3¹øVM½‰BÙÐÅÉÿ­)†!ˆIÝéNYö´UnêPà•j– §ª««÷÷÷ ËŒ0Ñ'óà¼ùÍÖÀ±‹Ô˜~í§ÍMó“éEföŒgßc1——£ÎI"›f"§^ˆÍÁåï}IÛÆÆ:º»»{ñâÅ®®®ÚÚZ'°—ôþc~iàøµ==ggg‘[ŽqÁ>{­‡¹ó·££Ã—6IB¿\OLLÐÞåb‡E·BDÂq`–å¸ý${±]²DgOBÁRrx\ÝëÀD„³m½{¡#º8)9xùv@ÉdòÎ;iwâEÂòòrCCÃÎÎΚ®Ìs{ëÖ­ýý}› `ŸMŸ¤nܸa_÷ÕÕÕa:ëݳ›&Ù/nÄ)Ü9ƒ' ¦¦¦³³3섉pX__¿råÊ™ûšˆçÖ6oNx³íÊÊÊzzzŽúÊÆÞq\ò@žÑfÛ7ú¬È3…àÖçBÄ€4{[mooK¤‹$ Y²!î°ÓrdèRøuzxx¸ººº¢¢©Î¾A'O;žlÚ¿_›£9] +>¶=ü.a§N‚à(·Ã&ÈØ¬æ°) ÁøøxWW5ÿ,Êsº¶6\ÀŒ&kþçÙöxvmÕ÷îînûL.ìL:(tPdFǃ–––L»®ñ ºíÝDŒy<Ó kàjkk§¦¦dIÄTª³³sqqñl½{ÎJœô°ýN¦§§íwû~Ýáfþ755µ¶¶Fmõ4Qä eRèÀZ„"®<žå\{{{iiéµk×h¹x ¢üá86¨—íÞxæÞ=çm·‡ßÙÖÃ,¢­¹Ø á}—¯¸Hx,ûiî­­-¤ºªªÊöº;Á"oPó+**01766¦¦¦â'Ï™Pë&Î ·oßNu´ÒE1ðx.žè²Ù‡µµµ´ãüõï%Îô±fgg±›éuÍÍÍéFl°½«íWă:¿-º¨È8S,ÛÛÛ ÃÃÃ+++¶˜WÚ-˜D¤X]]å~Ù­ëׯ§ÝK5gÛ`Þp‹ÝŠbàÈ €Fß¶ýA³Óîg,Â%®©©±]7ÂN‹â8Øú ÏÒÒ³EÅIZ!Ä©âÌhÐÅFNï¡…B„…m_SS#y.6dC !„Q䱓!„ˆ Éd’ß°"„ÈRh!bÚ<00 …"6H¡…Bˆ(¢™bB!ÄËØßßµõü777í[âÚÚÚæææB.¿(…B!~ÄôôôðððââbÚ³¶^oooaVcÔ(·Bñ’6WTT´µµe’ç„g[ãí’Gê¦&yG -„¢¨Aw;::Ðæííí/±edN{/v}-„¢xAžkkk×××wyssóÌÌÌ)¥M6´Bˆâå$ò ³³³Øß§”6)´Bˆ"¥³³ó$òlLzœFò4Ê-„¢ñïìY^^Þ××·±±Öæþ6Úqîܹ¼ˆ%Z!3+°¥úèèhí#î---ËÓ:â‚{ÀÅ xNõé¢Nu÷[„–lù§u,NnܸaÈóâââôôôüü|UU• -¿½½½æ!­ôú÷÷÷»ººòžBÙÐB‘……Ún´Ðµ–ommùýÐ:ÓÊÛ«œZYYq§ðÌ婎ÉdòæÍ›n2°Vðêêjcc#gÍÏÎ'æÝÈȈ?ꊊ ç“Ø>|h†TŸ„iÙ 8š{Á ³`Ñ¥Þ&?»»»ÃÃÃv<666>>¾¶¶FIÞ»wßúúz4»¹¹Ãúúõë›››”çìììàà`GGÇÔÔw³ººE'G”3ºŽHïííåÙŒ>BÄ‚þþ~j4¿a'$nÐþ^¸pÁßZÖÔÔX9Ó"£ˆœâ×|¢Óœõ_N+ŸÖ‘¦Ü³\ ˆ áüsà÷iÑÙ±)Šß§ Ä|ºS“…~TÇ”!544”Z§Ç‘æW£Çˆ.ÉãR ˜Î$ÕÊpii Ǧ¦&r111±³³ÓÝÝMÉsI]]9°p8Èo.4Ê-„Ù -NÛÜc3a?µµµù}š9ë‡kÓ:šêX__G$°¹ ¶ZZŸ¸c¸|¦M?î---Xþ”ãHÊýާqaÜ—••õôôú~wyyÙ†ßS¿3žœœ´SS˜ÂÉGl{—ÿ¾ æ2EúVVVb[ºkCµººŠs š¿Öy{{;.˜×þñmg”ç ­ú)„ÇÖÚë’’’|…‰mÝÚÚŠ¢û¥7-/^Ä›öÈŧ_±H9Ž˜h—èù¥ ô!²c£ôvÌ÷øÖ­[n²4zIÇÈ &#þ·é.„£Â­tÇNh‰ç·¡¡Áý¢ÜXÞ®ç‘e1²ã!…Bˆ#ƒÐ|g2[‡IiZ 2}ó™]ÿ3|¼|²Ž&ϧW8˜ÂhjîÚŒÊ"xE4³| n¥¥¥§1AÌ¡Qn!„82˜¹³³³ù sff¦ºº:ŸÈs.>/\¸`ï­u´‘€À`…LŽÙo›—ö”&¹£ªªªk\•¥¥%8‹ìx¬ùÀÐý1¾ÔÊFa^Ú !NÍ;%ÜL17Ëimmͦ\ÞÞÞÞÁ£™b4ÜþùP6SÌöDò;â‚»s$¦¦& °¾¾ž(ÌÝfŠÙ$¦ƒGsÓ\Ô$Ãï3á °ó977ç|r¼å‘êxðhZ@ì‰Jë˜}ÂaÞ¿?íîOÖ?H¥0[E¥UYòBñÚ_*++¹¸sÊ=Ì”ãÈ)ó911aw6ñh¬ÛÜÝíÈ å"&ØG,…ür¦H ooo÷»ÐXûËÙ”øLF›þä“O&¼Ï¢²8ÚÞÃöuŽnvXkk« <á) >#ÉÈâåpŽNEÒ:£ÓcGÚgÉýyIÅ„ ËøÆ~ûØÒŸz ž;::ÃÚ–‘DÊËæôµ•Bñ2¶··'''lŽ777+++Þî&§1g;Rh!„"Šh”[!„ˆ"Rh!„ˆ:GÚQQÄ)´BD°S! Z!„ˆ"Rh!bB2™,))9í4…C -„BD)´BE¤ÐB!D‘B !„QD -„BD‘ÇÃN€"?466º_!D B =ÂN…"oh”[!„ˆ"Rh!„"ŠH¡…Bˆ("…B!¢ˆZˆ˜°°°L&ù ;!Bˆü …"& ÍRh!bƒZ!„ˆ"Rh!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"Z—[ˆ˜ô;Bˆ¼!Z!„ˆ"Rh!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"Rh!bB2™,))Ñtn!bƒZ!„ˆ"Rh!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"Z—[ˆ˜ÐØØè~…1@ -DLhô;Bˆ¼¡Qn!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"Rh!bÂÂÂB2™ä7ì„!òƒZˆ˜€6 H¡…ˆ Rh!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"Rh!„"Šh]n!bBÒ#ìT!ò†lh!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"Rh!„"ŠH¡…ˆ Éd²¤¤DÓ¹…ˆ Rh!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"Rh!„"Šh]n!bBcc£ûBÄ)´1¡Ñ#ìT!ò†F¹…Bˆ("…B!¢ˆZ!„ˆ"Rh!„"ŠH¡…ˆ Éd’ß°"„ÈšË-NÄúúúÞÞ^Ø©/1===::º½½]^^vZÄKìïï×ÕÕ… q†‘B‹£LNNŽŒŒp|îܹ°“#^FMMÍ‚GØ ÿ:]QQñôÓO×××·¶¶†q–B‹\Á\îë룹yÿûßßÝÝvr„8KP}ÚÚÚnݺuûömÖ"GôZävsmmm{{ûÌÌ a'Gˆ3Æ… –––úûû¯]»Fm ;9âl ZNGGÇîîîÎÎŽ†µ…8 ÍÍÍÓ ccca'GDÙÐâÆÇÇ1%ÏBœêÑÔÔ -KZŠlh‘ååå®®.¬ç°"D|@¤WVVÊÊÊššš4ñ^dA6´ÈÆ7&&&ÒZÏûûûa§Nˆ³ uª··—îoØ ‘F -2²¾¾¾±±ø>ankk+))9þ|EE~ÂN¦g[^f{{;섈è"…Áznoo8NOO———ß¼y“Æ¥¾¾>ìd qV¡~ém´È‚Zd„¶#uyæyJx ˜lnnf§§§çÒ¥Kî/ö÷ÊÊŠûKÙÌ9‹¥Î%\xÔ,d¹ª¶¶#¦°%!’Ǹ0pûŽí'{ڊ䋾ÖÖVÍèYB‹Œ ‹.\8vvvò{çÎùùy0¦+++³‚¾ŽŽŽ.//gÍÃ(Ï.‹‹‹øÉW¦HOÇI[¾‚:%ò›ßÓN ÏÉi'£Qäc}}½Þ‰,h.wñbKjcg—ØXϘÑ(SKK ïÞ½›Ýÿìì,¿uuu˜ãSSSæHcÀ766ž;w®¹¹Ù9âÛ«¢¢‚$ÙšÆÖEH»“YóæÇÖ¹,--­ªªr“cId@㬩©É™h´žîK@³lüWÙB§;;;$øÁƒ¤Í"ű§§‡!k„@tdª¯¯þ„¹YòVWW¹2¿zõ*Ý»wÏÖe£wbž-.²¿»»K pÞHÞ‹/¾ˆO[Ë“ÐHƒy&@ûkÙ§0«««¹|bb‚,pœð† ,¿öV‚4²+s;IåBÿK ’ºµµEJ(Õ‘‘ Ð?gÐHiÀ ;p!XJˆÝ_ò.%—/_ößÙŽŽžF]ø΃+^—‹Žô¯­­!u=3Ö)|úé§I0Yséä/ýK‹ÂI˜V¼ \’ü·Ãïßž‚¥p8Ë£XSScåo1’; ™«\¦2uC ÇÆŠdØ@QLÐÑbҬРÐõg%íãaíÂ`£s´J´ãYb¤‘"¨û÷ïã™. OVM¹Öâ"a4m´}¤Ü®²K8 µ>ô§‡¿‚`~¸„¿B\¸àNR Ê•)IaZ,ø\óàÀ¡'á.á˜ÌâŸèì€0‰ñà—KÇ®%vζ>‚k- àÓB¶Lq-§–––œ\Ù~$øçxhhÈÒI\E€¿.%\È_Ê ñ`Å‚;¡ùóË_K¿$ØŠÝVжâ"=.%ׯ_·ÛAì„iüÚí£ðíûx\ÜÝw`~¬ÒJšø4ß)‹Ý”À˜ªYì—B£/‚¦’Ìh—©¯Ñ´–×úü5É$ý”ÒÝ»wÍØ¥¬¬È”é¿Ù%d|Ò¬sLÉXzÐ6K¡?®Ô”XW8E\¤Äü»üâÁ”ƒ`]±[ÄhÅåÊÖz-Y$41™š«( ÒŸzßÍÑÄÛÅëîˆ?³ÖrÅëïиèÌ›»Ð ‡>„Åp'F+÷œ/O¯…é:za÷ÑnGÀ?1úKŒHÝ3ƒ»Ë%,»²úŸOë°r!ÅèøJ¡‹½‡. ¶··kkk©ù´È4%9®†ÿÔ—d6$>;;Ë©ÝÝÝ„gp\]]}íÚµ€ç[·nYsL¤4müõŸ-++sk¡ôõõÙ€3 ñ^ºtÉ ÓLiã~hÅî4£„I"­÷;DM˜¤óƒü Æ–s§îêêBÛFFFð€·Ôym oAGòˆ“~J»¥¥…L`[[rí•+W,S„¹¸¸¸²²‚‚MW ™Lvvv’K×ú'Ùå–ù\½zÕFGG‰15ƒ•H×Ár×ytttØfeÆææ&ytHšIy 4SMãüùói‹´§§O½åc)ɾ‡„]k¿V¼ÖAIëÍAâ)÷—;B2xØü³=ÆöXr‹ýeëà>ò,ó`ûý£Ö/¾øb ֵĸÜÙƒ‘w¡ÅÈÝç©æn’{ç"н‡. hb¨ù©ŸNeÿ´m¬hžF=ÌíÑðð0Í_`R7Ý‚ééiúÖ ÓnÒØÙËcÛÆI¦õ4mØö°÷eoøèZÅ/âÍRâÏ’"µ™Y€å—¨IrïÞ½gžyÆù'‘Ö“ðØ c{eN.ˆËÞ¼ú¯¢p86sŸÔt‹ÛÍÓ³Al×jRÂ1)áÖ C<]”€{AK¿Ä†@¿ y„üÅ›ý¹%¤ÑÝ&‚µ'¹%Söy Я›!áÇnÏ!Aq÷Ê–Ä“}úˆ”¤½ïwôxàarr’R"v›çHV ~ÏÅS”5eB 9E¹]¿~=!Š–°xqê`Ù ¹£‚½B{”êîÞbº!JM<»qQmv¡ÆÌÌ ­çÇñlïžq¼ëê`¦Øt¼Yh€gÎr• ’ç÷ž]’RÇ ‡n—àÍ.q\©@.ìuµ½&D“Èšy³¼Ø€$6ŠkX2¼7¬vÀY.Ä3>m@;uXÕ eÁÂt/È­HíÞH9)qÙw´¼Ø8³åײÀÝ%¡fÿ]¶ÒðhwÁBð‡lgmôÞRËY®µ9öëtr]~­ßfQ¸b´’ —Eç¼ÙÝwIµÂ± ]:ísO}ºÜípéôû÷'ÉbwåÈ‹‘þßÁ= ›UÈòÉ‚¢›ŽbKÙÛ÷¼`S´r÷ï^Íæ÷Â^z¢‡vmâ‚Í…”B!%ÞTWì têûÚY^^nkkó¿t<%ìk"ûôËÿEMèÌÎÎR»»»UUUÿcCh(4ùÍ}ׄÑÑÑùùy›ý”G®\¹ÒÔÔäï. FEEÅââbê —ÃÃÃx³×ÕżÆNq"…Ž!ö¡³ß»w“Ôß²¾j=”ŽŽŽ„7a*ìl r¯Vûûûeeeöa¡ºØÐL±Bµ·OŽ‹/Ú} t¤ÐÆÆÆ°ÂÇÇÇ5cEˆ¼Ð×ׇYœãД­ê3;;XHGúÚ*†d%öT“#¶—íÂÂBKKKDÖâŒB ºtéÒæææ‘Þa@Û¼}QlH¡cˆm=›êŽ}¼n¸}nÔØØXWW§q6!Žu‡ÔÞÞ~ÔwFÚA®hÑ{èxbï®kkLMM| ŒVÆöËknn>êª B!»»»óóóö.ùذººÚÿí¸(¤Ð±¥­­Í–1Žñ: h¿ Óù£árïÞ½………ÆÆF·ù„TÙÖz;êôLÃ?å³¥¥¥©©ÉÖ™7***rÿ@œQ¤Ð±e{{Û¿è`^ he0°úûûeiź¿ipMx/žvvv¢óQ¢8%ô:¶øß:û ´",¨³™¬d[é=ìŠSG gÜÌícLáB„NÚš‹6û7\1F gÌt–-Ä%­-ºxBÇœššÿì!ÄÙ"`FË€.*¤ÐBÄ„d2ypp ib1#`FË€.*¤ÐBiœ-ºØB !D¤qf´ èbã‹=oô;BˆãC^\\œžž~üqmwTDhÅ!„"Šh”[!„ˆ"Rh!bB2™,))Ñ{+!bƒZ!„ˆ"Rh!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"úø=looŒŒtuuv¡Ië¾àaÇm-’ÉdÀ¿’ê?w Ðþèè(¿©‘fòORWWWS÷ÞÈä.B¤±±ÑýŠcÀÃßèq¨û¡µ¬¦¦&N¦Z–Ëqj’Zûˆtkk+­Kmê$ÿLî"Bˆ“A­˜™™¡$>|x¨ûÚÚZÍ#šššÜÙ½½=ŽSýÏÍÍüã“Àsqs·Ð8¾páŽþDâð£óO+à÷ŸÝ]ˆ3Š«}TÏCݵŒ:åj™ùÇ%à?m-3Ϲ¸«•´ Úgþiüþñæü[CÈr&w)t{N UÑú:…NëNåñW]«üþãTÿþªè$ÜdþP÷oÁ8 …ï÷`‰ øw)LõŸÝ]ˆ3Š«}…Nëž©öeñŸ¶–ù«vw»Áq ö¥öìýí†ùOUâLî"Rè=ôII&“®Zæâ­½xñ¢ÿïAÖX Ðï?÷’’¿Ë¯Z¦²²²’êßõ3rq⌒©öµVšÿ#Õ²\ÜWWWý.Ùk_ªÿ´ Q&w)¤Ðá@ÅnmmÍý=®½+JõŸÉÝÞ7箣øŸžž–î ‘;igud÷Ÿ¶–er_XX0÷À—LàŸ!wÿ"úH¡ Íöö6½W*^GGG.u{ßü¦•™ûäädZ÷ÙÙYÜsœbþ¹/,ñtÙÐYZÿšs<ÔÝŽ©KÄb6¤–Ö¿Ë~îÝ»Ç%¯´3¹ qFqµ› ˜ºº€ß=Pkðãj™ùçÿ‡Ö2.á wÃB2µÏü/{8ÿ®Öãß´3P[ýîw‰,%Ùg*ŠCáAwkP\ÝΞ³ÅZ__onnί{âåãþ‘´£ºÏÎÎb7dwoiiY[[K¤ŒÞÕ]šZlhkÍ'8*ùªe¨}®ÖäÑ=må÷| w‘¤ÐBÄ)´1Cï¡…Bˆ("…B!¢ˆF¹…Bˆ("Z!„ˆ"Rh!„"ŠH¡…Bˆ("…B!¢ˆZ!„ˆ"Rh!b‚­¬åJ„ˆ Rh!„"ŠH¡cζGØ©BœUäâD sF<ÂN…âD¨"'Rh!„"ŠH¡…Bˆ(òxØ B䇯ÆF÷+„ˆRh!bB£GØ©Bä r !„QD»OÆŠŠŠLfÔÕÕ---…@!ÄáTWW¯¯¯§=uáÂ…µµµ°(NÙÐ1$ËW·oß;uBˆœÌtjjj*ìÔ‰B :ž¤5£›››gffÂNš"WÒVd„²¡ãIZ3zll,ìt‰Sdaa!™LòvBDÞH[‘5VÔÛèè("]^^¾³³cÖs___öKðï G˜à~»»»ÙC0\ŵGÍW¥íCàx Î4ÇÎþ¨Ç¡~·ø¨¶Sêùõeðñžº´´¶¶ŸF¦DÐ,Ifq}}ý¡á Ì oòKii©}@BÈÙ/ÄÚvÍÜÖÖ–+=lñìR44äÏ”½;àøæÍ›$¿x¶B°Ë ÇÊÓ¥ÄeG[6ÒÊpccÃå×2‚;]±û“j±¸'Çn¿îüÏXù#øën˜ ù2$‰’'K ‰'(++ú^.Rëêánö·ÅhÉó¯ÿÖ˜B¶;NqáÇÒé?å?¶[Ï3ã2ÈólîvyÂ`pQXŽÌ? ã¦[¤ÖZ«G.u'µ–ᵿ(Y Rè˜ã¯Ø´#¹h³q¤M•"3[[˜TáÓš3k¾9 '…&h‰%àúõ븛ê#Q&·išF“ßöövÌs` 1ÑY Ö"§‘»ÄdÛÆT{=,cnnÎRKR×<ìØq…†‹¥„.~œNãÁ„ÊeŠÞZ‹oºåôÀt—ØÙÙá¯-AcKžeÄ4Þ¥„-/Ük¼2¿„lisùÅźk¤ÓuP,4+O‹Dšä”k#½DjÚ%æ™Ô¦Uh»A “FóCâ]Jìþ.IîŽ[®‰Ú_¼þ»IL+.ŽÍOâÑÎ1þSîØòίeÐòe.2žýQàN°Öô?$vSÜM´Ì»–”ë´H¡‹r ËËË===+++¹/©M+“ûPÝââb· õðð01! ”<óÌ3 o™$Žý›O?ýôææ¦cCІVWWÏÏÏÓ N[[ÛîöN ×644¤ºï{5¡å’}<»áMÊö×ý¥Ý´·†–HŠÔ¿õÃùGÛèmôõõ™7ÔˆcÎ’ýŠŠŠk×®¹M¿Ö!pQsíƒ8k¹0wkÿè+ &襤³³3ñhf@Âë-Iíèè¸wï^jqÙj‡89w@28ðÏBà.Ø_3| p||<ñ¨£`Üò8™ÖÉ©ªªâB²x*H‰eÙ¾ÎrkÌ"ê/^ÿSj;+.üXJ(® wÊì®u]Lðoj•±öeeeþ‡Än é§ô(ó\¶¸àáÏôi¢iüä䤕³(N¤ÐE- †‚éËKÚšgÐÐÌY›Þì‘ðô yF¤!tuu!ÉGpl¿í½ÝóÏ?;Ï6„h³´ì4y4¸¦µi“ÔÅô5àÇ{‰ÑÿVÒ ½sçÎôôtà%¨ Ó755áÁ©Ž™×h¡ ö¶´´ØŠŒ).h™"#8×—àÇ,`ÓBûKî-StV¸ŠÿLxRK‰}à m)béá×L={ýoÂ@J¬ôÙ$p­åv –_\L`p± †u »­p7 ‡qOGGG9°nÖ‹/¾èî,‰á,!‰D‰Q©2bl)±×®–zf$˜AJ(=çŸ ¿ÄåOžá/^—à9ç R"¢L\qQÚþSvL¤®›â2hÙÏ®¯äž(©Å§{H^xánÊÐÐŽ·oß&¢Ôd˜Í鱂Mˆ¢D ]ÐvÓàu!‘Ü?¡‘µŠn†ªCS…}xEM[ãvÜJxâÑHÑàºEÇ…JP6éGþÞºu‹ô£ˆx³ñ€;6±5â.4š<3¸ÝKY -á-ÿ7np Gw‘’$ÛO3p i{òÉ'ÉÝ?øAç‘#m4èDÍ1 ³u]¬÷sÿþ}üc,’}ÚV$Šb$^¬6õESíÀŸ)šu”Ïo@r9 ½ Œß½{÷òåËöœpœð GÜv)qÙOxÚIø” W¡%è–å—ô;ñ’Í™™—k±WÅþGâñFv0Ð ³…ÕH°Öqá,Þ*++¹ÒeH0¹&\BhÄË_¤ÿœ"%ä‚c7“ð:C”'‘Úû`»kvà/^Bs—p§p$aDDQTþZqùOÙ1îsŠ dnnŽò¤èlzs·»à`ì©ã®q‰KÙCBGŠS¤ßíyè¬ìC?h´Èå“ OÂf§ í‘™kǸ–—"÷÷ÖyO9-à÷ºôxé?%PZáï­¹ÿ¥é 1›øH¥xô:¿Ø+ó¼[ ¸÷йx¶Ù ¹ø´Á½‡.BdCÇ,°#ísç°™Õöj³ð`!açaŒ’ŒÎPÒ,3´™„¡Ó~ÛúäùµI×áæ«ÎÆÌÃMÆevv¶´´4G“·­­Í?`ž -=Vœh蘃¶ ,--å2o%----(‡ÿõ°â„Ðo¦3433“‹çíí튊 lèHuUEÐÎEÁ±å9áÍ=Æ^´w‡açCˆ80>>Þ××góÉsÁÍņ:þœpàôܹs6ivaa!—}®„YèèèXô8ôÊõõu÷1›}Âà_§Ìfç…qºè=tü9y5¾pá‚-0Y]]m= !ŽŠ­èI=¢6åòaÅòòòÅGpÕèè¨û{éÒ¥L‹8!:†Ð ¾.))±ƒººº¥¥¥c„i3T ¶««ëÚµk˜ÔÝÝÝj#„8”ÝÝÝáááùùyjÍ‘– ²™ƒi¿þ|•'âŠfŠÅºêiW¹‚“Lóƒ%m+K¼ð Yù…Ä*±%±ÂN‹x‰²²²«W¯&¼½dŽ÷MsÚºì¾Ø;âÔ‘BÇ“óçϧ®–plZœ lÞ¾füÆŒÔ!1ÝââAï¡ã‰Ý.ÇíÛ·ÃN—âh–_Åtö¯ +â:žP‡ƒ`n%B!Ä"°ŽÞ@RèxbÛ1ù]d@ qFqF³ èbC [üf´ h!Î.¶´~Btñ¡™bqƦ%ržÂýÃþðK_úÒ—¿üe÷÷±Ç^êýîu¯{ÃÞðÊW¾2ì Q¤P—oݺuènêì×¾öµ/|á ð™F gö÷÷ÏŸ?ŸËîo}ë[Ÿÿüçý»Ö§òªW½êMoz“¾ä¢ðì{dY@U8–H¡cÎÂÂBUUU–Œ¾ûÝﮬ¬P½s nø[ßúÖŸüÉŸ ;gBˆ—PŽ1Rè¢æ«_ýêêêêøÃ£^øú׿žJvò…(vT…ãºxùÊW¾òÙÏ~öØ—¿öµ¯ýÅ_üŰ3!Dñ¢*{4—»HùÖ·¾u’º ßüæ7?÷¹Ï…!ŠUáb@ ]Œ|ÿûß_^^>y8_þò—¿úÕ¯†ñ#’ÉdII‰Öƒ,T…‹)t1òùÏþ/®Ò¢>¸…GU¸HBô¾ÓîgwìÐÜ÷ÓBˆ÷*쾟QCûCÇ zÖÙ¿~þÞ÷¾—ßÿë¿þëõ¯}Øù"&¾ ÿÏÿüÏßøÆ°ó-Ò …ŽËËËßþö·³ûùÛ¿ýÛ¿ù›¿©­­ý£?ú£×¾öµÙ=ÓÅÞÚÚú™Ÿù™,¾ûÝï¾êU¯ ;ëBÄUaáB‡]æÕÕU›¯1úæ7¿ÙêK<šBåáø‰'žxÛÛÞæ®ÂñáÇvüŠW¼¢ººúë_ÿú¿øÅCßN}ó›ßû»¿û»……‚C«7u›äe©Þ ¯NÂ.H!ÂAUXœRè¡–R©ÆöצVººä¯®_ñÈNî;_óš×|ï{ßûð‡?üÛ¿ýÛ¯|å+©íôÇqüµ_û5jûÌÌÌ«_ýê_ÿõ_ÿ‡ø‡/|á ´5\ò™Ï|†³Tò¿ÿû¿ê©§~ù—™:ÿño|ãñü®w½ëßøFØ)îWŒÈVaôû?ÿó?U…Ï4š)&TæþçvuÛ°‰F¾¦kú¡Jÿõ_ÿ5Õøw÷w‰ë=ïyÏ[Þò*ùßxP¥©Éxå€ Ì©/}éKÔí?ÿó?ommÅÃûßÿ~.äà·~ë·þñÿ‘ÞwØ)^mN&“RèB…*ü§ú§tR«0¬*|Ö‘B‡É׿þõÂGJͤ>⟠ïüéOšÊ‰ß¿ŸêúÇüÇôÁÿìÏþŒþøóÏ?OÍwSFéz744PÛé›sUÂ[h,ì%VØe)DD¡ Ss?ò‘¨ Ç)t˜¼ímoû±û±GŠ$Óƒ¦CMÕ¥ž×ÔÔ¼á oxï{ßËÁ‡?üaj8=îý×å÷]ïz×íÛ·í*úÚôÙ­N „©=kEq›*üŠW¼"ì²ix…V ‘’’’Ÿþ韦÷ꟺùÄOPÓ~ÆãÇüÇ¿öµ¯¹Sô‹ÿ¿G<þøãÿû¿ÿ{ŒHé5¿éMoúøÇ?þì³Ï^ºtéêÕ«TxzßÏ<óÌ›ßüæùùù–––_ú¥_"Þÿøÿàñ8þüOýÔOáríÚµ}ìcoûÛ9 Üîç~Ž~ËÊʲÏC"–XÞßß÷o-u«ðë^÷:Uá¢3"ÁW¾ò•/~ñ‹”––6œ¡æÛQêO`öïÿûþ/#777ÃZ<„d×ÕÕ…µQ@UXœRèX9þïÿþï…¥T[[«máCgÁ£Ñ#ì´ˆc¢*,üèk«XñªW½ŠŽpö%‡>|˜÷ú虢 Ï }pu–Q~¤Ðqã•Y<¼éMoZYYÉcŒ¥¥¥ÙcB䎪°ph.wÑQ^^žßÚøó?ÿóaçIˆ""ïUؿҙˆRèbä-oyK¾‚Ê{c!„8”üVa­ÈY¤ÐÅuò‰'ž8y8h³zßBUá"A ]¤¼õ­o=aÇù±Ç«««s;! ‰ªp1 ¯­Š—þð‡ŸùÌgŽ7)ÔêváWSB8T…cºØùìg?›e¿´Ø!zý,DPŽ1RhñÒšGÿöoÿØŸ'-ô»ögöo|cØIBüªÂqE -~ÄæææÖÖU=í~ytºŸxâ‰Ôe …AU8~H¡cÈèè(5ÓÙžžžÒÒÒ,—»m<~ðƒØŽ7ÔmM'⬠*¤Ð1dzzº­­-í©ººº¥¥¥°(„8 ­çZ|¨WCZ[[3-‚ï6‹ñ#™L–””h?ÙXbÛ¢„ Qh¤Ðñddd$Õ±Î#ì¤ !„È )tjà1´¦(ÀLÁ´5 <0¥¦Ô@  ‚U¨¢ú}ýöžgÎ<»IØ$›l’¾_"g³;îÜ™;wvvVºÅ™žžþçŸä@ÿ ¤-…"14ËÝú¼|ù2m„B”,´Bш¤0Ë}ww—Ïç9888¸¹¹I[-Îׯ_3ÁnSi ÒúôõõõööÚAÚ²!ZºZèíííÕÕUÌóÄÄDé7ˆ¤xöìYÚ"ü)œœŸŸÑÈõø_Q u²ÐØæ™™™ÁÁÁîîî´K-Dm¡Á¿xñ¢««kkk«n Þ¶nÖz1!Z†zXè\.‡W{QìsB´cëëë}}}kkkøÓuÈ󼸸˜Ñ WB´ 5_)6>>~~~.ó,þ@&''iùSSSiË"„h>jk¡777雎ÒUãS+ e½¼¼‹åq€½*mlnnöôô`é³Ùl.—KWSBTÃçÏŸ_¿~?ü“õ¡å"½ÅGºJ¬U-4Y+ ÷\åúUœé©©)fggqÄc–/ÜãyW¶B‡X!¯a¢þ}Å)W,˜OÌDbŠ-reвÒU)LY! bõUqô(ÕWYÿÕÕUYJ¦Á[3ë………ß¿kwÓÛèè¨æÞîŵ1éªJð-k1â©•…ÞÞÞžœœ¬&…OŸ>ÑÏvww¯¬¬LOOsfyy¹tTƒîôñãÇ‘‘w•Ôîub@0b¹ï6Zľ¾¾_–rH°Êˆ™HL±CE.«8!©J¤S˜¡¡¡*µM\R¨8zæß–à—«ú*#šåÆ¢=÷ôôŒ«-‹ÝÝÝl6+½Å6&]%‚ñ$e§ke¡©iª¼šlCP{ŒmÝë™ õêUÁ«1ŸˆGƒÙãC¼“&ÚͱKÐ à/þúõ+]mcO³···âmnòª­ÓÛÔÔ”ÖÒß‹t• ÚéZíXB?’ø ÐWWW%®Òªhaß¾}p¹s€3ÔÕÕ511q{{»¿¿o'1`kkk/--ÍÍÍÍÌÌ…ÑE.Ÿ~xx8—ËÑÉ>}ú§ yðŠH‹B ´ì…Rþþý;ÁˆHôÑÑÑÎÎN9aœ'·oß2X]]ýòå‹+ˆ™ Xww7ˆM`q•L­Œœä*Åf2yFN3~üøAx Þìì¬KkapPpŠ`¹ÑZˆËI”3€ÉDLWü¢ FQ¶Q†éœ¿Ä½¼¼DôƱÛZ ð’ß¿Ow@Dtåï4GàLð}&ØyƒÐè•" Q(/b 2 @[ô@=†šíÁ—Ù*rñ—tVVV€ÒÜÞœT1w”i€\„cÎøÚFùÄBfê«Üw;::P~5³ÐÛÔ‹m.b²¾¾NíS×Í»ÙpÝ6Øo]¥‚UÙiºëü+Û[°™¾mEwYâ*=/* 7G#f™ º3ºEúwܲóósÌû¯¿þ¤ѧÓéµ±a… ¥L dýìÙ3ºu~ Oá±é²iÊtÖg‚™L†„Ç$&雡5“ãCµÙý†]tÆ5lÁ†ÀŸ?&:‰äóyÄø.//cŠÈŽ²Ø–UÆa?ÈåR°[kkkËÂ…èXMRÃqû‘8Y„Æ" 8\.˜S‹MYS4ŽØÊ#±A`B¢B˜|7Þ¼yC:(Ç-ô³GÏŸ?§š¨Û¿šŠpb`8í—‚S§˜I:ÕJ"”ˆ"plš7Úˆ«D[¹Ø£ Ka¬"ˆNIIÜ û°ú”‹2ràZ‚µÔbš$wÆÔ&ÍÀ—¹nPœùùy™çrAoŒäšÚä< ¨CF- «†‚î‚îÎ\ò–Èü® 8?þ,+ŠÉszzjéŽ3Áœ3Çt‘™ “µKtst…"a¬/ãiZÊV^~qµiˆ˜þsl!-ÇÄu)[:œ§Õ:ÙÈÂ%è²XšèÁÍql);Á™›ÁÊèð=32rÂØJ@N*Љð¤ƒ=s)ø‚9•ZüÎÝ/c(S #§—šý2 pÍ›¤Œ&•Ew¤ƒìÒ1W›ã½½=¿¾¢ÂÅJj3Ö£ D jÛoÌ¡ó¡¹e{ÂM5!L/’àÐû-£î´Í¯Kå”{S8Ä¿Ô2š,7Ç?é->ÒU‚øC1•b èÒ9IWSЊE©•ÍxiªIo†î—‹¤p9óþý{~³Ùl{{;Nž˜¿¸>®T8U¸_îêÁÁo¿éšqŒ0x®8…¸ƒ/_¾¼W2% { ˆWó³E  7Ñ鼊‡Š'‡$þIó“¬:£#8sß¿wŽQêËí‹jæúà5’Âï`”SbéúÁ},¶©|—=˜@t‚ãÌâââ‡ÜTAH•ÓRSl[ÈÛ±LóìOG 4€ÓªKÖCÍÒfwß=ëE]þ€—¿Nf{FÕp ðË+x¸n7¹#K‡DÛmmmZËmÄ×›®§ Jé…è~9IO‚!‹s«ÖÊBÛgªI®Î‘_›ŒÅZøF(4ãó'Šéj±»™à)}"Í#7ŒÞÙ¦7éa1E˜pB–^+ŽY"ž¢3º!aÅÐÐá7š&çCó¥ïÞ½C›ñ±°1\µ€š¦DþÇHÖæ}äuxxh¥ˆ&î°§¶¦–èœ Æ‰² žU ã§®®.ô5?”›úæÍ§^Û“Ñþþ>¤££#ÎËî8Ü„!ý™™ßùŽÏÊÊ ÃÓIA³ÊI.S#Îx£.êÚi›ÜZ&3¥& o¤Iª¬áê7+Cz‹t•8qTJ×G7þãÇû÷ù¨‘ËOöŒb:òÆi@4 þYèL4L4¢;ã¢ó—“ö5@œTúJ$tì×båóyŠžc9”`èØ?°X¾–²KйËQ\.N_*ÈÅIUQ¨DÝ©(>šKH-N«~þZ`—²•Î?ˆª×É_°*CµPPóуbB-§`Kó³ð„´íG,¨ù‚àÁÛTL*˜o´y¶øé-‰æiã#]%÷] 0FöX­µ²Ð¿KšŸ¡£Ä0#Øìì,¦(‰}P¤¬AŒh^Ü4{í…"-âÖ}èÿ1Ò%z†®åÞÛÛ[^^n´×7q¿|ùòôéÓÉÉÉÊæK“âüü|eeE_ýúX__ïêêª~Ï!DcRÙêw{EÅ>ë^Z½ žŠ¯­­a íqrt“¾€´¥ÈT¹+ªhNNNfff*Þ«DÑÂô÷÷Ó9ÐK|n]C ŒÐÑÑæ°ÑŒ´õáââbhh¨>íßV úk…ÏÒÒÒßÿ]ð•–¶ß‘·âgssÓv¤ªlS!š”õõuî=©‰ï¯'„h%ÚÚ Ûâzì)†'y¨þ›NB48¶m6›½¼¼Ä{–yB”Æ^Cž¯í,·Ÿýññ1ÝV.—ËçóØlí*'Z’ƒƒká¸Îš4BÄ¡ØS°zÌr‡ÀðmCû‚ ÑÔ 3îloo—aB”…}m(ºËX|h ¶”ºT !„é‚y.¸;a3}ÛJQ‚ÃÃCÆàü¦-ˆ¢<ÆÆÆìãÈ!d¡…h°Í‹‹‹²ÐB´ ²ÐB!D#" -„B4"²ÐB!D#" -„B4"²ÐB!D#’ÂŽ%B!„pœG7þ”-„B4"²ÐB!D#" -„B4"²ÐB!D#" -„B4"²ÐB´ mmmÑØ !šYh!„¢‘…B!Yh!„¢‘…B!Yh!„¢ùi „H†ÁÁA÷+„hd¡…hÒ–B‘ú¶•BQo†††~þüiÇwwwWWWÝÝÝö·½½ýøø8#Z!„¨?ÓÓÓãããþ™óós;˜ŸŸ·ùÐB!D d³ÙëëëÐÉÜÜÜð›ÑZn!„"æææ¢'ß¾}kæ9#Zˆ–á0@ëÅ„hîîî:::øug|:#Zˆ–󼸸ÈoÚ‚!b%ÆcöÏøtFZ!„H‹¹¹9g’9Í{ËB !„éà»Ñ!:# -„B¤ˆ¹ÑQ:# -„B¤¶ybb¢»»;ä@gd¡…Bˆt™-x^o[ !„irvv6>>Îoè¼|h!„¢‘…B!}9£á¸»»ËçóiKKÎþþþ´¥Bˆ–E:e...666¶··9¾½½}øðaÚ•vÚÖöõõŒŒD—# !„¨YètÀ$¯®®ž cØfff=z”¶PUAYÖ××í}¾‰‰‰(‘B¤‹žC×›ÝÝÝl6‹…Æu¾¹¹ÙÚÚÂB·€1Ç^YYÉçóGGGwuuMMMù;‹Z³°°ÐÖÖÆoÚ‚!’Aº~œœœ000??||ü',°zðà¶ùòòòǸÔ2ÒBQ.z]r¹ÜÑÑ‘ÿÕÏ?üéLuWWhÕi!„¨ò¡k ¾ã“'O8Èçóšyv`¡÷ööúûûONNÒ–E!šYèÚÒ××7==½±±‘¶ )cæy``àââ"mY„¢9Ð,w ÉårOŸ>œœL[† »»ûììŒ!Ëååe ¬]o@ݯ¢…®ëëëGGGÅv; à ôÞ°½*“Ífñ¼«À²(–” æË9×××?~Œ \éµµ5F-˜ê?vοv ¤-…"9~‹p||ŒûõëW±óóó¦ÿÓÓSÿ¼ìíí­^Ë¢XRN€˜©!gA+`rr²¿¿¿ú !Dk@¿Z°¯–]ÆÇÇñ8å&Ítuuœœü oµ www»»»öu<Û¤VˆV¥££ãùóç ?}ú´9ôõõEÏËB'ý<66V}Röl6ëO,_\\àÛÉ‚[y»½²+>oYl1ÆõõõÏŸ?9èé鱸ñ7'11a‹*iÛB48ôi4þ¿ÿþ»»»›.«¦«gnnnð¡ \HÛ¹oA¨HlOé0n’yzzzÞÃNÚtÇ—/_|Ãé¦Í­"é.­Åð»´´dÉr²µ–ÔÚÚšÿ.òéé©ËË9² -‘‘‘?âþþï,7bXÖÄå˜þÚeJÜsû>Ès¯–Dº0:´â¥-‹©AOEE³s«î²­­­èyYè„AËX©{ƒ9Y3«„Á c¿}ûfç­ ÝPkooÏVoMÇ­J{ûö-QlÑ%eçwvvHÍvÏv íì쬟>æ–è„4SMýû¿ÚŒº,Ž9<™`9XEÙÞjiWWKÁŽêà7‘Ô666h ´™´‹%DCÀÍEçFçY‹ÄéB ¦, 0Œ³0o÷s’*ïõð-´¹˜¸/ØT;O¬ßÿZh̪]ºÅ~–”9Ðt¸ˆgí Øœ`Kß8oaœ…¶§2„·`–2ÍË—?f#&–œ³±:µJ¬Ì35[;AˆfÄæ5¿/èÍŠ¢K’äîîîè訬Pø(gþ¥ŽŽŽžžûV4¢=ô>)¸³æþþ>çM<ÒŒî’íÇZZZjoo½½½&E –{gg'WWWþUßNß #€ÍÍÍDk@$ÀõõõÌÌ mFK…ð¡ËZ[[+±@§2è'&& ^’…N’ÝÝ]\̤úµ‘‘‘‹‹‹±±17Ë / EÏ‹¼èaC—°¦øµ8å&Û§OŸŠ%bŸyÆ„sðòåK;é[t†$Bãããï1¶dÆ\26;;KsOPÿ"¦¦¦B „¦”ž–®>Á4qм$ $8»î™nõàÈf‚­Ep£íÌòò²›ñŽBÖÖ«vuuá(/..úI‘H.—3[[l¼–ñŒ1£E—‚ óï®#™`8²°°`šb°ÛÚÚúìæÞKÃh†ñ„>{ÕPœœœ0Ì*¶Z›úâjhhã¹Ð ­ÊÞޣؤRÃjÐËB' F+´º˜1›63ì°“ØWŽq±Ç=šžžfE-bjq•0Îjúéà(¸ŠÁvIžžÎÍÍ‘‚-#M'€%âÒÄ'ÆÕ¦ƒfœh/Ñ“’¾ËHÓ¶0Æ¿~ý"Y{Š…æLüY [y‘V}aZd0îIK€j°iŒÄí"Ú ±»JÓzüø±[ŸhPƒÒV‰õ€þ“Óž÷šăè‚èÒKM%¦ýè½¥>Ëóu¯¾¶ Ý_×D0r>®¿Å["+ÅJ/„±!]( ·Š0mÅ$‰VÉÕ“¦Ó6½÷à½Á¶¶¶ì9`±R㢸we ":1Ší"JððáÛ››zæˆë‰ßÜÑѱ¸¸Øtìæ7[SeR¦«89ÆÛ«¬8ñ¥Š)L.—CÛÕ´ÛLìï 8¸•BËTiñ£ŒŒØw ŠÁÊ}ÊÝZÂæêàààÛ·oK¤# ù|^‹kÊ…{¸ÄÚ·dqæ­õls‚Ôn”is¸Íõ¯²S6¨Êdß8::¢M"^âKvkGó¾aÕ‡7YMc ‘«««»€˜ª¨²Û¡«.ÈÍüûàÌlsÁfûÉ“'=ºw©¬výiÒÛÛ;33síw5œŸŸ³m_¿~MÄT¤"ü§OŸÜŒðÇÃÃÃu.ÙÔÔÔä䤽jOçE¡Ã_­fugüîïïÓÃâÇÅyKKK¶„mnnŽ3x'x9(çÅ‹ïÞ½ëïï% ÉßËËKÊ»··G,c˜­Ú{†È€Hüx$àââ‚_2"YdCæ ¤"ØÁÁ©‘u&0–.Š_L܃Ôzð={”ãËÀ_¢P–PýrE‘”S/P_¸¶”Ú4|xxHí[ê^þt³Öür¿‹°]›2ÿnKLÃrW¹‰ìц›á° }ÕÙâj«d.æ[³ ¬ÅM* ýç2::JoRb±:€=p7U}à.¢«¢h=;m‹¥«y¦n;·Çѳ4LÎÛSF›ô—ü|ÿþnú6€Þ“~Ö¶Ó! ®!mئ¦sE·›Ëå2E¤Ei>|03LDúÜ©©)JºººJx>þ\PÕØK’%5Ò/ñޏ m0µÓÖ§‡vÂ`SrÁèFW9áâSÝ&mØjAßBcTìá±oJë3‘¯_¿þóÏ?Œ0ÜoÇ»wïì!º]²gÿTnôÃÉ´î,W5&õ…Âí¡/b÷Þç»´aŒ(!ù-«=s_0#"9Rjä±Ï<&¹=ê¶3Tã º ·* “) ·2RYš%6§r7iY±‹R±÷-¢PßMô)ˆ‚3–QKrkÕN†dçiËÂÞŠ.ý>bÃbv:ñ÷¡Kœ ¿„C5žø'‹Ír[`7÷H‚vììa¨¤ÜY”Ëf¤ f‰»,\j–x(nèÀÛ¯íU¬À/¯Ÿ¸;.xà~‰n[úX‚nÊ:ªU'ž;öOr@âNª‚ºµ“qôY0_¥®˜¾2CªéÊøéø2XRÑ›Ýéíg€_ ~‘‹iÛáWŸxÁU‹ß€}ÍK±]œ®Þ¾àW•…N’bßølLbZhZX힯×âC1,I}Û*ÎÎë‰Yhû k² ÆÜº•‚Úi¢¼(ÆäädYwY5w“Þ¶J,ôêêjÅ!NNNvww¯®®†‡‡±‹öèËÞàdgg§½ áNf‚3{€ûz)ìïï»—+2Á —üDB\\\lllXFsss6œËåÊf†-;Ž †¬€££#[6’v½‰ÿ°¶¶fû‰6HÕÐä†vÞÕÕ• TÜ===5}®ï³½½Í]™à«q"èý677ËÚg©ªéî´‡#-£ûÌ¿«=Ë%ô5 s[1„ÖÙ§3AïùÛ[=ë÷V+++þ–)nÉb¨ÆÝT¼ïCïììØU÷%iÂà^„â’oÁ•©‹Î1•-?[•¿Mã)1×-ÄŸ‰MçDŸÔ­K[hSb›·bØŽ™`aÈ·oß0„x ¶¤…ßéééËËKÛ®3þV5f°Íxýúµ½Ø`ëÖ××ý,Ží Û«=$€}ª…ÎÆ‡a¶0¤fË2‰eÏið9l¤…ľL-&81%¾²%R„võðáC÷14!Þ3Þp½?Ìšö ¤Õ(½Ð¦nY ï»ÏB»•ö—,Bo ºÑ¿Î‡ö3²Õ1·.øu) cÑÝsh—¯íµEÙŠ´««¥øò勽®šT‚Ö5Ô3i!R^—1k=½gCÏ¡wvnnÎ^ÇŒ˽ðw{{ëžTù'3ÞF²nÆ;½à_ŸÒ/ÀàÑ–ºoeÞò^ðÅ£³è¢Lprr’mÖäÇÑ·k„hml»Ù¥¥%{í­þ+3d¡“ÃóêÕ+<øQ¨~{‰pjjêíÛ·ØQlü Âö‚·Ù•L0‘ÞÓÓãüéøÐÔ.//www3AWî_²=˜...ÎÏÏíýr§îMD. 'WIÊi’—Åöövœ×"Eê˜mµŸàWë…h|ìÏÌÌ í?­%~m¿ƒ}ÎD²Ýýöûžîçû<ýt?}ÊG}ä988888x^QÔ ppppèµµµÍÍÍ---|2 0 ¸¸˜‹#Fù5j”RBàg%888Ä ˆþƒÖ××·¶¶†(O”––VUU9zHŽâ¬]»vµ··øá‡ÙªSô0uêÔòòò¨Ÿ¯à(ÁÁ¡?5üرc'Ož ¤WVVzÖlL~ìõ‘E&HÄ Aƒ¦OŸ®tè Žúà€Z)–‚F5vìØaÆå¢Uù!°ÝD\ä玅G }ˆþǬ={ö455å¢òÌg`hØÖ­[S7Vr¸íŒ3ÎpþgŽúò©zC ãÆKwرcG]]]”¯é“¨ñu+âG }pÀ›o¾Y__Ÿçy˜´¦æ16oÞÉLQr8sÁÀQ‚ƒCÁ£¶¶>ˆPÔÂÓ¦M;vl’<Ä>ˆª…©`æÌ™cÆŒ‰ºÃQ‚ƒC£³³sëÖ­9ò¤‹ÒÒÒ9sæ 4(ñ'ëðáÃQ7°w8Vp”ààP¨@È¢wÇjsaÖ¬Y£G¶ …(bˆº‘ÁQ‚ƒCဠb+g¡ˆz ›7oމ“:ú3+8Jpp(0tvv"gÃÿÉ´Pu×®]1ogO0¬uCò G …$ì¦M›b5YÔW+œ~úéQ·"ßèwèàP¸hjjr|7ÔÕÕ<#їЇçŽÜA›qÁûï¿¿sçΨ[á P\\œ˜^YYÉçÈ‘#8xðàAƒEÝÒôà(ÁÁ!.xå•Wúöš÷~(aøðáUUU|=E݇ÑÙÙéø ï¿µÖ×X“'O5jFÔíêÎJppˆÛ¶m‹ºù@eeåôéÓãi48+ÁÁ!èÃëÝObp”àà ´´´D݇¼BÄ0vìØiÓ¦Åg*ÉQ‚ƒC,ÐÜÜu"ÀÁƒ>kÖ¬ü?f&8räHv)Áùâ Q·"Uô´:>ÄiÒªøzÕUW½øâ‹©ß´ÛôžZÈüÜsÏ­^½:Oo-{ÀJÈn…ÎJppˆâ`(ô DêÒ¥K÷ïßÏõ²eË®¼òJ¥?úè£=ö˜®/ºè¢›o¾9y=X!ãÆãBU©ˆø€”Ç|Èoø»å–[ÞyçÏßÙwÿý÷Ë€cãòË/—L§¸ ’òãÿØó7|Üwß}æ.·Þz«îeÒM›IT(e>²èNp”ü `ÉçG}ÔØØØÞÞNú‡~ØÖÖFâ  (ûF>nذÚ8räÈí>|ðAo¸áì†+VTUU-_¾œ¯J÷|† Ù^¡íÌ®;ÁQBøàƒ$Ê?üðïã!uñ'N´~Œ–ÎΓâD3]pèС\“¡©©©¥¥> 8rŸ<¿ŠÉI!?!â¹mpRŽ=ʽõâ>©‡RÜŒt.D!§ø2dˆ‚šÐÆÈ‘#ÇŒC/ç«£Š>ä`Ì ôhYW_}5YÌׇzˆ~ŽÔæóÆoDdýRUɘ ˆ#QŸ0 ïAwá+|@U—^z©¹)ô±øä“O"Êoºé&nÖO"CͳfÍzøá‡e[P 9a25 3â€!¸í¤¸±u ´ßQB–üEÂ"s‘¿ˆiÄ:r¼¸x¨÷±Ì-F"“ίø 'd¡ Ï·Ë|•²_äƒt¤6E¤°Î40lØ0Ivò‹-<ßPà“_‘æÜ ~¥x»ÁƒóI¢l .¨Šöð)Ú¨««ãÖÔ@Íä¡6ŠP÷šŸ÷aŸEª}·S(&Qe5e~%±™Àm2‹Ó\ýWF L‘¼ˆ`©ùh¾JÚ"v½{[ ê6RIŠ.Ï'2ÙÊ5™ÇC‡¢ª¬ã+c¸¡¡ Ôƒ\¦þÑ£Gµ·whþGö=˜:Å.$ŠTƒ¢ž‰œà†dQiº‰D9j’Éç‡>¨Pf¥H?tèµíÚµ‹ëßþö·´G\UQQ1eÊìîêêjÇ1ãüðáÃtȨ’èuôÀûî»/ë5K^´hª½I43<)N¦KtRõ$VR `ìg±¶þ»âÙ-I´E|#Te®‰Id¯Ë@")üÊ5œÎÏOYjà'ŠË2ðüN@ž?·#¡¬¬Œ²dà'Y¤S\½YíQbyy9 ㎔•Êϵ›©Ê4¤åù^ uñ–LX„g„±öîÝ«•Øéßþö·ùË_BQÿ=âŒ3Έº éaáÂ…è=[¶l©ñò¾qãÆL*¤ßêJ` ÑÓ±U9›6mJ·yT²víZF¨©D¦)ò9{¡–KEˆì¶¶ïë‰Ǭ%šáƒ’’2twù~é4¼e¤­¤¿?]t»IM%娱cÈ寯FÍþs! ²\#£ëëëÇfºIºü‘#GäK^ot© 6’qÀ§†YK@%Ü”l0üØ”¥s/.T9ùa)ÿY>4æE×Ó}¨6xþä’æ¬¸ýÎ;Ÿyæ Ž1bΜ9óçÏ5jTÔÿ˜Ã_Àÿ>cÆŒ;vDÝTqÛm·½óÎ;÷Þ{¯¦æ²°‚­×§ä5ÿ©§žBîïÞ½û‘GY¹råòå˯½öZêä'—-[–V”BºóÎ;—,Yb iËvT±téRÆþâÅ‹ z*)ô}Jè–”Ž„EjûÞã5nd1Ò1}âÄ sMøÐcPäñkÏŸ¡Ç ^QWW÷ñë+*Ú·o9)Ef}R§#ÉÿŒàf`“%OMOiU_©G¬€‡uÔM Q‰TÂW‰{©ÿ$ja’ h!™ùuìØ±ÏâŒá!Qj¢ † zàß~ûíuëÖQç¹çžû…/|ÁM+Åü§tÂ÷3w;OM¢ÙáLæ«™ÊG®Y³†ÎŒ^O:Šybq{wtOUûï¿ñ=oÞ<ä8œŸüqÌ\U¾jÕ*‰u»AF€™M²Eô3šèíªD ¥H¿æškHaøÀö´RÃ)Rû-|wÂôCÉeîææ-þƒÄ ú4öÿ+ÒÿÏ“?ò!w±&ޤþ{¾¦¯ ©í\SJŸŸÜÜEWÅ./Ϫ%ƒÄ7׈xÒ¡%2Ë-gƒÈwÍJiÖHŸ šÍ'œ¤gA¾PPö‡üäZéÄêµ”””üÝßý]·ƒÙ!ÿ8xð` ùG¯kºRGÿ¥IFd"Zr­Í‡çû~?^UÚµ L o¶¿oùï~÷;J-_¾<êÿ¶A«™£n…C?B_£éãGŽÑ‘„,WZ³ÈÀ¸‚íRÝVÕÓ-Ì5Ú÷Ë/¿¼ÿ~ÉnÝèÌ3ÏD¦¿öÚk ±cÇŽí۷ˇ8†¥¦Nú×ý×°ˆ–‘8p`ëÖ­”•ǘ"ãÇŸ;w.&ΟþôF¢DÇ6Ohi“bchjÈìÒ0ñ6ädÖWáW¿úÕ¼yóìX¹=9ê&8ÄZ¡ž-ô)J•ö}ðàA¤¿–™ "{F(± —²¨5Ù˜[¶lÙ»w¯çËztíSO=uâĉ£FÂP@¼nذbÛ¶m¬d7n&BMM–l3àiêæÍ›µž)ã>سgÏ»ï¾{èÐAˆ¡¥¥E®ýšœBÏ¡ÁÉ_]ZZzÎ9çìß¿ã€D8ÉóE<Ê~CCƒçï7¾ð i­‚~ûÛߪ8£¶¶VuN:µ¬¬ ëá‚ .øùÏ® Ø H×é’AZr €†q_}ð /$.¹ÀáÇ£n‚CÀQB¨±(ãÇG·¶¶fz•¡áfíàÁƒ/¿üò¾ðÕÐÖÖèz×®]“&Mjll¼çž{Î=÷\˜ÃóW+ÙSù©·-Üð\ ¹*J>|¸üÒìû£ý(ôÿå" +,¶C$PPý,V8påÊ•Q?Txh±é¾}ûtäYà']$_\”.%Ø?÷Á-êêê óçÏ_¼x±H»±±éüc{{û¡C‡thE§L™ò·û·cÆŒQ ðtrøðaíã&¸ð Ï?ÿ|¹ŒÞ}÷]{–ÆlcNýý$&¦hv ð¡ðÚ:!Î6n¶mÛÆ“òÈÙþKþ Þ|AœŸã-FUUU•Å ÛJhnn®¯¯G(›M$7¼4gì2xðàÓO?ýÔSOEt"÷wî܉@—”¤Â?ýéO(ø&LÀz 'òtÏž=˜( ˆ{,Ì*ÑÆ12`ñ ’ë,†—^z)ÄV‰$è).l· ©<‘ñ+؆ö½ï}/ÃÆ8$3RAvùÀ+ôG -1 ¤÷äHè•!¼4Å.ýœsÎyï½÷øü7òÍÒª7ß|S{Pö± øPWEEEyyyii)ÒûöíØ Lm@$Dçײ²2ÚP[{äÅ7*ÔDh¤ò€IžW~íò£U°Üé /¼IÛ’Ã9RAÖW„0%(ˆ)|dæ'Gk è°‚á®C ¨#GŽØ;! ‰I“&?ž R~ùË_655iM”*A¯®®†QÁ(ã›7o†?È`G×2ß‘.x@šðD:3ÎLѼmÛ¶Íž=;tå™ qéGæ(à‰£cÇŽÁ‰SF)šÞ'·õöŠ$Ùt²1JôöíÛ§0¢víC Ës ˆ¤J“Ná1€/tk»Eê³F— d@σñP¿ÿýï‡nŒƒƒC†Ðá?ÙE¡R³®®îèÑ£‰GQ§¸ü4“µF‰H u—)z°3A·&Eê³Fö£•t!àOÆJP ‡¬#°\ÂÁ!³ä²‚B¥?Ðc`fYœ5Jå.iIÛ^o”VDîÐHñy[ ÿû¿ÿ›õV9x¾ub Èzµ…J ˜­­mIfz ™¬5Ê)n ³ówkÖd~£ 8PG¶ÙéO>ùdvߌƒƒC*˜>}z.ª-HJhoo÷)¡5uÇr*~ÚL¤gç ²‚Ä»':Òr¤4H|Ø*¹ßG„OêàÐQê#5$%œk”V…&"Þ€´“Îà׿þuº sèÙ ‚ïЗ;Á+DJÐYif¡§9'Ù>09paN1óˆ!ùTR·žêÄšMzÀ I¼{bNû"Iä¾^ÕÿÄ»{Ö‚¨äÅ“ß&ÀVPP<;ýøñãï½÷^Îþp‡¿lΜ9¹«¿ð¶ª!.›››[[[Oúø¨ëœaÒU:þEÇÂp¡H¢ùçhš£ÄH×Ô‡Í!k:6ûCg©UE"¢ÐÆ)+´$}ÙäüÈ?ÓMwÔË܈ åW‘S"Ug[ꈓSwWN5Oí´eºN8°Û©gWåæüê×j›V‹R•uw½RmC39e~ñ•D­¦›êB⑯¾úê§>õ©¨»FŸBÀïà Lœ81ëÛÓl^·kll¬¯¯‡šššS:RæHèsaH,"×HÔ6`íãš  *ëui֢ķž»¨N„ Îì”×!Ƥ“¹©»›£fT¿øCL °q\“G aŽ´ÔMÅvN…ŽàSBYí¤,÷5ÜÖÖÖQñ).ѯ}P„kÖö»n Nrª‹›;6ŒÚcÚ,:Ôf:òóU¯ÂÔ¹~ýú¯~õ«Qw>…#FD݇ء¸¸¸¦¦&§·(0J@JïÝ»÷ðáÃ---P‚¸—‹üBTIÞÙʵ¸AÂ]¿ê\Im–ìö|VàZ$¯¥}K}–`5 $1­_¡(ãÕ¾ïud)JPNîNN£ïs ¯ã-U¿ª•Ä'§¸ÇÔ¨Ü"ZvEcdè…ˆ$ÊižxKÊ…™X“|—Å vRÖ6¹DW^×$’"2iéQ€Ü¢£¬#à°qp`Ðqƹ¾K!Q‚©®®þ­·Þ:xð ø@½ÎX6"LJ´Ä·¦;qD13ßâù2NBD>U•±6¨IªDIUåä'éÎù‡SJç(×:Qkæ[ÄR*.DíÔA%%%Ðb)Ï䧨¨”’ü%Ev‰D?)ZNJ bùÛ)ÕéÃÌ QDæ‹fôÈf¾H(n Ãa²HÄB䪗ïeee¼y½mÛ½ ¥[GÝGúÜËt`ÆŒÙ=-§[% wÖ¯_¿mÛ¶cÇŽ!˜bš¸7“àž/¼<ë¸yMÖKæj:EU™i"iܵ"e–nÆä—`Õ]d1(3×'Nœaa¦ÚÀä×µq477›¹)¯ë 5%ª%^—­£ªdʘ;ªI²it¢§ña^i’*1µ©*ý¤Ù*¼LÍš|£ êÅ*î·ŽÖÑÛ†KlôÛo¿íBàe(:—ÛÁaŒ<ܨ`( øæ›oþßÿýß¡C‡ „—䯙Á>+ÙgΧ´å£d«×%7M _3ë"Aifð5¥cê4k‡D6¦6ï“ aj6sS¦N3ûdO ©6ã¶=ɦý’þòXØ7Ò{0óEFÊ‹ŒÍdg¶½îbJS³®L¾ê¤ ‚,ae;ÀÔ+¯¼â(!»¨¬¬t”ààù.L„üÜ«`(áÕW_}úé§a‰æd$žD öj #ø´Ǥk6FZBÖóO¾4깦VD Êi¤­ì#—Í켡µAyT§î"ùkôtC*ÒÒÒbìµÙHpåáW³ÈÜNsbèfºÌëšú÷ºÈÌ4Õf&M1y]|¦w¢‰2ÃXšì"…[ÈçI"Ø%°‚yŸp_ûÚ×¢î&} P‚;XÍÑ7oÞ¼\„3ê…A HŸçž{î7Þhllì)Tƒ¦;¤áÚîe bÉtóZO±àYîS£¶{]¼¢¨«ûË‘×Ô+ä"€{Fyyyb·wè'` bäÁ¥l£(aïÞ½Ï>ûl``H`UøàVø³šHËí%Ô|ZwïùssfªD[”¨©Í™5E¢Môk©¾æ[¤ïsS„c‘­¢ˆ™ÀaHR›é& h SÙ4ÆIn¨E+Ž$ÁUJ&_i§fÏÔ6­\i§‚ç¯\R“DäÔÒR Õò¤üª—02€ÞCii)y´¬‹[ðªu(·;vì‰'vïÞmŸùöÛo;JÈ.&L˜°mÛ¶¨[á"á/þ”€8ûùÏþÎ;ï˜ù"‰ªáÇ#¡O|JÒ!³$è½.é†ÌBÉBœ;vŒ<:jA>’I§¸=&;ýèÑ£F#¦8õP­¸ Š jIÔzSíá’¥B)š„¤&‘œ$666êØêá)(‚P&ƒâ‰r-Qîu-¢ÍèׂêÔÒR(‡Ê5ÅOÛthšÄçñãÇõ캣V‘Šä´p–ªxcÔƒ 'E§C“_×T.æ“™"+A¼8räHE$±ªªª²²’ücÆŒ‘­0gÎîøÜsÏ'3ÂëüóϺËô)Œ5*°Ä¡?€á™Oÿ¸S‘#G^}õUsTŽ›H%Ä“Q]¥nKšˆˆf¤°vð~%èuÞ½&@4-£Yu©Ãä”4W ¯š¬×¼ŠÔjÒ¥JkÎJj»d¨$»\d“n®¥œâj’q!À(šÏÑ£éîrhÆF[êhžl -ûÑv6²iÙ¨Ö‰ªf{š¶/ÈŒ0ËsEuš¹ÈŽÑWÍ5iÊìNPUÆØâþXÁ6Åú…`’Žo/" „Ÿ³Ó“gìe<žåsTe¶,$Öïu-|JþVCÂösxé„´ë ¦yúj|‰ <¦)¥)¯@…b8JñòÏ:ë,쯫«[½zõK/½dîø‡?ü!³?Ü!̸×^{-êV8äÐdŸý=¶!ê— õõõüãmFKE]ª®®>õÔS± PW5i“J=öª›^sv{Ýk¢‘ï©?½Ø)•ƧÞþäí±iÏûäŽÄ"f=+¬ÜØØxìØ1…åЯ0æ­æš·h2ëÈi$d‡ø@“EÑòsJxýõ×ß{ï=³öq¼ªª*cäW¯t’ ÝþÔÓnOõ¤rx§QÆS¬3õ ©·?Ý"Š«ªy9þ‘}ûö™Ÿ-ZTYY™î]ÒBîÎKqˆY555çœsNþÉÝ4&êôdÓÎ;[ZZ<_Q‚pàÀôéÓõu̘1жöº7s‡3f8J(h ÚN:•Ϩ’ ±£¿Aûf7&l‘ôš!ÏŽåt›—J†ÛŸ¡‰`2ð¿>|ج\Ò†AR<ÿ_K·©)&®©©qkº Ú“Té£P"VÅŽ̺RÊ¢=bÅ‘QyBäO,ÎDH÷5fk­Q·hjj¢‹—²ÖƒéúرcéÞ×!uLœ8êmmmº!Ÿ€6«êº¤¤鯭þñœJŽØQ‚ÂEáä´¥64u„P“›=åÏ‘c9ÜSgv4›gÿj¯‡qǫ劋ùÒK/¹ñÿì³ÏŽºYCLW!€Ð†BdkŸ È™¼žtM„ùSw,§u»3$"§³Fž¯™ °‚==ê¢d猅Y³fEÝ ‡¿ -‹)%xþ„µ‚•š¢^ú^„äȧ‰`¢^{iÎê„p,çbù©¶¶¶ææf»HO›ErÑ£GÏœ93êV8| þ‹>¶e$^”`¤ŒÂ*ö'Ü`NK—²(ӥдÚ9Ò²!t&¨¢ˆ³º~þùç£~š¾¼Äëy;ÿ2oˆ%%zhkk«ÎSŠ‚}Ú™s±ÐÈŽø–JU:–sAi!fz½K ¸"ŠÛ)UUUffÏ!?ÀPp¬-*++ûžÛ,^”`€‰%è9çOòÁ¢'9›ÓË!Úéå~ÖÈë:zÚ¾泩äå—_N·áàX!B 0ÀlÍéKˆ%Ø:G”àuúÛÙÙigN…rä.E˜PØ^š&BÖ÷š…Cb:Ä4àK0ž‹i‘O8Vˆ Ó¦Më{&‚+J°g´uù£®ÃŠù ÌKd8å’Çr*G#D¸!»³F‚9¼Z°÷–»Gy†c…ü³xìØ±Q·"'ˆ%|¢Y]ÍëŒ3{ª—>Hw¾%D‹ÐÅSoR~ !g¿±#F÷rÀžsÈ`…¾ççŒ-èü}xpŒ(Á>ÿKÇ{þÛ%ôtŠY"RÙÏœb¢—qÜÓLBa§ûó;O¾„À9<ö¼Ÿ k‘ ´žsÎ9ñœÊдQ·"k€úÒ㣳£566jâh)ª‘Má&:’ÿšÄ‹•íiù‰sbÖ¨§V½q0ƒ%D‚âââÏ~ö³£GŽº!Ÿ@MMÍç>÷¹yóæEÝìêÛÎ.bD ¶xâZ4 ¹#…9ò2ö*{iš9Š{Z(Žåžn„è p Ïh·é<ÌQÁrúé§Ÿ}öÙqØ?E.\HÇøýïßÐÐж×Ñó§M›u+r‹Q‚­i655)þ>” b1Q“â¯é¹óÒŒ{[!´K†t3³' ‰ìÍk›6mJ«ñÙ…¢îÌž=;ªy$úw?í´Ó^}õÕ;vÐaÞ|óÍaÆÅçì°ÐÙÈ}xÊHˆKØ»€ôAâÈK©ô|d¾ð4‹ RDÞL„üDKÚÚÚg‡Óz-y€b2×ÖÖ"Žó&OçÃL˜0áwÞ œî°yófDjkk«â¨ú xñ±œöë>~ü¸éÄò%h·ZòJòéEH±1±=-'\JD÷ DBå1í%a6lÈz{ÂVøÜç>‡zžk‹ÓË`îܹ /½ôRâi?Œ5ÌGZRpKfûxñ±N9å¯[¾å¿´²¨¨×x Ù]‚™E/Bˆâé"oÛ¹O›Ì¶/!þ1úe5>Öûöí;v옽º/óÊG5yò䦦¦]»v%?ËA¬€xEÈÊY@ýмøP‚dŸþzôèQÓk‘;2ì%I‰!säEð>I iÙìyGº”)°oii±IZKÌ×Bíý ååå(òž?Ü0Ä¡š.ªÃ‡¯¨¨ÐùÛõõõ›7oNq?ŠXaÆŒ3gÎ|óÍ7£~%½`ìØ±ýmÃG\(Á–P|ð±è@í>z-žÅs2ô"ôd"„x© ×§#ôôl½)`Æ9+!æ@¦ËÓàu-«­­åU,±“óÏŽ9R×\”––ê¯_¼xñ’%KBxŒåm¦àÙgŸ½uëÖxîmÔ~´¾½Þ´[Ä…ìõ*SŒP.‚ÿfÈ!É ·,†¯È–!±añq,gØLé@Š91Û?pà@uuuº sÈ?äÒgZò}çΙÜS²®®VHtDGzøÜ¹sã¹ï/׈ãÙÉ“'uÄæŸ›øÉI‰D„ÛˆS/‚ÊJÈ›c9C­ùƒl¶ã? ŒŸxª~±šß+¯¼‚±rúé§Çd²^~—yóæõO>ðâI HœÆÆF#q­È—žb&BuOÈç^“!ñô´\˜^n˽fHŒ„ʰB<‹C?„&‘,Xy 9³:+&ü â2qd£££Ãvˆzú“²¸WÙË’!âl"ôZ ÿNr翃CìÝ»÷ý÷ߟ9sæÄ‰ÅynÀèÑ£g̘Ño-±ÆÈ{š¥­­Íˆ`Ò‘5C† éVâd=|EŽö"äÈDè–¨ráXNL:thÀ²¡Fø¤I“B<”CÿÝiÛ¶måéÓ§>|ÿþýðDvØaÐQãÿ#&ˆ#%N좗ðkâ"Ôp| ÝæÏð #X¤ûÒ– ƒšJG°€Ä`ß¾}!šçÐÏÑÙÙ 1Ð0,XpìØ±·ß~;~)¤Ê¸qã¸Kž#ê± „Äж砵µ•¯‰qvÃWô:›”–!„‰•Y£ü˜ rg34¯(àNÏ[‡¾:Ïn¨ðsçÎ%å°äûàRLP\\üÓáö*çÈ«ì}Ò‹b/BLÖž¦^­NG¸—+**Ò2bˆXPBÀÄ+--MÜeò„ÓvÓ ‚í¥éU‡¼mOË–cY2dHâA’úU888ı „0’ÈÖ"T/…9“,FDS¢E,(!pŒ#ämáiŠ&‚²…3òæE}¯ä¶··–1Â~ίààPˆˆ%ÄGà0ÅÊN¾e¬'ÑÚ«œnãcëEèu«]ˆ]ÐðAâ2°–––ÍsppˆbA Ø3æš¶N¥Hbb¯rê{Ól!Â=w^„5ÀÙ­­­"¯¬¬ L÷eØ0‡ü#”Jˆ;EÑ,’œ¢Ó“¬ áUÎ|oZayB˜^‡ 6ÌM98:bA Ée/g4Ò'Ý eyó*§»?+V^„pI6lX UE¨ÎJpp(DÄ1ìê'W2Záte3­'ùžD¸g׫œJþÄ»Çċɽ`èãÇ2þ žÎÊvèó8îcܸqö °Ie”¡WÙn•Ê‹­¦™[¡'v(ØÖÖ6zôè466Ú_ÿáêw(t<õÔS=öØ#i%<ýôÓPÈwÜQ]]mÿ¤˜ãÎ;ï„Zž|òɨŸ¦"Ž”€¬±5P¾ŽzO7–Qò"á¼ÊéîM a"„ö"äÔ±ìù瓨m6+`:Ø9/Á¡[Œ7ÎþZQQ‘8D"ŸHó“ ¥€M›6­[·nÿþýÚ2G,ÜË`Øå¤{â(DìŠÌM„LžæSÙÏÝBXó ­­­@ò‰#w¦•Cî°qãF/]²‚8Z ؉öäŒ ö¤nKe;† O½°^„\›žïì LynªÃ'aOýg½NDÄ5×\õ#öMÄ‘ŠŠŠl›@| ¸›!–fÞÎØáEÈÑ®‚žšš•<É›TZZê¯ û„•päÈ‘Àžópwqè¸ä’K4ÿ#lݺuË–-™×Y]]=oÞ¼Àr&‡,"Ž”€j¦Ðʇ 2xð`} Ë([2™ï^¼:þ£ööŽââb“à7qÔϱxñbÛIðè£fN :r8Ž[;8¶YqØÒlg±WÙðA®½Ê©ŸÎ–J³Slj†y’¿1Ï„ÚÔÔ8/!@™î‡BD)Á6 ?ôÑÓ/T,£Ô7¦y={•SAhÿp8]>?&‚ç[eee:t¨ýÕ­8rp(DÄ‘lƒ@‡çØsG6’óA7"D¾7-+¥2÷"p6¦[ ¶Ô'âb‹8úìŽ\Á ‰§û†;T9Ü*£B<{h!\†p§ýÀÙMMMžà_³³9_B¿Å•>zM¬©©Y¿~}Š5$Éì]ÄqÜÚ(­­­ðAâDD¸rR\eäeìUg"„Óµsj"$6©½½C!pø]`«šó%88"âH •••æÉ¢Ø ­3ùªÓl­2ò2ð*‡xð»²3ÉZjkÏ~F»iÓ§³ q·ÉRTT4dÈ;1ܪSûðÎ^ÛÐSìT.â©K¡ÛÊù/'XpX0vìØpwtppˆq¤$£™”P$TÅ´PJ¸U§iMÎUŽÖ«+/‚ÐÞÞžè×éèè°S q¤„ÒÒRs­E¨„Ð!Vz¡båóM/gá+²Þ$Ï?B'p‚…޵°ó¸‰#‡BDÇíСCÍÖ9´îÈë-ÖiB꫌2 oçå׫œJ«Â1MòlZ„š|Å‘s/;8"âH p€äNך¼îu)Q·?…Û˜–b¡½ÊùÜ›–z«zú koo·í€Ä3Ž\à‡BD)aÈÁÆ—€`Búttt qÂÍ ¥~bZV6"äÍDHÅÉÄ‹ä•òw–çò7Ù_'L˜â¡¢E)aðà!ŽZwÔSþ^ù Ed²ÊÈË»W9§Ñ§“W>xð`þ›´ ÀÎãZ88"âH ö w]œ™Ì™oTö2^ezÊ(wîráE_k?³âV98"âB dÏæk|º'ç„[ušÉ*£X™™xz­¼½½½±±1-ÀνìàPˆˆ %V4šG ƒÚ“#!ÄÉ9‰HrbZNWåΫìeæEHÅEQZZ°Ûìæ`Á‚龇ÈJ°“ˆ³šE‘Pœ8Y‘Ü…óUF™Ì|óZ†­6lXKKK€;îŸÐ pppˆq¡;hZ@÷2d¬sÉc_‡p!äy•QOí¿‰àùq u¨‘Iá’H÷%888Ä q¡ä¾õí#Û&@ú nl”Ê…«NÃMþ„{Þìî`èµI™/<µÑÚÚš¸ÄÈDñ,Šupp(,Ä…laT\\b3„¤}ürŽV†[e”Åц¯H½,ÙOU³cÙG±;88 âB G5ò¨¤¤Ä,{Ø“3>HE•¶Wzy\e”»Cr¼¼˜žТ½½[Á¤À¶•%88"âB È—@ðjû·~MådÍ´\Êá\^ØUF^áŒRYxÚDH«,|ÐÙÙi¶ÜÐÐàÜË}q¡„aÆ92xðಲ2íuR¢ J‘Ä¥œOBèÅBùŸ2ʺ‰@…|þv¢}#³†ØÁÁ¡°J€ÌÌCII ”`T~9@YÙ•f„WhBþ§ŒRÉ“‚?@ PØŸ\,àààP0ˆ %´¶¶šu¨ÈwÅ52_µa­§²!\Ê¡Wx±œ2òòh"xþâ¢ææfÛŸÜÚú‰m îH5‡E\ÑŒ5ÊøQBÍ<’,EBí¶`ê.eÏ’}¡7*G2eùÞ´ø;°äì3sNžü ô›qppˆâb%™¢€ùèÄÝË^(—²—Y¬ÓÐ3qü†Ë“Žiœ6ÿŽÍvNç^vp(PÄ…P¢MÊСCÅÚ”X‡*¤ëRÎÐ…àå`Ê(+^åL"ž†Þ1×ÔÔdßÂ6eÜ>5‡ÂE\(¡¸¸Øhš¶ çóäÉ“ˆÔÀ²÷p.åл¼Ä2Je:(×^å&‚ç;~´Ù¤Ô××Û™Ï<óÌЭrppˆq¡Ïg]`”••É,Ð Ž‚9õ³Ò<Ë¥zBèÊ¡ODðâäU€—_UUeÛm'Nœ°ï^RR®f‡h#JÀJ,“¨Ò¾>µÕ>’%Ä#¯»ã3Óª!†SFy[xÈŒÄtSS“í êÖñãààĈZ[[<_¦ :T1-´/Áž£H7ðu`Õià×TÚ…ë)£HLÏÿ Ž?nÇ37~ÏÕîH5‡EŒ(ÁvQ¢‡ê¤ä ¨¥¥E¾„t——²Ø%Ÿ.„8Oeb"x~(ìOÛ‘±ùÉM98(bD Æ— +AËÞ%Ê5}n‰Q&.å>9e”â-’ß(°™ÜÎÆOsæÌɤyQ!F”€Ð×Ä‘çGD°ƒ¡4ÈD¾ËÜ¥œ">êBˆg Í1Ÿ2duÙQ+l+!ÜÂÁÁ¡€£Ñ‹è7Á5ehîH¾Ê´–%Ù¥œz%ù‰*⦑,<µ¡eÁöAxv¸çKpp(\ĈFމ¬1‹Ž´=M¾„ööö‚,“]i¡WzŮț‰àùGx·¶ÃÀ>;m̘1™ßÅÁÁ!ÿˆ% JŽ;&ѦU§2øÔ×pKŒ Å…¢þž·)£$uò§ØÕ655™_‰ààP¸ˆÑèE˜jy; _‚(!q±PO°ù ô£L\©¨ùIÊf%OòGËJÎÎÎζ¶¶ŽŽ-À¶3 RyíãÆË¤‘ýï¾û®=Ø«c‚mÛ¶EÝ„´QUUUYYu+þ‚Q‚9#Áóç|Š‹‹axB±²S©!àR'CóA’U§9]e”Ï)#Sœm‚c·¶¶Ú¾·O--À÷ßÿã?^[[u[ §Ÿ~zÔM Xá¼óλôÒKùŒ–!bD r&Ã0Á°aÃt3ÒU´×HjûÀ µÂËxWOmK^0SFÙÍ ”––šàØ Fa„Üù9)bíÚµ×_½c@7Xëƒë)S¦<ñÄsçΤ%1ò%€ºººcÇŽyþVµŠŠŠAƒiâ¨W+!+öA$.åód¨ã‡>½§[ÀÜmmmÆÐÜÜbSÂÂ… ³x¯>‰Í›7æ3Ÿ¹ì²Ë8$Ãñ3>"éñ¢Œ„Wgg'šfYY™ì¡“äTµ@£ü»”3t!Äj•Q*uBÍÍÍp¶¾rm(¶Èp]ŸÇÕW_Íh‡¢nˆC¬A©ªªúá˜çûÆ‹(H>KKKG­sZZZZàƒ$b1+KŒ"q!ÄmÊ(u”——› ¢ÆÆF›ÆŸõÛõ @¥Aþ¹CáâïÿþïóéÉ% ¼t¦fQQј1c0d(ÞížØ¬D1ò2p){™Måa•QÖM0tèÐêêjó`çÊÕÌ_PRRâ(¡[ð–&L˜àŒ‡tñøãÏž=;o¬/J1bO®%F§žzêðáÃ%wzÚ„œy#/3™Ú>Hñ¾Nee¯r"Š‹‹ùkÌW³›ÄsËz½úoþæoœçÀ!Ð',XŸ{Å‹ dB5jìØ±HDggggcc£Í“‰[ÂIöL\ÊvDèt‘Ÿ)£,.<5Ànƒ§gÍšenqðàA{õpUUUÖoZè¸ì²ËÕQ·Â¡€}yõÕWçáFñ¢„{KK³NÜ„ &Ož)­XÕEbü;“(¹irzݦ™q€Ú£›"û©Hùõi~RŠ®ÕTÓ${¡TÀâ1a½MãÍ0;§™7 ìî6õ«”^¦ydS§]Ê~Ló«Âò9qâÄY³faÃ\Ço½õÖž={ÌWxúŒ3ΈºÅ7ÜpCÔMp胸þúëŸxâ‰U/J@b?~¼®®®¦¦Æœ» %ˆôéè訨¨€$¯V Ò Ar¡Éê”f…HjmmmkkÓÐ ŽRÚ­š)N‘!C†477cŽÉMU:Äœ4†D¾=z”lǧu’HÕI:ŸÔ * ZšJÜ{Q\– ŠP\;ò¸¦BîEnÄcòt&]gÉ‘“O2ÈÇ®â2 øàdb‘:±³yÈ;„ÐÞÞL3fŒ~•ýÁ½•ÅÅCQ¯%)‚œE5ÖT¢Ÿ¯Z’OcથÚÀi9õ«%´–DÄ+‰ä¡$"sGŽI yú<&5ˆÏ¸ˆlê$'ùaŠk—OÁ…N1Sj8tè`yùÇ¿±±‘­é¸&'ùu î®‚|ÒNÞ•s;‘"HƒU–§#é”â%p#žzÊ”ÉÃË|$þY;vìØºu«m-¹h68䈬wß}wÊ”)¹¨<^” 3Ô4»b§#…çÎûÆo(òk¤dºršÝË×) šà–"QÙü¹.NÑ-DŠû¯é—>ÆÉ¢¢A”-™iM­(þ’v$˜©$jÓ4:UÉâ×óª•ÿƒJt®‰Š,Í-¸@|KL“Ê¡8ð„1;[”JøJ)Is¤69µ<F>¼‚§3´( _7:|ø0”@fc µµµ~ðÁŸD±f)¥}ãÜ‹k… œžþ)2?ôÐCƱ¬wË]\Tƒ»ï¾;ê&8ôYÜÿýßûÞ÷rQs¼(á…”A jÚÄþ©¦¦9…¢ =ÈV¹`ç±AÚ«ã·ÔšÀÎ^×<’òø¥zjšS Th·ÁÄn=_1$Ú¿¿º™4 4ÒLËØ'Y&®>qâD]`Çdëo‚¨ž}öÙmÛ¶LÞêÌ™3³u—BGN­û$Pä}³—0§8óÌ3í}ìÑbÅŠy¾ãöíÛ|æÿaýë_ç¨æØQZ³öÇ~"EóèÚ(¶Í>êêê¢nr_ÂÅL©Ù`<õÔS#ÀäYqV‚AþÃW|ùË_þéOÊ:zôhÔO®¼òÊüß³eë•W^¹ð óœ.w›áãE ž¯§£ƒ6‚uvvnݺÕ>à×!ؽ{7|€âo Ì‚]»výä'?yï½÷™e´¥xþCvÁôðÃÏ›7綾^ÊE‡ä=z4êé×¾ö5“äŽ~bG r™?~¼¼¼\)h=›6mr=ðÚ± ÆŒ1@Ìè&Ï<ó )æ”M-vŠº½qAž#Áü#;vìˆú¹û)à,³5kÖ ©ó¼Dë³^mì6AvŒðúë¯;>ˆ‡¦Ó¿ñÆtúÍ›7CØ Zã«sR£nl,˜UË)V¬XQQQÁõC÷k £O<ñDÞæNwîÜ™‹jcG }ô‘vhPAZRé-¶oß~ÖYgíڵ˅m :>7n\Ô-íwX¹re$N‡TµµµÿöoÿuC2Bì(AçújÝ‘/GÝ"‡!—~iiiKKK⯃6QFò‰)S¦ð¿83:&@^]zé¥Q·"#ÄŽ†Në­·Þyç-–ºEö†B·ÒG»¸=—Ì;·[’vˆ ©S§FÝŠŒ;J(**ÂJ@î :tàÀ AáœÏ?ƒˆñL©…àq***CI›e‹ Ø'¡:Äü}ˆB þÁ_|ñšk®H9ï¼ó “û￟œÍÍÍèdHjº.?­]»ö’K.™6mž{î¹’’¾úõlÚ´‰ñÅO܈ڨ–Þ»`Áº%ý“¯üºhÑ"» ¥Èy×]wÝrË-ŒYÅáà¦Òih€jÛâCE·¶uGÓ<îRUUE=»wï¾øâ‹©–çÕÒ¬ŽŽŽ3Ï<óÈ‘#vH· 5nþüù¤Ó~5 ê¿.ˆ•`ÄJºÓüsFß‘,^µj•z¹çkôKúô3Ï<ƒAÊrôulgú+e¹ÆœL4`5+E6U¥©OrÒ¸6¿&.Dýa2¢Œn®òAÕ”B ‰·¦©J4ÍÓteÉOŠF¦5Üzë­|j6@ ¡¶ÙÅ›ÑS“h:0N=õÔñãÇ1P¨;ÅÚsË W_}µ&zŠQsýõ×Ka¢—"%”1‘ÁšœùÖ·¾…h&¥0[---X¢¶íK7CÍG€ÒÉéù½šNH‘ï~÷»Ô³téRz_×­[g·Gv ;Ãóž{îQ¢,þ 6p@çF4†–lð±dÉ»ëê'Ï—ì4† yÜtÍš5üD“ô€tx ª£xÂâ (üJÍš.£Â›nºIÍ{衇¢þÓòŠØQ€æLwùŠz3¶°çw)úú8ô3QƒÁó¥$‚‹Ð è£ô›={öÐoè `»(Kï?qâ#GßB·’úƒ>E§§?q;~ÓHý¹ñÆ1M4UwGIÑu#R¤›PU`R‹Ÿ$ôiƒnJ›I¡,w¤ÁèVôr©™quî¹çê|Ò6º8?É*gLêñ)¥;r¯tg´ø_(8zôhZ¢ˆßŠñBºB½FÝ}z]W–cM3EôHS;±ãûÉ'Ÿ¤”:*ÿ»Œ “GÏOÉáW:œ²wß}·Ž¡+ÞvÛm SŠ.Jf¨‚@âZªŒÚùˆªB¸+Q)ük#—gY±b­å¦hcwÜqÇW\A~šÊ­õìÔ€p0 `80H)ÂÓñ«!€|D¬ šõŸ–WÄŽN;í4"¢‚Rö©æˆ<¿7#‹ép2™ùé©t þûI“&ÑÕ§éš¶ÇŒîH§Düy>ë`–b’£@6¡¬¤öã?nW.Ëàßø†º¯Ñ€<Ž‹ûÒ/¥Ý€9sæÐÿèÁ4CŒeƒGà÷Ýwß•W^IÇå¦tk®yFòóÉ|Ú‘¿¸/ &?5c˜KeóüA{óÍ7+§)âÃ?4‡!t*ª‚xóN¸:ÄfŒx~ÏAƒ‘ј_ã‚Ü^íºlÙ²n'')ü„šB¥‡`+ÐE}|%Q¦ƒÉŒ×š»Î’Jg “Q·ÀÖïö¹Ž92{öl»Ù·ß~;Ê~’YR‰L© FD?<*v”àYçD¦[Pú ¤0_&d^¾|9¥HÄÎð|MEEd»_sÍ5tE^¶µ©V61eM "•¿[IÍã0"$Óir`Ë–-Ʋñº¸M¿ê‚— »¬jŠ'*Žý ±£s¶p¸˜š’æšôºüiž¯%)¥žÄ¤¯c*ÚÚº½ Ñ?þ|†ý†ôÄOЇèsôt ƒ¢¹=´ {DhÒU>€$`t v¯½öÚ .¸ÜÖ¾uVÁ²É°téRÄ7Š9o¸á¾2ÄÌ: ìoZbÛ%ö‚(åüóÏ¿å–[¦)T‚ndÛÜÙÈÆíPƒe²KäœÐ®~5¯}ŽÑÁQâÐRÔÿOĈ݊£¢¢"ä‹¶&„(N¯åï·Ï¡ëÛ {·PÏX½z5=ÃóGˆV.y¾.U{¯Ï—Ît5)>Ô‰¥Ë\‹Ìó…2#Áž3õ|®zì±Ç”H~Ïç¡ÿøÿЯù +W®L¤r¢L=ðÀjCN®¥=1lîºë.î®jÍA"¼ Œ ¹ÈÏ€É|<ÝÖÖ wttèä8R¸Ö9Ùê9E¢à tú_é`š»W"½Åßëò~F"Ûóµ ŒéÚÒ¢PƒøjŒÑÀW°È‡¢ù%.qTr÷ÝwS¿QíÁ³Ï>KýRàäàR‘ÁM{H1<ßúÑÄ”œ¤ÐHø‰¯F{£ Œ™&¦ yjjÐöœ·…ƒ¯¾ú*òT"Éâh*ùÀÂMþoÓÝû Ÿ™U›œ¦ÒïMñ|‹•ždêQÇ2í¯vY“È'J–:œùµ•UÈÔ`ÚfÆ^â]LÏ6 !—xw»OÇW <`¯àµüáؼy3¯Ú®¯¯‡  „ÆÆFþ/®¿üå/ˆ°ßbÛ¶m§Ÿ~zn„€ýšè*hH¹=>ú(:Óúõë£nZòsjÈo¼‘‹©Ú8Z :99ôò•Ä…ü¶úc$l·vƒ-mõ$1¿Í¯Ù@Y“h†n¢ ¶k0÷ ÔcçѵÝ*Õ™xw»T’LZuÊ-ZZZ´#A‡Në¬é¸©é"v”àùrGÙG݇ JKKù_øwàønÀD€  ð &DÝ@‡¾€U«VRÌìC®;J455õÉEî(æ‰ÆoA˜Ã&ÿ  gò!CZ[[͆ó¼…@pèÛH´àmëÖ!§ˆÝŠ#ÏŸwÔâ D?†BQQPB{{;†‚L7käàÐ;+á‚”AýtG1V¦6d1(QŽwÄf¡ ØÞÞX øñÜÑѱhÑ"c^(⤠IÛ´ˆcË–-ÚEaj0Q•„óÎ;ïÀZüÝß;J@â¼þúë !N¯µccyþ¸ÌWâG Gá\ì¨yZ¸mwèµk×ÒõµZŽo “Sé_|q¸­jcƌٳgÏÞ½{[ZZÄ‚¿Éø–¡P0{æ…T(Nxçw>øàƒ1 '†Û¸qã¦M›³ÏóÇI_5k²~øažBûÝï~†@î›aòôÓOÛ«¶øiõêÕ÷Ýw_?<86v” èih!¶’›X©PÂ7¾ñyóæÅpõ$¼ø­o}ë®»îºþúëNR‰<ðŸ¦C#ôIÑ`ؾ}{`$(r™©³¦¦fÙ²e+W®¼ãŽ;B4 ‰pèÐ!êD)ÃbøÈ‚³ ô´ŒƒÊÊÊY³fEÈÚꜸE)‰ðÌ3Ï(|…Yn®˜4/¾ø¢Y™Mq Šý><Ÿ6ì— 81æë7Þxë­·jPTO b:e?dÈÅ^õ]H±ÓÃöÖ¶ü£§¸0ÁW¾ò…0±_Ô˽.[Áó­fÀR»:Mz¶Þ p Ì‘<FOhnnf8µ¶¶Ê·¬ÃÔ¼®ÝæùYŽíuè$5Ôd™¤öaSæZk»uŒ’W‘½®@ô¶ŠMþÚÚZ…Q²ë7ñ»èB¦¸×Z( ©Â÷’¨hʃ³nݺÄS­°]´M!ü4(tk”$›OÈ@§DØñ‰»hgèX¶lÙŠ+èWt3EÄ£KÉÌ©’øøã#; 1JñõÙgŸõ¬vwß}÷Í7ߌ6ÑÐBÄ0C†üwÜq‡ô!…áZá62Á‹žxâ ò3<×®]Kh5ØÑ5¼®MþF¦“A±ß©Sœ(¨À|*EZ¿l¶ñÝ-ÐäBœ)R舕àù²F'0‡+n´ú“d½B0"%é‚h÷×^{­bh›€©hߨè,¨'&v#"â50¨EF¥™0)Òå©ü _øãõDcî¡—3Øè‚ßøÆ7d5å+_Q´ÎùážÄt@•®Ôžî«kŽH¯=?¤ŽKd0S[GÁgl óÅÄ÷öº˜æÀé®õnjjÒa,*1› 7kT@ÄQ7 ŸHab˜ yÐíEö¼Nîóºâ‰š˜ èÝãq0‘6ì³-©‡^}õUÏ×f”˜ 8I¬ŽÀ쨎C`è™9"ú?_y,.Ñd‘™2ç)"¬‚&ZâàôBGì(á¢Mjé¡c`÷u{Ý‚.ÈßÏÿÝï~Wseµ°G¡áMè`u/[‹—H ôH;P„~‚3¸£,ýTIôt;«çûæ¹QÙ¸Ðè•ÓL~&xÕV ìðŒÆt(ÆàY´= h¹‘s/÷%ȃÅ1ë L7V‡GóШA% ±WqþüùÊ·Ývþ¤8ðÝB#ÂØ¥nlL†›ü JÁh–áuùPéÌÐ^²d vI¢JýpÅQ'Ž<³¢.çôúºQ·m¿‚±0<ß7åuE¨N Ô_YY©øØX°H6Ä 6ǘ茦*™Æß  9Ö<_ñᄞ¿ë®»Ì!£‰æ:BVõà Håf¢B¸ "Háó»Ð“Ž5½«[Èû…^²téR…YšŽyᎭ|ñÅ÷¤•_tÑE(=ÜÈĵöºØ‘!Èa`Çýh°ÈÇ`ŸÀsã77¸Âq ò¨3ÜÌ”CÿAì¬ÍB ejrêàÕb½Û”^Ž|Õ)­œŽ^UU…²O ¡/P M2@ÁOœòº¬::Ð_Œ.ÏPÑ!húX*ÆÑpÕ:uk{$Ló±zõjRã7óüY’醽+**ÒŸ¢ÅE|ØÆ\?T©"Ǿ}ûÒ-²lÙ2û+=Š-¸ÐµÒuT­ÇóWuÛ“ˆTÒ8€.eº“9pÍdî¶~c¹êôÍÚÚÚêêj¹²í<ºÀA';qâ„æ? Hܳgùª(÷v?äŽÔ/£5+°*´Û‡ü&lŠ(œî‰:ŒˆÐK%c‚ØÇ®««ûÏÿüOZÕÖÖöõ¯ÿ;É9y(´µùJ?Ð*õ<;ºõÆéê(&=1X4)ôTãrHŒ,Í×Äúí¨ñüª£šy”¨ÓÆŽ ^vÙeè5F©±ï.˜Úì˜Þ·AþÀÙdC³ãŽŠ}Ÿ:xcÿüÏÿÌ?2räÈ#FÐlþ¦ÆÆF.::: ‰ßüæ7ô˜X"oÁ±QP“ûÛùÀô=l‹'žx"ë´”‚I«” ÍÏ_Ÿ£àØq¤DV”ðÅ/~qìØ±ï¿ÿ~ÔŠZ©®àîŒ" ô–z)ÔŸÏ}îsX]C† è÷²°ø³¨sàÀ¿þõ¯£~gqAÞ(¿ƒ?â÷¿ÿ}ÔO#Ï=÷\¢Ï#hŒ<ùä“éîS›:uêÃ?,÷a®‘#Jˆ/ÁDÙ,**z饗&OžÜoCà]y啌ö¬/ƒ[³fÍW¾ò•tµ*ŒÆ¦@qq1¼Ê&Ž…ÖEýÂú#ÚÛÛñ‹_„8ú¢Ï`Á‚©°¬)]> uu5£~%!¾¾ÄÍ¡C‡~õ«_ÍŸ?>Œº]Ñà¾ûîËzvt°QZZ:zôè+®¸t°ŽŽ-E%è ¨ßV?Åe—]vâĉLJ^¤WèÈ:#v{z¯˜3gοÿû¿¿ûî»Q¿ŒÇalvGÐ`îÛ·¼Jœ\„‰O—ÆŽ‹­öÍo~Óó§J±LÜSñŽËVd ‡üCá /D,BÛQ·¥Ÿ 9ûì³ùË_ægÊ(§ˆ•àù‹ß1ZàÈçý×M˜0áꫯnhh@ ½É!]TVV"ežþùù—9å”SÊÊÊà.0>ô1ˆªµ)êöö_ðMš4éþûïÿêW¿ZWWW[[u‹ú JJJ*** „sÏ=wóæÍQ7' ˆ%È— ¹i©¢\¿ÿþûßýîwG5wî\´¡!C†h~IеÊöZ¿MùíRü¡ðêSk„‹±Š†¨¥Gj’V‚ÒTTuÞOàM ä4/*­»ìÞ½ûç?ÿ9Ÿ{÷î-ö¡ wæ¥i¾HzWQ¿˜~ lÔ¦ï}ï{³gÏþìg?«¹F`…^´H²Ï9wXë£ÖGÔ/ ;ˆ%Hd#etåååtôÎÎΓ'Ob"´¶¶" ùU[ºù£t_‡£ö›[%‚µªªjüøñÇÿÔ§>ŸZ¼xñÍ7ß+÷Ý£>º~ýzš$'|iiéé§Ÿ>vìØ¯ýëv¶;wþà?à“•î©¥ò ð9tèP˜fRxi2<ŸÇB ꬄ8@a¯;Zr‡Gy$>CÃlHrȱ£ÏŸ@_¸páœ9s@--ÍÏ<³nÇŽ:MMMÆ CNAè­˜ \C \(~ª(Äó—‘ÉùÙ­v,Úü„t£6„,2”»'¶‡»élK=¦ÞL`k4͆6Þ}÷]H4õµ@’ï‚¶(ñ!îQLlÏ'Nî˯ð„ì*2“-ê·âàà)bG 7ÝtÓ¡C‡üñ?ýéOžÏÈh@ò]çyiC1´¹à«çe“ÞŠðÒITZ-œ7SLIn- ¨Í‡ábïÞ½1_ÅA›KJJx4¬“Ècþñ|þùç=šJ%¼OÞ¡¤?Â]6<:¼^yûyò$k=˜± Ä fBÉÁÁ¡ ;J@*ýÏÿüϯ~õ+M\ ïôÍÍ͈¡òòr…GEH‘èùs*…H2ê*2«´´TóÚò†8ãZKéM|ÿDF vüJ©úúúmÛ¶ÅÓJ0@"õ1wîY&ñðáÃ?úÑ8¼¬$>e!T®yÕÆ],úä+/D“lr ‹\)¥tî^VV6f̘cÇŽ…8ÕÁÁ!nˆ% k^ýu­lÑä5‰ÈÄ„TW¯Ë½)¹¯…IšH‘˜ÓŽ*ÒjÆ ÓÙñèûäpµA¹T!yä/•‚xH‰ú•$ƒZLž<¹ªjŒR{ì±·Þz«§Ð¤å2  R…43i6&ºâú ,³Ë/¿üóŸÿ|]]æ”}ÌÁÁ¡@;J@â@r#©±ž¿Ì™Ž&k¦ÑÅ’û^WxN.töލB‚ŒRÔƒø#'‰šMUh‚H5G‡Gêü2ÊÖÖÖÆYùå‘+++y® ˆ)á9l¬—_~¹Ûˆ´6ILÀ[5¤«E&›Þ¼^`¢9¥éµOúÓÿðÿÀOßùÎwÞ{ï=rÆÇÍèàà±£$Nyy¹|•rrJÖ?^јmÕU_%èUÖœåbø@®IL>å@Fâkúi¨Yr¹%$(%%¹;†Bl £FÂD˜1cÆ”)SHyÿý÷룾¾>YÞ ^¬_Ï® "yLP sa?»^ ·;ûì³-Z„Ŷ~ýúŸýìgfíÒ]ÔäààCÄŽ<_[×lµ™&ÒáïUUUÅÅŨír$èWMÛ[ì¹­4Õ$¸t^­Ó——B»®¤#C Ê Õ;â$3s7Ð`¤ó„ ¦OŸþå/™F8pà׿þõÆ:d·Y®xÞ'Ï+{Kd LïJ®»r{ú‰Ï›‡ Î9眑#GîÝ»÷w¿ûݦM›Ž;FNÞï–×ó6‡TGJÐx-…ÔB#„"[‚ÓN; ͸¶¶Öž±ÙûŸE Zãu‰? •KÔ\VV&R=(<_åtçù‘ж]]]ýÅ/~1ýÆo £u8³Ùß§ýkЙŋÆU`6˜ˆuæBÏNA쀙3gžuÖYS§N1bø»ïîÂþàFÚ=΋Ò:]q¶a‡‚F)AÊì€.hÙíÙµk׬Y³þú¯ÿº±±xçÎ'NœÀtÐÔ‡YØ“¬É%[ðÕXfqPKº)b¥` ôñ$¢å’µý /;vìŸþô§­[·B¼7HB+‚´ÓXÊ»^‹<úÕU^—%¤·y`œqÆ<5LYWW÷öÛo¯]»Æ& BmõÐ63×D©ÖÖÖøìbuðü•{çw^ˆvÒB¬†Fº§Æf}iß²ǘÆ?ýéO_{í5¹@¥Øjù)ñˆ#PÞc¾0´/Áß-زfÍš怴CÐ,†$ §û·‹º½qAÞÎKàË_þòwÞ9zôèÜSë’ Íéå—_¾þúëóy¤ZŽÎKˆ£•€~ªýZ,2uêÔÏþó¨<¯¿þzÔ­ëw@¸Üpà [¶lùå/ÙÔÔd6ŠkSÄ ³Ãù¢Eeeå¯~õ«™3g2Fú˜Þ0.ºè"†{¡¿‹c\-™×bGÄÍÈ‘#ÿê¯þ »!’°VÐÀK/½4qâÄ/}éK(D"yY´jK â¼Z·?>`¤¼òÊ+1ßoß'Aÿß±cÇž={^xá‡^¸ˆ#%hë¶‚öå~ñ‹_„x]Gôø7ß|súôéãÆÓL#ÄèˆMèA¡–¢nfÿÅ?þã?Ž;ÖéLÑåiÛ¶mpsÔ Éq¤!hä"S$;‡h±uëÖk®¹Æ„¸ð|b0‡nFݺþ ÔÒüàY?Õ!`… &|ã߈º!áGJÐQ-ºÖµ¨[äð1ý0Áˆ#°0Ú´ë›Oírp[Õ¢j“ Rë9Ž9r饗FÝŠðˆ#%´ú@Ä”––<ØMÅü(A:OM;û´$L±²£n]?1u+rˆÂš$ÀP˜:ujÔ­8R‚BÐ2ù¬ðÁîÝ»¦F …>GJê=o¿ÌÖÜܜ͗{=z´ªªêرcXt}Å 7¸¹£¨0kÖ,þ‘ +yçwÎ?ÿ|»Wß~ûí¤ØÃdéÒ¥×_=)©LR1 (ž‰{ƒñøÀ\pÁ_|q¸37mÚ”:Ad´‡9Ž” w¥6[e¥ÂÕ«Wßpà æ+úª«®º÷Þ{MÊ‹/¾H úÑGMežê[>2iw_²dÉ—¾ô%>Ÿzê©t‹oÙ²%D©¬@+¯M@Yþ)í!w”PИ6mÚðáÃ~øa}åo}þùç¹0ÝLjÐM7Ý´nÝ:$ušô”}tÆ19x¾s¹§‹8RBii©‰>”• Qml½þÇ?þ±çŸ`n4RPµ† FwÏÚnîK_¿ñÆׯ_óÍ7+DDZؾ}û† rÝÎn¡U§¨B>aüøñ¹¸CÞHYñ|%iáÂ…Ë–-£#¡FLd>ÍÄÎsÏ=G‘óÏ?ÃwéÒ¥YÙåË—ó9¹ð|mÌää+•Ø¿p;:¼ô9¥P-EÈI~)v²×^{í>ôÓ_e±þIäŽ|r­§àWlô¥>¢~÷1Bw/{~¢“­ /^¬>$=èÒK/=pà)\ð a(@ ½ä‘GÑÅ¢E‹èè0ĪU«øŠÂB%½ÞTK†;ï¼E†ž‡"ƒ|§“i<0œ®¸â º rÚ—#@‘éX$PÑý÷߯è@ÔCmTuäÈ‘'žx‚ÛÙei3ÝÝ|ePa%pÁ}i›¤?Oqß}÷Q) >CU×]wC=‹‰'—²>añI“&å¢'8ä ôÃóÎ;á0{ölú0V¬Ì‚{î¹éÌØ‘Pk諨ó%%%Ö|üñ{ï½—þ¯<_²=ûì³\Ct]¾R3å“ …sÛm·\䡇ßzë­ôgCj¹¶5ÝžÛ1ˆeù¼æškH·µ·7>öØch{óæÍãÖ·Ür l§Ÿ/UUU 4h/’I1D­­hlkkËâî'i@t l ôrÙb#±ÙèÇô6„5ÒüÉ'Ÿ¤ƒ"Çm hõêÕtýÇœO®á ~¥û’™n·eËò0NÈÀíÊÉCîΠѤÍPN]?P&CÄ« vU µ TVV— c›‚<õOúÓ¬ÿAÚˆ ­ „òÝÅ!GР@Å–kA)ôR:$=*1²á™gž)Ú@ìz¾’ŽÎŽxµ%2C†#å]-uÒ™éùª!F‘ú§JôÊ¢ßÐÑÛƒ²Tä—^OSeጄ¾ü‡RÔpÍ'·&ÅÔOAîL@ƒ8R‚N„²(edгå"óºüit5:V·z´ÆÙèsލ š«Aá'>I§·‰°gégô?*aœ î”®¼òJä¸çÏÒ&ލ@YZX]]}Ùe—ÑS ¤Çîƒ<¦mž?¿”••Q6tÜζS@rÙ n÷r€½ÈLfjØ)6Œi(Œ³ÞÚ·ÉÃ@ Îõ]@¾óA¯îMÍ”Åbð|ÓÜ®œž/óW·FIB‚ÓBS_í²d&':ÃGc\€-ªŠÛ1jâ½5†ˆ#% _Nœ8aNEδ~NJRè@ô ‰ùMbbG´3¬X±Bé˜t; zìSȆÎǯŒcíÚµvåtwÕ€9¼mÛ6©0öˆ ”eXrmAµÆ¾VÏÖÊÏ·âó¡Z6¼ZeôQr}k‡<€A¡$“‚ªašnÁ¯”B=GBÐÛ üdyˆþ¾dÉ:3¿2ÍøÂz WÃ.I­IQJi30·€Näö“ƒ vY}}úé§á Û‘Fûi›ªâÖr›Gýšã‹8úÚHÇ,g±Z3_dRèô-zXò‚×]w¦4ÙèjZ§t tz$z}mm-¢ …îK"”nJ遼.^¼˜^0Š)ůØÝpMB“‚iQ”E¢CŸ{î¹vYueò{¾ÖcêÁ IZ%e€y€âX`Ïé€#E®uèЫB§RÇèö¬\ðiÄ:ó™gžY³fôtMÈ蛀~¾aÃê¡~:9f1Ú˜&Eåkii±½tžoFS–ÁE~Ô#rÒÛùd€pZűË2èî¹çy(âù  ˆÚÆ0a@‰!H4¾=ûAâx^lO_AÊL˜0áâ‹/ÖÊœ¬@þd[•~衇®¹æóUbÕªUž¿šB~fLG„¥.\ˆ¶¢õ Z‡d§s#¦éjtJ´:%ôCN4}u_ÍÙ-Ao’(WÏöü zõZz*UÊòN4Šx!T.—h›žB]ŸRÉ´í÷¿ÿ=†‹¼Ê:['[ðb/»ì²l÷…BE>ÏKÐQwn1e|À€ÍÃfþ—SJøÉO~‚ЙpÔmqÂ[mBoÊÛìþ,‡>€8R‚ç/:âÓÔCh½©æe+pí¬‡¾8ŽdÙˆž!C†D݇ ´WÙëÚÆ,‹A~…¨›æàà)âH ZðÞÙÙÙO6Äfw7™Ù•“;h벌‘A )8„ƒ‚Z+pÐUW]•çÃÚ¸¯b°zõêÄ`Ý×_½vD›”%K–!ðÀ\vÙedPÈ&D¥Ý á×Â:†!oˆ#%HÊ ŠfݽlzÆÒ¥KédùìtDN÷½õÖ[Õ•íÄÀØP¤0ÆÃÚµkéè´ŸN¯`|z"jP€0Æð=÷Ü“»á¯Ñ5Yr2é »/á’K.¹üòË«««µÁ8ÅR9Pté7®X±bРAŠTæù˸M<>¥(2+;óÎ;·lÙr×]w]|ñÅëÖ­Ó¯gžyæ²eËÎ=÷ÜÇ{lÍš5]tÑÊ•+£}ÉñD)A Þ1!¢F÷ mo¹ú꫱.ÅR¹[áИo¼ÑÖ­ ­&.±çï~˜5kÍ€ ®¼òÊU«VÕÖÖš±ÊÝqǼ48oáÂ…ŒŸÜ)wЀ<2d¸Sû/^L7SXí´’ÄÁf4ìÝnGM¯1±®Ãñ|¢2QøîiÓ¦™3Løî(¤6rÿî»ïÖ¯sæÌ¹Ò?mذáŠ+®€QHÆÁF)û@!6‡šõʵò¼óÎCk0ú…÷Éžè¦tôÄóµ“mO¬³[ èÉCcã4Lí‘âÃäu)D z:=€Òd¶_ra\sÍ5”¥µ”½å–[²þꂱ ·b¸/©ŠªY—  j<ôÐCئèÝ(àHRkZ‘ˆŒKV¸çoŸT¾!Î…›R&ÒõòåË{âEÓLÅÆÐ @abÔ¢¨‘vøîE‹¡`iÀÉ8qâUQ–ÌóæÍÓf›í„8RÿâFÁ²^¹9]ñJ?ÓÄ =ƒžª~ɧº)½\J5£ª™2  i¦•-µˆÏ%K–(Ö£F‘éý¤S7XµŠ À#Ó¿¥ïˆ´Kùþûï÷|…Haû .gxõD˜Ãžo†8î#ÿŽ¡Ù b>sÁßQQ@7CeY¶l™v×s9‹Ìe`ò륗^ú‹_üB1Jé±hßž¿ŸƒU±T•âd€!#\ æ“Žñº‚Ü=þøã>ø 4žn[¢ªjƒŒýŸ»ÐEåcà(轂]wÝu(LŒÁË.»Ì.: »pw,`˜äÙSRˆ#% _4)‘‹ÊK TVVÞvÛmJDU§k¢;ÐcöìÙ£XÓž?«ƒ ®ªªÒtN”¡¤¤Dá½ÈFm¤ÐYÑJd»ë®»Ö¯_¿råJÔ«žzž]Ó¿¥ïèô::á^t};R¶'žx‚&AW(A¦=‘B\(*ªç+z¹x }j jÅÀ0ÏÅí"‰þüì³ÏJÖú$ò—¯¯¾úÿÙ;(«ªûþ|ð†a@*˜pýV# Y‘1hM°‚ ¬2XA Ò…P ‚íš±åa%òH…•€ (b#X#DETÞÿçëììœ{çΙ{ï9wfk8wŸ}öãœßs?~{7ĉT…Ôù ±A¥&êrVC:ä$eŒñ_ɀȆª!uh^1%!ïÒx„ÂíDè$R–.]z­ÏMB ìðÝ\+Ž‹–6‚%éš²µnÝ:åq‚«¢¨<ìq“Ž`jP¤¢b›˜˜¦˜ä\C4Ð%Ô)©*Ÿ} #Þã‡Ôd˜8q¢Œq²á«Ê„ÑÁ;\KÖc’˜¡tð™ü‰ÏŸ?Ÿ6À*^Iœ>M#›Ø”MÓ6< yÐÀ„b•ý%JSøÀL²¦Ü Ô*†ØHp¥‘„9…md§  £@ ÔhNfõJ‚øšCmÌò¬=+¹¿oß>ñˆç+ —š˜‚›ÐX†GrrrìC7JCU.‚v/g,l‹Ï©Ž „›æ§!²ýû÷{1ÄíùÌcZn³A±Bå otêú6á»MyÙhaû¡å§:_ÓìY ¥%™‡‚Œ.Z´á¯RD±Poaa¡Fê1eÈÀ_xAA=ÿ\LÉSTTÄS8Äpf„=pàÀ¸ÕAü’mNF“)f‡ïÆ3˜9sæªU«tLaiÁ«vJ"QŒilÆ%2/hFŽ ™ÊêáBÔ‰C[Ð.Æ>žÁÂ… µ}:À3°‡šbMÈ}ÇŽf¸–J d̯äHcþ('¢Ç€BúÇ+«*ʓ®a!åu9$‰S§NFW*Iü@¢Â°Ûy´ðÁÆæglÈ8Prà€Ï_NHzôèa4cÆ S»¹ÖY—QZû=ØÞIÇY:Ùî1Gqß)mùòåŸ~úiíڵǎ»wïÞªºÏP§Š¯[·.µ'xà5ãèÄò[åÃôàƒ¾óÎ;^‰ææ/z‚/õÏÿüÏ-[¶ÌØ«‹82¯TFqØN`L¥^x!…‡Â#si£U•Ü—¯_‚ccê\_þ¢ÌSë(D Ø;#GŽÔ€lªÀÛ·oŸ}öl ¹¿ÿþûº6£FÎEØLõë×»iš‡Û([yœõ‘}àùóá[¶lÉØËI9¢¨4d„ipéÒ¥_þò—7ÝtSØ-J#î»ï¾Ôn (,,œ;wn:a¾æšk6oÞl<6E»ÓR}ÍêƒC‡½ùæ›M›6 »!i„9;3%À²GÒÑNx;h–Eˆâ\¯ÿ@‡ú~ôÑG¿ÿýïÛ´i£õ?UfÏ}J`ŸšBà«aþ<øàƒÞŸCõü ûD‡ÌcÀ€‡þôÓO]d‘pñÍo~%vC*Ž(z :ÞsñâÅâââ 6 Œn¾ùælŸ·É^àtîÜùá‡FU› wR5kÖLÓ‡äqüøñÇüöÛo¯Ú¾B”_þÝï~wmÅŠa·¥Rˆ('_ºtɬt<þüŒ3þßÿûwÞyç{g)ä–ð"«P¹f“çÌ™3ûþçÖªU«gÏžhc>ƒF*bÿ R'&”¿½ÃÖÜ2Î+9 L±y1‡%æ>ùä“æÍ›§ch¾Â€áQ™õêÕ38¤>íÉÀÌ ¶›—¶cÇŽM›6>|øwÞ1ƒE& ªÆ‹¼’£7Ã~+_M*´mÛ¶}ûö:tèÞ½{¿~ýÒ]ãµ×^ÖelùÀû÷ïG:÷ö;H"ª>ó¡k¼Ü~rqáÂÄÓÏþsÍmJ0a±j I{¦ Q3”Dz*ÝHLÉ/ÝU<†š>¸FÓÔ©S‡‹ÚµkKC,Y²dþüù‘Úå¸jÕªƒÞzë­/^¤_ü1ýåÍð~Ôñ2K@³ò }´Ã\k®ØóÛ)’ŽÊѸ=[ ¡O E¨nÝQtpÀB*u­\¹2:¬÷<‡ò"¢*Añe™Ž»ð¹Ùª’>È5¤??‘†gÏžUf$’QÏJ+PTýúõÍ*&2“GÇÇË1&6¥)Šø¹sç˜\DsH„.\ðqúôiL/èu2Ê@ý§ÀMÆÀG—Ðw©O…¡•¸×kÔ›¤£6Œke®£ààPQ•€©.­`vÉÁ$»^›¤ÜH1)9 È2IyY¸ü• ON¤¼,\ý•˜ãZö5%ë[º)<šK8è8ä/š@z®L‰LgézT;Ëä H}êÅj¬LÚ—’õ~øzof`Í W'ÿÀM/;8T D”“1ˆc¿3Gµ ›¤!PÁS§N!è6lˆØâ‚¿’Yrtt³ü wÄ’N£L 4ðü!)É89 ^ɹJÐ’§h¿4øÌ™3R ¼ŠÄzK³Á¼4^‘Þ'O)‘þ¢$äsèíñN¸+Ÿ%qÎ9›6mª—£q9­ 3·ÄsppÈDT%hXC뎼’Лš')"q†˜ËÉÉ©[·.æ??åh*‚Ç‘nç}hÀDBb®’i,ŸÃ˜ÀR9ÜâÙÈ.·—$‹¾L}À+ªåãôéÓzš2‘»À›Ñ œ¼ =¥Á:½1*"ý£>jÑ¢…4^¯NãKZö+qppH"ªdæ›ß5®PC* 0àÈ‘#ä‘<ÒȆL]©iyÀHO3e-5@º| 3— ª5¢ þ~ãßèܹsjcUC† ¹õÖ[›4i‚¤N¬Ìô»Ô$×(YúòÌ2?Q“zKüÅÛ¹sçáÇíX§ÇŽkÛ¶­Bñ“¢¤K4ö[qø7ÜpC—.]ºwï^\\œîº"ÅXxÀ–-[ŠŠŠ²zcZ,¢ö¬]»öÕW_5£·Ýv[^^¢ªj,óÊ  97nŒôŸ6mšŽB´nÝšD­5"EÃMò$Ì©è^fÃÞ ¹¹¹/¾øâM7Ý„±ƒF®ºê*ÌÊ_üâÇGRe²ê4…½‹¨—À[Ö¦l¿û»¿ãçž={ªj<Ô(ƒ7ÿøã¿òÊ+<òÒÿäÉ“M›6Õ±Øò ð-Ì2$‡°ðè£Îš5ëí·ßþíov[ª´¢cÇŽød Hal¾°Ñ!`Äæ î¹çÄ"ÉéƒPpþüy¤Ì7Þ8jÔ(3ɯ}Zô啬»¥Õ7Üpjûå—_þðÃÃnK5Šaß¾}›6mBj…Ý–Ê"¢*áŠ+®Àíܹs«V­Ü‘Ù¡ãÍ7ßD7ó-4h }šgöJft¤2dÐæÍ›_ýug3… Œ§C‡„ÝÊ"º*¿Ã‡‡ÖÃn‹ÃW@+Ì™3§qãÆÒZtdB_4kÖ,ìVSŒ;¶aÆgΜ »!ÞÇÜ·oßöíÛ‡ÝJ!¢*A‹‹´R(ì¶8|„N›6m®ºê*)ƒºuëÊ9à""É!“6lXQQQØ­pøŸ|ò _$ìVT ^FÊ´k×.µgË8T_|ñê¹eË–š68wîÜÙ³gµÿYëPÃn`5E—.]^yå•drò½ 1cͦBøkýúõC† 1 I?øàƒ­[·"ÔêÕ«—L™<Ž¡Ð¹sçò6[UǦÛÉF÷ïßæÌ™a7¤âˆ¨JÀêÄüL~-ݾ}ûÞ~ûm[?‹àìã¶ánŸL"ÙûçÁXeFÕé8û;“PøUémsÓÆimë »uÕøÓIzÒ|»]»víٳǜùõì³Ï‡6+úgÏžMi={öœ6mÚÚµkËŒrºaÆ^½zU@%ÀÚ;vìðü}øè!QöÌŒJ@\$ÙÇrS©aÆhúQ•`ïKûÒ¥K{ôè! :ÓÆ½{÷…AvdX¶lÙ¸qã à2C¦¯^½ºb*®;zô¨*õüÂümÑ¢EÆTB’}¬x™:Å€†€PÞU€ ª î¹ç Xh[Lí’››»sçNøÉHúP$80­Q¯aŠ•+WzþZûï¿ÿ‰'žÈLDU| …èc–"¢*᪫®úä“O’Ïß®];¨|ùòå²w u}lcés‹ d›8q"ÔÖÆÏš5KкçÎÀƒ«·oß.rO_/»ì2^cQQ‘"îáHsGsãCXHøb ¨šÁc>|8Z[â.0e0áÉC öÍ AƒÈ€…Á§ç)RßsŠÂâ>~ü8–™çÇè~á…ºvíJ ÅêAŠ‚KĪŽG°¨¨m‡’å:p§däÈ‘*G³¸û¤ó6v¡Ú`îzþØå(Ò}|#ì³±cǪ*„BÒýôÓxää¨10\Ž^¨¸%ºâW•Ÿâ RꛀMTݦM›Ä(J¨[·.uM™2EwiÞ?åp‹rHyàT OqM½(îŠÚI¡³¤ú»õêÕ aúHùd;|ø°ç›¡ ¸@'ÁMä§–ñãLJýÑ2ŠˆrríÚµ¡†r=5ó™1øÄèÑ£µÍŸR"w>¶È‚˜4i’çÛ¤ :º§Ò¼¼<{&jÎÏÏ'½¸¸º'ZÑÒØùóçó—»Ð µègi0Õ­^½šÑ+¢lˆXw¡ÝfÍšQ²ˆêT-Ó§Oç®ÚÓj@Œ§h'V×Û¶m“šÁvƒÜaÓG¤?ÅŠ‡é í'ÀÏ2©"y NŸ>MùgΜ¹èC!’š7o2Å8$˜€* IüåZ`J±A"žÎ÷äÉ“!3YßP”½MW§‘nAárR¡º… *]Ñh–-[–x€2&Õ 8÷+ž&‰G„uëÖ‘ˆÙŽÎP µà—“êÂ+™ÏãÁ &àÐÜì}nñ¸=„ ;Ó)j$ÛÔ©S)M¼ƒ;B"Oñ³ZmŠèÀ‘m–÷Äœ¼BœSùz\@”Èznź«8¤c}`!I¥„¸€žä?z¾1%"æ®ìJF’B²<¨ü°Äܹs©+q !V¹ÛP*t “ Í)Jr—2© =áù+ý¹¥R/>8íG-Ñ6(•nâJkžPÍ ¥S§Nöä‡lœ5kÖÐ`ÒQ ôB牞?ž‹r2=Mr§EÇŽœZ­<묆†O1ùuá• ºbjè"‚ãØ%,!™Õö*Ø=z4òtÆŽÁ(A²Ccð œå#ñ4Ï&$,w졸l¥&Q ¥áC`ÈS .,¶ŽiŒ${™Q€è…FºLæØµ!Õj)|D½Ï;*ï#Æ-0ÆŽL c€Öôjï¾ûn›. ÝC…°TˆDž8qâl¤à‡â{³¥4M°´K!±KªŒo¤Zp´©E©p×þýûuÍT¦o˜Md°qìá´vÇ“e¢–Nœ8ab¦ê7p”E0ÎA‚”X@ÿÐ!$4ćçCºeHqĈ={öÄ€éZ·n?®]»Ÿ±‹Ô&]®m™€´p—1ü´ŠÒà>BßÀ)òitW«˜H—@7¼fu:wî çò œ'‰ÎÑ¡¡ ¢œ¬ Êû”̹ J‘s` ¢Ò€çÅ`#`MwëÖ;%Iе¹ÃdÓÒ&ls(I7„K –W’í$'Ô í&Xo§Z(™ZÈÌO”„1gPf°–j3!¡ñPCúšƒ-= lFV~ø!oCÕ>}Úœfᦗ³b {ðD»Êô¡@ÄýPš¥¾cÆŒAžöë×OúØ.Xîü„NP8£Ã‡ÏËËóJȲLè`´Ž?õl¦:]€IÁrâAšÍÃ>° úôéCõÈ~>L!&LÈÍÍ¥G$Â,¸ûaŸÑ#\±)´¡•2—ßÀ ;vìÐ,–çS‰¹…ÿ Ù‰"!5„2D¦³ÎÅTòš[ɯX¥=šæåï¦M›âFƒ0µh4Éó't khêÔ©ˆxØO)/½ô<‰ŸékhÈóÝji›Y;lذXG¡\ÀEÐD:Î+‰FU™22Àz|®íñ³B ·÷ñ Í×­[wÒ‡hò‰'ž¯p{Õ5Ïês¯d žùiCu™Gìê¶lÙ¢G´qJÒR½ÚëcŠEÜCü\““¿²÷qÍÉ`ü~º©ü±ú¨Ñ'Ï÷¼5äe÷Ën^5ADÏKøÃþ´jÕª¼"L.¡MîŠ1iV 0Á`ÈB;hŒ ØP£”¸×6l TgV‚‹vÔxDͰ{è¬ò¨J´YÑ.ßn^2€»PKÔ<Šq¤#z~ðƒüõ_ÿuZH!;‘±óàß*¹Ê@S’™ùôÕ뼄ڵkWlx:V4RŒŒ;bhCб#Œ#+ncli÷q#µÔ¸Hð@Õq󨦙]~lg}éÒ%¬¦“\dl‡*ƒˆÎ%4hÐ šîK5‡f•µ } o„ò®S§NØMsppH"ªÜu4&¨Q£†ö¦™c™ùÛ±cǰ›æààDtàÈéƒhU­ƒ—ufŽNpçç88TDT%x~0Ô°›à„K0tJp«Ê`ÕªUž?ÿÔµk× ¯Ð/-Ôö|°k×®³gÏŽ1ÂLžíóa/ó#Ïïÿû¸%2ÄÄâîÝ»÷µ×^Ki0«º ¢«R>i)â¢[·n-Z´ÈdXö¡¶a N°©¶ììC?S,nÉô‚gÕ/-»†Ü©kРAéˆòH™(€T‚\„>2ö2ÒŠÕ«W›k-ÁÌX¸ÐÒBm?òÈ#S§N7nn֡Ο?U/›wùùù={öŒ»þЧL¿¸€kè×¼yó’ :PÝ]•òáä¦ÈB!²$ÏN¨÷ÜstŠÍà•åEp#¬•¨½ÀŽj91wtò‡¶Â‰)ë~ìØ±Š¸§aê$]èöܹsøê]Øo:Zˆ¨—n«‹[Ĥ1@‰è AÈË]#9³gÏÞ³gÏ¥K—4’›Áóc­(°»9ÃGQÚÜØì¥Ù O?ýôµ><ã¥ìsŒ õêø±ÁSO=•L¿Lˆ$º³páÂÊG°P«V-ôZНàæª0AvìØ)*îŤI“´ùŠoÍ]nh ç+ë Ù ›h?¤ ;§È€Õ‚¤Ö^}%â¿=ztÚ´i’àýÒ\v)q9…ÌŠuOÛ–.]ª³BÅ5ÉôK1ŽTÜgôœƒQ• Û3%ëX¨q©ñ¬H "Æ‘Ôx¥"°c›p¡ëP@òð“ÇQ'P' !â¨îÚµ‹k ‚a¹“§¨¨šCè‹%â¶„’7Ç]éöÀ5´+ƒ¨L—\ý‚…Ô’®]»Â-æü¬TÁ‰äëà%èñ±®¹æšt|,‡°eöêÕËœ„Œ>X·nÔˆõƒ>€È!3~bNAä³fÍêÓ§NF“Í„qƒÍ® ‹-Ây5Ay=ßöGÍôîÝ[BÊG‹ÄU š0Ä›PƈdlQˆ¢-Ù‘Í÷ Ö0ý¢Á |”ꉈª„ ļKÐÄÈ‘#! EËxøá‡¹Fî?øàƒˆ†àñg!¾-[¶è„)‰ué ñ·nÝuB9˜HP¿F{ä‡òü£CC‡]»vm\b¥vÈw¥1"èê—£­­ÊÕ/¯d_4Ü[®Ø×eâ’† ò´ÜÈÍ"T= <80ï%râ‹ïÞ½Û+ }ÊO„u ²)’çÇ‘Tœiè\OÉ®P.&00 C~Ķ$¯ µ¡§˜1"Ø„gáÄd&®M@EfvÁ+¡ò¸‡ÿ” 5 µ.‚ ÅÁµk×®U«Öe>Ü‚ê$2†?«H±H=ߘ6m>±çÛòÊЯ_?è×~ŠD…­~ûí·g?˜Ÿq«“;b[fbƒ›Ä=ü'{ÎAˆ®}—ù°93fÌxä‘G Q踨¨H‘Ó1ppK5R¯y“:FjÅ´ù‰µŽïœ——§ù7Ø£´Ô-Z´°n)¹‚F“*fþ@ë^j AS è®Qc cîMŒ92°3@çS,X°}ôèÑÜÜ\cî¬Y³' ''’ƒ#($Á~J†^)Zù#«‚Šö9´Ø¤£ ú»·€§tàU‚~)*pÆV¢g ¢»¢ü—¿üåm·Ý–äLÉÀŽó.Ä y-2µ÷²éWè‰lq3hÚ Ai õ“Ç̧ź ø‹-2Û<ßËîСƒmt£]b7XÖ€ÇöËóOàÑ4` ¿HÏž=ô£Áö 6T#!½ì cÁ±1M˜qâ«à¬)S¦Øl’*hý«ÎrHPx§NÊ̦èê¼÷Þ{}úôIaæ| ƒ¸!¯cÇyxÊx—q3h{²^‰ÉŸ¸Xb0Ã;±û6ãÒVÀöíhýúõ¥­tª4@„îiÖ¬™æð4¯ÂZÊ èç;ßùNV xpÍ&)<òÜsÏ¥\Ó`0éä«ìEtç0?1Æ«ö85Æ5æ|Ê‹]»ví=÷Ü“ÚQ£úõë˯S§Ž9µvíÚ¸ÜÊØs„ »éÅĉÓvbÍš5)/Mš4q*!m-»ì² 6|ó›ß »!iÖý‚ ìÃÁS‚¾}û&êg’¸é¦›Ð^7®U«V½zõø:_|ñ:û³Ï>‹ìØcu€PÕ>¯Bë8R^fÊ£œ5mÚtëÖ­Ù¾÷-Ò*áw¿ûÝ¥K—ªö6¨ØÃ>SRfj DlÙ²…/‚sаaCt˜,S¼œ97v. Ð¥K—ŠBè* •o¸á†áLJÝÊ"ºdÄ+ÆŹËÍÍE$9мöï~÷»ÇŽûío[¿~}4)W]uÕéÓ§qΟ?z¸xñbØÍ¬ÖØ»wï¬Y³n¿ýv7‚š7oÞ±cÇV^ˆîô²¬/\¸°bÅŠï|ç;·ÝvÛÇwÛ—C:иqãfÍšáüÛ¿ýÛÑ£G4hФI9 |íáBñŽÂnluÇÌ™3—.]úâ‹/¶mÛ¶¸¸ØÞïâ>@üð|±uëVdTÐ^”UBG‡vaþßÿýßþýû¯½öZ\³ë®»Žs ¼A^ºtI?íqídƸ%Út€FE4Pn2:tˆO©Yî“'OÒYZû¹U¢F 4ЯàÕæ®y‰_‹y!Ï?ÿü»ï¾K-¼¦M›âðxϸ¸'Nœ@ôhÔ¨jpB¶ké–[n©U«Ö]wÝ5lذÀ¸4!ÞFÊ÷ê—‰Œ?/­*±@tU‚Æ%nS1™Ïž=»oß¾×^{ ÁD:?IDùäLuz­p¤ô¡P·n]z„ŒÀZ”b@ŽsÁ‹ÒT¶­'ŒþÓy8R¹¹¹øÂ×\s ¾Eåää ¨…º(óÌ™3|2ó’U{دÄák › }d¦ºÀá"µkÖ«-¢«muêÔAR#²@È&¤B yG R é&sÁ„ÔÃCš£—Z/¯TÆŸdK€*>"Âï¾ûîÛo¿=[¦²q\t|º`Ž9«åƒÞÒõ×_?¦”SeNÄ4ú@q­M™zr´ù mÛ¶¼p~^}õÕ¼U½^é©S§ÐÇü¤êånØïÃÁÁ!5ˆ®J‹€ˆ—ÙþñÇË]@Ì‘ˆxJŠ“§Pd@¯q&ƒFíäy¤|_…ƒƒCXˆ®JÐé¾Hp„5˜ü $‘F´Í|ŽD¡ƒ±ÉþUД2NNÓÈ>®›ú ½}ûö×\sMÖ ÆKP?ýôS†L¯Õwt¡ŽÀ”æãÍ Ä5w‚nÐÈ)(3 „&hÒ¤ eJë½}òÉ'\5À-TÂÒ%dãB#QnÅ‘ƒC•AtUrí3Ü@ô‚I‡¯ÉP5³£zBêÕ«Ç]R¸@\ò—D<r¶k×.777A$1Ã~ñ¦‰mД ]ÖK0 ¨ì¼1z-AO:ÙGw5 PäA…èer‹bI?çƒBä^ð—ZT¾ô(åÈKspp¨ˆ®J@ÖhžQ%ãT*É&Ò%›Ì\‚¬Zmh@‹(h³ld„]MšzEä¡ð/¡Ã4ŽærZ¥‘})ÏdÓð‘^àu]éC ÕÑ…ÒdëÀO…®ÓëB²k©fì=_éž9sF¯Z)Òž?r¥Éeˆ|Ъ´2Ò!cˆ®Jhذ¡çK%-êÝ»wNNNçοñod¬ 7>xð`Øo"ˆtŒ‚þرc¯¾újQQÑý×yþ‡0Ò_ZAjØéƒÌ#×ÿСCvz—.]¾÷½ïõïß¿mÛ¶‰Ýß*‰Ì;ô¼dóæÍkÖ¬ |‹–-[¾øâ‹žDàVÄ]• #³ôÛßþöüã£G?~ü>ÂnZµ¾W‹-zôè1hРY³fýþ÷¿×P·4]ÏOMH„ÝÒê…n¸aÿþý8¶¬ágAAÁ_üÅ_ð™pûÈv3« êÔ©3lذiÓ¦Á#sæÌ1žÙûï¿ÿ›ßüfÔ¨Q|‹V­ZeQØ…hM ¢l5ÈÃÔä'†ÏßþíßþïÿþoÕ>'$‚Ь}âĉù—¬5KŠ‹‹ýë_ïØ±Cãx·Ýv[Ø­.@ôc“òwïÞ½7n4éGŽéÚµ+‰§Nr À2 0Âj÷îÝãÇG+Û·{ì1 Òþô§? »™å@„T&Ͻ÷ÞËÅ’%Kp{=Ÿþ9j–×Yvëª/ ø={ö`¡ª5Oƒ¡š““ƒÎøÕ¯~¥_ ÍË÷üè§&}ÆŒ8Óo½õ–½%Ó!“@ ¿ñƸÔwÝu—I„qÆÇE^^Þ3Ï<v“ETTêT‡Æá <dZçwœÕ:0…ø@?ùÉO´¢ Å ãÞPÕh…°[W]€*}ŸŸo"à—iÓ¦½ýöÛa·Îá«GÿñÿaÏâ¬X±B_ ­`k‹(#*Aú@ÃpÆùÂülÕªÕ‡~vë¾Â±cÇn¹å³vKSýž?fúÿða·®êÑ/™›Ì™3Ǥ#k>øàçDZ€Xý!G,_¾<ì&…H¨„'Ÿ|ReÆ “®¾új7yà(4jÔèĉšOFa£Å5ÛŒ)”]k*²ÆTÚ¸q£½º´_¿~›ºœ4iÒ³Ï>k~"Ëî¿ÿþõë×›4 ) …’LÓ|T¬w÷Ç Hÿ{M1>ýôÓîÝ»Û)………ú^xÿˆ8ÂW ÐÜÌ™3un0鞦߷oôd7Aú¤Øy ÝÙ³g{>'”Y x£b ÅÒz…9'\ Z´hßfB®^wÝuºU“Š2lSÉXйb–S§NV­Ze~B¨ï¾ûîêÕ«M VíÉ“'ëÖ­{çw&wú¨Jö”вz ‘…’$±¶dɸ&ì6–ðU‚!ñ|T¾@˜ñmÛ;>¤¶}ûvý„ÐwíÚÕ£Gyóæ=ðÀeV˜RÛ´iÓË&6…èºk×®é¯é‚60+¸žf<ÿ`/vÓª,%ºà%§j9ã!C iØMÐ*¬¡i níܹóž{î©W¯ÞܹsS~tk+KÀõO<¡ëtWt<åÛÒ¥KuË<ú裙ïT¹²J8tè‰ín»•Á•W^Ù³gOãCô|f$²IÙºu+yz÷î=f̘©S§¦µƒ;w¾ÏF?u 7¦µÒÒ@Ç+ÌÈ—_~i.7n¬C˜=ç(¤ ¸fÆÒžE¨$àˆöíÛ‹)P(xÁ° ú®¡"ÑŠŠŠŒ¯Ì‡–"Á¢ÊËË‹u y;ld!…}ÆOñàU ?gΜI¥¥5Oî5¦›ªü¤:™zj ¦wùkj!ƒjQå±çÞM›á¥pB ÐÔ-?÷ìÙC«$(ÖŒ¬>öØc©*6MY%9‚þ„ôSUìèÑ£½‰·k×n„ ¢{¥ˆÖ¡3ùιp¡¡ ›¦ 6mÚ$’WJ"E†´EÂ- 6"£ùkséS¦L±ËQ-äQ-d¹“Çp£x@Œ§Ž˜ ˜={öôéÓchå…ó½-§Gé¶vwH!l¾H­+&Rºà”l2xð`™P¤`3ikº\dùÊ“&M"¢‚q (§Æo³ V³fÍüüü×_’£üE‹a~áðÈK ¸Euk×®ÅéGFSNW°€i ǃٰaƒµ 8Pµ(ÙáÇé¦F‰aµ]H ¼¬Þ=ýôÓx$û÷ï׿'#¨:µG™M$0N`²!jS%`lOÉ‘J…¬%ß'Nœ(ú&E<€Gìùd§ÑOþ®^½bBŸ“øÀ´hÑš†€ JS,Ü‚’€m d4EA…P®®2@g0äžØ»‡ò ã#F肆AÙ”&@cP-‚»ï¾[:’…+È£ÇÉ@#iCqq±l4€þ …<ð6<Kˆ©h~ ð ÏÒG#Ä+…œ¢Š+®¸BWmïÞ©„tÀ,^Œ`QI ¡=(ÂGÈTzᅠƸ&Ú‚ ÆŽ …C·Mè J³MÀ­Ý»ws‹’¡ˆÆéÛ·/µÀYT:þ| )SìΚ5kÆŒ“'O¦Iԋć°M]¨J X2©E¥Z”Våq~ÂÈ.¦RDò¶R¶ž={RxAAÜÑÈ,£u©ÂË/¿l®Shû¦aª{ûeÊ_t9Bîr=ŸÜ‘¹h~’È@%Ë–-ÓЊhš¿;vì0y <4³yØ&ÐÒŸ2!)R Y9­kâæõèуf¬\¹›E;ähꂸiÌ Aƒdì@²Tjjñ|¯ªÕØ+ä¾|ùr¥Ð`È]ÁÊI"­â/ìáùLÂue^,¼W§NÏwêÖ­Û¼ys3cfP‡”‹Ò¼ÞtÌÖˆ)¼e fÁÐ1\€±dM{>=Œ9Ò0”í.têÔ‰[ž?U Ëg%'ÂʼË\²aŠÅ²ÁÙ›Ÿ¢Î;gjÁ6¢;ƒضY³fJD]FnݺuÊ_lfÎÆó× §»ºÊ L•€Åa®û÷ïŸÚÂå@î…ž¯$4ŸX³!²/—Ám÷ü ªæZG‹C^ÓÔH[$2‘Õ0'ö`kC"<›ÇD”3µˆÉd(**]7%åaéš4i‚¯€VÐ! —_~¹ñð0cmkÈ¡ò˜4i’¹Þ¼ysÊË—Amƈ¼’å6ÙÇÂcE‚³ ÉñŠüEŽC¤s–AŽc `÷À/øÜX0˜MØ^P~@v'À”)S°µä?îB­(¡L+۳װص%à–hšÑ®]»Ør4ÇîùƒÀ)|Ïð£™C¥vP$µM%ÄG—.]R^… HS?eø”fþ`ø+3ô}ØC@¨È¥[·nÜ‚ ¸…ï‰.¾q´!Ê¥K—"¾'Nœh‰R&_ó´qR dD-òÊ•e“Îßo¼‘Iß´i?Ñ.°·zaCl|ÒGÅ^)j iÓ¦µk×ÖY:çÙöðl5ïPyØûžÒ1.§)3Òâù£I$–¹á :´_¿~ˆWc‘€Å‹c¾Î]±^,?5„ …ã…ôéÓ'.•–Ô ’uÅSfÍz6lP-†åñKhjé©§žRÃ>¬†ÁP0]l!xíü¥y)ÛvLå(; ¡¨±½`>O:–ëBèP¤m&CR»wïNüü¹ËÌçY{˜Ek2£È6cÆ -„@c›`ƒÀ ¢¤ä×ÁÐ:4ª‘Y³Â隀{幓¢åÏ4U+AåH,Y²$vdŒrÂN\À±’Ö êe SøÒš@,ßάâ"x]Õ€ÓµÉçॗ^ʰ‹ÅÅÅæZã®ÑD$‚ÝÇFqH3h›yà…4jÔepéÒ%TŽßP ÏtÌ R¾ Ï!"Ð)ÂÑDh^B<ç`ðÇ?þMpîܹóçÏŸ9s†¿±ylÙ¡2HǪS‡( ¨¨(ì&”ŠÐ¼ô¤Ó Ùˆ³gÏ¢ .^¼ˆ¯€‹©ßù|iÞXyYfŸJnNL€¼ð C† ‰»Æ?cÐ^ÞÝÓ]»v}ðÁö éõë×—¶üšW­ZÕÙGiœ4iÒŒ3*¶TÏûóݸ§N ñu%Fh*¡ò«Nã~ÂTÒ€êÕ«5¤|·WòÀ*Ÿ2eJ§Nìž’¸víÚ¾}ûš­¤jmÜôT¬\°;¸ÿþ;vL˜0¡Ìöœ>}º¸¸e€b¸téÒ矎£à¦=Ó„À‹­˜JX½zušTB^^d€ˆD"ßsÏ=)©åÙgŸÝ³gO¹v·(ºÑÊ•+‡Þ¦M³“cÞ¼yy=Ä&Ê6fÌ­óV` ³D•Æ+0¸Íe÷ß¿:¸iÓ¦‘#G<˜2ãîf(/¢ìÿ…¦ìu………ùùùå-!ð Sì‹iÓ¦injéÒ¥•Ë´…igòO!úчްaúu딸sçNú瘘É0„Þ¾}{…lÒv6q cä‚BàÙœ9sæÝwß]f8âO?ýŸ•€2øòË/a.ì…’ mÛ¶)ÿ"ÕQžO~÷Ýw!3(ªSØ•”Kifc?Tmï¡+ ˆH}©°fR Û·o‡ì!þåË—cÚ{¾‹€ôÇTW™Z¥úÄO”6­m¡”¬R>JEqõÃ~ýiDhs Q^†… F8*hûš5kRR&öøäÉ“µŽØÞ„œäÄGŒ›À®º„ŽQ¨Æ VÜìhÞ´?î¦9ŠíÚµ«2,[¶Œ\„Gy¤Ì&á%hÔÀ'5|òDÿ,‚í¤da4ƒ{ué°)‘¢¢ÿ*ì£2ˆÞLLl d›h¸Bñ!µ8âÚ~Ö¤ð¬ì?…¶‹5ñzeÔ#y±u›&@ŸsçÎE|›htä4h³ãÆY’²mÛ6¨BÏ*ˆ¯gKe‚`S©Ø“ðíoÛ œEîPIØ£ê)‰Œ«:vìX(…5DW:skM/ièz0ñtg̘ÁSf RÀ˜(((€ö $X‡ÈÔ£h^)‹/¾ï¾û{Û ‚mγ‚ûì Õû:”Zh¿ýàŽ;lÃ_9uüƒBCü\¸p¡ “<82¾”tOFÉìÑÔˆ M%Üpà ¶Ú¬¼V€V®\ A|3þ’²È‡bØAô­â»Ç–6@‹Ë–-³ÉJ‚:IÇZQˆSE‡÷|ïOv )hŽ>ŒxšPì"\˜ÍR-OI$k/Ûev#+'lF/dì(°«, ‰'–ë]QLwÑAk“·dG‹/¿ü­àù'€+®¸Å`{ÁväN‡Êãå—_63 )‰^€ÈÆ62´Ø‘'±cýB¢ÆÎˆp—¯L‰¿°-(y±NŠ6²”ÙªÄyÆnüøññüÕœö€ŒN… íøÇðF[2Óq;ˆp ò¥û-%‰, f@ ;`åcÁóñ4.iÂ%É’ùcÔ…+Ó”ë¸çÉÈc€C0‹âÔ +éYÍÙ&s„râPìˆf(+’ ˜?Z¹l¤€NÅçÐ…WÃR ¯¼KÕÁ¢ùð{LïÊ<_º†…/| Œý£²¶QYù Êš1²í}­4Ó_l&hªÃ^éÖ­[‚ø(0…G®BJš²up u·Y u¡Z4UP¦T%§¨‘Ä&\Äš>ð =’cŽ¢ ºÊ](׋²;hÞƒšÝ¢E‹ò¾v{Ð/âäÃT ö¹›o)..~·ÙG›õ²€dþ@\(»9-¤´b1uEgÒ.&tˆO aÊ]¤ªJã)Y÷ Ú¬œ¢-2ËÒ1pv6y-öHŽœ{ŠL†O’æyQ4ÒtÐnª"­&.äòË/Wt#”6åÛÛÚƒ©‚Í‹!ßÇŸxçÎXNPÑôéÓEFböö1eÊržqCµ 1¦€Ê„˜±- XŒ ¾Ö<u¡'” 9hõèѣ؂:à6¤x 瀟‡ŽÖ^ͶɘfÆQ)*É™¶Õ«W›¥g]{%Ü?J’”ëý£2í€wø‚™D˜-0y°+åWÌKXïC×úê" Ll4ì5а ^µ=|´nÝ:™ÿj@ …ü”·:1AªáD|}­% @ë/°ÉL!èƒÀÖ¸ ¢%yöpq ›Ü*((°÷.x¾f’^.˜Ã½?·ƒ£‰Ð‚c vˆläx`½ œ7h¶˜ä1ìùÎ&×X"û /¼`O@iÂYc£|ïc±q¤Û[¼R¢d–0 ?ͳæAºA›=6h¿½A´Ö 6Oš.›»:¥ÖûóHÚd@½QW•†&›6mÚ‘#GÐ åpA OŸ>íù Þ¼3HIplœƒW_}U×·Ür‹m?ñ!4‹[±’ãòHÔ€÷¿uëÖ¸<âù~*nMiwSUdæã"npl#ÙV¬XQÞUO P5ƒc£ŒD‹ÕŸõë×Oðl›?‡dÙ•>¤dþ¾·Ì\’1Œýð¤hµriy$aeÎ{%k·í›üF1hª#nðct ¹Ýø@ž¸‹>Mì.˜[öH1´Ž}—ØÅÑAr8Â?  çΓ>°Šçìõ¡ëG}Ô¾…îÑQØC\‰´†"Áè(þ^{˜7oÞܹs¿+ø1ã«{÷îbÒ‹/FßEðBW ž5ÓµqãÆÀvÍÊкÖÏ™#÷¢‰µk×&žø‚+¼5&yh>`àÀ òð-Nœ8qéÒ¥Úµkk¡Šáµ×^ÓÝ.>2üöª̉+Æ ³í€Â«®ºªÂÅ"¿Ò)%€Ahdâ1I¬™ ¬~^¶lY™“m|‹ÀìñâÅ‹uñä“OFy;ºAÈGBÛ¶mµKÓþö8\Ç}„Ý@‡¯\œßýîw‹-jÑ¢*}pÙe—ákMêÁƒ£|Âxæ‘Ú#aùòå£FòþüL.ԃλ»Ç_­ÌîÚµkëÖ­È2#~È·:¤V%TÍ#ÁŒ9«ÿ÷G-GÙ«­&ÀEÈÉÉ™?þ… ¾øâ \,‰½{÷J §œ>ÈF­á#Ì&ã“!}~þóŸó›ß »u_Ílÿä'?±MØ_|Ñó‡ŒR®Ò‡H¨èû™gžñ|ú¶ãßÕ«Wï¿øwcOstÈêׯí3{ölÑ4åY¾òÊ+ž¿ðÔÞÅãVôèÑÃøÓ&Cꪫ®jÞ¼yØ­«¾@@ÝtÓMÅÅÅøÍ&qÆŒâË"}àED%xþ¶5í\›3gŽQ³¼Ðÿþïÿ^¶lY§Nš6mv«pÚ´iƒ¬:t¨™¾C\qÅÏ?ÿ<×7þÙÏ~v3«,ýû÷ç/n™‘”ˆ÷ÆoÜ|óÍÎxÊ0xá 6Äf‚ì¨È®Ç{Œ‹{ï½7»¢ÇGâ MGáå—_æõ 0@pˆžš5kîß¿úôé·ß~û­·Þꢪe —_~ù[o½UXX¸fÍè^Ãwè¤ߨ¨¨ˆ Æ ãoØ-­^àå·jÕ F° O®‡Ž?]ÅE…yq(à‹£Gnܸ‘wûصQ>`9"¤<RîÉ'ŸôJ–Û£2¿;wîܵk-[¶üàƒ ? ¤.]ºDºÆµ—MƒÝž€Çí)tûÚÄf 1Š¿õ­o!òà(ÖãµÐÚ¯÷Ξ=[TTçÌ™3ùä£>B%PÎ% j”Ö 1Æ[âCè”Í(¬Xs c¢*R¬åˆÓY„h©„ˈc‡Ê–G!ìn¼ñÆ·ß~[j@‰@®®õH¥Àm*Ö®/›ºuëÖÜsçÎEVä¡Ãä?ž4š}…^Ž4ÇÇ ÷ž>}šŸ\ ´É@:5qE¶…2Päd¾‹4q‚ÈhY‡H«$bK3 R\“"»¾mÛ¶øÃLr ¸0R>ȇø²BáÍ›7Gä5oÞŒ¿ø ˆÔh.Å¢a±>(SkÚ¯1"‰oT…FP ÜòªLS \4^þõ×__¿~}ª¦ þêÓ8•ààP•i• k§È þj{TÆ ù‹hCO §Ð ˜½’\žoò#쌻Pf’ª*y‡pÝu×åæ63w=…‰i ;]¡‡¤í¸‹CÀ_½1i‰–L-¶>@ã"h°ˆÒt¤Zd](‡Š!Ò*ÁL¬Q…ZÃ>EÆñ‡zÈÉÉùðÃßyçÛÑ\‚Ü…dL`pe :vìØ¾}{{}w4õç/¼[.K‚› Ï£¹wIpM*$©Ì,KãÆ¿ño4mÚ”Âu®2é§NBUT8ÚšƒƒC4i•€ÙŽYªQþjýŒ±Ž‘GÈ&TE-|ðÁñãÇ‘’HF >™É±ËÌB# É²Æ îÕ«WË–-í©#[£ÌËÁ  2Ú‹î )5mÀ5]6nS’³Áz3Šm‡‚lÑ¢…擉çÎ3ƒuTö›pppH%"­®»î:Œ\ü€ xþºæ¸@ Ê–@'Éuâĉ¢¢¢>ú¨¸¸Ø¬>Òá_^‰>à¯&KuN$Ö­[·{÷î½{÷þÎw¾£¹ÓèCZºPZAB­I×°ë5o¬¿ßfý•Y¡€Q“žï…4jÔ©õWèËÉ-@\¼x‘ki#‡*ƒH«I(" CµY³fȦ6mZ7iÒÔžDåÝ@fýÕðˆ–ÓÄÊ>[2z¾€øÃÕ@À^vYœ]W7n¤êHM2·k׎¢cgÌê ­C5ZгfV¯ÂòJö \;vêÔ)ªÇðñÇkÙ+%Ÿ={Ö EÚ‘0ÌGª³Ï o¼ñFæ+-,,ܲe Ì’][” Ò*Áó'~±Ü±ˆ¿÷½ïqùôè‡üËd>ýôÓ°_C8hÕª.>Çž={x øh´ÂÉ“'ñʵ¾Ë!¸ë®»Ö®]‹ææcUàÈø À>fµzbРA÷Ýw.õÃ?l8Ê^DZ%h£eË–?øÁöïßæÌ™°[T½€8~ü8^T×®]ß{ï½÷ߟ¾ú@ÛA¢³M©š£V­Z|¦½{÷:=aè„êéÓ§;66²EÖ!Šs§Ú õ£ý+Õ郰€[ðꫯ¶mÛAè¥K—Ð .\p›"ôAÇŽßzë-§ÂÂ»ï¾ ;lÞ¼9ì†T‘V x ?þñ8à=\ðþ_ýõ#Fh›uv´û.Q@^^^ß¾}G‘;d~øaóæÍg̘vC*…H«„F¡x±LÃnˆƒ§íÛ·—Vо[q<úè£o¾ùfØ­pø XNYqÀrDZ%€cÇŽ…݇¯Q\\Ü®];)°qÚ!,tèÐáÔ©Sa·Âá+ÀMš4ÑŽÎ,EÔUBµ]íAà%ôéÓGú@[ü¢¹¯Zá†nˆ·4œH r.~øaÑD ócEܨ 4ÅÆo9éƒ [dk…~ìuæ4t uÒ ÚF]4à ›bÁ“ƒÖ\îÔƒÝ<.ì–Š2?M«`ŒÊo.3a”‡Z;d =xÒ‚6¸†<0˜`–;î¸CÈ!sE{ˆõ @Wˆø… ˆÉðÄOpn@å>|˜kD¹hXùÔSO%?I@~”D>sæLX†kX} ‚+€d‡%‡*ÇÁ­M›6Q»”ú@-Gâ÷èу¢P*4U5ó“ü4,//OÓ!ãÆCç9•P¥€ °}ûvÑeò@RÎÑ£G5NêùÐ{õêe@¾¤@%P*ë#<õÔó±fÍS¬&ÁHD°bUÁ ”IEž/î¡'¨JÂzäÈ‘‰O箌2èA‰.4ùæù® …lÛ¶MB ô‚kÚfæE¨Ñ´6;v¬¦ÙÐ:$]Î;w©‘Ÿâ±Ê„*3q¶ÝÌö²AðAÀ–ˆaœhIS¨ Ï·xá…È߯_?1€€°†Ð—-[Båø¡ä‡ q¥¹@O@p&L ºäOB§^‰oêÂ?À³'¥¨¸‹ã.D¡{¾Ç“““C ¬ áÊò‚¾i9 C«T9¥;wîŒ2Xꕃ> "TQeŒ Í*ëà6·5K ÀÐŒYP„—@¢1˜Jƒ†˜Öb+(ßÜ‚&aÞ¡¸€»HˆÞáÁâââY³fÍö‘@%P,NcFŒ?b3AØp‡‘Ôf¢büøñ­[·ÆÄéÓ§çKvZ…g@Lùf’\®Íãºöˆ.ª Jð|#HbTô öìÙSƒ†q·›C@äv1 5ä¦Òí5Bš¡ñyþ ÒĉÑX=øH[”’Mbâæiš™s Ô¬YSÁ³lÀN˜9¥ à1„/ר ³È/<ó,Z êÄ•ÆÌ™>}zl6Š‚¾ñ¾Å-òKpP¨ÈôË´\öF†žÒM!è˜ Ð"{#ä&DeïF°¢*ì - Ä hÑ¢…ærqÈ©IcØáË-R(Ÿ8»°¾ôÒK¨ î–í““tÝ­[7½öáï–4‚$æ•[Œ¶ Uè0òP àD´ÏN™2…ljvËMQ4žÇá>éA]°{]mQ5U‚D?ôa¾®–cc}$~rÑšÑ;î¸Ã’2·°†$m¡$ò |‘ΖR }~ÂØïD±%#"ÿܹsi$rœÌXý$ê/̃½Û@ë”I¥2jÄAö&#dÖL²–O¤/=^‚Þé¨ç4I‡4"°Ü®‘û®2ÄÎ.´ñaž23gF`5„øÎ~0¶v qïªU¦¹ÅºÖ…Ö’À2Xc˜epÁСCaœ@±¦(©»_&§éuµE•eéØ!QÄ«-LeÈx%SaJ$KbB(kbé/:Æ AÔ"šëÖ­‹\Ö¼‚&ðX¹µpáB~¢E,D™†zõêE™æ'×Úµk±ý©KÁuqh$¢ÿ‰'ž  ÔŽ'.)¯uãÆã/Uлå¤àÓ¨(G˜ÚŒj+ôAÍš5ñ¾ýío‡ý¾lˆ9%·¾uëÖ#FŒ»EY‰_Gˆæd¯†°×É¡<ð94™œáf Ïþò/ÿ££ž—.]Ú²e˰ßMn¾ùæ›3PÄîÝ»a“°{¤d¥ue‡®ZµJ3iÅo¼Ñ¡C‡”[e½„*9àf])×q‡§2Í0ëÌ;‡HÁëTI8•5À-PDš¸ëh3­=uËOª$œJÈ&  ÌÄZXÀGÑÖ„š5kF|ÔÑ!y˜¥É™¦bvã—Ö*;Ž€vPÛ)Š) hJ‰;è…(¬o†{šp*Á¡|Ð1 Ÿþ¹ ƒZ•`o À µƒ¥ZõhÓ¦Mû÷ïߺu«B)qíÚµ«W¯¶Ã-Z´×ù‰'ž°»€V¸ãŽ;ÌSMS§NÍËËÃívZ!Îý &ZQÊab1¥:,Å€Jp^BUÂ!CVú@Â&¿“+MËa… Nœ8Q¡ŠLº®—/_®Ÿ0ÑöíÛG­Ÿ³fÍRH!'r?Ð;TÝ®]»P6?ü°¶/8P-TncýúõË|ljj\µjUlz~~>TK«lÅ0sæLRì,5‰”Ч*Ð<è,züøñt“;Ê@Áï2ù&ÒŠœœm8ÀvVih R4Ë™QØÞý>{ölÄ«‰†m2ØL!HÚŠhØjæAÅz%g9Œ3Æ‚²sçNÅ&ÐS-Z´Pð!PEEE†õÔ»öíÛ׫W-Bša6¢:T£#,()¬¨)I®àLÜ´2@pCß4 ¿Ø„$’Éãùaï´ûF¤Ï]HßûóÛ¨ xf„ Þ=ðÀëÖ­ó|¿{àÀ)où矎‹€2ÀKhÕªUÊËw ¯¿þ:ôܹsŠtnÛ¶Íó‰Ú£Gyóæ5kÖ 9«€£XñÚGIN~ò†·´ tñâŨ2 6=I1M±ZTÄ¿ƒAtKᘖ”€hí×ð}—CM„m ©wÅÅÅ4OÌÅ]wO,ª…— È‚)Rl‹&°jŒíÄÝ$HLæüX˜GÒ\§—(Ñœåðì³Ï*/–ÐÏ6%€—FŽ©@ìÞiƒ½Ãã†cÓ1|¤µFÚ½ ƒ¥¼|‡°°oß>‹ê2ÉÃ?Œ…±Á ˜çØR[¶là!0…ÅæÖK/½íAÒØ(dE‚áùñ4¹Î”ÌS}älB¯dÖQhžWËd0ûP4žC¢F-Ö‚l$rQÚTép‹?@ÜÆ9Phbˆ^‹M=_I”Fñ²}t¶”é´ 2Å’˜òרù…²pGPU% ÜÖØòƹT\/3kftqÈ~VƒEæÁ;î¸Ã i3¿‚I?~ܸJk?i¨Êì0€Ê1cD0NŸ>Ý6˜Ð\Y@ezgz¡€fa¿õÈ¡ ™“ E¶(,,,((@@X¨‡Y³f!L!GˆOѨ È@ÜdÀ®‡Ž»W¯^8ž«W¯ÖSò@yäLYIãÇç§}₉„êYgþ@ÙrØåð*J¶N8IÐ)ˆ[½£4zgÎÕÙ½{wÊOÿÒ‡"…ú=Ò£ ô­÷ïß/y ËÆ]õÞ11ÛÍJPó”çKyžUðÔºüü E¦“&ЀÊ4Á½MÖa› 3²‹Ã‡»G±¨F*AÑ ìè šÀ´Á؇ÔrÔ¤¢3j@FÓPøž¿D ¤Ó<%«\ãþ¢3ŒýÒ6µ£?lyŠ@ÇÌŸ?ßìAÓ³Ã-MòÊ3ÎulïìÔÿ@Ž‚ÆŽ2òéB†bb/Z´ÒEÄiZKçœ;wNqO1›Žû@XkÜ’ÖS$r­¥¢ë:(ÒuÜmJ´Oœ…#ì•EžÏ5š‚¶4Ûû’6$ú”_Í#ÜÅE5R ±hݺµ.0^CT¤3ù윲VÌö. ïÀS’Ýf=F‚c ð$lYš@£œJ‘§ _•v>³"ló9Ks~É““““Ž÷&MàZT%`äc LôÔ©S1ð¡R¬®å`ƒ#Ùaì*í£$l…ìV…†ÄiPüjòà—¯_¿-m‹ËìxÃ0ŠÄ¸”F¶kÂ-ûô´@„mXÌÞ°Û;Ï¿MÇú‹lGÔUŸ6aïtí”)SÆŒ£Ù©Žþ€âÛù€æÆ¯Ø¥¨ˆ•@fu !å™™a.J[MÉ®^½Ú^ˤ3 ÈSVì ûAMràðÂx¼EØ.­SP|\f«0êÔ©CÇqœs`}§ä8£Xo26Ltv L¡‰èÒ2x¾ì¶)‰ …wh…3? 5ìA¡Ä¶co¡¨`p»ñ©ÂUW]•Õ ™¢>½œ;WÑ¡ÒÓ­Ó?ø;oÞ<$µVËé@ã>þX74&??_ç_’A‘´IÜ´ibšªH*A‘޾ño¤°|‡ •ðÅ_T½SCXT˜_i*Ñ¢EO=õT:JÆr²èÍ:D=86ڬѬJ@÷à;Ç=õ3%Ð ¸í),óæ›o^²dɯýkÔ–éW\ñÜsÏeâee!2Ûóƒ${ÖBƒ*x¿°°0É5¦å‚ö¾•y V€>¸þúë3¥8MÁ±£n\ÄžÓT50qâDT]šqÂKë¹s禰̦M›^¼xñ7¿ùlÌÒ«¯¾:3ïÊ!1poºé¦ªç(hër:JÆçN‡>;v|衇Òû^ÒŒ, #Tº7ìV¤{~~~šöÓã·j1kª äý·oßþá‡>þ¼DO5j×®±×å‡züñÇS¾ÚØ¡¼@1oݺ5îºó,BÔ§—ÁÂ… ¿ÿýïñÅ Öðd#âÎÅ¥¥MkW ×\sMݺuGõᇢ.¿üò+®¸"%Sš©ÂÌ™3ßÿýùóç¿õÖ[¨í°›S퀅שS'Þÿœ9s2Viš†§²@%\ýõP|¯^½~øÃBîŸ~úiØ-ª.¨W¯^ýúõŸ{î¹ý×Å-Ðüé:)á–[n »ÑEæ]¨+Vlܸqÿþýèï'N|öÙga¿ƒê‚ÜÜÜ3gÎtîÜw-Ãõ¦£Ø,P W_}õçŸþ«_ýjÇŽÍ›7‡Ùn¾ùfD’Bö+Dó%ðJ¶×rqéÒ¥¸–‹]1µæ:ì×ð'ìÛ·‡©¼k±x[úçÎãkY΢aë<5ŠÂW°W:pà 7d¾ÒãÇc9ÖªU‹Úû÷ïß°aÃt×8dÈè°FÜxÃ鯖-[öîÝ{ñâŰ{Ÿ2dJèÒ¥ TŽ@iìâÀAÒ Ÿùôÿãÿhô·jq ¬S§NòZá•W^Ñæ°_ß°~ýúíÛ·›}vÉiQ‡Õüã¼O©”oÚ¯¹æš°ßD¤ц")¨ô€ Ô¥ Œ™ïc\”, J"}SGY0½Œ}ú½ï}qáÂO ü†œ"QÒÊóÅ–}¨K‚ŵ”ñ¥·)G%·û]Y½y´Â÷¿ÿý°ûu`ʄ݇* ¼À4•œ*AýÇ´Wô·€ 4„þêèÇ$×á¡92°#::@VxdYCFšRöJ\>„›H(“&M » U ê—d‡J@¡ä ›4‹ À-.P5kÖD`%©twØÝÊèiiheBïVÐ*#¹O=õ” ƒZ&îºë®°›àP5¡é¢4ž* :´E‹ 6DÉVÕM™Ê†UlNEà)3~ÆéÓ§³w)™@C.\8sæLy‹xÉüÕFe k|µ¹sçºY„dߦ#„ŽƒÃ£>š¾Â³F%xþY’5ÂìEZibY’Kf,H.3ê-‰f jü9(¤¸¸¹©c„yJ]ÛÏF ꯺)È—]O›y9êšÝ~£,ŠÓ( Q‚¤?BÍL!ð³^½zcÆŒÉÌfýª%K–„݇ª¸ò±ÇK_ùÙ¤L?þx›6mä ÈKh‰E#ÐÿÔOëìø€qñâÅ'Nœõ¡9jT…–lFSx¾?ôY 4¿BŠüzqòäIÛ90QêÚQž–Òœ20¾‚C÷îÝ/^|ûí·‡ÝõlBnn®sR \X2}ågÁ"TȦüÇ\µjÕ¶mÛŒ˜“|DxiÅפ#×°‘5.$‡@ôSÓžµ0In‡Y5h2h9SÔ€ô?uê”Ú¯îx¾žðJ”_‚Ñ3%ÊДŒŽHS—Í[BC 3x'ßúÖ·p¢³Ö0»€£¦°%Õév¼¬S Â}÷Ý———·eË–ÿùŸÿ9zô(‚L+Žì ±eäj§‚ü M9h‘R@njÁ×FU$9' $ÐMœjéBu\‰æ|£ò3?PˆW2ŸŒÀuhÞ¼y·nÝzöìyÝu×…ÝÝ,ŽÂòåËíãÀ*Œ‚‚‚´º^–ªÏ—h};vLÛÖΟ?ÿ»ßýNâþ“O>iذ᭷ÞjD¡Dž=™¬[(•gÂüáHpBlèÂóJü»_¶Jû²ò¤Éß A½: »¡®¿þúN:ñÞZµjvçªFµ}ûöl†æ:°-2°Œ-[U‚Ƭ¹œA– ‚‰3lذ!ì.ÆVg~~~Ø­pHÏ<óÌöîÝvC²yyyب(›¦—²»ví %ð‘Cú«"3u9•àà ÔªUëàÁƒðvØ qÈ2<ã#cÕeýÀ‘ƒCÞÆW˜3gNUŠé&äææ¾üòËv.—ààQäçç§ïØm‡*|J(¤¨¨(óƒN%88d0<І6lXº×:d ‡Q£Fa4„µ~Ä©‡p››[PPpáÂ…]»v¡ÒtH–CV€¯?iÒ¤ƒBË—/ÑPps !£»]?~ï!ì%…Áƒ‡Ý„ Þxã°›Pn4kÖ,RÖ€S B®°[‘"8äÕ¡C‡°›õpG_釯áT‚ƒƒƒƒÃ×p*ÁÁÁÁÁák8•àààààð5.«]»vìщ………5jÔ¸å–[é=ôé/¿ü²-ö„:˜ ¸>|xòÛ÷óóóyjÿþýúéöý;888d —Ýu×]Ç7R^˜3g÷îÝË-;}éÒ¥¹¹¹f µÎ÷QæX´÷LGgäääT@¸£«\à~‡Œá²'Ÿ|’ÿþþïÿÞ$¡P 6äZwÔb}ìØ±úIžC‡é"n øý><8lØ0´‹Jx ¦º @ÍsppppH—ÝàqoÉî%K–ÔªUË> Jjcܸqú)ç   À+ÝQú÷:F8èƒØ@¥yBÐnߊƒƒƒC¹ðÕô²t€‘þK—.EäååÙcJºèÞ½»¶Vò³°°]‚À_®CL¤k|)®€^±bE5rrrj×®›AsºFÄ7kÖŒŸälÛ¶­<¼Rî½÷^UÈÆÕžEyh>Ã@æààà ¾R ˆ~t€ÂÝŒÙcJ8 üý§ú'=¦ŸÊ`ÿµ!qŒG+ôîÝåÈ@]£G¦ö3ftéÒåÀ¥µ’&IaøÀ!0ó*ç™gž!½aÆÇ'åàÁƒøšáƒÚÃ~φ/"%vÄ{À€¤Ç¸$ÚËmøäÑÈ„€ Â-ÍPŽ2¾Šq„>@.#XyA ,ðJæí1¥ÀÄ2?½’Ù“‚V°Ãž´oß˽_¿~ˆû¸§HcÝ{¾”W¬àóÏØþÜ¥UÒ+4‰všª}ôÑ@:¥ÉqqþƒƒC,ãÆ?~ü®]»L"cóæÍžoàþô§?5é VsÄ¢_Ù¸°Ï3¸pႱku1gÎä[\éY|½/Á8öèI衇xYf¦× Í,çòÒˆf^7B9î¡¡.£EDÑ’ô×X ½;!ÏÀÁÁÁ!1q˜ªöªg uDY`U³}aÍñ¥åË—#â4nQdx!þ×*AÁöíÛ=ktÈ+SÒ4C`bqÿ†3ô”$$¾‹‹‹“„òíÛ¶m›É7åààP•ðè£z%cà‚¦QµBÒl· L£rkãÆ X›`Œ5 )WInÆÌ3†?í^–@·G‡<ßr—s`Þ¾ÒÞ½{ὃÍEÇn[+ ”Œ½2Ãy Þ´®\³fÍTÍ(m’ ÷¨YèÄ9ª!t¤qÌ"{IB³Š20J~ bËE°5JÈÃÒ$%,X°ÂÈOù˜¹=zô0»Ä¤Ì…¤‰äiÕª)+V¬ðüƒ+T‚i¡ý“ŽðsŸÌ\ð Us—~CP,)R rb÷¨çæèçâÅ‹Ùôj¯F `óæÍÔxË-·ÐÞEíÚµKˉ6â;ñŠ¥ÈÌ[¸páB‚Â'MšäùšŒÌ¶’«¨W¯žSr•âÎ,ªÔèò SµK—.f£n`U c¬ÄW¬Ä“Dz$///Éž““CETM¬Z¨çƒ‹ŠŠÍšEI¼ÿþûö³ˆržÕòÊ=z4V8UPޤáY~jí¥~R] ³çÏ<ôÐC4¯wïÞ¤£'¤<^öñg*Ag~ÚJC ,Ô©y#û÷ïçšÄfC© ¦éR¸}ûöe~^½Î%§@z¥Ù„>ÏJ=Øåàåmذ<ýû÷'3/ŽÖ“ & ‡ý,e’™V‘Ù¼ª®]»V±9d#;×^{mØ­¨dàb5K1 Ö4bÆ”¤Œ¡¬¹¹Z•c1 dàÍN†‚‚‚åË—ÇVÊÝ#GŽh/æBÙµ¿ž?_Ë_$ž¦¯•ÎuŸ>}xöÅ_ä'–*´èƸ;fvD’Ü^AúÌ3Ϩd#ê„ltÐl"?~¼º\ãË/¿ û»D(žÉ“'·iÓ&ì†üúõë÷æ›oÚ«2‰{ï½÷رcS§N »!â²Òì–[nA:Ȭ•DzĠƔFªb€JU(s nélT¤íÍ7ߌ%šx¡#wgΜ©2ñ0ï°Œµ¸F$bÚJ7 P0¦_úi e$;pWeÒ~zA iööíÛ_}õUŠ"”‡AgðÕ¸ûÆoPªôÒK/ášÐwJpmf%V®\Ù¹sç¿ú«¿JÆsp¨ AfÁ·pæÌ™;ï¼sÔ¨Qa7-@ 7‘¤1éXÖxè{.ÒV“ &Ûq¤Çœ”ìwªkÕªUË–-‘ײñ‘ìhÙÍ›7kÄ»4h've¢ð(– Ù‘õ 0>ç{ dC[P¯y·€îk…ÿJÈJà°?ÿüóðêîÝ»Ãn‹CGݺu+ÆQŽšÇ\I‰˜FE¼j±»™FÕPÌ3Ï íG7ìØ±Ã+ D~jÁ;yúé§•Ç¡ãààP­C`ïÏ5xôÑGë  švŽÍæYÛ¶Ê„––R "¶i!)Ù=`À€9sæ Ç‘×2ùµjéÒ¥äoذ!ר 2pgùnôŠJ™Ýsê‘i0?Qf”ƒ;¢8¤òE´a[ŠM9S9½¬yŒ*4šÓËTlz9Ã@ ßèÌ|IöI“&)~†Ö)y¾'aÇbü´sÚ@¾“ͤâmØå˜ ÍK¿úê«iQ Éñä®ÃŠÕÒQ€S Y¬P Z•„Ð42’½Y³fHç#GŽd¾1Úå@íZ1%„?—€¾êÑ£‡YtåàààPUí‹åþØca#ôÖ¬YƒŒ]A”à© °ÃW è¨]»v¹€EUšàE j‡šYt”y<ÿüóšc°S :„ßàéøñ㤣5(´wïÞ7öö¡ ,(..ÎÏÏß¼yók¯½ffrLxð ®Í¿v¼ÿþû-[¶´ÇýÉŒ"±CÑ"ß÷Ã~PñZc÷%4lØ0“³N%” |ðÁÿøG.®¼òÊH¹E«h[æ*8•¸SÕÊ€S åÂý÷ßÿî»ïšŸß§žz*t¼oß¾)S¦HWÞ½{ëT×Êãí·ß®[·nètðœJH\pl‡ÔcÈ!#GŽlß¾=†ùøñã,ÔŽ>ðüAÈ•+W8pûöí©*üxðÁCìƒCj~Œ£ˆ/ rß}÷…ÝlÂàÁƒñ«xiHLìhCˆn–Ʋ† ¦H*ø|h¬T¾lÙ2¼„°ºæàr8/¡ ¸cË*ƒsçÎyþð½IA@ïÙ³çÝwßµ]~’h§pMâÉ“'¹àJç‚ô˜=®yrê†jßµk—)¿]»væ.åPšê T­Õ;ƒz¡.Ø]³›Û—¸msHxó™YoRåἄ2€— sé’ÇÑ£Gù»iÓ&„`=ÌPû´iÓͺnÔ¨ÑÊ•+ù+OB‰]»v;w®çËÜûï¿ÿž{î),,”ä]²d ‚uÞ¼yFÚN:µoß¾ž?B•3aÂÛ v²mݺuРA :B3hCÍš5½’ã é/m¦ƒëׯ7úÏÁ!‚p*Á!õÐôò°aÔyyyŠUµzõjÏ_í£Á}¤¼„#2”D$¯„ìîÝ»M9èc mî’gçΚ@S‰f]©çÛø³fÍ"¿<Ø& 8[TŠZRÈE ä¯ 8(*Yù)} ª)|ĈžÎKMŠÁÚµkišƒŽÐ žåZÃM¦©TaêuH-ÐÓa:PÅàŽÊ@‡œ—P^hz™ \„¡C‡îÛ·wxöìYÏ_¢ÈŒ˜†Ÿ-Z»0I2TÐWxÚ‡I43ÿÉ,%ò}øðá¨" î{~ŒE;iÃwÜa§£ìT§Ñ0®³rnb°ÕGÈŸ¤ªC³V•‡S e£{÷î0¼›g®rss51[¯^½ãǯY³& ¾5Á°`Á óûï¿¿´rºu놟¡úr5@†¿*EŽ£®ä¯ oø¬rìü¥Y&L@%Ì›7O×»:†ÆžïÔ®]»eË–…õþ« Pº±a4*7pT6pHÇ9$ÆÑ£GßõÁ{Ã$G#î§NÊ­GyDãEHj<\ôÒ¹sçÎæqù X)iŽ\þ£U«V%ãÀ‘MÃSjÒ¶mÛ<\HSÐx'š! ÛÌ™3È#Zª„ô›ÒD7>‡4é&®pASåàd<ûì³aŸªlhÌ­8J œ—P6òòòda·"›€áo®áÕüüüF>°ñ‘éfìË׿Ø×HmLlŸ{î9/Þ å,^¼˜lf˜ âÄ ^D³=u>NçøÇ•J%‹ç»¯f¨î9]Æ<ûj6»}IJ äs{%öæÙÕQÐDj¯³sVà6H  …B…BA¬q@,‚ 8ŽõzÍ;µ„‹8Î^¯wÚ¿ ?A øëá+p¤„KE£Ñp8Ì; øƒJš¨¹ÝnÞ¼¤„K™Íf*Ðz ðsx<š«ñŽâ¥ %\¡X,²ÇÒ€»J¥²ÝnÑ´,.¤„+hµZ…B¬ÀÝd2 ƒÍf“w ¯)á:Fc8bŽv»ËåŠÅbhOZÕ®#•Jib¢R©Xc*ïpÞ‘Ûí6 Ç®@ún15M<GóÀ3Q}f³Y§ÓáËk£[P¹Úív©tÅ$€§aÛUÉd²ãAL :¤„QV Z!“É$“IÞ±¼¾Édb±X C>ŸÇjƒ”p;ú]ŽF£ý~ïóùþ±W܉ʪ"‘;Å)á^©TJ§Ó™L&¶Ç2ˆˆm¢žÍfƒÖ“ŸËËâØl6~¿?{½^<‰p¿ù|‡—Ëe"‘Ðjµ¼ÃyH bb‰!ŸÏëð<Àµv»]½^¯V«‚  $ƒ'CJxˆf³ …jµš^¯7’ÃÙ)È_±ó$èE»Ý®T*ÓéÔf³ÙívµZÍ;´w„”ðX”J¥½(—Ë‹ÅBòyn;H¥RÖ~Ìö)R*•” ¾^ Ïô³c DnÙ¼¸IEND®B`‚gateway-1.4.5/doc/wtls/fig5o.png0000644000175000017500000025350107374232663015163 0ustar toljtolj‰PNG  IHDR‹k¡»EvtIMEÑ 8*vTxd pHYsÊ&ó?gAMA± üaVÐIDATxÚì_LSçÿÇ«‚‚BùŠÂdÂÔQ]¾eñ‚ª³¸Äîb€&âvKØMñbT³ávKÊ.„d ²Ä’¸Á¶„&ËhvÞ€ûË ]2…du†úgÔ9鿤äûþÏ<;¿Rj{ZzNO?¯‹“ÃésžóœÃù<ïÏçùsݳˆ5kÖ455‰^¼xQ§Ó¤˜}lVÓÓÓcccØ1ÒÒJûÈŠ*Š  ÂÏŠQ'+uŒ·Û}ùòåS§NÁÆl6›ô§ÜÜܬ¬,l‘b||Üï÷ÛívƒÁ°B§ˆÉ’áW˜PÐk!¯×Km\ȧ¦¦&-- ™>|XLƒÓ‘vW¡­­­8RTT„«ààrÀäI%Ñ fN§Sé'Ê0~6lü­·ÞÂ~gg'4¸§§ÛÆÆFÁ ½Øoii©¨¨èèèp ˆ9ÀºQ™ŒŽŽÂ~aÅÒÌÛÛÛKJJȨñ“ÉdJMù<ûì³dò¨.°ƒ_‘Ìãñ`ŸjäŒ}\ûUUU¨7PSQÊòòrä€}—Ë…_‘^Lɨ¥]ua¦«±±1Ý#¿˜"Úþþ~8Ȱ4³Ù¼ ´rã8œ_¤Ç ¯¾¾;0Nʇ’!ÁR­ÜÔœNûV«ùL 444ˆ145|-Mg”```G°ƒ éõ{!ÔF é,ò©)rÞ†Y>È–aŒbƒ6jˆ4¬[„Î ú§ÉÅd ’~h¥—ƵdÂ8u…ÝÕÕÕ8ˆ?‘R’Éc‹ƒ¬£~‹!Öf$ HÔÌŽÒ¢¾Â)b‘ð'¥Ä–*.F%°Bÿ µPI!«öC‹’©{ÔOL Ëxûé͆ À, s…Æ)b¶ÈDÚ"½X¡aW0£ýDû”^f©ËE»xÃ0±…”OÚ¸-mî&Ñ]Ü–FÃDB #‹ÆéR±«ûuuudéÒî0ª+¨Z@a°5;BÚÅ6ø•NÁéTZª‘hd+£¸•û_¨…êâ#à™R£·4ÍÄÄLEü¦’••µbŠǃèÙëõâOŸÏ·ÿþÇ^N¯×‹û¸nÀ…ÈÏÏ/**ê@Ù Ãcó‡Ò‰J?W†Ñ8°_„¡N§³P@÷¨éG Òø5*Ô0bõ‚ƒ---¡³…ÉCYÓÒÒŽ=êp8p†ßÕÕeµZ'¦î0ÔB¨" ².— %AÊËËQœî÷û[[[QeáÒµµµˆ(ÄŽ<йÛÛÛ©\éÇÉHPÚEPxqáEJЋKŽ*üMòˆÉáÕ ¾çÔԔ𨱠 `CCC!bhjb"?v…}Ø ÒmåÇyR†Achr„Q ²‡ƒLùó`†‰‹›¬¨6 Tlp!S8z’üxj$_ I£°Õ‹ÔäIõá(PMe±XU2”U_TáÀqG]G§Sÿ¥äZm°Bÿ^w˜JÀô$¼»ÔX„·™†YŠ“Œé8M—Ò N4~‚½Á à„Â$`°™aÞ3ö¥™SŒ+ª;Dyâ*H†œ)ì‹2 Ç™Ê Ä¹ÒÂ,ƒEq]”7B}äJ?W†I`†1Œ‘vP' b–þDÚ «_\3ˆÀŠÅˆæS`ÔÈU ¶”!ÎMžê ü __ÔZê±^|±Õ’!7äOçb‡« ²bAˆÀy¤¥¥ÁÆðŠ»Ýn“É«ˆ¨¨¶¶Öçó‘¯srssa½ä83 “p”””@GQ?x½Þ‚‚H2uÇäêâêBm¤(]€„§««k||œæ'PWPø@Aq ΕömÇ§Ó “f{c˜„fxxØn·ë„ ™Ëw›ÍF=zJß.‹Š™™™ºº:Çc0&''iHøÐÌúpXlß@U Ã$(CCCýýý>ŸO't‡-SücÐH4Fmp+7Ã0 莡†aF°B3 Ã0Œa…f†a5 Í0 Ã0j„ša†aÔ+4Ã0 èþb‰vp»Ý.—‹fOêõúÊÊÊ€µf†a˜‚çCk¯×K+±/þÉh4ÖÖÖ.Ó·†a˜åƒ:áñûýˆ•C/^YQQqâÄ ñϳgÏNMM zrrrø ÞŒÈr|†–a°B'6æ²²²Ðò&kÖ¬¡U@”¾'&N@‰á™ù|>òÕT™>·[¼555‘~Ô–a˜(a…V5ãããØê„e9JKKuºî:¡íííµÙl±ý¤~qqq__×Å/ŒËåjmm¥ÑF£Á` % Ä{xx¸½½ï!ÜAœ‚—$Dz†ab+´êp»Ý¨=±Id,«ÕŠèŠkaE¯±oTcc£Çã9uê”<•…Hwww÷Ýw-´Ê0Œ X¡UT¹¼¼œ²TœœœœÑÑQ¦—}:ze…QSSƒÀš‡/0Ìò²À¨ƒÉÉIƬÓÓÓJ?mÒÔÔd4!ÀÞ‘‘‘ÙÙÙ‰ñn ›Íæ¾¾¾Ð‰@b\ ¯–Ãáˆí-àÝ€<£Tü’0Ì2Á_,Q ˺H»<$)]­ár¹ °ƒÚÖÖÖÝ íœ"÷ôô æÆéÈ$œk]¾|¹¨¨è‡~˜™™±Z­±½h3Ü…ƒÁt¦Ã0Q ­h8˜ÚèííUºÚ2VRR‚-bb»Ý.cFIõÔÔ21™L¡;Dð¿ƒ<Ãóëïï_¾æ™ââb¸UUU¸£¸Q¤uBǰ¨ÖŠÀ"¼ñôÅiªžÒ7ÍÈEéÁäÌB"F¥MøIN&''õz=¶ñ¼âæ±±1eoïü(´²ÅP'ýýýñ·V«Õªô}32áZIü~UUU˜3gTª`¥ÚQZÎÄn·WWWÇí¢ˆ¤§¦¦,‹Òwÿ·Ð-Îá AIIÉèèhœ/ ;…Û¤ô­3rà‘bÿÿOlÒ\ÕD”g*¼Ê{Í•ŽWµ@é„Qåg˜%fyh¤bšwß}÷àÁƒÐf7&“©¨¨hÓ¦M))ÿz'wîÜùñÇŸþù€ƒ—.]úæ›oöïßÿæ›oê„ð×^{-šÂ$œ<ÓºÒ#^¯ „§ÚÔÔÄz €FHMMMñ'Ø8sf³9àJfPùLLLÄÿºš¯çµŠöGŠutt@ž¯_¿^WW÷Æo”••åçç‹J|ïÞ=l!ÏçλpáTynnŽ~ÊÎÎÞ»wïÛo¿íñxÞÿýÔÔTÔ¿Ñ, ét:Kžu‚”™ÖKÀž¤Ò¥S 5²<‹êõzntayh_¡ÿþûol=úú믯[·NúôøäÉ“NDϨX¡Ü|ðÁG}ÃË/¿|ñâÅ‘‘‘íÛ·üñDzK¢ÎÏn?Äý±2žÕ²~$+q7ÓÔÔ¤t)Ô…ÍfkllTº “h\¡¿øâ‹]»vMLL¤§§#&øG Êmš;´víZ£ÑHcÄ@~æÌÝ#½—Çää¤ÒÏC&ÍÍÍô¡(‹ÅÂÃðz½g™ÿ'.ÕÕÕ :¥aGã ýÕW_¥¦¦vvv"JšÀjµB}ÿýwÔ­×®]«¬¬Ü¹sçâdò7nܽ{zÕ—W˜8ÏŽ-ˆDš `xx¸¢¢BéR¨Žœœœââb§Ó©tA&ñвB#¦1™LÕK—.!8‘rï޽ǎCê– ´ùÓO?…ÞCõå•§±±1¡?±‘>|øp¢ÌáŽ?íííßÉ“'—ZÁb÷îÝ=CõåC0z*¡»oñ¬xyÁ¥p»ÝƒAéR¨‘²²²³gÏ*] †I<´¬ÐW®\ÁöܹsK‰âºuë²³³!ÌçÏŸ§ï@åçççåå-•833ó—_~êËîQ¦… @â~‹>VÊ"½<Ž^Ï®FZþb ܆¦†¨7;†-ͰڲeKèÆðM›6AË·nÝúÓO?E#±ðFFFˆ#“˜OD€ü+++KKKÿŠPfjjjpp0šI™$Ò‰;ðm9`—%x[xÂÃÈ@Ë €øúõë3¬‚?…””p–((( aƒêG_€Ûxê©§bDÙúG æÑx x>}}}òz—F›Íæ„ ÎćñOZb®¹¹yppR ?5™Ø€›ÛÖÖ“ú~3¬Rébb†fzÅŠ:a˜ØÁƒc˜mvv6TëÖ­ÓÓÓÑ[lIö*Ë´/¢0Ó?xðàáÇ)))«V­Zü+Tv||&ÙÀÛkÐ Í]¤+P©ðßgÍ`±X¼äÙÙÙh²2 x€pzxö¹fЬB“ŽÆ<[QÞ¹FÙ@×ÛÛ»ÔÌ®Ç{¦!ŽC†±MMM]|ÊÊ•+ip;naõêÕ™™™Ò”Èmff&+++"‘†‡ár¹øKiiiÑ|³=™A›[rsszFb¤ìß¿æ<::ZRReVõõõx’MMM¬ÐšA³ z€ØÜÜÜ¥K—h þ‚,­ Ùƒ7°þUAU0"d7F-–ç………{÷îᦠ¯Ôx°3Tù?þ˜ŸŸ¿/€ÛÇÁ'žxÇ¥9GIãF¦¦¦’¶‰’À¿ƒ:ðþØív›¢É(ûn¾*É„QšUè Ð*“.\Ðëõ¥¥¥uuu8ˆP1%%øM2öå—_~òÉ'>Ÿ: ÅÚ±cGµ–œ\yc:äA3„Yåçç#&}nvv6nMzj}ãÆ ˆ:~Ú°av¨¹;¢/o ˆ~x%Jükx¸r”ÐÊin·Á4¶<ÄIr’B¡_ž?þêÕ«ûöí{õÕWÍf3Ô(hÊ :áÃa´HBíÏ>ûìÃ?LOOlj´˜Iöj?‡ƒª-h-ô ½víZ8K…ÎRÒÒÒúSK¸„àðKà¾@§7n܈ü{zz"ú wss3BŸ$§âââáááÊÊJ¥ ’ðàIBž- ß–-[¨ZŒH¤ËËË“|ÈX}}½Óéd…Ž p'''éÃ8Ü<Ã$-WèãÇ:tÈï÷ÿuïžWòÝÁ¹¹¹[·n…øJ âæuk×Î ÜözznÞ¼¹I`ñÒ‘ÒÚÚ*ã,’g(èÍ›7ŃáË3ÈÌÌDzˆñR ÿð6mÚ„k!" ,›[ ©Æø€×‰—ÿŠ!⨃ÁÀ‘4“œh\¡ÁÃùù?ÿç«N=ÓÒÒBŒxDÕ`üïÅ?¡[¿Ý¾½1''&½Ñ2–Ë…g°XžuB¬iVÙÙÙˆ•C$€~ÓUœ›ÞÞÞ0s>zôèÈÈHôÏ'áðz½xJ---‰û¹uuB"••e4“Ùùc’í+ô‹äY'[ö† ¹¹¹Kµoß>œ(•vèÖ܃Ñ+ôèèh¤cÄP7Ùívx ò,õëׇVh‚®…À}bb"ÌIÛ¸µd*…û-//Ÿ™™±ÙlÐ’¤º÷ø@"M=ÓÀ ÊÊÊxR“lhy}h"£‰»³³Û[·nýõÁƒ!†}-M» 31DeFÉà _’a‘Áîîn¨…ÛíæaÛñÄáp´¶¶òÊLRÁ W"mâ†äääܾ};Ä%¯ç¤^jjj†‡‡¹Ë9þà#’¶ÙlJ„aâ+t\‰´‰»¾¾!²Ø§”_ýUFI233ƒ.¡±éôôôÄå9©šL…‡À½¡ŠÐÙÙÙÛÛË_We’‡¤Pè•+W®ŽÒi8 é3g΄˜™ªÕù0N§·ó+ŽÍf“ñ9†IP4;–[… G”¾±±Ñãñ„“rñ§¶ÃdÕªUëèO8ôáÏ¥º½!Ò×®];}ú´Éd š@“Í¿~¿ôøø¸&ï.±€ ˆ÷3Ù¦Ý3IKRÄÐjµ|D‘neeefff˜+ºëõú˜‚Ú`0<ýôÓí màð¶oß¾TåšÙꤪªª³³S«Í ‡Åb ÿ;w “Ð$E ½råJÅ£Ÿˆ&d£´===KͰ‚pR»4’¥§§gddD¿XuÈ0Wàþýû7oÞ ˆÑáj,FÆå~’qÆív{<«ÕªtA˜¨¯¯¯­­ÅVé‚0̲“ K¬¨¡¡aaa! €FH½aÆիWG4¼+Jà ž¾}û¶ôC¡ìb0¿šÐ9r¤££CéR0ÿ‚obbBéR0L<àVnÕÈØf³̰ÊËË{òÉ'ñS<åYdãÆ(€ôÈüü|2 êöz½ãã㼆ªP¼=Œaâ+tœ¿ƒ4Qú¨c¬zšeƒHggÍÍÍýõÙ³g•-gl«„Çâãm<Š€¥9M&Sÿ /@À+ý~?}‚­H Ò²Q”~BÑ‚g"ã. Ò<+šI4®ÐJá_ÂñýÿÇÞµEq­Û!(BPQy ¢9˜G)âbdˆ¥Œ¹”IA¢õ DIŒàCÊ£– L<Ô‰@’s¥Š{$× ˜cÀ¤ RF7¢ÆF-Q@ò â]·¿rŸ¾=ÃLÏ‹ž½~tõtïÞ½{wÏ^ßÚïóôôD›ÕÖÖÆÖ@GÏhßÑF[ÜÑ&åŒb$$$`‹}ZÆíììHíiww·Î9kÃÆJKKõ8±Bý°~~ñ¾LäææŽé‰u]]]¶º5¾=îàðqh0ŠJpͱpÑ"ósûå—_̹ÍŠÁñ3òÂÝÑÑA?½½½%ô éÎ(//÷õõ%¿ÐæêÕ«ÁÁÁ™™™föÇRæ ¥ÄÄDd…üQ`(ňˆ¨Éùóçûûû߸q£¯¯O%Ì “<‘’aú ’õ¬êÁ㇇‡744àu –Œ˜OII»ÐðIà«ãq,88¬ Åjhñôc'''wKÀÌ" ´ G”œ–#C³º¹¹±³²‘‘‘P]HA2¨ªªÂÏììlPµ——Tµ eCæP~~~ fèବ,Ü…îEœ@'›6m ½ÿ>ªbppW©Õê‘zŸ6,ýa%> G¡êâââV­ZÅNá½ ö`6ÅÆÆ²þØ~øŒŽƒôŽFü~U‚…„Î$]#ÔŒ÷‹lů˜Þ» ¶ØÇ–Œ:ÃÓÒÒÄ…¡dÈm¸Q&©©©t– ™àS=ÇÇÇgdd %nÄ¢«á,]‚üqªººš.DVØ’ùBåATlv_ùˤ|ÜTaã):¡X a´TAž¢QÓŸ@%Š„1cÆ v ­-ÚâüüüáhîÈ‘#xä}ûös Mgtt4ØHOü]ðP]]]ee%iúÞÞ^•åÖaN Î333õ$@]A=ƒ-ÀÓ`kÆ.ØÙ¿?ñ7˜ UÇÖÚ!C?˜©¤¤D;CŒÔszz:Ò`G|®3Ñå4Ê€ô999`zÜV iãK¨©©A2|0‹õá-ã#¡ÞHŒK***À”Ø×î1Æ'„lA½Øïâß„«òòòbbbØ–(ù ØÄ¾`ÙÜÜ\¤Äµžžž¸§6n܈ q枈>°‚‚’yëSŸL†¦È%cQÁ¶F‰c”C±špîÜ9[á_ ?ÛzÐìhêâvttd«œÑ>¢%E3jzq Â3766–••¡578RA;þþþCCC: 0RÕiuÀ^1h‚€&Qu ñA°Ì¼,¼nðx‹,[¶ GÈ­´v8÷c f%õ)I€·ö 㦰è î‚ã8{ׂð‰­qй°Æ§…gÁ&…J Ò††ÜWámwñT-$$éa^ H黺ºð)Òð9uâONNF‘È òÄ>T; ÙàƒD2âlVl*$+ xÜç9‡ŠÕÐðœã¸qÎÎÎ’6ÔVÈÎÎÎ_&Y¢7š#öøã³S૪Uý}¹:AŽÊÑŽKz ª¬WÎÆÅ‹åÌäbV ƒøe±Ivâ:-!J]8oÞ<ýwM²Že6G–Ék^zL®ÔÔTq·¼ÐãÅêL€¯F$vªªª4 ˆ÷¥îÓŽdš!Øšæ<Êô[€”°`Æâ²+2‰l] Ž1…khmÙ¿Múÿÿaëææ6U(«««äªÙ³gSžMMMÚM¤@d ×±æ†FÐq;vʪô ƒ@Oði£0F;-HÕÒÒR ¶‘žž$@õhuuRRxK{Š8%C‚€aÄÄÄH°9öÈGç0Øx¸#î ¦Äv¸NØd¶¼ñÆú©.88ÙÂCÁNœ8¹L¥={ö,ž‘úÉ=`‡t3ò§eý*Á §F±‡[CõLód.L@UŒEzæà0 ×Ð7nÜÀvhh¨¯¯¯¿¯OgÇìÿÍ#óðhnnöññþx Ì’€„8X³½½Ýßß$jrw®Ì–EìÒzhhhðóó³HVÔ:s™‚-ˆ„樄I ³èèhÔv]]ÎïL ›L;Æ"41hß2êì".¤ ´§3N!¸É U¸#È>>>ž¦‘‡µüü|˜iii45 ¯žn„çÂ#Ó—€}<)Oa§†ëÍIã.jµÚ`„ùR›ƒc¬ÃÁ„8Çc4&WYY¹yóæC‡uwwƒƒ—.Y²déÒþ~qʉ“&mÛ¶ÍÝݽ­­-+3Sâk³·¯ïøñã½½½QQQÈaüøñõõõëׯ7­` :—$¥¤¤ÐòÕ«W!jçÌ™3µ„' ž’fl%?õÔSì'ªNIÊÆÁaý;À£4Òlë‚ØÔÍ`Â|‹Ñí¿ÿîÝ»iQ†þi¤rò«ñ¿’0z¾d£ ð^î'žx¼ ÚðððØ»wïó‹üñLJ  eˆcð7¤j ¿ €y8êèè8ø—¿\ºt üM>±U'™Y$Z`ƒ"ITTnn. Ú9 Г-•¡Y»^^^†üUëºäöíÛhé¦M›F?AÈ WZZ:÷¿öL"m„……)‰žUÂ;’óà#ŒÂ±»ŽœƒÃ((œ¡gΜyôèщ'¾òÊ+´ŽåÏþ3þÞŸîìâB" :R{Ë–-===¾¾¾¿·µáx?ÒìÙ³gÅŠÏ?ÿ¼t3¶æK[˜*Áµg«XÐtdÀ:6‡chppxx8-z¦AD°Hgg'v`€Ë†L§¹EÎÎθuhh([,‹Ú àîÃi¢££µ3/̵a¬!”ß1<‚‚‚ŒŠHfUPTP[—ÂöÀ»nllÓ¾Ø88äC± R¡eKNNN«V­‚Pþꫯ [o77þñ¨hêÔ©Þ>> pök¯½ö?µµÏ>û,v@“8~ñŸÿ\³fÍÖÖö¶¶ÿüÛß´xyy9D¹EŠGSxhj[‚µÿ~mâib IIIh£AêäB„†â˜çEòžf^&ôƒ.„)€Èz0=lƲ4?GÈ{ rê®ÖžÒl=àõUWW“Wòï1b·¶ð~u.¡¶7”––›œƒCyPìL1ØÉ“'§L™vùä“OÞ{ï½cÇŽ½ð ýýß}ÿ=væ›o¾Ù±cGÇÝ»4ƒ¬³£ãÞÀÔ-ã°]ÈŸþ´xñâYD»ðâ‹/Zªxb^ߨÉè·ÞzKgw1¤?8‰õçç烳Áš «W¯¦f Ô%Ó[2[u=yòdð=›.¢GnØ!Ež"À`m[u%4ž r­É‘t>ãîÖhµÕj5nÇåÚ¨¾ù²²2[—‚ƒc„ X†ÌZWWçîîÎnnnFË ºswíÚ%ž86000ÃLJæQCAByÿ×ßÿîúøã¯¿þzQQÑË/¿l~aÐâKf¢ŠÙ2:99YgÀ AÙ 8[fJ‹^ä†Äºx5y3ö¡,‰R?%K =íÙ"àSáëÇFð1À$åšÃ~` %ÝÔÔÔÓÓ#qͱyófPÔ¸qÿªˆWü¤¡bJ€mEEÔ¶˜žAó&&$$D"‘Å„ *BQ=<¼vÚ´i“&Mêììzì±Ç@Ø N¶€ÛP˜g1 àaÇ€•i4ÚÕÕfÊp«¿hm·¸@Œ_ý•Lá“­7š¼KZ#g–?š¢BYï.®Ç18‡RaG iâ™,Ħ½:ˆZá§Ÿ~ÚªÅÐéCLrú—½Ž?Þ"£Ô ^å´ Xæ]hÀ^%:&&Ül¬ûÓ ÇøÜ¹s‡3TÂòb™ÍýÎ;7mÚ$ É1’HHHÀ«´ølDŽÑ%3tss3ÍÙÚÛÛÙ’¡… &&&²ØŽzF/€¨m92W´eŸxg»ºº¬zœv £u.¿–I'pVV–Äsª9€xÒ³~,77וCŽÙÓ%%%ó¾n› °°°²²’»;å°O(™¡ÅS®ÐʃŠ(¤cmmmddä3Ïlçåÿ04§g;‡]0ô•+WN:åêêúÜsÏŵãÇ×™ÞÌV<1\¤qqWW¨Z§1óáèèV¦ãööv“P’ô·ø$[гiÜ/æcùÓÁä ??Ÿbˆq/cVŵk×V¯^ššÊ{,88”ÏÐuuu™™™´Oq®vìØ! €Až7ÀÇÓ§O—\^__èÐ!lé'´odd¤™Ó¸@ð¾¾¾:ÑK<`ߺu+00PΤ¶ÞÞ^6ÿKüýý¯_¿þÇtwwCI›Ö£ lmmµ,CÈŒU…  GEE©ÕjìXp\xkt±±±\I[°~Ž;VYYÉVqp¨ì¡[ZZØ>HL–žžNaANŸ}öYUUK.ü+³²²xƒòzÅŠW®\©­­eGhF7ÐÔÔ$¦g•ÀÙ¹¹¹ôóôéÓbe‰³5ÐÊÉÉÉâ<`íF$rúøøèî<¹‚ºäèlm°IsÈÚ‚µk×J€ØòòòêëëO:…öbñâÅ`;Ð6Kð¬T¼¸¸¸œœ}z:w``àæÍ›â#ÔMM‰Íwrb½•]ò1_€­K! AAAÐÓ°êvîÜ9VJn[œ9söMyyùÈRppŒ9(™¡Ž?Þ/vrrŠŽŽ–ð_€=—·´´üøã´מMf in°i—‹é¹°°pß¾}¿Kè°ÜÜÜ$³Ï$ )Ó|HÕ4lP]]œœ †ՅŸ&¯é²£–8=spÈòô c?‹ŠŠ xÖ­[ÇŽttt\¸pÁËËËÛÛ["C!L÷ïßÏ&r«d°HÁ<==!¿Ð¸³‘W£àïïOôœ Ó-",òøAä­ÝKñ‚P__ß²²2Ó:–Ñà9rÄ"2v7XUU…ú,---@]¨y>P-Ô3ÿ`88dBù ­>á믿^²d EpzçwîÞ½ËNó¶mÛJ?333Åô¬z4Bl©0Ì»w‰imm5öB6†ñACzÚ¢ [œ%1­-Ö-Z„gœ?>×|æuøï¨ªÁÓ0ï8CKpñâEý±a888Œ[Ÿ3˜˜èêêÊŽŒ7Ž~655‰éYõ(Tû)–ÔCCCäûsÁ‚)šoÈ/ÆarÜPƒ›©`×®]‹‡Öɯ8˜ŸŸú¿zõjRR’v‚   ¬¬,@r9j@ærd*³———EjCa€ih‚í¥lnrpÈ„ò5´J<^¸paKKËO?ý400°råJ l òF3zþüyrIA—AçìBèiÐ9ÞòõõµFÄè#GŽPa -*++ÁÐÄúç3F=ƒƒ é™0æ+Ó£Ú\>“Y'æÎ;2!8Ç>̃HJ@F9E"73«á pŒ]8XªÃvâË/¿¤)`Z%¬ú5k–$YGGǹsçnÞ¼¹téR™>AÁI–õÑn^´hò5ROéåË—‡K?{öl‡;wî ½•TZhhè¼yó@ÿK®V«¹wÆá[Jç »…³³³ATÙ ?â#&LèììÄÿ&s¶¢nÉÇŸW»LÁí¼²¡d Me^^^EE;âêêúÁˆ½~N™2…-DÖØýàÁƒl4¾wï^Ë–3H퇅…UWWëwBË¢ÐôôðpïÞ½ÜÜ\d ŒÆ…‚¡5BÅÅÅ~~~))):ïUUU…¦¤°°P¿â)--åã¬z*BmÛ3!‰O_ ¯ ð'…]Žÿ²ùóÛ)+ùCT£JÖÐà0ÐÒ ïë냼&ß#555´ûnnn .\±b[ŽbNOO_‹ê***²¬†–”ÿ1lѲCñk'ptt”9Ñ b||¼Áøx–œœmžFÕÁpÑž".FxxøpÏh4˜G|ê2ÁËË«¬¬ÌÎWkkhyÐ33s¨ðáþï nç• %khÂÚµk¯\¹òóÏ?3...ƒÛO?ý”9ðjmm½"`ûöítDâ”›&‹Yµ´`_úƒ‰u2´Îƒà*ß”#±6Oãˆ~zF[€[p ­‰‰‰iii¶.Ũ>•É“'Û9=ëÁ¶.Ǩƒòçr;wîܳg¿¿¿»»; ù•+W²ñfmÂóõõeûaaaÐÓƒ@H[·nÍÎζjQ'L˜jDsfš)€B&$$è‰n9ˆ§Q9SDh±/Ÿ—«¨pd´­ b{DGGó¾c¡ü^n•°† úXìΓŠ Ç¥K—º»»ÁÍË—/_³fþl‘ÛŒ3¬ç8šÖÑž>}ú·ß~Ó™`Ö¬Y:}hƒ•ÑÒ#‹ÃN€$ q¡®Nœ8ÑÐÐPSSÓ @z˜än…;‡Ò¼MF# Ðboøðà N<´ ×Ëmm(¸W6”ÏÐõõõ»ví¢¹ÜãÆ{饗֭[gT¨‰ÚÚZ ­nõ÷÷¯_¿Þª%‡ÎÊÊZ°`Agg§öY H%Ann.ˆÓü°r\|£Í={ölII‰UëAÀqss£Éº¶.‹mpíÚ5Šc·5 gh£ üqh°¾NZñ |ûí·§d @Þׯ_W 3Å$>·[ZZ gŦϟ?¿aÃk—Ú$ }¯s4&ÂÀÀ€¶ŒNLL˜ÙBˆÇÄÄè×а{` ÔÙ*¡£;'''>>Þ>ûxñAªÕê²²2NÏ&@ùãÐPÌà9ññŒ °Ú›o¾ù¡€””ì‹g‡‡Äô¬zgÂÚðôô¬¨¨×^½M€¦×6Š5ŸŸŸ9k-P ¡¡¡ÈD²èèhÞæÊÇÆÏ°uAFø³Pl>AŒƒÃ4(™¡¡2;:: ‹?ÿüsèB_`ë­[·R‚úúzý^?ÙþÐÐÐÔ©SÉëçZ\\Šêîî®}ÂúÖ­[’ƒ«W¯†ñŠMHH0v^(S\H^ôÇÂ*((@5ò6×(@@ÇÆÆÚº# |¸qvKÑ£‚ÐÌgÒ‚¤ þ;´ÇÐè Üêg5Z~)=zd‡¶#ø­ßú-w× ñcCÃÓÙ¾vww———ù÷î]Wá~üøq ©3ôg ‹€-ù&¢SÒÊ£££ÌªÐv:òxzÎÏÐBýïÛñV?“ªêúúzww÷êêjdA^øÎw¾ƒroÚ9Â(ìÐ'záë«§Bä{*íÜÓsq )766ÚÚÚ˜-UùôÌÌàÙ³g]]]sssóóó•[Ñ‘¿ÉÉIfrÕ,£‡G]¢áúÇ?þñ·¾õ­Bf”?úÑ>õ©OåÊèïýÞïU¹ bè <ïtòäÉ/~ñ‹FÒŸþô§uCsó{ßûžÃé—~ '§áôéÓcccÞ t… -x[[[·oß.e÷éÀ$uñâE(¿è…ØZ£¹ˆÄŒ´CÆ:³…'¾ªT» ¡©Éê˜&4ܹsÇÛ©QÔ9Cƒwß}~…«‚ ÔÂÐ~uÊas ê€wßw‰ÚEý3t°÷Jb$ßýîwsz”ª666´åG?5 צÙ÷ßÿ—ù—ã7~£BYKîììD£N¤øZ=˜ª~ùòåÐÐ:«¼•G“mˆßÜÜœ™™9sæÌÈȈ…=<ê ÁеŽCÎ!WTj4éO}êS(Ùe϶}öìY¶•µmëÌËË˳àÜÜܬOÅ\ÄQ÷ðð¨i4ÖyèªRD‹ÒW%n2Žÿú¯ÿ:úý¯þꯖ7S¸V^]]Mºô m±NZ $ẠgÖvIºì ´ŒHÏÎÎzVI¡ÎÏCײuh’žžž–³©2f·¾¾NšIùxððððð~üX¶/ ^׺r°w¬VV—×ÖÖü‚¶‡‡‡G:á-–ÔÖ××Q‹áÝR1{E`tt´­­ÍÇðððð¨&ü*w µøwÞ)1‘¢é9·ª•Ëù’‡‡‡‡Gð:´‡‡‡‡‡Gáuh:ÁÊÊÊõë×ùŸ´ ågh:Ü<11áÚãnàÚÃÃÃÃÃ#ð íááááá‘Fx†öðððððH#Í0×ÑÑQ = qÐó-)MO›vuuÑ’–å§ ïñôüâÅ (œ~ØÔÔÔÒÒ²¸¸˜´È €²¶¶¦ÍÞ Žzfè³gÏNOO{í¹ÁA`ÈKü@Ëúú:cîììlL˜›7oÂÊÇŽC†­ûûûÓ0±ð¨>˜VNNNnmm%-ˆG¨[†F_ah.û·gÆMT{sÈ%2ô¯¬¬Ä§ Äª¾ýä}e+Ù//"ë%VWoo/=!AƒÕ-z<%Š_»Fu~öìÁVWW‹Ÿû&ÞÓÓýëZ«úîÓÝÝÝ}eãÿ­[·Pß“ªŸ´aßJ£’+JŸôæjIׄG¨O†fЙ™™©Ä‡&¶üÏ—ï¾+“HD1’lÊÚôÆMF—`‚•Hît›+W®ìûiyllLK>ÍÍÍA8Lï; ‚'–——/]º¤Ÿ¯^½ÚÜÜt03ˆçí*ßÙÙ)d6P:Ò¿*@uí[iT2U]Q1è sssIׇG’¨O†.p@<(\P5fggl¬ç&Ê™ìñVË6OÑ„®‡àzttzÐØD€ì—_‰…0ì Ù»?#!Ý’û€ƒ¹ã†¡6$ÛÀÀÀÕ«W¥PšlA¨aS:&FB \ë©%ËO c‚¹Q¦¦¦¤j ¼4xå¢)”J2»†ì‚ŠO—)o—(OaóÍêrB“KTÿ}C’,ã8µ©"k…wß}×^Ú‚nÉ#.,u’=à©Ö0,é»Z£( é.{¸×Öáé{Ì'”N6UGRÈY]»’XnÚë#¨‘Œt3gvn"HK¥ñ²¨tîÛšS<·2#rÞâ9qóæM^·ôÏi<*ˆLÝm€!‰îb©6ž>}f~~þÈ‘#\œ:uŠáž‹k×®q‡ÿŒ’.\ ºª”›ÐP[eD°cÇŽqÓRæHŸð«««D_ZZâÿj÷§Ò¢“‘$á¾dà' YGGG¤Œ< )@JQø9==Íêù+)’å¾E籑¬-°ìañ”ŸÜ¼xñ¢Š)ðH2 ÉêB)^’[½Ù…jɨ’Kï¤C÷(kwÛTÈ„—.[HV >~ü˜JVµ«)&Ñi«IšŒ¶“Énj^Š¢®¸°”•w *ú ­ ¯ãäE¦ü$ºnf·é·¶¶òÔšž`A8o&î#}I2¸5£ÊÅ­ Å’x¤©ÜÕ3¹æ©Ò±wÊJÄ}$Q‚\¨8$hµÇ#~Ò%Ž­ Ê«‚^ÙQQ‘B©VïÝ»§dÕX“<I‰¼Œ§Ù ­§<’QUîðßíö@²À B:š}ŠË­PV«T¦^:Íž5µE*¸×¥tRPm{4&êp•{ff†÷ªÄDÖ××ÛÛÛ{zzìÎÚÚÚîîîÓ=ðJߺuËžnnnÚb/3 ÚÔÔ„KˆŒˆtæÌ™˜ìxÏyµ°Ì`ÊÏ F+&÷'OÝýìÙ³|îܹ•‘”))“`¾/ÓŒnvM¹¶··©„¡¡¡H°––ž’I¹Q\ŨF74§þþ~.ô‘U‹‡ÏŸ?ñYB Ä¦tÁXÌt¡Œ î º õ\¸)GšUk³ãããÇ×î-.¨Šì¥~´Rê3¿Ym’T«öi™&èêê¢áà¿¶‘ÏÕ9¡y•5ŒîG‰øŸ/ÊëÊêâš>C^‘ó蓆 ßº»ïß¿Ÿ½7Šˆ3µ1::j‹Ûš¼...ZçÉÙ‹4×á‘á­·Þr?~!ÃBæ.ôÞ©©©7n¸)˜å·P¶î­i IÓÉi,²s¯Ò_r¡¸]i´¸÷×Wë¨7†æ=a)}äÇy+Üáãòå˼‡Ç÷À»­Q»gáw|$"#ËØØC ão©>]ç;ãˆÀÝÝÝ#)S†. =ÂG~º!-ºˆ“ƒÄŽ/ƒ##Ñõò·‡@þ}넬‰%ʉ<")nZå¸4ä1ÂÚ&;í±WjÃ,„ ÆM؈1ÅK2.—qß,™RuýªÍ$†ú)î[8í^øÇoŠ911¡ëÍP,ùr¡ï£n`M釚®Q½6eä'õF=[[À%´2¡…k­<²½ŸÆRÙÉŽâÐ(r §F!)ÚaÞ~ûí œÆQÉ¢Â>ÅÿêW¿Jµón29£# áÒR¦³Üw?ÓWÉŽâ¾híZštΡÃ-¯³3E³d=zÄ„F' å^Ñm"õ_ÜÉxä¤ß2nxž®a$­Ä—Zy+"¢–Ål5òÕ«Ŵ퓕RŽ,XéQ˜€+¢–õuJ+fhÜ'øo±ôõËMÍÍÎMÓ~ZîÁLZþë3¡íÂXD×R§"*#íæÍya°ˆ9Ãd &Øš¼»8OH·Œª“Ùj›`Z´(×÷c[h-Zö Bü b(;¸óÚ‡Á @ÝF3pCiîXd~~žXpT§ Ôj°m:£ü$!á-ÒçÑÍúnm­ã¾G4º>¨}õSKÍúI‚H¨ŸúúCî¼|ù’ŒxjÝFå"]¸ï2(þ»Ÿ|íõiVµª¹óàÁ’"¤öFd—ˆ·RÕiAÓ»°²Ýýhm…âZµš ?Ó¨2I‘ ï2îu‰Ðrz5 샑GmÁ3tùÁ{άI,¸HºJ<>(ê C•1tš´_f,,,$î\’©7oÂÌ̌ք“®akcc£”N¢/—ú¤½ïæ­­­Ä­ÚÙ×­Ö&.ÇÐÔÔ”} ±d—‘¡:íçOºX¹Ák¥ï&I ’ÔC§!’–Â#7>|x ñ.çhãélM%…ÐfûòB>i’.YýƒUR–vª½VÏŸ?ommÕÆÆw˜íÚÃÃÃ#í(B‡v + °ÝÍ›7_e,¤¤ÚW«Í¤©Õø«¤—ÙË m?©DÊ;;;Ú¶#pýàÁƒ²$[e‹“““î—ÈÈþ8àÖ}ÛÅc|´Ç§šÒ–EôÈwh¡À¯Ñõ÷Š‚ìEc'D|·Oæû©M®„4kMtæ¢D×ÇN±‹!J1Ëe…Ò黣sÚ8;ͧ­ÒúƒŽÆqqP BK)% ð,D¦°53O«“ʲ^— 'šêÛ²f÷3¶¬W¸†Z®iǰººZÜi+™®¾ÀeÍ'mI ’ê¡3¡ÑÁJ,‰CŽÙNÙ¼wï¯.Ô%kbÅ )¤¶<(¼›l°g¼Iï°g|4Ø3,ã‹pÅZâ( Z–qPÄpÍËNH$SÙø4ª1“¸ªNÜÝ7!uÔÕWd¢twwK`Ù’´(R\dý8é~ñ3ä[ˆoú"¸YP¥U¨,4´,Sê4°,wu€ÞÞ^Öé°µ«dæÑ_?Í´õöö¶l_ÛYjå¥y ê@?½)wI¯ FvЙ`fiÚRG ªF®‰ËOÞ÷¸³`¶¸IM6>%¶ÂDÄÎ8óe _6>3Îr‘üÄÛýŒÃÐda73{tURY½•©ÝÌÞÚ€--ð” Y=SR ))”Œ¤RFQ¬RS½je%R¡.T+(Ζs ZvÊžl6CóŠ’5CgœâýŒÌÇMõ4[ÿF„–l˲e¤QFlÉjk®‘[ æÚíÊb}*Ä]ZÞ a.³çÿü/ˆVe‡Ù,0kØ5K‚d¦¤(¶ûLOE¥äí2«U#xåÎÄÓ‘ÆÆÆäË>uhÙ£¦i()Oá)µjPZ yèš2ªulº6‚DäÚD¶bHG&Ù•±ÈKVÓ‰i\¥#¯'A¸‡\¼HÖ2„©„ã4Ÿ#GèÜ­%%ÂÓ}ÅVxÍ_¡IÍ)Õ-)¸M Ýûºc+ÀïÎ0ø‰`ÈC¦H>;;+§5dA޲s —”âhו¨Z‰@¨Ed®_’ȘŒ;(¼•«ïî%mhØÃ÷uÈКme34ôÃklî l/•»®k m¼ërp&kY?]†Ž,Ü ®ŸS}"~/¢k|tošk[)åfÅP†þÍ•º 󱜑ˆñK+†6ŸT ‘åÁl$¢ŽTh„¥±è0ö“j‡Nt-gh¶À® [.¶Žj«j2-„Xj lî1,/ÙŠ·×!{èT7pû¡õ4ëün'Ïäñòb>6bÄv[Öý.CŸ——ÌÞtÖÝFÉï‹®C‹Jå&R"êÖRSã¡mN}×E&\u ®^j½ ·]¶²·z$4æ¦Ëz³Ë„^(²TÌeŒZGìy-yùÍE´Àýååe™é¾uëÖÆÆÆÜÜïjÄx5÷ÇÇÇ_¿~ÝÒÒÂüfΗÀ ¤éž‘ØÜÜÜ!‹Äù„9yò$ƒNà¸éE*)Ê:´mÖ‰BÊì”Go¸|ùr¾Ä列QÌ€¢=yò„¸ˆÍS2âBî4¨ŠJ7J ¨ÞÅÅE¹ª&PäºpРf1»¹¹YÕ+£ÖôÉø¸4ŠÔYXB"ºu9¥f•„F3,/rikk;œdôèÑ£ tH„¦¼÷B%Çl×ȱí>S@Þ;–C‡ç§>ñÐíC;~p€}yd’V6Õõ¥É…l¿èó¶Ü¹ÒÉy oß¾M[sAîdqúôi^ ±§hdàEËv"V¿Çz¤IO*f¬eW£íƒœ}œÓá«ÁÁA}â>¯_d0¼¢ŒrFɵ}ЏÓÛçC¹ã%Y³ý›s7¦rÔee$ñ"æˆIÄ•…»šG^®¡åÍL¸»Äýb­ÅR"æ\bâ© ¥ª°OtÔƒŠ©µwÂÈ`8<5ánb¯&´D\ 5ÚŒši!ZÓ,9êÎ8›ÔrêЙPÑ B.T‡ÑžÁ \ ¢@'êxjVóî dƒºpZKÓ’Í–[âuh²“Ò¹¯Ø f?eèÔ6UØ}y™Ì§CkŸ÷…(ú Å¡ÿ”BnÊÖXÓ,“kÞ Ý™½Õòj ‘Ù{‹™ª"XÛ'õ=¾aEP¯lµO©“ "ÐRm}|¼‘夥¨yTŽ& A%¦ŒwlÚ7ï#â*s‘âîõ‹OJ›Â²ØýH€Ìžƒ–l·+.-™g”|^^,¯BÄ"« YšLD‚i£xvg­ÚŽH¹RHîÖ@ÎÜ]gößö²erºA“‰×=“¡©äõ‡ëׯ¿÷Þ{:×[Óhii.¢‡‹¾¾¾“'O&Ur¼¸±±ámb§j&^7ÔÜ©©)8¾\&'y‹jÌkqqqhhÈöˆx:T·lWê:.óÀÀb­sú7%_"Ò0]ÛÚÚêèèжޤëÃ#/h&´ÞÝÝ]8µ\Ó©/^È÷Ä@^__÷S:ƒgèz3âãÇÏÏÏëÕGcâîÝ» ŽLt§F$™™™©ƒuŠ‚«­­MŽ®“–%I0³až”ïéµk×j]û*õÌÐÁÞ²}Ýï‡lL@ŠÚ¿“´,?E?ê‘¶ %-‹G!½b||ÜL52x_²ïóú¼|ù²^¢:|¸²²ÒÙÙyîܹ¤‹â‘ôRÓP½Æ\8`hxº¡¾@ MZ€„áŽìµ¨~yÔŽ„Ðust zn(%ãpûömHº¡¾@ ®C{xxxx¤‡’Ã…¤©n©=C{xxxx¤iõ³ör{xxxxxÔ|ÓèúÅ‹®þ]»àí¸yóf¾§ÌB(&ÿsÞÝÝ=}út|ú ±Ü×p|||ttô ¢Ò^‹‹‹ž¡=<<ps#D$ÀÜÜ”c¨•ÜowL§çBõŸŸr‘ÉÿˆÞ‘Ç~’&qó=Í'üÈÈHGG„š3u{ãÆø2 » FCp100`e‰“óçÏØ3´‡‡‡G£ ­­-µÃ"´º³gÏBðИRhii!5XÇ ÓÓÓÓÔÔtâĉ¾¾¾¡¡!® Æœ`(7Ñò¡(tMy`ÜÙÙá?$·¶¶F,6pù¡C‡š››§¦¦Ðk•)ÿ]UžDˆ‹ DAžödÁ#rA¤åNR{??µ*@xGäÄbiiéùóçf"[ÆS)é?{öŒÂÓP9˨*"X¤ÞP©ggg‘äîÝ»Äâ§+y|{†öðð¨[ì«©Ô 677á³}ƒÁ@W®\ Bö YÜ»woyyYa¦ééiRƒuL‰„o ÚL&ÓÝÝ ›BB\_¼xñòåËÚ•öôéSôÂÉÉIÔ}âa‰8¯^½zøða¡Â^¸p4_½zõàÁ4x(maaˆüw—···Éˆÿ­­­o¿ý6"*íA–¤ODbÁ»üÔGe¦2àå.$ $P(þ_ºtI7=J,DB<Ý!AfȆVF’%ú¾µÇS"Wò|áõíß[ýôðð¨h¿ÿ>ƒlv Úc¬PgÞ‘)þùóçcˆù(¸*ÇhÆÕù«}³8BEư׵k× --ƒÃg\ tòR¤!¸FÅ„ÏÜt Fù«†¼I *…êPsál)µ”‘ºººh#&â¡}vtt¸–XžC%"*ìÉ“'Í6OE~ O¯p+‡tÈšª NÈ=•lRcÞ@ D!5­E gΜ±%£˜òI\ÊŽÞ¬ùDáe’¯®®Æ‡,C#îDôðH ,¼¦Ã(:£*TÑÙÙ)µ&¦5I Ix™Æd˜&¼Ù@®o ùMMMÙOQ2ã6UÁÕr z€äÄëŸ1´îóE–;´ª3ùòSDûðáCž’#­F\ô~T[Za``€ˆÖáHBø’0:ÃjK«Ùg`IŠ) ¡2ñ")tYäÉ^K€¶ihÒï’;ר¿¤ †æ)¤ûøñc…'Mî €¾7£ »®µÝ2¶µµ¡#€ÊScŒ3AÈÍ£N$9Õ¿e¯†¦H333ÃT…Ìêl*êј%.xujÑ×}C¹d¼ÖŽFÒ;wîÈ. VÇCPQ(µy‡Fg°®ï‰Ÿ CˆYU{ÔÜFµdW Œ¢¸AxòºÒµ.¨sªªC¹´¥Z¨ÒÕWgtëÉÉI.4àý‚­µ‹¸ˆÑÓÓcb@“4A*úJ Qù‰Ø¤y*DDHéÁ#ôo~J$Gfè‚2¢¸k.­ŠïììØ*73•Û·o[²L(Søž4%33q¶ÊÈ}¢hYvC€ìÈB|l5„Ú<ûûûõM胃ƒûÛÉ ÊÃL„l‚ ä_x\šÀ«W¯VWW8èç¼–ŒÚIKäÅüü¼–=‘Òœf•q-D²2 †à2†Ë•,o%sÚ(ÙÒ T2|¬22¨\FOŸ>ýéd¨À B,jœÁ‹ë¤«Èã`Êp£µ¯¤eñø)hˆÊñ¨F9˜€F¯ÅQ. M»ÛJg¹’Õü)Ù¢å,#:qå2CïcS !fff˜/²•ÀãÎðâÅ‹¡¡¡çÏŸß¾};{‘Í£:` Ò"-ƒuE[A-..®­­ÕÖ÷i}àHÃgû`T.lmm‘`ª¾A”½ŒÙØØØèïï;mEg={ö,c³OÏ Æ…{÷îAÏ===úŽåQe¬¯¯···wtt<{ö¬Ò“$th´mµÕ·ê¤K_{(;ui‹xÒŪló!/C3miii¹víýÕïóhp@ ÛÛÛèÓ}}}~Ô®& I4 Hzpp°j™êl[[ÛñãÇÝS7UFn†ž››c ©-ì‘G+++¼3¾×z4˜§¢LŸ$C‰¨PÌ æççQßÍÂT£á§¾• Âa?òˆÖ‰±oKíéé!µÅÅÅÊM޳ÎYºÒ uPä`hèyrr‰³?ÃPeTÖÄÄÄÎÎN•õðHt¢©££ÃkÒCó©S§.\¸¬‡Dd`~€÷îݤ«$1èXZ¤Ã3s⦞–wÂj ®…àzyyùÕ«W»»»d·Œs)J—†‰x”¡k||zι²]øÀDÙÜùÜœÅÃܰ2g®YöÒaöܺ…¹)/¨®jöË|C†ï«&†+Ͼù^ ! ½•€è™±ˆzNZ–ŸnD W0-k(’f Èdd “ÿÜœ™™Ñr&.[!¸†‘¸5ÇPðZ—JS0¹„ÍMt®É‘ª¶ácXY– ä11‚†IGK¹tÒ1Ó@2÷­,O°ÈhFšÐ;Î+¬§¨>TÊ2e„†Ïd2VYØÒ””‘Vâñ!†&צ-9éù@bQ ®Eõ'N¸O)m|RÔ5A'ˆq¦æ‚Ê"Ò$7oÞ,0…B@ÙVÑb”qƒ¶Pÿã5k—ª F‘Ža Õ©ê›˜ê:vì˜ß8V ˆžyýÓ³•šñ°¡Hš!´¥¥…1\VD‚Ðèw2oôÆØÎÄ…khŒöêÞÃáÇGFFr’tWW×ÊÊ ´Ÿ£­­MVbŒ~L:܇>ïß¿o î„ ü× ÇS˜Uµ ª¹¹¹ÖÖVˆYf;ƒÐVï&a`VM&\1ŒüP¸t9°3gΡ_gúžæÁd~ŽXfà0ŒNÕ³häÀB¸{÷îå<›%«ß&ÖÓ§OcrÍÏÏ‹ãíØb$£ÇÇŸ8¤1 aSÐY=;ô¶oÁ÷ų¥¤ Ð K”Ä­.täWäç¾B–« A›9´ZéÌ.i>ÑĤ …¤ê¨4½ù?[ èT ¾é´†¤ŸMZÜ(ãyhÒa¨Ï8ãªþ3ª/--]¼xñÊ•+68Û+Cý0òwvvÝ"ZÕ¹t sçD—] »Ç-A•È’"û³š,)}‡¶&PîèÚ’"®ÂØT^•ãŽN¶èšÑZ.v¡)»+nZâåm¾lüœ¡5c*ĭƾ`ïk¥Æ/÷Sœ)múiöT5bj¥j4þ2"óZ2Q-ÒÖ÷ó1´´L͆L?ËfhSìD êUæPW¦m$žz2 ‰v¸EQ‰?ÜáÛÒq» [Ùä噢ø/ÕV3ëaªL[!Ps裎‰­Ús_B’ÚÞÞ&¼ÛùT¥*”–ª$›éÒä'ål†–¢¬^!-ÖjÛBrŸZ%¸Š©ô U~„¡ÝN™ŠÊ€Wf¡MçV-!°û *øð7c¹èÑ ¦dU|Í %$o5Vz»P—ùí¬AdÏã„È´)å(ý XÙ‡øJÛåÖؼD«+ZÃåE-.,ýœ¡yÝ+>ŽÛ½ÄÐîôGú¢Eßly\}H㯽e_ÓRIJa>†ÖЯ±’À$‹ä¨V¶¨"Ù´”mÊ1j:±´'WKëÆ¢i¨ZRV0¦psÔGžF†oZ]5€ îðMFÜG~âkW‚¬ ꃇ-¶k`RïL³!“VÅ¥N¨®ÈDJcbäó„k1z›‘-ÚvÑê‹l†ÎìmèP«¹µm{ìµÁRaÈÔ} l‰I‹.Cgö–¼LHƒ¾ŒX“†jµ$®µ§‘aTFë¥@[ÀTR‰T–&v¡•{Qk%2t ×ãQ¢ýÑšcèLØÕyŘ֮°ÂϚѧÀoi¶ôá~v-0¿HHé7«!ôíÐÔµøtÐ"i"ƒ’µÄÝ(‘è9S‹‘*òȾ•êãk|Ön\íKt/"qö•6;å%>L¤¶Ý,rÖOá­Hâ9óÒƒ­DÎb~vIKlâlج±‘Q CG>?S™âæ—ZŸLaõÚ"bã0´G5ñs†.p‰»ìÐz¬µÚZ3‰tJ­«ƒr%ë2G6Üðì h•†_èΔÀÐúÜc°•›ƒRZõ·ìiéÎ3´G%ð³ÓVr²–ˆo Èldd¤»»»ÄÙhª@e¢ré])/p»»»Ú‹žtùRŠóçÏkÈãK5sg¢™Ï”R5!›ù1Ö’Síê·Ÿ‹‹‹¯_¿Öw±Ž>ôħs÷îÝê$×,¼êu– ¼xñ"Þ¬!O«ÙWB.^aЦl)û™—‡G骫µçD²KŠÓ¡#ÒŠ‰sg²&Ì}EÞ¦†j*¬ü:“ —dàBºµŽ¢ÙRÇÍv­SjÙ‰ONNÚ6í<µô*¢àiÖ¡)ïàà`|˜}ÍIÙŠ}A…•·ø&žµW„R„)=埭rë¨O%¤Ü‘ƒ¼ "çéÂẆŽT3+¶ß‚;væGcE$}¢Žp$mK¦¤’Ù=Õ»vïçÔ^‚pa,³w$ûp]q 6ifhU» 97‚½å<€D—¡ã·Åloo«QdtA M«:ñe?íx….T|KÜÄÓÙ™l1Ü0îè§0v+óácW‘"èQvý”‘¡?²±±Qâ&ÌlÈ`–ÌQ-,,˜Å+×fVnµ•É|¸uë–l]™YÔHFù"ÊîU¾§9SKÅIr Ï‹‹‹fŠË5‡>22";ecؼtaâ›,¦nÀKTœ{˜FFäÌ’q¤½¹Œ'ö ±•Hã²ì.”©]6&¶´´ÈèÕÚÚÒÑÑq÷î]z£¢ŽuW®e ŒdI'’8cïH&@¬Ÿ=d‘W}~¢ŒŒéÕ#ISSSss³;´Ú¸¡ :¤Î5Ô0øËj$t #’D7›}HŽ„¡-ÔÐí!æJÅ#nšÕÞÞ^µ…]Ȫ¶.È]N>$yN÷‘dÍHˆxr¼A.0‹&"ùÚPF éhääQOO2µÂò³Œ‹ç)=‰(àŸwïsa¨Ú,&ÒÅ777cL¬eCs*¨««+òˆ® ÷0'O3µ‘µ÷lÍpPj¬©S®¥¬Âî9ƒô'&&h}í3g2/µdà,abš,¦õéQ+` ‹|ĵq_¦ƒpKAD 3ŽÓ]c>ü[oÔ€.«¤966„㸠Av-{ÆÙ‰ËˆPÒã/Êzö‡gnî«iÔ.î…ÐÎ_öí³ a®^½Š*l΋©Om5€n5OÒqÍl¯evb&XNß9ÒtÐrz™&ßsçÎe%ÐÁK[>qñŸr€Î¦q’ÒîÌKHJV¤,|&ü `›èTȉ<áU:÷4i‰ø4£kR£ö™qAÙVWWõbáûÀf¢Ù¦ BRÏYãËËËÒ¿iãwß}W7åhR¶¬©éåü|‚(ùkîë©ìšÉ;J:ÏŸ?—ãE“„ŸÖé[rÊin.í‚ÿô'Ë—è]*;ŠIÂ5å¢tÊš9‡ka››*—¥ÃLMÎdt‡¼ÜðV]¦G&`JK-ÁDz“„³%U¾#;/îÊ©pË×\4ÚEv,·ÉˆèŠí#uâ: M»Ï}AõÞ¿?i)j 9ükà–e{šž‘ÎØ:Ø[„ƒ'x³×–³» ½ÝÉ5Ú ²Ð§kiÏDçÎh7q±¯¦û2h˜-¶Œ&]£ȉÊa”ãÅ”A<³Á;{þüyû©á…ÿ'Uǰì ¶Žwą̈Å`(w ÙO©j9‹Ì $ÌNœe0<Ò|´>²irÀø ðS5äw ¸Ó/Gª·ß~Û3£Šp?e7o`åD‰Ëå‘ú Ï'–ˆUm»/#'tqó/¤Ï”\&Ñ]ƒ¨2ÙH:¼ºZëïìì öÌ’Ðod’BßQÜ¢iZ*IøÌÞWCª[©Ñ$$¨ ²,nåÅ«+»]I\+f²I+³Ü}‘(Ú¸. ·ÇL))p35ÙbSîfDƒ7e^Ñ /˲Oë~ªqÏ EàZÌv›Ï•Í•_kµçšõ°f’W"3í©R+ µ”Ûè2.FšÌ^µM]sU³@néji8pUCß¡#'¬\ä³B¹L©bÒ©Ÿ®kšÙ[–‘8~F†åISÕB§²´64åK<³·è(ÔR.iþy…íB6·elÊ>âÊ VãTW #SEz‹å+a,„ª×!mÿ*ŸO¾³‚Û± ö¼hÐ##FB95P Œá²ç(_U®& õ2¿a š?Bó%ª– x騃!¤gg› T d!%¶ÂÏvŠ•×Í_&¿ÿ>ŠjÇÜ‘Wöž"^/å,ÒWäEÕäšÒ4&ÖrkÄR· 20ÿF®úª/îÝ+Ù¤´…ëý9Z­.ñè‚"{·¢#Qd‚Øõ)b»*¸ hô§ÙÙYtÓqë6^þ×4Ep­šP‡9­Åi4‘1äàÃv[³ }GŒhºÆ¼"“öÁº¯wÎ}¹š–™/?U7áx™4¯'Îy…£ìïQÍá@ ¿;UFîl_·kRÉŒjz*k€™p—™Ÿ“ïZ[Ž–}Û”êŽ?”ŒwEÌ<•%>K\™Æx.°”냡™1k‘YC¢]P‡²*Hå˰ sÇÆOÂh“ÖDÝR™ë îÈ4¡»GØöÕËö>uNúJÓ•*V’YÈx"ÉÊÏ4¼.ÙÈN†¾%ž8Xûð%¹%haT@R 5…ÑÎ5™Òre ŒðŸk³¯n¹ÐQå¿ tc•bh)‘îXPóÓk{)P @›AfáJˆLÖlN:.µ£Í{†¦m ›¡3{ÖE?ÆôÜt0Ãeh)ñúF•١Ͱ»Ø.bv-;ŠùoÈäbhî½LÈ>ÒG³ZGJ4olwÔ Ã}$•>ªPÒû#½Ö½ñº*ùZ†¬­É%'CËü¸æª\sa[v¥ÜÔ–ÏÐ…3táK#9ÏÉä4Ï—ïNv ®‰uwËn¾ÄMÕÞ÷àÉ6u§™¡Ó‰JTZ ²-XWZ?züøñò~Іz™Ô´··Ã…¤¼²²ÍpÁð횘ššÒÚQWW×É“'€6í…;µ;îÉ“'nâš7¹Ö›õÂk«áÜÜÜÒÒÒÀÀ€>/¹766.]º„`î¸ÙRs?w{ô¹ÁôÍ;ØÛV°¶¶vùòåHÁµÖ ü'º-š©n‰¢í’„ʱïñ9±»»«šŒ m·nÝÊþ†lÚÞB=SpûØL}R“mmm4eAª­­-Fœõõu™¿Â/1---ÜG~ÉvæÌ}v3¢íôÅŽŒ¨4Õ=}øðáèè(uˆÌîG Âxhhèܹs$èn$)êD•Cm>ÿïß¿ÌcccH+%‰d‰•~ƒ6eßÏQÇÈé]8'r~ï´›Ù½"ûNv îcéÓñ‰ëMlÊW®ø—Ú£†@SB IK|¤ì§D´ÊDÙà­H0ø 4[ºò[o½¥=̳³³¼Œàn;Æz݇~d% ! Òò“êCùk2ÐóV@EäµH#‡HÜ)-?ñ ¦Í_<‚oàRãZjº€Òäë”XˆaúQma8høÝwßµÏ~È£\HM¯qd¯£¢¼óÎ;–$ÏŸ?—ArE'G­°éÖ´ãìÙ³îTC;§´ÉÐ /·Ó¤É#£gê%$MÕÍ bžL{"´D/Ù ÙÜt¸IH-¼“bh-á!fM­ä[h†½(;G6÷ì„ÂhN@o¡þùI˜7n@ÏjPÇÓOÏBwºV¼}z—m»k rîôö(Ð)K9rr 0þ0pE<)'FÕ ÙU);¦§§Ñ)3¡ÁÒ÷™ÿc±Î¾Þª$1O LÌÝiR¨¾™kÛ×S+Ðnù¤¥H®rïû5·¦aKâû¯r{Äãg«Ü:ZYÒL'˜zæ¨bÚ9RbjŒR Ñö¤¯']¾ŸI§¯¯’­Èöýc=„k«9ý˜™™IÅt» õ Y>‰|bó¨WìîîVœ82ñ>éáá‘”xŸLÿi«ÈÙ„ºDûÅjQ‡Žˆ­ÝË‘0ù¶Læ œ mÃ.ºÜõàƒšÞ<™n-Á{Ç ìõ·CÅ¥ãgV?ƒpV‹Pñù†‡G=bkk«µµµÎì>V5ôºhh;K#`mmíùóçå L˜ƒeB¼ù”l Œ///gBój¨Ñf’û¯_¿.£§»Ÿ2tooo7ÉjÊ•š9†J?Š(¸|þxă‘ÂOS „L:7j}Û LRÃd§N‚iÉ¡OV{÷ÝwÕŽ¶zG`I×oÎÓ±ÛHÊ0Œ»ž3P:aXÍn2XÁŽT#ڣβ*_Ù’Ò7YÔnå._<ÍþÒÄî߸qƒ©†ªv¨³³“0çΓ­d†éIM~4.ÝÊwöÊ®njjâé¥K—ÊÒ?÷mEQnÊÕÆL‹˜°ÐNæ‡Ë©,y¤ØšgÉ7¢ý%õåz(# OiZîp_µì‚4uŸÜ]Z‚rH™)•rç¹RuMÍ*Š[õZ“‘÷4º’J¾ÉxÄ}¹ýÛ2®m-…ÂJ~ˆ\µ!ÿ²ò:„ì´Xv¼ $«JS ¨¤ò¤É5¹¸á¤²U)&‰¸XÜ‚“2­L‚!˜ªB¾ Uo<â'’ ³$Q% Œ¦\Zùágç:5 Õy­ÇUCãTT>Óâµ¹a|€Ûd}!Þ!aÎeΜ‡ƒdSÙáIR ‘nv”r†5È;›wáH¢0E€­‹Îœ9ÿ…E\£ºfûÌÑz€þóŽ#›Lp š|q{ßûä‹H†WWWåíª án#ƒˆ}ì" ²7iî¸3{F1_½z¥î+¯W®\áçðð0!eF#îäÎüü¼ò_S›L¸ivvv6b+5žfƧ…’íííU‚î¶: €`òî@# Ò’wÈš¸äënåšùÔÒÒ’,ª“5U„ ©›f¾UÁd<]7U.ˆ%çäòW!ÚÏfõšÂ“Át"™›2xënöSiÉ„®R¶àó\6;Í€vfoÓ£ü}ÑåÈš·…÷„ íX–Áz³Œ_–]‹µ™nÍîŠ ‚†“ÉØDrßw/wÑ{tkûÖFÊ÷rÛèdžl2¹\æÈà¹9’G³Lì–Qå br_7e Zad‚¡FùFÒD$9I’µ%ÞJ6²—[ž ‚Е_¤,nIŒ E·MÝpÉ*#7 EÖ±:Y׈ªqÞ˜k‰¢ñ3»Üî-Š*÷D¥¤«–Èiæ‚RiC–§‚=O®ª}3ûìv_ÍeÌ-’̰ɘsDrsùì¹²Èd°ŸÖ›]SáÇB¸Ï¡1˜ØøÏœÞˆÑ›¹~ÌE‡zŒŒJBM ‰¨ŽññE—u»—¸Pá³-{[ÚOQ¸+IÄ-ŒÜr‰0t&tŸ…TŠh)#ªº) æåÜ"ãØoLÈ¢jÒR¤ñœÔç¬\ì{æ*å ­úG.ÌÝ€.\ ç >7ìTUäx•æ"{^Ë¢èú- –ÅÁ‘4 †Fá¦/†òR02Ÿ)$ o½Ü_šä¬%®ª‘;sPä`èÌž‹R<DÚµÕ%3#¸Dê Í§di2â¿RÊ !V&Œ9c@W09Å$eŠlÆÑÚMMsäçÄeh¹0Sµº*?Ųrç š Gc™=ÝW-*1´oHóÁ ܘ Ú–å«)˜[oîA:*M.Û"•™¡eéS“Ys¥çžÐu n mVÕX‚ºÜÚÚªšç'’h©#³÷jI¥Î8 ]Cþ-Ê ^ºïš:C™ÂÝþ:RÊȹï~~¼È‡4ï‹XJîKyeªH¬„¶Àt$ÓÕº ÖÉì±QŸTxRSxýà-ÓOC>+ fŠXî¹W¶ìšGž ö¶èT‹Žûê tnc”ðÃÃÃ:‰cm„0yøða×–—™4Ñ #·,ÛÛÛA¨d—~¸K¹|´ð©ƒË€iÓ&GÌt˜#ø[:Àóçϵ­ՇײA|«#þ|tƒèíhh¿¼EÃvé{T¶™0X—xJE yŒÈù4kûE›‚ŠÞzë-»oUС^Ëõ~‘ …×ÚÈ{ÇÿÁÁAw)˜Iê_v•ÂyD´íP k" É #̉ñÛâ¶th{ÓáxÝP¨4çŒm}}íY]%R.ùÉ.¾¼¼¬­Z²ÉH‚šœøÝ=Å0tNx#Ð0á[Ç#A¤J‡fÈ.£W:’’N–t±Ê ‹r¡tÉã2”)‡ИËÐ.`VÔÇ¥¥%w»†ˆ*çî%² qþ£žº~/ 7«Ó§O£’¬ÐÞ“'OÞy箥.¡—#[ -ÙÐï# ­/Ä—/_†×snÙÓúèv´!Þ}têÔ©wß}×b½ýöÛîn/¢±7›¦AfZ0::úüùs˜8·áî6íL&ÙÇ÷ôôÜ»w¯½½Áwgg‡ð³ÝÚܬtí%ÛFûbuu5=çzJ·W]4¨zK9÷ý$µàQ¤|•[n°ƒzôNXE“CR ¬%&³¢›oÙ3ç¡dóÔ^U ½»»›ì>Ü‚ -wËç›Næáf¨ <ŒÐåKWÈ繫,«Ü¶QÊßtƒÂ¯r{$ Tt—º´&»¾¾>55•ò¢¡Ü£“ݺu« Vu 5Ú4¹ÉœÆ±+Wr„Çfti;ýÔÖ$…‘Vm,by!½™¾ä-96,ü^nj“£‚”sXÑE‰íúõë‡Úw!Nêïïoii™™™IvèO³s4f׊×hÛvnç@.4ŠíB;2ƒ™˜˜¨~Êý™ÿUã@¨‚#˜àQ…,‚x†ö¨ŒÀ tTPC¨‰¢7§dntñâÅ2î©)/Î;—ÍÐh´•ö‡‘,7 Ze5ÛŸ™ýœ^´ŠNkêž¡ ðï?Ã4óMs[5ÄØææf•…©¿¢i3ÿóˆçæs/ni:BÒo¼ñ†ûÑÚ¬=¡?ܧ.\¸Pú¾$xW<¤Ÿ2 ‹›yAº»»Ý3ÍèIÊT.ïì‘{X¶@œ8q"g5’i 7ïÛú=|hhÈX–¾”í ’ŸÜÔÖn]LÛÝÛÚÚ¨´¾¾>KjqqqeeåìÙ³A8}”L`Å•½6îwuuÉ6"ÿ¹¶¼ˆN"æZC˜™™±›$¥Ÿ‘c¤i‰ë'a©,™Íí2ÿURÅ%³ß#%bƒ€ ¨Ê!A‰QÄÌØ3t£@Žó._¾,»ÓŒ5ñvÿ+„|N¢Ò¼ªVŠVˆç Û¿–s/ZÍ‚¤©:mt¢[ºÄ`åíímQ2l}ÜÁüü|¤›ÿƒÂwvvR!2ШÆÐ¨ËgΜA$cbiÒrOpþüy3µ‘ϬiÌöò˜bîÖ°ÂÛH­_Q@N´ˆN3ËgHQ[X‘+õ]†k.&''———¹©}vÕ¥K—!-ês=ÄÍ›7™äñ6%$ó¶ÝÝÝ'OžôôôPíjþ» °fkk+œm¼¨9=JÓæ´¬2r‚‘×{g$’Š`W®\á&±ÏMe­#<%}íóW¦2F©8˜Ž¤ÙaÈŽôÛÛÛu,¤µ˜¶êŒIA_J, ²É¬:ñ¢îÛ*'O—˜{,–Àm”ëX,"‚©Òx5deBí¥ûr‘ñëZ÷åëÉLR ù\Å ¼ûÖINžŽ _ö½Üî*·¹´Ò¦?.t4\õi‹C˜W€z{ùòåêêª\Z©6Tj-?hŸ}:ß …¢ ŒŒ¨€Zh)zû‚gèú‡üÀ¤‡ž ≔“Y  .a4×±ÝBN¨4"ÖcI×ÖÖøoßåÅH#;ƒìÝ»w#_:¯^½JT%…ÌgަDï–BjÛ­´¯¯zknnv]_ÌÎÎÂjòI À‚sssT&×h¨]]]Ð*$ÇMâ£T// QdW•÷zæBËÈTuÚ±aøâ&Ôk‰}iR~ï½÷t“FAr'MÒç]€,ÉQ+-.’ð”¸(©šlñ“`ýýý‘bê¸|SS“-æsM?A˜È:Š  QU9_RE—qUÄ#…Ð"^"ŸœÆ ¤Eh袕ÞCbV¹Óö ô.[å.‘uWZ·"VþãÛ¨ì«ÜÌ/mùš¬M`»à)J§ê…Je˜b#øÒ©üÔ)¬V"’Ò}»P`K Ï^(&¤Ö«ˆEI›²eê‚û¶RMàÕÕUÌÒq? j3„»éÛSݱ åk×ù¾ƒÄ@«Üž¡ëå2ãîábè{÷î•‹¡I*_.®Ñ±²0t<Ò`SL 4Eƒª¹(W²2À^ÉÕ4¼M±FAªÇ<eYï-#z{{çææNœ8QJ:/^ÔiNTÈ„EšA­B*333(Ðh¥åJâ×.ú¤Ë—óáù1´Ø‘ F'Ý!Y¬®®ª¤¦,d„Dqed[ùÊ÷³¢y.\âÁžÙpBföü©X:²Èm‚)÷ÙÙYË I”,¡gfdqj ‹Ì!¸Oa™‘01Ãàåeh¿—»n¡¯ÑÚøà¿@{$Ž………´mç®Ü…ÐZ-e缡ê—/_FHg¥˜2f¾¼¼¬ômΟ?ä1Ã` {æuCŽ‚P!¶Üî‡Xú<,äÂÓÑÑÑG!mggDšú`Á[u—uwõ^æEÉwqqQvl ]INŽòe@úðöö¶‰tóæM™‰ejÒßßÏÅNˆJ´…ÿ]ϰ¯ÑZGJZ†F©ŠkéܬW8 ¤[·nÁÓ333›››Ðgss³>?yòÄ Ÿ‰\ÑSÄ-&m MðÜÚÚÚÛo¿Ók6˜ ž8•LIšD<;á› p‡ÿ\çs\ÁD nF!–ËËÈS4~WÑ\ÛãL_t_6ð‘¹rÖT-ïš¿Óë L\˜µxÚÃãJ˜™™IZ„ŠCgŠ’–£NàÚÃãJXXX¨û…n¿%Ó£Œð íááQ=,..&-‚/ GÍÀ3´‡‡Gõ055•´D#,xTþ<´‡Gàúõë×®]Kóv¡õõõ/^TîtÊÖÖ–ÈjCõææ¦öÖ?~Ü6ÙVîäa#|hÁ¡CÚz¼²²¢óH¥€†»páBâ]š‰×óçÏ÷5DSvx†öðð¨*&''§§§Ë›&èââ"¹¯‹Ù‹/ê˜lye`æ‘Z!‰€éè訦%ê¿ì‡˜Sž:u z&ñê3´_åöðð¨*nݺU®¥`ÒA»BÍjjj’Õ Y[«««Oè&ÚCíÄÄ„Ž«ŽŽŽ–Ñ‹óÈÈHbuZVÐ@}}} Ô­ZJõÌ(ßO®©ÌH:ËËËÔ6Iéiö1q(|hhÈÒ!$ÉrGš†kÛ¯ŸúÌ/ ì~V˜››ëêê¢3èä½2ÍÞ@:Ü7G“#YÉFD¢[¾$B?éééá¦l¤D¡Š¯dí‚`<-—Q9ÏÐU#lé‰0È677C·Œ†r?õêÕ«ë!¸sÜn*̳gÏäÙ‚ÑùtˆÒyZJ|ÒU[ììì@H»»»Ož<™œœäõÜÝÝM- dÿlkk#Êàà`$ÍÍMÕöÍ›7™Øå-&“gR  IÇhmm%_æ[W¯^¥™d ξté‰BEµÍ}3Az÷î]“w$ׄ'#Ë”`gÏž¥oÈ4O:²¡Æ5Ò"3×½½½„!q,#Ùô¶hÕZÀ7ºÐœÊ)Ûa÷òZo÷Hdh^a?y”´t•BÊ=g¸Ó…âÀ(iîœeºh'T?63“\ð³h©Tù…#Íž3Ì….VWWƒÐTÖÑ£GååÂý¹´´d¾("„ì9Ì`gD—Lèè iw,–Ì#ÊW„êºÊÈ›ˆ&’ë$úƒzumŽ72¡«Àq¥G®ÌJÜØ…9ØóØAv„4w EÃ{Ψ+09eî¶°°°²²âšùÔ–[_ºÿþöövGæ‰Õÿ¬âᄪ }²c´hZZÆ7—ò™S¬Ì‹ƒÆÆ´«ÙÙÙ‹/!Ué«©…öÖQ?ü׆)÷g¶¸¢£¤B™®Óhš´›2?ÑYå¯ûûîc AmHd¸s{J¶¹¸0 ƒ‘E”u*wç#rNNNªc—åSŽgèÚÆÆÆÆÜÜÜÝ»wy‹ètŽxÒÕ–HÙ‹`æÈxDÄF°ÅX÷в[é»g«ƒ‘‘‘ƒ2´HT®PPʵ‰Ôx´èÊKÁž>P 2à\µª«24ã—‹ ­EG~Òåššš:Ý¿sç­ÉÀå“BdYxtt´««‹4µ0ÎT¬­­M2òíë¦GMLL†F$AÂ×$.¥ßÂ0—jii‘IPU777µž%•‘|«ÖÒvŒŒ™:0ÛCBò•k¬Rk¿,«"U†úôÑEM‹N‡è$BR¥¬zxh•[8Ъ¬±&sÊøÿ÷ÿàÁƒÛ·oÿÑýÑŸÿùŸß¸qcii‰~þãÿ8>"ú´XÎ.ü]@ +b®æUn}su/èúHŽü”ÇèH¡ø©ïÐú¸fnF4¥“€;ömNÕ.®`Ù Zî™ó» ífJS),º–sI}‡Ö}7¤¤²ŸJ°ôVÐ*·÷œQc`²Æ\offæÊ•+%.ñU!YÆA!ž3" ›½|ù²Î&— x:{G’áþç¾þõ¯ollØ~ô£ÜÔõ'>ñ &£Ÿüä'c2Ò¦³œ ¤ù€ÎT„3+ï9Ã#ÞsFíaqq±¹¹™qi¯by”¤HP_hÈ¢nv¥z¤Ì µ8:“C½sçN =¯¯¯OMM¹ô„œm×|ðÁ×¾ö5ØÔ½ÁÑ£G!fþËâ¾²ióGÒéQ·ð ]`,ëë뛘˜`šŸŸ¯I&ñ4#‘·_èQi@oñ'PjÅ”tû˜=\ßþö·!òê5hëFLÞÂ@ÒšħV‹{x ÏÐ5FŠ––†§ÇWa÷5ôOFdG¦^™ö¨4zzzò͹¯m8³³³½½½ùRøÁ~é¨ýèG;;;áב‘‘îîîÈÊöûï¿?-Ð6cþkf¾`LgËe˜ÂÃ#'÷9tèH°S§Nqß~Âè÷w/ÕÑ£G53È6çÉë€êŸtµUŒîg~Íàã£TŽ¡I6ÛÎhYPH¹ªÏÐ)ÅÖÖV[[ŠìAf–píÚµööv¿ çQ9ô÷÷GTÕK—.ñÿæÍ›ñÓÓï}ï{îϘ¥¦O‡°Ÿ2#å.ƒÌî}×^týÖŒ\®ƒP­äúÆŒ\3;±0AhB$’‚¦\Vi‘ù}N#'ñaܧº>~ü¸»²b$jß`ˆ¥L°lc)9ci^b³Ãl„°îE$¼%"óà,Ÿ´ž¡ÓÙgŸžž.¼Q%ÐÛÛËŒ-Ä“´G>0Ö”rú“‰ kùA;ÈŽ9¿¾|˜h?ñ‰OdkÏ.ÜÒjÏ èyll,øðް¹¹¹µµµO»–÷¨UyÑ××'i´Èøø¸.`ܳgÏRp4‡ååå'Nh4Õw™ëÑ—…÷Þ{¡ƒX OM’ZSS“;˜ÐÜÍÍÍ„‘W…iii‘í9“…,‡Ø5“'5Êõë×¹I\-õq_&Ù‰Ùm@j„$#­ ’Mó-$q$T…%q"2ó€V)2éhm@¹Ÿ¡%}$!}YhÁO*“gffF•:tˆ`9ÍÒy†NDÏÅY¬dÏ“´G…@o×Þ.ýÔˆ¿´´´oDWY‰?ë8ˆ‚py¼½ß ÁLèüZ‡çÙ"gºê “!ä7Úà•þüùððp~žgÊ"óײQsïÞ½¸GÎàÈ <ð­Z:sæ ¢¥µóóóL¼ÄýZ[[©[ºÁàKÂtww“”ûȽVDd›˜˜xùò¥ìƈ>L˜+W®LMM¹å¢8¤ðêÕ+fÇL6¨W&“···)Qvܸqƒˆp?ó³wß}—^ñöÛoS² w™éÎý™bR?¤O¡€B1§dr`¿eE‘røž¡ÓZ1…ô,x’ö¨(èö yŒ€Z~„ Ì­E8è)ÄBÔè 49„+·†þĘ^ß&}.\¸ ¿O1l×"_‘Uç1kþ pþüy˜ BÍ… # á1?C¿d„‘[-Â0à »ÜkE„ÎåÀCYhNðFˆàó· ÁhÊ®®.®åÕ ¦Œéort­Y²Xˆj¹ç†.MxÈî×E–kÝÚf´'ëœg¼]îAgKÒIÏÝñÎ;Lë~òHô+[î‹ Þÿý¿ø‹¿øáènÉ>è¾$T4ÆhrŒ7fŽ$ò4̈¬£ÒI×SÅÆ<33322ÒÜÜñ²Lu1Y¡žø ¼ù~éK_úÄ'>‘ï)c(£0ƒ² ¦Þ.wN0ƒ2+ÝjL+Oœ8Q^2õv¹ÓiIKQ(VWW+dyÔ£ÁÚì·Ä]vzÿðÿóT˧µxÖ¼Á!/“IKQ<þñLJIûƒ Ù@c©ÐwÏÐÉãÈ‘#:A(LMMÁÍ î„}mmÍ “U^'G¤Ù8ãQ5h݈¹iL˜ÎÎN×:X‰xóÍ7™kî«—k‰K§t<Òœ–Ëjž¡“ÇÒÒ’­o¯¯¯ëð¥vÉüÐÎÎεk×´í0†††bœðT:hŸPµyDqýúõC‡Õú^!)©ûÎü²“|ðÁ›››tÈ•••GE¬‘üà?ÐY,E"~ìcƒ¤÷¬¹¹9¨—q?:¼Ttt:aeÙé⇠"–¨c£v°¢çÐ^Œ¥µ¾æá:a\¸pÁ]ß¾|ùr°çüÎ)”lÞ™a¿?}ú4]¹½½]ƒÐ–‚\Þž8qÂÆh8[+ä¨#<¥ïjÍ\=xtt4r}öìYKœÙ€× o“.ø933c#d•nyxDûþÙŸýÙŸüÉŸ,,,@À>„ þðÿÐÝPö7ó7Cð¨¸3ZçÏŸöãÃâââóçÏÝ;²U"Ú.ñ$H6” 9ê˜5×êê*c i|Ä!’®­¼ð $`âÈÚµN[A{¶Súød-VfíP©¹ƒÆ +‰vFkxx˜GtPX™Dè¦cr*»}²„§¯Úîõ7,q¢(q&¡I–e.ø©t wîÜñÖK<’ºòŸþéŸj'6Šõ¹ÇŽãþO~ò ö­o}Ë®¿ño$-u €÷aD„Ê®™šs!³ÄaÄ}ˆØNËž‰n2û'Šì™áYÍžžî(YË%§ ä"•Õ!FÉ+[‚Ê—¡’0ŒfL§tÒ9eØdeeù‰¥ûrPÄp§1šçQÙg¥À3t’‹œYÊÞ ³¹Ñ0Œþøñc:ŸÎ¿«³ÚÂ&Ü)ÃxêptYú¨B¢kýœ®‰r¬ˆvÍœU>;qópõêUÑ9?#|la<<ª”céÄŸýìg¿ð…/t†¸pá—¿üå}ìc Ãë£EïßþíßvÄ >lÙ»ŽuíîîÂv“““A¸ÂßÝÝ u18¼zõŠª€ê"ƒTGÛ=ÊxEHÆÆ"F¹––…ˆôöö6ÕÈO˜›>”nd,ƒbú²àÊ„ÍÁØ… q– 9’¯l~ñggGÃ&²’0Ð9÷ßFFFýd…”;LéÈnbb‚ì"V9“…gèÄ@¯umÇ :Jç³yÜÓ§OÝort5­ok¼ÈÍmÑ›å#ˆþw$³Å`ÏZ“¬ÞèZïaÎÄ¥FËZ^ÇÒ“¼ $]£õ€}íøàý÷ßçâ3Ÿù œ­áoÿöo‹P£ÌÚ"CÐGu.ÈrRB˜×!"qá`thx4§Ÿ{·K—.Åld1æ.D†0Ê™lÚp£G 勿QÄ¥…§ž¡“½-ÛÈ{°·GL]–î;B_µ¶£ ¥9®(ÚÆ%J¦óñ“ àüü¼:tSS³Eb鳙ؕϩԶF8wx%®\¹¢ŸRµs™ý×èd ]I R¾eZÃô÷¾÷½|ŒûWõWv[|ç;ß Â¯×ÿøÿx ‘j•Û5ÌÛmbr†Ñö†‹HF31n¸Ý=ujjŠ07ÚíÕ«Wâ²¢ð”`ò©/ƒ%˜seQî¢%ÁÐæåUóáÇ($Œ‡}}}]]]¨%JD~ “®õ=”è‡ÜÃÀàXxµÃyñ©Á‹°,ÁHöéÓ§Lët_'¯è»\🫫«Ü'€¼®òŸGº£„×áÞ½{rï ?~Ìu|â<ÕŒv/c È7ª‡GêEûv”³k!>ûÙϪGýæoþæ¾ðÝüò—¿LÇFiþÊW¾’ï 3ú´34ï+•tzÈ&éꉫ·r½Sú|ë^†]3 0"å‹û4D&ÁPvaÖ+!dhÝ"2ò(µ¥¥%ä¿âÚX$è‘Ý4Ø ©õÚ’råç†J kDÑ#Ë‚0nvÉ‚"Ї½çŒ²á@ž3è:µòá–é­Ôtm ©]&ë=gxä„èîëEÆu4ùõ¯ýÛßþvv˜sçÎÉø׿ÿû¿oŽ1¬ïÐÌh[[[ycüh ÞsF`@@e.…¢|úôéqÜY.xω!ækn ¡̶$ûžíáQ4èft¤­­­Â7‹i7]ÔÔeôcèùw~çw´ÄÍÏOúÓGöÀ#…,üØ•hÞwïvÜÞÞ~ôèÑÜÜœ§çâP~ôû¢¶Î&½÷Þ{ÇŽ‹ùí‚`ñ®v=<öEoo¯ÎÚˆ}ñÉO~RûruDÐîÿÁüAv`èù+_ùJáò¦òæÜ;â­r'-E ÃëÐÕ]Ö5"–~<~ü˜ùoc“kkÅã8HUß­£íÙÙ(b»âøÃx+c:{Ãkë÷BzTž¡«xÇ·u€ˆÅ1ªaeeEV“’¤T0ÔI„|Ö¸ïÎù@€žãgúJ]÷onÔIú=vkk«§§'é⦞¡«l+%u†}7ÝxTŒ§uÀÐf¥îÒ¥K9تr<ßgo»m´ÕZŠÌHu “{„7“Ÿ…ƒûêիÇ˳€Gž¡«ŠFX.dO™‡G<îéHèÊ9·5çú"9·Ž¿~ýZ3Μ7ê(µÓÓÓöÓŽ§S!îlU{qq=x4„³rM1fùyóæMê9Í,’‚g誢AÊü–WaNer.Éâ,ò hooϾ999 mœ:uªÑöˆ™]B¸¹¹™kêfsâĉ–––¦¦&9®èëë£~h/ÍcúûûÛÚÚ#g?܇ïI›¤055uèÐ!Òt-k2CŽ?_טð ]U4u5ÚpæQ È1+™íV¡ìLg±"7¡Y8¸}ûvÒ•±?º»»ïß¿_–¤dkóèÑ£Ô•/[›Ô¹BöŽ}jæ9gffVVVvB¬­­ÉSí™3gC‹•‰~çÎÈ÷>êß{ö̆gèêµ ALònû]¯¥CÆkï†pïC¨_üâÓKW¦I¤³³ósŸû\äþëׯõ±æâÅ‹5qøÔ V—[Ó~õêU¾ÎA8ar7îA·TQ¶qVd°êúÿÙ{ßÐ8®4ß¿½1DLÀb 7 q°ü ĺX›Å6»X"—Èìܵ˜p%²w%ϰVö…µ»\)»` –H0‹ÍÆfl ÌJ`- –™`ŒeV #r# f ƒxˆîMÐï“úŽÎVª»KÕÝÕ]ýçù¼hª«OsêTõùžçüyRnµ~NŸ>ͯ½½½­­­Ú|/[ºÐÞB/l=t騈ÿy\hIkÒ¹0*´+ Ó­¯¯½ô»¼xúé§‹:'±­­MýÛX{IC$êêêâÇU‡¿œ ÒBÂØ•­® E¿ñÆêšæóîÝ»N\)±‘‘ý÷1¦ic&äóÔžþyô~``À/ÉD‹êëªêð-_ ´fŽ9b6t騑.î¼Ù2axxxgg§¬ü>&ìÅ‹eÑ®®®–&QuíÒ ¸wï^Ò5_biDa–gbÄîêêB5ÕXY__ïèè !ÙÇ4¡FGGÇÇÇåíñçÏŸŸó@žµçž\óp1²ù´Å bzzúÛ-¶’v^=ì¹oDˆ»ùêcÏI¶s†M±D6ÜFE⫯¾’¥X‚´bçÂ… —.]Š%*t—Fvúymç{Îõ=7æ©)hi›– ëåþúë¯ïß¿¿²²¢­fœ‡?>ib?óÌ3Řä52-̯#&×ììlss3–\‘ÖDPŸð'ÅŒ£>Áz®¸wMÅúeÝvooïÄÄ„‚— çÙ¼ÓÔ&óóój)VŒBËïO6W©]×öä5}úé§“ÎoŠû·míŒÛµF® ™×¯_×öqˆÖíÐÐP¼³‘ÿ®®.Dš¿êòòr%NuÄJY__w ¥ „6JúÔ-ZHþUR±@™#HUï("'úûûµÚ°2Æ¡y~?þñCäÙñèÑ£Ÿþô§¨u¶íÜ“¢R¦‰ño¡ô¨ 1&šššø¤y;>>žÇà·ƒ(†¼–‹‹‹h':]__—*ÞíÖÖÖ3gÎðòc#ÿ•(Ïbjj*›#¶\¡ÒU““±ň³¢¡¦îÕTžrWh„öí·ßÎÕ‘!Mà‰‰‰b8Ê ʤ³uÕ 人:, j@Ì_Úã|jg\~jhhà§èSQ43Ó0bD xøäíëëã,¤w”Hx¥y·‰­”™ÛÙ Z_[[‹ÝÌ5J†Üع%øe­ÐHìØØfq×rҒߵŠœç6£ÍX$¨r¸¡Œ6Ó¸“NœöeäôéÓIßYmÁsÜ·o_•ÍåN{kÑCþLZ=ø³ç4yaaטמWm¾xñâææfem ›«W¯æÔ’6Ê Úííí®Ïµ|ëyrr2[guàûlÒ÷TvtuuâBcxkkk!Õ?Yo›QŽ{¤<¿Ðr~©Ån½r¥¹ ±O/O´ï²‰t¥ÀóBžçææ«L:ãL‡ÿóþ6'ÏßæÞÓc¬í—_~™ñ£>Êè.ŽØþþïÿ>bÒe¾@Êpš/DáÓIäé)Ä9‰)´QbÜjàªß“©©)*ý†††;wîTÊZ’Ds·¶¶2¶¥’Qè_þò—¿þõ¯Cd¬ÖåÆ=†õúúºvtÿÿøŒ ­0Qò666ö’Gì:]>P¼Üf,QÑNŸœœìííÍøk}}}Ò÷jµKwww{{;@xåÊÓé²m¥þ¼téR¶©Ä9ÌÓFÜ…/aúì³Ï>ùä“P2^øÂ /|ùå—NÚ{`7cUÿ4@²¹ÈXXXˆ˜=lèùùyŒÏ¸f™•›Põ÷÷ûg‘>|8°-A!±ù±éÜ¥„æéÅ‹m×ÃÏ¡C‡®_¿ŽQÍÄ÷ßeMyËDçÖ÷HyÛªcKiê–¸zõª«»[ZZxWÔ(ŽG2BüõWõóŸÿüÀ:óƒüàW¿úÕ_ÿõ_+QnøÃ?ÌØ¥|ÿþýœÒ’N“ÛXìé Õôô4M³þvÌââ¢Æ?´¿:e»µµEÓ[ûýékàòÀIñÄÄD,¾B8é‘t.ŒrëùÁƒh3ÿk^ Ïc^»ºÔ(·nÝÚÜܬ««;qâék×®íyɾðhõo`Z5&—zÌQ¾¼7oÜP1XÕþ™J!Ždÿñÿ1ŠÐ¦_qU–KÂŒ?ñ0J6*†Êjó¸(`7£Í„?þ<åÆÿXš&<ÿç»wïªÅû466FËLÛ°óèQè_|‘“´‡¸k>S˪L ÃÀ_›ÿ¸4#é¼T?õõõØiع.ØC±æÉÉÉôžíèÆÅÀ)%¹¤ËoßGÇÙÓ˜ì!ýÕ¿ûÝïò¾#çñCêüδyûúúôÓ½{÷ü#Iœwù¤Eü·û·9=m ÆzyêÔ)t‘æ¯{ôèѵµ5þ½«W¯^å$-3àh6†8'ÕQñÛÅÄ0Œò‡k‹GÒ1ÂØC¡©vËÊwf,æ?üÃ?tö4†]ˆc,>ñÄyÓþý$D !a2‘Q@h‡a­3Æ¢UïÓ§Ÿ~êf\óSkkk¶H¢,ÍHÿÍ›75“™§q@ÒXÏ´øéÂ… 2&õúúº´Ÿv€¶t™™ñû…ÐúËüJÀ0 ÃHg…~úé§¿ÿýï¿ÿþûIç33êžåøË/¿D3~øÃÞ¾};ãž ¯¾új”†@×kÄ.î”×\øðÃsÊ?òÖÖÖXùÍÉñññ’•á¬Gȯ:Ànv')v>>|hž· Ã0ŠÇÞã²Ï=÷\cc#•²›ØŒŠÚé9y÷ÝwýÔSO}ï{ßs×¢š…O‡FùˆS?+!Ž=zäæ8V0“a—7¿k®ttmÎ,×rÞ{ÓÙYÉþÝ$)|š2þ)Ü4̆NÍÙ´ùb†Q5DÒ$ùÂ… (±jäýèG~Ñâ§>ú(åêhÍär_rÄLŠñ¡ùäT@ï½÷žf¨ÿâ¿ ÚçŸþ…^Hym‚>øÃÁøÍo~ÃOÿðÿàî"j¡_›÷555¥aæ¢&”ׯ_ïêêrª¼¼¼\WW7::Š=MÛB–´£ÜV”Õ È³F:L¡ £:ˆª@˜­Iæ(öïÏV#¤ÏäBÎ?üðÃ\ G¸}ûvz7õk¯½†qü“ŸüD -°°‘ç¿û»¿óÛýÓâ^J鮤»»ûøñã´lü"M)¹„Э_<ä¡cÂâ³3?H4[—¸-}6 È—R»ÍBù:=BÂh šôóZX•nnºÙÈŽßýîwR8'´~ý§ôöÇáǹe'ÒXÕȶûuhh‘ÞÜÜÄH ¬9F¡ý» È®ÍÕßÙÙ‘îríǯ]»vôèÑÏ?ÿë9åCkß\g1ß¹sgß¾}´™°¤¿úê«3gΔ¾¡`†Q ”£cËgŸ}eõ`KþôOÿ…þùÏŽ¹Îó÷Þ{úÅ_ôÇÐØØ¨eÜß|óÍßüÍߤ|ƒÓ‰ÍÓ™‘ÎèÓ4åµ?²9áªÀ¼6ä¼££#×.Šºº:ìxÄ>½åƼ¹Ùæ)Ï”¿té’öÓTÛH+7’(ZÃ0Œª¥ZÃÀòS&~ðƒ¸njõ]#ÒXÉ/^ô{/!'ùLyãî'ÄCÍ’"ï…X¹‚v...JS³…áW ßÀI¬çïB»ÜïSL?eó÷»gÓÄ0 ÃÈF9*4 ÐŸ|ò‰›SEFwÝ¿÷ üÄçŸÿùŸ'}C%%ÜÃ6íL^¿èÒÐéïïÇ,–?2œW2οøâ‹sssþð£ÍAS`vvvzzš¯Ù¬ü’5M Ã0ª½½~&Å_|ñÓŸþ4êÈ3 ßÿþ÷KÓÅâáE 1jK?«¼mmmòÙ›ò¬ð¦¦¦ÍÍMíÖÐÐà~Òj+·æ »™›’+oLðŒ ¡ôÙF©Íë§aF8å«Ð°´´TàƨHø¬´ Qè”'„¥ÉF0ˆ‘aé.Û·o_!±aLgëå‰ÙÚ0 #œvŸ,=Ôû…̬.¥<ïIYíø†MóæM(“ÝÝÝÙä¹<y†aT e­Ð)oíÓ«¯¾šÇêäïÿûå#Ï)o*VÒYøȪVjåçÍ;IFÙåUéܺu+é,Áü Ñ×=AžïÝ»À&r†aB™ÎåæÒs[öÒK/Ý¿ÿöíÛͪÅÁƒ_xá„9Ù…UÙX[[K: k”žžž<.ÜSÝm"·aF!T†Bÿ>¯û÷kCÓÇk3fyÚJy»bä·÷sÉß¹2AÐÚ#GŽœ;w.¢Ÿ“C‡]¾|YNÑÃÉèÎ(š«hSð £j¨$…v<å‘òÔ"é¼D¥œ»|;¶¸¸ˆBOOOÏÎÎf\õä“Ovvvžõˆ­y5 Ã(„ŠTè Å ÷%’,Ç<.]º´±±ñðáC,`-‰nooohhÈ5çDbs¹ Ã0 Áºt`¤–³B;´ƒV~¶m"·aFTÀ\¦Æekêf Ã0Š)téðïRõLOO'Ã0ŒÊÆz¹KÇÆÆF™EÇx§eåC­F¾ÒopnF‘0….)³³³Ù¶ª&jª· |8é‘t. È ëå.)52:[#·i†QTL¡KÊÂÂBÕ¯Aâ Ü‘Ì0 ÃH™B—ž‰‰‰¤³P\çªo…†a”SèRsùò夳P\ÆÆÆ’Î‚aF5` ]jV=’ÎE±ØØØˆèßÛˆùùùááa›¦gUƒ)tT±]Å·Vþ Í###¦Ð†Q5˜B'ÀÄÄDµŽÔZ·aF\˜B'ò\•óÅfffªµåa†QzÌcI2ŒŽŽVŸë’þþþ¤³` ³¼¼œtŒ„Y__ooo%*SèdØØØXXX8~üxÒ‰¥¥%óôiÔ¼ðÓÓÓ333›››ÛÛÛO>ùdÒ92ÊúÀòÝ$ÁÆ$Ë£Â7…NŒ×_}qq1é\ÄÆ¹sç’΂a”£Ó‡êë뛚šªgûF ë{l||¼££©ŒH·´´P‹ööö¦0:yxBTIç"ȶm4iT+’çååe“g£xðvÑœ˜˜È¨¦ÐeAÅõu“asQRV ï۷ϦsÇíæ¡¡!“g£4Ü»w÷-Ýà±^î²`{{ûøñã´¤’ÎHtttXÿ¶Q•¬®®ž:u ‘N—g~êìì œœ››kllL:×FÛ¶°° ‘iÿòzSèØhhh8räHÞ—£v===SSSIßG$úúúÖÖÖ ¹ß7n 8p é[1Œ ííí—/_Îè‡ä«¯¾ZYYñŸ!˜É³Q8¼HÔÿ---›››®ih ç=ò¾…æÙLOOwww'}+{@&çççQhë4ªááaL™lÃæææÏ?ÿ\Çmmm[[[6ÖcÄEggçàààè訫²qèrA½üÛ×Ç%Ù#“sss&ÏFõACy||<¤+‹×¾Å£®®yæLH“zyyyßwáÂrvý¦ '’.%“ôÝ—CCC¼nZ’)tqèС;wî𦖭HSµ··›#b£ZѦsQZŸÔ¤)oIkˆïFܲ¹ÏŸ?ÏA\khÍ']T‘ ÆŸ[VÞ‚K_ªé)òî]ºtÉuÌõÔS)ïŸõÁܺu+àL”üüìg?›››ã˜ëëëîÄ0==ý¿þ×ÿzüø1Iµüää$×þó?ÿ3ˆ’øõ¯ÍkÀÁ‡~øÅ_ðIŠÄðÓŸþ”7$åuæs†ð.9â!À{ï½'QÀNxûí·•„¾Þ¿ÿÿþßÿË]ÿâ¿ ’¸}ûöG}ô /p ÿôOÿ´µµõî»ï’mn™«TcçS„äL}}½+^Êðßÿý߉‡`333”I¸,¹ûrá‰ùÇ?þ1Ÿ*ÝÍ B655Ì]òå—_’rÈO¿ùÍoˆ™.ÁBu%ITŸ}öÙ&WÜxÆR%ZRá$ù'-W\ØýŸ~úé¾}û”“@nù•#•O>ù„Ââ‰'ô¸õLù|öÙgÏÑÅL³…þË¿üËoOîåFªÉ%‘ÿ䫯¾ÒD†¤3bÅâÚµk´>£„¼wïž*SþQÂòâÅ‹:怿–:Æ7ñ<|øP¿"œOþÌ Ë›`—/_¦Öæ˜jamm39r„*‚cÍ€AˆSùç$á9 âä+ñ“ F<’èââ"þÌóUIŒ¯ÄÖÙÙÉWbàkoo/‘?™T$üJnÞ¼Ixnø¹œOeŒÀÔêÿ'åŸKˆ–Ë•¢j9Bž“4È<ñ« ü÷å2©¤??©`‰Ÿ ¯^½ê¿Dýd€]Ì|¹î‹À\Î2Ƨö±”*!UžDÅy¾^¿~]9á– ¬IÏ-'‰–_GGGU&ÄC ܲžgxþ/ ×êe0….SÊJ¤yMžª‡êõŠ’ZÛ/çwîÜAÆøÌ> Ð:¦æÀ)(râW£öövTGó1%¥Z‰ö˜jÝáëàà Á$öNl¸] ú +iă„\~v¼Ö!w< T³ƒOâ”®K\]$™t×J˜IÉqs*Ã;žÆ“@…F`eƒ0ºM®Ü¨¯¯OO=Pû©3£¯¯O}ìþ¤Õ  vå¬0PWW2!‘Ê}} ›B—/jrò7ãÍæýN$ÃÃÃÓÓÓéïœaT´A©£¼ç²“0¿üÃÆ|åšÇRIjvZÀ###)oðt^:t¥œŸŸG¨²9ÿñÇ•Õ,j‡$ÉÄÄv’333ƒ ÞÌÍÍ!Õ¬®®§:~ýwª!7ëá+ŸüýÑrRAư)ÑŒÀ=ò±‘O}ÝØØà*i’1]è×NN›û4[zîܹ'Nè¾ÜOÄÏs20GO—¸¢È¶Ó%I\I¾þúëÏ?ÿ¼Ä›rö—jÆÔ<&p-¥È-f:Ro¿òÊ+j¸«x:œ'üÝ»wùÕ¥ØÐÐîþù¶ÅSÄ>##&x×yøÇ–2Q’#Q’Núî £¸Îç"Eî:ÀïxøÐ,Ë@?*ªIýÈ‘#ê†Õˆ5£`Ÿþ¹Î¸cw¡r\Â…vÃÞ镉òà/Eëzk‰äæÍ›|r-zì.ÄúÔ˜îÎnî5ÀUŠÍ Bûå$ö¨âôG¸/Qü—.]RÆHÑ/î §(EW’*X—«l¥šþb¸5—º?<¿r‰ž)Ø_\„O¿Š¯<èÀCѳ0…® 4­@oX ’sKIß·‘Ô~%0râìÙ³þ‰ZÉ"¯R==}þüyì„=ç6®®®R¡ ˜‡RÂÝ=ÿüó1LkHº•`—¢®ò4ŒrC ŽÎÎΈEŨ ÝZaµò;$?Õ;»6´û‡¢U‡=RÞzåCííír‰¯Û!<×raÊó‘²ãÙ£ê9s‰Þ¹üÔ:(Ž„qI+ª;wî8§+ò’ž7YÛ=Eê¿Gù!‘«N¡Üar’ÙÓ:iw |:^:ØñVNËM·Ü_»Ìøýxìx®RåÓ4ðXåàE—+iò ŸÛnå´+^ÿ…*Ow>p þ\)çòN!Ÿ;».?åÏ\.ØÈ‰sFÌįuíy¸p6…®~L¡ky„TyþqÒ, / -To†_X¤ÊPË…µ§7Ãɶ_¡%ázŽ:X\\”7+t,qÒî’‡{.E”šKÐ%¤8å+Ãï.[1h€,[Þ\ºŠvmmÍ¿à^~”¹þV›@þÀ¥ÐÌ JÝÇ¥v÷ê@övѪ1á¿j~~žÂQyºÖ-ð8((®t .0eÞßßOåM'9£u1Žëׯwttðtö,ŒØ\n訹4Ÿú—zJ¾|å¹p8Ô¿Ô ›››T÷TÁT7h9×J×kФÚ%6Âóâ¼õÖ[éÁ0³Ðÿìkt׿³‚~’"z RkL:iyʃ—[I÷ú믻HP8ÊÁ 0“TO^•¼ bõðoäÃ}‘ↇ›“+ÍÐÖfÌ~t Ù†´å„<åIu 3õõõºJ=êójliólÝ8Å’m/ íý“ÞøPkÀ¿ F·ÀÍjj·?Wkå§…Oÿ´7ÀÏIí8BTÚLEã9SŒŽ£|°^îê€vºê‚€#â< ¾ ò;k¬ä 9]‰9Å]nñ*à .¨¨5$‰j¢‘ؾqhθÁZõ#HÈ¡†¢ ÌUÄ€ËÚ&Zg:O¥%qI»ý(µ§2E!gÝœ$·kÙÃÔ˘7×5íÆk5þíÊ\‚­Wò£qqò¦®fWùøo!•©—ûÎ;n5J  ”7 åj8™T”œ:Þw¼^nm§ÍíPn.iW¼þ±pÿÓ!r׳¢xü·@®ü›X§¾ÛC®mž¹‚ÉW+gȉî…òQæóëå6…®rL¡+i³ªÑØ£¥©îíí¥jöÏøU+$âH|­U†ÓÕÎ Ü»6N®,Ô>H*u­ësÇÅpž²^nÃ([¶··ûúú:::Pšêq9gR/,õÁVz¿÷ôôô§Ÿ~Š(Zó}Ô ©Áq÷( .[[[]]]¼cÚA2éåCôhñÂsllìÊ•+ÅNÈürW9M)Sw9Fvfggûûûypw°— Ú¨šS¸Êbuu•F†öƒÒ”«<–AïÛW‹•a`c#"”­[·Ü™Í׋¼“6—» ñOÔäÿÛ ÌáÏßÖÖ¦é]¥ñ-£Fi Ô××_½zUóq*ˆ¡¡!×¶¨¸Ì'‹És~PnþŠÔÍfZl6V=]]]Ùv¨”CĤ3hds°½½ýäÉ“ònQúÔ?>::ZÃ=.hÐа]H<•hCó¼MeËb˜Ñ¼“6]…„ìÿZ‚#o¨piBaË&"Ï)oøvmmmbb¢§§'éˆ ¹=þ|ù«5z÷Õää$›ššøäB·Lˆ–wCCƒ ÖÙÙ)§%!(†Àš"¡ÕÕ!Î6:–1¶¤ÈoCtÄ/âe ¿­­M› ¸ä(„ºº:· ‹Z׿-.L¡«9ŸK?Ì#éÜ™™žžÆt^ZZJ¶ŸV Hølmm ©¾ËDË9ë(Or…×××§)7oÞä˜t~6ä"#}mîžÌÍÍ¥¯•Jåáúúz®S[x—²ùB)â|ã7¢‡ÏµaAxšDׯ_§ÝÌüñÇúivv–›rËÍÑïúúúØoÐÆ¡«téÝf@—-È3Užß±Ü2¤¼v•¿mŽÉH}}ÒÃ\FÈÁSNIË Ö³Rä“”ÊHf5x™›§Z9·;{zz¨ÖÝÖ5<¦µµ5—a Ÿß߀$PòZÝ›òê}툓ò”žËyPUñ`ÛéÑ£"û–Ϋ™uàÀßÚžÇÊWMçæÝÃ4$È?ÇÄÃùôÞZÍ"<©p ®UÄ- ÿŠüÈ‘#$„éÏKHêÔB˜ rþÅ´··ó©ÅÇä\¯7gF)mnn’®²G‰¹»Nyÿ…••rèÈ?9!Q’“7=þ>´fä;L… ¿{)¯Yã\ž‘Üàà g39wáÉ0·¯åËþÇÇçEÜß$Ó\…įuØ)oÒòOwR‹ÉŒb0£ÝÒ=£Ü áÏX¶ëþÞrDìP—¾Æ]uGoooNI»>RêGy´ö/ë¤ÆIÏXY!˜±DUŒÊPn«Ñ¹%@NŠôÒ¥K;žój¾"~#ˆ\g§#o$΃·;¯Ý,øUŽ …v˜ Q}jÁ®6äЃ–‚!x:yçÎj }ÝIs¥@žµ‡–·ÛQCÞ`øäWù3ÑW5›t³œá çZb&Q¿ 籄Ì^Þ³åZÄ¿Lß­6ÖŠˆÈ)XçEDªï2OAq,¯/ÎUˆTßyA÷‡Wl*ÿ ŸòÜžg|² ©Í9O±ÅòNZ/wÕ6º<‘õ0UW=tL =Û¼??o¾ù&ÖO®=äªÜÑõŒËa©X©:Ëyò¿œj%‹¬¨KZ}Â< ”ŒgtõêULOìEŠ“þ‘T¾f\Pç66±úN†††ÜOœá'LCÿ“â½¢ ]Ÿ '5Ñt±hSžm-•â$ÏáÁž&­ô1Z^ÎÞù„¡ðÉ-ÊyVÊ›H/§Ü¼9è=ZN*¼½ÚÃã¼GÆ‚ÒvX´z±ÂÇÇdz•ª¯Ø©\å?ÿÎ;ïpËd’ÿ†ø‡\})€æ?º2ñ‡WçAÊkûG%¸<ãÞ ¯¿þºü¯­­qƒî‘eË[Þ˜BW-þÑhjárî ¬Y¨úûû©˜=ɪµ¿=_ü‚:”zÙíQ©Ý¼yÓ_GË'°ÞëŒCÎ íþÅé²8¦ý0’ÎE>¨[˜?&¢ÅƒsçùŸòÜýÎ#ãy¡vütýúu¬4ÂûUáªÇ™3güƒ¬Òþ@¢êN¯««“u›1W½%𕦥Îð²QøÄ&פð4;N:•1ªt×Üzÿëëë9 Îw<²t‘øÛÚÚ2оXü#&''ýM™lžâÒí ¬þ¹x´-ø‡º¢ÖÀZK„$u<8ŸÛ.oÎSzØ8t5ãF£“šl„Àßñã¨+5—òêDª mt¡1ffÄ#åUmÔ×XQ^YY¹xñ"(DGG‡ßÃÄé÷pgHT»n=z4µÛO˜Dºµµ•ªÙ–çÒEÑ¥Òæ(i¯âsçÎñÉãvXñ@åå àXÓ­?ÿüó‰‰ Ä@-0>¥ Ëææf 777]ü˜Âh6’쟟ET´Ï¸Êß&Cbys8©Êdtó¡ÈíóÏ?Ï]¿¹"*ÒJ¿q¤Qï$‰òö’gìNb «¼œ)o¦Uàâ+WéÅVËRçi¯9¤$¹M¬Š0£u+ˆœ"Òø‘;)é%žÀ¾X*. uBšk…Ps’:MâÑ võ„¹“ÖÀ¶.qyãÆãybz1Ê m_št.ª“ÂûWµA7-ùÔP_ÊÛBÇŸ(•ÈŽ·mjw Ú?>­N<”ÛuµiËÞÞ^m¬“n»\ÕéãвQø´ÿ(i\Äèv^ûÇžCŠîÞ½{Ü;ÅN‹yÇÛ"B;žsìŒÅÂUÚê›»Ó¶ÇÛT²Žå[;=íý¬f%ê¶sЖM m”=R!>¹VWùcSBäM±‘›Æ˜^zÓ¬˜¹2©$àÖT\þQvá.!r½·Êª»Üí(Ã?i³ >óoÜúÃë€DõSúãPr„Ôè87î/$þ¼øæ÷ÿýx^C£\±3ŠG í¹8-Ô³s£húÏû•ØuHºáX¿B» íS^?–zÿ\Ûÿs( ½ãê‹2Sh 8ͺŠåi#‡e…¶â6Ô«Zh±ñYVf/9"2¦©ÊyªcÚþËÆ¡ #¨A2®(õÏSW¶ë¥LwD“m«]M(•Ë‹”7A†¯³³³uuuýýý!£Î!h§¤‹-ÈÜÜœÛQà ¥5>>®M¦ Œñ#6>C¼$•š ÜÝäääüü¼þ Iç(lÚ0Àí<ÀMl‘E+&&&Ðé±±1÷ëÝ»w———å«ÁM(s Íè·Æõ«&³h]£)ÓŽF#¯>4븜'®N¶va~hxÒ÷”™üš¡e…fAš m¥Æ¿™¼7GLKb2Pܯ)oMkk+_©%ý3ÅÚÚÚúú:¢>00€¦j¶ æ¹C)|ZŸjõO×ÙÙY&3žÞzë­"í7\†Îgx]å $c€¡¡¡ðÍQðtÏ$4R¯]»–ÓL‹(áÕ«Wc6€Û)ËÚ0JGú˜qìhs*·zUýÞñV÷Í<ªmoœûQpæÌÒ’/~%c]]]jwò¤8 çr~¯d„œŽXûxú³GÞøUO‡Q©(Ÿd€úªò×…¬hU2ĬÛqÙKw‡’dO­ê<çrk,ý••y~±Ie µó­[·´(¥½½½Ì·ê«b¨ƒŠd¥ïNòé`Fø#VnìžDi*QVÄœq’]cc#U( ñÆo:'IBºÖRý¢èü„ø}üñÇ´Ã*aþÝÔì|j‹ªÀUÚ²lÇç?N “¸åññq„ŠØ°h9‰ê|úé§ò,KsA¢ÚžÆŸ6^Ô¶TÝÝÝÜ"Ê-,K2ÉOSSSdoܸ!Oa­­­ˆ½^Q™Îo½õf4¢¨}¢RžIþ)7×ýCi9r„O°›‰\š^þÜ2©s .{džâB¿Èç¹»wïª ] û›_I.Ä\~þùç) -bʜְšJ…, ?òb–ÊU¡%Ìê"CzlÕ½>¡:àÁñþñàH«¾pá‚Iu‰)“ÔX×÷([zêÁØ·ÍoóØ}}S\T¸{qŸô8þ¼Ü¯úAZÐT~Mÿ«b #üÄ#@$T óõwÞ‘9ýeÓ¾“Ú,%〥¸DˆmŠDi´W^y…c ¿Ìb¹í$9ª”¹¹¹À~DHmC ü¤vv›£S-ˆÒÖ’ahÙ=jÇWž¯ÛÖ1¦4ÈÂL 4dags$î¸wïÙ o.*²Á ñDÈÙ[[[S"Þè® ©‡7×ȤZ]äA[¡hP ½/Dy¸nÇÜÜ ^/ óÀ(ß¼óa” Þuž·Ÿ–#Ï©¦™Æ2ãF:Fì”Ò€. n·€jB›E"ñF« ”øÇ¡drUøß!xé2Œq^~­?¡7ŒÓ94ù‘ݬ:™÷ÍßmÈŒ•ñð•Ô‘j¤ |UÒD¢“H´o&i}Bd‚s›Î¨%“¨#w!§cXwºÂHÚµ€V‘lkdër‚QVnࣙŸx:‹‹‹D‚Áí7®B€µ+¶;‰Ø¿: ´çwJ˜ô6Lwn¬wJÆÈò/'Þy¼*´ ¸ÇÿìÛsR¥¯A‚ õfdƒzñâEþÕþ­XèädÀ•x’piÈiÖ[ìs¹å1ö›¢Æ“ÕKl©ÝjQE®½µq²6iÖ‰š:ÚÝÅD+ߨxåûÚ× sýúu.ä+C¢ÕÂ-yÛñÞO·pÀ;&Vf¤¢Îõ´*å\Þãýó·ý±9ØÚå#' æ~u‘û#ÜñÜsV¸i§jE˜ÚÝï\ÉéÆÅ%€Üï öº$}–»¾ò“ÊÐIj"hÃÍoº¸+ÃÀvÔ;žsY~E8ý©¸WZÄ©‡¥ ²x:yxBå‰üÃï¡Ðä›"¨ÊÊÅú+òæÙSΕè ²º¢Ñ>öU¦Ð;žø¡±Ø$ŸñÒ5¯Ä ¾”^ìÑjï/Œl “¤PHl—.]â/ITDH¬°ÒîQ[kûO¦ÂCÓÐH:ÛF)@ž±2nµTVc÷¡¼‰®Ð÷îÝK:³Å"ú”´ Rh îŽ¥]Ub…F½âÚJ$?Š·PXêr(°©*K½|öüèììL_ežY¡uå__1ÂKÏûªn¥r€üP×È1Vº h \¸p!)ë?¢B'kÓžQU*4t{žÉ’ÊC\uGÆxwÅö:’T¼¡‘A¡%ÏÅè©0ÊÞ~ªÉ6*©bÝtIVóÙø•7–lkóÚ’e5¢Bs; –g±Q÷cU*´Ö‘[?¢Qlçl£*Á¹ÜÛÛÛ(ùòòrUz$0‘³ >c÷Û…¥¥¥ÖÖÖ£Gޝ®®òÊúíc–}褳³yogffÚÚÚêëëcŸˆ[ ñúó*72®ª¸µµµ5­Óµ%F1à½êééùôÓOyÓ2ïIPl„Ù¬çGSJÙuŒÐºE‡$èæ:ÎDž¯]»æ¤u/¶ûëh6tuwq‹ˆûFWœ íÐ$äêî=6JjÚðÅï(´¦­g wñ»d‹Žÿ*éEY½ÓÞÞοËzÊ^œ„à £Æ#bVxëiwK€8(j­E¡kaÛ’ˆݱ+4õLÉFdhðiÍé´Q8n¥ëž5Þ*4¯ 6ÓÈ.Ôòþ±Ãð]áÜv¶Â§lá{Û'‘·%^%ãe–{b.Þ;E¡kä R±+té÷m£M@­j:mä´YÛoD ÿŸãÐçÎÛ³·ÊÙÐé?-//Ë… ÿCjöííílc™üÔ×חʾ}:~×Wóóór8—+\•ÍÉNDäE}Ï`ó…$TT(‡==Ù¦< )ol¸HÙ ---³³³¼›››áËÛ533C˜¹¹9>9ø  Íû䄈TVOyíƒbûÇ.ô®z0Ùåÿ²©©©­­÷ÐÆ§(¸‰2¼9)ÏK¨™íÉïýrSQ¦¼z-~cßꇌ:u*åÕhäœTêëëiBÉ9°܈œ#öfðûÖ¶}Òx$…ÐF:ÜÇ´áȼ–M¯¬¬Ð´â׈íÖ¸ÏäZ€ç¨5錔ô–/yè/̛ɻÊ'­Æb$çþòIß· ·­õÛÈ+vvvÐÈ=§Dú/ɸrKNb@ƒª c™¤ån@áÃG’´o ŸÎÙ,áåÆM,Ò]P#+BÍŽS6\Mûô§El@†ipÈ¥*'iL5;u½ó(˱JyÇsÜsØÃÅælz¥Â]ˬ†!µkB`LÔ?Vª›Jy^ÚÉ€+I²­íÏä@†x´¸Ö­ZÖeŒOõ^Š+7¥åŒ99ø”gvå_S«ÈjÆÙªd dvB~Ã0ºk”•ÈÉ ?#ÒnæsNû(k©´ž‚?Âo|Ôûñ®SØsðµ¬< ›=›qU0 5u³†ã[½á¯ÑQœsÃø³¹ý¿\¥û TRÃVE¬ãðÆ´Mšç®Ò%έTSi!WÈ3ª¦ ™Q¡Ý ŠÍÍMM! ²AQè§Ïaº–äƒüõ耴¸Ó€ž¹bár¤‚¬@b£Q‚Äò'ýSOUìZ÷ÀCsb9p÷¨3òîDZ£©ÒÖw-ïojÔŸõÈžˆýS‰É=ˆôŒÏŒ“ð ÷±çǵ%Už” >ý‚ºãMðN—aíðª†Tú¯Îë½"tû¨‡ Þ‰cá ]>þ~KÞÎÅL¡íf\ùv¦Øüü¼6úȆëZÔ(wê»)¯ƒWT¬ËËË®¿+½?¼¾¾Þ]豜›› ô’io2b˜™™Q?’â5²ÆÕ·vL£Æç¸­­MƒëÙF“ˆ“¤9 uÖ¹Õ:?À×OÜ#€®®®l‘ë®OŸ>ükÇP"ç¤`’2'ò ³”•ú~ýkWÔ8à‘d¬¹¹™,é¹JýÀêoiiá“䈇´¸÷ÁÁÁlÙ£9’ÚÝrGr\râĉŒ½”qM|ëëëãAûKxee%}@„› x‘²ªÛƒ¶M–À/Ñòîq )J˜ó4D(pn°dî5jdŽ˜Cc±†aÄÈF+3B븮®ÎíPp5#B è*úôI×Ô’Òï}ûö§vw™åªŽŽŽ@xuð:7RHŹsçRžró5йniÊêÅOÔjvŽ¡¡!¹B¥y¡†ƒ³P„¡”Ð0ÍWâýC-øô7(–»wï¦ç“‚99DAÝy& Œlíp®Eh’[.!KVŸ¶†Š`TmÐc}}ýwÞá|?"ªMIɆŠ"}š©¤k-ªÉ-ëÞ3”6“.üU㎤»êåÆy[0Ciñ8æ ·F6ÜŽ°îÑ”l]K;æÌ™37oÞt#&îF8OQPn###j?!ç„?zô(ç9æ…‰8!¿pjmÞmoñsñâÅ=ýc²ø;3ö¢¦ÎÊDÒ¨ uœî“dqq=Ö†®[QáLÀÖàðáÇ\¢áXíå©ÞWmü©‘`d‰HÈ0´©'ÇÚZ‘\iÿT¡Yµ,ggwP­¦à'91wÄIlò­¾t-‹ ”’zb/{èr¨ÛÜmÂ*´¶MƒÐ(·d˜OnÄ‹«[ùtû¶’´bpÚ$T—«>}3%áùäŽôuà¶5å¦2öf˦/¼»Fsû£ìÌx?CBú;ãô*k˜&|±~tÂ{¹«x?«l„wÄÞËM P;…l½ÜµÉ·R²»•Å‚ÖÕìø¶7/sdLc¼jæTÛúáiÆîiRè ‰Á/àbûÜCz©óz‚ÎpÞï›îrçú& çÃ+rõðDz…W¸B×Ô41Þm»BSþ¥ÜØ1YL¡k“ýsssÝê–3ÓÕX¬›V]Î8p@“¤R^÷xø<€œ 0ÜãÍ­º•žD¤µDjxxxbbbyy™h§§§‘Rç5SA˜_;::hÊ’ðÚÇZKΜ9X«M€žžžm³±ººÚßßÿâ‹/®¬¬ É“““êX__瘂*êÚ•\}ÃìX¨©Å]Fmò…GQh&ÑÒÒUyìúT$È'*Bž5·.–8©³îܹSn# (%·É= ¥¼i :ïëh€_çýCõê5u«ŠžF˜?¼¿guccƒÛÅÏ1ò|üøñùùy®B?8^XXhD‘¨µib¢ÄCѼ6ømT7û1/äߣ ˆKç*7ÏÄVŒ: ÉÇlÍ;fµ™ü ÖÝœ|ìà©©)ùŒC;oݺ埩§*˜fV¯fÏamsœÚçkÌí÷榹‡êVqǘѤKT{.*äA)ær¦”64íÚÚl5Å·>Åj³61J†ã¹m’‘U´Ýmhh8tèPcc#ÍÄt¹% -HëÀMžwçLxÈÛZ]]]{{»\ÝÉˬŽåkŒ¤X¤Z¾6m;ç±®LNNÆ86dåI•ôry0<<\!ÙðHù:~1 µ†svssë|hh(]ž LÃ]nLd¬j-"×1çÕo¾b¾J<"[&”rèfŸkóFµ²?é $Éüü|‰÷·(eŠ ¨`âó•d@ûý„ø—#븭­-ötedû§ žôÐñ… PñÚq]Mh1}âï¶a›²¶¡5 ÙÕÕå§øªÍ 8„ç«ßCѺ-+´Ç! ¦ 9Ò· Ñ­É[™»ÇŸ'/ÿf,ÚPDyp‘+ÂßNè±?ÈGMÆüd$à-ÁïTD>ÑB\tiøÙï‡N»Y(Z,¡;wî¤<".BçHŽg—quûžS„´ñ‰væX\\ä‰\»vÍ»]:Rin4ü- " 8¹ ÒÄ©O…—Iô×I«ácÜû¤Ìq;ˆË)žQþ”µ íP/±ßîѬQÎówõ¯ uÈãW,TççYN=]´‹Š˜Ql,y×Ĥe¯ûÛþ®’"$ªÀ…ü›59oáÊ'­cóïÏá’öïâghhˆ«ˆÁ?Ê›ûIsÙÀªN÷=ž7d}}}½ë¥ ždÿ”é@ÿ¤ŒZç&–|’CÌ)L¥ÑÑÑ@A¥¼i¹BÎhj»Ò£iòú믻½uÝqÈy«G¶ò7b'ÛëÄSãßwòäImc“t6KolÆáyþI:wF)(w…vCÑ[JmË.!—SƒËQŸuuuTú\‹ (rÔ £mÖg iíQAÂÁØØ˜ÿ*þHœáࡽ)µé5™—qlbùT¿wï?e«°ˆêÍ7ßÔÎ.þãÔl«¶H‚ét‰ñ¿NãããmmmÇ=hYÖŽ<‹tÿKÎóQ+$mÇg…z™?äÍ›7ýݼþR› tÕ;w¨ÇùÔ…TèÎa2îrUôþXÛ* Þý*'þ=W¹<»ÅînDÇ.W$¼¹²wv7çð—ðÕ¹¤ögcg×IuÄC äÛáC¨óŸ¤µ×ª¬í´S»½ÓGP_7™Ôིšò:KÕ/Êí»qŽÍe[S‹Qµi«PÏ6Ÿ:V™xSáX/w,h‡õÚéÖÎHÀŒ6ïÜ5E¹+tÄÒÊ" âyãtwrT΃qh‡S¾úÕÆ¿[†ÿX!5K@#ë ÐÛÛ»¹¹©»ã–Õ6¢îÖ€eÊë‡hooW&5Èí–‘¾s†Ë¤*>·»šH" „ l ]à8ôž¯S â¶èZ£¬×C×ÕÕUGR?±LC]__÷÷w544$UVÚp3úMù‡Ò‡zzzUmò½°°ðúë¯#Ï[[[}}}Ü2çßxã·ÞzëÊ•+­­­œ_[[#ØÄÄ„‚«‹Öß)zÈÃ}]^^N…º!0÷U³ë¦’"×שêÑh´ÆlºIº•`”;Ùlè(†Nú\îëׯ+6g¨C;ÆWZ·fà§<¿%ȼ¦2hûíйÜ!vszàŒ˜ ½LrzjýSÌ€N j¤’.÷™bFy¢ÊTáá!ÕäWw´˜››Ó¦µó;w´Ø=vhtww“O-"ךkAšæˆŒø††nŠ`f:—’è¯SmB±Ð²¼zõªÐ¥auuu`` ®®nŸG}}½¨œ/¬ÒPs =111??Ÿt.¾¥·ØBÜÔž/M”0!ÛÑ+Óô)Óþiù·nÝ*ªonùøñã2ìüÇÙ›Ò+=÷$Ô¢yFþó.¤²”ò\ʶâw_¸³³óôéÓH!]lÙÊ!ýªöövç%ä½ÑæsîÏa\È£'Òè’;sæŒ|Œ÷÷÷ÏÍÍaB¥ûX&0 ©©©©ÁÁA²×ØØ¨éc|òߨÙÙ9yò$ç‘XbvÞNü÷H4„‰G»eP8'NœÐ±È©bz ÏèEÇ0ŒòóF;ÐçtuVVÑ[¥IÃgÅ­¶Ò\nÉ–ÚÙ]Ëyí'¨“Ôõ2’4Wñ8·ÏZ’tìØ1-ÉÝñ¦`¸Ëý³Tüñ\ºtIÃ?çÏŸç¼ ÚñVìÈïæ;wÜô"y.ä@yP<[\\Ô\‚q „8Ny¢ËíŽo©.çµ^È_ºwh¦(!ŽùÉ-¸ò߯‹Sa”îtttTF*gÎz†L"Zé"0S,Wdãj½x×’œh 8?É'9%©EVÊå©GF¶s}¥¬Ày7!¶»óüZS„wÒÔìì9£Ì‘7èB(Þ’ýJRhýÿ)M·|VçåH„ê  Gó8xÉp·Ix‰Â£¾(4ñð)oÕ‚Ëïy¡Rt>±\ÉK0çQ;¹V@P¥¸D.=~àár‹–È™¶<ÀɨKÝi-Y%æŒ ½³ë»[~9œBËÁ–âñÇÉO’g2¦ 9àÖÔ4Qö[úƒ(P¡)¿hÉŒ?f-¼ôjÍÅ«jTQ |Ò Ñw‘þ‡q͸PÉñ©cyDQ“®Bº*×ñïIƕͦÐF9£y£R¼iöeÝË€ EìÜŽšê×¹¹9Ì\~=sæLÈ£È$¼¦)ñyâÄ ÿ\•öööžžâyñŵ6÷õ×_Ä3;;˃áZž f+I¯¯¯“º‰K8ƒ g·ÿñ;ï¼366¶¼¼ìÖ19×¢ÙnkH?ü2A^?oÉ©@Ri>«Išb!-Ä“¢f;Ëó(™$¹bLØÑ ’SG7yPÜä5Τ{<%°¶òTyÊGéêê*­ÊD³uSé)º=IUª\˳v;\éQuÞM±G§Ê“=]¨FYÁÿÔ¯yO•'žblrŸ*óq膆þó虫©Ð1:'''³]¢ºcQ¶¬êèô9bT÷Ä2¦U£ õõõXçÈ©omm½ù曩Ýå7npÕéÓ§ÝX«<]´–3ç=È9‘çññqmߤ·AÁÜ«@.G-^² ¼°°€ÌØ•Ãôô´ ÀWtˆü•^‰  îW®\A¼[[[Ožý”ñ$gï¡{£ÓCº¤ÓÏûËÙ?îàwøŸàCIÐûGÿ^‚¼ºþy£”*_1œäéˆ_9CõKí¡)Jš¾Ã ò•É¿ q\|;WÑÿ?ÚTQƒ—”—£‹œÐn ;ž®Ä»­›“NQl§£7UbÌ»í™ç.üÞõOàLj§lI‹cn6zC5:üÁxpò×M¢¼ J:ß Q¸Bï93®úßxªrë'ÆîL@2ÝÝ)dº¾f;™1’ïÖ%Nß$>Ò¯ÄþD•ç@Ý’®ýEE[Ò•&-Í-X]¨–ÐÌ\7¡Gõžfê`H ò‰f£ÊºPqNºÙ0±OûƒjrRƒAF|Ì£¥¥…ãüâáZ,°ææfíy׆wê’å1']NAFGGÑH—h˜› /ê– ¶¶¶´$ié/”>$Q8ÜN÷BBZЦ|þW%xíë´Ú¡ZûöûûûÓŠååå}ûöùC¦÷ëÌÎÎf<™­bö;»0›=; hÆRr?"ç,,,hî y4õ’‡Œ;Ó\þùç9Ð3…Wç%Æm[þÌ4Ÿ ÀW5i ɯ¤Ë–l6S,«8*ˆZ›È}÷îÝ”×U“·ïÞtxÕy½€=ýb’ ‘àOŒ¿!ù/hŽª;ÉGÓc‹×™D*ýýýÑ}ú.--µµµù§³9s†?¬rèŸL>qº/®0]˜³Âu ç¢OÍ £…ä hø¸ø 5ë¡Ðˆom\ýü)¯‡™j…ÿ[__/ºtT*^E5b``` ý•¥þâr*2mÉçÎkÁç7779£mMO£n"~~"0¼’ ëp_55Q¶¨þÕË“†††¹ŠùªÉDÛ¤7b;>=$_¾ý¥å“üC³ _ñÁ–ÂÉøJøg’;&''3zФ¢XñHä¯åAPEuн_~ã2’×…WÁÙF¯¹²oß¾ÞB«Sp2ä™qáçŸ^Hƒš§°¾¾ŽŽq.\@ÆbTÇü 0 Ð äÞ½{”-:J½À±º‹ýwšíX†‹æãø+Ε;ïçoܸáÒ-qaÎÎÎVYïTåãî>vÜZ)jýÁ›››i,ž8qÂí2^WW§j™¹©ÝµRZ ïÞ@…ŠY'‰D+VÀ¿ŠRƒ²Š™w›„´´Äùùñ‡Líú—VHš­„Ôù¦¦&Χ¼îÙô“D¥!m¿óL³$!­âä¦2ÎK ŠëêêJú‘FBûdk詥ߣÿÑÇÀŽç¤©¢‡¢c<N„V™h&°ÿüW_}%?”;Þr¦Œæ=Òæk]½zuÇ÷Õè)gø…%®–oxã”ã³Ôî¢) k¨Iie<&$5 eEÕ Ñë=Ï;ç-Ål ‡NÕ’ïÏ(›²Tî8tÆ…UÑOf\Cý¤‹00hådôÕVîdÆO?¥Žå/™î9*Û…r›°EF«™P@eU»|®­­©2éîîÖHÙàà ç ÆOÓÊA ¨šäý‚ Ù ñN`ú¶èIµ<«nÕy…ÜñVôR ½½½N 9ÏWìÚt…æ¦8Pa)žK—.©L5o‚ ýÂ#wÙZ·³»zX'µe!ÏI¾Áy6ÚOIš­hw2)4?‘Šþ-ÙòÀóvjA³¦ËS·Ö7k¶…ø• åj[sÿxÞ”¯.¿àá¿e¢¢eäŸ'É1a(zâÑúÝ”·°fô9÷Ú«}¨ƒô“" ɃîBªm¡&› ë¾´!µ:^ªùªR&>ɧ–-ÅØˆó»¹sÑÿÄ5§bÁí7,×èEÊÿž *¦Ký²"Ê>ž¦ÐµŒÓépãÛYeþ]š¼½gEPú( Íæ ¦‚R×O;^­ÎWhÂ6Çê×t2!ϺJËGã-·ß ¾ô¦dO+"›››êFð«æŽçmV±“½—[š‹Ï&Í;÷'„½åÌZ$qÙÃí¦µã[ù@öÔ³êv³ð×Aj=èØŸõ`ûóà"t9WT.ÿþ§îš&ºÄ5Ù8#/cjÄRþÜE}Êü1Ô»¥†HÉ)Ïúƒ©'ªx9¢Ð¥t‘{®p5…6:­~Áb#g‘š\©§V[çZÕ¯vD¤ÎWþåiÕb„¥”qoÀBø½_î¡¡¡µµµ¢ÎI˃¹¹¹öööô¹6ªÐ_|ñE9 Gó ¸5ÊÑ… xPܧPâ” EŸ¾1pþܹs!ïσÛ98ú ËÖÖ–Ë^[[›&Œ¸_õSSSSÿòò2¯fÞ®Zpw¼yÅ¢l)ý+FFFêë뇇‡s]´@!ÌÌÌhOu®Õ^ŸIlù‰ÝÉy’qÓÃHGþ2K|…àš¡ŽmiiYXX¸ë¡“šG}ÒÓÓCí½ººÚÑÑAÎ'R‚œóæ“ Êô©S§âTû-.»^1:sˆ 0h4qjjÊÙÐ:Щ,ãzÇT–})ã;•i¨@K}d¹$ü»>ïì¬Ú.úˆ‡–$jÓ­Ôw­9®rWwwwgËê4ȱó]zÇk¯)EÚk„Äjç+I«38–Çõº «ƒƒƒ¶æd©—òqÆ«H=}¾^ú%”žß–•6—&ÃQlèT ttGéâN™ m”Þu½Ü…S¿Üþ/Åö/“7oÞ¤õ©©[;Þ0ƒë½ô;rgôÕøÞ½{î8¤¦Ð8‡’À°“H€æ3» ÑÅæ²§k}ª.ç{æµvB•ß³ÅçÓ!—aüÉ" zw‘Õ¾ ·_íGàWr‹º«dJ–Õˆ {ÇWY±‹ÛÚ(C4§'®EíŰ ¾]ûëØÞÞÆ`Ç´/êÖ¹•¥ÑÐЀæa•¶¶¶®­­•ÒÏW²7^¯ÁÆÆÆôô´Æ´–Ôÿ«s»ÖÞÞÞßߟȪqJ)Š#-·•uU2>>>00%dÞjþþ7gkkËí1£ÏIg°â¡bijjŠÅ˜zïbÏáw:å­¿&¥¥¥¥Äe””Æìì,Úœ”$BOOOÊVH:#ŒÁ'KD…NyÎR"vçŠ^QMn 'WDÎŒ¶“)Ò|sssÄ 3L¡÷Áài.,,ÌÍÍI³y¼¹uë–†ù´Íéòù_T¼½ÎåKÞðçâ?X”¿XºY­Ù°e¸øÊ(üÕËpVy±—;U„]4´Š/§JYމâÈÉh°^îÔ†Ó°Z”E_ºtIóub¾5BáÖHñ3/¯&½x÷E6Ê­Nö{ 0‰®Ð)Ï«bá)jµ¨¿©®¹#׉jß0¹Üñ_ãdºœ|ššB§ã¨œâ•&p(*Óé\É{GÚbÏ×ÉêE~¯öô:iTê1+·y‚eNN ]¸Û>ç†EŒ唓êc¥i¯—Ÿ ¹®›Bà666Æë«§xÑV=ªsz¥‹íqa'D¡wv­iivÒ¥gµâ­5–+9)t!{l_¿~Ýí›[ ì·Â t#¹¦ÐyÀED‹Ú)Mƒ,°ÿ´…@UÈß¹4›YìíDT-÷Â[ÜFb·rRè¼Íh7Hcï´_§i…ç¡yÌN7…V¹ñ;;;KcàÊ¥DÉ<T<#íU‘.Õª-K¹ª3ª›ožôöô aTzyØÍ›\:•ûh´[ðÑúÿïÿE¯;\·Ÿ¹¾Ρº)tt®^½J-Š]ÊDõ”{{{“¾û fss3©¤ƒ«­BØÞÞ^ZZ_^^n÷ÐÖ~¶‚¢üÑÂÊ­­­™™™ééiþ±}}}rµ–tÖ*˜è«­ÑMòwëêêšuÛÀd ùøñãwß}—ð_~ùå×_ýôÓOñÅ|â‰'þäOþä¹çž‹%?Ô­­­¹W¯¶êééYð(ý²(ž2ÿw’¦êNÜ®‘9(´· “J_Þ§s­ªŒÒ Ïõõõ§OŸNyil­‘‡B§<ÇCnP9­3¦ ^§öÙgüælž}öÙ³gÏîß¿?$­ááá‘‘04òœ‡ÿšUh5ƒ°ž±¡üëMNNŽŽŽR][»¼‚ÈS¡Óñû»1ŒZ ?…ŽbFco©«cmm-¤Nÿý÷Qè=S|ê©§z{{±ªCÂH¤IkOßy4Μ9“GqÕ¦BËCßÐÐPÄ­–Š íªS§N™Cª ââŠÈäÙ0¢@ý¨=s²1íXb=‡Èóüü|ºwîÜžñÐ\CMÃ;]22::zäÈ‘Œ›ß ÌfIW ¦Ð†‘TŽéÕ.º¨}/ÂÇ,y¸q%ªÚgžy&=:¨ ÷´F¤/_¾ÌAúFôd¬ÀþmLºb•f™‘MžW=R»í0d2}W%õNûµóßþíß^yå˜eêÇ&|à*¹aÏ–C‰4™Œe['£xì/< èM±B¶•ÄTÅBr•8U­vÓ†›!ÈÞÚÚÒ×kššzaaA_Qè—^zé©§ž ‰üìÙ³4¨¸i.8·ÛŸ>þ|!ÓM°òó¾¶²èëëÓ~Só2 iݹs§¾¾žRå èhCCƒh¥ñ&æg`ìb½Ü†‘ ˆ+U›ªZªé±±1N^¹reÏ ©UÝñžs¯ž~úé\3&gsd HyK¿¨…÷´ì Ác½wï^úy‰qÊ3sQP5­\!û/?ì‘ò¦ëûÒ.àü„$c‚똀÷A0®[%:ä$÷pFÉ0Ú0ƒöòåËíííT”êIÞÓ™ vð7ß|ãÿšÓPâ£G¢ø´ú·û·£Gb´Ñz/ª¤‹ªbȶFÎÍ Ìò›˜˜ÈfòÆúûûoܸ1î‘ò´qE•5œ|ñâE,ì<&]»vM]îI—œ‘ShÃHVj:|»åyÀÉO<¢'÷î»ï¦<ÚtCº»©ô‘U÷6NíT‘~ÞÍtãÓwïÞEt5äï|¼k½¬[ùt‘¨û½'´œ€´ÿÓO?ÍÉã£?7®F °^nÃHj[I`Ƶ1"£<çÍ_|±§Ébò´9›5ì è–]Ο?¯²Õ‡ À»ºº´1hz‡ŠúKæÌ‚ñ•HHKº©©I½ÜsssüqN9'¡rpyf¤c6´a$ŒÖÌPφô?çd(GáÑ£G¿ýíoýóÈ`ÐÏxäºtÍ¢ 22::Šâ¦Òföñè劤¹¹ùóÏ?Oy½~Êî|Êf-Xw“í×××1†”ž?ÞYW·oßvCÈëëëÅÉ6Ji@—lh‹¶íU™`½Ü†Qa`ÿû¿ÿ;òŒ¹|âĉóØ»~$XØÿñÿá¾~øá‡Içº:q®Ë«‰€#R#Ă6Œ„¡ŠßöˆX×cËÙÈ_ýÕ_9·Û˜ÎGŽqNH~õ«_éøå—_Fž¿ðÈÕG÷ÊÊJ*ÚZš¥S¸KÛß,éŒfCFÒhÚ¿F8¿ùÍoRÞl¯tÅuƒÐ}ôQÊ›_ö /è¤Îä„Üq;‡”F€*^žT•-JÄÚ0*Œ=MmÌe Q¿ôÒK|þñÿqÊ3ˆ‹áö¤–©bok¶áU™` m ÓÞÞžÚõ[…ÿò_þKÊF‰?iá–3—gffFFFîÞ½«¯¹šÑÖË‚&Ï' »»*ÇÚ0FU¡|Fáå—_VÇõÏþóùùù Ôô_ÿõ_¾þúk)k:np: šÍ[­½¸…sþüù¤³P\ª¸‡ ‚°™b†‘0'Ožä3úŽO=õÔ+¯¼rãÆ äö®‡ÿWg(ÿð‡?tÕëëëÚÌŠ_•ÜžLMM¥B·Ûªqúûû“ÎBq9{ö¬æ0&‘šÆlhÃHìÔÇSFߦâ¹çžûßÿû···7668p€8@’Qßßüæ7úêŸGÖèÁyÍ2‹‚6÷^³è‘%‹¢c£Ñ‰c6´a$¦ª¼wEüÛ¿ÿ‹ó¯½öZÆð9m¼±±±ººjƒ‘ÙˆØQéhÒ¤sQÓ˜ mÉÓÓÓ“Ú5[3òõ×_¿ÿþûq%÷å—_þú׿ 0;;›òÜK%]0eJŒÑš 8¦Ð†‘<‡F±\‡‡‡3øàƒÒgnç zOk Ûâ«íím ²¾óÎ;IL™R#mÿ†ÓF"˜BFYpåÊ>ÇÆÆ2Î͹ÿ~¼É!ÒÙÌèÑÑQò`ÛeѪ>OŸÙ03:YL¡ £,@© ‘Æd½"“Z )Û*8;55¿Ý¦ &‹)´a” E2Ý%ò³Ï>{rÏ<óLúÉþþ~DºŠýYNM‰–MLShÃ(ÅÞÞ^’j1Ð×í¼”ÄÅŸýÙŸù÷ÂÓÓÓ“““O>ù¤¹e¡¹¹9é,”ŠN[meefôüüüêêjWW×õë×ÝyÔtppð£>¼~øða!I´´´`‘§ïº±´´¤)å÷îÝ3:”Lí B‹cÇŽÕÚvÑ_ýõýû÷WVVô_sûÎiýá3Ï<“Þº-¦Ð†Q^,//×××ÏÎÎöõõùƒ±¡‹· —*¸­­-å5l‚Xµf@§jls³ÇOOO‡¬›Ðñƒž={6×í\óÀz¹ £¼ ®m'''CVHÇ&B{{»æoç䨤9}útÒY(5µ3î>??ÿãÿ8ʲÆGýô§?¥ÝÑ}~˜BFÙqøða¹ÅîééÁ’.jZXϘì|’èµk×’¾õrG‘Õ Ig¡è ´o¿ý6 ÓUKKKEÝÔÕÚ0Ê‘îîî`OcI777i¹K.éû.w8tJMÕOJ@bÇÆÆ0‹ó¸–«ÆÇÇó»6 ¦Ð†Q¦`Ô.//ó)37úæWQ@•~õêU™ìÆžÔ‚A™N7ݰžµí[‚1„` må‹iµµµõÌ™3éK¥ó€ ÉŸžž¦æE›mì9:UoPf¤Š\}øá‡-à•••ùùù¹¹¹õõu§¾ÎèÝ+œÿT1²g me "úàÁƒÅÅE´avvn``@SÉruŸ™™!Lg$aÞÜܬ)YRŦdmòÅ_dìšúÙÏ~vûöíæææ––DúË/¿Ly¶ò§Ÿ~zãÆlQÅè9ßa mÀ±cÇ>|xõêUDb||üèÑ£uuu]]]Q¶”^]]媴™KÐilIßY%QŦd8±Oç.Ò¼Š\Ñn0©·¶¶þú¯ÿZ»ªÓUÇɯ~õ«?ú£?â«:clÅXyaë¡ £b ²À䘘@\WVVfûì{ßû^º ¿>úèôéÓO?ý4ùÿá˜ñÖoD=Æ[0…6ŒJ«÷‚VÆñÒÒjòFÎ2^‚å×ÙÙI…X³& QH›5@2œ/ÕD# ôÛ…Ð~òÉ'y\ØÜÜŒ¹üõ×_ûEé%ÿ|ð¾bgû,ÊêÀž˜˜àóOÿôOö³Ÿ­®®ºÎó÷Þ{:°‹`9W}óÍ7ó7“òFÓãͤ)´aF$¨²“ÎB2d´5+äù¥—^òO^ëííuVò… ´° +ùâÅ‹nš?øÁ8É'_f÷Ó±cÇ ôTšŽíme†‰2ّɈ Ú¯©Nlt÷àÁƒR_×íNº!gàå—_Ž=‡¦Ð†Q% ïììð™tFª™lþ³ª›jí<@VÝþè!n¢ÐÙÙ£³O‡)´aFT>|˜t Š;ž~úiM(+ÄUç±cÇb¦Ð†aQ©A§%Ußm€¾âB€ËÃ'‚)´aFTjÐiI-t Ð¯¾új®ÝÔ„ÿþ÷¿_åíŠQ²}'Ÿ™¤KÃ0 £’ÀŒìÜPÝTëR«=yÊ#UØ4ï±qhÃ0Œ¨‘qY‘m‹ £4˜B†aäÀôôtÒY(5Õ)CL¡ Ã0r`uuµŠ=x˜M: 5)´aFnÔÈä)"5;]&ØL1èä©ïHFDÆÇÇ?žt.ŠŽЉc mUÂI¤sQø·,¬bl:q¬—Û0 #7666j¡û×lèÄ1…6 Ãș˗/'…â‚];âÊShÃ0Œœ™˜˜H: Åe||<é,¦Ð†a¹ƒ}YÅÞ<ªûî*Shèæç燇‡kdS9PÅV¦@— ¦Ð†Q% Í###¦Ð%cfffcc#é\…þþþ¤³`|‹)´aFžT¥’UqË£â0…6 ÃÈ“ÙÙÙê›ð<44”tŒßc m†‘'ÈóèèhÒ¹ˆ“¥¥¥ZXê])˜B†aäÏØØX5™ÑçÎK: Æb m†‘?ÕdFÏÎÎÖȦ •¾¤ó`†Q. ŒŒäzÕÇ:”tÞ ¥¡¡!×9bGŽY^^N:ãU‹ÙІa…R“ºm wb m†Q(È[EO°ÚÞÞ®‚FFõa m†íííIg!g3 ËShÃ0ŒÀ†N:ù°´´499™t.Œ ˜B†aÄÃÈÈHÅõuooo·µµ% #3¦Ð†Q%`ÀíÛ·¯B͸ªáøñ㕵<º«««²2\SìO:†aeÄÉ“' ¹üÓO?Å$]\\Lú>"A{nyyùâÅ‹yÇ`ê^TL¡ Ã0þ““…ÄÐã155•ô­ìÁ´ ýä“O&#3ÖËm†'hóÊÊ â—tFÂX]]0y.s̆6 È™›7obˆ9r䨱cIç%Èsggç‚És™c6´aFÌ:thii©««« -iä™vÃìììáÇ“΋±fCF• ÑÓÇP¸À<]^^niiḻ»;éìüÉ3­“çŠÀvÎ0 Ã(ÛÛÛˆôÐÐPoooÒyùÖ3É©S§Lž+ëå6 Ã(²¤ggg{zz’]˜499ÙÕÕeò\Y˜ m†QtPèÒoRIË ¯¯¤mævÅa6´aFÑ™ššjnnÆž.eº«««MMMóƒLž+³¡ Ã0JÄÆÆFGGGccãµk×J —ÃÃÃÓÓÓ¤Už‹¾Œ=1Ú0ª„ùùyjd>“Έ‘•C‡-..öööbLÏÌÌodzaaAÓÈ1Mž+[meÄêêêW_}•t.Œo¡ÆŸ˜˜ÀJ+ýH§‘8£:vzð¼ÐiÔzhh(F{šhˆviiɺµ+ëå6r˜žž¾|ùrÊ›§štv £ÜA§^|ñÅãÇŸ={6ðÓèèèØØ‚=88Xˆ±K[™%M4¢ššš²ÿfu` mD…*€Æ>uÊ›o¾©4Ã0"Âß§««‹ƒ+W®¤+ñÂÂÂßþíß>xð »»[}à%vyyùÖ­[hs}}=<›6W¦ÐF$°›ûúú®]»Ft^ £R™åtéÒ¥Œ^Æhþµž››ÛÚÚ:pà@ÀæþÿÛ;»˜º–óîoòñšÓ“Hõ>Mcš£Ip¥«Õ±{a|QãCU Tµ¥ßÀ‘Zû¨­97†›ƒo´Ò176j*PU©-œV2n%ã‹W¸­€´)TQ ‰IPª˜¤=¼¿¬çõ¼“µ?X{³÷^›µÿ¿‹­µgÍ<ó̬5óÌ3kÖ,Vs~æÌÆÊ¸æHÓ£D" -ަ¯¯þ¢2«O…H6˜aœi êýû÷óÇÜÝÝÝÙÙ±ãÉÉI~ío:–I®´RLÁÔÔƒzìq+"D`˜Ë`ßwff&ÿ~ÝgÜ1¿zºTkÈB‹|¬¬¬ íííÅ­ˆÉÁ¶mhhèèè+,ò ÷¡E>®_¿žk]h¼› q¢¡Mݺu‹áoÜŠˆªFZädssskk+óýžžžºººúúút:Mœ¸ÕâDbÛËìîîÆ­ˆ¨^d¡ENðž3Ÿ“ÍÎΞ9sfppÎåÂ… q«)ÄI…ö533·¢z‘…9¡ïÈœ…Ã<§‚5¥ããã©`¹éööv~97oÞ<þ¼û‹ÿ½¶¶æþ"!ÿ„9gñÔIBÂB‹'Ukk+NLek´Š ("aèò'¿n5²$ª»»ûÈÝ¢–‘…9Á.f~Jv``€ß÷ßaa!,1={öl!Ø×ÉÉÉ•••\³y8åùMÅÒÒqJU(ô)á¼"º•JT™(myË­ ÷I¹Õ¨@Ñs¼p႞‰%2‚Ã`‡ºQ³‚¤µ¼lƒ$ú>t£·T–„´]]]õõá/Bˆ‡$üEyB8ªÚ.•Y 3QÈ´\ìÓ¹öõ\“ÃHÂ%á˜ÂŸìì™ä‚ñà—$ȱ´äÎÙî—Ötà€˜&Ù EZN-//Û&0~^&‡Œì{$Äçx||Üô$/D1à¯Ó„„ü¥ÞHH«‘旗¿¦¿(lÕn;E[u¡Ó¤¿¿ß.¹#ÓøµËGåÏÍÍ™ªw—ÆX«ÏLM(Ž}-G{e€ÈdgÅA12åØ*ÂZõú÷@*NÍ®>¿VWÚ%³;cJzëÖ-{Ø,üêå×D‡$TŽÉçFÊz9¬kšËa×…JC‚Å·Òù…ÊÕ@ˆÖ`ÑÐßÕ‰]¯X: #²ÐµÍÞú,ºË¬]@&Y-´y0>ä˜n”cßž… Ó·~™®Ç:¸Ã—Ý÷aÐÇYj˜©0³} &ð{ˆ™ÕB[l‹cÂéé%Íz6Ã/”ån–À˜U³.Ø7Hc,‚MEÜhW¨Ã Ó´ž×Æü5“‰þÔÒãÇÍÙ¥®l*”Ù¿ÛE21éÖ9¦fLl›ièç•©‰ €Sä…&ß•—f9ëªÝ$£U—«[µäˆ4„X„\šTTúg^w 4ãíòuWÄ/¬ €\õú—Es ­rCØYwr´úw÷ ùr÷šL7ȵ »Žv9BñÉѯ12u÷ á®t¦X~Ëêߟ6`%!ÕøÊB×&z]ìîî¶¶¶Ú·iéJ"nÞIü̇d6%>??Ï©ýýýTàpÜÜÜ|õêÕPä;wîXwL¦tmüõÏ644¸½P†‡‡m„|ÏŸ?oŽi.Ý8E·'¢ƒn™(i£‡è52Ñó½÷ÞÃÙrátÐCCCض»wïh™ëÚÒét*ø¤ eÄÛnÉ]]] ===$íåË—­PÈ\ZZZ[[#Ž“ƒÁf(022200@LÒú‹‰,¹iâ×Ï•+Wì`rrÒ¾Ðyá Ü,w[@__Ÿ}¬ÌØÞÞ¦Œ®ÑÍCÒü=æêëë³VéÍ›7±â™‚ê¢~L“ü_s²´ökÕk”¬Ñ(O帿\Ôàfóof»í¶äûuëà:r/MMMqcûñ±ÖÏž= é`cPSÆ•ÎnŒ/È/ ‰fšø!!!S[™…°ò’5*Q!Ož<¹víš‹’6’ð«ì±=2§äeO^ýTTÇæî£mÈnq¹¹[¸7ÐÁ¾Z&£ —;ÄÝE ¸´ŒKìf IÈ-äWoþû!˜Fw™kw>æ–BÙë J¨@W½n…„]îCDqõ]|êå)>cDjÒž÷;naff†Z"w[爫?2¢¸‹2³¦NÐSÔ[JÔ,q;ñ¢ìàÙ¹BÁ_¡?Ê wO1Ý%&‘ݼ¨mv¡ÆÜܽçêê*‘íÙ3°:¸)¶Ü†h& ˆÌYRÙ`H=?˜4";•2ç‘ð€$D³$î€$œ •ÂWÛcB 2‘@Ñ,š•Å&$9°Y\ÃÔ8 ž°ÚgIHdbÚ„væ´ª/Њ`2Ýr«R;E44GW|W@+‹Í3[yÝ)î’„¦šý«lµá ´«`|ÉvÖfïM[Î’ÖÖد脇&r]ymÜfY¸j´š U—eç¢ÙÕwªZåXB§§ý}àÂ3ï.w9œž~|_%ËÝÕ¨t.GÆ~ƒkºßBb“ü‡šå®Ud¡“½€¿¨ 0íE§-ì„õ}¶0ª’õ“›E7;Š/eOßK‚-ÑŠß=š--<ŒD:ÛÂ[ ) ]ƒèë“ Çž@g>¯ÈÊÊJOOO>leoÙ«_þ5±3??O%ìïï766†&ü‹iXhÊý« “““ ¶ú©„\¾|¹££Ãî.*F:^ZZÊ|àbbb‚hö¸º–÷Ø©Md¡ˆ½èlÇOž<Á%õ{öÐ[­GÒ××— LÅ],!’CôfuppÐÐÐ`/ÊB×Z)–@hö¶âÉqîÜ9;°w ’vÿþ}¼ð©©)­X¢$ Gÿæºíê3??ÚHGÔzÛ*ä™%ö_ª‰ˆ}Ëvqq±«««Jöâ„B :þüöövAOŽp mݾ¨5d¡ˆ}z63º¸a¸½nÔÞÞÞÖÖ¦y6!Šƒ¶C êíí-ô™‘¾ W³è9t2±gW¡½5¢ÏÕÚ±D!„¨F4Ë-„BT#²ÐB$„‘‘‘ºº:=·"1ÈB !„Õˆ,´BQÈB !„Õˆ,´BQÈB !„Õˆ^~/»»»wïÞ }…&køb€§ÓéÐg-FFFBñMHfü(á&З?99Éof¦¹â£êúúzæ·7r…‹ioow¿¢¸ùÛŽ ?²•µ´´„ääjeQŽ3ûÌÖG¦;;;Yã›¶™‹üs…‹*âPZÅÜÜ5¹ººzdøÆÆÆíÛ·[^ÒÑÑáξxñ‚ãÌø> Å'&£„ƒ…›4Ž›ššô•$0Ÿ@Ÿ^ÀŸ?\ˆŠk}4Ï#ÃC­Œ6åZ™Å'$?k+³ÈQÂÉεJú„Pë³øt~|¢¹øÖ…Šœ+\Tº<Ç…¦hc…ÎNãñ›®5~ÿ83¾ß 73døa°aœhòý¦d(¾Ó03~þp!N(®õ…,tÖð\­/Oü¬­ÌoþùÃý~ƒãPëËÙûý†ÅϴĹÂEU¡çÐÇeddÄ5Ë(áŽÖÖÖsçÎùóîÀŠ@?~”ðºº:?äÐk–™¬­­eÆwãŒ(áBœPrµ¾B[¥Å/¨•E ___÷Cò·¾ÌøY;¢\ᢪ…Žvwwwôç¸ö¬(3~®p{ÞÝŽvvVvWˆèd]Õ‘?~ÖV–+|qqÑÂC \rA|:„èñEõ# ]ivww½Òðúúú¢´íƒƒ‹ZVfá333YÃççç ¸Äâ?þ\kF„ˆ‚ßÊ"Zè\­,O8×£XÜÍÍM³èã‹ÖrWšÉ›:£Ÿ†wîÜ¹Ìø¾ººÚÚÚš+<¢J…ÆÕ‰½&u5²(-¹Z_rµ²<áxö˜+ ]]]ĨŒ8)ȇ®4Œ¸ züc+Es…777G ÏC¡ñsA/SpÌpQ˜çÑÑQ÷.Ÿ(%ley‡††¢ËÇ–?¶~BƾÐpQäC›YJÎqww·s_²†Ó„vvvf,š{øäÞ°$>¦Ë¦Î²ÆO§Ó&ÍnÇ´%r±›RËß8Ož´BQÈB !„Õˆ,´BQÈB !„Õˆ,´BQÈB ‘l‡dmW"Db…B!ªY脳·Bˆc¡†\›ÈB'œ»qk!„8jȵ‰,´BQÈB !„ÕÈGâV@QÚÛÛݯ"ÈB ‘ÚâÖBQ24Ë-„BT#úúdI§Ó¹^Ìhkk[^^Ž[A!ÄÑ477onnf=ÕÔÔ´±±·‚¢ìȇN yÞʸwï^ÜÚ !"166–ëÔƒâÖNTùÐÉ$«ÝÙÙ977·jBˆ¨dmÈš «äC'“¬nôýû÷ãÖK”‘ÅÅÅ‘‘~ãVD”Œ¬ Y3aµƒÖr'“îîî3gÎø£o )yF›››/^¼ˆ»¸âGÌÎÎNNNrÑËq¡Eq´¶¶'yfCn ˆ»X¢Bh–;±Ð_÷ôô¸¿;;;%é¸é,ffflhêÔ©¸K)DµsppÀïÐÐPooom0Ô———e¡kùЉ…Ñ7Ôz‡’8Ј¢—™ŸŸ^ZZ’£&DDl\‹?=88Hó)hhë»Ñr k =‡N2·nݲƒãﹿ¹¹™N§;::ðÅoܸ!ó,Dth/´ÚFšv”ëª\¸ö«'е†f¹“ ^oCCCggç1ßÍ`ø?66†÷ÜÔÔw™„8Ù`žÛÛÛ1º4Ìè©°ëZÂ]kh–;Éœ:ujppðôéÓDz²²200°··§§ÎB†¹´)ÌíÚÚZô!/ 9nÅE h–;áÓ<ïîî^¼x‘®DæYˆRqæÌÚTkk«-"²Ð"CCC·nÝÒä¶¥…6ÕÙÙÙ××·"¢ªÑ,·ÈÉæææüüüôôô‘1qµ»ºº¶¶¶pÙõ¸Zˆ(вp£5A%r!Zä[Ë0ÿÈîƒ.¦±±qiii{{{}}=ÏvÿB-‹öE+‹[Q½ÈB‹œÌÎÎÞ¸qãÈh“““é3gÎìíí™÷<<<œ? ñý‡pHÀ÷#ìïïç—`HEÚBËEª¬c¹Ô‰¦èâO't‰ ÝÊ4ò+ôapqw]Vº»»'&&ÊQ(‘ d¡k—µµµ‘‘{A³.¸Å.\8R†9,~9}ú´½@‚äüIÆÆÆð¶]7·³³ãJ_<¿©À<ã©óK*ÒZpR…v*5{O Z³VOÄÚŸ¬ ¢‹¿pdœ¬_KÉLn¢M!ð÷n@K€ 8øµ’ZÙ-Ä/žœ•…ðññq¿Pöì€ãÁÁAÔã/‘­,9r¬>&®øÚ¶‘V‡[[[®¼VÂùëªÝWÕrqwŽ]~Ý1ø÷Ø™—ð×];°ÊeP‰šGˆi‚òˆ²ºbìå2µ¡áæ[ަž_½þ¥±H¶+NuÇôôOùÇvé¹g\¹Ÿ-Ü’§‚ —…•Èâ£ݲ@[WiÝQÚNf+#/äµ_¡†,jYè„ã7ìééiú‘(¶Ù(hGWeŽH¨ÇÌÄöF+bZwfÝ7ôàhh¦[b ô÷÷nVeæ6«…¦Óä···—@gæ9°Ž˜ìLˆõÈ™Uä’˜Ù¶9Õ[&Áxøð¡i‹ªvlB\¥bš0$"޳ÓD0Cå ÅhÖã›ÝröÀì.5°··Ç_Û‚Æ4¦žÄl¼ÓÉV®5ÑÌ/’M7W^Bl¸†žn€bÒ¬ü‘JšÉA”‰µ™^25–Ä"£mV mˆ t¦Ñâ ¼ÓÄ®¯áTrWÜJMÖ~õúW0™V][œÔË/Çø§Ü±•_+ •ËBL2‘ý,G¬ ý›Ä.Š»ˆVØ¢[¢Ü íPºVÑ,w­°²²róæÍµµµè[jÓËDŸj£³[ZZJy_¡ž˜˜ ÇÐ$$ÑäÚµk©`›$Žý‰Í7Þxc{{ÛŽñ!èC›››è‘ÓÓÓ³¿¿o½³BÚ‹/f†5Ò¢”…NŸÈnz“z ÿué7í©¡)I•úŸr¸øØ6FÃÃà kÄ1g)~:¾zõªû(Òøk—5iŸ?ÎY+……ÓYû³¯(LÙÑd`` õre@*-!Uûúúžaž1Ò! CCCƒ‘—pl ¿í¹ÝÛo¿1v‘m Ñ&féÙéòèpÍÖfUƒ8X³¯¡86ÙKŽþSIƒ~öý÷ߟ =µ™aú⎎"8«cî5¶Ð&{»ººlGFË”l…¢ T8i‘@â˜l¶ÐþRºööv+ƒRq௄G[jìÝwßE7ªbúðk®ž=þ7À&V{¡â!Üfk¹+/!f`±† B_[áj"‡qM'''9°aÖ³gÏÜ•EÎ"i(‰%ƺøµŠdŒ±ib]MFf(Ì…@jÏÅgÃ/yùê~õ:€ûœ{€LɈ:qÕEmû§ì˜LÝ0ÅЊŸß¾RvF¢hKLw“>Nà½{÷È(Síóóóù3B«Ø”¨Id¡kún:ÜB7‰þ*¬=Pt+¼°:tUø7¡GÔô5î‹[©Àx`„è¤èpÉ »ELJ‡Š([tC ïܹƒþXD¢™@"ŽOl¸“F—g·{(kÒRÁÄ¿~ý:§t©È•ì{š¡$èöË¿üË”î½÷Þsñ1rèF‡NÖ£˜íëb£Ÿ§OŸg‘âÓ·b¢¨FòµÉj³¾ØT;ð E·Žåóh !ÉéèmbüñãÇ—.]²·àl>€ãTà8Úä¶ÓÄ?ØNäS'¤Â–`·¬¼èOîäK1çææ\©bŠý ‡òD£88èHà,¢ð›° g‰vöìY®UÇm€é²(L©Ñ“$H#_þbêˆÏ)4¡»9˜T0¢>ÉÔžÛU³¿z‘æ’p¥D12¢*P•¿V]þ);&œcN!!>¤>©:Û…ÞÂí*ø7ŒÝu\5’ؼ”Ý$ ¤8…þî‘G®Ê>ò…F«(¯Tˆd÷4»(/ôG殑–—"úsë’kNx<.-Nÿ2… > žšûM‰ùÄÕvêåsèÒbÌK.¶pÏ¡£D¶Õ QbÚ俞C× ò¡“XAß¹sØÊj{´YyððópFQ§3²‚g†mF1ì´ï[¿¼¶è:ÞÒáÕÙœy¼jœPæççOŸ>Ñåíééñ' òÀ½¡­Çj}:á`ÛFGG———£¬[ÉJWW–Ã<,„8&Œ› ÍÍÍE‰¼»»›N§ñ¡«j¨**€¾œQmžSÁÚcüE{vw9„HSSSÃÃöž< n…„¨5d¡“Ï1'NO:e‹f£|çJ‘‡¾¾¾¥€#_¬ØÜÜt/³Ù+ þ>e¶:/îÒˆò¢çÐÉçøÍ¸©©É6˜lnn¶—ž……b;zÒŽhMQ^¬XYY9÷RMNNº¿çÏŸÏõÒ¹Hò¡½@èm຺:;hkk[^^.B¦­PEìÐÐÐÕ«Wq©oܸ¡>Bˆ#Ùßߟ˜˜XXX Õ´e­Ìúöè­<‘T´R,0TϺËgɘž´í,ñèÑ£<›|‰Jb•Ø–Xqë"~DCCÕ+WRÁ·dŠ{§9k[volÇ]>Qvd¡“I}}}æn E;ÐâD`ëöµâ7adN‰é×zLü}»÷îÝ‹[/!Da„¶_Åuö÷…ÉF:™Ð†C“`n'B!Ä "´ž@ײÐÉÄ>Çä‡Èâ„âœf9е†,tbñÝh9ÐBœ\lký”èÚC+Å’Œ-JE^ÂýÁ|ýë_ÿÆ7¾áþ~èC?Ã}üãÿÔ§>õÑ~4î Q£Ð–ïܹsänÚì·¿ýí¯~õ«î¯šð‰F:ÉÔ××GYÂý½ï}ï+_ùŠÿÕúL^yå•×_]oòQyòì@ &œHd¡Îââbcccž Œ¾ÿýﯭ­Ñ¼# dþÙÏ~ög~ægâ.™âG¨ 'Yèšæ[ßúÖúúú|PhÂO|â4ò¸Õ¢ÖQN6²ÐµË7¿ùÍ/ùËE'ÿØÇ>öK¿ôKqBˆÚEM8ñh-wò½ï}ï8m¾ûÝïþÛ¿ý[Üå¢FQ®d¡k‘þð‡+++Ç—óo|ã[ßúVÜ¥ÿ‘‘‘ºº:íY ¨ ײеÈW¾ò•"\eEcp!*šp ]s0úÎú=»¢¥¹÷§… äMؽ?-ª }:i0²Îÿöó~ðƒÒæøÿñŸøÄ'â.· ¡òMø?ÿó?_{íµ¸Ë-² 4VVVþû¿ÿ;œ¿þë¿þó?ÿóÖÖÖßû½ßûØÇ>–?2CìO~ò“y"|ÿûßå•Wâ.ºI@MX8d¡ã‡!óúúº­×Àýô§?mõ¥^®¡ñpüꫯ~îsŸs©\]]µãøÃÍÍÍßùÎw¾öµ¯ùtê»ßýîýû÷ÿæoþfqq‘ŽàÈæMÛF½<Í;ŒÁQ îŠ"Ô„E™…ŽZ) ˜flmi¥kK~sýf@.9ÑvþäOþä~ðƒ/~ñ‹¿ó;¿óÑ~”ÖÎxœÀ_ÿõ_§µÏÍÍýÄOüÄoüÆoüÝßýÝW¿úUú’|éK_â,üoÿöoåW~å×~í×hóò'òÚk¯ù _øÂý×Å]‘"ÕÞÞî~EŨÚ&Œýþ÷ÿw5áVŠÅ ùÿñ]Û6lá†Qªåš>4é?ýÓ?¥ÿîïþ.y½ù曟ùÌghä@“¦%mrr’0§¾þõ¯Ó¶ÿøÿ¸»»›ï¼ó 9øíßþí¿ÿû¿gôwEŠm‘…®$ÕЄÿðÿAfÆ« Ÿtd¡ãä;ßùNå3¥eÒžÿê¯þбó?üÃ?Ð81ÆOŸ>¥¹þþïÿ>cð?ú£?b<þöÛoÓòÝ’Q†Þ/^¤µ36'U*Øè,ì!VÜu)D TC¦åþÙŸý™šp"‘…Ž“Ï}îs?õS?UáL1ÉŒ PÓtiç---ŸúÔ§þàþ€ƒ/~ñ‹´pFÜÿôOÿÄï¾ð…{÷îY*ÆÚŒÙmN ÉÔ7kEm’˜&üá8îºYø°v Š‘ºººŸû¹Ÿcôê/Ý|õÕWiiŸ øéŸþéoûÛîãâÿó’|ä#ÿó?ÿSD¦Œš_ýõ¿üË¿üÍßüÍóçÏ_¹r…ÏèûÚµkŸþô§ººº~õW•|ÿõ_ÿ•Û£¾¾þgög ¹zõê_üÅ_üÖoýÈ!ü~á8à·¡¡!ÿ:!‰5ჃÿÓR'± üãW®Bô匪à›ßüæ×¾ö5NŸ>úà -ßÖˆÒ~B`ÿá迹½½׿!¨ÝÖÖKÖBTj¢ÈB' Üñù—©ü#¥ÖÖV}>vÚâÖE‰š°ðÑÛV‰â•W^a œË¡ÕÕÕ’·ÿ#ßÈó<::šÒ W'5aá# 4>'Â믿¾¶¶VÂOŸ>?G!DtÔ„…Ck¹kŽ3gΔ¶5þâ/þbÜe¢†(yöw:U…,t-ò™Ï|¦T¢JÞY!ޤ´MX;rW-²ÐµmòÕW_=¾l³FßBT5áAºFùìg?{Ìó‡>ô¡¶¶6÷…!D%Q®ô¶UíòÁ|éK_*nQ¨µíÊï¦$„p¨ 'YèZçË_þržïídÅ^Ñãg!ª5á# -~´çÑ?ÿó?‡¾Ï“ÆÝ?ÿó?ÿÚk¯Å­²âÿ£&œTd¡Åÿc{{{gg‡¦žõ{y º_}õÕÌm …U‚špò…N “““4Ô\goÞ¼yúôé<ÉÝg<þ÷ÿ×¾xCÛÖr!N j‰A:ÌÎÎöôôd=ÕÖÖ¶¼¼·‚BˆÂX\\Li?×ÚC£ªÒÝÝk|÷±X‘·¢Œ˜½»»+º°WqôBމA:á ¾ÿþûr kö€¸µB” Ír'Ÿk׮ŭ‚Bˆ‚‘…B!ª‘f¹6668xôèÑÞÞ^Ü5pžuêTÜ%"ššš0Òmmmqë"„8a”ÑBïîîâ=<}ú4î2 'é»wï^¼x1nE„'Œ2Zè«W¯NOOG÷žm)lÈÕÀ_XXÀØÇXGB{=??=ÉÊÊJÜZŸHToÑQ]U?å²ÐXÖ­­­îîîèIÎØ«ÒÆÌÌLss3–>N÷õõÅ[SB‡{÷îݼy3züóêC EõÕU ÁZ•£&Ëe¡ñž¹~gz``€ƒ7nàˆG,?^¸;Æó.n…©B^;Êdú÷EK.Z1ŸˆB"ªYäâ*ÊJwLe Š™»^E'Ïäø—¬­­m{{» J憷>4bÖ###‡‡‡ÚÆê­««KsoGâî1ÕÕ1Á·,Lj§\zvv¶¿¿ÿ8&''ég›ššÆÇÇ ¹sçNþ$T ^¸« »wïvvvº³H;Ò‰!ÑHå¾Ûh [[[Cþ}q˜äbÅQHDµCE.¨8!­òȉ¨ÌåË—YÛ¤EBÑÉS/ï¿\Ç¿dH` Yh*îçæææžžõ¡1??ŸN§UoQàS]•7â)•.—…æJsÉ#Á6µÇضÙ‘^‘™ðëׯg=ñ‰xf4{|ˆwr‚vs,ÂT ø‹‹‹‹/^¼ˆ·¶1Š%—ÙÒÒRô6· yÕ‡ÕÛÀÀ€ÖÒ‰êªT”ÐN—kÇú‘’¿½½½ç,wwØÓ§O/^¼èrçg¨±±±··waaÁ1`÷ïßçxlllxx¸»»{hhˆ$DÈœQäiñé;::úúúèd/\¸€S…>xEHÀ¢ ;{$ÉÏž=# IÞÕÕuöìY9a„#çÖ­[Œ&&&?~ì b!ýDkjjB„ØæÒÒgÉÔÊH g±(6Ó Ì3z¢˜)ðüùsâcðnܸá„c-¬œ"X.H ¹«ÒHåtP䎫+~© FQ¶Q†Õ9I»µµ…&ÔÇnk-tÀK~÷ÝwéHH]ù;Í9¼FŸ vÞ@µÄõ@•¢ I(/j :P¶èëºå¸|í¢S.þ"g||œTšÛ›“KL‹² 4ᘿ¶©|R¡3׫Ðw¨üãÌBÏp]lp‘©©)®>×úän6\± öPW±`ÈÇì4Ý‹uþÅí-x’¾mEw™ç,=/U@oN˜e2èÎèéßqËÖ××1ì7Þx“FŸÎíH¯ ³$D ZH2ÈúÒ¥KtëüŸþÃcé²¹•é¬9N3™ ˆI@&òÍКÉñá²Y{Ã.:ãš ¶`Cá{÷î‘!¨‡q½s禈ì(‹mYEd,öƒL1QN‚5­X’«‰4ŒÍád‹0àp¹`¬ZlÊš¢ÙpÄV rbW…‰IåØŠÈä;ðÖ[o!‡Êq ýì‘Á•+W¸L\Û¿š áÔÀpÚ/çšb&¹Ñ¹¬¡Dc«y«Cq–ƒÌ»‚\ìцI@»$§¤wÃ>¬>墌¸;ÁîªÅj’Ü[p5¹ |+Ź}û¶Ìs¡PoŒäN´É¹PŒPWUÝ=!Ýݹ:…-‘9,8;;;%1}VWWí/Ýq*˜sæ˜.2t²vŠ®3kŽ®P¤"ŽõeœB¦I¶òò‹«Íˆàïòò2ÇÓ¢qLZ'ÙäÎ]ët# 'Ðe:0™Ôƒ-šãØ$;ÅЙÆ`etøž9eì€J 6œV呃=s|Å\•ZüÎÝ/c(«F<®Zœ4ûe@à"›7IM+Kîƒì䘫ÍñÇýë•©Zù.{*0ÔIæ!£££ï½÷ž ¡*ˆÉ ’bÚ@ ermkcy›¢ •Õ|ûÓ!`nnÎjÕ‰õãpe¹gÐwß=륺ü/ÎöŒ ³†ó€_^ÄÃukä6ŽÌ“Ú®««ÓZn#z½ ÕUÉÉZ¥ôBt¿Ò“`È¢4ÕrYhûlÀq$ÐÒ9òk“±X ß…f¼±sþD1]-v7<"¥Oä¯yäŠÑ;Ûô&=,¦NÌükÅ1KÈi I.£‚Y\¾|™‚ð›)“ðÐ|é;#&6%âcƒzÀÆpÖ H®4%ò?–€X›CökÌ ¯ÅÅE+E¦p‡=µµjÉœ“Á8QÔ³KÃø©±±‘úÌ4?”›úÖ[o¹êµ]0-,,p“444DyÙ‡›8ÈòïèŒ3ì°:ÉjV äTOOWÄoª‹kíj›4-Ó™R“„‚G7Òˆ*hA¸úÍâP½EGuUr¢T)]ÝøóçÏÞç£L.?Ù3^ˆèÈ«™IðÏB!™q2º—œ¿Ú×qRé+ÑÐE°_Kµ±±áOÑsìÏ!‡†ŽýKå«a’@ç.gârqÊøZq@.N«Ì* •È’»*ÊŒŸ™K¨Z\­úIøk‘d+Y½Nÿ¬—ÒU`è*d­ù̃\BwNÖ;ÍϪm?aÖšÏ ¼MõG¤ˆùF›g‹>‘žH4OÕU ¡Ýñ˜cdÕrQ. }˜×üÄ%†Ånܸ†1jb)h#N.nš½|ÈB Ñë>ôÿé<=C×r?|øðÎ;Õöú&®óãÇ/\¸Ðßß_Ü|i©X__×W¿j©©©ÆÆÆãïy"„¨NŠ[ýn¯¨ØgݳR®÷¡SÁSñû÷ïc íqrê("­qk‘:殨⤰²²244Tô^%BˆÓÖÖFç@/‘õ¹u-t*0BKKK˜Ãj3ÒBT†ÍÍÍË—/Wæþ·Õ‚þšA!Dõ366öæ›of}¥¥î0ã­¸’333c;R·©Š'”©©)ÚƒÔ’ï¯'„HuuÙmq%öÓÆ<÷ÿ›NBT9¶m:ÞÚÚÂ{–yBäÇ^CÍ /ï,·Ÿýòò2ÝV__߯Æ6[»Ê‰DòèÑ#»Ãq5i$„ˆB®§`•˜å‡aÛ.†öâDÓÑÑÁ¸³¾¾^†YQöµ¡Ì]Æ*äCû0X°¥ÔÕ° Z!„ˆÌsÖÝ OÒ·­„yX\\d ÎoÜŠ! £»»Û>ŽBZˆ„€m•…"1ÈB !„Õˆ,´BQÈB !„Õˆ,´BQÈB !„ÕH ;–!„±¶¶ÖÓÓ“¹ñ§|h!„¢‘…B!ªYh!„¢‘…B!ªYh!„¢‘…"!ŒŒŒÔÕÕe~ÀNqB‘…B!ªYh!„¢‘…B!ªYh!„¢‘…B!ª‘Ä­€¢4´··»_!D…"!´Ä­…¢dèÛVB!D¥¹|ùòÎÎŽloo755Ùßúúúååå”|h!„¢ò öôôø!ëëëvpûöm;-„BÄ@:ÞÝÝ ž:ujooß”Ör !„±0<<œxëÖ-3Ï)ùÐB$†Å­â¤pppÐÐÐÀ¯ ñè”|h!æytt”߸BDKŒÇì‡øtJZ!„ˆ‹ááag’9Í{ËB !„ñà»Ñ!:% -„BĈ¹Ñ™tJZ!„ˆlsoooSSSÈNÉB !„ñrãÆ¬ázÛJ!„ˆ“µµµžž~Cáò¡…BˆjDZ!„¨Fô匪ãàà`cc#n-"éÙÖÖ·B‘Xd¡cfssszzzvv–ãýýýÓ§OÇ­Qa`§mýakkkwwwgggærD!„E ˜ä‰‰‰µµµŽŽ ÛÐÐЙ3gâVêXP–©©){Ÿ¯··7%BˆxÑsèJ3??ŸN§±Ð¸Î{{{<ÀB'À˜áColl,--qÜØØ800àï/ÊÍÈÈH]]¿q+"„( ²Ð•ceeåüùó£££>Ä0755Å­QY`´Á˜ƒÁÇÙ³g0²ÓBQ²ÐbjjêâÅ‹·oß^^^®…V§NÂ6omm=þ—ZFZ! EÏ¡+A__ßÒÒ’ÿÕÏznnSÝØØH $uÚ@!Ê|èò‚ïxþüy666jÍ<;°Ð>lkk[YY‰[!„81ÈB——ÖÖÖÁÁÁéé鸉3Ï/^ÜÜÜŒ[!„8h–»Œôõõ]¸p¡¿¿?nEª‚¦¦¦µµ5†,[[[ X»^…´··»_!D….SSSKKK¹v[ à ôÞ°½*“N§ñ¼©€e‘K”S âË9»»»wïÞÍT¸ 0Ò÷ïßgÔ‚©®Ù9ÿòÑ·BˆÒq(ÊÀòò2fìÅ‹¹"ܾ}ÛêuuÕ·À–––ãë`Yäåˆ( =³*\ýýýmmmÇ/ B$úÕ¬}µ|è²ÐÓÓƒÇ)71+ÔLccãÊÊJ-¼u–æççíëx¶I­I¥¡¡áÊ•+ttt\¸p¡9>zô¨µµ53\ºôÐq»»»/ʾ¢‘N§ý‰åÍÍM¼s ̺•·Û+»èpË"ëcìîîîììpÐÜÜli£o*N|Œôõë×———KWë¢\p?ŒŒpÅ{{{mQEIîm!ªú4nþ7ß|³©©‰.«¬«gööö𡳜ˆÛ¹O \HlOþ8n’yppð¶‡ÚtÇãÇ}Ãé¦ÍíBÒ]ÚÃïØØ˜‰å dkMÔýû÷ýw‘WWW]^Αe¨hB:;;} ¤=üñYnÔ°¬IË1ýµË”´yæö}ÐçÈZñÂèÐvˆc4·.BÄ=ý=dÄέhe<È —….1Ô2VêÈhÎ@fÅÌ*q0ÃXħOŸZ¸]B7Ôzøð¡­Þn·*íÖ­[$±EC&ÊÂçææf»g;Ðöƾ|Ì-ɉi¦š>úðÇ-´u1˜Ž GŸT°,JEÙÞjq_®DÁŽËÁoI¤MOOs'pÏÄ],!ªg9„Ó…f•, ]bgaÞŽŒæ $—¼ÅÃ·Ðæbâ¾`S-œT‡/-4fÕÎfºÅ~&Êh:\Ô³û Ùœ`“oœ·8ÎBÛSâ[4“Ìíåëñ&&•œ³b×Ô.â1Á½··WÉq=ñ›FGGOÜ»ù͹R.štÄÖ³‚G~öìÙ2ÝÆ(V÷ãÒÚÚZ…ÓãxHõõõÇWŒÒQFû`Ì1EY]EÉ1ŠÚ¦Xqʼn®UDeúúú¨íãÜ·©ÈßpДBËT¹!£'ïìì´ïä‚J;¥µæq 9ÛÞÞ~ëÖ­|øTDÆ0Û}hï¢*ñKä΀ÍÍM~ɱè†ÎÓÓÓhE´G!¬S±tIübâ)¢ÓüüüÄÄÄãÇÝ)+²Õ¹£ Ò8¶°B¹«s¯bÐß}³ŽîÖG©ÏT`KnÞ¼i¹!ß¾\‡žTäk^‡ 1“ƒ&wïÞ%²í—`6‰$V·œ²KãvS ÂåË—ß}÷]tFɆ†·¢Õv*ð&ј®àÜð\eÄÚÚ[_%ÛQNÃJ{*ìn®Q¦&ö> ¤M!MlÃyÿ¡2Yó—S½7‹ò½sçNžÑ¿Í(|þóŸ§V¹ñ¢´\ùÐBT;¡—ÎËÇÙ³gé¶*\º·Þz‹^øâÅ‹tmtŽ×¯_ç/±?AJ?N/LWK§i7±Cæïò—>þ·±±‘´tÄÒcbNˆO¿ÉY:bzƽ½=¬×P§ˆÀ‘Ý0ÑŽ;Ú²G"cÉ0BøytëfÈQ•cҢƹsç¨7BPrjjг{ÑÅbvñÒ¥K.œÀÑÑQÎbÆPÒ”§8]äc)ÖËV 0Ö•°dN‚Y’Xœ(õ™ ìË8f¼b‹)¶Ð@üEa“iUDu“ʱے_Ž©aª—â£*uB|Ë8‹bˆÂ6ÛY³ÊÆo¼‘ >PAU“;‡(@ŽÈ´È¨ÄHš«ßÜÜLmcÛ|!Á¿pXý¶C% M$;[£j_ñ± çSÁXÁþâãyëúlêëëóLÎáU£ÐêA@ÔuÜOÜ“C®Ï‡‰<ŒÛæhÀ_`ås"VŠåRþøõ9ò޾R C˜+ _mÚ±ðkûÓñëßöéP[žCm˜i Mî%zþ6ØÛÿÄÇâÀ¥µWLBÌÓõ·ˆGš)ãJôôéS$Xˆ­irg3ÐÍ–ì9Ý\­¢•)ã/ŒÂÞØÆ‚„£˜+Žt8­HØàKðUXŸ~.¶T“`ä6 ¶hv`Û»T¶¯–m×oZÙmìÙó/¹ÚÛ–ÀvuHž©¼ÖåË„ˆØR•¬µíÝ \«m¿¢ì5¬¯•2&!õrŸGWê¬ Ö/…‘«‘ÇÎʇ. ‘ÇÅ­Å ƒ¶W)nƒÆÉÐÕ:з¦Ï)_ÖïJá ”äÆÁaÂ÷*4!.:Þ%õ=ÌÍÍ!«6==rõêU7ÇKFöLoŒ{‰´tÄömSŒ‘±@æäa¤qR‰ïÒbõñÒÌæ…4±·mn!n‰Iþ;ùäeÓÝ™à#âÛ¡†/Æ!Am:}çÉ9B^ .¦ôÊ•+x~.ÐÞ´Ìê½åªOÚ ×‹zð={*Ç׿$¡,¡ëK …(W½Àõµ¥ÔVË‹‹\\‹CÝËŸnÖš_Ž£w¶kSêå¶ÄÜ—/_vgiDöhÃÍpØ‹~ÕÙâj»èœË'¶Û&XŽF* ]»tuuÑ›äÙ_¬`\£ª ´"º*úˆäÙi[,}œgê¶s{ô=óSÄä¼=e´)AÉϳgÏè¦÷è=égm;âàrÛÔ4`®èvûúúRE¤¥ÒÞ{ï=3Ã$¤Ï ¤ÄçàÞ½{Y«{‰X¤!?Ï;â>X 4´ÁD¦¶>=´{›² F7s•.>—Ûtà/£ [-è[hŒŠ=<ö­Qþú Á@äÉ“'ï¿ÿ># ÷ÀÛñÎ;ïØCt;eÏþ¹¸™NæÎ¡e¹Kcºq½¨p{è‹Ú¤=òù.÷0F”˜üt?Ó.Š‘)5úØgž ÓÜu[—‰ñ][H “)neäbehæÙœÊ5Ò‚cç¤hï[dÂõ>AŸ‚È:c™ cIšVùt(íKÇšîŽ{8’(ݧ^®ö,”Ð×,ÌmÅZdŸzL½ç¡·zÖï­ÆÇÇý-SÜ’ÅÐwSñ¾=77ggÝ—¤‰ƒ{JK¾YcW]tޱlù™TJø}hnž íVRØ_²½êbfþu>´Ÿ‘­Žq>tÖ¯KYKîžC»|}¸_‹¨([C÷åJ?¶×UK%Ð:£ªz&-D,Ðë2f­¤÷lè9t‰Á¶×1£§r/üíïï»'U~`ÊÛHÖÍxg&Ïú×'ÿ 0x´ù‡‡î[™GÆ<|ñÌYtqÚJ(°¿¿6kòÞ{ïe¾]#D²±ífÇÆÆìµ·Ê¯Ì….=žëׯãyDOÂå·—nݺ…ÅÆŒŒpCØ^ð6»’ &Ò›››?nµ­­­ùùùTЕû§l¦ÍÍÍõõu{ÿ„Ü)‚{‘Skkk=BOÎ"ÊišÄììl”×"Eì˜mW¿„_­¢ú±GT(º,`±ðtqU£_æÞÞÞîînŒ"4i-!¿ô†3L)¿îÕ¦t:í/ÒÎÿ×@þîÙ³gÝî9Œ 4Úì±Ë¨¯¯Ï)ðâÅ Bö÷÷OŸ>b¶”13ftzzzÌû*‰b8·BÔò¡Ëæ°^*u>t•\hó×§§§ãVD!ª½mU.ÚÚÚlwÙ¸©"쥲#?Z.Šcqq‘[Î6¨B$Yè2ÒÛÛk/•ƨC:n ˆ»2~dž/_¾û¤B‚Á6ŽŽÊB ‘d¡Ë þâþþ¾}ã,×â­\ç‹/Ú—eãÕD!N Z)V^0Hsss###­­­ U²>°ÂôõõÙgédž…":ò¡+úÁƒö트u©(»»»]]]lllÈ< !DAÈBW̳½ïtñâÅ"6î>q0.¹zõêøø¸Vn !DÈBWœHŒÖÜÜÜ;w0]þ70…šššjnnîìì\^^®Í‰}!„8>z:l»W÷çÞÞÞ“¾ ÄÚÚ†yaa¡µµõÆÚÃY!މ,t̘©¶W„mß®¸5*Œƒƒ{À,Ã,„¥Eºê8)û§Óé“î÷ !D5óŽÆß^—ÛáIEND®B`‚gateway-1.4.5/doc/wtls/fig1o.png0000644000175000017500000003430107374232663015152 0ustar toljtolj‰PNG  IHDRŠçãàvtIMEÑ 8À2UY pHYsÊ&ó?gAMA± üa8PIDATxÚíOhIbÿ[?&H$¬tY›,Ø9Œ³X³‡Ø°Œ½k±‡±™üÀžÃÚ!‹åä@bïF‚ìØYˆ|ˆmf+‡•a+ËÆÞƒ5‡µÍ‚5‡HbR‘ Mò!‘Hàåãþ®jÊÝOOOžº¥÷ý€D¿êªêêú÷­]ÕR©TcŒ1Æ”‰ÿWtŒ1Æ“åééé¢Ã`¶H[[[ggç–;é÷.‡“TÁ\`¾²²²¡XÛl‹~=èÜ»wïôéÓEÇJñ”¡ä’ú„ü€6È„Ô)$`CCCÏRŠ“úY^^ÞAßh®‘ ===ô€CrL§„ŸIZ¯bRµ<^¸páîÝ»ºÆRj`œÄK1$•åóÏþó¾¾¾à9®ÂP¹†ÍåU† ÜÂs=+®öq(¯2‘\…&BÁTvˆ>ú(ã[Þd›œ;wnSöggg¯_¿ž7?’²So}àÀ|Ç:™ššÚæ+ìlÒl|yñâÚ àñŽõ¼žìH`Z[[wÊ«†òQJCÖ.¹£££õ$MýT-§ÎÑEâD{§4dš€Éú{ #±á)8!†Ã8¹6WvÊ;$ ª:HARÀ£É6ögv4…×á]*-,PÍ£4wKqÉNõÄ5 öQ„¸’^qA{$ z$kC—*rXPŒpW[Åjp&7ã$z9[OÁŽüT**9ÃðKÕŠxp;IÇ=tMZÒUøÒ~á5CHd“WSø)ÉUÿ³ì§Áí©5¨ÜC„Ë<ÎTDfH©ø-â"ídN¾ª¤ üYŽzVQw %8‘W²I"*“*¯g’ÂÙÍÁíPR´ “j¬P`•:€M¢ñϸÌr—˜ÏD¯ HHô˜øATâJ¦0Ò%S]à9e0”} QªDó_]´sçÎ…ÒªB5òùçŸW­O^Å9I‚•\–ˆNx\¨*kùMAR|âmfTv=6;¸­(ÚB&ÉÐ [%*zªÃU#Ź%”¦JTOfâ ÑU¾Åµ«®•¡œÏøÉZ™ÊP#Rîmd"1ª¬ ÚWªvpR`›¼±ãbïõÆmT–ÔÿÈŒ|¨Ú_Ð:SÛ_Å»vøMLkqCB× œ°y0¥êÇ?µÓççç©÷égP§S“æmž|8Å?ÄR<¢ AC¦ ’ò• žã íõdv–………í{¢ý°> >ýôSMrýÅ_hú€r§R¬¹¿{÷î¸Í`JÌc_aCfffHuǵ,‹giÆ0¤&R%i¨u‰[D¤ž£QñˇÒÔ*iGN ª $b‚r“ ÈØá¡q}^v^ž×C‰ªn0$îh€c¢aJ/eLƒ“ëmy£\Nß¼y'§OŸÖD#^NÑ@‡ÆOðGN”µÑH _Ã29ƒ*€öÞ{ïŃ`u†ßl %•’V`Ö9„ÜE•]Õ^QhIÍçÏŸó?È3Ï"çˆR‰T4kfTi’½‰@ŠÛÐÐR‡úºžMž½D,IÃÿð¡Õ´ÖâÖSN“4}I>Š›*_¤úÊ•+júkBW‰«GðD•kÍ;&©²bˆ5 O¾>ÑS°LíAÍ>^\ƒê˜à3Ù†¬‚‚­5Àšzà ¼”°‰CD+ä7ž…焟`ÞyÖ ývŽ„OÒ˜i¹jÐ"ÔoÄ0¯£‚`‚éz’vÃÊ9D¦"™(zçwPk¥ÖHDR“¸"B¨À¹E·M1ƒp’@d>ø€ÖLìs’¶!òÙCg¢Ã$ÊÇÌõ©S§”FêŽ+Šyò$¬2?ZíIilM!Éc2ƒÛaÔHÃïañ9)3¸Í¤™¬ ÚÔþd? nÇ&™Ám.ây&:ÿ™5¢‚ú"¬ê$9â‘R%™¦0’´û¥¼R6Ð-­çLê[F¾k‘¶ûƒÛq$hž^óaFIqÇs%7¸-¯´\V®4´(MR aÈx• Å-y(núIÒlj‹Ÿz"0T¹Öx,©!îJ®>‘!2CÄa°7<"Y[•Yu[Ð"á8¿i:OÓ@km¶0¸M il!ŸÔI’›:,ÕÈpU´€ èPÔËNÊ37“b“Ì(¿r0M¤Œ'ñä e,dœÈ>ÿñ-h¿~¯b?ó>Ç6cËzV*åý ÁànÈ Ã¿SìyÎç™á™tÉg•qÅ·ä$Î!ºŽ“,~Dœ…2O̦XvAžCº¬WR2±â*_ôB¢dŠCí²Ÿ÷*°ªN2&ë•ki³¾´QS~=3Y"ÿ"ùdÞ«j}U#Öc ò\IR›uR?{Nžóóè%g'å¹Ó3z©º#{‘ý!Ïf ì‚<ïo¨ Ã2®¢ö-Ø,[“gš[ÒHÔeF³n§=uAh÷Vþߥ¹g-d÷:)cLáôõõ-,,¼ûî»úôví¶Y:;;‡‡‡·?]•x°ˆg KHOJѡػ$Ïùq•húÙcv“”¢C±KLNNvuuÑqÌ ª)3>±Êcö3¥Ø^c´O߆ִ£Ã6ÜÆaaA[©4”&•ç†n±¹”Rô+šzÙfz飾¢_ÂÔE#6ïÓNXE¿Y-´Iu9»Îš®®m‡>{ö¬öl4‹‹‹CCC~T}èÐ!]ŸS7ކËsØà³»»{½/PDØM7Á !FA%Tqq &-Õ T5öÛÚÚ´½ðË—/7»/J“ÇÕ‰'vùL˜LrhÏÏÏSym6¹õ €å¢£¶tPBÁ;ØïÚ8(oNJ}øá‡qÁçBÛm.^¼˜É'¤²väë´®®®r6Ñh;6NÕxåÚÛàïýýýúnvžU?Ÿ~ú©vimÜ#v£÷|éÒ%m¹o‹¿! ÚÖƒ&‰]»½ö˜ ‡ááa]„=;ƒ$ݸÿÅ‹===:££££œmÕ2 ¸¢°QñÕÙíh\Põª/h;;;C²Ö“ÜzýÙ³gnGïEŸº#õïöР‚O¢F•š1×ýùkAþ$q3'a$¯×i$ýÀÀ@FæË€ÎäÐYOµÉPtçΪ2þ‡£P¸¥ý^Tf1<|ø0N‘$:o&&áØàJÇ–ä…@çÓ`?S'à ‰¾J'-ôŽ0Ñ9+:ØFI†l†ólâó]t®y|VJL­,kÜ['î$i¥ÑÞÞ^Oôn™Ýgm¦Ï‹ñ2D4/©·Ëa¦Lj{ø0Ѫt¾$oX“~6ĺׇC‡éBnc;IZq­Ù‘ÑÑQj7n”|È«(Wü1‰µ¸¸¨C[3 §¬Î]ÀZ\EV­Ä3žl˜ÔV»uë–~¶¶¶†d­'¹Ã+ÐÚs:â #ºt¤z¥™Äl¹ào(ê:¥#¿%&T¸`.2ëŨ|µQvfâ3®Ó=zÄ]ô¦,'¯A»!ì¡T›üEäjދꚈå½0T>~üøàÁƒÚ!NÛ0ë êUµÀdA­Ud”+<İ««KÇucY=Ž®!ŸdZHŠUí8ÆCñy4ƒãÇ£ÒZ  F"Aµ—'ÏR ¬³p´ ®”U– ×§N ï?”¯äS3„¦Ù‡Mņ~¹•¬µ4µk.ѧ=›´}õ‘ –¤ôÊÊJ¼‡ŸŸá?žæ ¿¡¥QEðìx…]AÞô½÷ÞÓwdlž8q‚ˆÒè}’öøÕUh»w dUˆD^UãZ”:Š„ö#Òu’¨rÍX 0øOJ`HìÈ%–Ÿ×¯_ÇvÒ´ Ñ—AµÝ9ê‘´ Ó¨¦NHh <ý•>ø€t¤^Û†sg±@¶!éu¦¬ ¤!‰KE@žÁœ:[ªª>.4»MâA6S':IPiD}ªŸ8”¥ÒZÍ5,h6T)K=@¯EŸÿTš¨²2 išµÒ¸æõñxùòå0N#È{]M!¥¤²ÔŒWK…bWªÞckêViÖ9ã\h|”êTë4ñAƒ£Z·õäÉÕêX#/¬é‰a+S^Mvâ— †d$t'<CÝÒÁbIÚ2ÐÙ”ª‹Âë Bµ·Wnóòù¡’xx™f©ŽC'Êâ\´Dr«ÙY ý¥1O¢ OԎƆÜRŠklt¥ÄÖ˜˜J/í/Âw²ó&ùÀ+üñ€FÞU²V_ÇC%&Y'®âH&uHDŠ4ª‰!×:Te2I#_¥%¶ ²Í¥E%‡üƒT“ÐX c(!òVW]ðL¶ Ô“Ü©ê¼iÉ—¾LLÞ½{7¤Ú¬¡i*;Ô—‚TÐ:ǂ氠/•²êKQðIzò5þð8u²«&¥N_N^OÁ|×]2~j)P€0h­jµ€ç¥Úí žÖ­“Xzóà É:£å± V]%žw[Ó‰a5œ'éàŠÖukêký|p¥Ÿá‰ÁÛ`'~©Øaæâ[²'„×!¯’iÃ’äFѸ…g%„Êz¨¡¥O;£¡Ø‹+·K¥kû n‘ ê®…yO¬Ü.:ûA§‚êó“†9ºÙ•Û›ª’ÒŸØ ¬[u‘=ÐMotŠWvgåv© é½SCšë¡/ß7»6ÁÂýû÷ó;!l ÜÒ£ÚpcBS,4—¯^½Ú ¡HmUQæ­­kSI—ÊŠZ ¦4ÂÛ­íóŠ6£ÐNñ¦“ç$­‘ºaˆ¾Ú»eµ©Ð Óv¶b~ôèÑž®š›‡mäGer÷îݲ­ 3û€‚—†5iCÏ%-Õ ³!Û<6ÞEÇ”œF(´ö3)úÍÌ>¤{ÏÆ³ïñÒÔ½ŽåÙcöÞ$g`y6ƘýÆØØXÉW{™ ±<c̾biiivvÖƒÛ{˳1ÆìtncfO³yµr»¥¥¥è`˜­°ýÝØô{”-f=”RtðMC 8k½ÉÉIèµh©¤[Ƙ½Hf \cÌ>¦ê–Ôfcy6ÆcJ‡çž1ƘÒay6ÆcJ‡åÙcŒ)–gcŒ1¦tXž1ƘÒay6ÆcJ‡åÙcŒ)–gcŒ1¦tXž1ƘÒay6ÆcJ‡åÙcŒ)oܹs'úÍààà†&=)±ÉDJ“{µ´´”ÏþþþÄ&DûââblrðàÁK—.Ù+{e¯ì•½²Wв˜’±×ÝÝ1™žžÎ˜ðÈŒ_<Ò^­®®ÎÎÎfìtuueŽš™››[YY‰MÚÚÚ2gÀÙ+{e¯ì•½jZ¯|b•1ÆS:<÷lŒ1Æ”˳1ÆS:,ÏÆcLé°<cŒ1¥ÃòlŒ1Æ”˳1ÆS:,ÏÆcLé°<cŒ1¥ÃòlŒ1Æ”˳1ÆS:,ÏÆcLé°<cŒ1¥ÃòlŒ1Æ”Ž7ø{øðaÑÁ0ÆS‹žžžo|ãZ‹ÏîëëÓEþ]S~^(iy6Ƙ’S§<£Ä333ÃÖÖÖ£G àIæ{SZ<¸mŒ1ûœÕÕÕgÏž={öàÁƒüçgÑ!2cy6ƘýÃôôt¥RY\\œššú(…~slall¬££ãÞ½{E‡Ôl€·1fPçàvUæææ®]»6>>÷›GGGÏ;Wôk™uqïÙcö9÷ïß_YY‰õøüùóîC—˳1Æ4 ™3 ½´´Tt Lu,ÏÆÓD ÐwïÞ ?/^¼XtˆLu,ÏÆÓ\\HÑõøøøäädÑ!2U°<cLÓqûöíÖÖV]_¾|¹èà˜*Xž1¦é@›Qh]?{öÌ_B—˳1Æ4#.\;ˆ“ÅòlŒ1MJOO.nÞ¼YtXL˳1Æ4)ºðê°by6Ƙ&%ì÷¹šRtpÌkXž1¦Iimm=r䈮ggg‹Žy7Š€)ÿñÿñÏÿüÏ¿þõ¯;::zzzÞÿýF?‘ÇMLL|õÕWo½õûÎw¾S«3gÎüÿ”m>]_•ܺu«AoG|þÕ_ýÕèèèƒ~ùË_þÏÿüÏw¿ûÝ?ù“?áÖ?ýÓ?Ï¿ó;¿ó½ï}É„dyy‡?ûÙÏ0Óœ¼|ù²½½=ü¤˜ëâñãÇ>ºT¸÷l²Ü¼y±øã?þcä¤ÑC½>ùäê‹ÁÁA¤kjjjgýÇÏF¿BmSÐæ‘‘d˜ˆE’‘ÞŸüä'´K>üðC„Î;¤Þ|óÍ7ÿáþ¡Øð›}F¬ÍpêÔ)]'‹šy ˳ɂ^Ò‹ýö·¿<#!~œä‰úƒ?øƒ¿ù›¿éííÝAχ‡‡yF¿B $®ü§—L§™ˆ¥Cü­o}ë¿þë¿xåï¥|öÙgUÿð‡?¤…477Wà+˜&all¬è ˜×°<›,ï¿ÿ>Ý»_üâ\ÿîïþn²6ÊzþüùïÿûR;Lþîïþî?øÁåË—éb9l…²ÒÑÄ“?üÃ? nñ UÆæ—_~‰… .ܺu dòþè°@d’né¼ÒV¨ñú¼òüühÝ½ÒØÚ·¾õ­Ÿýìghrˆò¡¬hâGÇ·ô,±ÿäɬi <ìæÿ«üä–nddD ~þþïÿ>üÇ 2Ÿ´],×xwF¢Ë›jDú“|à}i½ m¬©ƒ+Émì9šÍÿИèììüì³ÏøzðØ×Ê/ây½ð`¿ØñycL!xå¶É‚°u¦ ®ôÕù£ßüÝï~7¶öŸÿùŸñϪ+°BÇš ©£~†Å¢ÉÚ‚LÐ*„ÍCânð9ßëEt‘.úå´'dB£AÅüƒ„ÿÿøÿˆM,ПμK†ýèGÿýßÿýƒü@Í䇴þú¯ÿZ^>|˜Öƒ,K«ŽNËPÁ&Vi%`‚'ßÿþ÷ySÿï|牘YOƒÿõ_ÿõ›ßüæn$¼infffŠ‚y ÷žMÔ‚î=?uXQ#¤ú—¿üå|ÊO~ò™üüç?Wç¥Qï7)UýDáè‹cY“Ðñ‚päùòåËò ;x…v¢¬šÀ¦7œ¤·ø€M~Ã$•F„߃:ñò™ÿø&᜚šBòig ÓÁ¥¡oIàó/ÖÀ-N~üãÿïÿþo’Š+šJŸ›ÿuþ#™D·è¸×èÚ*_~ù%ÿýë_£Á„J‹´ñ~³â<—Ç!Q〧ĭcL“àÞ³ÉòÓŸþ”Žæàà b¦þ"&È¢ˆ¶Ñ¥NÒÁØO>ù…FWÞÿýoûÛ½½½X£“]ÕO$íÊ•+èz±54 4댚¤wJ‰hq!#0XCáâÙn©2Ò‹[¹ByrNØèã¢Í\¼ÉÉI‚-ùÏO¢¨k:ñšá–$£‘¸E°åa’Žüó_ïŽÍÚCåô˜Õ{æQb\išö Í š ½õÖ[D¸|Xt0Œ)/è% ‹Ï>ûl½õÕ5˜››C€GGG·öh9âmšZ¢ßøÆ7vÜÛééiZ¢ºFŠ~Kó5Ü6fÐæÐuÞ,ô’é¬oyw—[·n!ÏÖfÓ8ÚÚÚŠ‚©ŽåÙ˜ZüË¿ü‹†ß·ìÃøÃÌJõ:ùꫯÞ|óMmibLƒp+-Ü6Ƙ=@ƒ·¡¥¥EÜ.î=cŒ1¥ÃòlŒ1ÍËôôtÑA0Õ±<cŒ1¥ÃòlŒ1Æ”˳1ÆS:,ÏÆc|ŒUé°<cŒIÚÛÛ‹‚y ˳1Ƙ¤Æ¡ã¦,ÏÆcLé°<cŒ1¥ÃòlŒ1Æ”ŽWç=ëÄ\cŒ1¥å÷~ï÷á­O¬*--ÞÝcš‰QN<¸mŒ1Æ”˳1ÆS:,ÏÆcLé°<cLSÓÚÚª .Y*,ÏÆÓÔtvvS˳1ÆS:,ÏÆÓÔôõõéâñãÇE‡Å|åÙcÌ+–——‹‚ù˳1Æ45§OŸÖÅË—/‹‹ù˳1Æ45]]]ºxôèQÑa1_cy6Ƙ¦æÀú¶jii©è°˜¯yµçvwwwÑÁ0ÆS‹ñññÆ}… ÌÌÌp±¸¸ˆZý®æ¯N¬RªcŒ)-+++󼯯ohhˆ‹ÙÙYËsIðà¶1Æ4;au˜§ŸËƒåÙcšãÇkúyll¬è°˜ßby6Æ“\ºt‰ÿsss«««E‡Å¼ÂòlŒ1&éïïç?Ú<>>^tXÌ+,ÏÆc^ŒqôèQ.®]»VtXÌ+,ÏÆc^qÿþý$߆¢Ãb,ÏÆcRè@_¸p!qº¼Ú–¤¥¥¥è`cŒ©ÅÔÔÔ.l!µººÚÑÑÁÅôô´Ï.÷ž1Æü–ÖÖV„9I¿„ÞÔnšÇŽËÒ÷“ocpp°F“[Xhh‡åÙcÌ×ÐiFS´–»~&''ÏŸ?_¿}ÁU˳1Ƙ×BOLLlê#«£GÞ»woddd= ñ•ùììl>W=ér³Ç_nh?o¡Ø„åÙcLù¤]ÿ*î>ø`ttôâÅ‹ˆtæ&---]]]KKKh3&o¿ý6†ÝÝÝáD˃j,;Ü¢;޵¶¶6ò_ÞÒnà×ööö†GNìTmÐÈ'< æ:~ÊØØX&xI:*®G;v¬°c°+•J16ÆS7SSS•"˜OÙÐÚ‘#G>úè#.Î;×ÚÚŠ´K\öââ"·oß^YYAõûúú0ÄäÁƒS)\¿xñâéÓ§I:ù5ì8p ˜\½zuyy™ÿÁ gΜÁ>~òÐ$=ɇ<:*naáúõë÷ïß—C.0‰Ÿ’žrÍ# ‰öWa¨Xž1¦ô%Ïuä¹²¦Ð’=‚­Ï©¤ ‡ü¯¬)·ìHR¥LÖtûá\#–RYÉ?Hž‘R»ŠÂ¥òÌÒ;<<Œüäšà¡Ùü¿ŸR5x˜¥oå̶¸téRþô·¥¥¥;wî´mAa£ätttPºC833311LzzzNž<™¤­NNNîæþ $%á!í4¼s÷î]™ÿÐ%Në|¤åßetttppЛN˜- lSÏ×Vd×gÏž?~\?:”¤¢«Êª­­-cŸžñÙ³g“´}ãÆþþ~r2r;==,sÝÞÞ®ëL0xÖØØ!¬<ÊNooï“'OX’vÐyâµk×ôŠFÕà¡ÓÇxŽç½LZIѵF„Ùw~~~Ãã`)‰ÚÂO¶Ô» 4j˜7èx„Zßµµ1Wó\ ùÝAÍöüËRƒPm¡Ü!N2i½^¤åß…Þ ^íÚ™¤ðÞ³º¶ê†Îk î=WÒÞª”Rµ®h,>}ú;\TÒ®0›*MFýTGYëÅ4¤¬!kå|þkÌ\½çð •ßÊëƒê$-Ñ}}}FA õXu¬óÁ+C„[ž÷ a §¡û5mSÛ€,¾µGPº(à C|È(½e¬'ƼŽÊ0Öd¢ÅÖÚ¬iØŸ Ìy–ä-ïCmyÖµ%!JÃ[Äþ¨ ç zÇ|øÔ·!rªÊ3v¨D2!Œå™È¬¬õl2äåYï’ñÐì Š•çª,–ɽ…ÆŠÅXž÷ ±<“¦4©÷©…¯_¿N+UÕ´ ˜žÆ#V-•äšv"Õ·†•4:ªŸ´CuK:自xþË íMYÃÏ$Ò<õê¸æA•Twåƒ µr2~‹Ê¡u•§`Gƒº<ˆbÈOü¤ñ«¯F}õ,îÒà€ZRcp[ƒrz¬GKñ–Ÿòî´ ÔØ×s‰çŒ…LøK!rÔZ‘“‘ç°â4alkp†ªï¢§l8CaÊFò¬¡à<{TžUöC½´Xž÷ y¦aÈE{{{hóª¬ÍÖHf’TÂDQl3|`¤Y?ƒ~¨á†‘«ú ˡ׎(V¬@¸Rû Pc0?ƒe A•·Aád-Q¡è–ÂOWr=yÖèBh=ÄQª©Ü8$aÖM†J;::ÂVJñ’ï/¿5ÿ>œ¤{#;§OŸæÿÂÂB°¶Þò7| ÖªòðáäæÌwæ]´V‹i©“O?ý4cBÚÔžåáÉ“'»¹äsËXž÷9((ÍÞ'N„þ\,\LÁrF/׃æg?Œ* +òáÚµk±’.É%AŠÕ®*B…ä±Á¡º•ÜÒÊÌ$=ínuuufff=ª~¿NëKG}ò¸´´TÇ Óá{¶+W®¼ Ÿà9¯IüÈ‚6'⥰€«0ë¬ýÔQ䬷"ͦS§NÕÏd ÕM>ÒªÚWÔÚ0¦NÂGÉaå6UÊ–?Ð0uQñàö¾ 3¸ªf-,Ò­ŠSemp;Œ«¤…YÒ̈qð?ŒWóÿÁƒx‹CM¯çƒji>˜[ÈR<~›_œ¤Ò¥eV­I¦RÐãôYÑ™3gòA•·!`ñà|’V+±Z¼V{iX ŽR}¼ü Þ šNÖä–,d>ùHÒo=ãÈIÖYFx2M«|¼á9mš8Ò4×Põ]2Ñbö …çC.Õ÷{{Uƒa©öžÀò¼OèLÑ5õ{<ÌK›Wߪñ«q’´NJ€I˜$–f,ÈP&ò\}¾ð ª>èk±¶Å>Ô^ÆÆZ%·ÆžÇA•·üç‰!´±Ÿ5|h\>0™‘óŒ?á¹ÁŒüÓãT[/râ䫤’‡p½xËDZÕwö§Ï{‘ÂåyO£íÞŠC˳1eG»îˆWÈüòò²—mïEŠ’zœõì¹ÝPôéÇvØ‹òì¹gcÊÎùóç¯\¹²án0õpõêUzÏùMC©Ê7&&&vj!!^ Þ¼y3,;%+b²°°ðìÙ³-¹ÿ¼wï^oo/ÖÂþµ Izò£ Ƶ\e=&&&´sQÌáǵ%h›í§æ‰ãMtÑÕջ¦6KÑ~DüäE´ ÀüÁƒˆôÐÐPÙaT<¸mŒ1¥gw·µ¹6£ÝqÖ›{¯FW8?µ¬´¾­:÷¬s'ãåsÏ2Ô•%ß¶<cÌ`ä9Œ$kâvÇÑ rOŸ> åøt I©6® ?ÿüóપÆJ;‰¤[ŽÌícy6Ƙ=À.Èsض3c¾Sß=Ç‹¼Ì†xîÙcÌ«…u‚˵k×2·|€J1TÜ{6ƘÒÓèÞ³ŽLMÒ]ëôˆÅÅÅxçyS›7ŠÎrÆcŠG‹Ÿó»¾ï Úü¿èÝ3xpÛcšééi}e¤OM°<cL³Îb?6Åòjp{½cÛ1Æ”„¶¶¶Æyþøñc]tuuý¢æ·´T¼4Ìcš´uuU[…ó[<¸mŒ1MÍÒÒ’vÍôº­Ray6Ƙ¦&ô˜ó›`›±<cLSÖ…yR©°<cŒ1¥ÃòlŒ1MÍÌÌŒ.üÑs©°<cLS3==]tL,ÏÆÓÔhÙ¶)þîÙcšš––],..úÛªò`y6Ƙ¦&ȳå TxpÛcŒ)–gcŒ1¦t¼:cpp°è`cŒ©E¿'†›ŠWsÏaâÁcL9™ššjЦ›ž{.'Ü6Ƙæenn®è ˜êXž1¦yYYY):¦:–gcŒ1¦tXž1ƘÒay6ÆcJ‡åÙcŒ)–gcŒ1¦tXž1ƘÒay6ÆcJ‡åÙcŒ)–gcŒ1¦tXž1ƘÒay6ÆcJ‡åÙcŒ)o³Wimmíì윛›[]]-0GŽ ×»^?©và1sáÂ…‘‘ÅO° “žžžùùyŸdŒ©…ø4[]$óÄêX•ˆÙÙY¤q×=•’7¿ÿ~___ˆ]FGG8°¸¸Xl¼™=™­Òâ<ÜÿÍ–ñà¶iGÝY?^Õ|pp°¥¥åرctR/]ºTTð‚·tŽÇÆÆ2æÝÝݲ¿¿ÿܹsííí}ôQ#`ÌÖ ÕXtÌkxpÛlJ5¢xçΔirrrii Cúˆ‡B„0Ç;Ü¥w«]ìÏÌÌÌÏÏwttà¡úâ‹/VWWéS†!_œtuu-//c“Ÿ¨ÚðððíÛ·ñ ?óÁ˜žžÆTu¤ÃúèѣÇyÅÓyœ¼¢‡ýôéÓ—/_ÆÁ‹Ÿ%{ 5 ÏÌ'À¼…Þ±*Ÿþ9\ïî—_~©Ð¤ ÀzzÑ hÌ+,Ï¥£âÁm³%2ƒ·hÛýû÷¹@î^½º²²‚ÖNMM…Ÿ\cr÷îÝ$¦{ðà?1GM5’ƒs~ò?Iû r‚>yò„~³,Ëa bñâ×8äË„‡ÿ\#–•tÜ[A¢ÂLâàÅ4OLó¢’ŽûaÈ b¨»XÃ'IµÁmt—»êågâ‡`(`КlSÜÎ̘±<›-’‘5½Q/ú¸IZ•„Á[„ qÂ=`å7Iu’êY’J¬\ È ˆ.N$Þ¨#¾Uè­¤BKo Êg…­¯¯O–eS®<œä-ð¸ØP½m^M?å?óòŒÜ*´ùøÁ9-^0ÌŽ‡0S;(ÏäsþÏÏÏWÒf±ü·<— n›Aƒ´(ñ©S§bóöövéôéÓ'OžLÒ!èC‡qqïÞ½$]É,ktvùÿèÑ#étww7ªâÀIíG£ýCCC±‰º¹8|ø0ÿÇÇÇeÎÅ;ï¼Û”¢?{öL? Õ… ¤ F†xE§üúõëú922288Xu$Pï^uIö™3gâ‘s’@&äÆìʽ*‰–/S^fËË—/‘·ÉÉÉ·S>üðÃ………dM×CU†œôööâ ?ÛÚÚ6ûtuy‘FýäB^…fZ¡£Lÿ>ÔV4)‚?„ÿüùóº–媬au®f§ ’_AfLQ„R`J‚åÙ4„Ç_»vmjjêêÕ«ô5)ùšv}ñâE=Îô£Ñí¦/>›BcŸ~mgg§f£ë"zçÎzášZƱOÒnt?¾ÑWÆ]ö`¦›KY®ô ÒÕÐÜ3–yµªXK³;::6 ˜:èÄRÑ ešµP¡XO¾5»JÅsÏfK ™šîÕ… /¥è5=~ü¸†ÑøB‡éaìôôô¯0×ÏØ+®qÎÏð”É3}Óà6ÀÏÌçUx•wˆ·˜„àñ,~ÆŸM~¹’nqÞ(ó²$\ãó™øÉ †k–ÚkeMý4hiXØ3§Aþ›-cy6f'Ñšó wGyñâ÷¢köO ®‹Ö#óÜ6f'™œœ¼~ýº¾¼ZŒŒŒXÓì]u¡ýŠŽy ¯Ü6f‡ †U™ŸŸ?qâDÑÁ4æë‰çm¢g¶ƒåÙ˜§öqÞ)Ì”}ߘ¤[“ÅƒÛÆÓŒ †–bøøÐ”˳1Æ4«««7nÜÐõñãÇ=ñ\B,ÏÆÓtô÷÷‡o÷oݺUtpL,ÏÆÓ\Œ‡Μ9ãuaåÄòlŒ1MĽ{÷´wžÐ!r¦„xå¶1Æ4 çÏŸ«µ“ôàTo]WZÜ{6Ƙ}ÎÜÜÜÙ³gÛÚÚ2Ú|îܹ¢ƒfÖŽgcŒÙ‡,--MLLLOO?|ø0ì&Z[[ïÞ½km.9–gcŒÙ?ôööÎÎÎ.¥TµÐ××wûömi—˳1ÆìÐæ™™™¼ùñãÇzzz,Ì{…Wò\çéñÆcŠ¢­­­kýýý‹‹‹º¦£¬‹îîo6MKÅJcŒ1%Ã+·1ƘÒay6ÆcJ‡åÙcŒ)–gcŒ1¦tXž1ƘÒay6ÆcJ‡åÙcŒ)–gcŒ1¦tXž1ƘÒñÈôn{¿-IEND®B`‚gateway-1.4.5/doc/wtls/fig4o.png0000644000175000017500000024755607374232663015177 0ustar toljtolj‰PNG  IHDR‹k¡»EvtIMEÑ :(ªl{Ê pHYsÊ&ó?gAMA± üaNýIDATxÚìL]ç}ÿ¯ã¤¡Icš4¡I mS³VÂ^·u3Ö¦`i2hkŒ4ÉLÕL5 ¢M¦ÿ@4 ¢v¶¥) Mi3–6ôÕü3Øþ€l“áÈ4A¤ÍD­ ZVHÚà6 $N ibb'|_;ﯟŸsï¹çþ<çÞû¼ÿ¸:÷œç<¿Îó|ÞŸÏóãó$v-"ÅþýûOœ8aþ^¹r%‘Hðësùòå´Q†\444œ>}Úà´ÿ}¥xýúõK—.eQ„TÑZXTÔgÁC=ÔÔÔ´ººê“uçSSSnQ ÄÅ‹ ŠE¦HDŠ„ª¾m8)Cß}÷Ýa(0„ÜMÁО")ü/*E%½µµ>ÿŠ_bN*˜,Љ‘‘>=¿Qg¤² ŽsêÔ): 7<í=gÚ¹$+Œ‚ž#Hbß¾}EHÈ"#Ü‘°ˆƒƒƒtiz RÕóh{{Û\ӱϜ9“4†sMB¦J«¥¥!BZIßàuziÒ§þ\uttÀÊ\'1ÔÕYé@¼®¬¬ðuF*t:`ÿææ¦»›èšÞܹܯ¸ÑÚÚJ̰~Ò`i;i˜§Š„$:;;›šš¢®H‹Û`:2Г'''èPµ»³Ñ-««««ªªæççùË…zxxÝã »»»¾¾¾ÊÁôôtÂah®“¦Eäkkk'NœÐ_È•ÜÖÖfÂ,//“¨766ò”0]]]馦†;Ðb?xð aøKß&þ¤ò¢@û§;ÃÐ'Ož„‰éMt þÒqèM‹‹‹ê\ô8w×S0zO †LðD»´´$Ö䂨F¯O8ÒÃtR¤GÂ餢"Øùóçù•РW†¼L]˜Gä–GÜGt(N"D>Ø^7X†Ž ØÍXŸÇ§Ó+èTæw®_¿Nkoo77éc½½½0:–_dÁîî.ÜNKÆ®Txú-äÊŒ­††`¸ÁÁÓ¹¹¹±±1uf°°°ÀMîЙûúú¸355¥!>iJÅ¢ãÒ[éôeC´/¾ø"èØ±cÆzN83Jt¨Ñp!B€ŽŒ‘MÇtÇI7äWù@xÂÐëN']__§?^ºtI†;7WVVöïßñâÅǽ9ÓÜÜL°¡¡!K]]D®$ä `C+“¶Ç Q³W.ÜÎ g”i÷öyhÈXˆßÓ§OCšfæ¾™ëâš¾§`„Ñ…Ú<ÒSÞý4ᚇVjpÀz5¯sm+òÄíóåæ¾ETÐW¶_¡Èp÷Y­öÀõ,(1k×Y}}z:Ý®ÓïL/èz<ÕjÅ ëïCL'%Í‚›w Æ}É Iþ€ðÜQHp§hÛOÜpgÔB…ƒõ–n#½õêÕ«­­­ÜtµÒ  :DÏß³güJ¿BkFîééA_Ö`x0ÇÎx¼ºº:­šL–~jjjüÓäÈÐ8ž…EÅ棟ÎÌÌH[ò£±±‘ßçž{Î=f– µµµ gæXœŠÑÜÕÕE/Ó”6Ýÿܹs I'M8+BÌ»R4‡Á­Õ £££fJ[p õbÉ ‹˜À2t4èïïor ¿ô :öàààøÃ„3¢EãW#ZwÆÇÇéc gÞ‹…­Iè`’&ò„3~EB}}}mmmGŽ9vì_zºC ÌÎÎ?~Ñè¡â`uyÿ뤢%# G9@¼ y#0â·:¾ o{q ±g×™{°ˆ?èÚÑUc C¢fmvðâóÏ?ov`çO>ùdª-aÙBÅ:/P·õÀöâÂÚÐ%ƒºº:TfúÏÈȈf”3z]»¥—––òž1â Ø±maa‘5:;; Ôm=°½8ž° ]2XXXÀn¾zõ*T½ººšÅ¤ïÌÌÌððpÞ3FœI§Á,,,rGº­$ABQ—Õ ;ÊmaaaaaGXÚ¢L°¹¹¹¼¼ì÷KeaaQ¢° maQ&9xð`ÚÍë¥ËÐq„eh ‹8Â2´……………EaÚÂÂÂÂÂ"ް~¹-²ÁÒÒ’üoooïÛ·¯¥¥åСC™:Q±°°°°€Ým‘1ŒË~öïßüøqÿQÅÁæææÆÆFMMçü" ‹`¬­­]¿~m;áœ"___oµí˜À2´EØÙÙže=§$ýì³Ïš¿+++ËËË:mA@Ïïëëëïï·"À¢h ÷éè*éÖ³³³[[[ê’©^ÑqX'NœhiiAí³'jDËÐaA>pà@@—èyddDÇhZXXätRÔhÈÞt{œ°õÉ“'»»»-U–¡-þ?èÕKKKØ»ú«ƒ³Ìx×âââÑ£Gu®m¾@WŸ˜˜°çÑZXätÏÁÁÁüöS êææf4l;™RX†®hÀÊýýý°²Ž†¨¶·[Xä(™Ž|þüù‚r³èÖçÎkjjŠºôå ËÐ Ìåööö¼ YçÌô……kL[XdúrkkkTþØÑ­GGG³8jÏ" ì~èJùÈ‘#1¡ç„c466áÜò&Ôø:#E§««‹¾áq)$ÝÖÖÖÑÑQLó½r`º100Ãî488uJ+++üF‹b …lll,êŒüÆÇÇëêêâ£ô— ,CW"öíÛu’ x—………Á™3gêëëcňÓd‰ŒE‘²‚eh‹¸³¾­­ÍolaM ={6êŒ$‹vÔ½Ì`Ú"FÀŒ®©©ioo·=ÜÂÂúÅb¾bƒìÕÕÕÙ!±¼À2t%⥗^Š: A˜œœOÇp²ÜÂ"*¬­­•Ê\¯ÆÃìò±Üaºâ066Vê-<<й¹+ Ö444ðuF,òññq¬çÒ"<»|,wØýЕú ŠmÔ¹È «««ÖÑ E%­º««+ê\dÓ§OÛdÙÁ2tN“½ᡇZ__·'mXT&P©Q¬£ÎE®µ~ø³€å®ìììÔ××—"='œÕ1Ö ‡EB˶ˀžŽyPr£wq€eèòÇÚÚZuuu Í¡nŒŒ¸ï$=ŽÚ¢ŒQ˶3ª GiM¥GËÐeìf¬çê/^ìììkÍçãÒÊÞ€=mÞ")ìJ±òDi-óZ*ã•2V>räH]]Ýää$+¬®®.»°¾¾ÎïüüüÅ‹©ŠÞÞÞð´±¹¹ÙØØ¨ˆ<ëñêÎÎNMÖÔԔǖܸ‹Ùs§¢vÚõb¡µoQÐùKÝS&ùÏeÈ7ž˜˜˜€2Oœ8%‡ëòå˼‹SSSÁ4ÊM0Âç1ÏòºêŸ}(K\¹r¥h-œ´<©744DÝíŠ;Ðv-wÙôèÑ£‹‹‹Qg${@ ‚å1¶´´ôÔSOqIg§ˆúƒÇv-wáÔ©S9Æ€åtúôé èY{rBËS>ë!÷éééRô)666¶²²¢!îüÆL„˜\D^WW·½½ME+vϾ}ûJÎŽEÌ»hhii ÌЉ[ÀÝÖŒTKGÔQ§þÜ|,®Á©$=̼ëÉ'I477'ÍjZ®¨Ó6³ƒeèr†§›…ÁÌÌ ðÍ7ßÌžŽÙýùÏ>LH‘4 ^áà*¥¨««‹:År6`—ŽEH„œ‡vw3z^ךû:ƒ5-ÆÆÆÎŸ?<Ò§ž={68z¨›8ççç={–qtww>|8U$]]]½½½ g ,ÕZ-î›ù ¸?ë½ hoGÛÙ•biaºlÉ™#!qîÜ9~1 “>Ū†¤ÃlµrcïÞ½÷Ýw_RÊ÷’&þåååêêê0§°¢&}ã ¤0TÁoMMM9}˜i`` ­­-Ó½~Àˆëëëuuu9N<÷Üsæzqq‘öŸtb%øŒ‹¡ƒÇ«4 ‰f±–Å `9·âËÐe‹LûÖ3šòû￟ʗ'ØÚÚzðÁ3ÍÉ<’¡ÁÛo¿ý™Ï|’Æ&K+Î666bE ˜ 8p‡¸ÂÞš¥…@T!L«¯“)èA!‡sÒ³ujj âN&í dé>P}(»u|z:Ý<­ +ï¼¹Xº4ƒT»=ËrÐ%ï°óÐe‹L‡¸5iýÆo„¹víZóÓU‡ýõ×"¥8\L¶¯^½u.Š}ûöq°°°€@GmÒ kss3T]º¾»a¦¼Ð³°´´”v-X0z,cž]fÂÌ+Óg“:EÉ9´6tX†.Od1Ä}üøñ·Þz+ÕT‚ó™Ï`"§ ùî»ïf1Ð =#}Þÿ}’ÉaXóßýîw§«Ú,ò yoFY„]Ξ=›»MVL´··ÏÏÏç> ¸5ã0Ä!Ý\‡D1—hõ÷÷kÚÛƒð>Ô*Ö†.Od*VЗ1[ÃŒ`ÙسgÏ}÷Ý÷•¯|åêëëï¿ÿþÚÌüìg?3Nüˆ¡¬Ç,0§XhÎ`GÆp{* j sŽ;è¶··!ûÆÆÆ´!|l•îŒþ©S§’*q‹'¬ kkk/^ŒÛ~[$ 3ìpð1ôk¿ök!·´æKó…›kܸqãwÞAŠù¹_w[I?D ·j455a'¥:>¨ÂA»ÝØØ@.cT¹7ïÆXÿiw@¥ë†~Š„ñ¬‹aç'öäÅ1E9>ÙÚÚgMé°‘QÈÈC'ršLºÜšx´½J›¦î¹çžÂu­ëׯ¿ýöÛï¿ÿ¾û&éVWW'=„æŽÛj2Ä(¹µSÑ ŠºººŽÿµ¨ó’ËËË,NZW®\ñØ‘cccªœ¤ˆÛÎ…ð8sæŒGÑihhH;n‘°£Ü >è3q¦ç„ÓƒwÊh91<çß ùË_®¯¯ÿú׿þ˜þÞÿýÕ|«ªª¾ô¥/=üðÃnõ3šì%ý‹áZPjšÇÀåšܼ½½]ºk¼ ‡`Ò*'Çmvˆ;$ì(÷mèîîXpinn^__/BNÐýôôtÀJµµµá3/82í±q…ISϯ½öšݹyófOO ;£‘üBƒì Ó6P&b8A7ŒŽŽ¢ÿuttغ° ¨à&=33ãÞí‚k~~~qqѽbœÖØÒÒBUGk|ûåI ÕëxÂ2ô§€1Oý÷"hý´òbæ›òúõë/¾ø"zƒ*øœ H.ÌÄ•èÄ­›?òÈ#‘¯±¤àXíæèŽ>ø ©ÓÁ˜Œ’¡H!É!ÄòMH@p•FÛ+Ñ‘Ûü¢±±‘ª@·ÎÔG Ý%ûüùóòÅÝÙÙùÇüÇîQ(tǧŸ~šÎBä"ìšÏ¦¦õ%—»ÛÔŠ…eèO‘t©¯¯¯··7ª™i¹ÜÛÚÚ"òÁkܡд&¦Æß{ï=³D ë9)=#¨œ«W¯¢¦ä—„óìì,º?jµÑ÷ïºë®_ù•_¤oܸñá‡ÞÿýÜô oÄÁ†îêêz饗°Z,7g ¢&g[Qç% B>ùääÌþáþë¿þk˜W mmmÚzŽº½½M‘^ IïÝ»÷³Ÿýì3Ï<óçþçwÜq݇¾6<<Ì+ô²gŸ}6Õ™TIAWžž†ïI‹„ü‚ÂÜÔœv…Õ½ò€]‹[ðŸO,?òe‡t]HÚŸ+W®¤*K˜£Ñ)/!_yå•ÿqð‹_üÂÉÆÆaèup'R€k¢¥×¡ƒOLL`ßçRÛ¼®È‰™Ø(ËÂÂwLü„ùè£^~ùerÈuRÅ?Ç<ä˜qLT(P‡—/_Ž:Ÿ‚vX´~mú/Þ ¹nßBRW!ê°¨ ¼ÿþûÛxóÍ7I1òÁ ‘#Öø²NxK'Fÿà?øïÿþoþÛÏ}@€\»víwÞ¹âÀ¿¿VéìQêÒ€eèOáahú ,ëC]ò z¬ßÔ`è´‹œåý ]ôü“ŸüÄ_„ò³ ݪ¦~“GòbÀëˆlªÔ%SÈÞn2ý)¸ jÝ"VÔR¢Ð·Ž:Ÿ"†æBgʹ9Õo€&eèŒ€Ê ŠMéYPuÈßzë-+¿é€|BùèH’Œj5ªž[r°£Ü))"ˆc²®{zzZ籇ôå©ã]¦¢Ožå ÿÜówÜqéÒ%““ë7ããã°þÒ—Ñ&ÛÚÚ>ÜÑÑñØcA·7oÞ|ßÁg?ûÙ»îºëÞ{ïMµ?sסg<{çwÞsÏ=UUU\dWÒ¦¦¦TiX$…eè” 1¥õ£[L .Ô×ׇdh÷ñ®I!—æäf:ª.z{{_xáÃŽÁId±aæêÕ«ØåaüýšÑ‹‡~ Ý¿ø“ ÿ )KÏyG__ßððp%3´4ø_ÿõ_÷øêI»ÞŠÆ‰úë1* ºÛüü<ÒììÙ³ôëçž{îÛßþ¶´ó@Õô²¤qòHôŒˆ¸ÿþûÑËÿæoþFôßÜÜL´š~9ë|áÂ…¢m7/DmÄÇžqÔ+W®ÄjKÀiž'xå¹ÂhZ½B„3»Áð”¡d?vî9˜4¼HF¹wµ]îyh@…xºpp×Rì £àjl\'Xƒ”cbþàƒ4â-¤ŠÖ„!|OO3ÓÒq“7-; ®UÂp‚µk¡‰EZX%e ºP* ÃcÿÝwß}æºÐËâ¤gÏù•9,ŸΜ9S]]]*+K╘L'Eˆ;î¸Mß¼yÓÂÁ#F²ëëë : TüÜÔêëÅÅEìé©©)8Ó›øÞ{ï ÎyØu´‡;ï¼óë_ÿú /¼ ›Å³/šAïëëëêê >ñVùæŸx≘l•Œ?,CW"<4œ¶£æ ¯¿þºG …‡Ç ¡Èkì777v—.]*f¢¤v.ç>•’λ}¼Ë ˆÁ3Î Ic¼ÎÍÍAíÚz ûÆ•Âç>÷9ÝIu|»Y§r×]wAðD( Zƒ¶Ê5÷5á…ì+ÉNddËÐåŒ]"ëuzþè£2:%Ú ÏnõŽŽŽ"äÙãÇg‹'òºrì 륒£w¸ï|òÉ' ×j ¬ï¾û.vmøh1š›ššüº¬6.£.?òÈ#>úè<ôuÃЈ7ûêxi´·Ã¹\ ÈLî§MW ,CW<ÃÚ+++îg:#)¦¥×•yzz}¼··7Ó1IM­AÀë555±ÑÕÜšx˜¥pù=+7 vvvΟ?_üqõTð8jÍK#,Í þg"„\û¹G˜t í©©·´´hUW~Ïe >bGZBµ’4k˜‚XdËÐå,i9(pÝÝÝpNŽJEÏâfxtrrrÅA¡ƵµµáááÆÆÆ®®®ðbý7ÞH8ƒi¼Òè@LLlò@Nüüž={–[[[ƒcpwZ @Ï(Å÷‘D=ȸtSòøøx?÷M-¹ŸRª[=%˜û¯;f÷+uuu„ŒêÌÈÅn¾4#[ªz1tÂq‚›ßDwww { û÷Ýw_ŽÃltj{$kv° ]ÎÐJuÃ.fÜÞEpßsÏ=Iû„D§ÂÒ2n[ lè„CÄ366ÒË{ï½§ù3´­v9}ú´YÚÖÖ[?~|kk‹äˆ™tƒ·~J½(&ûúúŠœhÂÛ?xð •FUóE`Pè¹££ƒÄ}žÎÏÏsŸêBûÑ:j²···Êw†n¡0ƒƒƒ G÷BCâ)|Àâ$7 á8$!äNÂ2†{È­:c}þê¯þª:ÑÍ›7SjF 6:&9Í€è<7wÌtuÖ@ø ˜¿¾ý=#ØýÐå m tO¹‰‚çô´ÿņ†÷a´.\м/¯ Äå€Ó˜wi¡£-%q :3¡EÆ0Ä[ZZàþ‹/"£{$dvvÖ\ŸH ±‡¸µƒ–EC¢~v8mFç¦ö®ðYùF]àzÝÔËMyQå-âAÏ~ƒ€¦Pp?z7Ïž=»éQñPÒÓ"#ªÑ~m}îïï×_XÓŒxk°Ä¸.H8>|Üû/2ìNl×ÐÁ¥ ß¸q#`ª+£ÃæÃU,ÕÚ4 ,C—?Üc³n«W&"âý¯xV|ð–!cïÓ6´¤žú¹g½IøãÂŒ$ÞzöÙg‹Y0šD„ÇH#!£££ aÇw42Tf¨V´™ ?þøã|,8N8>ãø"敘œ:L–Ð2:8µà[·µµ?Ýêêj÷±¶ú:o¼ñNç²»íæ†FÍJJ¨Ä|ð¬,˘×ݱs?€2SÅ™h¢hävN:$,C—9<=Aë5Ìtãk¯½æö÷YÀL,¾Ð8ŸÒsúôiÙÓœ{£j*ÐÇ—/_Ö_ÞŠƒï<âu."ñcÇÚÛÛÿê¯þJ+ºÅˆ°²üx† u?©ÕËë߆P »¼úìg?‹6àß{ Iæ3Ÿqß4ó_üq·{ÌÏÏÇä°ƒ’€eèröñÕ«W=7醡ނ¾ví"QîHs4qz;7?÷¹Ïå}øk×ñ0õÎ;ï êêê’†)~÷^YY‰Wð„³…æüùó g 4–ñàà Öña‡Yè CGŽ9|øðøøøÜÜ67æuoooÂQº|•º*Æ¥éPÆOHªðï¾ûnR­ º¥ó&\¶¯&’‰-é’lÑ?-§8ÃONNÚUcáaºœAöÏ«555øë6@¡þùÏî¹)ß¼™Îù÷z ˆ¤’›T†LA øG; G|lyy¹Èþ_QŒHQ&iãRêâÅ‹0ôúú:µ¤hÚË}sÏ\ðºþ*΄3å‰ 7c:Ÿ:uŠð| ………±±±¨™Qã å׆ŽÏ®ÅøÃ2tÅ!­ÿ}šüÚ×¾&¿ù޽{÷¢bgçoD£g~’¦Û?òÈ#˜ËZsï½÷2Ub— ‘ãh!fâß\˜ãGµ¤Î>áÀüõœRj^wÇyÈ;X“ƒ¨Ê»´´ìì¢ ·-_ýêWu’#ýÂ0tR‚LeFg ãˆ2ö$„V‡ÈÈGJ0øÐˆ‘ éÅyÝmUq:3úøƒ>ÈEÖîÀ ’.”%Ú` $!³ ø‡Y%œUÈò‹®®®0[Ô,2´Ý{ãÆÌÌLGG‡û:/Úa€ï7nd:Öm&°å\,Àåg"[%ì‡Î–¡Ëè­I=;jɆ=C¹b9 ßýF   ˜Ý™âÀQ6SW:—Â"À®‚*¬톎¡ljjÒa¬ííí­­­GŽ ^Výî»ï†?•ò\dáÛ ;Ø‘’¬aºüÅœÔþ“›~·úüú믧%i--I5+€Ç{ q€)ð‹_ü"»‚ø×¥ Èͺº:kFç›››Gµs~<ôÐCóóó---/^œ››£ù½üòËÁo½óÎ;!7.Óyåz(/ÆqZììì g¸¾µËÐåVè¾SSSÓ××—tÕUIïîî^»v ]>;Cpó£>úõ¯ýË_þ²{‰J©`bb¢ø§^–+Ú˜‰Ð] Ԍ9ìëСC³³³Áj1Ýó­·Þ ¹ÓÐó7 ½J´««‹‚ØMVÙÁ2tù|ß¾}îõbžãZ=€¤WWWÍFI:0ò¥þ'?ùÉ=÷ÜÀBÍ%Já1þÂøçÚ»w¯ªu˜w'&&RiĈà I-$HwÍÚT¢…øCayy¹8‡Ì§eDW8pà€%é`P?“““u._¾lÍ©¬qìØ1”ãŒÎ—ƒ¤aè7ÞxÃ8úN…;ï¼ó§?ýé+¯¼òò-¬®®æ~–Ÿ>VÃ¥ËПÂ?ëŒ-A ˆ‘d >›ššÂBMzv/ ‘Ql###tòÞÞ^ …ÄD+OKÒ_úÒ—tý Á§]|ûƒðY¤&3!yŽ`M_PP(%Ôax £rÀ—¢×ðe5ë¼¾¾ÞÙÙu¦J:ù*‹ÌÈ´‹À1Í=1ßwß}¹ïÚ˜ŸŸÉdébOÑN, $D‚r I¸!¼×ž¼ ªªŠÇÇÇýO³sß%ë(!تæÎÐÐP€3„¯~õ«ôpQ#öq!Î¥éêê"WÔpp0ò€5_äOòÆpõêÕ .XaDmP Ô ã‰6Vr&}êàÁƒÅIëÊ•+)Ù„·ß~;Ó ?üpÿBo½õÖÍ›7 Lg¼víªUŽ64ñ`ĭÖìn«Û€­ìL¦©9rD×ðbÑ2³¶¶`\f·‡mÃLåbÖhЛ®˜ÊkÆÇ[§NJKÏÚûˆ@Îûúú01WWW'''ÏŸ?O‡GX'dtt´±±1íRp¢|ºÁ r`ܨ&»»»±­+v,—MëBç‹:#å ´ŸÿøÇ_ùÊW¿Bÿ ïþï‹_übÂ|ðAîCÜրΠ¬ í\’õ’é¢È}A,ÅljjÂ2~õÕW?ú裤a¾ño„‰ úlmmM;fŸÁÜ:_Ï}_¶ì0ÍŒÅÏÓ´º"ÅGs’DÝVÚÎiÔ”T32¥‚8ÛÐhÀëëëô Þ=.ßaiñÞ{ïi?4Œ@ v4Zí¡ uW1° í­Khll,êŒ$Ü622’¯Y=úáÖÖÖÛo¿ÊBZ††–ººº2š‹MÅÓi³Šx*óA?;; [ÏÍÍeº\ tQSSCÁKå%Eœš¾ç¡ ‡<ÂuÏž=<òHqÊâ¦ÎÌÌLEi¨…€åöÚ…?è QÓ Xf´û÷¹T®^½JÔiëüñ7¾ñÚÚZm”Xv ›ßüæ7³³Â»»»O:um•ì(w¥£±±ñÉ'Ÿìééyã7üOïºë®¯}íkþûˆcHZëusI=Œ‹ï±±±óçÏ_¾|9êªÊÁ§Ÿ~zaa!êŒÈ÷K—.•úâ 8r'n-øøéOúî»ï‡¼ãŽ;~øaÏMóË/¿~&†>~üxF<­m%4'gX†®tÐ333wÞygÒ­Æå§ÿÅ7_É $2ý= {ˆþÕÕÕRìíf-^Ô)8ÄePÒ˜3tÂÑ„´¦Òí̺³lbÈJæTððÄìÁ½÷Þ‹=ý­o}ëHxrrrxx¸BÓBÃŽr'‡6Åpº¹¹9¿göÁ²Ð3ÑÒQ±ý›þé™ýšŸŸG"OLLd™ñññŽŽx7€žŽ£†¡¡¡R¤ç„3W’pxºì'äžzê©‘‘‘¨sQ8uêTooï¿üË¿ëCfªF¨¯¯Ч777Q…WètØ­C|üñÇ„¼çž{I—èœTL±kq;h£1—§"Æn~K}ñâE¢}÷Ýwÿ'àOx#x‹ëŒÒ"óÆ9óéÓ§B^¾|#»_½`@½8qâDÔ¹(,äÎ3ïm2`×­#“Vv™¤¶é°¿üå/ˆ·ß~û†ƒbV C1S,oX¯Ÿ· 1—#¤ŠƒééiãA%_€2÷íÛ÷ÏÿüÏI×ÒÉ=³ÔtByB%3555ä'é‘V~ŒÆ€V$¨Û©B¢Ëc¦_ºt©ð5Z@P±åíÔ|¦Bø›³ðzîîî~ýõ׃Wk£3ù]`¿óÎ;žs2üatPì[o½rg—MÉ/ì<ômhll É4‘ctt4¿¾Ž5!ýOÿôO÷Ýw_ÒVñ¥/}ɽ:TëAÜ^Ï`\:gR·k“““ÛÛÛ/¼ð‚»z'&&Ö9wuuÕÖÖÆÙEIHP«”¢\Wtó™NkŒ:#ùAÌç¡ï[újñ»Öuû=–@ºØÖ!“»ë®»¾ò•¯„ßßU6ËâËП"/žtІýû÷¯®®æ7N4n4ôW^y…nìºgÏžÇ{ÌíOë°­­­ù×n®¼0”±ØRÑÖ××ËÆ€Ž9Cë<­Ñaí?úÑRyê6‹ÅÜ@à¿úê«Á«ÌNgß·oŸ5x0PzzzÊUv”ûSH(£©TfÿR©B Åk~ë7ó7ýq&nõmLasçøñãÙízÔò´€ˆ¡à%„C‡555•Á`€´À£G&=/Ü¢@pŸçxòäIÚÕŸþéŸ~þóŸO8©¿O¨÷k_ûŠøW¿úÕG}ô _øÂ}÷Ý÷™Ï|:ç—kî|ùË_þú׿ž)=ƒ¹¹9KÏù…eèOAë: ™¡KÍ!ÝæææïÿûIÏžƒ¤_ýu·Î>22’©‡pôr°2CúÄ|½^F˜˜˜.§Ã¤µS.žÇ™”1fggÝH×[YYùË¿üˤdÐÞöîÝ‹^?øàƒðôc=Æwä—kîdqÆ¥`uµ¼Ã2ô§(šö‡»'TUU%=”B‡ï棣£óóó?úÑ’žÅ™pö_ýüç?7ÇaÁ¦SSS!]Ux}}=@¬#V ³€d¥yS?pà@ÑH-§p µÏ›Yz.2 dO¯_XXÿ·û7Œ`Oà´CÙñ‡‡þvZèuüÇüG@…Àß_üâÝãáXTßûÞ÷°°ýçfb7ÃÍðnÚÍe³@Ì¢9GëèèØÞÞž™™Éã!+ðßb(u÷aIá_ÿX  ´åëìdgЮȹ‡•kjjüÌmQB° }ÚÚÚJeoLÞ×r@½Èä;<½¸¸xíÚ5óèóŸÿÒ*³h?æææhfõõõI×d 9ÛÁ–Ânvß?sæ òZLjeqê9v31hÓñ”åìCy@K»i7nÜÀÌxàî¸ãDü;ï¼uÖ,²‡¢ð‚Æ}ùòe¨b|| !˜NNN®®®’8ËxX»l€F3 Ûòq~øá?ü¥’¾ÿþû£ÎE6°óз› î–òfŠ‹Go¼ñÆþýûÃû “ Lê°ê2ÃÚÚZ{{;.\Èz؆HZZZʰþÈÈÈÙ³gOŸ>¬ßð ¢\ŽW“ò®ÖIAçhvµvÉÁ¿”«úúõë÷Þ{/VuÔ¹³ÈQ³[Ä W®\ihhðÜ4S\}ôÑ/~ñ‹¼'JÌÄ—*eŒË—/Sv„)"5ü[ÔØÐÐÐ~SSSº)OéÙMky‘Ey€F…îåi 7oÞ´sÒ%«RY܆••¿'“'Ob–qÿÝwß}ðÁügù'‰ÊôF7¯®®öõõ WWWcUONN&ÝíÃÍååež9rD+Þy7/ãä™®º·ˆ3hT4矾±±Ñ´¥½{÷¦òp`[Øyh‹Û$=úBëPêëëçææò¸’Nƒ´Ò¢.z”8á áÔÿØØ˜jcssÓL뚺‚J5¤u–-b lh,i­ò*ÐÎL‹‚#j#Þ"^€'†[5¯-7Äëx¼”WÚ(wZ¬¯¯‡ ©ƒÅø:Ë1}z¦ÛBØQçÅ"cTÄ’‹ð¨ªªJë0¤­­íêÕ«¹¬oÒÑU壣£ž´Ü§÷XXXäZÉO·íééI:H&'tºîèè°ƒ41eh‹Ûr5ûÔSOqÑ××~þX{xêëëy1éªeh ‹agggzzšÎU×ÖÖzžšŽL÷´›ëbËзáÀ!­O¯¯¯÷÷÷ìÌA"¬¬¬ b£ÈoéÖl…OK[XXX$ìJ1 àæÙÙÙ -ýXÆóóó0±G1×ú&bkhh€øíЙ………ExXÚâ6Èy¤ß/UFÈâÌ kC[XXXÖ†¶¸ ˜¼»;;;¹LDå²¹V. -²ÚªX§¿XXX¤…µ¡-,ÊgΜ ãõÓ¢T`}ŠYXXXXXÄ–¡-,,,,,âËÐq„eh ‹8Â2´……………Ea×r[X” ìn+ ‹2ƒeh ‹8ÂŽr[XXXXXÄ–¡-,,,,,âËÐq„eh ‹8Â2´…E™àüùóà7êŒXXXä–¡-,Ê+++9žjaaX†¶°°°°°ˆ#,C[XXXXXÄ–¡-,,,,,âˆJ÷)¶¼¼Ìïää¤ùµ(8p ¡¡áĉºŽ:;y€Üv®¬¬Ð,õ›éëà!Q¥AST›´ŽW-ò…Jdèµµµééiøxuuµ¹¹™ÕÒÒ²oß¾¨óe‘1¶··gff ³ùùydbWW×ñãÇ÷ïßu¾2ÀÎÎÎÒÒ­q||œ" å«««;u¾,²ÁìììÖÖ_UéäÉ“|ÍC‡Ý}÷ÝQçË¢TQY M·Aˆ/..ö÷÷—œ(·’ÁŽ™˜˜( ±866ÖÝÝMSìéé±¢¼Ì€œÆ 5ò‰£ÎŽEI¢‚º½½K ®qQ‹rLooï™3g:;;£ÎKJÐiÍÍÍ4H;"ZÆ@qD [[[»té’ýЙ¢"VŠíìì´µµíÛ·o}}ÝÒsÙƒO¼î ±±‘Ouv’[¿££ ëÊJíòßwÂÁ¡C‡øîQgÇ¢ÄPþ64Ú+–ÊÀÀÀÉ“'£Î‹EQ1== .--Åj:£««ë¥—^ZXX°cÚ”Åööv{tt4ê¼X” Êœ¡¡ç,//ÇJF[ jÐ!LÔyù?h,çâÅ‹iCnooÛÕ‹åTF¾ìÔÔTÔ±( ”ó(7JkSSSHzÞã Óý-1ŸžozôèÑ8 wŸ9s&-=ËÒ¢)VWWWUUÙqÑ2_Ÿ6@Kˆ:#¥rfè#GŽ Yë¹ÂA@,F¾azii ºM;¹ºº:99ÙÐÐp÷ÝwÃÖ˜\kkkÑæÜ"¿  ÐhQgÄ¢P¶ –ŠhÎûÜóææ&öš¤âýóóóÁ1(o_N›·ðð<¿ðŒgäX]ǧ%Dh¸ÀµØñ”(ÌÜ3ú!×××õÎNûJww·ûH+ϧI;~ ´ê¶¶¶¨ª¨r@ˆÏ¸ŽEÌQž MÓ3Û—)øíïïO•îôôtp ˆ¤g*oJºõw>M+’Ôi6===aèr•ZiÖx§Aç›BÏnýceeÅSö`å¬ßÁõë×Ãh¹c{{»©Ä´Úƒ„‰…EÊ“¡Ã ÄŒ Q8::*ŸAæ&ÂQCÍꞢ&ŸqÀuoo/ô v$€_B)C!X3]]]†ìÝ=!Ý”îæŽ; µ¡¼utt<ýôÓè&o ǦtÚLL•y·2Áµžšhùk˜Œ¹_Ôx™I(©P¦PʳûÂÀ_ì ™ˆ­™ß&džÂ¦ÒêRA5=§ÝŽE}îß¿ŸOæq[kš¥6V5Ÿƒ–I–¸0µJÞø¬þ˜5Œaâá«y†Ü—˜î ¥eƒ‰d||œäL0¿¶šj-ˆ§×¸ƒq­xT.sÁM3©˜‘#Z•Ñ¢d°[vØØØ@cdô–jãÊ•+a´{• ä&➋ӧOs‡ßæææ'N𺪔›Ð (M%D°††nš˜yDâ'ü¯˿Á‚÷_wHó: )'ÜWøÛ×××ÔÔä)ãÜÜÁˆTwx…¿CCCÜ¡ÞÐ?Ä Ü'Zî›×¹&Ûä¤M`ùÃâ)¹)O‡æ)DH´ºP̧N"¼rnêÍ\¨–LUrîmƒxhymnéA…dšy>ôKŒÚ0…¢Jå•LwŽFbê\íòåË\PŸjœüîw°ë4c}¸c&î’/ÎwÔ»j|h’Ð"…4¯ð;22R[[«ävþÂ…Œ2¦†¤Ü•ãIÅ]¼¢Èå tvvò·¥¥ÅÄT]¨9qnJË'Œ&ø©Š"·¤ “îÎbaáG24Ò*‹v†¡ÝÖŒ”#x‘;’b>~%š·¶¶r¾›‚¡µûB¤Ë[aòÒìþ‹`u‡4 -mR¶s—q÷–¼ÞuW‚OòÎ#Ýtáæx©>ˆfOI[‰B b÷+Ü—Û,îË'µ¡úÑÇ2õ¶ëchq;Ï9‚ t‹þâ€fªÈId˜"«æÑÆÐx £›ïNÒÜQíñ)!Èõõu©)Ô¿j› Mü„ä“Ar„!C®&†]C“í„ð¼EüÒ®;0Ÿ’/«–L1)£„Q*æ¦ZòH×}”þªz‰')C«°R¯ÝºräP‡Š:±FŽr#ˆsŒdii©¾¾¾µµÕÜY\\ÜÞÞ¾r ˆ÷Úœ••3’F¯CîTUU%œF(,>|8 9¤‚LËü]^^¦#RÝyêi^?rä~â‰'2*#1S b&ÂT3ÓH=sM¹ïTBWW—'XMM O‰„¨Ü¯ !*™ ë´··sQ]]¸5hyõêÕ€]¿|äø)Ý@4£.ä1´ ÙPÏ9›vp&8àš¦Hmø?Ó÷¾÷=*V†)mÃ3–NÝšWž}öYµ*ûuuuÉ¥ŸÈÍȰ´Æ™™ 0‹dF¤é‰´š)ˆû[ nºgsô"Åô h“(튚$°Ýí’VéÔ„R5$i‡¦!ÑM¨„<æ¬@ƨFÊU ø=jÏë+yD­"ä7Y¼¨Ú064´šp `F¶£’›ñ·cRtvv^ƒiÈ8$‚Æî´xÍoCë“hFŠ“ðЉç¯;¤yG0Ÿd´ŒìÝÔ6´ÌVâ!{f¨³¥¥%© í6e”•ÚFñ˜Mc1k’Ìì!Fª’á]ÇÚƒiÄd»·lh•E#“y±¡w³²hÉ t’Ýðx¦V»ì*'ÕM÷Gß½e\šŒ™N8ö·–b³ó”Ú–Á*ÍO-„ëZêV=øpÊ$å2ǵ¡ï:ã@•¡ñ-}³[ö´Fã) @¯q[´d€;4f^7cѪò¯þHZ4Í€15~Më 751dlhw]©Zè&yiK¹ƒ:tK•üBrÉ DY”"Ê¡ýR&$$¤Œ°£çÓÏݳ€Äì™ÛÖ^¹té’^Ô¸¢ ñGlH"Éðˆ_ó1{$¾;9wœæ¯IÝ“1“[F*&3ž ë‚×%þô¢âWÑú/ Ì‹IÃø3&˜1y÷à0©o„¤çattt¸ÿœÝqž·RE²¼¼¼´´$oáîÀÍÍÍ'iÞLTnGæ¦ÖÖÖšÑly>Ù½åËehhH6ºœ*SF¹7‘óäÄ-—O]˜§ò¬¤­«ò»¢r‘s*D¾«r4ÜHܲõ3úôY{,ÑVÝ|eÞµC> ßNî/VÈU5_\›‰›ššD?„T0nríÙ9-Çïæ-y×!~÷ü1óÔl>Ft68P“–#E¨´ä ÇįMÕÄ ¿$a¼©ÈÑ7Í&fÂ’k²$\kc´{¬EtNaµ;\{¬·¶¶FxbPwлDE“s¡¬æ'_³r2Ã:ˆöa+c”W5ŸŒ`êÊ"Ùùr.”!CÓ… 1ªãghú³(YF½T´ä~Ëè@¦ÛŸÆ&ÚÄ-Ÿ‰[. C‹äßÛ³vË(¤\,í:}ÞÝ”Í(7€íäCÌŠôQA5ò™œp¼4«h»Ž„2þ°?™t{Q&9Ñ”‘p\p+cr fŠ™BÉS´‰Aœw±M k÷<çøÇç³õVäíòÆÜ½ÅÐj¤Å‡ãë˹­QŒo‰xä‚[š™ÚLss3TG¤ˆ× )]ò晚ëS¬RÑø•>¹+á)ê”åŠ×ÕD¥ê]‘nÂñ’`>ù“wšÄ-?eJ‹Lƒî“ŠÇÍ€)¬ö,‰2¥ù)-y‘K8Þ¼sjÀãÛŒ¬Èñø®ÓuJš±œ£é×QãÏOFˆÉvùø#Ž."A®åFhL¡G0Q§+"hÌ”nlnn;v,ᘼ;;;¼âqSŒ@‘[DÏ‹pž¼^»»ž™™‘/L®Ÿ|òI•WåjÛ‰îôööjƒŽ$¾Ñ}þ¶··Ëq±ä¦1d“í3gÎ@®¡Mé(lww·9!‘<ð—_ HyE îÁm´ b¯†ltttø÷éôÀàZÍ:ò²pMÂê–z£6 ½iD\©(>¥¾¯ü°jïŠ|_ëÚkqÀWxâ‰'¨UššïB…kç7/ª¹[©Žn¤ÍÐÒhùGŽ‘BpZ©"üñljÌÐD•+ &ZWWGü¼¥û„7©€õõu¢%9µIŽ)%àÙgŸÕ[ §û¸ý„+«ú¥e*B@ZÚôxþüysö†Š£ Mé. mUÇÅÒãôʹsçÜàuZ8}ÄÌ•øó$ħQþ-‚ÁWðœz^!(ÃyhÔ^ÿ6ƒBU¾¡éh‹=}Ñà!î#ª ž")èØcccˆ'=s¿¿¿_Þ$)äßx@`„)qºu(öªÓyQÒ²ÁàBd¢¦‡= ‡<•Í”j¦œìa— ÜÝG,ëœ3ÿ§KøKn‘;ÊsuuµâDŠQ.~ݳŒHvÒ%cnÕD4 SŒ 1µJ5æ2'Í»$„t.@[åÍôpè|"K‰Üuit¶Jªixš™Æ*` &ý’p5 5lµLn­9ô¦ñ4é¤õ Ñ# ϸæiw«ÓÍn(­_|1¤~cætah©È"7e ƒT§È$žôiÀ*“¤ Ud:ãnQi(C†ÖÑn"É èä0qÂpº†<0;P°ZPöéoßýîw=ŽJ††† ODÌ¢µµBuÛ¸D±qa'ÿX „ΕPž™à?dé¶µµA9Ä@<Êž¹0Ù&B’ è™ »¨ Ü禬á^xAEK8GKé"ሼ§Ÿ~µÀÍ|¥YC)ÈG¢"{µø"Xð(dÛ£%Pv¸AŠÉqØâ&ò“…äL­R'¹u…Zcç(&(´*£X·GE=”D³Ù³gK; x…Jæ+’V1<ÍY,þ “yÍ‚û_q_›_~’ÖU*hqIŽ_¿¢P®lŒ¸8 Î;0מþy-ñ(i`U`¬Dîi¼Ôå÷øãGU;;;‹ËËËvÒÑ"ጊ9rF·¨Ã#>.î‹Zê2.sGG±Ô¹ ±n]Éçˆ8¨kkkkMMMZu}XD‰ÍÍͺº:«®eŠÊdè2œ‡6X÷Q8pà€•é¹`ÜA¾NsÊÚÑdÖ$[T&´vO´¢ÎKÜ*³Ç…„CÒ¥nz…D™k%]¤?¯E7wttlllÄ䄜öövŒií‰:/ÅâH !µƒÜ"-è/“““þûtŸ ™#(g:á|ÈåååÞÞÞ"û/´ˆøè|zãÍ-˜˜˜xüñǵ7ê¼X¢çææfKÏá‘j­»ÑD»b ÌmhA~ÜN?,Ê›››ÝÝݱµVQÈžtè‘•Çö} ¯©³dø¾ÖóvŽpû8*ÐÁH±EEŒrû±¸¸8<<ŒbÛÒÒ’õY„1ÁÊÊŠ>¥ÎMŠ:;Ãí^ÊšYe­zéîîækÆg Débii©±±Q×òuŽŠ‡ ehã€s{{{ll¬¶¶6êY„…Ü•ë:­Sè’T­ÎèhÔٱȴ@£ë×ÔÔXbÎ/`hxº¢f …Jgh ‹˜Cft¥Ð ËÐñÇž={tàBÔ)n©-C[XXXXÄÖë§………………E\`ÚÂÂÂÂÂ"ް maQ&8þüø:#ùÁQgÀÂÂ"?ØØØXYY1ûµ,,’bmmíâÅ‹ÛÛÛ333›¢ÎQXè„«ÅþýûkjjŽ;¦ÓSB.y³ maaaQþ˜t ß>'Nœhhh¨´¥ÑÑÝèúõëcccýýý Ç=ÁŸÀŽr[XXX”3äœßžžž­­­‰‰ Ú<_|`FSíCCC«««‹‹‹ÕÕÕõõõgΜ 8éÎ2´………EyÑßÕÕ588xéÒ%ˆ¹}â–+zè!¦¥¥¥íííC‡a^' fÚ¢ ÐÇb«­­½|ù²ûð ‹øžÆ¤žžžæÁÖþ–¡-,Ê555 üF‹è!z>ã ê¼X¤Áþýû766ÚÛÛu投è¥Å¢Œ±³³#z¶G¥•’~5ËÐe…úúúþþþÎÎΨ3b‘ÖÖÖ4ÜU­;–¡-,,,Ê]]]›››SSSQgÄ"@ÏGŽ1‡lZ†¶°°°(ÀÍuuuëëëö€êÒE[[Ûã?®–¡-,,,Êííí vuXICj–ÌhËÐe:öÆÆFMMµŸ*;;;ÕÕÕf€ÔƒyÛÛÛûöí“Ç’¨ók‘hZMMM===v·•…E™`ddäàÁƒüF‹h0==àðz>{öìðð0¿´“®®®¨ók‘póèèhÂ°°°(À¾Ç©žBÞ«««»»» ³¸¸˜*äææ¦6R§rtUP(õàbšÓ>ÒNô÷)pž¿‘šÊßÙÙ± maaaQ€t¡áTO:´ÿ~„¾x7`”{cc;;ጵúà@fµ¿MêI%÷öövww§ ÜØØ¸½½?™×€¿{´Éó—ÒÆSh𽦧§-C[XXX”<–——Ò†¡í¶ÍÍÍ/^ ‰m:55#^½z•_™t ‡Ú{zzÆpO “ôÏMóоô÷ÜspmϨҰűéaht‘HÚI6 MÅQT*hkk‹Š.3UÔ¢2!)p´o„—=ë>æ@^c%œ‘Œ­ÒSB\'iRë ùÎGG—·~CE!·á-Y̪=êM[¨ÝXUU…mЉœp¨ŽêÅÎ6óÁP2×µ&NBÂŽÜÑ๰ž©aî’tgffZ[[•º!K…§ò1^5Mœ&«CCCØÍê˜|,žº9uêá!{b#N’ÑÏ»äŸwyÄ}>+iQ ’ÆÎ¦ÜY5ùT¡Tv]ëœH:;;#SãvCccc%ˆz$ëTœ¶ÖYX”®_¿¾°°@Ÿ§CÒtï¨sdáv_‡o„DŠsœEÆiQç"Àt†Ô¹Ð 7fwÔ9ÊW®\jC­ÓŒý¡C‡hÁ”Uª®¡!‹Š:ÄŒ¼FRkõJcc#¿QçËâÿÀ‡ÀÖÁzF‰Só³$S¬««+xÂÒ"æhiiÑHÉñãǹÆtŽ:GÙ# C‹›é”–Œð²cÚtÐÑÑQôñ³gÏZžŽ"ˆ³½½Ï‘_n6@²!ë¶¶¶ÎØl$î´,ò………:,š &ê¼ä„ †¦Wh†{"À™œ…E2˜ššºpáBkkkÌ]Ÿ?M:VÎ óDm}}=æÁêêê¡C‡ šÈúFüøøxÔU´-ÍÓàÑœä;ŒûùUXM„‹¸ž™™¹~ýúöö¶ÛAJRäQ—¢tqPĽ M¶úûû¡ç¤#Ûá“Ç‹Ûs[x˜cX„Lš„Ѳ†bÎ.ÿv@¦×"æ¤0>èýÙˆ¤)§ÊOüáÍy gW>ƒqÒÜöZ¢gdõœcT¹{ýÄ|§¥¡–UIëTG .¸Žä—›ÃÃÃZ&â"ùÃ5¼@ÇáZ.G’FH/ã](N¢êêêâNÂùܼε||šác>Ÿ< $3ÙH84L<Ê¥‘ˆ™ÔØØh–bž`ÑDœP—§ ë)fç /¼ ˜åʆkÒRãQÆc¨ÂMðÞÆÐ¤ÚÑÑÚ’”ž3ʵ@TæïÁƒÝOÓžI–úúz£0Q™ÆQ~â–é0Ò€b¾p¬D!z¦ûûÇð4iÀ×Dph‡ƒƒƒÕÕÕn7ÑÙyXQ$M•jÿNKK‹î¬¬¬$&£ƒÐMí(.\Cc|¯–[Ø·oB2)I=zt~~žZÏQWW'/1Æ>&îCŸ³³³& ʃœcó—§0«|˜@Ucccµµµ3qêÄë'NÐ7 ÃwW—wgCÎA‘2ÐÉ€>|8áèè´=陌ÉýoU0H¼ây4ro‘&sSSSIwOË›¹ÉÖ•+W¶ZOLLˆãÍöOB—/_¦ð1ð1 -Û!7w+‰¹¹9÷ýÓ§Oûc æ‹/†ß6®˜¸ØÚÚòD•Ös yàÝÉ¥‚;Ï*#=„hÃd`ÕAŽØu>bÒïN çÑUBÚ¯cž¦m‡M—Öhš"4?]“mº:5©¿ÄF÷ŸO(ÄD nø%íe…†ÊIÕ\Õ=à+¤ŠM;P†††ò’7}ñÑÑѨ+)9ò豄xõ».é§_{qòäÉžž#œM7¤~üÍÍͼn^4U禯Ë/MtG¨™¨$gHÚtÒëø¾¼~ÅB*9>–ü‚yš“vë‘.‘›`Þu™k‚¹Û;þBPÕð§Éo:iPJ(·p¦‡KFâ¡*ù¥6MÁä´] D ‘š‚ªž T©2Ë< M… ì:2—v@W!<ÑŠËÍW»SžÊwø%u¸MÝL÷Uj‚‘4÷µ©Œ§nšWÌüöõõ©‘1¾Á,ø‰;&ó\yÛu(A<*íÌ9÷ CHU•CeXe¡¼<¥W˜<«,²Y¹© ¨NLåQ’Ì·#ÉQÏDØÙÙéþ^ü5y ¼Ü^**ÝQµx¾»|Ìñ"ñ­'rþ*ZU‚>1)×ê«$DVnAz›)©*Ge4‰êP[Sªµ “ %°i‡nžœSF~iº£åO7)ô½ Ð7+ú"JGþƒÁÒhÒ~•:Uäž©rHïßydhTé=†Ö_ªnâghz "9™Š¡Í—•üÔ5Õî‘óÁ Ì»D‹¬@<òÈÍлŽ2a’‘»3c H­@DÄ¥bhbvkí&þš¼¦òx§ž°ßº²5U¼'OPª•Vf(wT¡”œÏ©“G²<¥®yÅ| Ï—“i®¬rMk "’ïí©VžJŸ8uê”xŽÈåw—2òˆû<ÕQîðwÈi1náVÛ¥ HgËFWü²Õ”yÑ!úFÑ*Üœš !U3jUÔ›œÊBð Lž• ›“¢$zËSâç-.t†>!¹PrP#T&ªIÕª.XMS‚¦ânJˆ¼X‘óKqô×-áøÑå&Ù“ÒÊ…š‡¢%]˜’ò90§ˆÐ­Óh,‡§ª¾©.D«„¿n‹y7µ©MfˆŸG¼å&Z*ÜŸn*PŸbw‹ÜÁW¶PMg¤Ю$^Í·“ÁD»¢ Ѥ rG¼¥n«×¥‘›Whz¤œI5°ú<Î#CKvQ½ø»·I®$%ÁŒp¦2’_º¿:õSwœtjéÖƒ²¡y *ñÈyaR†­J‰×±äŠØøˆ&Jó@atö%qºÕt®5H Kr×EÌ*¡°ÊŒ8+2†6â8)ŒqS¡þíñm¢Fcʃì3*ahÕ‘dºûcøG¹©,^‘d7&¯û+ÅÇtKYcˆ{Oäzê.‘dà.”û«hTÀ]W† ý™ß½}øW¶,ÍÈ]ÙÇî„ <ãB&*OI•.ä‡Vu«Vµë¢(·÷;wg–•L î:×…Þ4J7Õ%n9¼UÞÜ„Ô=CßîwÅ©²òÝmèÃz1íç0qê½xÂÍšÄÔ†ölàqkÜþtSAò"m°JÒ¹!PážÞᇔ›Fk¦ÔM;”ÂíAê¼úš+6’à†”Ë\ kÆÉòˆüúåÖÀ¤ š×„´|d{~n«Á'.t³^÷ÄIؽå_òÍ?U§•†]Í'Ð+²yÌ#åÁ´Ó6ȶ{°Zƒ‹º"nR1ü  ü覉<¿ŸÏOZSyäe2cn£Ð3š¡ÿÝ[R˜ûR©`¦Hzª–uÎv0CSËêN»·,iž¥¼À ê**™ª C'TSæÛ({jUäœh€§Èú–"wOPüš}ñèz»·34ñ˾t7KiÆP²±;Ý!ÍH¸Ÿ¡Å£zW©`‹íÁ|/¯»·ÏÅê;µÆÃÐf(x×ÇÐfØ3?¤È›¸[…û]©qʰ©^µ SRu`T蘭CÞÝ m>+‘¸Û¤jÌŒcs’g,x““Ššé¢Ð„éH¼›¯™Î’†_ÏaT"#¤}š!=Õ¿2 ‰l7CK"ËÛÍÐjo:„XÃ`i‘û°¼‹øBŸœ!M¶¡+ÉêÂ¥•w„‹>ehšfÍq×7$†v«?îIA“|¦/™Ža½5]*‰ ÏÉÐLÅÐ" Iv­™½vó–ØT)jÎ’·´&®¥áh UÉð¥Á (˜Sø‹,¹ ¹sCíRNËMæwogh-)'!7yˆùî­ "ñ—»·ÔvåÍÏÐüÕÙæ*/%ÕR-ºQ´r“¤0ž¹vÉ;MÛ{Z1'+šÁ5ŸÕÔ¹"w{Šõk««®Mäª+SR ^i¸ÒÝ”Šæ¡Ý mòcfÐݵgøƒ2jØÆ=h$ý@íJÍ áLr‡é:X7—®XÈ‘¡ÃØ”ùc¤WCUÜãän†îììÔ‚ ?C»G§¡G/sô?Zr ½ë4uz%úPéžVBø”¡u˜O˜wÌЇQ ÂkRž’‰ 4«¯i×k¸3&iSW´&rÏ€|†„'þ05ày7LÒæÍðäÇDÒL†¯É0õœ–›w~ øI³PÏ2*]F=3ßQAëw¢ÊI. r´!Q”NØHªgâÖд2àf>CÀz…U‹`t“¦’ C›AÄÊah‹bâÓÓ'“z÷L sþ¹išáÛ¨'¤¦ßÍ&t§6ºÀ=™ªWÂäAÑšÈݯx^Ï®×yâSžwÃd mÞLO~ÜI$Ídøš SÁiuwwëæTå ø:Ѧ}”Qé2 \Ì]éÀú?xð`${ÓsÆh¦>·ÏŸ?öìYík׊àðòP±½½œÑÖ^^ÏqK«F£­:‹²Ç‹‹‹ZúXü´å••߸k±¨ º½Ù¸×ë•(zzzž~úi~£ÎHéA{BÖY>æ/tK[ª¯¯—øBóC˜ÆÐææfí/C |¿Æþáááúúú#GŽLNNšvÉ}ãü=áÌ>f7õèÏLÀ'ó„É(¡'RD[¾@'Êåx•ÊD´çVå ýýý‘ŽY8 OÚÛÛu$ÂTGLOOWUUUWW»å†9sAóóóMMM’H-b?|ÆÁëuuu ÿüóÏ“JMM a”:RhÏž=Ülmm5Á”%‚‘ M.çüæá@ZŠÁ¼¥sn‰S.ú=E–«pº0ù'~®;::–––’Ü=zÔ& "!˜P-‘¨j‰¸65#îÈ=ŠTçqš¯ÿ MJ+’NJÕGMŒa¦9)©S¨Œr¢’R!Z¨’|]šòÖÖÖÔÔú,T=66¦GDâÞ•ü™ ødž0%¤ý©îzÈîØ,JßOµ‰ 0ÑJnu^xL9ðéíí•ÇSQ‘O?ýôÉ“'ÍáÅHl-5€ó¸¦ûËÉ—çԲÇó ŠŽYqIH^„ÑýËñ4§Ê0"îô¯ 6mêó䂇DdWW×ÐÐñ“µO¬#íÅ5áµQ“"˜$H”WTKd,ÕñÍY  £Ü:ÑSר&~îkŒâ‡?ü!µOÐK5:!|uª[úHKK‹9`J±é4b E11¿:UTר3:€Å YèBc@'—)Ïp±ç](<…"'âлîïí9°’I 0ã0žðæT7ˆŸC“₱°°`ÓÐál£„rà®%wþ•¥k†qÜã9¦Dæ“©&Sòh†›Lºþ„<@-ÕÙ¦îŠ2ÙðŒ,ñˆÔÝz h^OZþûîójlvv¶1‡îÊ•+þØâ‰ .D…¼Á8®/?hx€^eÒû´>`ǽìرcæ¯Î¹â÷‰'žoY¨™c!ä‰HwFGG{øSAâŸMLLtÒV Oþé¹È Y\b"2|úôiŠÌM©n_™DBt`¥§–ŽØÉãÉWù·¡%ßMµê ¾GUUùÆz¦¦<ˆ•F˜«W¯R~. ^Äwcc£?B”ÂPS0“Š  Û‘#G :îP_T+F'á¡d^Q#Љ™úÌæD]­ç$²D»á«h(Æ$íy¾$ŸƒÌ™”…BÁ—úÄ@´Ä0(eT6 Èi=<ÕÀ ÕEAˆÐ]v®í^ðl@&i^ò­¦Ö¯¥äÍÔ’;ÿä­­­š¡6ÌYœîC9¹àE÷Ž KxK•ï·YÑ®ˆ–œí³gÏR-XùßýîweÙS:âÂóʤ£üÒcy]ê”NÔ>ÉiœJßQ_:ÏÔ ï+äK/½D„\ðë.xÂÑx—ûMŠš;¼7û81AU”Ĉ«Q+˹iÅ:Ž>(M×Üç&=W'='éñ½ï}Ï(ëØ\Co´ÌõõuÄÔsÏ=ÇuÚ݉ÒÔ!iH"¤/gà„tŸw©¿2ŠÜoiÍ?D ¡l÷£'Ÿ| ƒ¸“ BIÉ0ah-V÷,Y§Ș¬ôküÄ€TÏâôú¤¸#¿ógæèMOœÜĔեuí¨!›*æfgg'BÖñ(V!!6:€1"©M"mˆiæææøöÔ¬jPÅ|$ñ„jü1+üÆÆÆØØß„ø h:Èr¢ó[Ü÷1pŸ}öY’ã)ßXc8DeòoJ*E› «°$ ½=þøãü5Ì!/é`2¬müº­%å­Ï;p;0Q‘÷ýTPxQ‚NuJSÓWLê©@C(„!Wž&˜;· ¾­³+ôˆO å<óÌ3nÅŽÑr³k:„×e‹è%9ôOïiŒ]c ©¾—ÇPÖ¸BÒð´`JÊ[e2ã?òfÇvŸ# š>&8i]ºt‰Ì󥊿¦*¤Ÿ58GÉš¬n;P[Ò¡æ³qOnžx¤I(·îÃäÍ¢@Pk:ùÚ'9ê\ä§ ²%re]$œ'WÍ‚¤“ ,AM˜&˜{=  솑ræBaR9„h͵4“º'~smòïÓ„9é áX\æ)D«³šÜ¯x !-yj Ü)';ùšŠ¦$¢öÉ'Ÿtß×à$ŸÊÍÐÜÄf¢fôdhÒeeXiV3-O*IÊ÷Z\0<„œ¥766R“äŠiI„A´™ *ܧédå×=â`S“:÷a2KË7Lu=ÿüó”ÝÓ¨2¦´Ð9Üä'[YiÁ”ZÁסìÏ>û,**DK:¯ÚÓ ”Õvâ–rJ‡ÖIµÇŸkâWÒDK‡ñ,úà›R j•ú$!þ¢á†M…H}áêewGXWPv×bxd±Ø³$ 9¦øl6±ÈZûÞ£N!°hFžóÑ›p¼´@÷Þ{ï·¾õ-ìÚ—_~ùßÿýßÿñÿñ÷ÿ÷ï¹ç}ó›ßÔ¼ï_üÅ_üô§?ýÆ7¾ øÑGå÷«_ýª"üíßþíÿú¯ÿú£?ú#b¾óÎ;{ì±ÿüÏÿÔhößÿýßÿÎïüÎ<ð¿ñ$´gÏ.(RûÏþìÏ^ýužbò’wá'un*~¢â"á0™!Hâ;ßùŽ)‹Ö#˜WàJÁ‹Èzå„ä( %%i.à‰¿ýÛ¿…´~ðƒpç·~ë·÷y‹ïM)t~ªÂsAƯ©VSd@¡(¹z饗¨–ïÿû¤®‰Jª0¼®Íøðµ¤¼!&È›@xæ/QQ.®a5õOþäO(2…úÝßý](“‹ø‡Ð[æ“i‹uÂM²áÎaÈö#<ùýõ_ÿ5a( bøƒ?øêÿ÷~ï÷ø Ü¤zEU­£aIšk“I"¤RÄʧÒÈ9$Zj†hÅ|æcéš‚ü?öÎ?´ŽëLÿã6‘‚E  H4`A@r¶6k –(Db!ébѰÖîw×rB%³`¥9ýÃö º‘h°U²¶ ] Z¤Ý+4X† ²V • YKlŠ[$H‘ A‚‹MÐ÷“yªÓÓ¹÷Žî¹wæÞ{ž?.sgÎ÷œ9sžóžïK˜ßþö·äE¬o}ë[£££Œó‚PW„¡9}úé§´R ÎM‚?ûÙÏŠa?ÈŒfª4¶,øQ•ÌÛ¯$P¨?ü0ËÃt5™æ¨òCñlc%|é?øÁ¢­·|ùå—ôÙLDzÚö•Fn&È¿ážïªpW}T™ü3ÒMhû¦” hˆ´çûM‚ÛàìÍúD)¯1ú ë·]‡• ´Æ,½Ã òäÉ-–ܳ4«⇾ O $Ù¦˜C ›bè`5šbQMsÃXçΓ÷åÂ'èu嘯=Q[(£æ¢Ê]XÜâ”###ñî—‰ë|íØØXVù¾Pà2ÙHn½ÅejjJg~666¤?éÐG6=ä‰'hÿ•zXÀ!€]=н\¼O:88¤"!Þ'“o—›ŠŠ»’2B;?B$g–Í M–î7ÊQ‡ˆýàÁƒT'­™ŒQ§ œ Âdã)ø«““æ-ð×ñP޶‘/÷K^J°½½]áGFFŒ&5€ÎÎNsƒÀæÐ¢Îà íÔÔrê-óK]#•ŒRDØ!|ÅÐhå:nIŠÇ|èÔyj»çMd9 XZ{o¢HÉ:T'há _[Mu Mvoòóî „t˜åno¾ÆhÛTΕ+W¨(F$ÚiñÊ+¯0Ì’D9Po c¨@aø"cwõ ÍãT»mö˜šÔ‰¹ë&$Tq655­®®¾öÚkÜ9þ<ù’‘v8éÈ#[жÜa¥®³Èj‚ >ö÷÷ž›£££f.gч,+{>ûêd†#²zD)l“‹²‘vF¥É¼#‰äª—g„™õfèÉZš·¿FR×Eæçç³O*§À±'ëP…8qâDröp$|/w¶»Û(\ÓÍtÄ6y‘ I^‡ÖfCtAÙ3 EQW{Ö:´.tTØoÖ¬CÅ.£Co(„z“¡’7nìí/óM‘5ѵÃä© ²ƒ­dň¡åO:Ó:´ÒÙó9N[YíÜͳ­óMbb.(ˆ½´L0Ï7ø˜¶Ò Bªj"i”AΜ9Ã/åd¬Ä…BŽŽŽÚc1 Uöü²ÄµwQ2~á&µ€ÀüjÀ%Û\3 ’e R#M3’Ò…IVRI$dÖÕÕÅETs • š 8–ã×ÉÄ:tÞ{t#GàÔòžßШs°{°¹–Ž(íåk#É:ôž¿'Yº&ueÊè¥Ó¡é-÷Á_X* ïÚ¢Xî.l«FOUïÍ_:smžW¾4 ú”MN»2^4:4‰èE X ,vIŒ £së‚·O²ÊÈŽB‘u¬Næ¾eíC”dÂȆt!¯@büCSTJ^à‡äíÏrë3ûS)zµ”P£$Bšê0ÜiäÓ_y¿_RAiŽ7“î7-U/;„¡íÖÆ¸L/Øy98¤ã¹DYˉ᜔¨sVÞ•ð('²ïHo •Ž›ò=#ó\C-°Í2§åÅÏ\%œ¡÷üÉçÀ2«'×…––õˆêq˜SUãU&0©ãZ¸MѵÍ—Å÷%ŠÒ$/ËNŸ;H /3BòÞÓV‘„7½ì_¤­%®ªšz'WüÉb‰Ýh (È Â[__/Ü€‰f´w š<eéSKšJKK ‚cÎ|'ÝÝÝŒŒ`z2ššš"Œf×–½eýÛH’ : Éw¸¶¶¦9b[qq(_h)Äv àŽRnoæ{1ÛB/‘º‹G,ƒô¯¼ò ]Ê©S§[ˆè¯´„IŸpìØ1:б±1ÍsŽŒŒ\¼x1ÐWttt”» ÛA­.ÌF?]ØïÔ zÌÍÀÏt_0'Ñ¥ŽóŽäÊèÞ½{¼ÊÔ¸„ 8ePÄ@²v°#ÛáíÕ½!I$’}‘A븼 hOޤòæ§+><n!í9Q´g­ OLL8¤#M8˜›3333¤ËG‚ÞÌ8ëСC䕺ŠL‰3yvTj!£×_tHßuÁ©˜ò¡ÏÖj@Z'7ů&³.®ç;M’œÚi C{þ8Œî¥®®N“†ûåhÇó‡ò³³³Uö’ÙŽ®H0`’Ïé¡¡¡329÷Øßß_vv ÒØ¯×™Eèjqq1òìYKÑ©wtýàÁi¨úÕíæ/ÆÕt@ ¥Y£WMŒ¤`ÓQ6Ïÿ¨ì§JÖäe.>|h‚µµµ95© EÁ| œ_Aó ©Ã ì†ÂûYºcíß±]· Ô¶¶)‘B`ÄLn¶ðˆ•ùÍïôÔ¥K—èpêëëSÕkèyaa;£ü´[¢<_a0t¹‰ŽZ„Žvka¢ìCgôf i>rZäääd‘Îö©ƒË²› P/"óU@¨fûe¸}Ô,­§ÚÁØ;ÄFl­­­(R…L/pÉ•+W ›žG™*ëëë3@J6~‚‚›ÍÒòÁjjž×aï•-dJYÕßkƒ±©½;wîèô-ÂÓçÔÖÖÚ>[mci‡:Îc;TBVªuv>{ª%"Ù[ŠŠ¥¥%Ƭ ß–d»Üi£ð—ûÁ¤†Û±IþN±ÈÅ˾»&äèè(Øù¥Ó7ºÎÉŒv´@†Xž‡NÅÑ£G5‰TWW¡¡ÑHÀС££#³yT¥–––sçÎ1"tûòC¦ït`` 2ÓKq#uQ¬è^âÀÎÎŽ ŠåŠ+W®déu­¯¯¯¡¡AÔsòäI³ßŠ/qÀGE@þð]ÃB ] Yâká!ÂË—/#ÐÊÊ µ¶¸¸èVgªkkk===ׯ_G‡®m¯ôÈÄÐ2V·té`f²p}ÔG¦ŽÔN¿d›ã"\¨sáY§r®^½êùþà‚@©å”ÁæˆÞÞ^ÛMC |j¥AÏòþ ï FC=Æ·ö£+*5ôF³ù7|CØÒùõHöFìDdDË$„ò”‘-ƒ]cÑx»ÈIµ¿pá‚NSwɱ?àà>|8==}úôéúúzÆïqYÐ̉å·÷yæÌ;°VÖ„ÍÛ ‚¦5Ó"µ\û'$y–;`CBº/ïêê²íI´µµqSæ-ÁhìAj0u¥–IxRSxýŠ@+J[ Y©Ò@Y6>[¶ÔšGÙxÖ õö÷‹ÉV‡Î@{þÖq ßßßO‚fF:ƒ‡¶my™ vò¥IØeY__÷|%[› Y‡Ms:2ääœÁ#whØ¡2°±±Á7æùªvöÆ-Qåà¹çž y:99Iß-¯t&h6 š½Ü°uàØ1Ú•í€áÞ½{¹näî÷qûöm†b¨>ô‰:J/G^hi7nÜ “¬ì,MLLÀ´d“õ…´}`Ÿ’y ê„×$†††¨„C‡iþ.\]]¥rÌëƒÕtvÜóg¹¾¦¦†ª– ùÿ÷G[å=š­þ™œŒñ tªXããã4 Õ¹dƒbíðÚÑ)¢a”r^‰¨©9iÄÀM¸ %˜W†`ÈIDiሠS®ÁÁÁÀ¦i¹N¡õòHe‘.ÙIõüÖRø:l m {å}îxh2!k-‰µÕœðmWÆ(“~N!ÄnŠÀódrLyÆGÚG'}Øw *!û©Eº²;wî@ÃZÅcX¦– Ž¡Ë†–dÓPiIè,xÙè~Ú/³K£ŠBAEÏ?ÿ¼¹¯­çkŠP/ŒEezY&û¬‰CÀÜ'®Žhg2!–qWIΠ6(‘|0£YÂOè¬TÎôô4u"e”_M!èf‚Ÿˆ"•ÔÿÒ¥Kð:ueÂSÃ\ Â¢s+ ÛÙ”œ_É£34) 0(ïÔ¨¿âTj.D¶W_}•(sÈCâÚÝlKk_ÃèšúE÷•):M¡3Î#Ößÿýß“5£=½h®MâD§´4¢SQ™ð¦,ˆMîÔŒàþ‚¦è"ܪà@$ü”¤CÅ d§X仢 „Ñóø4æççÑÀ4­ =ÐÑÓÏÞ¼ySìÂ_¶örË‘†V1eEÒ ÝšWÊ:‰ñK§,¨›{ù^ŠDž¸ŽJïù/"°ý­R8ÚÁÁ¡ºpýúus¨UÌØ#CßÕ†5­wÚvÊ´ƒL¿  0°õþ†+Íû@k4þª###áë,9ák…'áàP è+µ›+‹¢Ñ±&ÐPhñ€­?[> I Mº4Û þŽîÞ½»¼¼ŒöœÖyT‰ÑØØ˜ŸyöÂ!‡îKp í'è{zzêêêâú¢*©hãããÆ×j–P¿_[[[TW‰f 09@ËAÕ÷‘w"gÏž ÙºJóŽ GrDØî#KŸu´ÛrC;ÄYìJ AÙÂ2KÑ´-9Ë3 ÕïÛP ¤& ƒ×¹n.¶X››1Çê„ch‡RkiiÑiȸe)JÑ@’‹f”û±±±jî÷e%?ß}ps„k©ˆ—›©–C‡eúÄ.êÙÎpa²—3PØWC;”†À*Æ_ByÍps’¥$}óæMcô1 v/--e²¯R8œÞ;¨ö‘‹kKºCi8ƒAç"sÇMMMÉY7r¨l$í´U*>|x F¸Õ9§dÃ=rFލN[ãÛ©ïÞ½Ëè$pžŠ!7é[öþÒ¦· Iõò÷Â… cÀSnÊCÆžod›(²€}íÚµ®®.bñTN¸)‘ÇNÐómnÛ"›ñbI‚’? Yp“‰f CßdhhˆLõÈHHx…$ ×ErÐ|°÷I‡JºÊÓùóçewzee%·ß™œDÅx~±bŠ–ç º˜LM ̽Äl-dÛYÔçŠ`tÁ#>åª:§’4µˆŠÒ |ûâÐ>Ž;¦;ƒƒƒ²°fÁ¦'™ššª¯¯oii1ªçÜÜÜØØ˜N£’ÊìëÉ“';;;í“ÃÃÃ÷îÝ#.áé š››©á¾¾¾ÅÅEÞ7¹Ë(w­™èÚÙÙ8sæLêlÐøø¸¬¦sÝÓÓC²Æ…%oìl{pÝÝݤ‹‘k2¥><ߎ,ä…HÜ'B"ùòš¼¾¾nÛD‹¥é;₺˜„X0H%³ `èØ‹&oÙøãJËÓæ^FKJ†Ž÷À:IËÓ!á#´X"¥ùþ>ä…“ûR.5ýf”ׇ>ÖxûΠÀ9딳8"*0ôfôH²'ʵæ0xÊ/×¶.Åʪ̞¥ÐËÏX OÓ#íLäB›ºÕ2˜ £ áÅÜÆÛwÛ¥·cméáIP"aL¹Š§CW d<±dr, L¢Ï•/b,Z? M6^RèY¤fÒÕ¢…[öμ—Ë—/ooo—æ¥ÂØ!1ý£|´^M¿ÙÃPTÛS§NÙqe×»¡¡•Wkꨛ¶cãSî¡P͉ŷØ$O% ÛN Imrr’Á(QRWëMu÷ö ÉÆ‘ ©½#î ‘nI¨cß%0ƒïºò!?0É¡gñDEòtY-v¨l„LqgD½#ÙÞÞ^8–5S»bß©©)Ï7§eBÂÍúÕ$3QdÀÞ/ïdpžìŸk¢›`rìhC0x$³nè»555ð:ZHµÀô$8(¼§§‡0üÊÏ)´··ÜYzûÌÉ£T ‹…â)éI€V§bYrÎ ôAq‹PÕE+¼…„ÌrWÌFNÐ|l&ä1óþŽ"œå&#[<û¯¬†Â?ØÇ¦MKÑ´kãîÝ»©Eà¾Ù·¥(fטIÇLeK £Àœiæ:m*ŒòôW%R]R˜ë¢®j–ûÐ^èb‰C¹ƒ8Ã[-±88èöt4Uè?~ffµ,ÓSúßhÏ ëänìçw¢Ÿ íÇÍrW>bŸs¨rD2ß[v¨ÂA‰Cäp ]ùHòR¨C„ØÚÚ‚dlaÕiy#ÓŒ‚ƒCöpÞ'+íííÆ8³úk³™¶¦¦fii)nŠ‚k×®]¹råÒ¥K œêdèPTc D’­Ë9” œ]èïï_݇ü뙿Ï?ÿ|ÜÒ9T#nß¾·¥FåÍíïîî2Ö/ÄX´XXX(\%B'ɸ–¤H0Â2:†®@d²_è¼Í;Ä…ÅÅŸE()ÊzŽéëëK½?009=OMM æ-çµk×òΚ2.ø ‘ÍÍÍHœ{’”ch‡ƒ‘¶á ¹]c± ¬+”õ"´l[ÊêˆçŸxöüõ2¸§££C¦Oí½š¨Óû:̾†˜ggg×ÖÖL‚0$ÂÓL;÷3å"P [6“8e Yy±ËžM¾©#cèÊDªíh‡QÖŒ•Êz΀ñ}OOσŽ;ÖÚÚzâÄ ´gnÂjô!PWwwwCCCMMTm¡ó—›\wvv666ò—`²@#’Bååe®{{{yÚÕÕ¥¼<_£%$)pæã¾lƒpÇ^/˜™™9tè÷¥ÍËV¶l¡xþa3¤­­­µ­Ÿ;wN]Ÿì¢x¾-îÉÉIò QÁMÙe#…Ñ !Œl•¤þmii!ýÈ—6CW,Ï)Ðñ¢ªÔh›!Ê7}LLL@~MMM÷ïß¿sçŽ,_>|øUxllÌóG${{{zÅÏ>ûìúú:ÜV__/ƒÌ@/tþüyuM$eš‰FO¸)ö%:é@{vW¶±±qôèQñÌ™3žo×ÊG&:lM:ÓÓÓ1˜(¯¿þ: ÂÄå½ð‹´¢êË>çÃóÐüüü¼2JýKÑ<ü§Íó ,y8Áº|h^;Ù˜Ô~܇ÊNDxÇ¥K—7þÂúEòíætèJ†{NNN:ºâAo–Àš~éæj@´{…’9j„QXWWWÓz\M }öìY9ØØÙÙ¡•ÒÌZ‰ÔŒùÈ”šé@À¯¾újàQ[[l û2N , ‹ô‡‡‡Ñt¹@«ÎµÔ²*Á¯œ`þÂýÈc¼#„Ó¡+f5Ú-qˆÚøS #År÷åUWW§…dé…æB7Åp¯Er²R˜)sA,®ûûû‰¢¸(»ÓÓÓ}}}4 h•$BRÐ 4Á¶¶¶ä»B˜ô^yå‚‘ÂÜÜœF>1{zzøà`r'YÔôz°¸Ì”+ ›¿º@Éiooïìì$…À_gÀqîÜ9dˆvËÙå®p8k½¥Aˆ]n:PuŽ• í ãìr;„ÃÙåvpp()´«¨²^˜@ëe ÇÐ%ÂÌÌLÅÛèv[2"„ch‡ ÁøøxsssrŒ2¦EÅCªÚ:”Ž¡*›››«««ÆiJ2122·ED5L8”n/·ƒƒCé°¼¼¼µµU¼#akkk:q« Õ Y´·¹¹ÙlH.Þ~òÊXhg!à …$²²²rìØ±$ìD¦IÔ××GûÒiÆ´(;ÍC‡Š²íÚ1´ƒƒCI1<<<::mšÊìì,y ¹MˆçÌ™3½½½‘›bäQÖÆ>  ç………Èë'²žåÑê,1«”¥­­-ÚâÐØjkkI“7^Ôã n–ÛÁÁ¡¤j*˜t._¾Œ6SSSÓÓÓCw‰¢|ÉÇÝ»wï[ÐÍÓ§OC?W®\ÑYØÁÁÁ½8gcH²,077'·T,õÓ×רNµ3â¾Ý’kêSn3x)ö~ˆ™™=òüÉ Ò'®©yÂs³³³S°¹O`RHm$ÊÔXä& !e¾›Dça4\köÁ} É •…7½ý¶¤è&Ç––ÉÉËU:### ïîÝ»çùgÛÚÛÛÉE2¤­«áÚÁÁ¡¤PÿXx"ôè1Ð-ý#zÌôôôÇQÅ.ûàN³ÝT˜ÈjÝq‹ÂyZ¬wÕFƒÍÍMªˆŠZ]]åMuuuÔDê“gÏž•*¤ìWS¼.:::¸µµUþ-tþ[iÖ××;'Œ«vvvxJêªVv¤c“%yñ”·¾¾N‚ DÑ[æõ!3p}íÚ5‚qM\dŒØT àâÅ‹PMa•”½ÿùçŸ?þ¼Z¬l}SÞþþ~¢ Æ;w>L.2wš¶® ÅžCÅ6gT‡~æ/â–ΡX o¢?â7–Üs²Küøãç½-Ú°–ùåš;ù%µ´´dfV¹àoÞR!FN/c´õ¯I‚¨’’“ „¹ôWuΈ‡W™zÇæùf¹Ô<´ñîÝ»5óÁôë&éŒŽŽš02f$œžž~Ñönܸa;]È^ª„r‹555Þ¾mí••©ž?Zòü*µ˳Åää¤îK'6QRnýþûï+$Yð×<Òþ5]£ïËÛ4™û63pHÑ7©NùÚ²wÊHW922ÂȃK{ ßBý&ÄHØÞ!.0ÎbÈ©fDÓyðàA6±F`9x!zêÖÁ!WäêÛ'5654·Þœ p³;{öl®qsU ½rÖ¡ƒ^ã{™æàíðr5úWÅò—ùÕ|rjÙÕ‰…¤ÉµÒ·ß2ú«nê¾”]M7 ïù*8aÚÚÚÒêÐRŽyÄpAáûè>lÙÔêöünÓÛŸ*Pš&d35«J‡v ]–ÐDŸ–@à×¼{+"]ë(…Ì:8äá}/'F1 =„‡üŸÿùŸùùùëׯÿìg?ûÏÿüÏ«W¯Þºu‹vþÿ÷áóÐMç¡9%™¡Í:´„46@­jÕ,5€î˜›\5€ë´uKå›Ô´Ë/5 ÈÔDW²ú+™í جC+}û‚vb‡'µ´JŽY9šœœ4Å7ùªhva#y bhç9£Ì°»»ËxmllŒQgS|%HÖ¡zçŒä98›Æ611Ñ××Ç<Ž›)Ø_|ñÖ[oi®Rxä‘G¸©ë#GŽ0}â‰'B2Ò¦3Ø^__ÏF¶žžž<œY9Ïápž3Ê:„G?ÈŽO1B%)Ô¤ YTÌ®T‡$ƒqaooïÁhг–3CèyyyyddĦgÏçlsýÉ'Ÿ¼ùæ›°©}3€£GBÌüBÒôʦÍqW¤CÅÂ1ty€¾¬»»ûÊ•+t@Ú-YŒ\ÄÓôPdDvÎ~ayR¡y”—c%è-ü¤J­˜’f²‡ëÃ?„ÈC¨×€*B# ÀW@HZ#ƒðÔ²aq‡¼áº @OQWWG÷´´´T‚Ý×Ð?‘™:eºŒpíÚµcÇŽñ· ¹¡³³3ÓXû'Ožä÷Æ]]]™Røì³Ï õ‘Gikkƒ_:::3Ûüqø°’^\\ä.ŸššÊŒá¬LU88 Ž¡“ÙÍÙÜÜÌãhJ! ;2E™>Ppp((ý™ÚXoo/O,†LnHÔÖžŸzê©¡¡!º¾¾^Ç^~ùåÁ¿óÎ;ðzHš:JddH ÇóuÄ]yEýOyÍÊx¾å………Øeˆ¤ÞC'šÙÞØØÐ „Ò @¦(ÓžoúÎÍx;Plêl–xi„fwZ@´èÄæ/ôüâ‹/¢C‚8q‚ûæ/ŒþÁ„KuôèQ RÍyò9 úÇ]m¥£"yKCñ(^»v-v†F†HêÍ1tB±¶¶ÖÐЀ"Þ=•pé񴮮F7¡çP<ôôôtŽsçÎy~O><ýôÓOí¿!SMOù0u¼5ÊB ñGn~9Qn`ïi0æAÒþ=0LÚkF?f7»­PÕä›6‹@H$”a“pÙH4íˆ0f‡Bš(©9Úqe–\U”IÚL²)¯lÔÇÐI„,ÑŽŽ¦nY±Í f,Y¸úÛÕÕE:h!ޤ2YÈéO‚ZrVjÚAöøã‡Ïo{I´GŽIÕžmØ ÒjO èyhhÈûËa‹‹‹žvö¨U´ ³§áüùó|ûííížß5µ¶¶ò·¥¥ÅŽÂ_ñ( ¯ þj£¾ýȾ¦JIŸ7ÎMù>ÑQ1z›ÎÎN²/###5>4ã‚„ id#©ÔnŠ\hZµ>ŒüˆAÖÐ$ÉH…Z 1ˆD`o!ð¡C‡øËðz¦pAH b eçK½‘/<Ÿ’í|‰588HAˆþ.C'¢çLÖYPc 9I7GÛ¥e.ÕÑ£Gé1I; ´vííÒ_M,ߺuëÀˆöñªð³ÎžÏ=æú³Ï>Ëfï7ß¿X d œéª0ܼyÓó c©oyíµ×Á»ÐÌÅ‹¡.lnnÚ•°¾¾ÞÑÑÁo}}ý«¯¾J°ùùy±šýȾVDXœaéoooË 7O:¥Wª7O¤bÌdœ[ bÙ1ívÚ‡’/ÔÈSñx•H²—Á*iŽMOO‹Pu>ž¿“““šÚ¼ÿ¾v  % '²mll`xxØÎWE#ß’cèdAN`4l¬è13Í:´ ͳÏ>‰lޤººŒòõH³§ÛB5Ñ<'Í;W‡Á¹žBÌF⃩©)i`ôªUeÒǘц•yAŸ¡ÿÙ³gíyþER¬é%¸&ŒüP™G;;;öµ"’ÚsÏ=çùÓ:áfrämÊ_–ÁéÓ§©ÿ·ß~Û–MïÙÈ7Ó‡IÊD6:Xn"ŒñÁ• mø'0¬OxZ#M­=`ƒýîÝ»4 ”ãÀœ¶[6Jí|5Q¤>ÄD¹à®Õ¹;:½ÑÑQòp­¡$^¿~æ¦íe"Øùæ´ìèt衯¯6‘k¯œæèù¬)UCÇai¦p0F]]¹ãùK8Znáó;tèŒ6(ŸQ4gN°ð¬I !¡‡b@ÖBÔ}‡L@Ïo¾ù&cø‰©l@"t¬ávÁ䃎uzzºâéÙó»”K—.A9ÐISS“[2eÈ£ííí€öÉMmþbO­j¯»ôHóH×>èsè‘änêå,--QÕºOH]hÕVY¼öÚk긠gI@¶ááa’:wîÚkØ\k1Øót_È íQ?Î_5$Ô*87¥É ÓI“ˆ”ell ¢Õªæ‘‰6ßþç>räH¦§tÍhNô³tÜ5”•j—›ÎŠÞ,Ä^M$H`í9»ÜÉ‚´‡,3“+bÁ”£™¤#Ï3öÍùùyZùíÛ·µ´cÏ_AáŒpÍ7Í)†–å>¡êL ÖxMqGNÏà£> yª¯#öS¶UôŠbÓs’áÖ¡“8/û•ÝS§Ni¸÷þûïøöñAèVq=hÐ*f'dÞ@TF…ƒA¤z¬ÙûKUQÁL„¦…¾© >]åHìþJ§C'¨°9m[Õ:tkk«bøòÀ=Z¿¹yóæñãÇu§À-Ù|àYU‡Rb||Ül³*_loo{íqýîw¿m¦GŽùæ7¿F$í2T$»ËÒ1tü eäêí`aaáÊ•+:,HôlÖÆ4€ÔÍh1\iÈ:\K¥9¤bsssuuµH6Kít5Ò¢­­Í¶V ¾ño0Ö 7uâùã`Ïߥw U#¢µ:\²aVá¹YîøqëÖ­ìç·ïß¿o®uJÊü…zOŸ>mwmö¥¥%½®®Ž(´úqyª·£(ñì™±Qâ gzujŽüžxâ‰ÀÊñ'Ÿ|òÇ?þQf%hÒõWe“îgŸ}&CÜ< Xxì±Ç é«­­õ2Ûw¬H¬¬¬;vloo• p ʤ?ÉtJÍD,$w-ÞÑÚÛÛàæÍ›…òœ˜˜ ‘ä´),µø‚ôgffè] ™kt 3x…9Ío‡ L¨ Ü’uqÔGj€<,’EpNìbìûöÛoûÝwßýáh¶g¿÷Þ{:¾óïdCÉ<÷ÜspCRóU ãÙÙYJm³ãÆÆ7ubpŠØ$HmË®ùðáC:2 ºÉ¤RHX_®³‘D©©ø¹2´pñâE”¢®®®¼ëÇÍrÇ Z|ÙyóMÅä䤳^â¾øâ‹Ÿÿüç¢gëS>ššš¸ÿå—_š`¿ûÝïÌõ;ï¼·ÔIL†¨= š*ãWV0›}#Œr ¼/XY›ab˜¶&Y…¡ŒÚEÛÐÐ }û¤†xæÕ˜(hÆ0±î“  \Q@„!˜½jŽ0Û¥9Á1tl ‰~ê)!w¸¥¨vЫÒdi«(±PCÊþ\“zÏo|ãb_ƒoøÐ5,îù¶eÚÜÉ 2W@ Ç]CE‡œAAN)ej ««‹G0¥ÔÐþþ~ý©¿ Õ®ƒ­å¾ …’ôQŽQ‹ù• kŽŽŽÚ6 *®ÉÂȆ ÈFHh{zzª–}…¡/"²#$iÚ~$=_ñÕA¾‘‘$!$a¸)™eM–…ž5c–«5a@`}]÷ pæÌ4鯯F Cam“©&šCdžß–*`º¾Ü¡^Òôee 1tö;ÒÅåF]NÅ'Ÿ|òñÇsñ½ï}ÎÅþ×ýWä'ª+Ò_Sï/--¡FCTiU kÊ?=hɺ€ÅaAÚ*¹È°Röã{¸Ü¶fˆ¾+Bv˜G}LNNÊ#ªírŠâKÒ+˺¸Ù- ¿rGQì]Ò¼˜ˆÓ€Z;‡ž!õ€À(Ð…xq h@f(‡‘i% 8âEö[¦Õ;úé§™÷Ýwß5ãããøÃ<õú÷¿ÿ}N"UÏ,·æëêêdØ`bb²¹zõj`ÿi{{;äÂÂo0wîÜ œ2¢g`à¨Eb«ë“éT ÿ&Á´² ‹&áQ”Ÿi¦XQ”…œPq …Û>#b&À•+W} ‹D)/—‘Q­gó«÷N‘ ¦ðDD™Æøž–_M hóÅÏÇ&]~È ÒzÍ„ .Ä-oÌ5@à¸åuH"ÔŠlóóó2|û /¨E=ùä“/½ô’nþèG?BµBiþÉO~’é 3ú´C9J%¦‰»zÂê-ÚoêáÇ÷}pÍïƒPÉö‚rxÊ…D¦~¸Ã¿¼ÅM­CPâwïÞ厮MRv‚‚IJëÐ €6¯(ÜѵIЏ C,²È0==ð¶<&kÏßôj‹­Äí²Èš²ÉK÷Í…$áW’+e¸ŸL÷ü›Sý“&mØyΈ 9yÎàýUÞÂ-CÈpC6œç ‡´OÕ½ÈØŽ&ßzë­?ü05Ì©S§P¶´qé?ø9yE`­CŸ={…‰/ñ@£Îs†ìÿC3¨¤½½½:ww¡óº¬\ î:tRŒvŽ„J;wîœG\ç9#6ðW={¾†nNÙÁá@èÜ­<ïfE»¸ù¦ŒºŒ~ =?óÌ3šâæïSO=õø>x¤Ù»Í'¹yÛ,”¦½Ó«««eí%80 -_–‚ŒŒr…Ó¡#Cö:4Cªœ¬””ä:0›N‡ŽPÚææ&Zc¹ÿtøuttT;{ÓÂÖ¡mìîîæJêÐfr(ǬqA*WöþñuN‡.5è*•ž=ßÄX¹ÓCùâÚµkÇŽ«€MõRUÍ–´ÐöìTäÁ Ÿþ¹NTgÂìì¬ç+‘‰¥gÏ?kç¼zT´YÒ1t©îø¶Pî§}bGWW—ŸÛçjlp?ÜsN€žÃGÒ°þå22®¯¯w$]1 Mööö:†.5*ÆJI&$ÖÓªC¹ÀX©;wî\ÚæUT@#Ï´ì=33Ã#ø/dÊ=!` Q3(žå?Æ1tIQ “À°Ú\ 8D²4$tå´»ŸÂ'¥óCÚ­ã»»»qÞ¸q#î*9¨\á“å‚ÉÉIÍÙ8†.)>Q’¼åÕ¡,`œÊ¤’ÉÃ3ÕH»Ãqxxúĉea_€Á±s4WîåͶ:†.)ª„ºÊ¢;sH8䘂D5 <мé,VàæÚÚšNg\¿~=îÊÈèún™©ÜÁ¸Ð8¬t ]: TƒÉ@ÏË'y×k¥‚®ùþýû•ÔAOOOÓ¦|Ø÷!Ô—_~™.¬pešDÚÚÚ^|ñÅÀ}ô-Öœ9s¦Œ_¨8îcù‚!) ôŸ÷Dh%®Êq ÍK>ø¸e,œ-pV?²Áää¤çn†!‹ ±²±YFã©¥¥¥¸qÈ>D½¡Í›;N‡.ªdŠ» ëP< Â2˜“F[²£D½½½ËËËô•wïÞ»rjôÊÊJ{{»;yUvèééikk³·+9†.ŒoÚj@M :$rÁ»µµÕÜÜ\lÖa(ÐÝÝ=55…:77W¦‹5ÒÃøI—>|8pjà‘|S‹_|ñÅG}´ºº*W3ÆÂ¿ ±Ÿ|òÉblòŒ U²-âÕÁ!º­ÙÙÙÆÆFs%rПh@‚ö\Öm¸««kyy’žŸŸwÃ儃†×ÚÚúüóϧn (†–ÝŸL¦þ¼}ÓöGŽ9}úôO<·¼A”õמšššäZÕÁ¡@@™7oÞ”é{T\¼x1Zúïé顯äS-kÏM†1šÈ«Ë!*0¢ái¢(õiyÌr/,,üô§? ¡gƒO>ùäÍ7ß„­3¹s U8Œíèèˆ[„ê‚Îó· ŽØÒÒLO×ÖÖNLLD’,JsKKKww7ôL/ ýW ™i‡]CCC]]µGã–ÈáÏ€›ix###‹‹‹™¦…’ÎÐío¼‘Ö‰MÓOÃðPÞ@¡Œ[„Rƒ~!nª (Lf¨RÁH—¯›_Ȧ¯¯âÉd»;êKcc#‰@fÃÃÃÚ:^a8{ö,­bccƒO²µµUvLãªzÓêhºçÏŸ¿~ýúôôtˆ¡ÉDÏrC±cccùiÃ(ÓÄíïï7nÛãEYìm¦Ã¢«¢ÞäÃnggçðáÃ\ ¯ ?£¼œL–VÕÎ8‡’áèÑ£hÒ4ÔsçÎI °ÏøÈ¾}ÒKÒÎgggµ—ehh¨²ç)š¶ ­­­1 1út9PÚÜÜ|áˆ9›(Éehˆybb"=sßxk÷|.§©ÙwL ÔEà~,ˆÜ7x´`LF"/{iA688HxëÖ­,gì$Æ],‡ŠP<­“Q€ö yÃÓ £Ûô£Açêê*ÄL`ñ“ÂW67@‘/ûÐ_ûáÇq Uù ÿÏo+RüÔ• ï¼ózpàæG}ôöÛoó9}ýë_ÿòË/ÿîïþN*òÏþóoûÛ©z*Ì I¿üòËq—&Ñ;Åø\GFF²Y£‚ÈQYºººdì)-C+L}}}6²ŒŒ|×GV¯‹ŠžžžBLiìúúzÈT!ªvÜ¥¬"ôûˆ[ ‡ÈÃi«-…aúðÃ?øàƒ­P¤øÌ3Ï|ú駆Ú?óÞŒVý>úh&‹‹‹YЇ½°°Oóաꆙ¨‹ÍÍÍÑÑÑ@°´#ãÿ'Üvn‡¼‘­šø›ßüfõü‰åÓ§OÛ˺ ><ß­úÙ³gíÓM7nÜ0ûš››Q¶ Ôl ¤éÿÓ?ýÓ/~ñ ?øÁ~÷»ßýð‡?T¦uuuï¼óNÚ)å>ú(§¼ÄÓH‰>4¢’ƒ3ûެ5AÒ333öh¦««‹¿!›ÈÐÂ'&&xïq—ÉÁÁÁ¡Òp0ñÀUãããf[5õ«_¡9i·Ìgö7ÞÈ”N®VGÒâ‰'žøÉO~b–йx饗̘nÎ4ãú…\‰6ZžN¤«%LÞ)$ÝßßæÌ™†††k×®=z´¾¾ž¿}}}ÄBí¾ÿ>,s›IrîÀí¾qpppˆPÄŒ†”:³ý¤qQ„ÞgJ.”²& äg½Äð4*{È|õçŸcؘšš ºpúôéS§N­¯¯kª£±±±­­­¦¦ÆP/|öØc&î§Ÿ~ZTSwîÜinnCþùç|ðÒþò—¿|饗Rçª@gÏÍ… ÕfðÌÌÌñãǹ¾wïžÙqMÈ–––LédcJ)¤=ßfìàà ú1lm¶ÓóÞ!YsÖ™Åm\üá8|ø°Ñ›³_„. 7{™m†Ìú(jÖ¶÷ñÙEÃró'#M¤24_2ªÙ2ìˆ"•>‰GÉtj6u'tþÎ;ïää0 ïÔ©SÄ‚2e´D -ãb<…žçæædÜJš4$ý/ÿò/Äúýï/}:{z¦,%Û¶ «mll” £€W~6ÚÁÁÁÁ!'”úøÌ×å#$ÌÊÊŠÔ5X³±±ñ­·ÞúÎw¾ü /<öØcÿú¯ÿjß„˜=ÚæCwžyæ™,% ·Ñ-¾LOO÷ôô$Ó³úÍ›75ï­¿÷ïß?vìõ“öàœ›âvpppˆ9Ø+žzê©T]ó[ßúV]]ÝÖÖÖ_|ñå—_šGÜ ¨È„üÃþðÙgŸ™Uð§Ÿ~:Æe²tæù&A‘Ø3 ÚvöÖn‚5Y(öÎ,²¶³€ƒù›it•LÛãå‹$šàÐ2°­¨Õ××ï{ß;|ø0|ö‹_üBJ'Œõë_ÿúù矷S€°ÿú¯ÿš`_ÿú×ûûûÍn²¸~ "\__ooo—OžÙÙY›•0{Êlf²@üè¯~Í7|ÿ /Ä]  ½9Óӣƹeè<{gÏ&…¸í™aÁââ"ãCÀÊ‘;Œ61f’ƒ¿´Ç¸ <#î÷·‘!‰³ÜžO«ö™àB€»µÎB\Hå XöáÇ{™‹¢ é¢~¥¾žœœœ˜˜€¼mnjjÚØØ˜™™A¹WÑ2-Þ's}ÝÁÁÁ¡,P†ö|c)âŒK—.åȉ'â]ETpm@Ó‚q©êååeäDW>yò¤™)mllìèèà¾=Èàí™`ÆúÐÐPÚ¼J94qppp¨0$—¡=Ÿ_ ÙYMôðMã¥D&—š±àÚµköß¾¾¾G}´»»B½xñâéÓ§ÅÖãããÔ?4¬cTš²æWǸOûðüzNkk,Qㇲá½½½¸e8}ôÑÌÌL®¶É¾ÿýï—X{¶-w¦âþýû‰:ÔÒÒ¢Sé4€C‡’ÔææfÚåO¸üرc™b9ã”áH´-<õÔSCCC(sY.'C„?þñ“0¹mãöíÛq‹ð˜žžÖ^°7sݸq#Óî$·‘»Ä§ñl½988”/º—;(¥o¶ì»ßý.úô»ï¾kœUÛ8räÈ3Ï<1Ç{°*R=RÄ‹£GBÒÝÝÝ!jîèêê²=\à6r—òHÆoÜ‚888Dƒò`è?ÉúÈ#:ôÙgŸÉ³N {¾WŒü|?— áž+cü:99)ÇYyD?sæ tH€€a8‡œPN mð ž4nY²E2§|aÙ“'O2èÉ•¤³YEv¹ A¬CW ’ÉXGÝÞÞ†q³´!zúôéÍÍÍéykkËíåvppp(Ž¡K‡œ¨í¾¾¾ÉÉÉ\=¿9T ._¾¬ ô±±±±ÎÎN¨zhhèĉY¦à:6ð'Üeö˜u‡¬*(Ít²h̰òèèhÜâ8” Núð|ª–2sëÖ­lÆÓn§Xœ¨Œ­Uhq‹ààPDðÒÈP€òŽCón¦¦¦Îœ9wQB.,,¸ @‡ŠÄåË—Qe2}†÷ïß×ukkëÎÎŽ[ëqˆ ]]]CCCÃÃÃÆ™·çlnn¢S>xð nA€xɲ:Ú×ÔÔÄoÜ‚”1P‘iÞüÒ¬IñÙ†Ó<Óã?>::ššìÒÒRB’ £„ÒWŽã‹@-Ð4*·—;Aà3žŸŸG“?Ã#Pô;::œ!âd¢¿¿ee¥‰9ËfrèâÅ‹ž¤õÀ ž¼¾kFN©æ‰Î;·°°w¡½p“½‹‹‹q øg”¾o,qŽ´=sfbæëÖ¦€'žxâÉ'Ÿììì|ñÅ9·8ÍÃÓ`œY%‡ŠÄÖÖÖßþíßþö·¿}䑃—ÿz{{¿üòËŸýìg|!ÁÆÇÇŸy晞žž_þò—„çÛá jll„öÐÖÖöÇ?þñ7Þ€éëêêá§?ýéÉ“'ß}÷]‚Rƒ->ú裉‰ X_ÿíßþ>~Cò¿÷Þ{|§<"ãïÎÎΛo¾I.ãïÔÔÔ½{÷£†‚üÇüÇçŸþôÓOðÁ8tèÐ7¾ñ åHàüÇüì³ÏH Á—Ø‚!’S»³"kÒG”›5j€èˆ][[K²v#$€ îSù³³³ï¼óŽ$¤8Ä%VMM Eø/¾ø‚dé'í¤È…JP­š×GJ¤ I•VO),ï…¢‘2‘áßzë­Û·oócçXšvȰ†þÿïÿ}õâÖéÒ%U‡äâäÏxøð¡62Ä-ˆƒC±0== ƒfòîÝ»êLœojj’Ï1k{{{ÏŸ+æS"£K—.ñôþýû|ì\´È}æÌ™®®.ÂNŠ¿D$¤çÏr£i™¿ˆqóæMÒ¹pá7• ‰“ir—––¸?=Œ\ÔÕèII0t}帾¾Î#^³ú0=ƒ(„§„ä/9Æ–Ó¤¯`ª³gÏžöA2"M…T‚ü%0„¤h¦\›››“›ä‚TZ2ÐRI!³É]¹ð—ŒŒ$$K0[Z“µ*œ_nªÎ©^Bêͪ*¨:;ÇR6E BÁ¿ª¢Ræê=EÒ|'Žž*ôÑtÐY†¤ã¶é|~~nà7’Îâ´ú•òK×ožòˆ›|bð%Ä ¶à‘¹dˆF‚Zk¨‘Ô§ &ðžÏFpìôM‚ÈÀ}îˆãKãF˜4÷üÁº.L¡D¥vOeÄÖÈ€èð¹£(ÚËâí/¨ëB)ëOëëë¹ÖÀB^!íÜÉÅ.¾ûRKE¤¥ÒÌ»V² f375x %²i¤åÖ¡ ¾½••ZIìF» ±±qnn.ù›ÌòÆîf’ ˆÇܘ˜˜xõÕWSÃÓã777Ë[¥VÇÇÆÆl E¢Ru´4ÇÐÉ_Ý•+WbôíȇAß!:îúp8t:ô°eíˆ%F,//Ó-f³GŒ0|гíƒrxxúµ×^K /{逨££#5qIjuuuËG¦L‰ÛÚÚjv Éžsww7*& booï Ô¸ŒõaCŠDÔœ¹»sç±àÅk×®i#±‰KšFøTïäH¬™™"B¢ö#·´´x>ëgÅ`ggzf´ÁŽ{÷.0°hhhà¯Ö¿IÞEa80)ÂóH†•Y#cõov’å\ñAÙí)Qø–ºh„_©g¥×ßr_>ÉðC‘ƒìÈÔ^ÔqH84ƒ§K‡\qÉGäÉÂyJÙœâÚ|Ë<åšø­[·Pgù…<$÷Så!¥¦ѤÆ•‘WŒ«`š¶E…5§¿¸Ï_î“¿\×uÓ–Ç\ÉíðJßIíÉ;Š ¸Ðä¶Ó_#•¢kRÝNJ5™Z]&pª´¦ºUM² Äâ—1™Yž(ô¢C—h¯ZÉæ¤fáÐbL~‡5â‚cèB€Š™ºYÐ-]—`aµØéÇ…oÄѾ›å.h1fcc£¡¡aff¦x-//×ÕÕ‘Ùe³&çàPXYYI]ȬìììP4TLý­©©)ÄXo6(vúq¡Äq´xïºlðè£Þ¸qãÖ­[###‘¯ˆ`KK˹sçÈ‚ŒœEO‡ = mV =ÊߢæXìô«Œ¥¶¶¶œ]î2zíÒÒl •zþn‘®®®BØtwwwvvV»7¯_¿îôf‡êÄêêjª…‡¸ÀX †v:tYB<===Ípµ¹¹™žell,'ët& ‰¾¸¸HR$èè١ܱ³³“wÜϧîÜæN$vùºMây§¹°°0»»5€¦Qb£–!U‘Lóš‡öü…}‡²ÍnjjjÑÇáǵ1$mÈÛ·oÏÌ̬¯¯744æÌ™3Zv(Ð 677ëêêªùÒϾýöÛyÌ:TêÎÁ1#ã{÷îíîîž={V7s;v¬@Ih 4Ù¥J›&Y§õ~mÐÛÛKMNNNÒ]ÐQðáÜukkëüüüÜÜ\OOO}}=¢mÅFHõ–¾Dr³Ü•™»“ý>NF¾f7Ù;wø=uê”þòeÞ¼y³š{𠆬KÆ-EüÐŽ º,Vmà?™õ™ñåf™æÀÀ#utßááá´4|íÚµð :cÿ ™™H-Âk¯½Fî(ýýýŒ!ô²¶¶F‡644T  ¥¥;~üx¸Íö¬÷v‡â¢H§<’ 93èêêÊÒ@1:CTdYÖ‰ä7nxþú¢Œ<Ëä§ùBeg[¦¯ñVGG‡Lâ«8„—QÏ·s²çÛ…JaÎ=ÿ8¯Ìmò«ó»:a%[ÙÊZI¡È£+ò»•*2J ”Uj—Q;œe¸Û$ÈM% ñdæÚÁóížê¯.öücÇÆB¸ˆ\Âè¾a+â–Ñ[ þšèÊÈá…9{mª×ލú4÷E°¥’ä²NÁpAö½e»T&] FvH299)eЛÄU?¹¶ÇЕÇÐÕÙšä}Á 4蓃C ê7Ã#©3”Ñlxè¸y†¶m†6V²E\,--É$§n9ɲ´èᮓ#LM­aíí3´ t—2~I „‘Íä«d×××mó#²Ó ydyPcr!514³‹ Üeܜφ¡½=Ÿ#S…Q'&[¡{>O[ßÂÆ6‹Ì¡“É’ŽÆ+2~b¿hÕ°J¤û¦žoÕ–Jq¹¡½Y-)šŠ"°ñ\"Ó1¤À‹Ð'ׯC"n–ÛÁ¡ü°¶¶F/¶ººªCwuuuöY^³d¸³³377·±±C?ÒÜÜ\àÎÿ2ÅŒj ôGu/^¼822²âƒ·0>>ÎIÝ 655%MNïŽ Þ¬ÌýÚ¦³yï»»»r%)%½\Ö:mm˜û===žß´7Eá‰Ht3©.ká´¢S§NQ9™dä}¼±±Ñ^&Š£"PXmí¶¥ ÄÕn\ÛÚ¹g-ðs™Iœ¤´Në9£;É›å® 0NW_`[uÎôtC𣋻XQ]SÞS»þlÌå¯34öœµ$ k‘è¾uhî˜ÅZÍËK´–¢ L,R€¥m“¬¼.rŸ0ÊKc²–ÊxëÖ-¹O6n¹I:â \ÄCÕK+›™š6ëµÆ{´ê\„­WäѺ8²iªÙt>v¼t³ÜóóóH®5õ@EI6-åj9™\”&Þ÷üYnîËw5õf²6Õk¯…Ûo‡ÄÍÌŠÒ±‹€TZ‡V…x9Cnœuªá©†5gŽ$* õ#áó›åv ]áp ]î7«ï=55uïÞ=DéÐÚï£QH®»gØegg§§§‡6Æu¸wêÄ"ûhÑ‚osddäúõëÅÎ(qg´¢…VS’i.Ç!³³³¼8cË¢xØÚÚb«†+/¬­­1È@ Ô)[m!Î5‘¬(`šr|㱃zctkŽ;ó1Ü1³èQÁY,©LØ›µ9¾Á!z‡b‚¿µµUÛ»JcDžF ÔÖÖÞ¸q£Ä>| ÇÅ‹ÍØ¢ì„Žžóõfw¤Å3TÃÆŠGOOO&•2è·€:ØÑÑÑÖÖ&ë¥ÏýäÉ“ÃÃÃ%PÜ£R  I§uhÞW}}½cÙ$ j4mÒ­CW Ìá¼T”`áÄ!oÐá2„B—…ž=ùv}}}||¼··7îÊÈHÛßߟ|–âµf?}511Aà††~‰hŽ 1ò®««3Áºººd´$J!p¦HÐéê3­Ž¥M-.h44- ¿,(Sù­­­r2488h²£jjjÌ),z]ûZTp ]ñ¹Ôû'|Ä-CzLMM¡:///Ç;O«$ü¶´´„tßɤeŒu$¹îÂëëëÓ„[·nqM ™ÈH=›{ æææRÏ ‹¥rMpcc#×­-´¥L¶P i¾úê«Ù‡Ïu`Ax†Dõõõ7oÞdÜLÁßÿ}=š¥Pæ¸9ü][[yÝ:te‚]êD·S  è™.Ï6A,³ ž?®²Ç樌ô×m>ìd2BžrÊZfLО•#ר¤tFRãèÁ®žRiIwöööÒ­×5¼¦õõu#0•OoÏ@ Ô¼N÷z~¿/8žÏôD§1À Z«¢  ÛéÕÃ"\Û/K÷5Ì:|ø°”oùƒçµòWÛ¹i{¨†ÈýsM:ÜO­ÕÞ(“ E0£"Šý+ñ¦¦&2Bõ§’;½ª‚ŒQŽŽ~uøÉÕ¼¹C0ji{{›|%5fJíùßÂêê*š äG2%;YÓãóa4#ÛaªÙÝóüa1yFvCCCÜQÊHnÂËC Ž/Û¯;ÆŠ¸=$ÓD!"éë¶çoú‘lÑÌxÇu˜Ì¡Ø¨ÑæèžCÒ@?ÂÇ8¶k>o"6P—zÆ]}ÇÙ³gsÊÚÌ‘Ò?Ê¢µ}¬“'U°DA1#Iª¡ÌVÃ2K@ÒQƳ<#½ŒrÓrà{¸œ\h½òáÑï#mEÉ­Ú!ZøØØX¦ZÕà=•Xöý«W¯Rd„äÛA¿èC¦¾@ûMØá5yàùb{U‚èi}ƒž?^öÆ×××) ye™dËŽ¡+öj4½p’g«t tL™dõ¿ÜÔ°Å/ЇÒ/›µ=:µ[·nÙ}´l â{ݱpj·gI'vã˜üaÄ-E>д0&¤Å‹3÷ùNyïv…óÊx_°nÞ¼‰–Fx›nøèîî¶YÅýL5^SS#í6­TßÚ•¦¥îÐØ¨|R“iÒ@x†íííi“J5Í­ö_[[Ëi^õ‘©êÄ‹¤ßÚÚš6€übñELLLØC™L <Õ¥âÀ¬ö^<Æ|¡¦ªµp Ñ!ÉEÆæ¶‘ÍXJ/nº’aV£ãÚì>{È>ÐWj)ÎóûDº 9ºÐ³ sŇçwmô×hQ^]]½té(Dgg§­Š¡â ø0wÈT^7Ž;æíϦ$ÝÒÒB×ìŽç¨‹ªóRö(ÉWñ¹sçøåuV¼PYyƒ¸Övëû÷ïCñ+VY666òj¼½½mÒG†³¡d{I1>#–=&ƒbi9Ü”„RÍ~(èöøñã\ØÌ[ I‘WjÁ¡FµI2¥õ"3z') *ÓówZZ‰¥†­‘¥î3^!#$¤&)&V%˜V»Hœ*Òú‘¹)ê%€_,U`tBTš…Ðs’;CÒÑvÍ„“¸Y“Ö¶¢Ù(x4 (ò¥‡DAîKã–¢2QøüªÜ`¶¥@ŸZêó|:v¦t"{¾3Zo¡Ú^ŸÖ$Ìm¦ÚäràìÙ³r¬›Æ]®úÔuhÄ(|Û‹½J"4;/ÿÁ‘KHÕݽ{—²S팘÷|ºØóc§­bÉÕ7¥“Ûã@15‡¬kÙÖNMG¾ŸµÀ¬L;¹lró ñÈ…tø]ZZ"®bÙ©)#dSj`RÓ³ÂëB-ÀJY‰KHe¡ôESu٫삉Bâj·ÕD7e¸à‘œUðØcJj‡×™êQêëPv„Ôê8·kÆNÄ–­À–C _}ûÑ4C‡¤ÂyÎ( dèLïÅp¡ÞYEÓ7o3±™4˱6C‡öž?‡‚¥Ù?3ö¿ï#†Þ3ýEÂN»®"y›Å0QÛ(Š ¡Þ-0j„«HßD©4r>"“gª$ou ܹuh‡@’öD©½GLSÙf–2ÕM&W»ÚP*“ž¿A†¿³³³555!«Î!§¸«-ˆ¹¹9¶qÈ´FZcccr2]`j4HÈÔø ±’Tz0\ t úâ–(¸uh‡`<Ï`6¶H£ÆÇÇáé‘‘óôÎ;+++²Õ`6”ÀÍõõõð·ÖõT›Yä@WÁ ääѨˇÖÈ+Úuœäë…#Ó¸0?hxÜeJü†¡‰‚vA:ÚÁ¡Ô°ÉÛ0{Ät$Æ@ ŠyêùûhZZZøK/iïÖ××766 õÁÁA8U»µç¥*’VÁÓLZx&”»F‚†††Èv÷88 ZãWFÊâžlw(.Ü:tñß:tˆéí©ÛLt_»¯M{ÍÜ—[{Ï_Q6ûŠ¢=hvŽ{û›\R7é·GÞb¬òF¸Ê(k‘K{טd8ðkÍ&L*Ì6®Hmj{~£²4¯rB~5“XпÚG·Å…cèâ!?†^ZZ*ªTR©>,êÒAÕhÛ@~gë‹ÁÐ^¤§Qt-r!C`¬e ÆB5œ‰¢L˜œ@.¶hSÛóÙÈZËÙ³gÃŒ.\¸¨™íííúúz~#”SÉRüÈ“ @f_¹p³Ü¥C œ—´µµÉÞrMMÍ¡C‡d¥ðmA6*Õ>]WWWBv<½þúëEò7œ@ã3‹‹‹4WIàâÅ‹áÎQ ðTË$ R§§§sÚi‘ HðÆ‘'€ñ”åÚÁ¡tH]3ŽrNeN¯jÞ;Úî>àÌ£b ×ѦyÈGss³vȤ}±¶¶ÖØØØÚÚjÛþloo_YYÙÝÝå#­´û×úúúxº±±188XWWÇ5QÈ ª“cÄTÂ# $ŒÙáeÜY˜(ò@Ey¯"M®eÒ`÷††Ã…Ê… 猫,³³³º?>>îí› ±sΟ?/ã<ÆOèîî&/ÙBáéðð0‚õôôhÜÉ›âÉeü„§G2‚ŒŽX~ã0èN˜¯›ž_¹¨ Ē˲=Ë~œ&Qä±±1ˆŠÔÐh¹ ëÜ»wO–e.¨BÔÛ3ø“ãE¹¥:sæ EƒD)B@³DHMNN" ¾ýöÛ²ÖÒÒÙ«‰Ju~ýõ×Q£!Eù‰ò|%ù©73ýCm455ñKéÈ ½™ÄÅ©áõO‘É"ñžê‚¿ƒûçÎ;ªC3DCÿæ)Ù…¨Ëǧ6tˆP猆5T*äPòÈŠ™—+C‹˜5„@zm•}>¡2À‹£ýñ ð2ê„§/\¸à¨ºÄHÈ j$Õ÷l\zôƒ‘»ÍmóÈm}S]t¸igqõÑßß/ó«6 8•§©Ÿ*Ú0äÁ#^$¡N˜¿W¯^•:ž}c“ßI9‹„ɸ A1. ¢›BQòöüóÏs-â—Z,³dG—277ð·A‚ô6¤À#{ämB†Nu J®!Eúб{ØŽ¿¼_ãÖ2¦6b&†Ò°37¸{÷.b ›I 1(ÈÅ‹y#H…xëëëªCÈÞÕK!÷ðáBjÔ… r…¢E%ø¾ZäåÝÙÎrS^¼ ‘yaÔo³¼åp(hë¼)^­Ÿ‘#ïªf˜Æ™Ö‘ŽCä(¥]o•9‹„£MV”øâ`2™ª|w^* CEÜ—]ëÀ#ø‚1<GB?Ò›Õ'ÓÞìió€0ö);Òá/¹CÕ\ˆAù«¬ID7‰Èo&y~‚¤‚SL£Ô"$ìH)dt íNe!Œ¨]I·æBÚ¹¢Œº2 ç(Í<âí,--‘ ·aÜp –Wls²'}MÈç%%Lê˜W¦…+ë¤CI © ñΣ©0& Œž;pSµ¯E‚2µæ ¼ÐK—.ñUÛ®X²GN \‰7 —9íz‹|/·Ì"F^(z$Q0óÔ$n'¸ç›ç œp“§j%èíû;Wv*¸À¸ùÈ^QRw¹ë/T‡†Â¸ÐA7÷üíâ¦î¨÷|ã²<…8í\L“ÖiêeÉAo'K¨¼ñ€}ø¹©‚Šì\}Š´<÷–sEö rº¬!?öÆÐ{>ùÁ‘è$Å(xR9¯Ä€}©½È“•ï/”l*“2($µÑÑQ>I’Ò"Bl••RF¹Ö¶ozá¡hÄ-¶C)=£7¤uµ;ŒU }Ÿi zÄ‚ìúîÝ»q [,d¿%­ŒÐwG2®*1CÃ^Q¹ÉÅ;(¬‰M9ØHU•¦žŸ]]]©§ÌÓ3´ ÌþÚ¡H ÑÓ^5­»$¶ ¦ 0ýQ\Ú– ¯NSlPÿÉÐàŒÂ…,Ùú Æ²•½aéŠmu$'Ðñ–„C{)žÛ×ÖÖš››é"+òÈ£Cvww[[[¡½¸¼]»vÍì°0>!:::ì3ÚB¼åCw`A:Sín-™´Yúi—‡ÄÖbI¡C±Ù„„<¢ÝXº²²ÒÓÓØ?mÑh{YîHrpÈ}}}³³³ëëëiº¯ÔŠ[’¬r@u¥Ÿ>Ñú™Ú¤Nòd33¬3f¢•ö}éÒ¥’éYêÐÿ5eyl¯ìtè=¿?”G¯ÊVLâ‚ö¬8q"S 24m±ëüemA(¯hWŽ:ñ¼·%nnnšc‹ðtI²D6 ]ÙSÜB–3.åÈЂ6!;’vˆêiÃÿ‚¡µm=m¸K‰LÉñ­’_6§w:::øºÜN´d‚¦á“\ÌJ Ü\¸K ›§£Ú‹‚lºÜ–hŸméš~¦dÛ|hœ:óãxÚ¡p˜“®êÃfhš œi¤:7.Ø»:ýÂv?X¾àõŒ6¦yþn¯hÝ=‘²ÎéÊBuñŠ CWI Ϧ*"gèÒûmcL@¯êxÚ!oˆ›å~#›ð¶)vîܹg«ŒúheeE|øéwww3Ù çQ__Ÿ—Ù}*lÓW 28—+ˆ•ÉÈN–õ!ÁÌÌL„Vº —9oH»Íäm¦@lCC †@Ë 1|A@6ëͯœ dŠ‚ö 1Ÿ9s†0---‘Û‡Êf§[ÅC_tÅ•]ö/i½­­­Ñ~ì Ú ­…6CËñ|+¡2dv þ´—{vvöÊ•+!ö:äíRI yhñ|+¯ˆ"CÐiÍÒÃ’ƒˆ»wïf³·“Þœ~:;ŠÍΗ±oNôùùù“'OÊ"|ÞµL.ÇŽËT Te§à²”èš%C®>Ëd"¸™ 5ßÓÓ£.)*ÐR‡‡‡ižoÐçúõë4˜Œû¼J5s ¹ ˜NÚ3Ö ‰bŽÐö™ÖÕÕ)ºˆßÛoižo=¸ÛqÜËMiä‘ç›@˜Ï?‘ïå6B\E¾víz—[šÈ­y;”;têäöíÛô¢ôBôf¹Ùÿä9Ã6Õâ¦]¦R/Ó]ÂôRpéÓÒ3½­|™ÑÕÂv(Otaá'dPšHÖþIG±N@ÅÜê,L²W¯^M›…ID@$¥#»µÆ*º lÇ5mÀÐÔ¹S|©züUH#ƒ‰H‚Ô[@ Ï÷á:44d|òJ›u1 ¿ÑºúT ¡y?~\-˜ºâ>wôŠå$‡fÐàmcÂTZww7ãPdSÓ…,i $Nû¤æ¸ÃÀŽöF7ÚÑÑ!;¥„l&WhÆfÅ-HI‹<êCD'™ß¹¹¹bd§ƒ…fÚ½‚aÜJA^Æ‘W>@#„#ÜiGI»GFb€ † Òâk™F¥Ÿï ­4ò["u\Ð/s0ÜÑ2»J;*A펓&€¶}Úy‘ a:t™T%"i’ÁäVž0e¹V-ïù†{ŽúT2(®VU|ϯH³ò*ÛÊE2˜tÌ쇌qÊ’Žê\;¡ÏÒØÕ’ÌQ¥f¶Q!²Ök,ßò¦ÌÛ1Û²BªUìù篌M]pëÖ-Ó,#_“>pñ5!¶ÏJƒ‡q°#ªª°_­C¸Œ¤Ðš—{2û)wPhAËÌ©\‡NLLppY¯¦è5ÑÛŸÈù&ƒÀŒ£P-^rÓ›ìÖ××ÑZÚÚÚÐb÷| ±ÆÙx*HªÓäª?zÄ€¦¥åsø˜%#_¹r…ÞVÌ¡9XRN5• 'kv¡P•vÏW÷|æ–I.¨‰¨Œöš=u¨ —ByêÔ)™ä$$Á¨jª”ÚˆÜÕ|ZðQôôÀš Ô*<…[Â+3~×í1fêÊ1\HÈ“'OЉO_}õÕºº:3ú1÷ïܹ£oµ´ÖÖÖü¼Íä¹C(Yv±Ã93upˆ_1ôÂÂBø ™]Ô*·÷—óžï©[P¼eæ»RçÃkkkMt;ºNè-0K&ßd¤áiÉžö¤G°™ƒ!¼<¦Á²\Ó7¤Pð>=;i’5ä¢É:o†^äÌ}=¢ŒÃÃÃ===4¡p¹[‡¿UD L¤kÞ{{{ÛÛw ûÜsÏéoZhB›`6ýCÛ%3ž¡F²[Í$#UUaš‡œÖé^\?UJ‘Oû :#E»ø„?~ü¸Ò$.Ì” ±ø«c„\ð:J6[%{Ä ´ëàà!¾F„öGGGkjjŒ7h6ßÒêåÕîS7]ÓWŠ¿:„îîí{™%Vggg <¤Ë PŹsç<Ÿ¹ù˜Ü‡˜µeŒNœGôv¨L¡2¼ÐÀ‚ˆ¤€"Ij ^Áð %LOOóP.yD:èú¢Þ@:HÂ#bÉ{hH…‹SyñÂ… !r r&]`"Ë>´>??ol+f²6e›D†Ò4Uëù”‰D·+‡Æ¶ ®t#;$:®} {ss“(“““R¤HDë|rü‰¦åí¾@`È©'ײcŠTör¯<³^‰È?¨NSðHFÌÍi’Z“Â+åÀ²žj&VUd¯îKyó$ÏRâæÂ–ô©R#³.(¦-giB´x\`"Òe³f7Îð#ƒ6fcºKk4á'õsBø:tû³Ê„ðiƒÈסµU>îB—nº:ñ'³þq‹Q(èÊ¡ó=˽¹C„к¼£ëœ½ÙìÆ˜I÷Õé(eÝ×ë3„—su#‰Ædv0;¼îëZKQùï gèªÚ&&„ODÎÐÔ);Æ ÇÐÕ‰¯ÍÍÍUÀšúúúzsssggg ãv(bè¼£k‹if­ùÛÝÝ­5‚ÞÞ^Ï_æàþíÛ·íL ÏS…×þD"ê7p¬EÛ¸OF ¯ùsr'¤®µš311ÉÞ·+­ØY$ Ù;ÌŽUu¸Ë¡:ñµÂ“Ht¾kyyžVí,..B‡ò”îù›étŸ÷ÅÕÕU-¨ë¾½cN ÷úë¯ë/C„®®®÷ß_»íÓ}‚HפOøgŸ}vgggmm_]ollˆEн¾Ú¶‰ %^Š–ŸÜ¸ íàPD|.ò@c@å‚Rú®*@¥á‡âB ]fi ¼òÊ+fÂÊ|ûí·í­‚êщ¹É¿FŸÖ¦ÅÔ£Sƒƒƒ¶œD¡m‹,¹Ö‰vm(+ö0®:›b)uè•••ê9T¾²)V½‰Ci`¦šõ¦dPˆ¾ wÖ××øuuu\§Òíîî®±©˜”ÎdksÌÊ·’Õ6@Ï?±fN´µµÑàu¸«xÑÕ©Û+x%ÀÄÄDéÄ98”2Ëí䈢¨Yètòã>tGg”=:Z7Q¼¢5$õÂÐhç²ÚºÜÑÑa®Q¼ÄÖEuIRâÙ„ ”KïSSSfØçàP©x$nâ}´±iUy9Ú¾(â‚&“m]Ç6®®ëbŒ¤dÛ{íë .,..ŽŒŒTÛ‘åŠ-§±±± ÷â9T­Ck%²§§ÇXÌ1Ѿ¾>)grøÈ…BÎÎή¬¬žûš•MS]CZª$Jooogg§–3•!í¤L,Ê×óÉÏdíí{¥$eyÆfAtyy™XÚÜdr 3K¹sSE Y#›¤%5åÎÍ‹/ª®”/!Nž<©ÏJÐØêâ)ïܹ“ß{¡†É(›íÐÚnîgMfæ¢E¸ âX³½½=ïwUËýy°föÍI $£«\·—#.[¸ãþ·t¥@¢úáÇ|²B%¦A7šššª¯¯ßÞÞ– RÈæ#$èsá³cÇŽ>|˜ˆ´ãõõõG}T¼HȺºº BòK0zR~! Rã¦IŠmÿQ0 ŒÓÈ‹HEY{>§Êßinnn’)×hiD¡ë!Vkk+ÝÉ1PL²Þõ=¨Œ1,"CÇd³Rd "Ù†ìH!‘=µ¦¦†2ª®ˆ«“Hüíðå ùò+ãh¤LôBfbI„šÌ©cÀlÓ†¯b™Þ õ -fë¼> %°‘KU ÈO¯5ÍéÀT¤òVƒÍg~e >Ì߸Es(!â>“rHµç[Ýò|ÂööíÈGOe1Û*1rØ‘ËW•nÊÇ¿{¾%ž6©€Ù)þÊ™ðüµ Z‘,”£kù¤"$ÁFGGMŽ6T4Ù#3eܳ,yé ™©û}‘à‰'$ƒI\ îí{ôÚóM/Ùbp!5iåI‹€µÛ®iò(“•.…±ŸR'JJæ&dñ-Ú-?¶o+ãÍ\«N´ 8Õ.›=j!L¸;¬!NõXÒ(¼N²oNr!S2kz±#“‚íâ9$‰Ö¡ 4!i«>Ú5Ê}>×´n'¤ó U•çÏ=r'p&‡¤H9T@Í’%p"’Z kéëöØßtR„ìïï'¢¬uÚ kᒓѱ‚Ù&©MÖiçc=ß–5±HÁv+”ý 4b UGhÓñÑ×ÖÖšYúTØ•iON}Z¾§ŠM½¤^K$ã 3-¯ÅG¦úwˆ™šŸ__[[›ÜØÄ-f‰À€2í ß‹;€S%H:C›¥è€¥0i´Íû‰É%¿555]]]°#q!*%[ÃaáI¡tÂÍú d PdéS¸±cñ!q‡ûrirœ˜˜ ¼ñ¿Dt(VÁR³–-ž¦[ç+¥tæh¯©+㌤½½Xˆ¡#ÅŒ¶æ—û©~Mò†:Vä·‡>*`HW‚2Z$¾f8t=99i¦Fmká€O—vskmm=郑eõгzpŸ*Ä©®C"n=>#îß¿ÏyëÖ-{š×žÞá¯æ!¹©94ûB±æççeÛYé²Ád.Ltî+¼I!#‰ùk›§2â¿é#ËÈlr T»)ˆ®DW"Ù 73Á~éÒ¥@]þ«×¶ºCRYNj™ ? •”fþ垄릦&ÌÞS“ÚÌeƒ!ZÀ+y&Ð…‘¸æÏ#-—èZráÂ…¢~Sn–;ÀÊ ‹«gZûÿ³÷¾Áq]ç}ÿ2’¤­”ˆ=åÚjˆXc V0šXuLD‚S—à¨C¢Î 1I ´nI¥S@3-©q ø €7ߘL/J  Lä!:v µ€GàÔ!Ô‘¦*€T*Б4²„1QBIJñûø>æÉÕ½»‹Åîݽ»w¿Ÿ;wÏ=÷œsϽç|Ïsîù“‘€­Õ¹kŠTª²:Ï¥ÕE@Å Æ}ÓÝÝÏGåÈñÚA=¾);µgøN¡mЀµEá·µµQYçS­çsG&$a Œ}ÆÎˆºÈ<ÉÿuªMü_£õºÖ¨è^îC‡%fER?þ< fccÃßße+sÅr;V™šAU˜Ü]êaŽõ¿°°€Um†¯UœÂÅ%}}}ëëë‘Ì6mæÖjvêT,”âuªjü_£õºÖ¨h…ÆF¬…Y…qôèÑååeW\{zzÊŸW{V¦æî_2Ì&s›#MŠææfÿUøç,7uÿþ}æÎÎÎÝ»wÝ ¾“'OvwwsíK/½d.uuuÃv‰ &ØÚÚjmmåøòåËÛÛÛîØÆY’²µi¤Í± mΆ}Öèò³üùùy;(óŽj­Ð¢bɳ2µ³þ.k§ÇXÀ4)z{{m+ ƒpàÀ‹/¶´´¸±¸8?H/ñúyMLLØžþÄP©>}šÁèè¨m±jÇö1ÛŠYØI§ÓÒæò#mÎ ÙBq“]hÁS/Q{M|;8tè5‚]ž”ÔŠBÛ*<gk1KX»ÕÍ DbÏ¡óñ#dž*S¿šúÇäß¾};0ã£viiÉÆ¢»½¢ýV„o{GR~Ü<ºŒØª5GµcdÞ§² 2íµ×¤ÍÅP€…±ßש6¡Å©BÊ€ÍÝ "ºvíZ¶å˜¦¦¦ìò¬kT­ M¥O>æ3[Æ"»_xáL´@%bAå¾¼˜•)‰Ú¯C”4[Èo;0?¥ÏÅ’c¶¯[´5€­¿æþrŒ6óÒsû4§h©8¶ä¡­WÊ…H/Þ°ž­d ¯†·Àš™™1%æ°cË[·ÛU)pÍ‹Z#ÚMP„('´øóŸWImƒ1–ïw]Å}÷hµ¬¸Sîîß¿owîÜ1w~£a#‰ücAS‡q`óŽÜ¤,›jœk-dû‹g7˜90–Ò¦-9Çð¼/‹Ú…ló‹ìªŒ:?v#îÆÍ›»/¥&0–;¬i‚.úo ì¾ì³5ãhÞ‚!LÄ›¨±¶-'É|wL6Ú/ÙFhçOŽqË5;%&Çs©Ùñí¢ò±U# «p¨ßr/>X ­Ðn¶•Ø’[¶`ÈîCåý­­Í9º= ù¥šößg‡íl’€D°Sž=gâa×Ó$þ=zÔ¿Ê !åu´ž;wÎ…ìæ Û4ßðú£©‡ƒ·m5PÓ 79Ê­5æ¯ÓÍÑÙ’ŸX–¶f'&# 0»Þ,I·¼h©)X¡w®¯éÚ@Ùt„ ;=î£xñ³Vr(tÙME‘m•J)´¨dŠ‘g'Ò%šµ_M»OnooÛ6P/…}}}XHétÚ¶D˜QÖð2d³³³äãÆÆO?ý4.¶ø¥ "p.ç98p`yy9å­ÇÉ)Â!@›‰»¶¶F\øfFMmj¡X„á”ãØÜÜLÈ>À­­­ññqkyzìñÙÚڊǽpË(H q§üNMMå®+ f™c·Lâm NëÁÆCþ_+òattÔ=dQ›‡;¶.)SÒA7ö ÕUñB ÀmZ˜òÚ‘üR-ONNº¯©1² ³ÀÝÖ¼‹¼V©¦ïÐè"F$Õ}`çvþÃY´“ª™³þ¥ª ÌkêM´Ö}>èaÇh3#ŠÎ¿B}ÝðcZ]]]ÙnG?ŸùÌgr ŠÀ…üµí7RèöŸBÔiyÐJàñównnŽ»Ã3É $£*רê`¤ß^nž‹}æq Hæ™3glS¯¨°%mØ6±¿øâ‹0Û€#Üí6¸7•i¥F”Äåe£ÀÜ™vüàÁÛ’™_¼”}lv»ÞßxàypàB¶‡Gª¸Ê>m"–f‹‚[°¨'—NìÂÂB8Ló³ë}¥æ?\Ž»)[‚{×+GDåy Å }rŸ6Àí>É+^¢~QJŽ$°‡k“yh[¯CñcÄÜK•# 5¸heî‰jUý:°tü‡×ßÍèè„ú],À€ç°OuØÝŸÏþþÿc|(Q½¥f)'áIÜ…fMíz{S™S«Ûn¹¼äVi“ó¶øÿ®·G°]nƒ„"äÇ&NU—?ö]Ù†gc3ù7º(%];#¼ ¦1Ö")CŒ¶—s1!XÝÍoOO 3-ŽÉ½@÷~$,™c:Mây8¶Ó<ŠÌ–iÈ=8.‘änS½õŒcçLwwæ3¬¯Ù3²ûÁZ% ÄáMâ>ýJì40F5ã”*.Š[Ì`Û.©£Ln1M~š M»à!©‡–]Ñ.œþh’©Á ¤"¶>ûˆwŠ¢gjj I3Á …«d(*ÓÓÓ$ž¦(ÉælX@Ê“ícÇŽE¯too/æ2/¥ÅމÑ”t¿K?³³³áÁÉ&©}û¼BÔ*þýżÃþ·Ÿ[[[Å xó1ÂÂŽÙ*¨ÁÁÁ¡¡!Wé#£NyµÜÊÊŠßg¶¢tàÀ<KÁÎÎÿÊ•+ì¹ûÙøø¸Ìå’À×(2;vwwšƒî[áC‡8ecwükæ¥Ãzøü¨Çˆˆ_bɶ»<ñF¸êÑOÕÕÕ%i|Ö’}ÓÅ‚)OŒ”ÉŒÇJ5Eù¿öÙÚÅ„€jÚÎÔ>¼ÜÖ.ä å­#†ZGÕRDŒÇÆÆ¬7ÛYçî+8¾¤ •ø©µEKüš×)c÷åâÅ_ôwgÜÇv\ ;f|çMŒýod8£OÜQ²€ÏŒéÇ"æ¿ÛKÞ¶÷-iÖÑ^¹|ù2*C›#ŸoÞ”SduѬð9—!?èw·}šD$l¥Ãrv D²QUþIJƒ=ï_ñYjcål´¯eÏ‹¡d4§ÚÚÚøkãȬ’ S6(´'Ožä ¶ù¸Û?Üoß¾ýòË/óK!ïê꽿¿Ÿæ0WYé"ëÊf@§Îâ«’ÔÐÏÞ´”׿+x=à0¼ÛO?ý4eaÏ%)Mx£¹™{%c[kÏQpEG¤ÇlÚ ¶ænþëbRÉž@7ÌEŒžÑélAÓ—è„pG=RW$ôèáp{üDÂOQ]ÖZc_ì ›&IPEù¡y»¹¹‰Žnoo[·Õ¥K—¨,š=læzà˜f2LEÃ%âÜ96w×gnq=xðÀ†×ÙD5Ìm¶··ã833ƒ£e/7űEêŽmoüóºÚ²ÞæÎîd ±´Ána×”÷ÉÃ?“-BöóR;kæ3k.c¹SD§cÆ9Tù;º¿óq̶•sÌxãaÇ|êX›•x r\hŽýžùÛôÒµ°m6¬?…51ZÔ–*:àRh+F» ݨ—h§öü8ë‘çʬJ¨¯mD»UÖ40ïܹsáÂ'¸ó·­­-¬ÐÜ”m“à¹zõªí´aS“¹Ð/<œâ[jÊâ²3pä%³ÍlÚ´-æeÇø·`w3)4§ˆÅJK¶4¬¯¯»m’´ _ämps¦I§ÍHFi¸w®²•½Ðvá®W8­fi+Å“u‹·Ø¤8nÁ=h;6YÝï1¿“?ÎÔ.‘<ïæ¡Ðþ-C’ ¾ÍMõ*´(†Ànë¹Ì5ßS¡Å®­îµSèŸÖŒ.àÒäc_¹mGįfÝõÚ+÷ïßÇ^âÀtjPYá“[_Á¶Gâ˜jœÛ¸!z…¶u¡+pªZ²ÆÆßîz"ÖÖ3í$kx6===…¶Ã\Hű뙤xC칦¼¯žà¿e‚âñ¸¹†6?È?ḵ5¨îñÉ_b!1ürlí›@d§,i°»°­maÝG6WØM‡7ձ︶ͧ‰“­}c#¡"œg÷X¢çëv ±Î½H´– 6Ú¹‰öTè”7^¬t ¨ò™W&…®eœNï)`&{Í ˆ.ÿÑ3¶Œ’՜֪æZlb›m›-™}EEm;YåìjrëÃCÔ¹Ð*ü¨øI÷…éMÉŸÒ>ᆩàìKÀ®oÝ [e…JÁ8[/· ‹fhÚœ'ðþˆláŸäˆ/.¢°õ¿ÜnZ»¾9þ$ãÚ:ÈZvìOƒõ`ûÓàt)w/¥ßoꦉ]’zØeB¬ñÕ7 îÎZŽ¥{Än/2kj—ÛÚÚ4¥K¶‘B×Â6”Ù&†J¡E[ª¨lÑa4åĪ ¿B[eë ¯ÕÕÖŸj«›iPh[\ ü{!FÂOÖåîïïÇNÏsçê²1;;ÛÞÞž fÙú™Ï|Æ˃àÖÈ8ç?Ðb G‡¯%ßÉÚccc᳸?ÿüóÎ̘þpÜXüüûalS/;nmmÝÚÚò’±Sõõõ½½½ËË˼IQ-ÕÂÝñ.–t‡YÏd/± ÕÕÕ]»vm¿;¢“SSSd²Í€ä‰É¨q‘{Èk2¨©q¢¨¸ÜÊüe€Še9'nE*O*ç¹¹¹Œ•*@íÍ©®®.3„¸¿ˆôÝ»wm,¾Í.‰òœVÛ§»²µnòÁ ¶oΆ¶ûDj–qz×û¨lÙjÆw*ÓR䨚™¹)Ÿ m}ÚÎ$µS³¿`SmÓ­Ô­\ü»Y»GNÚ-ا”ÝÚл^W³Å8<<ŒOÛáÊ&[øÛ¢ÖˆCVûúúŠìl1K½lÏš†…¿­CÔ¤ff†|ÖÖÆY²Î_¬?ªliÎdžNÕ@GwžK§É†•†}»´º)âʵ¥gÙˆ0ÿx1¿ÏÈûÌ> Uö3îLûö5Þ~­«a×¾äjmûÂï¯m|¯ÿÏwîÜqÇ9j ûþaQ`‡™NØ0‹È¼-,,Xh.yvm@K\Ê÷Lnz˜ ÊýµôØø8 ‡_7\ÎEtŃ}‰EZlÐGxÜf¶1 üµlI{ã3’§BGû]ªÒȳ‹[ -*ä„_0¥0iìúÆèÛª.ƒƒƒMkrÃv ¥ÑtüøñõõõªØ9’¯„×`mmÍz&¶··í{m"™òV14ulooqík[yOoÖ¼‹+‘¥æÚµknÃõÜPF¸üV-°µµåsÜûŸò>œÕHuTjÈä¶¶67ݼnÞ¼ù¶¶Pè”W-¶´´,..Ʋºd¥Anئ½½½µ“!¶„uÛÂÔy*tÊÛçªD- {Empƒ-áä†)øÛ1ö¡¤ hllÌs‰)ôžØ~óóó4IM³­Ç|ëÖ-ûÌG–òjј–` z‡ Vd .\È8\©XÂfµà­ÀÉW¢ PÔ+pTe’g/wª»ÆÚ,¾}UÊ¥ø`@óD½Ü9°6œ}VË8ö"x¶Ñ¶|ù¿õ$ƒ" ¬ð%,•ÑÕ¶4Hüᇲ}îÜ9:î„T ù+tÊ[æ¬øm¶·ß¶±#6~"P;S~m½ÿ® )o<]ÆEñ `_;îH¡Ã¸JNùPxܶ¸=AI§  àö°žK—ªT¶¶îÕž«NŠd`=f•6N°ÂÙ—B¿lŸ®wÂŒå´/Õ·!x®²…‹IÏ~?®K¡ð@=Zü2å ¶ Ü×î´”&t½¤IJå8ǶÎÓÉÆZñjí—})49\pI-à*Ž"-`¿n뺜*["W ]|8¼ã“¨F¨&Ðæ=ЂٯB§öÿ5ÚMxËÓúÁ~ÕoŸ6RÞ|°ý¾Ì*‘BQ‹–º_4€=å’~+¥#8Û*;;;‹‹‹×®][^^n÷°=}5ƒ¢ò±‰•ÛÛÛSSS“““”Ø‹/ÚRkq'­ŠÉ¶•Ãìà||RÜ:;;§§§Ý60Ù|¾÷Þ{¯¼ò þ¿ÿýï¿ÿþû?þø»ï¾û±}ì‘Gùå_þå§žz*’Xü6;¥Æg[uwwÏ{”ZO™òNÔTݸ ³ÈÁ>Ú›…éV“ØoU%ÊúººÓ§O§J<5¶Ö(@¡…Îg4ŠÍ3¦ •»NóÍ7)‰s6O>ùäùóç}ôÑq  ¥ò^ry.` ÿšUhka=Ûúóq%c|||xx˜êZíò*¢@…ã_ïFˆZ 0…ÎÇŒÆÞ²®Žõõõuú×¾ö5zÏ{ì± .`Uçðc"M\{®Gƒ £££€ìªM…¶úúûûsl±S6hW:uJ RU?U@’g!òú1÷¾[“ˆ%Ösyž›› Ë3¶rX‰ß{ï=ì§vvÊSè®®.ääĉ÷y3ÌŒ; «·€®“g\â÷¹µµv4x ò\µ- æ²=J [/’ß±™ -D­Q˜ mؾdawªÎÆÆÆÔ^Î÷îÝûÿá?ø]ÚÚÚžzê)“gÄø»ßýî+¯¼‚6;6„8G’LNHRm‰%¬ç‚÷š¬5:ãúöSSS®‰ãÿÞ±¼¼|ìØ±”·È£?s·©zûн¾¾~ccãêÕ«—.]:pà@Ê—ÿZÚ¹ŠˆÌ†BäO¶=¼mùî±±±ÜjŠ‘íÿûùÏ…vÖ3–ôÑ£G©šýö45ò»ï¾›#Ld=8räÛߦ=âιê Ûö3ýýýîøùçŸß3šk¨i›755eÜüa–%]-H¡…ˆ*Çpµ‹.Ú¾¹¿YÞópß•¨jŸx≰7t:PAïùÑ‘IyÚN‘°"û·1éJ•›F6y^óH=l‡!“áý”¬wÚ¯_ùÊWΞ=ë÷³ìÃú±ñ¸Ê–aÏ–BiYü†N¢¤ûìc=–#pÛœ›Š›æ‚[vÛ¾O÷ôô3Ü+¿àk«‹‹/Ú~Sw3 i½öÚkuuuä*¯P@GÓé´Ø^I«««®÷›‡ræÌ™À(ú›7oZëA€y+VVV²Ùßø!|Ò©)X•ŒZˆA±Š¹œÚ¹¾¾ž*Ò>Seïùµ8õActÏɵ¶hñÞ{ïýå_þen…†™™™ãÇÓ\ %Vw·¶¶¢¯W¯^-G¶Æ›{V0‡ëÛÎ’)¯EE®òKÜýiëÐt¬X@“yÆqbbÂú¨ygx¾4›xdļNH5góì§ A àСCÅÜlSSñ3Q/·ñ€¸RµYUK5}åʯ_¿¾ç…ÔªîxϱW?þø~f‹Í‘$ åMý¢.ÉÞ·I„Çzç້qÊ3sQPkZ¹Lö_Þà‘ò†ëûOÙ.àœB’1Á혀÷Á:`\·Jþ’–‡eC6´±A ;22ÒÞÞNEi=É{.f‚üÃþÐÿw_ŸïÝ»—ÏšV_ùÊWŽ;†ÑFëÁÖ¢Š;«ª†lsäܱÀ(¿ÑÑÑl&oà›Boo﫯¾zÍ#åi9âŠ*Ûçä,ìݸqúÜãÎ9‘)´qb_+í tîí–ç<ŽoxäÝ+¯¼’ò kâÍÑÝM¥ÌXu¯ï”ùc;U„Ýݱ¾¾>÷}úöíÛˆ®}òwk¼Û(zó°nm}@ˆuŸ ÷„€–Ó0í¿{÷î¾V|ãábô°Œ«(êå"f¨mM3Î12ÊsÁ¼ûî»{®abò€„HžómÎf ;úòåËÍééé±¼µÞÙÙiƒ†;T¬¿ÿxã//–t}}½õrÏÎξþúëûJ9UÂ’g"Œlh!bÆæÌPÏæèÞ—¡œ÷îÝûîw¿ëGƒ~Êc¿û@×,¶CAF†‡‡QÜThdÞ–"ill\ZZJy½þ”{Êf›°îÛoll`þ®®®Ú%¼E¸˜ßÞÞNÈ62ÜB°•p²1222==­ÉW•†Zˆ˜±ŽÍÜvü«ƒEÅúúz…¶ô¸™Z"74hr,Ñ•í”ßÝ úó~Ƙvîfˆ¿öÚk¸ØZcnÌ ]‚g`Æs`Sᵤk¥¡^n!bæÖ­[©½>BçÒ‚yòÉ'sœ¥Ê6ƒOvU>ØJ/%ebb‚‡‚08p€_›Ðaø6¾Ôw!ö…Zˆ˜±Y4¹ùGÿèE)òœ{·«ÔÃ.ÙbVe©Ê m]]]¼*KKK333< èÈ'JiN]¥!…"fl¢Kî…#lôuT1¢Í¿ök¿÷}'ìZÿjÛ¥Ž«¹¹¹½½½D $?ŸÍËEÙÐwh!bƦÖì¹Ñ-Ráxÿý÷¿ýío¯¯¯÷»ß}ä‘G¨»Oœ8ñéOúÑGR¨ïÝ»÷Õ¯~5åU둺øÏ'açÏŸšššª©=©öK___’†»_¿~]3¯*)´ÕÇ[o½õꫯ†!¥===κúæ7¿é>!oll”âK¶(§]°¡i,jÛ« A½ÜBTÇÿé?ý'äsùäÉ“=Ø»þH°°ß~ûm÷÷ßøFÜ©N&néò$XˆTĈlh!b†*~Ç#ϺãØù—ÿò_ºe·1›ššÜ"$ßþö·íø¹çžCžßõØïÝ+++©üæêÔ,eÂ]~Üþfq'DȆ"nì ´?ŒÜ|ç;ßIy£½ÂŠë>Bë[ßJyãËžyæs4—}aËq»)E€OOJdË£‘B Qeìijc.Û'êgŸ}–ß_ú¥_Jyq)–=©e¼Úš6¼ª¤ÐBÄL{{{êáº%ùð‰O|"å}F‰§lâ–3—§¦¦†††nß¾m÷kF«—;6x>îTèîŽZˆ˜±ªÐÖþ̇çž{Î:®ë·~knnnË5ýÍßüÍùùù÷ßß”5Œû86š7©½¸ÅÓÓÓwJK‚{ª"fÚÚÚøÍÇÀÇ{ììÙ³¯¾ú*r{ÛÃÖÊ¿þë¿î>TollØfVœµèödbb"•s»­§··7î$”–óçÏÛƸRÓȆ"f°S¨ óߦ⩧žúâ¿ØÞÞ~ôèÑÇH2êûï|ÇþúÇ‘õÀÝF™åƒm6œ{µðšÅYÜ©(9ú;²¡…ˆLU[½+ÿ>úèg<îÿüŸÿóŒþ÷µðÖÖÖÚÚš>Ff#Ï~ˆjÇv ;5lh!â§»»;õÐlÍÈûï¿ÿµ¯}-ªè¾ÿýï¿óÎ;9Kñ¤0>õÔSÏ>ûl¸9Rh!* ¬çºººééé‹/ú??ú裥›†KÜÚÚšòš –ƒZ3 Sµ´¹™-º¹;«°­ç=hì>÷Üs%Õi}‡¢²ÀD³mÇÇÇsÌŽööv¿½¯…MjÓ§OÇ„rS#ßÝÑÝÑÑQLäü¿%QN¯]»ù< ?Rh!*ކ†[»»»Kº¤qa=c²óK¤7n܈ûÖ+Ûˆ¬¦H§Óq'¡äÜ»w­ÍØ­äü•W^)`óõ<‘B Q‰tuu­®®bOcI766–h¸‹.îû®t>wÊMâ%˜õ\Ì0ÌßÿýßóÍ7K‘6}‡¢BÁ¨]^^Æh33÷Î;~!F•±Î­}llLÛyR e˜or…0Û¶oÇo|ã?üá?ýéO»AaSSS4Ñ2ö£LOO=zôcûX´É“ -Dåb"m;_?~¼££#÷¨GSS“YÆo¼ñö4Å‘ÎÚ»ï¾ù¨1õr Q´´´lnnbûööö^ó@-Î;wéÒ¥=W}Z[[CÚGFFܬVB›™™©Ms°lJææüùóCCCè)5sss9΢©aƒ˜bò‘|$ìùþàΞ=‹x#êá]_ÙÙÙh—ÿ“B Q5`õbòŽŽŽŽ­¬¬Ly¤ÎXmoo÷cºuë&ò–‡¹ É]šñ,ââ½÷ÞûÆ7¾AsÓöO+)4L÷{Õ/þâ/~ó›ßD¹1 Í…ö„µnÍàæ/¥/ã4ñ{÷îqƒΖB QM`y\ò š ˜¦¢¾à”ý†ÁòÃÚ¦B¬YPT¦Íö&Gÿ ïóüü|Ê[˜6`ò¯¯¯sðË¿üËO=õ”s÷wVS@žyæZ¥¸ö1}=yòäoüÆo Õüý_ÿëý½¿÷÷øýÜç>gªLA#ðl ¹¼ùæ›.f.…¢*¡&:ïá\¬>r­ût:­~lQ øµ96ØÊ}Ê}å•WhYÖ××»¿nH××¾öµÿþßÿ»»ð/ÿò/ý›ÏÎΙàgŸ}öé§Ÿ&XÚÁÿàüƒþð‡)ßÚjlnnf먧…!…Binnv¿¢Ôàr%FÁ/UžÚœòú‡ÇÇÇýB›òŒælþ#™ÔƒÇ<ì8¼ànéÖß …Bˆ¼¨ÁåJŒKsc_fK„9Û@­ðUy®R°¼# M -DB°m¯Ô¹-ÊÉöövŽÅby¿ÿýï‡ÇK‡¯:xð ¦j„û«Föý­[·~õWÕþ~õ«_mhhxúé§ÝP2?Ñ.í"…"!ŒŒŒ ÆQ+|ô£Í=*;ã†Q¯B'''ýë‡<öØcnâSàcs9Áâ÷§ŠãO|âßüæ7Ÿ|òÉ'žx"œ!F-…Bˆ¼Àò‹; ñmš@>ØGÜgŸ}‘Î=;ùcûXOOÏèè¨É¡ýõÛ©\nŸ´ Ðÿi|ccc~~Þ¿ozFÃ=7ïx466=z4å­OâFn#È4± ¾îã´[à“vÃw¿û]4»ÛPJ¡…"/Š$\¥6mÉéô3Ï<“{àÞªì§Í#쎦¶È Ïäù;ßù¿û»¿ûÅ/~…6ûØvvvVWW¿ýío»¾n“p´™X>ùÉO¢Ó6,ÚÄ¥ÐB!ÊV&RúÜsÏÙŒçŒd“ç}A ¿ök¿†v¾ûî»9¼¡²þžs„–¶rx]Ï|ä#Ö8,b{Û˜ÙmÐ ‰0ǤÐB!Ê:ýÙÏ~¶ =é‘ÃÃÖÖVÀ ·.ëÏ}îs(ñއ;…]þöÛo?ûì³H¸s<|øð›o¾‰BÛôhn-Úí­´s†BˆZkÞÿÓù?þÇÿˆ#BËïÔÔÔ;#û#<Âïoþæo"ωgxCÔ¯]»öõ¯=µ vwwãÎ%!Dh¶U$ fÛ%#éÁƒq'0š››³ C±ŠÿJ#Ȱ¥ßF±³ ºþ…/|!Úä©—[ˆ„pÄ#îT$™h§ºŠJ#ø­·ÞŠdö¹sç"Ožz¹…"_J½Ødeâö-M¾6z<Û@ñ<ù•_ù•h÷4¤ÐB‘/þI·µC²;¯÷Ëg?ûYÿ^["…Bˆ|©ÁEKj¡Û‘¾téRðmZ׳Ï>[¢„I¡…"_jpÑ’é6°îî}ut?þøãèz):·Rh!Âèèhss3¿q'$Éܺu+î$”›©©©¸“P&ìkô¾ð…£Gæîô>rä¦ó¿úWÿª+}~ Iqç‰"°uVVVjÄ≋ÕÕÕ¸“PnŠY”»At/^¼˜òvÈxóÍ7ÍÑ$Iy‹z~⟈dá³|B !D¾lmm¹ÊºF¬sY;|ìc+ftw$¨—[!öA­™Ñ žjUùH¡…bÔÎwYȱŅ(Rh!„Ø“““q'¡|ÔTs¤‘B ‘ÒétSS¿q'$ᬭ­%{?ÓÓÓq'¡¦‘B ‘zzz–——ù;!ɧFOÑÑGèx‘B !Äþ¸víZÜI(2 cG -„ûÃv*L<ú;Rh!„Ø[[[µÐý+:v¤ÐB±oFFFâNBiÁ€®q‹Zˆ„€a·¼¼\ ;U‰_ÿ¼F¾µW8Rh!VݱcÇoÛUØ— ^Í#ÙwWEH¡…¢leê t… …BˆB˜ššJê7…ÞÞÞ¸“ ~ŒZ! $‘J–à–GÕ!…Bˆ™žžNÞ€çþþþ¸“ ~‚Z! yŽ;Q²¸¸X S½«)´ ¡··wii)‘ý®•Ì•+W’dF?ÿüóq'Aü Rh!‘#Gš››ù;!µE’ÌèéééÙ¤ZB !DQ %chÕÅ‹ãN‚øRh!„(–|\Ðî D -„Å‚¼Uõ«42’‡Z!" ½½=î$ò,º‘B ‘FGG›››¿£CÅ‚ =88w* aqqq||<îTˆ H¡…H›››+++üÆÚehh¨êúºwvvZ[[ãN…ÈŒZ!"ãĉÕ5=º³³³º\S<w„¢‚hkk+æò»wïb’.,,Ä}y188¸¼¼<00PpR÷’"…Bˆ¿¡Í£˜º=&&&⾕=˜ô@¡<wZDfÔË-„Q‚6¯¬¬ ~q'$kkk—/_–òL»aqq±¡¡!î´ˆ= -„уyº¼¼ŒHs\9"-y®.¤ÐBQœHcO_¸p!îäüxe’S§NIž«BˆRa"===ÝÝÝïĤñññÎÎNÉsu¡ïÐBQrPèyòoàMËàâÅ‹D­‘ÛU‡lh!ÂÖÖU°ö?¨L&&&úûû±§ËïÚÚZ}}=¼ºº*y®:¤ÐB$„‘‘‘cÇŽñwBDf.\¸€L utt”§Ç{pp°½½}fffll,î»… …Bˆ2qäÈ‘……¤czjjªt:=??oÃÈiTæœl‘Ë-Ê55EÜ©H8Ö¿m}Ýq§%áð>#{ç|8›iŽ*#ç4›››)nDª¦p"‘B‹È°'&&hÈÇ!Ê-ÄÝÞÞÕpzÚ»›››v<::ÊoOOýM§Ó’äZ@#ÅD4XõtçÎ µ‰[ãsrr2’…¸x¸c~mx¶¨4ÛJDCkk+¦ƒäYÔ2ˆôüüüÅ‹µnŒˆ)´ˆ€ÅÅÅõõõŒ{`UPg©Â5Æn___oooÜ I@ -ò>~üxÆS/¼ðBøÛÛÚÚZ:>vìæu}}ýäädÜw D9èïžö·J¯\¹288ï΢‘B‹½1mÂg©w°’ãú»»©¤p¿yó¦­Ý¿gD[î/öw•—°dGøªeêªU˜?ùÜ)M®brƒk !Þü)äµ÷7I%DF¤Ð"3ùh³ùuúôé°{___Ê“ÕááaºººrÏÆøÃGe³ÅØÔÔ„^æáðáÃÑfÂÒÒÖM@•ÊWŒ¾×<âŠ}_)A–Jý£ Qì7ÆÆÆÆl­ÞsÚ|étZ:-öD ]»P±"®³³³ËÄ– ΦÍË!²u«677£aÄbS9ÛÛÛs§!ohhÀ†~á…œ#×ÚÖ¶cÚ”·uá_»v­Óƒƒ”·jDFÃ¥µµ?– ~ñ<88èö-à0ˆíl2o$Œ!FÔÏ$À.'mn±BGGîžLŽqqQp-Ç\E¾Y˜¤Í’‹%Õ6(´¤â™³è> Ç]E~ÚIœå*ÿG÷ìz{{ûûûýOÜe,@¿¾gñcî6·Çãããv¡õZ‡SÂ)€xà\–?öÎp¹ò§Á´ť766=,.ÇÑ2gnnŽ[æ~üQX˜þìµGæKýÃù·4àÙîŽðýùï¿»ðM…9räˆ-ž­Œ˜Nó¤lÛf-¥.2¢ùеÕU¶­•=šÑö…íííl!„%pee%cï%7uYOOu’ßÝÝúæX‘ qbbT[Ô_6Sµ¥¥…šqÕãé§Ÿ&W®\y饗¨àøKÕvéÒ¥cÇŽa£onn† \¸M¢>sæÌ… ðsûöm.'=œmkkãÚ7nИ‹´õ{“ò cš;¥>%IÜÇ×õë×ñF2gûúúPS2ùêիègfflô÷‚ink£’h”p‰Ä…çÖˆŽ¹Ó×^{[æÁñ—«Ð]®"|‚À¹ð+_ù éjù³gÏ>ÿüówîÜáì‚ÿ‰p Ùe½hIåö]RQnžoˆÝoÊû†jÎþ‰Ž<á®]J‡D’§N"oíAÛ‹tþüy[jÃííÁ-Wݼy“G@8.ñ.:ÛÜ5ctZæ Ìä QðÄIÃúúº5þˆ‚yÓ¸qž&Q±î‘¹ôsk<‚å€(œ¢àƹ/®"a¿?ÿM¤¹;^NnÇŘ»¸¹ÂâÏ@?ä67b1öÎsw«õøÄOصõ U5#Ç{ú§fÏ8¹9ìsÀ#ìnþ©þÜ1*Åñýû÷ÞH¨ˆ]…˜q€tESS¿è7bµêÓB|šé ø±ÔÚîh ÃW¹ØñCÕi,ëœg ÙÎZì²Tô æ™ds–¿v•ù4±7Uær œÄÀÿD3óïÒÆ_±_2ÍnŠpˆã ú3«ß bàT‘B;ëîÑXÞÚÃ"%–.%´ù,%Dí±«Ì§»Y;°`›<\Æâ ä'‰7QäØ6‡@³ýo`8{ý!»| [8KžóB:ÿp_¸û_l—ÿœÅÝÞ²½óþXðé*\”HÀ•=}ÒÀ ïR9J™H6êå® hžcØÞ´T:ù´Ð­úȦÓ~°c2švá—¾ô¥ññqs±=qñÏAÀ³öR)†š¿£˜ÊÔ}F‡H?ÆY]˜V¹×oâÞ¹6›¹sòäÉÚãü²®¾¾žæBîõ¹„ôSçò¬³Ë £Ä:¥‰ÅŒQçnêÖõMj]˜–$Œ9Ä’¬À”tùàÆcóƒ7‹hpp< d‹-¸ákê¡Õ뇔p¹K‰ƒ´”ÐóŸ%œŒ9lïÀÜÜ—ðÄ÷|'É"¢p æ5æ^¸GK°EáÏ^¬äŒŒ÷Êvh&ëì5ÿ´ùìAÛ‹gºüÇ'ÙkùìïHeép"ÀÝE$.^$ž §NŸ>Í«eýù¢–‘B×gΜ¡äí÷Â|tšš+cUb[ýØ÷BþZ¶ TjT‘kkk®ò%®Ã‡[ŸsGGœòõ(¢³³³T»(Á¶‡Y±èMÆäQ¥ÚÐk.±Æ¤Þ' " _{ìØ±twwgÌ:›ÚÄ)Ò-v y„Oš‰‹@-\,1îSôðð0Õ:AYRý:mÞnß¾ýꫯÚçU¤ˆ#rx#‡Ó¯¿þºó´´x8Â$[[[m¯U544įôDx{èÐ!²—XðÈ¢ãqߺu‹ô<œ:uŠK¸–Sþ”ТâQi gé!ÙödÏW‘¸È2Í2‡Ò °nj²Ô¢ÀruÙ›mvŸ=ZfI#–æß¾ÂØ Ât)Œ—^z‰GŒ;±pw.Fû*Ž÷Œ›^˜6›±žãf)­6<µnE·/Jâïí,tÚ:„Ãàè¯3¨1—<ü]vá^nû~œÑÅB°ŽJ\p§jC9¬7ÕNÙ¯]e—’á÷c‰qþtú¯2—0°cìoÇÅ8¶Ž\¿ÿŒIõç›Ë=6ºcw ™cßÂB°_—ÉáÝÍZÞæ™’ðíƒ{¦þü ÷B[tΛ˟@¼á Ãgš1á>ó?|wþÜ`½èî/Íûú°»ðÏëaᨗ»6ÑÞVɇ†?möHVÌÆdÉØ‰Q…5æ”TÒÛA¡1²±ü¢º¯¸ÀNÂzŽ|¯í„è¶EeÆ3FRÖÖÖÚÚÚi›²è'/jåN bL!ŸöàøÐ¡C6M¹0²},D2QèÅÅÅ2èåüü<Ú³½½}þüùjßê'N—bç­­­ÀÈ;Q6hÅòL£ju544\¾|¹»»Û}5…lèâæ×†(Q3ܾ§®¯¯kÛZQËØ7õ‰‰‰¨Dòëêêl€¤lèZC#ÅH¶uÃã"„ÆþØØØ‰'*p-L!Êò¼²²¡<§ŽÌ׸îÚD @l„jØÝ¦–.Þ®®.ÚøªMD­a‹¥pPŠÑÐÙÖ<ÉF½ÜÉ„úÂ&)9íò Z[[³­&fffÔã-j¦ãããW¯^ÍØ2.&Xw<44ÔÖÖæŸh®ïZ@#Å’‰™Ñþ¯Ñ…myT6ójqq‘ …†‚-ƒw~=ÛÛÛÓÓÓ4…±qm)˜hÁnöá9;θH™H²¡‹ßŒ.›“Ú¿¢uܹ’dnß¾M °´D)pkÚ766–îËQ¸'̰åz´vw- :±Øê¾¶&bÙ è0¶ŽXsss´€"ŒíÈ„<«ÿ3„{ÂŒ¾¾>És ‘bIæå—_Ne8&„¨pÂmë’ÎÈ•†:ÉØÊÌ{î‘'„¨LÂÍkÐ5…¾C'ëðT·g-°µµµ¹¹™N§5„>Iø¿Fë t­!Zˆ„€0Û£q'DD‰ (±cе†Z!*P¢/Ð5ˆÆr !DEcJNž<)ºÖB !D¥söìÙ¸“ b@ pÚÚÚâN‚¢XTkå"!ŒŽŽŽŒŒôööj~É@#Å„H›››+++q-ï*„ˆ)´BQ‰H¡…BˆJD -„BT"Rh!„¢‘B ‘ÒétSSSÆ……Õˆf[ !„•ˆV,‰€­­-›‡êß´`ÎÃŽÛ<Âî˜;©«ƒƒƒp,ðþý;FGG1§2ºódÏãðÝ­¬¬hÞ­HáÒ”­ôùÝS¡½ã2–¾l%+•¥T¦²—²Œîâ&ÚùKk6wwÚø®¢ÙÅÁÛóæMrriiÉ9®®® 4=„c;pooowW=xð€ãp8333ÿøôû'@z̽¡¡!àæN8þÄãØäƒ¿8Z ~wîwµƒ?!ªšŒ¥)[é£ øÝ)SR(}ÙJ™ —Jçž±”‘ª€»EJò\ø$oHFw Ç*®¸ó^äB§X(ŠÖÖñ+«©rÀOØÝ*ÿq8QôK¸óPâlî»?gøt óû±öDF÷láQÕd,5ÙJŸ5²ÃîÙÂÉVÊÜqÆÒ”Í—€{¸eïRž£>±p¤ÐŽFŠËàà +–innÊè~ìØ1ÿßÝœcˆ(ÿæîŠŸŸlîÆòòòòqßõµK„Hû-}ÙÜs”>#ciÊVZ3–2BÈ]úeeeOwÂÉ]q‰J@ ]B¶¶¶(ÀçÏŸ6÷ü¿ãÚ·¢Ò}÷šš —ü¹¹¹Œî¢á}£Úå7î„$l¥/Û÷ãld+eQAi%©„ïÿØœzX…ÝEå#….”ŠÅÅE dww÷É“'ýîT£æžOÙÞÙÙ1ÿáabQAøÓÓÓwïÞ ŒÁ2v•ÉÈÈöœ“(’l¥ÏÜ)5ù—Êl¥,*ÖÖÖ¬=Mø~%ÆÝ*¢€»¨ 4–»TÐ^¦ÀP,Ãî`]já³a(`T»ùû/Â_ZZjnn»Óî¶á$BÔ ÙJŸ¹[©É³Tf+eQÑÑÑAi '÷¦¦¦U¢ÔȆ.´¬i2gtß×ç)ZÒ¤~cccF÷ÞÞÞüáö9àQ¤»B¶ÒgîKM6öë¿Ð’ÎXZqÏXeSÛJe@Ô÷ë."A6t±XÏRÊ3ŽÝ'gŠÊæææÄÄ„ófŸÌ}ÊÃïžòͰ$¤ËºÎ2ú·E£œÿÛ·osI`¦&¿¸z¸4pl)»¥ÖnáãHøÝ ß}MçZ·[–BT#KS¶Ò(5\(•Ò—­”Ùq¸T:÷Œ¥ŒäÜ­´.z˜*"KO6w Ç45Ûš ¢КbÅ‹î¾üQ`œRæãN›Úõ!¯­­;w.Z÷Ô»æü=lûu§ŽÝÛ½££cuu5ê߯»( ªÚ¡¡!*eØ/Q•²2”>Wj"tÏXAù=à."A -DBB ‘0¤ÐB$„­­­ÍÍÍt:­ïB$)´BQ‰h,·BQ‰H¡…BˆJD -„BT"Rh!„¢‘B ‘l­ÛÎA‘¤ÐB$„ÍÍÍ••~ãNˆ"¤ÐB!D%"…B!*)tÂÙòˆ;Bˆ¢PA®M¤Ð gÄ#îT!ŠB¹6‘B ‘ÒétSS“Û^PQíhh!BGÜ©BD†lh!„¢‘B !„•ˆZ!„¨D´?tI§ÓÙ&f´´´,,,Ä@!ÄÞ466®­­e<ÕÐаººwEÉ‘ @rÌʸ~ýzÜ©¥‚fÙòò²fÍ&†ááál§nܸwêD9 L2šÑçλyóf™S‚ðàÁƒíííÙÙÙ¸s%áܾ}{nn®­­íäÉ“q§%ùœ?>噹,], ²zÂj)t2™ššêìì 8nnn9r¤< @˜1å'''©ÂNŸ>w~=´;í ¿té’ väd,ÈÈ3"÷Ý‹r …N,Ö75HyzÆvvv†‡‡GGGQh¬ö’ZBÄÑþþ~~)_ ‘‡(È2 k }‡N,¯ÑåY2ª¤¹¹¹¾¾{6äY$Tmž™™iooǤŽ<ü@ÉÕP’šB6t’9tèmª\4f üÅÅÅRXBT8”5š§ètä­agFË€®5dC'™¾¾>;(ƒmÕÓk¯½&yµÉÁƒ———ggg#·¤]ù•]kȆN2¨f]]ݹsçÊ`@?~¼§§çÂ… qß´q‚±[__¿¾¾í¨LÌh‚•]khçŒ$C£Õ<|øp©#šžž¦J’< 0÷õõ9s&Z5Õž(µ‰z¹NäúûûóìHÇÂhmmÅhnnζ^’U Å«–ŽÅ#…Ų³³ƒÖæ3ŸhóüüüÆÆÆÊÊ "­ZL$ƒvuu•b\·¨5¤Ð¢X¦§§Ï;—ÏááaDúÈ‘#÷ïßohh°™Ó¹/±é[6"FGG;::ü¶··s‡`¸Šk÷{k\å7ôùKbZ[[§¦¦\’a—J€ô“æ. gua~rSº®”ý>ŽÂÞl\¸p—¤÷%j )´(–åå妦¦||b:§¼#‡nlläxÏ¥@GFF°¶iØßÍÍMÿ†¨ï©S§r\Ž4€_®âÚýÞW=xðÀÿ—ÃéÓ§ûûû»»»žqœ››+aFïEÆÆ é' -Õûò³g³ÉÉ'ióçp„ì÷qö†d#N/..–â¾DM!…Ųguìhooç—zsppÐê¯=ûƯ\¹‚ŸÞÞ^¿ãüü¼uüYȇKdøéøO¹c÷8,ý.=–òŒQ8–`{(¹s/¼'•Ù§"ªŒ]‘h<2žZZZâæoñÓB²E¦­­ÍáÂÂBÏ7nÜ mØX(ñ;wìvRÞ*N)ϼæìFû¹¼q ¡²c»Ä<àâO$Áš`p×Òà¬õ½›κ«Ì…ߣGbr™‹]h û‹7o±ã¹¥¥Gÿ­Y,mDÇ_<àÍ.±øµ{7ŸXx–TKIuWÝ¿ŸXÌ' ³è8{õêU»ÄrÒ2Ð <[Düºcç“Ð,©†¹X6Ú¹‹y Iä¹»kíãa¹H­¡†».$FZ<éÍ›7iNÙ ú³ËîÈWY°–¥þSþcK¡ÿ-{-p›w@öú®ù'üöôôXöò@q·¸¸A $öU‚ìÙ]ºt‰ ô§*Ÿ‚,Œ:á„ 6åߪi[h,cuPd¹¡úCNR^wwnŸ&?–ZóìdUàÀäg}}Zu׫úq·:Ž–ºu7‹B#Ì^WWŽNæ90apênQ¸«Ll¸„šÔšV«Z®Z.vK§…lݧüºG`‚²Ztø·Æ‡uùZ¤¸s;ÖûJV¸¤Zß;·`¿…Ëëvæ/ar•»;<11ᚆmù`I"~ír~-@S8óLj3*´5³lÛ4ÿû@Vð\8&ŸíY.I–?v³)ÞhÃÙ÷缉åŽíÁ™”N¹c×`r7hÕÝ‚­Ö鸋nÄ<÷õõ¹‡Â_kOänS:ÈÌ@#cOˆ…äñD,ÓÜÛRX)É@½ÜµÅÚÚZ:Ny]©TO‘,]WW·¯/Dm¤Ý:*×®]»|ùr WÐ:Ïž=›ò&ƒ...ú»UÑx÷—cªuë8¥’½}û¶}{FQ²¥a||<¼ePÊëÆ4ì3yëåF8ñc‹ÌsÙHªÞ@Ï¿õR¸Ïœx¦U‘òÚ(øt7Nì¿ÐÚ1ÄHªY„õÜl …Äb½ú¦dÎéîîæ”ÿËÂìì¬ÅB€œ"ßPñÔÆð×<¤²ÏÜ#¼TáwÀžrê¡•¼ç‹a틎'îÜdW³GÊûªb)AÌxÄþSîØe£õ.¸tIJ=\ÌŸ»»<ðPPëÞÞÞ=oÄžÂ~×#=´'xÜöž‘~!j)t 199‰•I%ˆÆD¸à2UBÅwñâÅ”'lV…Qý!ψt`\O?Z2ø÷5šŠ›¿œõ¯áÀMqk¶R„ªcâÊ6› …6ceËÃÊ*J‹4|¹ÅÞÚÚJ²ýúçO¶ ¡ûZaà^^~ùeûŒMt¦ ·nݲÚw29! ÚfÉ’ÊÓ$ÛÙ“¬³©kSSSˆ%ašDù'ü˜F¦­“óø±›%OÁôûõ×_7¤“d˜|òìîÞ½K,þOË„IìÖOJh±½úê«øÁeû!þÏÛÖFÄ…¼ çž}ú%+\€ G#I‰áF,4üð°ü§Ü±Sh$Ù„IúqÌÝP 9866f ÍËi…á¡XR¯_¿ÎÔžï9™Yð~”ÜQðJ å—H0RèZµ :F"ß"š1Sò¹J}gT 3Ø èeà5Iu늧¼5ÆqÁÂL]<<‘"ŽixóæMwS< û´áÏdÚI®Kƒø‹ìY'3÷b÷ëº"xÊdþÓO?òý¥=ðƒŠÛÜ9K ~H)á¬õ™ãˆòù_nœl´ü±l±B°6þ%êhÍ]333Ö5íü»ÿ”Çö8H §lâ7‚ø¹7!ðJ8ÿ\ÞÙÙIú¹SÞ+þrŠG`ŸZÜ4„ÜÐ,öß6H‚p¸£bÂUÖåN8Ö§F£6¤..ѶÔ_´÷ãZ4ÃŽš”ŠaãØ:«—,--6‰9ÇÇF”MVˆ7  <Íb´#)¶Ê7%×¾>èñÕ²¡k‚ŽŽê—Òí:e‡q-¢„ÙJFEvùòåpÇ©Hy4Y¤Ì) 3Áó”ç¬g ÷H¢Æp¿sçΉ'âβ¡Ž}L/Ѻ*&[¥A»OŠZæøñã—.]Ê8F¡`›››Ÿ~úiÙе†lèäƒi›çªœÅpðàAäYûaˆš…F*òL 5ZyNy_©4®»6‘B'›+R†ˆ¨›¬GNc[D­a ÈŸ={¶{±G.ù¢ZB×yNâŒ$¢åååÑÑÑt:­D-°¶¶ÖÙÙ‰ãÉEx4ùôª=£[XXX\\œœœ¼|ù²­Áw=ÛÛÛ¼ä6w®¦óððpÆuuR¾Õ~D²ÑH±„C£[6ÏåþK†m¯cj„Û·oÏÍ͵µµúèûï¿_@¤´š?õ©O}ík_û•_ù•ãÇŸ>}šOëûìÙ³?ÿó??;;ÛÑÑñ÷ÿþß'Þÿý¿ÿ7¯Ç¡C‡>ñ‰OàræÌ™¯~õ«¿ú«¿Êáàþwÿîßå€ßººº=‡«ˆRC}ýÎ;ïðRñžÄ–ZÁŠðÎÎŽk©j,ÂýèGU„+宾÷½ïýñÿ1‡l8CÉ·1¢”ŸÀì?øÁü3#766âZ<„d·´´ÄµpP ¨Ù]~T„E)ÐXîŠàãOý´GÆSòp©~îç~îÍ7ß,ÿ'¥úúú2Ç(DE¡",J:Q|øÃ¦!œ{É¡¥¥¥ÈËÿžk&!òAEXø‘B'@«<̧>õ©åååc<|øpî…ù£",Ë]s9r$ÚÒø‹¿ø‹qß“5DäEؿҙ¨(¤ÐµÈ§?ý鍂м²BìI´EX+rW,Ë]£üÑýQŽóm>qâ„[‚XÄËÖÖÖææf:¦Î;-¢ä¨×RèåG?úÑo¼QÌxJõ3Ï<£Ö·± "\ ¨éT£Y8¹¼¥¥Ee[ˆ¸P®dC×:ô•Ù„}~¢PN0Rhñã5þçÿüŸýy2B»ûç~îçžx≸“,„øT„“ŠZü„ÍÍMŠzÆýòhtüã/[(„¨T„“‡:äX–ùСC}}}¹/wÛxüð‡?´o(ÛíYùŒŽŽŽŒŒôöööôôÄ'*‰AkŠ%•••©©©Œ§ö¼\;#U)ØO>ÞÜÜ<66ÖÕÕwŠ„ÕGÉ{¹;;;WVV$Ï¢¹páoþÅ‹×ÖÖâN‹¢ú(­BONNR7-,,h>®¨Mé–––¸Ó"„¨2J¨Ð[[[Xwî܉û…ˆDzdd¤µµ5î„!ªŒ*ô™3g&&&ò·ž—=¦&øìì,bc Q$özzz:ÿK  ÞÛÛ»´´ÄoÜ·'åB_½(¯*ŸR)4ʺ¾¾Ø17Ç766vvvªÝÓÓÓétZù–¼cÊ«Hp-ž¨tºT Í“.r'y[qÌ>c>|8õAû8#&áÏ?ÿ|Ƴy~{³Ï‡»»»q­æX(A…€½877÷àÁƒxsQŒ<̦¦¦‚×ѣɫ:´,ß.^¼¨±ô{¢¼ŠŠuºT+–PDþ=lcc#ÇYÞ*Þ°;wî´¶¶ºØ9Àª¯¯ïêêÚÞÞž5GlllŒãáááþþþóçÏ÷öör Â=ŠœâZlúöööîîn*Ù'N`T‘¬"B@Q7{Ѓ_ýu¼Ù˜ŽŽŽ£G’€€†;áôõõѸvíÚk¯½ænÄ\.xà­¡¡ˆ-¯=??ÏY"µ{Ä‘³(Šõ4¤ð \2NûåÆy¦È$/:•@¸#ncËyËCkq–ƒð[A,öiÃB 1ö ¸œ;%p×ìCõ¹/î‘÷&Ø›C¶XN;m ž&¯?ÍeƒÛÈ&ÏÔCCCášBo´äªZrʶÀ~òª¢ ú¢&¤º º3SgCdvKÇæææ¾.±ô,--Ù_ªã”×çÌ1UdÊ«díUgÆÝMq~¬.ãaZÈv¿übjó""ü]XXàØ|š7޹օláàÎ[ëÒF.@EàÀÂ$lÐDzKi¦0Ø=:ü–¹ÄØ™@n¸Tq›$žpÐ3‚?a.Kíü•»ÿ±X¶ÐâqÙâB³_γY“Ü£¥Ê.w„ƒìÂ1S›ã™™ÿó 'žKìN­gØb´†HÆÜö¿Ì÷@ß²}áæ¼BH/)Á ÷¿ ˆºËm~] dÎ~ …Ë“ü‹ƒƒ§LNî~à±Ö ä[Í¢¼Šå-KѪt©j2ªX˜RÙдHM1!`ÍP]brf"._þò—ùM§Ó‡ÂÈó{æ/¦»+Œ*Ì/wöÖ­[~ý¦jÆ0B±\1 1Ïž=»gzˆ”(ì+ V©ëÍ (ÚMTúÏb¡bÉ‘¿£ÙIö8Ã#s¯¿þºûKsŒÛáy£Üþ¤Ú™ƒ~° a×kåäúDþ`>fOªü&{Ê“@ò$܇ VÝË/¿ì\È |Ò¨ä6­!Eb²-kc yë¢à*ËùÖ§#^€›7oZ®º`ý~x²¼3¤sß}ë%»ü ^þº4Û7‚p综€ëVÈ­¹ßkkå[þ(¯"'c–R QýâHM‚åóÍ¢T mÛU!•#¿Ö‹ZøE(ÐãÎù;Š©jÑÝ”÷‰”:‘¿f‘$ŒÚÙº7©a‘"$Ÿ¹ÇŠ#K„ÓèÁ%ÙD7- ¢8uê7Âo8LÜý¥/½ô)±.¿äÃY»A<ð¤¹#û삵>dŽÄ577gwÜa_m-[Â}2ˆ÷BòìÑÐ~ª¯¯'?Ãòý£©/¾ø¢Ë^[“†Ñìì,/I]]]>“Ý1¸ñCø½½½~ã;®^½J³Ãò$£¬âÈ©ÎÎNžˆo²‹gír-K3wÍ%Üxþ"MPû®z³0”où£¼Šœ|²”ªjüîÝ»{¯óQ"“Ÿèi/äiÈKáK°Ï.a?á ‹»œ¿8Ún€©Ô•¤Ðy°_»juuÕßEϱ¿9`àØ`Wù“a!»¹ÆÅâãOÄâR΢ÀÙå.‹Âþñ²Ååªÿþšg²Ýÿ œ½.ý¥ËÀÀSȘóáƒloNÆ7Í…ßC ·ýfÌùŒ`Á[WžÐߨ^îÝ‚ò­fQ^E宀ψ‘}VËF©z7§üÄ%ÂLÂ.]ºD cL‰m(²¯FŒ¨^\7{éB ù7ÖýPÿ#Ò9j†Žåž™™¹råJ¥MßÄt~íµ×Nœ8qáÂ…ÂúK£beeåêÕ«Úõ«¯¯¯/~͓ܤÓiÌô"×!B@a£ßmŠÊÐÐP6vC#ú"drrÒ—K‡DͲ¸¸ØÚÚJ[¥@¦±±ÑÆx‡O•v>tWWW{{{ss³©µÉÚÚÚ©S§ÔHBdcxxø…^Èxª´6´a–ôììla‹ªQ¥ŒSöæççk|¿)!DnȬÅåXS KyîôÐ.="ñØ´étz}}ëYò,„ÈMC »—j]îpô T[ÝÝÝ«««h¶V•‰äÖ­[ö†c:«ÓH‘Ù¾‚•£—;†-»XLˆª¦½½vç¡C‡âæ­­­ÍÍMlwYíBT¶ÛPx•±2ÙÐ~h,ØâSU´™£•ÏÈÈÈÐÐÐÀÀ@v@BDòœquÂjÚÛJ!„HçÏŸ·Í‘H¡…BˆJD -„BT"Rh!„¢‘B !„•H c¹…¥ ··÷üùóÚ9CˆÄ …"!ñˆ;BˆÈP/·BQ‰H¡…BˆJD -„BT"Rh!„¢‘B ‘FGG›››ù;!BˆhB ‘677WVVø;!BˆhB !„•ˆZ!„¨D¤ÐB!D%"…B!*)´ !N755i]n!ÃÝÝÝ¸Ó „BÔ.ËËËüÜeC !„•ˆZ!„¨DÔË-„B”›S§N¹õ…vvv666ìï¡C‡RÚZ!„(?===~—••;°ÙÐB$„­­-šäétúÈ‘#q§E±7”VŠmÀñàÁƒ÷ïßç7¥ïÐB$†‘‘‘cÇŽñwB„yÑßßvìëë3yNI¡…BˆXèééqblð×/ÛRh!„"Ðc,f¿‹ß€NI¡…Bˆ¸Àbv’0 SRh!„".üftÀ€NI¡…Bˆ13:l@§4ÛJˆÄ ÙVBT)/^œŸŸ¯Ë-…B!âD;g!„Õ„Z!„¨D¤ÐB!D%¢3*ŽÕÕÕ¸S‘W:[ZZâN…B$)t̬­­MLLLMMq¼½½}øðá¸S´?Ði›À×ÜÜ|þüùsçÎæó‰²1:::22ÒÛÛÛÓÓwZ„ …Ž$ùÚµkËËËíííµjµÏá^ÆÇÇm>_WWWî¨êØÜÜ\YYq;Î !ª}‡.7ÓÓÓét…Æt¾ÿþ7Pèˆ6ôÕ«WWWWççç9®¯¯¿xñ"vÜéBˆjE ]>?>44433ƒ0744Ä¢’@kƒ6£GÖÕÕ J§…¢¤Ðeb||¼µµu```aa¡X ¦¬@’Àdç‰ÌæC;bÂb4›Xß6ls3=,˜ ÎÁÄSöÈ“óós,~¤ åç"Ú×nK™jã C·ÀDÕT²i¾XcýgPyIÇÅ5ôâÂ;F…á_¬Ð(r…V¼E´Dô æUO—-òõõõˆi/e‘«4ÊýäÉëfÐÜÓ\¢w¿ÿžu’bww—ð(9j|,L߉‡%ªÐ—Ý0Ç0.ÕçÈ•yooX–:O§.HËžw3Ûï'!t¡¢p0¬žªˆð;;;©‰¨Ñfº£ì‘÷"Û{²Ç>¦tŽŽŽts_ãÕ¼Dä Éñènœú ­;$AT~òãT“(à !“WWW ¦"Óð¾‰Úï÷×××'“!éœÊ^Ò±Ü?eJcß ¡r‡c/3Ž>Î=8àC—“.su2Ô¼(6õh<þèõˆ3‹ôt˜{Õím¥1ÉÉ„DÂì¦= á^~¹£ÜDTÈ0¢Å’iqùÕ ç]R²©zeõ—ýËMìµãð Lâ&AqõW8d 0Lª0r·5´¿”vʇa©„wþ•d³ÂŠÀ®¤ÄÓó†2üº'[p\L=¯%—)›í¹Å&[[¬ŒÂDU…,Ű*N¼•$±Ñ‹4õÚÁo=ëºL†íñ9›ÔÐ԰꾯ӧ©nËÕE£: ]¼IZ4þMhZ §VÆí°¢§'NËW[• 益N]ãu×××NG³!¢d!ìîî.Ÿ>}j‹+lj+W8ˆã˜í^Åúý¾­(8Mˆ’q-þ o’âòòr_ i!J”|ƒD* G÷«;rCNÀÙÙYjóMg6¡Œ¨NÚ«Ô¼wƒÁ  £_g> õûúõëX~–¦înº;2WhbÂdFaj7 ™­¼üR`Z %Wîîg`F÷³0„ægÚ)½»{»*ĆâCÚZ^ÝAa´3„tsCN–]4ú¸üœW*šËm¼zõJ•ÊqÚ:Z¼ìW›êp ]2kkk¶¤8çççR{4‚DGžœœhB”̪ ŒyŸÑ·=k…†Yíj@¹‰u¿LC“¥V5.jhYÕ:–b& á5¡ƒXö)ôe­µò‘¨œ>"´¦Å•´³˜ ˜±”R‹âªÆ5tÉ ÞPãÆ²i¡ýmÛBk⃭¢! ÓЩÙSÓÐaBÚÁ445/;¸¢0©õ¬–nˆVŽ‹æP4]\ÎØt»]j¸w­œ…‚Vwii©NëYøwè’Á üðáÈíÆr±™qÛGâðb¬E±ïlôÜÓÑÞ©h|G»·½2 ù ¯_¿ÎŽ¢;³6Õ[kŸèðÜ€Ïq#Ú®c{{[½Òú'͸†.Ï›7olàºÿ§OŸ8ØØØxÿþ=z”FpkkKîs©"´†åæJ»ÝžÀ+Uíêêêðð0º÷ÿ`ü“pyyùóçÏÏŸ?ÓE uÁÜðò×`08>>ÖÞÒÜ* )ÉÇB;I—³^Щ Nþ©ô´jó9ã8u"—&ò9Zµ÷ûaüuWêö#ŽX]]ÝÜÜæd'¹º577ÚôÕˆbÎ"PÏ\D›òûüùó(»Ž—FÃNѲ) JóúãÇn%g?~$ u:ЩРs…`&ÕÅÅft*$§rÊXîöìÙ³+½S:TÑÒ}™9NSÐÊÍÈF…nCW KSµx1w»]9ÿÀ&®"Êý,Ê U*Ï‚fiµZá$íѧ‚ûÈ…½ùâ¡oÈEÙÓÒÇ–P¯×3nnn¸Ç1¦‚i*c6dq°ºd‹7]Jó†Ô$¥_ÞþÐt8μá6tU QEè°f×ûš =#-{Ý—VÊZƒ"MËâ8N ¸_îªxñâ %JºiAfmÍûà¦åŽã8NäºRºÝîÒÒR¯×kP†V«µœÐtfü¯ž×××TpÇy,¸†®ìÅ8ŽÛíö4;MÃæææ ¡Ù|Àt~ùòåÉɉ«gÇqœ‚øL±jA!iãÕ•••~¿?#ók¦×ëýùóÇÕ³ã8Nq܆®4ô·oß´wEÓ²ÔÊïß¿mZWÏŽã8cás¹ëãööv{{ûøøøË—/sï¬C{ttD×d1Gê§ÁÕVŽãTk躡}ûömÇN§ÛíÎ_cÊnmmÌ}GÄq§:|”»nPɘ•Z¼¶¶Ön·wvvÌkØãe0¼{÷nee…þÇòòòÕÕ•«gÇqœipºaä™]K„å·«i‰ÆãööV˜Ñ;‚ã8N‰¸†ž9‹‹cÿÞé8ŽS)ÿó·.8LIEND®B`‚gateway-1.4.5/doc/wtls/fig6o.png0000644000175000017500000015442507374232663015171 0ustar toljtolj‰PNG  IHDRŒ©¹0êtIMEÑ :üß¿é pHYsÊ&ó?gAMA± üaؤIDATxÚì½{T^WÿÿФ ½Ao¡7hSCë2: ^J¼F-Œ—0ΔÌê,ˆZˆk:Z¨„ŒË‚—Àôg@ç°U¨:¡®²Vàš Ñ é´!]JP§`[ÛJl¨IÁ6ÉïÕóI¶§ç¹pž œçòy­,ržsöÙçsöÙ{¿÷gŸ}öö D[[[AAlo³0‡öîÝ{&SSSóóóyyyf'{ŠŠŠV­Z533ÃOþú|>BÊ!¶ù»{÷îÕ«WKxÎe'á7mÚ$§8{äZgƒX4˜¢xùœ /ù™ìJþ7……ýlP@ìå1tQ”TÃgA‰e1ttt¸‘ ©è͈U<Îó¢¥¥åСCGuì_XXðallìÈ‘#Ž•••;wî,//'½$fþ655ñ—¨HVª›ÖÖV®Åér 2ÏÝ"Ûuuua]ËNoo¯\¨¢¢³}НÕÑ`)Y”…ŒŒ ),ü­­­eƒ‚@yœžž–ðR@ÈÕ,R %éA̲³³EY ·Ývú²è¹›7o®¯¯Þ®ÅûúúboFGG×®]Kƒ=cµÜ©A¸ñ§ånInžJ„CÔìÚîI‹¯|Ær²ÅWæ,â¿«à7È!ã+p.ûù‹®žÀÃ…d'ÈUpë9‹Æ ‘;ûûû{zzäîÄ®óÖ¢Ä)täsŠÆàà þâ+SFذ—G) ävJœNþ§ø,ý–’BÁ§\Jg±“bkâ!NÎ’rgN‘8íž½¢Ä?dr*QrrUU•È„doüC¶Éö¥¥¥µgo)Î%¼È±•””HIá(Û쯮®I¢tñSèÌF³(NŒïÎÖ`“4á¹Ìb[,“Îj*îk0±±±‘Rkø‹´Ýb¹IN$ɤ&"!ØI<>«œS¸¨,L:²-é…*ÛEš{,8*vbŒDkÚì§nò:)Ê"o) ’Ï),æ•eò(„ìM~–¾n{! 2O>§lvuu™~r)üÄ;—ªåf›rÄ_)zœHœr Û˜!¥ÉëôP·ˆH“ÿE‰$ÛÏÎΊLç)²-Ma¶í \),r:gIy!BÊ%‚Øø+û ɉ7K©$Œh¿\‘غ¾Ñ°ÒáX=zôСCR#`„ôNc±[ÂP°>¼eËüZî¶¢¢"˜›>77g¶‰ª²²’;d{ÇŽÅÅÅTC }}}òšØšššÄQ¤1 Ñ“FFFÌ~ÌÃ<ö‹<ƒ/}èŽqE‰hbÖÕÕ‰ûk ™y||Ü”Géߦ€H92€ðYYY” öövβ¿â‘bHA£íÏ6-lÊ,¥A¼}ûöôôtNw|``ÀôE)JBÐÜÜLîîîžžžF•|6ÁBªdÏê‘–>`dŽÆ¨ÏrD%$1Pp(DR7YP.$* ƒHÕÔÔÐÆmmm%N ”Db$r)^­:Ešj‚¹ls·ùùùüÜ·oUÚ,¦p“uªLDk¥ßŒªÁ?öÜÜ\ó"Û“Æ;ÛÔœE­DeĹ·GŠˆï€`ÔP ¼ýöÛÍ~wvv)kß/©FjbÀððpLÞ7(Ê’BÑ#3SÊ|¶ÂBž'“K¡ÉÉÉ ˜™ L˜´b¥Jêíí%6¢•â&¯Ê(b(=åš…Z‹*ÛO¡PÓ¨uó&OQâ²4ZC†§ k߬ Ç·ÝvÅ'à N¿Ž²@`r~®…4aã¢PC ‹týnذmN¡½kà+šAÌpxÖŽQÓ8òòÓìd’)ï†ñnÙ/Gå\G $™ƒŠãköË6í#Tù)=½þ)‹ s³!ûÅB OTg¬Ñ:VI$Ç ¦€ØK?Ùï_@(eˆ7¥²ººZ›¨dC ¦ /%bÞâ̹Ò-Ù|ˆ¡(‰Â„…ÉÌ&«Kñ±go9äÐyytÆ&sgl%ÈÄ,ØOô/\CÓ‘+ÒΜ¿îšä4ùñ\ù+o©C@ëŸÛÑ;·l`*N?5—'WW”å¡°°òHY[¿~½¸Ý‘Á¹“““^•VEñ¼aÜbÇ;Vãq‰Hƒ\ö‰Qw8º – /­(ˉûòÊKvv¶öu+©ÆÑ£Gåen4Pñ £ÇAä"­(Š¢(Ê’r^ôQ(Š¢(в¨H+Š¢(Jœ¢"­(Š¢(qÊÊè£Xdf•M›6åææêØEQ%éIŒcãããÅÅÅöÉ\Ö®]‹NŒŒ˜¡tššš››CÂc>¾NQEQLOOÏÏÏÏÎÎú¬ÙýÌLgf² (I‘¨¬¬ 6ÝšLïÂQ3µ™Ïò¶;::Tª—ɯ>ëótþîß¿ÿ¶Ûn“CùùùåååÚÿ¡¤ â?°!U¹½÷YK0ég¢ õbÄ”çÈO7“€¢ÓèQUUUÄz/"-ùX*w*t3³ÚöíÛ#[ù =hllljjRaXjdSY$Ž¼è³šöjº»»{{{ssseb,}(J* S9 UWWS"ì5›099ÙÞÞNÕGÁ©««SµŽCŽ=Ê£‰~JYc¢¥¥%ܧì±HË›æÖÖÖ%Zò1À¥Öǘ&¡ÏÖ?#ÓªS¸G²¯ÔAnª®ËãÀÃÞ¸q£¶Ÿ”xC𛇒ŸGŽÉÎÎeÍÊÊ ËBz©Ùrrrp¤d-z]NaC*õ:%”7àqÔÔÔÄ|Qvž/µ_+Jx8áê¢SЯж¶6o3~ ÁNÎ ‹ÈJ 6d½BjY×ÁÍ Ü===îêêŠÀ®nV(Wo™ŸŸ§Š@‰)‰7#kãÊ‚ÁöåAƒ!K÷–——G0:§ÈâK:}ºçÈ:îK§Jd’`«T8ðR¤còRÝ ²Øg*CÍ‚³K:¸©ePhQë`3ÅuPAAA”U &9V_W”e†L¾jÕ*²â¢™™ÒÆ¥tË´ÒríïïÆ$Yó›¿^§Mê"«'/n/»»óóó'''—çZÅE;’•ÞÞÞšššpßÐË›ˆ={ö8úߦ§§KJJð>^QQá_6oÞ<77'ª½m<£ªªªh–KQ"@RÞ> y©ÁQÁ/ •gR¡µ"¸ô#“ é©‹Øåššâtüó“6¾Ë^÷—ˆyœIžYl{ÞˆmïÞ½^ß–—H®‹Ø[¥AAíý@U±5r)âTB@®ðd   Ñûâ™H#ž$‡û7I@L 9ÕèôÒ©©êtd瘄T~D…“üF¡ hˆ`/…šš¢çM2¥´Ø¼ÊZ]]Ð0oDZ2Ÿ‡É‘ zÊCž9xéê ©ï–/u‡‰‰‰%*ÄìõÍy@l[„òzéü])zQ¾äV…ç衤Íç°Í‘öªKÁNAA×¹bi1müƹÔ#NiHêxoT¤cˆtKÄvLÖR— *ÌTîöX–ùÅkhüëíÇ:4::úꫯڿ]>qâÄš5k.»ì²w¿ûÝѼëî©ñäæ1{nnÎÜÔ™ø˜Åe)˜žžÎÏÏŸõ¼1<šÌÌÌÇëw¢v(ëÖ­[Š˜éTAVXXX[[›p'TVVæåå¥Ú 2ê±èÜEç:ܼysÌ¿„ŽtzllÌTƒ^`ƒéêêÊÉɹñÆÏ?ÿü§žz aöYV˜ÐõW5<<üôÓO£Öwß}w¸°aÆ‘‘OnS©ìiž™è´cr¾d‚"ÝØØ˜X í;7óLYYŽŽ×¶(IÈÀÀMÀ„Sh@«h¿¦Ô¢´H¶oß«Øìáýããã^ß«´Ø^ žõ¤ÙûðÃ_{íµ_øÂPh²j-Ú|ìØ±+®¸ÂgµèìóÎ;ï†nزeËÐÐÐ7¿ùM÷ö¶Á"£”}ç¼LO²zÒä9ð²Ms²²²ÈiêLÔ“Žd-üü*¯ ‰D ¿¢­­ÍkC– r«ØH7ÿ¾ ãP¡ æ³á³ëI“wQèÚÚZ¤”¿¥¥¥yyy4=.ºè¢Gy—zÅŠ%%%œó‰O|‚Ÿ[·nýèG?úàƒº¼^{{»·] ccc²Tã®yhÉRãI謪ª’5I%†Pàx$¨BC]]]¼õÊ.)1Th)íôõõųBû,·V6ΓäxË[Þòµ¯}ícû˜8ÍÂw¾óS§NÝyçøÿõ_ÿeö£Ö™™™O<ñÄ/ùK—×£àù ›{®®®–Åš’ž•QBOÛÒÔÔ”R•‘²<à'466zmEä¬^½:##Ã8J”Äÿ ~©Ì}"Ò?ü09àùçŸw¬Ðò¹Ï}ZºÁ/rÞóž÷ »î;ôqͽ¾å7&Þª¨¨Ò ÷¾Ö%Ë6Ùê!•ÑrÎø£¤Äu£…––š^[‘$,Ûd—Ñ û ‘>~üø÷¾÷½w¼ã޼øâ‹¿øÅ/¾þúë/¼ð‚ý²ÍY¸àd}7Ã=Ї!XkŽ%%<Ô0W‰W¨Lãä³E%98tèPvvv¢7Í â¼‡6Qˆá »KŠÈëy(Öš5k~ô£½óït„xì±Ç~þóŸãßxî¹çyäÇQDýÇ?þ±Ë|{DºlÛ¶Íór"ÇbûÂ#~˜ut‡$"999 ÑÎUˆ¬¬,¯MˆüíaJ)Pç¾¾¾•SSS×_ý™3gpš!>÷¹ÏÉÆÛÞö¶õë×;Ž"u>úhEE…ý­ ÏÍÑ|*•––R‰oܸQö £Lò×eÍNF/**¢Ñày‹a)HOO÷Ú„hááz>ˆ!Î!ë†Õ5EžOâ¤E¡¦35FBCMË£Œ‡^É„†üൠn[9::zþùç_~ùåÁ¡Ð÷sʳÏ>‹ÀË„8î¯Z]]ÝÔÔ–/+«d×ÖÖú˪|C"£ˆ³®®ÎÍ £ÓPH¾>Uš)IP€qzŽ9’oA³lÑéR ypøða÷§¤eeeÚYšèðèñRxš´9233ù™å] ÁÀÀÀÊßýîwhmOzåÊ•8ßœþÚk¯…;X)##ýH#ê.ý*Y犘±gÑ~¡ÞÞÞúúú‚‚‚ؤ¥;xŽòÉq~~~ÿþý6l`ϦM›ÂZm3YÙ¶mŠÖ@_’nçβ2£’¸HMH733CC¶££Ÿ„‡+Krym{¨Ï“^îÈ*¾‹.º…þõ¯ÖY¸°.߬È^v…ærŽ0Ï=÷ÜóÏ?ÿÊ+¯œ:uJöÈûo7ÍŽÊÊÊX&gÀ½'Óëv"n4­´ÑÑQññ!âÿÛ‰¥Êÿ»ÏÐP"’u~½„bN¹À¥nkk;|ø0"½eËyóèµi‰·ÝÝTkö V[„ö;iн}/{FFF†††:;;ÛÛÛ;-º»»ñiŽ;æˆÂþiõ¢à¼›2‘§¹ä§êüóÏw£‘B£ÓSl›sÕiÚ .Ix؉;×XhdLƒÜ]NNN*÷Ü&ëWþKõÛÜÜœ×V,EEEþ¯VFHzm\~ìߥ®ªªòß¹wï^Ù¦»ÿþûå'Gb´y^^Þy¾s½‹¯¿þ:Œç;ßaϧ?ýé–––§žzê—¿üåS>úèÇ?þñgžyfçδDe¹Äýt¬8O¨,þ±tì¬\¹2à¨+¯¼ÒlXÔ©v©ÓuuuÉ4 †öur‹©F¡+++uÎÅ%T….?M\ d¶çÂÂÂdªÓ<Á!T;Fe…ŽŽŽêêjÿ`0âíðŒkkkÍáÆÆFŽKøÝ»wû, &U´/ÏN úä“O~ë[ߺõÖ[úûô_ÿUuçkÖ¬aÿÿÙx饗Þÿþ÷õ+_ùßÇßµk—Ïz-Ö㹺t€zzzÞþö·?÷Üs(.Màììì´´´€!Ù饗Ú÷©>sæÌÐÐPèž|r³™‰, Ø´iS \Œy£Á&Ó³S–j@ú© ](D}}=uýX+b¨E‘û¼Ž«È“¸ËŽïúPnr!›ššqÊéT\ò¶NjiûFþþ·°qãÆ7Tö­o}ëÃ?|ã7žzýu~âRŸ8qâw¿ûÿì’{öì¹îÚkOžAÊÈÈ”=‡F=Ý œâܳžtnn®(´°*=ýæ›oÞïÇê«®’§OŸö9½(nú'1ýoÿöoí}é\pAèSV¬XìãàÙÙÙ‹.ºèg?ûYè]بƒ*šuä “RÑÑQ2UÒ÷d*ƒ0Ë·|Ô³©3þ¹Ê"9Æ666†;A |¼È(dÑNóÞPÔthhÈg}jdwyí‹ÈÙ+^ZöÌ&Ûˆ‘Ù‰y×"ØÌÙ´ÎöW/ÌÏÿ÷ÿüOXÝAèô–-[܇Ÿžž^tð¡|íø” -9úôÛßþ6ࡹ¹¹Ë/¿ü»ßýî?þã?;gš{OÐVgkk+Ï›¬Cº%è-D ÷Ká!ë‡û±¾’ôPÛ”••ù,×'uäÙ@PQQ‘ýL8̹{÷îòòò`ïþPÄ`cwÌ*,###>«¹# ¸iÓ&jZGg°ñ¶rGýc¾x ø¾Ù¿¢6#÷~V¤Ïœ9ƒ£ìx¹šãLJ•jnúº cÿ˜J`Ï…^úDàO;N4¼öÚkïÿû»ººB }¤–OĵuÉ@¸’ÈsÊJ ¾¾Þ¾Fº¢à”””PŸ$ú¢Ñ@GÕ_WW—²•C0B|Ž(F\JÚLx•››ëÿú€ìÁÁó m^¬¸ìÚ Øõ-— oäW4,Ú×MNúä'?ùôÓO;öã »™w÷ꫯ~þùçƒýãÿøá˜DOš!Áä ZjwÜq‡yyŸ²PB:;;ÇÇÇSÐaRü¡ŒË').NÜ>"-Cˆ”¶¶6ª¸°æ×“·Ÿ!F•âIüÎwYt§éϥ͡€ñ²Qñî?¬^ür‡/W\&‘vÓ×][[ûûßÿŸÞ±ÿøÕW_]Ô™¾ä’KÎ?ÿ|ÿÙN ˆ}kkëØØXrŒ{¬¬¬D¡½/+&PBð™¶nÝ:::êµ-ŠÇˆB'͘©(¡ýš™™™ÐÓ}·Z «îuú¨EˆÁl¥™™™o¼1ôéiii7ÝtÏ1Öï?Hçää$úÇ555ä3UhM`Ή;°@‰ xÏœ Òçg`` ÑW° &„‘‘››ë¿“´Š`ð?­Ÿ`#ÏÃ]Ew¬.ï¼ÿ,Ò]tQX½CçwžûÀ‹v2SÉúûЗS,¡ÓYrʱcÇPeG´/¿üò·¿ýí;ï¼Óqn-EM422’(K¢.2a…ÿwƒJêPYY¹{÷îïåv í×DéØŸm8Xnïè•!ßam4,Ú×ýÀøëŒè^pÁW^yå[Þò–p¯ˆè^wÝu·ÜrË 7Ü``4»¤¤Ä¿'PwPYYÙ¢“´¤ TCŽv¨’R477S´Sy¤X@ð9¢Óz;ð¯ð,¼µÊ‘{¥[>ÝÝ|0íÀîF#ÌW\qÅ¥—^ºråÊ+VDoÞ…^xã7âX¿ôÒK8Ö>«Ó»££#A?"ìëë£&J &ŲA;4•'ôNq¨^[[[Ã]w$E º˜™™ÑáC‡ŽL ö¹KÆçâï-iÝëxY.îe <é·¾õ­QÆ`Ühy¯|ÕUWá&ÆD¡íw{ýõ×KÐ ¸ãŽ;bùrÒÔÔd¾ä³ƒašä?ÿ wF,ì{h\»y«åô=±%„Áò-„×*Þ000°¤‹ŽSvâ§„KiiiXSC&7Ô!÷Ýw_@­u¤U_qqqVV@¥yŒŸ¹ NŒ Â¡r>dá&°st÷»ßýîüãî/Ö •þƒË ÕÕÕâF‹B›u®¤ñ"k×F?‰AÖ¹ª««ã†¯½öZŸ5Ì›k9Vu”ÙCýÄ2#­¿€cú·oß~ðàÁþþ~¨È"=Qh¼pI 6|÷»ßå¬Euš6xGGGXÓò¹3Â]?1´Á¢Óú" ¡ñJæ_ºø)>}}}þ¥ âü¶œ•R¦} žãîÝ»³³³©Hó›ßØÙS‰6UÍ7¾ñøÃ¯¾úª FÆu”ïŒ&&&P–¡¡¡ÌÌÌ;w†øÎ •A†Éu©ñ.ºè"sè¼óÎ{íµ×Èœb”ÙÊ'NH^¹øâ‹%ÛÎþð÷Kaäã™çž{Žík®¹FšìÛÒÒÒÞÞŽ~K%^SSíÊìn:mL $J[[‘Ð>ؼy3)E;ˆ%ÅOž<™›››pïiÄ]v”v¹jÏž=Üšä6R’Ê… ‰ÆOò ÉHªÞ~ûíæD Æ~SkAÑfÍ´7ÇÇÇsrr$Ú •‘\‘`fÆ;Ùg¿ @Εé&d¶[Âð,ÆÆÆdð凓±œ i±J CÒ[0? X› “Ò(Ñ@ö8räÈ2ˆ„ð»víBP{{{©}ÐZžŽ¬RNxž®-å §%¸ÿ~ä3//Àæ+À¸:vŠô“ò/ñsѽ{÷b9%ËùKãƒCØ#Ý*æCXÿ BB&Ù»·¥kJ&MZ‘DË3 žº…<)Â,KVVUEƒlLÙ‘Þ»Ûn» Jû9y–6(aù?Cpùn+E¾[*7„}eOûC9;Û×9¦“5¨-yŽMMMÔcwß}·è+Žß\€Š9.túôéÒÒÒ|àéééàïyŽ`;ü-ÓwÒÒë_ÝÔÕÕ‰Ï'V’ÔËÁ&¹Üd±èµ¦,ÆPdÁ†ÿ¨‰2(4Dÿ°,àˆøÉČڄ’‰“Á]Kß4Gì 'Ýàfé4ÓR!0ÕMZZÒH›Ñ¥J"fB¢åd â—xvïÞM´ÒŸCvçñqŠ}*€€Pbö°Ÿ”§ÙDTäfª3~Rµ‰©Ty÷ÜsÍ)j@!^H°ÙóiL$‡ê(aA+L²<×2e(/•¨y©ÙäC^©ÇwîÜI‰#XJœÌ¡Dr>åÄø÷ ’³ðñ7ÞH+*àìcž©tåš=TGRarâ~ðƒ÷½ï}óH²£~FÝðÅÉ!¿þõ¯ñL¤Â”^ ´,XÇ0‰é>ô‘¾üòËÿâ/þâ±Ç“ŸÕÞgµ Ìr¸ðþð‡Ý§ Mûê]&J·¹ôÔ›uË£áþûï¶ø´á /´—ÊRBÌ(ÉÓ ]°í£!P;d¯¥¥…¬`>Ò'«QYؿ嗗‰Ó¯’QˆÐ‘í/ÑD嘀ËQs‘ƒÅåõÇ@r!w„lc-¥…V-€ý[·n%ÃÐ +“Ñí6tuu‘‰ƒM)•|î‚t$,EÌI£>trrNNY‘lI.%ëʆ#{¨ëL˜ááaÊ2'†;¸Ï:±¦-œQbüc\ê{ï½ÏPꢀ“œàäHÏ"ÏZV=F¡Å¢vý⿈š…,àaó—KH­ÅƒiŨWeáÔ€õkppÐ|9ü†ã¿§_xáÜìlúªU¦§óoÕœ¿r%ÿ®¾újY«WËOösô¢ /|ùر·¿ýíÔ§×_½ËtñoêÚ‹ÕXî_|ÑeHûr¡±ÎÆì·ÃÓ%·‘zzzêêêdT‚¼ý"WI¶ <ÁøKÝ:âË:VŒ©¨¨@Œñ$6Ÿ•ƒÙ&÷Ɉ‡L&ñø,uvîÛ·OÆS8 ó@v—UWÉúä`YIwŸ¿ä]|,Çfò«™ Fb“uiü¿ S7ZY:È’ÿíeAz¶iJÊâ=22H™SL`{Ê#E`ÙÖ ¨Ú뇽³{2)›Ù~ݶd³ íY̊ʳ­­Ÿ2«t"ù—]víƒÂÀDu÷Ýw#£{÷î%˜ ¢ñ= ûð H{ðÁÚóÏ?ÿûßÿ>:úÄO”nÜ(í;üÑÿïßÀ¹y衇vý¿ÿ'ýøO?ýôúûßÿþ÷Ó øãÿH}úì³ÏÞu×]‹& ··nÝ:ûìÀIzÅ⦛nr„ÇQ“ÉDå=« & }‰^x#¯»î:Y–„» xHß/ŽšÃWnooÏžÔÖŠ7x"!æe‹!$5¾ub¹YøÁÑÑQ´Y|ù°@,©,D/e·Ïo’6öoذÛnÁÕËÊʨ_h.„DóÚk¯ÉÒÑ´mÉ”TÙœ;00 ‘p.‚mŸìÂŒ¶kôp!•±$Vc¨j—g6Pã $4é«COQ–П„(çwžt3|ö³ŸÅ]Œ¬5súôéS§NÉdYöüÅÉvùàåMÊ´&.¸àš'OœÈ¸ôRÔŽ¨ðŸÿùÞ÷¼ghp0wíÚ /ºhÅŠÇ^~yõUW½ímoCó°é½ï}¯ûËKÏŠHMjFhËË.í¹~ýzÂ`Ïr©ñ‰ñh鈨DD©–é>d®Ú¾¾>Z¤;§›·ýb[³‹*Óâ.h Ò¶Àæ„ë†íïïO¬IÍÈ$2>ÎkC ,ڊϪcµñjGº»eЕüÅ!DÅ[;sæÌŸþô'—QIà?üá¨úè8QôÞ¡n¡A¤ý5îìûów¼ã<òÈ /¼ðŽÂŸüô§_øÂðªiYœ´|:eÿv‘f¿]/Ø^i,N¢òY~¶Q÷ôôô`3F„‡0###ðŒc>ú(×@ íÒõ—ù—æ¯ðøãS-®Y³&âd²÷{û÷B£Ê òá•W^±{T!†(ËwÛþsç"ϦƒHæ¿tsõ£þûCÜv†îðÐÜÜLœZ ´ˆq£uñE>÷×ö«¡¸¸XÛzmH<‚è<ðÀßþö·Qe$Oº¬ÓóÊ~j÷³9Ñÿ['™š;óî¹çûKŠ7‰4F‹Ô}õ«_Eªž÷ÝwKˆ×®HãCËDÍòÓ,uüøqüÚ˜ÌgBË媫®r8 ×Z„uQ­´âÃ5•³ü?u%MHI´!‚=‚¦¦¦²²²è§fKtPè‚‚‚`S)©å‚jDßLû¬Á+Ô$Ú½ y9‚ØQ Ë´þóOœkhhH7vÞãLJž€ì•W^‘¡aW\q…¿Û$…%jTn²Ä”}çÙHzè¡ááaŸåÔ¾÷½ï)ýÅ/~A3áï|'¾µtÜÏÍÍ}ùË_–X6lØ€#è¾§W';¾¹2o…Ÿþù›nºÉŒhwpòäIÇ̨þÉqà 7<÷Üs4ðõc;«\0H#ØÍIf#¶rBÊŠUSSS)5b___CCu: J@È”ŽTÓi¬[·n•OQt´Šd"n|VéwA˜ÚÛÛQ4G°W_}•\Bzp/ÑfǨäˆiiiÁ$Ç\‰JcA¦üæ2çwÞOúSDšæÕ,5#ÖoÙ²Åg}xgtŸ•`aÉÍûZª2qùË/¿ì³ú žyæ>uêÜ8Ç2ýýËfyí%¥¬¬Lž±¼Þæv¨ä½òR_š¬CÜlcôõ™æ)L}¤Õé^¢*èïïOˆÕí¢â@ÍL%¼cÇq/,D§e…þßÿý_‘öYC¦.¸à‚`/§M…NE9¬JVjö»CQå5kÖ|ë[ßúñŒNË éË.»Œªð÷¿ÿ=²ÍåÍSòÕu×]‡wøÙÏ~Öñ…Ù¢“hñ‰HдSD§/¹ä\aÙƒÜru÷km‘LÈùò¬BAkƒêà»ßý®‡«àPòhy:$fòõqqkòê½´´T–uóÚ"%1 `’g¤G0ت½‰‹|^%ÛÔ¥ƒƒƒIvƒËLCæ˜ûÒ _ÓÔiv¾öÚk¿ùÍo|ÖÃ(£¼–fç‘#GPOTÜåÀ1\¾€Ý?¾*ÂöŽw¼ã2 ÙóÀ Ásssfg•…Ïz‡ÍÎpEšªG<ÄD˜!ëbÉOnßzzzzll̼%rÿ=xñk]º•ÜW4ß2ÅÉ´õø $iMMôS1%Í›Z:áãRâÊ5™gdd„üC+¶¾¾Þ1'q‘¯ŸÍ JôId†“€s„Éè°: ¿úê«È³d0Kd›Ÿ7ÜpƒËnpz°ê>;ºº¶¶ö¾ûîûÜç>÷ðÃËNÚ3332¤K¾ÔöYë‡ã@ÿÃ?üÃç?ÿùOúÓ$ ±N†QhîVÖ6û;;;s-cª{{{333qñ]º\´?’¦ÚÕÕÅÃ"•6©•Š‹‹}˜+Å&Ĥ7в(%%%”‹žžZùT#Ô”—#=ã–¡¡!Ž;æà³É‹×€ Ód¤€ ?"Ã8Ðè+E’q o°pÿ¢šÖd°ºîl»àæ›o–IGiìÙ³ç#ùÈÅ_Œšž8qB˜wÒÿùŸÿifQ¹å–["H ™¨©©)´@®X±…þÃþ@¡¢Íhob`Ù”æ$ªl_9#;;ûÀܪi/K7@Àø“o>îz“…ü”ae‰ë†¢Ð<Ðäp}b ¹šÇÖzÒ„lò£ä€ÚÃÌxß×××ÚÚ'Ý`‘Á-èœ-1áxþùçC¯…ŠËWH^x¡ÿÑßÿþ÷2®K~âdºŸ”g¬áu6º5kÖìØ±£´´ôÊ+¯üÌg>#Ûö•@Ì"\¥@°¿ù›¿ùçþçÒB檬¬lnnF­»»»»úê«¹áŠŠŠŽŽÇè*îÁÁAÚ5޵­Ì’Yò“¶Iˆa#œžd"í@¦ŽñÚŠÈÁûIúQ?‘Æ´´´œ ‡mÛ¶Q”¼6<.ÈËËKè)êð.h¿&nã;nA#ûûû &“Ÿ<$¾øK>¿‰MBƒZk8žE^})†¾ï}ïóY­ÔñÙgŸ}òÉ'‹ŠŠÌÐ-<ú/}éK4|ÖðôÈ’yÃFkQë€ûÒD ;â %k™ëÄFn×]4;33³ÙÂÿô-—ä Ñ+£ÎÎN) j„TvŽ#‡)¬Nˆxƒj9Ü)7 %¸©÷Þ{oèqÇ!æ'Á½¾ôÒKq/Ÿyæ™Ð_W;@Ë(ËÁÆi*ÄÇ\¶ðƒðÓg}¸ü‹_üƒŽ9’••%_F½øâ‹hžÔˆú¿ýÛ¿E–"E>ë%wÀ8Ä(nÀjZ¾:0sÇ£Ffêlt'ÃÜ­Ì@Tbሄ[ˆ`.Ï‚¤ÀyJЯ¨iÃñt’»«#JT¡#C*–Ä=T¯Kù¥;}útèÉ2µe@N:…B¯X±‚ ÖçX¡;}ßèîÆ]þÔ§>e®«Žà?~üóŸÿü÷¿ÿýþð‡<ðÀ®]»ä({¤v ¹qÕUWE?'Iƒ»쨣š^XXÀó.,,´¯î‚Ì›døÇ´”M™ôÃ_¡}Ö(³äž®K^CF¹Š—WlݺuçÎ^[¡$'x¢ ºÊ2õ›ûU”pA)ÿû¿ÿ;D€Ðkf¬°ð[bÑ=¡»ußð¤‘gôFqì›nºI2,ßIÓ¸¸õÖ[åjÏGy„=ÙÙÙ·ß~ûO<eº  ˜øOÿôO²§ÁÿÛðÚŒXÆ!šB£Ó¤x°/SÄQ£ÒÒÒb†Ì$ ÝÝݳ³³:3ƒ²DÔÕÕÑ„M¸rAÕ·yófu£—”•ùà?,@À©ÇNœ8qòäI™IS4׈Ÿv9§ Ñj|c²ë¯}íküýÊW¾B¤¨õg>ó™›o¾Y¿öÚk/¼ðµ×^kŸ ÿìÇ?þ1ïyÏ{~ûÛßâpG“.ÜLVVÖSO=eƦ —_~¹}G‚Q®ä[¬òòòE»ª0%6kx8ÀÛÞ½{wÒK"¯h333^žÍ<ÝÐ@¥¼nݺ¥ˆybb"eÇ‘Çzzz«!XQQ±~ýú}.±×yÛ¶mnÒ •Á ~æ™g‚½–F Ű×_ý׿þ5óòË/›o ü¡|}ìc =‚ µ½½=ÄWïgOþ¿ÿû?Z8¯Ï?ÿò‘½{÷’‰qd¯=:½×¢¸¸Xö\uÕUøÜœÖ§ Á¨ªªºóÎ;i›üÊÆôôôéÓ§Myƒa‹Æ&ÂIñùùyÇ!\´€û“ò ™)!î#×®]K‹ÍkCâ üÝ%ª’ˆÙë›ó’òòr,¯­p…‚¢‘¥8VÄ6«»ÐÒ‡wìØ±ß –ÕcŸ\è0þìú³Ÿýì÷¿ÿýï}ï{²%g~àéMøkýã“}Äb×®]ŸúÔ§b•ˆäÂýû÷ÿä'?±ï$9^|ñEó‹Ö þ1­‡¾¾¾€Ói±Ÿ£òí5m"ÿ©0ðÅ‘ùÔ™"ƒçØÖÖF¢-Eä###1YîÓwnH ntræSâꜘ¥YI¡ hÄ*¶ÞÞ^jÝ”ZÔËCˆüüü»îº+àt%'Ož´¿–=~ü8^ЂðüóÏ/ú Æ–-[Ãxö4Žr°¡gæzâ‰'¢|'m¿Pnnî£>êXð ¯ÝÌF£ dYófÚ|‚eÀæÃ‡;²5yýàÁƒ)ØeTQQAÆvyGꎆ†raWWW”ÊÊ3•²‘‚fQôôÒ±úGf– HÛ(ýZ®uuuX˜j/€¼z'žžŽ&Ra’à÷ß¿c*ï•+WÚGJáC†˜‹"33óšk® q9² nÉ¢ï\œ/´q^Ÿ|òIGoÃÓO?m¶/»ì²`꣄DAE>ö±íÛ·Ï>Ìý…^ ñ"Ê=44DÖš¿!¾±ö_½‘ ¸X* ËTÄð«3©Ýh9r}•y #«º»»©‰¢WzE Ér1\|Zæ“édþãÁÁÁȆ¿ŒWVV¿³‘  ^ccc±ŠÍå,°SSS¢nRa"7üàíjèp¯Ñ૯¾y:}úô‰'ø+ÊÅó 1ç‰!ôçdž7DÚ>8m ¿Ÿ¼ba†•çŸÿïÿþïwÞy§üÄ: ¿Ÿ™9ßÂgM„r×]wE™ŽvP‘ŠŠŠûï¿ßÿcµ+V^R³ˆûåjÊjpA:— Iä{ˆ¬÷LÞ“}ýcà‰ßÚÚJy¨¯¯Gzƒ]‚sÛÛÛyЄÑÜn ÏÇ|A3’]‹ƒ5¥h#îΡFjhhÀhlltÑ%r®¬)@e¾—¥(¥¬<Çòæâ±Ç»êª«D§‘äk¯½v™ÍxC¤©4¥ øÙÏ~öÉO~òçÖrÆåW\ñ“ŸüDtýé§Ÿ–¦b¬À!Û»woaaáèè¨L‚Fkàúë¯'‹ÏÍÍ:uê’K.1s” nÖ³"B æ{ß¹ö M™pRN$C¿Ý!gÓ ÆÛöZØ›‡EUŃH¬OT½…º›ÖO {ÿH|ÚÁgâKYd`ÎSX^¯œ(3ƒM$PÇòižÒÆÅÙp•9¡[·ÊòÃ#«©©yî¹çÌzÍW\qÅ2wA½!Òäžù—y×»ÞõÒK/Q{¾þúë Þl_•ž¾råJjá뮻žúÊW¾Ûdš*˜$ICn>vìzü–·¼EŽ"Ò'Ož”U?ÉÊ.{hÉ&Ö7‘Kñz‘jê…ÐzIõœËÞò)H¸— ±`¨¢Äâõú¬oCÕK™†bjjŠÒl ÐÈ4U^ß´ óvïôéÓÇG¡d…Æe3 Íþê·Ø1íW0pmiV,E‹ODÚwn$6ªð / aÍWî@ÜhIèØ'aÂBA•$=ϤðÆóóóͨ@* þîÙ³gvvº¶¶Vk%E°÷<ÓÍÉÉ¡tÈ¡ÉÉIªþ áyÛ—óQ’yBm‰»øÊ+¯ ’øÓ!&ñŽ-igbýÙx4à´QÌ$Þ¤‹Ïú<š=öïa6£40ò¯øC­D"Ëk_ìôôt­ƒ””…†,޲óþýûo»í¶ÌÌLìÿz-Õ †”142PœÚòüóÏÆutO|é%AÆ%™=¢ÓŽ1u.±CV‘VEQ"ì±Ì_ -“Ãî’¾¾>ÇìÜò”&L¸£[ _SSÓÐÐàÿÁ´¢(Š¢„…|—•——g&µ\VFElña$ëa.õõõMMMnwll …Þ´i“SEQbêƒÕÕÕ•••!FUUUEEE¦ëWÆñø¬q ---±ºh܉t@¸gäVfÌ!Õò® è°¿LÕQ”Š¢(Jô¬^½úÀ>ëEõÔÔ”ù²×¥.ñõš‰EhwïÞ,€YöÜ!ºò3???ØEþo»EQ%Ή/‘Fkñ•qš]¶GäEµ›À*ÒŠ¢(JÂ_"í[²‰/ó#GŽè×DŠ¢(Jw"­(Š¢(Š_Ÿ`)Š¢(ŠbP‘V"ç…×V(J|±°°@¹˜žžöÚ%Ðîn%rd–yÍBŠb…^·n]^^ž6a•èQOZQEQâiEQE‰ST¤EQ%NQ‘VEQ”8EEZQEQâ”ÄX`C‰O&&&¼6AQâŽÜÜ\ŠFzzº×†(É€~‚¥(Š¢(qŠvw+Š¢(Jœ¢"­(Š¢(qŠŠ´¢(Š¢Ä)*ÒŠ¢(Ч¨H+‘“oᵊ_LOOS.***¼6DIô,%r&''½6AQâŽùùy-J¬POZQEQâiEQE‰ST¤EQ%NQ‘VEQ”8EŽ)‘“——çµ Šw¤§§S4rss½6DItînEQE‰S´»[QEQâiEQE‰ST¤EQ%NQ‘VEQ”8EEZ‰œC^[¡(ñÅÂÂåbzzÚkC”d@Gw+‘“––Æ_ÍBŠb…^·n]^^ž6a•èQOZQEQâiEQE‰ST¤EQ%NQ‘VEQ”8EEZQEQâ]`C‰œ‰‰ ¯MP”¸#77—¢‘žžîµ!J2 Ÿ`)Š¢(Jœ¢žt(ìŸ9öõõymŽ’ÌÍÍ™u<ñ«V­ZåµQŠ¢$$êI`ll¬½½}hh¨´´T—LV¢ÁîííE§ëëëËËËU­E é7ÑÝÝ]WWGeJ•Š3äµ9J’0==ÝÑÑZ—””ôôô¨T+Šâé³ôõõ!ÏÔ¡T¦«W¯öÚ%9ߺuëÆ›ššTªEY}'ýÆløÅÅÅ>«—{íÚµ^›£$3£££¸Ô999šß’•éééòòòÜÜÜþþ~¯mQžTÿNšâDuY[[{àÀ­1•塪ª …F°Qk¯mQbÏüüüäääÔԔ׆(É@J{ÒøÐùùù]]]Tš^Û¢¤´ÇÇÇÉ~lèèEQ‚‘ºžtX }èС4 ]{N‰ÈóììlYY™.<¬(J0RW¤kjjð`Ô‡V{¡@¤íc ”åGr¦V5JLHŒ¥*eIÇ—B¾sCŠÜ#ßÅdÊÅCÚÛÛq QœZór!V H÷8~sˆ—KÎ}eee=ÞŽYY|Vχ.ºê<ÁuëÖ!Ò:‹°=ñÞÝMuYVVæ/ÏB¸r»oß¾Ûo¿Ýë{R¢eIµ³Ü«[s|n1}*ÕŠ’è$êÀ1EQeddDÆÁ)Š’ hw÷rÓÙÙ™——ç?,™»ÃéÑ®øø‡'ˆ‡ºîi »»ep\L¾6TÂE»»•’ž4uÍÌÌŒÿÀ±âöö^¨:®Á nß¾Ý[Û–ˆÂÂÂ%šMÓóx‚2¾,æ9KKK£ŒDf.ÃBUhEIC¤*©©©Dó‘‰ÿ|Þ²°°PQQ«Øz{{ã°ñ¾wï^ûgiñFü˜GæŒÆÊ¥ƒ2¢òì-¹¹¹:5I¤©‰"“j OXë$†EMMMZZšÌIâ³z +++srrDƒñžù™žž>99iNA¡ Oa&°ì—SdösÈñUn{{;7"‹]¹\T&6Ù¼yóºuëø)“p9Üľ¾>ùÈÃØ#K€pVss3‰Š ™5e¹Á8Ê)²"'644•9·©© k;-¸({ÄrÇÏÌÌLYÞ‘«^¾6JlŽdËR"\Qæ±OÌÆx{â`ª¹„#í‡d‚Ùó°GR“dжIO‚ØÿqžüåfåÄ`É螈=éh …sV­ZEÖÒ¤•Øàõ7`ËMQQÑèèèRÄÜÒÒ2??___oÖ½˜²Å¸nccã™7ÏÝ}Æožê™™Ì“åøÛÓÓ#“o›ðD(G©8$QqEÙð›ãš=UUUlgggóWVþiUdŽhÀ æ'Ȳ2ÈÈ|y̵úûûÅ"©®®æî8E ðYÓ Xîq¯…rüô›Í›ð÷(€³®˜»ã§ÏšX›h &s•Ë‚ŽuJìÆ›ÒM2j!Â~Ì03’ÊíÛÆ<Ì(//'NY¼H:´epûר\‘0ÄÉÓ‘£̶<“Œá~¬,K€,EÎT%q‰÷O°b=ž¨c°˜€†ó¾}û¤âöYo}–곦#ݵk×¢‘ +è.ìÜÜeJQâÁc“Ød9KYº'o£f2/A£ÄõÌÈÈÀ$Ô¯—`2O þýû÷K²°Ÿæ¿}²3®ˆž?’Cmmmö•+ey(ìa§x«ü±ÿ´¿î•˜ù;44´qãF|P3§˜À~™M"—ˆVY°ß>Ÿ9)`Œ7ò¹aÃÎÂÿæ6Ít§˜Á!¼[!¨fÛäÒjçβ.¸ïœH“D2O™4Ì…HsN¤$Ë\òÓgùOXŽ ’Œá:R8âê+Šâ ñº»£„ŠUV}Žy̲ÀâwÜá;'ÌvÐÿy¶}V_«,í|ðàAû~Q/¤‡Ï¾6†LŽBã®ÉºÔˆ™¹(GQ#Zfúä\ÄŒ¨Ð*NAWhIÈLŸD.ÓjîØ±Ãg­Ÿ~ó×Þ’@ä Ñ3.DäœË_YÒnª™¾›Ë•––J:˜ŸÁ^²ru 8IJ>•Ù999)+p“\þ‹‚ØCÚ—œ(32ʼ¡Æ RC–â–Cè±Ù6禵µ•ýd’Q–¦Þ9é Ü ,Y&7볆•I2Êk÷ù‡«/óÜ)Š¢Ä?)'ÒTÜèô¢‹^Dâ„"ÎY˜E¢ ÔÝx´ŽwÒ>Ë_D2ÑZ”Õq ^gUTTÈìZ²“zŸPqˆÑ]…Dе1’†ééiš4ød|ƒ¢DCʽ“öYnƒÌȪM‰þ%ŽòÈÈ:Ãi«ñùð5C‹:Ê¥I=<`̈ær(=N3b/í$—+NÆ?²Z¸ -ÔU¡“†ùùyG‡™¢DL*zÒ¾sß>577G)6^177ÛO{iû¡›Y´äÍw¬®ÛØ<Ç}2ÚOAžÇÇÇõ‹¤AgSbH*zÒ>Ë™¢rÄéIÄÊ1æ“o¸O„Øjj2)´/œdh£”––vtt$b&TeH¹cªEÜ™÷Ãk[”TDºsššš´;GQ”e uEÚgéô¡C‡JJJ~¥(K‡LpÖÜÜ\]]íµ-Š¢Ä/)-Ò>K§§¦¦ÚÛÛC|’«(±¥»»›¦áÈȈúÐIIzzz^^^èOíÅ%):pÌŸÊÊJ*M]ÝOYRÆÇÇ·lÙâ³>%_ŠÅ.EI2T¤ÿÌÑ£GËÊÊ>,¯ µUbY‹&`kkëìììîÝ»õk+EQ\¢"ídzzz`` ¯¯ojjª¤¤$///ÄÜ–ŠrÑÜÜœ|M³oÓ¦M²î–¢(ŠKT¤C!Ÿ9RÕNNNê'Š{¤a'sss“ìK3EQ– iEQE‰SR}t· ‡,¼¶BQâ‹……Ê…NÀ Äõ¤•ÈIKKã¯f!E±£Ó‚*1D=iEQE‰ST¤EQ%NQ‘VEQ”8EEZQEQâiEQE‰SRt=i%&LLLxm‚¢Ä¹¹¹ôôt¯ Q’ýKQEQâíîVEQ”8EEZQEQâiEQE‰ST¤EQ%NQ‘V"'ßÂk+%¾˜žž¦\TTTxmˆ’ èèn%rt”Å,µnþ*†……tzÕªUk×®õÚ–¸#33sãÆºÔº{T¤•ÈQ‘N)ž$yjjª¤¤$//OªZ¯íRrÑÜÜÙ)++«¾¾¾¼¼\Õ:*ÒJä¨H§¸†›7oijj¢>UQ‰d-¤º··‘îééQ©öGEZ‰éT§§¡¡¡­­mÓ¦M^Û¢$-ããã[·nݸq# A•j;:-¨¢(ÁË©¬¬\½zõÔԔ֛ʒRPP0::ŠK››;22¢½5Ý­DNž…×V(KÂôô4õ&ÞsWW—*´²>îÆ¡™››ÓácJ¬ Ë‘ñŠŠŠª««½6Ç{Ô“VåMP9REöôô,ªÐ}}}ééé™™™iii•••œèµíJ2@Æ;|øp]]jíµ-Þ£ÇEyëׯonn^4$Ú¼zõjÜhkÞº€—£Áûÿ³‚ÅoÂGŸh\1t<###îc“¹P\&¤Ë Ò!±ÞOáOwuu{mˆÇ¨H+ŠrªûöööÑÑQ—á͇­ÙÙÙü--- ¬¥¥áGÎ7mÚ477‡B³ÁÏÔy“=00°¨”€ ¤ÕØØ˜Ë˜ IøÜë½–¹ÿ™Vàò_4ÞP‘V"ç…×V(15­¯¯·wuO±®®.`Ęz–`h3îñËØÝEýuD«¦¦Fêhþ²-Î:û;;;Ù&6ß¹ï¹í'²G¤‘¿æ\D‹`æ¹¢¢!'ÒR x›„á\bà~1Àg¹È²!`hhˆC$lˆy¤‘’£„1wAl[°Ÿ04_Ä~¢îæ‰In¶0W$$áÅ Iû}I1;åÙÓÓ$)—p¤9…Z®"}*ƀ͛7ßsÏ=ru“P`.ÊO ‰1\QRxÜ’JrSœâ>wíÚµ«¬¬,¬ ™d¨H+‘³ÎÂk+”Ø ntSSS¸'"íT¾ÕÕÕÁš'R‘™™)ò€ÿ äææ.êäaOQQ‘txRS㯣D233ƒ¼ÉÁƒ¥ePXXˆ*×¼  @ngjjÊgé7íél篘dÄUAb#''‡«tttøwÝfÏž=l <\‹0>K¤eCؾ};Ñ®^½Zú–‰°¤¤Döc3!±–;â.¸wÑv’€2M¦D"qž³¸Y¹G1ommµË0!G,¤bäеFbKKKI+vrE’‚›5a***î»ï¾}699)` W—0$£$ßÝÝ-•6WdC ûy"˜——Çö!iV ’¬’ÒóßQ”HÑ,”LìÞ½ý÷,QAdi~~>tH´™„—Ÿ¸ÔlPƒoÛ¶Í?<'&&Ìñc!"0?9‹Cl zF1@Ób`¿=~6ÚÚÚfgg8 sKxÚUUUlŒ³ØÏUIa¿„„”Óeƒ+úÎM½'¦ÊOÇ~»%l8,‘xüã”{”ùdø‰µƒƒƒÆ0‰Êa9j"±ÇO lpƒÜ&;‰–d1§ÈÜ5ì!rãµµµ‰±Ÿ£ö„’çB3Ae?O–y Bʽ—[p”[^žœ™4¨'­(ÊàwÖ×ׇu ™yM½ŒÏ$‹pàfÙ»¾ÅùC‘ñ½|VÏpX#¤ð§qÅü=3ü9jvÍQZ6x®8Á4ªpy¦þÓÁr®=¡$Îî®]»xA¡7lØ ãÌÃB¾ óß/^u”Cð–õ¤%!ÉÉÉIˆ*FQ”hPOZQ™8¿û.Ür-ó@ÉW­^Ó“——gZ2GGfffyy¹›3•°p¤vœƒ']YYAw~~þää¤}>tGGG4}ïËŒzÒŠ’ÀH¯ÝÔÔTŸŸÚ¡Î2óIy…Lže~²ÝÚÚÚÕÕUTT$Ó„Ùihhˆ`r´h(,, k>ËeFæ\sÞ‘ÚqÎðð°ù¾.b¤°ÌÌÌ$BûT¤% ÀÑ<`¥T/þËK8/ þÉ8¦––ûWײÅ"`ä£ ­¯ö£ŽØÌϽ{÷šYS\.<å,à‰w: ¶‡±2Û˜gÜbÿ›uÙ¼ˆÛÁgggíã´Ã%AåYP‘V"Ç>}„â9(tÄR-3,Q]SS“žžž••%CÐÓÒÒpûø)S—àÏñ333ÓÑ-é;·b,#Ú0RBâXËN\mbc¨8Û2ˆc:ö†¿²ÒñpuKÆ)çh]]‘°Seº4ÇOÂÐb$bãŽØ& ±Ù‡Ý±ÍöËDÙü$¼L`nop°-ös#vƒ¹ 1XÒGÌ ‡ÊÊÊØæ(ÛEEE˜ÇÝÉÍ^â –&½½½N·`ƒç"]˜ÙÄ81O:²¯HœÄ•ç³xý ˜’ÀhJ&¨åÍ#±AŸŸ¯¯¯—O]É32ç†d®+sG;&ñ63iÍNaß§ ¯Qf·hll”9½ÍDÜ2í†\ÂDÕÕÕuÆš³šòÅ-aä;`N,//—™Fð·zzzhåÈ,ÙŽŸ¾sóos#&6¢"ÂÇÛgê[Š,dIû4ÔÄ/“´8&úEäq3|ÖäárHfÀf»ººZ¶ejn"—D–ÉÆÅ™,E&7— <©'‘Ëѽì‘seʰ¦ÚŽ9r×^[á+½n$(Š ²êTÌcF6pæp(E>}V÷£ùgt×®]O”înŸå ËbSUUU%%%ò>'¸¸¸Ø>wwvv¶|݋ҘKÈRsssĆÞÓhhjj’‰*}Ö™lX–i’ëb•ý§}"R¹§–ôõõ!~öùGùÉ)ruDT†ã­²à\&$Þ¡,åøLH&—…&¥;AÚ+GŽ1‡WÙæî̼ž(+W”æZ’à²Ú·´ìWéìì$ZžŽt¢H‡'ÊN.͉ñðe`` Ìð íîVå p(© —¢Ç%C9î¸ã_ —£\···WvtbûQA‘+ÿ˜ÑÚõë×;ÃpÀ~äghhù‘AT*}ôLˆèò#$ÊWSS“™™i~†è)%6,¤e#ž®@ä,Kh#„!Ú=ØyûE2id,(4f`€X…üsË9ÄR‚™6öpEY᛿Ò še2ç¹,˜!7Ë’‚†öÐF k”%"‚¥_’ iEQÞ@Ö?0£±bˆ¼?ž³@ºÌ ÙÀEÞ·o!ØE…mö°Ÿs·mÛ†PáO›Y8ÖhUww·‰9==]b– Ÿ¥¾4***P£ááaY¨Á"N’¨0†¨ g™ŸDÎO‰ÓØ âpBbš½yóf®HÓ„H)o‘͆€HË _ȤkÍµÆÆÆ8W:É1ƒô)++Ã*Yg‚F‡¤a‚Ép-Z-lßwß}Ò‹n’Â~§Æ~\pšP$òàà Ü¬íêê’Õ'i!-E–p)ÌóJà7ÊQ£ßI+‘“––æ ÿ“\%nßKVYðÚ–¥A»ݰaÚ†EâMlòBï1“®æ$€l'îÚµ+•»»õ´9Ñ|¡Ä!hs}}=~U¿×¶,8¯2LÚg½ú&*\ÞÚÚZuŒNãÖ{}s±AæÆ‰…îííõY¯¼6ÄKÔ“VåMà»ÜqÇÉ=·ô`Ç*¶………dê{˜žžŽ‡ÅEd Âììl2¥m¨H+Šò&œœœœÁÁÁ÷`!fffŽŽŽj&ÔcŠ¢¼ —±±±ââbχõ*©‰|2×ÑÑ¡ íS‘VÅù@¹¤¤D^ *ʲAÓ077·¹¹9iFáE‰vw+Šüéõë×ãÓ¤ø{Aey QØÔÔ422¢ëžÔ“V"ç…×V(K…Ì YZZZPP࿦¢ÄññqYÈKækóÚœ8B=i%rô;éÔ¡¹¹¹»»»¡¡¡ªªÊóq¿JÒpôèQY“Ôg}§ò슴9*Ò)ÅôôôÀÀ€LU]RR’——'SHzm—’x‹ææædA0š}2U¸×FÅ)*ÒJä¨H§,òšƒªvrrR_y8ù®W­Z¥~¡?Ò°“¿¹¹¹:ÖaQT¤•ÈQ‘Vhµ¬[·.//O›/JôèÀ1EQE‰ST¤EQ%NÑ6”È™˜˜ðÚE‰;rss)öu!%bô´¢(Š¢Ä)ÚÝ­(Š¢(qŠŠ´¢(Š¢Ä)*ÒŠ¢(Ч¨H+Š¢(Jœ¢"­DN¾…×V(J|1==M¹¨¨¨ðÚ%ÐO°”È™œœôÚE‰;æççµh(±B=iEQE‰ST¤EQ%NQ‘VEQ”8EEZQEQâ8¦DN^^ž×&(JÜ‘žžNÑÈÍÍõÚ%й»Ǭoïµ!JŸŸoZ0º²½¢(£"€éééÞÞÞµkת³¨DÃÜÜ ®¯¯///WµV%,T¤ßDwww]]•)UjQQ‘׿(IÍ¾ŽŽŽÎÎN²VOOJµ¢(.ÑcgéëëËÊÊ:|øðîÝ»U¡•²víÚ¶¶¶ÙÙÙ¼¼<²Yssó‚×F)Š’¨'í£º¬©©C¡©L½6GIrL~ƒÕ«W{mŽ¢(qMª{ÒÔ˜2ûôÔÔ”*´² ¬Zµª§§g:''gzzÚksE‰kRZ¤Qh*JªK*M¯mQR‹ªªªC‡Œ{m‹cx²iiiºöŒRW¤Å‡nkk£ºôÚ%Y»v- ½aÃõ§E FêŠtMMMQQ‘…¦¥i<44tôèQ¯­V’ tº£££´´TÇ‘)Šq¬¹¹yrròÀn———›…çV¯^}øðaý„F‰4§¦¦Š‹‹]æFEQRŠTô¤ñZZ[[]†G¤G-ØÆ™îìì y{{»ù9b‘\%JÇ=„©¢™MänàÆC§U¬"Œìv¢OaC”‰ÙÔÔDËO_N+Š€3©Ç¶mÛ6mÚîYóóóâ@£Ö¡#' ^‘ù æèÞ½{ Bœ.ŸÒ²Á߉‰‰hn“Ó%ª€‡–áÑsãÀ…¾åp#Œòv$…åo”)lˆ>1wïÞ«TR«ÝÍ)Æ)tøy---2‘ø”±q!ñ½Ø‰öË%ÎX}}½DÎ!~ò—£\ÅÄ&W)**"Î={hµÈ,å\Hn¶±±‘³zzzì6H ÷Å1`ƒØÃm²‡[dš¹ ŸõºôCØÝ s ûåÞÙà¬ÒÒRI7¹¤›=B{‚K0““Í]ôXÈ~ö„Háþþ~IXΕ8±ßÄIše²1æÑ;Âø,•%¹$’Tf¬«ªªrŸÁÈÜæ’e|EQ’”ijO¤4‚EE¨yíÝרǩ—©µ©¯¥Â%pmm-u::A=."ê 9¥¢?pà€DÈQ6‚‰4'b!ÍU$B†8GGG¹;6D$¼F®"b,ÈUC`l`·¶×B ‘ž±0gqhpp{!˜ôês”=¨ ­âä/JûƒCÒ;m¿#GÒR”ó¸5þ²-Ñ“ØàZ&˜£»›ðF.!ï#w!i"…ɘkÞPœ±õ«Ë@qâ´‹¨Ýi…HCD+Mc•Ë fr…¢(Š!åº»ÇÆÆÄ¯rŒè‡Øg[³rhhÈþåÌÑ£GÇ-*++ÑÅÎÎN9ʉÔÝ\”KKHâ™››knn>räHNNNEè®Î‘‘.‡—IÌ2ƒ©\eß¾}r ù;d„›ù&óóó‘–ÂÂB®åˆ“0ÈÌ´¦ŠìÄ6Ÿå®¶À„á1€{AÕ|–c*Ž/ rèÐ!ìAɸ}~Ú AWW×wÜ!]6lÞ¼Ùg‰´ÏrÙ‰„k¡sœ>00ÀQs!DÎÿ.ösÀÆ“&$ñœz‚Ää61i ñ3ؽ¬µ'Î…x¸$çú'{ˆä\—áEIRK¤ÑêÍp? Bá²²²¨Ä¥•¡¼ü-+++..6ÁP|µCç@AQ9DÝͶY´IõGí/Ÿk£C2  xfĉLööör.ÒŽ|·Z]]͵̸eÂÓ>Àß­©© vƒ"‡ØOœDð}­ì”;rŒW§ ;1RÚ\ÔÿF233}çZ¡nhh˜]·n @0DE7SWÎÌ̈XÊrB`E¦Ä’I?Ø_VVƉééé²Ê5‘cÒž={ì6Û]^,7áÙàrT4Äi4rÇŽ2Ý):·sçNlC•Å{ÆÏf?G #ûM´4P$*N1;ÙCà-[¶`ƒ™`„³H.îTV"Ø#6HiUØ{݃Á)Ä/òü%*b9—Þx.Ác²ÛCšoذ{‘Oh0û¾ûîãgZZiË-/Ã"ÜŠ¢(oÂëÉ×Çêα=îêê:|ø0~¤,«Ðßßï³úcÍb ðYKtàwÊâ>KMeêžžvÎ[Èr b°LËe·Ü¬¦%„'°Y¦É÷æ%:¤˜Ÿ»wïÍÎζ›mò€Yƒ¶¶6™QK®n¿4’5¯ÎX‹Aù¬Ï¾¹÷3Ö"`>k‚6ép–…L|Vw·}¡¡´´”H¸MûsA&ù+·ÉµÌº²^…LÜðÉšå.Ìf‰ Ÿµ^ˆYÄÌþf·Š`ü”[6 ÈMñ@å‘Éb$KGˆ%ÀEIMô;é˜Ù§ÿ”%arrr|ÖwÒˆquuµt ãÒ!ŠxløÖ²úþœ™C¯T¦É”™ Ž·Î4ðqe¡L;Òý‹#( E¸™±”Mök¡Ux™2+–LBÞÛÛ+¶a*Zˆfû¬~Ì–)Tenpÿä" )f7˜müW3 „Lëm_À›ä’DÜ?—U¤Ìúõëe‰OâÇ™–îz W›—•.9*¯ÊèÌ3Š¢,7^·–•%õ¤©å‘+Ù¦ŠÏ’š]1¬¯¯oii·˜mYÖPÖ[×Ùgyo"ƒ¬Óé0[¼CY¬Zbž™ ÒîI³!†!NOZ¼³£;s®“À¾â²ÏZäÑwn½H’ ü%Œ,¯ÉµNZ0âIÓ˜`[îK:$~¶i’KÜwódƒyÒlH{HÒ‡Æ6‡=´J,¤ueO"YÙz©Ë‹zÒŠ¢8P‘ŽÒÍ+ 8RÛ"‡è™¬”|ÆÒ6Ùsƪ‹íb‰c'¦#—²†±œâ{sǬ€Ò äòNZâç§é=–hå,Ùȳ§ÖÑÍ+'LÖœ6ö8í8ä–Àü57bîKVžö7Þ\×è7Wáfi È’ÕrkÆ‚É"Ór"¶¯m¿º i6LšKBúðöˆàïáÇíùDvljÄiEQè±ann.++KÇââb4ÃÞI 2ÊIœòˆ‘µ¶¤SóÆÇÇSö;¥………ÌÌL’"V(†È²Ü:*8Ñá ®[·Žö–>J%zôtlÈÈÈ@GûúúPk±b£œ;ÖoŽ¼ç––c^Ê*´ÏÐ^RR‡ ­(ŠâzÒŠ/ˆ¶h0\´ÌÌÌúúzèµÕŠõ¤•¢ßI+Jáæ4Uÿ®]»ÆÆÆj3ÕŒ¢(I‰Št2`æ2 ‹ÎÎÎE;Ò#‹y)pcíR'I᳦^ikûÿÙ;_¨8’ömç|çŠQA 1³Á,1PAÁˆˆ5³`LÀ„˜(ˆ 1kBL@ TP|×öý¦~ýöÀdzf¸/1§º»ºê©êž¾ëé?OÍœžž~øðappð&AÑ1åŒEº˜œœÔKày@áÚÚÚâkæææ~){…”\s­xÝ…X{«è%ù ÈEŸ…jƘêÃ"]îà$õôôܼœŽŽŽ÷ïßg¢0#ù••ªÆü`ŒßÞ* Šœ=kÒ%›ÍNLL(´­17Ä"]2NNNFGGù677k†Òø‹x9ºMŠòÕÔÔ´´´(ucc#¿äÑ»l½lR6.»è%‰µµ5Öp!žŸŸ×VÅ c}{{{bZÆ••êÍDóJ) 7µ“‡EêB¡ù}üø±Â€c‰, ÷K5²†º°SfàËR#ÅRH¼Ò®®.ò¨LåawÜŽoЧ©—òõm™)SRëÈvéû}LNZº‚´š‰nÎÇïP2™É¦Öéè¨oa||œZ¨+t£®ª‰ÅÐäx ïr#ÄNOÛó/ œŠšrƘ›’ö‡ÚwÊ­3™™™Q ¬—/_’¦¢¦¦¦?~°HZAÇŽ¢¸"§§§ Ú¥@cdS€0…˜^^^ŽÇÒR ë}ñ3HÖEô~~<Ô†vĘLôµB{†@!3‹\G°œv‡ÔÈD±Ï¨TaÑÈ©H&²Dydù‚"´P»¢‚èìŠoRZ¡¾d†uww“™~Pó3QÄÐD²vll,ÄîŽwEè@Å/ »PWè õ©!”¦zUBÜ`_T˜”Áíö¸I0u·jž1æîñwÒ%–+¾ÜD” VÔh.»š¢1º¯¯¯®®®££#}f—ÙÚÚ¾`&'p¦ûí7­Ñ¬ŽÊÏV|H6ê¢Í¥/­±'¬âË¢4Ÿêð³Õpl›øñÃ5k'™)J“¨£ô«‘J°tK¢+𘩗ä7~ ò/ÉÏz|bº…ZôÙ’O‚ÝãÓ«ZÌD/Zk±"BvOMMuvvŽŒŒ¤mˆ1¦”øvwÉÐõ%@4+CôcooÑ⢟ûÂjŠ\é™± ÛÒÒò Ù;@QPvWHm/}— ):::BQë³³³¸ög"Uceþ—¶TcnÊÄÖ£¬š,$Ý‚&3‚ŠÁìH]˜‡.’]›4SµÒaîKtEs_Ò~u£>Oc ªI£CW »ú$IA¿…îÛÓ ÒTD?°æððP4 ¿2Xª¯¯gQ%‡Åø¼Ôe vrXãocª‹tÉèŽ@ ^¿~,€  1HîÝ?ÿü“Ø*W/x===’XÝ –³È^Ÿ>}BÎQ.Ç™èF4r’x&‰üxöÒäÍ—®Lôhw6ñP9Ž&]V‰M¸Âzм²²"‘ËD:§É§±Y’öåËz€•dØDëâÙ´/Íyòä þùçŸ[[[¹“e%X^^ÖtadŽwâ¤):â@ôy4e5;j¢ëij[L62ÐUrXœžž¦“Ëù™´èëë+dŠ3cLáˆc铈&< Eºmn e‹tnŽûï¿ÿþÇ0,XXXHÛäK¸aìîò<½ï! d99åü9ö¤ÓßÍß#ùçQèLtŸcffFX­—ÎÎÎÎÏŸ?§m…ùwκÉÉÉ0-º17Á/Ž¥Oü“ʵµµÜGÚ&Œo~é}Êu>;; w髚–ç@cL%b‘NŸÄœT÷yŠªâ(¼ÇªX¡AŸÅ§m…1¦”øv·1Uƒ¿ÝmL•q¿Dº³³SÏ/oƒ·wÜ"j¼¥WÌò”‚‘]Eooo{{{XÄà Á¥qõØ]ZÒÜÜﱚˆl6{ogŒÐ›êƸ_"îÝÎJ÷r ·jjj{{[B˨ˆD˜Qq~~¾)bgg‡m4°ººº±±±¹¹Yà Œ zšvÇ”Œõõõü¯¿cî÷K¤qénõšNáˆS3$„ÅÙÙÙL¤p8¦ò¶¥LlÕ¦ÌÏ!I ú_ÜŒP¬Üz"Âb¨T!ÄeUتzY£¢4¤"„ ÔûåË—D²?„O‰ïBQ”,— «™ÓÓÓÝØ››CÂÃz|Çø½ ö¢œéDüjWשEŠ8¦p%ñþTw)OèX%ÔäÐð0ñ¥J¾½SâZÐõõõi[an §åE4íwÚ†˜ª í¸¤wMCCÃþþþm”<11Aá###µµµ333ŠpÉÊŽŽ~ŒÄòòr&úHƒ4‰¯_¿²Fá£ùU!ß¿O,*8…(g¼Òºº:­§Ŧf‘JùeÇL&¬µµ5µfÅHaåE’Z‘“Ý› ”#ìWm•O΋(h9¶±)m[ÒÜŽü’™êÀœZ´žE­×.™H¤eO}ÒCÇ Ýee1Ün%2$7"â AZ³‡D¼R=ùNØIMÍ.Î^*0$ؤy¬U` ØÏ&Ù25÷¾qÜÔ°ˆ†.t›Biq¾~ýú(•íèèPE¡ ol¢÷”‰DÃuK\ëoé5…ÂÁ 7/ç~þ£©bî×<*®×—]þè¥ñwïÞájã¯ëÙöÍILj’.2æðððæ7Þkjîé?º¬ØÝÝ}üø1#K¿àmnν»Ý-4×BîÍ[SVŒŒŒœžž"Õ>Ôsë’°²²‚_^ ‰b¿èÙGÚ†cÊŽû;îÄ9Ó»¾Æ¤Å‡æçç¿~ýZ’ÒìI—ö¤M ¹_ÁLâàL%"^s—ìììLMMù}1cÌUÜÓÛÝ‚‹cccãöövºoöšûÉÒÒÒàààáᡟ¹c®âþzÒ™è[^.‘gggýýý÷sF“>|P|S?Š6Æäá^‹t&ÒéÕÕU…Œ®¦©LÙ²³³ÓÜܼ¶¶†B{îðª$›ÍNLL §mˆ©üšÉA¡õ§š››³scnäùÕ«W$Þ¿_ªËWVVÂ4 ¹|ýúµLÞ`7ƇEúà2úúõëLôåOGG‡ÕÚÜÆKKK G:33£Hg%äªxmšU%íÖcn„Eú+{vvVstvvùk Sz×axxøö¾„¾Ê™¶mL`‘..µ›››EL>aî'ÍÍÍwùÎv®3m7Ú˜êÀ"mLÅ“ëLïïïû­4cª‹´)Mx¦½2)w¦_¾|Yªæºp æææ8"aª7cŠÆ"mЧ¦¦&M»”¶!æœéããc¿ó˜" jJÈ}ÿNÚ˜êïYÂƘ*À"mL• ¯¼ôkŒ©,ÒÆT øÐüÚ6¦š°HcŒ1eŠEÚcŒ)Süv·1ÕCMÿÑÆTö¤1Ƙ2Å"mŒ1Æ”)icŒ1¦L±HcŒ1eŠEÚcŒ)S,Ò¦xj"Ҷ˜òbww—ÿEKKKÚ†˜jÀ"mŒ1Æ”)icŒ1¦L±HcŒ1eŠEÚcŒ)S,ÒÆcL™òÿÒ6ÀT0i›`LÙ‘Ífùkð›¶!¦p8~cªO°aL•áÛÝÆcL™b‘6ÆcÊ‹´1ÆS¦ø –1ÿe}}}ttTéóó󃃃´-º/455ÕÖÖ*=88Ø×××ÐжQÆ”~»ÛÏÛ·oÃo…‚OMM­¬¬Ô×׌Œìììµ0w‡c~~þéÓ§¤‡‡‡‡††*ñpœœœÌÍÍe³YìOÛSñØ“6Å£Ù5*ô’<ÏÎ΢Íããã•(UŒtnzzzll¬âF»»»?~ô艴m1ŸI›ûÈÒÒ®óÑÑÑññ1`….78.‡‡‡{{{¸¤kkki[dL:øv·¹wô÷÷¯¯¯ãå455¥m‹ÉR½¼¼ŒWýôéÓŠs©¹9is¿hnnƇÆE³÷\) ÕŒ¨ÚÛÛ¿}û¶ººš¶9ÆÜ)¾ÝmîøÐød_¿~µBW/ŽÚÑÑ‘isß°'mî >|ØÞÞÞßßÏ“çüüœ xÛVñ2dkk«¥¥…£Ó××—¶-ÆÜ~»ÛÜ ÖÖÖFGGwwwó«/pppðýûwÄ m“Í%œœœ466ú}s°'mªüãÞÞ^ü°ü =88è&eNCCÃâââÓ§OӶŘ»ÀϤMõ355ÕÙÙÙÚÚš'®ö‡òdÀ{«ù_ð¶ßFäÙk{{ûÁƒa‘±B|ö¶¶†tXOɔώíííøŽéöžž® q^¾|‰3½²²’¶!ÆÜiSåàFOOO/,,äɃ"Ÿùï 677 ½ººJ¢wñùêêê¤(XB‚ºvvvT)‰ááaÒXH:îÇ }ýúõÉ“']]]¶”AÚ]7¿]ñþýûþþ~ú3í¦sëX¤M•3??ßÝÝ?´âP®¯¯çÉS[[Û‘‰bM“¢Ž:†ØRRâÙÙÙ°#r‹ËÌÀÔ"þ=õ²†ü9ëÇÇÇÃ^¬×KR‡‡‡q3v ÇóÞÜÜ$AÕrµ—––zzz‚[Ïz¶b k”Ú¥ŽŒ-ÈÌ/õ²Fåh¯9@9ì_$ÔQ…Ë !›Æ$4|a½ì Ù2‘BëëY£Ö¯+·­­­¢±Ž1UÎ…1UÍ£G¶¶¶òdàÐÑÑ111¡?‰<ùÉ€­49QÓ‘‘~©åøø-g%¥-//+žžòKž™™ücüøAN†Ø³‹Ö“M6“™ß‡ÎÍÍ…ªU2cTJ Fì~zzÊ"»ÈrJÆ$¶òû2BÕ‘ÐÖ……UJP;SB¨Kf³‹P³†­CŒ-d6fP£ ŠRù¼¸¸HšUµl&›z†„zxccƒ1’ÒBÖª9ÆT7iS<å?ÎC*~i!Z˜¹²&«ã"-]D{H ÁH‘$VJ&H£FÒæ‹Hí)¢> Cðd†J#J°¦nE …óE¤Uj ;Êl½Gº)B…££º—€ä“l"M[0¹Ux¯Pma% Ýá—"4˜͹ø9X ûJΕ-tbJS6 ,(¹¸#K»ný* µ1ÿYdLøínSͬ­­éVvþ<Òrxüø1¿È ¿]]]躕ÿ3QWWÇ/Ú)©ËDwƒÃÖ¿ÿþ»½½-Ôëåãã㣣£rdI£ßýõW&ºÜÛÛ«[Ö ¹¦JMñV±27Ã3Ñmy6«¨…5³³³ÃÃÃj݃>}ú”;›ÍjèÊa¯Ð-¡ò’)Võž#ãÖR ‘©aen”7 XZZjiiaÓu禤(,ÜÝÝõÇr¦ÊI{”`*˜ò?…‚w­ÉQ–¢ÄË'דVBî¼Ø„#¥˜YJKüð2•ˆ»’Òxö½Ôìp÷­ÕýmJc¥TÛš~¢£Cr:åUS©Üb¹¿}}}?o¹Çë wÈÃínßàñ³ØÙÙÉâÈȈžÄÛ«v©½áv72¿ººzñÓÏf¥nËó›{Ï t÷âΚ›bOÚ”{Ò¦šÁÕ“ X Ò<}%…—†xäºÑä ŸQ¡4ñzszzº³³C†Ä»âx¡(yºh9u8dcýÞÞþnîMøLô{õ÷÷Ó.ö%N766R+\ ¶Òpy™Áƒ'³nÈ“QÇHŠBPÉ|ttm-Þ–õõuu CJ¦j5„œœP#Öâ Ç?-›ššjÐ"v¢è”/w™Ì›››£££¸Â$È\\|·kYc*G3ÅSþóI£RÈ^uÜU°-½_ÖÞÞŽ:^÷ñU´µµ½xñ¢Ta±ÏÏÏëëëH¤Ã‡à%ï•ÝØ/+<Ÿ´)!ö¤© ôr8²„/‹æ•J¡ñ¡q¦nôMÀBœûàFÇ=ìÒb4÷‹´)žðÍ’¹ôx¸´èõ«Øq«6—9ŒKâÏDŒ¹ iS<ž7И\ü×0¥ÂÇŒ¹›a17JW!(W&zj^BÃâÑÁJÞÒ¸ñETT\GsϱHs=z#Ââääd|F¦ÑÑÑK…- ›Ù…YÜÛÛ+•a”<77·»»Ÿ«ã†^ÚŒ§¢ 9;;“=‰Ž2Æ‚EÚ˜k°½½}qÕlSSSỬKa+yÂb©Þÿ àšolld¢hÞwü^Õ¥5ÖÕÕÉcLX¤¹oÞ¼êîî~ýúuXÙÓÓÓØØˆœ‰¾EÖ}]¼íÔÔÔ “Èf³šÏŠ­ño¯å\¶··SBâÖ÷ôô4»777ÏÏϳ \Rr*0e²æüüœº¨šòåš#“õõõèeÿãÇãe’“lìÈJ\dY¥i¸(ŸüHÉ2>‡ŠÈ£¸l™hÒ1R“v„±SµP”ì‰7Š]Øä©»)‹´)ž_Φ\e 98иÂèôÎÎNxÂ:77Çb˜f*û|øð¡¢]"l[[[¤×××/}(+¿|yy91Ÿ&}«ø!¿ýö[&úVêÓ§OýõÕ)~+©—Å/_¾P~üe{½_ýýû÷¸k«y·NOO)m7"<]Ö„T4l4$Q`&ú¶ %ÆTEÔb|€Àc6¥ÑÆx/^¼PÐ1ò'Kfl`ˆPÅ¡HôÂAiß0÷‹´)žÉˆ´­¸;4MŒ8‘šù²»©© Ò|eœK®ÔH‘Š)ó¥eɃÔ={öìÇa%R‡+v¦3Ú ™È•ÏÄ¢l^UàÀÀ€&ÖbKK Ú<33ƒ%´7EÕ]ÌCæ%ç‰rÇA™ö!5¦°HSè2æÔÂŵʼn|ôèQOOzŒ~‡‡ÍøRÈÞ¤ž%#WíííHxÜs P,zOÉH]PJMPM háììl<¿æîêêb/œxÉ!º˜¸«v"ÃñÈ'Ož`–È¿×\U «äF爅xÛØžISÅèè(Í—Ù,R Oo°’æ,--%Ú+7:ðÄsŽÝmŠÇ±»¯‚žÙØØ@;ñ¡QÊ‘‘‘´{¢ ÙÝÝeLP†‘A»Û”G3¦ôàžâPêö¯]FcLÑX¤)=zõúüü¼¸I1FX¤Mñ”óîrÀ }?iiiñ_Ô ¿8fŒ1Æ”)icJÀÁÁÁ¥ŸWåçíÛ··÷R[þâ¹è5À´ØÝÝM×cÊ‹´1%E\__/<üóåÛ@áÀRîc̱HS(a²E%%ð<¢®®N“EâU+^‡ö"ÙßßÿæÍ›QõÒü ¿œZXÂŽ’žUžø¦>;;{ùò¥2““WVV2?#Vò{UŒRÊ$»“`ö%ì¡q­ä åP]˜j‰vÌ]tlc.ç˜êåÑ£Gß¿/Ui™(6uH´F<}ú”4MDÔÖÖŽŒŒ455ñ{||Œr+öÜÜœ ùúõ«¢{†ü¨)‹äg+›Htww³2Ô»µµ¥bÉÆ¢Òäá7¾‰’CZáµÉŒ…*“ß­§pvÇòDë~üøådÃrŠÂ<———)„´bšîïï+?k(D¡T´H½¬áWÓ^Ñ'ìÈ3Ó[‹üª9d£œë^ŽÔíw~Ns§X¤Mñ”ÿ8ïVE1C`VWWU‘DW²¡ ŠÈ]DÒ´-dÙ."&¡hØ$Ø‹’C~I&ú‡Â¡y¤•â›âi‰± d=…H,ƒx‡D¼uØ××GzffFµ`9Z®¡Ö¢¦!ÿééi(–û’Eõyó„Á¹‹Òø\{~IÙŠ´ÚRž¶™ŠÃŸ`S(‰OªpŽQÄÞÞ^ÄéÒüHZccãƒÈ3OÉ «©ßÅÅE*ŠßîfEìêêzöìÙßÿÍ¢¤Qßa‡MŸ>}Rº½½ý?ÿùO(ðììLa´ùIz¬ïš2$ÔBC(jrrRß ÖÓ:Æ(ZÔ!ÍÍÍab 5™¢âËæøbÚGÕ˜²Æ"mL¡hé +õõõºI{ÕÔȨ‘0ãsÇ×¢d{{{‰üè"røêÕ«ßÿ}~~^w†¿öãǨÝÑÑ:J±üñ¸²²‚w6…l‡‡‡¡@ªVÌí¥¥¥ÄT˜¹0>èïïoiiÑDœa‚j „/_¾ÄgÂÖäkkk™hjÎÎÎNª~÷îÕÅÃa& ¾ˆîoÇ‘:ar-cÌÿ¶+o*˜ò?…J{»û"º/}||¬´ZTùˆîF„ž=+¡©-±Y"/—”ñ}•ŸÒÂCkÖSl¢Þýý}2«RÄ;Ô›ØÒ227CXÏ Â"bZ«ݲ&­¬ãù•rÔµTóij.êDÎ`ð¥‹zXp­cáÛÝæ>à 6Lñx‚ü´··ããƒâàâ›êo%¢·Ó/ [ÐɺN«‘ö;ðŒ=Á†¹ø,cn =]žÅY Oj+‘/_¾ä¿UŽÿýáÇ••Ý?HÛdcª?“6Å£‹ÌU ]ácèŠFŸTåGç d³Yþü¦mˆ©,Ò¦xªCL…²··W__Ÿ¶—ÐÐÐ࿆)¾Ýmª™–––Ü—¨‹&D« -·!áõK3B"úØÝ³»»ûüùó 0æ°H›j¦´/ïLNNæyyê–èíí½‰²oâqøöö6 ѧS¹ÎÎÎ~ùžÈÆ^銴1÷‹´1¥ß´§§§äÅNMMutt”°ðׯ_?|øðªé7êêê~ùŽ&%]>þâ“S­X¤M5ÃE|ii©„¢”£££™è»#ÜÜ´µµ!¢ø—¸§555õõõz$Ù‘‰n/···³•_2H ‹$úûû)¼««+^cww÷ÎÎN(<Ü`‘ª›››µ;ž={Æî$É #³Ù¬’NNN( gZ ­¤!”ƒ1xÆ”O9qód!¿ rÂ&2”ÃÇEûûû~9ËT?i¨m*˜"PÜ=µµµŠãqsø¿(*enmm1èëëûþý;Ž)¿!·&º8==Õ_Œ„"444,..êcâ‹( w|Q…+ÊXÜ`Åc …Ø•b“¢|³uhhHÅ*†6 E,‰ïˆÍMMMì…w®@ÜšEƒzÇÆÆ´)ØÌJòSÞ<é‘‘ÍÉ‘‰b€‡ä© O±Óª=?êöƘ›à·»MñÈK+óYñDqKu_TA­³õõu…¹Æ¹¬««ûòåKÈ£H×8Ä ¢I‚E\UM©é%w3,*°¨Â\g"‘þå§ÆŒV"Â+`Ú…_lûüù³æ§Šï¢(ž/ÿ~ooOïÁÕFPàôô´rÖEŒc']‡<ÏÎÎþóÏ?aä‘:4ƒÓ¶âr8|ü54lJÛSñøv·©rИ =%aCS`JnllDÆpj‘´úúzTPóLãE!ác$ôud͵Læøâ/+mii¡X ´yžŸŸ×§êggg‰üÿý÷ÒÒRbú „ 3vBíñ'ÓäÏ233ÃÈãÉÖßߊëUêD]TqUèò[ç>ݘªÄ"mª4æðð0hÛMÀ7êéééèè@•qÐÑ T ™AN0ަ—Fƨ”5/#H™Ýqp‘=ò£|ˆebñ—­ ^2ãÎj UïïïËcCDù1ƒüŒ!âϤ‘dœã°ÈÙÖ§ÆäDk±D›^tíåÍ>‹H<ãg—x™w¶ééû×kÌÝãØÝ¦xÊ?v·àšŽ>Ýý×S•Ëìì,úýîÝ;Æt]˜«`ÁÀbkk+>%WYáØÝ¦„Ø“6ÕîK#ÕiR1àúã"÷ööNMMé6@ù€Ie«ÐÆ”¿8fîËËË­ñÇ®æ*ô¾÷ÙÙY9|ggggzzº|Þ_3æ¶ñíns_àúÞÞÞ®‹Ò¶ÅƒÞ×ã8z¤eî¾Ýmî \ßë#m[̵á¨=}útqqÑ mîisèëëëèè°NWøÐõõõeø€Ü˜ÛÆ"mî8Óoß¾Íf³a† S欬¬´¶¶nmmùÃhsñ3isQØíL‰ó—±½LZèÛ¹ŽŽŽ¹¹9&s?±H›ûËÎÎNKK‹¢R§mŽù/ _ª8qïß¿÷×Væ>c‘6ÅS)ÁLò³½½=;;»¾¾ÞÙÙ‰Z—ÛGG÷г³³7oÞìïï÷õõáCWè;bfbJˆ¿“6÷§™H­‘j­ÜÛÛÃÏ®¸µ0mHÛŠkÃð(Œüþ¶1q,ÒÆü— Ö•K|ÂicLà·»1Ƙ2Å"mŒ1Æ”)icŒ1¦Lñ3iS<i›`LÙ‘Ífùkð›¶!¦ð'XÆT55þGSUøv·1ÆS¦X¤1Ƙ2Å"mŒ1Æ”)icŒ1¦L±H›ây‘¶Æ”'''ü/æççÓ6ÄT~ÔOuL°QMøíîrÀl˜bOÚcŒ)S,ÒÆcL™b‘6ÆcÊ‹´1ÆS¦X¤1Ƙ2Åï‚S=øíncª {ÒÆcL™b‘6ÆcÊ‹´1ÆS¦X¤1Ƙ2Å"mŒ1Æ”)iS<5i[aLy±»»Ëÿ¢¥¥%mCL5ðÿÒ6ÀS<›ñ5ñyɺ»»[[[Ó¶ÑS<þªÒgÁJ“““l6{é¦ÚÚÚÓÓS~oµöããã´û ì888èééijjZ]]MÛ–ò¢¹¹ùVOȪÄ"mŠÇ"]ôöö®¬¬ä®Ÿ˜˜(ílßçççkkkÔµ»»{vvVWW—vÓMå¡3§¾¾~dd¤»»ÛšýK,Ò¦x,ÒåÀ¥ÎtiÝè>LMMe¢ûç~ÚjnÈÁÁ|¤Që—/_¦mQùâÇŒ©lr¯qccc%Qh.¦mmmëëëÛÛÛûûû333VhssšššÐæ­ˆÝÝÝÆÆÆ´*SìI›âÑÝÔÒÞS5Ep¦‘í’<*üöíÛòò2—Ô´›hª™óóó©©©?údËÅ"mL52Í•î†÷¹hâ1÷õõyfî œégÏž-..vww§mKa‘6¦ÎôÍÝ胃ƒÖÖV_+ÍÝùÇèplḷÀŸIS „'Ósss7)G>4>ÚÜ=MMM§§§KiÛR.Ø“6¦J3}ÃtssóøøøÀÀ@Ú­1÷Î䯯ÆÝÝ]?ŸÎX¤©&jjnôÄ“^\\,°®ø¢¯$¦„ìììtuuúCj‹´)¿Ý]nÜD¤¯{Y´HWŒÀŽŽŽ*Å=債 i’2~&mŠg2"m+LixõêÄë:.ß¿¿ˆ¸t+×Ùšÿ¥%"ÿÀnee%þEY[[[sssXd“Þcïíímooë)–ò}úòåK½µ>==­€ÏSSS­ñªUUP~XIá8 o#PŠ•°¡åoÞ¼‘ŸÊÖ³•A€DV¢ŽÊIŸ ±á$-áTCØEui‘B´W¼]ÚåÇlUáʘbÉ,Á ¼zõjdd„òãáÙI A4m¤äÜ6²ïáá¡v¤sÔ]jHBVYThX°¾¾Î¢êMä—©*ŸÂ©BŸNQû/=ûkÁqÇŒûîL_S,>…Ê¢;þøñãZ»LDç{?ùáÆø£GÐÑ­­-4u?ÑeQ+•‡•2‰< IùUE¬_^^Æo–S¬,a^{¨š =FvDàjku—ÏÍJZA ™(ŒÙʯ>7'¿ê]\\d=’IZ²Geu h_2'ÚÅJ©‚ 333df‘Ò0‰¢hqkBi2@µ`*ktO“ØKkÔ±j”ÚÅ&!Ý¢#EBÅnll í¬¡ºP—z€•ňÌìNs!aÝ‚å:»È£^"C(YC(Ò^ÚS{¨º´eV¾Âšâ±H—Å$$\Á¯‹.îðéÓ§ü†ÅEš«yHHö¤ \‘Ã.h‹Rš‹H•Yd%i F ”†2!i‰ª¥‘ì‚Þ …d.Æ-a«l 3¿H‡¤¬ÿ¾ÆuQºêÒÜ”*3Ñ® “$°Dc”‹Ÿº+;5j ¥%ÂÆ1ª™/"×P†•”Œ”ùðáÃKÛi¶²/r–)gX$s8X¥na/êÒ°)·ä[ºPÝu%W ÿ/mOÞ“2³³³×}ò·´´trròüùó/_¾hÞíjooG¶··¹”XTcc#WáwïÞe¢Û¶a=þ\oo/R§ETgrrR9>>Žpöõõ‘Æ€ÑÑQÖd":·^œZ¬B“þþûoT­«« AJ<åEÛ$·™èþ0öàkR Ñßß?==­Mõõõ¬Ñ.øŽÙl61» .&Utvvæ¶+þ0ML\FvÔë]òªµ Cl#ßþùêÕ«ÿüç?!?„9i ‡@<íeÇ«ždk†4½v§[™èÑr¸i/ º‚ÓãÅ‹ê;ž¢”v%Ü;Ò%cJFqÿh.ÇÁÍ-ü§øee%—~-æzÕ™«=i9vò8ã½n2ÏX÷~Y¿Å-të;›™WÒh8Ðr›"d9åé*ÏEt^î5û2>y‰;±r@)„ÝíŠ{ÒJ¨.=¤—r¾Õ´p‹;Þ|yêÚ‹AèØÐFùÄ¡¹ž´nÑwwwÇ=T*•= ÛÝ¡3ލ!ò¤YT‹Ôñæ«JKçg5a‘6¦z(N¤¹¶q䲎[ÉŽñ;Ì(Yx®‡lAVÉ£]B‚_t=÷©6~a|Q"DæDN­ ¥%6éÑ)šD¨ˆ•¨šì‘Áº•­æ„Ö…Ç«á 7ãƒPÆÄE4ÞR²…ÚC»‚Ù!AߢE2çöR¼oY£l¡Ø—±‘^õ.´Q{%:M†åh¢vÕoaQf'J¾ô Þœ{.ÒfbLõP\0“Æ)+g`Õ<;;ëêêBB ¿ŸŸl6‹OyÃÙÆJÕÆææf’ô³gÏKÕÆ2¡··WﯥmH:ø™´1¦jA®vwwQÓºººR©×ææ&E•É$XBÓÔF[e ‰nï‡')÷ªAs±'mª{~ØÁLŒ©ð9ð¥Ò¶ÂS2|»ÛÂÛ +ð6&''ŸWóóóú<:w=CŽŽŽÂ‹:99™››»‰F¥ÇÇÇ---ú$:í¾ùš3<<úG‹¹“ˆcsb¸F×íííÑœúúzš£·ÊÕÀD¶ÍÍÍx&eÒ~sÍT0>…Ê }tÝØaeu¯z•÷ª/¬.ecccdd$ú£hcô¹åä¾µÞÚÚzzzzó&SNáº2±Ù¢>Rè¥i~ø¾Kkòн Îî¨un¶D©£½Ò¶"5|»Û˜êAQ¯óÌÇ!JI<\‰ˆÇÐHÄÓ¸j}ÆŽó×_‘#‘aF3ÏŸ?§¯XÔЇz_½zu€þ§ó9ñ‚©Ožd„„ºsjaX|„Aß^zdQzVj~L9dwú» °'mŠG/t¤m…¹=elkkK÷¾7—u.Í>|[ÆÅgQS5ÄXráF`]Óã%p­ŸŸŸ륦ËËËxÆ!©›Ì³šý"Qž1kÜÓx¥öåËT‡UUh+¨|¼@”Rs]$@þ1F’vUo£©ˆ„ùHÐyò„B4íU\{(„±…™‡Ù8‚yJÓ½H ôñãGDZ·åUu¼*ä_­ÎDJ&“h‚LÍFd¢€£ÀÈÇ<ùÓ¡œ¸‰Eµ:^i ¶ª ¤±¡ØD¶P¦ôçýád˜¢ç剻åccc4ðÒ#K—2ĉ¿ßg®…# SÍp!FŠð;::¸t" ñ€Çû:Pn r_¿~åx={öŒ‘GùD®fÈ‚÷qÛÈ`$”x‡îŠ?¤¨&,ÒÆÜ ô¹ÑçÏŸOOOõ6íííù:PnLOO+7ìkÍÏ}«èÙ< }é ·„DúÛ·oûûûy²1¦a4S³ž”‹´1÷Çî.[Å2‰tìA)ÃkkwCá±»wvvܬ­­-,,èþ*ÀowcL™RV -{îX¡¯þýòòòÉÉÉÓ§O777‘ê´-*~qÌ_3Æ” ¸ûŠu“¶-%À"mŠg2"m+Œ¹†…ø|ú@+¾æ—_Xr` þ_áùCü²´HÝ€<àR¯­­íìì¤mÈM±Hc*ô¬$ß•!ŠGGG™èS±_f¾í+>–(¬¦¹9µµµÓöööò ‘[icÌí²²²2::*MUìÁÁÁ x³³³,r=%[Q)2³ž¤X__׳2ŸGà˲¨©DBoå×b"¦§§6„lòVùewŠ:<<\ZZêéé ”c%$ÂŒô÷÷¿yó&L^ŒÉD#-Æó³2ÞpY¥<ñMñt]]>tf%9Y©F±‰zÉvÕ'ï˜Ê¦³³³ÐêÌÐá·CÉÁ*… ×qQÿkǸÁ—.†þ/[šššZ[[+}Üc‘6ÆÜ"¸2Šz­œ“““þù'—NE×d>DÙŠšJ_I(<5‰††=X™››CžEå#笡)=rÕØØ˜ •RPÏÞÞ^´V Üæ"Ÿá*Í`Á¦x Qv‡è¢*Õèú*)É<<µ¦Á AáHš¬":Ç&=.eS8^\\¬­­½ø9Mu<³*’åñ¶„ ­Cf¨cˆDÖòýú•õ}}}¤gff”GÚßOkfh~e›v¤L­gqkk+Þ(u r»ÃÔêqzzJWh>J©ˆÎ¤–ÎÎN•¦ÉÈiZÜ`J‹/’Ÿß`ÀmŸŸ7œOºˆÖË ‚eŒ¹-j#BhëÄE— Q;p|Re Q,ä@Ç£{âÞá&¾{÷.ù”¸ª‰É.C±èÊðð0ƒ›ˆãž?ì|ß>¡y@f1ó¿±»qm©¿ ÔpDyâ›°‡4-éVL·ô)V³`…2/}­ÏÈŸè ä™öâIÇg '© Kt§zccc(Q‹‡ª«¯¯Œ«_ÄíŽÃ)sÄÜý·Ý%Ä"mŠçÂ0̯ÀGÔe´SŽW$*„§Ö¤ Ô¢±±ñ÷ß*¥É¦4 •âe"Zëë뤩‚M¬G®PåLDéB½ÚÛÛq"»»»WVV45“ =99É^ˆ÷U Ñ<KKK‰((*65êþ4íãǺKL”Œ‘’^\Û°IÙê"B3;::45ÅÑÑ:š¿‡ÑW '?ØÖÖº‚ñ ]AQñ~@nÌ< ƒ°‡­ô J¦˜tB“NƒéÕø"¯+â,zûóçÏ•+Ò¾WiÌ}綯h³&{V:‘àWO‹ºƒ-Zw¿¥îdÃ% (SùÉßÄâ÷ˆxf177§¦yT… ѾÁìÄî˜ÄJò¨äÀò`L¶²‹ÒÊLŠo iòÄ3_¶…õñ ZŒ[{ºBwøÃダš‰ö³ ‚=11Á‘NôÂàÜÅï?¹Õ“çâÆ·»o¸{ê8 1÷ò Š×‹£©[¬8yžäºàøâˆkúÎKÁ!îêêB­ÉÖÓÓszzZnÎDáaA/evvöððpff&ív‰owcÊŽ³³34#ÜÏùÑüF6‹‹‹y2´¶¶nooÏÍÍ566&~WÏŸ?g¼’¶Åc‘6Æ”uuuñG¤‰'¦¦ é1:¶r]Ì{‚¿“6ÆS¾|þü¹¾¾>m+RÃ"mЧ&"m+ÌMihh(IˆÍK¹*HÖÝ °by2Ä#se¢×³ã±/ÂîŠù_¢t¥Õ´âz@í­Ë§§§ÏŸ?OÛŠôHûÍ5SÁøªB`Û ó3zI*$Bš\JmmíÖÖ–ÒŠ2ÞaÖÝà‹(NHæ­Äƒ{¤Õº"z@ïÉ+ô Æ'2oll”asô¡sÑ»‡P0Š=icL&DÙ¼›òÃ"žëôôô/wO|›XÌ5>·Øø.‰Ý‡††(/s{{»££CD"ت)HZüÓj=&GÕØ%Oï…M¢o©¯2ã—VHÏ\ÕÏ °›ö†øä*‡¶‡Ï²û¦øI4FÒÛiÕž>iLãS¨:ÀY¹¥Â3?ãd)8%ÐÚÚÊbww7îQx£8ø¬ By9¯yNMM]D:Ç3QÄ1ÖPZ¨1^¬b‹âH±Fß"Ë †ÕÕUåß³ Û§óÇñ£˜§ï¶CÔLŠåU‹‡U¼RÕŽº+ÑÙÙÉ^Afpì0^›÷4´—ͧ”ŸßÃÃC™G!¡ WßY£® ^Œ¡«eùåýg"¿9X(OZßF«ÓÔÊaG…å…&¨dŒ”çûÕõm£Ø±7)¡Ò=i_aMñX¤«ƒ›_ó‰‚\ü ü * £Áb4¡@ÓÒKr*ê¤äv#BᬋäQÄ Ÿ"g[¢¥°Þä¤^tuŒßוR†@âJEdý#ƒB\üTzE±ŽëUPkØE!JkS#I…´V­ ö³¨&d¢ç¯ªwaaá"ºÓ‹%Òo!B]4½Ø]ÇŽÂC?Ó½!¼öU·»ñ 6(<ª¢ HÏ(Y1^ôïfÔZÆÜñÉ9q“*]¤ý –1÷9m·wSQsRñËÕgg‡«? ãS8#BÃÃÃh!Ò¢øÒr¸ÏÏÏu“Û¡:,jh„S¾õUñ™åê›®¥¥%JPìOM]%ÆÆÆ´RÞ§B`jv ͸…Í$X3==­›áò;ua?ê¨i¬ÈðöíÛׯ_g~Î,"°3´BñM±­§§GíÕ4V¤iiªÆì¹¹¹l6KCâß=c*6ŸDÄûYkó¼l¥·ÆFGGß¼yóâÅ =\Çã×zErÏÔB¯“!8èwÃÚÚZ|þ±{ˆŸI›â‘”¶¦p]F n©p.÷\ÜùETº»»Ñ2ÍÏ{{{RÜ5ÒïÞ½ÃôáÔ-VôLÞ$Ê_Ìó”´¾¾yÓô‹‰f²×BÄï¿ÿÖKx47THHŒQe,ÙÐô‘yæ'Fç¨Wó\!-³³³rM€­Ù£þ¤ä§@µ—†SÚ<55E!È$%HÉ£œq¤Ȧé4rŸ=ã}~üø›/}µžõÔÈåÒaÏVÝÞÏ-YlÜÒ©’ã1à^?Îø^¥1&z„yK3ú¡šªRÏ€© ÃçCo666´¨×w©õÑ a%.¢pÙzY·‘‹¤õÞoH=ùf%Ùôä!TgTö$â9«À°ˆU˜qxxHÎøzZ»JK  ¦ô$…ŸžžbåS›ùÕ”ÌñV$ÚÊ@!::‰[Í´WÝHQ躞ñ³^ ʤÝÖN<°ôö%[¼-l%Mušà’_•¬˜çJ`¼&Ö¼¨ñæa·+ývw9Æì5ÆÜ= (™1ÅQSSƒ®ãþâô#oÈdIŠÕœ]ñ{æ÷ööö›GßÝÝåÜ® ïÂø™´1æ_p1ëëësgx4…344ÔÙÙ™‰â&f´¼ (ôí=Œ([^½zÅ9Y­Å Ç"mŒù®† OŸ>Åçð•±8$¥zê\ª2)mcc£¹¹9íÆÝ)ƒƒƒº™Ÿ¶!éc‘6Æüœ¿ýýýööv½4dŠ£´CJ»ô­õ*fiiiss³roP—¿ÝmŠGA€Ó¶Â”è£Gô=’1w íÛ9¿8fŠG³køª>é½½=ÅÙHÛs`ŒˆH—V¡+ýÅ1{ÒÆ˜$‹‹‹CCC;;;iÛbîŠm®o»=4Œc‘6Æ\ÂÀÀÀÂÂBWW^HŠsMšªyÆÎf³OžjkkÇÆÆ+q£+K¡3ö¤1ÆT%¸ÑñYÃ3èFgìIcŒ©Jp¦ã’\‰ntÆ"mŒ1¦Z‰ÏV¡3‰Y¤1ÆT'Á{®P7:c‘67¡&"m+Œ)/vwwù_Ü·©«Ê–‰‰‰LźÑ‹´1Ƙꦩ©©BÝèŒEÚcLuSÑñÀ-ÒÆcL™b‘6ÆcÊ‹´1ÆS¦xªJSmCL5à·»Mñhv ŸBÆÄÙÝÝ}üøñ£G*÷âjÂowcŒ1æV°HcŒ1eŠEÚcŒ)S,ÒÆcL™b‘6ÆcÊO°aŠÇïu“KKK‹ÿ¦TX¤1æÞQ¹Ÿ$]—ƒƒƒóóótÛ˸­è}ý´1ÆT9ÕÚÚÚÊÊÊéééÙÙY]]]ÚÝ;Ôí¨õÈÈÈÓ§O ßÑ"mŒ1Õ dÿææfssóË—/»»»›ššÒ6ê^ƒC¿Zµ¶¶þr‹´1ÆT!(Áàà ~›c÷–!'''ÃÃÃŒ¢òä´HcLUtuu½xñb||¼¶¶6msÌ•èH=yòdnnîª#åO°LñÔD¤m…1åÅîî.ÿ‹›¼+tÖÖÖš››ß¿m….sð¡¿~ýš‰Þ,C°/Íc‘6Ƙ*aîííÝÙÙ)äa§)8p¹[ý –1ÆTK§§§v +޾¾>½û}xx˜xDmOÚc*œ°áááííí«Zß ‰´5—ÐÝÝKûu–EÚc*t—‹ûââbž÷„ÛÛÛ?~üÇØÏ.[ð§9Žƒƒƒñ•icŒ©l¦¦¦†††pŮʰ¶¶¶³³Cbyy9mc+†“““Kß*8Óá` ‹´)ž‰ˆ´­0¦¼Èf³ü/†‡‡ï¦:´dzzz|||È“¿¦¦!Ÿ™™ÉDJ‰(’@çH£¨ êˆÆtuu±ž5øñ ÚÛÛã†,=}úôáÇÁ†l6Ë"ÖR‹ÒBŠÚßß§ÕÂÖ?~P;i~+°‰Ì{{{äÇ€`9{Q#Þ¼y*¥4ôYÅž0.Ñ €oß¾‘ŸÅÉÉÉããcŒGV@ÐZÄ^¤C‹È })¿££ƒœÖÄû)&Ð5áÙ³g,ÒÖ3˜ ÞÓ¦!,†® §z2¿CßÝÝýãž cŒ1• ‚´¼¼œ'¢Kýa„Ò§§§¹9¿ÿž‰nwú„NOLL 4ÚJúÑ£G숆éN>+YÃz%ÈŠb/-j/Òx±$ššš´)«}GFF”F¤É‰‰Ú„1*<*M9É@iäå$+ØÉ¾Ê/Ý%³Ht f Ð"Òñ‘Aoۨد_¿’¿¯¯/ÞWCÏÇ› öª cú\–„’ÕcêêüG–œ[[[$ìIcL¥‚놷—'‚¡ÇÕS™Ÿw}Ù±±±1÷í¶–:Ÿ^7ý£áá™1÷ÎΪ¦A‚o¾r¼´ÅÅE5p|||}}½³³3ÏórRÞ|â1Axt-ÔQµ 43°™ÅDíž8â˜)=éñ»cÆÄA0æææ²Ùìm¿;¦[¦ùçPÊDÿPÔh~~>©ˆ¾ÂÒRübj<³‚H£+^î;Þ_¾|Aq¥ßyÞ'GhÛÛÛÉFQ˜×ÝÝÝß߯—Ñ05]ZZ’¾²>±/ëÉ ïéé‘Î!ºüNNN’ F\ãÊÊÖ§Z|ÿþ=`†žþbÇ"¼[·½½ÍØåÝ»wüªùj‘nS'ÀEþøñc]DX‰y VÔ„ÄWmzíŽVS5^8‹ ¨:þ¦˜ÚÈ/'ÉÆÆÆ¥}ˆê#öÏ‚en‚f×ð)dLœÝÝÝÇ?zôHïñÞjEèA!µ R8¯È ~¡´ ½ÜÜÜDí‚Æ³&8¸ˆëõ˜Y¤Ü¨{ék"™§L ’ñu“ùÁƒìEáh³"_*‹XBEß 6 ýÉŒ÷Ï&ì”ÙjyTúºB6Ç;‡lN6úöL}…~ŒŒ|ûöEJCïqÊi¥ÑF!ò}Ci¬ÄûOÜN-¢pú½Â €b)!ØÌîº ®œj¬ú?–çàZ¤MñX¤É¥ EºR@öPÐ~‘ÆO-íwPTÑÕÕ…ÿŠ^⦗m¨s}óÍÕÕ·»1¦"YYYIkBÌ[BŸKÕÄÑD¨J[îöööÜÜ\ccãááay*t&z0¡„EÚc*½E\5,..ÆWWWo£–¦¦&}cVøíncŒ1¦L±HcŒ¹6 –»þä䤈/>(ê—µKH}“b‘6Å£îӶ˜ò¢¥¥…ÿE5½Ïu)Šœ•»þøøxrr²ÀBÎÎÎÚÚÚøU(®"l`÷"Œ/ÜÂë¢æ”°@‹´1Ƙÿ×q‘›íª|ø€S»±±¡Q¹(.°žOÚcL5糋k‹#{Û³…Þ~qÌcLõP[[«gÆe;yƵ°'mŒ1¦Ú¨…ÎX¤1Ƙ²Å"mŠG±Ҷ˜ò"›Íò¿P\ª âí۷龑"‹¥hÏùùyü“î"Ír[W\süLÚ_+5&—††ÿ5îÔ4>¥$èëjŠE­ÏÎÎB´“›°³³ÓÚÚZôîö¤1ÆükkkŠ5¶²²288ˆ.--)˜6ÒÅø#ÌÁ¦ÑÑQ²)& ‹(œbMdÉVJËDBEQá«åK«$Ūü°Hɳ³³ª ÇT‹ZÃV%2‘ÿpA±2@»„EÌ[__'[0^Ò:úfk<„¸ÂÓÀL…MìKž°;‹X›hBÿ›7o -¾KhNþ E,ÒÆcþ R¤@˜è :ôðáÃæææÎÎÎááa…ùüøñc÷AN~ÇÇÇÉ)aCùxÒ¨ nø³"§’PHbÝêêêb1×M-%±§LÅÁB´mnnNÚÆŽl•j’@ï)ôþþ>ö°eU µ§OŸ†EÌC>5ùG¨QóoRBîMovd÷gÏž±éøø˜ºs4­ôûƧóÊDƒ:$,ªÌ0⩯¯§öR WrG‘à1Æ””ÒN°AQ ú~é"šOBñ³Xóýûwd»»»›t|ê‹ÓÓS;::ÈÆ^ìrMVñéÓ§øô¬QÈ-v×üñÅÖÖÖ™™™Üæ„ÈC~~7»)"Lã/#T&JÌV køÕdñÅPivÉ­4Í“ïŸ?~Èò„¹:¶¶¶ÔöL‘;wGM/Y vÌDÑÇÔ—‘Œ'Ø0ƨ‹ÀO]\\$ï¨Ûø|ø—Ùl9‰?^%îìo¿ý†3ªÐÖ8»h9ž·n vDÇÆÆH“!±øËo¥ð§1F³S “™œˆßÕÖÖÆV\d '144¤x&ïÞ½S~ü×øbðž)™¡F!ƒÛMÏ$žRËuN8Ð…€ìuisX¤Mñ8*¡1¹œœœHÒ*.Üò¶³³ƒ˜õ÷÷F Ö¸ËÍÍÍl¥]ñülB;ÿùçšLzss…NäÉD"ÚÛÛKÉd£Orû……-&ÊÇ~3t4ý3käëïíímll0t`<ÁÝÓ&§¦”¦"Še½fªÖb!Ç…ÿüóOÆš›Rï‘á1³ûÇóvP~GGåç8ÈÉøàóçωûùr ã͹ÊÇî6ÅãØÝÆäR¡±»‘Íõ„ ¡F¨2E¹BNfgg§¦¦Žã»èÙ3ºˆßüíÛ7M`…&áIëý²ðö5…ë%gy¢ÈR(Y[U²œõP~"ÕQ¨¾eRíØI-$XI6v!C(–üÊXÔ^d ­NtB&š e ßM± ïZ>:£¾RBÇ]95  ­ RëëëɬªC?Ç›“‹bw[¤MñX¤É¥BE:?È'.rƒLƒNÿõ×_ˆ4ÞíêêêXUÝx‚ cŒ1¿Fk…ÎD"=66†Ãã«G­¦$ø™´1Ƙ|tttèmäü88P 2É ë777_ì¶Ÿ¾ßg,Ò¦xÂ÷Ƙ@KK ÿ‹;Э¿ñ-¤¨ ¦¦¦&''C<Îññq…ð$ëC8ODñ&[OOO6›½íöÞ+8=z”±HcL…òàÁ}JT¦"”FŒ_¾|¼gdX›øE9^½zöjjjBNôÑsžù£B¸ïLÎ:¾)(B2T7icŒ©HHįT:ÝÝÝMiŠ}c=77'éE°‰“EÅšÖzí…‚"ÒˆwmmmøÚXcà[×ÔÔðÛÜÜ\__ßÖÖ–‰—õoß¾][[c+CáááÞˆLô–¸rb[ñѤìè舄œxƒ—_­|øð¡³³óßÔ-—5Æs[àï*ðu©JƒÖÖV…›~úôéÈÈÒ»¼¼¬Emjhh ÛE†Zñ´±A¿‹Ì?Èùýû÷ÕÕÕ‹(@Ø÷ˆ ;¬Y\\TH/3áWa@ œze Õ)Ú¶¾ï"OÚëÐíêR‹´1ÆT*[[[\ÍKUš&ŠXªðÚäV"úè'ZŸE#º«y,¤¦øÙ>Lˆ´ž¦kÍQÁ @` ɡРöÕà€EÙSÂiEÊz;̺áï¤1¦RAØžúæ¥é¶vˆÍIáuuuè"BËbøZº¹¹9<ÀÎ¥¥¥…QV”ÛÆÇÇÑWÏÏÏëëë3?|jN޾¾>½£þîÝ»¶¶6¼ðîînÊ—›ÞÛÛ‹#&|šŸŸ×‹l—ÆÊ®æææè–ÿ.¤=b0ŒO!cr‘³x©‹y fºù\ÐH”8,â ë¦+r_&m¼Ê“F¤åò"Ϻ…®É.e0Î1iyÏH5µÈw§LMøH~­‘N*b ™åF£añìÕ„n„Ö9v·)Çî6&—;‹Ý-äžRWxo+u5oÕ³gϰjaa¡$Åâ=···ãW«-Þ¾}»··B«úv·1ÆT0(–&ÔXåîïàà`&Š‚ò÷ß—ªØW¯^áW·BŸœœLNNÆg³'mŠÇž´1¹Ü±'-ÚÚÚ^¼xQV“»ŸÕÕÕ•°@ú31 d•q~~ÞÒÒÂAü¿Òö¤1¦ ØÚÚâúކŝïéRZ…ÎDݦۥ···££#q-ÒÆSñà_noo766"ÝÝÝi›c®M?Ç.÷ù½EÚÏÄÄDÚ&Svd³Yþw˺¡¡áôôwsgg§¬î{›üœŸŸ···?zôhqq1w«ŸIcLõ çš È\i›c~#ª®®®©©©K38v·1ÆTúÄöÉ“'¸òñÙ'M¹qrrÒÛÛ‹B/,,\¥Ð‹´1ÆTÈóñññÞÞ^}}ýììl 'Ë27çààynll|ùò%‡)ÿ;¾ÝmŒ1U ò¼´´477Gzxxøùóçi[t¯ùðáÃúúzgg§¢°ò<Â"mŒ1ÕÔZÓZd¢‰ Ó¶èŽ8???::J1[KKË£Gô⢎EÚÞ õ{¤ÆÄAñ\¹ ¥m‹ù7Jooï]–)-iS<Ž8fL.©D3WQé"íÇŒ1Ƙ2Å"mŒ1Æ”)icŒ1¦L±HcŒ1eŠEÚcŒ)S<Á†)¿×mL.---þk˜RaOÚcŒ)S,ÒÆcL™b‘6ÆcÊ‹´1ÆS¦X¤1Ƙ2Å"mЧ&"m+Œ)/vwwù_´´´¤mˆ©,ÒÆcL™b‘6ÆcÊ31ÆSUhJï†ø´÷ÍÍÍ}}}iÛX(žOÚç“6&Ï']d³Y´ùÒM_¿~mmmMÛÀBñíncŒ1ÕFð¤´F¤mÝ5ðínS<i›`LÙÇ_ƒß´ ¹×¼|ù²¡¡!×™~ÿþ}Ú¦]ßî6ÆS…¬¬¬ôööÆ×àCýú5m»®‡EÚcLu’x2]YO£…ŸIcŒ©NâO¦+îi´°']?~üHÛ SœŸŸWâµÀ˜ª$8ÓÇÇÇ i›smüâØ%looÏÎή¯¯?|ø0m[LeÃÕ¡¯¯oxx¸©©)m[J>1ZYYIÛS1Ô××?þ¼¹¹¹¶¶önjÄ™îííÕ{di·¾ìIÿ8@\LÑæ§OŸŽŒŒð›¶E¦âá¤Z[[cÌ·¿¿?444>>~gצÛààà€æ,,,0øà’×ÙÙYWW—¶Q¦ò``Ç_ƒDww÷ÀÀÀ­Æ9g(ÙÖÖvxxX¡"ýo$ óãlj‰ .7ü’NÛS…p^-//?|øß´m)„™á#×™™™ããã´Í1ÕŠ­­-ù¸üÞÒµ÷û÷ï=J»­ÅãÇ2;;;õõõ{{{\zÞ¾}[ÑŽŽ)[8¯¸ 1œ?;;knnÆ%MÛ¢BÁéÉf³ëëëÏ%udd¤R=SfhØÇ°•S å4ã ,Ûî»Høð¡··www—Åòlµµumm-m[~ ñññíímþ ÖfsKpíEžq“ŽŽŽ¸ [§ãÜk‘æ´˜ššB¡«ò¥S¶p¾íììp1šžžNÛ–+áBÙßß¿¹¹¹¿¿ï?ˆ¹ê………—/_2„­ [M·Íýé¥Ú´¹{½ÓÓÓÅÅÅò¼¡Ð---X˜¶-æ~Ñ××·¶¶V)·šî€{*Ò\···­Ð&-8÷t1ºj®ž´B¿}û¶‚¦ó3Õ„n5õ÷÷—çö޹"­k>tþgl\¤j"ÉS#å†÷µ°*y,¼³[j‰Þ ¼ÿ¾¿¿¿L<†ááaP áûOôfYww÷¥ÏèaùÙ³³³—ÞÛ/yÛ©ëÒÃÊÊžžžÛîÚ}óÞP‡_º‰æÏÏÏçÙ÷ÎÎëŽQœÍÍÍ>Z__þüùÝ4ê6¸w"Í5hllì—¢¹Üd"EçªzvvFþKg‡Eï¹B­®®f~^°(¿$v–É vþÏü‘®2æèèh{{;Ïîd(äííˆÒZε¦ÿö/›Pº®ϵ³³sjjª´=P+++…¿Ë-é Ÿ}ŒŒ\š ÷zoo—ˆ n®x°r||¼´ ¡ºD°}þŲdÿ†…ßžŒÉlzã†O Ôá—šMó/õ7D©ŽE!]”{Œ.enn®««ëæ&U.÷K¤9u¸ rrÝäjÅ•÷ñãÇ,r½ô6—3.:º¨é‚¥lì888´‹¹rÅ¥ímR¡„®õøUoÞ¼‘ÿ§¢pA¸Ê„/ýƒG‚ˆò¿b‘<”¶´´¤a2[ɬ “* ¡øØ$“‚´$…Ô‹këëׯÃÊoß¾…¦)4GèXŠ¥vš©—òX_WWwéàF…‡ɦ0邺âËfµTæ)F´š¦®SÕª7q å@k½ò„Ó¡KãMPçSc¸¾¨"UMuägëID84J´··«.Ž…jTBõ†Ãš‡™™™üþÍÝÀ3>kPèÄæÌÏÿp~`|LWhLœür¤4´¥“À‰4›ð—{Y©þ$Íšßø0K{%ªæÁ¿>ÜÆÐ¶’¾ô‡Æè KÂ-²A­Ðý˜`•Nà¸yjµµW‰Œ›Moh(‡rBæ`ÏADüj“ë¡rI ý–‰ÎÏø96éXÈÔDO†•êmÒª1Þ^%T—¬ +ö*®?§§§7qZ>þÌ ¸èÝÓ'íûíwÊòòr'¸hf¢ëΧOŸÔQ_¿~½*3t¼'3‘Æëž¡‚A¢â‰Ûœ|CCC$ðBH°’Ѝ—4»_ÏÅYÄ$Ê¡4 „µ•ÄÆÆ~¿â@i>sÖë[ÃPiòkwY800À“5,j_2è7±—j‘å=bòcCr¶²FsËèá=—x5V»„€|‰3MCÛPkõƒ†Øz{@#$u Tos1okkKA‹èÀxzœÁJìÁGr’?t©zCM…$èÉÕÕÕøaÅìÁ0%ø ‡[ /ÕJS‚_òS¦Î:Ö°ËUg…¤ûÞCÑî¤Í¸«2¨£t Ô?>Ž,›8½"ô R™9Kõ'Š÷›gåh/Ž‚2d¢;[¡]ä×zV’戰(ƒuç¨+Ô¢ÓOåè¾Ò ]îYäpëÌÔŸBÁ^Ô4ò_D×ÖË<Öèa¿þ_䌿…0[gŽ Ô¿ {dkÈÀÙìa‘•ŒqÉ ðÔ²'þwÐM½¥ïXvç_̾¬¤ÌðVDzF™øA¤9ºd©[ÈþãJ„ºÈ †¨O€® Gü"úÇåù;Ä¡'oòd:õÖ ¹_"Í‘.ð ýt2ÅÓ—’+Ò:ù8#IpZ‡+ g[ÈÆJþ¬!CEMÀ rÂÉÍÖðçTü<]ÅTš®tü95ª :ÖèÿUP>6þZqÉÔ•ˆDÈê…Ä=1]Ñ‚Ì`kÂåUw]&¨KvÆÿÀ ‘NÔ(XÃú¾¾¾‹èª„ÐX'” áʘ8ñ£¥„F¡Kã"Í!¸ô°Æì›»>tKB¤é ìŒÖÝON”©ts‰666Æ»4¾©g±tƒ®ÚªÓ&Àaå@äÖKár‰6\·9—Z˜çE¹<þïˆÃ œ‰Gè=!È}¸£;ÿT¡8kúÄ+L¢ÅqáÊ}’Êy¿­8¾‰4Hì…àÑÿz•!¾^‡Rå!ô8<Ï“{óKŠø?r"ÅÇREÿ¯Q‚-ØÏÿ¡ô‹/JþÁë}£ð08¸Ý¸&W}ÜuÝp:zh’vëËÎgÎä·oßêã‚RûêÕ«B‚4˜›£.T*AÍENl¿j…¦©£Ó6Ę˩©©)ü­œÌeÏe×*GE ÷Æ™1·MáWoE;8;;+¡ó“.÷È“þÿí¡{ÓÞÆ3…œ«¢njå`jjÅ0ÔªÀæ'qSTbØ(pUT™šb®rj(ª:µª|ß_Þ§ç9$ièÒl¹mÞØs—47ç&÷ÞsoróžN§SúŸ÷Ít:M­d^„Á`;Ÿ¾k>rÏ"pL;¨.VýøñchAk–¡Y«»W”E$«ÊqrrRs%7£Þ鯭e§É´¥ÈmëíŽtÞõ(.©ûôéÓ’“ä³äº³z¹? v*mÍÛ»¼ìm1¯j”|lî K>¡ay«ò÷åòAM¨¹ZpqpQYpOqÑP è‰m—Oã²ã"lj³¡5o4¶£âQšÞ 2›“Fݳ»ƒ³à–!7>¢ÀFüæúúÚ®ò¡¸¦åL¡uæÌÏÛR:ØÞ$_7Pa¼ü܇g‹lù°Âã(VoŒÏïòéxæü¨I„¿ÊàvJÞ§fBôúÔH áQ!1*WÃWb6¨0±k“8†ymY1` 1ð›ï(QUc·pO~0¨w1Lãœ4ªxµ=[ŸîFɧ/$žÅÃáX˜K{˜fËáªxÖfØ$˜g”LJc†#‰]È ÎP9_dŒ&¼&à_ÖZÂNrÒô£þ¼´ÊÛéË’*²n͉oaáF(>åtêÂRù!r±48µõA“6cpüÅa/ÌÙßäÑô‰~—¥mºïl¢ÛòÁ9–1ió˜áÃÒûègé&Y]ý¢Ü¿Ë§-v‹ þRw!uÍÊ×:;‹E”b(*o®9ïè}Îó‚UÐÙ¿fUÊN–…uÉÀðVêX¦Smß/¢‹òæ^aÿˆ-”4w& “èÈSѵQ¸‹=•O3+Úc¦r OqKgj=S/[ÝÍÈóU-ýúõk§ÓA­}ýú5Œs…æÝívq l³d4bô LÛ±|\ÍÂ;À±ð‘GGGplÓéôSÂÞÞ§¹777ÈÆX¹z½~ðüùó(/;zŠáp˜]ùÉàØnZöÔ@õv²,èݲEöE Í®ë¶U`(Kqx ŠÓ©óÆE³¸Gfôû}XHIj"X‹IC»ÝæÌ”Åï²´ÅW¦Ò'?MƥΠPãbÞu; ©€(µ€ëŒ›X¡v‡A©TÜ…ÃÃC ¢Êø`~—Oó@j¡³–ž¯ïÅp'/^¼À!|$γ VŽeq,¨óÎ΃MeA[È ÁJΆf‹¨ÙÞ½, Ãi`/çÇðšïß¿·¬ ʬ͎’Îã 8Ñ­­­‚R£¼ .À%N‡ÙKd³%(8î2z-˱ ˆp±ßÅ.äƒYÚ²ÂYø¯@V׳òÅä———謼Úyã¨{”P ìZIVð|CÇKþ½ßôp—OdzÁ2ßZñí'‹Ñü™4ÛGµð¾8#ÚÆ³ÇÂqòâŠï‰™æË$ü FFϤÑòùŠ:ú{ðkoò||I³“_ûXYxv+rêöâ7>¦,œX°ÔöJoÞÚxJ?³Ï®qÍΤ ”še¡ÙÞ0¾ÕÃFo ߃Ú.¦yk²ï-(²Ÿ{ñª–¨EáÄ»½§É4_:plǘQ2ŒÛO°]–f,ËÔ:?ÃŽófÒöNš‹§lÁ+*ŸxO&ÊñÆImçij9{Ar_ž"Jž!ͳ“ eÁ¿±È– ˆfºñÜÈ—DD‰SD½*˜I£t~ #±FÉø&þ{Fn-Åfù|8gÃ2láCoîJýŒ}…-[IͰ-aŠªUKWm†+Gtœ4¿;}à,|Æ.­Þ˜¢¨ŠAõA6æ«ïû ÖÛçÊì,w>~÷î]h×Y°–ƒÅr4×IG3?Í+ë¶E4 Ì¡ûýþÅÅE˜,.{\?-V zh¸gIÊG °‘…ë!wvv0ŸVm: ^¯Ç¯Þë¶e.\'?-zè§OŸªO&û+??øùóçÖÖ\uÝæˆ5g0´Ûmt@&Ê,˜ÇÀCó‘cݶˆ¦0Ñ@PåÂo F£gÒÆùù9<4æ7›››kæL„&è}QµàùÂ|ÄsèÉdòêÕ«V«uzzºê«,EÈ ~óæM”D®ÓÃO£ßIg$üøñ냃ƒ½½=-Ë帺ºº½½e‚“ÞßßÇÜtEýÜx<~öìÙ£G(«X¢Bà•ß¾}{}}­`.rÒù ‡ÅÔÓˆ³³³?þ¬JLbða˜ t:íímüÝÝÝ]qZ…í0„¥NNÝ‰ææææÃ‡ß¿ïv»ÔÙ­Û¢@‘“åÙØØˆ2RÃbí·¶W†èjƒA±¨mÓ˜N§¸D«ÕmKpxý`¤å›ÿ‰œ´(œ´YF£Ñ“'O¶··‘¨Û±ò4}u·B,rÒB!D ÈI !„"'-„BŠÄLDyWáiµZhø[·!bÐên!„"Pô¸[!„9i!„"P䤅Bˆ@‘“B!ENZ”ç(¡n+„‹ñxŒvqrrR·!bÐênQiw ‘EÚÝ¢B4“B!ENZ!„9i!„"P䤅Bˆ@‘“B!E«»…Bˆ@ÑLZ!„9i!„"P䤅Bˆ@‘“B!ENZ!„9iQž„º­",F£ÚE§Ó©Û±ÈI !„"'-„BŠœ´B(rÒB!D ü{CEùUáIEND®B`‚gateway-1.4.5/doc/wtls/fig6out.png0000644000175000017500000014113607374232663015535 0ustar toljtolj‰PNG  IHDRŒ©¹0êtIMEÑ 98œö8m pHYsÊ&ó?gAMA± üaÁíIDATxÚì½}tWÇ}çÿŃ6¶äØF6²ÓHÞt8k”¤i‚´I6h›cÈÉD#zvEväž³ÀöÄR’"m¤vˆIß§Ïëé~ï;wîܹóžÏܙτ®D¢µµuùòåÚÞæá8pàJÆÆÆ.\¸P^^~ôèQ·“=+W®œ3gΩS§øÉßP(DHb›¿ûöí+..VxÎe'á×®]«S(=ºÖ•© äáǧ f„rNWy¦¸RþÝËÂ~6xAüïcìÄ0 o„”ÅÑÞÞLH¤ROFºâ pM(ÍÍÍÇŽì¿xñb___( ÃÃÃ'Ož 쬫«Ûµkך5kÈ/ÅÌߦ¦&þÙJuÓÒÒµ8]§ óÜ-²ÝÐÐеütwwëBµµµ$;dÙ E ֛ݰ`Á½,üÝ´i¼¼ÇWx½ ”j‹ÞÃÈ{³Å‹KY<ðú2å¹ëׯollL= \‹+öôô¤ÿÞ -]º”; zÅk¹Sƒpÿ²§u ·¤›§áµ;eCû-iÙÊW<#[¶2g¿ì®‚Ý CÎVà\öó]wê¡´óÖètÊ?oAÈÓo½)¼˜2Êõp;ym]<ÄÉYzïÜ)ŠÓoÙFöC!—(PùKA(ÉëÖ­“L¨xc²M±¯®®æ¨¿xK¤8—ð’!b«ªªÒ›ÂQ¶Ù¿aÃIoQ?/»"Ðh–â¤ùîÂw‘Ò¤&¤q{j¼³M]ÀYÔJTFìÑå¸=rD|‚QCmÙ²åÈ‘#>ø ÛOàŽŽ¢"gýû•kä& Ø¿Z¾7ƴ«Gaæ- ù^Ê<…\/5HiiiÄÂL`^ À¤«*©»»›ØˆV¯›>•ñŠ¡ô¼×¼P¨µTÙ /5Úx¾äFö@‘Fk(ð4aýû‘ôøàõ‰8Dƒe×ñ.˜’_æ¡&l`\jÈË¢®ßU«V±Í)´w]lE× HË:0jC^?ÝNö ™ú6ŒuË~l|Õ¹È27Ã×í×6ý#Tù©ƒˆVÿ˜Ç)w·¡ýJ¡ÂÕo4 ‚5â§ü*ˆ™ŠPð‚P2õ7þ³ü—s/ˆÿmâ'ûÃãä-C¼¹Ü† ÞE¥ ½˜.¼Þˆ W®¾Ýz‘ÝD ÃÈŽz¸Â슺^ñÖ¡€îèãÑŸÌ]ñ½A.fá?1üåâ5téébÖ•«ã×ã‡&9M~,Wþê+u hÝ`szçf ’ŠÑOÍ•‘«¹È¬Y³ôY ÛvÊÔ¡yN™W—5ÛÓæ+Vð>ò®-[¶Lfwrpîèèh¦ÞVÃÈXØÅo¬Œ'@2"ígŸuG  bÆÈà¥Å/ÒUUUÇŽCe(íšI¸páB6Ö¯_ÏÛH;5ä}v©¬¬|ì±Çúúú,X€ÔͰH‡ycÀû²xñbëë6 ññq}ÌMÞAlÂÔã pMÒgÆÿ&gP&M¡$¨óèééÁ¬ä'‘.Ôº¶¶å>uêTWW/äÈÈÈv6ø¹cÇŽ•+W"ÛnÆL’eå}1…6 ´(+ïNÚ:>pÌ0 ôXnØÈ¹sçjFYYÙÖ­[kjjJKK9ʆ¦"Øšaœé;0 #O0‘6ŒxA§±˜—-[Æ_õxkrüDÑ+**†‡‡:”锆‘'¥2ÌÄ0ò’ªªªÀ¶þj´vuuõ{Þóžâââ·¿ýíþð‡f6ø«éLûØÇØ^´hÑ;ßùÎùóçëo¦oÈ0Œ\%ùc3 ¶‹<«¬]»¶¬¬Ì¾œ†ayOnˆôÈÈHee¥ß™‹F¸ ºõÅÊ™œœD§ãë½a†aø9~üø… öïß?11ò¼û9OgÎYPŠä€H÷õõÕÕÕEs·&÷.õ©ÅÚnoo7©žaT^CÞôtþ:tèÐ¡ŠŠŠ5kÖXÿ‡Q€È~`CU¹¿ylJN@ý†ñõùPt=Z·n]Òz”-"­r¬Ê ÝyVÛ±cGr+¡[·nmjj2a˜n´€©‰£,†¼&¤¿‚={ötww—••É1–=£+§ 6ðFøk61::ÚÖÖFÕÇ‹ÓÐÐ`j…ŒóhR_€RkL477'ú”3,ÒúÒÜÒÒ2MK>#˜Ôæq,€k†|ý3r«žç _ÕAñT1\—Ç…½zõjk?Ù†š›nÞÉ“'/^,e-))IÈBz©ÙJKK1ôfMy]NaC •f:'Œ×áqÔ××§}Qvž/µ_+JdÐáê”.EÓEkkko3{ ÁNÉ ˆh%У>´^!µ‰Öuˆgî®®.wvv&‘®îV(7ŒÌr᪔˜Wƒäèqµ`°yÐhhéÞ5kÖ$áS´ø’¹OÏ8ZÇ}úT‰B§cÿLŠtZ>ªÇƒû,d¨Y0vɇxjZjÍS<1P-_¾<Ū„$V_ÏB´¬K¦SaLò9sæP§,ÌP—·#Z¡U˵··7•$iÍoþf:o ­ž<Äc¨d²»»¢¢Bng^Å);ò•îîîúúúD¿ÐëKÄã?è;~üxUU–GZò³¯¯¯¡¡app0;¿ÆSJ¹}ךAÒ˜†™q'žåPÂ+++C^åPñ©­­ Ö¯_?99)ÕO=m<£uëÖ™‹F9?“ž}1T°‹b•™Bh­ˆ8íÈÞwß}Óqƒˆt¡ ã1mÚ´)ç'ÔÕÕ•——Ú 2ê±Ô Ü)}®_¿>í3¡S¦òqÕào—ª$G:;;KKKïºë®k¯½ö©§žB˜CÞWúßÿû¿ÿþ§Ÿ~µ~ä‘GÕ€U«V fä¶I*•"Í3“Nœóå¼Ò[·nÍ-…]õûìw¾óÀQDýûßÿ~œå^Þ·mÛ–ñ÷DÇÒûÁ#{˜˜˜t‡ä"¥¥¥YÕÎ ´/ý¥‚€D=¥=×»4òŒ’’’L'!U(‡YÒÃdÌ ¨sOOÏì±±±;î¸ãÊ•+Íú§ª·¿ýíË–- Eê¾÷½ïÕÖÖúçhÅ€úk»G*S¥Q êêj*ñÕ«WkÏþýûQ&ý³f§ SRf¼Å0Ì;7ÓIHnÆ1Ä€’ã¾ú»Ï甥¦¦&°imr¹„º¦(óyÜ4%Ôt®ÆÈi¨iy”ÙÐ+™ÓP2„xž=44tíµ×ÞtÓMÑ¡Ð÷sÊ3Ï<ƒÀË!NüWݰaÕYBU˜VÉÞ´iS¸¬j‰FgCCC<€‚NC!{úTÓÍ”cѯþõ ^sÞ LêÖÖÖ'N Ò7nÔ—ÇL'-7Èlw7Õš„i±GŒðoÌ“æµ÷ïeÏàààÀÀÕP[[[‡Çž={°iNŸ>ˆÂ?µzJ0Þ‰'žräényƨºöÚkÁhd Ðèô˜ÛîÜ)uš¶Bœ‰Éxعëk,6Ó »+--™ž[ŠGÄess3o„¿N LsØ¿èªßÁ´§*_gùOÔoy<Ø~åÊ•‡VÿJ¦VFÈ{m\~Fìߥöû%t;8 mê±áááÇ{L?8ê´£ÍËË˯ ]í]¼téLÕóµ¯}=ò'BMôÔSOýó?ÿóSßûÞ÷>üáÿâ¿Øµk-‘À¤¬8‰ß+Æ*‹}¬ŽÙ³gGuóÍ7»mK­‘ê8uº¡¡!ŸÔоΪqÑiGRB×ÕÕM·Ï qˆó¥Èo⻘¤:/:F¦ *Œs²hî²|ùry{^±bE>Õi! T;NeE{{û† ƒ!À¼ûËxÓ¦Mî‹ðÖ­[9ªF<áå¸=ѤŠöånAúÓŸþÍßüÍÛÞö¶¾ÞÞïþÝß­{øá%K–°ÿ_}¼øâ‹ï}ï{?ÿ¹ÏýäÇ?Þ½{wÈû,Ðc”Äiuuuýþïÿþ³Ï>‹âÒ^¼x± ‡ýozÓ›ü{œT_¹re`` vO>¥9Ÿêеk׿ÐÀŤÑ îtZŸ]¢ 8 XÞ$ŒTù›J4&lÄVf¡¤¡_Ò…B466ÒX·ÉZIC-Š|øG™®:7þy}(·†#ÓéT\jÊ«–öÏ0 ·¿ÅêÕ«_WÙ·¾õ­ßøÆ7îºë®Ë—.ñ“úܹsÏ=÷\øX˜ÇüöÛn;þüõsç6mݺmÛ6µâ$NŸÒd™B6éç­·Þ;<ÔËí©Fãi†±˜_Ó4 w桽ÍøË34^£AóúÒ?E"‰æN´ÎÆ–––ˆ¾¾™×Ÿ†>M¥B˜¼®ê¾ºº:of™R9û½M /¯¼H¢hí¿Ã ö¸Ïˆþ…vPP7~sùòåÎ/'¶lÙâNפ ô÷÷kω'PÏxNqî–tYY™ZÌ™;÷ž{î9Fñ-·(Àk¯½þqzJâéŸ$éÿé?ý'_úu×]û”¢¢¢h“ƒ'&&æÍ›÷£ý(v ¹.lêk¥YGÉpå ¢PMGOfz‹DÞ÷µf-³æòQÏÎøçuù10vëÖ­‰:£‚—\…B"ítaRÓ7ÕÈoòú‘óW¼´*ü…MÛˆ‘ÛIò¦E4ÏÙ´Þ课xáÂßÿÃ?$Ô„Noܸ1þðÇŸrð¡æC&€r¡)#GŸþíßþ-â¡ÉÉÉ›nºéë_ÿúÇ?þñh§kšM޶:±ÒxÞò-Go!i¸_^Š~¢“õ§$½_ (]æƒb†¡¶‘£uLŸÂ‘guBmmí4õ3Í$IøˆÜ·oßš5k¢½Å(b´±;ÎWÿàà`Èkî(×®]KMè vÖ6B¨܌LjߛÃ+êhñ¸÷7DúÊ•+Ê»±9{ölB¹O_7aü“©{®¿þúØ'{:p¢ãÕW_}ï{ßÛÙÙcè#µ|.®­K”Džó£»> xýk¤§Ît|ÏC*r½ºÌ!x‚UUUÔ'¹¾¨F*PãQõ744låÓU`dR¢ÐÎáUYYYøçv²‡&xøGh÷a%ή͈-x].±‘_©0e_7%é£ýèÓO?Ø)ßÝ[o½õùçŸvôå—_þÀ>@¦gÏ2ˆ)¢é==ôûx_°ð†tttŒŒŒ¤Ë` ŸãîPlJMõÀ,Gcúà×€'n ‘Îéñ­­­Tq ù×Ó×Ï£J±¤#Î3Â\ÖkŽŠÓôçÒîPDG¼ZS'Æ·ÿ„zq°Ë•†®8C"O_÷¦M›~õ«_aÓöc¿òÊ+SÓ7Üpõ×^îíÄØ·´´ çǸǺº:ÚŒ³÷ª`3mÞ¼yhhhš.ÑÛÛ›hGK`>B!›t3‰:oÆL¥íWZ‡9ý©¥ÅY_§å‘7F€h–´óHûƯÐ1hnnÖçêp42 þ; ï„W3C"O_÷'?ùÉh~”N:u×]wÅ>:ñî»ïæÙ ÆÑú½±§éÒÒÒ\ŸŒQ__O93…vЦ᜵ H^îÖ’9Ö3¯FΈ†VSíëëËõl£ ar”••…ï$¯’üÏ{mäy¢kC èõÂõÍû·"=oÞ¼„z‡®¹æšøOÙÉL-nC;ât±„N—xè”Ó§O£ÊhÏœ9óå/ùᇜ›C‹GQ æÊ’¨3†VDô¡(éÀËŸK¹d'uuuûöí+ð^îj¿æºH§—ìlÃi`¹¿£WC¾ÚT˜²¯û‹_übø\gD÷ºë®»ùæ›ßò–·$zED÷öÛo¿÷Þ{ï¼óN¿£ÙUUUá¯q:555S:i)@¨†íÐTHWyç;{X3ÀöíÛyµí³B¬Ã“'Oš[ïá/øE̦*PzÕ-Ÿ‘NbÂt¿0£ÊK–,)++Cbï¾ûî[n¹%Üewü\ýõwyÜpà ڃy§[•,¤§§‡š(‡š3íÐ4:öJËCÆ”À|u韼•G&E„Ké:æ1Ýã™Ëe^¦A¤ßúÖ·¦ƒ3£õ]UÆò(**JãÍs·wÜq‡²€ÁC=”ÆÈg’¦¦&7“Ïf„kR’Âî zø÷иŽç«vŠî{ÒKŒk.Dº.”–eLM¡gŒ¾¾¾)§ü'Z’˨d–8_Øpª««r ™ß‡>úhÄ3KdxeeeII UAeŒŸœ˜D…Cå,½'ppt÷»Þõ®øÃñ_,¡*×;6lØ 3Z íŒfî_Ž»Cž‘”D‡¡bÐ:WFÜðm·Ýò†ys­ÀªŽòšè%fµã"ŠÇŽ;Ž9ÒÛÛË]¯\¹2Ü‘ž+\9°jÕª¯ýëœ5åkO%!·|qB2]?1v‚¥Óéê[îïïOqŒ¡õrÏ4^)ü±Ãð ôôô$T’)ù>øà4}äN´üó&Æó†ÃU]Û4¡ ìÛ·oñâÅT¤?ÿùÏý‡ü¹DûŒ¬þÒ—¾ô|à•W^Ñ`dLGÍ3:zô(Ê200°páÂ]»vÅhУ2È!¹.O|Þ¼yîÐ5×\óꫯRKpzŒa+ל;wN[óçÏ¿5üËOMI´I¢š<óòË/³ýæ7¿Y íœ\*äRŠŸ4dâlÕlË–-eee´ h Zëׯ'†úúú›nº‰«œ?>â¿,GæB´£´3È7š~îÖÈIrÏeš~ò——–ªÇèö»=* þ¾‘‘ûÇZsýÌák¨„йl¨AªJ‡Èå;“¿ö§\«¦úSH˜@¯€ –ÆYãTÍ'Nœ0S8û¡`œ|XåŸ8‰Ê•MȉQþcg‘ÍØt¨ï–Ê<÷¯ìéŸò†·¯«+=Rƒ©E±ÁR¢Àð8yä}¨ÅÔ¾îºëܰ'Çk¯½F!ùÃ?üùs瀿×x‚EìPqò7Có¤Õ^ÝP ÕàT’¼$Ñœ\®õ˜òZccXéÁF¸Ô\£L 8"~²&y™yÏy312¸k$Y?©üo¸šäné4×R!05ѬY³¨†¨Å]ÚŒÄLH*/ ñ+ž}ûö­ús(î<>Nñ»ˆ%fûÉyšMDEi¦ÀOJ*ÊýéOšæÕŸ‹°¾¾>š÷|êÍ´«ÎŒEÚÄßÕ¯—ãÀ€ûU ŠáÙÏ_¢ |2àrÔ”`™¼á¨rGT:¤–·…V-€ý›7o¦ÀР(SÐýièìì¤G›×4æBÒ‹m¤%12¤Ò~S!¯–ý½Gñ>k˜.´e)Æêd¦0?øàƒuuu¼,hð£>J‹–"(ÆX¼GýiLá¯ýë!¯3œ¢BTÑÆ1¸ò¯?bù§e@# FùïêêŠQþ#B½Á³N‹ #¶p¦ˆ³1©?ó™ÏЮҳˆø #G=‹ñ‰)³†Û»ï¾ûü{HÄ—<î¾ûî@x›úœ®ï¬0e«ÿ…^ ‘·ß~»–%á.xÔgEYØÊ<Yöd}®L"ä‰ÄðË–FÈjlëÜ2³x X$qzÜÜH×à qŽ=JÐP *wn!<žÜzÄÑ%mß\#¢þü86fSö†&mW<´ñéOZ?çÏŸÿ·û·¼P¨&Í/”õ¦›nJËEÑGZHx< D¹´utt G¼õ$I½>¯÷i£Ð¼÷Þ{Qû}ìc¿yõÕ Íž™_YY©Aÿ43ÙóÙÏ~öM ¼ÿ}ïB›eË'bIe!½¤ôÐ’ …ÍTa?íMnl‡W¯©©¡~¡¹cÍ«¯¾ª¥£i­P(©²9—V"á\Û?ðضOÈz¢Ë¤$]c¨jgƨ߀ÈhÒåV‡ža̱§„×\sz;>õ©Oa.&ךyíµ×._¾¬iJþüÅÈŽ?lhçýê­‰ë®»ŽæÆùsç¼éM¨QëÛß~Ï»ß=Ðß_¶téõóæ>s¦ø–[Þþö·£y¤é=ïyOü—W—)ŠHMêFhëc—„\¶laÔEƒÂac!ÑÒ‘¨GD¢‹TË݇|Õª?|çt÷µ?@zkv©2 î‚Æ m Òœsݰ½½½¹5õˆB¢ñq™Nˆ‘x…“7÷PÇZãÕº»5èJ1‘FYkW®\ùÍo~gT üë_ÿC'JïêD:\ãÞè|Ç;Þñï|ç…^xÇŠ?øáÿìÏþ «š–Åùóç9Êßu?üù/|á«_ýê'>ñ‰?Ù¸‘&CEE…¦5ÇéqL沜iè[æèè(÷†áû™Ï|ÆÒM¢Î%<"¼øŒ¿2ˆ`®ïº¡¡¨ä%ƹ)Öì¨òþýû‡‡‡1Ó#έL£«B^6²k:ztsžuDGlF!@%›ëϦ*%ê@i?«W¯Æˆú‹¿ø‹7‚ -»þúë;;;ÝTäsçΔ1öw¿ó&¢ƒÞ|óÍ{÷:uЭ®ñz"Ýg³ÚÚÚÇüž{ï}À-äóŽ;îxirò…_þò­÷Þò\j“ôo~ó›Ï<óÌÓcc÷ÜsNLÈi޳))7¿ÛE”D]¼öÚk1–Þ Q©!þ=á1øÇ[ÅÉ”ªìG«‚'z‰hhއ‰tѵ•¦ j•Å‹çôªÉÓ„ù3‡&_,^õ¸á†œ"À᪌¥ªîëW^yEbŒ´Sðœ‹ÌKþ9”´l÷ôôìܹSÛ³ßùÎwê‹)1>ôÐC_ûÚ×°\Qš_޳筿÷{?zâ‰w½ûÝ?û—ùÈG>òâ‹/~å+_yÛÛÞæ÷W•N’¹„Dú»ßýîg?ûY˜Ë—/Ÿ× Eñ}6Ÿþô§ý)~G¤I´¤îóŸÿ}ZÛðóçÏ÷ÛÖñ€622âï±þß¼y3†?ºÃi/ÀÍ7ßLïÿûÍÚ/þ5-Ü÷`,iLóóìy}qzàÁ$ºNb4â_ž+/y²mÛ¶£Gž:uŠ”#9˜Óñ,Žr"ïaZŸ£È›#¥ÙjdCð¾ Éqc¦Ó’1¨ˆV¬Xò¼‡f:-Ù G9!‹05”uÖ¬YáÝ®Hï”jBò\&8bˆ$ÐgØÐ•Ñ+ûÏ=÷–ñ_þå_ƶñÿûÿïIg µªÿ­4R†õ… ô éÈÉ}TxñÅã1¦©ÜÓ2m£»»[«£ÄsÅ’’LdZ'eee©ôWË —žVO,Ù Up}}½Æñ™B~¨a¨ãx5 ³…Šˆ¶{kk«ÙÐS"‚Ë–-Óø¬5nü ½gÏží€ì¥—^ÒаE‹…›ÝHRB¢Få¦%¦ü;߈ô«_ýêþýûCžQûž÷¼GR:11ñOÿôO4î¿ÿ~lkuÜONN~ö³ŸU,«V­ÂŒ¿§Wƒ“s®ÜWáçŸþî»ïv#Úœ?>à5<;î¼óÎgŸ}–æ¶~z½ÊEƒÌA0¢Ý¬“d6Ò+'d –Í+(oˆ===[¶l¡2CÁˆeƒ·£ÐtšëæÍ›5ÅF«Ä2%›Uý.S[[ŠöÊ+¯PŠbHæ%Ú•œ4ÍÍÍ$)ðgc€ÒX@)iJp™k®¹æ‡?ü!"ÍN÷i–š‘Ôoܸ1äM¼s:ÍJ°„ä‡f‹”ë'$H«w`ÿâ¿×éË—/ ãX Kœñ ]“z–MIMMž±>os;Ôú®<Ý—¦èðB®÷À°ÎûúˆBHs„¦>²jȈº—¨ z{{sbu»Tàu f¦Þ¹s§yÜKé´¶QèŸüä'á"ò†L]wÝuÑ>N#4M…N¥8¬J+5‡ƒMBQå%K–üÍßüÍ÷¿ÿ}tZ¤o¼ñFªÂ_ýêWÈ6—w3¦4êöÛoÇ:üÔ§>˜a6%”$Z|igºvŠtú†nÀÖä–«ßqÇqÆO6!ç3³ ­ ªƒ¯ýë\¥ƒ’GËÓ!3ó¯‹[Ó§÷êêj-ë–©”ÔÖÖæ}3(ŸàŤ̨G0Úª½¹‹¦Wi›º´¿¿?Ïnp摲€ïK‡fÓDÔiv¾úê«?ÿùÏCÞ„a”QŸ¥ÙyòäIÔsà&_ÄîŸß^a{Ç;Þq£‡ö|ñ‹_Dƒ''',Xàv®óyß°Ù™¨HSÕbˆÇ˜AD2´.–~rÛØÖÇvß_)£ÜD ^vmœõ)÷•Ê\¦,q[­@–Ö×׫˜Š)o¾Ô¢ÐÙ°­±$ÜîçÜ %yï5…gppòC+¶±±10'wÑìg·‚‘:y8‰è#L£Ãbè42üÊ+¯ðÊ«€aX"Ûü¼óÎ;ãì×ÐãˆU÷—ĆþÊW¾ò,Qôüá‡ymùÁ¦90þ|õBŽŽþÕ_ý•æhcò>ú裉fǦM›š››ãñm)…æn5Ž×íïèè@¸”Û/±ÝÝÝh•ä9eüÜEÞ´@;;;±4räuç3/–””8p §k%^›NofŒ¼iô UUUTb$ÞŽíÛ·Ó¸_¼x±¾üe:iÉ300`î¸Ó6Û™3g¢Y½è4馛nºþúë‡a hÿyÖXæ8¯Nk2Z]÷†HßsÏ=r:JàñÇÿà?ˆ*£¦çÎS÷MúÛßþ¶ó¢rï½÷&‘ò ÔÔÔ[ i. Ð¿þõ¯‘[D×_Q’0Š)²*ûWÎàõ;|ø0·ê”IÝãÏ? ÜõZýÔ°²Œ›¡ICÅÊÍéFÆ4A©æ±&´ž4á“s~”P{8« §§§¥¥%§Eš[0Ÿ-iáxþùçc¯…ŠkR¸Tï~õ+ëÒOŒÌø‚òL£5¼ÞˆnÉ’%;w®¾ùæ›?ùÉOªsÛ¿ˆ[„‹£´öÿãü¯ÿõ¿&‘ò TWWGõ޳gOÄ`·Þz+7\[[K80úƒŠ»¿¿ŸvM`m+·d–~Ò6‰1l„ÓóL¤ÈuL¦S‘<]]]y?ê'9ÐlÁ+‰°mÛ6^¥L'<+(//ÏiuX´_s·ñµ ‘½½½S“󓈇d‹¿è slÔ*ZÃñXôé›HIèüÁ„¼VêøÌ3Ïüô§?]¹r¥º…]ÿñ4BÞðôä²yÆFkQ눓}i"P±£‡ÒÚGnÀ:±Q§ûuÍ^¸pávðÓc´\òƒ\¯Œ:::28R,›éó F(dã8i0˜ê„È6¨–u‰hÄR‚™ú™Ï|&ö¸ãþI0¯ßô¦7a^þ⿈=»:ZÆ»í³Ú"M…øãÿXÛßúÖ·øò&.ÿÓ?ý :yòdII‰¾Iÿò—¿DóT; êÿëý¯ärd¥GÈûÈ11бšÖ¬÷•5r®³Ñ]Œ w·ú8]刄[H—gAV`<åè,jÚp<üîêHSèäPÅ’»ÞC­ñ:MPPº×^{-ö‡d¹¶ŒÈåË—Q袢" XBÓ±bwú¾ÞݹüÇüÇîÚ˜êÞÙ³gÿÇÿø{÷îýÛ¿ýÛ/~ñ‹»wïÖQö¨v ¹qË-·¤îΓ¬Á\Žv4PM_¼xË{ÅŠþqdȼóʉ}LKÙÓp…y£ÌòÛ]—>C¦¸ŠW¦Ø¼yó®]»2 #?ÁÍÑU–©ßâ_õÇH”òïÿþïcˆ½fF‘Gèê‹ñ»[÷uKyFÿ‘aÁ¾ûî»UÐ`Í“¦qñ¶·½M'P{~ç;ßaÏâÅ‹|ðÁ'Ÿ|2Å|AAIâù/ÿ%0Ë%|nx__ íób@GŒÍF¡Ñir<Ú Â1Ôh…Ä9>«Ø³gÏÄÄ„yf0¦‰††š°9÷^Põ­_¿ÞÌèé¥DeÞ÷¾÷E ÑõعsçΟ?/OšÒL#~8NŸZ\4F«ñug×_øÂøû¹Ï}ŽHQëO~ò“÷Üs¿úê«/¼ðÂm·Ýæ÷†}öýïŸw¿ûÝÿöoÿ†ÁJ¾h²ÐSO=實‰›nºÉ¿Î#Áx¯Ð]êî5kÖLÙUE"Qb·†G¬í}ûöåý¸$Ê ™¦yt¹iæé˜wC•ò}÷Ý71=z´`ÇQƺººr«!X[[»lÙ²ý€•(éõë¼mÛ¶xò •ÁþÅ/~í³4R¨„]ºtég?ûsæÌ7*Þ¯}èC±Ga£¶µµÅ˜õþÆÉÿú¯ÿJ+ãõùçŸG­;;;ÙùóŸÿü‰'žÀ0½ÿþûßÿþ÷k.“›QòôÃ:Åì㺼-Ä¿ÿ~­›-Ξ={óÍ7ûiÚÑD7œÁÁAÌn,éð¾nžÖrSžý sTCцÎe!¼$$8ÿ\DÙmôšššj¿îÙ³‡æZ<äAŒ¶nÝú×ý×<òHD–Bÿã?þã3Ï<ƒ úg6c]PœÐl¿;LÜÿóþÏüùó1©ËËË#΄nii™âÓIùüç?@þçÿüŸßüæ7ÓRøà?xàÀ 1†ìmWA§xTVVjÏ-·Ü‚Í͹ M‰Æºuë~øaÚ&ÿâãøñ㯽öš £1$lÊØ4 œ¿páBà&ZÄýù å†Â”÷K"—.]J‹-Ó É.°w§©J"æLß\&Y³f V¦S¼¼9ñ§‹ôõø´úðNŸ>ý\$Ð`­†œ.>Ìåb‡ùí´ëO}êS{÷îýæ7¿©Å(9óÿðåÞ„¿nÐ?6Ù=vïÞýÇüÇéÊDJá¡C‡~ðƒøw’¿üå/ÝO ,Z+ØÇ´zzz"®Ë~Žjî5m¢pWØâÈ|á¸Èà9¶¶¶’iÓùàà`Z–û ]ˆߣùŒìz#f:FVòRðj¤+¶îînjÝ‚ZÔ+ƒ ŸøÄ'"º+9þ¼ÿ³ìÙ³g±‚~…çŸ~Ê)7nœr ãߤ1”£…ˆí™ëÉ'ŸLñ›´ÿBeeeßûÞ÷ ^aµ;¯apª@‘u_¦Ý,i>qâD XSÖ9R€]Fµµµäaz—w¤îزe ¥°³³3Eeå™êÝ(ÀG3%öMzú˜ý£0Ëay›¢=@˵¡¡¡¯¯Ú L}“ž;w.šH…I†?öØcWÞ³gÏö”†Œá‹báÂ…o~ó›c\Ž¢‚Y2å7—àmŒ×Ÿþô§Þ†§Ÿ~ÚmßxãцU§™‚Š|èC:xð ˜û /¼@ãEÊ=00@Ñ— Íßs¬ÃWo$G".Vh™Š4Î:SíF3èäÉ“è«ü&WíÙ³‡š(u¥7ŒDQ‘KãâÓò&÷ òÜßߟÜð—‘‘‘ºº:â 76 Ôkxx8]±ÅévllLê¦ ¹yßûÞçWÀyßzë­ÈÓk¯½vîÜ9þJ¹x^1|ž8bO?v¼.ÒþÁi}½½”­ˆ=Éoœpíµÿûÿo­À§OŸNW>*+á3ŸùÌ_þå_ú³æÅ_¤õ@ŽhP§ÓAìyºáÿ›ššh`q]/N¾ jT`*øí=‘ææf˜¨uBc¾v [UU1ä¨g‰œÆÖé y:MCS5rŠ…p||œW€÷KªÌF°–<ؽ{wüR-gMh3oS~{EŒuõúõëS×iª#qœ™ÏÔò¦ª01…øÃ.^¼Ø‰ºX%–¦D쟒hKKüÎ%¸üW¿úÕ%K–ðãþá>ú‘ø‡XGäW§N]ëò¡|âŸH1ý "µµµ=öXødµ¢¢"òK5‹Ì¯€TóŽi}›p%޳c!ïQ¹¬?úrLñ Cd~KK ïCcc#ÒíœÛÖÖÆƒ&Œ äŽÊ|ŒViríö:8´|¥1éîj¤-[¶` lݺ5pH¢;11Aä\%ZS€:ÊÍ—åU*XyÎôåâ‰'ž¸å–[¤ÓHòm·Ý6ÃÉx]¤©4UüèG?úèG?úòÕµœ£qÓ¢E?øÁ¤ëO?ý´šŠéB ,®X±bhhHNÐh ÜqÇñÉÉÉË—/ßpà ÎG©ˆg=+"äå±rºÚ¾¡)“¨@êD²1ö×J6­`¬íP¤…½yXTU<ˆÜš¢šY¨»iý¤±÷̧Ñ_Á¢O Y½:Q3£¹NÔ±ûìË/¿,óuÑ¢E3ÜõºHSzþÛûoÿá?ü‡_|‘ÚóÒ¥K¿‰ÞlŸ3wîìÙ³©…o¿ýö§žzêsŸû\z;iª$e ¥ùôéÓèñ[ÞòE¤ÏŸ?æÌ™g ÄÙÃ@K6·æDN7ÎêEª©bë%ÕrÞÑÑ!ÿIt ÆX0Ô0² Y½!onÈ”z)7ccc¼MÑÖŠÜTeú¦X¸¯{¯½öÚÙ³gQ(­Ð8c ˜åÿô‹Ypû L[šÓÑâ“H‡®ŽÄF^xáä!!ådF+£ÓŸ…9 U’zžÉáÕ«WWTT¸QT@ü}üñÇ'&&0 7mÚdµ‰Q ø{žiÈ–––òvèÐèè(Õ°¼ýËùùо†P[b.¾ôÒK¨$öt 'ÞéeÖ•tOOŒ6ÞçÄ›| yÓ£Ùãøžh3Jsøða'ÿF8ÔJdòþýûõYÃW‚=wî\«ƒŒ‚…†,†²„ùСC<ðÀÂ… %Ø>{­Ð †Ô §¶¼öÚkS1ã'»t‹7Aã’ÜétGGG`L]œøÇ!›H†aÉáÖ˜áYB3d°ÇIOOOÀ;·>‚Ò„Itt+áëëë·lÙ>aÚ0 Ã0Bó²ÊËËSË™avêQ¤—ðFZƒ|illljjŠGq‡‡‡Qèµk×Ú`1Ã0 #- >èQCCCMM b´nݺ•+Wº®_ã yãš››ÓuѬéˆpÏÈ­ÿÇTEi†a¤NqqñáÇCއ걱17³7N2Q²ë3-‹ÐîÛ·/Z·ìy@tõ³¢¢"Ú„¢ð¯Ý†a†‘åd—H£µØÊÍq¶Gô¡:žÀ&Ò†aFΑ]"š6ÇÈùÉ“'m6‘a†‘CdH†a†!²k –a†aŽÜÝmd'úÆo®— ÃÏ¥K—Μ9STT´hÑ¢L§ÅÈy¬»ÛHy™·"d~´&Mqq±'6ŒT°înÃ0 ÃÈRL¤ Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRlt·‘<6Ë0±)XF1‘6 Ã0Œ,ź» Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRL¤ä©ðÈt* #»8}út{{ûÞ½{3#°U°ŒäÍt #ë¸|ùòøøx¦Saä fI†aF–b"m†aYЉ´a†ad)&Ò†a†‘¥ØÀ1#yÊËË3ÃÈ:ŠŠŠŠ‹‹Íq·‘Ìw·a†ad)ÖÝm†aYЉ´a†ad)&Ò†a†‘¥˜H†aF–b£»ä9vìXÈóàé„FqéÒ¥3gÎÙo#ult·‘<³fÍâ¯!Ãð3>>ÞÞÞ^\\ÜÐÐé´9uw†aF–b"m†aYЉ´a†ad)&Ò†a†‘¥˜H†aF–b£»ä±)X†ŽMÁ2Òˆ‰´a†ad)æÌ$²EOOO¦“cä“““+W®tëx–••Í™3'Ó‰2 #'1K:ÃÃÃmmmÕÕÕ¶d²‘ vww7:ÝØØ¸fÍSkÃ0ÂDúwسgOCC•)U*ÆP¦“cä ÇoooG­«ªªºººLª Èé7èééAž©CåÏ/ÓÉ1ò“‘‘‘Í›7¯^½º©©É¤Ú0Œ)±oÒ¡‹/VVV†¼^î¥K—f:9F>³|ùò¡¡!LêÒÒR+oùÊéÓ§÷îÝ»hÑ¢}ìc™N‹‘óú<éãÇS]nÚ´éðáÃVc3úuëPhµÎtZŒôsùòåññq¤:Ó 1ò‚¶¤±¡+**:;;©43£° E822BñcÃF?†µ¤RècÇŽÍòðOÊ2ŒT@ž'&&jjjŽ?žé´†‘¥®H×××cÁ˜ md9sæ`OSi2f:-†ad#*ÒÛ·oíêêJW„T²sçÎ¥ÂÕÏžžÌîññqw¹… Î Cz aeee•••ƒƒƒþÄ=Îâg žJâ*áÄîo O2ýùÁ”W¬Xá¿Ç@æ“°Øb©Ü]=¡bOoÚ´IC Ã0¢HS϶µµõ÷÷§1NL¢5kÖ´´´ègSSÓ‚ š››õ³£££½½ý¨‡*em"AÚ 966¶k×®“'Of:Ÿ¦…a)ƒInyR}}}qÆLŽÅ<âÁ3ЦÄ\4v¶“òéøÞA»abbµðŒ\§¨¨¨¸¸Øwi¡Eí¬®®NûdèÆÆFD±ÈU4v—mö¬]»¶Â9çÒÚİxñâÉÉIÂ/_¾<¼^ qуjŸ¶‘–g¡r9ôþàÁƒ!Oç8‹Àά'˜ÎUcÅH°Ó¥œÈ#JñŒ˜9W¶©Û´6Ð<5;ˆäé*´]¸M¶Ù¯”h?±XÛ\½®®ŽØh¯>â=*màOȲ²2f§?° Z Ñòk9·@Hm“N]ŽÓIñp þ„Mz¤·ØJËÆ§#fcæAžlþ•‘®§Nâ®ù›ÐYÎêe#F0Ôwß¾}Û¶mCe/\¸€ ­õpaÊËË àÖ‡ØÓÙÙØI̘þü%Bb APUU¥h Ï)\ŽŸ$€ àÄÖÖV…GøÉ!Bbͳ‡ŸœˆYÏO—0à'‰—ÅìÜ&qê„q·à6”KœEju;¨²6ˆV— €RB"ý)álJvêܸ8ÉRÂë'7Nø*÷(uQÞ°aÃÖ­[u_Â=e¦vÙ–·Nå‘(UìäŠÚPÂ\¹ ¥R˳K{´†aä4'ÒÔƒ~ÉŒ“8Eõ¢ª¥ÆWmË…¨èù‰EèÂÄi 0§•Û#acCz†Œ>|ØÉ§K•6H€ÎÕY„$6ìríÑ)Ú Žx”ö(µè™š2åW 6''1DZivJ˜i¥Dm¥DBîOg Nÿ=r"i %þgä2䊧Êþ¼%°îH³áɤßiâ$<Ú„M«H'W2 ÃÈo ®»»­­ª0õxä%àŒÁcÿ‚ t‰ööö‘‘êú8ݤÛøø¸L؈‹n©3–C7nŒv%%%þŸeee'Nœ®¯¯„D‡¸<’dâ×…H?Êž…¼ž^ ÝrßnçÎgŽ!„h^Ä;ºxñ")Áf3ª®®®ÊÊÊ–––Ç{,Æåü?t;½½½Ùá}ËJ‰"ß¾}{uu5áMX*`µÇÿÞ0Œ!WEñ[±bE'"Wi©s›››ª¦¦&ÿN„Í“m ÅÅÅØ¦nøX4*®ÂM¡©lttt`4G ?00€¢èCi¸Ë*ˆ+nÙ²Eߤ1 kjjPÚ P¥Hhm˜úúzTœ|&7H)\¸p¡²È](í¬[·ŽœOb~—Ú¬<©Ý»wëyäÒ¥KgΜ)**²ÞFêäÒ*XÔ_(Èn¢‰§^Æ>3¯aI€Q‹žéT¼S'ü}÷ÝwêÔ©4ÔG˜Ñà¡¡!Ú•••˜IÍÓðø$f«û'|“à}ûö™#ú B)ÒbzÓÔ˜3 ŠÜi­#˜)J\¤“®¬¢­­ EPÝÇ…tÑ××§îqìæ¦ƒ¤‘¯,!¯çÃ]Í&ÒFÉöînªËšššpy‰ÊíÁƒ|ðÁLß“‘*Óªk<2ukéæIÓãaRm¹N®3 cJ5Î0Œ%Û-éåË—Ÿ:u*Zww¢6G6ttwtt”——‡KVY6¤Ðˆ O ušÌS¢M¢ ìØ±#<ŠSZf†‘ArÃ’¦®AªSC<û÷ïÏì½PuF\‚ ¯jóƒ+VL“7ÍŒ$'(g/i‡ÂY]]b$ò\F M¡ #È ‘T:ccc‡NeÀm¸?ÌrñâÅÚÚÚtÅÖÝÝ…c×8àŸ––mdOò(œ©¤„÷‚·ƒwÄä9³ÜtÓMæ»ÛH¹$ÒB5QrR]VV–Ð:‰ Q__?kÖ,ù$ ynëêêJKK¥ÁXÏüœ;wîèè¨;…&|__µ_§È‰û+++9#ÚÖÖÆh±K"×EåØdýúõ÷Ýw?å „Ëa&öôôh’1 c–á¬í۷󗨸[ÃQLt!‚q”S´"'nÙ²…¨Ü¹MMM¤¶Ãƒ‹²G)ü\¸p¡–wä*„×<`—BÅÈF °–áŠò7âŸOÌ.ñþÌ!©î ô’ƒm+y¤G¹J’ä"†mò“`Ü„'$¹Y-ã'iK:•—ÂH;³g϶U°Œ´‘i¿¤3ÍÊ•+‡††¦#ææææ .466ºu/Æ<´x×ݺuë•ßõÝ}%ÌOõ©S§Hž–sàoWW—œo»ðD¨£K—.å¢âŠÚ]õqÍžuëÖ±½xñbþjå¹U‘h =$˜Ÿ$@Ërh‘[²‚kõöö*%D²aÃîŽS”€ç•ÀºÇ:øºêÍ›ðŠ{”p6Ðwwü y޵5ûY¾ÊµàG`âÝNu“ yèB¤Ÿd8¤º¢Û%d¬Y³†89E™Àßþþ~ù÷¯È Cœ<%Ál뉸lô;l-2%Ó0ŒÜ%ÛŽ¥*z,Ñ€°´€†óÁƒUq‡¼¯ƒ!Ï yîHwïÞ=e$è z€ ;99É_¹%,6Ŧå,µt#F6"ÖG3/¡Å(1=,X@’PGùioo×<- Aü‡R¶°ËÒïìŒ+¢gÎŽäPkk«åJ-EzØ)k•ŸƒƒƒþŸþÏ½Š™¿«W¯Æu>ÅûåM‘kÑöûý™“.ñbC>W­ZÅYØßܦswJ28„uË!Õm»’@^íÚµK낇®Š4Y$?e—)ä9'Ò Ò2—ü yNaI9iP6&:~CÜì`Ã0ä^wwŠP±jÕç´Ç¬zè¡ÐUaöƒ„ûÙy}­ZÚùÈ‘#þýR/¤ƒÏ¿6†Üƒ£Ð˜kZ—1så(j„BËÓ'ç"fD…Vq ºBKBž>‰\n5wîÜòÖÏ@¿ùëoI r+V¬@ϸ‘s.µ:¤?©Î}7—«®®V>¸ŸÑ>²ru ÄZŸÊíÕ ÜdWø¢ þþÄk''’B¢•ßP— rCKqëzì¶Ý¹„iiia?ŃlÔÒÔÑÀ:'ÿI7¨%Ët³!oX™²QŸâ/?\}†}§†‘ýœHSq£ÓS.z‘ˆŠ8éá‰rPwcѾI‡<{ÉDkQÖÀ)XiœU[[+ïZÚI½O ¨‹ bt‹+²‡‹¢üDÛ¸AÄ#ëSæ ¢,E®(Ÿ$˜£{öìÑéÈØr^a¿VVV¢XÚÆ%¸.·h…ô÷÷+©F„û%6¢õÛÇòNRe§Æ­@âµSë…p®.„!Ü!š/þ`:óZÚŒX’±¼s”0ÜéGž·lÙÂU•ËFÙúqòvbbÂ|† 7Ü‚¦¦¤¤s0‰•62Œv"´ÝérUAž`Óë q´0´0=®Ž !Õ©˜}r‘­Ïð2ÖSŸz” (±³ýžB&ØÚyÃéÓ§÷îÝ»hÑ"àm¤NÁ}“yfƒÌhÕ¦ÜûCyppK£Ûjl>lÍØ"Žrir ˜d¤r9”£±W;)Î'³­–¨Bk€º)tÞpùò儾tF Ñ’]û´}ûöÅ&SLNN¦wjïñãlj0/Zúò®ë¦7¶Œ6úOAžGFFlݪ¼ÁØ0ÒH!ZÒ!Ϙ rÄèÉÅÊ1íÎ7âÏ„ôjj>)t(‘l´Qª««©Ðs±†1ÜÀ1Õ"æ‹ü~d:-F!¢îœ¦¦¦íÎ1 c(\‘y:}ìØ±ªªªˆ“£ cúƒ³íÛ·oذ!Ói1 #{)h‘y:=66ÖÖÖcJ®a¤—={öÐ44:/)**2· Fº(ÐcáÔÕÕQiÚê~Æ´222²qãÆ7•|š»4 #Ÿ0‘þ-ããã555'NœÐgB«CtAÑ¢ ØÒÒ211±oß>›meFœ˜H9~üx___OOÏØØXUUUyyy ß–†JÑä䤦AÓì[»v­ÖÝ2 ÈéXhmfªÚÑÑÑ,\§ÙÈZÔ°Óß²²²<›ifÆŒa"m†aYJ:31Ò‚z¬ ×0ü\ºtéÌ™3EEE6ÀÛH³¤ä™5k­†s j¤‘BŸ'm†aY‹‰´a†ad)&Ò†a†‘¥˜H†aF–b"m†aYŠî6’Ǧ`F86ËH#&Ò†a†‘¥Xw·a†ad)&Ò†a†‘¥˜H†aF–b"m†aYЉ´‘<™N…ad§OŸnooß»wo¦bä¶ –‘<£££™N‚ad—/_Ït*Œ<Á,iÃ0 ÃÈRL¤ Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²8f$Oyyy¦“`YGQQQqq±9î6Ò‚ùî6 Ã0Œ,ź» Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRlt·‘<ÇŽ y¼3ÃÈ".]ºtæÌ™¢¢"àm¤Žî6’gÖ¬Yüµ"d~ÆÇÇÛÛÛ‹‹‹2#ç±înÃ0 ÃÈRL¤ Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRlt·‘<6Ë0±)XF1‘6 Ã0Œ,ź» Ã0 #K1‘6 Ã0Œ,ÅDÚ0 Ã0²iÃ0 ÃÈRL¤ä©ðÈt* #»8}út{{ûÞ½{3#°U°ŒäÍt #ë¸|ùòøøx¦Saä fI†aF–b"m†aYЉ´a†ad)&Ò†a†‘¥ØÀ1#yÊËË3ÃÈ:ŠŠŠŠ‹‹Íq·‘Ìw·a†ad)ÖÝm†aYЉ´a†ad)&Ò†a†‘¥˜H†aF–b£»ä9vìXÈóàé„FqéÒ¥3gÎÙo#ult·‘<³fÍâ¯!Ãð3>>ÞÞÞ^\\ÜÐÐé´9uw†aF–b"m†aYЉ´a†ad)&Ò†a†‘¥˜H†aF–b£»ä±)X†ŽMÁ2Òˆ‰´a†ad)ÖÝm†aYЉ´a†ad)&Ò†a†‘¥˜H†aF–b"m$O…G¦SaÙÅéÓ§ÛÛÛ÷îÝ›é„ù€­‚e$Ïèèh¦“`YÇåË—ÇÇÇ3 #O0KÚ0 Ã0²iÃ0 ÃÈRL¤ Ã0 #K1‘6 Ã0Œ,ÅŽÉS^^žé$FÖQTTT\\lŽ»´`¾»§FËHôôôd:!FÎPQQáZ0eeesæÌÉtŠ ÃÈIL¤#püøñ¾¾¾îîî¥K—š±h¤Âää$ nll\³f©µa a"ý;ìÙ³§¡¡Ê”*uåÊ•™NŽ‘'Ðìkooïèè huuu™T†'6pì zzzJJJNœ8±oß>Sh#,]º´µµubb¢¼¼œb¶}ûö‹/f:Q†aäfI‡¨.ëë뇇‡Qh*ÓL'ÇÈs\yƒâââL'Ç0Œ¬¦Ð-ijLyŸ3…6f€9sætuuaL—––?~<ÓÉ1 #«)hK…¦¢lmm]·n]¦Ób(ôòåË8ÀßL§ÅH'ãããíííÅÅÅ ™N‹‘ó®%-ÚÚÈK—.Yµj•ÙÓ†aD£pEº¾¾~åÊ•ñ(4uè±cÇle#½ Ó˜\ÕÕÕ6ŽÌ0Œˆ¨Ç±íÛ·ŽŽ>|8žÀkÖ¬qk2Ÿ8q¦Ðé‚fâØØXeeeœ¥Ñ0Œ‚¢-i¬––––þþþ8Ã#ÒC!ïkSGGGìÈÛÚÚÜÏA$ÉUR4Üc$•C4SR‰<¸ñØy•®“»ÔsØ‘bf655ÑòIKb ÃÈ' Q¤›››ÑÝøg¿~åʕ˗/—ýÀļeËWáDší+VÄ8}rrR£ÍÛÛÛO:•Êmr:‘D;´cÇŽtçkn–pG±o9ÑS¼å0SÏaGŠ™I¹"17nLKb ÃÈ' N¤1ž¨R£©W JKK±’7lØ{,.öYyy9–zÄ£UUU»wïŽqú‚ :;;3Ié„;Ú¹sgÈû´-[¦‰îînù]¤‡æoŒyеµµ±#'Lü¬]»cÚFåóæÍãMç;ß™é„yÁ•cß¾}TˆIœ¨ìZºté… bDŽU466òÌ;ölÛ¶ “}ñâÅ\”ýGEÂÙßÚÚê¦ecÖ‡¼¥8…z(üdÛÅŒ.GâcÄÆ…h.($5‚.ÁO’×ØØ¨È9ÄOþr”«¸Øt••+WìÀì¡Õ"/å\H7»uëVÎêêêò§A9@TÜê`Pz¸Möp J€:*t!oºú!tû‚ÀœÂ~Ý;œU]]­|ã‘+ßüú3\Á\IvwÑå¡ý쉑ý½½ÊXÎUœ¤ßÅIšeÚ&1îÑ„<•%» Y*uëÖ­‹¿€Q$¸Íi+ø†aä$'ÒÔžHi'JE¨y†ha¨Ç©—©µ©¯UáxÓ¦MÔéèõ¸DÕAr8JEøðaEÈQ6¢‰4'’ Bº«(B†8‡††¸;6¤FŠ«‘«HŒ…®B“öpk<”0‰ô)w‡úûû¹‚‘TÅÀÔ…Vqò—ÕþàaœHëŽYGH)ÉãÖøË¶¢%$Ibƒk¹`ŠÐNx…Ñ%~ÊÃ9Ly ÙX±ÄæbvÒ@qâô‹¨?1j…¨!¢ÇJÁ¥*ÎæJ…a†£àº»‡‡‡eWÅ>0Ë ùÖ¬ðÏœñ¨««C;::t”©»¹(—VH♜œÜ¾}ûÉ“'KKK*›ª’è¨oŠë¥7 ÚH'ºNuLelÛ¶ú7ä}¡äï²eËF2¼uëVwV{{;‚ºc–••!®þ%6šJŸlsôÑGÕÂÃ1 /TAŸ–õ}š³ÚÚÚdÜû‘äø¾ûî yV{KK êâ¾­F¡"Áö1éÇè$*]×h²yóf¥ÃÙ Œy~ì±ÇÐZÙÊ‚—{pÊ2„Ÿñe%ŸÃ#$4ð^w CCCþ» ƒ9ËItèP ¯xÐ$æáááØ#Ô$Ø0ŒB °|w;#8‰s©âuhøž8A9Ô}Ša€bOg:cŒ¬€Ö…ã>Ó 1RâܹsO>ùäüùóï¿ÿþL§ÅÈy ÔãX„ëqÒv6¦-òŒTgúÎŒlaõêÕ4à2 #UΟ?ÏÛMCÜDÚHé °fÍšS§N%mˆ†a‚}“ΦІaFlL¤ Ã0 #K1‘ÎCbLçAEEEì!u-++s?KJJü3ÐæÎ«‰àìôXåA`v¦² ã±cLj'|ÿ¬0zzz"†4 ÃÈ9L¤gçÉdºAwìØ¿Æï=CW^¾M¸)MSF,X°råJíìëëó' ··÷ÀœcQ¬¤×€:ê±iÓ¦¥K—jÛ9ì4 ÃÈuL¤Ó ÕÖÖ†Å988ÈÒ%Iëîî®­­e¿$ c[+f*ª&!Z‘ŸœŽíˆt¹IÉœâ”Ì-Cé6ŒMlsæÌY½z5µ£ß-š?yÚCxÐnO <·à\²ÈïŠÖ&ijjb›=ÜZÈ›;¤aꚸ,‡k.[PM®Â_ç¬M‘s-’-GcŸþô§•'üuÚ¯˜]6º4û-þ ¹uÓ¶œÕ•¿GAg)»tG.  ‰cZÝõ.¦6®•.…ŽÊñªn$¶kUÃ0Œô“éVÂŒ2­–t?µü@z”ð÷ĉþr¢›éÅDÚ0Œ¶ÀFz˜œœ,))‘áXYY‰fø;iSA£œd”'ÖÚR§4É)ØyJ/^\¸p!Y‘®”F´,·F˜¹ ¯›šØo#uì›tzX°`:ÚÓÓƒZÓH—Uv`ýæ$ ¾hnnvÉ+X…yÚ«ªª²P¡ Ã0Â1‘NZV9½q¢ý鲫l¹-±Î#Ó©ˆÊèèè”îÒÊËË.\ØØØ¨ˆ™N²aӈ͓6Œ,"žoÒ´ÛvïÞ=<<ŒT;W3†aä%&Òù€óe–Sv¤'ótOj§;Y’!ÏõJkkëÄÄÄž={êëëSqŠnF6c"ìØ±CƒÀc€Â­X±Â¿§½½}JÙ‹'æä 1 ùëŽ'µÓŠÉg0áhÚ˜ó¡fFþa"í`$ÕÖÖ¦OUUÕîÝ»Cž›‘Øß¹ÓuÅØ½•ä9ÕïzÖÈ,óæÍãu{ç;ß™é„ù€‰tÚß²eKIIIYY™Vh`{+Gݤ(߬Y³***ä€zýúõ¥¥¥ü%Œf…ÕypHÁ¨vÑK6úúúØCEÜÑÑ¡£òAÆþÊÊÊÀ8£žž®òÖ•’n®N~r-š¿÷ÝwŸÜ€“¥Ðõ—®È®E:µ`¶,W$Z"ñ_´¦¦†0ŠSa8]·ý‡üÛ\—ø57ŒÀÄ©›ÒÝ,âL9LHîÂeÛº…×9ïï- fLw§§£¼…¦¦&®Âµ\6jÂLà§»e¿£ïlÃùNÏtBŒ×™?>"}ÿý÷g:!F^é‰Ú3Ê´:3imm•¬µkײͅ–.]záÂ~²-§c§®"¿"Ó.9#˜„ÉÅô¾}ûü¾´ƒÜz_¹ê$ëŠ7ÓÝïjC'’˜7ÁZ®=£ ˜Ÿ›6m"…„$Áît¿KçûŒ‹Ê-!åÉD)Q¥¼³³SZ¸º¼‚¨tùi[®¾” ¶fÍ“ºýç14p ¥vëÖ­Îw·?+\Ê™;…k¹ÜP>p!ݱ麊ÁŸ`Eèÿ)7)΃Ûô‘Š3•ºiMža3MÁJ˜°Ôø2Q4X^£©vµDcÀ…õºuë,X@‹;äMµÂÊ\¾|¹›ÁLH`L?ðÀÚ£Už£XÆüŒ8é éÅLÄèD]0°°VI˜T'€Vx\½zµsÖÎâÅ‹ ƵˆD+Di¦5éq‰GV±eÑ nŸËagëÆIƒ;„À»mç?\«v˜¨´0‰2JÕRq)Áz&$ÙÈ ,f®Kò×ß…NÙ—„g?61ÙÂU4m ÉgƒÓý &Wõ3ä ´ÖÏœpÙÝÜÜ\]]ÝØØ˜é„†‘N¬»;m¨~D P ­ÊàýE´¨ôÃL¡¦È•¾ ‚uww#’½‹òaÄér©Íψc©¢“'O"Ѝõää¤_ûCžª±3ö -]1< q’ö£¬Z,$äuAA%ÁœÈµHºHtÝÒJÕÚvk_¢+Zû’á¯:êcä0 @Aµh´Ë tWS’äô[¨ßž¬àY°Í…Èöœ8qB´~ •`ÝÔÂ… ù©˜ÝOÿºÔY éä±úÞ6 #0‘Nrf‚lÞ¼Ù ˜@c Ì»C‡ŽÊÔsV`mm­$V½Á29«¿¿9Gi¨ŽC^G4rîûã,-ÞL$~é yŸf1g•ýhÑe]1pSX_‘{zz$r!Oç´ø4i–¤úè£CCCá‹eØ·oŸ– #°?+'-ÑáÏ®HþFKVs¢º|»U‚ Fî…ŸŠÙýlii!“³ù›´X·n]øñœfAggg¦“}wggñ.@Î;÷ä“OΟ?߯Ž©c–tæÁ¶Ãb³ùHI£Oþ1:äõs´¶¶JóÕCjuuõþýû3 #tþüùÁÁÁŸüä'™Nˆ‘ØÀ±Ì³~ýzÿj9}}}៴о™Òú”é<99ézéón-Æ@Ã0réÌX“ª—¨JŽøs,4->Ó©0 #Xw·aä 4Vlt·aä…%ÒÕÕÕú~9l÷˜á;âŠÓ4Ä,FÌÎY4êêê*++ÝO,<ç\SÓ¥%eeeþ›åQRRR°+Fh¤ºa†£°D:³½¹nåÄŸþæææááa -­"6ÜŠŠK=FFFˆPÞF½½½ŒsF9=ÍtƤØÃß Ã(4 K¤1馵N'rÄɉÂ϶¶¶§p¦²¶¥LÕ¡ÐÕ!Isúäÿ9è!Xá×=îá~º‹Ê…¸RåŽêºìQTZRžF\®{ðàÁÀ%”~ç>Å Q§K¹dX·ÙÒÒ"áQF{{;îöc;úû68‹«`Lü‡pueîHÇä®ÄŸŸÊ.…q« ݲ»q·ð¥bž¾"‘äÆÂ… 3 #UŠ‹‹)TþÑ †‘<™öK:ÓðþŒMGÌÛ¶m#òÆÆÆ9sæ´¶¶ÊÃ%;«ªªø+dlìÛ·S§N±ÍÆáÇÙ#÷ÑüU$G ü”'p"QHÿE,X ýÄ#ßÔüä¢üåÄç&lùòåΩ5§ÈG ;¯x.©u!Brºü`€ü~¤]úåd[ñòŠç´œ´qÈïm[7¥µùK`.'æ\Eûù©ý:%䉴Òã÷ÚM€M›6ÉO*Guw\®««‹BøýÙÅ6WòyþOtS[·nå® ÏU”¼+žËkÈt©L[á,À7Ú0ò›‚{¥©â§i·z‡DK2ÀI‹ôR!% e¿6´üƒ´M’ŽúºÈI¿·üZýÍf[R¤‹ú{{{•NW„lr'Zþ…=®xk?¸ô‡®.Ñ¡ .¤¤êFFÍî],U&˜‹<ä9ÇÖÀl·äÉö7A®\]½ƒØtãüd›`J›[ôB~RÕ$RHyp“w3ÝTàÆµrFxþd ·nJ*˜HFžQpS°¨¬×¯_?­ëh–³\F«§70 “nÅŠò¼]RR"/žê†•œp"§øºžäŸÕ!]ZuËB|mª—X}ÎÑbHn³”Ô¹sçj§nª»»[=¤AK\h«ŽŽòÁdûÑGmiiQ0Ô70ZûåÑ9§—-[žçþì*--ݱcûOœ8QVVvüøq”Xû%Ì!¯ã]«}Lé‹tfàÓ¦Ét* ÃÈ. N¤1­´¼Ätxø:xðà–-[P d˜ !TÿøÇµ`hMTd'5²¤ ­Ò!ô iAQzè¡ÀÏøïÎ]´§§GæoÄ Í;yòdÈûÔ8Êu•3GŽñï—vrwZBÊ7‹Úq/Ü>IuŸx¹M„Ç„"XSS“Æ#pn¿:;;‘ùcöìÙƒÞ—@¡É®ÑÑQ­ÿAª6oÞŒfû³ S›ÜÖuoΕgï¶¶6.än\ ˆ‘ÄáÌz½ævÈõφaü–L›òËÌ}M#Øjˆbkk«–C¾âuùRíºEˆ1"ûûûõÑñÀêeå§ëneÃü<àáßlkµc·á¿¨¾|ÒI-Í)DÎYŠÐmpHëX+B‡K?‡”f·¡¤†÷û“ê~"‡.‹™Æ¡ÿ¿½3†‰#Y×öX:–-î• 2‘‰Ì&ÆÚ£…dqbH ‘Ñ à$àœ€ØÄv²,$Ɖ!Y®Ò•Œu¥Å 8£µÀ‰!‚"îèxe‚+þgû=®¿Ï Œaèž™÷ FÕÕÕU_õÌô[_u÷W¡¶8kkkw"PÙÖÖV5ºñÎf=¥C"«ãšWþ%=¦pv0†AÃÅë©Ì´1eLe-°À£âzípÙéG¿|ùW]÷¶/NÖ¢&É"cvvv.>ñ~íZ…þ£S¿U¸ZX6i[LÉSqÓÝbjjJk-äNÞšT188xpp€TߺuK÷­‹Âüü<~y:Å~ѽ¤ 1ƤŽÊw÷õõ1àÕ³¾Æ$Åôôô«W¯ÖÖÖŠR›=é4`OÚ‘Ê fgzww7+â•1WÉúúúè訟3ÆœF…Nw .Žõõõ«««É>Ùk*“ÙÙÙ¾¾¾ßs1ÆœFåzÒ™è]^.‘‡‡‡===•¹¢ƒIŠééiÅ7õ­hcL*Z¤3‘N¿yóF!£Ëi©“ZÖ××Ph¯^–ܸq£µµõ¯ýkÒ†˜rÀ™üZOy艤Í1eòüøñc¯_¿.ÖƒåóóóaÐ\ÖÖÖRò»1¦0,Òÿ—Ñ'Ožd¢7 [­ÍÅaü7;;«p¤ãããŠtVDN‹×¦UU’î½1æBX¤O@±²'&&´æA[[ÛîîîÆÆFÒv™ÒCÏ: \ޛЧ9Óv£),Òg‚Kíòòr‹O˜Ê¤¡¡á*ŸÙÎu¦íFSX¤)yré­­-?•fL`‘6…£¯Â²W&AâÎô£GŠBÕœ—ÏŸ?øðáæÍ›ßÿ}Ò¶˜’Ç"m çÚµk™hÙ¥¤ 1ÿâLïííù™ÇqXPSD*ý=icʼg sHcÊ‹´1e‚ÞòÒ§1¦<°HS&àCói7Ú˜rÂ"mŒ1Ƥ‹´1Æ“Rüt·1åõkþGSVØ“6ÆcRŠEÚcŒI)icŒ1&¥X¤1Ƙ”b‘6ÆcRŠEÚεˆ¤­0&]ìïï?þÜ¡ßLQ°HcŒ1)Å"mŒ1Ƥ‹´1Æ“R,ÒÆcLJ±HcŒ1)å/I`J˜gÏž%m‚1©ãÆ­­­7oÞLÚS8¿1åƒØ0¦Ìðt·1Æ“R,ÒÆcLJ±HcŒ1)Åw°Œù'‹‹‹CCCJmoo'mQ¥pûöíªª*¥ûúúº»»kkk“6ʘTà§»Má<þ<|–(ˆñèèèüü|MMÍàààúúzP sõðu¼zõª¹¹™ôÀÀ@)~Ÿ?þðáÃÍ›7¿ÿþû¤m1%§»MἈHÚŠA^ÔÕÕ‘F›WVV=zTŠ’PNpþ*mmm­®®0r*Å!àü±¼¼üûï¿'mˆ),Ò¦™Evww÷ööksÚ¨­­å{ÙÙÙÙÜÜd µ°°´EÆ$ƒ§»MÅÑÓÓ³¸¸¸±±qûöí¤m1ù@ªçææö÷÷›››×××KÑ«6æ‚X¤MeÑÐЀ‹fï¹T@ªQµ´´|üøñÍ›7I›cÌ•âénSAàCã“­­­Y¡K ¾/¾µÝÝ];Ó¦Ò°'m*…éééÕÕÕ­­­!I›lN`¿¾¾ÞϘÊÁž´)𻺺ðÃò+t__Ÿ˜¤œÚÚÚ™™™æææ½½½¤m1æ*ð=iSþŒŽŽ¶µµ555å)ƒ«===§ÞÛµoûyDž£VWW¯_¿6+èÍlqïÞ½†tȧfêçÀ––|ÇdÏž:ž¬ q=z„3=??Ÿ´!Æ\iSæàFMMMå)ƒ"ŸùgP>E~óæ ‰³¼¼‹ÏW]]-EÁ´µ¾¾®FI ÆBÒq?¾¿¿mmíîÝ»ííígì)‚¤Oö™¸øtÅëׯ{zz8ŸIwŘKÇ"mÊœW¯^uttä­8”‹‹‹yÊTUU5Fd¢XÓ$‚¨£Ž¸›JK‰'&&ÂÈ-,K0GP›ø÷´KåròGFFÂQäë!©¸H;•ãy///“ i¹Ú³³³Á­'Ÿ½Šª¦´.udlAa>i—Õ££Báõp`|“2RGU.¨„bgÐð…|ÙŠe"…Ö ùäè…õóÊmSS•h¬cL™slLYsçΕ••<z{{ù#´¶¶>{öL yÊS7ZiJ¢¦ƒƒƒ|ÒÊÞÞZN&µÍÍÍ©ŒîžòI™ññqüc6¿|ùBI†Øsˆò)&›)Ìç­[·&''CÓª™1*¥#?88`“Cd¹‚k²—ÏGjŽ„öNMM©QZÔ €Ö1˜B[2›ChB ööG0¶Ù˜AŒ6¨JõcðÌÌ iZTÓ²™b:3$t†—––¨#©-œÏ³ƒµêŽ1åEÚNúÇyHÅ7-D ³F®ääïu\¤¥‹h 4)’ÄJÉiÔHÚ|©#EÔ+ažÌPm¤ÑB v–©+h!Â|i•:È2[ÏÇ‘¾¡—ÂÑQÍ% ù$d»HÓŒAnÞ+´E_È$¡~Ùy'Bƒ‰Ð㯃•p¬ä\ÅÂ)¢BìQm*¦5öÍÒ¯Kÿ„zýòåˤ 1借î6åÌ‚¦²ó—‘–Ãwß}Ç'rÂg{{;únåâLTWWó‰vJê2ÑlpØûË/¿´´´„ôýû÷F3‘Ò·µµ©iBð:#ôÄ8n´æ¢ñíHÐúîî.Më®ðØØå9 ²*Þ tOš24ÚAµ0-Ò/F÷ïßÏ=™èñ.mb*Ŧ§§±„nR}稚ššp/¿hÅÏx›²Çž´)gpõäžy·zK ýØÛÛËu£)^£B·â $ðàà`}}YÏŠã5†ªäé¢U”Ô$p(Fþææ&–; Ÿ‰Þàâ(äŸ~q,etsº¾¾žJ0XáÒH°—ŽkØ@¶pТ€/÷\߬1%Š#Ž™ÂÑë³iþ ¡RÈ^ÿ*Ø–ž/kiiAÏ;E|xÆ>,VXl|t\déð"xÑOÈ|„&öSß”îýëý:c.‚=icJ=Ž,áË¢yÅRh|hœé,7ú"`!Î}p£ãvqÁA¿Èl¹1%EÚNxgÉ\ Y·‹‚¿*b…Ý—jsʹqãÔ›7o&mˆ),Ò¦p¼n 1¹ Ïáac.ˆŸî6æ|,G„ÍÜ(]gAѸ2Ñ]ó"VôžÆ/ ¡ÂN”1ŽEÚ˜ó¡×Âæ‹/â+2 (l=ØÌ!Èæææf± £æÉÉÉøZ¬ðľ`¼^ý: ‡‡‡²'ëDc΂EÚ˜s°ººzqÚj£££ù§:ÙK™°Y¬ç¿¸æKKK™(š÷?Wub‹ÕÕÕ²ÇSicÎÁÓ§Oûûû;::ž77—µž&çVñC~øá‡Lô®Ôo¿ýöóÏ?Ó\UU•^˜¦]6ß¿Oýñ‡íõ|õ§OŸâ®­ÖÝ:88˜™™¡¶ˆpwY RÑ5ŠÑ‘¬ 3Ñ»U(1¦*þ6㳩>Æ[|øð¡BŠR>«³Æ†eŠäóçÏtðÇIbÊ‹´)œI[quh™ qЇªPÈîÛ·o£@ÊÁWƹDe‘"SáoÊR©»ÿþôôtÈDêPb|Êó¦Åæ\ŒPÐ?¢(ëY‚vQ²££C¢©|‹²yZ…½½½ ÷­ÍÆÆF´y||Kèo&Š$ªYÌCæ%çYõ0Ž¡€NfÒ_©1%€EÚ˜3n!caM-œQ\[œÈ;wîtvv¢Çèw¸ÙŒÇŒ\áMê^2rÕÒÒ‚„Ç=×€Õ f¤.(¥¨¦´pbb"^^kH···sN¼ä]ÌšÕ@;‘áx‹äÝ»w±Käßk­ª,«äFçVˆ…xÛØîIÓÄÐÐÝ—ÙlR!ÏÙ “îÌÎÎîîîfõWnt<à‰1æ4»ÛŽcwŸgfii íćF)“>eÈÆÆc‚FuìnSDq̘âƒ{ŠC©é_»ŒÆ˜‚±HS|ôèõÑÑQa‹0cŒ°H›ÂIóDw°BW&µµµõj¢¹Tüà˜1Æ“R,ÒÆííí_¯ÊþÖå=Ô–?„x.z 0)666’5À˜tb‘6¦ ˆ‹‹‹g/}ù2P8°„OŠ1æÂX¤9+a±E%%ð(¢ººZ‹EâU+^‡Ž"Mùx쎞žž§OŸ†Û–'–ÏòËi…üv”ôÄÄ„ÊÄw…ôááá£GT˜’T8??ŸùºD&Ÿ§Å(¥N p8 áXÒÁzwÐÙK™P µ…¡•¸ÁáÀÜMÇ61ædŽ)_îܹóéÓ§bÕ–‰bS‡DSDss3izQUU588xûöm>÷ööPnEÀžœœT%kkkŠîÊ£¦lRž½ì"ÑÑÑAfhweeEÕRŒM¥)Ãg|5‡´ÂkS U'Ÿ½½½Ê§rÇò¬Þ}ùòË)†åT…ylÎÍÍQ iÅ4ÝÚÚRyr¨D¡T´I»äð©e¯8'Èᤵ3Ó[›|ª;£žó^ŽtÚ¯ü7eÌ•b‘6…“þqÞ¥Š4b†À¼yóF It%J  ˆÜq$½AÛBáPì8’aІM‚£¨9”—d¢(šGZe ¾+ž–«Bò©DbÄ;$â½£ÂîînÒãããjËÑr °5 åBµ$8–blêœ9Ï28wSŸkÏ7I­HsÂ9W/_¾LÚSø,cÎJÖ+U8Ç(bWWâtby$­¾¾þúõë ä™§f…ÕÔçÌÌ Å§»ÙDÛÛÛïß¿ÿË/¿°)iÔ{Øa×o¿ý¦tKK˯¿þ*<<èééillÔBœaj †÷ïßÇWÂÖâ ™hiζ¶6šÆ}¤¹x¨Î,ƒ£ùíø&òÏ@',®eŒù’våM “þŸPq§»£yiMfj™MÕè.EèÞ³ZÚ%ÒñzpI9ßWå©-Ü´&Ÿj³ÚÝÚÚ¢°E¼C»Y»BZFæùñ"l"ö¨µZÑ”5i­`/¯Ô£¾¨§ZOSkQg• Ÿ¸©›çú.<Ým*/°a Ç lä§¥¥ŸßTs¼¥ˆžN?q1l±½½ÍIÖd8½FÚ¯À3ö¦ð+XÆ\º»<11³îÔ–"ïß¿Ï?UŽÿ====??¯ùƒ¤M6¦Lð=iS8z¹ÈœÒU1œõJU~t{ÞÀ7Z[[oÞ¼™´!¦°H›Â)2%ÊææfMMMÒVœòŒH'm…)<ÝmÊ™ÆÆÆÜ‡¨ &D+!-·#áõ œ…¬ècWÏÆÆÆƒ4À˜+À"mÊ™;wîñÁ¢/^äyxê’èê꺈rlÖíðÕÕU:¢W§r ~ó9; PŒ£’ic*‹´1Åß´³³³èÕŽŽŽ¶¶¶±ò'OžÜºuë´«««¿ùŒ&%YÞ½{â“S®X¤M9ÃE|vv¶ˆ¢”õõõCCC™è½#ÜÜëׯ߻wÅ¿Ä=½víZMMîÖwEd¢éå––öòI dÖ&‰žž*ooo·ØÑѱ¾¾*lÒtCCƒ§Àýû÷9œ„"yad]]’ö÷÷© gZ eÒêÁ¾ Èøø8#Œ§XOO*®G©³Ú¢‰ÓB—_*8÷YÑ)K,Ò¦ÌAcvvv‚¶]\ÞÎÎÎÖÖVT@Õp‘àãØiyidŒFÉyA‚ÂŽƒ‹ìQåC,³6¿Ù Ú¥0î¬rhzkkëÅ‹X…ˆf•Ç Ê3†ˆß“F’qŽÃ&d[¯S­ÅíBzpÒè/Ÿ8…höaDÖ=~‰×y5`›î¾_q»Æ\=ŽÝm 'ý±»×tôéêßž*]&&&Ðï—/_2&àÔ…õ¸Ò+++ñ%¹R…cw›"bOÚ”?š—Fª“6¤dÀõÇEîêêÕ4@zÀ¤¶¶¶Ô*´1ÅÅŽ™Š`nn®)"~ÛÕœ†ž÷><99™´!¦øKÒc g9"ž_—¬£££©©)i1…ã·*Máx¬ÄÁi«««;qWUUÕÁÁŸ—ÚúÞÞ^Òç uüïÿþïþçþû¿ÿûüÇ$mKºhhh¸ÔdYbOÚ˜¦¶¶öÑ£Góó󹻆‡‡‹{A<::ZXX ­ÃÃÃêêê¤{Ÿvþë¿þ+iR‡~9555ƒƒƒÖìobOÚŽ=é4p¢3]\7zzzztt4ÍŸ÷öö666&ÝiSÚlookÀGµf ™´EéÅŽSÚÈ™ÎÊ,–ÍÅôÞ½{‹‹‹«««[[[ãããVhsqnß¾6¯DlllÔ×ׯ¯¯'mTJ±'m GÏ(ÅŸT2‰åL#ÛE¹UÜ××÷ñãǹ¹9.©IwÑ”3GGG£££oß¾õ-‹´1å@WWW¸3Í•î‚ó‡\4ñ˜»»»=3WÎôýû÷gff:::’¶%EX¤)‚3}q7z{{»©©É×JsõðÛct8<<ìÑaÀ÷¤)Âé ÆÐOc…6WÏíÛ·f#’¶%-Ø“6¦L3}ÁtCCÃÈÈHoooÒ½1• ¿äúúú ߟÎX¤)'®]»Ð?º¯¯OzffæŒmÅ7}%1Ed}}½½½}ggÇ/R[¤Máøéî´q‘>ïeÑ"]r0ÛÝÝ-÷” ÖNMM%mHÂøž´)œI[aŠÃãǹ ž×qùôéÓqĉ{¹Î^ûW#òìæçção”Ý»w¯¡¡!l²Kϱwuuµ´´„|ª¥þëׯ“¹½½ôé<+ùW©¡¿átåΊܞ §m¦ÎÏÖÖV5Ð÷Hå—t¶GFFö÷÷/£òÂ"mŒÉ(”DWp.Ðy.£Ÿ"H¿yó†—ÝoÖ‰‡‡‡«««™èö$¶mGÈNvQm@ª)o½¿¿mm­¶¶¶§§ç\O-˜G_½zuZoʧôò,¤r}SE—jÆ‹“““}}}—g|I`‘6Ædž•ŸJùìe ‘LÔQ%Ià³b!v"œ¤%œê‡¨-mR‰ŽŠ÷K‡LOO³W•«p`ª¥°/ðøñãÁÁAê‡g',TuÒô‘šsûȱ;;;:“£Ó¥ŽdÉ*›:,..²©v³ÊËTÕOå4¡W§hý›žý¹à{ÇŒJw¦)ÿ„ÒFÁ_~ùòå\‡<‹Î÷ÖÖVþúÃÄø;wÐÑ••4u+ÑeS™*C¦L¢Œ‚GR†M>ÕùsssøÍÁrª•%ìÂkMs¡ÇÈÖ\mm¢îò¹É¤Ô‰‚Àh“½|êusʫݙ™ò‘LÒ’= ¨ph«··WÇR8«_d²I§0›Ô†IT¥@ëŒ“È µÉµ‚©ähN“8J9:±ê”úÅ.¡§Eß U»´´„´“Cs¡-2©Š…9œî0BÂ$N –ë×E% „š5„"MåÅýIcM·ÎÒÂWXS8é´QØ×„„+øyÑÅ~ûí·ü†ÅEš«yHHö¤ \‘Ã!h›RšãH•Ù$“´#jC™´¬¦¥‘‚Þ ….Æ-a¯l 0ŸH‡¤ä‰@_ãº(Ý m18ödõ+È$ ,Ñåø«îÊNZBmYaãU„ÂÇ‘Æk(C&5cuÞºuëÄ>ÆEš½‹œÇ‡eŠÇ6)¾ ¬Òiá(ÚÒ°)·æKºÐ§ë2j.¼T¥1•ÎÄÄÄyïüÍÎÎîïï?xðàýû÷Êѳ]---hÀêê*—ò3VU__ÏUøåË—™hÚ6äãÏuuu!uÚDu^¼x!A8»»»IcÀÐÐ9™È‡Îm§«Ð¤_~ùUkooG²îò¢m’ÛL4?Œ=øš4‡BôôôŒiWMM 9:ß±®®.ku\LšhkkËíWüf<:šµp8PwÉ«Ö! }°?ýôÓãÇýõ×P‰’t¯@<ýåÀÓîdk…4=v§©ˆLtk9LÚ‹03Á©àçñðáC+^¢”~eݨ8’%cŠFaÿh.ÇÁÍ=#øOñË J&—~mæzÕ™Ó=i9vò8ã½&™ƒg¬¹_2ãSÜBSß¡Ú,y ÆãÊËDæƒ-ñv„l ¤<]•9Žfàå^s,ã™—5+”J8<«_qOZ µ¥›ô2@ηº¦¸ãÝ—§®£„»´´ú(Ÿ8ô1דÖ}GGGÜC¥QÙšî'“áˆ:"OšMõHg#Þ`Uq)à÷YNX¤) i®­\¹¬ãVr`|†% ÷•ãP,È*etHHð‰®çÞÕÆ/ŒoJ„(œUR9¡¶¬]ºuŠ&‘À"U“=2XSÙêNè]¸½îp3> aL\Dã=¥Xh=ô+˜4ñé+Ú¤pîYŠŸ[rT,œŽel$×pD½ }ÔQY'M†å¾Ð¬ÖÙÔy ›2;«æ¿Ä‹Sá"í`&Æ”…3¹`œ²4£“¨æááa{{;röyøüÔÕÕáS^pµ±bõ±¡¡$}ÿþýbõ1%tuuéùµ¤ Iß“6Æ”-ÈÕÆÆjZ]]½¾¾^,õZ^^¦ª”¬A‚%tM}¤³e¦Ð™hz?ÜI©@ÊvmLbOÚ”~ØÁLŒ)ð9𥒶ÂS4<Ým Ga„í„¥¼/^d½F\Z¼zõJ¯Gçæ3imm={Uûûû“““ñÀhtoo¯±±Q¯D'}nþ„î „ó£ÍÜEı9k¸Æ©ÛÜܤ;555tGO•«ƒYÅ–——ãM˜„IúÉ5SÂø'”6ô^Ðyc‡¥êK<íQÞÓÞ°:‘¥¥¥ÁÁÁxè‚ÑëFÔ“ûÔzSSÓÁÁÁÅ»L=gÔ•‰½Ì6õê”B¯(M÷Ãû]ÊAÈCwô48‡£Ö¹Å²šH½è•´‰áéncÊE½Î³CR„(%ñp%"C#+žÆiùñXÙ¹ù¸ƒ£££yjÈDñXâ¾æiM÷÷÷S¬­­mzz:«°âkžxln7ótŠz ÁYÌe#S‘[¥ÇÇÇùÔ{Õaoè'GA¹)pb±<çü4ò³…õËd|OÚ˜2c4"=×D´ðzj:66¦´Âo]»v­«««¦¦†Ïåå庺:Ò›››ñ÷··ïÝ»òé—¡°–¯ *êápª%¿½½=M㞆JTC|½K¬êééùî»ïõ ¨ ³ìÿþ=µ¡^ p¦Õ6)<22Â'ùª\öh)É––râU…%&C;uéææf-BUT®ª@iÊgÍØ3{þ•ó~ê¿ÍSìÉ“'œ“û÷ïÇ¿¾Á°Šèúú:†…¥/²¾Y„¡¡¡ð¥sÎù–:icÊ E›Š/´œ,\¦Ucppðàà€Äðð°¢xf¢×‡öööT1CB4JAÉü1䣫««Ÿ>}µ墯ˆZì­¯¯WL’ÅÅŬÅÐuejjjff&dJq©uD{´HÆÎÎÍeN”‰J‚Ættt`3ýÒæÃ‡£¨gáÆ0ý¥-E0= F½½½z¹9ðÃ?lmm¡Ž´…%ô“ªªªÂéôqþ+çý:èÃNxîmì8?ÿü3%1f4óàÁΛúÐîãÇãpþ9ùüð‚©wïÞÕYbL@79'ጙsáÇŒ)7¸,~üø‘kk\–aww—«¼yvÔo£QƒÐ2Äá“/âÖ­[ŒPw~ZapnOüfQz2µ>&›|eWú» °'m Gt$m…9Ýe¼wï^²óÞ\Ö¹4OOOË-ã⎳¨¥â7,¹p£‹°®éñ¸Ö¿zõ*äKMçææðŒB„S“ÌZý"«ß,9¹ß¬:>>>Îáœg+tX¤MávWÌ\ ¸h(\MM ßQ~¯îRA‘"¼FDô矞ŸŸ?ŒÀ?“ʪš166†àqM™™èûÇ•_WW‡h¡ÔöôéS4 iǯÕ}膆†––öR%Ù¤š@hµ`@ dƒÊ\ûwïR‰–½Šk•0¶Ð-ó°G0OiN/…½}û‘Ö´¼šŽŸ„ ùW¯3‘’É$º Së"2QÀQ`d€ŠcžüéPOÜ€¬Mõ:Þh–ìUTHgCµYÅBJp~øýp~ø*¦è~yÖlùðð0<ñ›å”2ĉ?ßgÎ…# SÎp!FŠð[[[¹t" Yâß}÷¯i‘[[[ãûºÿ>#ôD®fÈ‚÷¿qÙÈ`$”u##§+~“¢œ°HSèu£wïÞè3ìÚÜÜôu mŒ)7ìs­Ï}©èÞ< }â—„DúãÇ[[[yŠíîî2¦a4“†UOŠˆEÚ˜JDZ»S ¢˜’HgÁ”2<¶v5œ=v÷úú:ƒ›………©©)=À_øéncŒI)©RhÙsÅ }.ðïçææö÷÷›››———‘ê¤-*~pÌŽ3ƤÚÚZÜ}źIÚ–"`‘6…ó""i+Œ9†gñùô‚V<ç›oŸ±æÀü¿³—ñË’"qò€K½°°°¾¾ž´!Å"mŒ)=г¢¼W†(îîîf¢WžYø²¯øX¢°šæâTUUñ¶´´¤'DnaX¤1—ËüüüÐÐ4Uq°ûúú‚àMLL°Éõ”ìE¥(Ìf¸“BbqqQ÷V(|/˦– A¼U^›!lˆSØŠÉ[å“éjgggvv¶³³3¼PŽmÔf¤§§çéÓ§añ’`L&1h3^žÌxÇe•ÊÄwÅÓÕÕÕzÑ™LJ’©N±‹v)vÚ+ï˜Ê®ÃÃÃp*t2Ãg;Ô¬RØp}/:ÿ:0nð‰›áü§–Û·o755•ú¸Ç"mŒ¹DpeõZ!9_¼xñÓO?qéTtq-öpëÖ-$poo½¨©ô•„ÂS“¨­­Õ•ÉÉIäYQT?rN5Hé‘«úúúÜÐ`¨”‚zvuu¡µJ(à6ñø W™h vÅcˆrxeX#ùQ„×ÚB¢1záxff¦ªªêøë2ÕñÂjH–Çû´…I Ž!ÙíˆP~mmüîînÒããã*#íµ24Ÿ²MR§òÙ\YY‰wJ§…½½½¹§ÃtuBÄÁÁ§BëQ²ICœLZikkSmZŒœ®Å ¦¶ø&åù \öïó‚ëI°Âzªð+XƘˢ*"„¶Îz¡èÄR!jޝBj£L!Š…èxtOÜ;ÜÄ—/_f"ŸW5k±ËP-º200€Àà&â¸ç;ÆwŸÐ<  0Š˜ù×ØÝ¸¶;;;4Š_‹j8¢2ñ]ØC–t+¦)}ªÕ*X¡Îc_ëu#Êg ä™þâIÇWÂàLÒ–h¦zii c¨Q‹¾5WSS7W;¾‰Û†“rÄ\ý»ÝEÄ"m çØ0Ì·ÀGÔÄ2Ú)Ç+ÂSkQjQ__ÿã?•ÒbSZ„Jñ2­ÅÅEÒ4Á.ò‘+TG%³¢t¡^---8‘óóóZšI~ñâG!Þ§uDëpÌÎÎfEÉ@á°P±©Q¯ð§ koß¾Õ,1-R3FJzqmÃ.«ŽÝlmmÕÒ»»»èhþ3Œ¾R9å9÷îÝ §‚ñ §‚ªâç¹U0óL4 ÂörfP2ŤZt2ÌYo"üj±$žÉâl¿{÷®tEÚs•ÆT:—}@›µØ³ÒY >qõ´©l¡èКý–ºS —( N•§L|›Ÿ"â…Åä䤛”QªDdz³Ç$2)£šC˃1qØË!J«L0)¾+¤)/@yÙòã´·v/"œ Íð‡ÛuíçûÙ³gŒ!é¬óŸepîæ§¯\êçøÂÓÝ<1»°Mq:¿|ù0Šyzo;DͤZ>Qµx(PÅ+U먻mmmdÇãµkffFqOCIÐ}N‚Êó¹³³#ó¨$ôôè;9:´‹1œjÙCyyÿ™ÈoʓֻÑ:iê õp ÂŽò….¨fŒ”çûÖõe£Ø±©¡Ô=i_aMáX¤Ëƒ‹_ó‰‚ ü * £Áf4¡@ÓÒKJ*ê¤äv)Bᬳ6)£ˆA>E<ζDKa½)I»èêŸ×•R†@âJEdý£€BUzE±ŽëMÐ9¢%е©€¤BZ«^P ûÙT2ÑýWµ;55uÍôb‰ô[cˆÐ]à(×wGåá->³œB½Ó5;;K Šý©¥«Äðð°2å}*¦V§ÐŠ[ØL‚œ±±1M†ËïÌj ûQG-cEçÏŸ?yò$óue¡ŠoŠmꯖ±"MïHÓ4fONNÖÕÕÑ‘ø{ϘŠÍûñó¬/kó}úðáCÝ\ÇãW¾"¹ÆWê ¡×)ô«aaa!¾þXâ{Ò¦pä%m…)\—Q‚KªœË=w>•ŽŽ´‡Lë3Âææ¦”wôË—/±ýF85ÅŠžÉ›Dùâ›yî’ÖÔÔ oZ~1«›5ñã?†| Ö† ‰1ªŒ%Z>2ÏúÄèíj+¤ebbBB®°µz´Â_#ô‚òT¨þÒqB›GGG©™¤©#eT2.œŠi9Ü{ÏxŸo߾ſ­'Ÿ²œ8,CàÙ«éýÜšµÀÆ%ýT²Àx ¨èÒÏUc¢[˜—´¢j¡¥*u˜†Ð0|>ôfiiI›z|—ÖÉ?Ž&„•8ŽÂeëQdM#gm’Ös¿!!tç›LŠéÎ+B¨ΨìÉŠç¬ Ã&VaÆÎÎ%ãùôw9Ô–…‚˜r&©üàਇ’ºÙ̧–dŽ÷"«¿!ÑÛÛ«T¢o'kª™þê4Rº®{üä+AÔ ií¬öw¾Â±‹÷…½¤iN \ò©šó\ Œ×šW-^<ìv©Ow§1f¯1æêQèDÉŒ)Œk×®¡ë¸¿8ýÈ2Y”jµfW|μX__oii¹xDñ ~Û%ô^x¾'mŒù\ÌšššÜÍÙéïïokkËD7q³V´¼(ôåÝŒH-?æ7Y®ÅÏŽEÚó'\ §¦¦š››ñ9|e, I©î:«Nj[ZZjhhHºsWJ__Ÿ&ó“6$y,ÒÆ˜‚ó·µµÕÒÒ¢‡†LawˆCm'>µ^ÆÌÎÎ.//—îuqñÓݦp8i+L1á ½sçŽÞG2æêA¡q£=ðƒc¦p´º†Bå"½¹¹©8IÛb*ƈˆtqºÔ³'mŒÉfff¦¿¿¿¾¾~}}=i[LE Øæz·ÛCÃ8icÌ ôööNMMµ··ã…$¸Ö¤){g躺º»wï*pzÒ¥ ?8fŒ9ŵ˜ŸŸÇ¥&=::Z鱟LQað7;;;22¢_Zq‰ßÚÚRz{{›Íøt÷õë×Kè—ì{Ò¦p|OºBÐZ\øº»»‹£ÃT ›››èåîîîêêjccã£GZ[[‹þj>¿ØšššÓÇ*¬lÒgâ¬X¤MáX¤+ ©upJÞ½{§åªLœÿû¿ÿûŸÿùŸ¿üå/ÿöoÿ–´-éiD;Ö«`cL™ƒP-,,ÌÏÏVWW'mQšӎZ677Ÿý@‹´1Æ”'x===ËËË =êèè¸}ûvÒFU48ôó¨õððpSSÓ7±HcL‚ôõõá·ùy Ùßß`555U[[›§¤EÚcÊ  ½½ýáÇ###UUUI›cNEßÔÝ»w'''Oû¦ü –)œkI[aLºàÊ‹óÊe7‘Ö^¿~ V蔃½¶¶–‰ž,ãgsb‹´1Æ” sWW×úúúYnvš”055ÅW__¿½½»×¯`cL90qpp`ºäèîîÖ³ß;;;Y·¨íIcLɃ600°ººzšBë]a ‘´±æ:::p©sßβHcLiƒîrqŸ™™ÉóœpKKËwß}÷·¿ýÍ~vjÁŸæ{ìëë‹gZ¤1¦´íïïÇ;­ÀÂÂÂúú:‰¹¹¹¤-œoÀ™_–°H›Ây‘´Ƥ‹7n´¶¶þõ¯½šæö÷÷ÇÆÆFFFò”‘sÖÛÛ›'˜ ʤ÷5ð¹Ñ‰¬½ˆÖ‰5—åå團˜¨«« ›ñ·ÃÏb¼š¦ûœ‡ï¾ûnkk«(=¢6Å]\\ó5*'5ÐÆ-ohhÇ2î¹}û6MP ˆk8á´N>õë…xªÒ0HåÙ«’a¯Næ­[·øìééyúôé7}›áááÿß—ccŒ1¥ÉÜÜ\sssž{{{ºÔÿ‘ç²Dbrr’dÕÔ‚¤ñ/ùT p¼= ƒ˜©Z Uŧ 9HÔ—/_Ølmme“LJ’I1*¤Z ƒù¤k VVVø¤<Ÿ Mó‰ëš#‡:pmmM†…£¨AÆommÑœîÐÑA ‡C¨™ÇQüMÒª–z’+äMË~>epSiUN¿°\ưÙßßj¦!êÔáù¿VNTøš,ÒÆSª HBžáÞêN„Ò¹%%9Ÿ"ÐÔ- #é"?$D²­åCUñ© Ý¢&Å ³™‰æ–) VµK¿TR ‰.r®8n333¹”Æ!äÈø0 ÁŽB5`ï‰"ÝÖÖ¦’¡-‰çÈ`2Õ»d'-r6ÔV¼æ¸aß„’œfbŒ1¥ÊÂÂBþø£èâqtt„ë©6qs9p``6ëp=åÔÐÐ0??ÿ "¾}jiiÁuÖ,nô;¾¤­¾¾¾‡’ÖÞÝÝ]íÒ£^º¡ŸR~ùòå½{÷ÈļÕÕUL"'M5cØ?üÐÞÞŽ%š4Á‘ýõ×_U3»â3áÿûßoݺ¥4µa66 sZhò¼´öæÍ›ÙÙY*_ZZÒ}bÙÉ0%þüž¨¯¯×¨"óõ9µ¬r^4sþçkÓ M)£§»“¶Â˜tñüƒËúï¿ÿ~٠ɱûf± ÏR´‡ÌÞÞ^6°PL~¡|AMÇÿàrF5w-O©‹{ÒñKAü@-!OšL$Ù–÷ÌÞÛlf"6óuŽW3äÇ‘£}Eù{¡Mó2þ Í'åÉQ…ã›ì·¥¦ƒJɰ`€2ÕJ¨òa’™ò!?$ËNò)©þ*“q‰î#“ ÈDÝõ©¾è¨<§(Þ•Œ·Îf®mjV¾n‡V¾ùåz©JS8ZË?!câìïï빤Kmhcc£««‹Ï¤{\tvv"{ÝÝÝ?ýôÓÝ»wSþúèÑÑÑõë×}OÚcJ”ùùyÝB6gannnaaabbbxx8ý«„…ß-ÒÆSªèn®9 º!ÿòâ`&ÆcLJ±HcŒ97!4XŠ´uÞÚ¨ªàÀÝ¡†øËWeƒEÚŽžBLÚ cÒEmm-*uÙO%šzâ+Ú{{{/^¼8c%‡‡‡÷îÝ㓪.(Òz`;é³R|,ÒÆcþIÜ QGÄQDn±ÓÊ„%fggÃèáðêêꥥ%>óÔpbsŠÅ}ÚæiäïB<'koܤ<Å.Õ·HcŒùS‡pjëêêWWWI444´´´d¢u´H×ÔÔ°‰ Q&×]ž˜˜ ŸJ´¹°°@úúõëZÍâ»ï¾£ U®Õ/¨6ˆ7Å#âé²j{{[ëiöôô°©¹ üo¬¢’ÍÍ͸1Ðʛؠe9¨D] ]ZgÛ:¨Òõõõ´Å¦:Hù4Jaí¢ï¤Ù•[,kW±HcŒùS š[ëMMMM}ùòµÖJÌ|îììüüóϰ%~8*522²µµê@Œ×ÖÖ¦§§;::¢ •Ę™œ°<­d¥235#ÛT¢%7²*g €OUñxã”'óÄò€B£—´{âlò±6k mÁ‰gâÍQuuu˜:99©Žc3™SŒ'æççûûû5ÚéÎÎNŒ Å¥d±êååeÎgÒV$†=iS8Ï#’¶Â˜t<#*ßÿýe7” 󂬮®ž÷…ö¼ dÌÑё†\R+éÇ"mŒ1%ɃrƒvÌììlgg'ÃnE)ùøñc___ˆó5??ß===OŸ>å-[9111==­@Ù¡ɱ’s…þ¦6Š)'iÕ¦5.u`0fkk«ºººªª*ÅåU˜:É)Ë*99µµµ‹´1ƘÃÃÃ,7-ljjRÄMd ¾uëVݹs'T˦¨©z³Vù‚œgÏž‘à“2Ê<88àþþþÌ×HG¡*zeff†,Ÿ››kmm%S‘¿BÍäÈ-סøá39kkkªJõ‡D™ÁHåÑ£GÇfbŒ1¥‹V¸Ô&Èêêê¾¾>Œ/}çŸn_ «B¼î,FFFÞ¼yCm¸ÅZ5òÇÔ®\A[\Ç'&&ŠRU]]ÝæææÐÐPî ’dòOïêêºwïŽrÈokk›Ekãϯ­®®"êºs¬Õšã ñ ‘}ëÖ­MŒ­k:½±±:::¶··ãÆàš£ý˜ÑÙÙ_~#€mZé² ` ÂiljjÊ8v·¹ŽÝmL.W¹ÀmÕ××#œò5/^®-Ú°··‡^R§–&dnmm±+xÌ‚òìEzÑ•?gºµµÉDÅC !ü Qsì’ ‘@¶µchQ½ÓË`q8VwµC¢œÞÔbˆÃØkee%c‘6Á"mL.W¼ žåÝ»w=§UNÔÕÕMMMuttd<ÝmŒ1% Wó±±± ¹S[ àF×××K¡3icŒ)ipÙ¹ Ÿx›Ö”"¯_¿›icŒ)mfff^½zuÙy›+ §§§­­Mwè…cwcLi£§±wvv²ì2%Äìì,ßãÖÖV<ÓŽcL9À%^18‹ò¤·¹bºººr‡Yžî6Ƙr ;¢¦¦&+¶I? °PhX¹!ö¤1¦|À!ëééY__o-›”Ó××·¼¼|Úˆ=icŒ):::PhܲçÏŸû½¬”³¿¿ïÞ½L ý´›ö¤1¦ Aª;;;{{{ç$… ÏZI,ÿœ‡=icŒ)Cšššvvv["&&&|¯:q666†††š››ÛÚÚp ¿yWž´)‡5&—+ zŽŽŽÐ郃ƒºººêêê¬÷|ÌesxxÈigÌôèÑ£ŽŽŽ³?ï÷¤1¦ÌAEhS‹R$mÔÁ˜i~~^ë['£¢‹¼¼n‘6ƘÊÍÖºR•ÀÆÆÆòòòäädÒ†ˆïIcŒ1)Å"mŒ1Ƥ‹´1Æ“R|OÚγgÏ’6Á˜ÔqãÆÖÖÖ›7o&mˆ)ü –1Ƙ²eccCa±“6¤@<ÝmŒ1Ƥ‹´1Æ“R,ÒÆcLJ±HcŒ1)Å"m çyDÒV“.>þ¼¼¼üáǤ 1å€EÚ΋ˆ¤­0&]üñLjôï¿ÿž´!¦°HcŒ1)Å"mŒ1Ƥ‹´1Æ“R,ÒÆcLJ±HcŒ1)Å l˜Âqàwcr©­­õ«‰¦XØ“6ÆcRŠEÚcŒI)icŒ1&¥X¤1Ƙ”b‘6ÆcRŠEÚεˆ¤­0&]ìïï?þ|rr2iCL9`‘6ÆcRŠEÚcŒI)fbŒ1¦¬Øßß·ö#âáeº»»“¶ñ¬X¤1Æ”µµµ¯^½B›CN|åûµµµ¤ <žî6ÆSnœöà^SDÒÖ{Ò¦pž={–´ ƤŽ7n´¶¶Þ¼y3iC*šGáOÇiñúõë¤M;×¼F‚1Ƙòc~~¾««+žƒ]ZsÝ‹´1Ƙr¥®®.îL£Ð¥5×ñ=icŒ1åJüÎtÉÝö¤1Æ”-Á™ÞÛÛ«­­MÚœscOÚcLÙ"gZÏ‘%mK!Ø“6…£øñ(Ƙϟ?øðáæÍ›ßÿ}Ò¶˜ÌÆÆÆ½{÷vvvJT¤ý Ö©looùòEéwïÞ$mQêˆÇ0q¶+QWWW¢—S0üñÇòò2ß»E:%ܾ}»tÿ†élö÷÷GGGggg_jŒI ‹ôŸ Ï?&177çk¨):Íûûû¸Ô™èI{ÕÆ˜³à§»ÿôuÚÛÛñžKñ=wSB ÌŒq©ù™ÍÎÎ&mŽ1¦¨hOúè訫««ººzggÇ“Ûæj¸}ûöÖÖVccãòòòÔÔTÒæcRME¿‚ÕÙÙ‰BÏÌÌ$mˆ©8 ¶´´ ØøÖIÛbL9³±±3ÆgÒ†HåNw÷ôôÔÖÖZ¡M"TUU­­­!Õž÷6æR9<<¬©©Iڊ©Ðén®Œ›››y–CÙßßßÛÛ‹ç\¿~¿'iÃMY]__çÎ? aÌ%±¸¸XÒ/ÓV¢Hooo÷õõåN299™©cppp||%ÝÑB ;ØÏyô裙xx×¶¶¶fffòTHUxÚ/M-¾yó&=ß«ò7‘Ç 6}v²Î^@7Vø¼3Œ©(¸à—ôŸ«â<éÇÇWý&¯^½âS1(rÁ{;þW…(Êj)yž32± —Yܺu«¹¹9O ÀMüfCŠõQ\ã·#¾Yì›](b[§ÁE„aÄi¿1Srìïïs8×uÆ\ü1«««K:vPe‰´æ¢Ãâß$Ì”vwwŸ«¡·oßÖ××K°‘:löõõe311ѱ¸¸Èç½{÷–——)OzhhˆÏL$ÛÒÒByrd›R…öööééi6)Ãxbdd„œLC‡‡‡jK¡È»ººt8»d’4X×6³”ftt ŽëÇØØXèMcg& {IåTÛÙÙI7) üÝÝÝá E „é#g@¯­c§FTNš®qNd{õ¥Ð=âtQ=%A»Y_eÚÚÚ”Ï&e8\³Íᔲº@yΟá$¨5Í!”ÇŒQ~(@%ȼÚÂrµ¨„ èkÍÿƒá ë»0Æ.‰¥>ü­,‘æÊ~Ç. ±0—àóÄô ázýñãÇß~û«p\QÓ;wî`OSS"755õàÁƒ§OŸJYIÌÍÍQž_ÇÞ½{cjjjø¤fÊóãc/ÚÆ®ÞÞ^ #6&‡Ožä($!Tî3}˜1‘‰Æ KKKÎW€U:¥|§©.èœP¹[¨!N#õ#ðX—òÓO?)?àû✨­P›TˆÆóídÏrÁNÅEÜqcL.üåÏëb¥Ž¤çÛ¯äveeåìåõpšr¸.ç˺!šùzOZ÷ ã÷­ã7Goß¾pö÷÷sé§Z.ñzç8v5¾Ì™kkk˜D1 5øäXŠaakk«Ú%G»ÅoÃFcȧ’ãØb%øDÿõömV =ŽÝU•bQ˜JR³N a$»Ð-öªûÇ9÷¤³Z{;BgCûãuf"$Ÿbz\ ÷žtü[P§”@2ã§T]Pù¬W¡Î¬Dn~8-¡6%02Dƒ?>ýž´Œ¸øœF¹*]¼S0üø¼|ù²€ùS'm~ùÀŸ=Ïó(¥BeyÒ8g!•Âxcˆbp¾qï®_¿~íÚµs=áÜÖÖ&)Õ?0ä£Ð8X ¨¢Å1ýõWí ¯Þ#½zÌ+/N0Æ#Tø‚¸›¤$r ›===¸†:„Úpi1îýãµsài#JtÉÌÊ ¿o,_{i:ÜÊ¥­úúú/^ Ï´ÒÒÒ2<<œå”Ÿ¥Erð9] q·Ww6«NŸ8ŸtöÄ&T ÷›¢þø)ï:ã|I]]jwd¤îS„ŸJ&º_Ài _k~¸ ,..ž¥äiШ–qKà æ\ðçâÃOëÄ™'Sü t§,iC.Je‰tæëµû, CRèÜCâWço222Âoiç þ÷¿ÿ=äÏÏÏsUEc¨ ÅE¢ž>}š‰&™¤‰‰ þ±ÈúDZ\yÉÉD3ðš~§ G¡vÀBd˜OÍ–£Y¯ôܽ{—Ÿì»wïN|Ä É¿ÿ>­h7ÝmÕ´°6i%FoÏï¾ûNöô÷÷‡³$ÐéÇ“™G*ð€³ZN]æ´Ð.Í1¤¸AaêÔ éééé¸ýtÑ¥ Ve5æÑDn¤!¾Ð¬Sz^8 žø6úé'å`°Ô‘|=: /:ëkÍ_-}/øU1Î èì•è닪€pGÉ\.¸@õ¦…¤]ù«ƒ!êioRåáàà ¾yâtwõ¬¬¬p­ÿôé“–X ZÅâ e5feCBô‰¼ijúD²Ì(Œ,{8« è MØÆí¹Hå¹ésÕ™§³§U~šÙç:íüO[ºí‚½3áÿøÇÒÒÒï¿ÿž¿ØÜÜ\îäMü.)®ŠŒï‹_ü?ž*(âßYA³W¢à°PYõpaÅ×Äïám«Šˆ‹7”Õhøc‡„ ð‰E'†;UÍYfF–=ü%±òß /º5ì¹`å¹ésÕ™§³ï•ç‡OŸ÷´Ÿkvïü4ç» fùÊ€ÿþïÿ>m×iß^µHÚðRåíÛ·|¾|ù²è¯t&H‰tªà:Πauuµ®®®ˆÑF766ÂhW×½ 522âØ–Æ˜«§¦¦æÁƒ===å·ÂB-U¹½½ÝÖÖæç2Lj¹víÜÿGÝÂÏõÉ*ç]ºœøÝݹs§tU4—A=8ÆËÔÂź€¸H=ÚÛÛ /z™"|w%Ë\6$Òéá\‡g¢`X—4¼PT¬<í¥‰ü6ç>¬w®‚‡¡èi¡˜â‚åðH†††&&&.¾ÀÆ<2Íõºà‹5—ûµKuÉa©6ù©,‘Æ™Nü=)йtzssóË—/—aÌÖÖVžšãïG€„&²V掳¼¼œ»¼Xuuõõë×Ã[dcccX”ÝU@}ëêê”À„Þléíí=88˜žž¾HGN4²è¼{÷î‚£"ZR]~·åJ‹ÏŸ?ó›ùðáÃÙ RÍ/?ióMÊHúñò+e||\qEŠÚðÛo¿…Çý¹D†¨Rñ]ñt(Àß’Ìð&ù*–ÕDækð,>U˜V¿pˆªRNhzeeE…IçÖ¬ME ‹·%“TgøyPsÜÎ<]tww¿yó†CÕkii)Ï+Ô&³ƒ…T¥\­´ú–ÆÔ¦$Y FÅC¤e“krâkáì…¾„ ã»B:~ni…?ç+Ê;|ç ‡—‡²yù¤D)8âØq‘^’4åDe‰´f‹[!Z¢•§ÙlmmåR«Eâ»ôöW(&-‘§¨ ¡¤•Ï&þPsss¼‰4N¡BfR?Åøœœœ$G*Åf<|)5P†F¹îK½´6¶jMS ®¯Èj&šoÈ|}ò(×N©fV—óB=:DïOËT㔪ݺu‹LÜe-d©`™Áä\•ÈxÆUZiŽÈáàà`üääiàLrl|ìrì¬ Á.Ì1º°†]Yi}‰úr…Êg"H¦^ü‡TÄ_¦I‹ˆ´1YT–HGîà®]‰~ã_¥ùsö÷÷]‰ïRú81[²ª(Ù!_…ã­°9<<,¿1PkjC®äqÎÌÌd]âåí©Ln¬é èYѤŽûø«+v¢¹ýŽÈýdrBg£pÔ€Êò£Ï¸HË¥5H©>ކ¹r˜_¤A±b|ÄûH%´…ý ü"c4ËßÒ2RÃ…ð+¼©[‘Ì/òCâÌ}ŽÇ$…EÚ‘ʺ' ¯_¿~üøq±jãªä/.. „ÛÌdJ§ÙµººÊ.ùsJÇ×c>ú &øüÈû÷ï#„ªFó|HÚSøénS8Š8æŸ1qÔ{ÒÆcLJ±HcŒ1)Å"mŒ1Ƥ‹´1Æ“R,ÒÆcLJñÓÝÆcLJ±'mŒ1Ƥ‹´1Æ“R,ÒÆcLJ±HcŒ1)Å"mŒ1Ƥ‹´)œkI[aLºØßßþüùäädÒ†˜rÀ"mŒ1Ƥ‹´1Æ“R,ÒÆcLJ±HcŒ1)åÿ±)¾)WäIEND®B`‚gateway-1.4.5/doc/wtls/fig3o.png0000644000175000017500000002261707374232663015163 0ustar toljtolj‰PNG  IHDRH { ºtIMEÑ 84æà pHYsÊ&ó?gAMA± üa%IDATxÚíÝOlçÇñ5Jä$ÃÅ>ìôൔ‹ª˜pŽheÒƒ}H°’’ƒ7Rˆ?l©ÄV¨H*e÷ˆJŠ“ƒ}(8JT’ሊ Tòúl‰*ÀÁ¾$ RÜ_æ)Óaýß»ö;ûÎ÷sXÍÎμûîûÎû>ï;3»[111‘,¹t:Ý××§G×ñÍ2× ”l¯Ø^!°¼B`x…Ànd2™šš×¹ðP·û|ÂŒ àÀ+6€Wl¯ØÀ\.766æ:"°€ÙlvttÔu.…7õž¯½öš¾øâ‹Ë—/oÙ²¥`ƒ{÷îMþ×Ý)W¢´¯j6mÚôÊ+¯<ùä“ išy|õÕWj®?n9QT[·n4æ˜rƒ‡ªxg^3¥^xÁTévÓ kAÛTÂÑW£>ÇŸ¡í,A7øËŒ­¡¡¡¢¢¢±±Qª¥¥Å^PdRÚµk—‚“]r OQ }öÙgšÛi䫈¥©ÞÚµk«ÔžëëëÕÞ´»’R¨Sš{÷îUlѣюÚXé(LzÖ¨Ê5ÿË_þòàÁƒ°Q™[·n©×ûýï¯Ð~ìØ1[©‘þ¶mÛ´R/iƒpcuŽÚ,ºEŠVÍË/¿}©ÈªyöÙg­«eêQ“BןµÌܾ}[=ÉÙ³g šŒhÞ ÒVEhXle®zÔ´x[ : Ózm3yž¡ÑÆ©S§4”)¨tPùŸ \»vM*d­TákAmmmZ¯5*s+|5¥RÓä[mG›tbzjÍJij´a+Õ¦leXËÑõ ë lšcõõõ ^¹rES({AÑHOÛÛÛ׬YsòäÉ‚Ýþö·¿ÙìM/ ~7oÞ¬yXgg§–?n?€¦¤ÉÀêêê4TT‚ÚÑÞW»¸®ÐRR¼þúëgΜÑÐ#zJJËZ¯Ñßÿþ÷#GލFÕª)j ~ð¯ýk´Õ]¼xQíóСCÏ<óŒëähÕD¯”°jÔ5(Â…Ã^Ì‘úÊ®®. V¯^(¨"ðŽ=ªªQ÷òÖ[oéÕ÷ß_Õ”¢Öz»ªª)H\õ«‰ ê%ž'E4gˆÉTR±ÿB àò˜ÊMå¯ùÜŸÿüg=UnÕ(Ôuþù糺(Q´WMMj-\imMÍêË/¿T Zýj¥Ú”µµèõ,E5­W€XX7øË©H;»Xð‚Â’¢ô¬wìL®³§žzÊ–•{Û@QP!pM`IªÉ µ4Uê[CµUÍèm½*O+U«V­Rì×Ñó¯ýK]­VîÛ·O+Ã&ª-U—Z9yôŠb̽j†††P5 –·MîX1+Õ‹ ÙFÿù϶oßnë5ŒØ´i“ݰ¦>JSm£•/½ô’I®¯¯·^X£KgrâJùüùóvÿH ï}Ëf³6+p‘ÔŸþô§ðPÞ»ñÜsÏYÓ°Å~ø¡jáßÿþ·È s)µí¥æÞ$šóY³Ò8C ~úé§áÉgµ¬è P­I/i÷WÙ´ßcëîî>wîœÊÝæpwïÞ9! `ŠÀ:†4]ÓTïàÁƒŠ—k×®½zõªžÚ´Okùì«Jsdd$&–R ©í¥‚–]o§ªdttTÛ¨ GWT8ªòFCX°¹Tç[56ÃS#d8²`˜«x5o×DçXÑ2ŸÜc´¶¶ªâ ¦Qªš)ïôÆ|iP¨!‚‚ñ\6¶2ë±à{jeË—/·Ú,hkŠp:t0,¸œ6°µ´´()é~4ßš!Å-=VTTôôô(ži~VWW§y›žê³é¨Ú°ûDôT#m£…7Î2ˈÐWÅkt©>4ìæž h.¯Ù€Æõz|ùå—íÚL¸Ò†?ZcO^‰m%´¨U£¨¦5jv•Âõg-3vuGe¨rŽö˜¯¾úê7ß|£±²jáĉª&•ðŽ;¢+mKÕ¦æªÙ¯¾ú*šòž={Ô+q­×äÏõõJ^¥mÇÿíÛ·§ÛL/©‚4™ ¯@§‚«ÑªÄcÇŽibÍêí·ßVjÚ º2õ¨­)…wƒOLLL¬ oS¼sçN8]«ªª² cîÒÐBmm­˜m– ŽTÅðrÝýû÷mAk†‡‡mùÿøGt¬^½Z.\°ægwÊi¥¦äVOvÊXã—£GÚ;\©„*ØR°UåZ¯-£o=3†¹‹Vâ–&m%¬ušÕÂY Ý~‰YÙÙ'»+A!M«¾O]›ä6øøøãU¼Ï=÷ܻᆱ§jVzT©}ÕÊÂóW¶±æÓê:ëëë-}¥©Ú¹~ýºêT‰»þ¸1ee½ÑQíÂx­×r¸Þxã  TÎ*ÛÝ»wôHö½9TkªÍ?þñ© †mM±ÿ~µµ?üP¤‚ó±ï¿ÿ¾V†m-ºñänp.*&¶äà«fFYÜîå£jLܪæFÀu.bAõRü )êÊûúú&ßâ°0—/_.8§—XüV$À+OŸ`|úyŠXaÆð àÀ+6€Wl¯ØÀ û½x×¹ð àÀ+6€Wl¯Ø^!°€™L¦àï7Qü2¸þÉ%J+ÑÿÇVä544 ºþ%°lÙ²§Ÿ~Úu.SüßJår¹Tùwq«š‡>xð $I•{óQ½¨v\çâ1?ýôÓÏ?ÿ\’¤Ê½ù$zÆVäÿÞ¸q£øÄ”Š/X TPi=(IR4Ÿ’+á¨Ü›O¼F‰Àð ÜÈårccc®sá!¸‘ÍfGGG]çÂC6€Wl¯Ø^!°¼B`x%Ñ¿<åóy×Yð36€Wl¯Ø^!°¼B`x…Àn¤ÓinŒ\ 6€Wl¯Ø^!°¼B`x…Ànd2™šš×¹ð?‚ nttt¸Î‚Ÿ˜±¼B`x…Àð ฑË寯Æ\çÂC6p#›ÍŽŽŽºÎ…‡l¯Ø^!°¼B`x…À†9éíí½zõªë\:xð 7•™ÎÎÎññq×¹(\Í—¯‡Y<uIØ0'ÃÃÃXµ„ššš¶¶6/ûyéêêZ¹reÜIø ©©©\šÏt‡™Ê¶¾¾~ÖÝëêê´ñ‚ó©#y‘¾Ä=e£–#GŽÄ¡ù#Ñm`` §§G3q|éÍçósßÝy`SnÕy-Á{¦|Iviò0™º›ÎjŸn[f:VöŠéÔænhhhº—T;K“‡yåJÊ¥ùÌp˜UfÞ]ýL1 D±'›Í.F ÌШS1h>E™H0µv1ƒhø6¯Ý—žò¬`¼4北|òÁ£ÔzMJ\•À”ãeu4ÇפMys•±0{ª£¥y¯)[·æFW®\qX3䪌šÏt‡Y__ŸÛP¤ušO1}M£°ÖÖÖô#®¦åÈZµBšÆt®fÓåjtttÏž=ñÉ•:°UŠŠ"®ó÷\Í—f}âO«ۙ×Y¢EÏF½0O¸Î€K:@7nܸsçN{ZSSÃ?µÏJG¿¦¹¯«MIUyâĉ²î.KEU£ šõü¹Z_³x6êb$:°Ù·7ºººìi}}=mvÍ_C×yŒZcww7³m»e&“ÉÄ*xÄ3W àëaÏF]¼D¶‰ß83_---1¼’|éÒ%‡·üÅJ>Ÿa·Ï\Í×É“'ýëúSqmÔ%‘ôkluuuöövϾ˜RZñ<ýBT Å3~Ä3WóåeTKŵQ—D¢[[[›/^¼Ø××wîܹîîn×9+ѧ"Òl8–Ïçs¹œ¯s1”Édjjj\çÂC‰l²fÍ[X¹råÝ»w]g@‚p·Ú"It`kiiioo?}úôÍ›7»»»Ãûþå+Ñ­¯¯/N755iYQm‘~·°”Ø*++‡‡‡—ì×üK ‰mdddË–- iw»ÖÕÕ={ÖuîEIb`«ªªjnnÖ,­à'd¸= ÀRÊårê…ÊýgYb(‰ßcÓatòäI[Îd2»wïöööºÎ€Éf³‹ô_k —ÄÀêêê *›âó3Û€Kâ©HÑülëÖ­©à¿qíΑ±±±ææf×ù+¡­ªªÊîõW0³Ü---ÿr$GB[*øyÖ³gÏ*ÂÙOjüøÍVH²D_ckooÿöÛom9›ÍjÒæ:G€b%:°mÛ¶Í–ÓéôÐÐëH|>¯žÇu.<”èÀVYYyèСññqE¸\.Ç56ð@r¯±¥‚ߊlkk{ê©§RA»xñâÌÛ÷ööüg[t´•Íf·lÙâú3%Zccãýû÷mYƒ=ö÷÷ÛÓšššóçÏ»Î`¢ÍÜ|<ȯ»µuëÖðëOÍGä•+W\gp>&’Mýààà Bšæ²ñt¿*Y]]½ô™WÎëëë”Z\9rdºã\ƒ˜¥ÏjGuäºTb„ægj#±j>ÅHô©H¹yóæ—_~iŸËåfÞXÍòÀS¾Ä?ÄFýSvê7 ~> NÐ|âlº÷*Çæ“èÀÖÔÔTWWwòäÉþ€ÂÛ¬»LÙu–cÅ{iº‘ýfLÐ|bN4ye96ŸD¶K—.]¹r%ÿÈ\~ÚÊ®³+ÞW“»NúÍø ùH§Ó±ú%¿ŽŽ?šO¢[mmíwß}7ß½ ºÎ2­x_Mî:“ÜoÆÍ'μi>‰l###»wï®xdŽ_()¨û2­xE»Nú͸¡ùÄœÍ'Ñ·ûÜD7÷ÿcSÝ÷ôôŒ¯_¿¾L+ÞcÖuvuu¥è7c)l>åÛozÌæ“è[ëãæþëþá¨óĉ®?¦`£N†ñ6Ÿðo+Ö|ÊzØ‘è[CCCôi}}ýÜ/äªî5¨áÇJâIͲ£££ªªÊuF05k>ü:kŸçbx Ñרš››ÞV®\ÙØØØÓÓã:G€b%:°)¤µ´´¤/^ä¶,%õ<ܹØjkkíô£¢Z?ÌHt`ÓX©µµU•••.\Èd2®s(V¢›âÙÉ“'m¢öÁpN<èÀ–Ëåêêê*MMM½½½®s(Vo÷íÝ»÷øñãçÎkmm½{÷îðð°ëŠ•èÛøøøæÍ›9òÑGÕÖÖêÑuŽ$H&“áw!C¢gl;wîܱc‡&jkÖ¬yñÅùiK‰>g‘$:°>}:\Èf³UUU®s(V[ø#Èødð@Ò¯± éÑuF%“Ä[ø}5-444h–6Ý.þˆÊ1w÷î]×YÀ´h>¾JôŒ­ÜuuuŒŒŒ¹Î¦ zzë­·\gS³æsõêU‡yÈår´ßÅ@`+Wjýýý©àŽa×yÁ¬^ÔoÒsÅPØ|ÜŽ<²Ùìèè¨ëÂð­\…ñLí“®3nÂ~3ÅÈ#–ÂJ¹téÍÇ?I¼Æ^Q³3ì;v쨬¬L•Õ]‘Ñ~3´Ò¾¾>×™ÂÿEƒ™<ª««]g ÿCóñ^¢glŠgõõõÕÊKÁ$€I[¬ô›)&m1Cóñ^glåþ+þ“ûÍ£Î8™Ƙ´ÅÍ' =c+SSÿÕV¹w9¦ì7SLÚbcºæÃ¤Í'¶23]¿)ÝÝÝ®s‡iØÀÀ#çâÖ|òù|ù~‰6Îlef†OO]§[3ô›ªFÎÍÐ|r¹ÍǶ2Ó××7ñÈàà`}}}øôþýûåx#ŒOª««'"T;ª£ðigg§ë &Í'!l¯Ø^!°¼B`7Òét¹­6žl¯Ø^!°¼B`x…Àð ÜÈd2555®sá¡$þm ÄAGG‡ë,ø‰À+6€Wl¯Ø^!°€¹\nllÌu.Ÿw?1cx…Àð àÀ+6€WlàF:æÆÈÅ@`x…Àð à•DÿòÈ©S§œ§PŒ[·nýøãÅçaÕªU/½ô’Ã2YñêÚµk%I§ª3gÎ\¾|yÁ)Ä­j®J•ZY7Õ‹jÇaþ'Ëår¥úw· .è±³³ÓõgZ Š‰‰ ×ypfË–-®³ ëÖ­sÛÅLFÕ˜¸UÍ©€ë\Ä‚ÊAµSd"étº¯¯O%É’Òr]0±À©Hp#“ÉÔÔԸ΅‡}*êèèp?1cx…Àð àÀ+6p#—˹΅‡làF6›-ÕWªE`x…Àð àÀ+6€Wø­Hp#ŸÏ»Î‚ŸžK¶¦¦¦ººÚu~bmݺu?\gÿóÌ3Ϭ^½úúõës©”U7n¸Îu"¨¨Ÿ}öÙk×®=|øpæ-U‰÷îÝ£Y-¶ÊÊÊÚÚÚðéX`^ûŽŒŒŒ»þs²¬á¶ŠŠ =*÷öZOOÏ×_í:‡1rêÔ©ùþëã¾}ûJûo„¯¼òÊóÏ?ïº$bAeûÉ'Ÿ;vìÌ™3›6mšu{Õ]Á‰©j”His•ÉdÔS».Ç4T¥¨j¾øâ ±3o|ôèÑ‚f¥#|Ö½æe1*ºì(2å#:::¶lÙràÀ¹ï‹ròäÉÒÎ…ZZZvîÜY’¤~¹ÆväÈ‘‰ÀèèèÚµkëêê,’+ª}ûí· K÷êÕ«%üÀeaò¿>ùä“Z¹bÅ [.&Âiðk jó¥ú[Âr÷«_ýJÝŸúD öö÷j–*LUM*˜7“™°‚êëë‹ÿÿÉr§QÕ¨ßüæ›oÞxã +á¹S¥¨Ãåg#¬SµÁ°¢NåPèêêúío[Ì?újwÅ‹T0Ÿ+&ÂmܸÑš››Ãå"=vóˆ2wñâE=îØ±#|+~×®]á«ç-æéñܹsáÜ.D²ð¬f{{ûG}¤§å2o]5›°Õ½ð ‡R^>ìììÔpA[ö÷÷kã°ËÓBØÒô¨§j{6l;ÙpY>ü»ßýNÛhÍûï¿ÿùçŸÛz½—6 ÓŒ¦·?­_ o¿ýö­[·Ô‡~õÕWöoúÔVÑÒ Ësr™Ü¸qC¤jÒö‡ÈÖZIT%k;Ú«a±Ÿ8q"¬ MS†`ïv¯ÓeÏ?ªU•p*h“òÔã­ JGx.—ÓÂk¯½mVü3Ø¨ÂÆ‘aiGëTmÐ*:ú¾áñ¦ÖoB¨—Îd2©`B¦n_ƒ‰0®(VEŸN©­­M‡º¶Ô£¶ Ç"JM!* uZ¯m´­±WµÆ^ÕíôéÓÚF¯Øz=µ4Ã-µ\UU¥•Ç)Þ<¢TôNvTibØÚÚzðàÁ­[·þðÃ7oÞÔ›éøX³f>’RWxÓ6š666j½«}€ÞÞÞTð3hƒƒƒ¾N/Ôä4&µ u8 ÎUšp3-«ÿUg§VwôèQ­ÑIýàòåË­?ÕTC ÚL]€¶Qýý÷ßk½º5?ÅKí®ÇTp&Moªò×LÚ’ÕuÚåÞ½{zI U뵬zѾ¶¥ërZDú¤¶ÐÔÔ¤B ‹(,›Ì©jT€*(›:GYßg§(UøV šah¢DT/*R5ÛÌRP‚zÉúD=µ}­oµwÕ²V*AåäúõëJÖ6P²J*ÌžëR\DV2:øÃ¢V¨¢Ó«RÕS À;ªdÔL´±† ©GÍJe¨CZÛÛ…RÿjPZ¶júç?ÿù›ßüÆ^Õ@ç“O>‰Ö©vÔ‚Ò´6¢÷µ–{æÌ•Ž]ç«S×%·ˆîß¿Ÿ úgõ窈†††³gÏjîeóááa5(õçwïÞU—®Çººº)“R©{W‚ŠJAk4<þ¼VÚÉ?›ð¨AY`Ó›*¾èUm£zïîî¶¹“¶Q)3ZV~8 —4qR¬Q´¯–µ–Õ´µRQé½÷Þ›ácNq»¿>Lt¦¥ÎQ)êÓj2— þòu÷îÝŠgZ©£˜¯wR)èchÍ¥K—çZíô¦¯Q- úT=ï¨Óüæ›o¬ý¨å\ÅI£Wuj© j•‰ú;í¨§j‡jŸ¶™F©Š”ûöí»víš*X¯jGµ1õ JÙšexãƒÚ¡^Ò¡ ]”µÆ0­Ô¾ª‹bN2”kúé§á•‰Å•Œ^Ò£”z±)SP9«Lcí¨‚UyZ"ÑnîwÞQ½¨TCЫªAõ’Jß®T–UË–ˆRв5Z +ׯ+Þ‹Æ u&v볫ô¶oßn­`ÊíÈ›•z54m¯’þùçmf¦ ²òÔ0ÂŽ|*1X£³: Ó´Á¥Þ]ÙÈf³ÚÒÒQ[V:û÷ï·:]²ÂQo°Ä7Fž;w®?044]¯Ùˆ"ÊÖfiŠŠg*=›ÌÍ …=;鵋RPpÒ}ðÁ¶&E /¾ø¢âœôª•…;h§FmcÍŽÕöîÝ«”Ÿzê)­Ñ”Î^Ò„J+Jm¢9ƒ)n÷ÿì³Ï¢3P%¤8ÙPÌKç!u€ZÐR Ó«Šg逖²’RûQÃÐñ1CËœ’îÐîö4³_¾|YŠjªæM›6©™­L™ÈêÕ«õ¨vnOµWx~ÆÎ+µ$6 Éß}÷] ¢H=*R›`Ô\X¹ÙE‰„篬Ò¼A]­jÇ&ÓQTuhøo†—Ó«Ëž§«\oØHNñ& áA®q˜ŠqÖ&£”ˆJÌê%@X Û£RS§ÙÆ §yÕwk>gË_|ñ…¶·,¿Ï«× CÚæÍ›Ãõö[Ìa”UðÐäÄâÇܯŸY³Ù[êQ_” n3IÚT0°Û³gf]Ó%bgÕµ†V”µeÍ ,“á0q:ÍØ4QkooWP #­½ÍñãÇ•´fi·ô9íDY¸sçŽÅ6ÛKÑniëk©©hÐ×××§Áþ¬-!Ú€­M>|øµ€æ«Ík°i•àíÛ·õÞ h§¼\‰b§‚¡ýtXAÍ:Ïj¦u¾ª« ° år9Í¢ó€É´ªCU^RUA: í³O×'ª›ËÄ(Z/·¯=Rð£øvŽñûï¿·‹¡‚¶©½Â‰² 1ç\“C»¦Vó§‚¶cwÚÛ½Q iš~mݺնLM),†¡ËBÒ|óÿËŒM Õ£"¹¦zãõë×G7Òݹ¹yÛ¶mv˜*ü*ÇôËàà`cc£œ´›d4ÁT ÔTTã£óçÏ;©˜Å¦q„]ÓÐ[mC½¡]_ÑÓð¬`Èîq8zô¨ÝN¢§Ú]kÔõ¨5Ñm¢öæ›oªåÛ)ÍHôTí0œÞ)u¸–”]¢Ð0 7ŒD½H= N> l¥ù(ž¡|Μ9£Á©´“‡ÚÅ.‚jeÁ¥ÊåË—Û%ÌTpÚSÕª¡] £ vÑ[+Y»ÆfË¥½…=Î4äR1†×mÂÝ@¥ªSqé¥"œú%*kVê¦ìRY*˜GÆnikkK}ë‰'ìêµ=Ú6JMiê}í›ZÖ¼N·$Ц4vP¹BÀ [ŽŒŒè€W‘ªðµ ›–Õ/éQá-º¥¥fç9µã{ï½§wQ §wZPEk6¥&i;EŸùfþ Í7mÉn±~M[éj椊vŠ™ ³UUUš´)†)Ç ¹ ]ZÖŽ÷ïß·+{6UX¶m&_.kjê%mYíÊîò²`£o—RlŠÝÅ6ЫŠLª35$upÚ׌êïìK´¢”Žº½—VªÕ/^¼hQP{ÙØ_ý©Æ§6“S7aÏ0Û×u-.]Ñ`fU®± ’ fÀêššš&ŸúSÙövANÃU–톻f¦†j³p/µ « UºMïÔµF;*Au¯–“ðr¦ÊŒ^µ[=/éÓ©Üì·A³uxLª4T8j6'›• ^%¢e»—J ÇêEÉj$¡Ò‹^4ÕvMTñlûöívC€¬NUVòÚL‰Øe?Õ £Ž¦ͤg,`D¿”}áÂ{ªAƒŸ´mRÁ-øêÌUþP NÞ7ö¶F[jû;wî(P)L("ªÿ·d£›¥‚©ÔÔ§)e­T± [šJi9 `]]]ß}÷ݯýëTpñÏn¿ÓQ¶ &“ULLL̼…b¬ÅÏññqu% Z³&Z.’pj.Ô¿L9Ýqˆª1q«š‚›~“̾KPd"šôõõ•ê&;¥SpKHbÍþ[‘ c¢jr¦À¦9Y{{»ë<€ÔµzvZ+&fl»víÚ¹sçÕ«W«ªª<¾}–ØÂ~1³šÓ¯ûÛ×®]g€Ùñl¯Ø^!°¼B`7r¹ÜÜÿísG`7²ÙlÁoƒ¡$l¯Ø^!°¼B`x…ÀðÊœ~R Prá?V£´˜±¼2ûÿ±PF˜±¼B`x…Àð ÜH§Óܹl¯Ø^!°¼B`x…Àð ÜÈd2555®sá!~R àfl¯Ø^!°¼B`x…Ànär¹±±1×¹ð ÜÈf³£££®sá!À+6€Wl¯Ø^!°¼ò_¬“½qUvIEND®B`‚gateway-1.4.5/doc/CodingStyle0000644000175000017500000003034211775124034014606 0ustar toljtoljCoding Style for Kannel Code formatting Don't make lines that are longer than 78 characters. Follow the coding style defined by the astyle program: astyle --style=linux --pad-oper -m0 -s4 Tabs are 8 characters. Indents are 4. Example: /* * This function doesn't do anything sensible. It just uses uses various * C constructs to show their layout. */ int foo(int bar) { static int tab[2][12] = { { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, }; struct yow { int plim; } barbar; int i; assert(bar != 0); if (bar < 0) { for (i = 0; i > bar; --i) { while (global_variable < 0) { global_variable += i; printf("%d\n", i); } } } else { do { --bar; switch (bar % 3) { case 0: printf("0\n"); break; case 1: printf("1\n"); /*FALLTHROUGH*/ case 2: printf("2\n"); break; default: assert(0); /* eeek! */ abort(); /* die, stupid program, die */ } } while (bar < 0 || global_variable == 42); } return bar; } It is OK to deviate from this style, if it makes the code clearer. Commenting Each source code file shall begin with a comment of the following format: /* * filename - one-line summary * * A summary of the purpose of the file and a summary * of the functions it exports. If the file is the main * program, a short usage summary or a reference to the * manual should be included. */ Each function should be preceded by a comment like the following: /* * One-sentence summary of what the function does. More * detailed description of what the function does, including * return value, purpose of each function, and a summary of * who takes care of allocating and freeing memory of the * arguments and return values. */ Similar comments for global variables, constants, and data types. Error handling Typically, functions should have a return type of int and return -1 for errors, 0 for OK (or 0 for no input, positive for indicating number of input items read, or similar values). When returning a pointer, errors should be indicated with NULL. When a problem is noticed, the lowest level that notices it should log it using one of the log functions in log.h, and then return an indication of failure (unless it can handle the problem itself) to its caller. If the problem is associated with a system error, i.e., the global variable `errno' details the problem, it is the lowest level that should pass `errno' to the log message function. The callers should just report which operation failed, but not report a system error (i.e., they should pass `0' to the log message functions). This way, an error causes several lines of output to the logs, and it essentially produces a stack dump. This helps diagnose the problem, since it becomes more clear which parts of the system were involved in the operation that failed. If you want to incorporate the name of the function in the output, use __func__, not __FUNCTION__. The former is part of the language starting with the 1999 version, and config.h takes care of defining it somehow for older compilers. Memory allocation Never use malloc, calloc, realloc, or free. Use gw_malloc, gw_realloc, and gw_free instead. Do not allocate large arrays on the stack, because there are systems where the stack space per thread is quite limited. If you call a function and give it a pointer, and the function stores it somewhere for later use, and the caller still uses the pointed area for something, the called function should make sure it makes a copy of whatever the pointer points at. This makes it easier for the caller to know when it can free the area. Log messages The logging functions in log.h shall be used, not printf. Note that panic must never be used after the gateway has been started, except when an error really, really, REALLY cannot be handled and recovered from. For example, if memory allocations fail, there is little or nothing useful the gateway can do and therefore _for_the_gateway_ it is OK to panic. (This is not a general rule of software engineering, but it does apply to us.) You almost certainly want to discuss things on the devel list before adding a call to panic. Log messages shall consist of complete sentences: start with an upper case letter and end in a period (or other suitable punctuation character). Error messages (functions warning, error, panic) should indicate the operation that was being performed, and the (presumed) cause of the problem. For example: Reading configuration file smsgateway.conf: out of memory. System error 42: Not enough space. Couldn't read configuration file `smsgateway.conf'. System error 42: Not enough space. Informational messages (function info) probably shouldn't report system errors. Filenames should be given `quoted' so that it is clear what is and what is not part of the name. Similarly for other data that may need it. Open question: The name of the function or source code module isn't very informational for people just using the gateway, although they can be useful for debugging the gateway. People debugging the gateway would probably like the source file, line number, and possibly function name be reported systematically. What to do? Log message at the `debug' level: naming convention for `place' The debug() function's first argument is called `place'. It tells the logical place where call is made from. This is not the same as the source file and line; those change too often for them to be useful. Instead, it is meant to identify the subsystem and subsubsystem (and, if necessary, subsubsubsystem). The following subsystems should be used: wap WAP Box wap.wsp WSP implementation wap.wsp.http WSP implementation wap.wtp WTP implementation wap.wtp.timer WTP timers wap.wtp.tid WTP tid validation wap.wml WML encoder bb Bearer box: misc stuff bb.udp BB UDP sender/receiver bb.boxc BB box connections bb.http HTTP admin things bb.thread Thread handling bb.sms SMS related stuff bb.sms.cimd CIMD implementation bb.sms.cimd2 CIMD 2 implementation bb.sms.emi EMI/UCP implementation bb.sms.smpp SMPP implementation bb.sms.sema SEMA/SMS2000 implementation sms SMS box gw Misc stuff used by all boxes gw.msg Inter-box messages gwlib Library functions gwlib.http HTTP implementation gwlib.octstr Octet strings test Test programs test.fakewap test.udp_send util Utility programs If you need more subsystems, please add them here as well. Debugging places can be set via '-D' (or --debug) command line option, with format like "wap.* bb.csdr" (see gwlib/log.h). Any places need to be excluded from the set are marked with preceding '-', like "wap.* -wap.wsp.*" Using integer types Avoid the uint32_t type, and similar types with other names, and try to live with: int (-32000 to 32000) long (-2 000 000 000 to 2 000 000 000) unsigned long (0 to 4 000 000 000) unsigned char (0 to 255) The ranges given are _minimum_ ranges. Do not assume that there ever exists an integer type of a specific size. If you think you need one of a specific size, think again. If that doesn't help, discuss things on devel@kannel.org. The exception to this is that it is probably safe to assume char is 8 bits. Do not assume a plain `char' type is signed or unsigned - always use unsigned chars. However, remember that it is almost always smarter to use an `int' for a char (and store non-negative values) instead of an unsigned char, because of the complicated type promotion rules in C, when dealing with a single character. When using an array ("string"), use unsigned char as the element type. However, remember to use Octstr whenever possible. Some library functions require the use of a specific integer type. In that case, use that. #include directives When referring to header files that are not part of Kannel, use the syntax. When referring to header files that are part of Kannel, use the "foo.h" syntax. Since Kannel source code is spread over several directories, use the following rules to construct the actual filename: if foo.c includes foo.h and they are both in the same directory, use "foo.h" if foo.c includes, for example, gwlib.h, and foo.c is not in the same directory as gwlib.h, the path relative to the root of the Kannel source tree should be given, thus "gwlib/gwlib.h". Header files When writing header files for Kannel, write them so that they include whatever other header files they need, rather than relying on the caller to do that. An exception can be made for header files that are not normally included directly by a source file, but bundled by another header file (such as gwlib.h). This will result in some header files being included multiple times by a source file. Deal with that by using this construct, where HEADERNAME is the filename of the header file: #ifndef HEADERNAME_H #define HEADERNAME_H ... the body of the header file #endif If your code is not in gwlib, #include "gwlib/gwlib.h", but nothing else from gwlib. Use of #if, #ifdef, etc Try to avoid using the various forms of #if for portability purposes. It's preferable to write the code so that it works everywhere, instead of having umpteen versions for different platforms. Only having a single version makes it easier to test and debug things, for example. Don't comment things out with #if (or any other way either). We use CVS, it is always possible to go back. Don't add new features and make them conditionally compiled. Either add them completely, or don't add them at all. Typecasts Don't use them, unless you're really certain it's needed. Almost always when you think you need one, you are doing things that are too tricky and may become a portability problem in the future. A common exception are the braindead BSD socket functions: they have been designed so that typecasts are necessary. We try to make wrappers around such functions in gwlib, so that we have the cast only in one place. Abstract data types, constructors and destructors Use abstract data types whenever it makes sense. Avoid defining structures that are used directly in several modules - this is a maintenance headache. Instead, define an abstract data type, Foo, and functions to manipulate that data type, e.g., to access various fields of Foo. This is sort of a castrated version of object oriented programming. It's a good thing. Use the following naming convention: typedef struct Foo Foo; /* The abstract data type */ Foo *foo_create(void); /* Create a new Foo */ void foo_destroy(Foo *); /* Destroy a Foo */ void foo_destroy_item(void *); /* Wrapper, for list_destroy use */ ChangeLog We use the file called `ChangeLog' to log changes, not CVS commit entries. CVS entries are not usable by people who don't have CVS access (e.g., they are off-line at the moment, which happens often for laptop users), and are also harder to browse than a single file. When writing an entry, please try to make sure the entry is at least somewhat understandable without referring to the actual patch it reflects. This helps immensely those who want to follow Kannel development without having to wade through millions of lines of patches per year. CVS and tags We use CVS tags for releases. If the version number is X.Y.Z, then the corresponding tag is version_X_Y_Z. Stable branches are called stable_X_Y, where X.Y is the stable version that started the branch. If you want to use tags for other things, use some other naming scheme. For private use, prefix tags with your CVS login name. Initialization of automatic variables Try to avoid embedding initialization of automatic variables in their definitions, since they are easy to miss and this can lead to trouble. Also, it's too easy to mistakenly use an argument value before it has been checked with gw_assert. gateway-1.4.5/doc/dialup.txt0000644000175000017500000001137207157171327014466 0ustar toljtoljFrom: Roger Willcocks To: devel@wapgateway.org Subject: RE: WAPGateway Date: Mon, 17 Jan 2000 18:39:58 -0000 Here's a list of the changes I had to make to RedHat 6.1 'out of the box' to get the WAPGateway 0.2 up and running ... My modems serial line rate is fixed at 9600 baud. Install the mgetty package: rpm --install mgetty--RPM In /etc/inittab add a line: S0:2345:respawn:/sbin/mgetty ttyS0 -x 6 -D /dev/ttyS0 In kannel.conf add (the IP address is the address of the Linux box) wdp-udp = wap interface-name = 192.9.200.100 wap-service = "wsp/wtp" In kannel.wapconf change the heartbeat-frequency to the same as in kannel.conf heartbeat-freq = 5 --- XXX: sidenote 7.7.2000: In new Kannel (version 0.9.2 and up) configuration files are a bit different. Just use gw/wapkannel.conf for both the bearerbox and wapbox and you should do just fine (except that if the wdp-interface-name '*' does not work, replace it with actual IP of your Linux box) -- rpr@wapit.com --- Add /etc/ppp/options.server (first IP address is server address, 2nd is assigned phone address): -detach default-asyncmap modem crtscts lock +pap -chap proxyarp noauth passive 192.9.200.100:192.9.200.200 debug In /etc/mgetty+sendfax/login.config change about line fifty to say: /AutoPPP/ - - /usr/sbin/pppd 9600 file /etc/ppp/options.server in /etc/mgetty+sendfax/mgetty.config change the connect speed (was 38400): speed 9600 Add hello.wml in the root html directory of your http server (RedHat 6.1 supplies Apache)

Hello, this is a message from Roger's Linux WAP server :-)

In /etc/hosts add 'x' as an alias for the local server: 127.0.0.1 x localhost In /etc/syslog.conf add a line saying (to enable ppp debug messages): daemon.* /dev/console In /etc/ppp/pap-secrets add a line saying (ip address is phone's assigned address): wap * "" 192.9.200.200 --- Now configure your phone (mine is 7110) with homepage http:/x/hello.wml connection type continuous connection security off bearer data dial up number ip address 192.9.200.100 (or whatever) auth type normal data call type analogue data call speed 9600 username wap password -- Hope this helps, -- Roger ----------------------------------------------------------------------------- When you access a "web page" using a PC based browser, the "web server" tells your PC browser what kind of document it should expect. This is done by using something called MIME-types. The common MIME type for a plain HTML document is "text/html". However, for a WAP micro browser, which cannot read HTML, the MIME type has to be different. The MIME types for serving WML contents are: Document type MIME type Typical ext Plain WML documents text/vnd.wap.wml .wml Wireless Bitmap Images image/vnd.wap.wbmp .wbmp Compiled WML documents application/vnd.wap.wmlc .wmlc WMLScripts text/vnd.wap.wmlscript .wmls .wmls Compiled WML Scripts application/vnd.wap.wmlscriptc .wmlsc To add the above MIME types to the Apache HTTP server, here's what you do: Edit the srm.conf file (usually in /etc/httpd/conf) Locate the AddType section, and add the following section to the file: # MIME Types for WAP AddType text/vnd.wap.wml .wml AddType image/vnd.wap.wbmp .wbmp AddType application/vnd.wap.wmlc .wmlc AddType text/vnd.wap.wmlscript .wmls AddType application/vnd.wap.wmlscriptc .wmlsc Save the file and restart the Apache HTTPd. ------------------------------------------------------------------------------ Date: Mon, 3 Jul 2000 09:33:16 +0200 From: Wutke Matthias To: devel@kannel.org Subject: kannel working with S35i The new version kannel 0.10 works really fine with the Siemens S35i. The preferences for the Gateway can be found in the menu internet -> profiles -> -> preferences They are to be configured as written below: Profile: Name of your profile Dial Number: Phone number for connecting with your provider (Server) Connection Type: Analogue or ISDN (has no effect) User: Registered user at the provider Passwd: Password of user IP: IP-Address of the Provider's Gateway Port: Port, which the Gateway listens to (e.g. 9201 for wsp/wtp protocol) Startpage: Homepage of your Provider or any other wml-page Cancel Time: Time in seconds, after which the connection is closed gateway-1.4.5/doc/ChangeLog-1.1.20000644000175000017500000002476607525470177014675 0ustar toljtolj2001-02-26 Richard Braakman * Making release 1.1.2. 2001-02-23 Peter Grönholm * userguide: Wrote section "Setting up a dial-up line" 2001-02-21 Richard Braakman * gw/wap-appl.c: Suppress server-generated error pages if they are in a format (i.e. text/html) that the client does not accept. 2001-02-21 Richard Braakman * gw/wap-appl.c: When suppressing an HTTP result body because it is too long for the client, also adjust the Content-Length header. 2001-02-21 Tuomas Luttinen * gw/wml_compiler.c (set_charset): The function uses now charset_to_utf8 function to convert the WML document into the UTF-8 charset before feeding it to the libxml parser. * gwlib/charset.[ch]: Added the functions charset_to_utf8 and charset_from_utf8. These are frontend for the libxml character set converion funtions. 2001-02-20 Peter Grönholm * userguide: Updated section "Installing Kannel from RPM packages" 2001-02-20 Richard Braakman * userguide: Explained more about syslog-level. 2001-02-16 Richard Braakman * gw/smsbox.c: Fix a potential buffer overflow in sms_split(), by removing the partlist array and using List directly. * gw/urltrans.c: Fix memory leak: destroy_onetrans also destroys "header" and "footer". * gw/urltrans.c: Warn if a service configures prefix or suffix when they will not be used. * userguide: Describe when prefix and suffix are used. * userguide: Improve description of "omit-empty". (Suggested by Gildas Perrot.) 2001-02-16 Richard Braakman * gw/bb_smscconn.c, gw/urltrans.c: Deal with cfg_get_multi_group() possibly being NULL. * gw/bb_smscconn_p.h: Add #include "smscconn.h" so that it doesn't depend on the caller having included that file already. 2001-02-15 Lars Wirzenius * gw/smpp_pdu.def, gw/smsc_smpp.c: Implemented the enquire_link PDU and the corresponding enquire_link_resp PDU. This should keep Kannel connected to an SMPP SMS center even when the connection is otherwise idle. * test/drive_smpp.c: Cleaned up shutdown. 2001-02-15 Tuomas Luttinen * gw/wml_compiler.c (set_charset): bug reported by Aymerick Jéhanne fixed so no more 2*encoding in the XML-header. 2001-02-15 Richard Braakman * gw/smsc_at.c: Corrected timestamp calculation. mktime() uses local time, and it got a GMT time. Converted to use date_convert_universal() from gwlib/date.c instead. (There is no function in the C library for this task.) It probably still doesn't work for negative timezones, I'll have to check the specs for that. * gwlib/date.[ch]: Make date_convert_universal() a public function. 2001-02-14 Lars Wirzenius * gwlib/octstr.[ch]: Changed the octstr_create_urlcoded to be similar in name and usage to octstr_url_decode. * gw/bb_store.c, gw/smsc_fake.c, gw/urltrans.c: Changed the places where the function is called. 2001-02-14 Lars Wirzenius * gw/urltrans.c, doc/userguide/userguide.xml: Restored the meaning of %a in sms-service, implemented and documented %b to support binary data. 2001-02-14 Lars Wirzenius * gw/smsbox.c, doc/userguide/userguide.xml: Implemented X-Kannel-UDH header in responses to keyword fetches. 2001-02-13 Uoti Urpala * gw/smsc.c: Fixed octstr_get_cstr(NULL) when username, password or allow_ip wasn't specified in emi_ip smsc group. This bug probably appeared when smsc.c was converted to use cfg.c. 2001-02-13 Richard Braakman * gw/wml_definitions.h: Applied patch from Aymerick Jéhanne to correct encodings for "ordered true" and "ordered false". 2001-02-12 Kalle Marjola * gw/bb_smscconn.c, gw/bb_boxc.c, gw/bearerbox.h: Modified so that SMS messages from smsbox are directly put into corresponding SMS centers, or if not able, either rejected (i.e. discarded right now) or put to outgoing_sms queue which acts like delayed list * gw/bb_smscconn_cb.h: added new callback, smscconn_connected, which is called when status changes to ACTIVE, and makes bearerbox trying to empty outgoing_sms queue * gw/smsc_wrapper.c, gw/smsc_fake.c: modified to call that new callback 2001-02-12 Lars Wirzenius * Makefile.in: Moved -I. to before other -I options (before @CFLAGS@) so that Kannel's config.h is found before any config.h that might be a system header file. 2001-02-12 Kalle Marjola * gw/bb_store.c: Ooops, forgot to add earlier. Anyway, now uses straight octstr handling instead of using octstr_split and thus does not need so much memory while unpacking the store-file 2001-02-12 Kalle Marjola * gw/bb_boxc.c: removed heartbeat message kludge as it caused other problems, had to think this more... * gw/bb_http.c: removed debug information of HTTP query result because it caused ankward output * gw/bb_store.c: Added. Handles SMS store * gw/msg-decl.h, gw/msg.h: added new 'ack' message type and new fields to sms. Name of these can change later. * gw/bb_boxc.c, gw/bb_smscconn.c, gw/bearerbox.c, gw/smsbox.c: implemented first version of SMS storing/retrieval system. Consumes lots of memory when starting up, so does not work well with checking malloc, will fix that today. * gw/*kannel.conf: added (commented-out) store-file row 2001-02-10 Uoti Urpala * gw/smsbox.c: Fixed bugs in smsbox_req_sendota(), added 'from' CGI variable to sendota requests. * gwlib/cfg.def: Added missing 'speed' variable to otaconfig group. * doc/userguide/userguide.xml: Documented the added 'from' variable. 'speed' was also missing from the documentation. * gw/smsc_fake.c: Implemented SMSCCONN_FAILED_TEMPORARILY (probably doesn't make much difference in practice). * gwlib/octstr.c: Fixed memory leak in octstr_append_from_hex(). 2001-02-08 Richard Braakman * Applied Stipe Tolj's patch to cfg.def and userguide, to fix OTA configuration parsing. 2001-02-07 Kalle Marjola * gw/bb_boxc.c: kludged to use internal heartbeat to wakeup sender from consume if other end closes the connection * gw/bb_smscconn.c: modified failed routing access log output * utils/accesslog_parser.pl: added failed routing to final output, and change all keywords to lowercase 2001-02-07 Kalle Marjola * utils/accesslog_parser.pl: added simple perl script to read (SMS) access log and print statistics out of it, based on hours. Uses the new format printed out by bb_smscconn.c 2001-02-07 Kalle Marjola * gw/bearerbox.c: Bugfix. Fixed memory leak caused by access log / new config * doc/userguide/userguide.xml: made it clearer that sms-service is selected by keyword and number of parameters * gw/bb_smscconn.c: Bugfix: fixed access log to use Octstring return value * gw/bb_smscconn.c: Compatibility breaker: modified access log output 2001-02-07 Yann Muller * gw/smsc_at.c: added support for Ericsson GSM modems (patch from Chris Blown). 2001-02-06 Uoti Urpala * gw/urltrans.c: Changed the %a URL parameter to mean the original message as-is, to allow binary data. Previously consecutive whitespace characters were changed into one space. Note that %r was NOT changed, maybe it should work similarly? 2001-02-06 Kalle Marjola * gw/bb_smscconn_cb.h: added new failed sending status, SMSCCONN_FAILED_TEMPORARILY, which should be called if connection to SMS center is lost temporarily * gw/bb_smscconn.c: added handling for new status * gw/smscconn_p.h: added comments of the new status * gw/smsc_wrapper.c: added that when reconnect is started, message queue is emptied from messages with status SMSCCONN_FAILED_TEMPORARILY 2001-02-06 Peter Grönholm * utils/kannel-stable-rh6x.spec: Added rpm spec file for Kannel stable releases. * utils/kannel-stable-rh7.spec: Added rpm spec file for Kannel stable releases. 2001-02-06 Uoti Urpala * gw/smsbox.c: Rewrote message-splitting functions because they had lots and lots of bugs. Basically they didn't work if split-chars, split-suffix or concatenation was defined. 2001-02-05 Richard Braakman * gwlib/octstr.c: Fixed off-by-one error in octstr_case_search(), reported by Vjacheslav Chekushin. 2001-02-04 Richard Braakman * wmlscript/wsasm.c: Avoid generating 0-length functions, because not all clients can handle them. * gw/wap-appl.c: If the response body does not fit in the client SDU size, generate status code 502 ("Bad Gateway") instead of 413 ("Request Entity Too Large"). 413 is definitely the wrong code because it refers to the request, not the response. 502 means the gateway received an invalid response from the server, which is pretty close. Also, do not touch the status code at all if it already indicates an error. The upstream error is more interesting to the user than knowing that the error page didn't fit. * gwlib/http.[ch]: Add http_status_class() function to distinguish success codes (2xx) from error codes. 2001-02-02 Tuomas Luttinen * test/decompile.[ch]: Applied the patch by Neil Hunter that implements the codepage switch, changes the indent size to a #define and adds basic support for different DTDs. * gw/utf8map_iso8859-7.h, gw/utf8map_win1251.h, gw/utf8map_win1257.h, gw/utf8map_koi8r.h, gw/utf8map_win1253.h: removed as obsolete. * gw/wml_compiler.c: Patch by Vjacheslav Chekushin applied. The patch makes the libxml aware of some aliases for different character_sets, so these can be used in the WML content with the libxml. Some other modifications due modifications in the wml_definitions.h. * gw/wml_definitions.h: Patch by Vjacheslav Chekushin applied. The patch removes the use of the utf8map in the character_sets[]. Also utf8map removed from the character_sets[]. 2001-02-02 Tuomas Luttinen * gw/wml_compiler.c (string_table_collect_strings): Removed the if (strlen(node->content) > WBXML_STRING_TABLE_MIN) -line that won't work with XML_USE_BUFFER_CONTENT. 2001-02-02 Richard Braakman * Added gwmem_type() function that returns the name of the malloc wrapper used. * gw/shared.c: Report gwmem_type in the version string. 2001-02-01 Richard Braakman * Updated doc/release.txt to better reflect actual procedure. Only covers development releases for now. gateway-1.4.5/doc/userguide/0000755000175000017500000000000013312227707014431 5ustar toljtoljgateway-1.4.5/doc/userguide/sms-gateway.fig0000644000175000017500000000441507207170677017376 0ustar toljtolj#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 6 90 90 6525 2835 6 135 1350 585 2475 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 135 1620 585 1620 585 2475 135 2475 135 1620 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 450 1620 540 1620 540 1350 450 1350 450 1620 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 540 1980 540 1665 180 1665 180 1980 540 1980 -6 6 3240 1170 4320 2250 1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 3780 1710 497 497 3780 1710 3825 2205 4 0 0 50 0 0 12 0.0000 4 135 540 3510 1755 Kannel\001 -6 6 2475 900 3105 1305 4 0 0 50 0 0 12 0.0000 4 135 495 2475 1035 SMSC\001 4 0 0 50 0 0 12 0.0000 4 180 615 2475 1260 protocol\001 -6 2 2 0 1 0 0 56 0 -1 0.000 0 0 -1 0 0 5 1350 1125 2025 1125 2025 2475 1350 2475 1350 1125 2 1 0 1 0 0 56 0 -1 0.000 0 0 -1 0 0 5 1350 1125 1575 945 2250 945 2250 2250 2025 2475 2 1 0 1 0 0 56 0 -1 0.000 0 0 -1 0 0 2 2025 1125 2250 945 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5220 540 5850 540 5850 2070 5220 2070 5220 540 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5850 540 6525 90 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5220 540 5895 90 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5850 2056 6525 1606 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 5895 90 6525 90 6525 1620 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5310 1395 5760 1395 5760 1980 5310 1980 5310 1395 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5400 1395 5400 1980 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5490 1395 5490 1980 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5580 1395 5580 1980 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5670 1395 5670 1980 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5310 675 5760 675 5760 810 5310 810 5310 675 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 4 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 4230 1395 4860 1215 4590 1710 5175 1530 0.000 -1.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 4 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 2250 1575 2880 1485 2700 1980 3240 1890 0.000 -1.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 4 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 675 1800 1126 1716 946 2211 1260 2115 0.000 -1.000 -1.000 0.000 4 0 0 50 0 0 12 0.0000 4 135 465 90 1080 Phone\001 4 0 0 50 0 0 12 0.0000 4 135 450 4500 1035 HTTP\001 4 0 0 50 0 0 12 0.0000 4 135 930 1395 2835 SMS Center\001 4 0 0 50 0 0 12 0.0000 4 180 1260 5265 2520 Content provider\001 -6 gateway-1.4.5/doc/userguide/userguide.xml0000644000175000017500000143017313312154361017153 0ustar toljtolj ]> Kannel &version; User's Guide Open Source WAP and SMS gateway Andreas Fink Chairman & CTO Global Networks Inc.
andreas@fink.org http://www.smsrelay.com/ http://www.gni.ch/
Bruno Rodrigues
bruno.rodrigues@litux.org http://litux.org/bruno
Stipe Tolj System Architect Tolj System Architecture
stolj@kannel.org http://www.tolj.org/
Aarno Syvänen Chief MMS Developer Global Networks Inc.
as@gni.ch http://www.gni.ch/
Alexander Malysh Senior Software Engineer GTX Messaging GmbH.
amalysh at kannel.org http://www.gtx-messaging.com/
Alejandro Guerrieri Senior System Architect 3Cinteractive, L.L.C.
aguerrieri@kannel.org http://www.3cinteractive.com/
Lars Wirzenius Gateway architect former Wapit Ltd Kalle Marjola Senior Software Engineer Enpocket
marjola@enpocket.com http://www.enpocket.com
Abstract This document describes how to install and use Kannel, the Open Source WAP and SMS Gateway originally developed by Wapit Ltd (now out of business) and now being developed further by the open source community, namely the Kannel Group. &version; ×tamp;
Introduction This chapter introduces WAP and SMS in general terms, and explains the role of the gateway in WAP and SMS, outlining their duties and features. It also explains why the Kannel project was started in the first place, and why it is open source. With hundreds of millions of mobile phones in use all over the world, the market for services targeted at mobile users is mind-bogglingly immense. Even simple services find plenty of users, as long as they're useful or fun. Being able to get news, send e-mail or just be entertained wherever you are is extremely attractive to many. The hottest technology for implementing mobile services is WAP, short for Wireless Application Protocol. It lets the phone act as a simple web browser, but optimizes the markup language, scripting language, and the transmission protocols for wireless use. The optimized protocols are translated to plain old HTTP by a WAP gateway. Kannel is an open source WAP gateway. It attempts to provide this essential part of the WAP infrastructure freely to everyone so that the market potential for WAP services, both from wireless operators and specialized service providers, will be realized as efficiently as possible. Kannel also works as an SMS gateway for GSM networks. Almost all GSM phones can send and receive SMS messages, so this is a way to serve many more clients than just those using a new WAP phone. In addition, Kannel operates as Push Proxy Gateway , or PPG, making possible for content servers to send data to the phones. This is a new type of WAP service, and have many interesting applications. Usually servers know whether some data is new, not the users. Kannel's quality has been recognized on March 7, 2001 when it was certified by WAP Forum as the first WAP 1.1 gateway in the world. Greater quality recognition are the quantity of companies using Kannel to successful connect to a variety of SMSC protocols in lots of countries. Open Source is a way to formalize the principle of openness by placing the source code of a product under a Open Source compliant software license. The BSD license was chosen over other Open Source licenses by the merit of placing the least amount of limitations on what a third party is able to do with the source code. In practice this means that Kannel is going to be a fully-featured WAP implementation and compatible with the maximum number of bearers with special emphasis on SMSC compatibility. The Kannel project was founded by Wapit Ltd in June, 1999. Overview of WAP WAP, short for Wireless Application Protocol, is a collection of various languages and tools and an infrastructure for implementing services for mobile phones. Traditionally such services have worked via normal phone calls or short textual messages (e.g., SMS messages in GSM networks). Neither are very efficient to use, nor very user friendly. WAP makes it possible to implement services similar to the World Wide Web. Unlike marketers claim, WAP does not bring the existing content of the Internet directly to the phone. There are too many technical and other problems for this to ever work properly. The main problem is that Internet content is mainly in the form of HTML pages, and they are written in such way that they require fast connections, fast processors, large memories, big screens, audio output and often also fairly efficient input mechanisms. That's OK, since they hopefully work better for traditional computers and networks that way. However, portable phones have very slow processors, very little memory, abysmal and intermittent bandwidth, and extremely awkward input mechanisms. Most existing HTML pages do not work on mobiles phones, and never will. WAP defines a completely new markup language, the Wireless Markup Language (WML), which is simpler and much more strictly defined than HTML. It also defines a scripting language, WMLScript, which all browsers are required to support. To make things even simpler for the phones, it even defines its own bitmap format (Wireless Bitmap, or WBMP). HTTP is also too inefficient for wireless use. However, by using a semantically similar binary and compressed format it is possible to reduce the protocol overhead to a few bytes per request, instead of the usual hundreds of bytes. Thus, WAP defines a new protocol stack to be used. However, to make things simpler also for the people actually implementing the services, WAP introduces a gateway between the phones and the servers providing content to the phones.
Logical position of WAP gateway (and PPG) between a phone and a content server.
The WAP gateway talks to the phone using the WAP protocol stack, and translates the requests it receives to normal HTTP. Thus content providers can use any HTTP servers and utilize existing know-how about HTTP service implementation and administration. In addition to protocol translations, the gateway also compresses the WML pages into a more compact form, to save on-the-air bandwidth and to further reduce the phone's processing requirements. It also compiles WMLScript programs into a byte-code format. Latest WAP specifications defines some additional conversions that Kannel is starting to implement, like multipart/form-data, multipart/mixed or MMS content conversion. Kannel is not just a WAP gateway. It also works as an SMS gateway. Although WAP is the hot and technically superior technology, SMS phones exist in huge numbers and SMS services are thus quite useful. Therefore, Kannel functions simultaneously as both a WAP and an SMS gateway.
Overview of WAP Push Previous chapter explained pull mode of operation: the phone initiates the transaction. There is, however, situations when the server (called in this context a push initiator) should be the initiator, for instance, when it must send a mail notification or a stock quote. For this purpose WAP Forum defined WAP Push. Push is an application level service, sitting on the top of existing WAP stack. It defines two protocols, OTA and PAP. OTA is a ligthweigth protocol speaking with WAP stack (to be more specific, with WSP), PAP speaks with the push initiator. It defines three kind of XML documents, one for the push data itself and another for protocol purposes (these are called pap document or push control documents). The server does not simply send push content to the phone, the user would surely not accept, for instance, interrupting of a voice call. Instead it sends a specific XML document, either Service Indication or Service Loading. These inform the user about the content become available, and it is displayed only when it is not interrupting anything. It contains an URL specifying the service and a text for user describing the content. Then the user can decide does he accept push or not. The push content is send ed to the phones over SMS, but the content is fetched by the phone over IP bearer, for instance CSD or GPRS. Because Push Proxy Gateway tokenises SI and SL documents, it may fit one SMS message (if not, it is segmented for transfer). Using two bearers seems to be an unnecessary complication. But quite simply, phones currently operate this way. Push over GPRS can only simplify matters. Overview of SMS SMS, short messaging service, is a way to send short (160 character) messages from one GSM phone to another. It can also be used to send regular text as well as advanced content like operator logos, ringing tones, business cards and phone configurations. SMS services are content services initiated by SMS message to certain (usually short) phone number, which then answers with requested content, if available. When SMS services are used, the client (mobile terminal) sends an SMS message to certain number, usually a very short specialized number, which points to specific SMS center responsible for that number (plus possibly many others). This SMS center then sends the message onward to specified receiver in intra- or Internet, using an SMS center specific protocol. For example, a Nokia SMS center uses CIMD protocol. As practically every different kind of SMS center uses different protocol, an SMS gateway is used to handle connections with SMS centers and to relay them onward in an unified form. Kannel's biggest feature is to abstract each SMSC protocol to a well-known HTTP protocol, simplifying services deployment.
Logical position of SMS gateway between a phone and a content server.
An SMS gateway can also be used to relay SMS messages from one GSM network to another, if the networks do not roam messages normally. Kannel works as an SMS gateway, talking with many different kind of SMS centers, and relaying the messages onward to content providers, as HTTP queries. Content providers then answer to this HTTP query and the answer is sent back to mobile terminal, with appropriate SMS center connection using SMS center specific protocol. In addition to serving mobile originated (MO) SMS messages Kannel also works as an SMS push gateway - content providers can request Kannel to send SMS messages to terminals. Kannel then determines the correct SMS center to relay the SMS message and sends the SMS message to that SMS center, again using SMS center specific protocol. This way the content provider does not need to know any SMS center specific protocol, just unified Kannel SMS sending interface.
Features WAP Fully compliant with WAP 1.1 specification Already implements some WAP 1.2 and even WAP 2.0 features. WAP Push Supports WAP Push SI and SL ... SMS Supports a variety of SMSC protocols, namely: CMG's UCP/EMI 4.0 and 3.5 ... Full support for MO and MT messages Requirements Kannel is being developed on Linux systems, and should be fairly easy to export to other Unix-like systems. However, we don't yet support other platforms, due to lack of time, although it should be working without major problems on Windows (through Cygwin), Solaris and FreeBSD. Kannel requires the following software environment: C compiler and libraries for ANSI C, with normal Unix extensions such as BSD sockets and related tools. (GNU's GCC tool-chain is recommended) The Gnome XML library (known as gnome-xml and libxml), version 2.2.5 or newer. See http://xmlsoft.org/xml.html. If you are installing it from your distribution's packages, you'll need libxml2-dev in addition to run-time libxml2 package libraries. GNU Make. An implementation of POSIX threads (pthread.h). GNU Bison 1.28, if you want to modify the WMLScript compiler (a pre-generated parser is included for those who just want to compile Kannel). DocBook processing tools: DocBook style-sheets, jade, jadetex, etc; see README, section `Documentation', for more information (pre-formatted versions of the documentation are available, and you can compile Kannel itself even without the documentation tools). GNU autoconf, if you want to modify the configuration script. Hardware requirements are fluffier. Some informal benchmarking have shown that with a reasonably fast PC architecture (e.g. 400MHz Pentium II with 128MB RAM), SMS performance's bottleneck is always on the SMSC side, even for example with multiple connections summing a pipeline with 400 msg/sec. We haven't benchmarked Kannel yet on WAP side, so there are no hard numbers.
Installing the gateway This chapter explains how the gateway can be installed, either from a source code package or by using a pre-compiled binary version. The goal of this chapter is to get the gateway compiled and all the files in the correct places; the next chapter will explain how the gateway is configured. If you are upgrading from a previous version, please look at for any important information. Getting the source code The source code to Kannel is available for download at http://www.kannel.org/download.shtml. It is available in various formats and you can choose to download either the latest release version or the daily snapshot of the development source tree for the next release version, depending on whether you want to use Kannel for production use or to participate in the development. If you're serious about development, you probably want to use CVS, the version control system used by the Kannel project. This allows you to participate in Kannel development much more easily than by downloading the current daily snapshot and integrating any changes you've made every day. CVS does that for you. (See the Kannel web site for more information on how to use CVS.) Finding the documentation The documentation for Kannel consists of three parts: User's Guide, i.e., the one you're reading at the moment. Architecture and Design, in doc/arch or at http://www.kannel.org/arch.shtml The README and various other text files in the source tree. You can also find general information on Kannel's website and information about existing problems at our bug tracker. We intend to cover everything you need to install and use Kannel is in User's Guide, but the guide is still incomplete in this respect. Similarly, the Architecture and Design document should tell you everything you need to know to dive into the sources and quickly make your own modifications. It's not a replacement for actually reading the source code, but it should work as a map to the source code. The README is not supposed to be very important, nor contain much information. Instead, it will just point at the other documentation. Compiling the gateway If you are using Kannel on a supported platform, or one that is similar enough to one, compiling Kannel should be trivial. After you have unpacked the source package of your choose, or after you have checked out the source code from CVS, enter the following commands: ./configure make The configure script investigates various things on your computer for the Kannel compilation needs, and writes out the Makefile used to compile Kannel. make then runs the commands to actually compile Kannel. If either command writes out an error message and stops before it finishes its job, you have a problem, and you either need to fix it yourself, if you can, or report the problem to the Kannel project. See for details. For detailed instruction on using the configuration script, see file INSTALL. That file is a generic documentation for configure. Kannel defines a few additional options: --with-defaults=type Set defaults for the other options. type is either speed or debug. The default is speed. speed options is equivalent to --with-malloc=native --disable-assertions, while debug is --with-malloc=checking --enable-assertions. --disable-docs (default is --enable-docs) Use this option if you don't have DocBook installed and/or you want to save some time and CPU cycles. Pre-generated documentation is available on Kannel's site. Default behavior is to build documentation, b.e., converting the User Guide and the Architecture Guide from the DocBook markup language to PostScript and HTML if DocBook is available. --enable-drafts (default is --disable-drafts) When building documentation, include the sections marked as draft. --enable-debug (default is --disable-debug) Enable non-reentrant development time debugging of WMLScript compiler. --disable-localtime (default is --enable-localtime) Write log file time stamps in GMT, not in local time. --enable-assertions / --disable-assertions Turn on or off runtime assertion checking. enable makes Kannel faster, but gives less information if it crashes. Default value is dependent on --with-defaults. --with-malloc=type Select memory allocation module to use: type is native, checking, or slow. For production use you probably want native. The slow module is more thorough than checking, but much slower. Default value is dependent on --with-defaults. --enable-mutex-stats Produce information about lock contention. --enable-start-stop-daemon Compile the start-stop-daemon program. --enable-pam Enable using PAM for authentication of sendsms users for smsbox. --with-mssql[=DIR] Enable using FreeTDS libraries for DBPool and DLR support on MS-SQL and Sybase. Optional DIR specifies where to look for FreeTDS libraries and include files (defaults to /usr/local). --with-mysql Enable using MySQL libraries for DBPool and DLR support. --with-mysql-dir=DIR Where to look for MySQL libs and header files. DIR points to the installation of MySQL. --with-sdb Enable using LibSDB libraries for dlr support. --with-oracle Enable using Oracle OCI-Libraries for Oracle 8i/9i DBPool and DLR support. --with-oracle-includes=DIR Where to look for Oracle OCI-Header files. --with-oracle-libs=DIR Where to look for Oracle OCI-Library files. --with-redis Enable using Redis for DBPool and DLR support. Requires the hiredis library. --with-redis-dir=DIR Where to look for the hiredis library and header files. --with-cassandra Enable using Cassandra for DBPool and DLR support. Requires the DataStax C/C++ driver for Apache Cassandra. --with-cassandra-dir=DIR Where to look for the DataStax C/C++ Cassandra library and header files. You may need to add compilations flags to configure: CFLAGS='-pthread' ./configure The above, for instance, seems to be required on FreeBSD. If you want to develop Kannel, you probably want to add CFLAGS that make your compiler use warning messages. For example, for GCC: CFLAGS='-Wall -O2 -g' ./configure (You may, at your preference, use even stricter checking options.) Installing the gateway After you have compiled Kannel, you need to install certain programs in a suitable place. This is most easily done by using make again: make bindir=/path/to/directory install Replace /path/to/directory with the pathname of the actual directory where the programs should be installed. The programs that are installed are (as filenames from the root of the source directory): gw/bearerbox gw/smsbox gw/wapbox The version number of the gateway is added to the file names during installation. This makes it easier to have several versions installed, and makes it easy to go back to an older version if the new version proves problematic. Kannel consists of three programs called boxes: the bearer box is the interface towards the phones. It accepts WAP and SMS messages from the phones and sends them to the other boxes. The SMS box handles SMS gateway functionality, and the WAP box handles WAP gateway functionality. There can be several SMS boxes and several WAP boxes running and they don't have to run on the same host. This makes it possible to handle much larger loads. Using pre-compiled binary packages Installing Kannel from RPM packages This chapter explains how to install, upgrade and remove Kannel binary RPM packages. Before you install Kannel, check that you have libxml2 installed on your system: rpm -q libxml2 Installing Kannel 1. Download the binary RPM packet from the Kannel web site. 2. Install the RPM package: rpm -ivh kannel-VERSION.i386.rpm Upgrading Kannel 1. Download the binary RPM packet from the Kannel web site. 2. Upgrade the RPM package: rpm -Uvh kannel-VERSION.i386.rpm Removing Kannel 1. Remove the RPM package: rpm -e kannel After you have installed Kannel from the RPM packages you should now be able to run the Kannel init.d script that will start Kannel as a WAP gateway. Run the script as root. /etc/rc.d/init.d/kannel start To stop the gateway just run the same script with the stop parameter. /etc/rc.d/init.d/kannel stop If Kannel is already running and you just want to quickly stop and start the gateway,e.g.to set a new configuration option, run the script with the restart parameter. /etc/rc.d/init.d/kannel restart If you want Kannel to run as a daemon, you need to add a symbolic link to the Kannel script from the runlevel you want Kannel to run in. E.g. to run Kannel in runlevel 5 add symbolic links to /etc/rc.d/rc5.d/. cd /etc/rc.d/rc5.d/ ln -s ../init.d/kannel S91kannel ln -s ../init.d/kannel K91kannel To run Kannel as a SMS gateway you need to edit the configuration file which is at /etc/kannel/kannel.conf. In Kannel's documentation directory (/usr/share/doc/kannel) there is an example file called examples/smskannel.conf. It has some basic examples of the configuration groups needed to run Kannel as a SMS gateway. For more detailed information please see examples/kannel.conf in the same directory for a commented complete example, and read the section "SMS gateway configuration" later in this same document. The logging is disabled by default and you can enable it from the kannel.conf file. Just add the log-file option to the group of which box you want to log. The documentation will be installed at /usr/doc/kannel-VERSION/ or /usr/share/doc/kannel-VERSION/ depending on if you used the RedHat 6.x or a 7.x or newer package. In the Kannel documentation directory there is a HTML file called control.html. It is an example file that shows how to use the Kannel HTTP administration interface. It also has a template for sending SMS messages. Installing Kannel from DEB packages This chapter explains how to install, upgrade and remove Kannel binary DEB packages. Kannel's packages are available on main Debian repository (http://packages.debian.org/kannel) although that version may be out-of-sync with latest Kannel version. Before you install Kannel, check that you have libxml2 installed on your system: dpkg -l libxml2 Installing or upgrading Kannel from Debian or Kannel repository 1. Install or upgrade the package: apt-get install kannel See http://kannel.org/download.shtml#debian_repository for information about kannel repository sources.list Installing or upgrading Kannel from a file 1. Download the binary DEB packet from the Kannel web site. 2. Log in as root: su - 3. Install or upgrade the DEB package: dpkg -i kannel-VERSION.deb Removing Kannel 1. Log in as root: 2. Remove the package keeping configuration files: dpkg --remove kannel 3. Remove the package completely: dpkg --purge kannel After you have installed Kannel from the DEB packages you should now be able to run the Kannel init.d script that will start Kannel as a WAP gateway. Run the script as root. /etc/init.d/kannel start To stop the gateway just run the same script with the stop parameter. /etc/init.d/kannel stop If Kannel is already running and you just want to quickly stop and start the gateway,e.g.to set a new configuration option, run the script with the restart parameter. /etc/init.d/kannel restart If you don't want Kannel to run as a daemon, run: update-rc.d -f kannel remove If you want to restore Kannel running as a daemon, you need to add a symbolic link to the Kannel script from the runlevel you want Kannel to run in. E.g. to run Kannel in default runlevel, just run: update-rc.d kannel defaults Kannel package starts by default with a wapbox daemon. To activate smsbox or select which box you want to start, edit /etc/default/kannel and comment/uncomment START_xxxBOX. To run Kannel as a SMS gateway you need to edit the configuration file which is at /etc/kannel/kannel.conf. In /usr/share/docs/kannel/examples/ there are example files. They have some basic examples of the configuration groups needed to run Kannel as a SMS gateway. For more detailed information please read the section "SMS gateway configuration" later in this same document. The documentation will be installed at /usr/share/doc/kannel/. In the Kannel documentation directory there is a html file called control.html. It is an example file that shows how to use the Kannel HTTP administration interface. It also has a template for sending SMS messages. Additionally to kannel-VERSION.deb, there's now an optional kannel-docs-VERSION.deb with documentation (userguide et al) and a kannel-extras-VERSION.deb with contrib and test stuff. If you want to test development version, use the packages called kannel-devel-*.deb. Using the gateway This chapter explains how the gateway core, bearerbox, is configured and used. It covers the configuration file, keeping an eye on the gateway while it is running, and using the HTTP interface to control the gateway. After this chapter there is distinct chapter for each kind of gateway use: WAP gateway, SMS gateway and WAP Push proxy. These chapters explain the configuration and other aspects of gateway of that type. You can configure your Kannel to be only a WAP or a SMS gateway, or to be both at the same time. You just need to read each chapter and combine all configurations. There is only one configuration file for all parts of Kannel, although when Kannel is distributed to several hosts some lines from the configuration file can be removed in some hosts. Configuring the gateway The configuration file can be divided into three parts: bearerbox configurations, smsbox configurations and wapbox configurations. Bearerbox part has one 'core' group and any used SMS center groups, while wapbox part has only one wapbox group. In smsbox part there is one smsbox group and then number of sms-service and sendsms-user groups. Details of each part are in an appropriate section of this documentation. The 'core' group used by the bearerbox is explained in this chapter, while 'wapbox' part is in the next chapter and 'smsbox', 'smsc' (SMS center), 'sms-service' and 'sendsms-user' groups are in the SMS Kannel chapter. Configuration file syntax A configuration file consists of groups of configuration variables. Groups are separated by empty lines, and each variable is defined on its own line. Each group in Kannel configuration is distinguished with a group variable. Comments are lines that begin with a number sign (#) and are ignored (they don't, for example, separate groups of variables). A variable definition line has the name of the variable, and equals sign (=) and the value of the variable. The name of the variable can contain any characters except white space and equals. The value of the variable is a string, with or without quotation marks () around it. Quotation marks are needed if the variable needs to begin or end with white space or contain special characters. Normal C escape character syntax works inside quotation marks. Perhaps an example will make things easier to comprehend: 1 # A do-nothing service. 2 group = sms-service 3 keyword = nop 4 text = "You asked nothing and I did it!" 5 6 # Default service. 7 group = sms-service 8 keyword = default 9 text = "No services defined" The above snippet defines the keyword nop for an SMS service, and a default action for situation when the keyword in the SMS message does not match any defined service. Lines 1 and 6 are comment lines. Line 5 separates the two groups. The remaining lines define variables. The group type is defined by the group variable value. The various variables that are understood in each type of configuration group are explained below. Some variable values are marked as 'bool'. The value for variable can be like true, false, yes, no, on, off, 0 or 1. Other values are treated as 'true' while if the variable is not present at all, it is treated as being 'false'. In order to make some configuration lines more readable you may use the delimiter '\' at the end of a line to wrap and concatenate the next line up to the current line. Here is an example: 1 # A group with a wrapped alias line 2 group = sms-service 3 keyword = hello 4 aliases = hallo;haalloo;\ 5 heelloo;haelloo;healloo 5 text = "Hello world!" The above example shows how a list for various alias keywords is wrapped to two lines using the line wrap delimiter. In order to use the delimiter '\' itself, you need to escape it via a prefixed '\' itself. So this is '\\' to escape the wrapping function and use the character in the string. Inclusion of configuration files A configuration file may contain a special directive called include to include other file or a directory with files to the configuration processing. This allows to segment the specific configuration groups required for several services and boxes to different files and hence to have more control in larger setups. Here is an example that illustrates the include statement : group = core admin-port = 13000 wapbox-port = 13002 admin-password = bar wdp-interface-name = "*" log-file = "/var/log/bearerbox.log" log-level = 1 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" include = "wapbox.conf" include = "configurations" Above is the main kannel.conf configuration file that includes the following wapbox.conf file with all required directives for the specific box, and a configurations directory which may include more files to include. group = wapbox bearerbox-host = localhost log-file = "/var/log/wapbox.log" log-level = 0 syslog-level = none The above include statement may be defined at any point in the configuration file and at any inclusion depth. Hence you can cascade numerous inclusions if necessary. At process start time inclusion of configuration files breaks if either the included file can not be opened and processed or the included file has been processed already in the stack and a recursive cycling has been detected. Core configuration Configuration for Kannel MUST always include a group for general bearerbox configuration. This group is named as 'core' in configuration file, and should be the first group in the configuration file. As its simplest form, 'core' group looks like this: group = core admin-port = 13000 admin-password = f00bar Naturally this is not sufficient for any real use, as you want to use Kannel as an SMS gateway, or WAP gateway, or both. Thus, one or more of the optional configuration variables are used. In following list (as in any other similar lists), all mandatory variables are marked with (m), while conditionally mandatory (variables which must be set in certain cases) are marked with (c). Core Group Variables Variable Value Description group (m) core This is a mandatory variable admin-port (m) port-number The port number in which the bearerbox listens to HTTP administration commands. It is NOT the same as the HTTP port of the local HTTP server, just invent any port, but it must be over 1023 unless you are running Kannel as a root process (not recommended) admin-port-ssl (o) bool If set to true a SSL-enabled administration HTTP server will be used instead of the default insecure plain HTTP server. To access the administration pages you will have to use a HTTP client that is capable of talking to such a server. Use the "https://" scheme to access the secured HTTP server. Defaults to "no". admin-password (m) string Password for HTTP administration commands (see below) status-password string Password to request Kannel status. If not set, no password is required, and if set, either this or admin-password can be used admin-deny-ip IP-list These lists can be used to prevent connection from given IP addresses. Each list can have several addresses, separated with semicolons (';'). An asterisk ('*') can be used as a wild-card in a place of any ONE number, so *.*.*.* matches any IP. admin-allow-ipsmsbox-interface (o) string If this is set, the smsbox listener will only bind to a specified address. For example: "127.0.0.1". smsbox-port (c) port-number This is the port number to which the smsboxes, if any, connect. As with admin-port, this can be anything you want. Must be set if you want to handle any SMS traffic. smsbox-port-ssl (o) bool If set to true, the smsbox connection module will be SSL-enabled. Your smsboxes will have to connect using SSL to the bearerbox then. This is used to secure communication between bearerbox and smsboxes in case they are in separate networks operated and the TCP communication is not secured on a lower network layer. Defaults to "no". wapbox-port (c) port-number Like smsbox-port, but for wapbox-connections. If not set, Kannel cannot handle WAP traffic wapbox-port-ssl (o) bool If set to true, the wapbox connection module will be SSL-enabled. Your wapboxes will have to connect using SSL to the bearerbox then. This is used to secure communication between bearerbox and wapboxes in case they are in separate networks operated and the TCP communication is not secured on a lower network layer. Defaults to "no". box-deny-ip IP-list These lists can be used to prevent box connections from given IP addresses. Each list can have several addresses, separated with semicolons (';'). An asterisk ('*') can be used as a wild-card in place of any ONE number, so *.*.*.* matches any IP. box-allow-ipudp-deny-ip IP-list These lists can be used to prevent UDP packets from given IP addresses, thus preventing unwanted use of the WAP gateway. Used the same way as box-deny-ip and box-allow-ip. udp-allow-ipwdp-interface-name (c) IP or '*' If this is set, Kannel listens to WAP UDP packets incoming to ports 9200-9208, bound to given IP. If no specific IP is needed, use just an asterisk ('*'). If UDP messages are listened to, wapbox-port variable MUST be set. log-file filename A file in which to write a log. This in addition to stdout and any log file defined in command line. Log-file in 'core' group is only used by the bearerbox. log-level number 0..5 Minimum level of log-file events logged. 0 is for 'debug', 1 'info', 2 'warning, 3 'error' and 4 'panic' (see Command Line Options) access-log filename A file in which information about received/sent SMS messages is stored. Access-log in 'core' group is only used by the bearerbox. access-log-clean boolean Indicates if access-log will contain standard 'markers', which means the 'Log begins', 'Log ends' markers and the prefixed timestamp. This config directive should be set to 'true' if a custom logging format is desired without a prefixed default timestamp. access-log-format string String defining a custom log file line format. May use escape codes as defined later on to substitute values of the messages into the log entry. If no custom log format is used the standard format will be: "%t %l [SMSC:%i] [SVC:%n] [ACT:%A] [BINF:%B] [FID:%F] [META:%D] [from:%p] [to:%P] [flags:%m:%c:%M:%C:%d] [msg:%L:%b] [udh:%U:%u]" syslog-level number Messages of this log level or higher will also be sent to syslog, the UNIX system log daemon. If not explicitly set with syslog-facility, it logs under the 'daemon' category. The default is not to use syslog, and you can set that explicitly by setting syslog-level to 'none'. syslog-facility string The syslog facility to send the syslog entries to. The default is 'daemon'. unified-prefix prefix-list String to unify received phone numbers, for SMSC routing and to ensure that SMS centers can handle them properly. This is applied to 'sender' number when receiving SMS messages from SMS Center and for 'receiver' number when receiving messages from smsbox (either sendsms message or reply to original message). Format is that first comes the unified prefix, then all prefixes which are replaced by the unified prefix, separated with comma (','). For example, for Finland an unified-prefix "+358,00358,0;+,00" should do the trick. If there are several unified prefixes, separate their rules with semicolon (';'), like "+35850,050;+35840,040". Note that prefix routing is next to useless now that there are SMSC ID entries. To remove prefixes, use like "-,+35850,050;-,+35840,040". white-list URL (Deprecated, see white-list-sender). white-list-regex POSIX regular expression (Deprecated, see white-list-sender-regex). black-list URL (Deprecated, see black-list-sender). black-list-regex POSIX regular expression (Deprecated, see black-list-sender-regex). white-list-sender URL Load a list of accepted senders of SMS messages. If a sender of an SMS message is not in this list, any message received from the SMS Center, or tried to be delivered to the SMS Center is rejected. See notes of phone number format from numhash.h header file. NOTE: the system has only a precision of last 9 or 18 digits of phone numbers, so beware! white-list-sender-regex POSIX regular expression A regular expression defining the set of accepted senders. See section on for details. black-list-sender URL As white-list-sender, but SMS messages from these sender numbers are automatically rejected. black-list-sender-regex POSIX regular expression A regular expression defining the set of rejected senders. See section on for details. white-list-receiver URL Load a list of accepted receiver of SMS messages. If a receiver of an SMS message is not in this list, any message received from the SMS Center, or tried to be delivered to the SMS Center is rejected. See notes of phone number format from numhash.h header file. NOTE: the system has only a precision of last 9 or 18 digits of phone numbers, so beware! white-list-receiver-regex POSIX regular expression A regular expression defining the set of accepted receivers. See section on for details. black-list-receiver URL As white-list, but SMS messages from these receiver numbers are automatically rejected. black-list-receiver-regex POSIX regular expression A regular expression defining the set of rejected receivers. See section on for details. store-type filename Kannel can use store subsystem that means storing messages on hard disk or in a remote key store until they are successfully handled. By using this subsystem, no SMS messages are lost in Kannel even by crash, but theoretically some messages can duplicate when system is taken down violently. This variable defines a type of backend used for store subsystem. Now two types are supported: a) file: writes store into one single file b) spool: writes store into spool directory (one file for each message) c) redis: writes store into a redis key storage. For redis as message storage you will need a group = redis-connection and a group = store-db configuration group that define the connection to the redis server and the table name to be used. See file doc/examples/store-redis.conf for an example config secttion. store-location filename Depends on store-type option used, it is ether file or spool directory, or none if redis is used as storage subsystem. store-dump-freq seconds Approximated frequency how often the memory dump of current pending messages are stored to store-file, providing something has happened. Defaults to 10 seconds if not set. http-proxy-host hostname Enable the use of an HTTP proxy for all HTTP requests. http-proxy-port port-numberhttp-proxy-exceptions URL-list A list of excluded hosts from being used via a proxy. Separate each entry with space. http-proxy-exceptions-regex UNIX regular expression Same as http-proxy-exceptions but match against UNIX regular expression. http-proxy-username username Username for authenticating proxy use, for proxies that require this. http-proxy-password URL-list Password for authenticating proxy use, for proxies that require this. ssl-client-certkey-file (c) filename A PEM encoded SSL certificate and private key file to be used with SSL client connections. This certificate is used for the HTTPS client side only, i.e. for SMS service requests to SSL-enabled HTTP servers. ssl-server-cert-file (c) filename A PEM encoded SSL certificate file to be used with SSL server connections. This certificate is used for the HTTPS server side only, i.e. for the administration HTTP server and the HTTP interface to send SMS messages. ssl-server-key-file (c) filename A PEM encoded SSL private key file to be used with SSL server connections. This key is associated to the specified certificate and is used for the HTTPS server side only. ssl-trusted-ca-file filename This file contains the certificates Kannel is willing to trust when working as a HTTPS client. If this option is not set, certificates are not validated and those the identity of the server is not proven. ssl-client-cipher-list filename Defines the list of encryption suites and ciphers to be used for client side connections. For further details please see https://www.openssl.org/docs/manmaster/man1/ciphers.html ssl-server-cipher-list filename Defines the list of encryption suites and ciphers to be used for server side connections. For further details please see https://www.openssl.org/docs/manmaster/man1/ciphers.html dlr-storage type Defines the way DLRs are stored. Natively in-memory storage is supported, which is very fast, but has no persistancy. This means you will loose all your temporary DLR information on bearebox re-start. In addition a spool directory approach is natively supported, which garantees persistancy with a reasonable performance, depending on your disk IO performance. If you have build-in external DLR storage support, i.e. using MySQL you may define here the alternative storage type like mysql. Supported types are: internal, spool, mysql, pgsql, sdb, mssql, sqlite3, oracle, redis and cassandra. By default this is set to internal. dlr-spool filename Depends on dlr-storage = spool option used, it is the spool directory to use for DLR storage data. maximum-queue-length number of messages (Deprecated, see sms-incoming-queue-limit). sms-incoming-queue-limit number of messages Set maximum size of incoming message queue. After number of messages has hit this value, Kannel began to discard them. Value 0 means giving strict priority to outgoing messages. -1, default, means that the queue of infinite length is accepted. (This works with any normal input, use this variable only when Kannel message queues grow very long). sms-outgoing-queue-limit number of messages Set maximum size of outgoing message queue. After number of messages has hit this value, Kannel began to discard them. The default value, 1 million, works for most installations. smsbox-max-pending number of messages Maximum number of pending messages on the line to smsbox compatible boxes. sms-resend-freq seconds Frequency for the SMS resend thread in which temporarily failed or queued messages will be resent. Defaults to 60 seconds. sms-resend-retry number Maximum retry attempts for the temporarily failed messages. Defaults to -1, means: unlimited. sms-combine-concatenated-mo boolean Whether Kannel should attempt to combine concatenated MO SMS prior to passing them over to smsbox. Default is true sms-combine-concatenated-mo-timeout seconds How long to wait for all concatenated message parts to arrive before timeouting. Default 1800 seconds. http-timeout seconds Sets socket timeout in seconds for outgoing client http connections. Optional. Defaults to 240 seconds.
A sample more complex 'core' group could be something like this: group = core admin-port = 13000 admin-password = f00bar status-password = sTat admin-deny-ip = "*.*.*.*" admin-allow-ip = "127.0.0.1;200.100.0.*" smsbox-port = 13003 wapbox-port = 13004 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1;200.100.0.*" wdp-interface-name = "*" log-file = "kannel.log" log-level = 1 access-log = "kannel.access" unified-prefix = "+358,00358,0;+,00" white-list = "http://localhost/whitelist.txt"
Running Kannel To start the gateway, you need to start each box you need. You always need the bearer box, and depending on whether you want WAP and SMS gateways you need to start the WAP and SMS boxes. If you want, you can run several of them, but we'll explain the simple case of only running one each. Starting the gateway After you have compiled Kannel and edited configuration file for your taste, you can either run Kannel from command line or use supplied start-stop-daemon and run_kannel_box programs to use it as a daemon service (more documentation about that later). If you cannot or do not know how to set up daemon systems or just want to test Kannel, you probably want to start it from command line. This means that you probably want to have one terminal window for each box you want to start (xterm or screen will do fine). To start the bearerbox, give the following command: ./bearerbox -v 1 [config-file] The sets the logging level to INFO. This way, you won't see a large amount of debugging output (the default is DEBUG). Full explanation of Kannel command line arguments is below. [config-file] is the name of the configuration file you are using with Kannel. The basic distribution packet comes with two sample configuration files, smskannel.conf and wapkannel.conf (in gw sub directory), of which the first one is for testing out SMS Kannel and the second one for setting up a WAP Kannel. Feel free to edit those configuration files to set up your own specialized system. After the bearer box, you can start the WAP box: ./wapbox -v 1 [config-file] or the SMS box: ./smsbox -v 1 [config-file] or both, of course. The order does not matter, except that you need to start the bearer box before the other boxes. Without the bearer box, the other boxes won't even start. Command line options Bearerbox, smsbox and wapbox each accept certain command line options and arguments when they are launched. These arguments are: Kannel Command Line Options Print the version of the Kannel binary. --version-v <level> Set verbosity level for stdout (screen) logging. Default is 0, which means 'debug'. 1 is 'info, 2 'warning', 3 'error' and 4 'panic' --verbosity <level>-D <places> Set debug-places for 'debug' level output. --debug <places>-F <file-name> Log to file named file-name, too. Does not overrun or affect any log-file defined in configuration file. --logfile <file-name>-V <level> Set verbosity level for that extra log-file (default 0, which means 'debug'). Does not affect verbosity level of the log-file defined in configuration file, not verbosity level of the stdout output. --fileverbosity <level>-S Start the system initially at SUSPENDED state (see below, bearerbox only) --suspended-I Start the system initially at ISOLATED state (see below, bearerbox only) --isolated-H Only try to open HTTP sendsms interface; if it fails, only warn about that, do not exit. (smsbox only) --tryhttp-g Dump all known config groups and config keys to stdout and exit. --generate-u <username> Change process user-id to the given. --user <username>-p <filename> Write process PID to the given file. --pid-file <filename>-d Start process as daemon (detached from a current shell session). Note: Process will change CWD (Current working directory) to /, therefore you should ensure that all paths to binary/config/config-includes are absolute instead of relative. --daemonize-P Start watcher process. This process watch a child process and if child process crashed will restart them automatically. --parachute-X <scriptname> Execute a given shell script or binary when child process crash detected. This option is usable only with --parachute/-P. Script will be executed with 2 arguments: scriptname 'processname' 'respawn-count'. --panic-script <scriptname>
Kannel statuses In Kannel, there are four states for the program (which currently directly only apply to bearerbox): Running. The gateway accepts, proceeds and relies messages normally. This is the default state for the bearerbox. Suspended. The gateway does not accept any new messages from SMS centers nor from UDP ports. Neither does it accept new sms and wapbox connections nor sends any messages already in the system onward. Isolated. In this state, the gateway does not accept any messages from external message providers, which means SMS Centers and UDP ports. It still processes any messages in the system and can accept new messages from sendsms interface in smsbox. Full. Gateway does not accept any messages from SMS centers, because maximum-queue-length is achieved. Shutdown. When the gateway is brought down, it does not accept any new messages from SMS centers and UDP ports, but processes all systems already in the system. As soon as any queues are emptied, the system exits The state can be changed via HTTP administration interface (see below), and shutdown can also be initiated via TERM or INT signal from terminal. In addition, the bearerbox can be started already in suspended or isolated state with -S or -I command line option, see above. HTTP administration Kannel can be controlled via an HTTP administration interface. All commands are done as normal HTTP queries, so they can be easily done from command line like this: lynx -dump "http://localhost:12345/shutdown?password=bar" ...in which the '12345' is the configured admin-port in Kannel configuration file (see above). For most commands, admin-password is required as a argument as shown above. In addition, HTTP administration can be denied from certain IP addresses, as explained in configuration chapter. Note that you can use these commands with WAP terminal, too, but if you use it through the same Kannel, replies to various suspend commands never arrive nor can you restart it via WAP anymore. Kannel HTTP Administration Commands status or status.txt Get the current status of the gateway in a text version. Tells the current state (see above) and total number of messages relied and queuing in the system right now. Also lists the total number of smsbox and wapbox connections. No password required, unless status-password set, in which case either that or main admin password must be supplied. status.html HTML version of status status.xml XML version of status status.wml WML version of status store-status or store-status.txt Get the current content of the store queue of the gateway in a text version. No password required, unless status-password set, in which case either that or main admin password must be supplied. store-status.html HTML version of store-status store-status.xml XML version of store-status suspend Set Kannel state as 'suspended' (see above). Password required. isolate Set Kannel state as 'isolated' (see above). Password required. resume Set Kannel state as 'running' if it is suspended or isolated. Password required. shutdown Bring down the gateway, by setting state to 'shutdown'. After a shutdown is initiated, there is no other chance to resume normal operation. However, 'status' command still works. Password required. If shutdown is sent for a second time, the gateway is forced down, even if it has still messages in queue. flush-dlr If Kannel state is 'suspended' this will flush all queued DLR messages in the current storage space. Password required. start-smsc Re-start a single SMSC link. Password required. Additionally the smsc parameter must be given to identify which smsc-admin-id should be re-started. The configuration for the SMSC link is re-read from disk before the action is performed. stop-smsc Shutdown a single SMSC link. Password required. Additionally the smsc parameter must be given (see above). add-smsc Adds an SMSC link previously removed or created after the service was started. Password required. Additionally the smsc parameter must be given (see above). remove-smsc Removes an existing SMSC link. Password required. Additionally the smsc parameter must be given (see above). If you want a permanent removal, you should also remove the entry from the configuration file or it will be recreated after a service restart. restart This is the hard restarting version, where we fully stop the bearerbox and then initiate from ground up. Beware that you loose the smsbox connections in such a case. graceful-restart Re-start bearerbox gracefully, hence only the changes in the configuration for the SMSC connections are performed. I.e. an added SMSC group will be start, and a removed SMSC group will be shutdown and destroyed. Any unchanged SMSC connection keeps on running without interruption. Password required. This is the soft restarting version, where we keep all internal parts of the bearebox running, including the smsbox connections. The same graceful restart can be initiated by sending a SIGHUP signal to the bearerbox daemon process. log-level Set Kannel log-level of log-files while running. This allows you to change the current log-level of the log-files on the fly. This includes the main event log and the SMSC specific logs, if any exist. reload-lists Re-loads the 'white-list' and 'black-list' URLs provided in the core group. This allows Kannel to keep running while the remote lists change and signal bearerbox to re-load them on the fly. remove-message Removes the message with the give id (an UUID) from the local storage subsystem.
Setting up a WAP gateway This chapter tells you how to set Kannel up as a WAP gateway. WAP gateway configuration To set up a WAP Kannel, you have to edit the 'core' group in the configuration file, and define the 'wapbox' group. You must set following variables for the 'core' group: wapbox-port and wdp-interface-name. See previous chapter about details of these variables. With standard distribution, a sample configuration file wapkannel.conf is supplied. You may want to take a look at that when setting up a WAP Kannel. Wapbox group If you have set wapbox-port variable in the 'core' configuration group, you MUST supply a 'wapbox' group. The simplest working 'wapbox' group looks like this: group = wapbox bearerbox-host = localhost There is, however, multiple optional variables for the 'wapbox' group. Wapbox Group Variables Variable Value Description group (m) wapbox This is mandatory variable bearerbox-host (m) hostname The machine in which the bearerbox is. timer-freq value-in-seconds The frequency of how often timers are checked out. Default is 1 http-interface-name IP address If this is set then Kannel do outgoing HTTP requests using this interface. map-url URL-pair The pair is separated with space. Adds a single mapping for the left side URL to the given destination. If you append an asterisk `*' to the left side URL, its prefix Is matched against the incoming URL. Whenever the prefix matches, the URL will be replaced completely by the right side. In addition, if if you append an asterisk to the right side URL, the part of the incoming URL coming after the prefix, will be appended to the right side URL. Thus, for a line: map-url = "http://source/* http://destination/*" and an incoming URL of "http://source/some/path", the result will be "http://destination/some/path" map-url-max number If you need more than one mapping, set this to the highest number mapping you need. The default gives you 10 mappings, numbered from 0 to 9. Default: 9 map-url-0 URL-pair Adds a mapping for the left side URL to the given destination URL. Repeat these lines, with 0 replaced by a number up to map-url-max, if you need several mappings. device-home URL Adds a mapping for the URL DEVICE:home (as sent by Phone.com browsers) to the given destination URL. There is no default mapping. NOTE: the mapping is added with both asterisks, as described above for the "map-url" setting. Thus, the above example line is equivalent to writing map-url = "DEVICE:home* http://some.where/*" log-file filename As with bearerbox 'core' group. log-level number 0..5access-log filename A file containing all requested URLs from clients while wapbox operation, including client IP, HTTP server User-Agent string, HTTP response code, size of reply. access-log-clean boolean Indicates if access-log will contain standard 'markers', which means the 'Log begins', 'Log ends' markers and the prefixed timestamp. This config directive should be set to 'true' if a custom logging format is desired without a prefixed default timestamp. access-log-time string Determine which timezone we use for access logging. Use 'gmt' for GMT time, anything else will use local time. Default is local time. syslog-level number Messages of this log level or higher will also be sent to syslog, the UNIX system log daemon. If not explicitly set with syslog-facility, it logs under the 'daemon' category. The default is not to use syslog, and you can set that explicitly by setting syslog-level to 'none'. syslog-facility string The syslog facility to send the syslog entries to. The default is 'daemon'. smart-errors bool If set wapbox will return a valid WML deck describing the error that occurred while processing an WSP request. This may be used to have a smarter gateway and let the user know what happened actually. wml-strict bool If set wapbox will use a strict policy in XML parsing the WML deck. If not set it will be more relaxing and let the XML parser recover from parsing errors. This has mainly impacts in how smart the WML deck and it's character set encoding can be adopted, even while you used an encoding that does not fit the XML preamble. BEWARE: This may be a vulnerability in your wapbox for large bogus WML input. Therefore this defaults to 'yes', strict parsing. is assumed. http-timeout seconds Sets socket timeout in seconds for outgoing client http connections. Optional. Defaults to 240 seconds.
Running WAP gateway WAP Gateway is ran as explained in previous chapter. Checking whether the WAP gateway is alive You can check whether the WAP gateway (both the bearerbox and the wapbox) is alive by fetching the URL kannel:alive.
Setting up wtls security This chapter tells you how to set Kannel up to handle wtls traffic. wtls group is optional and single. The prerequisites for this group are to have defined a wapbox group, and a pair of SSL certificates available. Instructions on how to create self-signed 1024-bit RSA certificates are in . Current imlementation provides for the following functionality: Supported MACs: SHA_0 SHA_40 SHA_80 SHA_NOLIMIT MD5_40 MD5_80 MD5_NOLIMIT Missing: SHA_XOR_40 Supported Ciphers: RC5_CBC_40 RC5_CBC_56 RC5_CBC DES_CBC DES_CBC_40 Missing: NULL_bulk TRIPLE_DES_CBC_EDE IDEA_CBC_40 IDEA_CBC_56 IDEA_CBC Supported Keys: RSA_anon Missing: RSA_anon_512 RSA_anon_768 RSA_NOLIMIT RSA_512 RSA_768 ECDH_anon ECDH_anon_113 ECDH_anon_131 ECDH_ECDSA_NOLIMIT Keys might seem a shortcoming, but all mobiles support RSA_anon. Some of the other RSA_anon keys (i.e. RSA_anon_512, RSA_anon_768) are propably supported as well, just haven't been tested yet. All wtls states except: Suspend/Resume wtls session Cipher change when already connected. In practice this is handled through another client hello, while already connected to the same client The simplest working wtls group looks like this: group = wtls certificate-file = /etc/kannel/server.crt privatekey-file = /etc/kannel/server.key Can also be the same single combined pem file with both certificate and privatekey parts. The complete variable list for the wtls group is: Wtls configuration Wtls Group Variables Variable Value Description group (m) wtls This is mandatory variable certificate-file (m) filename Public key SSL certificate. privatekey-file (m) filename Private key SSL certificate. privatekey-password (o) Phrase Optional. Needed only if private key was created with a passphrase.
Setting up MSISDN provisioning for WAP gateway This chapter tells you how to set Kannel up to deliver the MSISDN number of the WAP device using the WAP gateway. Mostly this feature is interested because the WAP protocol stack itself does not provide such a protocol layer bridging of information. In case you want to know which unique MSISDN is used by the WAP device your HTTP application is currently interacting, then you can pick this information from a RADIUS server that is used by a NAS (network access server) for authentication and accounting purposes. Kannel provides a RADIUS accounting proxy thread inside wapbox which holds a mapping table for the dynamically assigned (DHCP) IP addresses of the WAP clients and their MSISDN numbers provided to the NAS device. Beware that you HAVE TO to be in control of the NAS to configure it to use Kannel's wapbox as RADIUS accounting server. You can not use MSISDN provisioning via Kannel's RADIUS accounting proxy if you can not forward the accounting packets to Kannel's accounting proxy thread. So obviously this feature is for operators and people who have dedicated dial-in servers (NAS). RADIUS accounting proxy configuration To set up the RADIUS accounting proxy thread inside Kannel you have to define a 'radius-acct' group. RADIUS-Acct configuration The simplest working 'radius-acct' group looks like this: group = radius-acct our-port = 1646 secret-nas = radius This example does not forward any accounting packets to a remote RADIUS server. There is, however, multiple optional variables for the 'radius-acct' group. RADIUS-Acct Group Variables Variable Value Description group (m) radius-acct This is mandatory variable if you want to have Kannel's RADIUS accounting proxy thread to be active inside wapbox. secret-nas (m) string Specifies the shared secret between NAS and our RADIUS accounting proxy. secret-radius string Specifies the shared secret between our RADIUS accounting proxy and the remote RADIUS server itself in case we are forwarding packets. our-host IP address Specifies the local interface where our-port value will bind to. (defaults to 0.0.0.0) remote-host FQDN or IP address Specifies the remote RADIUS server to which we forward the accounting packets. If none is given, then no forwarding of accounting packets is performed. our-port number Specifies the port to which our RADIUS accounting proxy thread will listen to. (defaults according to RFC2866 to 1813) remote-port number Specifies the port to which our RADIUS accounting proxy thread will forward any packets to the remote-host. (defaults according to RFC2866 to 1813) remote-timeout number Specifies the timeout value in milliseconds for waiting on a response from the remote RADIUS server. (defaults to 40 msecs.) nas-ports number Specifies how many possible clients can connect simultaneously to the NAS. This value is used to initialize the mapping hash table. If does not require to be exact, because the table grows automatically if required. (defaults to 30) unified-prefix prefix-list String to unify provided phone numbers from NAS. Format is that first comes the unified prefix, then all prefixes which are replaced by the unified prefix, separated with comma (','). For example, for Finland an unified-prefix "+358,00358,0;+,00" should do the trick. If there are several unified prefixes, separate their rules with semicolon (';'), like "+35850,050;+35840,040".
Using the MSISDN provisioning on HTTP server side Kannel's wapbox will include a specific HTTP header in the HTTP request issued to the URL provided by the WAP client. That HTTP header is X-WAP-Network-Client-MSISDN. It will carry as value the MSISDN of the WAP client if the RADIUS accounting proxy has received a valid accounting packet from the NAS that provided the client IP.
Setting up a SMS Gateway This chapter is a more detailed guide on how to set up Kannel as an SMS gateway. Required components To set up an SMS gateway, you need, in addition to a machine running Kannel, access to (an operator's) SMS center, or possibly to multiple ones. The list of supported SMS centers and their configuration variables is below. If you do not have such access, you can still use Kannel as an SMS gateway via phone-as-SMSC feature, by using a GSM phone as a virtual SMS center. In addition to an SMS center (real or virtual), you need some server to handle any SMS requests received. This server then has simple or more complex cgi-bins, programs or scripts to serve HTTP requests generated by Kannel in response to received SMS messages. These services can also initiate SMS push via Kannel smsbox HTTP sendsms interface. SMS gateway configuration To set up a SMS Kannel, you have to edit the 'core' group in the configuration file, and define an 'smsbox' group plus one or more 'sms-service' groups, plus possibly one or more 'sendsms-user' groups. For the 'core' group, you must set the following variable: smsbox-port. In addition, you may be interested to set unified-prefix, white-list and/or black-list variables. See above for details of these variables. A sample configuration file smskannel.conf is supplied with the standard distribution. You may want to take a look at that when setting up an SMS Kannel. SMS centers To set up the SMS center at Kannel, you have to add a 'smsc' group into configuration file. This group must include all the data needed to connect that SMS center. You may also want to define an ID (identification) name for the SMSC, for logging and routing purposes. SMSC ID is an abstract name for the connection. It can be anything you like, but you should avoid any special characters. You do not need to use ID, but rely on SMS center IP address and other information. However, if you use the ID, you do not need to re-define sms-services nor routing systems if the IP of the SMS Center is changed, for example. Common 'smsc' group variables are defined in the following table. The first two (group and smsc) are mandatory, but rest can be used if needed. SMSC Group Variables Variable Value Description group (m) smsc This is a mandatory variable smsc (m) string Identifies the SMS center type. See below for a complete list. smsc-id string An optional name or id for the smsc. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. This 'id' is written into log files and can be used to route SMS messages, and to specify the used SMS-service. Several SMSCs can have the same id. The name is case-insensitive. Note that if SMS Center connection has an assigned SMSC ID, it does NOT automatically mean that messages with identical SMSC ID are routed to it; instead configuration variables denied-smsc-id, allowed-smsc-id and preferred-smsc-id is used for that. If you want to use Delivery Reports, you must define this. smsc-admin-id string An optional id for the smsc to be used on administrative commands. This allows commands targeted to individual binds even if they share the same smsc-id (for load balancing scenarios, for example). Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. Several SMSCs can have the same admin-id, though it's not recommended. The name is case-insensitive. throughput float (messages/sec) If SMSC requires that Kannel limits the number of messages per second, use this variable. This is considered as active throttling. (optional) denied-smsc-id id-list SMS messages with SMSC ID equal to any of the IDs in this list are never routed to this SMSC. Multiple entries are separated with semicolons (';') allowed-smsc-id id-list This list is opposite to previous: only SMS messages with SMSC ID in this list are ever routed to this SMSC. Multiple entries are separated with semicolons (';') preferred-smsc-id id-list SMS messages with SMSC ID from this list are sent to this SMSC instead than to SMSC without that ID as preferred. Multiple entries are separated with semicolons (';') allowed-prefix prefix-list A list of phone number prefixes which are accepted to be sent through this SMSC. Multiple entries are separated with semicolon (';'). For example, "040;050" prevents sending of any SMS message with prefix of 040 or 050 through this SMSC. If denied-prefix is unset, only these numbers are allowed. If set, number are allowed if present in allowed or not in denied list. denied-prefix prefix-list A list of phone number prefixes which are NOT accepted to be sent through this SMSC. preferred-prefix prefix-list As denied-prefix, but SMS messages with receiver starting with any of these prefixes are preferably sent through this SMSC. In a case of multiple preferences, one is selected at random (also if there are preferences, SMSC is selected randomly) unified-prefix prefix-list String to unify received phone numbers, for SMSC routing and to ensure that SMS centers can handle them properly. This is applied to 'sender' number when receiving SMS messages from SMS Center and for 'receiver' number when receiving messages from smsbox (either sendsms message or reply to original message). Format is that first comes the unified prefix, then all prefixes which are replaced by the unified prefix, separated with comma (','). For example, for Finland an unified-prefix "+358,00358,0;+,00" should do the trick. If there are several unified prefixes, separate their rules with semicolon (';'), like "+35850,050;+35840,040". Note that prefix routing is next to useless now that there are SMSC ID entries. To remove prefixes, use like "-,+35850,050;-,+35840,040". alt-charset number As some SMS Centers do not follow the standards in character coding, an alt-charset character conversion is presented. This directive acts different for specific SMSC types. Please see your SMSC module type you want to use for more details. alt-dcs boolean Optional data coding scheme value usage. Sets the 'alt-dcs' value for the sendsms HTTP interface to a fixed value for each SMS sent via this SMSC connection. If equals to yes, uses FX. If equals to no (default), uses 0X. our-host hostname Optional hostname or IP address in which to bind the connection in our end. TCP/IP connection only. log-file filename A file in which to write a log of the given smsc output. Hence this allows to log smsc specific entries to a separate file. log-level number 0..5 Minimum level of log-file events logged. 0 is for 'debug', 1 'info', 2 'warning, 3 'error' and 4 'panic' (see Command Line Options) reconnect-delay number Number of seconds to wait between single re-connection attempts. Hence all SMSC modules should use this value for their re-connect behavior. (Defaults to '10' seconds). reroute boolean If set for a smsc group, all inbound messages coming from this smsc connection are passed internally to the outbound routing functions. Hence this messages is not delivered to any connected box for processing. It is passed to the bearerbox routing as if it would have originated from an externally connected smsbox. (Defaults to 'no'). reroute-smsc-id string Similar to 'reroute'. Defines the explicit smsc-id the MO message should be passed to for MT traffic. Hence all messages coming from the the configuration group smsc are passed to the outbound queue of the specified smsc-id. This allows direct proxying of messages between 2 smsc connections without injecting them to the general routing procedure in bearerbox. reroute-receiver string Similar to 'reroute'. Defines the explicit smsc-id routes for specific receiver numbers of messages that are coming from this smsc connection. Format is that first comes the smsc-id to route the message to, then all receiver numbers that should be routed, separated with comma (','). For example, route receivers 111 and 222 to smsc-id A and 333 and 444 to smsc-id B would look like: "A,111,222; B,333,444". reroute-dlr boolean Indicate whether DLR's should be re-routed too, if one of above reroute rules are enabled. Please note, that SMSC-Module should support DLR sending. At time of writing none of SMSC-Module supports DLR sending. allowed-smsc-id-regex POSIX regular expression SMS messages with SMSC ID equal to any of the IDs in this set of SMSC IDs are always routed to this SMSC. See section on for details. denied-smsc-id-regex POSIX regular expression SMS messages with SMSC ID equal to any of the IDs in this set of SMSC IDs are never routed to this SMSC. See section on for details. preferred-smsc-id-regex POSIX regular expression SMS messages with SMSC ID in this set of SMSC IDs are sent to this SMSC as preferred. See section on for details. allowed-prefix-regex POSIX regular expression A set of phone number prefixes which are accepted to be sent through this SMSC. See section on for details. denied-prefix-regex POSIX regular expression A set of phone number prefixes which may not be sent through this SMSC. See section on for details. preferred-prefix-regex POSIX regular expression As denied-prefix-regex, but SMS messages with receiver matching any of these prefixes are preferably sent through this SMSC. In a case of multiple preferences, one is selected at random. See section on for details. max-sms-octets number Maximum allowed octets for this SMSC. If this maximum exceeds Kannel will split SMS into multiparts. Default: 140 dead-start boolean Optional, defines if the SMSC connection type is started in disconnected mode (dead). This allows SMSC to be connected at a later time with the add-smsc HTTP administration command. If set to 'true' the connection will start as 'dead' and will require a start-smsc command to activate it. Defaults to 'false' if not present. instances number The number of same instances of this group to be created. This allows to declare the config group one time in the configuration and to multiply it by this value for the numner of runtime instances. (default: 1)
In addition to these common variables there are several variables used by certain SMS center connections. Each currently supported SMS center type is explained below, with configuration group for each. Note that many of them use variables with same name, but most also have some specific variables. NOTE: SMS center configuration variables are a bit incomplete, and will be updated as soon as people responsible for the protocols are contacted. Meanwhile, please have patience. Nokia CIMD 1.37 and 2.0 Support for CIMD 1.37 is quite old and will be removed in a future version of Kannel. Please let us know if you still need it. group = smsc smsc = cimd host = 100.101.102.103 port = 600 smsc-username = foo smsc-password = bar The driver for CIMD2 is a "receiving SME" and expects the SMSC to be configured for that. It also expects the SMSC to automatically send stored messages as soon as Kannel logs in (this is the normal configuration). group = smsc smsc = cimd2 host = 100.101.102.103 port = 600 smsc-username = foo smsc-password = bar keepalive = 5 my-number = "12345" Variable Value Description host (m) hostname Machine that runs the SMSC. As IP (100.100.100.100) or hostname (their.machine.here) port (m) port-number Port number in the smsc host machine smsc-username (m) string Username in the SMSC machine/connection account smsc-password (m) string Password in the SMSC machine needed to contact SMSC keepalive number SMSC connection will not be left idle for longer than this many seconds. The right value to use depends on how eager the SMSC is to close idle connections. If you see many unexplained reconnects, try lowering this value. Set it to 0 to disable this feature. no-dlr boolean Optional. If defined, status delivery report requests (DLR) won't be requested at all. Some CIMD2 SMSC have prohibited these reports so if you are getting error like "Incorrect status report request parameter usage", this option is for you. Defaults to "false". my-number string The number that the SMSC will add in front of the sender number of all messages sent from Kannel. If Kannel is asked to send a message, it will remove this prefix from the sender number so that the SMSC will add it again. If the prefix was not present, Kannel will log a warning and will not send the sender number. If my-number is not set, or is set to "never", then Kannel will not send the sender number to the SMSC at all. If you want Kannel to pass all sender numbers to the SMSC unchanged, then just set sender-prefix to the empty string "". our-port port-number Optional port number in which to bind the connection in our end. CMG UCP/EMI 4.0 and 3.5 See for changes. Kannel supports two types of connections with CMG SMS centers: direct TCP/IP connections ( emi) and ISDN/modem (X.25) connection (emi_x25). emi_x25 is an old implementation and supports less features than it's IP counterpart. If you still need this module, please tell us to devel@kannel.org so we can fix it. Sample configurations for these are: group = smsc smsc = emi host = 103.102.101.100 port = 6000 smsc-username = foo smsc-password = bar keepalive = 55 our-port = 600 (optional bind in our end) receive-port = 700 (the port in which the SMSC will contact) idle-timeout = 30 group = smsc smsc = emi_x25 phone = ... device = /dev/tty0 smsc-username = foo smsc-password = bar Variable Value Description host (c) hostname Machine that runs SMSC. As IP (100.100.100.100) or hostname (their.machine.here) port (c) port-number Port number in the SMSC host machine alt-host hostname Optional alternate Machine that runs SMSC. As IP (100.100.100.100) or hostname (their.machine.here) (If undef but exists alt-port, emi2 would try host:alt-port) alt-port port-number Optional alternate Port number in the SMSC host machine (If undef but exists alt-host, emi2 would try alt-host:port) smsc-username string Username in the SMSC machine/connection account smsc-password string Password in the SMSC machine needed to contact SMSC device (c) device-name The device the modem is connected to, like /dev/ttyS0. ISDN connection only. phone (c) string Phone number to dial to, when connecting over a modem to an SMS center. our-port port-number Optional port number in which to bind the connection in our end. TCP/IP connection only. our-receiver-port port-number Optional port number allowing to specify our port when connecting an SMSC. TCP/IP connection only. receive-port port-number Optional port number we listen to and to which the SMS center connects when it has messages to send. Required if SMS center needs one connection to send and other to receive. TCP/IP connection only. appname string Name of a "Send only" service. Defaults to send. All outgoing messages are routed through this service. connect-allow-ip IP-list If set, only connections from these IP addresses are accepted to receive-port. TCP/IP connection only. idle-timeout number (seconds) If this option is set to a value larger than 0, then the connection will be closed after the configured amount of seconds without activity. This option interacts with the keepalive configuration option. If keepalive is smaller than idle-timeout, then the connection will never be idle and those this option has no effect. If keepalive is larger than idle-timeout, than keepalive reopens the connection. This allows one to poll for pending mobile originated Short Messages at the SMSC. keepalive number (seconds) A keepalive command will be sent to the SMSC connection this many seconds after the last message. The right value to use depends on how eager the SMSC is to close idle connections. 50 seconds is a good guess. If you see many unexplained reconnects, try lowering this value. Set it to 0 to disable this feature. Requires username or my-number to be set. wait-ack number (seconds) A message is resent if the acknowledge from SMSC takes more than this time. Defaults to 60 seconds. wait-ack-expire number Defines what kind of action should be taken if the the ack of a message expires. The options for this value are: 0x00 - disconnect/reconnect, (default) 0x01 - as is now, re-queue, but this could potentially result in the msg arriving twice 0x02 - just carry on waiting (given that the wait-ack should never expire this is the must accurate) flow-control number This SMSC can support two types of flow control. The first type of flow control is a stop-and-wait protocol, when this parameter equals to '1'. During the handling of commands, no other commands shall be sent before the a response is received. Any command that is sent before the reception of the response will be discarded. The second type of flow control is windowing, when this parameter is unset or equals '0'. In this case a maximum of n commands can be sent before a response is received. window number (messages) When using flow-control=0, emi works in windowed flow control mode. This variable defines the size of the window used to send messages. (optional, defaults to the maximum - 100) my-number number If the large account number is different from the short number, assign it with this variable. For example, if short number is 12345 and large account is 0100100100101234 (IP+port), set my-number to 12345 and every message received will have that receiver. In addition, if you are bound to the SMSC without an explicit login, use this configuration directive to enable keep-alive (OP/31) operations. alt-charset number Defines which character conversion kludge may be used for this specific link. Currently implemented alternative charsets are defined in "alt_charsets.h" and new ones can be added. notification-pid 4 num char. Notification PID value. See below for a complete list and other notes. Example: 0539 If you set notification-pid, you should also set notification-addr. notification-addr string (max 16) Notification Address. Example: 0100110120131234. If you set notification-addr, you should also set notification-pid. You should use notification-pid and notification-addr if you need to inform your exact "address" to your smsc. For example, if you have a Multiple-Address (MA) account with several connections to the same short number, you may need to tell your smsc to send delivery reports to the exact instance that sent the message. This is required because if you send a message with instance 1, your instance 2 wouldn't know about it, unless you use a shared DB store for delivery reports. Notification PID Value Description 0100Mobile Station 0122Fax Group 3 0131X.400 0138Menu over PSTN 0139PC appl. over PSTN (E.164) 0339PC appl. over X.25 (X.121) 0439PC appl. over ISDN (E.164) 0539PC appl. over TCP/IP SMPP 3.3, 3.4 and 5.0 This implements Short Message Peer to Peer (SMPP) Protocol 5.0, with most used support for 3.4 and full support for 3.3. Sample configuration: group = smsc smsc = smpp host = 123.123.123.123 port = 600 smsc-username = "STT" smsc-password = foo system-type = "VMA" address-range = "" Variable Value Description host (m) hostname Machine that runs SMSC. As IP (100.100.100.100) or hostname (their.machine.here) port (m) port-number The port number for the TRANSMITTER connection to the SMSC. If set, receive-port must be ommited or set to 0. use-ssl bool Defines whether we should try to bind with SSL enabled connection to create a SSMPP (secure SMPP) session. ssl-client-certkey-file (c) filename A PEM encoded SSL certificate and private key file to be used for SSL connections. This option is used together with use-ssl for client certificate validation with SMPP SMSCs requiring it. transceiver-mode bool Use a TRANSCEIVER mode connection to the SMSC. It uses the standard transmit 'port' to define the port to connect to. This is a SMPP 3.4 and 5.0 feature and will not work on an earlier SMSC using SMPP 3.3. This will do a bind_transceiver only and will not attempt to fall back to doing transmit and receive on the same connection. receive-port port-number The port number for the RECEIVER connection to the SMSC. If set, port must be ommited or set to 0. smsc-username (m) string The 'username' of the Messaging Entity connecting to the SMSC. If the SMSC operator reports that the "TELEPATH SYSTEM MANAGER TERMINAL" view "Control.Apps.View" value "Name:" is "SMPP_ZAPVMA_T" for the transmitter and "SMPP_ZAPVMA_R" for the receiver the smsc-username value is accordingly "SMPP_ZAP". Note that this used to be called system-id (the name in SMPP documentation) and has been changed to smsc-username to make all Kannel SMS center drivers use the same name. smsc-password (m) string The password matching the "smsc-username" your teleoperator provided you with. system-type (m) string Optional; used to categorize the type of ESME that is binding to the SMSC. Examples include "VMS" (voice mail system) and "OTA" (over-the-air activation system). If not set, defaults to "VMA" (voice mail alerting). service-type string Optional; if specified, sets the service type for the SMSC. If unset, the default service type is used. This may be used to influence SMS routing (for example). The SMSC operator may also refer to this as the "profile ID". The maximum length of the service type is 6, according to the SMPP specification v3.4. Defined values are: "CMT" (cellular messaging), "CPT" (cellular paging), "VMN" (voice mail notification), "VMA" (voice mail alerting), "WAP" (wireless application protocol), "USSD" (unstructured supplementary services data), "CBS" (cell broadcast service) and "GUTS" (generic UDP transport service). Other values may be defined mutually between the SMSC and the ESME application. interface-version number Change the "interface version" parameter sent from Kannel to a value other then 0x34 (for SMPP v3.4). The value entered here should be the hexadecimal representation of the interface version parameter. For example, the default (if not set) is "34" which stands for 0x34. For SMPP v3.3 set to "33". For SMPP v5.0 set to "50". address-range (m) string According to the SMPP 3.4 spec this is supposed to affect which MS's can send messages to this account. Doesn't seem to work, though. my-number number Optional smsc short number. Should be set if smsc sends a different one. enquire-link-interval number Optional the time lapse allowed between operations after which an SMPP entity should interrogate whether it's peer still has an active session. The default is 30 seconds. max-pending-submits number Optional the maximum number of outstanding (i.e. acknowledged) SMPP operations between an ESME and SMSC. This number is not specified explicitly in the SMPP Protocol Specification and will be governed by the SMPP implementation on the SMSC. As a guideline it is recommended that no more than 10 (default) SMPP messages are outstanding at any time. reconnect-delay number Optional the time between attempts to connect an ESME to an SMSC having failed to connect initiating or during an SMPP session. The default is 10 seconds. source-addr-ton number Optional, source address TON setting for the link. (Defaults to 2). source-addr-npi number Optional, source address NPI setting for the link. (Defaults to 1). source-addr-autodetect boolean Optional, if defined tries to scan the source address and set TON and NPI settings accordingly. If you don't want to autodetect the source address, turn this off, by setting it to no. (Defaults to yes). dest-addr-ton number Optional, destination address TON setting for the link. (Defaults to 2). dest-addr-npi number Optional, destination address NPI setting for the link. (Defaults to 1). bind-addr-ton number Optional, bind address TON setting for the link. (Defaults to 0). bind-addr-npi number Optional, bind address NPI setting for the link. (Defaults to 0). msg-id-type number Optional, specifies which number base the SMSC is using for the message ID numbers in the corresponding submit_sm_resp and deliver_sm PDUs. This is required to make delivery reports (DLR) work on SMSC that behave differently. The number is a combined set of bit 1 and bit 2 that indicate as follows: bit 1: type for submit_sm_resp, bit 2: type for deliver_sm. If the bit is set then the value is in hex otherwise in decimal number base. Which means the following combinations are possible and valid: 0x00 deliver_sm decimal, submit_sm_resp decimal; 0x01 deliver_sm decimal, submit_sm_resp hex; 0x02 deliver_sm hex, submit_sm_resp decimal; 0x03 deliver_sm hex, submit_sm_resp hex. In accordance to the SMPP v3.4 specs the default will be a C string literal if no of the above values is explicitly indicated using the config directive. alt-charset string Defines which character encoding is used for this specific smsc link. Uses iconv() routines to convert from and to that specific character set encoding. See your local iconv_open(3) manual page for the supported character encodings and the type strings that should be presented for this directive. alt-addr-charset string Defines which character encoding is used for alphanumeric addresses. When set to GSM, addresses are converted into the GSM 03.38 charset (Since @ is translated into 0x00 which will break the SMPP PDU, @ replaced with ?). If set to another value, iconv() is used. (Defaults to windows-1252) connection-timeout number (seconds) This timer specifies the maximum time lapse allowed between transactions , after which period of inactivity, an SMPP driver may assume that the session is no longer active and does reconnect. Defaults to 300 seconds, to disable set it to 0. wait-ack number (seconds) A message is resent if the acknowledge from SMSC takes more than this time. Defaults to 60 seconds. wait-ack-expire number Defines what kind of action should be taken if the ack of a message expires. The options for this value are: 0x00 - disconnect/reconnect, (default) 0x01 - as is now, re-queue, but this could potentially result in the msg arriving twice 0x02 - just carry on waiting (given that the wait-ack should never expire this is the must accurate) validityperiod integer How long the message will be valid, i.e., how long the SMSC will try try to send the message to the recipient. Defined in minutes. esm-class number Change the "esm_class" parameter sent from Kannel. Accepted values are 0 (Default SMSC Mode) and 3 (Store and Forward). Defaults to 3. log-format number Selects which SMPP PDU dump format to use: 1 - for multiline (default) 2 - for one line Sema Group SMS2000 OIS 4.0, 5.0 and 5.8 The 4.0 implementation is over Radio PAD (X.28). Following configuration variables are needed, and if you find out the more exact meaning, please send a report. The 5.0 implementation uses X.25 access gateway. The 5.8 implementation uses direct TCP/IP access interface. group = smsc smsc = sema device = /dev/tty0 smsc_nua = (X121 smsc address) home_nua = (x121 radio pad address) wait_report = 0/1 (0 means false, 1 means true) Variable Value Description device (m) device ex: /dev/tty0 smsc_nua (m) X121 smsc address The address of an SMSC for SEMA SMS2000 protocols using an X.28 connection. home_nua (m) X121 radio pad address The address of a radio PAD implementing Sema SMS2000 using X.28 connection. wait_report 0 (false)/1 (true) Report indicator used by the Sema SMS2000 protocol. Optional. group = smsc smsc = ois host = 103.102.101.100 port = 10000 receive-port = 10000 ois-debug-level = 0 Variable Value Description host (m) ip SMSC Host name or IP port (m) port number SMSC Port number receive-port (m) port number The port in which the SMSC will contact ois-debug-level number 0 to 8 extra debug, optional, see smsc_ois.c group = smsc smsc = oisd host = 103.102.101.100 port = 10000 keepalive = 25 my-number = 12345 validityperiod = 30 Variable Value Description host (m) ip SMSC Host name or IP port (m) port number SMSC Port number keepalive number SMSC connection will not be left idle for longer than this many seconds. The right value to use depends on how eager the SMSC is to close idle connections. If you see many unexplained reconnects, try lowering this value. Set it to 0 to disable this feature. my-number string Any valid SME number acceptable by SMSC. This number is used only in keepalive request. validityperiod integer How long the message will be valid, i.e., how long the SMS center (the real one, not the phone acting as one for Kannel) will try to send the message to the recipient. Defined in minutes. SM/ASI (for CriticalPath InVoke SMS Center 4.x) This implements Short Message/Advanced Service Interface (SM/ASI) Protocol for the use of connecting to a CriticalPath InVoke SMS Center. Sample configuration: group = smsc smsc = smasi host = 10.11.12.13 port = 23456 smsc-username = foo smsc-password = foo Variable Value Description host (m) hostname Machine that runs SMSC. As IP (10.11.12.13) or hostname (host.foobar.com) port (m) port-number The port number for the connection to the SMSC. smsc-username (m) string The 'username' of the Messaging Entity connecting to the SMSC. smsc-password (m) string The password matching the "smsc-username" your teleoperator provided you with. reconnect-delay number Optional, the time between attempts to connect to an SMSC having failed to connect initiating or during an session. The default is 10 seconds. source-addr-ton number Optional, source address TON setting for the link. (Defaults to 1). source-addr-npi number Optional, source address NPI setting for the link. (Defaults to 1). dest-addr-ton number Optional, destination address TON setting for the link. (Defaults to 1). dest-addr-npi number Optional, destination address NPI setting for the link. (Defaults to 1). priority number Optional, sets the default priority of messages transmitted over this smsc link. (Defaults to 0, which is the lowest priority). GSM modem See for changes. This driver allows a GSM Modem or Phone to be connected to Kannel and work as a virtual SMSC group = smsc smsc = at modemtype = auto device = /dev/ttyS0 speed = 9600 pin = 2345 Variable Value Description modemtype string Modems from different manufacturers have slightly different behavior. We need to know what type of modem is used. Use "auto" or omit parameter to have Kannel detect the modem type automatically. (some types should not be auto-detected like the Nokia Premicell). device (m) device-name The device the modem is connected to, like /dev/ttyS0. When the device name is set to rawtcp or telnet two other variables are required in the configuration: host and port. See the note below. speed serial speed in bps The speed in bits per second. Default value 0 means to try to use speed from modem definition, or if it fails, try to autodetect. pin string This is the PIN number of the SIM card in the GSM modem. You can specify this option if your SIM has never been used before and needs to have the PIN number entered. The PIN is usually a four digit number. validityperiod integer How long the message will be valid, i.e., how long the SMS center (the real one, not the phone acting as one for Kannel) will try to send the message to the recipient. Encoded as per the GSM 03.40 standard, section 9.2.3.12. Default is 167, meaning 24 hours. keepalive seconds Kannel would "ping" the modem for this many seconds. If the probe fails, try to reconnect to it. my-number number Optional phone number. sms-center number SMS Center to send messages. sim-buffering boolean Whether to enable the so-called "SIM buffering behavior" of the GSM module. if assigned a true value, the module will query the message storage memory of the modem and will process and delete any messages found there. this does not alter normal behavior, but only add the capability of reading messages that were stored in the memory for some reason. The type of memory to use can be selected using the 'message-storage' parameter of the modem configuration. Polling the memory is done at the same interval as keepalive (if set) or 60 seconds (if not set). NOTE: This behavior is known to cause minor or major hiccups for a few buggy modems. Modems known to work with this setting are Wavecom WM02/M1200 and the Siemens M20. max-error-count integer Maximal error count for opening modem device or initializing of the modem before reset-string will be executed. This is useful when modem crashed and needs hard reset. Default disabled. host IP address Hostname or IP address to connect in rawtcp mode. Required if device is set to rawtcp. port integer TCP port to connect to on rawtcp-host. Required if device is set to rawtcp. smsc-username string Username to use on a Login: or User: prompt prior to be connected to the modem. Useful if modem is connected to a terminal server and rawtcp mode or telnet mode are used. smsc-password string Username to use on a Password prompt prior to be connected to the modem. Useful if modem is connected to a terminal server and rawtcp mode or telnet mode are used. smsc-password can be used alone without smsc-username for devices only asking for a password. login-prompt string An alternative string to be used instead of Login: or Username: password-prompt string An alternative string to be used instead of Password: Modem definitions are now multiple groups present in kannel.conf, either directly or, for example, by including the example modems.conf. (See ) Variable Value Description group modems This is a mandatory variable id string This is the the id that should be used in modemtype variable from AT2 name string The name of this modem configuration. Used in logs detect-string string String to use when trying to detect the modem. See detect-string2 detect-string2 string Second string to use to detect the modem. For example, if the modem replies with "SIEMENS MODEM M20", detect-string could be "SIEMENS" and detect-string2 "M20" init-string string Optional initialization string. Defaults to "AT+CNMI=1,2,0,1,0" speed number Serial port hint speed to use. Optional. Defaults to smsc group speed or autodetect enable-hwhs string Optional AT command to enable hardware handshake. Defaults to "AT+IFC=2,2" hardware-flow-control boolean Optionally disable hardware handshake on the computer side by setting it to false. Defaults to true. need-sleep boolean Optional. Defaults to false. Some modems needs to sleep after opening the serial port and before first command no-pin boolean Optional. Defaults to false. If the modem doesn't support the PIN command, enable this no-smsc boolean Optional. Defaults to false. If the modem doesn't support setting the SMSC directly on the PDU, enable this. (Default is to include a "00" at the beginning of the PDU to say it's the default smsc, and remove the "00" when receiving) sendline-sleep number (milliseconds) Optional, defaults to 100 milliseconds. The sleep time after sending a AT command. keepalive-cmd string Optional, defaults to "AT". If keepalive is activated in AT2 group, this is the command to be sent. If your modem supports it, for example, use "AT+CBC;+CSQ", and see in logs the reply "+CBC: 0,64" (0=On battery, 64% full) and "+CSQ: 14,99" (0-31, 0-7: signal strength and channel bit error rate; 99 for unknown). See 3GPP 27007. message-storage string Message storage memory type to enable for "SIM buffering". Possible values are: "SM" - SIM card memory or "ME" - Mobile equipment memory (may not be supported by your modem). check your modem's manual for more types. By default, if the option is not set, no message storage command will be sent to the modem and the modem's default message storage will be used (usually "SM"). message-start string Optional integer, defaults to 1. Specifies starting index in SIM buffer for new SMS. Most modems start numbering from 1, however a few like the UMG181 start numbering from 0. This parameter ensures that all SMS are fetched when using "SIM buffering". enable-mms boolean Optional, defaults to false. If enabled, Kannel would send an AT+CMMS=2 if it have more than one message on queue and hopefully will be quicker sending the messages. reset-string string Which reset string to execute when max-error-count reached. Example for Falcom: AT+CFUN=1 A note about delivery reports and GSM modems: while it is possible (and supported) to receive delivery reports on GSM modems, it may not work for you. if you encounter problems, check that your modem's init string (if not the default) is set to correctly allow the modem to send delivery reports using unsolicited notification (check your modem's manual). If the init-string is not set as si, some modems will store delivery reports to SIM memory, to get at which you will need to enable sim-buffering. finally your GSM network provider may not support delivery reports to mobile units. About rawtcp mode: This mode allows you to use a GSM modem connected to a remote terminal server, such as Perle IOLAN DS1 or a Cisco router with reverse telnet. The teminal server should support raw TCP mode. The driver is not tested in telnet mode. It is recommended to use keepalive variable, in order to automatically reconnect in case of network connectivity problems. Modem initialization This question has been asked frequently in the users mailing list. It usually comes in two forms: Modem doesn't receive or transmit SMS. In its current implementation, the at driver will panic if it cannot find the modem device and bearerbox won't start. This can happen either because the wrong modem device is configured or the device has no write access for kannel's user. In the first case use system logs to discover where is your modem assigned to: grep tty /var/log/messages Then verify that this is indeed your GSM modem device by connecting to it with minicom or wvdial and issuing a few AT commands. Wvdial is preferrable, since it can also give you a working init-string In the second case you need to give write access to kannel user. This is no problem if you run kannel as root, but it is not recommended to do so. In Ubuntu linux you just need to assign kannel user to group "dial". In other systems you can either: chmod 666 /dev/modem or preferably: chmod 664 /dev/modem chgrp group /dev/modem usermod -G group kannel-user Modem doesn't receive DLRs or SMS. By default the modem doesn't know how to treat incoming messages. To tell it to send it to kannel you have to configure init-string with the +CNMI=x,x,x,x,x command. X's are decimal numbers and CNMI stands for Command New Message Indication. There is no hard rule about its values. They are model and manufacturer specific. Best to consult modem manual or manufacturer's web site. Failing that, wvdialconf might give a working CNMI. Finally see modems.conf for examples and try out different values. Some Nokia phones do not support this command, but are ready to transmit incoming messages from the start. Since this setting is modem specific, kannel cannot understand what it means from its value, and if using unconventional values you should tell kannel through sim-buffering and message-storage. In any case it is useful to add +CMEE = 1 or 2 in the init-string in order to make the modem more verbose in its responses. group = modems init-string = "AT+CNMI=2,3,0,1,0;+CMEE=1" message-storage = ME or SM Depending on your modem, you may need to adjust it ... group = smsc smsc = at sim-buffering = true This will tell kannel to search for messages in ... the modem (either memory or its SIM) GSMA OneAPI v1.0 ParlayX SMS SOAP This implements the GSMA OneAPI v1.0 ParlayX SMS SOAP/XML interface in two flavors, the Ericsson SDP (service delivery platform) ParlayX and the GSMA OneAPI v1.0 SOAP interfaces. Example configuration for the Ericsson SDP variant: group = smsc smsc = parlayx system-type = ericsson-sdp port = 10000 connect-allow-ip = 10.11.12.13 send-url = http://host/location dlr-url = http://our-host:10000/dlr-location smsc-username = tester smsc-password = foobar Variable Value Description system-type (m) string Type of ParlayX connection. Currently supported are: 'oneapi-v1', 'ericsson-sdp'. The variants have the same ParlayX SOAP XML PDUs, but differ in the authentication scheme they use, where 'ericsson-sdp' uses WS-Security via wsse and 'oneapi-v1' uses plain HTTP basic authentication. port (m) port-number Port number in which Kannel listens to (MO and DLR) messages from other SOAP service side. send-url (m) url Location of the SOAP service to send MT messages. dlr-url (m) url Location of our side SOAP service for DLR notifications. smsc-username (m) string Username associated for the SOAP service connection. smsc-password (m) string Password associated for the SOAP service username. use-ssl boolean Defines whether listen port should use SSL. connect-allow-ip IP-list IPs allowed to use this SOAP service interface. If not set, "127.0.0.1" (localhost) is the only host allowed to connect. Typically you will allow the IP of the other side SOAP service here. window boolean Number of concurrent sending threads. If not set, one thread is used. Fake SMSC Fake SMSC is a simple protocol to test out Kannel. It is not a real SMS center, and cannot be used to send or receive SMS messages from real phones. So, it is ONLY used for testing purposes. group = smsc smsc = fake port = 10000 connect-allow-ip = 127.0.0.1 Variable Value Description host (m) hostname Machine that runs the SMSC. As IP (100.100.100.100) or hostname (their.machine.here) port (m) port-number Port number in smsc host machine connect-allow-ip IP-list If set, only connections from these IP addresses are accepted. HTTP-based relay and content gateways This special "SMSC" is used for HTTP based connections with other gateways and various other relay services, when direct SMSC is not available. group = smsc smsc = http system-type = kannel smsc-username = nork smsc-password = z0rK port = 13015 send-url = "http://localhost:20022" Variable Value Description system-type (m) string Type of HTTP connection. Currently supported are: 'kannel', 'brunet', 'xidris', 'clickatell' and 'generic'. send-url (m) url Location to send MT messages. This URL is expanded by used system, if need to. no-sender boolean Do not add variable sender to the send-url. no-coding boolean Do not add variable coding to the send-url. no-sep boolean Represent udh and text as a numeric string containing the hex-dump. For instance, text=%2b123 is represented as text=2b313233. port (m) port-number Port number in which Kannel listens to (MO) messages from other gateway use-ssl boolean Defines whether listen port should use SSL. connect-allow-ip IP-list IPs allowed to use this interface. If not set, "127.0.0.1" (localhost) is the only host allowed to connect. smsc-username string Username associated to connection, if needed. Kannel requires this, and it is the same as send-sms username at other end. smsc-password string Password for username, if needed. max-pending-submits number Optional the maximum number of outstanding (i.e. acknowledged) requests. As a guideline it is recommended that no more than 10 (default) requests are outstanding at any time. The "generic" system-type For a generic HTTP-based relay, the system-type 'generic' can be used. It can use the escape codes known from sms-service's get-url config directives in the send-url string to indicate the HTTP API calling style of the remote HTTP server, and the 3 HTTP body response parsing regular expressions 'status-success-regex' for successfull acknowledge, 'status-permfail-regex' for permanent failure and 'status-tempfail-regex' for temporary failure. It can also accomodate the incoming parameters and response codes and text. This system-type has a lot of extra parameters that gives it a lot of flexibility: Variable Value Description status-success-regex (o) POSIX regular expression Regular expression to match against HTTP response body content, indicating a successful submission. status-permfail-regex (o) POSIX regular expression Regular expression to match against HTTP response body content, indicating a permanent failure. status-tempfail-regex (o) POSIX regular expression Regular expression to match against HTTP response body content, indicating a temporary failure. generic-foreign-id-regex (o) POSIX regular expression Regular expression to match against HTTP response body content to get the foreign message id in case of successful submission. generic-param-username (o) string Overrides the default parameter for the 'username' field used on incoming requests. generic-param-password (o) string Overrides the default parameter for the 'password' field used on incoming requests. generic-param-from (o) string Overrides the default parameter for the 'from' field used on incoming requests. generic-param-to (o) string Overrides the default parameter for the 'to' field used on incoming requests. generic-param-text (o) string Overrides the default parameter for the 'text' field used on incoming requests. generic-param-udh (o) string Overrides the default parameter for the 'udh' field used on incoming requests. generic-param-service (o) string Overrides the default parameter for the 'service' field used on incoming requests. generic-param-account (o) string Overrides the default parameter for the 'account' field used on incoming requests. generic-param-binfo (o) string Overrides the default parameter for the 'binfo' field used on incoming requests. generic-param-dlr-mask (o) string Overrides the default parameter for the 'dlr-mask' field used on incoming requests. generic-param-dlr-err (o) string Overrides the default parameter for the 'dlr-err' field used on incoming requests. generic-param-dlr-url (o) string Overrides the default parameter for the 'dlr-url' field used on incoming requests. generic-param-dlr-mid (o) string Overrides the default parameter for the 'dlr-mid' field used on incoming requests. generic-param-flash (o) string Overrides the default parameter for the 'flash' field used on incoming requests. generic-param-mclass (o) string Overrides the default parameter for the 'mclass' field used on incoming requests. generic-param-mwi (o) string Overrides the default parameter for the 'mwi' field used on incoming requests. generic-param-coding (o) string Overrides the default parameter for the 'coding' field used on incoming requests. generic-param-validity (o) string Overrides the default parameter for the 'validity' field used on incoming requests. generic-param-deferred (o) string Overrides the default parameter for the 'deferred' field used on incoming requests. generic-param-foreign-id (o) string Overrides the default parameter for the 'foreign-id' field used on incoming requests. generic-param-meta-data (o) string Overrides the default parameter for the 'meta-data' field used on incoming requests. generic-message-sent (o) string It allows you to set the text returned when a succesful request is made. If not set, defaults to 'Sent.'. Note that you can use all sms service escapes here, see for details. generic-status-sent (o) string Overrides the HTTP status code returned when a successful request is made. If not set, defaults to 202 (HTTP_ACCEPTED). generic-status-error (o) string Overrides the HTTP status code returned when a request is rejected for any reason. If not set, defaults to 202 (HTTP_ACCEPTED). An example for a 'generic' group looks like this: group = smsc smsc = http system-type = generic port = 13015 send-url = "http://www.foobar.com/mt.php?from=%P&to=%p&text=%b" status-success-regex = "ok" status-permfail-regex = "failure" status-tempfail-regex = "retry later" generic-foreign-id-regex = "<id>(.+)</id>" generic-param-from = "phoneNumber" generic-param-to = "shortCode" generic-message-sent = "Message sent with ID: %I" generic-status-sent = 200 generic-status-error = 404 Loopback SMSC (MT to MO direction switching) This special "SMSC" type can be used to route MT messages in bearerbox internally as MO input messages again. Therefore this tyoe is the MT wise counterpart of the 'reroute' functionality of the smsc group when MOs are re-routed as MTs. group = smsc smsc = loopback smsc-id = loop1 reroute-smsc-id = my_id Variable Value Description reroute-smsc-id (o) string Tag the rerouted MO with the given value for smsc-id instead of the canonical smsc-id value of the smsc group itself. Using multiple SMS centers If you have several SMS center connections (multiple operators or a number of GSM modems) you need to configure one smsc group per SMS center (or GSM modem). When doing this, you might want to use routing systems to rout messages to specific centers - for example, you have 2 operator SMS centers, and the other is much faster and cheaper to use. To set up routing systems, first give an unique ID for each SMS center - or if you want to treat multiple ones completely identical, give them identical ID. Then use preferred-smsc-id and denied-smsc-id to set up the routing to your taste. See also SMS PUSH settings ('sendsms-user' groups), below. Feature checklist Not all of Kannel's SMSC drivers support the same set of features. This is because they were written at different times, and new features are often only added to drivers that the feature author can test. The table in this section is an attempt to show exactly what features to expect from a driver, and to help identify areas where drivers need to be updated. Currently most of the entries are marked as "not tested" because the table is still new. SMSC driver features Feature cimd cimd2 emi emi_x25 smpp sema ois oisd at http fake smasi Can use DLR n y? y n y? n n y n n y y Can set DCSTo use mclass, mwi, coding and compress fields. ? ? y ? ? ? ? y y ? ? ? Can set Alt-DCS n n y n n n n n y n n ? Can set Validity ? ? y ? ? ? ? y y ? ? ? Can set Deferred ? ? y ? ? ? ? n n ? ? ? Can set PID n y y n y n n n y n n ? Can set RPI n y y n y n n n n n n ? Can send Unicode ? ? y ? ? ? ? y y ? ? ? Can send 8 bits ? ? y ? ? ? ? y y ? ? y Correctly send GSM alphabet ? ? y ? ? ? ? y ? ? ? ? Can set binfo / tariff class ? y ? ? ? ? ? n ? ? ? ? Can use throttling n n y n y n n n n y y y
SMSC driver internal features Feature cimd cimd2 emi2 emi_x25 smpp sema ois oisd at http fake smasi Can keep idle connections alive n y? y n y? ? ? y y ? ? y Can send octet data without UDH n y? y y? n n y? y y n y?Does not mark it as octet data ? Can send octet data with UDH N y? y y? y? n ? y y y? y? ? Can send text messages with UDH n y? y y? n n ? y y n y? ? Can receive octet data without UDH n y? y n n y?However, it looks like the sema driver can't receive text data. y? y y n n ? Can receive Unicode messages n n y n n n n y y n n ? Can receive octet data with UDH n y? y n n n N y y y? y? ? Can receive text messages with UDH n y? y n n n N y y n n ? Correctly encodes @ when sending y? y? y ? y? ? y? y y y? y? ? Correctly encodes ä when sending y? y? y ? y? ? y? y y y? y? ? Correctly encodes { when sending n y? y ? y? ? n y NMiscalculates message length y? y? ? Can receive @ in text messages y? y? y ? y? ? y? y y y? y? ? Can receive ä in text messages y? y? y ? y? ? y? y y? y? y? ? Can receive { in text messages n y? y ? y? ? n y y? y? y? ? Can shut down idle connections n n y n n ? ? n ? ? ? ?
SymbolMeaning ? not yet investigated y driver has this feature, and it has been tested y? driver probably has this feature, has not been tested n driver does not have this feature N driver claims to have this feature but it doesn't work - feature is not applicable for this driver
External delivery report (DLR) storage Delivery reports are supported by default internally, which means all DLRs are stored in the memory of the bearerbox process. This is problematic if bearerbox crashes or you take the process down in a controlled way, but there are still DLRs open. Therefore you may use external DLR storage places, i.e. a MySQL database. Following are the supported DLR storage types and how to use them: Internal DLR storage This is the default way in handling DLRs and does not require any special configuration. In order to configure bearerbox to use internal DLR storage use dlr-storage = internal in the core group. MySQL DLR storage To store DLR information into a MySQL database you may use the dlr-storage = mysql configuration directive in the core group. In addition to that you must have a dlr-db group defined that specifies the table field names that are used to the DLR attributes and a mysql-connection group that defines the connection to the MySQL server itself. Here is the example configuration from doc/examples/dlr-mysql.conf: group = mysql-connection id = mydlr host = localhost username = foo password = bar database = dlr max-connections = 1 group = dlr-db id = mydlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc MySQL connection configuration For several reasons external storage may be required to handle dynamical issues, i.e. DLRs, sms-service, sendsms-user, ota-setting, ota-bookmark definitions and so on. To define a MySQL database connection you simple need to specify a mysql-connection group as follows: MySQL Connection Group Variables Variable Value Description group mysql-connection This is a mandatory variable id (m) string An optional name or id to identify this MySQL connection for internal reference with other MySQL related configuration groups. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. host (m) hostname or IP Hostname or IP of a server running a MySQL database to connect to. username (m) username User name for connecting to MySQL database. password (m) password Password for connecting to MySQL database. database (m) string Name of database in MySQL database server to connect to. max-connections integer How many connections should be opened to the given database. This is used for database pool.
A sample 'mysql-connection' group: group = mysql-connection id = dlr-db host = localhost username = foo password = bar database = dlr max-connections = 1 In case you use different MySQL connections for several storage issues, i.e. one for DLR and another different one for sms-service you may use the include configuration statement to extract the MySQL related configuration groups to a separate mysql.conf file.
LibSDB DLR storage To store DLR information into a LibSDB resource (which is an abstraction of a real database) you may use the dlr-storage = sdb configuration directive in the core group. In addition to that you must have a dlr-db group defined that specifies the table field names that are used to the DLR attributes and a sdb-connection group that defines the LibSDB resource itself. Here is the example configuration from doc/examples/dlr-sdb.conf using a PostgreSQL resource: group = sdb-connection id = pgdlr url = "postgres:host=localhost:db=myapp:port=1234" max-connections = 1 group = dlr-db id = pgdlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc Beware that you have the DB support build in your LibSDB installation when trying to use a specific DB type within the URL. Oracle 8i/9i DLR storage To store DLR information into a Oracle database you may use the dlr-storage = oracle configuration directive in the core group. In addition to that you must have a dlr-db group defined that specifies the table field names that are used to the DLR attributes and a oracle-connection group that defines the connection to the Oracle server itself. Here is the example configuration from doc/examples/dlr-oracle.conf: group = oracle-connection id = mydlr username = foo password = bar tnsname = dlr max-connections = 1 group = dlr-db id = mydlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc PostgreSQL DLR storage To store DLR information into a PostgreSQL database you may use the dlr-storage = pgsql configuration directive in the core group. In addition to that you must have a dlr-db group defined that specifies the table field names that are used to the DLR attributes and a pgsql-connection group that defines the connection to the PostgreSQL server itself. Here is the example configuration: group = pgsql-connection id = mydlr host = myhost.com username = foo password = bar database = dlr max-connections = 1 group = dlr-db id = mydlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc MS-SQL/Sybase DLR storage To store DLR information into a MS-SQL or Sybase (via FreeTDS) database you may use the dlr-storage = mssql configuration directive in the core group. In addition to that you must have a dlr-db group defined that specifies the table field names that are used to the DLR attributes and a mssql-connection group that defines the connection to the MS-SQL or Sybase server itself. Please note that the server configuration directive must match the corresponding [section] on freetds.conf Here is the example configuration: group = mssql-connection id = msdlr server = myservername username = foo password = bar database = dlr max-connections = 1 group = dlr-db id = msdlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc SQLite3 DLR storage To store DLR information into a SQLite3 database you may use the dlr-storage = sqlite3 configuration directive in the core group. In addition to that you must have a dlr-db group defined that specifies the table field names that are used to the DLR attributes and a sqlite3-connection group that defines the connection to the SQLite3 database itself. Here is the example configuration: group = sqlite3-connection id = mydlr database = /path/to/file max-connections = 1 group = dlr-db id = mydlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc Redis DLR storage To store DLR information using the Redis (http://www.redis.io) keystore, you should set the dlr-storage = redis configuration directive in the core group. In addition, you must have a dlr-db group defined that specifies the key and hash field names that are used to store the DLR attributes and a redis-connection group that defines the connection to the Redis server. Since Redis is a keystore and not a SQL database, keys and not tables are used to store DLR attributes. For ease of configuration, the same configuration parameters in the dlr-db group that are used to define SQL tables in other DLR storage engines are used to configure key names in Redis. DLRs are stored as Redis hash keys with a separate key for each DLR. Key names are in the format <table>:<smsc>:<timestamp>. Some SMSCs also append the destination to the DLR keyname resulting DLR keynames in the format <table>:<smsc>:<timestamp>:<destination>. You can specify the <table> portion of the keyname by specifying the table value in the dlr-db group. In addition to one key per DLR, an additional key with a name in the format <table>:Count is created to maintain a count of the total number of outstanding DLRs. Here is the example configuration from doc/examples/dlr-redis.conf: group = redis-connection id = mydlr host = localhost port = 6379 #password = foo database = 2 idle-timeout = 3600 max-connections = 1 group = dlr-db id = mydlr ttl = 604800 table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc Redis connection configuration To define a Redis connection you need to specify a redis-connection group as follows: Redis Connection Group Variables Variable Value Description group redis-connection This is a mandatory variable id (m) string An optional name or id to identify this Redis connection for internal reference with other Redis related configuration groups. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. host (m) hostname or IP Hostname or IP of a server running Redis to connect to. password password If the Redis server is secured with a password in redis.conf, it must be specified here. By default, Redis servers are unsecured and in that case, this parameter may be ommitted.database integer The numeric ID (0-15) of the Redis database to use. Ideally this database should be dedicated to storing Redis DLRs since a separate key wil be created for each DLR. If this variable is ommitted, the default database (0) will be used. idle-timeout integer The number of seconds that Redis should hold the connection open without any traffic. Some Redis servers are configured to disconnect idle clients very quickly, and if this is the case you should set this value to something more reasonable. If ommitted, the Redis server-wide timeout from redis.conf will apply. max-connections integer How many connections should be opened to the Redis server.
Cassandra DLR storage To store DLR information using Cassandra (http://cassandra.apache.org/) database, you should set the dlr-storage = cassandra configuration directive in the core group. In addition, you must have a dlr-db group defined that specifies the field names that are used to store the DLR attributes and a cassandra-connection group that defines the connection to Cassandra. Here is the example configuration from doc/examples/dlr-cassandra.conf: group = cassandra-connection id = mydlr host = localhost #username = foo #password = bar #database = dlr max-connections = 1 group = dlr-db id = mydlr ttl = 604800 table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc DLR database field configuration For external database storage of DLR information in relational database management systems (RDBMS) you will have to specify which table field are used to represent the stored data. This is done via the dlr-db group as follows: DLR Database Field Configuration Group Variables Variable Value Description group dlr-db This is a mandatory variable id (m) string An id to identify which external connection should be used for DLR storage. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. table (m) string The name of the table that is used to store the DLR information. field-smsc (m) string The table field that is used for the smsc data. field-timestamp (m) string The table field that is used for the timestamp data. field-destination (m) string The table field that is used for the destination number data. field-source (m) string The table field that is used for the source number data. field-service (m) string The table field that is used for the service username data. field-url (m) string The table field that is used for the DLR URL which is triggered when the DLR for this message arrives from the SMSC. field-mask (m) string The table field that is used for the DLR mask that has been set for a message. field-status (m) string The table field that is used to reflect the status of the DLR for a specific message. field-boxc-id (m) string The table field that is used to store the smsbox connection id that has passed the message for delivery. This is required in cases you want to guarantee that DLR messages are routed back to the same smsbox conn instance. This is done via the smsbox routing. If you don't use smsbox routing simply add this field to your database table and keep it empty.
A sample 'dlr-db' group: group = dlr-db id = dlr-db table = dlr field-smsc = smsc field-timestamp = ts field-source = source field-destination = destination field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc Beware that all variables in this group are mandatory, so you have to specify all fields to enable bearerbox to know how to store and retrieve the DLR information from the external storage spaces.
SMSBox configuration Smsbox group You must define an 'smsbox' group into the configuration file to be able to use SMS Kannel. The simplest working 'smsbox' group looks like this: group = smsbox bearerbox-host = localhost ...but you would most probably want to define 'sendsms-port' to be able to use SMS push. SMSBox inherits from core the following fields: smsbox-port http-proxy-port http-proxy-host http-proxy-username http-proxy-password http-proxy-exceptions http-proxy-exceptions-regex ssl-certkey-file Smsbox Group Variables Variable Value Description group (m) smsbox This is a mandatory variable bearerbox-host (m) hostname The machine in which the bearerbox is. bearerbox-port (o) port-number This is the port number to which smsbox will connect bearerbox. If not given smsbox-port from core group used. bearerbox-port-ssl (o) bool If set to true, the smsbox connection will be SSL-enabled. Your smsbox will connect using SSL to the bearerbox then. This is used to secure communication between bearerbox and smsboxes in case they are in separate networks operated and the TCP communication is not secured on a lower network layer. If not given smsbox-port-ssl from core group used. smsbox-id (o) string Optional smsbox instance identifier. This is used to identify an smsbox connected to an bearerbox for the purpose of having smsbox specific routing inside bearerbox. So if you you own boxes that do pass messages into bearerbox for delivery you may want that answers to those are routed back to your specific smsbox instance, i.e. SMPP or EMI proxying boxes. sendsms-interface (o) string If this is set, the sendsms HTTP interface will only bind to a specified address. For example: "127.0.0.1". sendsms-port (c) port-number The port in which any sendsms HTTP requests are done. As with other ports in Kannel, can be set as anything desired. sendsms-port-ssl (o) bool If set to true, the sendsms HTTP interface will use a SSL-enabled HTTP server with the specified ssl-server-cert-file and ssl-server-key-file from the core group. Defaults to "no". sendsms-url (o) url URL locating the sendsms service. Defaults to /cgi-bin/sendsms. sendota-url (o) url URL locating the sendota service. Defaults to /cgi-bin/sendota. immediate-sendsms-reply (o) boolean This is a backward compatibility flag: when set, Kannel will immediately answer to any sendsms requests, without knowing if the bearerbox will ever accept the message. If set to false (default), smsbox will not reply to HTTP request until the bearerbox has received the message. sendsms-chars string Only these characters are allowed in 'to' field when send-SMS service is requested via HTTP. Naturally, you should allow at least 0123456789. The space character (' ') has special meaning: it is used to separate multiple phone numbers from each other in multi-send. To disable this feature, do not have it as an accepted character. If this variable is not set, the default set "0123456789 +-" is used. global-sender phone-number If set, all sendsms originators are set as these before proceeding. Note that in a case of most SMS centers you cannot set the sender number, but it is automatically set as the number of SMSC log-file filename As with the bearerbox 'core' group. Access-log is used to store information about MO and send-sms requests. Can be named same as the 'main' access-log (in 'core' group). log-level number 0..5access-log filenamesyslog-level number Messages of this log level or higher will also be sent to syslog, the UNIX system log daemon. If not explicitly set with syslog-facility, it logs under the 'daemon' category. The default is not to use syslog, and you can set that explicitly by setting syslog-level to 'none'. syslog-facility string The syslog facility to send the syslog entries to. The default is 'daemon'. white-list URL Load a list of accepted destinations of SMS messages. If a destination of an SMS message is not in this list, any message received from the HTTP interface is rejected. See notes of phone number format from numhash.h header file. black-list URL As white-list, but SMS messages to these numbers are automatically discarded reply-couldnotfetch string If set, replaces the SMS message sent back to user when Kannel could not fetch content. Defaults to Could not fetch content, sorry.. reply-couldnotrepresent string If set, replaces the SMS message sent back when Kannel could not represent the result as a SMS message. Defaults to Result could not be represented as an SMS message.. reply-requestfailed string If set, replaces the SMS message sent back when Kannel could not contact http service. Defaults to Request Failed. reply-emptymessage string If set, replaces the SMS message sent back when message is empty. Set to "" to enable empty messages. Defaults to <Empty reply from service provider>. mo-recode boolean If enabled, Kannel will try to convert received messages with UCS-2 charset to WINDOWS-1252 or to UTF-8, simplifying external servers jobs. If Kannel is able to recode message, it will also change coding to 7 bits and charset to windows-1252 or to utf-8. http-request-retry integer If set, specifies how many retries should be performed for failing HTTP requests of sms-services. Defaults to 0, which means no retries should be performed and hence no HTTP request queuing is done. http-queue-delay integer If set, specifies how many seconds should pass within the HTTP queuing thread for retrying a failed HTTP request. Defaults to 10 sec. and is only obeyed if http-request-retry is set to a non-zero value. white-list-regex POSIX regular expression Defines the set of accepted destinations of SMS messages. If a destination of an SMS message is not in this set, any message received from the HTTP interface is rejected. See section on for details. black-list-regex POSIX regular expression As white-list-regex, but SMS messages to numbers within in this set are automatically discarded. See section on for details. max-pending-requests number of messages Maximum number of pending MO or DLR messages that are handled in parallel. (Default: 512) http-timeout seconds Sets socket timeout in seconds for outgoing client http connections. Optional. Defaults to 240 seconds. sms-length number Maximum allowed number of characters for a single SMS in smsbox. If this maximum exceeds Kannel will split SMS into multiparts. Default: 140
A typical 'smsbox' group could be something like this: group = smsbox bearerbox-host = localhost sendsms-port = 13131 sendsms-chars = "0123456789 " global-sender = 123456 access-log = "kannel.access" log-file = "smsbox.log" log-level = 0
Smsbox routing inside bearerbox The communication link between bearerbox and smsbox has been designed for the purpose of load-balancing via random assignment. Which means, bearerbox holds all smsc connections and passes inbound message to one of the connected smsboxes. So you have a determined route for outbound messages, but no determined route for inbound messages. The smsbox routing solves this for the inbound direction. In certain scenarios you want that bearerbox to know to which smsbox instance it should pass messages. I.e. if you implement own boxes that pass messages to bearerbox and expect to receive messages defined on certain rules, like receiver number or smsc-id. This is the case for EMI/UCP and SMPP proxies that can be written easily using smsbox routing facility. If you box handles the SMPP server specific communication to your EMSEs, and if an client send a submit_sm PDU, the box would transform the message into Kannel message representation and inject the message to bearerbox as if it would be an smsbox. As you want to assign your clients shortcodes for certain networks or route any inbound traffic from a certain smsc link connected to bearerbox, you need to separate in the scope of bearerbox where the inbound message will be going to. An example may look like this: group = smsbox ... smsbox-id = mysmsc ... group = smsbox-route smsbox-id = mysmsc shortcode = "1111;2222;3333" Which means any inbound message with receiver number 1111, 2222 or 3333 will be delivered to the smsbox instance that has identified itself via the id "mysmsc" to bearerbox. Using this routing the smsbox instance (which may be an EMI/UCP or SMPP proxy) is able to send a deliver_sm PDU. Another example showing the combination use of criteria smsc-id and shortcode looks like this: group = smsbox ... smsbox-id = mysmsc ... group = smsbox-route smsbox-id = mysmsc smsc-id = "A;B;C" shortcode = "1111;2222" Which means any inbound message with receiver number 1111 or 2222 that have been originating from the smsc-id connections A, B or C will be delivered to the via the id "mysmsc" to bearerbox. smsbox-route inherits from core the following fields: Smsbox-route Group Variables Variable Value Description group (m) smsbox-route This is a mandatory variable smsbox-id (m) string Defines for which smsbox instance the routing rules do apply. smsc-id word-list If set, specifies from which smsc-ids all inbound messages should be routed to this smsbox instance. List contains smsc-ids separated by semicolon (";"). This rule may be used to pull any smsc specific message stream to an smsbox instance. If used in combination with config directive shortcode, then this is another matching criteria for the routing decission. shortcode number-list If set, specifies which receiver numbers for inbound messages should be routed to this smsbox instance. List contains numbers separated by semicolon (";"). This rule may be used to pull receiver number specific message streams to an smsbox instance. If used in combination with config directive smsc-id, then only messages originating from the connections in the smsc-id are matched against the shortcode list.
SMS-service configurations Now that you have an SMS center connection to send and receive SMS messages you need to define services for incoming messages. This is done via 'sms-service' configuration groups. These groups define SMS services in the smsbox, so they are only used by the smsbox. Each service is recognized from the first word in an SMS message and by the number of arguments accepted by the service configuration (unless catch-all configuration variable is used). By adding a username and password in the URL in the following manner "http://luser:password@host.domain:port/path?query" we can perform HTTP Basic authentication. The simplest service group looks like this: group = sms-service keyword = www get-url = "http://%S" This service grabs any SMS with two words and 'www' as the first word, and then does an HTTP request to an URL which is taken from the rest of the message. Any result is sent back to the phone (or requester), but is truncated to the 160 characters that will fit into an SMS message, naturally. Service group default has a special meaning: if the incoming message is not routed to any other service, default 'sms-service' group is used. You should always define default service. Service group black-list has a special meaning: if the incoming message is in service's black-list, this service is used to reply to user. If unset, message will be discarded. SMS-Service Group Variables Variable Value Description group (m) sms-service This is a mandatory variable keyword (m) word Services are identified by the first word in the SMS. Each `%s' in the URL corresponds to one word in the SMS message. Words are separated with spaces. A keyword is matched only if the number of words in the SMS message is the same as the number of `%s' fields in the URL. This allows you to configure the gateway to use different URLs for the same keyword depending on the number of words the SMS message contains. The keyword is case insensitive, which means you don't have to use aliases to handle different cased versions of your keyword. keyword-regex POSIX regular expression This field may be used to enable service-selection based on a regular expression. You can define either keyword or keyword-regex in configuration, but not both in the same sms-service. keyword-regex is case sensitive. See section on for details. aliases word-list If the service has aliases, they are listed as a list with each entry separated with a semicolon (';'). Aliases are case insensitive just like keyword. name string Optional name to identify the service in logs. If unset, keyword is used. get-url (c) URL Requested URL. The url can include a list of parameters, which are parsed before the url is fetched. See below for these parameters. Also works with plain 'url' post-url (c) URL Requested URL. As above, but request is done as POST, not GET. Always matches the keyword, regardless of pattern matching. See notes on POST other where. post-xml (c) URL Requested URL. As above, but request is done as XML POST. Always matches the keyword, regardless of pattern matching. See notes on POST other where and file (c) filename File read from a local disc. Use this variable only if no url is set. All escape codes (parameters) in url are supported in filename. The last character of the file (usually linefeed) is removed. text (c) string Predefined text answer. Only if there is neither url nor file set. Escape codes (parameters) are usable here, too. exec (c) string Executes the given shell command as the current UID of the running smsbox user and returns the output to stdout as reply. Escape codes (parameters) are usable here, too. BEWARE: You may harm your system if you use this sms-service type without serious caution! Make sure anyone who is allowed to use these kind of services is checked using white/black-list mechanisms for security reasons. accepted-smsc id-list Accept ONLY SMS messages arriving from SMSC with matching ID. Even if this service is denied, Kannel still searches for other service which accepts the message, or default service. Separate multiple entries with ';'. For example, if accepted-smsc is "RL;SON", accept messages which originate from SMSC with ID set as 'RL' or 'SON' accepted-account id-list Accept ONLY SMS messages arriving with a matching ACCOUNT field. Even if this service is denied, Kannel still searches for other service which accepts the message, or default service. Separate multiple entries with ';'. For example, if accepted-account is "FOO;BAR", accept messages which originate with the ACCOUNT field set as 'FOO' or 'BAR' allowed-prefix prefix-list A list of phone number prefixes of the sender number which are accepted to be received by this service. Like in accepted-smsc, Kannel still searches for other service which accepts the message. This way there could be several services with the same keyword and different results. Multiple entries are separated with semicolon (';'). For example, "91;93" selects this service for these prefixes. If denied-prefix is unset, only this numbers are allowed. If denied is set, number are allowed if present in allowed or not in denied list. denied-prefix prefix-list A list of phone number prefixes of the sender number which are NOT accepted to be sent through this SMSC. allowed-receiver-prefix prefix-list A list of phone number prefixes of the receiver number which are accepted to be received by this service. This may be used to allow only inbound SMS to certain shortcut numbers to be allowed to this service. denied-receiver-prefix prefix-list A list of phone number prefixes of the receiver number which are NOT accepted to be sent through this SMSC. catch-all bool Catch keyword regardless of '%s' parameters in pattern. send-sender bool Used only with POST. If set to true, number of the handset is set, otherwise not. strip-keyword bool Used only with POST. Remove matched keyword from message text before sending it onward. faked-sender phone-number This number is set as sender. Most SMS centers ignore this, and use their fixed number instead. This option overrides all other sender setting methods. max-messages number If the message to be sent is longer than maximum length of an SMS it will be split into several parts. max-messages lets you specify a maximum number of individual SMS messages that can be used. If max-messages is set to 0, no reply is sent, except for error messages. accept-x-kannel-headers bool Request reply can include special X-Kannel headers but these are only accepted if this variable is set to true. See . assume-plain-text bool If client does not set Content-Type for reply, it is normally application/octet-stream which is then handled as data in Kannel. This can be forced to be plain/text to allow backward compatibility, when data was not expected. concatenation bool Long messages can be sent as independent SMS messages with concatenation = false or as concatenated messages with concatenation = true. Concatenated messages are reassembled into one long message by the receiving device. split-chars string Allowed characters to split the message into several messages. So, with "#!" the message is split from last '#' or '!', which is included in the previous part. split-suffix string If the message is split into several ones, this string is appended to each message except the last one. omit-empty bool Normally, Kannel sends a warning to the user if there was an empty reply from the service provider. If omit-empty is set to 'true', Kannel will send nothing at all in such a case. header string If specified, this string is automatically added to each SMS sent with this service. If the message is split, it is added to each part. footer string As header, but not inserted into head but appended to end. prefix string Stuff in answer that is cut away, only things between prefix and suffix is left. Not case sensitive. Matches the first prefix and then the first suffix. These are only used for url type services, and only if both are specified. suffix stringwhite-list URL Load a list of accepted senders of SMS messages. If a sender of an SMS message is not in this list, any message received from the SMSC is rejected, unless a black-list service is defined. See notes of phone number format from numhash.h header file. black-list URL As white-list, but SMS messages from these numbers are automatically discarded accepted-smsc-regex POSIX regular expression Accept only SMS messages arriving from SMSCs with a matching ID. Even if this service is denied, Kannel still searches for other service which accepts the message, or default service. See section on for details. accepted-account-regex POSIX regular expression Accept ONLY SMS messages arriving with a matching ACCOUNT field. Even if this service is denied, Kannel still searches for other service which accepts the message, or default service. See section on for details. allowed-prefix-regex POSIX regular expression A set of phone number prefixes of sender-numbers accepted by this service. Like in accepted-smsc-regex, Kannel still searches for another service which accepts the message. This way there could be several services with the same keyword and different results. See section on for details. denied-prefix-regex POSIX regular expression A set of phone number prefixes of sender-numbers which may not use this service. See section on for details. allowed-receiver-prefix-regex POSIX regular expression A set of phone number prefixes of receiver-numbers which may receive data sent by this service. This can be used to allow only inbound SMS to certain shortcut numbers to be allowed to this service. See section on for details. denied-receiver-prefix-regex POSIX regular expression A set of phone number prefixes of receiver-numbers which may not receive data sent by this service. See section on for details. white-list-regex POSIX regular expression Defines a set of accepted senders of SMS messages. If a sender of an SMS message is not in this list, the message is rejected. See section on for details. black-list-regex POSIX regular expression As white-list-regex, but SMS messages from these numbers are automatically discarded. See section on for details. alt-charset string Defines which character encoding is used for the SMS message when passed to a remote HTTP application. This includes how the SMS message text is send in the HTTP GET parameter list and in the HTTP POST bidy. Uses iconv() routines to convert from and to that specific character set encoding. See your local iconv_open(3) manual page for the supported character encodings and the type strings that should be presented for this directive. dlr-url string (URL) Optional Defines a default URL which is fetched for DLR event, if no specific X-Kannel HTTP header parameter is returned by the HTTP response. dlr-mask number (bit mask) Optional. Defines a default DLR event bit mask which is used in combination with the dlr-url config directive, if no specific X-Kannel HTTP header parameter is returned by the HTTP response.
Parameters (Escape Codes) %k the keyword in the SMS request (i.e., the first word in the SMS message) %s next word from the SMS message, starting with the second one (i.e., the first word, the keyword, is not included); problematic characters for URLs are encoded (e.g., '+' becomes '%2B') %S same as %s, but '*' is converted to '~' (useful when user enters a URL) and URL encoding isn't done (all others do URL encode) %r words not yet used by %s; e.g., if the message is "FOO BAR FOOBAR BAZ", and the has been one %s, %r will mean "FOOBAR BAZ" %a all words of the SMS message, including the first one, with spaces squeezed to one %b the original SMS message, in a binary form (URL-encoded) %e the original SMS message, in a binary form (printable hexadecimal byte codes). I.e. "xyz" would be send as byte codes "78797A". %t the time the message was sent, formatted as "YYYY-MM-DD HH:MM", e.g., "1999-09-21 14:18" %T the time the message was sent, in UNIX epoch timestamp format %p the phone number of the sender of the SMS message %P the phone number of the receiver of the SMS message %q like %p, but a leading `00' is replaced with `+' %Q like %P, but a leading `00' is replaced with `+' %i the smsc-id of the connection that received the message %I the SMS ID of the internal message structure %d the delivery report value %R the delivery report URL value %N the delivery report notification message %D meta-data from the SMSC. See for more into. %A the delivery report SMSC reply, if any %F the foreign (smsc-provided) message ID. Only relevant on DLR url's. %n the sendsms-user or sms-service name %c message coding: 0 (default, 7 bits), 1 (8 bits) or 2 (Unicode) %m message class bits of DCS: 0 (directly to display, flash), 1 (to mobile), 2 (to SIM) or 3 (to SIM toolkit). %M mwi (message waiting indicator) bits of DCS: 0 (voice), 1, (fax), 2 (email) or 3 (other) for activation and 4, 5, 6, 7 for deactivation respectively. %C message charset: for a "normal" message, it will be "GSM" (coding=0), "binary" (coding=1) or "UTF-16BE" (coding=2). If the message was successfully recoded from Unicode, it will be "WINDOWS-1252" %u udh of incoming message %B billing identifier/information of incoming message. The value depends on the SMSC module and the associated billing semantics of the specific SMSC providing the information. For EMI2 the value is the XSer 0c field, for SMPP MO it is the service_type of the deliver_sm PDU, and for SMPP DLR it is the DLR message err component. (Note: This is used for proxying billing information to external applications. There is no semantics associated while processing these.) %o account identifier/information of incoming message. The value depends on the SMSC module and has been introduced to allow the forwarding of an operator ID from aggregator SMSCs to the application layer, hence the smsbox HTTP calling instance. %O DCS (Data coding schema) value. %f Originating SMSC of incoming message. The value is set if the AT driver is used to receive a SMS on a gsm modem. The value of %f will contain the number of the SMSC sending the SMS to the SIM card. Other SMSC types than AT do not set this field so it will be empty. %x the smsbox-id of the message, identifying from which smsbox connection the message is originating. (Only available withing the access-log-format directive) %v Validity period in minutes. Available only if SMSC supports and sent this value. %V Deferred in minutes. Available only if SMSC supports and sent this value. %# This allows to pass meta-data individual parameters into urls. The syntax is as follows: %#group#parameter# For example: %#smpp#my_param# would be replaced with the value 'my_param' from the group 'smpp' coming inside the meta_data field.
Some sample 'sms-service' groups: group = sms-service keyword = nop text = "You asked nothing and I did it!" catch-all = true group = sms-service keyword = complex get-url = "http://host/service?sender=%p&text=%r" accept-x-kannel-headers = true max-messages = 3 concatenation = true group = sms-service keyword = default text = "No action specified"
How sms-service interprets the HTTP response When an sms-service requests a document via HTTP, it will accept one of four types of content types: text/plain Blanks are squeezed into one, rest is chopped to fit an SMS message. text/html Tags are removed, rest is chopped to fit an SMS message. text/vnd.wap.wml Processed like HTML. text/xml Processed as a POST-XML. See application/octet-stream The body will be transmitted as the SMS message, as 8-bit data. This can be avoided by setting assume-plain-text variable on for the SMS-service. Extended headers Kannel uses and accepts several X-Kannel headers to be used with SMS-services, if option accept-x-kannel-headers was provided in the relevant 'sms-service' group. X-Kannel Headers SMSPush equivalent X-Kannel Header username X-Kannel-Usernamepassword X-Kannel-Passwordfrom X-Kannel-Fromto X-Kannel-Totext request bodycharset charset as in Content-Type: text/html; charset=ISO-8859-1udh X-Kannel-UDHsmsc X-Kannel-SMSCflash X-Kannel-Flash (deprecated, see X-Kannel-MClassmclass X-Kannel-MClassmwi X-Kannel-MWIcompress X-Kannel-Compresscoding X-Kannel-Coding. If unset, defaults to 0 (7 bits) if Content-Type is text/plain , text/html or text/vnd.wap.wml. On application/octet-stream, defaults to 8 bits (1). All other Content-Type values are rejected.validity X-Kannel-Validitydeferred X-Kannel-Deferreddlr-mask X-Kannel-DLR-Maskdlr-url X-Kannel-DLR-Urlaccount X-Kannel-Accountpid X-Kannel-PIDalt-dcs X-Kannel-Alt-DCSbinfo X-Kannel-BInforpi X-Kannel-RPIpriority X-Kannel-Prioritymeta-data X-Kannel-Meta-Data
Kannel POST Kannel can do POST if service is contains a post-url="...". X-Kannel Post Headers Parameter (escape code) equivalent X-Kannel Header Notes %p (from) X-Kannel-From Only sent if send-sender is true %P (to) X-Kannel-To %t (time) X-Kannel-Time %u (udh) X-Kannel-UDH in hex format: 06050415820000%i (smsc) X-Kannel-SMSC - (mclass) X-Kannel-MClass - (pid) X-Kannel-PID - (alt-dcs) X-Kannel-Alt-DCS - (mwi) X-Kannel-MWI %c (coding) X-Kannel-Coding 0=7 Bits, 1=8 Bits, 2=UCS-2- (compress) X-Kannel-Compress - (validity) X-Kannel-Validity - (deferred) X-Kannel-Deferred %n (service name) X-Kannel-Service %D (meta-data) X-Kannel-Meta-Data Meta-Data (Only SMPP TLV's supported at the moment)%a or %r (text) request body Kannel send all words (%a) unless strip-keyword is true%C (charset) present in Content-Type HTTP Example: Content-Type: text/plain; charset=ISO-8859-1
XML Post Kannel can send and receive XML POST with the following format: <?xml version="1.0"?> <!DOCTYPE ...> <message> <submit> <da><number>destination number (to)</number></da> <oa><number>originating number (from)</number></oa> <ud>user data (text)</ud> <udh>user data header (udh)</udh> <meta-data>meta-data</meta-data> <dcs> <mclass>mclass</mclass> <coding>coding</coding> <mwi>mwi</mwi> <compress>compress</compress> <alt-dcs>alt-dcs</alt-dcs> </dcs> <pid>pid</pid> <rpi>rpi</rpi> <vp> <delay>validity time in minutes</delay> </vp> <timing> <delay>deferred time in minutes</delay> </timing> <statusrequest> <dlr-mask>dlr-mask</dlr-mask> <dlr-url>dlr-url</dlr-url> </statusrequest> <!-- request from application to Kannel --> <from> <user>username</user> <username>username</username> <pass>password</pass> <password>password</password> <account>account</account> </from> <to>smsc-id</to> <!-- request from Kannel to application --> <from>smsc-id</from> <to>service-name</to> </submit> </message> Don't forget to set POST Content-Type to text/xml! There could be several da entries for sendsms-user to enable multi-recipient messages. da doesn't make sense in sms-service. udh is the same format as X-Kannel-UDH. Example: <udh>06050415820000</udh>. On Kannel->application, from is the smsc-id that message arrives and to is the service name. On application->Kannel, from contains the credentials ( user/username, pass/password and account and to corresponds to the smsc-id to submit the message. user and username are equivalent and only one of them should be used. (same for pass and password. When application POST in Kannel, as in GET, only user, pass and da are required. Everything else is optional. (oa could be needed too is there's no default-sender or forced-sender. This is experimental code. XML format could and should change to fully met IETF's sms-xml standard (yet in draft) and additional tags needed by Kannel should be pondered.
SendSMS-user configurations To enable an SMS push, you must set sendsms-port into the 'smsbox' group and define one or more 'sendsms-user' groups. Each of these groups define one account, which can be used for the SMS push, via HTTP interface (see below) SendSMS-User Group Variables Variable Value Description group (m) sendsms-user This is a mandatory variable username (m) string Name for the user/account. password (m) string Password for the user (see HTTP interface, below) name string As in 'sms-service' groups. user-deny-ip IP-list As other deny/allow IP lists, but for this user (i.e. this user is not allowed to do the SMS push HTTP request from other IPs than allowed ones). If not set, there is no limitations. user-allow-IP IP-listforced-smsc string Force SMSC ID as a 'string' (linked to SMS routing, see 'smsc' groups) default-smsc string If no SMSC ID is given with the send-sms request (see below), use this one. No idea to use with forced-smsc. default-sender phone-number This number is set as sender if not set by from get/post parameter faked-sender phone-number As in 'sms-service' groups max-messages numberconcatenation boolsplit-chars stringsplit-suffix stringomit-empty boolheader stringfooter stringallowed-prefix prefix-list A list of phone number prefixes which are accepted to be sent using this username. Multiple entries are separated with semicolon (';'). For example, "040;050" prevents sending of any SMS message with prefix of 040 or 050 through this SMSC. If denied-prefix is unset, only this numbers are allowed. If set, number are allowed if present in allowed or not in denied list. denied-prefix prefix-list A list of phone number prefixes which are NOT accepted to be sent using this username. white-list URL Load a list of accepted destinations of SMS messages. If a destination of an SMS message is not in this list, any message received from the HTTP interface is rejected. See notes of phone number format from numhash.h header file. black-list URL As white-list, but SMS messages from these numbers are automatically rejected. dlr-url URL URL to be fetched if a dlr-mask CGI parameter is present. allowed-prefix-regex POSIX regular expression A set of phone numbers which are accepted to be sent using this username. See section on for details. denied-prefix-regex POSIX regular expression A set of phone numbers which may not send using this username. See section on for details. white-list-regex POSIX regular expression Defines a set of accepted destinations of SMS messages. If a destination of an SMS message is not in this list, any message received from the HTTP interface is rejected. See section on for details. black-list-regex POSIX regular expression As white-list-regex, but SMS messages originating from a number matching the pattern are discarded. See section on for details.
Some sample 'sendsms-user' groups: group = sendsms-user username = simple password = elpmis group = sendsms-user username = complex password = 76ftY user-deny-ip = "*.*.*.*" user-allow-ip = "123.234.123.234" max-messages = 3 concatenation = true forced-smsc = SOL The second one is very limited and only allows a user from IP "123.234.123.234". On the other hand, the user can send a longer message, up to 3 SMSes long, which is sent as concatenated SMS.
Over-The-Air configurations To enable Over-The-Air configuration of phones or other client devices that support the protocol you need to configure a sendsms-user.ota-setting group is not necessary, you can send settings to the phone as a XML document, but this method is perhaps more suitable for continuous provisioning. If you want to send multiple OTA configurations through the smsbox and you do not want to send XML documents, you will have to declare a ota-id string to the different ota-setting groups. OTA Setting Group Variables Variable Value Description group ota-setting This is a mandatory variable ota-id string An optional name or id for the ota-setting. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. location URL The address of the HTTP server for your WAP services, i.e. http://wap.company.com service string Description of the service ipaddress IP IP address of your WAP gateway phonenumber phone-number Phone number used to establish the PPP connection speed number Connection speed: 9600 or 14400. Defaults to 9600. bearer string Bearer type: data or sms. Defaults to data. calltype string Call type: isdn or analog. Defaults to isdn. connection string Connection type: cont or temp. Cont uses TCP port 9201 and Temp uses UDP port 9200. Defaults to cont. pppsecurity on or off Enable CHAP authentication if set to on, PAP otherwise authentication normal or secure. Indicates whether WTLS should be used or not. Defaults to normal. login string Login name. secret string Login password
A sample 'ota-setting' group: group = ota-setting location = http://wap.company.com service = "Our company's WAP site" ipaddress = 10.11.12.13 phonenumber = 013456789 bearer = data calltype = analog connection = cont pppsecurity = off authentication = normal login = wapusr secret = thepasswd And a 'sendsms-user' to use with it. With concatenation enabled: group = sendsms-user username = otauser password = foo max-messages = 2 concatenation = 1 OTA Bookmark Group Variables Variable Value Description group ota-bookmark This is a mandatory variable ota-id string An optional name or id for the ota-bookmark. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. url URL The address of the HTTP server for your WAP services, i.e. http://wap.company.com name string Description of the service
A sample 'ota-bookmark' group: group = ota-bookmark ota-id = wap-link url = "http://wap.company.com" service = "Our company's WAP site" And a 'sendsms-user' to use with it, with the same conditions as for the 'ota-setting' group.
Setting up more complex services The basic service system is very limited - it can only answer to original requester and it cannot send UDH data, for example. This chapter explains some more sophisticated and complex SMS service setups. Redirected replies The basic service system always sends the answer back to original requester, but sometimes the content server needs to send something to other terminals or delay the answer. To create such systems, an SMS push is used. The idea is to get the initial request, but then send no reply. Instead, the reply (if any) is sent via HTTP sendsms-interface as SMS Push. This way the service application has full control of the return content, and can do all needed formatting beforehand. Note that when no reply is wanted, remember to set the variable max-messages to zero (0) so that no reply is sent, unless an error occurs. Simple sample: group = sms-service keyword = talk get-url = "http://my.applet.machine/Servlet/talk?sender=%p&text=%r" max-messages = 0 Setting up operator specific services Those running Kannel with several SMS centers might need to define services according to the relying SMS center. To achieve this, first you need to give an ID name for SMS center connections (see above). Then use the accepted-smsc variable to define which messages can use that service. group = sms-service keyword = weather accepted-smsc = SOL get-url = "http://my.applet.machine/Servlet/weather?sender=%p&operator=SOL&text=%r" Setting up multi-operator Kannel Sometimes there is a need for Kannel to listen to two (or more) distinct SMS centers, and messages must be routed to services according to where they came from, and replies likewise must return to same SMSC. This is done via smsc-id magic. Here is a shortened sample configuration, which handles to distinct SMS servers and services: group = smsc smsc-id = A denied-smsc-id = B ... group = smsc smsc-id = B denied-smsc-id = A ... group = sms-service accepted-smsc = A get-url = "..." group = sms-service accepted-smsc = B get-url = "..." As can be seen, the smsc-id is used to identify the SMS center from which the message came. Then, the denied-smsc-id variable is used to prevent messages originally from the other SMS center from being sent through the other one. Finally 'sms-service' groups are defined with accepted-smsc so that they only accept messages from certain SMS center. If you want to use SMS push services, requesters should then set the smsc request parameter, or 'sendsms-user' groups should be defined like this: group = sendsms-user username = operator_A password = foo forced-smsc = A group = sendsms-user username = operator_B password = bar forced-smsc = B Note that if your SMS centers do not set the sender phone number but rely on number transmitted, you should set faked-sender to all 'sendsms-user' groups.
Running SMS gateway Using the HTTP interface to send SMS messages After you have configured Kannel to allow the sendsms service, you can send SMS messages via HTTP, e.g., using a WWW browser. The URL looks something like this: http://smsbox.host.name:13013/cgi-bin/sendsms? username=foo&password=bar&to=0123456&text=Hello+world Thus, technically, you make an HTTP GET request. This means that all the information is stuffed into the URL. If you want to use this often via a browser, you probably want to make an HTML form for this. Kannel will answer to sendsms request with following codes and body texts: SMS Push reply codes Status Body Meaning 202 0: Accepted for delivery The message has been accepted and is delivered onward to a SMSC driver. Note that this status does not ensure that the intended recipient receives the message. 202 3: Queued for later delivery The bearerbox accepted and stored the message, but there was temporarily no SMSC driver to accept the message so it was queued. However, it should be delivered later on. 4xx (varies) There was something wrong in the request or Kannel was so configured that the message cannot be in any circumstances delivered. Check the request and Kannel configuration. 503 Temporal failure, try again later. There was temporal failure in Kannel. Try again later.
SMS Push (send-sms) CGI Variables username (or user) string Username or account name. Must be username of the one 'sendsms-user' group in the Kannel configuration, or results in 'Authorization failed' reply. password (or pass) string Password associated with given username. Must match corresponding field in the 'sendsms-user' group of the Kannel configuration, or 'Authorization failed' is returned. from string Phone number of the sender. This field is usually overridden by the SMS Center, or it can be overridden by faked-sender variable in the sendsms-user group. If this variable is not set, smsbox global-sender is used. to phone number list Phone number of the receiver. To send to multiple receivers, separate each entry with space (' ', '+' url-encoded) - but note that this can be deactivated via sendsms-chars in the 'smsbox' group. text string Contents of the message, URL encoded as necessary. The content can be more than 160 characters, but then sendsms-user group must have max-messages set more than 1. charset string Charset of text message. Used to convert to a format suitable for 7 bits or to UCS-2. Defaults to UTF-8 if coding is 7 bits and UTF-16BE if coding is UCS-2. udh string Optional User Data Header (UDH) part of the message. Must be URL encoded. smsc string Optional virtual smsc-id from which the message is supposed to have arrived. This is used for routing purposes, if any denied or preferred SMS centers are set up in SMS center configuration. This variable can be overridden with a forced-smsc configuration variable. Likewise, the default-smsc variable can be used to set the SMSC if it is not set otherwise. flash number Deprecated. See mclass. mclass number Optional. Sets the Message Class in DCS field. Accepts values between 0 and 3, for Message Class 0 to 3, A value of 0 sends the message directly to display, 1 sends to mobile, 2 to SIM and 3 to SIM toolkit. mwi number Optional. Sets Message Waiting Indicator bits in DCS field. If given, the message will be encoded as a Message Waiting Indicator. The accepted values are 0,1,2 and 3 for activating the voice, fax, email and other indicator, or 4,5,6,7 for deactivating, respectively. This option excludes the flash option. To set number of messages, use mwi=[0-3]&coding=0&udh=%04%01%02%<XX>%<YY>, where YY are the number of messages, in HEX, and XX are mwi plus 0xC0 if text field is not empty. compress number Optional. Sets the Compression bit in DCS Field. coding number Optional. Sets the coding scheme bits in DCS field. Accepts values 0 to 2, for 7bit, 8bit or UCS-2. If unset, defaults to 7 bits unless a udh is defined, which sets coding to 8bits. validity number (minutes) Optional. If given, Kannel will inform SMS Center that it should only try to send the message for this many minutes. If the destination mobile is off other situation that it cannot receive the sms, the smsc discards the message. Note: you must have your Kannel box time synchronized with the SMS Center. deferred number (minutes) Optional. If given, the SMS center will postpone the message to be delivered at now plus this many minutes. Note: you must have your Kannel box time synchronized with the SMS Center. dlrmask number (bit mask) Deprecated. See dlr-mask. dlr-mask number (bit mask) Optional. Request for delivery reports with the state of the sent message. The value is a bit mask composed of: 1: Delivered to phone, 2: Non-Delivered to Phone, 4: Queued on SMSC, 8: Delivered to SMSC, 16: Non-Delivered to SMSC. Must set dlr-url on sendsms-user group or use the dlr-url CGI variable. dlrurl string (url) Deprecated. See dlr-url. dlr-url string (url) Optional. If dlr-mask is given, this is the url to be fetched. (Must be url-encoded) pid byte Optional. Sets the PID value. (See ETSI Documentation). Ex: SIM Toolkit messages would use something like &pid=127&coding=1&alt-dcs=1&mclass=3 alt-dcs number Optional. If unset, Kannel uses the alt-dcs defined on smsc configuration, or 0X per default. If equals to 1, uses FX. If equals to 0, force 0X. rpi number Optional. Sets the Return Path Indicator (RPI) value. (See ETSI Documentation). account string Optional. Account name or number to carry forward for billing purposes. This field is logged as ACT in the log file so it allows you to do some accounting on it if your front end uses the same username for all services but wants to distinguish them in the log. In the case of a HTTP SMSC type the account name is prepended with the service-name (username) and a colon (:) and forwarded to the next instance of Kannel. This allows hierarchical accounting. binfo string Optional. Billing identifier/information proxy field used to pass arbitrary billing transaction IDs or information to the specific SMSC modules. For EMI2 this is encapsulated into the XSer 0c field, for SMPP this is encapsulated into the service_type of the submit_sm PDU. priority number Optional. Sets the Priority value (range 0-3 is allowed). (Defaults to 0, which is the lowest priority).
Using the HTTP interface to send OTA configuration messages OTA messages can be sent to mobile phones or devices to auto-configure the settings for WAP. They are actually complex SMS messages with UDH and sent as concatenated messages if too long (and compiled if necessary). You may either pass an HTTP request as GET method or POST method to the HTTP interface. If you want to send a configuration that is defined within Kannel's configuration file itself you have to pass a valid ota-id value otherwise the content of the request will be compiled to as OTA message. OTA settings and bookmark documents Here is an example XML document (this one contains CSD settings for logging in to a mobile service; note that you must store DTD locally): <?xml version="1.0"?> <!DOCTYPE CHARACTERISTIC-LIST SYSTEM "file:///gw/settings.dtd"> <CHARACTERISTIC-LIST> <CHARACTERISTIC TYPE="ADDRESS"> <PARM NAME="BEARER" VALUE="GSM/CSD"/> <PARM NAME="PROXY" VALUE="10.11.12.13"/> <PARM NAME="PORT" VALUE="9201"/> <PARM NAME="CSD_DIALSTRING" VALUE="+12345678"/> <PARM NAME="PPP_AUTHTYPE" VALUE="PAP"/> <PARM NAME="PPP_AUTHNAME" VALUE="yourusername"/> <PARM NAME="PPP_AUTHSECRET" VALUE="yourauthsecret"/> <PARM NAME="CSD_CALLTYPE" VALUE="ISDN"/> <PARM NAME="CSD_CALLSPEED" VALUE="9600"/> </CHARACTERISTIC> <CHARACTERISTIC TYPE="URL" VALUE="http://wap.company.com/"/> <CHARACTERISTIC TYPE="NAME"> <PARM NAME="NAME" VALUE="Your WAP Company"/> </CHARACTERISTIC> </CHARACTERISTIC-LIST> A bookmark document looks like this: <?xml version="1.0"?> <!DOCTYPE CHARACTERISTIC_LIST SYSTEM "file:///gw/settings.dtd"> <CHARACTERISTIC-LIST> <CHARACTERISTIC TYPE="BOOKMARK"> <PARM NAME="NAME" VALUE="WAP Company"/> <PARM NAME="URL" VALUE="http://wap.company.com/"/> </CHARACTERISTIC> </CHARACTERISTIC-LIST> Document type definition (DTD) for these documents is not available from Internet, you must supply it as a file. Kannel gw directory contains an example, settings.dtd. OTA syncsettings documents Used for the provisioning of sync configuration to SyncMl enabled handsets. Best supported by sonyericcsson terminals. Sample syncsettings documents to set contacts, connection data and authentication: <SyncSettings> <Version>1.0</Version> <HostAddr>http://syncml.server.com</HostAddr> <RemoteDB> <CTType>text/x-vcard</CTType> <CTVer>2.1</CTVer> <URI>contact</URI> <Name>Address Book</Name> </RemoteDB> <Name>Synchonization</Name> <Auth> <AuthLevel>1</AuthLevel> <AuthScheme>1</AuthScheme> <Username>yourusername</Username> <Cred>passwordbase64encoded</Cred> </Auth> </SyncSettings> OMA provisioning content OMA provisioning allows the configuration of a wider range of settings than previously available in OTA terminals. Refer to OMA-WAP-ProvCont-v1_1-20021112-C (at http://www.openmobilealliance.org/tech/docs/) for details. A shared secret (i.e. a pin or the phone IMSI) can be used to authenticate the settings. Defaults are 'userpin' and '1234' a. See the cgi variables 'sec' and 'pin' for available authentication options. GET method for the OTA HTTP interface An example URL (OTA configuration defined in the Kannel configuration file): http://smsbox.host.name:13013/cgi-bin/sendota? otaid=myconfig&username=foo&password=bar&to=0123456 URL containing XML document looks like this (you must URL encode it before sending it over HTTP): http://smsbox.host.name:13013/cgi-bin/sendota? username=foo&password=bar&to=0123456& text=MyURLEncodedXMLdocument&type=settings You can send either settings, bookmark, syncsettings, or oma-settings, set CGI variable type accordingly. Default for this variable is settings. OTA CGI Variables otaid string Name or ID of the 'ota-setting' group in Kannel configuration that should be sent to the phone. This variable is optional. If it is not given the first 'ota-setting' group is sent. This is unnecessary when a XML document is send to the phone. username string Username of the 'sendsms-user' group in Kannel configuration, that has been configured to send OTA messages. password string Password associated with given username. Must match corresponding field in 'sendsms-user' group in Kannel configuration, or 'Authorization failed' is returned. to number Number of the phone that is to receive the OTA configuration message. from string Phone number of the sender. This field is usually overridden by the SMS Center, or it can be overridden by faked-sender variable in the sendsms-user group. If this variable is not set, smsbox global-sender is used. smsc string Optional virtual smsc-id from which the message is supposed to have arrived. This is used for routing purposes, if any denied or preferred SMS centers are set up in SMS center configuration. This variable can be overridden with a forced-smsc configuration variable. Likewise, the default-smsc variable can be used to set the SMSC if it is not set otherwise. text XML document An URL encoded XML document, containing either settings or bookmarks. type string Type of the XML document, supported values are "settings", "bookmarks", "syncsettings", and "oma-settings". Default is "settings". sec string Security model used to authenticate oma-settings. One of: "userpin", "netwpin", "usernetwpin", or "userpinmac". pin number Authentication token.
Setting up Push Proxy Gateway This chapter explains how to set up a push proxy gateway (PPG). An example configuration file are given. A working push proxy gateway is described. Routing wap pushes to a certain smsc and asking for SMS level delivery reports are described. Configuring ppg core group, for push initiator (PI) interface PPG configuration group defines gateway's service interface. Configuring a PPG working with a trusted PI is easiest. Actually, you need no configuration at all: in this case a PPG with default values will be set up. Do not rely on this, default values may change. For PPG core configuration variables, see table 7.1. An example of a core configuration for PPG working only with specific addresses follows. Note that ppg-deny-ip-list is not actually necessary, but does make configuring simpler: IPs here are always denied, even when they are mentioned in the allowed IPs list. Ppg-url is a simple stamp, used for routing requests to the right service. You can change this stamp by setting push-url configuration variable. group = ppg ppg-url = /wappush ppg-port = 8080 concurrent-pushes = 100 users = 1024 ppg-allow-ip = 194.100.32.125;127.0.0.1 ppg-deny-ip = 194.100.32.89;194.100.32.103 trusted-pi = false PPG core group configuration variables Variable Value Description group ppg Mandatory value. Tells that we are configuring the PPG group. ppg-port number The port PPG is listening at. Default 8080. ppg-ssl-port (o) number Mandatory value for PPG HTTPS support. The port at which PPG listens for HTTPS requests. There are no defaults; you must set the value separately. ssl-server-cert-file string Mandatory value for PPG HTTPS support. The file containing server's ssl certificate. ssl-server-key-file string Mandatory value for PPG HTTPS support. The file containing server's ssl private key. ppg-url url URL locating PPG services. Default /wappush . global-sender string Sender phone number required by some protocols. concurrent-pushes number Number of concurrent pushes expected. Note that PPG does work even value is too low; it will only be slower. Default 100. users number Number of actually configured user accounts. Note that PPG does work even value is too low; it will only be slower. Default 1024. trusted-pi boolean If true, PI does authentication for PPG. Obviously, both of them must reside inside same firewall. Default true. If this variable is true, all security variables are ignored (even though they may be present). ppg-deny-ip ip-list PPG will not accept pushes from these IPs. Wild-cards are allowed. If this attribute is missing, no IP is denied by this list . ppg-allow-ip ip-list PPG will accept pushes from these, and only these, IPs. Wild-cards are allowed. Adding this list means that IPs not mentioned are denied, too. default-smsc string If no SMSC ID is given with the wappush HTTP request (see below), use this one as default route for all push messages. default-dlr string If no dlr url is given with the wappush HTTP request (see below), use this one as default route for all push messages. ppg-smsbox-id string All ppg delivery reports are handled by this smsbox. This routes all DLR messages inside beaerbox to the specified smsbox for processing the HTTP requests to the DLR-URL. service-name string This is sms service name used by smsbox for wap push. default-dlr string If no dlr url is given with the wappush HTTP request (see below), use this one as default route for all push messages. service-name string This is sms service name used by smsbox for wap push.. concatenation boolean Segment wap push binary sms. Default on. You need not normally set this value. max-messages integer Maximum number of sm messages generated. Default 10. You need not set this variable, expect when your push documents are very long.
Configuring PPG user group variables In addition of pi lists similar to the core group, ppg configuration specific to a certain user contains variables used for authentication and enforcing restrictions to phone numbers pi may contact. All variables are elaborated in table 7.2. As an example, let us see how to configure a ppg user (a pi, named here 'picom') allowed to send pushes only from a specified ip. group = wap-push-user wap-push-user = picom ppg-username = foo ppg-password = bar allow-ip = 62.254.217.163 It goes without saying that in real systems you must use more complex passwords than bar. PPG user group configuration variables Variable Value Description group wap-push-user Mandatory value. Tells that we are configuring the users group. wap-push-user string (More) human readable name of an user. ppg-username string Username for this user. ppg-password string Password for this user. allowed-prefix number-list Phone number prefixes allowed in pushes coming from this pi. These prefixes must conform international phone number format. denied-prefix number-list Phone number prefixes denied in pushes coming from this pi. These prefixes must conform international phone number format. white-list url Defines an url where from the white-list can be fetched. White list itself contains list of phone numbers accepting pushes from this pi. black-list url Defines an url where from the blacklist can be fetched. Blacklist itself contains list of phone number not accepting pushes from this pi. allow-ip ip-list Defines IPs where from this pi can do pushes. Adding this list means that IPs not mentioned are denied. deny-ip ip-list Defines IPs where from this pi cannot do pushes. IPs not mentioned in either list are denied, too. default-smsc string If no SMSC ID is given with the wappush HTTP request (see below), use this one as default route for this specific push user. forced-smsc string Allow only routing to a defined SMSC ID for this specific push user. dlr-url string If no dlr is given with the wappush HTTP request (see below), use this one as default route for this specific push user. smsbox-id string Smsbox handling delivery reports fro this user. forced-smsc string Allow only routing to a defined SMSC ID for this specific push user. white-list-regex POSIX regular expression Defines the set of phone-numbers accepting pushes from this pi. See section on for details. black-list-regex POSIX regular expression Defines the set of phone-numbers rejecting pushes from this pi. See section on for details. allowed-prefix-regex POSIX regular expression Set of phone number prefixes allowed in pushes coming from this pi. See section on for details. denied-list-regex POSIX regular expression Set of phone number prefixes denied in pushes coming from this pi. See section on for details.
Finishing ppg configuration PPG uses SMS for sending SI to the phone and an IP bearer to fetch content specified by it (see chapter Overview of WAP Push). This means both wapbox and bearer smsc connections are in use. So your push proxy gateway configuration file must contain groups core, wapbox, smsc and smsbox. These are configured normal way, only smsc group may have push-specific variables. Note that following configurations are only an example, you may need more complex ones. Bearerbox setup does not require any new variables: group = core admin-port = 13000 smsbox-port = 13001 wapbox-port = 13002 admin-password = b wdp-interface-name = "*" log-file = "filename" log-level = 1 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" unified-prefix = "00358,0" You must set up wapbox, for pulling (fetching) the wap data, and of course starting the push itself. No new variables here, either. group = wapbox bearerbox-host = localhost log-file = "filename" log-level = 0 syslog-level = none To set up smsc connections, for pushing SI or SL over SMS. Here HTTP SMSC is used as an example. Variables no-sender and no-coding simplify HTTP request generated by Kannel. Send-url specifies content gateway, or sendsms service. group = smsc smsc = http smsc-id = HTTP port = 10000 system-type = kannel smsc-username = foo smsc-password = bar no-sender = true no-coding = true send-url = http://host:port/path To set up smsbox. This is used for ppg delivery reports, see later. group = smsbox bearerbox-host = localhost smsbox-id = dlrbox Kannel sources contain a sample push configuration file gw/pushkannel.conf. Running a push proxy gateway Push proxy gateway is started by simply typing, using separate windows: gw/bearerbox [config-file] gw/wapbox [config-file] You can, of course, use more complex command line options. An example using HTTP SMSC An easy way to test and implement push services is to put ppg in the front of an existing sendsms service capable to send SMS data messages and to understand HTTP requests generated by HTTP SMSC. (See next chapter.) Then you need only configure SMSC configuration send-url to point to sendsms service. An example of minimum SI document Service indication (SI) should work with all types of phones, service loading does not. URL to be loaded is the main content of the document in both cases, however. Here an example (this is a minimum si document, not usable for testing, probably, but you want PPG to generate only one one SM per SI, if at all possible): <?xml version="1.0"?> <!DOCTYPE si PUBLIC "-//WAPFORUM//DTD SI 1.0//EN" "http://www.wapforum.org/DTD/si.dtd"> <si> <indication href="http://www.gni.ch" si-id="1@gni.ch"> You have 4 new emails </indication> </si> Note following points: a) Every SI must have different si-id. If there are none, href is used as an (very unsatisfactory) id. b) this si should not interrupt the phone's current action. An example push (tokenized SI) document HTTP SMSC generates a HTTP get request when it get a send-message event, expressed in Unicode. The content gateway, or the sendsms service must, of course, understand this URL. So here is an example, cgi variable text contains the url escaped form of a SI document. It is usable for testing prototype phones. http://matrix:8080/phplib/kannelgw.php?user=*deleted*& pass=*deleted*=to=%2B358408676001&text=3D%02%06%17%AE%96localhost %3A8080%00%AF%80%8D%CF%B4%80%02%05j%00E%C6%0C%03wap.iobox.fi%00%11%03 1%40wiral.com%00%07%0A%C3%07%19%99%06%25%15%23%15%10%C3%04+%02%060%01 %03Want+to+test+a+fetch%3F%00%01%01&udh=%06%05%04%0B%84%23%F0 Default network and bearer used by push proxy gateway If network and bearer attributes of the pap control document are missing or set any, Kannel uses address type for routing purposes: if the address type is a phone number (TYPE=PLMN), network defaults to GSM and bearer to SMS; if it is a IP-address (TYPE=IPv4), network defaults to GSM and bearer to CSD. So following minimal pap document works: <?xml version="1.0"?> <!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP//EN" "http://www.wapforum.org/DTD/pap_1.0.dtd"> <pap> <push-message push-id="9fjeo39jf084@pi.com"> <address address-value="WAPPUSH=+358408676001/TYPE=PLMN@ppg.carrier.com"/> </push-message> </pap> Push related Kannel headers This chapter recapitulates Kannel headers used by ppg. PPG uses many Kannel headers. These are very similar as ones used by smsbox. (Both send sms to to the phone, after all.) Kannel headers used by PPG Variable Value DescriptionX-Kannel-SMSC string Name of smsc used to deliver this push. Smsc configuration must contain some of corresponding variables, see X-Kannel-DLR-URL url Url smsbox would call this url when doing the delivery report. Note that it can contain all Kannel escapes. See table 6.7 for details.X-Kannel-DLR-Mask number Mask telling smsbox when it should do the delivery reports. Values are same as used by smsbox, see chapter Delivery Reports for details.X-Kannel-Smsbox-Id string Tells which smsbox does the delivery report. Smsbox configuration must contain corresponding variable.
Requesting SMS level delivery reports for WAP pushes Push content is a normal binary SM, so you can ask delivery reports for them. These are useful for testing purposes (did the phone get the content at all, or did it just reject it.) Another use is create fall-back services for phones not supporting displaying a specific push content. (MMS one being perhaps currently most obvious.) Generally speaking, this service is very similar to smsbox one. See chapter Delivery Reports for details. For ppg sms delivery reports you will need a fully working smsbox. Add configuration variable smsbox-id to smsbox group (it is necessary, because there is no MT from any smsbox corresponding the delivery report bearerbox is receiving): group = smsbox smsbox-id = dlrbox bearerbox-host = localhost log-file = "/var/log/kannel/smsbox-core.log" log-level = 0 access-log = "/var/log/kannel/smsbox-access.log" Start smsbox normal way after updating the configuration file. You must add to PPG configuration file two less obvious variables: ppg-smsbox-id and service-name. Ppg-smsbox-id defines smsbox through which you want to route delivery reports, service-name makes possible for smsbox to handle wap pushes as a separate sms service. Setting ppg-smsbox-id will route all ppg messages through same smsbox. You can route delivery reports of separate user through separate smsboxes, by using configuration variable smsbox-id in group wap push user. Or you can use X-Kannel-Smsbox-Id . This means routing every message separately. You can supply dlr url and dlr mask as kannel header, or as a configuration variable in ppg user or ppg core group. (This is order of precedence, too.) First one is valid for only one message, second for a specific user, and third for every ppg user. So following is a minimum ppg core group for sms delivery reports: group = ppg ppg-url = /wappush ppg-port = 8080 concurrent-pushes = 100 trusted-pi = true users = 1024 service-name = ppg ppg-smsbox-id = dlrbox And you can add Kannel headers to http post request. Here an example code snippet (C using Kannel gwlib; this example asks for all possible delivery reports). http_header_add(push_headers, "X-Kannel-SMSC", "link0"); http_header_add(push_headers, "X-Kannel-DLR-Url", "http://193.53.0.56:8001/notification-dlr?smsc-id=%i" "&status=%d&answer=%A&to=%P&from=%p&ts=%t"); http_header_add(push_headers, "X-Kannel-DLR-Mask", octstr_get_cstr(dos = octstr_format("%d", 31))); http_header_add(push_headers, "X-Kannel-Smsbox-Id", "dlrbox")); Here status=%d tells the type of the delivery report and answer=%A the delivery report itself (sms content of it). Other ones are needed to map delivery report to original wap push. With these you can use with following http post request http://193.53.0.56:8080/phplib/kannelgw.php?user=*deleted*& pass=*deleted*=to=%2B358408676001&text=3D%02%06%17%AE%96localhost %3A8080%00%AF%80%8D%CF%B4%80%02%05j%00E%C6%0C%03wap.iobox.fi%00%11%03 1%40wiral.com%00%07%0A%C3%07%19%99%06%25%15%23%15%10%C3%04+%02%060%01 %03Want+to+test+a+fetch%3F%00%01%01&udh=%06%05%04%0B%84%23%F0 Note that you can use all sms service escapes in dlrurl, see Parameters (Escape Codes) for details. If you want to set dlr url for a specific user, you must set configuration variable dlr-urlin wap-push-user, if for entire ppg, default-dlr-url in group ppg. Value must naturally match with one used in group smsc. Routing WAP pushes to a specific smsc This chapter explains how to route wap push to a specific smsc. Smsc routing for wap pushes is similar to sms pushes. So, firstly you must define configuration variable smsc-id in smsc group (or groups) in question. Say you used value link0. You can send this as a Kannel header: http_header_add(push_headers, "X-Kannel-SMSC", "link0"); Then you can issue a request: http://193.53.0.56:8080/phplib/kannelgw.php?user=*deleted*& pass=*deleted*=to=%2B358408676001&text=3D%02%06%17%AE%96localhost %3A8080%00%AF%80%8D%CF%B4%80%02%05j%00E%C6%0C%03wap.iobox.fi%00%11%03 1%40wiral.com%00%07%0A%C3%07%19%99%06%25%15%23%15%10%C3%04+%02%060%01 %03Want+to+test+a+fetch%3F%00%01%01&udh=%06%05%04%0B%84%23%F0 You can use configuration variables to route all messages of a specific user or all ppg messages. Set default-smsc in group wap-push-user or in group ppg. Again precedence of various methods of setting the smsc is kannel header, then configuration variable in group wap push user and then in group ppg.
Using SSL for HTTP This chapter explains how you can use SSL to ensure secure HTTP communication on both, client and server side. Beware that the gateway, is acting in both roles of the HTTP model: as HTTP client, i.e. for requesting URLs while acting as WAP gateway and while fetching information for the SMS services. as HTTP server, i.e. for the administration HTTP interface, the PPG and for the sendsms HTTP interface. That is why you can specify separate certification files within the core group to be used for the HTTP sides. You can use one or both sides of the SSL support. There is no mandatory to use both if only one is desired. Using SSL client support To use the client support please use the following configuration directive within the core group group = core ... ssl-client-certkey-file = "filename" Now you are able to use https:// scheme URLs within your WML decks and SMS services. Using SSL server support for the administration HTTP interface To use the SSL-enabled HTTP server please use the following configuration directive within the core group group = core ... admin-port-ssl = true ... ssl-server-cert-file = "filename" ssl-server-key-file = "filename" Using SSL server support for the sendsms HTTP interface To use the SSL-enabled HTTP server please use the following configuration directive within the core and smsbox groups group = core ... ssl-server-cert-file = "filename" ssl-server-key-file = "filename" group = smsbox ... sendsms-port-ssl = true Using SSL server support for PPG HTTPS interface If you want use PAP over HTTPS, (it is, a https scheme) add following directives to the ppg core group: group = ppg ... ppg-ssl-port = 8090 ssl-server-cert-file = "/etc/kannel/cert1.pem" ssl-server-key-file = "/etc/kannel/key1.pem" PPG uses a separate port for HTTPS traffic, so so you must define it. This means that you can use both HTTP and HTTPS, when needed. SMS Delivery Reports This chapter explains how to set up Kannel to deliver delivery reports. Delivery reports are a method to tell your system if the message has arrived on the destination phone. There are different things which can happen to a message on the way to the phone which are: Message gets rejected by the SMSC (unknown subscriber, invalid destination number etc). Message gets accepted by the SMSC but the phone rejects the message. Message gets accepted by the SMSC but the phone is off or out of reach. The message gets buffered. Message gets successfully delivered. If you want to use delivery reports, you must define a smsc-id for each smsc group. When you deliver SMS to Kannel you have to indicate what kind of delivery report messages you would like to receive back from the system. The delivery report types currently implemented are: 1: delivery success 2: delivery failure 4: message buffered 8: smsc submit 16: smsc reject If you want multiple report types, you simply add the values together. For example if you want to get delivery success and/or failure you set the dlr-mask value to 1+2. and so on. If you specify dlr-mask on the URL you pass on to Kannel you also need to specify dlr-url. dlr-url should contain the URL to which Kannel should place a HTTP requests once the delivery report is ready to be delivered back to your system. An example transaction would work as following. 1. you send a message using dlr-mask=7 and dlr-url=http://www.xyz.com/cgi/dlr.php?myId=123456&type=%d 2. Kannel forwards the message to the SMSC and keeps track of the message 3. The SMSC can not reach the phone and thus returns a buffered message 4. Kannel calls http://www.xyz.com/cgi/dlr.php?myId=123456&type=4 to indicate the message being buffered 5. The phone is switched on and the SMS gets delivered from the SMSC. The SMSC reports this to Kannel 6. Kannel calls http://www.xyz.com/cgi/dlr.php?myId=123456&type=1 to indicate the final success If you put your own message ID in the dlr-url like in the example above, you can then use this ID to update your database with the message status. Depending on the SMSC type not all type of messages are supported. For example a CIMD SMSC does not support buffered messages. Also some SMSC drivers have not implemented all DLR types. Getting help and reporting bugs This chapter explains where to find help with problems related to the gateway, and the preferred procedure for reporting bugs and sending corrections to them. The Kannel development mailing list is devel@kannel.org. To subscribe, send mail to devel-subscribe@kannel.org. This is currently the best location for asking help and reporting bugs. Please include configuration file and version number. Upgrading notes This appendix includes pertinent information about required changes on upgrades. From 1.2.x or 1.3.1 to 1.3.2 and later 1. at module was dropped and at2 module is now called at 2. emi module was renamed to emi_x25, emi_ip sub-module was dropped and emi2 is now called emi. Certificate generation This appendix includes pertinent information about required SSL certificate genaration, where needed. Self-signed 1024-bit RSA SSL certificates using openssl Generate private key: openssl genrsa -des3 -out server.key 1024 You will be asked for a passphrase. Generate a certificate request: openssl req -new -key server.key -out server.csr Several questions follow. At the end you may send server.csr to a certificate authority, which in turn will sign it and generate the certificate for you, or you can sign it yourself. Remove passphrase from key: cp server.key server.key.org openssl rsa -in server.key.org -out server.key rm server.key.org Self-sign the certificate: If you chose not to send the request to a Certificate Authority, you will need to sign it yourself. This one is good for 1 year: openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt Move keys to desired location: mv server.crt /etc/kannel/public/server.crt mv server.key /etc/kannel/private/server.key mv server.csr /etc/ianwap/private/ianwap.csr (key request) Update configuration accordingly Using the fake WAP sender This appendix explains how to use the fake WAP sender to test the gateway. Using the fake SMS center Fakesmsc is a simple testing tool to test out Kannel and its SMS services. It cannot be used to send messages to mobile terminals, it is just a simulated SMS center with no connection to real terminals. Setting up fakesmsc This section sums up needed steps to set up system for fakesmsc use. Compiling fakesmsc The fake SMS center should compile at the same time as main Kannel compiles. The outcome binary, fakesmsc, is in test directory. The source code is quite simple and trivial, and is easily edited. Configuring Kannel To use fakesmsc to test out Kannel, you have to add it to main configuration file (see above). The simplest form for this configuration group is like this: group = smsc smsc = fake port = 10000 The fakesmsc configuration group accepts all common 'smsc' configuration group variables, like smsc-id, preferred-smsc-id or denied-smsc-id, which can be used to test out routing systems and diverted services, before setting up real SMS center connections. If you include a fakesmsc group when bearerbox is connected to real SMS centers, you should add the connect-allow-ip variable to prevent unauthorized use. To set up multiple fakesmsc'es, just add new groups. Remember to put a different port number to each one. Running Kannel with fakesmsc connections After configuring Kannel, you can start testing it. The bearerbox will listen for fakesmsc client connections to the port(s) specified in the configuration file. Starting fake SMS center Each fakesmsc is started from command line, with all sent messages after command name. If any options are used (see below), they are put between the command and the messages. The usage is as follows: test/fakesmsc [options] <message1> [message2 ...] Options and messages are explained below, but as a quick example, a typical startup can go like this: test/fakesmsc -i 0.1 -m 100 "100 200 text nop" "100 300 text echo this" This tells fakesmsc to connect to bearerbox at localhost:10000 (default) and send a hundred messages with an interval of 0.1 seconds. Each message is from number 100, and is either to number 200 with message 'nop' or to 300 with message 'echo this'. Messages received from bearerbox are shown in the same format (described below). Fake messages Each message consists of four or five parts: sender number, receiver number, type, udh (if present) and main message itself. Sender and receiver numbers do not mean anything except for log files and number-based routing in Kannel. The parts of a message are separated with spaces. As each message is taken as one argument, it must be put in quotation marks. Message type must be one of the following: "text", "data", "ucs2", "udh-data", "udh-text", "route" and "dlr-mask". Here are some examples: test/fakesmsc -i 0.01 -v 1 -m 1000 "100 300 text echo this message" test/fakesmsc -i 0.01 -m 1000 "100 300 data echo+these+chars%03%04%7f" test/fakesmsc -m 1 "100 500 udh-data %0eudh+stuff+here main+message" For "text", the rest of the argument is taken as the literal message. For "data", the next part must be the url-encoded version of the message. Space is coded as '+'. For "ucs2", the next part must be the url-encoded version of the message. For "udh-data", the next 2 parts are the UDH and main message. Both must be in url-encoded form. For "udh-text", the UDH part must be url-encoded, and the message is taken as literals. For "route" both values are literal, where the first value defines the smsbox route destination. For "dlr-mask" noth values are literal, where the first value defines the numerical DLR event. If multiple messages are given, fakesmsc randomly chooses one for each sending. Interactive mode If no messages are passed on the command line when starting fakesmsc, it runs on "interactive mode". When running on this mode, fakesmsc accept single messages typed on stdin (without quotation marks) and displays the responses on stdout. This allows for a more finely controlled interaction with the backend applications. Fakesmsc command line options Fake SMS center can be started with various optional command line arguments. Fakesmsc command line options Switch Value Description -H host Use host host instead of default localhost. -r port Use port number port instead of default 10000. -i interval Use message interval interval (in seconds, fractions accepted) instead of default interval 1.0 seconds. -m max Send a maximum of max messages. Value -1 means that an unlimited number of messages is sent. Default -1. Using 0 can be useful to listen for messages sent via other channels.
In addition, fakesmsc accepts all common Kannel like --verbosity.
Setting up a test environment for Push Proxy Gateway This appendix explains how to set a test environment for PPG. This contains a simulated SMSC, for instance a http server simulation (this is used as example, because it is simplest) and a simulated push initiator. Between them, there is the push proxy gateway to be tested. This means that you must configure HTTP SMSC. Creating push content and control document for testing Here is an example of a push control document, which gives PPG instructions how to do the pushing. <?xml version="1.0"?> <!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP//EN" "http://www.wapforum.org/DTD/pap_1.0.dtd"> <pap> <push-message push-id="9fjeo39jf084@pi.com" deliver-before-timestamp="2001-09-28T06:45:00Z" deliver-after-timestamp="2001-02-28T06:45:00Z" progress-notes-requested="false"> <address address-value="WAPPUSH=+358408676001/TYPE=PLMN@ppg.carrier.com"/> <quality-of-service priority="low" delivery-method="unconfirmed" network-required="true" network="GSM" bearer-required="true" bearer="SMS"/> </push-message> </pap> Because the push content is send to the phone over SMS, right value for network-required and bearer-required is true, for network GSM and for bearer SMS. However, you can omit these values altogether, if you use a phone number as an address. Address value is international phone number and it must start with plus. It is used here as an unique identifier, SMSC, or sendsms script must transform it to an usable phone number. Here is an example of Service Indication, a type of push content. Essentially, the phone displays, when it receives this SI, the text "Want to test a fetch" and if the user wants, fetches the content located by URL http://wap.iobox.fi. <?xml version="1.0"?> <!DOCTYPE si PUBLIC "-//WAPFORUM//DTD SI 1.0//EN" "http://www.wapforum.org/DTD/si.dtd"> <si> <indication href="http://wap.iobox.fi" si-id="1@wiral.com" action="signal-high" created="1999-06-25T15:23:15Z" si-expires="2002-06-30T00:00:00Z"> Want to test a fetch? </indication> </si> Note that the date value of the si-expires attribute contains trailing zeroes. They are OK here, because SI tokenizer removes them. But phones does not accept them in the final SMS data message. You should probably use action="signal-high" for testing purposes, for it causes an immediate presentation of the push message. Production usage is a quite another matter. Another example of push content is Service Loading. In principle, the phone should fetch immediately content from URL http://wap.iobox.fi when it receives this document. This sounds quite insecure, and indeed, user invention is probably required before fetching. <?xml version="1.0"?> <!DOCTYPE sl PUBLIC "-//WAPFORUM//DTD SL 1.0//EN" "http://www.wapforum.org/DTD/sl.dtd"> <sl href="http://wap.iobox.fi" action="execute-high"> </sl> Starting necessary programs PPG test environment contains, in addition of wapbox and bearerbox, two test programs, test_ppg (simulating push initiator) and test_http_server (simulating a SMSC center accepting pushed content send over SMS. You can find both of these programs in test directory, and they both are short and easily editable. To set up a test environment, you must first configure a push proxy gateway (setting flag trusted-pi true makes testing easier). This explained in Chapter "Setting up push proxy gateway". Then issue following commands, in Kannel's root directory and in separate windows: gw/bearerbox [config-file] gw/wapbox [config-file] Of course you can use more complicated wapbox and bearerbox command line options, if necessary. To run a http smsc, start http server simulation: test/test_http_server -p port You can, of course, select the port at will. Remember, though, that PPG listens at the port defined in the ppg configuration file. Other test_http_server options are irrelevant here. Lastly, start making push requests, for instance with a test program test_ppg. Its first argument is a URL specifying location of push services. Other arguments are two file names, first one push content and second one pap control document. (For command line options, see Table C.1.). For example doing one push(you can simplify push url by setting a ppg configuration variable, see "Setting up push proxy gateway"; q flag here prevents dumping of test_ppg program debugging information): test/test_ppg -q http://ppg-host-name:ppg-port/ppg-url [content_file] [control_file] This presumes that you have set trusted-pi true. If you want use authentication in a test environment, you can pass username and password either using headers (setting flag -b) or url (you must have set trusted-pi false and added wap-push-user configuration group): test/test_ppg -q http://ppg-host-name:ppg-port?username=ppg-username'&' password=ppg-password [content_file] [control_file] Test_ppg's command line options Switch Value Description -c string Use content qualifier string instead of default si (service indication). Allowed values are wml, si, sl, sia, multipart, nil and scrap. Nil and scrap are used for debugging purposes. Wml does work with some older phone simulators. -a string Use application id string instead of default any. Application identifies the application in the phone that should handle the push request. Sia, ua, mms, nil and scrap are accepted. Nil and scrap are used for debugging purposes. -e string Use transfer encoding when sending a push content. Only base64 is currently supported. -b boolean Use headers for authentication, instead of url. Default off. -i number Wait interval number instead of default 0 between pushes. -r number Do number requests instead of default 1. -t number Use number threads instead of default 1. -s string Use string as a X-WAP-Application-Id header (You must supply whole header). -I string Use string as a X-WAP-Initiator-URI header (You must supply whole header). -B boolean If set, accept binary content. Default is off. 1. -d enumerated string Set delimiter to be used. Acceptable values are crlf and lf. Default is crlf. -p boolean If set, add an preamble (hard-coded one). Default is off. -E boolean if set, add an epilogue (hard-coded). Default is off.
Using Nokia Toolkit as a part of a developing environment This chapter describes a developing environment using Nokia Toolkit instead of test_http_server program. You cannot use a real phone for testing a push server. Sending random messages to a phone does not work, because its only feedback (if it works properly) in error situations is dropping the offending message. Nokia Toolkit, instead, displays push headers, decompiles tokenized documents and outputs debugging information. It is not, of course, a carbon copy of a real phone. But it is still useful for checking spec conformance of push servers. Toolkit runs on Windows, the first thing you must is to install a virtual machine (VMWare is one possibility) in the machine where Kannel runs. Then you must configure Toolkit for working with a push gateway. Then start bearerbox and wapbox similar way as told before. You must set the correct client address in the push document send by test_ppg program. Use IP address of our virtual machine (easiest way to get this is to ping your virtual machine name in the dos prompt window). Your bearer is in this case IP. An example pap document follows: <?xml version="1.0"?> <!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP//EN" "http://www.wapforum.org/DTD/pap_1.0.dtd"> <pap> <push-message push-id="9fjeo39jf084@pi.com" deliver-before-timestamp="2001-09-28T06:45:00Z" deliver-after-timestamp="2001-02-28T06:45:00Z" progress-notes-requested="false"> <address address-value="WAPPUSH=192.168.214.1/TYPE=IPV4@ppg.carrier.com"/> <quality-of-service priority="low" delivery-method="unconfirmed" </quality-of-service> </push-message> </pap> Note address-value format. It is contains type and value, because PAP protocol supports different address formats. You must use test_ppg's -a and -c flags when pushing messages to Toolkit. -A defines the client application handling pushes, right value for it is ua. -C defines the content type of your push message. SI works with all Toolkits, wml only with some older versions. Testing PAP protocol over HTTPS When testing HTTPS connection to PPG, you probably want use test_ppg's configuration file, because number of required parameters is quite high. Here is a example test_ppg configuration file: group = test-ppg retries = 2 pi-ssl = yes ssl-client-certkey-file = /etc/kannel/certkey.pem group = configuration push-url = https://localhost:8900/wappush pap-file = /etc/kannel/ipnoqos.txt content-file = /etc/kannel/si.txt username = foo password = bar With a configuration file, you can do a push by typing: test/test_ppg -q [configuration_file] Test_ppg's configuration file directives Directive Value Description group test_ppg Mandatory parameter. Start of test_ppg's core group. retries number The client tries to log in to PPG number times before discarding the push request. Default is 2. pi-ssl boolean Mandatory parameter for HTTPS connection. Does the client use HTTPS connection. Default is no. ssl-client-certkey-file filename Mandatory parameter for HTTPS connection. File containing the client's ssl certificate and private key. ssl-trusted-ca-file filename Mandatory parameter for HTTPS connection.This file contains the certificates test_ppg is willing to trust. If this directive is not set, certificates are not validated and HTTPS would not be tested. group configuration Mandatory parameter. Start of test_ppg's test group. push-url url Mandatory value. URL locating PPG's services. pap-file filename Mandatory value. File containing pap request's control document. content-file filename Mandatory value. File containing pap request's content document. username string Mandatory value. PPG service user's username. password string Mandatory value. PPG service user's password.
Setting up a dial-up line This appendix explains how to set up a dial-up line in Linux for use with the Kannel WAP gateway. In order for it to work you need a Linux kernel with PPP capabilities. Most distributions provides PPP kernel support by default. For more information how to compile PPP support into the kernel please read the "Linux Kernel HOWTO" at http://www.linuxdoc.org/. Analog modem This section explains how to set up a dial-up line with an analog modem. Download and install the mgetty package. rpm -ivh mgetty-VERSION-rpm To run mgetty as a daemon, add the following line to /etc/inittab. Read man inittab for more detailed information. In this example we assume your modem is connected to the serial port ttyS0 (COM 1). S0:2345:respawn:/sbin/mgetty ttyS0 -x 6 -D /dev/ttyS0 We need to start the pppd automatically when mgetty receives an AutoPPP request. Add the next line to /etc/mgetty+sendfax/login.config /AutoPPP/ - - /usr/sbin/pppd file /etc/ppp/options.server In /etc/mgetty+sendfax/mgetty.config you might need to change the connect speed between the computer and the modem. Note: this is not the connect speed between the WAP client and the server modem. If you are e.g. going to use a Nokia 7110 as the server side modem you need to change the speed to 19200. Usually you can just leave the speed to the default value (38400). speed 38400 Add the following lines to /etc/ppp/options.server refuse-chap require-pap lock modem crtscts passive 192.168.1.10:192.168.1.20 debug In /etc/ppp/pap-secrets add the username and password for the ppp account. The IP address is the one assigned to the phone. wapuser * wappswd 192.168.0.20 Configure your phone (this example is for Nokia 7110) homepage http:/yourhost/hello.wml connection type continuous connection security off bearer data dial up number (your phone number) ip address (IP of host running bearerbox) auth type normal data call type analogue data call speed 9600 username wapuser password wappswd ISDN terminal This section needs to be written Regular Expressions Note: this is not intended to be an introduction to regular expressions (short: regex) but a description of their application within Kannel. For general information regarding regexes please refer to . Syntax and semantics of the regex configuration parameter This section describes the regex-configuration parameters and their effects in combination with the respective non-regex-parameter, e.g. white-list and white-list-regex. How-to setup the regex-parameters examples, short syntax, what happens on errors Regex-parameters are configured just as every other parameter is configured. Regular expressions are supported as defined by POSIX Extended Regular Expressions. Suppose a configuration where only SMS messages originating from a sender using a number with a prefix of "040", "050", "070" or "090" are accepted. Without regexes the configuration would read allowed-prefix="040;050;070;090" Using regular expressions yields a more concise configuration allowed-prefix-regex=^0[4579]0 The following table gives an overview over some regex-operators and their meaning, the POSIX Regular Expressions manual page (regex(7)). Once again, the extended regex-syntax is used and the table is just meant as a means to give a quick-start to regular expressions, the next section features some more complex examples. Operator Meaning | or, for example "dog|hog" matches dog or hog. {number,number} repetition, for example "a{2,5}" matches - among others - "aa", "aaa" and "baaaaad" * shorthand for {0,} ? shorthand for {0,1} + shorthand for {1,} [] bracket expression, defines a class of possible single character matches. For example "[hb]og" matches "hog" and "bog". If the expression starts with ^ then the class is negated, e.g. "[^hb]og" does not match "hog" and "bog" but matches for example "dog". () groups patterns, e.g. "[hb]o(g|ld)" matches "hog", "hold", "bog", "bold" [:class:] A character class such as digit, space etc. See wctype(3) for details. ^ Start of line anchor. $ End of line anchor. The advantages of regular expressions are at hand Regexes are easier to understand, if one is fluent in POSIX Regular Expressions. Although simple expressions as shown above should be clear to everyone who has ever used a standard UN*X shell. Regexes are easier to maintain. Suppose the example above needed to cope with dozens of different prefixes each with subtle differences, in such cases using a - carefully constructed - regular expression could help to keep things in apple pie order. Furthermore regexes help reducing redundancy within the configuration. Regexes more flexible than standard parameters. Nevertheless, it must be mentioned that - in addition to the overhead involved - complexity is an issue, too. Although the syntactic correctness of each used regular expression is ensured (see below) the semantic correctness cannot be automatically proofed. Expressions that are not compilable, which means they are not valid POSIX regexes, force Kannel to panic with a message like (note the missing "]") ERROR: gwlib/regex.c:106: gw_regex_comp_real: regex compilation `[hbo(g|ld)' failed: Invalid regular expression (Called from gw/urltrans.c:987:create_onetrans.) PANIC: Could not compile pattern '[hbo(g|ld)' As shown the erroneous pattern is reported in the error message. Regex and non-regex-parameters Using the regex and non-regex version of a parameter at the same time should be done with caution. Both are combined in a boolean-or sense, for example white-list=01234 white-list-regex=^5(23)?$ implies that a number is accepted either if it is "01234", "5" or "523" - note the use of anchors! The same goes for all the other parameters, thus both mechanisms can be used without problems in parallel, but care should be taken that the implications are understood and wanted. Performance issues While there is some overhead involved, the actual performance degradation is negligible. At startup - e.g. when the configuration files are parsed - the regular expressions are pre-compiled and stored in the pre-compiled fashion, thus future comparisons involve executing the expression on some string only. To be on the sure side, before using regexes extensively some benchmarking should be performed, to verify that the loss of performance is acceptable. Examples This section discusses some simple scenarios and potential solutions based on regexes. The examples are not meant to be comprehensive but rather informative. Example 1: core-configuration The bearerbox must only accept SMS messages from three costumers. The first costumer uses numbers that always start with "0824" the second one uses numbers that start with either "0123" and end in "314" or start with "0882" and end in "666". The third costumer uses numbers starting with "0167" and ending in a number between "30" and "57". Important in this and in the following examples is the use of anchors, otherwise a "string contains" semantic instead of a "string is equal" semantic would be used. group=core ... white-list-regex=^((0824[0-9]+)|(0123[0-9]+314)|(0882[0-9]+666)|(0167[0-9]+([34][0-9]|5[0-7])))$ ... Example 3: smsc-configuration Only SMS messages originating from certain SMSCs (smsc-id is either "foo", "bar" or "blah") are preferably forwarded to this smsc. Furthermore all SMSCs with an id containing "vodafone" must never be forwarded to the smsc. Not the missing anchors around "vodafone". group=smsc ... preferred-smsc-id-regex=^(foo|bar|blah)$ denied-prefix-regex=vodafone ... Example 4: sms-service-configuration Please note that there are a mandatory keyword and an optional keyword-regex fields. That means that service selection can be simplified as in the following example. Suppose that some Web-content should be delivered to the mobile. Different costumers use the same service but they rely on different keywords. Whenever a sms-service is requested, Kannel first checks whether a regex has been defined, if not a literal match based on keyword is performed. If a regex is configured then the literal match is never tried. group=sms-service ... keyword=web_service keyword-regex=^(data|www|text|net)$ get-url=http://someserver.net/getContent.jsp ... Meta Data This appendix describes the elements and syntax required to access meta-data coming from and going to SMSC connections. Overview Many SMSC services have means to exchange data that doesn't conform to the established format For example, the SMPP protocol defines the TLV (Tag, Length, Value) mechanism to allow adding arbitrary parameters to it's PDU's, thus extending it's functionality. To achieve this, a special group and parameters were added to abstract the meta-data into something that could be used disregarding the SMSC type. Currently only the SMPP module is implemented, but the format chosen allows for other modules to be added in the future. SMPP Implementation A special group type smpp-tlv is needed for each TLV. Each group defines the address, data type and length of the TLV Example configuration: group = smpp-tlv name = my_tlv_name tag = 0x1601 type = octetstring length = 20 smsc-id = a;b;c Variable Data Type Description tag hex 32-Bit HEX address for the given TLV. Must match SMPP specifications for the TLV (or be agreed with the SMSC operator). type string Accepted data type. Accepted values are integer, nulterminated and octetstring. Must match SMPP specifications for the TLV (or be agreed with the SMSC operator). length integer Maximum data length expected in bytes. Must match SMPP specifications for the TLV (or be agreed with the SMSC operator). smsc-id string An optional smsc-id for which this TLV is valid. If smsc-id is not given then this TLV is valid for all SMSCs. To define list of smsc-id, just use ; as split char. const string An optional constant value which is used if no value is set for this TLV via meta-data. Beside defined in the configuration smpp-tlv group, SMPP also supports some hardcoded meta-data values: data_coding source_addr_ton source_addr_npi dest_addr_ton dest_addr_npi MO Messages Meta Data coming from MO messages comes urlencoded into the %D parameter. Only TLV parameters defined on the configuration file are honored. Example http://localhost/myscript?...&meta-data=%D&... MT Messages To send into an MT messages the meta-data parameter should be used. The format used to pass the data has 2 parts: The ?smsc-type? (surrounded by question marks), which specify the kind of smsc receiving the data (at the moment only smpp is implemented) and then a set of key/value pairs with the data to be transmitted. Extra smsc-types can be added surrounded by question marks and followed by the key/value pairs. In other words, the data should be coded using the following format, where URLENCODE() implies that the data between parentheses should be urlencoded: ?URLENCODE(<smsc-type1>)?URLENCODE(key1)=URLENCODE(value1)&URLENCODE(key2)=URLENCODE(value2)&... ?URLENCODE(<smsc-type2>)?URLENCODE(key1)=URLENCODE(value1)&... Only the parameters defined on the configuration file are honored. Important: For the sendsms interface, you must URLENCODE the resulting string again to pass it as a single parameter on the URL. Examples If we want to send the parameter "my-data" with value "Hello World" to an SMSC over SMPP, we'd use: sendsms get-url: http://localhost:13013/cgi-bin/sendsms?...&meta-data=%3Fsmpp%3Fmy-data%3DHello%2BWorld sendsms post: Send ?smpp?my-data=Hello+World on the X-Kannel-Meta-Data header XML: <meta-data>?smpp?my-data=Hello+World</meta-data> Log files This appendix describes the log file format. Bearerbox Access Log 2001-01-01 12:00:00 Sent SMS [SMSC:smsc] [SVC:sms] [ACT:account] [BINFO:binfo] [FID:1234567890] [META:meta] [from:12345] [to:67890] [flags:0:1:0:0:0] [msg:11:Hello World] [udh:0] Variable Value Description Date 2001-01-01 12:00:00 Date Result Sent SMS Result: Send, failed, DLR (deliver report), Received, etc. SMSC smsc Smsc id (smsc-id) defined in configuration group smsc SVC sms Service name (name) defined in configuration group sendsms-user ACT account Account name (name) defined in configuration group sendsms-user BINF binfo Billing information used to send this message. Foreign ID 1234567890 Foreign (SMSC-provided) Message ID (only available on MT messages) META meta-data Meta-data used to send this message. See for an explanation about meta-data. from 12345 Sender to 67890 Recipient Flags 0:1:0:0:0 Flags: MClass, Coding, MWI, Compress, DLRMask Message Text 11:Hello World Size of message and message dump (in text or hex if it's binary) User Data Header 0: Size of UDH and UDH Hex dump Log rotation If Kannel is configured so that the bearerbox, wapbox and/or smsbox log to file each of these log files will continue to grow unless administered in some way (this is specially true if access logs are created and/or the log level is set to debug). A typical way of administering log files is to 'rotate' the logs on a regular basis using a tool such as logrotate. A sample logrotate script (to be added to /etc/logrotate.d) is shown below. In this example the Kannel log files found in /var/log/kannel are rotated and compressed daily over 365 days. See the documentation for logrotate for more details. Of particular note however is the postrotate command, this killall -HUP issues a SIGHUP signal to each Kannel box process running. The SIGHUP signal has the effect of reopening the log file, and performing graceful restart of SMSC connections. Without this command Kannel will continue to write to the rotated log file. Kannel bearerbox can use the SIGUSR2 to reopen the logs only, without performing the graceful restart. This may be more applicable for logrotate usage. /var/log/kannel/*.log { daily missingok rotate 365 compress delaycompress notifempty create 640 kannel adm sharedscripts postrotate killall -USR2 bearerbox && killall -HUP smsbox wapbox || true > /dev/null 2> /dev/null endscript } Glossary M MO Mobile Originated - a SMS from mobile to application MT Mobile Terminated - a SMS from application to mobile MWI Message Waiting Indicator (See ) MClass Message Class (See ) Coding Message Coding (See ) Bibliography RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1 http://www.w3.org/Protocols/rfc2616/rfc2616.html Request for Comments: 2616 The Internet Society 1999 3GPP 23.038 http://www.3gpp.org/ftp/Specs/latest/Rel-5/23_series/23038-500.zip ... 3GPP ? 3GPP 23.040 http://www.3gpp.org/ftp/Specs/latest/Rel-5/23_series/23040-530.zip ... 3GPP ? regex(7), GNU regex manual GNU 1998
gateway-1.4.5/doc/userguide/wap-gateway.fig0000644000175000017500000000354207053015145017346 0ustar toljtolj#FIG 3.2 Portrait Center Metric A4 100.00 Single -2 1200 2 6 90 90 6525 2565 6 585 1440 1035 2565 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 585 1710 1035 1710 1035 2565 585 2565 585 1710 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 900 1710 990 1710 990 1440 900 1440 900 1710 2 4 0 1 0 7 50 0 -1 0.000 0 0 7 0 0 5 990 2070 990 1755 630 1755 630 2070 990 2070 -6 6 5220 90 6525 2520 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5220 540 5850 540 5850 2070 5220 2070 5220 540 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5850 540 6525 90 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5220 540 5895 90 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5850 2056 6525 1606 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 3 5895 90 6525 90 6525 1620 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5310 1395 5760 1395 5760 1980 5310 1980 5310 1395 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5400 1395 5400 1980 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5490 1395 5490 1980 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5580 1395 5580 1980 2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 5670 1395 5670 1980 2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 5310 675 5760 675 5760 810 5310 810 5310 675 4 0 0 50 0 0 12 0.0000 4 135 1125 5265 2520 Content server\001 -6 6 2295 990 3735 2430 1 3 0 1 0 7 50 0 -1 0.000 1 0.0000 3015 1710 720 720 3015 1710 3015 2430 4 0 0 50 0 0 12 0.0000 4 180 1110 2505 1777 WAP gateway\001 -6 6 1440 1215 1890 1575 4 0 0 50 0 0 12 0.0000 4 135 420 1440 1350 WAP\001 4 0 0 50 0 0 12 0.0000 4 135 420 1440 1575 stack\001 -6 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 4 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 1170 1845 1845 1755 1755 2430 2340 2160 0.000 -1.000 -1.000 0.000 3 2 0 1 0 7 50 0 -1 0.000 0 1 1 4 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 3735 1395 4590 1170 4365 1890 5175 1530 0.000 -1.000 -1.000 0.000 4 0 0 50 0 0 12 0.0000 4 135 465 90 1080 Phone\001 4 0 0 50 0 0 12 0.0000 4 135 450 4185 990 HTTP\001 -6 gateway-1.4.5/doc/ChangeLog-1.4.20000644000175000017500000013365711132672446014670 0ustar toljtolj2009-01-12 Stipe Tolj * */*: update LICENSE preamble block to 2009. 2009-01-11 Stipe Tolj * doc/examples/modems.conf: added modems group for the Sony Ericsson P1i. Thanks to Christoffer Elenius for providing it. 2009-01-09 Alejandro Guerrieri * gwlib/dbpool.h gwlib/dbpool_sqlite.c gwlib/dbpool_sqlite3.c gwlib/cfg.def: Fixed missing section on sqlite 2 section on cfg.def. Added a "lock-timeout" parameter to Sqlite2 and Sqlite3. 2009-01-09 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed #460. 2009-01-09 Alexander Malysh * gw/wap_push_ppg.c: applied patch from #473. 2009-01-09 Alexander Malysh * gw/smsc/smsc_at.c: Fixed length calculation for concatenated 7Bit MO messages.This fixes #456. Thanks to Paolo Losi and Matti Ärmänen for bug report. [Msg-ID: <496720A1.5010705@sci.fi>] 2009-01-08 Alexander Malysh * gw/smsc/smsc_at.c: applied patch that fixes 7bit encoding. Thanks to Riku Palomäki for this patch. [Msg-ID: <20080711031340.25df040e@karvalakki.kyla.fi>] 2009-01-06 Alexander Malysh * gw/smsc/smsc_http.c: applied patch which will allow to send concat, 8bit and unicode messages over HTTP via Clickatell. Thanks to Donald Jackson for this patch. [Msg-ID: <290be5f30901042256r416032ecu1a909f23ee46baa7@mail.gmail.com>] 2008-12-10 Alexander Malysh (CB)* doc/userguide/userguide.xml, gw/bb_alog.c, gw/dlr.[ch], gw/msg-decl.h, gw/urltrans.c: applied patch that adds foreign (SMSC) ID to message. This patch breaks access log format and extends Msg struct. Thanks to Alejandro Guerrieri for this patch. 2008-12-10 Alexander Malysh * gw/wap_push_ppg.c, gw/wapbox.c: fixed memory leaks. 2008-12-10 Alexander Malysh * gw/bb_alog.c: fixed memory leak. Thanks to Nikos Balkanas for test case. 2008-11-25 Alexander Malysh * gw/smsbox.c: escape string values in the XML document for MO messages. Thanks to Michael Zervakis for pointing to this issue. 2008-11-19 Alexander Malysh * gwlib/log.c: fixed double close/free in log_close_all(). Thanks to Werner Coetzee for pointing to the issue. 2008-11-19 Alexander Malysh * debian/kannel.init: apllied patch that replace usage of run_kannel_box with kannel oprions --daemonize. Thanks to Alan McNatty for this patch. [Msg-ID: <4922140B.3000803@catalyst.net.nz>] 2008-11-17 Alexander Malysh * gw/smsc/smsc_at.c: wait OK after issuing AT+CNMA-command. Thanks to matti.armanen at sci.fi for the patch. [Msg-ID: 491E905E.908@sci.fi] 2008-10-22 Stipe Tolj * test/test_ota.c: write the binary ota_compile() output block to a file cleanly. 2008-10-22 Stipe Tolj * gw/ota_compiler.c: re-order INLINE attributs in oma_ota_attributes struct to fit the order in the spec tables. NLC. 2008-10-21 Stipe Tolj * gw/smsc/smsc_smpp.c: fix possible segfaults in handle_pdu(), where we don't access the resp PDU structure correctly in the case of shutdown phase. 2008-10-10 Stipe Tolj * doc/userguide/userguide.xml: add HTTP admin 'reload-lists' section. * gw/bb_[http|smssconn].c, gw/bearerbox.h: implement HTTP admin command 'reload-lists' to allow re-loading of the '[white|black]-list' on the fly while runtime. This helps a lot while the remote lists change over time and we want to keep bearerbox running and don't have to restart in order to re-load the lists. 2008-10-09 Stipe Tolj * doc/userguide/userguide.xml: some typo fixes, using 'aspell check -H'. 2008-10-07 Alexander Malysh * gw/smsbox.c: commited patch that allow longer account parameter and clarify error message. Thanks to Vincent CHAVANIS for this patch. [Msg-ID: <48E35531.90603@telemaque.fr>] 2008-09-30 Alexander Malysh * contrib/kannel-monitor/index.php: applied patch that adds inbound/ outbound load and version info. Thanks to Vincent CHAVANIS for this patch. [Msg-ID: <48DA51D6.9010209@telemaque.fr>] 2008-09-21 Alexander Malysh * gw/bb_smscconn.c, gw/bearerbox.c, gw/load.c, gw/load.h: added simple bandwidth meter with heuristic and needed changes to bearerbox status. Bearerbox status show now 3 speeds: 1 minute sample, 5 minute sample, and over livetime. Example: SMS: inbound (0.00,0.00,0.00) msg/sec, outbound (0.00,0.00,0.00) msg/sec 2008-09-16 Stipe Tolj * doc/userguide/userguide.xml: add reference to the below binfo support of SMPP DLRs. * gw/smsc/smsc_smpp.c: add 'binfo' support for SMPP DLRs, in order to proxy the DLR message 'err' component via our msg struct value. This allows users to specify the '%B' escape code in 'dlr-url' too, beside the normal DLR value '%d' to provision the DLR error code to the backend application. 2008-09-12 Alexander Malysh * gw/smsc/smsc_smpp.c: switched internal queue to gw_prioqueue instead of List. 2008-08-24 Stipe Tolj * gw/smsc/smsc_smpp.c: switch if condition statement to ensure we don't run into an assertion panic within octstr_get_char() for a NULL'ed source_addr. 2008-08-13 Stipe Tolj * gwlib/http.h: add complete list of HTTP/1.1 return codes. NLC. 2008-08-08 Stipe Tolj * doc/doxygen/kannel.conf: change to 'CREATE_SUBDIRS = YES' for the sake of filesystem IO performance during creation and read. 2008-08-06 Alexander Malysh * gwlib/http.[ch]: added 2 new functions (http_set_client_timeout, http_cgivar_dump_into). Fixes: 1) use conn_open_ssl_nb in conn_pool_get 2) reinject redirect requests into the front of the queue 3) don't panic if we try to put slow client into port queue but listen port was already closed 4) don't return already dead client in http_accept_request 2008-08-06 Alexander Malysh * gwlib/fdset.[ch]: added new function fdset_set_timeout. 2008-08-06 Alexander Malysh * gwlib/conn.[ch]: added new function conn_open_ssl_nb. 2008-08-06 Alexander Malysh * configure.in, configure: added MacOSX10.5.sdk 2008-08-02 Alexander Malysh * gwlib/charset.c, radius/radius_acct.c, wap/wtp_resp.c: fixed compiler warnings. 2008-07-29 Alexander Malysh * gw/smsc/smsc_soap.c: fixed compilation on AIX in 64bit mode (converted int64 into long long. Thanks to "Bostock James" for notice. 2008-07-28 Alexander Malysh * configure.in, configure: require C99 compiler because we use some of features of this standart. Thanks to "Bostock James" for the patch. Msg-ID: <84E219D8B81E5F4688C4A8992426CD83013D79D8@fr-par-mail01.comverse.com> 2008-07-28 Alexander Malysh * doc/userguide/userguide.xml: applied patch that clarify that float can be used for throughput. Thanks to Vincent CHAVANIS. 2008-07-28 Alexander Malysh * gw/smsc/smsc_emi_x25.c: fixed X25 speed (AIX does not define B115200). Thanks to "Bostock James" for the patch and to Vincent CHAVANIS for pushing it into CVS. Msg-ID: <84E219D8B81E5F4688C4A8992426CD8301318309@fr-par-mail01.comverse.com> 2008-07-27 Stipe Tolj * gwlib/dbpool[_sqlite3].c: fix minor compiler warnings. NLC. 2008-07-26 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_http.c, gwlib/cfg.def: added new config option 'use-ssl' that allow to use SSL for listen port. 2008-07-24 Alexander Malysh * configure.in, configure: fixed hardcoded library detection for oracle. Not all OSs have .so. 2008-07-24 Alexander Malysh * gwlib/dbpool.c: Fixed deadlock in dbpool_conn_consume if we don't have any database connections available anymore and database is temporarely not available. 2008-07-24 Stipe Tolj * gwlib/cfg.c: add more semantical error statement if we detect an unknown group identifier. This shall help the users to find their config typos. [Msg-Id: <48877F65.8060605@tolj.org>] 2008-07-19 Stipe Tolj * gwlib/mime.c: memory leak fix while duplicating headers. Thanks to Paul Bagyenda for providing the patch. [Msg-Id: <93C3937B-F5F7-4873-ABF4-391308F9ED09@dsmagic.com>] 2008-07-15 Stipe Tolj * gw/smsc/smsc_http.c: memory leak fix for Clickatell and Brunet HTTP API. Thanks to Donald Jackson for the patch. [Msg-Id: <290be5f30807140151j5cf784u3b5fdcf3191b890d@mail.gmail.com>] 2008-07-14 Stipe Tolj * gw/smsc/smsc_http.c: add 'cliMsgId' support for the Clickatell HTTP API to allow defining client side message IDs via our UUID string morphed into a MD5 compliant string, added also support for 'alt-charset' config directive support in smsc group for setting a different charset encoding for the Clickatell HTTP API. 2008-07-04 Stipe Tolj * gw/shared.c: ensure we handle OCI_[MINOR|MAJOR]_VERSION only if they are defined in the oci.h header. Pre Oracle 10 versions seem to lack this. Thanks to James Bostock for the patch. [Msg-Id: <84E219D8B81E5F4688C4A8992426CD83012A4AFE@fr-par-mail01.comverse.com>] 2008-07-03 Andreas Fink * gw/smsc_at.c: size_t is unsigned so if -1 is returned, we never catch it. 2008-07-03 Stipe Tolj * gwlib/gwthread[-pthread].[ch]: add function gwthread_sleep_micro() which allows sleep of microseconds. Thanks to Werner Coetzee for providing this contribution. [Msg-Id: <86E9DA9FF04EBD468B3574F22A0B0DB648811780C4@comms01-cpt.internal.clickatell.com>] 2008-07-02 Stipe Tolj * configure[.in]: add support for AIX 64bit builds via setting the ar archiever call in $AR env variable. Thanks to James Bostock for his AIX contributions. [Msg-Id: <84E219D8B81E5F4688C4A8992426CD83012A44E9@fr-par-mail01.comverse.com>] 2008-07-02 Stipe Tolj * gwlib/mime.c: fix and relax function mime_entity_to_octstr() for end of line chars. Thanks to Paul Bagyenda for providing the patch. [Msg-Id: <841FABF4-5733-4610-B097-19120DF0CD4A@dsmagic.com>] * test/mime-multipart.txt: demo MIME multipart input file for test/ test_mime_multipart.c. 2008-06-30 Stipe Tolj * test/test_urltrans.c: fix compiler warning. NLC. 2008-06-24 Stipe Tolj * Makefile.in: add 'datarootdir' reference which is required for autoconf 2.60 (and higher) output files. 2008-06-24 Stipe Tolj * configure[.in]: fix shell unary expression error. NLC. 2008-06-24 Stipe Tolj * configure[.in]: fix [] bracked output, and change --with-sqlite to --with-sqlite2 to make the difference to more recent sqlite3 version clear. 2008-06-24 Stipe Tolj * gw/smsc/smsc_at.c: fix compiler warnings. NLC. 2008-06-24 Alexander Malysh * doc/userguide/userguide.xml, gw/smsbox.c, gw/urltrans.[ch], test/test_urltrans.c: convert keyword handling to use regex and allow keyword-regex to match the whole msg body instead of only the first word. This patch doesn't change behaviour of keyword handling except keyword-regex now match whole message body. Additionaly, this patch adds escape code '%O' for DCS because it make sense to have DCS as whole instead of splitted into fields. 2008-06-24 Andreas Fink * gw/smsc/smsc_at.c: support for protocol type = telnet compared to rawtcp it does interpret telnet escape sequences. Also supports specifying smsc-username / smsc-password to log in on the access server. New params are login-prompt and password-prompt 2008-06-13 Stipe Tolj * gw/smsc/smsc_smpp.c: fix possible assertion check panic while calling octstr_get_char() on the source_addr field, which may be NULL according to SMPP v3.4 specs. 2008-06-09 Alexander Malysh * gw/smsc/smsc_emi.c: fixed name issue when we use alternate host/port. Thanks to Vincent CHAVANIS for spotting this and provided patch. 2008-05-31 Stipe Tolj * wap/wsp_headers.[ch]: fix encoding of 'Content-Id' WSP header. Thanks to Paul Bagyenda from Mbuni for the patch. [Msg-Id: <96EDF863-5963-48C4-964D-8A8E375544CC@dsmagic.com>] 2008-04-24 Stipe Tolj * gw/bb_store_[file|spool].c: use internal function pointer while packing/unpacking the Msg struct. * gw/bb_store.[ch]: add store_msg_pack and store_msg_unpack function pointers, allowing a box to pass their own msg_[un]pack() functions to the storage subsystem, in case they use a different serialization. * gw/bearerbox.c, test/test_store_dump.c: add the function pointers for packing/unpack to store_init() call. * gw/msg.[ch]: we need a wrapper for msg_unpack(), for passing it as function pointer argument, since it's a preprocessor macro. 2008-04-21 Stipe Tolj * gwlib/socket.[ch]: add host_port() function in accordance to host_ip() to get the port number of a TCP connection in use. 2008-04-17 Andreas Fink * gw/smsc/smsc_ois.c: fixed compiler warning. 2008-04-16 Andreas Fink * wap/wsp_[strings|unit|init|pdu].c: fixed compiler warnings due to signed/unsigned char mismatch. 2008-04-09 Stipe Tolj * Makefile.in: fix 'make clean' target, by fixing find expression. 2008-04-09 Stipe Tolj * doc/userguide/userguide.xml: add missing documentation block for 'alt-dcs' in smsc group. 2008-03-23 Stipe Tolj * gw/smsc/smsc_at.c: fix at2_wait_modem_command() to ignore specific OK responses for AT+CNMA acknowledges. Thanks to Marius Huysamen for providing patch. [Msg-Id: <47C93579.8000409@mhg.co.za>] 2008-03-15 Alexander Malysh * doc/userguide/userguide.xml, gw/smscconn.c, gw/smscconn_p.h, gwlib/cfg.def: Implemented max-sms-octets config option that allows to set maximum length of SMS for SMSC. 2008-03-10 Andreas Fink * gw/smsc/*: fixed a lot of warning due to pointer type mismatch ( (char *) versus unsinge char * and the like) 2008-03-06 Andreas Fink * gw/smsc/smsc_at.c: fixed an infinite loop for receiving delivery reports with SMSC string being empty. 2008-02-21 Stipe Tolj * gwlib/fdset.h: remove trailing ';' in a macro. Thanks to Paul Bagyenda from Mbuni for spotting it. [Msg-Id: <5B21C330-DA5A-4E6D-B431-9AB31479A446@dsmagic.com>] 2008-02-19 Stipe Tolj * gw/dlr.c: adding more debug output for the warning() in case the DLR could not be resolved. NLC. * gw/wap_push_pap_compiler.c: typo fix in comment. NLC. [Msg-Id: <0a5a01c872e6$4c682f80$9600a8c0@VINCE>] 2008-02-07 Stipe Tolj * gw/wbxml_tokens.def, wap/wsp_strings.def: updates from OMNA page. 2008-02-02 Stipe Tolj * gw/ota_compiler.c: fix bug #405, where we forget to switch codepage when no inline value is processed for WBXML compilation. Thanks go to Maxim Sobolev for reporting and proving patch. [Msg-Id: <47A3C8E6.4090008@sippysoft.com>] 2008-02-01 Stipe Tolj * Makefile.in: we need first and second level directories to care of. 2008-02-01 Stipe Tolj * utils/start-stop-daemon.c: add Cygwin platform support to allow clean runs for the preprocessing make target. 2008-02-01 Stipe Tolj * doc/doxygen/kannel.conf: doxygen config file for generating source code documentation. 2008-02-01 Stipe Tolj * Makefile.in: ensure we get second directory level too for the preprocessing target. 2008-01-31 Stipe Tolj * Makefile.in: add build target 'pp' to allow building preprocessed outputs of source files via $(CC) -E. This can be used to verify how our massive usage of preprocessing macros are resolved. NLC. 2008-01-29 Alexander Malysh * gwlib/gw-prioqueue.c: Implemented extra sequence in the gw-prioqueue that will guarantee the order of the equal messages. It should fix #436. 2008-01-24 Alexander Malysh * gw/sms.c: fixed truncating of the message if split-chars defined in the config. Thanks to Giulio Harding for bug report. 2008-01-22 Alexander Malysh * gw/html.c: fixed #425: SMSBox goes into infinite loop when it encounter hex escape sequence in html response. 2008-01-09 Stipe Tolj * */*: update LICENSE preamble block to 2008. 2008-01-09 Stipe Tolj * gw/[sms|wap]box.c: incorporate 'http-proxy-ssl' directive handling. * gwlib/cfg.def: add 'http-proxy-ssl' config directive to core group. * gwlib/http.[ch]: fix a critical bug when proxy'ing https:// schema URLs. We interpreted the SSL scheme for the HTTP proxy call too, even while this should be a plain http:// call, and the proxy itself would then use https:// to poll the resource. Now we do things right, which means per default plain HTTP is send to proxy. If we want SSL-encryption towards the HTTP proxy itself, then 'http-proxy-ssl' boolean config directive can be set. * test/test_[http|xmlrpc].c: make use of the 'http-proxy-ssl' feature. Thanks to Carlos Perez for this report. [Msg-Id: ] 2007-12-21 Stipe Tolj * gw/wap_push_ppg_pushuser.c: remove HTTP Authorization header which is encoded in the bytestream. Thanks to Mathieu Bruneau for reporting and providing patch. [Msg-Id: <48797AC0E8188A408AC4D3C3A091450D022B2D7C@MAIL01.gameloft.org>] 2007-10-18 Alexander Malysh * gw/bb_smscconn.c: fixed segfault when concat handler disabled. Thanks to Vincent CHAVANIS for patch. 2007-10-08 Alexander Malysh * gw/smsc/smsc_at.c: fixed memory leak when we receive DLR. 2007-10-05 Alexander Malysh * gw/smsc/smsc_at.c: reset reconnecting. 2007-10-05 Alexander Malysh * gw/smsc/smsc_at.c: fixed memleak. 2007-10-03 Stipe Tolj * gw/smsc/smsc_at.c: removed compiler warning. NLC. 2007-10-01 Alexander Malysh * gw/smsc/smsc_at.[ch]: applied patch that has the main goal to follow a simple rule: "If the modem reports an error during SMS sending, don't retry the sending, but ask it what it's got to say". This patch should fix errors like this: CMS ERROR: Unknown error. -> maybe Sim storage is full? I'll have a look at it. (500) Thanks to Andrija Petrovic for this patch. [Msg-Id: <47010443.7000104@software888.com> 2007-10-01 Alexander Malysh * test/decode_emimsg.c: new version - Fixes a segfault when we are decoding 52 operation response (eg ./decode_emimsg 03/00020/R/52/A///98) - Operation 31 Ack/Nack is now supported - Operation 5x Ack/Nack is now supported - Fixes segfault when decoding 52 when xMSG is NULL Thanks to Vincent CHAVANIS for the patch. [Msg-Id: <0d3f01c801bd$07a8f860$9600a8c0@vince> 2007-09-27 Alexander Malysh * gw/dlr.c: changed info to debug for the info that we still waiting for dlr. Thanks to Vincent CHAVANIS for patch. 2007-09-03 Stipe Tolj * gwlbib/cfg.c: fixing memleak reported by valgrind when we use directory inclusions. 2007-08-29 Stipe Tolj * gwlib/cfg.c: remove empty lines. NLC. * gwlib/http.c: add 'Date' HTTP header to any HTTP response we pass out. 2007-08-25 Stipe Tolj * gwlib/gwthread-pthread.c: fix valgrind conditional jump error report in gwthread_pool() for .revents value. 2007-08-03 Alexander Malysh * gw/smsc/smpp_pdu.c: whitespaces fixes and various PDU parsing fixes and enhancements. This should not break anything. 2007-08-03 Alexander Malysh * doc/userguide/userguide.xml, gw/smsbox.c: fixed userguide for XML post. Also fixed XML Post parsing of smsc-id to match userguide. It's possible that this will break existing applications. 2007-07-22 Alexander Malysh * gw/ota_compiler.c: added new WLAN-related tokens in order to get new Nokia WiFi/VoIP OTA provisioning working. See OMA-DM-CP-2005-001R02-CR_CP-WLAN-.doc. This fixed #406. Thanks to sobomax for patch. 2007-07-22 Alexander Malysh * gw/smsc/smsc_at.c: added CLOCAL to c_cflag. This fixed #404. Thanks to sobomax for reporting and patch. 2007-07-22 Alexander Malysh * gw/smsc/smsc_at.c: set reconnecting = 1 if we have issues opening device. So we will sleep reconnect time instead of hammering on maybe not existing device. This should fix #412. 2007-07-22 Alexander Malysh * gwlib/mime.c: don't add an extra CRLF to the end of a message part. Thanks to Paul Bagyenda . [Msg-Id: ] 2007-06-14 Stipe Tolj * gw/dlr.h: fix bitmask for DLR_IS_NOT_FINAL macro, since DLR_SMSC_FAIL is a final state, we need to ommit it here to be semantically correct. 2007-06-12 Alexander Malysh * gw/bb_smscconn.c: fixed segfault and simplified handling of timeouted concatenated MOs. 2007-06-12 Alexander Malysh * gwlib/list.c: fixed gwlist_timed_consume. 2007-06-01 Alexander Malysh * doc/userguide/userguide.xml, gw/bb_smscconn.c, gw/sms.c, gwlib/cfg.def: applied MO concatenation patch. This patch was originally written by Paul Bagyenda and then extended by me. Thanks Paul! 2007-06-01 Alexander Malysh * gw/smsc/smsc_smpp.c: removed GSM-03.38 kludge because it's not necessary anymore. 2007-05-20 Stipe Tolj * gw/smsc/smsc_at.c: fix a possible segfault while read()ing on the device file descriptor. Thanks to Ben Suffolk for the patch. [Msg-Id: ] 2007-05-18 Alexander Malysh * gwlib/list.c: use macro instead of direct access. 2007-05-18 Stipe Tolj * gwlib/charset.c: imunize charset_[gsm|utf8]_to_[utf8|gsm]() functions for NULL argument. Currently these would panic due to octstr_append() called at the end with a NULL argument. NLC. 2007-05-15 Alexander Malysh * gwlib/list.[ch]: added new function gwlist_timed_consume that works as gwlist_consume except that we are able to specify timeout. 2007-04-24 Andreas Fink * gwlib/gwlib.c: call log_init before http_init and socket_init so error messages from those init calls actually are able to appear on the screen instead of crashing bearerbox at start. Reported under MacOS X by Alejandro Guerrieri. Only happened if hostname was not set. ERROR: Can't find out official hostname for this host, using `xyz' instead. was being sent to a logfile not open... -> crash 2007-04-20 Stipe Tolj * aclocal.m4: fixed typo and updated email references. NLC. * Makefile.in: adding creation of symlink for 'gw-config' if we have used '--with-suffix' while configure, otherwise gw-config is also appended with suffix string and it does not comply with external components depending to find a 'gw-config' in the PATH and use the cflags and libs information for their own builds against Kannel libs. This is safe now for both, w/o suffix. 2007-04-18 Alexander Malysh * doc/userguide/userguide.xml, gw/bb_boxc.c, gw/bb_smscconn.c, gw/bb_smscconn_cb.h, gw/bearerbox.c, gw/bearerbox.h, gwlib/cfg.def: applied patch that implements outgoing queue (MT) limit. 2007-04-18 Alexander Malysh * gwlib/mime.c: applied patch should help take care of issues where the Content-ID for the start element is enclosed in '<' '>'. Thanks to Paul Bagyenda for the patch. [Msg-Id: ] 2007-04-16 Stipe Tolj * gw/smsc/smsc_http.c: fixing default charset encoding policy in chaining Kannel instances via 'system-type = kannel'. As we use now UTF-8 as internal encoding, but still WINDOWS-1252 as default encoding for smsbox's sendsms HTTP interace, we need to forward explicetly the CGI variable charset to the next instance here to let the smsbox know that we pass the message in UFT-8 format for normal text messages. This is a temporary issue, as long as smsbox's sendsms HTTP interface isn't switched to UTF-8, which we should do in next major revision. 2007-04-14 Stipe Tolj * gwlib/octstr.c: imunize octstr_truncate() for NULL argument. Currently this would cause a panic when charset_utf8_to_gsm(NULL) is called. Now same safety bail-out behaviour as octstr_insert(). 2007-04-11 Alexander Malysh * gw/sms.c: fixed #397 that smsbox blocked HTTP requests. 2007-04-04 Stipe Tolj * configure[.in]: modified the docbook.dsl search path to be more generic since some distros have more recent version paths (ie. 1.79 for FC5 on x86_86 architectures), and we don't want to sum up every single version. We relly on any match we get in the for shell loop and continue. 2007-04-03 Stipe Tolj * doc/userguide/userguide.xml: documented change of 'smsbox-route' group logic from the commit on 2007-02-27. 2007-04-03 Alexander Malysh * gw/dlr.h: changed DLR_SMSC_FAIL back to 0x10. Thanks to Ben Suffolk for patch. 2007-04-02 Alexander Malysh * gwlib/octstr.c: prevent possible heap smashing 2007-03-30 Alexander Malysh * wap/wsp_caps.c: fixed possible heap smashing. 2007-02-27 Stipe Tolj (CB) * gwlib/cfg.def, gw/bb_boxc.c: re-defining logic for the 'smsbox-route' group that is used for MO routing to different (identified) smsbox connections. We know support the splitting of shortcodes depending on various source smsc-ids to various smsbox connections. So this behaviour is more generic then the one before. The naming convention changed, this needs to be noted in the NEWS file for upcoming relase. [Msg-Id: <45C25496.4020003@tolj.org>] 2007-02-27 Stipe Tolj * gw/smsc/emimsg.[ch]: adding function emimsg_duplicate() to allow duplication of the struct. This is usefull in various ways and places. 2007-02-27 Alexander Malysh * gwlib/octstr.h: fixed octstr_dump that dumped Octstr with GW_INFO loglevel. 2007-02-26 Alexander Malysh * gw/smsc/smsc_at.c: fixed bug that AT SMSC put UDH without UDH len. Thanks to Paul Bagyenda for the patch. 2007-02-26 Alexander Malysh * gw/sms.c: fixed two issues (1) max_part_len calculation; (2) we dropped last utf-8 multibyte sequence. [Msg-ID: ] 2007-01-31 Alexander Malysh * gw/bb_smscconn.c: use enum in return from bb_smscconn_receive. 2007-01-29 Andreas Fink * gwlib/octstr.c: fixed octstr_split for cases where first occurence of separator is at position 0 2007-01-26 Alexander Malysh * gwlib/log.c: fixed deadlock from my last commit. 2007-01-26 Alexander Malysh * gwlib/cfg.c, gwlib/gwlib.c: fixed Stipe's last commit. 2007-01-26 Stipe Tolj * gwlib/cfg.[ch]: fix memleak and revert Alex's commit on destroying the hook lists in cfg_destroy(). We need to do this in a global module scope, so we introduce cfg_[init|shudown](). * gwlib/gwlib.c: call cfg_init() and cfg_shutdown() while gwlib usage. Thanks to Florian Bruch for pointing to this inconsistancy. 2007-01-26 Alexander Malysh * gwlib/log.c: converted usage of List as rwlock to real RWLock and fixed some deadlocks. Additionaly we now have clean memleak stack when compiled with memcheck. 2007-01-23 Stipe Tolj * gw/smsc/smsc_smpp.c, gw/ota_compiler.c, gw/wap-appl.c, gwlib/octstr.c, test/fakesmsc.c, test/test_[conn|list].c: fixing compiler warnings due to unused or uninitialized variables. NLC. 2007-01-22 Alexander Malysh * doc/userguide/userguide.xml, gw/bb_store.c, gw/bb_store.h, gw/bb_store_file.c, gw/bb_store_spool.c, gw/bearerbox.c, gw/bearerbox.h, gwlib/cfg.def, test/test_store_dump.c: apllied patch that adds additinaly support for store spool directory. [Msg-ID: ] 2007-01-22 Alexander Malysh * gw/bb_boxc.c: implemented resend of MO/DLR messages if some box sent nack with ack_failed_tmp status. 2007-01-22 Alexander Malysh * gwlib/gwmem-native.c: reverted last Stipe's commit. It doesn do anything usefull. 2007-01-22 Stipe Tolj * gwlib/gwmem-native.c: segfault prevention by setting all free()ed pointers to NULL. This follows the secure coding principles of CERT-CC. A non NULLed pointer may be containing bogus after free() and a redo of gw_free() and hence free() will lead to segfault eventually. 2007-01-22 Stipe Tolj * gwlib/dbpool_sqlite.c: remove gw_free() in sqlite_close_conn(), since sqlite's sqlite_close() will give a bogus pointer and we segfault. * gwlib/dbpool_sqlite3.c: same as above, also fix a deadlock while closing connection due to typo in while break condition. * test/test_dbpool.c: add sqlite3 sections to the test 2007-01-22 Stipe Tolj * test/test_charset.c: simple test checking GSM->UTF-8->GSM conversion. 2007-01-14 Alexander Malysh * gw/bb_smscconn.c: set smsc_running = 0 in smsc2_cleanup instead in router thread because so we never call smsc2_cleanup. * gwlib/cfg.c: fixed memleak. we should consider moving hooks to Cfg struct. 2007-01-11 Stipe Tolj * gwlib/cfg.def: adds config directive 'dlr-url' to smsc group to allow DLR bridging via HTTP SMSC type 'kannel' connections. * gw/smsc/smsc_http.c: adding generic DLR handling for type 'kannel', which allows point-to-point DLR forwarding though the whole kannel instance chain. Uses 'dlr-url' to identify the DLR inbound port to the next kannel instance in chain. 2007-01-09 Stipe Tolj * test/decode_emimsg.c: adding a simple tool that decodes a EMI/UCP stream PDU and prints more readable informations about it. Thanks to Vincent. [Msg-Id: <1ad701c6e08d$88bee420$9600a8c0@vince>] 2007-01-08 Stipe Tolj * gwlib/mime.c: fixing segfault in MIME multipart parsing. Thanks to Paul for providing the patch, and Vincent and Martin for review. [Msg-Id: ] 2007-01-08 Stipe Tolj * */*: update LICENSE preamble block to 2007. 2007-01-08 Stipe Tolj * gwlib/charset.c: removing Alex's debugging octstr_dump() calls from charset_utf8_to_gsm(). NLC. 2007-01-08 Stipe Tolj * gw/smsc/smsc_fake.c: enhancing the faked DLR support. Now we pass the ACK of the MT first to abstraction layer, in order to obtain SMSC success DLR, then care about the final DLR indicating success. 2007-01-08 Stipe Tolj * gw/dlr.h: fixing typo for DLR_SMSC_FAIL macro, obviously this is 0x16. 2007-01-07 Stipe Tolj * gwlib/charset.[ch]: re-add prototypes and function charset_latin1_to_gsm() and charset_gsm_to_latin1() for the sake of backward compatibility of external boxes using Kannel core libs. This should be reviewed and merged into single array for latin1 and utf-8 transcoding values. 2007-01-07 Stipe Tolj * gw/dlr.h: adding macro DLR_IS_NOT_FINAL() for non-final DLR status mask. 2006-12-19 Alexander Malysh * gw/sms.c: fixed wrong length calculation for concatenated messages. UDH send always as octets. 2006-12-19 Alexander Malysh * gwlib/octstr.[ch]: fixed warning: inlining failed in call to 'octstr_convert_printable': function body not available. 2006-12-19 Stipe Tolj * gw/smsc/smsc_emi.c: fix charset re-encoding for OP/53 DLR text. Thanks to Vincent for providing a patch. [Msg-Id: <2ab401c71669$8afc34b0$9600a8c0@vince>] 2006-12-14 Andreas Fink * gwlib/list.c: fix mutex locking for gwlist_sort. It was using the wrong mutex giving deadlocks if you did gwlist_lock(), gwlist_sort(), gwlist_unlock() now also unlocking the right mutex if the list length was zero. 2006-12-02 Stipe Tolj * gw/smsc/smpp_pdu.c: moving 'Unknown TLV' output to WARNING for the sake of log-file readability. User's may switch to appropriate log-level in case their SMPP SMSC uses a lot of vendor-specific TLVs. NLC. 2006-12-01 Stipe Tolj * gw/smsc/smsc_emi.c: some updates of references in comments. NLC. Thanks to Vincent for providing a patch. [Msg-Id: <0ac101c71542$ca5d3780$9600a8c0@vince>] 2006-11-29 Stipe Tolj * gwlib/http.c: fixing case-insensitivity for MIME/HTTP header value parameters. Thanks to Paul for patch and Enver for review. [Msg-Id: ] 2006-11-27 Andreas Fink * gwlib/list.c: fix mutex locking for gwlist_sort. It was using the wrong mutex giving deadlocks if you did gwlist_lock(), gwlist_sort(), gwlist_unlock() 2006-11-23 Stipe Tolj * gwlib/http.c: fix HTTP/1.1 keep-alive interpreation handling. We need to check response headers in addition to HTTP status version to see if server/proxy will allow us to act in persistant connection mode. 2006-11-19 Stipe Tolj * gw/ota_prov.c: fixing bug #356, where calltype parsing was not right. Thanks a lot to Richad Kotal for patch. 2006-11-19 Stipe Tolj * configure[.in]: fixing bug #368 to support Oracle 10g, via 10.x instant client libs and headers. Thanks to Martin. * gw/shared.c: added sqlite3 version output to version preamble, added Oracle OCI version output. 2006-11-19 Stipe Tolj * gw/bearerbox.c: resolves bug #369 by adding warning() calls for --disable-sms or --disable-wap functions, so users are aware that the function range is limited. Thanks to Martin for this patch. Some more source code beauty via indention. NLC. 2006-11-18 Stipe Tolj * wap/wsp_headers.c: re-adding quote char (") recognizing within the wsp_field_value() that isolates header values. Thanks again to Paul. [Msg-Id: ] 2006-11-18 Stipe Tolj * gwlib/mime.c: fixing bug causing segfault due to destroyed, but then reused Octstr pointer. Thanks to Paul for spotting this. [Msg-Id: ] 2006-11-18 Stipe Tolj * configure[.in]: add /usr/lib64 search path within --with-ssl block, ie. FC5 on x64_64 has that lib64 layout for devel import libs. 2006-11-17 Stipe Tolj * gw/smsbox.c: allow empty message responses. Thanks to Colin Pitrat for this patch. [Msg-Id: <44BCDE02.4090000@bull.net>] 2006-11-17 Stipe Tolj * gw/wap_push_ppg.c: adding support to pass the 'from' source addr via X-Kannel-From HTTP header in the PPG request. Thanks to Christian Boustany for this patch. 2006-11-17 Stipe Tolj * doc/userguide/userguide.xml: section describing the new 'interactive' mode for fakesmsc. * test/fakesmsc.c: adding 'interactive' mode via stdin and stdout to allow a more human like interaction with the fake smsc module. Thanks to Alejandro Guerrieri for patch. [Msg-Id: ] 2006-11-13 Stipe Tolj * gw/smsc/smsc_smpp.c: relaxing the TON=1 must have >= 7 digits condition. According to Andreas (see reference), there can be international routable numbers with less then 7 digits. So we only drop a WARNING here and continue with processing. [Msg-Id: <0C09E1C0-D32C-41AA-AD14-4F8D849D92C4@fink.org>] 2006-11-11 Stipe Tolj * gw/bb_alog.c: also add octstr_convert_printable() if custom access-log formating is used. 2006-11-10 Stipe Tolj * gwlib/octstr.[ch]: adding function octstr_convert_printable() to allow a simple convertion for an Ocstr to be printed in a printable locale character set. Converts and non-printbale char to '.', as octstr_dump() does. * gw/bb_alog.c: ensure in bb_alog_sms() that we use octstr_convert_printable() before calling alog() for DC_7BIT messages that still may contain control sequences and hence break the "one-line-per-entry" rule. 2006-11-03 Alexander Malysh * gw/bb_boxc.c: fixed message of order issue when we retry to deliver to smsbox. Thanks to Ben Suffolk for the patch. [Msg-Id: ] 2006-10-31 Alexander Malysh * gwlib/conn.c, gwlib/http.c: fixed race condition in unregister/callback usage/destroy of callback data. The race is as follow, spotted with help of http.c: 1 Thread 2 Thread 1) http:conn_pool_get 1) http:check_pool_conn 2) conn = XYZ 3) conn_unregister in conn_unregister destroy callbackdata 2) dict_get(conn_pool, key) -> crash because connback data already destroyed 2006-10-26 Alexander Malysh * gwlib/http.c: security bug fix for http.c. We have issue when we use keep alive connections with our connection pool. This is scenario without a patch: 1) http_start_request(..., ssl=0,certkeyfile=NULL,our_host=NULL) 2) http_start_request(..., ssl=1,certkeyfile=XYZ,our_host=XYZ) in (2) we will get from conn_pool_get connection from (1)! 2006-10-13 Stipe Tolj * gwlib/mime.c: fixing unquoting while contructing octstr from mime object. Thanks to Paul for this fix. [Msg-Id: <121E1E3B-AADA-4FC4-956A-AE410B416EF9@dsmagic.com>] 2006-10-13 Stipe Tolj * gw/urltran.c: fxing alias support for sms-service in smsbox. Thanks to Vincent for analysis and patch. Also removed debugging grp_dump() from Alex' previous UTF-8 patch. [Msg-Id: <000901c6eb10$e930c750$9600a8c0@vince>] 2006-10-10 Stipe Tolj * gwlib/mime.c: fix MIME boundry check and fixup. Thanks to Paul for this. [Msg-Id: <443F5E2B-781C-425C-8B85-E2D7ACEAA430@dsmagic.com>] 2006-10-10 Stipe Tolj * configure[.in], gwlib/regex.h: ensure that we use the pcreposix wrapper lib for POSIX.1 instead of system regex if PCRE is enabled. 2006-10-06 Alexander Malysh (CB) * gw/sms.c, gw/smsbox.c, gw/urltrans.c, gw/smsc/smsc_at.c, gw/smsc/smsc_cimd2.c, gw/smsc/smsc_emi.c, gw/smsc/smsc_ois.c, gw/smsc/smsc_oisd.c, gw/smsc/smsc_smpp.c, gw/smsc/smsc_soap.c, gwlib/charset.c, gwlib/charset.h, gwlib/latin1_to_gsm.h: Applied patch that converts internal kannel charset to UTF-8. Please note that I didn't add smsbox compatibility code, means smsbox expect text body to be encoded in UTF-8 as default also MOs will be forwarded in UTF-8. It could be workarounded with charset cgi variable. 2006-10-02 Stipe Tolj * doc/userguide/userguide.xml: fix once again URL in example of 'generic' in order not to use '&' char. 2006-10-02 Stipe Tolj * doc/userguide/userguide.xml: fix URL in example of 'generic' system-type of smsc http group. Obviously brakets indicate an XML tag and jade doesn't like this. 2006-10-01 Stipe Tolj * doc/userguide/userguide.xml: fix typo delete in XML structure. 2006-10-01 Stipe Tolj * doc/userguide/userguide.xml: updating SMSC HTTP section for new 'generic' system-type regex directives and a group example. * gwlib/cfg.def: adding 'status-[success|tempfail|permfail]-regex' to smsc group for 'generic' system-type of SMSC HTTP. * gw/urltranc.[ch]: adding urltrans_fill_escape_codes() to make the msg struct internal values available via the escape code function. * gw/smsc/smsc_http.c: adding the new 'generic' system-type to allow the usage of the escape code sequenced in send-url and regex parsing of HTTP response. This new system-type may handle a lot of existing properitary HTTP APIs of SMS gateway aggregators without the need to code and add the explicite HTTP API to this module. 2006-09-29 Stipe Tolj * test/test_urltrans.c: modified argument list for urltrans_find(), according to previous patchset commit. 2006-09-29 Stipe Tolj * doc/userguide/userguide.xml: section on new 'accepted-account' and 'accepted-account-regex' config directives for sms-service group. * gwlib/cfg.def: adding 'accepted-account' and 'accepted-account-regex' config directives for sms-service group. * gw/smsbox.c, gw/urltrans.[ch]: adding service routing based on account field. This allows routing of MO messages depending on the account set by an aggregative SMSC provider. Patchset submited by Alejandro Guerrieri [Msg-Id: ] [Msg-Id: ] 2006-09-29 Stipe Tolj * gw/smsc/smsc_fake.c: add TODO comment to add a SMPP DLR payload text for a DLR returned back via fake module. * gw/smsc/smsc_smpp.c: obey charset more closely in msg_to_pdu(), where we don't call charset_latin1_to_gsm() if charset flag of msg struct carries the "GSM-03.38" indication. This is not yet used by smsbox, but may be used by external modules before we have a clean transition to UTF-8 as internal charset and target charset indication via msg struct's charset value. Also ensures now that we write a "FAILED DLR SMS" access-log entry if we receive a DLR, but can't find it via handle_dlr(). 2006-09-29 Stipe Tolj * gwlib/http.h: remove semicolon ';' from #define of http_receive_result(), otherwise the macro is not usable in regular expressions in the code. Thanks to Paul for pointing this out. [Msg-Id: <100C7857-7696-4A6F-B5E4-B5B4D1735E00@dsmagic.com>] 2006-09-25 Stipe Tolj * Making stable release 1.4.1. gateway-1.4.5/doc/doxygen/0000755000175000017500000000000013312227707014112 5ustar toljtoljgateway-1.4.5/doc/doxygen/kannel.conf0000644000175000017500000022153412132245245016234 0ustar toljtolj# Doxyfile 1.7.5 file for Kannel: Open Source WAP and SMS gateway # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = "Kannel: Open Source WAP and SMS gateway" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = "$Revision: 5037 $" # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc/doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = YES # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields will be shown inline in the documentation # of the scope in which they are defined (i.e. file, namespace, or group # documentation), provided this scope is documented. If set to NO (the default), # structs, classes, and unions are shown on a separate page (for HTML and Man # pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penalty. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will roughly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.c \ *.h \ *.def # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to directory from which doxygen is run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = YES # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is adviced to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = COPYING # If the HTML_TIMESTAMP tag is set to YES then the generated HTML documentation will contain the timesstamp. HTML_TIMESTAMP = NO # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = YES # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the # mathjax.org site, so you can quickly see the result without installing # MathJax, but it is strongly recommended to install a local copy of MathJax # before deployment. MATHJAX_RELPATH = http://www.mathjax.org/mathjax # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvantages are that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Helvetica # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = YES # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES gateway-1.4.5/doc/ChangeLog-1.4.40000644000175000017500000014511412366723635014670 0ustar toljtolj2014-08-01 Stipe Tolj * */*: updating the LICENSE preamble to reflect the correct year. * gwlib/gw-timer.[ch]: convert to UNIX line ending. NLC. 2014-08-01 Stipe Tolj * test/drive_smpp.conf: use seperate config groups for transmitter and receiver, since we have deprecated the usage of both. 2014-07-31 Stipe Tolj * gw/smpp_pdu.c: add the PDU type value in the ERROR log entry in case we can't [un]pack the PDU. * gw/smsc_smpp.c: ensure we check the SMPP session state for every handled PDU we process. This ensures that we don't blindly trust the SMSC side, which MAY send logically malicious PDUs at specific state times, i.e. bind resp PDUs while active sessions. 2014-07-31 Stipe Tolj * gw/smsc/smsc_smpp.c: add the foreign_id to the access-log entry also in the case we DID NOT request a DLR from the upstream SMSC. 2014-07-31 Stipe Tolj * gw/smsc/smsc_soap_parlayx.c: reverting back to svn r5060. * soap/env_[fault|header].h, soap/env.[ch]: removed, due to revert back. * soap/Markefile.in: reverting back to svn r5060. * soap/plugin: adding directory needed for the local libsoap_plugin.a sources to be compiled. * soap/service/parlayx/parlayx_sms_send_service_2_1_wrapper.h: re-adding the wrapper for the soapcpp2 input file. This patchset basically reverts back the gSOAP plugin library build framework to the svn revision 5060 vesion. There was an approach to establish a concurrent build framework for several gSOAP plugins, but it has shown that this is not easily possible. Even while the latest versions did BUILD multiple plugins in one binary, the runtime behaviour was not as expected, mainly for the WS-Security part and the way the SOAP ENV header is threated in the HTTP request construction. We are rather moving back to the working version for GSMA OneAPI and Parlay/X. 2014-07-09 Stipe Tolj * doc/userguide/userguide.xml: fix inconsistent documentation for HTTP admin command /log-level, and add a note that this will be also the log-level for all SMSC specific logs, if any exist. 2014-05-15 Stipe Tolj * doc/userguide/userguide.xml: document the new policy about SMPP config groups not having both, the 'port' and the 'receive-port'. * gw/smsc/smsc_smpp.c: enforce ONE bind type per 'group = smsc' context. This patchset resolves a long standing bug #418, #208, which caused the internal state of the connection not to be reflected correctly, if the receiver was disconnected and re-connected, the transmitter session may still have been indicated as "offline", and hence the route was not considered during central routing of the MT messages. Generally we're moving away from the concept of having the transmitter and receiver session for SMPP configurable in one group, they need to be defined in seperate groups. 2014-04-29 Stipe Tolj * doc/alligata/alligata.xml, doc/arc/arch.xml, doc/userguide/userguide.xml, doc/wtls/wtls.xml: move from DocBook V3.1 to V4.2 and fix various XML tag errors. No content change. * configure[.in]: we need the xml.dcl to be added to the jade execution to have a clean XML tag declaration, since we are in SGML mode here. * Makefile.in: add $(XML_DCL) reference to the xml.dcl file. This patchsets moves the 'make docs' target to use the DocBook V4.2 DTD and schemata in favor of the too old V3.1. It also fixes some slight XML tag inconsistancies in the XML structure, but doesn't change any content. 2014-04-11 Alexander Malysh * gw/smsbox.c, gwlib/gw-timer.[ch]: added callback function to gw-timer 2014-04-03 Stipe Tolj * gw/smsc/smsc_soap_parlayx.c: re-order header includes and remove comment block. NLC. * soap/env_header.h: add SOAP_ENV__Header struct for Parlay/X modules to the abstracted SOAP env library build. * soap/Makefile.in: change the SOAP env build and incarnation of wsseapi.[ch] inside the soap/service/parlayx implementation. * soap/service/parlayx/parlayx_sms_send_service_2_1_wrapper.h: removed, moved the SOAP_ENV__Header struct definition to the abstracted SOAP env layer. This patchset fixes possible segfaults for additional SOAP/XML modules, when the SOAP_ENV__Header processing is taken from Parlay/X. This needs to be taken from the abstracted SOAP env library. 2014-04-01 Stipe Tolj * doc/examples/dlr-redis.conf, doc/userguide.xml: Patchset fixes bug #689 reported by Lorenzo Bagni. 2014-04-01 Stipe Tolj * gwlib/dbpool_redis.c: add handling of REDIS_REPLY_INTEGER in function redis_select(). * gw/dlr_redis.c: re-write the DLR messages counter retrieving. We can't use an INCR/DECR counter approach, since TTL'ed expiration won't correct these values and we end up in inaccurate counters. Rather use the DBSIZE command on the specific database used by redis, this is unique then. This is also more performative, since we don't need to update the counter every time we change a key. 2014-04-01 Stipe Tolj * gwlib/dbpool_redis.c: fix typo for REDIS_DEBUG macro. Add more possible debug output. NLC. * gw/dlr_redis.c: DLR-URLs need to be URL-[en|de]coded for redis and '%' needs to be escaped, since hiredis uses this inside redisCommand(). This patchset fixes bug #690. Thanks to Lorenzo Bagni for reporting. [Msg-Id: ] 2014-04-01 Stipe Tolj * gw/dlr.[ch]: reverting back to the direct dlr_add() including the use_dst flag in the function prototype, there is no way to handle an int type via va_args without knowin the number of arguments passed, only void* can be handled this way. * gw/smsc/smsc_*.c, gw/smsc/http/*.c: addopt the dlr_add() call to the function prototype. NLC. 2014-03-11 Stipe Tolj * soap/Makefile.in: make sure the gsoap enabled build is installing correctly, so we have a working 'gw-config --libs' reference. * Makefile.in: install all lib*.a library in the install target, which ensures that the gsoap relevant libs are also installed to the target. 2014-02-11 Alexander Malysh * gw/dlr.c,gw/smsc/smsc_smpp.c: Added meta-data support for SMPP response PDUs. 2014-02-10 Alexander Malysh * gw/smsc/smpp_pdu.[ch], gw/smsc/smsc_smpp.c, test/drive_smpp.c: don't print TLVs if they are not configured for this SMSC 2014-02-10 Alexander Malysh * gw/meta_data.[ch]: added meta_data_merge function. 2014-01-31 Alexander Malysh * socket.[ch]: renamed interface_name to source_addr to avoid confusion. 2014-01-08 Alexander Malysh * doc/userguide/userguide.xml: fixed compilation error. 2014-01-06 Stipe Tolj * gw/smsbox.c: fix HTTP retry starvation in a sequential retry with in loop sleep time. This causes MOs that can't be delivered to the HTTP application layer to be held in the retry queue for too long. Now we use the timer abstracted data type to trigger the retry call asynchronously for every MO message event. 2014-01-06 Stipe Tolj * gwlib/gw-timer.[ch]: abstracting the wap/timers.[ch] module, making it independent from the WAP parts, and useable for any delay object handling. 2014-01-06 Stipe Tolj * doc/userguide/userguide.xml: document escape code %# used to escape in values from the meta-data parts. * gw/urltrans.c: implement escape code %# used for meta-data values. Thanks to Alejandro Guerrieri for the patchset. 2014-01-06 Stipe Tolj * doc/userguide/userguide.xml: document HTTP admin URI /remove-message * gw/bb_http.c, gw/bearerbox.[ch]: implement HTTP admin URI command /remove_message. Thanks to Alejandro Guerrieri for the patchset. 2014-01-06 Stipe Tolj * configure[.in]: implement --with-redis option to support Redis. * gw-config.h.in: add HAVE_REDIS macro definition. * doc/examples/dlr-redis.conf: Redis config example. * doc/userguide/userguide.xml: adding Redis support documentation. * gw/dlr_p.h: extending the dlr_entry struct to hold information if we used the destination address in the lookup process, also adds the TTL variable to dlr_db_fields struct. * gw/dlr_redis.c: implements Redis support as DLR storage backend. * gw/dlr.[ch]: add 'ttl' config handling and extend dlr_add() prototype to allow passing the optional argument for indicating the usage of the destination address. * gw/smsc/smsc_[cimd2|emi].c: add use destination address flag in dlr_add() call. This is required since these two SMSC types don't have a message ID returned by the SMSC. * gwlib/cfg.def: adding config 'group = redis-connection' context, and adding the 'ttl' directive for 'group = dlr-db' context. * gwlib/dbpool_redis.c: implements Redis support for the database pool abstraction layer. * gwlib/dbpool.[ch]: adding Redis support to internal structures. * gwlib/octstr.[ch]: adding function octstr_replace_first(). * gwlib/utils.c: add Redis version output in version_report_string(). This patchset was originally developed by Toby Phipps. [Msg-Id: ] [URL: https://github.com/tphipps/kannel-redis] Thanks to Toby Phipps for the patchset, and Alejandro and Juan Nin for raising the topic again. 2014-01-02 Stipe Tolj * gw/bb_[boxc|smscconn].c, gw/bb_smscconn_cb.h: renamed enum value SMSCCONN_FAILED_TIMEOUT to _EXPIRED and also the access-log value to 'EXPIRED SMS' in order to make the meaning more clear, thanks Alex. 2013-12-28 Stipe Tolj * gw/bb_[boxc|smscconn].c: handle new SMSCCONN_FAILED_TIMEOUT case as return value of smsc2_rout(), which now checks internally if the message is still valid according to the validity timestamp. If not, i.e. since there was a continues looping in sms_router() since no SMSC was available for a particular time, it makes no sense to shift the message to the SMSC since the validity has expired. In that case semantically it is cleaner to DISCARD the message in the bearerbox scope directly, and avoid sending the message to the upstream SMSC with a logically expired validity. * gw/bb_smscconn_cb.h: add SMSCCONN_FAILED_TIMEOUT enum value to indicate that the validity time fo the message expired while trying to route it. 2013-12-17 Alexander Malysh * wmlscript/wsgram.y, wmlscript/wsint.h: fixed compilation error 2013-12-10 Stipe Tolj * gw/smsbox.c: fix valgrind reported memory leak, when handling a failing DLR HTTP call in url_result_thread(). 2013-12-10 Stipe Tolj * */*: cleaning up the code by removing gcc warning occurances of [-Wunused-but-set-variable]. NLC. 2013-12-02 Stipe Tolj * gw/smsbox.c: add SIGTERM handling in smsbox, otherwise the process will be cleanly killed, but we don't have a chance to do post-processing for the shutdown phase, i.e. removing pid file. 2013-11-29 Alexander Malysh * gwlib/socket.c: use POSIX function to convert to address to IP 2013-11-06 Vincent CHAVANIS * gw/smsc/smsc_smpp.c, gwlib/cfg.def: added support to specify our port when connecting an SMPP SMSC. 2013-10-17 Stipe Tolj * gw/smsc/smsc_soap_parlayx.c: changing namespace to use parlayx prefix in order to allow multi-service implementation in a single binary. * soap/env_[fault|header].h: using service independent SOAP header and fault struct processing, which is needed to support multi-services. * soap/env.c: dummy struct for undefined namespaces since we don't have them included directly from the service C sources. * soap/env.h: pre-processed by soapcpp2 to generate the service independent code base for the generic SOAP routines. * soap/Makefile.in: cleaning up the build process in order to allow adding more gsoap service implementations. Before this we got several clashes while building a multi-service binary. 2013-10-14 Alexander Malysh * gwlib/log.c: applied patch to reduce CPU load by logging. Thanks to Jacek Raczkiewicz for this patch. 2013-10-02 Stipe Tolj * configure[.in]: add the /usr/local/share/gsoap default target in the gsoap detection. 2013-10-02 Stipe Tolj * configure[.in]: use grep -e rather then grep -P in the gsoap version pattern matching. The perl compatible grep may not be build in in various distribution. * soap/Makefile.in: use GSOAP_IMPORT include directory rather then using the system default location. 2013-09-26 Stipe Tolj * configure[.in]: add detecting openssl library path on more recent Debian based distributions, including Debian 7 and Ubuntu 13. They don't have symlinks for the libssl.so libcrypo.so in the standard directories, but rather use the machine specific path of the gcc library path. This will allow to detect the path and hence ensure openssl enabled builds are working out of the box on vanilla systems. 2013-09-26 Stipe Tolj * gwlib/utils.c: fix build breaking if our own configure didn't detect openssl. PostgreSQL's always defines it, and hence we run into build errors. Using a simple preprocessor trick to reset the #define again if we know we didn't detected it on our own. NLC. 2013-09-16 Stipe Tolj * gw/bearerbox.c: remove PANIC within dispatch_into_queue() if the sms_type is not handled. This ensures we don't run into infinite PANIC loops in case any message is injected in the storage subsystem with strange values. The message itself isn't removed from the store. 2013-09-16 Stipe Tolj * gw/smsc/smsc_smpp.c: fix PANIC conditions within octstr_check_range() if the SMSC provides a positive ACK via command_status = 0x00, but doesn't provide any message_id. We'll consider the MT still as successfull, but warn the user via an error() entry log. 2013-08-23 Alexander Malysh * aclocal.m4, configure, configure.in, gw-config.h.in, gwlib/dbpool_oracle.c: added OCIPing to check oracle connection. 2013-08-23 Alexander Malysh * gwlib/http.c: fixed issue when Host already set in the headers but we set it again. 2013-08-22 Alexander Malysh * test/test_http.c: added don't follow redirect option. 2013-08-22 Alexander Malysh * gwlib/cfg.def: added dlr-mask to sms-service group. 2013-08-19 Stipe Tolj * doc/userguide/userguide.xml: document 'dlr-[url|mask]' config directives for 'group = sms-service' context. * gw/smsbox.c: add corresponding DLR values in func send_message() if we have some default values from the config, but no adhoc value from the HTTP response. * gw/urltrans.[ch]: added dlr_mask into URLTranslation struct, and access functions, since the struct is module scoped. 2013-07-03 Stipe Tolj * gw/wap_push_ppg.c: fix assertion check conditions. 2013-06-21 Stipe Tolj * wap/wsp_headers.c: adding some debug() lines to trace WSP header packing better for WAP Push messages, i.e. SI or MMS indications. * wap/wsp_unit.c: added wsp_pdu_dump() to dump the WSP PDU before packing for push transport, source code re-formating. NLC. 2013-06-19 Stipe Tolj * wap/wsp_strings.def: add various new WSP byte codes. * wap/wsp.h: add WSP_TBD to wsp_encoding enumeration. 2013-05-07 Alexander Malysh * gw/smsbox.c: fixed issue with DLRs because we don't have URLTranslation for it. This fixes #686. 2013-05-06 Alexander Malysh * gwlib/conn.c: changed conn_read_packet to accept startmark -1 and ignore it in this case. 2013-05-06 Alexander Malysh * gw/dlr_mysql.c: fixed memory leak. 2013-04-13 Stipe Tolj * doc/doxgen/kannel.conf: automated update via 'doxygen -u' to the configuration file. 2013-04-09 Alexander Malysh * gwlib/socket.[ch], test/fakewap.c: patch with - parse WSP message and save only the received payload to the output file - support for connectionless get/post - robustness fixes for Post (resend group segments if no ack), packet loss simulation Thanks to Piotr Galecki for this patch. 2013-03-28 Stipe Tolj * configure[.in]: revert back, not handling the 'pg_config --libs' output as these seem to be the static libs used while linking libpg.a itself, and they add unresolved dependancies on various systems. Causes more trouble then it help, going back to the old way. 2013-03-27 Stipe Tolj * configure[.in]: fix PostgreSQL detection and libs handling. 2013-03-27 Stipe Tolj * configure[.in]: fix sqlite3 version string extraction. 2013-03-27 Stipe Tolj * */*: updating the LICENSE preamble to reflect the correct year. 2013-03-12 Alexander Malysh * gw/dlr_spool.c: fixed compiler warning. 2013-03-09 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed issue with validity value because variable was not initialized. 2013-03-07 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed issue with registered_delivery flag if we ask only for failed DLR. This fixes #675. 2013-03-07 Alexander Malysh * gw/smsbox.c: fixed issue with DLRs arriving with a unknown service. This fixes #681. 2013-02-25 Alexander Malysh * gw/smsc/smpp_pdu.[ch]: fixed issue with TLVs default value. We initialized to -1 but the value was unsigned long therefore 0xff. Made TLV integer signed long and added check by packing of the PDU. 2013-02-25 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed sar_ multipart TLVs support. 2013-02-21 Alexander Malysh * gw/smsc/smsc_smpp.c: added support for sar_ multipart TLVs. 2013-02-21 Alexander Malysh * gw/sms.[ch]: made prepend_catenation_udh function global. 2013-02-13 Alexander Malysh * gw/charset.c: don't call iconv if charset from & to equal 2013-02-12 Alexander Malysh * gw/smsc/smsc_http.c, gw/smsbox.c: fixed issue with validity and deferred introduced by the converting to unix timestamp. 2013-02-11 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_http.c, gw/urltrans.c: added support for validity and deferred values. 2013-02-09 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed issue reseting user configuration parameters. This should fix #680. 2013-02-04 Alexander Malysh * changed validity and deferred fields to unix timestamp. Nothing changed for the external calls for smsbox. 2012-12-19 Alexander Malysh * gwlib/utils.c: fixed initgroups call. This fixes #676. Thanks to Alexandr Ryabukhin for report. 2012-12-19 Alexander Malysh * gwlib/utils.c: applied patch that display compiled PostgreSQL version. Thanks to Alexey Savchuk for this patch. 2012-12-19 Alexander Malysh * gwlib/gw-prioqueue.c, gwlib/gwthread-pthread.c, gwlib/list.c: fixed gwthread_cancel function. This commit fixes #667. 2012-10-31 Stipe Tolj * gw/smsc/smsc_smpp.c: the sscanf() is NOT taking a POSIX regex pattern. The '^' chracter is NOT representing a "must start", but an "does not include". So the whole pattern refuses msg IDs that contain a 's' character. Fixed this to comply now with the real printf() semantics. This fixes bug #663. Thanks to Mark Poulsen for the bug report. 2012-10-19 Stipe Tolj * doc/userguide/userguide.xml: add 'alt-charset' documentation for context 'group = sms-service'. * gw/smsbox.c: adding the 'alt-charset' handling for sms-services, allowing an user to define an alternative character encoding then UTF-8 to be used while making HTTP calls to remote application systems. Most of the diff changes are source code re-formating. The essential logic changes are found at line 1112 for the MO handling, and at line 1693 for MT handling. * gw/urltrans.[ch]: added function urltrans_alt_charset() and corresponding element in the URLTranslation struct, keeping the config directive. * gwlib/cfg.def: added 'alt-charset' to 'group = sms-service' context. This patchset implements feature Feature #661. 2012-10-19 Stipe Tolj * gw/smsc/smsc_fake.c: handled the msg->sms.coding types more adequate in function sms_to_client(), as most common terminals can display UTF-8. 2012-10-19 Stipe Tolj * gw/smsc/smsc_fake.c: add missing declaration of msg->sms.coding when an MO message is received and forwarded to the core layer. 2012-10-14 Stipe Tolj * doc/userguide/userguide.xml: document that we can use SMPP v5.0 bind connections too now. * gw/smsc/smpp_pdu_opt.def: add the TLVs added in SMPP v5.0. * gw/smsc/smpp_pdu.def: add optional TLVs to the the SMPP v3.[3|4] PDUs and some new PDUs as defined in SMPP v5.0. * gw/smpp_pdu.h: added a couple of NPI values defined in SMPP v5.0. * gw/smsc_smpp.c: add basic support for SMPP v5.0 handling. This patchset incorporates the new parts from the SMPP v5.0 spec into the codebase, without being intrusive to the current default behaviour. 2012-10-14 Stipe Tolj * gwlib/http.[ch]: add function http_request_url() to gain access to the used URL of the transaction, i.e. this will be required for HTTP RESTful implementations of OneAPI v2.0 in the SMSC HTTP module for the receiving function callback to distinguish MO and DLRs. 2012-10-12 Stipe Tolj * doc/userguide.xml: adding documentation part for new SMSC type 'GSMA OneAPI v1.0 ParlayX SMS SOAP'. * gw/smscconn_p.h, gw/smscconn.c: add new SMSC type create function smsc_soap_parlayx_create(), depending on gSOAP support. * gw/smsc/smsc_soap_parlayx.c: implement two variants of 'smsc = parlayx', for the Ericsson SDP 'system-type = ericsson-sdp' and the GSMA OneAPI v1.0 'system-type = oneapi-v1', both based on ParlayX 2.1 SOAP service. * soap/Makefile.in: generic Makefile for SOAP services implemented via gSOAP created C headers and sources. * soap/service/parlayx/parlayx_sms_send_service_2_1_wrapper.h: wrapper for the gSOAP wsdl2h created header file, to include WS-Security via wsse imports. * soap/service/parlayx/typemap.dat: namespace mapping file for the service. * soap/service/parlayx/wsdl/*.[wsdl|xsd]: web service description language and extensible schema description files for this service. * configure[.in]: implement --with-gsoap[=DIR] to allow adding gSOAP support for SOAP based services, i.e. for the ParlayX SMSC type. * gw-config.h.in: add define HAVE_GSOAP. * Makefile.in: set include marker for the soap/Makefile[.in] spin-off Makefile dedicated to the whole SOAP building framework. This patchset adds generic gSOAP support for building SOAP based SMS services into Kannel. As the first implementation, we provide ParlayX 2.1 with the variants of the Ericsson SDP and the GSMA OneAPI v1.0. More SOAP based services can be implemented easily now. 2012-10-08 Stipe Tolj * doc/userguide.xml: adding documentation part for new config directive 'dead-start' being a global config directive for the 'group = smsc' scope. * gw/bb_smscconn.c: use the dead_start flag in the connection struct to determine if we're connecting a SMSC or leave it in 'dead' mode. * gw/bearerbox.[ch]: changed prototype for smsc2_resume() to indicate a flag if it was/should be inited. * gw/smscconn_p.h: add dead_start flag to smscconn. * gw/smscconn.c: read the SMSC type generic 'dead-start' boolean config directive to determine if we are starting this SMSC connection type in a disconnected mode (dead). This patchset was originally provided by Alejandro Guerrieri. [Msg-Id: ] Thanks to Alejandro for the patchset, and Juan Nin for raising the topic. 2012-10-01 Stipe Tolj * gw/wap_push_pap_[compiler|mime].c: process the 'X-Wap-Application-Id' within the HTTP header of the payload content part of the multi-part MIME type, and NOT inside the meta-level HTTP headers. * test/test_pgg.c: ensure we inject the 'X-Wap-Application-Id' header to the correct section of the payload multi-part MIME type content. This patchset fixes bug #551 and has been confirmed in production. Thanks a lot to Nikolay Khrustalev and Rafael Aquino for reporting and providing analysis data to resolve the bug. 2012-09-26 Alexander Malysh * test/fakesmsc.c: segmentation fault when the program reaches EOF. Thanks to Rudy Matela for this patch. 2012-09-26 Alexander Malysh * gw/smsc/http/generic.c: fixed segfault and mem leak. 2012-09-24 Stipe Tolj * gw/smsc/smsc_smpp.c: reverting the last commit, since this has no logical effect in fact, due that ASCII is the first byte range in UTF-8 anyway. We get the same result, but still go throught the convert routine which can be considered overhead. Thanks to Alexander Malysh who pointed this out and voted for a revert. 2012-09-21 Stipe Tolj * gw/smsc/smsc_smpp.c: fix missing conversion to internal encoding (UTF-8) if we receive IA5/ASCII payload content. Thanks to Donald Jackson for spotting this. 2012-08-31 Stipe Tolj * gwlib/dict.[ch]: added function dict_duplicate() allowing an easy logical content duplication of an existing Dict structure, added functions dict_traverse[_sorted]() which allow in Dict traversal without locking the Dict logically outside, before going into a traversal loop. The sorted version allows to pre-sort the data elements of the Dict via a custom sorting function, then traversing the elements in this sorted order. 2012-08-31 Alexander Malysh * gwlib/octstr.[ch]: added two new functions: octstr_str_search and octstr_str_rsearch. 2012-08-31 Alexander Malysh * gw/smsc/smsc_http.c: fixed segfault produced by last commit. 2012-08-29 Alexander Malysh * gw/smsc/http/*.c, gw/smsc/smsc_http.c: splitted HTTP SMSC submodules into files. This allow us to reduce code in HTTP SMSC itself and prepare this SMSC for dynamicaly loading of submodules. No behavior change in any implementation. 2012-08-22 Alexander Malysh * gwlib/octstr.c: replaced old hash funtion with hash from Robert Sedgewick. 2012-08-06 Andreas Fink * gw/smsc/smsc_at.c: fixed a bug which crashed bearerbox if no modem definition was used in the config. 2012-08-06 Stipe Tolj * test/test_dict.c: add a second Dict to cross-key check, testing value consistancy. 2012-08-06 Stipe Tolj * gw/dlr_spool.c: reduce code complexity be re-using the essential parts. 2012-08-06 Stipe Tolj * */*: updating the LICENSE preamble to reflect the correct year. 2012-08-06 Stipe Tolj * doc/userguide/userguide.xml: add documentation about 'dlr-storage = spool' * gw/dlr_p.h: add dlr_init_spool() prototype. * gw/dlr_spool.c: implement a DLR storage using a spool directory. This uses either a SHA1 or MD5 hash representing the msg ID, adding a suffix of the destination address. When dlr_find() is called, we use the same heuristic approach to resolve the correct DLR message as in the internal DLR storage module. * gw/dlr.c: add initialization call to dlr_init_spool() if configured accordingly. * gwlib/cfg.def: add config directive 'dlr-spool' in the core group to let the user define which DLR storage spool location should be used. This patchset implements a simple, natively supported (no external libs) persistent DLR storage on the local file system using a spool directory. 2012-08-06 Stipe Tolj * configure[.in], gw-config.h.in: add detection of POSIX.1 nftw() availability. * test/test_file_traversal.c: file traversal test, using two different approaches to traverse a directory structure recursively. 2012-08-06 Stipe Tolj * test/test_hash.c: simple test program replacing test_md5.c which computes both, MD5 hash digest and a SHA1 hash digest if openssl has been available. 2012-08-06 Stipe Tolj * test/test_dict.c: add a lookup phase too, in order to have a populate and lookup phase while testing. 2012-07-17 Alexander Malysh * README: applied patch that corrects docs build on current debian. Thanks to Martin Atukunda for this patch. 2012-07-04 Stipe Tolj * doc/CodingStyle: fix type for --pad-oper option. NLC. 2012-06-02 Stipe Tolj * gwlib/http.c: fix possible problems for HTTP/1.1 "Host" header value. We need to remove the port in both cases that contain the standard port values, port 80 for non-SSL and port 443 for SSL-enabled connections. 2012-05-31 Alexander Malysh * doc/userguide/userguide.xml: removed meta-data from smsc group because it is not supported there. 2012-05-23 Alexander Malysh * gw/smsc/smsc_smpp.c: added workaround for deferred=0. 2012-05-16 Andreas Fink * gw/smsc_at.c gw/smsc_at.h gwlib/cfg.def: implemented ability to disable hardware flow control from the computer side due to some broken modems who not simply ignore hardware flow control but actually wire it in the way that if its enabled, flow is always disabled. You can now say hardware-flow-control = 0 in the modem definition to let the computer ignore that fake signal. Note this is not the same as enable-hwhs which is the AT command to tell the modem to actually use flow control. hardware-flow-control is the hardware flow control for the computer side. 2012-04-20 Alexander Malysh * gw/smsbox.c: fixed issue with shut down of smsbox. 2012-04-19 Stipe Tolj * doc/userguide/userguide.xml: adding documentation for escape code %x applicable for 'access-log-format' in the 'group = core' context. * gw/bb_alog.c: adding escape code %x for 'access-log-format' pattern handling, which substitutes to the smsbox-id. Reformated the function to comply with CodingStyle standards. 2012-04-08 Alexander Malysh * gw/smsbox.c: fixed double free bug for post request. Thanks to Bartlomiej Balcerek for bug report. 2012-04-06 Alexander Malysh * doc/arch/arch.xml: fixed #354. 2012-04-06 Alexander Malysh * doc/arch/arch.xml: fixed #355. 2012-04-06 Alexander Malysh * doc/userguide/userguide.xml: fixed default source and destination addr ton. This fixes #636. 2012-03-28 Stipe Tolj * gw/smsbox.c: fix minor compiler warning. NLC. 2012-03-21 Alexander Malysh * gw/smsc/smsc_http.c, gwlib/cfg.def, doc/userguide/userguide.xml: added new option 'generic-param-dlr-err' to pass dlr-err for DLR. 2012-03-21 Alexander Malysh * gw/smsc/smsc_http.c: don't convert HTTP dlr errorcode as stated in SMPP spec because HTTP is not SMPP. Just pass dlr errorcode as is to smsbox in ?dlr? meta data group, similar to other smsc modules. 2012-03-21 Alexander Malysh * gw/smsc/smsc_http.c: request DLR also if conndata->dlr_url is set. 2012-03-21 Alexander Malysh * gw/smsc/smsc_http.c: write the whole URL, with query string by debugging. 2012-03-21 Alexander Malysh * gw/meta_data.h: added some defines to use for meta data. 2012-03-08 Stipe Tolj * gw/bb_boxc.c: fix MO routing logic implied by 'smsbox-route' context. We have been passing MOs that had a strict smsbox-id routing decission to an random not-identified smsbox if there was no smsbox-id connection. This breaks the MO routing criteria. Now we obey the smsbox-id routing decission and re-inject the MO message rather back to the main queue. This patchset fixes bug #633. 2012-03-07 Alexander Malysh * contrib/kannel-monitor/index.php, contrib/kannel-monitor/xmltoarray.php: This patch adds replaces the * acinclude.m4, configure: added GIT version check 2012-02-21 Alexander Malysh * test/test_http_server.c: allow define custom response headers. 2012-02-15 Stipe Tolj * gw/smsc/smsc_http.c: inject 'text' and username variables to DLR message passed back to a smsbox connection. This harmonizes the behaviour to be similar as for the SMPP client module part. 2012-02-08 Alexander Malysh * wap/wtls_pdu.c: fixed possible segfault. Thanks to Armindo Antunes for this patch. 2012-02-02 Alexander Malysh * gw/bb_smscconn.c: fixed bb_smscconn_send_failed for DLRs. 2012-01-25 Stipe Tolj * configure: fixing autoconf generated script from Andreas, which breaks the 'config.nice' re-configuration handling. Seems to be the autoconf version related. NLC. 2012-01-24 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed compiler warnings 2012-01-16 Stipe Tolj * gw/smsc/smsc_[http|smpp].c: again, minor source code changes to follow our doc/CodingStyle rules! NLC. 2012-01-12 Andreas Fink * gw/smsc/smsc_smpp.c: proper handling of network_error_code. Kannel assumed it was the same 3 characters as in the delivery report string but spec says something else so its properly converted now. Whitespace changes (removed tabs). * ChangeLog. Corrected Stipe's year 2012-01-07 Stipe Tolj * gw/smsc/smsc_http.c: slight code change from Andrea's previous commit. We don't need to allocate more variables on the stack as we have a temp Ocstr* already. NLC. 2012-01-07 Andreas Fink * gw/smsc/smsc_http.c: added new parameter for DLR named dlr-err which can contain a network error code which is parsed the same way the err: field in SMPP delivery reports are parsed. * configure[.in]: added support for MacOS X 10.7 Lion SDK. 2011-11-09 Alexander Malysh * gwlib/octstr.c, gwlib/octstr.c.debug: fixed segfault on some systems where long overflow occurs. This fixes #623. Thanks to Lutalo Joseph Willrich for patch. 2011-10-31 Alexander Malysh * reverted commited that moved .foreign_id injection from dlr_add() because it breaks other SMSC module as SMPP. 2011-10-26 Alexander Malysh * wmlscript/wsgram.y: fixed compilation error. 2011-10-13 Stipe Tolj * configure[.in]: need to test for , tbough it is defined in IEEE Std 1003.1-2001/Cor 2-2004 it is not fully portable, i.e. OpenBSD and Cygwin lack the functionality. * gw-config.h.in: add HAVE_UCONTEXT macro. * gw/shared.c: add header include to fix implicite declaration warning. NLC. * gwlib/utils.c: include only if the system has user context support, fix minor compiler warning. 2011-10-11 Alexander Malysh * gwlib/log.[ch], gwlib/utils.[ch]: extracted backtrace output into extra function. Added fatal signal handler in order to be able to trace segfaults. 2011-10-11 Stipe Tolj * gw/smsc/smsc_smpp.c: moved .foreign_id injection from dlr_add() to the submit_sm_resp PDU handling code, otherwise we would ONLY see foreign IDs in the access-log IF DLR have been requested. Now we see them in any case. * gw/dlr.c: remove .foreign_id injection code in dlr_add(), due that this is the wrong place to do it. If the user didn't request a DLR, we still want to pickup the foreign ID and use it, at least in the access-log i.e. 2011-10-09 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed encoding of LATIN1 messages. This fixes #613. Thanks to Anders B for this patch. 2011-10-09 Alexander Malysh * gw/smsbox.c:: Set charset to UTF-8 for POST requests. This fixes #614. Thanks Anders B for the patch. 2011-10-09 Alexander Malysh * gw/smsbox.c: fixed double charset processing for POST requests. This fixes #615. 2011-10-09 Alexander Malysh * gw/bearerbox.c, gw/shared.[ch], gw/smsbox.c, gw/wapbox.c, gwlib/gwlib.[ch], gwlib/utils.c: This patch should fix issues with restart HTTP command. 2011-10-06 Stipe Tolj * gw/smsc/smsc_http.c: fix default DLR storing behaviour for 'generic' type. We shall always store the DLR temp data in a successful transmission, even if no 'generic-foreign-id-regex' is given. If it is given, then we try to regex scan it and use it for the DLR temp data, if not, then store our own UUID as reference ID of the message. This ensures generic behaves the same way as type kannel. 2011-09-30 Alexander Malysh * gw/smsc/smsc_at.c: fixed double reencoding issue when message retried again after the failure. 2011-09-14 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_smpp.c, gwlib/cfg.def: applied patch that allows setting of esm_class in SMPP module. Thanks to Alan McNatty for the patch. 2011-09-13 Stipe Tolj * gw/smsc/smsc_http.c: fixed double hex encoding for system type 'kannel' and 'no-sep = yes'. Due that we manipulate the msg->sms.[udh|msg]data directly, and the msg is re-queued in case of a HTTP call failure we get perform the hex encoding again, which results in a truncated content. We need to perform the transcoding on a copy and keep the original. Thanks to Paulo Correia . [Msg-Id: <4E6F3FF5.9000009@go4mobility.com>] 2011-08-19 Alexander Malysh * doc/userguide/userguide.xml: fixed userguide compilation. 2011-08-19 Alexander Malysh * doc/userguide/userguide.xml: another try to fixed prev. commit. Thanks to Nikos Balkanas 2011-08-17 Alexander Malysh * gw/dlr_pgsql.c: fixed panic when DB is not available. Thanks to Alan McNatty 2011-08-17 Alexander Malysh * doc/userguide/userguide.xml: fixed prev. commit. Thanks to Nikos Balkanas 2011-08-03 Alexander Malysh * doc/userguide/userguide.xml: update to wtls section with available ciphers and howto create SSL-Cert. Thanks to Nikos Balkanas 2011-08-03 Alexander Malysh * wap/wtls_statesupport.c: applied patch that fixes a problem with debug log output when large MAC names are used. Thanks to Armindo Antunes 2011-07-23 Alexander Malysh * gwlib/log.c: Fixed compilation issue when no syslog defined. 2011-07-12 Vincent CHAVANIS * gw/smsc/smsc_at.[ch]: added support for throughput in AT smsc 2011-06-13 Alexander Malysh * gw/dlr_oracle.c: fixed sql query syntax error. This fixes #607. Thanks to Heiki Pikker for this patch. 2011-05-20 Stipe Tolj * gw/smsc/smsc_loopback.c: after switching the MT to an MO message we want to clean up any MT specific values, that are still present due to the duplication of the message. This is semantically cleaner. 2011-05-11 Alexander Malysh * configure.in: added MacOSX10.6.sdk 2011-05-11 Alexander Malysh * gwlib/socket.[ch]: added function to enable/disable Nagle algo. 2011-05-06 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_http.c, gwlib/cfg.def: applied patch that adds meta-data to generic http smsc. Thanks to Semion Spivak for this patch. 2011-04-28 Stipe Tolj * gw/smsc/smsc_http.c: fixing removed portno assignment in r4894. Thanks to Rene Kluwen for spotting the defect. [Message-Id: <030b01cc052c$60054600$200fd200$@kluwen@chimit.nl>] 2011-04-18 Alexander Malysh * handle INTERIX differences in the configure. 2011-04-18 Alexander Malysh * removed INTERIX check from gwlib source and put it into configure. 2011-04-18 Alexander Malysh * fixed memory leak. Thanks to Roman Shterenzon for this patch. 2011-04-07 Alexander Malysh * fixed kannel monitor web interface after r4897. This close #594. Thanks to Roland Discein. 2011-04-07 Alexander Malysh * applied patch that adds support for limiting listening for smsbox connections to specific interface. Thanks to Roman Shterenzon . 2011-04-05 Alexander Malysh * gw/bb_smscconn.c: fixed last commit. 2011-04-05 Alexander Malysh * gw/bb_smscconn.c, gw/smscconn.c, gw/smscconn_p.h: apllied patch that implements speed/throughput meters on a per-smsc basis. Thanks to Alejandro Guerrieri for this patch. 2011-03-30 Alexander Malysh * applied patch that fixes some issues for HTTP-SMSC: 1) added support for max-pending-submits , so that we don't eat all our file descriptors if we have much traffic 2) changed open_sends from long to Counter, avoid race conditions 3) start new sender_thread because otherwise we are unable to limit max pending submits and if throughput is set we block the whole bearerbox instead of only one SMSC 4) changed shutdown sequence to run safe in parallel 2011-03-30 Alexander Malysh * applied patch that fixes DDos issue with our HTTP-Server implementation (consume all available file descriptors) and also adds possibility to set keep alive timeout for each listen port. This patch will limit maximum open client connections to 500. 2011-03-25 Stipe Tolj * gwlib/dbpool_sqlite3.c: ensure we handle the sqlite3 version >= 3.3.9 function call switching via #if pre-processor macro so we choose either sqlite3_prepare_v2() if we do have a local sqlite3 version that supports it. This ensures we build again on CentOS 5.x ie. [Message-Id: <4D8A73B6.4050508@tolj.org>] 2011-03-22 Alexander Malysh * debian/kannel-cvs.init, debian/kannel-devel.init, debian/kannel.init: added status command. Thanks to Konstantin Vayner for this patch. 2011-03-21 Alexander Malysh * test/test_http_server.c: don't do anythink that use threading in signal handler. 2011-03-21 Alexander Malysh * gw/smsc/smsc_http.c: fixed alt-charset issue that we try to reencode even binary and UCS2 data. 2011-03-21 Alexander Malysh * gwlib/http.c: added new method. 2011-03-21 Alexander Malysh * test/test_http_server.c: don't do anythink that use threading in signal handler. 2011-03-21 Alexander Malysh * gw/smsc/smsc_http.c: fixed alt-charset issue that we try to reencode even binary and UCS2 data. 2011-03-21 Alexander Malysh * gwlib/http.c: added new method. 2011-03-21 Alexander Malysh * gwlib/http.c: indents. 2011-03-21 Alexander Malysh * gwlib/log.c: Comparing a va_list with NULL is bogus. It's supposed to be treated like an opaque type and only be manipulated with va_* accessors. This fixes #587. 2011-03-12 Stipe Tolj * gw/smsc/smsc_http.c: reverting back last commit due to veto if Alex. Need further investigation. 2011-03-11 Stipe Tolj * gw/smsc/smsc_http.c: ensure we handle 'alt-charset' correctly, in case we get DC_UCS2 coding in the payload. [Message-Id: <4D76BF9C.7070700@tolj.org>] 2011-03-09 Alexander Malysh * applied patch that adds sqlite3 DB and DLR support. This patch was originally contributed by David Butler, posted 2009-11-23 to the list, with Msg-ID <22DE7AAC95BA4B5A9EEF3FEC90222162@VAIO>. Stipe added userguide parts and fixed destination number prefix handling. 2011-03-08 Alexander Malysh * gwlib/list.c: applied patch which fixes a rare memory leak. When the destroy is called, it extracts until a NULL is found, which may not necessarily be the last item in the list as gwlist allows you to add NULL items to it. Thanks to Donald Jackson for this patch. 2011-01-25 Stipe Tolj * gwlib/socket.c: fixing memory leak in tcpip_connect_to_server_with_port(). 2011-01-24 Alexander Malysh * gw/bearerbox.c: Added support for HTTP-Proxy. Thanks to Christoph Gysin for this patch. 2011-01-10 Alejandro Guerrieri * doc/userguide/userguide.xml: documentation parts for the syslog. * gw/[bearer|sms|wap]box.c, gwlib/cfg.def, gwlib/log.[ch]: Extended the syslog functionality already on wapbox to function on the core and smsbox groups as well. Also added the ability to specify the syslog facility to use. [Msg-Id: <4CF8F91C.8020206@tolj.org>] 2010-12-17 Alejandro Guerrieri * contrib/kannel-monitor/index.php: Fixes display bug on kannel monitor. Thanks to Mariana Gambande for this patch. 2010-12-10 Alexander Malysh * gw/bb_smscconn.c: Fixed panic that we destroy message twice. This fixes #582. Thanks to Alexey K for bug report. 2010-12-09 Alexander Malysh * gw/dlr_mem.c: fixed PANIC and memleak when flushing dlr_mem. Fixes #581. Thanks to Tom Moertel for bug report. 2010-11-08 Alexander Malysh * gw/bb_smscconn.c: destroy old lists by reload only if we were able to load new one. 2010-11-08 Alexander Malysh * gw/bearerbox.[ch], gw/bb_smscconn.c: moved bb_reload_list to gw/bearerbox.c and added wrapper function. 2010-11-04 Alexander Malysh * doc/userguide/userguide.xml, gw/smsc/smsc_smpp.c, gwlib/cfg.def: applied patch that adds the implementation of client SSL certificate support to SMPP. Thanks to Luca Corti for this patch. 2010-11-01 Alexander Malysh * gw/smsc/smsc_smpp.c: applied patch maps the receipted_msg_id parameter on MO message to the foreign_id field, thus allowing to use %F for MO as well. Thanks to Alejandro Guerrieri 2010-11-01 Alexander Malysh * doc/userguide/userguide.xml: added smsbox group configuration variable sms-length to the userguide. Thanks to Luca Corti for this patch. 2010-11-01 Alexander Malysh * contrib/web/sendsms.php, gw/ota_prov.c, gwlib/fdset.c: fixed some spelling errors. Thanks to Luca Corti for this patch. 2010-10-20 Stipe Tolj * Making development release 1.5.0. gateway-1.4.5/doc/alligata/0000755000175000017500000000000013312227707014213 5ustar toljtoljgateway-1.4.5/doc/alligata/12-11.png0000644000175000017500000001342407344776077015407 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ O¹€ pHYsÓÓŽ{¸®gAMA± üa£IDATxÚí]=›Ü6’îñ󊈎$GÝYަ'²M+²3²Ële—­í]ä½° 7ºÙè6“/Ò(Z;RwäqÔìHRD2R3ÂV üÁéŠï´Zl¼¨B¡ $)県.þíÐq· 8F‚Ž‘àc$xà 8F‚Ž‘àc$xà 8F‚Ž‘àc$xà 8F‚Ž‘àc$xà 8F‚Ž/]€2ÄøñˆÇœpÅ‘L–ËÇ"ØË#8÷aª:÷ÆxVÓ«y”ǃ J)qˆÓ©Ca:Dí•ÇÃO ‰ê·G½]^Ρ›®€½ ÀóHò”ƒ)[± ŒÕ1;‚Eºà>|ªÜ’…ƒÅõƒ´,±xŒú’ Ñtr_ ; {€8¼¬x¸©uÕ{¨GÅ%0‡½ôÚÛªJ%=œÇJªrÌí$,׌£HJ`,  ~Áâ®L\kpsI)Ù+@‚“îEœ’k냤Ü+Žâ]Lõ\d{„ƒÊþ¦÷§}³ Á@^ø)\þÆ=/b ¥o¹Ò¨[äIŠZ”U¤¥9ɦȖ¨ªASyU?ËÔ–¶%œó¢àg’â6¹îr):UT´…ãE[Ê\Â˜ç¹ 0¹7iMyC‚c⾿ñÃpã åF¢Â"—|NQ†µ(ÕŠíK+,{Ra” ¥gX^.Qø¨ê]Êî±ÙƒÙìþ d½i1ìðW@ëĬHD‹ÃÌb¶MÕ~Õ(§Tœ[ umÒ@aÐÆõ¯„ž›0Üof:Ó(µD¿—6óè„Íf“YSQ¶5²€ÝåíróqÃy%…Vì¦ 9)3èÛ2(‹4µ„- “¹Åý™-±´“zD1÷É™«m#"SGÑÔ˜jG5oƒ`èCFžç1—Ù—ÂB‚c²ô—«÷«àc€Vn:Oç;…Ñ®ÐÊžlÕZÍÐÎÒ¢¦½5i&dt,Õ“ªŽµ1ѳ-Ù ,šØÈkÁ°;c“ùìÒþšõûý·Ë·AH£És[‚Ú¤)D!¼*3 ÝÕ‡–îsölç-†tªV,y~ÞP­¢Ñ„Î1œÀ9@ØÁ,£ºæ¬Õ±}]hÏÐMhabYÁÚ“Åm×mßuø,Í¿ôBæ«7:Å|¡=C²›Ä À0M"ºœrš.IöV«h{Íi û<͉¹½†Ä ßòìÆVZ´2\¸òWKnCuGÕîwÖn]Ž|jí~5‘#˜QoöàlêÕÜ‹ö…)×Ä_E³‰ÃpU–ºÛN 3%«» yå= 'Œ"µË3*¬!é axp‚ƒ=R|ìèäªT“Ý‚1õÓ·×½î„4äIc|ÚÀQCð¸:ç¨aázª!Ø0—Þ”~ЉÅºø‡ïâ”^Î=6Ø>„%7Gª ¦‡•:‰Fô„z [G0ŠbüòÝOE×=µGïÇ%eá[ó-¼Ä¸–¨Ëmĵ§ì 6h›gU>¹¸.M·ŒØÔîÍ…nr7Ùäs‹4ªr&uÁüãÿ[÷GŸ#íEwl/ËÓ-×Üui;ÁîQ=u'ó`^çªì÷&¾F{-£=íÖoüGÏIíQuQÚ»C«68ß% ßb-À1Äÿi‡ûƒ+§Iò‰Íöìö^ÏZ•Ð4 ßÅ2hq¹>Q1ßå:º]Uÿ¢(T-G­j,}©^n ×­§ôàb†9Ý››‘[®°<…ÚŠ¶AuÀ³Z®—|7óˆ{BÆ›ƒ÷Ò€?`zo:07?àÁ¼dg 6œ<*Ç`ý>âPãí0û¢GŽò6üZgVµŠV–[ÞȺþõ§q >Dh@ÕËà>qÔIZ5ÁÊ6“ÏØÏ<ÒzĞѥÕí|ÑÚ33¥¾>¡‰àgŽvѤ£^&>BGÃ1˜“'bœ\Ó=°KÌíÕ7ôŸé‰¹¬ÆÕ)ºX´%øå¯?ÇUqSVZܬ=¢5Jp]_²|Þ²åÕFv»Ã,Á…˜rmX¸!Ž7Ú:Ø«è;qmC´uبTÑ´ô­?´ÆõÙÚ2:ª»­ •ó` ¡3J°µÐÖÞLm>‹œl´õøQö?øoÿx‹/MÊ>)šÔŃG½zxRf.›97¿Ít8œZ_>ÝÙíUÒäuQÑbõ†-Å#©û‡å3{²Æ{Òö‡J)Uo5®áØM2,öÃJû‚¡¥©SÿÆÃ#Ê»†å[MGô‰Jëáj ®xa]dñ”ñ=£°.:y„w·1˜:­@\ú³*4”u\¶ÞK†Çã„I^NZj+Ú¡†aØž]³ßѰNý®q*–é#¬ì‡Éê1˜&oVØ öO.®»´N#a-Õ¥ÇbÌéU9ƒÙÅË•p@džÿ[ ƒíu´'n/=ÃR[wŽâÝ+z†z8¹xXÕ¹†]¹tý*ûD¥íÇÐ5ѤbîjmÃi’J¯m».ÛèÅÀÝ/·Øðk$T4ŵ·H¦ÍýÁ¥C¬ù½’G߈GNF‘óh»ÛÈ%Jo*)ì”yTO±éí£xƒ¡¿ÄhbË9d½ ÄýÈã­ {Bîµ¾gßÌDŠÇ\:»Îܶô'ÂiŸpâh‰Â?›OÄ›”Æ»Wö„T´RDMÞ.h 6Ðì0ÞáA#î6V–Ñ“% ñQP*ѲàÆD°zñ÷ˆã„5_˜³ŽC c0OûмÃ_ø:2ï§$uÏ7üÜÌéÒÁ-rxU8+ÿž#ŒÓ$€xGm^ŸyöÐ]ñÝíY³ÊŠâO–ZõS—UΛ‘sï•Ù_žJýef'š|oқߟɰ•Ø Ç`tGãLIÌ”sQ “^u«ÒÈ.ÉzËI6†‘KTphŽÝôù)]=Y˜…KÕ\©‰µexlëçÆnQ. wéIñƒîN’»·?gŽt(.¹±X]S³èŽ¢!M‰‰1€˜æØvòt<á¶;EÚ<9aÅC•õ”¬sVo#D5uY$þÑÃÿÎäRçZqP÷Äw—ádI.ß±ö^é³g½ª{og›¢æ?™½NÍs"iB¨²ø I™ü¹£°ù[s²+âk¹8®N‚¡p.•>K½öT+:Õ*£v;„è½2Ù+k•v䯭{ø(G]þ“­W>%÷! »I­»u·¤ÀGgOr¬„ûe8töbE»óX¸ r‰+MÓ¶x%fKôëué1·ê¬ôwÂʆ‚oIašî ê‘–X*µòBЙ˜Ë&ÞÔR‚MÑ$‰M¸YXË× s]LGQÞü0Þñ¨å«=%»”ÈMÙÔò¤úûƒÙ=6aº%á6¢`ŸÇ™{w‹¤õÕ¹^Ez;X–9jzŠ%m-ØÔâê —M½imˆ0sµZ &b-´úADWNåwSdâAÞ¥ë$Ë¡»𠲫صÃÌ•¶!˜HŽ?Œ`0ÏG”Ï ?é·÷ý8Š®p ¾$1s‘ì¢ìµÍí[‚‰à8üR rr»×½÷Œœ&8ndŠY0\Ò%ÉTÛ+ÃwÂ.—~ ÈöŰ'X"܆a†<$qÕœªVë)¤OôŽ´­S[$Î _â,ÿ§ÔR¢¨ŠÕ£Õ…„H¯AG"«Ð˜`‰þb4«ó''ÃÆî&u„82.dÿ ×ϼ·¤[44³x&iÖòIš—û?=W,IJ¦.ú$õŽ˜³DK‚ï±è79pÒ&È51®.¹)$Ãâ ;PõŽŽn¸iǦÁ¡«5"Ao>‹¶Qø1 ‚6€cƼ‹vL q·3.ý©FŒ­2†ßB•2¯ÐU‚¡d¾ïóHým‚ f(Ü#ºGjq[…>àZÔsá§—>@D–ΫдAD*6Ù&i‹ÉŸØ^[.9†é  ´$ÈÆÕÕÕì«Y_eé*ÁP¦`Hþde ¸¸’+IHø„e<ãY ¥Ä«ÊG‘ç±ÙÆ&<=²zvŠÑJþ¥)(£<2dâ Ç„ax³¼Y­Wù¯¿L§¶ÎH3¾è$¾Qì"£Äƒ ("öPÊ•a ú9÷ª9XHÀÛ$¶rb  ÁÇ Lžå9@>~ôøÙ³}Å0ZW»«24cj¬9¡òØMäw¶m¬D…: ç7ÿóòá˧ÿñ4í÷]ÐA‚câ¿÷±zæÅáz½Þl6°AD ƒŒ®˜ç¹Ò£j8g »y…JLf áW·Ëõ­ï?ÄœÙý>G£Þ¼¬nWhvÈrn “)^,Ù^?A6—S±­+g5 ‚76‘8ãúo×ó¯ç‹ïÝ Ùž`ôjmÉ(|ûøÀ·,_ªi)Ç4ñË ëTÁ’f؆^íbç…L‚(1rÔKë™õ #TÔÂI­›N.`[J¹ÔÕ)©;Ž¥—£µC€é׿¼^,Ý©öP©—@ò”¦’HTêîPJ8yч²°R5N•‹GfnOæ­\Pk˜>€®ÁF؈ÖþŸ8жx€ ]~jN$Xo%'ùŽð{}»†V>è:·%8Æñ>²‡†»‚‹ëßQ$`þ‰c+PÂÜP6…܈@G9 ‡³ƒjlµZy ƒÄ€é/ªâòÅF¤Ì{^èÈ6Z¯‚餫¥Ù’`àUJ-z%·‰ÑkÝP/wŒÉ·Òæ£:­ÄËz\PÃ3â,ÚPÍò8÷šÂô T¹‘!œ†ÏEø“½ÄÀL@3±‡¢Q*mëAÛ‚J€‘¸c ;ŒÁh@n¨Ã€;¥šˆd‘ËÅ‘òKSN'bÁˆ*¨bF\wqMÆ¿¼éƒÉdë‡7ÿÂл “ù¾×‹ y§€‘EÒ ™¥ÊEv9ˆ2ÔóëËXµ¼Ý1Ì*@-Ií-ŒÐOœªçöâ75òa‡pÙ‚z[þ¾^|Õ>¬ÐŒö*:Œ0¨„ÆQbúŸxƒ%èDGǾA}±{ J,1§ôPѵe˜O™ÿÛú2û„z“=×rYè!!Êùæõ6aFP ŒRʾºœž]@•Aˆ…‹ ¾aš‹ÃšÙ Û0ˆñÞk*–CyÐ2p†´Z¸´à6ØiÜNelK°èz`DUÐé„yÅÙ—óËïŸL°˜T-¿Ç׈ +c»!Âã—‰Òz¤÷Ø»†«åW‹ ~Êýøï?^,Ç/ÁÐçßÌ—‹¿¿ú;wqšÄð¡Þ4öçî„Q4M` ¢÷<ÂÄ`D™Òd'TXah™OÐ`…ñ)cáo¯Bÿ­ˆ˜ƒt~·WÑ0ù—0Áø†Þ¾á”lpD#ôï *‰¦ƒ —3Œ.«úÂÚ|üè1Ìñg&dÎ@ÀìËÙ£«G¯o^+wìrz{³ô—;ž#”¬+ ÐNQ±ÁhÅf£ ìpÕóiCP±¡W ×èÜŸtêkK‚áòP7("XzRÈ÷9„ëå Ùõ:-ÀšØÔ‘W› :žu˜Ç{ùüùóó³s´KOPÎù|þìù³—×/— ‡¶ oQj9Áô€VBÞ–FP{HÇÿBP¼\»—ÐÝãD›"f›Àúìlv8 vÈl:sùò×”3FrõM‹›5…‡ëŽuŒ0ÈÑÃþÃÕÕÏ/.ξš¿rÖSÕ¯~œ?œ_ÿãå›ÿ{SyoKB1Å]î%¾<1éW§(/^Ú>ÊÕÅ•[›£ÌïŸC woŠö*´Êbqñæ—×›>ýýNº,xR¤ÜÅ n "´ÜÆÛ'& öO‹] ÆØùùù3æ-./ÀæzýËkþ ÝrFÑ… z{›ønuH Ø ¹poá„ó|>ÙÝ“ÕaE‡ðo\ÿïõ‹ ‚P½j©¥þH˜­¶¸Gˆµ 7¤^~·ývñívò¤6ß "êºúí¯ooþyãß®aî'ë¥cõœ4Œq–•sdŠF-ýøÑâÙŸŸ/¾»<(ÁDÅ^½zõâÅ ËÄD§ä0’á´<¿[¯çÏAdÑÖ8þ°``-V·«õj ³ü}‰.Í!¯Z)ÕpZCÓ‹ï?ÿçÏÐõ{‰üw]“%Cf777×»VÁ%©{“e¡8Ä‚AÈh``Ø•"«VœºÔVAJ³ðFÁïÞ¾¾¡¡6Á†äžn£y§§“)ðúôOO//.‘Ý>ú}‹îDe|Ùmi°5¤¼¯s™€š KdÍ#WÑ>ï}„w¿¾ÖÓ’ìýÐ28Z]^Ì¿žËVêëú½­ª”i`Z*(œãÇh@â£ûb¡Ñ=&­ŒÏúºœ÷Èõúv-õ6Híì+ìú“ÉD6T¿Zí–ͦ+,%ÆEw:ä„"±ªvs2•êÇ´.zĠዱFœF‚Ž‘àc$xà 8F‚Ž‘àc$xàøRúåi³nðIEND®B`‚gateway-1.4.5/doc/alligata/12-4.png0000644000175000017500000001406507344776077015333 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ ;3rVè pHYsÓÓŽ{¸®gAMA± üaÄIDATxÚí]½—Û¶–öäÒ¨ÊN%¹Š]¦Š]\%ÇÝv±»íbW»[åí)_µóª}íj³•ÇU’ÊR•I5Te»"YY¬°÷ ~à‡$ŽÂßèh(ð À÷ââ^€¤œs2âxñ/‡ÎÀˆÝb$øÈ1|ä >rŒ9F‚#ÁGŽ‘à#ÇHð‘c$øÈ1|ä >rŒ9F‚#ÁGŽ‘à#ÇHð‘c$øÈ1|äøêÐ(CŒ_xÌ 'QÉd9},‚½<‚cp¦ªpoŒg5½£„8 6(¥Ä! þ(¦S‡ÂþtˆÚ+‡ŸÕoFÙöZΡ«®€½ ÀóHò”ƒ)± ŒÕ1[‚Eºà>|ª« $‹óiYbñõ%¢éä¾@06A*¶qxY#`¸©5Õz(£âx…½´ÚÛ¬J%=œÇJªrÌm%,÷Œ£HJ`,3 ~Áâ6O\«psN)Ù+@‚“æEœ’{냤Ü+Žâ]Le.²Ž-ÂAåÓ»Ó¾²Ù†` /ü.çŒEž‡ÒÆ7\iÔ ò$E-Ê*ÒÒ+ÉªÈæ¨ªBSyU?ËÔ–¶%œó¢àg’â6WÝ^¥˜éTmPQ‹6Ôs‰ç1æz€ÉIkÊ?ðýµ†k?à˜)7WÉ_)Êg¨ð”<Çp ­¿N-Jµb;ÂÒË–Tè%hé–·K>ªz—zw¼Ù½Ùìî d½i6ìòW@ë'ĬHD‹ÃÌb¶NÕ~U)§Tœ[ uoèÒ@aÐÆå¯„~5a¸56Þ$Ìt¦5Pj=ˆv/m:щ7›MfMEÙÖÈv—×Ëõç5ça”dZ±›2ä¤Ì oË ,ÒÔ¶$L^-îÏl‰¥œÐ#²Ñ¸íHÎ\m™ЦÆT…8ªz#èC.Äó\Ï>“¥¿\}\Ÿ´rÓq‚<ß)ôv…Zf²rlTk5C[K‹šöÖ¤™Ñ±TOª:ÖÆDÏÖdƒ¼hb#ïÀîÌ›Ìggö÷¬'Øÿì¿_¾Â@MÌQl j“ª™`Ug,º--ÝçìÙ>6"Î[ éP­˜ó|œš›Ö-cÛ£9\’ì1oêz÷ïÍUm×)­ ²ÿQtº\xêžRp‘˜òš»Íý+t¹VÕ¤íõ¥Ùi²•^³\—ºÚ7×KQÌ_¹Oã\Ë Éµ(ÉòNõ*ƒÒÁP%¤<$¡’´:Ôö»i.ÊÑ}–ÚÔîÍÒYFîzþøòò·ç¸ñHm|÷–6—¨$‘g§¯?ü¨]R$Î/äÆëåÛ#çúO=%=>¦g[ ³T¿•Š7ÊüKájÛ[äª/Wm[_ ‘>>ŒºÄ5‡Qˆì&R+ˆ¤©+G8hDŠt¦ÕT(d*dy \?—“Œù–@2”cNÿiÞ¥_*Ç}IíZö UÍ™^2Œo-Öâ>Åk2ÚÔòcï‘5À¤ Ã0’7•ζ”]øé‡üˆº›ý8L~ˆøà¶Ë@j±¢O/•V§ Ä>˜õäƒ)ó$Ñ9F%ý–…7_V~§WÓ·õ=1s–V¢ì6Û~V ~ôŠÂ&êV¸·²µ‘xmëa’`å.NÙ%dË®bZªb[#9'|ºÂÌm2k‰"ßúw#Žu}n™ÕÒ*A  ¬üX°7%¯Â¥Ï,ÆnF-½‰5‰¢dÙíà[hÊ_ZeE-ݵ;×PvT¨Z(S+&ú€;a;•‰à0•`’p);]'ñ³4ý×Â,d½¨_‰îLô˜™HvB¢…e–àdc«™‰¦M˜­Òæz¯²˜ttî^²Ú':xèL«@¬‰È0þbq¹Ÿ1ØÃDÓÒUýzñÈö•Ô0«6Ç·¾×›?^Šÿ¨\=Rﳬ‘à$XK¤6îEb Õ¡ÛAº½gÕšzºi_†};˜\•Ë?—K -EM?îP¹‘:ÁGìPÓçó‹Dv0²ºïͦެö\³££d4ýüñå¡Ë{0ì¯Ó­EL¸Ý8Øèè(Êöð&•ýupþðçl‚•3«Á´ÙQ% ޲­tŽAül6,-¬ÜP÷ò×çúÏ¢ÉJº¹©ÁÒƒ¥i]š±Ò”ôøâ‰¥—:ô>X!®§¸º“#‰æÔ晨‘*  ö—*½{θ5쪽©áRƒ@låɪ”àˆDjœNÞ¨»V±B‹b¤'–Š{Êe`o#. JZ3«U4 Ÿx"¿ZLûù£Ë×I×Y×z§)9'~•doR¾-Åqp"«C2cᎮTÑÜpæ$±ÏHý+‡ k±#Ž©CÎæãÁ yovrïÄ|®qF/±¯lÈMÆ8tvzBÅx—[èèAXÑ=âxHí ã;n+pŒ×;³ +Ä÷8÷ê–£zÚl§0󈽡ÆÛaVÑ#ÇÃ…|2N­3«š`¥Ü+¯°‡¨j¿ œaøÎ¬H®^©“ÁNñà#Žª3W%¨¯gt ä3ö3´.Å.¢ª'bm¹ê°Ú(²~Xí½ö#è]zJ; Öž™ioU÷õPÐ",Ÿhjÿ¼PÃDk4:D7µ†6*:Ñq¨¨ªeØð¸µvWîë”}¢!ÁœDBš÷U͉~šn?§{ ËÏkóß ºø…K0Ë–ê µ\BØn¥aUÏòÙu1{ACW%%Ï]n_™°—¨ªáDËr£Õ§6{‡?ˆJa–àBLÙhÏí-ªjB¶ —†Ÿ …Ú³Šî‚Êx0¾ Ë_á³ÐôÇþµŸUiÀNi.]Lp‰°7ÿzn~¿N¥ÓÒ·þСǃ•zÓ‚c<²xûQ½ºÐîÅZ# Wµ7qZØ)ª4)뢢Ѫ)0XúeDÃq°Ò -_–<¢*¥T½Õ¸†cc4Éðø~€xpéO³¯ÃÞ£9Ø•¾†~–:^/[Õ4„ñÉxÃ>ãÁ¥é*tŒ ÎûXÉb}'l2²JO*ž2¾çU¶ÅTô%eÚ¢éE”«²Ñ …©“É#¼»õÁ´óÓGõí«líì\º&¸v²ý•ÍËkìR¥Poö8²Ú“åЪnFºßx°y]oïKߺD”[YíV[Øoªû`Šï+ H$d–ŸÝÆU¶µñ†gµ;²d^_êh’Ã@ˆ‹K‡n‡™iQÞQay•)åXõ¡5ãà¢.âÁÏÓ»ŽÏêÞ/´µÚ_Çë·‚•dŠƒŠ†kÈ%¼á[W†³Ê¶hµ°òrÍ×{ÞEª`Ó›^N¹ò—Ëõ H×ñàVèHyÉË))v '“Õ<ÜHðzµô—’`eË9äfˆG¡Ä=!÷ZßûßÎD ó\:»{â¹5U´ÃànB\‰–(üûó Þ`Œùï ©h¥ˆ¬# ¤.àŸíÆÇ'ƒ ]­h* ñQP*Ñê8eG½ø{Ä0aGÍWæKÇ!…>˜§mE>e‡ÂZP5çÔfïP5Â)ú/‹Gçíê(®Æè^ù÷,a"˜js­!“×:Ïš¼#³ÇÚÀ‹JÊšUV×,]Q³~ê.•óæ‘Pšõ<ëë‰1êÐe™dîâÍýD“q“û`tGãHIŒ”sQ “ž«¦ª‚ý5‘«œ´NŠ5&Ô' °Ò™«åÚÒwÑ)\(Á\ªÆJM¬-Ã:¢ã`·tÉL®¤UUQU阧ÜR›ìPœrc1µ¹†`І4•ïÕAu^±íàih!¦] (D‚ò²·°K³&·­'§Ànþ¢9¸}¼ùŒ¹–äôkï•>zN7†Ékqz^VIªúÎÝ’D4¶¤qêPýÓ4oLŽTå'¿‹Y®L¨!sæRé³ÔÙ¥ÙÜo &áhÍPÛ+ÝåP/¹’Û~„k­å¹W“y{³|)?¹¬ž?¼ âŽÒþ*¸ýù ÎþŒï“¥ìɃÿ‚¤¤v¨‡]g/V´Ë<æ…› §kεf^\õ¶+ôëuq*¶µr©Š.+¦Ü[ZvýMÎæÊ|÷ÇË'Ú]Þ]ÿdÎ34JÏõ&lj)Á¦h’Ä:\ß|º‘¯æUwDåÕÊ–G-)Ù¥ˆÜÔ›ZžTÿïŽ7ñ&tCÂM掻µö¾»Å-úì\V‘Þ–yŽšžbI[ vµ8ûÂõ¦lZ"ÌÜ­V‚‰˜ í‡~ÒGö³sÕsM³?+sT< ÇiÕíê¨Ïå“Gù]Å™x'²¦>,Å.^Av±K̇ñ’¢!ÇFЋç#ò’ÁÙ-ƒÍ,¤}Â)ø’ÄÈE²‹² Ô Ý¹^“©­†¶“` à8üR rr‹wnõœ&62Ù,.,‘ ªí•á;1À’~ ÈöÙ°'X"Ü„a†<$qÕœªfë)¤MôŽ´®S[$Î _â,ÿSj)QTÅêíŠBB¤× #‘UhL°D1šÕù““nc»„I!ŽŒ —‘LÍ"ófÜ’fÑÐÌâuþ™¤ZË'H$i,÷?=W,IJ†.ú uGÌY¢%Á;A,ÚMœô£ rUŒóK…dX<ŠÉ”ox%n¸i‡ ÓàÐÅ‘ åó¢uD›(üAÀ±Ƽ‹v  q·3Ný©FŒµ2†ßB•z=Þ¡«CÎ|ßç‘ú[k¼ pë©Åmú€{QæÂO–>@D–Ž« )hˆTl²NÒ“?±¾6\r èIóóóÙ7³¾òÒU‚!OÁ:üÉÂ@vq&W’àâDAXÆ3ž¥PJ¼*|1æÍîyÞ’§·€ì„ž-…¢·’i Ê( ñ…cÂ0¼Z^­nVûÏ¿M퇺F|ÕI|£ØEF ƒŸÈ"¶PÊ•a ú9Fò¸ƒå‡\&±‘åh>Øà Ðb „OŸ<}ùr_1ŒÖÅßl‹ $͘kN¨<¶ù­m+QF!††ÂùÕÿ]½~ðúÅ¿½HÛ}tà˜ø},‡qqxss³^¯aƒˆ]1Îs¥#FH°#Æ t;®P‰É¨4üêzysíûðÊÞÝ>{£Þ¼¬®WhvÈ|nˆŠðsA°PÃêõUj˜Èå¶®œU,^ZGâŒË¿_ÎÎß-ºg²=ÁèÕZ’Qøöÿôo™¿T+ ÓRŽiâ—AÖ©êƒ%Ͱ ­ÚÅÆ  >¡@ xä‘A,­KdN”7ŒPQ ?n$µn:¸€m)åRW§¤n9– \öÖ¦ßþòv±Xtï¤Ú @>¤^ÉSšJ"QP©»C)áäEÊÂJÕ8U.yÁpskÞÊ¥†á謄µ¨ éÿ‰£hƒšÑå§:éD‚õZRp’ï¿o®o V§÷ºöÄm ޱ¿„l¡¡À6£Å¬Çúw‰˜áX ”xn(«BHnD ¡Ü ‡³ƒjlµZ1ÐA¢ÃŠôU‰"Š­baÊÙJCëõS0tµ4[ ¼J©E¯ä&1c­êùŽQ"ùFÚœ¢7B§•xY jxFœÀ‹ÖT³<†ã^3C˜¾Ê72„ãÀ0â¹ßb2K Ì4{(e Ò6 êTôÄsØ¡FrM¸Sª‰H¹œü)¿4åt"&ìQŒ>:q±ßÅ9EÿbÓ{“ÉÆ¯þ;„®w&ã}Ö‹ ¹S@Ï" iÐÌRår1“’øP·g!°jy³bU€Z’Ú[¡_¸ä›É1d¬‘;„ËÔÛò›ÅwQíà Íh¯¢ÃƒJh%Æ¡ÿ…‡1˜Q‚NttLàÔ—wgBA‰%æ´-T4mÙæSÏÿýæ .öõ&9Z®å´ÐCBäóÝÛw mÂŒ ¥ÔûælzÿŠ B,\Tð Ã\ä6”ȑ؄AŒk¯©˜Å fà iµpiÁ­±Ñ¸òØ–`yB  0¯¸÷õüì»gÌ&UÓïñ5âÂÊØ¬‰0ÇxÀe¢´éïïáj¹ÄÙ"¨ß°`?üë§‹Åð%šàüÛùâlñ7ÿà.“<|ý›ÆþÜxMèƒèF<ÑQOi2Ž*,0Ǫ̂ °ÂøÔóÂßß„þ{Ù…1éýn¯¢að*%.aÂãkzýŽS²Æ9ŒÐ¿#46*¨$j˜v6\Ž0º¬æÓ kóé“§0ÆŸÝ›9K³¯gOΟ¼½z«Üy@°ËéõÕÒ_n]xŽP²®t€Bóp¸ˆŠ z+oÆ< Êg½ñw_ÖzµpŽÎÝI÷À¶$neƒ,‚¥'5 ¶µ(¼Y^‘m«Ó¬4Q,¯6t˜ìu<æ=}töêÕ«“û'h—Þ@>çóùËW/__¾^‚Ú€¾E©å<Ój ]xŠoƒtü‚âåÚr\B·guBˆmë³û³ÃI°CfÓéüÛ³×ÿ¼¤Üc4’³‡hšÝ¬q(Ü8\wܨc„AŽöïÏÏ¿zrzzÿ›Ù𕳪þpþÃüÁüòŸ¯ßýïʳ Å?t9K|ybЯNQ^¼´~”«‹+·6G˜ß=î^íU4h•ÅâôÝ/oן|úÚtYð¤I¾‹A1"Ü@Dh¹ô·ß/ž.žNîM@íß.v%<Ï;99yé±ÅÙ)Ø\oyË¿ [€!g]˜ ·7‰ïV—ŠÝ ÷8OæsБÝ=YftÿÆåÿ\^\ü¡4zÕTKý‘0mrknI={¼ývúè„ù-¤6_!"êºúýoï¯~½ò¯o`ì'Ë¥:cõœ4Œq”•sdŠJ-ýôÉâå¿¿Z<>;(ÁDÅÞ¼ysqq!c™˜è”F’`"ƒ–çãðzòàDmᇛƒlA°º^ݬn r–,ÑÃ¥9äU-¥N«(`zñÝâ§ÿø š~/‘ÿ®s²dÈìêêêòï—*¸$uo2-»X0=400 ìJ‘U3n»ÔVAJ³ðFÁÞ¾¡¢ÖÁšäžn£y§§“)ðúâÇg§gÈní¾Iw¢0¾€l¶À4ØR^×¹ÀL@ ŽKdÍ•#:WQ?}„¿}ÖÓ’lýP3Ø[ÎÎe-õuÿÞfUJ40-Žñc4 qŠÑ]1ÑèŽ'­Œ¿"ôy9‘ë›ë©·Ajgß`ÓŸL&²¢úÕj;˜6›Î°”'ÝéŠÄªÚvÌÉPªw i^ôˆ á‹±FÜ6Œ9F‚#ÁGŽ‘à#ÇHð‘c$øÈ1|äøqbp£ |ßIEND®B`‚gateway-1.4.5/doc/alligata/12-6.png0000644000175000017500000001377407344776077015343 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ .(ýÃŒ pHYsÓÓŽ{¸®gAMA± üa‹IDATxÚí]»›Û¶–î—ï#]ªìT’«8Õhª8ÕÈUÒÙîn»ÛîÚÕîV¹ûÄå­vRííÆ®6[y\ݤ²¦Ê¤UÙ©DV+ì9/|h¤¡yF–)>ðúáœRÎ9i¸ô—C`¤ýÒðÀixà4xªÔ¥‹óiÙÉâ=êK"Dõľ0v*öq{Y'`xhtÕ{(£" LáFzímV¥âÎÅU9äv–ˆ<“8–˜È¨ŸD ¸+7Ü^RJn”€ƒÓîE¼’¼ÍÎA4ö ãxÏ2QÇá¡ð€¿éÝi_Ål0€}Š–¿qÆâ @nã[®$êq’¬giiJ²)²%ªjPͯêgÙÃÒ¶€s^düÌ©¤Mª»TŠ…ÖbƒŠ¶ðX¼¥O‚€1?šÜ™´†¼!À 7a¸£hn8ÊE…E*ù”â x–×ày–i}:µT*Û¦+,{Ra” ¥O8f— |õ> î³{³ÙÝðzÓb68ü^¬C`_°â$jv³mª®«F©x¤âÙRRyÃ6®%™© Å­±ò&ɧnRíAô{©ÓŒN‚Ùl2kÊÊ®J »¼^®ÿ\sÅi¡º!¯Àey[FJ#Õš°#`2µ¤?µ%‘zr (Fã¾#1óc¤ØÖQ 1¦ÄSÍà …c,ð÷R8ØÁ­‡œ‘Ž€DtB–áòêÃÕæÏ š1Ú”Ï{u¦ÀFLö~—±³šwª4µ]­9g£Ì JÍSU÷ºØ`Ù–lPC.ʼàØwLà×ý{s%íê„V½ˆ£ð*¼ÚDéC`ž mÚ"V%Qí… »úÐÒkY#doÖÍüW•W’W µ-^,y^áòÒûœ{ÆNeñ¤“'^oцŽH¤°S ÀbøAhU\ið*Oɸž8©qÍIsÿt*§!Ó6œ›U4”¾Æ¼¥Ó,,}ã››µ(–¯ÜP£I®g4-J²¸S³‰DbP;t*xh“ª2ÔQͼÙlP±ÚJ{@˜á Iyîƒ/XÖn<‰e ‚ž?úïñä‡È2"||òlqŽ…óE će>L~ž}{Î|’~tØgÏáÛü`î釉(${zz.ì}¦ìçÓÌåUò9b9Ó2ïJŽªF$÷ñO¨<€†z¾8O[,ÅYxE˪îçq0Œ¸Q!º)×R’2n:P)¥‹|“ö^Y"]ÉaŸ•É™T‚Ë¿ÉsOç¯Ìdû%•K.q÷¼ü²3œUÔ0ƒÍÎ$1¯íZø'u'åQ^[qeã`QÅ2SéMÕèJ–õ#©ì’·‰’¥ÝüéÃsø(‘†eEî ¤zèÓÓW»>îи€·ü˜gôwîÎÒGÌû‹'séè3Åô+)­—üL¬êŽÕ'J 膒#+JGO¨;~*8s "]údƒy¬D—q¥®sىʔdªÚÅdÁâ±>ЗL‚“òýmI*w\•‘>ÖÉ;DîóÀ]‡*gNžf³(SWÅLw¡67• à(á2@ÓžÑmå<*…³ûãUèöU6³“å2ê«îÅ,”ª•Ó`AJˆ‹žeç`c0ß¡+ Þ=Õ¶©EV÷NÅŽeÏ´qI$º­ «’•ìÐeÝ,f¦XnÇ.í('åJï)ÊÃ+^±M Ÿ§h1|zŸe ËÔŸ¢.'@‰ï^m÷ÞP5R6k ¶¹÷’]U¦öÔª®¾þýE£|mót $\Õ7›ƒ‡É4Å“æy‹~Dòªswj•ªX—|ݳkÔ&¹«R¶ÄØsdóE/ÿx· W Ôüá•:Êñ¹ÑMŽDš”þl 2 0B\û¬u ·HdòÖAò ênIú¡TêS¡o˜ŽÔ'_ÿ”}ý\0¨ñd™?µŒh9·a¤ÖTe %õPTœ¨Q¼ØGXùé‘öKÀę߉ÓZ pLb19y×GTzr6èH7KR>›;*HÕ Ú5O£„‚ 5Q¯òÑ”zê‹·åî/}8›ž-,ÔÞ]]¥åï‡üdÆ`ÉxîèJ%‹'øQøÓæ*HRtAXüþ÷M­ov/MÖw^‡0Ÿœ¬œj}d'Ÿi®N5lj¹[’5]¸¤JŠXží4,>îÊlÍ÷ŽFlµ™”d´åÝ,0êºÄªˆw1ðçNö° ý6ÇbéI— ¡)ÌZ„2‰‹¨š²_PªÑœ8VA¬'ZØÅŽÔHb»ßãž{U(Ú’{‹ZL°s-@ÆÖÇ*¡¤™ `½†ÞEzjšþkqÃl'¿;{²²žg—€WïzG»ÈDm‚q/«âYJy;Ø,fÉMó’“Ež=<¿xÿÌl£ÒHK±Õ:ÊóƒsÛþJâŽnÆRJœ¢=®Ì©\娗ÄÛIQÇ1Ø1ñFQKój_AC÷Fh…,D‚»… ¯ÖWËÕ2ÚFjÉ"5´·Š5ºa©íþdþ*p@ÙìîýiP³Ø°†ƒYšÁ.«ÝéÏ‹Ž5hXC•›òò…CŸT^y²^J[Â…Ÿ#›Þ.êäªTscGºåT·üóV¦@ãNw·™V”×|³szô¸'µÇØí‘‘“™40:”orÔeNV–L} CV‡KsQUûqîYKjµ'«JnY5zÛÉE¾Ö¹*yùÔLK¸”4gÇÔì'«úãªÑÛGnÿ–J–cÔV³Kî¸Ejµ· ³Fä¶“KŸ»Íö+÷úYx9`Bá:©½«àÔæn=E5µYxùÙSõ¤;±cs;3)·h®ãüž›\Ê}œD+&ÁqÝ›™Ô¾^îc¢Ï¨Ãn’5ñ`¾pÓ(c‹{B>ßµ£‡¢Òx0ÐôÎt~onŸäjŸ²3Ò­§J€•|ƒ ÇN5j’ݹøxI®Ò®Õ‚m+F:fŠQªçÁZOÖ¸Úû¸©NÛµÎèéöS-Ë—(¤EmÛÞóÐt½ïçæÓ(¥.ª[°î¤V]þë‹n±wâ8¨ÿ);VÇ–>bÞßbÍn£­ªŠš+[/IYß5Œ&q n>æ~k£Ž yͽøZªí&‘ÓRêâ6lÌÁvÇÇ7úížHñ†=m{|“dçàBLÙ¡/¹l±Ðô‘ŽÔoÈ¡û^-{­lŽ‹h;Æ.!ÛƒlôÛãÚâÛÅÖ•"šÒ²=ú³µï•Ñ¢4­{·ýÁ=1ÍáYÙA ~ÑìyZãÙ:†~«Öžç²h'·;&Õ.Ó.vpe<8ü¾ûã¾S'»‘09Öxð@æJV×®ü`þåÜþ ´j>èЫ­¶>0ºUĺˆh1{ãØ!þL@-ÅÑqKØqñÙ­%õV㌭Ѥb@I×c ñæÈ"†©Wô«¸¦kŒs=nЬ-]?ÿÅölé]Ý^[;RŸTòÎmA3ælc0-C8¶n#ßn—ÑF·ÙwŒmG.Ï>-lmíÅꧨ…éSêeÉVkÑžõ]jýÙÁM5aÇxFïe¨rvD“w—¢Õc0U¯³Ëѳ‡çúزØ=Z|ÐÅïh‰7»GŽ‹e¨z¶¶<îuoº@¹j «Üö°UTíèðͼŒÉeù™ª@» h—Æîep vµÞ¤Ô¥î½-PöÊÇÐÕØÁÅ.~}&Þl\¹ê·Ç}`í7´[pÜ(Ü{±[Pµ킯5Ø"º˜z\—mkÈB±í/ÜIÉ"ÂŽ¦8¹ÁtÐݨ÷¡öRe utUÒr!pñþ™~%y[^4íéí²Þ넊½…¥3Saëöò ÛÛGUÄóTڣᴺڈõÈÇ/(å^ë{ÿ›£gà³»3ø¶?nøSæ±háRÔ™ïÏ'âMJÇ$iÖ*»ÔM‹¦¹ýHÇÅ,ÇFÞº"½•·QJ瞸TU/BË%r3è¢d„’t”Ы'ËcjZ×#lN›-]VDÊ`È-©ê¥ ¹¼Oæ¦ýÖ÷ʤQCÜDh/0ö¤Ã2}§¯Õ9ù|pÒ!0VîdñN3‘ÜI!>Á@R¯ä1Ó—pÊÃ䋺Ð|ªÜYÒ¶ìû¨UMÅ5…„ÉmµAªœ )½.i£¶4¡Uán¿—1CÂTJác…܇F­7[¬•ùÀvú uò@d3‘Y¯€n€}çNÕˆhæö—ó³ýZæ@³?+KT¼!‡iUvuÐçÊÉãü¥âyò ;²z;C ‹`.kÀùJ׊hÕx€ñ&ŒbŒÅ˜¼`œÝ:º™YHîäå-`i—Jt‘wÚæÚ+ÀD`}.>ŽøA¶*ÍI‚ã¦L1 Ћ֤L{DND~fé¨ñºx™,)ÚFQE<"I×<ªfë)Æöµº­µ.’ä™/d#þ×ÐR¢ JÔÞù BBd̽#UÔ`I1ü%¨VçN‡Ý&u‡¸3)$ÿ ùg^}\Ò-ªY¼nvQÚ¬å3`Òs,÷¿~V,AJmSÓ ±'䉪]8ŽÑorÄI?’ WGœ\²($ƒâ‘4K7ê `À† ž–ÆA4Í0¨‡7ŸÅÛ8ú3Úl6p Ìû¨÷—½òEl#!%ØzÀcø-±@P9tå`(Y†üdz‡u›¶«ÐŒAD 6Ù&ºÅäOl¯-—ƒyL- ¼ñäÉ“ÙW³¾ÊòEÇ…2mÖ‰Ÿ¬ gr%‰ÈþDú™ÐG6GÉñªòqÌX0»8=½`§ðì £•üÓgGylIØèryyµºúûþ}:m汪¢N"ðtQ ›("öPÊ•b ò9Að¸‡õ‡¸Lb+ åhØü¹‰ÒÍš è1PÃÇ¿xÑ ür‚šê*H3žM 'Tžv†üÎþH+#CGáüòÿ./\<ÿ·çºßw¡'$übõ8ØÅÑjµZ¯×p@D ƒŒ¾°ó|éˆì ›îì u2µAÂ_]/W×aøSîö9õN€ËÕõª²œ[“ÔÄK$šÂë'ÀæÒǦpV°xýq‹'Îÿq>ÿz¾ønѽíF¯Öz#…ïðð–åÓ¢‘–|LS¿ ¢NÕ,a†cèÕ>v^Hdó‰Ç9j€¥v‰È‰úF1 jáÇ¥ÔÕÆK.—²ZƒºÃX p9Z{~óË›ÅbÑ}j0@år 8OI*I©€Òî%„UqS K‹qª\<2ÁhëòZÍ£ ¨5˜ k°Ö¢5¤ÿ'‰ã-Þ `F—Ÿ¤S6[I‘—~Çø½º^A«Nïu‰[ X.YºB§ÕGbøËEa5¸zSžpdpmЧ¯u">pélâm‚k¸°‰uɶÎz$ä@÷Ý»KP áps¼@>E1ˆ7.¢{xSj¦~Œî°$Ƙì’e[¶úm9ý¾«¦ÙAD£~±¦^Ø©ž àA·M¸œ+·%åt"æsQŒ>zñQ,ãœ" °é½ÉdF—ÿdÞF©9ÈzQ1öJ x„žŒ+9@ª Ôóë³È£¸v»Þ$ tB¯•Ì-t”Oœª}{ñ›&øpAxôø'¾ü}µø.®Ý¬ÐNm¥1ƘŽ©î~âQ£¬€íà |3èÞw&ÆÙTÛ  ‡Š®-{À|„¿­.!±O8<á)€Šá8-ô$ÊùöÍ[Ôb”¡¥4øêlzÿª L,<ð Vb j `KlA’áÒ\*fË0hxBj\ðkì4~§2¶Xt=б*ètbôåÁ—ó³ïžN°˜T½¾_#.¡íšˆÑšo¸<)• z'xÿ¯èj¹ÄÉèÁŠýð×N‹ãç`è‚óo拳Åϯæ>jÑ.¸eÓ$œû“€â c½ÃüqE%É8êÛXah™OÐ0HóiD¿½ŽÂwœ+q-Z k/o/¢Á6-ÆQ…DÀ×ôú-§dZa£ù/$6 ¨4¨¤G.H >ªéÖB LÀٽɑs$`öåìÑ“Go.ß(oìsz}¹ —;'„¬/mEhZ(Ø`´ f,  ìpRûiMP°¡Ó§pÜtßí¦%À=Ô Š–¾”0b»ÿhµ¼$»^gÄߨž”*;¯a*ºbÔ XðøáÙË—/OîŸ0vìì«Ú±ù|þâå‹‹ó Њ¢-È[äZP$AõÀmŠ<†)¾l Îã^n®Ö¤»Õû¢M@ ”Ôg÷g‡ã`̦Óù7gÿ<§<`4–“K¨.nÖ¡#¬|nÚõêa3 öû'O¾|rzzÿ«Ùñ g“À’ùáÉóóó^¼ýß×`é±-‰„ùœ¥®aªG”“G·ò„påõäÈó»'ÐÂÝ›¢½ˆ©²Xœ¾ýåÍúcÈAþ@¿“-O+–»3!ÂÐ"BÊ-`¼ý~ñxñxrobÿv¡+)‚“““[œ‚Îõæ—7ü:€bFÑÃr{›ºöLHI¡qáý@—ÈÉ|2²»££åŒY>P"ÎÿçüÕ«ŸÀÖ—J¯š‰gKzp”ïU°µŒF§ž}»ùvúð˜;ù-„6ß "(²úݯï.ÿu^¯Àö“õRƒ±rN*Æheåü\¢‘@J?~´xñï/ßž`¢Üѯ_¿~õê• uáÉr_‡rÚÁ=¨y~»\OœË¢®qüQ£&„1˜Íæêújuµ‚ÆYþ¾Dïá¯U­¤%œÑP€ôâ»Åÿñ#tý^ÃÝN#*———çÿ8W±){ÓYƒ8Ä‚B Q@W²¬ ßv®­"ÉÍ`f¬×ðûwïoh(ô÷‘ì Ãy9L×ç{~vz†èöÑﻬ+ ’Ý]Cò+à:4¤Ìƒa±¬½qÄà*ÚçCœðþ×÷€º0ÈÞ-ƒ£ÕÙéüë¹l¥¾òï`A¨@Åè³” müHœrWÌC¹H-ãs$sÚÆÄzu½’r¸vövýÉd"ª_©ÖÀ™ÊÈ x’Æ9Y&Iƒ"ÕªvsjJõN{x¤c¢ñÅX§àÓðÀixà4q Ÿ8‚OÁ'ŽàÇ@ð‰c øÄ1|â>q Ÿ8‚OÁ'ŽàÇ@ð‰c øÄ1|â>q Ÿ8¾ÚwÊãGÄ#sÂIGò°œ>ÁYÁ5xª ðlŒw5}£„8 ¾PJ‰CüQ$C4=ƒÜÆF HÅ ./k ¿jMDµʨx¦°“Ö@{›U©¤‡óXIU޹„Åâ™qI ŒeÔO"XÜä‰knÎ)%;HpÒ¼ˆSòl½q”{ÅqB¼‹G™‹¬c‹pPyÀßøþ¸¯l¶!È ¿„óß8c‘ç¡´ñ5Wu¥(Cž¡ÂSòÃ…´>Z”jÅv„¥–-©ÐKÐÒ;,—(|Tõ.õîy““Éý ÈzÓl6 Øÿì/€ÖÏ>ˆ/*Xq-3‹Ù:UçU¥TÜRqo)Ô³¡K…A—¿zjÂpkl¼I˜éLk Ôzí^Út£#o2MšŠ²­‘ìÎoç«?Wœ‡Q’iÅnÊS2ƒ¾-ƒ²HSKØ’0™ZÜŸÙK;9¡Gd£qÛ‘œ¹ÚwDdj(šSâ¨ê  }Hˆ1湞}.,$8&s¾ø´þ ÐÊMÇ ò~§ÐÛj™ÉʱQ­Õ m,-j:[sÌ„ŒŽ¥ú¡ªkmLôlM6È‹&6òYðìN¼YO¦lå¸^‚ýÐ_ø‹ ä“9:µIUˆL°*3 Ý”‡–žËÚ¨[3–i濪gÅy‹!ªsžïä:ë–±éÑéˆVk:výhí©Ú®SZ5CŠþ'Ñéreà©gJÁuÄÁ”×ÜÃhî¿B—k¥QMÚ^oPšMБ&[išåºÔÕ>¹^ŠbþÊíxçZIÒ¢$Ë;Õ«H$¥ƒ¡JHyHÂTǪ̀!8ìw×Ò\”£û,µ©Ý›€’Š.ÒŸž\]øI;Àž?y}ýágâè5\QZ{…˜NX’&Ë Ùóó××.Þ‹Ç?lŽCæå—´Pù†âj_6(Ñú¦ ©#1&ݤcD Áa"»‰Ô "iêÊ‘…"i5e Y0&*å*­;¨/™rÆ|Û håÏçÓ×%¤ÇÝÍÏëùÏ›ï¢P…–—a|c±Ï)^“Ѧöt{¬‰`0©Â0ŒäCŒ/FQ+<2*+eÌe~˜Ùª¨\Uƒ sMJú8Gr|¯LOÉ‹-ë´²PÅšáYå±9—¸€è¦òt…¢¼¶ý‘‰`å.&¥ìJ9NDt2~ÒºÎUe^ Ä÷¾ê„•^©g¯4Ûí‰OA _Xùµ QRâ…KŸYôKF-½‰5‰¢dÙíÑ·Ð¥UŸ¬"&=Û‰›º4ÍO·‡2µb¢X°¶óP™S & —J3'~–N–Š”VbUÍÚSؔ좠“:MÐ’]§pÐÂÎ2KpòEïw7ÚdFYFõJ¬UÑ-dFiW²tðЬXuÀBN#9px1»ê1ç94TS)mųU÷Z¬Mª˜óÚëûíÞüþRüÊÕ#õ>Ë N‚µÄÆîöÚØ|0wÖptë;·Ñw„É=ÿc>÷çÐRÔôá•_R'øQc몵'(ûYsÙCo2ö&µ÷š-Cd‡ ]a»åˆ · ]ûà¢lË ‚8¹z8RR/ÿ5é}SX‰_ƒi³©Ž8A¹>p”YÑ ~6D˜–VQNzr•;¬vYpx\ñß^²Q[[ÉR\OqµŠ“#‰æÔ晨Q9v¬·âUè"¶òdUJpD"5N'oX$W5âÌ VÎ\z„hÚ®Š÷,f¬ô‰¥Ù+Í|÷,• Ìž²œKR-Á0|â\™RzL»á,ÛRç~£I+-.”&X{A_°ÏR=X¸£+%˜g ñ·ÏÏóÝ^-,]ÿ¥ålQ×ö·Xú­ôì²ÚK–ìÙÈÚWÕwGº½Ì³sry݆± ¯Pm>wluy¢½f#«`¢íÚwջ¬Md÷æR§'Z”ªU4çzw›™F÷ÄÄ.žÓ(þÓ-DYÏ^mh¤ÅC›——G#áj&tŽaRù³µÎýÚIO¢\«ó·*Ы¢ã…‰e…Ê`Ãbµ˜/?†kiH§Û‰HCˉ6‘µŽœ$ ò/§¯s®JÏe“ÑÃ1«™o&]N9•‹à´³vBlïÜ¿›äµGlE€ÅÚ¤ÒéMTtW-@CÇ9Yj¾uúUÿv”q¤„ÅVÑ$N[XÍzC—ʯ$xÒ‡aã (>tØHv5ÁròsóáÐî½}í°½öAÕÀ°Ú‰[æ5W¹ÂÌqSsxÕ”ÍÝXúÜÚ+mªç³x°ô^R!š†”·‹yw5ãàR+b+|‡º“¶QÌ56¶™ã^z¥åC«œÉ†m»–)ï ¶*Zwl”®ƒ¶DUÉs­Ä2…ÞëÑ yÍžÐeN–D2§#—îóé•Íó­é ;~èM*›Y•möª|~~eÔ«]·bïRÔvß,û£“Ýeq檣_Qî;šÛv[õÔIp2Ö£GÐC¼¹Ò¦æ†ºÅ¸ ¬G4]=l3ÇÃ᪳»°³°÷Õ^Uö?ûïÿx®9s’ýq’9NcåY ìË<¦¹|œƒä¼ÉÙƒ3ó½Æ|pWÆbµŠñ.·ÐÑí¬è;„}„6([VÁUyÔÇé#Åõάj‚Õ¶owZ| -Ä—˜¦Í1þã@·Ã¬¢Žr~­3«š`¥ÜËS0¯J² "é§lŠÔ˸ùàümÉÕ+u2ØÎUiZ·—…{wu ㌄Üc?IG´—ò]u»¹-Wè.3|/MÍáv1fsþÍÙ6çk½í«^ì$XÛ3³Êªî¸¢¤VÐ-/+V¨eœØp‹½N2g¬Ñå"ô1’=ºŽEÙ¶‹7Û\osA÷Û/§Èn‹‘RÃ>˜“ˆÞEÏ–!Ì@Únj©@ÛƒY)»G$¾Qô5ï‰z h¨¢µØ­$ft ]—ž:ÀÍJa–àBLY„…åkr *·8Z?E,ÂBÈ–—ÕÆk-kİзvÿRsþ÷²Uie<_†å/p/4}Òôm»w2¼/”®&¸DØ›~=5¿_§REÓÒ·þÐaÃ= Ò[e!fÆ>xÓãGõêB»k Ø':­¾“ãÝÃD•&e]T´˜`7P|¸`é‡ ÇÁJ' –ÖîP)¥ê­Æ5£Iosy~~%™ÞËX~» ¶xt÷UȆ~–:õoÜ1láPÞ4î ñµ›]M¨d±¾6Y¥·+7Ö¹)àZ;y£é⪧䎷[‹\Ìáóê=¥‹Ë‹±gó*ä6¹*ƒ“-¼»½»–1|õá'|ã¯ñ¥æ`m—8k‘¿¦k…«.0\&aÿê.’u©ö–³ÕmtiµíPb¡â{ßɹÑYs”×f-rEÛRT¸ôµÚöÝd¥Ã‹Q 9`½yag;¨G3ªiRã»4óûÿV ZE; „¸¸DѦítiË=®¸m—TëÉ[Z+\)XNyšCÍ8¸h£GU'*Êܺ`Û“cˈï!äÜ~F¨hHC.qȵ#}ælöZÎ~q»ÅÄU‹w AâéÚÇ•k6õS mjz9åŸÏW ¼ ]L’ý¢wòòàmàèæ¢²x0ÊžCÏFg«ÙÜHðj1÷ç’`Å­C–‹@l}œô!PLµÊ~øíDažK'÷Ï<·†`£Švü ×!®DKþÃéH¼IéX%øèŠVŠÈ:Ò@êþÙn¼Ã‹Æl]­h* ñAP÷*Ñê8eG½ø{ÀaÂŽš¯ÌIÇ!…>˜ëmEôw}ïŽZ”Ž£Z¤ð¦pWþ= Fƒ §ö²LÐ}[ÝGhY‘êã­+jÖÏÀp¯¨ZÿR<˜B.-|CašŒ›ìH1öÁèŽÆ‘’)'^’8:´Bê Ó© ¬$*êлéþ)6ÔI°KÕXi°¶Z¡(—†Ý§Õ*B¼`#žŠÝÛ_2W:§ÜXÌ®© 6P4¤)=1‘(¼5Øìë™V Ð9TYO‰ëQù€ QU]‰úè¿2©ƒÔ¹VÔÌ\I:Ó%IuÉŠ¡3¥ÉœJlnÚÌùDO€Sw»²C©ú'($ gòç†ÂD"íûædWÄ×rr\ŠÆÌ¹”q¦J“,8JÛÌ­ùÝrjR_EÅ®EFiÝ•G©§ŒmzÜÀ1H0üC²…÷Éî³+ÚeóÂu ¿h¶¶ÀÛB¿Ïí1µê¤ô5¤ÔÂ'Ô3AçSí`©ÔÊ v½°)š$± WËÏKù:a®wŒ(¯~èïxÔrƒHÉ.õ@äÆÞØò¦ú-¼{ÞÈÑ5 ×¾Ã0Î4Øí–ôÕ¬âx;Xæ9jz‹%m-ØÔâì ׳qmˆ0ó´Z &bïh?ôƒ0ˆx”8²Ÿ«ö5Íþ¬ÌQñ‚§U«£>—OåOȃ{Ù‘ÕÙØ‚]¼‚ì6b—XL$ÇFЋýå^áG½mƒi¢;“Ÿ!+7Sì¢ìµÍí[‚‰à8üR rò¶¯uBN62Ù,.,‘ }<"ÃwbÔ%ý_ÚgÞ`‰p†QòÄQTs«š­§°—6Ñ;ÒºNm‘8/|‰³XüŸRK‰¢*Vo¿P"cBc‚%"ø‹Ñ¬ÎßœtÂêPWð² ñšb+ɼ·¤Y44³xß-©Öò É1–û?½W,IJ†.ú uKÌY¢%Á[A,ÚMœô£ rUŒóK…dX< ÷;åkÞCI€.dÚaÂ4Øw±$h³_tÑ: ÿ ƒ €/À±Ƽ‹v  ñ´3Lý©FŒµ2†ŸB•z=>¡«CÎ|ßç‘ú[+LP¸G„uÔâwú€gQæÂO–n ¢.KÇÕ'дND*6Y'iÉŸX_k.9†á  Ô$ÈÆåååä›I_yé*Á§`Hþda »8“+IHpq¢ ,ãÏR(%^>Šó&ø8\.—«Õ ¾ƒÂ £+Æy®tĨ€“‹šM¦9ó ~q;_Þúþ#LÙ»ßgoÔ;€—ÅíÍ™Ï5Á­=‰à1–lFêõUj˜Èåw]9«X¼ú¼ŠÄW»š>žÎ¾ŸuÏd{‚Ñ«µ $£ðéÿáß2©V@¦¥ÓÄ/ƒ¬SÕKšá;´j/$|F@ðÈ#M°´.‘9QÞ0BE-ü¸‘Ôºéà¾K)—º:%uñTಷv0ýö×·³Ù¬{'Õž` ò!õHžÒT‰‚JÝJ '/úPVªÆ©rñÈÃõѼ• J ÃÐ5X +QÒÿGÑ/4£ËOuÒ‰뵤à$Ÿ~.o—P«ã]{â¶ÇØ_Â?ÙBCMF‹YõÏ(0ÿ±(ñÜPV…܈@C9 ‡³ƒjl±X0ÐA¢ÃŠôU‰"ŠoÅ”:²•†Öëç`<êji¶$x•R‹^Éub4ÆZ3Ôó£Dòµ´9Eo„N+ñ²Ôð„8­¨fyŽ{Í aú*ßȎÈç"|‹‡Yb`& ™ØCÑ(•¶fP·  'î˜Ã}0+êxÀRMD²ÈåäHù¥)§#1aDT±G\ìwqNÆ¿ØøÁh´öÛÿ¡ë]‡ÉxŸõbCnгC4³T¹È.Q†r>¾EPËëUèÔ’ÔÞÂý©zÕ6~ÒX#N—-¨·ùïËÙ÷Qíf…f´WÑa„A%4ŽãÐÿÂÃÌ(A'::Fð êË»7¢ ÄsÚƒ*š¶lÓ±çÿ¶¼Ä¾ ÀC–k9-tŸù|÷öH›0#(F)õ¾¹?<‡"ƒ |Â09†/J dƒH¬Ã Ƶ×TL‡bP3p‡´Z¸´àVØhÜNylK°hz`DUÐè„yޝ§ß?a6©š~¯VÆzE„9Æ.Jë‘Þó>þ3\Ìç8[õìÇýñ|6;| †&8ýv:»˜ýýÍß¹‹Ã$_ÀƱ?uGEÓú zOtFÔSšŒã€ 5óê¬0>ö¼ð·7¡ÿ^vaDŒAºG¿Û«hüŠF‰K˜ðøŠÞ¾ã”¬°G#ôï *‰¦ —#Œ.«úÂÚ|öôŒñ'F{dÎ@ÀäëÉÓ˧ooÞ*wìrz{3÷çž#”¬+ Ð<.¢bƒÞÊ›0‚²ÃYoüÝ—Aņ^-œ£sÔý°- †ÇCÙ ‹`éI #Þç.ç7dÓê´+M'‚ËÆ«&{yÏž\¼zõêìáÚ¥ÇÈçt:}ùêåõÕõôÐô-J-ç!˜PKèÂ[ÓJÇñ¿/×—ãÒÍö ¢N£M`}òp²? vÈd<ž~{qý+Ê=F#9{ˆ¦Ù͇ÂÃuǺFäèaÿáòò‡ggçç¿™¾rÖCÕ/œ>š^ýãúÝÿ¾¡<[“P ñC—³Ä—'ýêåÅKëG¹º¸rks€éý3¨áîUÑ^EƒV™ÍÎßýúvõÙç  ÝI—O ä»# D„–›AûÃìÙìÙèÁÔþq±+áyÞÙÙÙKÍ.ÎÁæzûë[þÝ 9£è½½N|·º $Pì†\¸·pÀy6‚ŽìîÉê0£Cø7®þçêõë¿A(^5ÕRßf­Mîb-ÃM ©ßÍ@¿?9!ÀF~„Ôæ+DDý@W¿ÿðþæŸ7þíÆ~²\ª3vQÏIÃGY9G¦¨$ÐÒÏžÎ^þû«Ùw{%˜¨xÛ7o^¿~-c™xÐ)¹Œ$ÁD¸-ÏïfÀëÙ£3Y´5?,Ød ‚Åíb¹XBåÌŸ£‡KsÈ«ZJ5œVQÀôìûÙ/ÿñ 4ý^"ÿ]çdÉÙÍÍÍÕß®TpIêÞdZ(v±`zh``Ø•"«f»ÔVAJ³ðFÁß¾¡¢VÁŠäv·Ñ¼ÓãÑx}ñó‹‹ó d·vßǤ;Q_@6[`l )¯ÀëT`" †§%²æÊ«¨ŸO>HÂÇõ4‚$[?Ô öVçÓÇSYK}=¿·Y•Ò# LK…cü Hœbt_L4ºçI+ã.BŸ—ó ¹^Þ.¥Þ©|ƒM4ÉŠêW«maÚl:ÃRb˜t§C(«jÓ1'C©ÞqHó¢l _Œ5àØ0|â>q Ÿ8‚OÁ'ŽàÇ@ð‰ãÿ}°,uÔ)¾IEND®B`‚gateway-1.4.5/doc/alligata/12-5.png0000644000175000017500000001371107344776077015331 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ @fƒ pHYsÓÓŽ{¸®gAMA± üaXIDATxÚí]½w9’öÍ{MGhFÖF¤£±#QÑx"ÑÑLf9Ûlìì2ÛÑÝE³÷ŒÂNÝf²£›‹,Gë‰DEÖFlF¶#vGfG¸* ‚ýFlÑý“žDöÀU(ThÊ9'=Úwzl=ÁŽžàGOð£'øÀÑ|àè >pô8z‚=ÁŽžàGOð£'øÀÑ|àè >pô8z‚=ÁŽžàÇwûÎ@büñˆÇœpÅ‘<,§Ep–Gp žÃ£ê<ã]UŸÆ(!ƒ”Râ?SÂüêuV^_)Tßeë´¼}W];'8€ 'æ‘ä)!¬Ä) 0V׬ Ç÷‘àS¥&LÌΤy³×¨?’!ªÏ ÷‚±R±ˆËóÃFQ­‡2*)ì¤5ÐÖfU*éá`xoX›òŠÇ$XÁ"ÃE°ä˜©A$ ,RI§mg©pMžg¹–§SŠ\­X0]`Ù’2½ͽÃñq‰ÂGU? þ=|4߃¬WÍf‚ƒÏÁ Ðú9ñE+¢Åagq³NÕyU)·Ü› õlèÒ@aÐÊå/„™š0Ü*ov:u äZ¢ÝK›ÎgtèÇÃqUQv5²€ÝÙílñeÁy%™Vìj†¼Œ”Yôm”Eª-aGÂdjq{fK,íä„‘ÊmGr60>#"[C1Ô˜ªOUo`@BŒ1à»çÂa\»ËéÑ”«èà ô¸áͧ›å—%cô@PÞïeÌ™Œ1Ùú]úÎb\›ÒÔv¶ä˜ (5]ë23á.*¦9æ©gÁˆïØ·G¥íÊ”V‰Š 9ø€f^†KéC`žImRâ1¬H£Ú3A×塹ç6![ ÑEÏŠÓ&¡‹gsž6¸¼ä:ç–±6Y<éä‰+C‡$ÔDØQBðr¹vѪâÊ‚WÏ”‚뉃š×‘4õ/cS9u™¶îÜ,¢aôUFdÈ–N3¿³¹YŠlþòj4Nµ ’¤EÉ&ïÔ¬"‘” ŽIUÊPBp…0Æ…_ñ é¾Ù¤VlRSÑùBJÒö‹úöìñùåõsóà³8ò2›d^"ÕÀLÂ(y69¿œ½dŽê·PñFÿ4Ƈõ#rô‡y†‘ ÒÝ#k#z\è}ѳ˜H­ ’j_ðÀ‰,déLrÊ6 ™‘°<^´Ëêü­º«’ÄÝ Ï*’$Î J¸ÁÍzH’=§xMÜ F~”×ÖA]ÙVîb oÃÙ¦¨.7•+s̽¾$(Ö²”$y õY~ÐGôÁìó L¤èʪÏJÌ¡FÍðMå±>—øøèºò6Špé3µeUÑÒûHrÙ•r,‘³‘ÜrY·|¨w‹Ë¹·TÍ|P`ùׂDéP››‡ÊFp˜H0Mzx’e·Eç‘ìªÏ]f¹½UØuƒ2µbbX1q±³ìl|^³+?²»5h-­!íp¼¬j"ZÉ“ŒìÖ X,ˆÕc\mR)°©e¹díËJ‘Kak*Ú9Ô¢rõI¹Ï²D‚e,äm9øòbz±õòÈŠËŠ¯F.m¹ý¨ãílYºêJOiˆ7_Uº¾ÄŠ6¾U6„·Ó 6UeÊν¬4Á¢S¹)“©è ,1öl¾èÙ¿ÞÏ‚9¨5¿D¸Cååè±@MŸMÎMÙFÆ>FˆKïµöÁyÔ?ÿñbßåíö%ÁNάŠÓf»7kðÛÁÙ£ß̯ ~. Û6,,D¯’÷OÙV)ŽI\Nq1Ábr$)pj_^¿í$+eu:­ö#*ݸ{圶Ÿãfž¬ˆDjœøªtúòÃËg'k»´ÔLÝ%LßȾó²]8ƺŠ%¬k¾!¿†ŠÎk³E›# SÊõÐ6÷¬yAêšÔƒ*iŽlšötjdëˆ3AIÉŒƒ;ºP‚yŒ¿ …1mD‘¬dÇ©©`NvK2£ÒÔÅEwÙ‘½½R:–‚ì׊vâ?ß™’jLs%Ï_dû`]ÚÜúªäNr¼Ëâ%.õ]»ø8dÛp¢×6Ž7qjR¾K\ê ®Ñü[LÓýʶÜÚP4e¿, T¬¢9ÏôãŠâËëçÏN.«FÝÒž48¦YU¬än¬Ñ/´Žô ûáòxC±ŠFzsʉ,¨…z~ÚV®LU½cYÆè‚ÃÙ„dW”Ü—Y8/54öÁÑÙ"ÍfÚ)öÜÓ¬ {hȽ µ3PUãH…Á†›àfÌÂU¨"ÁDM·‘†=Läø–‘ 6|Š+ÒF¬d©’ƒËéÚT®r$Ï_]x0î…J°ýeÓÉŒ.vt¨é¸pìÞ¥‚8PìÔÓœO=î 6e—k.><ï£ý;/Ô¥ŸvÜŽQ^ÜÌæ3\Üà%ûãˆ9,áÂ&ZÔöÔ#gÒñ`<ßMŽ&ö{]­h>Ø‹íÎôh°›d'·ô¿ƒØ½u’çǤt3%ËÊñ·6ÜqÌ«í³Ùc_(±¥íäžãîBnœR:T².Iì» =òÉÕ+e2XÿÅXE¢Ü+]’r|¢{â­Ç†»ˆ²áL±­l³|#«Òv~ö³Žî~KT§ù*¿»ä¡¬7 æIC ·õÝ\Dkô¦>»Dy›ƒ‹ôJ*ÁÜÅz÷‹&¦Û8ØØ33W¢s{.{{æÊŸ{\6‹¢¸lê¸}K3÷U-ÝGû/§ÜY¥Øòf×ó;æðH5QÑ“ÅIÔÌIÙ®êë”"ÝšTyeWe®Šv×fíÊÇþ×ewvMs\^×Y‰›Bó™¶vC¯‡De­8®»ÐÛå®&Áàžé\ãÁ4Ùú[Û«² 6Wîú`€ÏŸMì/Pú®$áÌ‘>¼{4öÁŽ/Öê±O4štGûå…]sУ…‹7"õw¹<2ýÇŠö=Y=võV㎭냳“}”ÒïƒÄ»ƒE S¯ÁëeKš†Ã<醛«úOŠ®/Š(dóf_—–JagÃ'kM—wÂßÙîÍ}S(Z×å\)`¼=äŒ-y³,xÙç€8çÛS"m}0Íc8rØFÞîG´,Û- —./vßIgf^tòîÊrJ0®c°¨xA½»â*]ª›ŠÂšbWº¼¸RÀØ’7R¼Ú8{ÔÛîÛâ>˜âËy–déX5 awM×»10n˜Û¬ÆÞ E¯ÕÞØ¶–9Y „ØX¢¨:{½6i—}RÖú9–ww{Ôzù}h %Ѥ¬/ìòÃsýVYwÕD€š,/v¹±vÞr‹ß:¯ÅV´ ¿V‚AEC©%j1W/éν1¥Û²¢Kwó°O­µäÍ]Ÿï=ÐÔÈÈ"rM×{æU Åt+ÅzSËv-ïî0¯¯·Ò̤©RmC Ê)¶½œCÂÁ /Ð냿½xp´ÕRñ`±)ót|ÿØ”léo#8øÈ=Ám§ùÍRlÝ„w„ÔG~Ñ{µãûãR‚íÿ¤çbCpù€ÉÙÇüw-Zy§Ê9°z²„!¾N£õh×Ð$L„èIí<çƒXãÁžà˜öº¸[¦³#+ÖaÀSéèä¤'ëòú¹i£gG,&ìg»€¢QSvk•ì•ö¡²ïj¯œ(.ñd1ê”R—É«Ô2µ½¬ÞÀ‹JÒQBñ–#§¬}0º£™Ë$Ys']û Ì®­Ì$"³Iž²ÉÎÁÙhin<4Ði&ÎEOVÙ~ÑPÓ2¹”,Û·¬á$*îîHUŽ®“l‰þHXé,ñoèS8åÆajs‰Š¦hHSºª6F*r“Ca×¾'£}S´¢ЃÚl¯hR«NÂÕƒVúà†tè…DöǺÉÔµ¬cUµP@¬¥¸ð'm·šŸÍƒÄ˰›ˆ¯ãÊ„!áU󳜽W¦{Dè&¯©N—¤•¤z¡Ÿå^c a°%bí¿UóƤ+Bþ€¤|ì:,탙?S‹næ~]0 Ïh†ÆYé.‡zI•ÜõWøNkÞ[šÌÛ›Ù+ù›ÊêÙ£s"ž(- |ÓhÏ)töè7|Ÿ,eOþüÂýžâü!9JpùòQH.±³ŒͼÞkOë ]·šWðÙ(—ªè¼bʳ¹e7ßäl¯ èÝÇWOŒ§¼»ýÕžgh”À+‹1hØ¢IQ]ϯåû¢yQãí‘A¾|á 'ª¹¨d—úÇ£c÷›Ê%TÁЂ!®"”äÍíM··zÉœË Ž×ƒcž£ª·8ÒVƒ]A-N¯ø¥/ N?Í"ÁaD|¹#ba° —Q²<36ƒ/ϱڸvóka޲¤8-z\õ©|š[âËSÙ#òà^¶ÜÕ>,Å.€Á* § ]ª¢UåÇË Œ–\n€É3ƒ³;‡ª³¶ /ãK#É.Ê.P[Ý q%˜ŽÃ¯ Å Ç!o°y}¤4A·±‘ÍŒá´OÊ8+ã³b€%Uï‘êgÃ`‰p†QòÄQTr+'¦ºÝK›hº®µ-§…/™d#þkj)QTÅêíŠBB¤× !‘E¨L°D?1šÕ雓nc½„I]!®Œ3ÉÈ=q7±ñêãœfQÑÌâeþ™¤ZógÀ$ÇX꿾W,IJƦ¦bKÌ9‚òïÊ´X´›8iG¤Êˆ¾sB¡,v¤Zš¡%‚.dÚcÂ4Øw±z$há­+Ñ* ¿„Ëå>Ç>ó´ûü{ ÷ú¹]ň±ö@Æð¯èÄ|ŸÐT‚!gAðHý,– LPìÑ%¬{¤?’ù·eøÊô1ê2=®>€¦`t"R±É:Ñ5&¿b}­¸ä†' $P“ gggãïÇmå廆 yZ.–’?YÈ.Fã„WŸŠô7B›O”¯ EŒùã#ßÂáÑ ;¡gM¡è­ä>‚2jyÕ`ŒÖ*\†áÕìêf~ó×ÿüëhTÍcU„F*øv‘Q ËÏKÈ"¶PÊ•a ú9kÕ<,?-8Áéj]*²¾ü²Ä¶ )@‹>}òôÕ«]Å0jµ.24ãÑØpB¥±ȯDZebh(œ_ýßÕåÃËÿöB·û&h@pL‚Oø8œÏç‹Å>d™Æüy8ñ@8b„{bÌ@×ã u05‚†¿¹Íoƒà!¦ìßo³7jÀËÍí š2Ÿ+¢"ü\,ÔpDÙ\ÄgS9«X¼ø¼ˆÄ»˜<šLš6Ïd}‚Ñ«µXJFáoð¯ø–ùÓª™–rL¿Ì@Ì(cÏÂghÕl¼Èò3 ‚G>é4ÁÒºDæDyõðãFRëêÁ|–R.uµ&uͱTಷö0ýö÷·Óé´y'UŸ` ò!õHžÒT‰‚Ò“7¹( K«qª\<2Ápug^»¥†á謄…¨ éÿ‰£h…šÑå§:éD‚ÍZRð’¿þßΡVGGM{âš—³ Kçè´ZaO ?ù/JÄbp5ÓS828—èÓ xdR:zKÿóN,C]²*óvvß¿¿Ã¾4G«ôSzã"º‡W1efêÛèšKbôÙñ:Y¶b3À³ÑÏM-Í*í‹õ|àNµ\ šmÌåÜ€H¹-)§C1Ÿ‹bôÑóÉÕ2Î)Â𠇫 ¼úï4ó*L†ƒ¬c«Å#ì,\)‘\L´#”óÑièQR»Z,c0:¡ÕJá6ÊW.ùVÜÇùpBxôøW>û8Ÿþ•nVhG]‚ÁhŒ0æ€}gb;_yC/+èÄqðþ2hÞ÷†úÙÄÚò¡…Ц-[Àdä̯ ±¯Ø=á!€‰á8-tŸù|÷ö(j¦æà úߟŽœ@‘Aˆ…þÂ(9†J dƒH¬@“…øN*1[†AÍÀ²S㲃_`£4Êc]‚EÓ ¨‚F'z_îÿyrúÓ³!f“ª×—Bve'´ZÑ[ó%—¥qAïù×ÿ of3œL€n,Ø/ùåd:í¾Cœü0™žNÿþæï|€V´/¶§ÅÁd0ô)öÐÐÑ{ŒÀPWÔWšŒ£½†šù u4ù~øÇ›0xϹR×¢š¶òú*Æ ¢E?ª˜ðù‚Þ¾ã”,Ð* #þ * *鞆Kƒjºµ0F` CÀñÑpÌ9ÿyüäìÉÛ«·ÊÛ8½½š³µ‡ÇJv ÇŠ Ð|M bƒÞÊ3Ÿ‚²ÃIQüÝ×AņNœÂqØü°5 †ÇCÙ ‹0Ò—ÛZÎgWdÝêŒøÕNeã5† À®èu|æ?}|úúõëãÇŒu]|U=06™L^½~uyq VQ¸}‹R †$˜PKèáYQ|ÙÇ!(^°3Ì^W›Q¢N@ –ÖÇÆû“`ŒG£É§—ÿ¸ Üg4’“K¨Îî¦CGŒò¹9®W׈1:`>;ûùéñÉɃïÇÝWÎ&`$óËÙ/“‡“‹\¾ûß70Òc+Š`8à,qõˆ1¡ºE9ytý(OW^OŽ0¹ 5ܼ*ê«hÐ*ÓéÉ»ßß.>ô´;9¢åI’|gc&D ´ˆÐrSèož>> Aíß-v%|ß?>>~å³éé Ø\oË¿¢ˆ!g=\ ·W‰kÏ”ŠÝ ïºDŽ'БÍ5gtÈüqñ?çç¿ÁX_½j&ž‘-éÁQ¾W!Ö2’zúãôÛÉãläwÚt…ˆ èê÷Þ_ýó*¸ÃØO–KuÆÔsÒ0ÆQVÊÏ%* ´ôÓ'ÓWÿþzúãé^ &ÊýæÍ›óósêƒù¾å´ƒkÐòüq ¼?<‘E[£ûQ£*ÀÌrys{3¿™CåÌ>ÎÐ{cøkU-i gT0=ýiúëü M¿•Àp3‚“ˆÊÕÕÕÅß.TìAêÞdÖ v±`ú>h``Ø•"«Æw]j‹ ¥†‹|ýþø†ŠB_jwÃy9Ž€×/_œžœ"»m´û¦ë²ÙÓ`kHy^'c5<8,‘µWŽè\Eý| @®?\ë:À [?Ô öV§'“GYKm=¿ ‚ЀŠÐg)Žñc4 qÊ}1åž/­Œoæ´OÈõüv.õ6Híø{lúÃáPVT»Z­5‚7 #'àIôs²LÈEbU­;æd(Õ:¶@p.¡1Ö£'øÀÑ|àè >pô8z‚=ÁŽžàÇÿéIÔ¹pTSXIEND®B`‚gateway-1.4.5/doc/alligata/12-10.png0000644000175000017500000001314307344776077015404 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ 1—ìû pHYsÓÓŽ{¸®gAMA± üaòIDATxÚí]=›Û6¶öÉóPSªìTÒTIªÑTIªQª¤ó¸»íîv±«»[íþ„¸ÜêÎVw»W›­<®6©FSeR‰ª2®HV#V¸ç ~ƒG¢h¾#Ë?¼8ç 圓ýÅŸö€‹àžc ¸çî9‚{Žàžc ¸çî9‚{Žàžc ¸çî9‚{Žàžc ¸çî9‚{Žàžc ¸çølß ÈC„_!yÄ 'aÊÝrøXGyçà1Ü«NÀ£^U÷i.%ÄqaƒRJâÂÅýÔ¡°?¢ŽÊóá'…ê·KÝͽœ}];'8€? 'â¡ä)&÷¬Å! 0Rçlû÷¡àSÝM 8˜?HóvfÏQ_’!ª ÷‚±R±ˆÓó*‹›FQµ‡ºT<ï°“Ú@[U©¤‡óHIUй„Eâ™QJ ŒdÔO"Xܤ‰^žRJv à¸z'çÙfå š{ÅqLü÷º#dk„ƒÊþ&O&m%³ Á@^ð,~å®2†ÒÆ×\iÔ5ò$E-L*ÒÜ;É¢H¦¨¨@µ¼ªŸy'K›ÎyVð»¢&wÝÜ%›h­6¨( Ç ×”c®;b€ñѸ1å5 Žˆç{ÞÊ ‚•çsLÔ(wIß)LWRàš<§äDZ}ŸJäjÅf„é Ëš”i%hî–‹>ªúeGlút:}2Y¯›Ì{÷Þ-Ðzïø¢‚;Ñâ(g1Y¦ê¸*”‚K ®Í…z64i 0híü¼›0ÜjoåtêȵD½—6sé˜M§ãi]Q¶5²€ÝÅÝbõqÅyƉVìj†œŒ”•èÛ<(‹T[–„É»Eí™-‘´“czD2j×ÉÙÈØF„eÅPcª@U¼!4‚7r]—˜}*†~ðáaµªq²…ŠŽÈÂ[Üþqëô±£;‚òz'cÎdÄÈ•µß¦í,Á)MËŽVì+C¢¥æ®¢smú`É’¬‘C/ÊgÁˆï”Ézz`WyIгG(6•‘ìSvŽÜ@Pu¼¡XE‹ù}‰`¤Ú†Û ·•§b8R˜XV(wU¦&…?3ØM•Ô§ô#Yìèà™Ÿ±ÍuyóÒ>`WR:-\»äæ®Åû·ƒÈ*ÚS.Á›[p*g9Z!7—=š Ï‘:BYy•ä©ÙÍÛ… oW·‹å"XjÊ"5&´ïd(Öl¸À¨;}rŠüÉ¢¦ÇuÉ~Nm‹á‡ P9»0Ù‘. Å Ë#Äa£. U4¥5§|¨ðV´$Ñ!,œ°'äö‘,8©­¢K<[¹ÜVTtåù¹=ŸÞT‘múÁ…ñ`ïÞûðû|§Nr!ar€ñà’•~4oI6b³Ïgå¯@ûSÉ-û„ƒ&'¾®G…¼ú¸º¹»z!Á‡ŽÜ ¶ìhrüô¸©«› èrÆEË·WpT3š¤¤}ˆ!î%º²h´¥‰’%J_¨= ØTIçsQÝRÖ6²,_[; Mä¼s[ÀbÄ\Õ ÿ B‹eä´Œ(ÝÇﮬF±'Ë¡´D VôŽ‘b{-ZÜË·wö¢×j§—‡-@‰íº ?˜UƒCèVF–ÒÒi &ÖŽQ,X6üVü³w«;`gØÊÈ"âyº’ „v ªõÜ®›DÁZîräKYÁU(Óä2³"$¹\øbáè`ßyþTz­ïñ×S×8R‰2‚]0¤7X8Õ0VÖdz±x“ÒPÚT7ÉÖp³ÌóvV4I¹:†>q×°¥MEOkÔýñޙA…=Hmga)x¥F–ƒÚ`nÞÚ€—§5&ä®M7 1bãjë·®P€)’ºÓËo.ˆ±†`ù¶^Î%Ù°ÃbÄ‘´ÝœÃJÑxñ+JÃ(\z‹Û{OõÃÙ/¿½ âÕI:™*[´üQî›&õ¡Üû˜÷7Ïüt vŒ—¡ÄÅ>fã6%UáùÒ6Øq©è)ÉåXô—~V.rg˜MØÍ’Òç%göB}RÉ®k²ËñrSÝ®z­Îˆª¾R·bm“«òW\µ_ŠMLJè_Sp7g¬ttE°¢!W"jŒ×ÙUçÉTÔ$¾”Äï3w:´ä#¢ï4þl$ÊÍ»;ˆ¯åØ©ªßG ;KBUXz¯¨á1VhSv[ç˜f>‰£NÅ ý4‘2×øQl‰) k•=UùI‚¡fmE‚!e#*}–2÷Wq[(-Küê·×:糟6ú\çÊÈ¡¹Q¹S .lÀ#ÌZø¨Š˜þ$)IïɈbWä±Mg_ŽZV%‰%0v'mI°Ë\Fu[•õùW?ÁG²k^?ÍýúäÔ9%whvfm8ŸÆ·ª·èC]ù)d—PjudùúàÒn’Ä*X-ï—b0%žZ¢jÚçà‘/_@.)Ù¥ D®ò”ÕÓGÙƒ.]“`â; “ó³)mkL9:×-Øß –) ë^bI[vµ8úbÄ&î$xãý¨ÒÕL„Çà l&’cß BŸ‹0ÕZá½­ý[ v'ãK=É.Ê.P[ßD°%˜Žƒbã€7}WâVHi‚n#‘ÌìäÏX6Ì©¡2|'ìré¨Âp@Å$±ÊdØ,¬ƒ ( +.åÄT·{©­C—µ¶E¢´ðŃlÄÿšZÏç‹ÔÚùŠB¢†FmIdj,Â_„fuúâ¸ÙØLaRgˆ3£Ìmà_æù‰WçT‹šf¯òÏÄÅš?&Þ—?ʉ –$Å}SÓ ñHÌY‚ªU8º€HÔ›8iG¤òdòœI! ;R,Û¡%‚.d'¼ô¤hú–ô×að1ð}6€cÆüí>è@ãagúSŒKd ¿E#ÆZ|¶ )ó<‡êoå¯ð†Â="¬{¤·GñzÓuGðÓÕ+ĨÓt¿ºUÁhD¤b“e¢KLþÄòZsÉ1tO@H $A6ÎÏϧ_LÛJËg[(¤É_ù’?™H.ŽäŠþÄý¡ä¥Ä«Ì‡¡ë²éSÆÆ°{rdÇôl(­•üÓ{PFyXr_8'‚ëÅõíòöoùÛdbëŒ,ÇV*øv‘QâBü{’ˆ5”reX‚~Ž<î`þaè!º–åhð?úAÆdRõúRH.Ú š+"zÜçr§4.è»ùOp»Xà`Ôo˜±ÿõât>ï¾Cœ}=›ŸÍÿqõ>B+šášî$òf£1£h{BD\ÂDcD™ÒdímÌ0”Ì”X”|ÂXðëUà}M&êöÁÑæ*ú ¢Qâb&_Ñ»÷œ’¶ÈAˆÝ¡±QAÅA%ÝØpi@bðQÐñGèCpút¼Gæ,L?Ÿ~wþÝ»ëwÊÛ8½»^x‹‡ÇJv$ûŠ Ðö&P±AkŦ.£ ìpPÿ°"¨ØÐéC8žŒ·_¥!ÁðxÈ$zúRÈåþƒåâšlj‹m êÈÊktW¶:ÌeϾ9{óæÍÉñ Ú¥‡Hçl6{ýæõåÅ%ô)‚5è[”ZÎ0= ”Ðó¦ø²)Øÿ x¹9[“nfï‹2M€ZXŸO÷'Á™N&³¯Ï.ÿyA9si(—Pܤq(zùÜì׫s„AŽØÎÏxvrzzüÅ´ûÊÙÄäéäÅù‹Ù—³‹^¾ÿ×taÝ5 D?q7võˆN¿ºD9ytù(OW^OŽ0{r%¼}Q4WÑ UæóÓ÷?¿[Ý{ôÔ;éÐàqâtgc&Dx ˆÐrsho˜?›??ƒÚ?,v%c'''¯™;?;›ëÝÏïøöå]䌢‡ ôö:ví™2C±páýÀçÉl:r{GGÃ2}`D\üßÅÛ·?ù~ ^5Ï\1dmŒýb-£ ©gßÎA¿~s B€•ü©Mˆ ®þðˇëÿ\{wKèûÉ|©Æx$–“ýcê¦ý\¢@K?ûnþúÞÌ¿=Û+ÁD¹£¯®®Þ¾}+C]¸ÓÉ9ı&8-ÏoçÀëÉ—' ²hkt?jTƒñýÛ»Ûåí gñÛ=\†¿V•’ÖpFAÓóïçýó_¡ê·ÞŽà8¢r}}}ñ÷ {º75ˆM,„ŒF])²*`|èR[)ÍÂß|¸¾¡ VþФ?ѵšóñx}õ㫳Ó3d·z¿-Á:3ž€¬¶À4ØR^×™ÀT@uú%²å…#WQ>x 7¿Üë:À k?” ¶Vg§³¯f²”Úz~ H40-öñ#4 qÊ1åˆI+ãS„9lCf–wK©·Aj§_`ÕDz ÚÕj­œÈŒ ZýÆ‹}µo¸²¨äIªZœ7¤•%IQäkT'ÐL_Õת5…¥] 缬ø¹]I—R·¥”+™ *dá±xCý ñ}Æ&>`z2íLyK‚„A°¢h„+5‰EƒE)Å’âygäy†is9¨´ŠÝË,{Ri” •¿°¼\jðÑÔO¨âÏÏçæ ëm«Ù‚ààSp´~ @}ÑÀŠèq˜YÌËTWB©ùIÍo+¡® C ÚºýµÐKŽ[kçMÂLg&JïAô{éÓùŒNýù|:o«Ê¶N°»º]­?¯9â´ÒŠÝŒ!¯¤e{[å‘fž°%a²´d8·%‘~rJ¨Fë¾#9›hÛˆØÔQ43¦â)ñÆ0FÄó'¾}-,48!«`uóñ&ü¢—›Å ò÷^i´+I™IáØ˜Öz†¶ž5mØgBÎÆR}Wݹ6.z^’-ꢩ¼ü»sº˜_Ø_³™ààsð~õ>ŒBé41O±%¨ME!*ÁêάXtÛZyÌÛ³lDRô²P­\óâxœ¹›Ö=c;¢y\’ì36ñO/”´›ŒVƒ‰9ø(]®<ÏNÛz¬òk¾ ‚×4ÚÔêcŸ‘5 .UE±¼¨—ËÅ(jEFFU¥ì[i6DnË0® ÕæU^3èöhA …ó3¹g;m~¥ïÏêS[™-Ó_Ûc¶ay7;=¦€¨ÚWµUÖÖb<2¬ÒÅÕìJ=–רp’‹­­ÒEC÷/Ƚ°Q·] Ùü«B%Í•±Deáz,‚–6 DÎ’/RúÌb\2šh™}Ló¨é,JžÝ¦P5VEo/5±¶-ßý[Q(;ÊÕJˆ°à l—¡2eLR.•eNó,=›Ú¦îƒ\eÀª¶î’]¯´ÓÂÏ2kpº¡»[k2€´#…ÛÅUÊ~Cý•»=2tF'+Q°ÐÓX/J^~8ÊÖÌ`ß ¢PjÝŠªkE¡9åÂ[ÙsK ñæ÷—â4®>iÎY6hp:YK2_n@è®GY ߸ñünW!)1;*¼­Æàž0¥*Wÿ\­‚ôµü@¤CåF–wØ”ÿ¬ÎS>óç¿5/ºë8Eæ°s$„ÛM]Çà²nËIqÐÖ…ÞĆhªÃ X9V5¦8*Ï·/¿p‰VØ™¶R¿‹î2aÍmÃÉ­„¥u•Y’³“³l*§&Ê~©JÆ•{Umr£ª¼hP?"L&ZzXå"!ö×l)qW¨pȾVí€=\B!iVâz‚ÅâH¢%µ•ÁN³£Ö0Ü9ë[YT£v¾’¼ú¶i`u»vâ'V™¬Z‚c«88[¼¡lŠ“Ës2†ßWNNTÂ,Ó:«;,ôv¡¤b5ˆåZ’z †ð‰§ú«Ïi÷^F]H¾ïÏ i(_tÅ-·bWI2c‘Ž®%˜çñ"·C$)wAª¥(vWyÊZÄ6ºVo¢±”`"¨mµ:×Ëõ†J)ìS‰+'ûscp‡AÉ‘¶¢×ìd•ϱå®ïXå^²Û^k‘ë¨7ÑœMr·9¤8lKk–©Ž.šºÈ^L6gÂåþØ£•æ±…·[›è.ôƒ®f¢+-a+ó8¸Ü©]Ý]ÉÀåâwëÀy›®ìZÛ_‰ s‘uîÈ3ÊLÔÁa“ˆ®¶œö˜væ¶rlä¸`Ø3‰µjË‘XÕÚé›àf¬¢M¤îh£ÚýÎm¼hCîÞR§m 4,0œlŸB!l(O|ÊæOg¬á^´z‚×7«»ßD©…:é"Ùv71òñyßûF-ÁNg~ÁVc0§¥Û¡öˆ>ò®%x¸;mvÃt4ØQ|L¨ az¥*Uü:à=ó‡€{ÚÈÑ@°[uwÔè“‹–pú¡ÃvÑÝ¡BYû–gÚO3ìsyzWôY“%Q}£qß%;–È&n³HögJìâÌÝ¢ra¥ÅïŽòa¤U8JÚ#Ê·{÷ð7a°U•Ýa÷¨ž& Nãà‘e”íïëpoÙž€£ç´ñ¬¦Ç(Zíg0 ÚãþàúEwâ‰Íce÷(ü&{ÔÄ»¼_.Z–q,©ŽÁ×H<0Ž»â¨S•w$ØŸYþÕj^ÒœÌjXÑ÷Ÿ¥«æh6áßêîg‡@å„?`v2[<^˜—RÕ/›uÓú c¨ÙD;Žò6üFÉxû¨(¢oEœ}Þ by÷J“µ“åÐŒ&ý1®è@Ègìçií°g Ô»Þu`§ÁÚ33Çšú+œ‰9ZÌÝ"ž ŸÚZƒ‰~XhI°‹yÌ—øt^ôCƒ½;å=(ºN ×L+ßúC“uÔÆÁJgÔ`§´õwÚ½XËaO¨4Ñ.Q½»¤ÕÑ Î’²>&ZLî;Š¥1Øò™¿­3YÎÓÚjµT½Õ¸cãl’Á5wñ¾ $]ÅõšÃ'Ã#ª»†s¾€Z›a““UùóØâ)㣴z2}„w¿1˜:ˆ ‘÷Œ¼§/'mF½íQbaâv š}h°&ëÇ`š¾ZÁ¹UÇËçÿ¼hJ\¶ÄÎÅÚ3jË3Ž¡)âàréqÃeö~ƒ‰¦n9壗“Edí¼å£@I¿”{ÔóïÚŒ[â1w«PܺÍÿ*(¼Ö÷ôë¹âÖî Þ&‚™Çà_´‰ðN´ÔXŸ.¦x÷zÙ}A…I—q›· š'ü󸋉 }½h*q§¨‡Gjõ÷¢Ö/ì¨ùƒ¹䘪'úgˆ³‡C@޽––ÕädQ€GíËr°hóHy·ÊŠ–†çd©U?ŽáãMã&;RŒc0¦£1RavúNÜO\Nzæ“Êǯ0«ÛµeâÆƒ& žP+9okÇ ¹‡OæÔsKmvØ£¸äÆbuMÁi*Þ{&S'¬tu‡ Èñü[Ø©×(¸ŠXåYÐ&ƒŒÁ鈊Ĥ]ö*¾‹éÓ㜮(7H¯§|H$OŒ?Dnsžþó^ªPV\í³\פÁ…žÂøVqiöh³†ÚÓ†ï =Ô`QC[ùÉŸÏUì:ŠÕ²+²O>Ãh0ó™mBýE³}~Ú Ã^wÀÒÚU«}æutŠ]ÊfÃh0Šcž/_'̇•˨Q-~àÇßF%Ù¥>22±|}° Á'þÔŸÒ ‰61¾Ã0ÿlùÝEKzªŒÕìïË:ÇmbI[vµ¸úbâÏØÌ·f—FškjQFaœ>]˜éÏ o¬±¼Í­­Qù„§u—k¢¾POýIÉ*¾Œ+Nî¬p=ám}Á.^a¸lÅ.±$˜HŽÃ Ša0ÏGä&ïaàØƒëWÈʸT²‹º Ô¶m &‚ãè´ô8âý^÷ÞKpÜÈU³qdK’õxDN߉4¤Ìcàt€Üè^ {‚%¢MÅQÄ#’ÄqÃO9ÑÍíAúÄàÈdù"IQùÒd±ø?£–EU¢ž¼­($jiTO"ëК`‰þt«‹?N‡í-Lê ^õ  <§ÜKroÆ­è-Ý,Þ”ŸIÅZ½@"ÝÇ ÿg¿•K’ÒÐERwÄœ%:¼$¢ßÀÉ0–  b “WÜ’cq!å>@K€.tÚc–«ýöƒ^moâès†!lÇ>8óôû €ÆÃž[úS¥:†ŸÂ”ú^¡¯CÍ‚ à±ú[‡k,P¤G„wÏd¥·S¦?1¿MÔЈ‡¤Þ˸e]AD¤a“2É$&¿¢¼6\r á ( H„óìÙ³ùó¡êÒOƒu סäO6ª‹PID"ÂÉ&¶´ÀÓc™¯$5>k}òôåË—»å¦7°ùi“$ ÷&Zªˆm ¿õm¥Ê¨ÄÐQ8¿þ¿ë«/¯^üÛ‹¬ß÷A õý`ó8ÄÅÑÝÝÝz½† BR#<qÞD&bÔ„š²ÌžHxrå6,üÍíêî6¾Ä’ýGCŽFƒx¹¹½A·CÖsCÔ ? 3¬^_¥ÂD.·uã¬`AðúÓ:¿¸üÛåâ«Åò»eÿJv'³ZëP2 ŸÁ?à[Ö/³ ÈtªÇ*/ƒ¬S:QÎ6…m4ãØy¡ð*‚Ç>9j‚¥w‰Ì‰öF1j‘Ç¥ÕÍ‚ Ø–Z.muFê–ciÀåhí`úíÏo—ËeÿAª;Á@ÔCÚ%ÐEׯ zˆ/#ê+KÆ1 ÂƒdîAà…ñ™ïG¿½‰‚÷r#"é?ûÝÝDCð&5.eÂçkzûŽS²Æ9Š1¿#,6¨tÖ0l¸ŒpvY­§ÞæÓ'O!ÆŸ?ž9KȤۓgOÞ^¿Ué< xÂéíõ*X¥¹&) ›ÍÇp ŒVþœùŒ®zãïî× fµpΣiÿåä †ËcBñÄOfi©8º[]“m¯Ó&XSƒz²ój± Çä¨ã3ÿé7¯^½:;=C¿ô!ê¹X,^¾zyuyµ;´{‹ZËy®fñÀÃÚÐZûñ¿ /øú¨›ù¤B&„ˆhXŸŸÎ§Á™Ïf‹¯/®þqI¹Ïh,WѬºyçP¤q¸ž¸Qç‡3ìß?{öýÓ³óóÓ/æÇoœu@¨úã³_..ÿqõîß@(Ï6$!~4á,Í剠_ýDeñ2ù¨TWimŽ °xtî/Šî&¬Êryþîç·ëOûýN¦,xÚ€´ÞåI1"Ò@DX¹%Œ·ß/Ÿ.ŸNOÁì?,v%|ß?;;{é³åÅ9ø\o~Ëï1-À3Š)L°Û›4w«ë@ ÅnÄEz γÅldÿLV"¿qù?—¯_ÿWFÒéUK-õGÂl´Å=B­åthêÅ·K°oçßœƒ`'€Ô"fýÀV¿ÿõýõ/×Áí]$æÇH6Oijåd|LY1‘)„Vúé“å˵üöâ 5ßðæÍ›×¯_˹LÜéUœFÒÉD8=Ïo—ÀëÙ—g ²èkÿ´`€S†áÍíÍÝÍgõû 3\ZB^I)³pš €éåwË¿üÇ_ ë2óßwM–œ2»¾¾¾üÛ¥š\’¶7]ŠC,8„¾v¥Êª]kë µYd£€àï?ß ¨u¸&…§ÛhÙéÙt¼¾øéÅÅùÅPÓáC,º d·¦Á×ú ¼.æ*<—Êš…#W!Ÿh‡_?ëÙ ’ìý ­.Î_-¤”†ºþ`«*eF˜– cüH\™ñH¬Ï8ñ¥—ñ¯}]ÎGäúîöNÚmÐÚùØõ§Ó©Ô°VmËf³–nÑP¤^Õv`NC©ÁqLë¢v€ÖowxXpŽà‘ÃæEó7úF>@?œƒƒs@rÎÉ€þâßv›Å@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs|±ë !¯‡<â„“0 ån9},„£<„sðîU'àѯª{7F qlPJ‰C|(î§… üéuTž?)ìT¿eë´œ]W]['8€ñPòƒ{Vâ©sÖ‹ý‚ûPð©Rˆ'æçÒ¢ùsÔ—dˆ&GûÁØ©ØÄéE€á¦ÖDT롌Š[` [i ´³Y•Jz8”Te˜[KX$î…¡”ÀHf@ý$‚Åuž¸VáæœR²U€ÇÍ‹8÷ÖI¸WÇÄp/!ëØ"Tð™ªúuŸ¸Ó£éôéd½n6kì=x·@ëƒâ‹ VìD‹ÃÌbºNÕqU)%—”\[uoèÒ@aÐÚå/…žš0Üjof:“(´D»—6ËèØNÇÓº¢lkd»‹»ÅòÓ’ó Œ3­ØMrrRfзEPib [&S‹º3["i'ÇôˆlÔn;’³‘¶M EScªBU½!t‚ 1ÆÜ‘kŸ ŽÈÂ[Ü~¼õ?ùhå&ãy½“ëírµÌd娍Ör†Ö–5­ØgBJÇR}WÙ¹6&zº&käEy/ø»Sw<›žÙß³š`ï“÷añÁ|i41G±%¨«Bd‚• œY°èº<´ð˜³eû؈(k1$Cµ|γýqbnZ·ŒuæpI²ËÜÉÈ=>š©Ú®RZ*,dï£èt¹2ðÔ=¥à:bgÂkæf4ó/×åZiT“¶×”fÔF¨ÉV’f±.iß\/E>Åv<2-ƒÄiQ’æêU$ƒÒÁP% < ’´*Tìû>ö»+i.ÊÑ}šÚÄîMÓYD^JH_~{©»úíe¶†½†K C+Ï ?ÎÞ\-~6b£øçÍÏ늟?žŠ”*Þ0ù…½L 8"ë5Ÿ™êË–‘iCêPŒI×éQApÈn,µ‚Hš¸r„ƒFd!OgœS¦—5-aW7/^Rõ¨4k5"ª Iv¶5PRÖ8Ö(«hÎôÐ.¥Ökþ˜â5mjµaï‘5 &U¡¼©“òÅ(j…GFe%Ë1Ëþ(Ða.Uѧª¢á§<˜üLj<ÙΜSÈ–<§š­zâ2)ý¨Õ}iú¦štWÊ#åøXì¢ëÊÓµ·òÚZôG&‚•»¸˜])ÇòÖFr£ÊÍì,;Ùf;“HÈ–Àœ”ù^™Æ‘Ím(°âsA¢¤Ä —>³»U´ô>Æ~Ô8Š’f·…oA/y¦Þ ]¬KË)!‚›¤Ö€òÊýyP ÊÔŠˆ>`ÁNØÎCe"8H$˜Ä\*ÍûYêþmê¨.ÚT_ÝéyÞÚ}»Nn§…e–àxCïw×Úd«F]53òìf:ø ¢…‡ÎhdEªrж0þj~Ù>Ãm(1hѺû S³×ÒIâŸiÀÛ?.ÄT®.©öYVHp¬%e†ðF¡÷^f†,Ïiܰäåúô4 ™kÙõv“«rñçbá- ¥¨éÂ*7'ø€-@ÙÏ؈»Ó‰;­¼Ö<é®aˆlÀÆnº0æe[ÄÁ]q€5¦Í&:bàvÛ(²¢Aülˆ0,-¬üPWÄ R»÷Ášh†–9Ï\žü„ ù×É]JUS\N°˜I4§¶RØÒc|z¨Œf°‰1´Nç›~dåÉ*%8$¡'“7ôz¹)d/ÑÆ™n¾ªnšÍ.ÉYãLnV‡EAI˹$åã`>q®"UzLÛ˜° žäBCæ BÝB³KZfr;Þ4`Æ%îèR æiC<Ïmá@ÞÆ_·.ìÝúm.©Ìä¶)¬Fh#Ä_”_êö2ÏÌ9 ªÌ…ÒÓ ³æ«¤¹ ¹K[2gH[ÑkRÑQÞ ¯ö]5vÁä£Aš›ˆl5º` ‹€R¹Šæ\WÉ© `d­­Ë<®«Àpá ÇiðÐb$\nE£ a˜þ̇bjEcô« /lf³l´IsˬÛûšJƒ ·ËÛÅýM°R‘†dºˆ4´šÈÑc”MàjÙÔòÁ€;bÓññ„U<ÉRîèP´ã_´XEȣ͡"«pžÅ³I…Ó †Xa Êœ—@Ë9Yj¾u²©o ú¹[wwTŸbMâtPÉ»D›Ê/%xÒ=‡aá (Þ'Íß°‘ìr‚åäç¢áP>V¸7cÿ¶hà1µw®e¢XÛ©´† ¡õ†ÑmbKç4*.ó˜æ„n'¬§œÙ.<9Ù“£|H¸ò¦u˾)XÌ»«×퇷¶Ï@ás`ù3u—SWAèmUtÞ±±óx°ž‡–OŒÙŸ¹sÂÒ¨öIWy²â9e¥ÝÃxpWÏ’ìIðJ¡pb¥Åu¯U¹ñàöbÚ¸ ›ô<ç8¶s´]Nxçñ`ó³h–‰ÛßÔ~PÔ¬ø5`·TO•Çã`^_È<þe~$Ë&…²£6i&U˜BÙMuƒ+SÃsl… v“N{ÏqåY¥ñ`ïÁûðç‡`Å™¯¯ÈqÐOžm°ÆkÞ×>'ëÕJ5€äÝéÉщùÚòIwbÅæ~¸+ËÖŠØ~6Îê*Yo…[èhóŒŽ_dÄú$Á‡ˆÂ {®;™ÍÌ×ïl8Tà)ªvf™§ì s¯åÓf‡ÿa ÂÛaVÑÇû ù~¥3Ëøø¨H"³;³ˆ(Éaö‡’ÏJ„òé•*ìÌÈÚ3/ügƒªáŒqFB®±¿^Òúò·—úŒŽ²H\Ùóí†X©áù]›'ç qܲHðv©h”Ò¦¯z± 6hkfVZյ·e×V†` þçÆk“öÛg¢¶†nauwÞÉt™}@Íp!'!Uë7Ô ãl¤{-ÑÆmX;lãøØ­ˆ|VZ‰š*:nK–OÌebs•k27¾©õOÄ 0Kp.¦Ì«õ…Íê •×–uÆ•)7[›´pz^?4Ai4 _†åÝâZhú2¤„¼üîr×yÞö„ãÂhÁG„ÝÙ—3óûuJ%˜¾õ‡â8xCáÂÞMçàúÛ–tX°`샷ôØÝÊŸ.´{±Ö€-¡ð1üVÏ[8­leš”µQÑbzÎ@ñÞ ç‹fÉ—5ÇÁJ' +Fo¥RªÞj\Á±1šdx›Ë0`[P5]Äuªß¸cX¡¸i Æ×PÊbu'l2² /-VÐ1r³'ã%¼ÛõÁÔÐ@†yÑ[FZˆã—“V£ÜŠv(±Pñ6ÔkµcØw“å}0ß­0˜Uû…ìú¿%0XÑ „8¯‰kË(,ÇØ‡Æ¨çS+n;`k°á×H0¨hºžN9`ïÐÊÈ"r=XË{œ|)ó¨å+Þiz™Y’¼_øâyä`×eþ\y­ïñ7SÅ-µ2²L3‡Á_° ðI´XYÏÆâMJÃ#Â[‚&i\†Ö‘RðOwãØxÏÐÖŠ¦Âu÷(­öVô µû ;j¾0'ú`ž´•ü㣅+Ýe¦¦ê:Dö= F˜¦1[³`¡Ê›—•¡Œ½{OØ,Z)]ã]¼u…io*4#?a=ÿtè Ä€Æã&;6öÁèŽÆ‘’fg¢o7¯?;°[B}R9婱z\[:>lÆIU<¢j¬”îÒõgÀó¯¶ÛuÍ$hêA¡”x®©M;§ÜXÌ®© ˜¢!MÅ{ϤëD¥8ˆ£òaž~ ;u*µjÁ ¬ð,h£Núà‘« iRÏ{Esû‰|ötN„S6õ¢ì‚Ë‘kŸƒ£_ÞªôyÁÕ1ËÉqUìPh)Œ³Le>'Ÿ?û%.'Íl´,-"ÊÖ`©¹zOöY5ú JÙÞ'»N«ú¬ˆ³s™KsðÎgo€Kù?ßþq;Ÿý"72H޶-t·Sˆœ’¿­dŒ•ýQ&ÿŒìºc6±”àÒÇG,ƒåýý|0ïD?W?ÐÆÃ† DJv© "7q'–U/áà>qÇH° ñ†éç77ƒGŸËJö7ƒežÃº—XÒÖ€]A-ξ¹6 ¶¿´Z‚‰˜ ížø!“‡ö³sÕº¦éŸ¥9ÊŸá´ìvUÔgòÉÃì¡ü¹s'+²:k›C°Ë€WÝZìK‚‰äØ÷‚Ðçr}Dn²ñËQlNΗ$Æ¥’]”] ¶¾‰`K0 Å ÇoºðZ+d4Á~#•ÍürÞ±lèã¾nHéÇÀp€Ühž {‚%‚U„AÀ…aÅ¥œèêv'm¢s$uØ"QVøbg±øŸPK‰¢*Rkç+ ‰šÕ’È2Ô&X"„O„fuöâ¸ÛX?¤ÎàE .â9ùV’z3nA³¨ifñ*ÿL\­Å$â},ó?¹V,IЇ.ú uCÌY¢!ÁA$ÚMœt£ 2U dò‚‡BR,öb²CG7\È´Ã,gû Ø:xµ]¸ ƒOïû°»`ÌÐîƒ4v†©?到öøŠã·4W Ã;´•`È™çyWDEø¹ X¨aõú*5Lär[WΪ/–¡¸âòï—³g³ù÷óö™lN0zµ–¾d¾½?=à[æ/Q­È´”cûeuªú`I3lC«aã…Dü]²×Kë™å BTÔÂJ­› .`[J¹ÔÕ ©kŽ¥—½µC€éw¿¾›Ïçí;©æ©—@ò”¦’ˆTâîPJ8~ч²°5N•‹G&¬æ­\Pj>€®ÁJXŠÚþŸ( Wx‚ ]~ª“Ž%X¯%'þÅC~w÷P«“£¶=qS‚#ì/áO¶Ð@`Ñ|Ö#ý; EÌ9Ö%î(U!$7$ÐPÂáì »½½e ƒD‡ê/ªE[…ó‚r;Ó•†Öëƒ?·µ4 ¼J©E¯ä*6#­êùŽP"ùJÚœ¢7B§•xYÏÔð”8¾.©fyì{Í aúú*ßÈŽƒˆç"|‹»Yl`Æ ©ØCÞ(•¶bP·  'n™Ã}0Kê¸ÀRMD²ÈåäPù¥)§c1aDT±KFØïâœ"Œ±ÉÑx¼ò‚ëÿ ë]ñxŸubCnгC4³T¹\LÀ#”óÙY,‚Z^-ýF –¤öFè#§êE½øM#|8 \¶ ÞÜÏ¿++4£¹ŠB *¡q‡Þ#"0£èèÃ7¨/÷ɘ‚‹ÍiZ¨hÚ²Ì&®÷ûý5$öˆzw9Z®å´Ð]Bäóý»÷ mÂŒ ¥Ôýêlr| E!.*ø†a.r J dƒH¬?Âg¯©˜Å fà iµpiÁ-±ÑŒZå±)Á¢é TA£æw¿œ}ÿã³IÕô{|¸°2VK"Ì1îs¹SZô‰{ó¯àv±ÀÙ"¨ß°`?ýå§Óù|ÿ%šàì›Ùülþ·ÿà#&¹¸è›DÞl4v)š&ÐÑ'Œ¸¢3¢®ÒdTX`¨™G¨ °ÂøÄuƒßßÞÙ…1iýn®¢að*%.fÂåKz÷žS²Ä9Ñ¿#46*¨8j˜t6\Ž0º¬æÓ kóÅó0ÆŸwÈœ%€€é—ÓççÏß]¿Sî< xÄéÝõÂ[¬]xŽP²#é …æâpôV”Îzãï—zµpŽÎÓqûÕo ·‡²AÁÒ“ÛZÜ/®ÉºÕiVšÌŽ–W :Lö:.s_|{öúõë“ã´KÏÙlvñúâêòjzhú¥–óL¨%tá­h¥‡ýø/Å˵Çq ]/Ï ê„1ÚÖ§ÇÓÝI°C¦“É웳«^Rî2ÊÙC4ÉnÚ8n®;nÔ9 Gûçç?¼89==þjºÿÊY U:ÿiöõìòŸWïÿ÷- åÙŠbˆŒ8‹}ybЯ.Q^¼¤~”«‹+·6G˜==n_ÍU4h•ùüôý¯ï–ýíNº,x\€8ßù n "´ÜúÛæ/æ/ÆGcPû‡Å®„ëº'''.›Ÿ‚Íõî×wüÝ 9£è½½Š}·º ÄPì\¸·pÀy2›ŽlïÉj.þËÿ¹|óæß¤Ñ«¦ZêK¬´É=B¬e¸ $õì»9è·ÓoOA°‘ µÙ Q?ÐÕ~ûpý¯kïîÆ~²\ª3‰µåäø˜²¬#SThéÏçÿñzþÝÙN &*ÞðöíÛ7oÞÈX&ît N#q0ÎAËó»9ðzòõ ˆ,Úû¬ ²ùþíÝíýí=TÎâz¸4‡¼ª¥DÃiLÏ¿Ÿÿõ?ÿ M¿“Ȱ³®¯¯/ÿ~©‚KR÷ÆÓB±‹ƒÐuA£À®Y5#àÐ¥¶ Rš…7 ¾ùp|CE-ý%ɬn£y§'ã ðúêçWg§gÈní¾‹9Y¢0ž€l¶À4ØR^×™ÀT@ ú%²æÊ«¨ŸHÂÍo7ÀzA’­j{«³ÓÙ³™¬¥®îßÙ¬J鑦¥‚Â1~„$N1z*&=q¥•ñ9BŸ—󹾿»—z¤vú6ýñx,+ª[­¶i³É K‰aÒ9 ˆ­ªuÇ¥:Ç>Í‹°Ô|1Ö€CÃ@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷ÿN‚°<]i/IEND®B`‚gateway-1.4.5/doc/alligata/maininst.png0000644000175000017500000007252507344776077016577 0ustar toljtolj‰PNG  IHDR ¦Êê¨tIMEÑ 1ÅBÄ pHYs Œ Œs®[gAMA± üatäIDATxÚìyp$×}ß_O÷LÏ 0»À\.ì.‘â’–h™R¬H²,ɦU’9vEIÊYÆvU*ÅŠªì?R‰ÿ°Ãrª\‘½>bË–«œÃ–åC¡lS”Dï%¹àÞÜ{qƒ9ûÌïuƒžécz.Ìï§À­AÏëׯ{¹¿oÿÞï÷~1  ôß™3g:= }ÅÑ£G#€þ -@`´ €¶ ¹=ÿüóèvNž<977Ð`vv¶Ócì‚ ¸óÅ$Ϧd>:=Zнœ:u*L³`ô=’ß°Âà7ï… €¶à¨çÁàSÂw^×uköþÒ'Ró]Pd¯ÁÀª_»ðº(u@cÀƒ;ŠÛ¬{šo??Ã}0¤GâyÝ*ÅÙOù«ô`ü/¿uúyÐIàÁ€®Ã)žŸÝXÓžPUŸ¶üTuØÀÀvÌ?  À€6âÌ-q/)¿à7è>åèUͪÔ;Tr2lpzUŸÝ_•”Ohì< > hžSd͸/ z2úg,Ü‚á÷/Á}JùHù }n¹ÏSš¼­D•lxº&žC~ @ó4¿Žz O PÏSj¾”5p ó— 7ÎfåÏU§w…é2Ðrªœ˜&݆,2°kiUj@]”ÈèrZR  èÜ3fÁ8§Èvx¨˜×ÝLÙ‰iÞ}aÐ7hÌÎ8+¡ÏÏ5O‡NѪ*®˜"]‡Sêz‡²5Æ3|âŒä³J5ržU3S ü`œ³ae©¨kŠ ói #4¹öÅ tžÿ[;…!äÁšÝºÏ OÜ2P>º÷lSþ5LcÈèZ0E ‚VÅ&!0Úô9(3@§€Àh òÐ, l@÷Ъ¤d7šÂÞØ€^D„¶ö qžx≹¹¹N€iw„1m -@`´ €¶€ ?h/§NêôÚÈÉ“';=@Ç€À€6‚^v3ˆÁh °£Ô»¹dpûò·ÍŽ:¹Ù€þSd Ÿ©Ú†2ü®”¨Á @óÀƒÁvÜŽ…óH¹ó«ð¾…[Nœ;%»༜ó*îë†<:†-UFßyĹ“qù+gûÖ jãäª6U×­9x¦È@q–?yòdURYÀ4”û«vÌY5ÓgÍÁÏÎÎb Ø Ð?m¿‚ÿÐ^ÊKa¤,W9Ut¹gP5xº_,» h;u­†qNˆ9;t­ÒT Ë€@ßC¾KÀ‹b0 ‹h­r¸Ã!®<}<ÐExN‘¹ƒçöç0”*ñK* He®ºn½ƒ`7;JÙøVqÏÏ5›yöæwÅ0ßÖ^]ƒ`—ƒ)2m -@`À.ÓY´ €¶Ð|³È޾üËèR~›}°ÓCôð`´ €¶Ð 0Ú@[€Àh m -@`´ è1ÜG–¸?4ÓmÍöeZÛs Ÿ’{CÏv_±;펎ñÕ¯~5àÛüãîƒöv“5·³lw¥d÷ÖË]U›Ùs<Ý6Ⱥ¿‡)è* 0 “|þóŸ÷<®ëúÙ³gîÖiŒÊÛ»²-)*¿ï;e>Bå¶tUb¾çª!¹?»GâwJøâ9Næïšk>¢à _=Ì_è 0 Ã|ûÛßÙ²l}¿Ϻ ó²ÑU¦­ ÞŽž[¨%Gü„-à`ø…ï¼f81½b0`Wà4L-œ^« ÃÔkþÊÎAUŸe“Úü{F/üzö<Þ*›^³ˆGÿô­ ö÷þ*žîQ ÇÐ>äë¼Û'hl$MÞH·õv è ÂÌü4ÐU€ÁÒƒàsý왼à4jàÆÝ!¨†ï1øFZ¼™þSd`WÐÂ7âªy­ÆzöŒ¶†<§ãš'|ŸM>(ЋÀƒýŒ3ªÊ¦;?;ç‘ü¾õì¶™žÃžµH‡Ê'†¹Çð«·eÍÓë}P kÀ€ÞÀÓÊ×üÀB®Ýõ0aÚ÷ærásœÍÒ‘çµÂ?–&nÜ)d½t]×ÛÚ_Z¥¾¼)З@`@ÇøøÇ?ÞÌjÊ0ôßdKué¿%#}v;» èsúÌ0…Ÿ(ëôH;p× Û@€¶Ð 0Úb0ýO,bH‚‘ˆh¢`FCŒ˜žÍŠºHê¦P0$Õˆ¨&^>MéH?†D5)ªƒ’šÕ”¤$DÝÒC`L ÿ˜)øŸN²c0¡¨K$-$0ôkNt)¯Góºh2!¯K¤=%¦‡˜9$©c±RZ*Ç $*R„´„\’ƒ IH²Z,«E³º”u¨ˆb0Óî»Ó4“@X 0½GT0§â¹ 9¿OÎÇ·”`J†´ªÊkZl]•×ùŸ1ƒd† Fxͨy¨ÓKˆÌ¼gpížÕ„¨ ,Ht3B*²¢ÉKJrQ‰ Q7.`Àôc±ÒƒCK~Ò¢â²_VãKJbE•U3¢CQÓKd´èš*D‹Îƒ&J‰óùáùR‚Dn  K@FP/Q2Ä\›(¯W ƒßZ™ºR´çÁ .€.L/Aâ±®E×ÕX\Ö¶Ž׊)kVjáÜ·ÊscÇš§o¬cÕVZ;Yn«Ý—~\-ìt9˜@`l$ZÓ’2-Ž9¦ÈfîÈ}éôavvÖ÷–¡…Ö$`+âÎÒÁQuç}¦K‘#ú¨ŽÅ¸œì• ² K>IÅãg6FòFOþUÎÍÍíüEËn«ôBœß–¿*w«óÚÜÞ݆Õï"xž0š·~U„Ñf÷)Ì_´B>¥ºú]KOZ¥>ƒ”xDÔdDÕÑhi(ªÐQ0%Á¨yº,ê3‰ì¹Üp§ï£e<ÿüó­íйqrÕA·õüì6mU†ÛÝүϚÔ@c »´ßS yŠ_ãàa×Õ'èf 0; y!VmPTE-)jô™´$*Áä?¬î ½ÀL ¡ýZ8_„›Üî·É–N<#Cuõfó±æ/í÷Üê½q(ÄnÓFÈô'D}$Z"9IG•a©DêB~‰È¸–4ß?u‘Qc7Jƒ—òC¾×Þ øM¼å—«Ù§ßì“ç‰5{«ëZƒiÇ£ý¦Å 2biÉžXq8Z’ÉòNœ«¢f•oQ Ñ0YÁL+5Ù0…¢!ÑŸŠÑL^ç¸hˆ¦)ätI7úþK05 hMãÞ [íš3Q­½\0uM‘µc wÀ´1rMöÆŠ“r~O´ ‹< _^o¯›‘¼.u‘C±Êàtɪ[¼Y¢Øþ¬9*ƒVÕcƒ»@üÏŽëG,bˆ¼à¿N·P°ªúƒºhØEh8ºUbãìªù@â(» Lã³2-MÇs3ñÜÀV%cr5ÖTyC‹mhÑu>D¹ biÿéµð¸ÁLF´xD‹ºÑ“¢ÆÿŒhtG9=JNRÖª @÷¢ôf­~g2óšr6ð3£õ®í¨êӳ稹p&;º¦ÅŒæ¦¬4_¾JŸŒ¾}Dè îÙX3x\Ýþl2¡à*2& FLЫHŒô5 jik9§$˜Q’ß.IËù|úR>]à)Ѱ£@`|ÉkÑ·¹´„zå' IFÔ¸¨óªb¢ÊkÀD4ò*¢="ð0»`M¸Ùí+ͳ«ŠTf“¹}»»Ï%œŠ!.(‰ëÅÁ[¥dA— -€Žñ¥ä¥ Ë>(ñzb£±â°¤÷ :¯Ó}&'¡*„G`ÑZíUC,|g^—–•øº&¯©QÅõîžÐô=˜:HˆúD,?%çöÄŠ±ˆ. |â«¥WàÅ`Ê>“½ÿ1³ªÅcš¬hÉë|Á£fDò–¨(¼ŸUk÷‚¨ LmHE¦ã¹ñìx,/óù®¢b׆!U°~"%ƒ/.Q6÷3æµaʳ^ª©ZoÍm`Lf6¬‚1VÏpJ=&2ç“rþ¾ÔòX´¬+äj,)‰5±XJdô˜fØþ„IìZ 0Aº<>rË/Ý«LF‹½’Ù;_Jô÷â»öÚ¾xžmtz(€^DRäk6{scìFq Óƒm±ˆAÜžXq|cPT£]]ÐEô‚Àh+ZËG¤‹ï耯RcûÙ”ÈKC >‰ÅÃÑ’Tlß2L9³Ÿùò˸ӇòVÊ*ïs·É®J©˜<ø_4šª¨oçÈ IÊ߃ 0-ÊV¹þö=g@_Ò­SPÙ…öò-vcƒ-˜nY·ˆÀÆìØ8ûálOrF¡šÂ…üÐåB**rá‘ô¼ì5]vïÀꤜŸ/%o–’ó¥„ÙÜjù_I£¥%e4Z*/Ÿ$ûÙZF#8–¿¦PN ÖŽ<Ë€4¦¨K$?Z´`H%¾x3R²„Gµ¶,³úa²ÀsdK½È]KIê€ÈK,“› ½OxÒ}£쥛ìoγ[LqYó¥<;¿Âž»ÌÞw}èŠíÀˆ¬ `‘”£hHžC†˜^óéçÈÀÚ «S7‹u‹_L0È Ú+LÊ…´Tâ ò#z™²4€Ë€XÙ:UṴ̀²œõ­}ÌÌ-gK´6F‹ðå;ÌÏ?ë<·? ¿¿Hðf0Ío æ÷9àˆóWÏ«‡iÓä#­kƒœ†û½K— L^eü:Å?®NïêkEö×çØ[‹ì_?ĦSuôß‚U6æþ¡å!©ÜÒ0#á·ä¬õ<Ï’d»mº…ˆ•ð°j‡\ŸÒVMšÒÖ [ÁqÄ´NUÈû1Ä÷¶hT³³³¾GZhhªÌVoY1{´ž;ŒÕ¼£Þ½kÐt“ÀïòG¯³¼Î%D–Ø!¶?ͦR,a »¾Á®®±›Yf›:jsq…ýÎKì—e{Û5]F0-Nf&2r`.è%ùvvxY‰×ì–ºÚ'%2äôÄ"z«Wkú=ÝH^Úk37ÔŸ=Óy•¾g³åДWç”Wz–“âÚ·ÚÜÜÜÜ{e·ƒUz!Îo™Ã²;-wRuzùˆ» ë¾ ªF€Ý§0Ñ ù(êêô"Ý$0ß¹Ê^¼É¢"{â {ü›¬é“¢äTv~™ýŸ3ìZfóà;kì_e¿x‚%kVT©DDß+îLföD iÊädµè¼’¼V\Tâj`š²$˜{b¤+r!QË“¼s;,/03fí¾Üä-ÐØrZÔÞI,ÃëǨðÍĺ¼&4k×îz™ÿþ¾žŸý¶(h<ëÅ|v>ö³õ~97€{`5·:>ůq𣨫OУtÀ,äØWβ‰$ûܻؑQϯ"§xØÑ½ìó³?}ƒ}÷ú¦+sf‘}ãö‘#§ÔOT0öÄŠ3ñÜt<›Ø*w_*êÒš&“³r³4`íT_cç±QÛÏÒOBÔŠ†¸¢ÈWõA²þ¶?Q. S†|š¤¨I*¹8iIIIŠ\k-Nò6VÔø­ÒéʺSÌ{²Êwä–l-ÜpK7~“`5Ϫyõ0mÊßú=œzï ÊtÀ¼|‹GìéÑêô°›ìÕÛìì2W Śő%>'&‹›¹ËäÙ<{=´ílìÊ/2¦í§åìÞX!!êU)¹&BH$$9=º¤$–”xÁIT¸"3Çå")DÉ_Êì¥?Õ¬®ßÎ Ë؆Ôˆ±TŒ°‰žŠm‘Ñ¢·K4¶4iž,êcÑâ4Éžœ X†BûœºV¤¡ª}½ä³a‚_Ò[~¹–ôé×I;ÞÂL;žè{ºF`neÙ/œ¨P—Ë«ìÙKìy–UXÕ~,×Ö+~]-²o¾Ã>u¬.'FLrƸ¿’MK¥øV‘1“ EC*èRN—2šLÆzU•‹\Qjl-L×Uƒ tbù ý:_JÜ*%xéÍöÊ-vu­—¸Xª§„t%eC2{dŠ˜f3CöaÓŠ«+ZÄö“h¨ž—&i9›¹’O‘òÕ5³·"@ö  íüv;ÚoÝQMG­k©i[Ý¡”–PÓ ;·&¬å(ÌY;ú’®˜½ƒíÝZ _PÙ_c߸²¥°§çû‘C5’”¨ŽDK“r~9+Ý´ìæ†&Ïë"™éŒ#×F3>snE Ùhr}†$uY‰¯ª™Ó<‰x1Ï^¸Ê^¼Á3t­,Sâ?76Øsï°÷à“~)¹ü=I×Ãé¯43\–×3c4ò`i!Oh€¯t±–×HJ\Ô¬¼5ž¦,n/¯©8E¯ŒöÛ›yjJÅÔI—‡œÃk>Òå7 v’®˜éÍ+ö¯ò—}òZ¢ÜÈ’ñ¥ƒÁ›J®yŽÀ'=Þ­ìlàAIMó¥é|5>™Ë5U¾^$EQ¹_"ØËàˆª'Dm&ž;”ØX×ä·6Fœ¾ ‡¼–¸Ä¾u…¯u_Œ°Ñ8Ÿ#»>°•¤`ç2¼t‹]\eÿì>v0mßÂÝëC’â¾9R—ï¯N(þb$ã±Â´œ›ŠçÈS‰ †úFËkkblÛÙf¡U¿kp&ƒ1¯‰#g? [ﲪ>;rãžwÝÀÀüžO@òBÍ+ú úÔOtÀØ|áEfìÇïfL°‘ÏQ¦·vzµÿÁuöí«|6Ì×æÙ‡p5’«æÊHE6ÔèºÓ--i>ã–<‰±hé`bƒ¬6ùomŒ¾®¨tI®Ñéyö¿ÞâSU^KZfw±û'Øá>Ôh„ïŸÝ:—§êü.òÚfƒµ¶:žs£dD^ËìñS‘™4Â{×HY»¹ÐKËsÆ<©»vöûÖ}0¸Ÿð Xépźn9Ì…B>«€f!Ó(Âg[€¥ËæöÓÇ>qؼZŒ~wekx#qþ.b†ýÞË<†áÉõ _ü/‰|ºì‡–ùo†1Zô¦.ÒQeŸœÛÏòúc‚AŠõÆÆž·³Ã¯—؟ϱï]çs}Û' |Yϱ&¹ÆHþã‰Y‘´óº¦gª4¹MÍ;?[ôËÓñYdÓ‚€ô6ú™.˜Ç ÄôßyPÿØdäÏ®«¯­Iyç›7iÌÉGØo~ŸÝöŠu“£pzýä½ìõyÞæ³÷q¡D#%©“r~š§lg ›L¸˜®V—ó+ìœæ tœsbc öÑ»Ùc3<[ÌÆž Ëo)ÉÏ`Œ%¼ÿ:t)èR<¢U/êÞE-IZÙŸÈt¹ýÆë*ýM— Œ(üò=ÚÇ&…72¯ÌÅòîy™û§w²ÿyšÏA¹¹b™õr{éû­ÙÏ?Ì'£{.‚9(©C’Bº2ÎÓ4·±¦ÊoeG¶ÕE5Ø7¯°¯že«GGöðûÔQž…Lrrq…]^ãu<ÉßÊkÛ‰dô.OŽËÔ ›ÝËŽól‡‹£‘¥‘hõô`R¬–›á¨rGr­ËÕÐ÷t—À<8Tú¹‚(_¼b,)|òçSS™ç–’KŠcœä<{‘Í{91×2,£ðÈ9µùßgØï¾ÌÖL‡¹4WQ QÕt´4-&D-1">+ê S ß%_Žê5öÕsìÿ]¨H>&ä§ŽòÚÏ·²ì[Wy5Òž¼ê;º©×æ¹+sd”}ìnvר}˜Fp>›ž‘ù¼œ³yНÁT7\³d±B7ÏŒv Ý%0?1% Y#úöòæzŽOL%?8nüÂiV*{3©»{Ô[`ÖŠ,SäóÀ$ûÚ¾6óËo²_ª.$#XÕÀH?â—›”J©¨Bê"דdµ $®·²¢I3þô öµŠxþh‚ýôq½ÿí—x…›]qbš|õå«·Ø¥öÃìÇŽØõr †ôƒõ‰GÓói‡ÆÈcvpõŵñª×¼«„ ßlh±‚UM <ŸGÊ”uYÐIkã|ãz,FÂÊiîæL@ÒEÌ'§Èø›× ªº=°'§Ø—¯+Ï-9Ö—~|÷šÇ,™Ð|h˜—X>æ¹Îo/ñ–?zxón­Å•“ržìfÊÊZNˆjSIº)œÍl®–_ʳß…_ÈtˆòÉ®o\æÙÆJØ*/¬—ølÛÕ5ö/"M¥®—”ø7V¦ï\;ÏlMŽ™‡ë5v67ì|YÍ·2Û"¯È9²¤ÊE]ô]åãBÑZ%µ6³K×Ð¥[UMÐßt‘ÀÜ™,ŽÆÈäEÈYqÚêX„}fÆüæ²¹]S‹—Š‘¼}‚+þØ#\`t+.òèft]3…eU¦R2š1ü^…eBÎÅŠî(º'%C¼]J.”ü—›|ÕιåêFŠÁ¾ÝwYeHèôWo³?x…ý›w“còûÒ+ë.þÝbü§¦”CI> ÙL8—|äTÞO0ƒ2¯¸l/uœÏ²Vèþ…Õ}ïN/ÎÄy½-ÝŒ\)¤ÞÊŽnhÑŠ€Ïbž}ñµP›Oœûù‡ÃŸ¡3DqE•ïX›”ó$3Ö¦Î%:ætI0b#áyt¼ˆ™¤Ñ‘¤õ+¯‡†Zd€ì¬ÀdJ<­ë¥››•ö‰#£<À0ÆãÎܧÿtT|ìvñgö v9¬ë!¯Wöã75¼µ¡$Y^(žWyû¨÷²Ä*ÈMyq}œÜ€‘héµÌÞëÅê²ü4ø/¿ÁW´ì$¯ÍsWoʱ?´bU”aÖÊ/޾›W‹J|PT'äÂx¬pÏÀÚ›–XºKÖbÒáhiHR†­h$Á$iù2ž°ƒCÖðK§Ùn”Klñÿü~[]Xåºôã)óxjÛh–ŒÊ”±ùܶDU‘زž9u[„¸ ÞêüÆû›ó\~ö$Ù¾/BCšDcp”/Ëëâ‹ëd^3UŽ ³‚"_»À^¹ÝìÓ’ù–ô³ˆ%7ËÃèVÜõ ×’+ëA¦¼Â—g’ÀÐø_¸ÊÛeçBºìMò 4Rkj0–p^Ç`BFeò± ù4©ˆ;o,%ª‡’ûãI‘/&ÅòL@«h½À]öØíŠlýë ìå›ÛêBæìÒæ¯ ‰%cÜ(“i¾oœÛèQn ó\í¼<ž7ølUÃéa¤+‡GØ»&…c{ÇÇ#i~­UU½QˆV$ “wBúñê-®Ç—×øºß «ì}y:ÜÁ4Ÿ`¼‘Ùnmï4CJ3’àwñî}áñGîx|\ÿ䌰?¡¥%.y]¿’7õ¬ðÂÊæà#±È‰ã‰Ã'œòÀ™¿}'÷•K|YÌMKQH¢›áŘi´ñvÅ`èɬ>w™/ýydŠ/óò¸Ð½ÑÕ ŸÌéQRR8z`¶Î™¼ì4ÿàÜ@3bm#0ó‰fþ_ìš²@£ÑâDvz÷v}fUàÿû˼ÜY½´É;YöF™8“`_xÀüè÷ÔE>Åw|¨ôç ))²¡±K'ýúãõ_á›Ê”IFÙóá}ñ5+5^V`­Ä~ñ„_M¾rS•—jÅüU½O<ÏQÂo=¼LÃ[˜Ô5*¿m%ý;my]ÑzwÇi¸OÐÓ4.0cÑÒìàê>9¿¤È¯fö,)‰Mi)¨ìë¹-¦—nÓdïÙÏ'mHDb®kÑ»öž$/Õe©BN—þêÖÆ¿:Tmò~°ª^ÊÇ·?=Ïã+žHoÚS’§MTît)Ö 4l(¼°Ø½{Ù½ŽZ™ä6‘dõD¼IÞ»Ÿ}äÈØtüßßÉ>5£OøÛó=1a2.Ý(²x„ý»;YÊòäR{`8òkM¾‘àSs'0?2;ò¶÷9ôäÉK£1Û[ç_ìÎ1;;ë÷• -´55·"î£òÜ,¹ÞÛéÂ[»F&*GS«wYõzOoŒ]ʧÕrž‰Êï½¼¹¥ 8ÛGs- äéXoòêú½‹Ý3FÍþäÚÀ§g´”cPyýÆ)¯;æÇ^¹UÈqr×èæœÛK7·÷b‰Wo¥|+DÖ²ªó¸úö¯ûÚùíUœaØ?Ä>{¿pÏØC{Øo×®µˆE3Í¢®ÓßÈ#ÃÚÇöUø “²pï½£ï|úXõ9%ûj82äˆ>-‰ŽÚŠÉýBÕˆ(†¨X1˜:î®EÌÍÍ5ßI½”ÝVé…8¿-U>î6ëÌË«p·aMïÖÚ«FF®Ü§°@O+Ìs¨«OУÔ-0d§Þ3<¿OΑIúÎê¾[¥ä¶Å"+üǯó0¸SÊA‘»GùìS•Àƒÿ·ù»ö±qöž™WïŸøÏo›¿zT°—U’ºüÊñ…eG°ýí%ßÕ'ä.ØÀ¬+²¼ö§ù¢Ë2ŠÎë¯ÔäŽáŠídH_›ûŒÄ{lš=9Oþä”ökÇØdˆÅ'sú¹lôpRù/÷ rå¼ÔºfœÉ¨<Á‰nòt²€š{“¼^5Ë)lH6¬Ý<§ÙtDÅŸÔþÛýf*Ä3.êæo^˜ÿõ>åx*æüJ1Ìߺ¨^+¦*N þÖžoíÇž$û™ûù`.®òjlŸ{cI‰/+ñsÙô½ƒkw$×í~”mNmGKÓÖ— ± K JòFq`Q‰wPiZˆó59üN½áí]c–1xTMžX3Nãü6 «€M}s0‘Iðù¥sÙájuáGW<òwÉ ÛËî›àÆîßžàÛÔ¿xûÀ0Yð³ËÚ¥µ¿ü»á¿üð]ì¡I©Þ îIøqÿwb¨çï8Êæ“±&y³¡wùÜ`_9ë-'(“ãòÞýìèxElœTóp±ý¸Ä>{?{|?©Ô‘í×…Râ«·#"û£‡ ·º=GU~£x¯N1ha ¦ìê˜#ÉuÁšÄ¿RôƒŒÄy¤Êƒ)¨ìÔKìÓÇØÍð4âÏ=Èí/9¤F 9hŠ%3Ü&¾ÿßÿ8áXvþ—¹3á&*²Éñ&^¾ÅW)Úɧyp’'qt­¿¿Ìž‡‡d€~HB¨M:ÎWÆL§x^2¹,£+.9tÅç.‡ZøB ú™ûØûP’`ü‡»´™DX£üø˜ùûX¬²ù|IøµsæŸ\ÜNÑ&Eyý6ûÛ Þ‰Ú4€»Æø2÷ZN=ÚoñÙBê7§lÏUZ‹üo”^ÉŒÿÐð­€Q‰¼Tsq$]:Øxi}nÁ¯¯WoI6úK§Ùw¯³ÜÁ½™ãã|`¦È®fxJÙÊ[Õ‰adI¿~‰ûŸ9¾¹`Üg›½I¾7 ùƒl0Ê#ÞÏ^ä"÷î)öcwñˆËV• .)Ü£–É"Oð•­Š™äôDƒÛÜ} QsLŒ°Ýc« ãÅÓØ‰‘:bæSñŠ_Jì/n²?¼9³±¥¯äµç÷ýëìÒZµFWàöñ<Ξ¤çôÆ<ûÒk¼1ªcrK°Ð+ÃÞXáýc7¾¿6q£8æPEc’°3a ç%š¿"â(ÀIƒiÊûÙE%^-2ôúÿô{øœ½e¯6Ó”mÈÌÍ-òÌ„e ÚÇCÖLðŸ‚Æ¿t“‹“3vBNuõØÌæÎÁ_¿X‘ÄE–ôGò¹ Ò˜²ñ$1XγŸ½ŸŸ¯¼µáøvL%<äî<%”ûòÈûÈ‘òâùј0h$)‹¤åÏo²/]æ²_êHç 8gùÚ~çHl]9<ÂÁéiŒ8îÎ0y"ÃeÓáãÕ <ꥥ:VŒÆ#ÚcÃóÏ.Èê]°ÅC8#äÌkîÈB¹È#xþ*8‹,`T ßNÕØÜmjŽªæ»;îpŽçý†}ê3ê3kªœ¹U:’\»^˜W\¯Àdæž¼—}øN¾¾2«ò„.ÒrGÈäÙ6N¶æ¦È±(û ôëtŠMßÃ]þÆ÷*4†d‰üú³ì¾Lrï„|”Êpw_Þ\àK Iº"-ʸ=¿je% 铳Ü1ÚbEa7ŠìŽdíSmóôºù×·o.Å/å}]a·Vx©˜¹%¾dÕé²ÐU¦‡xµ˜‡¦øŸ#•ªIOèv–‹ñw®m&j“ïBž z@3ñPE¦ËÆO-“Óšg»EËsÆ<©¥pöûÖ}0¸ŸÖŽª™ž=¿ þ5ÌéùUÈÜHKÿQŸÀ¼“ÿÿìIŒ×yÇk_ºzéÙ8C‘CÊIÑE-‘%±e'6„bØ` ˆ‘‹á“ I®9$ð)§Œ @‚QbÄH XA‹%+’¨áN‰Î>½wíK¾W=ötWUWwWÏôß ª§»êÕ«ðþõ½oË,HuÚ/¾ûBaíƒêÔ]£«Ø0åG ë߅h!KœØ#0©OBÛ_½LÆaÌß=I*˜MííÀÂzñTgNå0X¾ Õ³á1ËÁÛ{ÝUþÁ‡ÌËz¿]ô¤ GŒíQ+º·¬yKuî½²ó^…¿ÝôtÐ¥å-P÷é±êŒ{>| PÓ… dx¬H¦#?t¥ª“]D°uÀŒ+ÝËù‡ÿ3g§ˆiÕEš³‘ûò¿Hj&X\™¦±´&‚<Èô'0 'Û–\äÉú•b­ «[¦¼¬Ã‡’ê7y4ÜX%ñƒÙÖ¨ë{ƒ˜AHžœ%~ûO7‰ãú›‘å2È:UO9)‹Œ#1k§{·øÓáM—é™k8¬î†÷¢ïàN•º¼Ýû0ÐÅçæ;>s)ê—%îƒ÷½Siª(˜ÇdãhŠx/,×¹ÖÐ7M¹fs›†·axºES+*ukxã—kTI½ßêÖ߬@üöçg¨S“÷‹.S¾¹V3ˆë~µA”õF‰T˜†°ÝÖQxbþѹîý1–òžÊl‰ñZD·§ÈLBÍ:ñ‰AtúÇ£ß)ϼT\–ýµ‰¡½iQ…—ãK‹å2 1aÏ·žG×þŽ–YéŽo¦H&õoK{ªždêO/û൫ÔW©?8µ'_Ò¯°™áÌI^Ÿtx#ï¶Ã ¢•fJcx\Íâ7L¹dIu;2ðÛT#Fêþ…9²”¡:ô‡$>@ô_-@!ü=0a@@8½F”¬£F€È‘ɧfI\1E" À€»ºM$„ˆF‚âàCÕ ®¼ гúÚ‰À’<íÍ”ûÝCé—¾¶[xc{þ¹üz¿/,í¦À0èe½LSÔQ©ñÚú¢Ñ±¬Û.õï—‰Û •çÏéÏ!AYG2Ô«KÔ×O?ö½…R`Ü"¯Ãú8-h kqL¬Êù …팓¦¬I^[LÕL—ãfÍHÝÖÓKìÜ胥üãÞãÂTÏLö>l¸A08`ä×HI‚îÚ3 -`vüÖ1"0+ëmS%ZnæÎTŠšòc(@™æ2%×Ö~"³}\®Ñƒît™Ã©‚^§¶š½GÉKÔt<¯ˆè2õ¿·‰ÉR *O ·¸˜§¾ó8 jp<ÒàÍÛ¡­à`Åwtµ—Í¥‰û ÞÀ|BJyÂÍ>"5O§Ëðë ü£‘ýƃ(Y† ÈadÀSÍe?¨¯«9°Hà•æL1ÆÖ¼ãÑKBç®”a“’À–CVÆß9I¶Âv»˜ÀóøL–ý gQ* rÃßšJZ<ŠÖNu8°Z6M©l‹ºÃÄ1Ó†å’TÐÀÂɰ¦/dIpðñ<‰àR„Î8®@¶T’ &š –Ç÷ŸÙÙü¯ëÔÏ®ï|Îø¦ÉdŠ$“NÈ$óþÍI;ÁÇ01ʤ%βÖ©y\®çyƒî׃o˜Óy¨*§¡fó—…kÍ\еañšäõoHŒå¬î×£/5&¯©¹Î/`ñm=ÑÃ3ø·ÎìÉ_ñÆ‘Of·²ý$mt_¥î›†¼í»^t—ò¾Ü©’ààÀ8øy²Yw$Ó™dͶFj\Œ€wL`ë,Ýë‡6—!©¦Çüzlܺ<í‚Þç8sB0æÄf†3¥$<óžG¦f‡A‡„’æL1m¡b ŸiÚ¯dõTvûDª3}äššÿ´^p""¸Éu/ÜiÖ~:·‘ês#®…ár FjÔ«¶ ;¬3~ìÃõ=5i–8E^Z$ù:ñ2l8ÚÛíé×Åé—¸Â@ƒDì¼ýê"q¨„ãk‰Ë3®HÛ`çµ^ ¥+³ööJ+†²aÆJþG¡’j™¼‹ç×âƒôàr#¼¾*-'6<¹{TÇ!­è¯¾æÐtø²%­©uCn’²ó}ú @Z>h«Ð5¥$Êçæ;ZÜïÂÒÞ‚Ôài¯épžßW8ËÙu›[5îUU‰S i’ ló¾}Àù[…[ÉñüÕ õÜP׆ßHÔ8"5‹‚&ûž$ŽvÆMVNº~Uá×µ©X‚ >É—ýÈóæŒ vÚFRd©oŸ%ÅÊ–¶H¡—âž]~Õeß*Ï=—_Ÿàu*Û/G¿¬§Wt¥AÖúA}ÑwjÔZ}çýé")z,v¬ÌØ_Ì”N¤j¬í‘mCñ£ú䪙º¿_˜£~~“ΉÀñH™gÚó³ÄšëþðK$ŠìnZ®wŒÄØ_ž\‘‹Ú/ê¶ðVy¶jóÃ… ÈÃCò3/6“Qæ¥FµQ>çùòð¾Z'ëlÛ–xKÍNäB¬°W®4 ¦lãôþ Ic{å¥ãÔ7Oß8èøáhlˆÇÓ¥]å…û\Ë|RŸh8{â…,õ½§¨þ„ÅEPÖ¨¿ÿ€ˆÙñzü{£º ãÉhÔ7`Õ6¥iâ‘®À¿q*.ÇÄখ»Ö̵qq4ñî€õ«úû¾Š½eRnÝH-é’)jNT›K0€&c^lÎIÍ k ‰ÞÅ8ãÇ^W Y»!2ºqz^%æ4’šmØhÑ[jràŒ<ž‚WIY°TŽ3gEuAjäxc¥! €–xWO/ëi¿$Ì kÃøÇäz‘×øHWŒpCÍ]oæv£×ÂhUý:›)Ï >^g³àOêýôR1Ñ»FÕ½jGÛ"bß,l‹lø_ ðfq‹ gö)ÑÖæ²-À몚Ëú®ã)A+ðºÄ8 í±¾‘Áí-×èxŒë‘í§V'fÝåʦT±P—šÃ·ûÛyÚ=‘ª=¦T21Jú[ûNeö®®ô” ˜Ø¢\2³³©šë·d¶=x‘p!Ã…OØŽÐqYÚh—÷‹T2¤t2¹qŽô{öFZ°2>ðkïZvá’¬1Ñ>l‡%¾(l´ø‡¡® cÎ~¯ °Ú¶”憚õÖnPÖ7„½Î 8Ò¡hÐX£[ wàÒËPÞ3¹Íãr-¦o¼ép[¦ÔS]`¡?•ªžÏn…ny­; !$Ò¬f uÀi3C^.Ós6´/4íäÀ]ðD`\™qàMе%Æ&o›#Rä²¾±£W ¸¯MSþ¿Zqc”ÁcûF‡;½ãCj¯´{컿퓊ܛê9Nôl£Gëy<‚Œùˆ Oúõ¡K(fys^jƼʲæ…Üæ¥úDÕ"ΙàÍÇ3¥nu» ´dÝïà'Äp`¦ 6sÏo¥ÿ1 ´Ï_{@fZÄàÏ kʬ#ìÔê÷x®FÂÏø!"@È«¤©Oös-3ðMŽ—xÄ*rg©ý}Ø)=Oø3â*a®þˆ?ãÌAÆŠC¿âo?õñP«0˜;³¢ ËèM5[¶ÄÀ“O*Uio€5ØRfêj3¿aÊû¶þz~iKË ½|Â#ÐN˾ü„M §eùÚCÁ¿»[‘­_Îvi0-œ-€U×Ê!M¬ª[<g´¸‰„ È¡˜š%ÜPs)•¾’A<SÊ‹r Îý´Qè(&æBqoû°TÀ蹡f‡ª 3\³À 4á 5GòrÜÖ¿­}9êžtÙþnÞAÝÔÅ‹‡É¦ŒCüèdAçÐ ŒCÑÕ&+–øxº”ã;¬qN§Ë"ë¼[žn/ˆBš·ÕRuy·2³¬+cáï?è€5†èprXtå°ÌAâ3^ÏãƒÚpK˼]™`犦¼"¯ Lg|ÁnZ <ダ^uA9(i݆0PoGR @W:” De×ñN\5ZÕA¤_ñíû·eRcØ<"6¤F¿9öªÃÝTsKÍBG¿í‘PÝ)AÓn©QÀ~Ž‚ p˜†»¤›õÆä9SáÌ4k÷«+¦ËÔlR àŽ¦Ôœà`åe=ý¨R]3”š-ô}#‚JÆW`h?é]bl¿¿–®°f†³R~§–~ë {m¸¬á±U[lµ¬Z=âqá˜e-½l ëAd@ÆK`Ê“XŒ’§O‹z†(ß§âQ¤R ˜) *u[¨ÚBÙë6¯9œ;×õ¨ëΘ%#‚"ÆB`üÈÖ¯ÍI*)ÌZ1m—d úɤ?*R÷[OÂ{Íåô®:`}Ñp†­2€ ò0sÓ*­?'jóR£À|d¨ˆÓªKæ1 [ râk‰áW*-·HA‡œ°Nrœ5'6ç¥f×»Ëgí¦—ë«:|ÍÀ4Q]ÔÅð_WÝ|AÃɾ ŒÌ:S‚¶(×fDõ¾®x´N¬,’ª-´äTD'ŠÒ»&1‚ 2žì‡À0q±,Êõ£r=ÙôN­{®áðfªd‰KP÷¸A$F+0,íÉr2EªKŒíytÓæ·-yÍHmšRÃæ s‘>hïÖÝà²û«Ä«)GØ×åhåÒÑ6­¯ka­3dÿ•À0´Wô³J¤…¥]Íáîêé›jvÓ”u—Å/8sæLØW4MG´%îþ3â«ñdà®ÛDr’0I2œy.]Z`ÁÔmá––¹£gê6º‚t°´´óÈÀÎ’=¿Š*¬ñp`yÿnk#BÞ"Æiÿª}w4€=4ä ’, G{§”ê¥Ä3.+×ÔÜš‘2ǯ="2μþú룾ÄîâKuMn?† R‚˜ãw¿oÑóŠTÿ»m ‰“¤À(¬ýtvsNjn™ò•f~UO¡‹Ùgb¶ ëXM{û²Q6±/TüAdHL`&yãùšëÑo—g–õ4J r ôkjŒŽÍ!Žð ȘŒÀ€ír!·ù¹š½ÚÌů÷… 0ûl= ±‚Œ!ɈA–3ß­L_jP]ѽ=Õ¾ÖþÕèžåGîy¹}¶-ДAƇd,˜U#uÐ7‚<øtIû3{ûWÃxJ:Æéø0ð*— 'þ™6‚8cQMy˜é+f,bõìЛˆã»¿ <7ú”ÁƉžmÏscÞ~¿“Aƒ4‘ ò “˜À„t–—û=«në%£ÞzÏÒÌœ<ÁöZtîj¥ !-³=:W-Õñ\82ú0õ×õŠço(ü,³r££œ[p§ËêöAÏ´oð±Al˜¿yú_šyBwÌø§H,ÿêw~øþ?´V÷¢˜ùï¯þCÓnør2öÂÏ~ô×¾ûìä Ç ;Lá¤ŸÜøùªVùË/~»nia‡ñ w½¾ú7þ¶n‡sàÀÏòÓ¯ü…Ìò "À/fºÎÿùòAÏAd‰ ÌùÂâß]ýéÿ¬|ÿ”oûÒ…‰Ã.‘ –f‹Rö»oþxM¯ŸRÿò›Æ2Ì„ùÇ[oüëço…ü£s˜åS5K¿Z[yùW? ;ìÅ™3râ¥1ߨah&Å þá?]©Þ <àñüÑ?ý½ƒž&‚ H'É K3'Ó³¿Ü¸üqåóøg-¦§oþiñžÀ´¸\»{'d·gVÊï>ůj¥ˆk•ÌfëMÍÒ"[P&û!G ÜõújØ °3‰ ²$“¶rD.ð,{£¶Ö×YËêö”˜Y 4@yIfq?¦LohUÕ1ú:ë³Æ†ÂI“bfÓ¨èöÀ´J±bØ·`<躂 H2s23s[Ý óB‡Q2e³±˜þöκ©jÝã9™ç¤i›¦é¶t t`, Ò" ð•ÇäQpyÈ}^Eá"êEÅ«G@&Zæ2•©¶Ð‘¶tH‡¤IÚ&Í<Ÿ¼Mû,!ÉÉÔ„ððüVV×éÉÞßÙgg­ý?ßÙ{·N%ò©¢÷Œ‹Hý­`-Ò·á$¦ ¶éÒ((((q#0ÉŒèÜWԫĩ̘"ñÕ`Ü[‘¨LªW¸/ÓcTë-·/àñpˆt%,š†¹9ùaéäz…ʬäBf`™E 2 Ô*ømçåFM·I¥5€ÜúÑÞa0,"Ž'Óð¤h ‡ˆ½ù£¬&p_à¯Ò¬S› 6ŒãýÂÃXqd¡¦·´- CAA¹· ŒÀ$У”"?ÆG¡V–̈‚0ó7xéQ3cG»/Ó¤–ž•]7[­  tî²´SxÙá$ºÑ <8IÆÛ´Ý?6ŸÙÓZÒmT/:slDŠƒ…¢²ŸZÎÙŸáèQYÆç¦0¢#HL 4f;· ÷àÞ•fýUyÓáŽòSÒªž?7‘p  aD:ò0U „“àÀÃJ³và<ƒ@Éb æ &äF¤‚KSpD#l†û~&Ð ¯µeFemoÛþ¶Ë¥=Š?…á^˘AàÂÐ#ñ¹ë®íÒZ ÿPPPîm#0iL~¡è?*6«$ù¼ "g «ª¡¬ØQaI?µœE*Âä?Èùaí¯z+f|dêŽq/·ëº7Tî¾Ô]/Õ+aŒ a‡0x÷ó²)˜'˜ð^Íg†L-í¹!ÔÈ\œ—3Š“4 0dq&Ô«³¹$Ö±Îk«~©W‰€eà4 TahÀ§Ieòó¸C7Ž|¸J›ª~9,*"4+fÌYó€üPp7{ƒ€®å(œò&‹­SŠ?ÿ¦O? ¢2×dΈ>/«ù¼¾¨A-Íî5iû»Tai<2{(+ÈÏöÜ¥r£víµï‹%ÕÀ`™ îôÐË8ZøHNÂyY]À ”{› xÌÐ"[Ô2?ê6i$óÉyD!ƒé{·±z/Ò·3bF½½ÄS#?ÍYZ(.{«b·ý£ºÅ à³§õºìyßç­›4›ªö¶h]ßl4•3pIb­Ëž;+fìŽÆc_7ž!lîé5k{•ÚeûöËï×\œTðIγYìã[j×Çb³¾^þƒÙfmÑH‘î⺲cî™-à €—YÀËÀïy9mÆŠ¡³~l9óÔ…m.7ùë­&½þæ[²«Š–]Âó@;ŸO™þCÞÊí G6WïnðŠˆXìü‘z«ñš\Œ_åÞ&žv™ŠÐÕ˜KÄâÓ˜1SyÙàù Ó`¸t( ÖËÁ@LÂâÕ!í…ÅC&w›TïTíCzÔmT­)ÿÞhµ¤2£Û½ÊÂ"Ð>û¬€Îsf3Á½l†Ô îTi÷mcŸ3Á =J“Â}-àõ—‰¤0À·éÝQO<=bÑù­§¤UÞ\×vs_‘bCåžó²ëßNXf´š€¼Kª€ëÆ «{[ƒ· å&“̈ê5éT·Gd¡âIcÃS–¦LËÊéåˆÎ8+­ýòƱ …PoNFªWrH4&Úm ™Ä°ðÔÙq¹[¯ÿæ~*[g5­¯Ü=„Ás–I°´|èÌDoѹ6¨;}j Œ±–Õ¬.ÿî«q/ï¬ð©.¦/|äSIÓ£‡/<÷A¹Ü[a¸ôIIå³·ÿ:|ôgBeàÁh-ÆT&?„]ÄŒ¢` ¥ÝH@k“Ñ &¦³bk”í &Ò¸‹“ò߯ÞïR]È8ÂDnú¢ÄÉZ$„X ô'$Uóy¾ÞK8‘þßoªÜëR]ðX\+® *+†ê:„pe€ª•½œ6#hýí'Î9WúÏ s9ïÖÀù &æroܧKÜ‘¯Uì{# ÍFAñ•x0I n‹Vjµ{®×YL “(‡Ú¬ïÐõXaX¢ï•”‹±Ç¨Q™nMqYjÑHÀ ÎJeoˆ¥†§ªÛ€¸Ùs'qפU‹Kf½|ù«ƒWÜÌã¦wç(‚ÿÆîÕÕ•k0sæœy¯A%v.c‚-ß5_èÁÎ ¯è,ÆÍ5û[µ]. ¦0¢ßÈšQñ´È6m÷Þ¶‹.K΋¿-ç9­Å`¶ÁžXߨqyÆÀ?6ŸùiÒ«Ï]ÜŽƒÚóéééH_WÌËXËÅÀàèPÅå™ ÞQÀq¾/±¯å·”A&ŽÙ¬’Ø{0•½Bà²,.Ù:6"åÔ´ [sžS˜ü…ç>\rqÛ u§ý¢dðo™Â.ó ³Ö~e—Åæ\Ss Wïm»0=f¤Gƒ¹‘©ç¥µ*W î~^ö»Õûƾ֩—?›ƒd¤Y#’¼§µ¤Ë œ;†CBÌ;dïѸÜfµô”¸²ª·í¬¬ÖeHpé‡ãr·ß82ô·åjñ‚„‰H/v7Ðñä» Áã:wàÒqð„œ6;û.ϸ8?\¤“¿reÇYÍ´èá/¦>¸(iònáùZÎÖ)ENŒPÝ5“?šŒ YX°xZh§›‘$f¿`´éº§ó=x0T<‘N H'«}€?²XRUpìM—-`àãh¤»wÙ’ÏÚÀu™öFæÜ ¶`_Û…õ»+B‡½œ ÷²Ã%]γa àV®¾° *ó¤¤ré¥íºê·»,daçM\5¿”À$3yØì¼‰Œ#cÇ.NÌи½f]I-5ô¦0ù%LÚÝZÒª•9x0b½œKbQî¾þ…° &nõäþ¶‹ËJw4:i*ЀFôGc–Á™U¼)€—–§Eg3~y±´jꉷ«z[Ëð(aŒzxWsμê®BAA¹—”ÀÄÑ"ZÔRû~,Z0ñ‰¤É9áÉg¤5kË¿/–V‡†Ž'?7vQÒäÿJŸšÏëœTTl×öXlÖ8jD¨{#0d²â6 l]ÅÏß6tÞ4`DXâμW"É̲ž¦À^:‘Îý"÷ÅÏê‹¶Ôp¹¯(‘ÆÝuß*à¾\ênu?¡  Üã J`iQíºû1”ˆÅ‡é¬¸ìƒÚ_K{û‡9 1»„% *ñμYì„( HÑÀ&C#lv’ÜP÷†@›a/æcæ%ä;ý®©ØåvËxZÄ7–ýÞQª4kïãf¶…Æç6j:‘Ô…E þ8iå5…ð`Û厱*ýáõÃmðÁŽË» Åå`ä]—½`ÅÐY1TŽspþµ8†N ELe›Íõ ýHºªX*‡E mhÓÊÜ[cÜ v‰CʾLÓøN³Z‚ tSEP üp-i°úåvü÷`èx2+[4· ¸©LþÚÌ9ÿ7¾N%ú¤îÐÁö+ý;ö Ee*÷ÌŸðxRþšŒ9@o6Wï¯W‰*¶iºÂ4b(V*Kô  É«(—ÿkü²“ÓÖ³ Ôw«÷ þŠA 뉃pQfTºü¶/\?©Ç¨ñÑ* ŠŸø/0ñ´Hln»}ï^Aݦí¶bà …ð´´º×t+W—Au\R162%Ñ IoŸÌèÔ+pXlH^‘KsH4>™£2‹\8-©žujc2#ú†Z\ë´éçîÛ'!¡n Êÿáÿ€žÌà5ß¾FÐcR¿U±+ÿè›|JØéi_J{°zœM ­6ûÄÔõT<ùþãom®9Ð{{Ty±Nôn'Ø4ª; VË8n*Rc«Q¶ÿÚq¨ ÂB¾ï»t ßЃ€»2ÀMÁ"7ÜHhóî   ü¥ð_`â¨ú—3ö½Âyg?#ò'cž)œòæA^Ñýë6ÿÛg EO–|\«êp^ µܧ• r“vOkÉ‹©3€(º/É$P—$0 > tÀ›Õ€Îíï@‘¾ÇoS€Ÿè ‹ƒm°Þbä’Y.‹Y`«X'Ð#1}¯7uVcðº3˜WdÉÌèNÜ!b#ƒe©Åæ<–0ilDòÎæâÝ­%»êUfý ©Ó_úÐT^öΦââ2àÁ8ÔëÀ I/|ZW˜•ñyîó¯þño¡Fc „MgÆþ3g ÌÞß~É O’ÕVI„L°õRWÃÒäi$,~*o8èm³ÝüØÜ¤kÓvá èÃÑOƒŸƒA  9Xf›µLÞ´(1¿U#›#w¨£,$]‚‚ò×ÁIcò‹%ÕöñîYs— ™Fïnþòö6mw¿³R$.ŸDwQÒäÇ,Ù4rÑ'×}\wÈ~³Hƒ:Ù·|¢×¬}ê¶sž)ž¾áß'w K:õ Ð6›Í†ÇâR™üÇ'Ή§0yH„ ¼Ð'ìx>…ƒTæ³ú" Ãc“ï(ý®ù´Ç¶™¬f Ï‘DÄÄ0Cï3>Ÿ+ÏMe¨Q à‹†£"}eúì?zš¾ºq,T½íÎ ²r!;v“dlà¼ÇŒ[î ¸ü6TY¼ühª›Âã:üÿËÞyÀ5u®<9IÈd¯°Adƒ \ˆ{g[¥×m¯bÿ·íÿV[µ·Z«½mÿÖzÛ«¢¶·ÿZmk­­uVëÂ…Š dÊ&l!d¯û&GÓE¢>_ÏÇÏáä‡ðþÎsÞ÷}žÕOŸlzaÁ°|¾íìò.W)¾¹&ÚÙ?Å[½­¤]*Ô}FÔìç§‘Ш}œ“s°:Ko+b ¯ßQ+l}áÒÖTÿ„Å¡)¯GÌÈ%MâvÔB¤.楦‚%YÛ0qkÂóåå’^Íh¯ÈoMX'\i熻?inÑ’E $0RaËÛT…Jy”sŽdZæ”M£¼"wß?m4%O&|7o/~ÞmÔä> *ʤ7"‘háУMfJô®ôw§í«G|Ý\ €+#bL¾þ²«aëó—¶LbÞ4$í¹ ÑîütŒ“ƒ†H*‰òŒ_¦!‹¸RÁ³7_n*4ô¹Â¶Júcž¬WT¸£¯öÇsõwïp«B½¼h.ù·ò·bgé©IG²—EÃÓqNîÖøWîèn˜NEœÀŽ]4êÜïørs›. Éɺ¼—B'üPy‰×ue„Q¦ø ñ :µ˜ àº$tRzö®¾¾×ö¾[€K‘®¹ƒ_7ªX¦L%Ã,æÓë^zô…¥éæ2ecíˆ%]Ök¡å·±—…/VNò1ÕŽ)ï›Ø0˜ÕR´ñî_ºë’^=|:zN_=gϨ¿1ÈÔµy{o´Þ7êÑ«FØÒ/ ÉâÝ®‰›?Ž£=b\PS;å"®”ïH¡­Ÿ¨qÄéIu’)r¥q0È8c’©H|VšVÅÌ¥“LU:Бýùð%Ó}‡ÑI&ÓhÙ[ž‰ìÝ#ÓÙ4ókØÐeR¨«cçRMoYE½Ø•´â…便ÕbaŒËnÑ{Ö£A O©;Öãhô5Ñ,fÒë&ˆÖ`4cJ3U¾©\–w¹—Õº<=XiÁ1=Dí,2•‚uÙ“ïDaÌ H|1t¼ÝíÇÊKßÜ?{§­RAP}’ÿË如´±¿$¿{—Wu°*ë—êkâ®Î¸äJ¥œ bz™òeâLah_ì0HTW¦‰ÖÐð*ÑŽšg&‹LCÿ·K:óÛ«‘]%3¦Ndúáñk^8žUE[šrµ¥Ø”ÁJc’é â¶v©àý¼öŽykËûÓ{‡r[ï‹2íÛB‰2Ò#bKü+¨:dºP2•ÜhÚ%ÅÍ’Ž¯|±3qùÙÉ~­¾~ºþV£˜×d%5@¥"|šhñ€q!,ïwðj¥Ê? §`ä8—À%,E%#¡Â»o‰@$c$‚ýÑ_/¸¬ˆLÜË{Tr4ÆF·B·–Ç¢žx¬˜¦‡;•U:'Cï:Fï¶UQxôhmŽ®»¹J™ÙxïßúqQpò_BR>ºØhÉ¿O|ß|Õ*•J¤l¼f’ý»è¸L)çS=ï+3ÉrZËÊ;]XNõb#Ž,;ä¢÷nýðÅð¥iÁÉ—š ¶ž0UT‚û@wV@ýZìzkéÔ³VÇÎûuÜ;U‚–ì–’ŠÎ&dúø1ÝÜÃ"üv—þñ[ÍõÌ)›rgm1Ó¼›Ürü¤¸£nÖù.Lš˜´tàDd*aÆæoœÜâV i?îÙóS6f5ç·UÕ ¹¨k޾#=ÃGyE¨¼ò]Ù…3“?È›ù¹©zݨ,¤‹|ú+&T´oczùÔlÅnÔD°b ýÑb#)²Dx€§+æpuvfÃ=ÃëhLo·›ñh½ÿUtt[ñqoš fÕ¾ýzwIÖvFwÑÉxRjÆášlóɤJz–'±x÷Ðcœ£i²š‹~_e¾ªãš¸ùª®hýß EYvmç†Û?M`Ç%z„ոǯµ}_~áDÝÍZa+…HŠ>òF·½Ðž äâ=å™{4 ÏÉ4–az¤¾-’±R¶ôêöw~~Æø°‘ž‘r•¼IÌ»Ö\ºþöþ\n9²]&Yo¾êjA‹¿'½‰ ss-\Àf;ú¸^0Vžr¬ô\ß!·Þ02h8"ë·U¶Jùè°$%ß²Fžk¼óVÔ¬ËÍ…íÝ-D6 “L{/n£|Y|\ï£:QÛ¾Š‹è0Ì%S)j„Vâ|¹˜oÖ)2× AÓ—Å'ÅF>픋‘qc]Õ¶›R¶°XËF[Ý /ZÑøGØH›§p¢æ³{GŽŒ_³yØKkóö!  û˜bÁX¨£÷Ö᯲¼Ò.né/g€ut;s`8‘®+Wf^yéeÑ»ØÓ¡¶ÛÒôšG011c´Ëkì)¤à±F=g®÷»ÏÌÌLOO'î›×ßmëS¢ý¿ýDÝUrê·šìFq»L)7¥4˜Ú5 9éùRèøCRòÚÊÿ÷Æ7eO'üüÉèb~…qTTJ€—L¥Ô¦1ühÅŠ0$€ýƒÿgddþꢂ °`PÀ«ÿÇú¿ ·,lêÆ!i7¹åwÚ*‹;êêD\…RY/jcQh.L*F wò sô‰v Àò¾ÞRòêÕíçòM­Ì@´ƒÍžØ˜?áËE%'¿¾:Î%(É#|°[ðüÀ$/š3äàCwiµ‹R‰B^-l*âqNpr/5ÔuA0Ø(ðd£L©@æ‹v}0`ýà xl `@`›`r’ß/¿½G©RI”]<(c¢‰¢»|U¬ñ‰1Œ$QŸ«ãK-/W*ð3TŒÒûx'R¥\ñ0æ&ª‘¢viÔ6©BŽû‡&jªîåê[¹J¡u»IÔ¸¼4ãSµwg‰’Y]Æhûæw ÀÓ†I.ÚßÕçrË&ü±N×ëÉ·ó“?t¢0´WBK¯èlšÄ´+)}ìɵwað˜}£ßB}Sv¶´£Þ‹æ¼,| ƒDý¬àð;7¿C×oÌØçØ›†e6Ý{#û«üöšm`±3—M`ǦÌj.ž“ù ÅîvnʇaŽ>V×[ÖÙðföÎ4Ü–j4†I¦¾>}ãÐ4 Ѹ{ãï+..¾òR—Ÿ“W=ã?ÜòŠ´¤]ÞúsU“Lã/ü¾GÌÈÈèQzžNìe™²?Ã=Æ%„:²É&S*‰œâÓ"år ¯ ññTÝ­ç€ÅÆ! fyMõ‚®;Rè½i O*\™ó-Rôhîä[ÒQWʯ_“·ïÌäÉú%_hÊGê‚L–w¢{Ó„|K@¶ËúÛûOÔÝ$±Hg?‘\Z%hþ²èX²wô ¿øG{Éâ`×à™æ ¶Á^fšßÐ݉éÚ[%ü½™M"^ËKô0l ž—@4&±<;åâíE¿#ó]oó6Ý=¸6v>2e†º†41Wê™Ü#µÙ5‚ FJô ŸÄŒžôOÔå^n,¤’(lºKµ …E¦½’ÈôÔm WÊÇ-’A#÷Œzã£üƒïßú±²³©JÐë M&QȾ.;óseAÉ@¸£/ª¢C&:Ts­˜Ç!±X×Àé¾ñNú•æ¢ãµjoÍÙ¨I‘8'  ñºõòeâÂvµ3fÔÍœ›3ïM>óX)o‘¨={¶KÇ89í5(o¬kPªÒT½ÛØ jÿ¥æ*GЊiªNõK`©Gko\m.&cèîÜæV" L ‹Ä2Sß+AUÈã­ÉæÉ„èv%yFLõja•x|±ÑãÕk; =í ä’íÅ¿sD\4>NðŽÛYrªJØLÐÄãÚVtbYØ”ì–ÒOîBW…$£áxúÙÈÐfqÀ¸ŒÄåçò·Ñ-‰ÁɉëÝŒy¿Çm)•J=¿Â—‰:¤]"K”²½e™·Ûªš‰¢=e™þt·vìÊÜou}òŒ84îÝœÖûxÛ´|}ÿÌÙI…¤½¢T)q—32±ªkÐÏ6©`ò™õ7¹Ú+#="ŽMX«›¦¼³qâéõÚ.#e†ßÐ#ãמ®¿³­¸K›=åçófnAwE¶aðó§êoÍ;ÿ©øá|F ®ô:úù{À㌮"ËÓl¤÷¥»®‹{ÖÅXHJG ãó„—ñweþ ÷m‰¯ù2Ütœk¸‹µHx’<ÂÑÉo5ÙÈ Á?¥IoFÎÄ ˆr~SCW/hhFOñÈ!k¦Íq§úhÄ×ó}I'Q×~>…ƒÎ‘>mŽqëˆ%ÈöÂÕe¦_ü‚ QèäzKé n™6×óÁcfú #h,’ú®õR02þ ®^„l¯t25ÌÑÈÊçUãê2;`ÄüÀ$Í-ª@%ëf?ÎÉE]FÚðlШ1^Q¨Á ´ÓH¨Ëÿ1=Þ=TS~[³äÏxJ‚ê§ÊËH] ¾;߃ꄮ|o,Ā娋ÀpÜÓõ·ÑQñPq®Á«cçyL#Qæ$ù0\ šPÊ G:ë¬ hÞ_á'Ëç&yª¦C&Ò¾ms¢0–…OÅ'l fy•ÎÞ!NûiWRzƒ¸ýr£Úpˆ#{ Ë[7¡é¾Ãð)}™šêŸ0/ I(PŲð) ƒÆ4ÓéºÁ˜Ñè?Õw¨Ñz‘, ›ˆ”@¨.»º“+é(ž½ sÊëÙRýG ƒ <í"7f­’¥Uѳñ ¥&úçÃ;æðNÌÜ1š¸gz M¢P[NdŒ´að >±ýð à‰Ã^æ÷º›SÏ~ˆŽï+.ôw[º°«äTa‡D$þ=j–7ÝåÑJTÿ#ŒÌp¼4`ü'ñ‹‘tµJù‹.~þmùy½wefK%`D Èþ@jj*ѪñŸJEfã=Œ€!Ó­§‹žmnt£ç¦Blu›à‘7¯§Ÿ&îiS£»ò¨š ½Ä^æ`ünQÎþµ¡àÝëÂyÜŠÅ'ÑÉö EÁɪØÉì!{Fÿ ™ x—uAÃú[‘³|é®é×w·Ké×vò¤Â7#gZRlZȸ‘žeŸ>ZsÃDšäanPÕî:sN¨ÒÑ^‘û«®ÈTŠÔó/0îÚôÿcÓm}{£¢¢L}D$­ðµl6ñ±@­Žü¨› ÂGv‚½Ìt¿aº«Èì‘BºþÎþfI‡#…¾6v>“Lí}™8N¾:sûZ„rÉ7egE¼P'ïÉ+‘ƒì˜wLð‰³¤X6Íåçª+nè4My¸[(:šwº×—‡Mswp\w{ÿ}~îÒ?V]=”²Ú—îÖm¥½Ä|Ô²>—ME86œÑ0B¥n.£½™ øGº ÐK©×B ;ÕûBÀ:ìë5ˆ]q°:ëº[è$-xÌXï¾xF’¶»ôôGù¨¸4‰=hÓ°4‚zÍtg^«E±NÖß\™»G¬¾7oetªåõªÔ»yî ’•1³·]AÂövÎÿ÷A—b4Æ¥ÑÀz£¤^+ÆPíà«=ѽ®>Ù0 ²…å›Ê¥Äl&eOÕ¥÷…€ÕØ‹coÔ [?¾û«T)bz¾3#ôÃŽ¬žy¸§Y0æ@¢¤ú8ߘoyF¥JùUééý•—i$‡Ž…ûö”gæq+Úe‚¾ï²%Øô\7â}rõÙ»8S Óm@·uú»…J©Tu?Å-”Kp\F±tŠ\Téæ‚ßŠ:8{;:5„åՃ̕™#˜µ¢\©PiÖ‰™èP7}2·{Tÿ4Öåµ´Úc·é6’"K„ú{˜‹ ÷^Îú7:AÃêØy,Õ+M…³3ÿY'4–8˜©ú+MÏ^ؼ}Ä2Ýܨ,dv( ª×®noóš) £[j ©6ã“ä4Œr¾!?§õÁ.–wcæNËëÊò¦I2•ây?P0õ>Mô#•dÑ}v¤ÐQ÷óÛ«¯µ”ºÖ\¢nL/|ÞØ]Ù°g é¶Opu ‹½ÌÁ”ðë¿+ÏDÇ1NŽL)+jÒdœm¸‹ÓF‰wÅ7Û_m)©qu?šé?ÑgÒ˜\ny°ò¯…M `xXÒdÁàÞ‘… É¡šëxÃÐÑ jï6o´sÀ²ð©HJùõ¼ZÔ€A£’=c,©×#¯‰Ìò+d'87‹x*Fy3jÖXÏèX—ÀåaêbQ™wÛ«Q±©#ÆxFèfŸæ; )(j9RD3ªl*ííèÙ¾t7”÷tým¹JéLa¬òü#üýö%}¯=F­„nM‡>¶-À”úž~¶`ÂüŽMø‡Bõç>D…Î$Ó^89ÕDQG-ƒL󣻕ðë\XlºËq+% ™7íÁ~”WNáÆÕlJäç8\³S}Ë›I¦žš¸®¨ƒƒïÒtögkr-Ÿ†´‡‚‘™ ›2Íw(:îú̇î¶ìÛ⇻2µ Ñ8:ÓãïÑ© ƒÇ ÀáNÐìý2a骘9e|µŸ´¦G(‹NŽÄÄšuó<Ê3¢dö¶ Ð×@$xJ€9À&€À6° 0€Ml `@`øo{w›å¨ `Ø,'Ù™½¡l'«èlgúÜœë!|¥P€ø>¿£ˆ¥Ré `‚¿ƒÁ9<oÍïïoïJµ8kï4·8lë½È„ë£ Kö֧е>_oMê¸n=ÕM¿£rËÃ5)¯¶p辚ƒÓ¸BFÙ„MíòÝX¸Ër‹“mbRu?mÓz.û¯ò8w…uMR·„fÇ^š!2œÛçQÙ˜Çÿ¼m•áa™šrŽ1ë÷?òú¢ÊãÜO÷¢GW.Aê]ým£¬R´4ïS‹["{ŸôE§-‘WØ]_xveùù.Á[çg!ú¢š:îßú°ª%- /Œ^ͽͶ³®ˆü©· ©’XïºXß²ŽšƒÓp ÷ɬõ”ÊefR«Ã‘ ‚×<¥Æ7ªÌRT¯ÿ®ƒ†ÇUy×^²l[¼wò£J­ê²»Ð$œ†r¢U¹Ò-V~ÓW–slK‹ è·ÜÞm£­á8s0úk”’ì:PO¡JÙiÆz]h ¦’jž4{É–×98P #Íšþ¾JzcÙkw,€»ªt…kb’sÒwe9ǨœÆRoµCiÆð@ÂŒPˆü¦Òæ\<].4=ÌÃ.w‡ã忉Žu„+½rܹbÍ«<ÛúÃeÏZcœ9˜è5Ò‡4zí–ï ÿTSs0Ù!²hý—Ú·Dõ˜×­Ò-,ñõz­ëʯB!Es‡Üï÷¿ Nz/óäƒû<ãÏçóçç'œvbˆ `‚0A‚|ŒU`&H0$€  À `‚0A‚˜ ÁL`&H0üwý°õ|>{W@$Z×µwtC‚¡Óý €Š˜ƒ˜ ÁL`€©<¾•—ÖqKÍöÛ§áºc˜ûƒi­íh¿Ÿ6Z}`‡ pÑn°Ò[]v׸}¡ÿäu5ä£ï*£¡\‚Û•Ù–å•úvüo{¹Ìl­R ‡KÆH0ÀlÜÄ ·ÂÙO­û BÂÈ(§C‚fã¾æ»ë£ÙâÀ”»iC¿eµèQ; 0-w|i‰5ÙÞ “¾(ëj/±L¦¯-Á$?p9ÊÖ¹K#^~PFÒÆA¸wBÅíÓ¸+Ýyõ%˜ƒÉvb¼Ý—Cm}tˆ,Zrª2ÌÿƒLÅk[ÝF›Ý訚æ¸Êo¤vQžÂg¹¤Î°ÆzØ‹ ì‚H0òÈ.8€0A‚˜ ÁL`&H0$€ þ’MÝï÷ÞUÚívÛû…`B*#¤ÕéCJ‚Akï÷»wfCH«#¤U0DŒâõzõ®Âliu»BJ‚˜ ÁL`&H0˜ÊÃa} Þçz¼ªÛš*gñøV½¶ã+€~¯½åËÛ×½B|‹ óðþKyþ‡ù¬Zñ!ì…˜5bô`0‰ð©öžyïíò³¾rFßCÛôŠŒx¿|ìÊ[ïžc«p9KÌèš%ýŠ}–+"Ÿlxv©Û2Zò’¾S1l4z0˜Ÿ×¤†ËáBvåd,ÎQLw!,á³ò³p®+²ëdý²§&ÜÀŸ…îA#Á`~©gIùÓñ×ä¶M›TÃä¶•%Qõ:[ÛÆã_ }R'»wwyËð£.1$Áà ‡ÆŠ‘mÙBxu-9Çè˜[ªÌZß,° WI–ô d›jl¾ðÓöA#Á`~åüøoÐå„Ä#g&¯wËp—ZïY®Hûz¦†×º¤=&ù1‰pÀÁ¢×2Ú‹³ž>Ilçèî¢ß].³Êf…»t!|YÜô(}уÁ<„üh£)—Ú½÷Yš°8GM0ݹè%=-Ñ ¶…47ž·Ry²»D‡È¼ /ů z$LE3Ÿ¿½’ Ÿf‹¤]+ ήW~WâX™»–Áâ¿k²}/„>zÊXÞÌúk ‘@;£b™¢í 8¾g‡MMŸW6 ‘LЃAüÎ`u„´:BZŽƒ¦n·[ï*̆VGHk!Á ©ëŒ>7CH«#¤µ00A‚˜ ÁL`&â“üÏç³wÅ0¾è \Y$Á¬ëÚ»V8=¾è ’`ÞïwïZáôø¢'æ`&H0$€  €óøêH6ô@'‹ËIEND®B`‚gateway-1.4.5/doc/alligata/12-7.png0000644000175000017500000001417707344776077015342 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ ‰[W pHYsÓÓŽ{¸®gAMA± üaIDATxÚí]¿—Û¶–öäÊ©ÊN%¹Š]¦JR\%'Ýv±»íž]ín•·ÿÁsùªTû:ÛÕf+«8•¥*óª‘*Û•ÈÊb…½  ÁÒhd~££¡@ðá^\Ü ’\Áz/þå¦ Ðc·è >rô9z‚=ÁGŽžà#GOð‘£'øÈÑ|äè >rô9z‚=ÁGŽžà#GOð‘£'øÈÑ|äè >rô9¾ºéØâW"‘ &X’&”LËÇØ+8÷aª:÷¦xVÝ«…œ± „ Î9 XÓyÀaLí¥ãá'‡Dõ;äá&¯à¦›®€½ À“Š„xÒÄ`ÊZîSŭ`™.¹O$Ÿ*7 ½p°¸~ۋǨ/bˆg{ûÁØ $©Øäá¶Nâ¦ÑETïá!——ÀöÒxg«*•ô‘*©Ê1·‘°T^3M’À”  ~2Éâ¦LÂhpwI9Û+@‚u÷båÚfç`÷ŠcMüSòŽ="@壻£®ŠÙ„` /þÏþa˜DJ›X ¥Q×ȉZ²­H­9QSl—¨¬A3yU?mË›.DQð·’Ò&¹nr):S\¶E&k X…á  ï S^“à”-V‹ÅrÇËÅJ`¡‰¬°Ì%ŸS²Ež£Á3òǼ:ŸJXµb3² SO*ŒÜz†çå´ÂGU?àÑh|o<¾;Y¯[Ì/>.æ@ëLj/*X™ˆ‡›Åí6UûU£”œRr®êÚ0¤Âàµë_ 37i¸Õ6Þn:³°Z²ß“M…|ÇÃq]Qö5²€ÝÙÕlùi)DœèB+v3†‚‚”9ô­ Ê"Í,aOÂ(·´;³%%;YÓ#‹Q»ïgc‘¸:Š¡ÆTƒªyãd†a4ˆüKá’à8aQˆW-fóóÕ§Z¹Ù<Î £]¡•CjÕZÎÐÆÒ⮽i.léXn&•ëc¢›ð ÌÑ:Pׂ?`w 'ã3ÿkV«èŧÅÛÙÛU¼"£) [’Zݲa™À¹‹oêíû‚=ÛÇN¤y‹!›ªKž3sÓ»glF´@ÉQÑý{ÕÚUJ«BEƒ…¼ø ]¡ |ËܲxÂåè˜/ç³ëY¼ŽÕ(OÁ,ê2æÄuZá°SÐ9ôlx«­£A8Žî¢j¿´sÉŽÈ‚µ,³å‚½Ç_7ÐY(ÝoØ%‡†áΨë{?ñm_˜=×…88ø·Bbk#Ëê­#·K}âU±K¥Lø‰µK‚“b9¼Ee_rBì¡®±löKsš™ƒøù0\=;[O/`K@†ôi°—•x%;?eØÌ€3¤Õ—Árq$3œÚÂOˆ»uYçÁž{Y UŸr3H½Œ¬R NX¢$g‹7ü®kNó™îûŽæÖ½wkº÷V’ae·.ŽÚ…¾˜˜k»ªH-3%ϵ$å,`,T¤ª4¦]]ùJ÷œéV8¹™ÁDÏSšUœUyå|°™‰˜‡;ºT‚Ŷ!n¬‚즉Û4Yݽփø+šÁ•+ó·WeœøðñUùÙ‰iˆ{ÀÍP\báWÃæ—kP˜BW2ç[nàªDÎoEW´ú~ÍÄ2§·»F¹Üü¹Ó\ÝuwÜf.a<ïék,‘ew“¶9¦¬.¬p?±ydÙm;e·³î¾‹îL‹ö?9VÛX[³–ž°&ÒÇçv¦Ý4K›5Y½¦£ïÚØž·ŽeÛ/ä)ú;…ÏzóFV‡ðŒ¹UtW÷îœl?÷G³Ç onÚwØû¿¯×zéÜÝž]•ªlaB¶dnç¢ì÷¨ž* Öóà²%;ç¸;´%Ê& >kü:TÑ7|k(ŽžÃÊ£JãÁ‹‹·ÿ|¯E¨o$äú‰>¾èÙéZa€ìüa> ’7ŒÆ'÷NÜç–¯‹–Ol>PSªn;»ˆ’ù®h狦<º:§M§$7‚þ ·(yiµ3«œ`õàÁ#PÒ_4ʗͶ 3÷Ø*ÆP·Šî9>\HÕšTšHå+å^mdYƒ3Y¢O@©næÖ+/Tv®»HµBOuofl×"$t÷J• ¶uU:‚3í£¶ŽÌáÏ•ùÉ'ôTV¤Ê½µ2/E•C¢\‚ÕjYzÆþÖ#­­Ed­ï"ñ¹{(s¸:jçØöÜ[‰,ºÛßl¸­êÎã3Vì´5}JX7òxƒsñF“üo›ôɪ²s^蜼˜•§–ÎÕ¥ÛåA{ðf×$X°¤JˆÍ ì¢Äe¬X‡üÊXSv®{`.{"@Wqwµ6‹Ðk{²Üìî"Dh]@cŠ©ûà"á‘9{CM‚·û’;lEÝS¬·›6޹:즢ø6¨Ý­¢ 1eáâØ³þe§X%•Õÿrã«‘ÚÕ]žZ™w‹Òx0¾ k1Çg¡ê­LúåHõ$Ü£=¬÷3¼E8š|=q¿_§TEsëÿyó•Ò=£tì!fÎ1¸ÓÛò» ý^¬Õã&ááâ*—`ïùn]£L“†mT´\`×S|¸³/'j΃•Nè-­ý¡TJÕ[+8vÞ ŸuÉ^±õbÈ îÛdëÞO\6-Kôñü=äîB:žÞÕ Ø âƒŽ‡Hò Åëe˺†4¾6ì ÌêÝõ¿ÉÀêªu'Vz=;\åjž—hPB;JY¬„]F–õôÄã)ã pP7M›¥jäï …¥“úÞíÆ`îè M§Èe÷svå««{ó8k·N¡«çUÔ…~9i5JU4Þ¨â¡â˧fa×ÊKXý·þÁà—e㋵̞áí–%´‘}ðŸÞ”ÁßW¸b+`ìVCKõe½“¬,†ê n¼RÌi@ËzÂóù¿Ž5Y!q‘Ò²¾c55[†]ëž~(Cf‹Qê­ œc¨FÅ<¸˜{RqYK5ŠŠÑsEcÍÖk޲`ða€}øuƃAECt‹ƒÏ#ýÛ4Š5°ïÌXÕÊêÁ»+¶ kÁg$v¾^v1›-çx@v0ÓÏ‹f}Hx(ƃQö~2<‰ÂŠƒW½?x1#‚·»ž¯xáu¶=vS£±ï;–)a4àã»'Ñ ‚`§ŠBøÄëïDÓ ÿþdˆèuì ™heH¼# ¬*à¿=Œ÷O?0´µ¢¹4Ä{A½y”‰VË%;ô:Ž ?j¾rgÇÆ`‘õz)ÇË÷OÌ1Àmôw2%¸uh/åP|#µ»§fuÌrjä3ÞicÝ^˜nËöž“m³Ê‹âª§Ír¯¬rNcÇDþË”fk#¬ÑñbûЛÏÞÀT˜ëy“Ÿ;Ç`tGãLIΔsQ —ž{zn®b=»¦—>\²´[ÀsìfÏOi.$„®æJu¬-+…_&»E¹tܨHâ#Ý$)v¯~Ù:2à¸äÆcisE°£!Í™‰1€˜åØtòtãñœý kžœ°b€.àÊzÒ®GåfL5µ-ÿèÁmåR7èâÍgá ÂÉ-ßñö^™³g³ª{ogŸ¢æ?[{õB?×éÊåê#)dš3ú¹¡ÐþQr²Kñõ¼3¡J‚¡pN>K³öÜ(:7*£vŒ™½Rï¥Ze¹öÇhÁ>ÊQ—ÿl×+Ÿ’û0Í®®u»î¦{|Löˆc%ÄØçx„Cg'Vô ŒÂ(^¯r‰sCÓúwƶèÖëÒanåY™ou¦†‚o¢0K¥õÈH´J-]:S4ˆ†áÈS‚]Ñ$Â2^^¼¦× SL{8ao~ïDÒð‘Ä.@äFÑÈó¤êgtDw¢a4äk¯öyºÕawws‹¹:7,IoÏ2'uOñ¤­»’Z\}1ˆFá¨2D¸uµJ fr-ô"^¬âU¢Ÿ.š/æ¨,±z®éöÏÒÈqZv¹*êså4Ÿ”¬æ—‰åàÆ×^­Ø W]Ånjæ®´ÁŒ8^-âcù|DzVø­~­Ï*¤}"(ø’äÌ…ØEÙjëÛ ¾3Éqü¤ä8ïÜê9MpØØ*fÁp µlpc/…ï¤]N~ ÐFóbøLˆ×qœÄ±ˆYš$§ªÕz 7Ò':GÖÖ™-’æ…O;‹åÿŒZÎU©zû…¢1ò´$² µ &$ð—¢Y?Y›[˜ÔòÈ´ =2uƵt‹šf–¨òÏèfµ/Ðiaîv.L$é©‹9IÝsžhHðNÊ~“ƒ`Ýh‚\ãz`ËM![,Åb.Ö¢ƒš7BÊtJÓফÕC£ƒ‡‘&ë$þ¯V+ØŽ#0æh÷ÁwýÒŸr¤Øz cø-Ui$ÑáÚJ0”l±XˆDý-WKÌPºG¤uR¡7¡ÝŸèßÖKçqÉ=Í[Ž +ƒ)6j“¬Åè'¶×ZÇ0=!–„Æ9??3îª,í$8eP¦ÕrEüQe ¸¸’+YÌèæDÍ®1ñ4@ŸU¶Ç_UG>|²5= åhEY ʨã T)Z«pLÇ—³Ëùõü¯ÿù×ÑÈ×éÆW-ÅØEVXX}\A±‡r¡ K©Ÿ3%Á¹¾Fz¶‰ïÕ§ö Èz Ôðñ£ÇÏží+†Ñ¦úºÊ@ÐŒ©©á„Êc3‘ߨ¶©ebè(B\þßåË/ŸþÛӬ߷A ñý°Àê ˜Ç×××Ëå6ÓJx çyrĨ€šÒÌ1‘håV4üüjv}µX<Àœ£»]ŽFx™_ÍÑì r®>Ú“ISb3Q¯¯RÓDAÛ¦rV°$xùq™È3.þ~1y8™þ0m_Èæ£Wk¹"Fá{ñÏðMåË´2­åXùeuÎÊØÆ½°j;/d²úˆIÄš`².‘9Yß8AE-ý¸ iÝlrÛ$夫3R7“§Ñ:`Àôëß^O§ÓöƒTs‚(é%<¥©ZAeõ‹>ÔbMC“Z£ ãõ­y+Ô¦ k°–²5Èÿ“&‰|•¤]~jÖl¶’B ¿ü¾¾º†VÝk;7%8Åñ>ÔCc‰MA‹EOÍï$‘°ø,°8‹15…”Ü„AG¹çÕØ|>AÉ+1_T%«(·Š•±:¶ ­×«ÑpÔRˆ ¼’Ô¢Wr­ÆÔè†f¹S”H±&›SŽFè´’/뀳`%KnX‡ã^sCš¾+Und, ^Èð-&‡î5|—|+öP4Ê@¥­Ch[P 0·,a‹1 È%"àN©&F, Zü‘(¿4|(쨂*ŽØÇ]\S„ñ¯pto8\/âËÿŽaè]Çz¾vbCî0²HC43©\dW€(C=žÅÀ"¨åõr•¬Ôioi„~\½j¿yj;¤ËÔÛìÏëéIåà Ýh®¢ãƒJhiãpñYÄ)˜Q’Ntt áÔWtgÈA‰is:B_O=`2Š\_BfŸQ`RÀ çz. ½IÈr¾yý¤Mšœ£œGßœîŸB•Aˆ¥‹ ¾aš‹ÃƒšÙ ëx•â½×\NCh8ƒ¬AÜ;Í U›,»Ñ@t:i^‰èëÉÙ? ±˜\-¿Ç׈K+c½dÒ+A‰d=ò;Ñûßãùl†«EP¿aÅ~þןO§Ó×`è‚“o'ӳ鯯~œ&Eøúƒp”.&ƒaÄÑ41ˆß Y$#)M&pB…†–ù mV˜EQüÇ«xñ–†0&ç í£ßÍU4Lþ@E£Äi&"±äWogK‘ãý;Rc£‚ÒQÃl°4CÀè²Z¡/­ÍÇÃ|oxƒÌy‚œnν¾|­Üy@ð@ð«ËÙb¦};rš [Iê$PhNQ±Áhȃ²ÃUoâÍç%Cņ^-\£swØþ° †Ë£CñN–ÏÜRI|=»d›^gXµÁê¼Æ\0iÔ‰ÂèñwgÏŸ??¹‚vém”s2™<{þìåÅËè¡5è[”Z!b0=ЋÖš'P{HÇ1(^aÜŽËøæñ ²M“³M`}||s°ñh4ùöìå?.¸ˆBžÐê!žwÛ8”na:nÔ1Ò Gûçç?>>9=½ÿÍøð•³ ˜ªþ|þóäÁäâ/ßüï+˜Ê‡kË)~<¡öåÉI¿:Eyñ²öQ®.¡ÜÚ`r÷Z¸}S4WÑ U¦ÓÓ7¿½^~\Ð?ÐïÈe!tt¹‹A1&Ý@Lj¹)Œ·?NOï Aíß.v Qœœ<‹ÂéÙ)Ø\¯{->£[ DÎ8º0Ao¯µïÖ” Ån,¤{ 'œ'“ èÈöž¬+:¤ãâ.^¼øÛj“Ñ«–Zš„Y‹{¤XS¸ $õìû)è·ÓïNA°“ßBjó "£~ «ß¾{{ùûåâê:–ñ1– ÆÔsdã,+çÈ”Zúñ£é³>ýþìF f*ÞðêÕ«/^P,ËaLá´<¿Ÿ¯'N@dÑÖ8ü°`€Q¼Z­æWóëù54ÎìÏz¸ ‡¼j¥Là LO˜þò¿@×ï$òßvM…Ì.///þ~¡‚K¤{õ²PbÁ Œ"ÐÀÀ(°K"«VÜv©-I³ôFÁïß¾¾¡¡–«%Ë=ÝÆðN†#àõé_žžžuïbѬÌB‚º-0 ¶É+ð:‘K¨éÁq‰¬»qäà*ÛçÃ$áý»÷ÀzA¢Þ-ƒ£ÕÙéäá„Z©«ëw¶ª’<ÒÀ4)(œã§h@âÊŒ»r}ƈ¬Œ/溜ÈõõÕ5émÚñ7Øõ‡Ã!5T·ZmËf³–„~Ñ šPh«j30ë©Tç8¤uÑ=v€Úoïq»Ð|äè >rô9z‚=ÁGŽžà#GOð‘ãÿuÞ*3l©?¤IEND®B`‚gateway-1.4.5/doc/alligata/wapdiagsmall.png0000644000175000017500000014227407344776077017421 0ustar toljtolj‰PNG  IHDR,û`ÆS´tIMEÑ !€ÖZ pHYs 2 2@õ_hgAMA± üaÄKIDATxÚì pUº€'23 dAG’I6ë‚<ò4@KníʲeÕ]Å»\A \WT¼¢…º”‹µµ«Ëò°öŠŠ«€È-«nQˆŠÏ› „Â#\1É$˜Ì‹Ì+L’ûOÿзéžéô<ûLæ|5ÕÕééÇéÎôùú?çô9 _ýµ‚B¡P(9H”; …B‰_¨„( …"TB …B‘ *! …B¡È•…B¡Pd#Yî ÏÌ43ð¾]ºt)LäNi,QYY܆ù r'ŸB¡ŒÈ•ˆ­cµZàêsص:-oµÕkVÃ4sr&|fΜ ù#µ‘ýÁ§NR0²ñù-½¼ %Œ$ùžhwå®)S~îr¹kkê`Igg| Ĩˆ´„^g1[ƤyiÃK4£ ’Àý›7o–;!ùÉÉÉvööv¹“I‰a•PUUÕï=Úpâø¦Wÿ F™{ÿ}°0++3;;ëÈÑ£í­í9?ËAÓÀ<;-(.Ðgè=nÏË/½,÷Ä0óçχéáÇåNEÐ:RÜ#mDD ‹ãNž<™ŸŸºùÌkúóŸ6mÔëuW®\U0áQõÿÔ\êî6¶1$Á¾‚©Ùdnjh*,)Ä=È}JÌÖÑjµ:.İÓv¹O‹(¡Ó§O———/X° t÷´©Wº¯àòºÚúºº#àC®þD¡„^óÝStèÓCTB”XA<ì°X,f³9B‡ë †Ýãï¤H¹ÑhŒ\ú)#â$488˜˜˜¸wïÞ¹s炸_ͽÿ>°ŽÍÞÆ@¬”„D   \œ¡0rWäY9I¦ò®Èé‡w< Œ(þ NB Ÿ7.\¸ð¡‡~[v lŒ \ † œ¢yhÀõÇzà äÅZ­6¸ºv˜¡c„B .[—¨¶Õ*ǨT*¥R­®Ù$FMMM4*¢ð NBpoÀÃ8ä€555_}ó9÷+£±cïž}ÅCƒÞ7‡¾ýòÛÂâB]Æm÷’V¯ÅF rŸ …âÍš!ǽº… ‰µ‘Ñhäµõ—x°I îÄívº\®˜vŸGΤ¦Ž†©F£SøRaa!- £ð NBp»bYœð«DæÔŽö³É¬³ê¼?tÁ».xƒ™{o\P‚FJ¦FõJè#ÖF‰«Vøû6åØív)âñ Ú¦III|ªLKç(,dI+„`ZVV&ü6+;륗_üîØ1c›Û&ø$çg9` ^Gk5‚ë„òóóáQ`Ù²er''&ñ¶—ÉÉ »¦”"/Œ-ÒÊ»ÀCmmmÂosssý¥ÒGgšÐ öˆ°°N˜rH*¨¨©©‰>ëPÈ’d||ðÁ¼yó6lØ ²šˆøekuZZ«~ø!hÆŒØo%PÄÅ-ñ u¤dý•waÑÜò®¢¢"Xè3%áÕ0å7Q˜`HÜé´–ˆB–„ºº:Ÿ‘D j<Þ˜›—+÷yÄ*` ¹““@> úñ™Ý+8î‘X×"Dby$’!–Ô “„…o&SO. œowwÔg‚!©ÔCq‰ ¶Õm›"X:*w*b‘(ôêRÊ»0$ò~•‰@jáˆà!•*•÷õPœ‚Ü$kjê.]¾Ì.‡ •ã3¯¼xé¢Ü 1 /`ç öîÝ[QQ!w¢b5.a×¶¼ËgæîÓ@.—#:p'ÚgHD=Ï-!Çsöì¹cG·œ;ßÍô›0{vé£<Ì®°}û?Œ¢2³3L“:¦C(œ9s†­E›>}ºÜɉ Dj\¢pˆdî¼ôD´H" k‰¨‡âB%tàÀæææmÛ¶AˆóÌ3kfLŸþôÓk…«áÂï¾ûîøñ†ï¿?V_]Ÿš–êó%VŠD¨{§¢Yã‚Q‘^?Ögéœ,Epþk^»vÙ§‡NžÜxÈ_Ÿú”˜ƒ\ %%%!!Ø*Ò  z¬ ìšh X§§§GŠ`}½^>CýÀV Ü_“”¥Á´'Ž;„6Í¢aPtà5OÀ¡ÊÙBiŸÆ, <ð 1ÈdJ+¡´Tõ·ÎLKH ô@–ÄÞ ô€'à6À Gk ææfñýsÛ€Ï~üñG®Ï222¤›,¼€üž{î¹+VDù¸„À“3Z ƒ¢°y¼ q ÷ ÆIÔF±¹"éAÖââ¶;@ýð”òËÏÏç k²Phll,--.ó:!^YœÝ.óØØñÜ ÒWfã$ÖF´°.† TBÉ£’O57¿»ó=îs¿74qüV©òrãÆ \Ðà $na»¸s|î+Æ#Ý:èܹs[·nè!‚וª,Ëâ®_·„þš0}T—ˆ°KÓaamÔÑÑw«Éd¢W›|H”Ðè1£5Zͮއy‡ÝŽ Á.Ø|KêųQ£œŽ›#°û-®ð÷¿œŸ†ôð€Ì ä³ G¤âÇç®àa<Ê/ñ€ {âĉââb‘u„Î@‹}Pné?9L˜úN{ ›X­Ã¬3òr[›ÍÌŽO©TÃó%Î'$ óŒ’Í‚§··WîS¡ˆA¢„€ººúÚš:ÍÊËqT!éNáÏ»¦jÏžU«þ0õSØõá[X¹ùôéÚÚºù¿ž/ý@¨„P‚áÁd>d¤ƒÀ RJÉÅ›,^¼â$ oèpÒIMM û&ð´$RYåÏa„{ NŠ+lî<^[ZòÛ‹Fp—Ñ:’!QBðÛ:zôØÜûï<ô‰Ål]±ü1}à+0ÍGû÷OŸ>½±± –Ï™= ‚~”Ê”Q)£ÚÚÛϵ´HìCâ Èèƒzx°Íá tàîG¼Ý?pÏÖÖÖ@“‡c‹Ífó°mêöíÛʀʼŠJôhUDT>¿òé-¡®È §pîJ¥J£Ñù³FE ¢¶¶62O'Î!KB~ùå—J¥rúôÒï¿?¶sç?ß{ïݸÿ76/_¶ <ôÔš§×¿ðüòå+wïzëÖí÷”ïjwUÕÓk×îØ±ã­ï¬]»¦´´ô¿0ä¤Ñd2ÁÝ\ÐÃÃgƒìaÛˆì 2÷€^ âEup8 ¶¤l{÷Ýw}âp yÕ'P½CB^ÏËËãþi±„ZªÃd”ÑÞi…øô–p ¯ðg)òt ˜àg”ž®S©ÔþTO´tŽ@ȒдiÓêêê***@(©©©••ï»ý¦Ó€gàR÷e‹Åú ëq×Ïëk«áÙ§jÏîÇ[ùì³k\N—ÃnlÙ²²{ï=~üXuuµD)¼7UH¡ \°9ܨŸ¬¬,È‘=d¬]]]Ò÷†¡‰”ÁTØci‚;œÉÉÉÇŽé¹nl^Y\R›Í–£Ë蜷$ˆºœ ö€ÏõìŸU„ Œ¸ÍyBjâÁÓïOîqý$‹œÀFfsˆŠ°tîÔ©S´ÁQ%!–Ì̬ñãÇ644=òÛíïïW§ª‹Š ËË—½¹m+¶Ýt»]ð)))êï¿Ñn4ÖÔÖ•Õ××C´õÍí­&ä$FFFvn}úôiœG€“°¿ƒ@÷›Ã¶âÂýÆupáÂ…  ÞEéâÅ‹wíÚ%¾‡p 4·¿¥Âç&rH®ñkøX­Þ*}ÌgýÓù ˸;çγÉf:˜¸Ù¸ :ùþ°*ÊÏχ{輻P AHtðàÁ²²ÒCŸ} ®[÷ LKK½­ö߸­ãRFzjõªwÞݹk×?ß~ûXVØ]Y)‹à—­ð6á½L(úQHx1n0ì+Â,£ …|ôÑGDµÏ&ù«µ¹! &Ó!AØÄ_ ~zýX\¢á—p9/S0Âã-‘Øtž;ÃVA“ÀL¸0ràªHØÎîP³•zˆ•ðàü_~öégsæÌ.+›ƒKì}v0Оª=ÿxkÇšÕ«–V,­­­ÁW+W®¨¯ÿîÕM¯e²¢œN½^R0Uô „àÂ/a•Ï=f³9,QȰuB(þ_KJ`Eˆâ–< ·åT‘”Ü–„)|‰Šîp5ì@‹l”PKXŽ  ŠÜî4FÏKõ9+!à_~ùÀ'}~ø‹ù>XRR<§l–ÑØîxnݳ‡£ªªjNÙœŠŠò×ߨ ù¾Éb޾œ^–ÃRšáYé*)Àí ÑR<è@2lͼZ¦R©yePLÀ¤²ÙÌ„žáú+*Ǥ¤Ü$€•“HäÄÓî“ÂèØ3ØN¡‡àV2™† ‹9ˆ–Ûí?~<üŽ¿ùöëʪʎήõ«Ää$W¿¦?\¸pø«¯`5tOôKá´´´pY÷bP¸ª|đһD(mç(QÃé´ÃGXKtº±àªk×.GèÁŸÈÎ&ƒ]^ÄÖLþb&®0HB!…%Á)c…‚[ »@Äe¡H\ AæøêÆM03)srŽÁ0{ö¬¡Ä„óþ—»úÀƒ Ûå]AN­Ëð¶k‚™èÕÔÔ„kW¨£Ñ)ÏËË W•8âˆ÷†@‰-üÕÌÃ’ 2¥—Î…¡™Ø˜ [FøtIÜ),Evè!^¤HËåd‡\ }rðü,4:í ϺںEÿþ;kz[\½¦T)ÇOœpõr7.ìhïØ°~ƒÜ'ìž8 o•8S§NvPºã£D5óX:¹HJÂPH8å9IX|ÇFHÌ¸Ž¡*â57n"õ9+¡‡ùí… ?´´œOJNVˆþ8:æ^ïÃÃéJ" ãËàÀƒ°Ø-ÊU>áҺuëV®\)wB(*r¹Ò ‹gów ‰`¹Ó¥vçâ)ä: ‹ï| 7ëx‚/©ÃbIŸ:qâ„Ü×#!TBðÜír¹þ°ê÷‡?ûâÊ•«³f—ЬlÈ5èô:«Åš™‰]¥Eçó0¢ÕjÓÒÒ"Qå3,Rš½Ñ:¡˜ëŠtº •*•½5 CW*£Z4'1© ŽT*•R©öÙê/”ÀÈŸ‡ÆŽÛÓÓ#÷5ˆ;•Ðöí[±r~ôèÑ…ùìrnwœÜÒätMú ü°º¯º]®¥R£ ¾ÿfY°X,a¬[ ˆýû÷Ó—„â³¹7)ÉÂÍye/šÝ©ðc#¶µ¨(ˆ6´ZÍZímýbÌœ9óäÉ“´±\”!´ð .I•\W[ßÝ}EÁU]½|墱óRGLaž]æ¯[m*µ 6éw»á#÷ÄRˆ–äN©l¨T4O p[¯aI ÃöDH0ôÊ•‹0åuKˆ*Òj3‚(üp8ú¸—ÉÉɉ¹r”X‡P ͘1¦éZ ~°ÏÁŽö° h&3'ec6™q}´®<&=Ýé¢c0‡™E‹µ´´ÈŠèÁëæ’­*Öaj‰z!ódO òqÂ=„@²AEèQ6ý &¤ N¥Ì¥¸-ŠÂFÛrŸh|A\qv…ùä“«¾øâóÄäÄöý׬Y%°0!1¡·Çd»ÞwíêOn·{`À“u«£R³ÅSÇ9ïknúŒŒ;'ÜÙÞJDOÌ„Óßß/w%Ö;`‡)šƒhÛSçODS…aABúï¸c·µžB µD6›Y¥Rq;â3 ííídQŽHˆ“öàp8Jg•ºûŠ¡ƒßv¯iÈ1èt:ìôZ©VfeÿÿùECƒCN§Óít)Õ*˜—û0ÃF¢&“éÅ7T,[þ·Í[ÜÿÇÞ™À5qm <„$„B „â²ÈâÚO÷ĵVý^Zµî¯}U«â†Z¬[]ªui«¸k±¶Ö}Áµ­lqÙIÈFï$cã@B6çO~ùÍܹ3sï sÏœ{Ï=G³H.#3+öàaôeáÕí@ì©Ó¦Ïš=÷Êå«ú”Ä2äN-ô—Cõ•!GGÇwž…ñž˜¨ åFûÉHWº.È+ E i¬‰Dø†md–T¨× ¹y¸Á·«;Çš`¢V&Ejj*6!ôvêÈ!¾5[*•ºs׎ä?ï<·{÷Nggg$´œ+V?qrÄÈðÙ³oßêÕk‘Cùí;´Ÿ0aüéÓ¿AH)*.¾Q×óÓ?ýôË/§>Ÿ9ýã ã.Zœ_W«k Cõk¡§‚ß=š‡Ó¬]5vU,í¬á½ïZü•ÇgffÁ‹^ø¨0œÆ«®J©´&XÛRl« ´£R…R)“H‚J{:Jµ}[¬úN y'NœØ¤S>¨9!„ÜÜ\ôøtg¶¶”7bööòÚ±ckIii73u>Ÿ÷ëÅ‹çüýÕ~•:y{EDŒ[²t1lw ž3{NÝKÚ>snôêUõ¯yðàáÈ©‘lWWØîÜÙÿâ…KsæÌÒ§0ЃãPñè@áꆪ3 tjÈ¡w.!ÒY3šPn.Ö“´.&*„NŠS©”ŽŽ xüüü|ÉCÏvž…ù…/_=ÈzèàèàÙÖ“öO4Uoou4F™L¦1«©©!X›hÕÌ—îÝ»ùå—Ó§O7vA JAAA»víÐn{h4Fk¬¤éß¿¿NJžfá¶v!W@@|ççå£óøøt‚o±¤+†²RÞýû÷+ÊÕ}qçÿ6žúzp´ÃPC2™ÄìÖÍ4CI$b´M •iìªX2&ÚS'%%âÔ‹UÕóÀY™Y¡¡¡í;¨-U8îøÔÏ/©ªâ•”Áƒét†ÃG=?2v%, =—µZ†Q†êãååE£Ó®ÅÇ2úÍ‹—.‘HÄŽ^ãã?ž@RâM–‹ú¯þéÝztuvr^òõ"‘¯gb±¸Iw/++F/ÕG0Aš!‡ mÑÆÙžžž˜2Ôª˜¨"‰xk<͆SŒ×H4<ŸÇ¯ŠÈèÌfÙRÔÅZ dO§I%RìÍERSSûôécìR˜ *CïâSè4úŠËV¬X•”xC¡ƒìù&f­…B ¸Ü+W®–J¥µ|iƒ§/Y´ðÓOƒ§ÆÃÃ#3+sð Á³gÏÔÿî*• -‡ôÎ2A”C%%/Ë/ ètÌÁpXGFF» uÈÌÌìׯ›Í~õª$//OPQ)‰{ôèF¡Pþúë>^c2ÇrU¿÷Ée2UȺTAykk‘Dª(/·µ£83ƒ‚‚Þ·4ÍöíÛ7lØP?~œÆ6¤þ¡¸¸8x=wss3vÙ ô¼hC)¼k¹\úž—…«p8œnÝ»‘êÆ¤Ñh}Ô“áàÐÙß¿gÏ|N§ùß/„S¿›·qãpÄUb–³³6‘@°öôhãççG&“;uêïïð3 Ø +<.4$dÒ¤‰Mõµ–J«(*2ù ¥…íª*‘±&o ¹‰D’¶Ù5n%¶\'‘Hh[|¡PXQQ¡Ï]0š‡UBB‚±ËP‡#GެZµ ô_¹B Ÿô´ í¡ËW¯å?Ï#ÕÿMÊêj*•êâʶ!ÛÀ¡JA¥ÖRÎC3öÍaq>(GgÍ`ذaW®\©Ÿ?|7Øzo9dñÀ»‘N'®c‚e©@­]\Þ¼v˜o­u,ý«ˆN}ëׯ»ì–Œ‰Ç5ÝØ5H»RH£» ­'áÝ3¦ÄhEÒÒÒºwïŽNÑL×KuŒz-•J%‘€>dÞÆr8Ô©­Å¡+ÒàÏ÷¯}­© ¡êêꢗůJJ¬pV¥%¥ð]‹«%“Èr©¼LZÛH Ñ·Æ[Lä1’’‚-jB¡°´´”Åb¡Y,×·Ì.X zZåÝ·é!“mQÖ®:ž~0 ) !d™:Áš¨¨U”•òÆŒãÓÉ‹@ *•Õ}?~2“ËíšfÈ}hìz˜4Ož›6C hÂbÈŸ›—g”FHÄh5ä™H¢åÌ·€É­BxŸn®“c×Ãi§RT¤—kj™M8àú¾(é3 ùÞW6[Ï’xzv8óÇé.ÁÁÆj 6Û]kc†Dñ1G#´&WU%ÖZ(p8mÐÙ°uB­Š)ZÇÆ.†.L&½+“éå>ÄÏÌ™³†àçë }·P(JIM¥Ríu&>«««Ÿ>}Vüê•··—»tôV¹ùùU·on•JÕNJAÎûié …<8(ñð[SSSVV–Å}àÈpðõó³Õ$Âé°¡P(à²AÁAΚ*@ÎW¯J>z9 M}¢ccF§;ægc& ´~Zí쨰kŽ¢ÔÜ1Q!„a‚èŒÅ!ßÉÒ¥Q7oÞNOÏ„¾þò• "¡hÚg3ÜÝÜ$R ôx¿ý§Í *ŦÍ[þ8s®W¯nÞ¼µvMô¨ˆð•+Vý•ú·­-ô•V¡¡}V¯Z…Dµß¶m‡ ™œ“ããã½oï^++ÜÁC‡÷ìÙÇb9óy|7w÷Ý»wº°Xp:¯Œïêê"•Éòró/\<Ëttü%î×­[·ùwö‡ÓÃÃÖ|½¨©M)h= P(T¹\nv+X‘).­ÛlD”꣥À†A10ôBG ÂiÞ£õ9qûö­ð}øHlZZ*H…¥QQC† :|8ö䉣Jeõ¥Ëo<'Ýýóî±£'þøãô–-›bÖ¯Ûºm;’>wîl8÷÷ßO=|ôx÷Þ}HbDDøÁ?ŸŠ;~õJ|NH“ìukc¾Û¼ñÂù³W¯^$Z[¯ù'ž—wÇØØýG¤ØÙž={„_LÌúeKÿ´oÏñc‡öìÞ[øâE3DÇÆÌL§U$±ÖBAã%¯]“«­¦±Ëhá`š†^è¨AzŽÅÕ'3=‹D$-‹ZÛJ•ê—ðúPF‘Dünë6œºs”ðxîäì”——ïáîÞŒºXÆ V´ÛlÍA©¬¹±@¿ˆ´ÍBz¡£ ©TÍìjitZŸ>½Æ‹ì’Éd‘X¤=D"‘¾øbQ3I£ªQQ©Tô¹ ™ŒÆ.[)¨ÔÆÂ)/¯€”s’4¦ÿŽüËIG|áÂ/éö [LèzZÅL'‡d2©Ö%™l«Tb½¢A1?õÃ(èhBM jG£Ùs³¸……é™?äð±—/‹RF÷Îdm¶!ƒ+äŠcÇNÖÔBϨøéçHzII)ÇO¼qóè‘caá#¼œ+vý°rþ}?mÏî}?žÐ`N¯Ž^~þ~›7~·¡uíjÂË¢¢f7‹Ž …jvkn  ÚÙ,£66dôQÐG]@ ÇpBèÒ¥‹?ü°k÷îÝì¿yë†\®^š?U•îd¦ …¢±ëÜ»wËÍjFà¾è]±X\[[ ¥Êyžc°F0 PñâWozh=¨u‹ßÂØµ44 EVì.^¼ð»ï¶EŒ—=oÞܾ!Ó§>hÐÐM·¸°]ðxk''&(l6{Çö-×®Å6rìØ bÑk éÒ¥Kƒ]¾lÅĉ¦O›)_kÒ†lùûþ111qР! æ>ò? æãÔ‘ñhZ·4Úí;·«jjF;2lôå+WŒækB8‹˜z‹@‘Èüâ'™†['ôMÌ:;Š]·nÝd2ùí;·¬ÔVCËx|Þþýû£W¯Açüõô/ÎÎ.ýúöW‚b\ÏxôÈ‘#ŽŽŒ°°ð¦`òäI'NœÔî.ZüULLÌæÍ[úÒ;Ä0` âŽLÇM›6ÙQÔc;.œOKO[±|¥N6…BN"5Ó‡‚NÛZ$Dïê¹BH‹PXI"Ú 1‘]軌†#x¾zUìèÈDÜœÿëÓÈž=zLú)™l«ãs¿ŒfO×3'ÅÖŽBiÏiè57æ¸rHgmÐë&âñ­‡A_X¼½½ûöí7tèеkÖÙQ©ç.œc±X‘‘j—Ì ýdç*Ú¶}+´v…€Ÿ›§V !Q»‘Åͨߞ𣠮U[«$â¹Æ®k« 3!ÔŒ×4]+ÝÆ$Ncn #E ¿ž¡7œ˜Îúçl) Às‡v„C§¿—vex´/ÇÔ `4­944ô¯Ô¿^ïÙ³é˜õëââN}ûí†;wn_OHºuóÖùóçn&Ý<—–ö÷ößgfd,‹ZVÿ:׮ůY»¶´´dMtô¡ƒ ò ¾úê+è%ÓÓî¯\¹2/7wó–-/]À©!Ü"!>~óæM°»&úíEž>}½fL*Y]VVj¬6i=>ž0ÁÉ™¹ë‡´ö¦H›s¹âã¯]¹z)>!>ùÏhíÌÌŒ¥K£ä YròÝÅ‹—€ÜJK¿íV¿=—/_¿´çó\µ¬QôýÎOŸ>5v][ !ôèSkªŠÎ,…iRS£Ö~´»f79¤P4à»›2F³©Q©ÿx1QTËJJËv}¿ëçý?vôòÎ~¦îÔz÷ê––¾aý•JÙ½{Ï’’’%_/iðRC üøIp×®!½Cnß½óâEÁ‘cG£¢¢ÜÝvÌ8c×ÕÒX¿~­¹ôæð¿„ŽÁJ£9˜Qì;©TJ¯œY©Tbš0Ž&$Uþ~æŒ6X² ɶ][Ï Ö?yò¬³gm6•F»W*«÷îݓݴ[…LGõ <ªÔr3++ª=o]§âÖk*•joGɇ.€%amMˆ^}=1ñîÝ;8u›Û(är*ÅŽnO7n¼6hH ƒcc–––-\´t —/‹ƒlO†ƒ£Õ?ÄHÇVöµ8Ì4km>ÚÒÌŒbÕŸÍÍÍ5v¡> ª %''WTTàñV))©:´8pЋ…È!¿¼GÏîaÃõ #htzqQñ¹ ç”*E~~ÁèÑcáU¥B ïœMXxø¶íÛŸçä > §ž‘ÃÕÊËùÎL'†Cáø¾¡}ccc]Ølè—Édrûöí Ù,ÃÞž¶v͚ŋûwöwç¸ÛÛÛçä>wrr‰*{ý_/2ÙÚ§­G›€À '&sÀ  ÷  ¶§óæÍ‰‰9qâøäÉ“Aà»®F£²²ÎÊ!PãÌÂO}¨ÂÂBcêƒÀ:22Ò0w²³£Òéd²-F:lȈaðo ÿ£®lŽH,ºqã¼k'$Ä“lˆ¾¾~‡Ívõðp+,,èÚW«Öl|||H$’§g[8ªuHlkk‹ìÂõ===í©ö4{H‘ ÀàÚZܳgOacäÈ‘p/È»îS¦L±±±¡Óé:t@ÎêØ¡£‡‡{NN6§®]»6;ÐŽi5õòòB*ßµ[.7·ÐìgÙUUâ>½C ÇÀ À'uêä éîáÐ9NÑnøúøê´'Ò€Ú[tìèòâÅK77Ž…5 Nmú¥F»[] ¯+Rcªi$$\Ç[ãóäÝ‚€2]S£"“_ko¶¶¥šjc7ÀÛ€Ò:Ô}1åñx%%%Æ.×I„r8{öè GŽ ç>àÞ¾usÉ’eïM ŒD'ˆÚí¿¹Ðàà… ÿ;*,Ì0·sp`j'‡Lßb›ÉdéX¤¦¦bB†Á$Ö” 0€WÎß°a}JJò¤ISŒ] Œw }kßBQ]“óÜØm>:¡KMÙb„e}ûCL “»··§-˜÷c—£Qx<Z‚^µy׋E9Ïs;´oŸ‘‘I$ºw%ÕÏ D"¡PÜ%Ø…ÅR(7n’He“&Mtvr*ãñü|ýœYY\dûÁƒ‡.l'&Nç>|TÁç²]Xˆ…÷Á_ŸôÌ,"1 ๠\üÉ“§îînŒFÜе ý°X¯cQ(T…BnÓv<¾É? (mõõ\k¥E¥¡µkg‘˜„ÂÀ0qZê½øÑ£Ç&L8°?ÃÑ1)ñÆôŸÍ›;»²R0uê ‘Xܶ­ç71߯øù^ʽC‡’ˆ¤øk «¢W|³ný²¥_3:7//<|ôŽ[‘íñã?þõ·SÊêê¹s””–2™Ì¢¢¢¹sfO›YTü2bÔØ9sg%^O*,|‘˜:Jo×â¯ÿvúTk7ZMJ(¬Ðvñ°!•¶ºÅ6›íÖ"× ù{ç×ÔÕÆñ°gH˜‘%ËQ*ˆH­q ¢Ö*Îú¾­VP»ÞV[Gµ-jÝ£}ÅÚ¾ÅÐV@Á Zm«V@AAÙÊH€„=Þ'9ôöš e„$ÄçûÉ''÷žœsçwç>÷Ÿî­¢’'¢O›¦¬(Ät\W8~:êçÏ>Ù±ãSê‘a==½ bÃ#¾wÅ­ü}⫯Ϝ‰ ûÆÄĸÇõï:`}è¡qý(b‘ýF„!€¢_’šRú¸T*EÁH×ÐÑcä¢`'ᦢ‰I‰çÏŸ“w‹e„Ø>ªÌ^là zÀÜܼ¦Zh°îÜÎPSWÛ²uû†›>ÊRV&vü‚ù¯d¤ßIOO ûnÇŽmT:8(>‹ÿ÷kËɳD¾¾“\Ý\®\ùœ8ožð °áÎísqã/‚ÓÚóùN›»Z×^#¶œØ–q¢ Óq õwîW!³³³g³ Ɇ»yy¹òyöíùÑœ›—S\\2Üy¸‘‘qccCaQ—+\5ÎÍÕ]]]Ë«LKK³°0þø“iÓ¦ øxxŒÚ´yôØç{ö¯væDÎýùÌéòòJ55U-M°“'ÕÔÔy<ÞXﱿ^þUÀdee{é¥ÈȨAC766jkjWVr_ž7wë–­Æ¢éÈÈ3›7o¹xñRJj2ôÈÎwß}wèäÝ%Ò®„ªª¤S”ÿôéï¼óÞ„ñã½½½åçgdd¼öïegç”–>ÎÌÌœ8qÂâÅ #ÂOýç½w444éi†Ð'Í;xè°­­­‘;<âtMMÍd߉µò8Žûòµ×V¾÷þúÏwÕÖòuuÿzÝ€ÝÐPGÙ£>";'ûü/çûºi(B½GAE°µ³ýäãOà?jõšÕ Bp}ýúk+ÚZ[_ý×rðIW~ûí¿_| C¤pyÍS/¿<ÏÑqØ¢…‹’®]ÓÓÓƒ«r›5ÒsÔ¹˜sÏ›-\´ÐÇÛ:ázBBpÐjaTR]}nNîØ±ÞL}ýÁCt}ö,ÇŒ£¦®îääxóÆ J„˜ú̼¼‡ÁÁÁLƒ±Þ>d× ø+8::¦¦¥DG ZlÊ1 ^µÊÆÆ.&F8ïìì´lÙrH‡ìü,éF$|'ù‰•••ùùùÊ!B’rªªªÝI5459ŽXzêÔ) =û÷ܾýË`åÊ×!óÕ¥K׸ÑßfÀìY B®..c¼½- „èi ((HK[{ÅëoÀ¥˜³³ãW_…7”4@áj´W&&&ÚZÚyðྠà5»÷ìݼQväñx•ÚÚºÔ2  CýnV¤P\"€öhЖÓPQUmjl¬««…±’ÄbÂ(×ãÔ0òÖÖÕ557ëéê° Xðrvt’w#äq[[Û¥K«ùÕd¬d± ß_÷>XÌšÕð\G »ÈÅ•«òÐÉÛ·m_¿þïåb ‹ OŠðôô —Omg# ¹$gˆVhký{›5UõƆF†R  Çd²»ûȪ›«ë×%Óo¬\±üÕe<—Ã@rFŒqîl$\@0™í x=¦§§+™†ÄÚ5«W®xþ/Øìö¨k s ªpÂéˆö Ÿìíí/ü"å] »‚\"¶ÅGqª«ª£ÎFyòDëâ¥K¿\hÈÆ½è“œ"üFxݽw:_Þ}ÐWˆ-ì/ÝGVµ´´(¢r(bˆÄ¦Ã4u0¥@Š ‰Ø¦Þ²Ùƽ‰0D”Ù­×-ªªxqñqÖ––vöö áÇ ¢0¦ˆ$¼F{ÁˆÀ­¨˜:uš››»®Ž®‰±±¹¹9IØØØº»»?ÈÉnin3Æl“¼$;,­,ËËÊZ[Z–½ºÌÆÚÖÆÆ$ÇÕÕ•¡¢â2ÜÌËc2™®nnÔº± ÆŒ ''§q/Ž4hPEe…Á¤‰¾99Ù†lcÇÔÒÊÚc”Gþ£‡öv¶¶vÐç––VNÎÎÐÛPÔüù ŒŒuuu-,,Y,•w¯HMMMúîvð³jz°ÁÝsKSS“šš:å›utô ¥ûLfû-ýv:¼úºEK/% žˆ¾þ:¥D!ÖŽ“äÑ£¼#GîÚ¹[ÞA§Ûä»¶–÷6º…ªª5)ÇÝ+‚>”bùÔ.Ýaß…üþd_7çBÌ’À‡U{Œ‚Úa›—áò®‚ˆSöôC<ººú8§Ô-$&匰ŸsôÏÏf­\ñ†¼k âH^í(îÒœŠIm­€’€øœ£ "„ Š ŸÏG3Ô{ª«ÿ^F:°¿ì_ŽôøÏƒ ÝÍPï›”ë}ªªª˜šÈ»eH·Qôç„DÑ fÈÔÔ”Êᯡ¡¡_lb­8ÔÖ {¼ 8µe‹% L×ÑÑíú¹ˆB"„ ÝÌ]„²ZŠFÉ ¯)×Iª¨¨Hnùƒª£4àt‚tÉ;Cd)y׫Ÿ!ZS®ÝýtÒzzL±—¼ëŽH !é `†Ä6wÐÕÕ§ÖèDºHuõßxvâ6Õ]¹ABžfH2BÍ6Â@¯nA7CŒŽ"Àu±¨úúú’’y7é6xOAzHAA¾¾¾¹ùS»…âÍ¡îfˆÚéÌ=z»sDíêK®ˆ‰ý9ÅEAzNVV–©©©:m¡w555SSó²²Ô¡.BÌ¥Cô]$mt8•Fߣàt‚ôŠ””±›CD‡ð Ö®Óá!ITÚNCÞµF¤þŸ H¯àóùÏÒ!ŒSè"bw†˜L¡ö›‰ÖïV…_…@Àonj"oëëëÛÚžòÇMMÔ/Òp°ä /y7¥Áé8é-D‡FŒ!6/Çf1D+mË·zP˨²²¬÷Eõô;CÚÚ:MMúššOí>6úYÞÕì¼*îñÐãOÊž0õôç2tóG›/YìæâNù9|ä°““³ßd¿Ô´Ô³ÑѼª*;[Û+VhkéÀ§7“ÿŒ­ªªjmmussŸ:eŠ¥¥•¼›%}Ð !ˆ :Ôô×5/è‘‘©¼¦æTTTÀq8–0¬+¸-{fˆè7tl¿³A»víÒÖÖ~ãU.®®ååÂ+€ô´Ûû÷î/,î! Ž'ìä·qâ—>®o¨ÛññåË—khj€Ü’O>âìä¸ ðå¹ó¸s×Î Q´#ÛÀý,]²t÷®´Ô4øñ wv¾“™!)§¬(ÜoA”ƒ¬¬¬ÌÌLÉ©9‘"Ѓި Üp.X(„Dt"?D‡d31Øõ†t¨@\.·Ÿ*p÷^&xŸ‚‚úGùÔ¡mm©·RArìì }aHaaѬY³²2ïþzùi>”ÃåV>ÈÍ–w›ú L@¾¢´´kkk±h‚šmmË–––¦¦Æúúº††öy<È‘<k"WZZp–¤ÿQuÀÁP>xð`zà[A´x¼JEˆSx–†¢[&=C__ŸÃáȱ]ßü/ÌÄÈØÈÈ(1))0pAg= ªzèÐ!7WWU•9V­Zean¹uÛG»wï9s&Òf ­@ÀøèÑK/½è`?XŽ-ê#T.]º$ï: ˆ’b'RÔ! H’™]QŠººº¼¼<BRɰ=t¾¨µµ¥‹eJÑÒãz4*==½¼¼¼ëNœ8Q. ÉAÏáóknÜHÊÍÍõôíââ 9ñññcÆxÑmPzzšžž¾ƒƒCIiñÕ?®¶´4ñöÕ!ŸVUón¥¦egß³´²â˜q\]]©eEAd(•••©©i×¥¨gÐå‡þíêX®òòÒWŸÈÐÐüœäGÅÅÅ$]PPÝi(Å!¤‹à=!‘|>ÿîÝ»©©©0Èv>×K L(9333!!AL†s8–¢Ûdw—ˆ„ð=K —¨z‚ƒ” ™C” tB" Àf³ aí7íár¹<ORx$y–bˆ,QMMU_ÏΑ5„:”0=¤`‡ Bò»e2 W{P+S$ *Þƒø"ú®ß”¼Ä@ùP*‚!€ùHGGçYgQŠ)§ë_Jü ñÔ|y¢¶¤ˆ„T|x‡®K,vÔˆñŒ¨ñ!!‘8ògYB‡1°z”;±¶¶ÆÛþÊ Š‚<§•ÀuÙÚÚêêêvx ¥F ZÔ8ýy&:,VûZA ¡©© ¼ñdÒã9¤"„ Ï5äÖTçRD ¤¥+Ó D~$çß$Á¹ç!AÚ¥ˆÃáØÙÙu.E½¡¶¶–Çã‚®3rÏ(B‚´óXH‘¡¡!›Í––íE»u"}FÔEH)ABä)ˆA‚¬½Þˆ!|¼´{‚ÂÃ. Ôí¡óäÉ333†(gä”!A:†ˆ]¢EEÁ$ux<‘ú¹½Ê$"ÄÀ9%EA†i©KÁ9¥׎CD¡yòä I9yW‘2(B‚(4du"‚µµµ¼«ƒH!AšÂÂB*NHù@BDÑ¡ïì ïº REAE‡n†¨ÇWåEAE‡ŠM`ˆÂä]Dš !¢èЗùA'¤d !ÒÀ@meEA)ÐÚÖÚØØ@Ï·I½mkk#kù0Dô¢e~bùrÔ†Š‰*(è°ub= ¬®®njl”}=ûxA ˆxôèáɰ°>Ø@vk…yçÎÏÑžSü¦‘ng¤_ˆ»ðþÖA:*úŒ¶¶Î ÿ™Ôé7mÐÔÐd×2 ˜=ÛÁ~Xùô¥$7„íkjëj¿þúDYY™@ ˜å3vÜ‘/ŽØÚØÌVU^ʃÄFEE®YýfEeyè±ÐJn¥¶–vàÂ…ŽÃåòé/ BD Ø´}›—’šLÞÞθœœzúÔOTtõ¹³g--„›ãÕÕ׆ÿxêĉ¯køÕÔé™w²ÆOÿÊ+¯¨««‡|Ò¡jüËXXYYɸu‘Qgrsó–/_>wîÜ‚‚ȹwïþ±ÿ†þñûï䀫üoóó…íÞ½›Åb{yyUUñzó½Ï(B‚HUUÿéÓ"##ÉÛó1±3gÍlji&²zsófò„‰ }ýÚ5SŽ©‘‘Ñ•ËWè%86j”G@@ åÜÊ É¯(**¢Ò26CÕ¼*¨0ˆè/ïÀù IæÔi~ÇBCSo¥ÂëËcÇà-Éçr¹œ´™>ÝßÓÃS–õì !"ü¦L¹w÷^II1HNbbâtÿiþÓÚeé|ìy7w7sŽXœ3‘QsfÏ^°`~tttSÓßwMJKƒÉˆ‹‹333e³ %Ëo¤Ýb‘±šî–vàÐÁÇOJAnIæ ‡ÁK–,Þ¿o¼/^oIþìÙ³ÃÃÿûîdMMµšÞòøP„‘,6(Íå+—ArArD²t¿¸¸(>>~òäÉpLzzZqQ±ƒ½¼***“S’©Ó=ºuëÖü‚‚Ímêpì–£hm³gÏç%ÅÅëÞ_—z+…ÊŸê7u”ÇHxMñ›BeN›:ýwÞ¾zõÚúÖ󪸲¬gUA©áçç÷Õñ¯ ±déF»,¹;~¬¹¥™LLÅÄÄèèê„„„@ÚÀ€yú§Ÿ<=G“{ûÛ·o³±±ë¼|0CššÂøpB÷ïß—Y»ÀÀY[ ܵsWèñcG =NòÁ­†]5á`¯ÿ³w&pMû„! „¥l e«ÈæâRm+‚Šk].>»iÕZoÛgkïçºÜ¶n×½½mŸúj}hííSk«ö¹¶Ÿºc¯"¨ÑŠì„„%!d7dìñ *KNNòÿ~ò‰sæLæÌ™àùå?óŸÿ$މŽY¹jÕžœ= ,´èw@7À ÏHNLFzÓÜÜœ24ç 蹋cFAéÊÊŠýveÕª}üz­[¿®ðfáÍ›7ž¼~²1dI òÕjº…ÃGTVV‘O¡L»íú|NëæÆMNJ*¯ ¦Á4,!ú dŒ}ilSSñ\FØGŒ]ŽŸ<Ž £Ðp¢üócF?v<:*¦×òòòª­­µÌ}ݽswÏž=!Á!7nÜÈÈL7_øÛ}ÿäºq…Bá¿®\™9s†eZH_˜ÙÙÙT·ÛÁ?@ÌåºãCGGÇØçb‚PZ¯Ó§¥ www' ‡††¹¹º ÇCmfÐét„K‚Z­&¯`í B#8Ýåæ­ááa"O…R‘’š2>sº)±T*%ß —Ë•EDx{yJNf±YÈÌÊšÞqÅáÔ©ST·àI9r$N §|nnnŸÔl§OŸ>Mõ-Ú0' ‘£º-@" GÔ¶|ü Ï€NP¸dè@„ Tyiýˆ4ƒ0†`ƒ;DšACà›`ÀbU°¼PÝ àææF¤£££­°ÂžQc„ª«SˆX èQ"ô´ôyQøÿìŽ(,!°FZ[5T7Áªqvv!Ò½ï+&“éäÄê«Úzs/vˆX#·K,·Oñ“ßõ¾¯D"/±o_Õö´DFÅZøŠV Ç@?Z5í''ø1McàË£²+6‘ 9ޝV«ÕétT7¬ ƒÁ@¤‘S]]Iu‹€"d X,›Í8\ücÝoÈTFFeAŒRYï'˜=¶ˆP?‚µÙ:nFzV ñY¤LX”J¥B¡°OoNèŒ#“Iu€ž"Ô/ Ùè¥ötW-±”¤¦¦l#ÀžÑëtNÆ(ÚB¡GeÅ}ª›ô¡>ËÖ»áÕõÈ*//¯®®)ì ¹¼Žpiè‹]‹‰™ÒË®§’½þfh4šÖÖò)ggŽ‹ËƒuL¦¹ï]T*•J$"舽ˆÖ¡P(ˆLÁ0‰Ú„]Ôžd¼‹ÅbÉd2óòÓÖ3 âÐ©ÆÆiGGG‹eÉŒ Rtýúu˜+²ax<>ÿÅ1t¤©±A©TôUmd9@؇5–Ä–E ö~Ť >4ï €äG,£§ws?X{èNËxJЧ&aY‚Äç »S#Ô†ääd$¥EEE`Ù$èÀÝGu+z޶µµk#;ÈÙyÐZcƒ"„…Y<}21câ @V#t¡š‘µZÕÒ¢êötW!R£ššJ¤F\.ÙFD 2¨©¨I`@ lJ„úÉ'€ˆ´Õ¨;¨Ïå§sý d¡_È0ê,EØ$*..¾\†l–Ò;¥T7áI éïKðø|X¯JSlD„¸\.’Ÿl³H8<Ö€Lwû¾å§¹¥EÝOòc6Œx<‡ãÚ¹ñR©T(ÛP¶Äü…ó©n“rìȱ~ªY©PŒ ÀY,6Õw ôÚ‹›Í–ÉdO"?Xo4š²S‘Æ3.D>²0O©L¨~…Bnù!ÓØ¨lnnäryèer u‹««ëÕ«WA‡›bÛ4!$?È1ãÀ ù0÷÷Šg\ˆCda0:§¹¸¸pºœ€!>‹ $ýz¿[¶nËÈòG¬¹¿._¹dÉ[ûö}WRr[«m5è ø'áÐ!CÏ?g0´­ZŽ+å¬X¾";;ÛÙ™îe`B\Zêpt_ýÚT°<è(1°ÐºŠ—ËŠŠ2#?èϱÇ>i$ç4%’"ôê<ð…ÊÈå50€._þmذTâð×3gæÏcذ”ÄÄøŸùåzþõ¹¯ÌAùáá²È¨È¼¼+_}µkË–­(ÇÇÇçüùó›7oR6(¿þúk‘‡(6æ¹þn-X€GØz´¡¥ùûûK¥Ò.Oa£+Gß^׉¾)B‡›ê’¨ÈHô~¯¬¬ºª:!>gøûë´­<YEDÉ9sþãÊ•+G®(¯ DèÚµ¼¼ükÏ%‘ø——ß¿üÛe??ß„ø$MkË;¥ímŒªêª™L¥RËdêÊ “æ]»ZQQ9xð`±·Ï›B¡Gnn.>¤ªû˜Ú4!33@–q 0z¦uÌÁàaºþ‚3a÷îœcÇOàtueuwÅP«Têf“Ìå+—WUVªUê¸q8G§kݺmköŸ²Ï_8Ÿžž¾båʉ&üßOÇô:½D"Ù²ykjZêÒ;AAA6løâ‹/Ïœ9SVv¯   ¸èVBBÂêÕ«7nØtðà÷,g6ŸÇGr6fÌ‹–ì l:‰R ¸¸¸.‡à,ì@ ÓY¸¤áaÄþCûy\3%õ«¦MEèûŽO}ýƒ…åŽL'ww÷ÆÆ†ÌŒÌÜÜKŽKcs“ ÿ‰“'çdg;2™³gþ©½½ÍÁÁÑ[ì}5ïÊþÿÝÿ·ÿöî;ïŽ9•D÷_rûª')1iDÚC›ÔÁ„XÚô„6"ÔYÆ)ÀJ4xPÜ€8½fÝúǖǃ‡8=~üxœ Ö90>XöÁ¾½ß”—ÃçóŸ•E üa)3O<ž{G‡†—^|éÓmŸˆ½|Üܸa¡aÈô‰Ê$~†qÑ.zg:Â# ÂK[ ô¨€XÚ4„^RÝ)N§“ËkìDz94É”J¥¨?QÙŽ?:XXT7 ®©¹éâ¥Kyù×nþû†ÉG† Âvf¿”žŽÒãÒÇž8q;{þœFÓòd €þ¼´é3;;›ê6<†î=^Šº6»  %l‡††„††:9uزÈj‘ÉdbÒúY‡#“IýüüÐQ‡¤¤dT€8+‰jkkX,½^„dêäiBøøø†¥;×}ð !|¾ 44ÌÓÓ—G5DF>åèàÎð•JeüÀø  g|}|ƒ‚‚\9®Tw- 4‚Óµµ]Ìù¹ººq¹î8³7‡êö>)³gÎÆ‰µZ¥jî]eæú¤ËN³X%=ÆË[ŒJ#¾:åXûpœ²7(!!|˜š’B¤%~<2Fàa§QG¥§%ŸÅñŠŠŠ%&2½<½3Æ'É¢… à Çø èÕe1 –KK…è†UÇu©@mmmv¨@½¤¶¶Ê`Гs$ ”ZÓØððQà!ò¤º9ÀScÕ"„£‘’sðÊPP §ÅèYÞ`’‰žêv@oÓ‡îX¯ _ë&™È¢pe(}A"”›{I¥j‡òzù­[ÅÄuuu ÷îÝCïÄGPº²ªcý9Êonîb¿UÛzñÒy}NãÂO…•Š›Í7ÉD ÔÙ× X·îï55µæË´··/zkñåßrñáúõkSRR5š¼êèãO>ª¬¬ødÍ'kÖ®n5n;†ÞQzÓ¦(òóòó:×¹ûë]û÷سwOÁõ‚¢â¢;wPÝÐ+¡Î#Ev2Ô`§u:]mm­^¯ÇiDcczoiQãY(L™,ÜÙÙ%PI¥R©V?p›î˜Ëéý÷ßCºrú—_êŠÜÜËþeÙËÓ¦&''mß¹SÝ¢Þ½ûbbco•ÜÖ´¶VTTr8.«W, Î]8ÿåÿ½dÉâ:¹<2òYT¹‡Ð#1)áÔéŸwîØùÚ«¯¦¥¥ý~¯ìZ~ÞáÃGF=? 7éß²eÈåõèЕ.IHHäp8S¦LC…ëjëp¦ZݼÿÀÁ©Ó§eMš¸}ÇŽ{e÷jjkç½1OFu×`¥X±ÑìÇaêÔIee÷×®ßÈb±JJJÔ--ßí?àåãíd Š50.Î×ÇWŠ—º»q7nÚû\Œ—çCŸÔè˜hô.‹5M``àÕ«×Ξ=çOrÅ~yú4diUUW§¦¦¢ßŒ³fÍœ3gΠAÉä¼½Ä+V®Dïæ›êj”(ÿG—”–2>}úÒÅ\™T–”˜¸fíZGê@7X—¡Ç¥‰G\K‹Ú~œõÊU«V8:0~øáǘè(7Ž[Ö„ ³fÌˆŽŽb<ŸqÞ¼×·¹sö¬YÝUU\T$ò}òÉGDfbbbcSÓ´©SÔÆÛ¯Ì[\|kÁÂ…&}Îr2Ó¨—Ë7ÒÔÜd¦ýÁAA¨‘£FÊÈÈœ0!}wécÇ KKýì³Ï¨îZ¬ëšêl555ô¨&ZRX\tò䩪ªš×_“øKJK7|°ì/î\î’w–x…ZÍCspÈ!/Ϙ–бPHH0²œåÁ7ÎÊâDii©²¡!ïZ¾J­zyút,`¨Ø+sçdfvÈŸï!‘¼µxQB|"Ãh?!ã‰Ë}™Û™ÍöõígGùçΞC/”ÎÊÊJN„ ‡0Œ€x<÷ŽÂ>¾îîüôŒqÛ¶nã¸rä’ÀÉÙ“ƒ0|øª»°eÈ ±¡R© ºEÀSàpêÔ)ªÛðd¥BÑ0ŒfBQGu»,ŠZ­F‚áì쌕J% ΄ÖV³³KwõŒñüç_|Š^òÞæÍˆ=u:zíí퇪Õé´x.·¼¼¼¨¨¨¯nÁhwuíp-1´ЗÈus§º_éA°œ¾y#¿s‘È ÏÀ#^Hêö>)ÇŽà y]m?m~Û›K;¶ËžïWˆÆß1bá«SŽYBvna\uÝ•4£@ˆ´´Ô91™^^è×à O±!TªFd ÞD‰¤¯Dˆ| LG&(f°êr6H9zʇ.»]ZªÑhæ½ñ:Çë\È‘sÐW ÕÚ…ÖƒµˆPç=vhõ!Èâ‰0ߺ­­M¯×“úÐW`‡CP‹µxÇ‰ÅøƒdT*{q;Àj± b³Ù&s!v²0Ȫ0ù4‚xb@äÚa"Ôe´lªeû s“|èê »£t¥^.Ç ˆÜC;¬bNÈdw5“‡#ÐO@\Q€rZZLãä:::KŒA{;~ wC«m5:þnÙ,ÓÉ*_@/±ŠoÑÄ‚±¸î‰úwÄ,66¶»Sùù–^<ثׯSÖ+ ½ªYÍãw¸qÊdÒóç··µŸ¿xáÛoÿ©PvD.öyNšœ5tȽûö]¸p ©”A¯OK69+ ‚BÑêEˆøÕCcqÝѹ¯úOOذ(Ó§LewY\¸`ñ7ßä ´‹qÜwlß¾cÊäIÉÉIè°øÖ­Ë—/#º¿Ü_"™4)«ººzéÒeƒ’“©¾  WP/B~~~äC#&Ó‰X_Œ…T·¨—·ÃD·Clÿƒˆ|¶#Ä{m]-‘FÔT×lܸiÍꇧ¥áœçbcñv‹ŒŽ`Þ¨$zE<++.¾"Dw¨!`BèI¨CÈû= ‘§Èl# àl„ñ¨¥Ô@IùÐôB ìX]Qqß|±s/ ?Ååryîî••(™(ó “·¹¹é~y9Q‘_¯¨¯©é³%½Å¾zƒA©¨ï®€4Bº}ÇÎz¥ÂCÐÅðã¤Ißxý5“ÌÆ%霙Êkƒz2¼+‡‹O Ió4}¨4ĸtMuÕÃKóÑå<Ìð…Ñ/”•ÝûéxGàê¬üëªyo¾þ{Y:ÌHÏP«šþ1>>áÍyo¾òÚ\¬U/¾ðbêДß¿‹îåÄ©ÇOžÄUùž^^»vïÊ/(è«>ôò«š›È“Cd%%‡KÃÖ¬Y»hÁ‰Ÿ_[;£¦¶¦°°päˆn÷Ñ‘¬8³ap…NX€5`FiD"Qïë×h4ÄL;ÃßaÜ ÊççwJK:ÊÅ…óØšOž:±ø­·±5ú×3¿dMœ´iëfdý¤¥¦¾ýΔ?!s|½\>jÄH\ qæÜÙœ½9á¡aïÿçRB„ˆüŒôq)CR°¡zØlv³J…Ò\77œ0I?‹õLpØÝ;%]ê‹å´aýú¿®X1ÁB‰Ÿ¤½­½F^`F„ú"Ø/d¥A2CÞ8£ÿ”ÓbĤ<¿/BΔ޽k0‚´ZÝ3AA‹Þ~ëËÏ¿Dʬ¢»wSH06nÙ´ôÝ¥„¡KÄ PZZJ®ÍÓÓ3B10.îÈOGÑa„L6!sJ¨ÔªÿÞõÕ˜çGkuÚÃGŽ;–Íb8ô½ù¶5(®®n,ãât¤C^ÞâŠò'ž;ï³O·’Kz{{mÙ´ñÿÙ;¨¦Žý‡¬„ÂV1b%¸ UôT­ Z»jíë&Z«Öþ«­Zµµ.­Ö>­ÕêkO_=¶¯=u·.Å"jmA­Z­mYU¶H „ÿ!WC¸ ȒܹI~Ÿ“ù3¹wîÜ ¹ß|g~3÷Ö­?ËÊJYhO?ÿèè>(ÿùé3`ÙÉœº) œ8q|ÜØñUUUgΦ£Êe\Ì5rd°áßÿð=z÷™§ž¹yëdAôzÝÀØXÂßÄÇIƒUUŠÿ|õ¥yQ1Ñýø<—Ë“ÄHnܸñÆü)oQ«ÕS’’¦LN:zìèÚÕ«Q«HV¯]ûЊ544Èå²ÐžDÒÛÛW¯kR@º2r䣤Q¦TÇ`Ä™gFEERßž€]œTšvøõbÆ¿þõbC}ý’åËÍtiKÞ^ÒdhÊËÏçr¹Riü;w^K~M[§›6õIB„ÒϵoItÇ!=ØþɶìËYjµæ^Q³w9wþüK/¼ˆåÐáëW­Ý”²¡Î¬}ÚA¥R"Ióɇ)Nˆà0Ø[iu0OÒ\iÚé奬Kb1±ðÒž¦¦¦ô³Í#=ÆOH?›þÕ×ÿ%öܹ}GX¯^íå-…õìÅåñø|~^A;Ï=<, ;bøðrrD^¢éÏNßµ{çŒé3ÿ¸y“Xbç¡”——±ØlS„EûA €Ó"ÐRˆ³½•F©D·Í–û¦Bá<¿Ç‘û1a:öãь̋h£OTÔ~0å>rD'•·1kåÇJÌIžÝØØ¸s×N¤m›·¦$¿ü*ÃQYY¹÷›}Ï>ýÌO?Ÿþ9íg¥J9sÆó»öìî`õäå2@È}08ÔNàô€TCÁdQšvÈk_ðÓéÓÄÆ'ÛÿmžŸvöL;…¤žNM}¹@ “É6nÙŒ>>¢sòÛïþGäÿ–‘^¯^CC}aA^xD$×"Hp5@„»JãÄè:6üÓ>H‡*ÈA úŠ ò”ذðÞ-ÙKäíÎx,»9lvË}]8c;Ü)Ìï~!Î íDˆÅbâ Ž( Ð,‚‚Ðw_Ù:HA v¶XŽ‘.ת gº~ª««swoY¢Q(ôªª‚› í0 0„‡‡›2m¥4æÒ¢2bJ‚Ò87ÍA ,¶ïý q F£'йøE¨´´Ôü4@Oâãã»Y( `¹\&š)DäYêP¹¼\.—wå”#‹Ø;à¡à!nnn¸«t‘:#¦¤yˆ3ÃØ™†»‚i#Hái·ÔÓ©¬o`ùùN_„Ìo[JU‰»R@›´£4Z­–ôiRƵëWÂ>}úšr2.þÚ¯_ÌÝ»wJJJI;<$ûr6)3!!Á´³Hä-‘H¼EÞ;-`,‚|Œ+)ØlÝn€Îà¡ÒÒÒ˜OT$€Øòûï¿•¦Ž?Ö+Ü\„v|úÙo.¬V©®\¹Š’™™™HW<=›Òtåò´‘““Ããñzgköïßr§ðJÖÖÖîÝ»wÓ¦¾>6˜™t„Ž)N ~b@l‚#à i“'OA/´1sæóO<9m䈑D¾4®yˆë£õ"éz饖ž“ÄÄÑ(i04ÎJN¾˜q1)i î+p!¬)à®`w˜¸+ÐLii«>ŸŠg@[èŒ455ᮈË!—Ëôúû! Dîv‡.NÈ<Éd2ÙlvCôÈ --íÖ­[¦duµºË…èõº¡¡ Ãp_“Ëa¤€»F€Ý¡…Y Ð#t‰D2nÜ8S277§Ë… {_TT¿“³î›€tH^. íÑwEŠ …1Œ:lJòù B@§@ÿ?R©Ô”ìÚhR!ªª”\W,Ä]€ h1&Äh=“‘aì‘#ó"Ê,/-+-.)ÁÝŽ N'„îz$B7Gô#s“¸–“Á ǘÄÑ«ßÿ qÔèë7®£äâ·yè5ëåYb±¸oŸ>`ñÿ½…Þ64aÖË/{ …(3ù•d䢪ª«ß\ðzkêä)‰#Gzy‰B‚[-…µpÁÂÕï¯FúT]]íé)\ºxISSSÐ+Þ}—Çã!…›þìs Æ¡¿¨(Ü-áÀ`sBV;âl]\\l5ß×ÏWQ© íTir¹œÍfûøøàh*{fpt®ß¸qâäqq€øÍo®ß´¾_tô¹sé(_ÓÏ{>5eòýžº?ÿº}2õ'´1oîüÏvng³˜A÷U'ërv~A!©ð£ÇŽÈdåÇ'Ìž5«¿_!÷öñîÝ•¿nͺ ã'.[±TcÓá(W›YÆdÛ6{ñÛKJKJ-ów|¶íÍ…‹.\8שÒ6lܰbù»xË> 3äéYÏfsL9èC¥J™_X€^ɯ&3ššt:ÝÝ{E(ÛŽíè ;í‰i'O4í¬­½¿(e­¶FV.G;oÿìS"G¯·rç¹WTTT\ÌãqÎ_Xx·P(ùL&«¡±žË㢷ÔêêààJ…wK80xDÙ RL61JaÃS¬\±œXæóÝ{õyï½D~½¾þîÝ{-M.¯`±Xíì ­ÓòÝù.¯¨5O¡Ð%3¬™!ôÑÀB>€£ðèðÁ|þÝ»wŠJJ._¹üôSO!íðóó=ÿ˯þ~b6‡Ó;<Üü¨ÿøüôÙ—³ccco§üÕVásf%×ÔÔ"›uøØá̬¬w-~õ¥W˜,7ô%ÉÍÍ{}Îë§>}ùʪ÷V}´á£ry9îÆpTðˆÕŽ8ÛžbРGˆ666&$ #’ÙÙÙĆe[UUºãˆÅV×ú$ÐhÔ\.¯ÑÐXY© d±š°¤¤d÷žÿ¼óöbôãˆ"RQH¢Ð_›S&“õ EIC£Ç㡤ùé †Æ’Ò2—+‹‰œ´3grsòfΜáááÁáp¶™!R#úq@z´ ГÓi§‰¡ ½^_PØüO»çË/"{÷öõñ=á—Ò²2O/O•Jµc×gªêj´sýƒõþxìÆøûùíûö”üæ»ÿ•Ëå¤Â×oÞH|1+*䥯î­ÛþýHì@UUUNnJž8uâö_Ͷeë–¦¦&ÜáÀ`!KT[[Cñ²Û·í¸þÇuYYù»Ë—&Ž…rÒÒÎlß¾Cä-jlhüàƒ÷cbúY=pý†MlG¡¬,).ARºiÓ†ŠŠŠY³fÞɺ”=aâøÅ‹Yµ{÷Nìÿ¹³ç§ÏxNàáqéR–—H”››Ëf±wìØîïï‡tkݺòóóÝܘ#F _²äí_.\X¼h ú&9rtÅÊå£GÙ£)4šjó9C B€£PnÄ<©! Ñkyùù¤Ñnÿó÷ß’÷Ьt H9æ·‹¦¤éDV:†è8K¤ÑP“-ôẑ#G û>ÃøoºlÙò×ç½–²y£T:hÆmxï^Ñõ7/zkË–ÍigÒϤŸuss“H$ÑÑ}׬ùà‰©S­U\\rèБøxéê5«ÂÂÃäòŠ ¿þ–”4)%e“›cçÎ]hŸ”-+JTìúõî?pðÚµë¡!!áa=6•<`€ÄNMQ_ßêñ°„T‚A„¬Ù ªŸÞýÂÌçCBBÆ›óO.Jž?wÞÉÔjµ¿edpyÜŒŒL]ÛOî7ö±(#Ææü“ƒ.'44T$%$ ‹ŒŒl«¨8é )IIcFžúhDxx|||NnsŽ?üûµk7oÝûûŸ9“ŽJCÅöìÙ•ìçëk§¦ÐjkÛÿ€ìÕÝq–78êm%uuuÈ‘ƒ.aaa[?Iq³uQ .@²X,âÀ9¯%S9k‡Ô#fÊ Ú y{{›'±Ø K}t„F­ȬLxüqTÉvb,ápØ5 º¢¢¢.5fLbaÁщ‰ON›/•r8ÍG¡cUª*ƒ¡•l¿Ëollõ€€20;!Ò€.bcc_}å•÷V®êÑ£G}}}£Á0fôèŽ>*qÔÞ½û¦OŸ©V«SSOv­¨w—.=gîŒ/ˆDÞ •bÞܹýcú=þø¸O¶n»~ýzddDJÊf;]~mm­HÔÒÝNÊ T„,b×Ô¨í}Òóç™ÏD‹ŽŽÞ¿ÿ{Ò6“É\²ôíÉI }}ý¢ûö!òþ{+¹\±áååeÊ$¶ã úöÛ}¹9¹½ÂzZ- ÕÁ¼´3žKJšLÚîÙû»ï¿¹uëO½N*‘4G"<ýÔS‘½{W«Õ}¢¢ì×DMMä§§Ãl!ú³5e+î*€  T„,ûâ(8)é9H6†b¹Íf³±ZH¿~Ѥ ËmSÒ²(RI²º„^æ{r¹Ü!C†PÐJ ­–N€@mú3@2wÀP:&DϾ8€A‰%°„:'d9Ò7>èȰÖÔ8ðZ™z½wÚAY.‡ûÚÀÁ¨ªR¡îZ€-ÁöA«Ï& X@6È´M²A€CB¿¯CBZ\*‹&Œ0™L6»ÕgNˆ¶x{#«à‡»]§J¥T(*­¾Õ¾ œê”~_Ó>߃”ŸmA?Ý,?/¢¶¦¦­·ÌmP¹¬Ôdƒòórp׺Yû}ýüéS'›Aߥª*ˆ¿ì\.Ïæe’úâ”J¥¯¯¯ån |X€½à˜Ù $?rÓ[uuZܵCUÒª>N¥Ýq¦$“ ÑáÆßßî“ø|ŒXæ§§§ã¾z Y—³pW¡£ <´ýüÍl\^†»¾¥àìŽ ½4šjÜ-ɪիpW¡£¤žHmçÝæ®¤W)•¸ë P ¥v„4âÍáÀR1àê˜A<‚ Bé˜R©4ãóJee7Ês]NýtêTê){ŸeÒ„I“&NÂ}­€3ƒl‡svj³ R r9(!™L&‘HÌs G®kTTVüýÏßö>ËÁCp_(àä€ ¨Ž ­Œiú€«6`P¢]PP`n†ø|µšÓÐS£Àå Ù ­¶¶±Ñ@ÚG(¼mh4(UJN'‹‰ád´ML'b2™<}ÊÅ¡Z„,{ä<=EJeîv€RÌmJ©@6hÿÁƒ~Í@ÉÊŠ ‘HÄ6*Í»?G¯^½úåWÿ­¬¬D™ õõñññË–¼“™•µk×ç^"Q¶®oŸ¨ùó^÷÷÷Ç}Y@§Á0Yµ¸¸844Ô”3.H+$o Jš4yLâh´ñúü7¾± *2’x÷bfæÊ•ï?ýô“'Läñ¸²òòC‡Ž †ÚÚZ¡@¸jå N¿öÃu_½wÉ’wp_Ði0ˆPAA¹1À €‹lnƒˆ^5?#hƒçÎ êÕ«ÃØ ·eËÖgŸ{vÁ¼¹nnÍcØ(_:(Î͸ò;߃Oì/ÏËÏÇ}Y@WÀ°l^¯GfÈ<™!x¼4¸6ÇÏ_lJ6¨-dòò¼¼ü—^˜I(‹Í"’ŠJÅùó¿ü”šzúôÏÒx)î+ºžµã,Í¿`YYîÖÀî´zdƒò!lP«›§pðÛˆ;(--=xðŸÏŸ={Ö”¤$ÜWt<"D˜!sb2™^^ÞÕÕ*Ü €A6ÈÛü‘ ò‡Ì êÕ+ŒïÁ¿˜™™8j”å»’’O?݆ûš€nmQd†Hs†„B/è”ç¦S6áÎã½øÂÌ7ÿrá±sEeÅÑcǪÕ0ÉÝIÀö(d†Hs†ÆN¹ÊÊòúz=îfÀö°9‘È›ØF_ó.‘œ<‹Åfoùx+ßÏb±êtu<®ûرá¾À6à|¼©L&‹ˆˆ0ŸeÆd2‘‚H9pJL Ä0ÎN­ocbÆÇ›7÷èÑÒWnóæÎ6uj©¬L[§û‰ÄBpDB‚$&÷5Ýó3¶¯^ýöά©cíãa'aI€$ì , È"›¸âR«b•ÚÛªuׯE­,j]@¯UA´ÚÚ¯W¯ÕÚ"Úº#hQEAAYd5¶°“p'ç`8†Eõ$a~OŸ™9s†9ñdþóμ3“jgg‡Õ!"‘ÄåÂÉ!‘ÃÁÁ€ ¢bY,¸ÿ,d( ¼I‰‰±PŠ”´”Ž®ø`Éx? d¸à,Bííí………–––ØD` ¡‰ªªüÿlbcc£ \[[[W×ó_ÖŒ€w­!" Ü«"g0™Ìüü|SSSl"Ô!±@EEF— ¢´µµ† % "îU Á‚¿JKKI$’ÐÊ!¨C"Euu5F|~AJD4ƒ XDB„Èd…BQRRÂ&B222û£Œ=… Ð ‚!*"´´4[[ÛÞ:¤ @¬«cA¿mÜáp8Ø(%l/‰ò•¨©®•" 4ƒ BˆŠú×!999 :›]ÝÞÞ†w!ý‚—DY[[c¯b}%P¢D h½_ººxåååêêê$Òm&‡Ó(%%¥¤¤,MDH„ýë´´4•ªÉá4´´4C“H¼D©©©Q(=«IHàçõæË00X_ ”(£¡¾ï*Hyy¹{÷þûË/¿\¸ð lº¿¿¿‰©±×†MØ0—Ç­¨¨Ð×Óǻֈ–^릦¦¿š#‘”››9p–HÂÀJ—–– ¢ò‚(^'¢ "È•+WÙìÚ[ÿÜZàá!#-#Hg0T ¡ðÄ„'NüxôGmÝ¡ý¹„ȉÑ!Ð uuu3F躥‚¢"±¾¾¶­­ïš~TÀ³ã]hGD–( O@¥Ñ÷(QBQuuuµµ=ÃJP¢ ŸªjFRÒc--­²ÒòGº8»œßÒÒröÜ9T¡>[YU¡­©3„ƒ(ŠJYYø©7®w;"+ËŸ%êììRÄãñFÈ‘H~!Fo‰¯ :°D ÓWB_¿gXJäãÞºí;¶îÚáõV"S(îsæÊÈö´ù\·–ÍFÃD"QII¹¹¹‰Åf«Q(ÊÊ=²—…ùÇŽÛ»÷ß ¬¦®L®>³ Ñ!Ò¦¤¥¥;¶Ïö•" Bð "HŸ ,QÔJäƒd .6nœ¥…Ù Wç;1wsssÆŽ5à–‡ NŸ>tPWGÜ~-ìZÂýÁ»çä4AßÐðÆõMÍM$"ÑmšÛŠå+ ˆíܱ«±‘ããã¢[|¶”••÷Î6DZ„H;‚®PéÓ$"ŒÔA*ÈðÁÑã¼?‰ÂÚmh“Ãi쟌$“kjXk×® ࿾øWìݸȨÈEIU³³£„CBC¢#o¯\µ„ÿü#äÓ9ŸzÌ÷Øãï4ÑÉÄØèñ“ä¿ÿº8e㱑qfv¶• úú3>™ 2kÒ5Ož8Ù;ÛpžEÔE5‰ètº®®î;òC C/‰``È/³­õ‰Ï––¼¿ˆHpéÒ%Ò¡yöìPiwïÄ.Y²D“®5˜ÛÜ0cætŸ‰giižë<½½½ÍÍ,@б±ñ½¸{ùyy@]Ì[‘þ¼–Í^ùÚâé3ÛpžEïd¶Á#6"„‚J!7W7ðÁ»8ÓÈiMºÀ3µ«‹Çb±¨THok}c]³‚"ßÔJ$ðQìɌθ¾—Š Qï×22‰ŒŠ’““óõõÆ&Fܼ{ïë%K…®öÉúo×ïÛ·oÓ&þB"vmíÎ;A <"<,,ìÓY³~þyò“”þîd¶Á#f"4’‘••~!’„ÿnÿ+WØÙÚ£ÑÊÊŠíÛ¿?w.4((Åâûü4qš””ù?Hcc:–˜˜„Mœ<ñ_PH+â믨 8}ÆŒùŸÍÿ uØWb4~Y§L*ÌBwY9yEh xëïÞ‰&æî?ì“’’ÖÔ¤õ—mÈO$–":zzz‚(‰¤\_ÏÆ»R›Çã]E[K›Àªæ}Oг¥eee)jjØt4ª¦Féhï(~õÊÚÒúÿäGtE;;;ñ®g@·É}ž»õx¡tyyùÕ«WÇÆÆ•••:::êtOè ÂZZZS¦L!’HàEJyšÌãñ®…EGFËË+ØØX­[÷­ç†õ—.^LLJœê榠ȷ~Ðãu€¼U¯­NII!‘”ÆÛÚÚ;8ö™mȈ¥>/ÞUÀŸ¦¦&¼«€?9/r¼îpu5s8…46xõwɘ6Î. àãã+H„ííÀ$Ü¿ø÷eß­>fc̸\nRRbHH(•J[¶l90Œää䥥¥]]øK_Ñ0@Þ}µØcz ¤ô™mȈ¥ A$’$Þ"á|udddT”W á!/ùD ÑÖÑ>rä0I²¾g"2‡ÔÒú– ®ÔÕÔØµpsë‘B5³FAAÞÆÊ†Š íª©«]¼x©³“ß³WPèžtì­+‚Kgb)BeeeX·×‘°^UZZJèÀ»F"Á—_}é<¹{0úÕ«¢uë<‡Yˆ$±ìë¥æfæ22Òa7nìÚ³?ð‡Jƒ€ˆÓw›¾‹¿ïeaÑúo¿mkk'‘”ÈÕÚUkÌÍøÝää§)W®]ÅûQ ï“3§ß¾½ÅÛ[”f0***3fÌÄ«>b)B½‡ã$Õ7˜É222K—.A™õ÷÷Ÿ0qB΋œaaMMMííòòr ÝÁÑ!%™ï+Éá4)#®_߬ûæÒåËõµüíÆõôô–¯X1´ !bŠ&>ÖtìÑŸÉÊÈhhhÈÉÉ×ÀÏÛg÷ž 4+–­p°wHM}ê>wîÓÔÔØ¸X£ÑF$I Btíü_竘Ìï·î(xYð,=7Ȫ”C‡‚SRSŠ Atæ¬OÆ[Ûhà×>ˆ¥ìŠ IõM¨®®Í0õddøÿSü5RucV­Z¥«£›ý"+,, ðUVVvu™ZYY~èÐက²h¿¢¢bÞ¼y¶6¶¡¡ç"ÂÃW¯^ƒ÷Ó@>úêjjù@Kôtuëëj&&úlñÉÍͥѨééü•ö&&¦wcïffg •P]SS[[ÛÒÚ½µFw°·WUQ}’ò¤°¨è Ïÿ‰Š¢åhïÐÐXŸ›—÷CÞ2™Q‘ß$¿D1hÆ÷Û¶çååY˜[„E„÷—ÍÑÁqé’¯ †¹™ÙÕkW°—¾Û¸ ØIJÊJ'OÌÊ~á<Ťtñº”U”/ü}á{¿í1wî$4UhÈ"ìÕššî±ëÒ²²Ò^³Œ5ØPBfV¦ Zòz஡¡ï¹TU1ƒF›Á®.ÞÉ“'€ ³X`677}œ=ÝÅX„ 1 UÑ!I2†Àã™ . ( Eéõ>í ûI£Ñ±ùA ö >‹5Ð7Á-66=›P  DÕ aK¨¢ò–‡@ Ãd‚£}Ú³çÿ9ñ«¯Œ´LXø[7oÙØÚ¤§ k]—½ƒið ùC™>Bˆ·1™L 6†€ý‹U "ºxW ˆ 'Ngiyö쟺ºzæfcÏüvÆÖÎvÙÒ¥[Ò|y€y”š––””XßÐ0ÑÉÉÊÒ ÛyæNTt$ÈnwqžJ¥ò—¬–W”Ý‹‹[°`Aï!¸‚—é/rrílm]œ]ß‹©$Þ"DèËRUUkh{ð $Òg7¹¼K‘|¤¤.üWfVÖ…óÔÕÕÈd²ŸŸ_C}O/œËãþrüø;wutuHDâÿÿò+ȶgO€þ뱨¨h ueeåćîÞÛ»g/СçéÏCC/¸ºº ‰PZÚÓ‚¢èTú™Óg%ìÙ3ü£ ÅÞ» ´ËBYcHNNìgJi4m¡”Bd Ëí¼kŒtäååý|}G2äpš||}Ô(êØ«1·£##£6xyúqàÀþ––Öƒ‚ öövÁÁ‡Á¥;w¾*.¾Öï>à÷~ìØOfææîÚ½ÛoëÖ¤¤ÇÉÉO†ÿb/B„¾©¨TM¼+5,Èd5¡¸²²²jÄI);;[hÆx¾ùæA¸¢¢ÌÏÏ—Í®ñFðòòBýu>>>~Ûöm‚³!JËJÀ 8BïbA†]»wÿë<¨ ˆ‚bñþ ‘ …¢~ƒ7n°·³ºqó–é“Ù³ç’É%%%ss‹U«W¾,*xٽ͒¡á(uuupiò¤ÉFÆF))©ýý•JFeUSVVæúµ«¡¡!y¹9ŠŠŠ™™„a# "Zg¡M¤¤¤°Neâ…´´´’’ðÌ¿@h³²3kXƒ¡ÌÚÃŽŽŽòòrŠšú6„öÎö™³f‚€»ûgNcA~Áo§O΢#G~d0*Aþz„ÞÅÞºuÓÑqÂTש‰Iˆ×8Þß2¢5Êhúô>¶ÁnlhÐÒÒ’–êiçUUù[!3^»Mb¡Ñh-ýŸ‡‚zðËHË“ ýÌžý騱cÃFìç„P@=+“À? […Çã56Š®“BSç÷?B:ÚÚ/Y¬I§EFF§¦¦ÙÙÙ®]».++(냄û ŸB§Ñ€ªÊË+äåç¶µµjjÒ(riiI^~^ii)(gù²åà%{ø(¡ªinÓôõûÝŠäÔÖæôK‹L&£a€•µemmÝÅKsrr&MrböõŽ¢44Ô=~œlnaæää`jjŒyœ¦ËW.q8œ… utu?Iº;ÏÝÝÚê-‹ ÈBW_ïåËBйDw@dffÉËËY[Y åy@N¿¿¢LMLÀªdÕõë7ßËÑš’` n~nn®P¢²²ª(OÅ?HÈÉÎqpt¬¬dÄÇß¿¾dÉ¢ËW®¥=KM}–¶ÿÀ~KKËZ6›Åf ùÏž=Kú{wÕÄõï<I€°PTÀ‚¢ˆ€Š nµ­Zõi­JK=ÕÿVíkŸ­Xm«m­Z«ÛÚªí¿ÕÚžãRVõoÝߣHQÜ„„$ y¿äâ@– ðûçf2¹s'F¾¹wîÌØde¿s÷nvvöÉ'F%)•œ¿páÔéSYY\.ĘÑüéÕ«“ÈÏçŸÑLcØlöŠüãê•«,;>~F3kÖÔ¨˜ &äͱc'¨å;v~ Q:hPøÖÏ·ÂÃí_l³ªãXu7³gÍ’J$üñ;ùçý ß2þzôʼn/’óÿÀ£GâÑxjÏÞ¯ÅÅS§Liª*.Ça̘Ø3§Ï~·ÿÛk×®^¼xqË–ÍüñGûÙEzB ý £££aˆÉdº»{J¥%ÖyaÓAaa;¾ÜuïîÝ7ÞHX³ö=GGîÙ´tWWþÅ‹òø¼È!‘Óâ¦+•Ê+W®Ü»wÿü²ªªªBCBÿí7òòõè"*Ao !ýú]¸x‘Ç{fòí·ß!±¸è‹/¶7Óxabb¢«›«]³É-x@ØðáäÊ=”sYçí¹öÐÓ*“–©ÕÕC"~þé—·–.e „h6`àòå‰ý˜œ¼F£Õ°lmGÇŽ^¸`y¶W¯žééW¯^«­«åñxK–,ŽŠÚLm ,¬ªR9|äð/Gêëëýýý&¾ôRûÙuBˆ¡”ƒ·ÒÉééÌfkÎ!>Ÿÿí7{·oÿrÿþïy|~@@ï… u[[Û´ô4rû†Àï1ccÿ¹eÛ²¥K Çvaç¨ÒØ1c>ùôÓÛy·æÍg´ê*ÑZíó¯qЫWÀs×iŠ‹KqcÆ ÜÝ'½<‰Å¶[ºtiffæÆ·mÝF÷;PWóBp¿½{÷ÂwVÓ§||„𔋋®¯Ç1"bHaQQ}}­——»î‡ ß2?ûl³B¡((¸ïÂãûùúºðxä/ÌèÑ£ óöö2*Ã÷Ôäädñ#±¨ @èëëæêN¶ÒN]*„jkkoܸÞ)rèò•+©iéJeeºæÍE‹-Z|÷î]F³èÉ”¶[·n‘qÓâ¦=“ Ÿ†¦ª’ÊdPOT\”PèÓ­·Ð™3gþúKw¡èè¨éÓg6³æì×f}µk—ÐÏ·ºJ•’²aÓ'›zôÖjðê>™ISw!1}ŠÏw…Ó5]ôLëqrr†Ó2©¼§/ø1ã¾0SSSix ;’@ `rØM«ÕZ[©Tª<ýq¬¡ÑÃÜÜÅÅÅ99yzzWWWçääÔÔÔP+‹ùxëF¥R©ƒƒdt‡áTYY … 7„¼]¨sç²RRR¼<¦ˆD"êû^Z* .~ ›ëÑ£¹>?T[$'K>ôð@×›škR+6°Ù,…¢ꮩ*Bg¿¨PT&“ùùú⇅Ð1ЀÑð jF€)çÞÌ6]>'ž^ ÿ¸'M¤»½-uêø)R(“JJJÑÝœV3|Ûýwi§Ð0R¸¯G÷îZZ—ê Ð{ÈËËëׯŸáBÒ’É$55Õt7°—Ë<ØÝÝ‹ÅÒý+xé‘§ Kg˜@€$Cw Ô3·‚'}¾ZµºoŸÞ\®cFf†V£¥ž5üŽ_a¨"›3¬Ä°ïÈš..vv·©6Y:òþþ½üŸ|Eò…>‘ÐBÍê"³ãŒˆÅbÈ!£…CnnÖsþ½=G ð& dú%7nÜhUUk׬}PPpëö­Uï®ôö6óˆBuœ.Ø" ‡à·Qˆ¡?ÈÞž+—K隃,4=#•ñ$ 'ÔªÚ<=½æÍOãî „PÛtÙb<É!___£±&è|¸»{VUU*4\ç:@..®¦ ½7‰DÒÚB¡Î«kÇQ ‡ cat…S†~h:"> kŒ t€ÜÜ<šJ h-&B¨[éÊ=!‚ÌÛ 4<ß°ó,DB]]B!ëÐ u—Ãq0º,)™““SÕôU›B¨B2êb]F×!†>‡rssËËËM‡æQTS£ªªzlÞcEÍ ¾ÅÅÅùùùØB5oÓ'›” åŽ;énˆ™u‹"ÄbqiiiPPi—ˆ¡"ËÙÁÁ©¾¾ž+‚LjÛ†lllØl]ßÇÞžÛLü@¨¨¨ˆ¸B¡æÉåå y9Ý­0¿nBº;Ít‰úcEúŽ‘€¬ ¿©É ÍdI(àJv3”——‰H6BfôP\(ô±ÜYzíÜ\÷ !‚t‰<<<šŠ"‚tbH 1ždR£Z’:”âââû÷ï«Tmìf!„ÐãÇ•?öðð„‚D"ñóó£nÖpëöß[·nKYŸÂÐýùr#ËëëëÊÊʪªª¨ëC’%°” I ÍTKT(²2™@ pttjfs­ÒCˆ¡O”F¥™µ–¨ÔÃøAµßÉ“9rxúÌ¿ý½ºZ©°fM²¿/ˆ„÷Ö¾a³|ùrXmeÒÊ!ƒ#Ï_8wèà!¹\÷"#‡,[ö6DHVVÖž={>ühÝîÝ{Š CCC?øàƒ¦ªeècoçÎÙåÔTWóù®óæˆÙèæZ»/Ý4„*ŠØlv@@€éÕk̺>ååå8ø†2ø.+“Éoæä@HT(•›7oþö»ïÖýχwïÝóz——ÄÅOƒÕ„>¾"у͛· ‰’œœ,*mÛú9×ñ›w–%Br@ ÿÚ·/<|РAE"ÓÆ¦©j¡ª¯÷ìÎÎÎYòÖ›þ¾þG~=uöéÓÇtsmØ—nBD^nn.ôuÌ•F¤ßÙß>°ëƒê«“’¹\.&LìØq(¼òÒ¤ë×®K%ÒY3g‘u¾Ú½ÓÞÎnþÜy\.'80hü¸qiééBäÙáÆO‹‹×jµÐï¡îcZ­¢B~ætêœ9³¡x8ë¿f¥§e\¾tyêÔ8£Íµ†ÐSFiÄÐ_Õ˜<Õè„:CÐÝ!HÈžÚÚZì÷ „:‰ àäè\WÛøœ›7sÕjõ† ÈC(k5Z™LJ’0™Lr³¦ª-j4š³gS³²Î=Y‡#~dž™½B i$²ä¹×WÇîBÈ ùúúÊd²””›§“§xOn/ÄnÙ¡nOÝü¬É“'K-tpàš¥…]ü²=æ¢zºˆB:\§¦¦¦¾^÷5Z][3lè°2©,ëü977WG‡Ë—/={æçóxöìéêôiCë¡W^.ÏÏÏ7Ý\Œ=!„ê:† ‰<}úìû¼ÏdÚøx{-YòVXXÿýßîOOMspp())­Q×Lž<¥UuBU ,øøã‰‰Ë…BøÚ]\\u¶ººúúù&'¯öñÒÝ®VÃB¨Sò~rú$²¹¬Œî&<•–‘öÓ?ÇÆŽêX­ªÎHO¿wÿ>†BuY†î&<•‘‘Ô÷Ý•«Ø,Ý}g^yåeµº–îFµ†B†Z]S¡(o=FØvvÔiðQ?EUmæ«®YŸïFw§ÑjJŠKe2™§þÒs®Ï¶SQQ^VVæ!ð ®zKl˜6ÎÎ=¨Be¥²òq¥À]`kË¢Öß.=tÃõõu©¤ªªªw@ò,Yë3tw*èéß“za{`!Ôi(•ðcöjÝÜT‰èÞKëbcót ±U©úÚì×Ö®y/yõêÄåï DåDËöíÛÿÊÉQ×Ôðxü„„ù£F†åk’×y …¿ýÉ`®xw9Ïÿïµï¿¹dñøqÈ W¬X1lèÐÅ‹—dee8x°\^Á‘˜˜a–™™¹{÷×ëS>ܵk÷â¢^xá£>jám„j’áÔ8«:S54¤RÒJeeå‡ëÖ¯[·®¤¤áæÎ_íþ*///1ñˆ¢°¶lù§øÑC†þÝ7þ÷ÿnߺ5cæŒB9nßÞ}ù|—C‡~$wºðŸ ‹ÄC‡Pp^Õ+ ×¶m[W%­ºvýú¾oö1ô·US({ÿµ/:::>~בk˜Ðm†!„BM¢¦Æ©Õm¹c[Ça2™£FÅîÚµ3&fø•+WW¯^]RZR®§¥¦O˜0! À–e;}út­V{ùÒò޽]ÒªÕÓ§M_µ*©h&Óföì×=üóÒŸZæßÿþ9¸_PÿÐ'Žs8ö¯¿6j€zÆwîÉ]½Á¨‘#_Ÿóúœ9sW®XÙ¶ËfÁá8„jœÛž*++Ì?Ú~ž^+W®ñÙ§[Ž=2 ý6ÐÂW…„†úøxC:‚°aË–. †å>>¨¨Èºº:e¥ÒÏÏwjÜÔqãÆA_G*•›VÕ³§?‡cEÚØØÄÄĸ Ü óÇáp¼xÑ">ßU¥R1™ÌȨHøÀ˜q÷™©©©ôÎ"„Z%@”kkÕÛ®­í“~Kn×ʾ-M}ÇÍϦ¦ Ü×kÕkµZMMÚÞÞÎh¸L«ÕB8™.o „•ÑBòa š×Ap8!kÔÑÿó­m»V ~ènE# cw Ÿ½Æiy=¦ İԇ'& „¢ ö„²J¥R,[~»Îz¤LK¬U¶Ø{º÷›BY ©žå·@…P^^Ýoýüüü¨²H$ºsçÝ-êÊp8!„žÁã=½‹]˧«¡¶ÁB¡§œœœ)+•JZú¦Ý †B=EÍ’gèçLÓÝœ®C!„øùùa7ÈÂ0„B¨vƒ,C!„t D³‰Ý ‹ÁB!Ý|ÃnÐõë×énQw!„Bº8ª$‰¬êNÞ]†B¨» 1œ€Gƒ, C!Ô­999yyyQ!°dIxÙ„P÷åììN=‰D8Á°'„ê¦HQ‡‚***p Îò0„BÝ”ádH 7nà@œåa!„º£wwwê! ¢ B¨ó!w»1<¯¥=¨›Xƒ˜˜˜Žh°\.///WêYäzH ÃÉ7oÞ,++£»Q݆B Äd½½}ÕßA5{éÕÕÕAo#;;›Æ(rvv 3ÜMH ’’ºÚƒ0„ê4Œ¾¿ƒã'Óݨ™ôò$øÍÒ —J¥¹¹¹–o†ÑL&`¦¦¦ÒÝ„Ð󅆆zzz’òñÇ:™\Fw»ZÄ•ï ¿çΙ;é•Id ü釰d Ù·o_ÃÊÉÉ)--¥û½éî0„ê hÓ§›2²2ènQÅŽŠ]›¼–”óóó -³]Ã7À²8‡µsvv¦þ€Îž;[.—ÓÝ¢¶ƒøÔ2´ï%¿ÇÐO¬ ³:t‹¦***²³³Õj5ÝoÒÁBÈÚQ³à6~º±ù"‡^¬A3«2³2á7ä‹Årww︂øñ÷÷wss3‚Ãó¬ †BÖŽœÎr;ÿ6ùóm*°oàŒøð}Ÿz±s_Ÿ ½Ã¿ο“oú,ì48(0ÈÏϯƒ.Rj? ý\YY&UÁBȪÁ×yR¸tùR£+@mþd3—Ë¥»¥Ï€8Œ´&©Ñ‚Ý2 ³ht;ÁY- !„¬uV?ô„LŸ ܼ©!nƒüÛ?úî&3æÍ™ aIk“òósˆÚHY³ŒÈ‘Á7gzªv€¬ÎŽCȪèAa⤉FO&ÐÆO6^ºr©ººšîö6àp8‹,žs‚8ür×—ªjÕÌé3¡‘3âgþõ°y7A²‡ÏçÛÙÙ™> ñÙV[[K÷;žC¡Î*:*~ߺ}‹œ¸j… aa‚ƒ‚çΙk–‚àa<™.Øhöü?{gÖÔ•öñ@ Ù „°BdGÄ—¶Zë^Û>:­ÎŒÕnÓýqim;ýÔéöµuë7Ï7mgF«3µ~um]j«µîµ.@Yd…@ØIHB$$ß›LY½ ïïÉ“çÜsÏ}ï{onÎÿ¾çœ{. åg¸"„ Ãe”’$.]¾4tZá:Ž{ B·ÿÇf’vØí°J¯×u·í±cGwíÚukû-))®ªªº­‡¶qㆠ—.ÜÖ] #P„Š„‡Éá;/?¾µº†üü‚³gÎ °xæÜY±¯¯P(ên[«ÕÚÚÚÚå*°.5,ãuššmým=4K‹Åf³Ý¹S9´aPí‚ HxxxL{hÚ‰?ÅÆÄ>txîÃsjjk~þùܬYs Й?~IIÑCMFÓc>–”4²¸¤¨¶¶ö⥋ ^,&“Ù·_”RÁãðþóå¸<îsÏ<»eë–Úšº„ÄøIï#™ üžÇå®Y³F(Ž;V$“ÍÁþW;wBGç>¢P(|˜Ãåž:y*>>aþ¼ùn?!rBCÂHB«m8pà L&ûÓsσªíÚ½ 4ïÑG™4ÊÖfÛ³{wZFºÙÔDõÙB`$„ Èe欙¿œ¿`³µ=vlÆÌYsç>²ÿ7#ä›6mž0~ÂôéÓ7mÞ¬ª(/*,:tøÐÌ3E"Ùüر®ädÇFÇãóxÏ>ûܧŸn‚Å¿þõjêjŸyúi¶Õ§v‘‚ CÓ'yÔÈŸ|!÷÷ó÷óõkµZ·nÝòÀ”É  ãS'@1Mæì™sB¡`DÔˆ¸ØxˆœŽùNUY~äû#_|±•Á`Œ3öoÿô©%Kâã&‚z‰Å¢Ôqãív{NN6ÈRc£!<,œÍáŒ=&,Lžv9l‚ÁÙ³gû¹¹¹…HII DR)ˆ „>]ú¼à‰Çw|µóå—^¤{Ò3Í´X,…ÅÅÞÞ^ùÛ¶mƒƒ‹ÅTŸÚ!FB‚ÜF¢GDdsˆ~N<={Ö,š«nÎó>w~òSD"aum5)SPX(‘øCÂËË›ƒoY`Pbbü×®á ÑÑÑï½ûÞ¡C‡23u[þöÀ7™Y™©©ã;îÎa·“È^¥ZMÒµuµ¾ÝˇÍî¸8aüÄ×V¼öÙæÏ+*U2™lá‚…+_[¹~ýúʰXWWGõ2äÀHA†%ùù$±àñ»öÜâH°;Àè”Ñîʨ ×.S§L-).†H,§§§“ás!!!÷ßÿñãÇ;nÈ 3–/_±víÇÛ¶oc2EÅ¥šúz“””ðéß78ybâĉeee--u¥Z«k7vìÚuëÊ(‰¯6OrúÌ)b?J©LLH:|øp—>8uê¦M›Ï;›››7yÊ”¿}ú¿4OÃæ,Y¼dãÆOx|D]kV­zjÉÓ6lðòö®­©’Tÿ2CŸ~ú©Ë#”QÝmS]Se08;Ö„b~¤\al2–8TJW0t‰4@Äðø‚æf“^oP«Õ6[[¯º¿°¨˜êƒ@îiä. 1cÎŒN«Ž~w¾ÓÒÓVýeÕnvË¡oy{{÷àÿ5=X0šy\{±Ùböa9ƒ¨Ù««ãܤ Ãjµ:²/w6› ÖVW«…"˧¹j0.—ËöáŒz¶×Ül Äv稹J‰Dêéé ±”———Íf­ªR „B› , Ã…;Aüƒ^ oت­­­¶¶Z$þ`•©ÉX¡RÉå‘, ̶P¶b‚020pÒíY én•©ÉLDH©Pr¹|@¨kÐi4 TKgXlï”ä1p!’ðœÍf‹ÅþR©4++Óbiíy[÷á£!C–¯w½ð‰…j Ù`èÝ5ïUWoÙHGˆ AAÁî|€›Ó^. î^+ " ±È¾AˆµŽehÎ[X¯Ž9¤XǪ·A×V ÷V° ¤(66þf#ˆ›Þû„@·[oÄfk¯Á››ÍC 6Ën7àG§m€ÍuMp8ÜàÐÛFêÙ±sI,úâyÍ£Ú΀¿ÞãâvA:Ñ{R±P ‡EµkÒ?b¢c:u«X­ÖwÞ罿¼ÑÆ z!1!1;'{ÿ·û©ö”ŠθœW;•èj7‘!Aï"äp8ÜªÓ 5Ìæ&†§'ƒAÿ­£Å“Æe³!§cIKk‹ÅÜÊå¶ç›LfR!ÓYÀÒb±´þ¶è*Ïf{ûú½¾Ñm ðùB:ÞÜÜù=tð˜Œæ¬¬,ÇõÞªzV¡p&HëÜ-€·}éXBÓØØ~ñ§ŒJ¹¹oÿÂÅ D‡ •>|ýqÕ.Ó8lŽ; î“7—q·˜••• îÞ8ö½‡ƒ6cƬ^KæååÁwll,Y?%þ’:MºRݱXPpP§œÔñ©ùùù®z)R12)ù¶ŸÓ»—ÞE„Á‡Åì˜ãìésUÁQQQsæŒK/œð°° à`/ƒvcE_W[“—_psy‰$@©TÒ\"Àãq“\?'”¯¬®LŒ ·x ………ÕÕÕàI|\¼P(ôpõB~s³977Ïd2uéyë7_ô뺨×éoù|)‘ÁAÁ¶6[ZÚå^;–dà@4O111]€ªó±ß=öÑÅÆ8+ÓŽ@-ûöïûrç—ÍÍ]7“,|b!I8uPөӧΜ<=ïwóûR8=ÝùH[„Žÿ1yd2HŽÝÞ÷¾éé“'O¦9;r˜$çÀƒ‹95žÅdîÝ·7&:Z(Û¼yó¼yógΘIÕyîô.BryDx¸¼cNqqû žž¿õ*Ëä FƒA§×H˜Lg/DKfKÓÍåi® „äè¾Ü‹±Ñq¤KrÌMF°’’’a[[[yÙU“Éèç' ”92-íR_ô@* $‰ú†[C ¾yÓéR©lÐïà¤KàJ =jôÍ-r¨èßøó[$&$&%$Qí/-+'+;'»;ù¡¹ÚâH$4¸"‡Ýž—›ŸÕ,VVªìyªÔÖf…zntŸ/èÁ„5ðɾ’]PXøøãO¸3Ë˯ýøãqwÍ9Œ{ô¤ “˜LfFzŠÐ-Ó»u’ Z÷ÍYry$¬ji±¤¥§;‡-VW— ùZ½¶¬¬¢_n‰}ýàÖ£°0Ïn§ùûù5LR (¬R«+¯]sΙ¡Ñh›Í (/ïÅ>‹å ŠEsMSØ0ª­­’Jƒ@ëëk|ò¤Oèõí±û†µ@lºÔ!›‹‹—.‡j{¤ôÉ?>IÒ=Îî/Z]Ù³g%ÿØø¸Ã]m$P¬\ùæñgfeÂ?*–5«ßqorõêU÷Fõõý›·´ ?ßb¶=ztÚôéÔžÒaMï"¤ÑhÜ­ÒNÛeI"W‹™Ä×î!s>ÞLZ?n¸Kʾ’W_çT‹šguà/!«x<^ô%I9ì‹)J2*„m ç+?¿¨ºº¦Ùl±´´ Ä‚ô­VK‚!ø_ô CÃP 8w4¸mqb±D$¾¾â*uµ¯¯ß[o½ ™|øþ/ùa1™¯¾ºÔj½¡ÕÞ Æ~íN­®¢9</Yœrý\äè]„à V«û` Jjüý¥|¾(0Ð_¯3„]oÄÓhûy˜ÍMDh×›Œ½¼Û]åp¸ðq—lmmíõ2–øûúû;gõ¨P©ŒÆ ägtºÆX@["‘H¡?Ñ¡mÿÞ–—Ÿ7¼¤ägá‚…)É)DàÖvpà šë®”N§ÃÝp“©I"‘ÉÃåæ&gw€¯¯LJL £FzòÉö°¬æú<@}dêCS'M˜DݽKÌGvó á"ðó ˆŽŽ·Ûí$0ª®®ªªìßOKsÞ’:åXš[®†Üââ"¦Q3‹Å ŽéõÚ’ÒÎ#³ :0™úñœŽŽCîžÚ>%JUf0˜¼A~#44”jú ž0\ãE‘‘‘]®Ýµûÿ¤“¸á¥¥ç/œ?{æÌ[oþù–wº|ŲuëÖ2½}ñTô| ÷ƒ90!/¯°¼¢ÂßWÂf3éž «Íf±´hꚌCñmC2aaa"‘¨ï#K‡r¹\§Ó•——wš„¥K´ºúššZ¥RÉ ;±°µY‹ŠŠÚÚl$Ýd2·Ù­tº@(ª¨Pñù΂S&Oáò¸ÎµFS›£Íh4……†•îœ>vª®ª$·|±eÆ´éd9—m04’4ì"H ¦À”™3sN ,pùŠ¥Þ^,·¤ñîé6ccâºóÒ|.¿¨¤¸ËAú’%KÑœµÕª×ë5 }jʃSmmm4‡sŽ×ûï»/4,ÌÛ‹éãÃúð¿?òððعsgx¸|Á‚ßÛlVƒÁ!Ϊի®äåN˜0133 Ê€·V«3jÙ¶}û믿®ˆŒjh¨û¿Þ¾ÿ¾ÉtºçÒ¥Ë!¦yñ¥Ÿyú¹.=‡>ûÌ3Š^zA«­ït  EA†P9ºhõ_Vgdf@mKµSýcë¶­t:ý©ÿoïÜ£Û*Î~#Ë–¬÷Õûa[’¿âwœ°@($ЂC–Chš¤íaw!@v!›@ i¡À¶==§Ý.Íî?“òZ¶»4)^–‰m'±­[¶$K²,Ù²õ´lËûÝ;ò"˶lL™ùŸÑ¹sg>]}ß<¿ùþÎûî½4»Ñhôz½sËA‚#ÿþ;•J…>BÊ<ng6]°èCÅÀœ ü_ÑÊ¢=ÈÁŸ/6ÍfgïÛ¿ï•W74ܱyó7é+ìÙR‡d>ùtÑz,}?+ÞÑœÃá,*,‚dJ¥* ¦«:ê€Í`h®’£¡ú|¾ÙÁdd§ƒùª] Ôv¦-ã,Š ¦ª@ÐÊš©Ôl / oÝx+AÍåxo¿ýo¾ù–éb—mÀ¶´GC/Ä76¶û‘‡ÿæ[ð1‡Ãiû´åBç¹ø4¯7îܱ 666* ­VÛéÖÓ}–˜—ÕM›6þËo exù•—ëÖ¦Zò„Ø/^‘•Ç2Ï a0˜eG¯×Ëd2¼þÆëï?ÝÅù¢Øvè TUV¡ó‘“v†Ô*UKËiïØ(—ÃÑéòÖ­[;.tòyüššj©TJ’¤F£«¦R)årÅää¤^o „ðQ  ø|£±0C@£ÑÂÿââ’ÿýøãöösÛ¶mS«Ô……ƶ¶6¥z,j”ä/!EMM–”C¶këêÅ"aûÙ³eekx¹¼* ²Ên·ôÑGEEEÛ·ogg±#‘\&h_þ(0»ä"‘¨¬´,77Ò@ œ^ÂÀT=÷+Μâ‰?Þ;”Ôk'‹>4ˆ9ù;á#\.£Êa§Ÿ™F²o3Í%bœE‰y‡Ç#ãéð 󅨏q#Z‰pçwîÌÐ>P`„ÞÿOÊš‚:yòdÒ4Vjzzz¹Va Ýëñ¾`ÆÄP‚™SžW%¤G€ü\—¸ì%_Ù,<'D’’ššZæckë'Á`¢!!Å¢šjqˆkÐiºx)á#Ayô)…ö|+ñþ{0Áìo3í¨ÕZ´¬¨&•[ÊËËDb­-§ƒ¡pºk°8.ƒnÐʰ@­Ê¡:÷o½5¢–qî$Á×ìœg'˜&••ñË^ò•͆Z­U³â(0f§AÓnh†pöG‚žVE¡sºŒ¥g³³H23¼ÿeø22ûÛL;K(Ò*Vì–t—}Ñèõz¸Ðq­Ÿ´(ƒš)ŽÀ1_ ü&A©)dÊø+¥–7:—"ÝÝÝÁ pÐér -[ÑYD]m­D"ýKÉêZ dEÂÎösíé.Ër=!Jñû•f#T_€)†Ã¡@€ZìmO­V»ØÇ ´´´uu™–±èUU•BnC] “A”—•/íÆã'Ž>üò;ï¼595ÑÙÙyªù5:ê=vì @Hvöì™tW³ Ì ©Ô±Õîv‡#2>^F¿7yyù‹urrn'JŠ ùô‰r]¦ÉHìF…B.&ÅB>?!1J± …T"‘çää@ÏÝ;2Üoég|Е——Kiï¨jµJ"´?l“é˜L­N«R*¹Üܬ¬,0œn·Ûjµ-PZT*O£RóùxXܑё¾ÞþØ]3±'AÛc«Õâr¹˜ùm¦v¦‹&­ÒæC Ü}ùrüIJT¥B¦‚‚E"ߨ¨mÀ622ÊÄæétRŠŠm°8í.&Ê` …y½^‡«PP9ÀϬ§çò‚™-y&7‡cÐé¤NEZ¢Ð’}¿H¾5ÈÇÜov»<Д×ë p2é]¾ÜÍÔ:ñ<§À G¢ƒlÑ$ÓŠópe°m˶Æcé.ŲQW[å ouêwýù䇟¶¶n¸ùkn÷Pk[kOwïÑ£Gýë_••­™ŽFù«_¶œnݲeË /¾°¶~myEEÓÿ|°vm}êù/ÝîÞûÄúCšd™ÙÌg„àW›ËCa§} 29U\\¿pÐYr¥Ìi_Ä©nBʵÕéÎÉbO”j+.^ Ê:é˜>¤Qj•¥¥¥ñÓJ•L®@ëòóujµÅB Q!A­Ãÿë®»ŽÃá07 …"@Èáq.u}6§ØìÚÚH‰î‚geggÃG»u´p|l0èGy–—Wh´ºŽ HM3µ[[[ÏÍå¡| À¡ ­í J£Q«ÊÊ×0ãÒD£Q¤Žóót«‹K T0û,O—'KzSÅ„!Ýn …̈7Dù¸ràÉ}Ð4„v!_À‡4bÊ‘e‹Ž°ÑjµÈqf6ó!µVÏPxœrçpØQ3ߨ7ºœƒK^ê*%Id<Ï¥‹³ØYµµµÐ†^ˆÉt!8&A%Ðõt»²VeUUV¤Œ2E ¥ÕjõŒx¸6K~>5aët:@ Ò@!-–?,‘ˆêêêá)J™ê1§>]½ºù.¤Ûàý#Ã^6;K®ˆÍ„­.Åööt÷[¨ýe¥¥ÅZm)! òó{Íæø¬¢Ñé–OOOOUUUÁ{˜›Ë—J%.—›Ëã0J;`ƒ~ä”@(ÌÍ¥‡X¤@ÇFGÛ©ðÓ<^îúõשêAÒ9÷™t\ì…ÂÐ×(..ƒÊ®)«hnžG ©°¡Í’”P¯Ë/,¢Žµ…ŠC±ÑÅB½A¯§€7 .t¦(Þ5eåÈõ÷›ûûû²XÙÆB¤ašº3è+H$’û·ÞŸY~zæ¡bMê -ªÜzë¦}û÷º¿÷½íù´.2è ·Ý¶iß¾}J…⥗^úàOMpñÁtðÀÁm÷okhh`1ãm±Y8¸iÓF“ɤ×°XìæææŸÿüyxÙâ‰n¸¾¹ù“§Ÿ~Êdºxº¹™”Iÿêúë½#^&ÜôÁðK1›û ÜrèÐ!©”ìì2mÛr߉¦¦Ü»÷ÿ>>uºå“ºººS§š!Çã~íµ£Á@07—ûèžÇ Øavræ4BÐDU+5(ìt:QÀj·"#mm™L>4ä^ÚSEôb9*Ckß84Ø#TËš{ôpM„ˆBÃcwÚ§)/PDVÁ3ž6‚þp0[e ªÍã¹¢eΞ;ô3.4¦Ñ¢þxß °X„F›â‚¦Ç3ŒÂÞQzœF‹µX­è„¼>s/Ò€y³ŒÐ¥K¦ zºÃéÑk~x<A¸óu±>hIfb̈9gbÝnw½ýšx~ÿ(ô-4:M¼u ¡ü­V»T*“ÉPBdçæH*,VhóÐÙÙ¤]˜ôõ[ô#rOÒÑyÏÜ×Fˆ z3âÅ+òÑQ§‡’ö$ñù®:Ò0uf(ÐW#Â|îÐs|0ÝÅY¶?°ÌWÿ‚^û—ó›Æ7Áê¼øâ‹èâ ×op:o¹e#úöÑ•Jóê«ÿÚÙѱÿØÍÓÓú‡?øÑùŽóxï½§žú1´‰ÀrR²¢¢ÌÌ*룓éõúéUÄ®»x|^ó©f&\R\BŠ%‡ÿùpWg—DJ®YS¾k×ÚýÐí w¼âdFoÿÆíßúÖ·‰i¢§§ç­·ßÞûøãðØ×úÂt‹üÚeNEíPf|F&•IÉX”Ù«•ŸŸ¿d# Æ”´‚‹±ü齇 I 5½¡Õh‹•RÎþ¨-•J ¦¹lš?=h8”&‰0ˆ²bb™n_x<ÖÀü99ìñÈ•rtºGU“Â1cί~J¬îÆÂB=ðÂÜ(¡·¶$elÌFˆ˜±sKû"–&´yˆ?Ê–yUŠÆ×.ñ‚¹Biü>ß\]š3ÐÔ$I‚ZW¿îùŸ>àé_<Ï4U`ºA‹‹#è.‡»ãû;s²³[[ZÐEø®ïþî=ñïíTt²¨°èг‡ü›=Ãn™4ævq4·j&ol(öxÍ=½r©¬°¨°bM¥ÛㆾÑ3Ï<† ÷öö˜L]c>ê|Nè¿öÚk=f³V­Ž?g埅ï¹ûî#GŽ€*»ó››¯í × s!fI Ö$Y'K@‰$´ISÄå øý| ¤dT*Ïfçˆ%ÔêÀ€ m$är9µµµÐ߂ƅÍfËú%•œÆƒ¡Þ.èsôõõ••—çääÌ“~qeÚivìTÒÝø¬«îOIÊÙìyžÂ¼Ÿ6›%ºjÊ}b"2gž3=•Tb_^¡-©ˆwrrá£@–&ÀÌìò´V¿¶”øÑ7Žvuu¥»P‹¦¢¢â­ÔϬXl78öÆïÅ‘L.?{¶½asCpÆsh‚–ÿÉO~|Ï=íóùÆÃã îM¬¯¯ûw¾{÷]”ƒÑïù çÊÊÊÁ:¶œnñ»™pÓ‡M?;tèÕßåñsÇC¡‡>©Véæ20Ðãr¹O=ý4—³œ§á­<’!)I2KFG›* ³ää]Lyîú*¢Dë™Öšªj°@ … šÌÐ7t:úú­(¾¤¸˜Ç£VÍuvv@E§ÓÍ•S¼V£h0¡¹OϤ´4Ó 2£OPë„¡›±€Åfggƒ]DKݘå|€|<¥y¨š·W*Ö«ÁÄNMŽʭ!tæÊS$ŒMÏûýW¹Þšk;&›çp®20KÚr‘ŠxGf^?èg³©“çY€!ÁÖ­[áÿŽ;¿|:}ö§ÏBE‰Ä’ n‚€X$Þp゚^ fÌ`0xrSS“H$¾íë_‡ëï¾û6‹ÅÞ±ãÛv»ƒ äë_o,++u¹;::¢ÓÓÏ=ÿ)ÿíß=ÔpGd^YYÉãQöþë¿ÿ0æóíÝ»·¨¨ðï÷<žnñ_»$ÿ‰ª´±n(‚3g·È VWC@­Ôš{ú–æ†ÇX`DÓ<3 ¥ârf¿ËttT³§T•Z«ò¸=>_Lóêtùãô¢ ‘HàõŽ¡V íµ‰ê«1=’ªs»< ňNEN‡NGMBTVUõöõ|clvŽL!°Ú Ÿ7`³èõmáê¢îKŸÔº¾bt¯uÀšbe]z=5Aš´¢ªÒiwNNFøBËùüóž;ŠÕë áppÈåUËËåªÔj’Ÿ={åg¦Ëý~Ü«RiМXŽáaJIb2]‚* §×;l‰ž_6f¼k.¡E³qD‰Å;1>éñ Éd h•U”Û,ýðíäÇg“º3šááaP܃Í)ªÿòx½Þööö«~ð)#•ʶlÝÆ¸e›í‡{×®]ð¿duiñ#”c§øn )!ïúÎ]ÐÃ;W@­â)--CQUU5••ÕLú=ý ô&¼þºëá¥ß÷ä¾={öTUV¿ûoA'éÞ{ï¥ò¯‹ýB©Æ#¡Ï»/~ù0õáG†Ë{:øJ"‰Êι²$Á1˜dÃa³##„6®öö.ºO øC~ô}WW׎CÏ6òûýð¸0í˜ Ò•5µµÓôŒºK­ÖÀ_ËÈ'`·@ÿ‚"† R[ÝÝ—!ŒtýÍ7oD>zѵµõ‡m¶>ëþš-`©¬ŠbîuÑó7—Í=Yì,°R*…J)§–Ì¡·¿¿ßl·9R¬l(¾Ðu¡º¢ʦ)åÒ˜ëܱ±ºä“ð›„bKK×””P?NäþÈnˆÏG VVV3?•p8ÔeêšÉ*‰@j ƒU.—s¹¹P~ø#¨ L#dÜõ¡!×üBs¹¾ÄÝ6©ˆ÷¢éÒºõ¨‚B¦Óƒû  © 0Ó¦!IÒh4JèìÌÌÙl^B(ž¤.Ý’&[l¶ó‡ã/þ`ç®Æcÿväˆ\¡Ø½û‘Ù¹åds7Üxãc{…0Ðéà˜¤$ñ¢- Š˜–´Z-³'Û jÙ»m-œœœ´X,¹¹\´Æ Úé.×PÂÇøôV‹¨è zV‹.2D§£]Cn7Á"´:F©žšœt ¹Á8 …"¿/`µ[cK¹²¨ )e±ÙpÝã’ÌI¡ÑÈárPJ6+»ÐH5y û ƒ˜Ûý£ÛJôÞa/hgfÜL,ªUåñûƒöA{Ür²$µ‰Dè²”,''Ä"ð¡x(§Ë韙TƒX¸EJ’(6w:FéEz:®´´” æ<¬©TŠnÉG&â¦L’ „ V.póó  ðP/jeÄ‘P¶ù…–›“ømÎó>0 h§gh쥷·—IYHÏíMMMÅŸª9¿x©š±³òty¤DD#èB[Ä;—JÈãóç:K-ƒÈĹî¥õ~®M¢4ó8$dZÏ×”ßÅk”ŽrXvJJVëèeµ–þþ/¥("±¡À: 4]kk[ºÅrmÁ!3Mº‹ƒÁ`0ËFz¦m X @ÀßkîA½ Ç«Vªø|n2`0ÌW‡ô!4åÃãñ×­[öˆ%4Z2°²ñ1 3é1B=æÞÐx(_—OÄ+ˆ-5†ŽÑÀ€Õ–òl?ƒÁ`2ôÌ ]y|Ö*‡Z7 …WÒ¤åòÂÊbår($‘‰‰¤ëD0 &CIóV¾é©é@0ôÅóYÙD§¢XJ fE’y§c0 fÅ€ƒÁ`Ò6B ƒIØa0 &m`#„Á`0˜´ƒÁ`Ò6B ƒIØa0 &m`#„Á`0˜´ƒÁ`Ò6B ƒIØa0 &m`#„Á`0˜´ñÿOˆ·-yoÖíIEND®B`‚gateway-1.4.5/doc/alligata/11-5.png0000644000175000017500000001312007344776077015322 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ 8*=@­ë pHYsÓÓŽ{¸®gAMA± üaßIDATxÚí]½—Û8’îÍ{”#P‘½‘ähhþZOMñðCª H…d@ñûÎÀ€ûÅ@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs|µï ”!Æ/.¸ˆ„Ç\íVÓÇ8ÎÁc¸WŸ€Gc¼jÛ»1JˆÇ`ƒRJ<Âàâ~êQØÀŸÑGÕùð“ÂNý›Q¶IËÛwÕ°s‚ørbÁO 1¸g-±>gC°Ü/¹ç’OšD2q°8–í,ž£¿C4=‚ÜÆF IÅ O/k 7&¢[eTÞSØIk ÍªÔÒ#D¬¥*ÇÜFÂbyϘs%±Ê€þI$‹›< £Âí9¥d§ NšñJîm6’r¯9Nˆá^6BÖ±Ex¨<àoòpÒU6› äEwÑâWÁ÷}”6±Z£®‘'%j<«HKSRU‘ÍQU…¦òª–h,mJ¸EÁÏ슛¤ºI¥˜éTmPYãkêˆï36òããÆ”oIpL‚0VA­‚P`¦F\X¦’O‰gȳTxJžg9‘Ö§S‹R­ØŒ°´Àª%z Zz…ãí…ª~DýþôÑtúp ²¾m6· 8ø,Öψ/*X¹-;‹Ù:ÕÇu¥T\Rqm)ô½¡K…A·.%ÌԤᶵñ¦`§3­RëA¶{eÓùŒŽýét<ÝV”],`wq³Xý¾"âI¦5»)C^AÊ,ú¶ Ú"M-aGÂTjqwfK¬ìä„™­ÛŽâldl#¸­¡jLWˆ§«—C'cÌùî¹pà˜,‚ÅòÓ2ü=D+7õÔõ^¡·+Ô2S•ã¢Z«ÚXZÔv´fŸ KÍ]U纘èÙšÜ"/†Ø¨{Á°;õÇd==q•ãz ¢`,Ã(T.&óLj“ª™`Ug,º)-=–µQïÍX¦™U÷ŠóCêªsžï½ä<ç–±éÑ<à«5Œ¾öum×)­‚!Åà“ìt…6ðô=•àzrgÊkîf4÷¯Ðå:iT›¶7”al nÈVšf¹.ßÂ,E1åv½0&;–hé]JC牷¹»y­ËÔ”Ýø~ÕÃ…z‚vò‹¦G’£u3mZªËY{ëÚÁÇf¦€{ÎíÈ¥PÓDb'¦r¸p,Á"ZGú‰6j<ïl<º2  ŽT‡ >eÓG'¬æ–j Öó­ÓMsk`·;‡vð”œú`A·{Èj@·ì¶©üJ‚!=pXN0a‘àâCBYLÃE²« ö’ç,3†…ÐzŽ‚ÌÎ9œ1DËpòafxk8Ä¢kîõÔ»¸ªèœ›]|œ²µO]¦G‹ÏaZ‚ò–§:Í4sWÙw)Îá¡^ÃÖ­Ñ!xQŒÕtŽ´^ªäÃ}t¶*>׿qЪöÑåß»DéÄJ‡ëšYæ`ƒí´ê§<Ï´_îþlgí Jª‰bwëþh¶)sÔfÍ”žûUÛ¦ßr\á°à¶TOÁ‰lŽåTtÕ¥‡xïu¹ÁXõ{ÏqíY­Ü¤®ä¸ê„ÎõÄšQ¨múˆ°uF‡(w“pE‡ÐÚÒÒܵhíå–Kj?,ùŽË :ºz†å ˜°\às°¢ î<ï^Ñt<¸’`ZúÖ:Y{@¥ì tV „öøQýt¡Û‹µì¥*ºÕóÁCÐê`P¥IY-§ç  }°ãš¿[G²$Kkw¨”RýV㎭£IÓ|pˆw]Óe\¸L§µ,áPÞ4ãk¨d±¾¶Y¥—s‡UÆtŒÂzÑÉÞíú`ji ƒ‹¼cd…X¿ Ûáºj+Ú£¤ÅºBékµÝ»Éê>˜&oÖ̪ÃBnýß*X¬hB\Ô㉵cT –gíCÔøÁÅÔyÍmì .üZ M‡é”ŒVFQ~ô`- ò¥Í£zŠ­OÒì2³òA¶ÛE(ŽŽö]æ/¹×ú>þvª¹­{;Š‚`æ1øDëŸDK”õãÙop$¯—í´›dpÉ·y» }À?Û>ñ¡­M¥!>êþQ%Zí­èAjnÔ|eO8Ž(ôÁÂl+м\ü¤: Qí+¹uéÍ*º1=}b—fŸÌˆç†Úô°GqÊÃìš‚)Ò”HK†Nv7˜tÔݪZºLdßÂN½Z­Zr+= šÃ¨“>xäkCšèèUqü\ošz߯²Mp¿/f­Î›É‰²qDl½\¹‰9xæå­ÌÓ¢à‡˜ãä¸: ö(´&X®2® feîŸóW³$™"¥ÛÆÎÒ3iõ *ý«ßÞ$š ÚåŽn‡ Ú¨W¿'‚ªšNc•ìÊè“]§Së©{gÈù̧ŠxnmSU=Ð`2‘îÜꪴxÁ«ø4Nj°ªeêce׳‰£W.Fšb­n?ßª× ‹ÖjçËAyõm‚7\ R±K}¹‰?q¼¨~1Rÿ?öÇtM¢5ÇwfW¿¼?£ËœË*ö7ƒcžù¶—8ÒÖ€]I-ξù6 v¿´^‚‰œ DA…\ð´ÀÜ}v®^×4û³2GÅrœVÝ®Žú\>Ï*îQ;÷òú7/±4» xÙÝŠ]âH0Q‡AÄC¡ÖG6ï8 ºŽÁ¶„—Ÿ!«üRÅ.Ê.P»½‰àJ0‘Gw Å Ç‘hºðZ+ä4Áa#“ÍârÞ‰l˜‹}«á;†Tq PͳáN°B´Ž"E""1ç5— bªÛ½´‰Î‘Öuj‹ÄyáK‚ÅòJ-%šªX¯¯)$zjTK"«°5Á þb4«ó'ÝÆæ&}†([hÏ)¶’Ì›qKšÅ–f–¨›]”Tkù‰dËýO¯U+’×ÅtRï‰9G4$ø^Ëv“ƒ Ýh‚\™¢ä¡ ‹½˜ì@ÅZtPàFH™ö˜ãl¿»A/åàký…aÀ±Æüí>p ñ°7Lý©FŒµ2†ßR•úÞ¡­C΂ \ÿ­Â&(Ã#ÒºGjq[}À½(ÁO–. ¢OKýê4£QŠMÕIZcê'Ö×Z(ŽÁ=!šÙxþüùôëiWyi+Á§p*þTa »8G$"!üIÂ2‘ñ,…Jâuá9gÌŸ>òý1ìžÙ = eo¥þÒ=(£‚[ñ…s¢(º^\/o—ùï¿L&®ÁH;¾j%¾œ»È(aP€ðsYÄJ…6,A?ÇHžð°ü°ô]+Ç@ÂßÃ(yNR€%<vþæM£1¢JšHšqol¡òØ8òÛ6Ö¢ŒB Eˆëÿ¿¾|rùê?_¥í¾ ZHpL‚OO€_ÝÞÞ®V+Ø r GÒÏ©@ŒPCŸnü ½3ñAÃ/o·7AðSövÙuàey³D³CåsMô¿K5̉&[(W@n›ÊYwÀ’àÕç—W\üíböÍlþý¼}&›ŒQ­U¨…ïà_ð­ò—jdZÉ1Mâ2È:Õ}°¢¶¡U°ñB"ág„à>9h‚•u‰ÌÉòFµŒãr¥uSç¶•”+]’ºáX)pÕ[{˜~ÿÓûù|Þ¾“jN0PùPz $Ok*…DA¥á­„“}h +UãT‡xT‚ÑúhÞÊ¥÷t VÂJÖ†ŠÿÄœ¯ñI3†üt'H°YK^òÍåC~7·P«“Gm{â¦ÇØ_ÂGµÐHb“ÑbÖcó›sÙ‹;µ@‰?ŠTUHÉåÊQœ=TcËå’’7_T%‹(·Jçvf+ ­×ÏádÜÖÒlH0𪤣’ëÄhŒfhæ;F‰kesÊÞƒVòe=#PÃSâ…>_QÃò8œðšÒô u¾‘!ô#Ä 9|‹»Yb`& ™±‡¢Q*mÍ nA%@OÜ2‡-ú`4 WÔó;­šˆbQ¨É\Ç¥© c9aDT±OFØïâœ"ÿb“Gãñ:ˆ®ÿ'‚®w%þ>ëüW@Ï" iÐÌJå 9PÎoÎ"`ÔòzÆàU€ZRÚ[¡w‚êõâ7 òဠقz[üv;ÿž×.VhGsqTBã(1ƒ;Å`FI:1Ð1†oP_þƒ1%–˜Ó>´PÙ´U ˜Müà×ÛkHìõîò´\Çi¡û„Ìç‡÷@Ú¤A)0J©ÿõÙäñ)„X†¨àÜ\ä6”È‘XGaŒÏ^S9ŠAÍÀÊjÊ‚[a£µÊcS‚eÓ#¨‚F'Í+áÿavöý‹1f“êé÷øqie¬WDšc"j§²éÿã?£åb³EP¿aÁ~üã§óùáK04ÁÙ·³ùÙüïW#t“|\ô‚Mâ`6ûMèƒèF|ÙQ_k2jæê¬01ñýè׫(øYuaDú íG¿›«hpþ@E£Ä%LøbEo>JVØ#Gã;Rc£‚JF ÓÎF(G—õ|zimž?;úh¼GæLÿ0}öüÙûë÷:œ½¹^‹MÏ“Jv¤‚ Ð|tQ±AoåO™OAÙá¬7ñánEP±aT çè<·_ý¦!Áp{(d,=¥aäû¢ÛÅ5Ù´:c€•¦³Uã5|A©^ÇgþùÓ³·oßž<>A»ôùœÍfoÞ¾¹¼¸\€Zƒ¾E©"Ój CxkÊ¡ô°ÿE x…ù8.ÝÌô–uBˆô6õéãéþ$Ø#ÓÉdöíÙå?.¨ðåjöM³›5eG˜}Ž4È1ÂþÃóç?œŸœž>þzzøÊÙ¸ª?>ÿqödvñËÿw®<[“HºøÑH°$–'~}‰Žâ¥õ£C]B‡µ Àìá Ôpûªh®¢A«Ìç§~z¿úÐ?ÐîTÈB$Hò]#2 D¤–›CûÃü|~>~4µ\ì*ø¾rròÆgó³S°¹Þÿô^ÜaX€!gC˜ ·×IìÖ”šÝHÈð:œ'³èÈö‘¬3:d|ãâ/Þ½ûkFÊèÕS-Í%aÖÆä)Öj¸ $õì»9è·Ó§§ ØÈÚ|…ÈQ?ÐÕ?ÿòóõ?¯ƒ›[ðýT¹tg<’kË)ÿ˜²| SVhéógó7ÿõvþÝÙ^ &z¼áêêêÝ»wj,wz%§‘d0ÎAËó»9ðzòäDmÃÜ8Ȇ˛åíò*gñÛ#\F@^×RªáŒŠ¦çßÏÿü§?CÓïdä¿íœ,5dv}}}ñ· =¸¤to2-»X0}400 ì*‘Õ3Ž]j« ¤YF£€à?¾¡¢VáŠäV·1¢Ó“ñx}õúÕÙé²ÛE»ïbÒ,L ¡š-0 ¶†’Wàu&1•ÐîA¿DÖ^9²s•õó)IøøËG`=AR­j{«³ÓÙ73UK]Ý¿³Y•*" L+…>~Œ$N1z('=ð••ñ%œ—ó ¹¾½¹Uz¤vú56ýñx¬*ª[­vÓfÓ– ä;Ê¡H¬ªMÇœ¸RãæE¸lýðÇ…àžc ¸çî9‚{Žàžc ¸çî9þ \rà~ò嚦IEND®B`‚gateway-1.4.5/doc/alligata/progress.png0000644000175000017500000002747207344776077016622 0ustar toljtolj‰PNG  IHDR0ð/¥ttIMEÑ 0 V<<¦ pHYs  ÒÝ~ügAMA± üayPLTEÌÌÌÿÿÿÖÖÖ–––¶á°Áæ¼Âæ¾¾ä¹Úð×¥Úž”Ó‹±ß«îøí×îÓ÷üößòݧ۠”ÓŒõûôäôâ«Ü¤éöèÑìؚ͡–ÔŽ¸â³ÜñÚçõåËêǜ֕ºãµ¼ä·ÅçÀôûóØïÕáóßÍêÉT¹GmÃbqÅfjÂ_U¹HS¸Gb¿Vâóà›Ö“ì÷êZ»M]½PÛðØsÆhÇèÂyÈnñùïfÀZgÁ\ùüød¿X€ËwwÇlŠÏãôá„Í{|ÊrlÃa£ÙœüþûtÆi²à­X»KÏìÌ×ïÔ´à®øü÷{Éq[¼NƒÌyoÄd­Ý§Ñ†ŸØ—íøëËu®Þ¨©Ü£éöçŒÐƒ`¾SÐę̈ۡ²ß¬ŸØ˜†Î}чÓíЈÎ˜ÕÈèÃn¿Dg¾DŠÆ@}ÃBYºF’È?˜É>ŒÆ@wÁB†Å@`¼Eo¿CÇ?yÂB_¼FsÀC^»FÇ?”È>i¾DÄA€ÃAp¿C?Š5#L-c&S¶FF™;8{/:-11l*K¥?<„3B J¢>P¯C M©A&Hž=DL§@<  Gœ<! Q±DO®C +^$>5t-)Z#&S *K¦@9}0&U %QC”97y/ F/g(@Ž6P°C5A7# (W!4tÄDzÆCÌâ;ëí8ÿô6òï7Øæ:»Ü=—Ð@lÁE‡ËB?Œ6¤Õ?öñ7ª×>‘ÎA´Ú=®Ø>Óå:Y«?äë9Þé9ÁÞ<`©<(‰·7›Ñ@K‹2òøæûó6í÷çêêꤤ¤ÿ\.Úü,DIDATxÚí‹_Sg¾¯WûR - *5ÂE°*“iµN«Ž¶hÝUìîÌ8§ç$!@‰€­b½ÔËh¯Ñ޶Uë´µ³O;uOÛ9íìÙsfö>û\æœÍþ‹Îz×õ]—$ë Y ˜ïóQȺ'y~ïu½Kà‚Øyà?ÀýÍ,ɨ0Øxð?fÁ}Sª»áAE˜ÙˆaJ)Õ4C“=ûU˜ÌaÂÜ÷PảN“=ûšì†è¿ˆ¾àzË™Lg%êÄ|fâðJéð>¸ß—~ùœ¿ñ¹;…1å5ä7k²G˜lÂ8}mš&ìOgaôíù&k:êçq0Õ-¶cš=s&}„!êW‘6¼¤sˆ±À. sVÇsb}1ëèŽÓ²{aÜížá÷£0†êšy»ð »cFù»"ÚobþiŽv Ø—afggÙìËØn\‰.hW!æÝg™Í–7$¿Y=à1›LaÌ´÷ì¬õªöïÛz,!Ì¡däWî…y@!JÉat taˆõÿ¬ù5󕦆=«ù§®#ŒÃ™%ã„NoȺ`z—z^iÚ[{óÖkX>ŒõX‡Cç3ÂPYd+ÜDaØ´7}ý¦¯Ó8ØË0¦iŠ8dÖzÅÌïô›õûyØdw»·û±öóÌ_Ò £,²Â< D7ÆøÛ·'”šÖFÂ[¾OkaÁª1½šµdIÙ…!æýÍIgzsÚv%›ìæ N§Ð?£éSZ-!aÒEãK² c.NØ¿¡L°g5ÉFÂ8“.Â0³ÿ­ÏZ…™µ¼ç÷étŠ4X޽_…qÈ’rˆ0N±ØšLfS²EË®ž còö"³0ŽÇ.@aЏ6aœ ½i"Œ9‡Ð²‚Ùl…^&ך5j  Æ Ã~Í–¬dÖU¡—Mmö ÙΣdÚ“yûdÖþ™,8k}£ó™ô¸ªV§‰0N°Õjæë1ª¤³li„˜Â\*°DÌesiI~™¥Z=˦›©Êc>‚½"{e“0–•6,Ç_ƒñFç3Þµô:[Åþ¼óš…ðíxÖÒkÿ6@¼-2 áۡ˜û¢©Ù×äaÈü·Ef!|=4Õ ±$»‹5š00¼á~gލ¬eœ-Ú€QPlIîF˜b¿}°`…) papavaZÈã“_„tÂûÍ“0Åþ[¼ßH/L±ßYî@ïxÂJFkQ^`_© rf±ßü<°Â8íL”’0B™?èOAÿá ŒP¦o¤;Û×è?K’FÐìÐÿ1¯ÊaÌík؃JŒFi˜1¥x눽 Ãü7ÿ²NŠÝÞT„®R†bNuã…`0é…Ñt2²¤b78£«„)3%~Yæ,©,S„a÷+Å,©D"Œü !.„lYRé–aJR˜2=cä*³0ÖZ’iþ³Ô(!aæ@Iªá „Ɇ¹ðRò@˜¬ ³€Â. àÂ. àÂ. àÂ. àÂ. àÂ. àÂ. àÂ. àÂ. àÂ. àÂ. àÂ. àÂ.JMëd&øïp,½{"KL™Å΄ÉN) £Îù¡Î-eš&QÙY›ƘQ0& ag±Rö.ö‡.¥%Œã¬@¶‰…ÓÎæ©‡mº˜ô“Ýß@óäˆeeVaŒÐ‘~îªR±¥¬ä„؉yMSRéFÏ“¬S i„1ívßSRÂXªH¶íYR™cDI“•„1&KF-ô¦)ù  Sb°µ$™&QÙÑZKØcQKºÿ…q&§„. ;(qaržñ”¦09ÏxaJTÀ „\@À„\@À„\@À„\@À„\@À„\@À„\@À„\@À„\@À„\””0Ž7› Ì‹üL“ù¨´wJº¹àjÕÞwVJJ˜2¤ßÎEÚd4ní7߯àêöÂxDÆcºUÑXáx;¤mÒ˜2}ƒvFΉc\Fã,ú9;vÙ}MWb~A¾e¼¶ ã8S‡Û®ÕÓÌaâwÂXOÎÜém7Bº_ž|³%,L™ñµ:ÌÌPÆîç LŽǸ¦ÌA¬Â˜WzòÍ–ž0ì„.Z wÆ:iŒq ÿÄ1Ú‚MË}Ñœ%Y£ {z›0Æûöä›-=aô-æ?Y‡4OŸ%•9’6#Ê!K*³¿A` N·[™MŸ¼³%)ŒöÊ(÷r—aÌÅPë‘y+Øa 5æ=Q†™ëÇ2^gª%©ŸÝ<÷KÆIc´ýMµ$ž‰cóËæeú;1 Sfy3ì•ô_„áüXÆëœZzsþº=J§y„±cÉø€0 ’¹E˜\'‘-öG÷¸(%as¢ô„À %( ¹"”•¤0ÿä„<ü;„<@À„\@À„\@À„\@À„\@À„\”¬0ÿr£4…¹S’Âûm-hJP˜bBZà”œ0 @À„\@À„\@À„\@À„\@À„\@À„\@À„\@À„\@À„\@À„\d&P¿@!Æ+2 Ó$.PB¯€0€ ¸XØÂtB˜B³@… ½šŒ…ÃáÑT*5.ýŽ F“ñ„ñ–'ÌX0M ›H¥$_I™àÄÄ„ñŽ%L<99dVex|2ª…ã G˜Ðà¨9¬Œ&ãiö…0ž±`„™4É‹†"v†0ž±P„™0d GãÙö†0ž±P„G]F_u³3„ñŒ#LD®G\í a Ɔ˜Ý ŒgäI˜™[Ó‚Îo®º:&Â6é:Ý>218’©=/¥5ÒØw‚0ž‘a.ýV`¹ü¶‹cÆÂ™Ê1‘Ã1ŽÆ_­ô<>>žœœ<ú!ŒWäE˜™ËÒçïÞ¾}îŠb̵KYÃKÂ4æÛ`‚.mIÇÉ`0›{§P­öŒ¼sNî¾6%¿|ã¶œ7šÊx@|b4a*õ†ÝØ’aÇdZ€0ž‘a¾Þ:k, áF8ž!¸$ÙÌh$aépXª= …Ê=É„SoÓÐ`æÆ3ò!̯¯©e– ×oŸ;wã81Óo¤±åÕS9²¦{$¤ãs§.\¸0cÄ£¤ùž¥ìƒi ŒgäA˜™ËïÓ_S¯¿É|9ì9¦§<½!Ä”¡(âЬé;ï\¡ôék'ÏüJÛ|İ,ᢻÂxF„ùLÎ>¹bª(YBL§T4IŒ+ªLF'¬]GcQ5htž=ÉÔÏ…‹7ÔºÞõtÔ¢K$L&1D" Æ!ŒgäA˜Ïéã‚¶sD -©ñÉ„óÍjñÁAµ[úì›Ö³(¥#mJÄ”©/;‚vÏÈSÃ݇‚pùî­÷.³1zøF£ÁxÚŒd"¬ipá¤vìùSÇ><~çÎOo½óÑgÒ­”ÌÔ¾#Ñ4²@OÉ0·.¿ dOLˆ8ñFÖÖåve Îë•ãþåÃOØJù”6!â0;ÿT2cÕÂxF^„y÷õ©/§Lõóù)#Oš9}3ãa‘ÃräPâËÕ_«m~gìM8cZƒ¾f0s# „ñŒ”K¹Wß>{óìÛFÅZÍ}Âz|†0E"?ÂD¾¾÷¯Úëëz=iF|G8æØäËÌs˜’ 7gÏ+áå ©$sæ½kJMiúÍÞWöWÇ[ Y‚0…'?Â|{ïÞ—¢ø½œöSç5c>‘BŒpÆš½L˜ç9”3¤3Š!]½zæ#s-éœ\6Ѝ­½jå;2 aŠE~„ù뽤?ÿ$/¼£%¶äÊ¿ Óúð˜ˆqÛ¢4Ô:ùÉ ·Ï V.ÊÆÅ‡Ø<‰&K$éD¡‰‰hbRa<#/Â|wïÞŸ©0ûΔ'Ý–ªO‚pZŽ+ÉIçlD 0SÇ”ÝO›œ¸!Ÿ@)ñ(õj½Ö4³Mÿ k a<#/ÂH9Òïä8óÏté„–Ò’*¯I¿¾H“©%ÍᢆäÃDc£CCʸµ]&u8ÍBK¯gäA˜©KßhÂü•._e„y×Ò«4M±¹IpL Y9k½¤Úò›v–gãsæ³ã§Þ<ñg9KŠüíÞßäuÓ†0¢6®™*JcÚ“²ÆƒrÙ…/Â5Û˜O¥^ñ0…gN¼ë-A¸|Iüý½{?DÄ?ÜS„™b…¡c7-É-µR»>pá‹Óèš -9Îò‰„BÆ3æ ÌçòÀoÉ*̽oãQ…y›É’ĘBŒFT*¬ª]K7]ù"\VÚÿL¡*N ±!F*í&&cÊ4(ôzFîÂ|.·˜\¤µf*̽è9—Ò’ùœ* í>|û“ÚƒZáãÂùL–0•¦O$[Nœ½sçÎ æ4cZçuäðQS% ÂxFîÂ32 YŠ\è=£¥ò-iá¼’Ú´~}ù½w>6bêMgUÎÿæŒ"Æ»¯}  ³¹!¾¦v9\<­ösjtŠc¶AÀÆ3¸…Qr©—”¿¹¿ç_5a¾¡Kç´t¿.…A-ÃhuíËÇ>3ÎuÜÉ–és¯M}÷Oßû•škxOZyWª|} Gœ÷Þg…I¦RC£ÊØ©„2–jÂx—0‘äd”Ž0¸pãÚͳJýE^ÿ½&Ì?Ñ¥·´t•Ô¸CcÂŒi­pEëþàÐòrñÆ¥#ÿë/òɾþ’^òúö_Þ”ÕÑû5§?eÞU(‚aB“©Aš4ŽM ˆŸ*I÷ßè–¯T_~1±„v>Š¿´‘TlÑ-å„'í¾Ü¾tä?hú}­ºøÃÿüíE%Ø¥š×3å–Æ;\  ‡éPÜ©O/ÊAãŽZÜs˜¯•–{¬õŠòµ#òœMA¾Ëà¬M—S'Ä?|}Ï@î§Æü%’‰ÿ¦ïzÒ(Â@˜BâV˜DJ¹›uŠÆ ZaþBKºcË}4]iWÒ”>Ló˜Zk–{§Lõ!Z™²Œ¦OE¾at¡FÍì¾R >SF¾&[Cò ù¦`¸&N)Ý|ÿ ý}ÏèéÛïFäzÒ·t‡Oô4•Š*wéo¹»ú5V+tµ æ_>#f}¹÷Ïâ—?&ŠL·&=ù%Z¦RÈ•Õca¼Æ0“ÃÊ/+¥ÚÚ‹‰ ·ÿû7ùëDSI¸$^˜ÖŠ0Slޤܫo 0—/Y}ù!ôÝך92g"ŒdìI¹ùð(Ó5¥ÏEa<Õ0Aýѯ« vÆ• *£¶ÿ¿¡'ê)Õ)ZÂe÷½r}Ê!ÀÐã?Ý3˜IÕ—?+§¾iørlJ*[ŸÕ‚Ó98a¼Å•01}¬ÛÁ0F<{ŠIñkÊ@)£oè¸8CË-tÕUµ>4}íäqµ©ÖR‚¹ü®(~iöå‡ß±;â%#tÑ;O:ïjLÓtœ©Aã)®„IéÃïêåwiÁõÄqÙiÚ {U-ÛN¿ss†¶Ë¾s•ÖÃé×gΞ`n;1˜óô6Éoî9ñµÜ¶sé–^d:)G–ãFdÂÜÊ;0âV­×æ5ã^5YñêíæVÚC¨˜kò®3o]L›ÉiÖ—é×èªß;èòÃiUþÄ1M—+(“èÒ CÇqBÏp%ÌÐðð¸–ÒSgoÜýí[2§OÊÍvâ5{ùL 0çÏ(÷‡ÿmú‰¨>1˜Ega¾þ>Nï"Ðzœ®ÜPÇÏܦ‹Z'xØ"Œ$7„ñ WÂÎüHú J‚Þ¡fú–Zü9™áÆÇs¬/o)“4|k±å©Úõ±¿>:®&Ÿº)G¹ÓêâÛ8áQ㮄 Éã­ÓÏÊò¹’¨ŸI•î+úà—72LBuÕÔ‹ô©ºö«ß©Õ¢üý7ß~'\Ψ%¤é»×µ¹ ~uö˜Ò£tY볞´ 3<a<Ã];Œ2ÛF81WæÈ3Í•«ô:ÿW)nÜÖïV›ˆÆF(±£QëäbŸšJ¼ÆŽâ‘/%äWï×&Z7¡ZÕ¦É{N*àÞ¤¥Š±ŒS`Ž( æ;Ìeã™ã†'ß/±ƒò.¾yîSv*xÌñ*)z½Ãýxóä—ãJ1欔EÜÑ .éu¡y’Zî™Ñ•¸ü›37M“Áˆw˜pBó*¹xúÍwn¹þ‰¥=Ks©Iã\#îÆ‚ÌdîãjþrK¾'V)€¦ÒÊ–z_W…8÷‰­"u†‰'oÍ(·¬¼uçWÖݤ"õÑô‘,a¼ƒ¸Ú°šÒøP^Ss§4L…!Ë('eê bñ1{w5–I…17GâÁD,ãtãhéõ~a+É2¨-_7„q-€‘­¸Á„ úè¾8Ýó„À–XfõZT(:Î>Ix*a<„_µ$£ß×|õšz·¼(FÍÉ9’tœ ‘æH™ªQhˆVÒÃcìp=ʯ¥«óµc§Õ}dzº"C‹âÆ3¸…ÑZâcúš ïœÖ«ÅN=—¶eø=©°ËÜ'"[¦=â¬iÆ+gÞž‘PªQ‘l,Vâ‹\uƒ0žÁ-ŒÖ²šrºÞ¨·¤&Ä4üê¢pÚ¨I‡ä³ër°ßÛö–Ú‡ fjELyWÆ3¸…Ñç# Ûó› #åÒú"UÃyï&äü-ezXÒÙs憺sÌŽ™'Ï4Ba<#ç3<ð(U#Ïœ€0^“Ó„BæGÂ:aaŽfÚ8t4È–mÆŽÌM È’<'ǨŽ̤ͨª…ú655Í…–HÔe[?ƒÆkrž²l,í®R“Je{,Áî‘2w,E\=k˜7ÀŒA¯™Ë´«Ì3Iô$ ª™Î˜¹ú=j.äN8UzR# ¹FžÚa¼g®;‡‚Á„J4È<ÑÑ:8Ûô°FóH«Ô(}¾„ù‘xœž8ÆSCbº¯ ŒgÌU˜tвæW¦ž'£)‡¸™©ª¤•ëñ¡ÌîĘa<#OOd³2fKÏ!&ÆÕ, ºìèÔÔ™ ê„íêè7$@ñH§ÑN†2Jzºnéu ;Áh41)‘ˆNX[!Œgx%̘SÉUÍ—âöL*Ï@ÏðJû,e\]Èk_ Œwx'Œè0aPÞ@ 8©±9 ï„qè£Ô†u¦¬Õl³`ðH˜xÒ!¾„µšÌ$óÈr³°È»0ôF3§»‡´ÊÄp4‡3C˜ù@>…‰LD'Ç[×F¦2îhœïÌfÞ/aâ‡'»€Rã“m¹!÷'†0ó‹|ã0U%<™ƽ¬acÀ, K²Â'LxpµÎy( Ê0iá&¸r#ÂhUµ$¤Í’Ø Œ‚‡czç£0`®@À„\@ÀŸ0OÚè•V÷±+z61 ÏûÙM¹%?{îÂ<æD¬" äyiu3³štle6×w±›žÉM˜½ì9zæ ŒæÉA˜¶ÅÖ5õRaõå>I˜•úÒ>I˜uúRMÎÂôj/·ÏM˜bÇóM.Â,û…uÍÚåFˈ LñÈA¿ï5i**­Âüæþ$a¤ðaMšE5¢=Âè£5!Ì}DÂìôZ“æ—>ÑaL”hÔ#KZÈä LÕz[Òl¢e(Ãô60ìÓ7d1ÞiÙš1Ât²çêï…0ž‘ƒ0»l‰ÛAÚ3 ãž¡OZåßÒTïóù6,•ö›žPð¯[Ñ´ÚGYÖ¶h»?“0]¿l©©–v\_SÑÜ®¾¿–Ê¥Æ+ræáÇìá nO–Zƒ”%uì TT:´eñúºfñc“r†m duKó!Jwù²ŒÖÙ·xŒfñ]Ò‹ö_Ó¢G¥«­y‘좥ñ'vl\õB;„ñˆ„Y»È.Lã žjuïêÇÕåžd›¶©›ž¡§…lÜÄœz]K ­Wl©ojê×ZSS›ÓüšC;=·?F*{Å=ÝOVí‡0‘ƒ0ÕUvaÚʭ´ffwýõÅ=ŸÞÎO…éz¤úKÃÿöêÆÞ–JóÊ^ÒÞßV×mÙsÿæµ½½M••Š[Æø…éÑ"‚_ãšv5Åv7qD˜ÞÀJæ|[Öè/%aümõö¾¦½Õ•-•æU’0kê6ÙölßÜ"ö (>Bàf/ù{Ù›ªÖ@KiPìinµÓ—A˜—êL•œ.V˜Gk÷Úã—¸Ÿ÷e˜¦Æ&Òèf„é Ohq'°v}£îR3Ù¼k—nź]»Ö¢eH=/¶V?¢ï¹r5„ñ~av·©)ZN~zЧƇ^)pa¶ŠTTбe˜ªj-åŸ'þ½¤]Ûò$XÌV«­¨ÐËÊÛHo»±çóF;4„ñ~a6ª™ÆÎ•ë ©ÑJ ÕûÜG¹aE]w³Â ´éU‹~ß+ÚRé³4Ü <¢-íÐv ­¥—Æ:ãüÂ,ëVtYhéxzi{^þKoø™ûÃsð—âÊVF˜ ½Q®ÞüŠqÂ',}Iô·E…9¨Wõ{û!Œ‡p ãȃ*ÉAÙ-"÷ =\‘³03ÂlÔ˼Ý&a¤b‰0MXaÖ®Ð÷Ì* sW˜.¥¸àï®{üy©0Z»DÉ”jrÊ’r¦íV˜ÕÍ®…y€C˜Md§*E©l¬[¡.­\ïw=€Ê•0ÿ¹Uì©{Ú0~¹/Ke½ž;AÏপ^+I´7Ò¢%â&âÏK–´F»/`GkÏg6=Y¶ ÓV¡í¹"àofÆt5êÁÂx‡05ò/ÿ–†@k÷ ÕUJˬ”SåC˜ ãÆŸTg7.»lŸµ ÃÜC°$`äH¦pSQ!'Y=ù)½µ¤ÿу¤6ôï¬}%ÂèJ´Ôm`ö­]‘fÕêå}Ìž¦pÓ0 ÿ:T]OkGýmŠ ËºóQ†‘õ¬l$»ªÌƒêdalC4ý‡šÈêæ£¦pó¢:²·üÙ¦ŽC«7Wù•dlZœ§ÓÓ½¾¶ü Ñ‚S„ñïk%m7AB˜à^˜Þ€ÞGü Õzasw[~„Ù¶Ú·H3ã%½†ì$ÌÞÆçvh—ßcTÀ!Lp/Ì^­åýÉduóª:ßÏÕ4knÍK–´…T¨U#¿14°gIÛ5º­‹ˆÑpa €{až (IÛh8$¥_o÷ã¤i;]³Å·Âí}I„ñonQ³8Ñÿ_ž X„1E˜ƒkvª‹þÅ:SPÜ Ó­ôül[R« ìZ£†„v²4Ó}Ié…éf…ÙÐ+P¡Œ•¬ n…a†h.ª« ·Îfè­¶eIæÞjSX\ Ó§ nè«!Mjcëºz¢ü­ÿŒ¸ÞP¾Q_ع¢â—ÆÙ-½Õ# „)&®…QGÌvú«|Ë舂žµÛ•MUº0™#ÌJù¾Ø,©{Y&az-Âl€0ŵ0/ùô RAZº¶/ñ­Ðò‰ýÄmÃ]—éF6q»c„ÙCÒgI;É&“0u[ôJ<„)®…y¦F{µ®œø6’úf­ÐÛáZqqu»qÊCuÌ­²†0{I{ŸÑ aŽ0~²Ÿf/ÙÛSk  ‚0Àµ0Êýd;_i#­+û;ÅuªkÕ1bkazÙ¬%p9!Œ0•ëR4Ôn^¯ß~/ Óó¬¡OY]«¿-ÿßú:£ÇÂ×Âü§åò¯äYmž»þUD½Çùq÷“"ö>ö솥{ö¶oiñU/f…aZ‹û·T1Ã\¤R-1º"ýû]bìÙ[õ(± Lp-L½:`öézŸR»éÝMšTÚxfÑlß±¬–º†æþM†0ÍOÖ²ƒ[˜‘ ’0K~ÆlÛ]ÎXA˜àZýøþŸÚ:¤ÈÁê}Z²¶¸¦¥M¡µ±­–u/Z*ú}Ì`Kÿ.½Y™ ³Ô׿“6ÒÍ,m\ a ‰[aö}b—C¤±oSyLŸmÁýx˜¶TZÈØÞê–‡ÅêŒÙ“ V˜þÆFf&¦:ßô…̽ú¦¸æP]_¥¯{+iÚ#E†þîVÒtH^×µ(Ð¥Ñ. Ó¬/uKÂlÒ—Ö>³K=¾ò=k +švˆ=mµÏ(¹RWK ±I?Š6´tm¨Ý}¨]]Ѱ£Á׬4ö<[a Š[aºµÛßôqS¢ÿÉN÷Çule,sܵŠl©a£ï9©„´ó¾º5+›+}Õ{v3GÑ–¹ÝkúŠú—|•Ý+W¶T×Vµª5„ñ·Âô®S1Ïô“u6üÌB‡ŸÝÔûhm¿èĪjù´ý/UnØÚZYÕ+v±GiVi+¤M×ʶ­[·6ü¢OܾŠÂxNaŸ—ÔË–l ö‘-¼§Ê8Õ/„ñŒ?`k…o»meí~_2a<£ÀÂø+Ÿ{Æ2ýüMdin'ƒ0E Ððóÿ]µ¯²J+ltmZQCÖ>Ÿ÷«@Ï(ü3ûW6ùHà`£D€¶–ošû)!Lá(ÊCB{:öw7Kìyªwî'ƒ0O•\@À„\@À„\T˜<·çB˜"Q_MžQ’³«Å¶¡Bª_÷4¤?™ZžñÔ´GR_@¯È(LÞQM‡mÀ(ú»éüùN¿#ÉD¼¥a¼¢àÂôÒÝ­k_~¹&ðX€ÔU,?Ð mè¦÷ORýØòtǃ«–/®¡/Ö.^^¾LZ~ùå—« Yß²|ÇimÍË/ïªÞ±x5=¤rù¶„)fݳ=¢XÓ.Šíûý¾Fùî€MÕýr„YCGËø«ž%å;éú'kÉKtÔ¯)¡7-m$Êö}"å?}¢ø÷õdÜVüÄfS +L'}æˆ$LC;½1`§OúÕ%IðFì}QJü>éUùsô…äŒü<®ŸÐûda|ýÊö¨0~êÚªÍÒ*Ú“Ù a DA…¡“žéÂHiNÇŽX)JæÐ{Xéú O‰â¶­Ò‹%O‹âÊ’uýêƒw6ÒJ[Ãveqïii ‰Î*ÔAŸ±a CÁ³¤®n)Ìì’…é§ìø;éÇ‹´´žÎR#qúèähmÍííK%Oz7okoo’…Ù-ýذ‰ŠÑÕ)n¢;=S) ³þ uÆFSŠQKý4/«¥9Î:Æ[~ÓzjÅ^)7ê÷õÐÙ€¥’,5j/-˼`#*Â,ªÙ·o߯~ù1\¦ –ñÂ一0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸€0€ ¸( a@þ(aÈ#% È'papapapapa%#Œ×},‚õMü‚únKF¯i¦Ð, &O—,´0A˜<~(ãõu!Ì\/ a ×%!L‰ #}ølIi{Faígš3i/žþ’&ŸŠ_Aÿ‘eŸt—t% ÷Å!La>·0Æ·¯ü­ eÊŸ¼ÀþÊY˜2ý/æŒ0‚åªJTÒB“) A˜|~¨Ü…QSQMTm©,S†¢\Ò­0ªŽeNÂØ.'(ÿYö‚ún!Œüù- fEò/ŒñOÞ,!̸¤uOã݇š[–dÆX™ö’™kI‚EôsÙ„4ı¼=2í ôÝBùó³/#LY¾„1V¦;4ÁŽÒ^°@ß-„Q¾õ‡åWÚKfi‡1Õ¬-ÙO–2 ²$ï?ÔÚaAûÓ·U[ò"Œ~Ê2»0e¦÷`”uÓÖt,Ðw aòsI´ôB®KBÃuIa¸. a ×%!Ì}'Œ·3í8Sà è»-a¯±¾‰‚_°@ßm©ò„\@À„\@ÀEza2˜§×;Ò ãõ­ÁÞbãyí¶äH# €0€ ¸€0€ ¸0 @Vap„\@ÀæpK±ËQ`¡ñÿ¥9ÐJìs6ÓIEND®B`‚gateway-1.4.5/doc/alligata/12-9.png0000644000175000017500000001327407344776077015341 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ  Ï«àê pHYsÓÓŽ{¸®gAMA± üaKIDATxÚí]¿—Ü6’îù=RÙ‘ä¨[‘¥hz"ÛÑ´";Ó8»ÌrvÙJÑÞEÞû¬p£›n3IÑù"¢µ#uGžšIŠHFÓŒ°U( þôt7ÅoæÍ°Ñ$àC U È…lÄpño‡.Àˆýb$xà 8F‚Ž‘àc$xà 8F‚Ž‘àc$xà 8F‚Ž‘àc$xà 8F‚Ž‘àc$xà 8¾8tŠáŸP„"L°0 )™–…ð­áüSÕ øm„W5½›Ã³8àœ3‹9ðÃ1[ð£ÅÔ·t>|ä¨>;ÜÙåeºér¸s‚ør"O11˜²•_‘:gG°L—܇’O•›D¼p0¿~%æÏQˆ!ž|ƒÜçÆN IÅ O/êj]Dõîpy ÌáNzïmU¥’!"%UævÉ{FaHQÔG&YÜ•Ih ^]RÎî Áq÷bVÁ½õÎÁîÇ1ñ6¦:6²Ž=ÂBå?ÓûÓ¾ŠÙ†` /¸ –¿ Ç ]¥Ml…Ò¨[ä‰D-L+Òœ¨)Ò%*kÐD^ÕÇ¢5åm "/ø©¤¨M®»\ò…NÔ—ma9á–»6s]DZ]ÀäÞ¤5å Ž˜ç{ÞÆ ‚ç ,”Ê Ë\²9…)ò*6",ÏJG´.Éa7·ŽeV—6ülíNeRwÂT%à"`’´:Ôìû>Ž»[2iv¯S[5ìQƒæY§:úÇ„‰Ì …×&ÇíºQ¦Tµ‰ú½Ê*ÒèZëñÔ?2éÙ7W¯Þ««B9'U£{j|ÑA »\u;vZNš‚¬•Ťu’Iêœi¾|“é'ö†F÷m”XÌ™†¹96SmËÑ1âðÝÇ8Ñ©M†Å„sl•ƒIAH+å‹QÔJŒ^I]“*%2Óë)±©æÔϯ¾¶XhÊOnQó¢–ÀqÒfv¬vcg…ö»òÚ̪VîbVÈ.Éqö™Z6òéW4DÇQ¹Løò– Iaº£ :ÝüY#2Ò¢¾è‘×#EÇ5Y²8ñ¡¾.;YÝy÷rÙŠ¸Ú¬fKa@±Q4 ôóñ[ÍÇåiê]¿”àŽ ¹äÝLe‰™“§2×êBŸOÔSLJuZ0\ÔQaE7£¸ì‘¡ŠÄí›É¤,þ_ç¯.Õ)ÂD²ËU4Mv»¹$«Û®EË6z©õ]†„½o£tœjð8KµÔ=Ü-¸ŸQ†‡®ìë.¾hB_1£Ú©NÙój…àöˆ£êvû€©ŠÎxM2í’yº«ðiîüC½e(Ì*Ÿ¡^˜FY‘ÿ©¡Þ']ö>zïþùNÜ̦í×vOñà»Çéx0“;MÜÉÙý³ê Y 6ìoJs’ŠÚÌýqJÛ Ÿ¸:íf›8Õ«âãwU~v0Û¦£ñ4éê·gN“GGtïЫ\Ñ!ÆîÇ’ù®0P¬u*ºùê#Ž mŒ¬Îkö­q@É‹êYÕKvJ绣7ÿTP¾l¶­á¬oÂ’¤°ôÓù'AL®bcg*@ÍZmE—rL>ý/¥—¹$3.Æü¶7W¤‚ïU>>*³è¥4-íeÚÚŒ}oQvŠéá¤:=ÛM’N«²WëéíÛ¥¹3׎Ì¢L“:]T´ôm4^’UÖ5ñ_fÎÌä©[*Îcx0Üó·¡££2Ø` 6ÙA÷<çó1ñ›?&süHÚûòñ/)g–z«q Ç•Ñ$øÝÙè°ê—ÐTgÕË uN$S@-œá˜[^/[Ö5ÈøÂ}Xz²±kÇচv€¡ É"qœþ¢žƒ*#«ðòÐ`—qstyÒ°CRшü«ßéŸÁ#€Uó`^ÑAî|ŠlÎî0m«´*Ž_NZR Æ7œ¨x&ºÑüùnݤʟ™ù¶i1N<ù£Á|zSþj»(¼¾yïùå<ñà8išÁRÒ# ÷‹æÎôþlæÎª/¯°¢âü#Š2<>~w(™Z•chŒšhR^ºÃ²/Fì&tÇ`ƒÃ$‘ÐÂØÍîâ`pa¥=nü},@ùÊ»±L(®{°·Äøn¨_¯|ù<òÈü!ýZ_öðë™Lq\›Ïî׿”£ÊíXüÛŸD‹•õÃù¤éÛ¡GtnEÂ&o¬øóì«FºZÑ\⣠e¢ÕÝŠ¥öxaFÍÕYLJ1Xè}Æ€gç Â………>Ô9¼Î]•¼gÁUs€tOfò¢ÍîôWþ>‚ö™P«Ckum¥Í*#ŠkVt¨U?ZVŠÝ÷Ï’ dv^/ dN`Æ/egCì"eë +ªIŽŽ·0æñ¼ÉL„+Ç`tGãLIΔ3Qò5—E«mò»Ó2³—²Wœy¢Hâ`¦Õ´x†Ýdÿ”NáB‚cs5W2¶¶ö±È&i”îí{ÇÈËeEO%ñ‘ƒîN’»7?§Î´8.¹±ºü™ŒIa”PŽÄ×KßÕä)3†ÝÑ];#ižŒ°b€ÎâÊzŠ]dè ¨©‹"ñOýw*w:»7Ÿ9¶‹“%Z¾cæ½âšDÛ =tÙícžûM}kÕìÉcz¨Öø+)d1gôqGaIØ Ù%€ø:âËê% gsòYRí_—tƤ—ó_v½Oë›\«³^ùêD\8Ðû{?¿ª#fõsò)™_³+ëØ³VOêìÇJˆ±Ïq‡Î^¬hÛq7Øúú‹f“%œô9Ó“Å”^¸Þ³:‡|n&g6F>œò¬ô n¦Av, ¨'Zb¡ÔÒ 3¹¶;q¦†\M"l‚Íúãš^',ô£¤2}rpÊ(n~ïDØr= ±Ë]¹©;5¼¨þÉ÷ž;q'|Ë‚mˆï0ŒŠÖoÖV¬9ôÕ¹NIz;–0lz‰!m-Ø•Ôâê Û:ÓÚaênµÌäZh/ðüÀãÝ…}¯ðÚ«}MÓKK”?!ÃiÙíê¨Ï”Sß)YÍ/“[ \GX»åÐ’]xÙmÄ.«&8™W 9ö½ „Á÷GT{…ŸôÒ;ƒMÝîVΗ$g.Ä.Ê.PÛÜn0’`pÜ‚ƒÂà[ý#£ Ž©bæ '– ®}Ká;i—“Ãtоæ‚m„A …aÍ¥‚éêö }¢w$mØ"QVøbg±üŸPË™¢*’‰ñG¢“1Ö‘È24&˜ÂO„fuöâxØØ=¤ÎgF¹lhËÔ4RoÆ-è Í,Q矉›µxDœædþ'×ÁDR˜@ã×Ö¸ô§¶Èþ•ªÔ•èñ]%JæyžÕÏÆß`†Ò="­{¤íx¿i‹;6|t’ DÔiɼz]ADH±Q›$-F±½¶‚8†é  ´$ÈÆåååì«Y_eé*ÁP&ãT(.®äŠ0~$a)ÏxšB’xUù0twöÀu'<=²czvÊÑŠ~’”ÑŠ7PEh­Â9A\/¯WëÕ_þë/Ó©©3²_tß0v‘Qæ@ü>{(ʰý!yÂÂúC>&±¥‰r4øŸü Þ® r€5|úäéóçÇîÓ†š&U’€fL4'T»‰üζ”(£CGâúÿ¯_=zõÓü”ôû.è Áó>xX=óâ`½^o68`2…AF[ÎólrĨ€Îøn^¡ãY#høÕÍr}ãy0g÷~Ÿ£Qï^V7+4;¨œ[&¢xŠ›¡z}•š& :Ö•³€%Á››P^qõ׫ùãùâ»E÷B¶'½ZŸ…¿Þ?=à›Ê—hdšä˜Ç~d«1˜h†cèÕ6v^ÈÄÿˆ¡ËŽš`².‘9Yß DE-ý¸!iÝdrÇ$夫Rw“§ÑÚbÀô›_ß,‹îƒT{‚(é%<¥©±‚JÜJ Ç/úPV¢Æ¹rñP†Á¶õ[¹îPk˜>€®ÁFØÈÖ ÿO†r*I3ºüÔ K°ÞJ Vü7Ä¿ë›5´êôAב¸-ÁŽ—ðK=4Ø4_ôHÿ†r·[3ר)¤ä† :ÊI8œ-Tc«ÕÊ$,¥À²Šò(_™¢@GºÑÐzýèO']-Í–¯$µè•ÜÆFc¤uC½ÜJ¤Ø’Í)G#tZáËz˜ jxÆ,ß 7\³<ŽÇ½V iúúªÜÈ΃ˆ2|‹ÉNl`Æà©ØCÞ(•¶u mA%ÀHܱ„Æ`4 7Ür;¥š±(hñG¨üÒ\ð‰\°Ç1úh¹ÌÆq×aüË™>˜L¶^pý? ½Û žï;½Ø{Œ,ÒÍL*Ù ÊPÏǰjy»ñ#˜U€Z"í-Ð[A|;4‡Œ4òá é²õ¶üc½ø.¬Ý¬°íUtbP £Ø8ônE%éDGÇþ‚úrïM8(±Øœv¡‡Ê®M=`>u½ß××Ù-êL²ô\Ãe¡‡„,çÛ7oAÚ¤Áù_!æ~u1}xU!–.*ø Ó\äÔÈ‘Ø~„Ï^s¹Ê–+ÈjdÁm°ÓØÊØ–`ÙõÀˆª ÓIóJ¸_Î/¾ûa‚Åäjù=¾F\ZÛ “æ˜ð%’õÈï¹ïÿ¬–K\-‚ú +öã¿ÿx¾X¿Cœ=_\,þöúoÂÆi’+÷šFÞÜž¸Mƒø=‡¹r0â®Òd'TXah™[h °ÂÄÔuƒß_Þ;˜œƒt~·WÑ0ù3አ¿y+8Ûàˆ„èß‘T5LA3Œ.«úÒÚ|úä)Ìñg&dÎ@ÀìËÙ“Ë'o®ß(wl ~s½ô–;ž%•¬MÎPh.NQ±ÁhåΗƒ²ÃUoâí톡bC¯®Ñ¹?é¾ûMK‚áöP7("Xz¤aäû‚õòšíz`m nQçÕæ‚–C£Žë¸O¿¹xñâÅÙÃ3´KOPÎù|þüÅóWW¯– ‡¶ oQj…Àô€VBÞ–‡P{HÇ(^¡?ŽËwÛ3È6aLÎ6õÙÃÙá$Øb³étþõÅ«¿_qá:<¤ÕC<)nÚ8”n¡;nÔ9Ò Gû÷——ß?=;?øÕìø•³˜ªþxùãüÑüêï¯Þþßk˜Ê;[È)~` 'öåÉI¿ºDyñ’öQ®.¡ÜÚ`~ÿ Z¸{S´WÑ U‹ó·¿¾Ù|ôèèwä²qârçƒbLº˜Ôr o¿_<]<<˜€Ú?-v ®ëž=wÅÅ9Ø\o~}#nÑ-à g]˜ ··±ïV—ŠÝ@H÷N8ÏæsБÝ=YVtHÿÆÕÿ^½|ù‹ïdôª¥–ú–0[mqk 7¤^|»ývþÍ9vò¤6Û 2êºúÝoï®ÿqíݬaîGõRƒ±-÷–£ù1w²ŽLÙH ¥Ÿ>Y<ÿó‹Å·%˜©xÃëׯ_¾|I±LL´ Ncq0ÎAËóÛðzöè Dmã 6Ù|u³Z¯ÖÐ8Ë?–èáÒòª• §50½ønñóþ ]¿—È×5Y2»¾¾¾úë• .‘î—…â ¡ë‚F]Yµ"àÔ¥¶ $ÍÒ¿÷ø††Úø–ÙÝFóNO'Sàõ§?ýtq~ìöÑïûXt'+ãIP·¦ÁÖ y^ç3 5=–ÈV7Ž\eû|ð@ÞÿöXO"HÔû¡ep´º8Ÿ?žS+õuÿÞVU’G˜&…sü H\bt_.4ºç’•ñ9B_—ó¹^߬IoƒÔξ®?™L¨¡úÕj{X6›¬°$Œ‹îtЄ"¶ªvs<•êÇ´.zÄÐðÑ#N #ÁÇHðÀ1 ]> Server User Manual &version;
e-mail: sendinfo@3glab.com Web site: www.3glab.com
Copyright (c) 2001 3G LAB Limited. ALL RIGHTS RESERVED. The 3G LAB logo and Alligata logo are copyright of 3G LAB Limited in the US and other countries. In addition no part of any documentation contained in or on this packaging may be reproduced in any form (whether by electronic means, by photocopying or in any permanent or temporary form) without the express written permission of 3G LAB Limited or except as in accordance with the provisions of the Copyright Designs and Patents Act 1988 as amended or superseded from time to time. Linux is a registered trademark of Linus Torvalds. Solaris is a registered trademark of Sun Microsystems, Inc. UltraSPARC is a registered trademark of SPARC International, Inc. Wavecom and WM02 are registered trademarks of Wavecom S.A. Nokia and Premicell are registered trademarks of Nokia Corporation. Siemens and M20T are registered trademarks of Siemens AG. Openwave is a trademark of Openwave Systems, Inc. 3G LAB recognises that other trademarks displayed are the property of their respective holders. &version; ×tamp;
Part One: Getting Started 1 Welcome Welcome to the Alligata Server User Manual. This manual is in two parts: This part, Getting Started, provides an overview of the Alligata Server, and explains how to install the program. It covers the following topics: How the Alligata Server fits into the architecture of the Wireless Application Protocol (WAP), the Short Message Service (SMS) and the World Wide Web The internal functioning of the Alligata Server The hardware and software you need to run the Alligata Server How to install the Alligata Server from a Linux/Solaris windowing system, or from the Linux/Solaris command prompt How to spread an installation of the Alligata Server across several computers in order to maximise processing capacity The second part, Using the Alligata Server, is a detailed guide to running, configuring and using the Alligata Server. It covers the following topics: How to start, stop and administer the Alligata Server How to change the Alligata Server's configuration settings How to view the example WAP sites provided with the Alligata Server How to create WAP sites using Wireless Markup Language (WML) How to create dynamic WAP sites using the Perl scripting language How to create dynamic WAP sites using the PHP scripting language How to use the Alligata Server's SMS features to deliver World Wide Web and other content to mobile phones How to use the Alligata Server to send SMS messages from a computer workstation How to configure a mobile phone for a WAP service 'over the air' using the Alligata Server's SMS features
1.1 The Alligata Server Package Your Alligata Server package contains: An installation CD-ROM from which you can install the Alligata Server, some example WAP sites, the Apache Web server, the PHP scripting language and some modules for the Perl scripting language that are useful for developing Mobile Internet sites. A booklet, Your Pocket Guide to the Mobile Internet. This Alligata Server User Manual. An Alligata Server Quick Reference Guide.
2 System Requirements There are two versions of the Alligata Server, one for the Linux operating system and one for the Sun Solaris operating system.
2.1 Linux Version
Minimum System Requirements Hardware: 100% IBM-compatible PC with at least 16 MB of RAM Hard disk with at least 30 MB free Connection to the telephone network via modem or similar Software: Red Hat Linux version 6.0, 6.1 or 6.2 or Mandrake Linux version 7.0 or 7.1 (The Alligata Server may run on some other distributions of Linux) Perl version 5.0 or higher. Perl is standard in most Linux distributions. If you do not have Perl installed, download it from www.perl.org
Optional Hardware Accessories Connection to the Internet, either dial-in or dedicated GSM modem (Wavecom WM02, Nokia Premicell or Siemens M20T) or subscription to an SMS Centre (SMSC) or GSM mobile phone with integrated modem, for sending and receiving SMS messages
2.2 Solaris Version
Minimum System Requirements Hardware: Sun UltraSPARC with at least 128 MB of RAM Hard disk with at least 30 MB free Connection to the telephone network Software: Sun Solaris version 7 or 8
Optional Hardware Accessories Connection to the Internet, either dial-in or dedicated GSM modem (Wavecom WM02, Nokia Premicell or Siemens M20T) or subscription to an SMS Centre (SMSC) or GSM mobile phone with integrated modem, for sending and receiving SMS messages
2.3 Optional Software Included with the Alligata Server In addition to the Alligata Server software, the Alligata Server CD-ROM includes the following items of open source software, which you may find useful in setting up Mobile Internet services: Apache Web server PHP scripting language Common Gateway Interface (CGI), HTML parser, HTML tables and WML modules for the Perl scripting language The Alligata Server installation program gives you the option of installing any or all of these pieces of software at the same time as installing the Alligata Server.
3 About the Alligata Server
3.1 What is the Alligata Server? The Alligata Server is two applications in one: a WAP gateway and an SMS server. As a WAP gateway, the Alligata Server is an entry point to the Mobile Internet. If you are a system administrator, you can use it to link your company's employees' or clients' mobile WAP phones to a local intranet or to the whole Mobile Internet. By using your own installation of the Alligata Server rather than a WAP gateway belonging to a telephone network operator or an Internet Service Provider (ISP), you have complete control over what services you offer your WAP phone users, and you can guarantee they will not be restricted to sites 'approved' by a network operator or an ISP. As an SMS server, the Alligata Server allows you to send messages to SMS phone users from a computer workstation, and to implement dynamic SMS keyword services such as retrieval of information from the World Wide Web. Although SMS is much less flexible than WAP, it is available on almost all modern Global System for Mobile Telecommunications (GSM) mobile phones. With its SMS messaging features, the Alligata Server provides limited access to Internet content even to users of non-WAP phones. WAP and SMS complement each other. SMS is simple to use and widely available, but limited in its capabilities. WAP offers richer functionality, but as a new technology it is not yet as widespread as SMS. By offering both SMS and WAP functionality, the Alligata Server is a bridge between established and emerging technologies. The Alligata Server is based on the Kannel WAP and SMS gateway for Linux. Kannel is an open source software project; if you would like to know more about it or contribute to it, visit the Kannel Web site at www.kannel.org.
3.2 The Alligata Server, WAP and SMS This section will help you to understand where the Alligata Server fits into the architecture of WAP and SMS. Before you read it, we recommend you read Your Pocket Guide to the Mobile Internet, included in the Alligata Server package. There you will find definitions of the terminology used by the WAP standard, and a description of how the WAP components fit together. Every WAP phone is configured by default to use a single WAP gateway to gain access to the Mobile Internet. This gateway can be hosted by an ISP, by the phone user's employer, or by any third party with access to the Mobile Internet. A phone can contain configurations for several gateways, but it can only use a single gateway for the duration of a session. If you want to change gateways, you have to close down your Mobile Internet session, switch your phone's settings to the new gateway, and reconnect to the Mobile Internet. The conceptual model into which the Alligata Server fits is shown in Figure 3.1. A signal sent by a mobile device is picked up by one of a network operator's base stations. It is then routed through the mobile network to the Alligata Server using User Datagram Protocol (UDP). If it is an SMS message, it is first sent to the network's SMS Centre (SMSC). The SMSC's main job is to hold pending SMS messages for recipients whose phones are turned off or otherwise inaccessible. Once the Alligata Server has received a WAP data packet from a client and decompressed it, it uses Hypertext Transfer Protocol (HTTP) to retrieve data from the relevant content server on the Mobile Internet. On receiving an SMS message, the Alligata Server scans it for keywords and parameters listed in its configuration file (see Section 13.1), then sends an automatic reply to the client device depending on which keyword and parameters it encountered. This reply can consist of static text, or it can be retrieved from a local file, a WAP site or a World Wide Web page. The Alligata Server's reply to an SMS message is another SMS message. This means that, in principle, it has to be sent to the relevant network operator's SMSC in order to be routed to the recipient device (or stored if the recipient device is not accessible). Most network operators charge a fee for terrestrial access to their SMSCs, but the Alligata Server allows you to circumvent this if you own a GSM modem, or a mobile phone that includes a GSM modem such as the Nokia 7110 or 6210. The Alligata Server can use the modem to send SMS messages directly over the airwaves. This way, you will get charged the same rates as mobile phone users for sending SMS messages from your computer workstation. See Section 9.3.2 for details of how to send messages using a GSM modem.
3.3 Inside the Alligata Server The Alligata Server is a collection of three programs: a Bearer Box, a WAP Box and an SMS Box. In fact, an implementation of the Alligata Server can include any number of WAP Boxes and SMS Boxes, all linked to a single Bearer Box. All incoming messages pass through the Bearer Box. The Bearer Box performs preliminary operations on each message and forwards it on to a WAP or an SMS Box depending on whether it is a WAP or an SMS message. A WAP Box implements the WAP protocol stack on incoming WAP messages (apart from Wireless Datagram Protocol (WDP), which is implemented by the Bearer Box). It decompresses the WAP data and forwards requests to Internet servers using HTTP (see the booklet Your Pocket Guide to the Mobile Internet for more details). It then handles the replies from the HTTP servers, compresses the replies, implements the Wireless Session Protocol (WSP) and Wireless Transaction Protocol (WTP) layers of the WAP protocol stack on them, and sends them on to the Bearer Box. The Bearer Box implements the WDP layer, and sends the replies to the client device. An SMS Box scans incoming SMS messages for keywords listed in the Alligata Server configuration file. It carries out the function associated with the keyword - for example, retrieving a piece of text from a Web page - and sends a reply SMS message, via the Bearer Box, to the client device.
3.3.1 Program States At any given time, the Alligata Server can be in one of four states: Running. The Alligata Server accepts, processes and sends files and messages normally. Suspended. The Alligata Server does not accept any new WAP requests or messages from SMSCs. The Bearer Box does not allow new WAP or SMS Boxes to connect to it. No messages or files are sent out. Isolated. The Alligata Server does not accept any new WAP requests or messages from SMSCs. However, it continues processing messages already in its system, and accepts SMS messages sent via HTTP (see Section 13.2). Shutdown. The Alligata Server performs the shutdown procedure. New WAP requests and SMS messages are refused. Requests already being processed are carried through. When all queues in the boxes have been processed, the Alligata Server closes down. You can change the state of the Alligata Server using HTTP administration commands. See Section 8.2.2. There follows a more detailed look at the components of the Alligata Server. You do not need to know this information to use the Alligata Server, but you may find it of interest.
3.3.2 Bearer Box The Bearer Box is the interface between the mobile telephone network and the rest of the Alligata Server. It receives data from mobile phones via network bearer services or SMSCs. On receiving a WAP data packet from a mobile device, the Bearer Box implements the WDP layer of the WAP protocol stack on it, and sends it on to a WAP Box. If a session is already running between the Alligata Server and the client device, then the message is sent to the same WAP Box as previous messages from the device. If, on the other hand, the message is the first to be received from that client in the current session, then it is sent to a WAP box at random. A basic system of load balancing is used to avoid bottlenecks forming in any single WAP Box. Load balancing works as follows: at regular intervals, each WAP Box sends a 'heartbeat' message (see Section 3.3.3) to the Bearer Box indicating its load - that is, how many sessions it is currently handling. If this load is significantly higher than the load of the least busy WAP box, then the Bearer Box stops sending requests from new clients to the busier WAP box. When the load of the busier WAP Box has fallen sufficiently, or the load of the other WAP Boxes has increased to near its own, the busier WAP Box starts to accept requests from new clients again. Messages are distributed among the SMS Boxes in the same way as among as the WAP Boxes. That is, the Bearer Box sends all messages from a particular client to the same SMS Box; it assigns messages from new clients to an SMS Box at random; and it uses load balancing to prevent unnecessary congestion in any particular SMS Box. Within the Alligata Server, the Bearer Box acts as a server to the WAP or SMS Boxes. Once running, it keeps a list of all the WAP and SMS Boxes connected to it. This list starts out empty, and is extended as boxes start up and announce their presence. The Bearer Box is in constant communication with the WAP and SMS Boxes via 'heartbeat' messages (see Section 3.3.3), and dynamically updates its list of connected WAP and SMS Boxes as new boxes connect and old ones disconnect. As well as receiving incoming messages, the Bearer Box processes all outgoing messages from the Alligata Server's WAP and SMS Boxes, adapting each message to the bearer service of the client's network. In the case of WAP messages, it also implements the WDP layer of the WAP protocol stack. Since all incoming and outgoing messages pass through a single Bearer Box, there is a risk of bottlenecks arising when traffic becomes very heavy. The Alligata Server is designed so that the Bearer Box does as little processing on each data packet as possible, thereby reducing this risk (particularly if there are several WAP and SMS Boxes running on different computers).
3.3.3 Communication Between the Boxes Data is exchanged between the Bearer Box and the WAP and SMS Boxes via Transmission Control Protocol (TCP) stream. TCP is a protocol suited for use in wide area networks (such as the Internet), and its incorporation into the Alligata Server means that the Bearer Box, WAP Boxes and SMS Boxes can be run on separate computers, if required. The advantages of this set-up are clear: it means that, outside the Bearer Box, groups of packets can be processed simultaneously, and therefore the Alligata Server can process high volumes of messages very quickly. If the TCP stream between the Bearer Box and a WAP or SMS Box fails for any reason, the Bearer Box notices this and removes the disconnected box from its list of available boxes. Any packets from phones that were routed to this box are then treated as packets from new clients, and redirected by the Bearer Box to an alternative WAP Box. When a WAP Box receives a message from a new client that it identifies as being from the middle of a session, it sends an error message to the client device. A WAP or SMS Box can also go 'catatonic': its TCP stream to the Bearer Box is still running, but it is not responding to any messages. So that the Bearer Box knows when this has happened, WAP and SMS Boxes send 'heartbeat' packets at regular intervals, effectively telling the Bearer Box that they are running and functioning normally. If the Bearer Box stops receiving heartbeat messages from another box, it assumes there is a problem even though the TCP stream may still be running, and removes the box from its list. When the ailing box recovers and announces its presence, the Bearer Box reopens the connection.
3.3.4 WAP Box A WAP Box receives data in WDP packets through its TCP connection with the Bearer Box. It implements the and WSP layers of the WAP protocol stack on the packets, and then decompresses them. Each incoming WDP packet is handled by a single program thread. This thread creates and manages a WTP state machine and, where necessary, a WSP state machine for the packet. The same WTP machine and WSP machine handle all packets from a given client session. If a packet arrives in a WAP Box while the WTP machine for which it is destined is still processing the previous packet, then the WAP Box sets up a queue specific to that WTP machine. This is preferable to creating a new thread for waiting WDP packets, as it reduces the risk of the WAP Box's thread table becoming full when traffic is very heavy. Once the WTP and WSP layers of the WAP protocol stack have been implemented on the incoming message, the WAP Box converts it into an HTTP request, and sends it to the relevant server on the Mobile Internet. On receiving an HTTP reply from the Mobile Internet server, the WAP Box compresses the reply, implements the WSP and WTP layers of the WAP protocol stack on it, and sends it to the Bearer Box along the TCP connection.
3.3.5 SMS Box The design of an SMS Box is straightforward. An SMS Box receives SMS messages from the Bearer Box via its TCP connection, parses each message in order to extract keywords and parameters from it, and then executes a service according to which keyword the message contains. The keyword is the first word in the message; any other words are interpreted as parameters. See Section 13.1 for more information. If the SMS service in question has a url variable defined in the configuration file (see Section 9.3.3), then the SMS Box sends an HTTP request to the appropriate URL, retrieves the data, pulls out the content between the prefix and the suffix strings as specified in the configuration file, formats this content as an SMS message or messages, and sends the SMS message(s) to the Bearer Box via the TCP stream. The Bearer Box sends the message back to the client device via an SMSC. Other services the SMS Box can provide include sending a fixed text message or the content of a local file in response to a keyword. For more information, see Sections 9.3 and 13.1. The SMS Box also listens for SMS messages arriving via HTTP from computer workstations. It converts these messages from HTTP into true SMS format, and sends them on to the Bearer Box to be conveyed to mobile devices. See Section 13.2 for details of how to send SMS messages from a computer workstation.
4 Installation from a Graphical User Interface If your Linux or Solaris system includes a graphical user interface, the installation program automatically installs the Alligata Server using the graphical procedure described in this section. To install the Alligata Server from a Linux/Solaris graphical user interface: Place the Alligata Server CD-ROM in the CD-ROM drive. If your version of Linux or Solaris automounts CD-ROMs, a file manager window will open, showing the contents of the directory into which the CD-ROM has been mounted. (In Linux this directory is usually /mnt/cdrom, in Solaris it is usually /cdrom/cdrom0.) If you are running your Linux/Solaris session as root, you can continue by double-clicking the install icon in the file manager window. This will take you straight to step 8. Open a terminal window. In the terminal window, type su at the command prompt and press ENTER. You will be prompted for the root password. Type the password of the root user and press ENTER. You will be returned to the command prompt. At the command prompt, type mount path_of_your_system's_CD-ROM_mount_point (In Linux the path of the CD-ROM mount point is usually /mnt/cdrom, in Solaris it is usually /cdrom/cdrom0 or something similar.) For example: mount /mnt/cdrom Press ENTER. If your version of Linux or Solaris automounts CD-ROMs, you can ignore this step. Change directory to your system's CD-ROM mount point. For example, Linux users should type cd /mnt/cdrom and press ENTER. Type ./install and press ENTER. Solaris users The installation program requires Perl to be installed on your system. If Perl is not found (for example, if you are running the default Solaris 7 system), you will be prompted to install it: Perl is not installed or is not in your command path. Do you want to install Perl now ? (y/N) Type Y, ENTER to install Perl or N, ENTER to abort installation. A dialog box opens containing information on the licences used by the Alligata Server package (see Figure 4.1). Figure 4.1: Licence dialog box If you agree with the terms of the listed licence agreements, click 'I Agree'. The main installation dialog box appears (see Figure 4.2). Figure 4.2: Main Alligata Server installation dialog box Note: the Alligata Server installation program detects whether each item is already installed on your system. Items already installed do not appear in the installation dialog box. For example, if your computer already contains an installation of the Apache server, the option 'Apache Web server' will not appear in the dialog box. In the dialog box, select the items you want to install. See Figure 4.3 for an explanation of the options in the installation dialog box. Figure 4.3(a) Global Options Install path Shows the directory into which the Alligata Server program files are installed. Defaults to /usr/share/alligata in Linux, and /opt/TGLBallig in Solaris. The install path cannot be changed. Binary directory Shows the directory into which the Alligata Server's binary files are installed. Defaults to /usr/bin, and cannot be changed. Figure 4.3(b) Installation Options Alligata Gateway (Kannel core) Installs the Alligata Server on the current computer, including the Bearer Box, one WAP Box and one SMS Box. If you want to install extra WAP and SMS Boxes on other computers, see Section 6. Start the Bearer Box at boot If selected, causes the Alligata Server's Bearer Box to be started automatically every time the computer is booted. Start the WAP Box at boot If selected, causes the WAP Box to be started automatically every time the computer is booted. Start the SMS Box at boot If selected, causes the SMS Box to be started automatically every time the computer is booted. Alligata example sites Installs the Alligata Server example WAP sites. In Linux, these are installed into /home/httpd/alligata/wml. In Solaris 7, they are installed into /usr/local/apache/alligata/wml. In Solaris 8, they are installed into /etc/apache/alligata/wml. Section 12 provides a guide to viewing, using and understanding the example sites. Apache Web server Installs the Apache Web server. You will need Apache, or a similar HTTP server, to view the example sites. Development files for the Apache Web server (Linux only) Installs the Apache development package. You will need this package if you plan to extend Apache, for example to write a new module. If the computer already contains an installation of Apache, the Alligata Server installation program automatically updates the Apache configuration for WML and Wireless Bitmap (WBMP) file formats. Apache manuals (Linux only) Installs the Apache manuals into the directory /home/httpd/html/manual. To view the index page, open the file index.html in a Web browser such as Netscape or Lynx. PHP language Installs the PHP scripting language. PHP is used by two of the Alligata Server example WAP sites. It can be very useful for developing Web and WAP applications. In the Solaris installation, this option includes the PHP IMAP module (see below). IMAP module for the PHP language (Linux only) Installs the IMAP PHP module. This module is used in the example WAP site PAT for liaising with your e-mail server. Documentation for the PHP language (Linux only) Installs documentation for the PHP language into the directory /home/httpd/html/manual/mod/mod_php3. To view the index page, open the file index.html in a Web browser such as Netscape or Lynx. CGI module for Perl Installs the CGI Perl module, version 2.69. This module facilitates the output of Web files from Perl scripts. It is needed to view the Alligata Server's Perl example site. (The CGI modules supplied with most Linux distributions are too old and will not work with the example Perl site.) HTML module for Perl Installs the HTML Perl module. This module is needed to view the Alligata Server's Perl example site. HTML tables module for Perl Installs the HTML tables Perl module. This module is needed to view the Alligata Server's Perl example site. WML module for Perl Installs the WML Perl module. This module is needed to view the Alligata Server's Perl example site. Click Begin Install. The Alligata Server will be installed on your system. Installation progress information appears in the terminal window from which you launched the installation program. When all the files have been copied to your system, the dialog box in Figure 4.4 is displayed. Figure 4.4: 'Thank You' dialog box Click Launch browser to go to the 3G LAB Web site, where you can receive information about Alligata Server updates and support. Click Exit to cancel the installation. Click View Readme to view the Readme file. Click Continue to complete the installation. If you clicked Continue, the dialog box in Figure 4.5 will appear. Figure 4.5: 'Install Complete' dialog box Click Exit to finish the installation, or View Readme to view the Readme file. To start the Alligata Server, follow the instructions in Section 8.1. 5 Installation from the Command Line If your Linux or Solaris system does not include a graphical user interface, the installation program will install the Alligata Server using the command line procedure described in this section. To install the Alligata Server from the command line: Place the Alligata Server CD-ROM in the CD-ROM drive. At the command prompt, type su and press ENTER. You will be prompted for the root password. Type the password of the root user and press ENTER. You will be prompted for the root password. At the command prompt, type mount path_of_your_system's_CD-ROM_mount_point (In Linux the path of the CD-ROM mount point is usually /mnt/cdrom, in Solaris it is usually /cdrom/cdrom0 or something similar.) For example: mount /mnt/cdrom Press ENTER. If your version of Linux or Solaris automounts CD-ROMs, you can ignore this step. Change directory to your system's CD-ROM mount point. For example, Linux users should type cd /mnt/cdrom and press ENTER. Type ./install and press ENTER. Solaris users The installation program requires Perl to be installed on your system. If Perl is not found (for example, if you are running the default Solaris 7 system), you will be prompted to install it: Perl is not installed or is not in your command path. Do you want to install Perl now ? (y/N) Type Y, ENTER to install Perl or N, ENTER to abort installation. Information on the licence agreements used by the Alligata Server package will be displayed on the screen, together with the question, Do you agree with the licence? [Y/n] If you agree, type Y, ENTER or just ENTER. Information on the installation and binary paths appears on the screen. For example: Install path set to: /usr/share/alligata Binary path set to: /usr/bin Note: you cannot change the installation and binary paths. You will be presented with the questions listed in Figure 5.1. In response to each question, type Y, ENTER for 'yes', N, Enter for 'no', or ?, ENTER to receive help. Pressing just ENTER in response to a question selects the first (capitalised) option in the square brackets after the question. For example, if the square brackets look like this: [N/y/?] then pressing ENTER is equivalent to pressing N, ENTER. Note: the Alligata Server installation program detects whether each item is already installed on your system. You will not be asked whether you want to install items that are already installed. For example, if your computer already contains an installation of the Apache server, the question 'Install Apache Web server?' will be omitted. Figure 5.1 Command Line Installation Options Install the Alligata Gateway (Kannel core)? [Y/n/?] Y installs the Alligata Server on the current computer, including the Bearer Box, one WAP Box and one SMS Box. If you want to install extra WAP and SMS Boxes on other computers, see Section 6. Start the Bearer Box at boot? [N/y/?] Y causes the Alligata Server's Bearer Box to be started automatically every time the computer is booted. Start the WAP Box at boot [N/y/?] Y causes the WAP Box to be started automatically every time the computer is booted. Start the SMS Box at boot [N/y/?] Y causes the SMS Box on the current computer to be started automatically every time the computer is booted. Install the Alligata examples? [Y/n/?] Y installs the Alligata Server example WAP sites. In Linux, these are installed into /home/httpd/alligata/wml. In Solaris 7, they are installed into /usr/local/apache/alligata/wml. In Solaris 8, they are installed into /etc/apache/alligata/wml. Section 12 provides a guide to viewing, using and understanding the example sites. Install Apache Web server? [N/y/?] Y installs the Apache Web server. You will need Apache to view the example sites. Install Development files for the Apache Web server? [N/y/?] (Linux only) Y installs the Apache development package. You will need this package if you plan to extend Apache, for example to write a new module. If the computer already contains an installation of Apache, the Alligata Server installation program updates the Apache configuration for WML and WBMP file formats. Install Apache manuals? [N/y/?] (Linux only) Y installs the Apache manuals into the directory /home/httpd/html/manual. To view the index page, open the file index.html in a Web browser such as Netscape or Lynx. Install PHP language? [N/y/?] Y installs the PHP scripting language. PHP is used by two of the Alligata Server example WAP sites. It can be very useful for developing Web and WAP applications. In the Solaris installation, this option includes the PHP IMAP module (see below). Install IMAP module for the PHP language? [N/y/?] (Linux only) Y installs the IMAP PHP module. This module is used in the example WAP site PAT for liaising with your e-mail server. Install Documentation for the PHP language? [N/y/?] (Linux only) Y installs documentation for the PHP language into the directory /home/httpd/html/manual/mod/mod_php3. To view the index page, open the file index.html in a Web browser such as Netscape or Lynx. Install CGI module for Perl? [N/y/?] Y installs the Common Gateway Interface (CGI) Perl module, version 2.69. This module facilitates the output of Web files from Perl scripts. It is needed to view the Alligata Server's Perl example site. (The CGI modules supplied with most Linux distributions are too old and will not work with the example Perl site.) Install HTML module for Perl? [N/y/?] Y installs the HTML Perl module. This module is needed to view the Alligata Server's Perl example site. Install HTML tables modules for Perl? [N/y/?] Y installs the HTML tables Perl module. This module is needed to view the Alligata Server's Perl example site. Install WML module for Perl? [N/y/?] Y installs the WML Perl module. This module is needed to view the Alligata Server's Perl example site. The following messages (or equivalents) will be displayed on the screen: Installing to /usr/share/alligata xMb available, 5Mb will be installed Continue install? [Y/n] Selecting Y installs the Alligata Server and any other selected items on your system. Installation progress is displayed on the screen. When installation is complete, the following messages will be displayed on the screen: Thank you for installing the Alligata Server, 3G LAB's Mobile Internet Server! Please visit our Web site for updates and support. Would you like to launch a Web browser? [Y/n] To visit the 3G LAB Web site, select Y. If you select N, the following message will be displayed on the screen: Installation complete. To start the Alligata Server, follow the instructions in Section 8.1. 6 Installing Multiple WAP and SMS Boxes The Alligata Server installation program installs a Bearer Box, a WAP Box and an SMS Box onto a personal computer running Linux or Solaris. The following instructions assume you have already installed the Alligata Server on a personal computer running Linux or Solaris ('Computer A'). If you have not yet installed the Alligata Server, please follow the instructions in Section 4 for installation from a graphical user interface, or Section 5 for installation from the command line. You can add any number of extra WAP and SMS Boxes to an installation of the Alligata Server. To add a WAP Box to an installation of the Alligata Server: Connect a computer running Linux or Solaris ('Computer B') to Computer A using TCP/IP. Install a complete copy of the Alligata Server onto Computer B as described in Sections 4 and 5. On Computer B, open the configuration file /etc/alligata.conf in a text editor such as vi or Emacs. About the configuration file: the Alligata Server configuration is a list of variables divided into groups. Each group begins with the line group = x where x is a group identifier. A blank line signifies the end of a group. (Full instructions for configuring the Alligata Server are provided in Section 9.) In the configuration group beginning with the line group = wapbox , change the value of the variable bearerbox-host to the IP address or URL of the computer hosting the Bearer Box (that is, computer A). For example: bearerbox-host = 10.0.0.1 Repeat steps 1-4 on a new computer for each WAP Box you want to add. To add an SMS Box to an installation of the Alligata Server: Connect a computer running Linux or Solaris ('Computer C') to Computer A using TCP/IP. Install a complete copy of the Alligata Server onto Computer C as described in Sections 4 and 5. On Computer C, open the configuration file /etc/alligata.conf in a text editor such as vi or Emacs. About the configuration file: the Alligata Server configuration is a list of variables divided into groups. Each group begins with the line where x is a group identifier. A blank line signifies the end of a group. (Full instructions for configuring the Alligata Server are provided in Section 9.) group = x In the configuration group beginning with the line group = smsbox , change the value of the variable bearerbox-host to the IP address or URL of the computer hosting the Bearer Box (that is, computer A). For example: bearerbox-host = 10.0.0.1 Repeat steps 1-4 on a new computer for each SMS Box you want to add.
Part Two: Using the Alligata Server 7 Introduction to Part Two Welcome to Part Two of the Alligata Server User Manual, Using the Alligata Server. This part of the user manual explains how to: start, stop and administer the Alligata Server change the Alligata Server's configuration settings view the example WAP sites provided with the Alligata Server create WAP sites using Wireless Markup Language (WML) create dynamic WAP sites using the Perl scripting language create dynamic WAP sites using the PHP scripting language use the Alligata Server's SMS features to deliver World Wide Web and other content to mobile phones use the Alligata Server to send SMS messages from a computer workstation configure a mobile phone for a WAP service 'over the air' using the Alligata Server's SMS features This part of the user manual assumes you have installed the Alligata Server successfully on a computer workstation running Linux or Solaris. If you have not yet installed the Alligata Server, please follow the installation instructions in Sections 4 to 6. 8 Running the Alligata Server Note: to run an Alligata Server command line command, you must be logged in as root. Therefore, before using any of the command line commands in this section, change to root as follows: At the command prompt, type su and press ENTER. You will be prompted for the password of root. Type the password of root and press ENTER. You will be returned to the command prompt as root. Once the Alligata Server is running, its user will change from root to that specified by the user variable in the Core group of the configuration file. By default, this user is alligata.
8.1 Starting the Alligata Server Each box in the Alligata Server needs to be started separately. The Bearer Box must be started before any of the WAP or SMS Boxes. There are three methods of starting the Alligata Server. To start the Alligata Server:
8.1.1 Method 1 If, when you installed the Alligata Server, you selected 'Start the Bearer Box at boot', 'Start the WAP Box at boot' or 'Start the SMS Box at boot', then the relevant box will start automatically each time you boot up the computer.
8.1.2 Method 2
Linux users At the command prompt, type /etc/rc.d/init.d/box start where box is one of the strings bearerbox, wapbox or smsbox. Press ENTER. The procedure to start the Bearer Box, WAP Box and SMS Box on a single Linux workstation is therefore as follows: To start the Bearer Box, type /etc/rc.d/init.d/bearerbox start at the command prompt and press ENTER. The Bearer Box will start up. To start the WAP Box, type /etc/rc.d/init.d/wapbox start at the command prompt and press ENTER. The WAP Box will start up. To start the SMS Box, type /etc/rc.d/init.d/smsbox start at the command prompt and press ENTER. The SMS Box will start up.
Solaris users At the command prompt, type /etc/init.d/ box start where box is one of the strings bearerbox, wapbox or smsbox. Press ENTER. The procedure to start the Bearer Box, WAP Box and SMS Box on a single Linux workstation is therefore as follows: To start the Bearer Box, type /etc/init.d/bearerbox start at the command prompt and press ENTER. The Bearer Box will start up. To start the WAP Box, type /etc/init.d/wapbox start at the command prompt and press ENTER. The WAP Box will start up. To start the SMS Box, type /etc/init.d/smsbox start at the command prompt and press ENTER. The SMS Box will start up.
8.1.3 Method 3 This method of starting the Alligata Server allows you to enter command line options that customise the way each box runs. Using this method, the procedure to start up the Bearer Box, WAP Box and SMS Box on a single workstation is as follows: To start the Bearer Box, type bearerbox at the command prompt and press ENTER. You can use command line options to override some of the settings in the configuration file. See Command Line Options below. The Bearer Box will start up. To start the WAP Box, type wapbox at the command prompt and press ENTER. You can use command line options to override some of the settings in the configuration file. See Command Line Options below. The WAP Box will start up. To start the SMS Box, type smsbox at the command prompt and press ENTER. You can use command line options to override some of the settings in the configuration file. See Command Line Options below. The SMS Box will start up. For each box, you can use a different configuration file from the default file by including the path and name of the relevant file after the command. For example: bearerbox /etc/alligata2.conf
Command Line Options If you start up the Alligata Server using Method 3, you can include options in the command line you use to start up each box. The format for command line options is box option value For example: bearerbox -v 2 The available command line options are shown in Figure 8.1. Figure 8.1: Alligata Server command line options -F file_name Log file name. Does not override the log file name setting in the configuration file, but outputs to both files. -V number_0-4 Verbosity level for output to the log file specified with -F. 0 provides most detail, 4 least. The default value is 1. -S Suspended. Starts the Alligata Server in suspended state. See Section 3.3.1 for details. -I Isolated. Starts the Alligata Server in isolated state. See Section 3.3.1 for details.
8.2 Administering the Alligata Server
8.2.1 Administering the Alligata Server from the Command Line Each Alligata Server box understands four administration commands that can be entered from the Linux or Solaris command line. These commands must be in the following formats. Linux users: /etc/rc.d/init.d/box command Solaris users: /etc/init.d/box command Replace box with one of the strings bearerbox, wapbox or smsbox. For example: /etc/rc.d/init.d/wapbox restart The available command line commands are shown in Figure 8.2. Figure 8.2: Alligata Server command line administration commands start Starts the specified box. restart Shuts down the specified box, then immediately restarts it. stop Shuts down the specified box. status Outputs a summary of processes currently being run by the specified box.
8.2.2 Administering the Alligata Server Using HTTP You can use a set of HTTP commands to set the Alligata Server's program state (see Section 3.3.1) while it is running. You can also use the status command to retrieve information about the Alligata Server's current activity. Figure 8.3 lists the Alligata Server's HTTP administration commands. To send the Alligata Server an HTTP administration command: In the 'Location' box of a Web browser, type the command using the following syntax: http://hostname:port/cgi-bin/command?password=password http://localhost:13004/cgi-bin/suspend?password=PAPaya The port number (13004 in the example) must be the same as that defined by the admin-port variable in the Core configuration group (see Section 9.1). The command must be one of the five HTTP administration commands listed in Figure 8.3. The password must be that defined by the admin-password variable in the Core configuration group. (Note that the status command requires no password.) To save having to type a whole URL for each command, you can create an HTML form. Here is one for the shutdown command: <form name="httpadmin" method="get" action="http://localhost:13004/cgi-bin/shutdown"> Enter Alligata Server administration password: <br> <input type="text" name="password" value=""> <input type="submit" value="Shut down the Alligata Server"> </form> Figure 8.3: Alligata Server HTTP administration commands status Retrieves the following information about the Alligata Server's current activity: the program state; the total number of data packets queuing in the system; the total number of WAP Box and SMS Box connections. No password is required. suspend Sets the Alligata Server's state to 'suspended'. isolate Sets the Alligata Server's state to 'isolated'. resume Sets the Alligata Server's state to 'running', if it has been suspended or isolated. shutdown Sets the Alligata Server's state to 'shutdown'. The shutdown process, once begun, cannot be stopped - though the Alligata Server's status can still be queried. If a second shutdown command is sent, the Alligata Server will close down immediately, regardless of whether any packets are still held in queues.
8.2.3 Monitoring the Alligata Server Using <userinput moreinfo="none">less</userinput> You can monitor the Alligata Server's activity by opening the log files using the UNIX less command (for example, less /var/log/alligata/bearerbox.log). To watch a log file update while the Alligata Server is running, press SHIFT+F from within less.
Shutting down an Alligata Server box There are two methods of shutting down an Alligata Server box. To shut down an Alligata Server box:
8.3.1 Method 1 Linux users From the command line, type /etc/rc.d/init.d/box stop replacing box with the relevant box name, bearerbox, wapbox or smsbox. For example: /etc/rc.d/init.d/wapbox stop Solaris users From the command line, type /etc/init.d/box stop replacing box with the relevant box name, bearerbox, wapbox or smsbox. For example: /etc/rc.d/init.d/wapbox stop
8.3.2 Method 2 Send the Alligata Server an HTTP shutdown administration command (see Section 8.2.2). Note that this method can only be used to shut down the Bearer Box, not individual WAP and SMS Boxes.
9 Configuring the Alligata Server The Alligata Server is installed with a default configuration that allows you to use it as a WAP gateway. If you want to customise its WAP features, or implement SMS messaging services, you need to make changes to the configuration file. All the configuration data for the Alligata Server is held in a single file. By default this file is called alligata.conf and is held in the directory /etc. If you want to use a different configuration file, specify the path and file after the relevant command when you start up a box. (To do this, you must start the box using Method 3 - see Section 8.1.3.) For example: bearerbox /etc/alligata2.conf An example Alligata Server configuration file is shown in Figure 9.1. Figure 9.1: Example Alligata Server configuration: # Example Alligata Server configuration group = core user = alligata max-threads = 99 admin-port = 13004 wapbox-port = 13002 smsbox-port = 13005 admin-password = bar wdp-interface-name = * log-file = /alligata/admin/bearer.log log-level = 0 box-deny-ip = *.*.*.* box-allow-ip = 127.0.0.1 admin-deny-ip = 10.0.0.2 admin-allow-ip = *.*.*.* unified-prefix = 0044,0 group = wapbox bearerbox-host = localhost log-file = /alligata/admin/wapbox.log log-level = 0 group = smsbox bearerbox-host = localhost sendsms-port = 13013 global-sender = 123 log-file = /alligata/admin/smsbox.log log-level = 0 group = smsc smsc = at modemtype = wavecom device = /dev/ttyS2 group = sms-service keyword = proverb aliases = Proverb;PROVERB;potd;Potd;POTD url = http://www.awebsite.net/potd.html prefix = <!--beginprov--> suffix = <!--endprov--> split-chars = ;:. split-suffix = -cont- header = "Today's proverb -- " max-messages = 10 group = sms-service keyword = ota # In one line! url = http://localhost:13013/cgi-bin/sendota? username=otauser&password=foo&phonenumber=%p group = otaconfig location = http://www.asite.net service = Company Home ipaddress = 10.0.0.5 phonenumber = 44998123456 bearer = data calltype = analogue connection = cont pppsecurity = off authentication = normal login = phoneuser secret = barfoo group = sendsms-user username = otauser password = foo user-deny-ip = 10.0.0.2 user-allow-ip = *.*.*.* max-messages = 2 concatenation = 1 group = sms-service keyword = ota # In one line! url = http://localhost:13013/cgi-bin/sendota? username=otauser&password=foo&phonenumber=%p group = sms-service keyword = default text = Sorry, the Alligata Server didn't understand your message. group = sendsms-user username = tester password = foobar max-messages = 10 split-chars = .;, split-suffix = -cont.- header = "Msg from tester -- " password = foo user-deny-ip = 10.0.0.2 user-allow-ip = *.*.*.* max-messages = 2 concatenation = 1 The configuration file is a list of variables used by the Alligata Server, divided into groups. Each group controls a different area of the Alligata Server's functionality. The configuration file is a plain text file, so you can edit it in any text editor. When editing the configuration file, note the following points: Groups must be separated by one or more blank lines. Each group must begin with the line group = identifier where identifier is one of the group identifiers listed in Figure 9.2. The format of each variable definition is variable_name = value Quotation marks around the value are optional. Therefore, log-file = /tmp/bearer.log is equivalent to log-file = "/tmp/bearer.log" However, quotation marks are required if the value begins or ends with a space, or if it contains special characters. Within quotation marks, standard C escape character syntax operates: Escape characters \a Alert \b Backspace \f Form feed \n Newline \r Carriage return \t Horizontal tab \t Vertical tab \\ Backslash \' Single quotation mark \" Double quotation mark \0oo Octal value (where o represents an octal digit) \xhh Hexadecimal value (where h represents a hexadecimal digit)
Within a group, each variable definition must be followed by a single carriage return. A hash # at the start of a line indicates a comment. The Alligata Server will ignore this line. The Alligata Server reads the configuration file when it is started up. If you make changes to the configuration file while it is running, then you must restart the Alligata Server before they will be implemented.
A summary of the characteristics of each configuration group is shown in Figure 9.2. Figure 9.2: Summary of Alligata Server configuration groups Group Required? Multiple groups allowed? Identifier in configuration file (group = ...) Function Core Yes No core Configures the Bearer Box. WAP Box No No wapbox Configures the WAP Box. SMS Box No No smsbox Configures the SMS Box. SMSC No Yes smsc Configures the connection to an SMSC. SMS Service No Yes sms-service Configures an SMS keyword service. Send SMS User No Yes sendsms-user Configures a user account for sending SMS messages from a PC workstation via HTTP. OTA No No otaconfig Provides settings for over-the-air (OTA) configuration of client devices.
The rest of this section consists of a full list of all the variables that can be used in the Alligata Server configuration file. Variables are arranged by group.
9.1 Core Configuration Variables (Core group) The Core group provides general configuration information for the Alligata Server. This information is used by the Bearer Box. group = core Group. Introduces the Core group. (Required.) user = user_name The user name under which the Alligata Server is run. The Alligata Server automatically switches to this user name after it has started. (You must be logged in as root to start the Alligata Server manually. See Section 8 for instructions on starting the Alligata Server.) Setting user to root is strongly discouraged, as it could compromise the security of the system. Example: user = alligata admin-port = port_number Administration Port. Gives the port number on which the Bearer Box listens to HTTP administration commands. It can be any value between 1024 and 65535. (It may be under 1024 if you are running the Alligata Server as a root process, but it is not recommended that you do this.) It is not the same as the HTTP port of the local World Wide Web server. (Required.) Example: admin-port = 13004 admin-password = password Administration Password. Defines the password for HTTP administration commands (except the status command, which does not require a password). See Section 8.2.2 for HTTP administration instructions. (Required.) Example: admin-password = PAPaya smsbox-port = port_number SMS Box Port. Defines the port number to which SMS Boxes connect. It can be any value between 1024 and 65535. (It may be under 1024 if the user variable is set to root, but this is not advised.) This variable is required if the Alligata Server is to handle SMS traffic. Example: smsbox-port = 13005 wapbox-port = port_number WAP Box Port. Defines the port number to which WAP Boxes connect. It can be any value between 1024 and 65535. (It may be under 1024 if the user variable is set to root, but this is not advised.) This variable is required if the Alligata Server is to handle WAP traffic. Example: wapbox-port = 13002 wdp-interface-name = IP_address If the Alligata Server's host machine has multiple network cards, specifies the IP address of the card from which User Datagram Protocol (UDP) WAP packets are accepted. If set to 0.0.0.0, accepts packets from any IP address. Example: wdp-interface-name = 10.0.0.3 log-file = file_name Log File. Specifies a file to which to output a log report of the Bearer Box's activity. If the specified file already exists, new output will be added to the end of the file. If a log file is also defined in the command line when the Bearer Box is started up, then the log report will be output to both files (as well as to the standard output). See Section 8.1.3 for command line options. If log-file is not set in the configuration file, it defaults to /var/log/alligata/bearerbox.log. Example: log-file = /alliglog/bearer.log log-level = number_0-4 Log Level. Sets the level of information to be recorded in the log file. Settings are as follows (with 0 providing the most detail and 4 the least): 0 Debug 1 Information 2 Warning 3 Error 4 Panic If log-level is not defined in the configuration file, it defaults to a value of 1. Example: log-level = 0 box-deny-ip = List_of_IP_addresses box-allow-ip = List_of_IP_addresses Denied and allowed Box IP List. These variables list the IP addresses of WAP or SMS Boxes to which the Bearer Box may, or may not, forward packets. These variables allow you to prevent third parties from intercepting TCP packets as they leave the Bearer Box. Addresses in the Denied and Allowed Box IP Lists are separated by semicolons. An asterisk * can be used as a wildcard in place of any single group of digits, so *.*.*.* matches any IP address. Examples: box-deny-ip = *.*.*.* box-allow-ip = 10.0.0.6;10.0.0.7 admin-deny-ip = List_of_IP_addresses admin-allow-ip = List_of_IP_addresses Administration Denied and Allowed IP Lists. These variables list IP addresses to be denied and allowed HTTP administration access to the Alligata Server. Addresses are formatted in the same way as in box-deny-ip and box-allow-ip. Examples: admin-deny-ip = *.*.*.* admin-allow-ip = 10.0.0.6;10.0.0.7 unified-prefix = List_of_telephone_code_prefixes Unified Prefix. Lists substitutions for telephone code prefixes in SMS messages. Substitutions are applied to the 'sender' and 'recipient' fields in incoming and outgoing SMS messages respectively, and ensure that all equivalent numbers are formatted consistently for SMSCs. The format for each substitution is r,p1,p2... where r is the replacement prefix, and p1, p2, etc. are the prefixes to be replaced. You can define any number of substitutions in the configuration file by separating each definition with a semicolon ;. Example: unified-prefix = 0044, 0; 00555, 05, 050 white-list = URL White List. Links to a file listing telephone numbers of approved senders of SMS messages to the Alligata Server. SMS messages from numbers not in this list will be automatically discarded. The white list file should contain telephone numbers separated by carriage returns. Note: only the last nine digits are read, so it is theoretically possible for unauthorised senders with numbers nearly identical to those in the white list to gain access to the Alligata Server. The likelihood of this occurring is, however, minimal. If the configuration file contains a white-list, it should not contain a black-list. Example: white-list = http://www.awebsite.net/alligata/white.htm black-list = URL Black List. Links to a file listing telephone numbers of prohibited senders of SMS messages to the Alligata Server. SMS messages from numbers on this list are automatically discarded. The black list file should contain telephone numbers separated by carriage returns. As with the white list, only the last nine digits of the number are read by the Alligata Server. If the configuration file contains a black-list, it should not contain a white-list. Example: black-list = http://www.awebsite.net/alligata/black.htm http-proxy-host = IP_address/URL HTTP Proxy Host. Identifies a proxy server to be used for HTTP requests. Example: http-proxy-host = 10.0.0.8 http-proxy-port = port_number HTTP Proxy Port. Identifies the port on the proxy server to which the Alligata Server connects. Example: http-proxy-port = 13005 http-proxy-exceptions = list_of_IP_addresses/URLs HTTP Proxy Exceptions. Lists Internet addresses to be reached directly rather than via the proxy server (for example, computers on a local network). Multiple values should be separated by spaces. Example: http-proxy-exceptions = 10.0.0.3 10.0.0.4 access-log = file_name Access Log File. Specifies a file to which to output a log report of SMS messages processed by the Bearer Box. Example: access-log = bearerbox.access
9.2 WAP Configuration Variables (WAP Box group) The WAP Box group provides the configuration for the WAP Box or Boxes. There cannot be more than one WAP Box group in the main configuration file. If you have installed several WAP Boxes on different computers (see Section 6), each WAP Box should use a separate configuration file. If you are using the Alligata Server for WAP services, remember also to set the wapbox-port variable in the Core group (see Section 9.1). If you are not using the Alligata Server for WAP services, then no WAP Box group is necessary. group = wapbox Group. Introduces the Wap box group. (Required.) bearerbox-host = IP_address/URL Bearer Box Host. Identifies the computer hosting the Bearer Box. (Required.) Examples: bearerbox-host = localhost bearerbox-host = 100.100.100.100 bearerbox-host = acomputer.asite.net log-file = file_name Log File. Specifies a file to which to output a log report of the WAP Box's activity. If the specified file already exists, new output is added to the end of it. If a log file is also defined in the command line when the WAP Box is started up (see Section 8.1.3), then the log report will be output to both files. If log-file is not set in the configuration file, it defaults to /var/log/alligata/wapbox.log. Example: log-file = /alliglog/wap.log log-level = number_0-4 Log Level. Sets the level of information to be recorded in the log file. Settings are as follows (with 0 providing the most detail and 4 the least): 0 Debug 1 Information 2 Warning 3 Error 4 Panic If log-level is not defined in the configuration file, it defaults to a value of 1. Example: log-level = 0 timer-freq = value_in_seconds Timer Frequency. If not set in the configuration file, defaults to a value of 1. Example: timer-freq = 3 map-url = url#1 url#2 URL Mapping. On incoming URL requests, replaces url#1 with url#2. Asterisks can be used as wildcards to right-truncate either or both of the URLs. Example: map-url = xlwa/* http://www.extremely_longwinded _wapsite_address.com/* This example enables a mobile device user to gain access to the URL http://www.extremely_longwinded_wapsite_address.com/contacts.wml simply by keying xlwa/contacts.wml. Note: only one map-url is allowed in the configuration. If you need to map more than one URL, use map-url-0, etc. together with map-url-max. map-url-max = number URL Mapping Maximum. Sets the maximum number of URL mappings to be defined in the configuration file. If no maximum is specified, the Alligata Server allows a default maximum of ten mappings, numbered from 0 to 9 (see map-url-0, map-url-1, etc.). Example: map-url-max = 8 map-url-0 = url#1 url#2 map-url-1 = url#1 url#2 , etc. Multiple URL Mappings. Define multiple URL mappings, unlike map-url, which can define only one mapping. Further URL mappings would be defined by the variables map-url-2, map-url-3 and so on, up to the maximum specified in map-url-max. Formatting syntax is as for map-url. Examples: map-url-0 = xlwa/* http://www.extremely_longwinded_wapsite_address.com/* map-url-1 = olwa/* http://www.outrageously_longwinded_wapsite_address.com/* device-home = url Device Home. For Openwave's UP.Browser, defines the client's WML home deck. The actual URL supplied by the Openwave microbrowser is DEVICE:home. Both parts of the variable definition are implicitly right-truncated. Thus, device-home = http://www.devicehome.com/ is equivalent to is equivalent to Example: device-home = http://www.devicehome.com/
9.3 SMS Configuration Variables (SMS Box, SMSC, SMS Service and Send SMS User groups)
9.3.1 SMS Box group The SMS Box group provides the configuration for the SMS Box. There cannot be more than one SMS Box group in the main configuration file. If you have installed several SMS Boxes on different computers (see Section 6), each SMS Box should use a separate configuration file. If you are using the Alligata Server for SMS messaging, remember also to set the smsbox-port variable in the Core group (see Section 9.1). If you are not using the Alligata Server for SMS messaging, then no SMS Box group is necessary. group = smsbox Group. Introduces the SMS Box group. (Required.) bearerbox-host = IP_address/URL Bearer Box Host. Identifies the computer hosting the Bearer Box. (Required.) Examples: bearerbox-host = localhost bearerbox-host = 10.0.0.1 bearerbox-host = acomputer.asite.net sendsms-port = port_number Send SMS Port. Specifies the port via which SMS messages sent from a workstation by HTTP are received (see Section 9.3.4). The port number can be any value between 1024 and 65535. (It may be under 1024 if the user variable in the Core configuration group is set to root, but this is not advised.) Example: sendsms-port = 13001 telephone_number Global Sender Number. Specifies the number shown as the sender's telephone number in outgoing SMS messages. Note that most SMSCs will automatically replace this number with their own. Example: global-sender = 44998123456 log-file = file_name Log File. Specifies a file to which to output a log report of the SMS Box's activity. If the specified file already exists, new output will be added to the end of it. If a log file is also defined in the command line when the SMS Box is started up, then the log report will be output to both files. If log-file is not set in the configuration file, it defaults to /var/log/alligata/smsbox.log. Example: log-file = /alliglog/sms.log log-level = number_0-4 Log Level. Sets the level of information to be recorded in the log file. Settings are as follows (with 0 providing the most detail and 4 the least): 0 Debug 1 Information 2 Warning 3 Error 4 Panic If log-level is not defined in the configuration file, it defaults to a value of 1. Example: log-level = 0 access-log = file_name Access Log File. Specifies a file to which to output a log report of SMS messages processed by the SMS Box. Example: access-log = smsbox.access
9.3.2 SMSC group For each SMSC with which the Alligata Server is in communication, you must configure an SMSC group. If you intend to use the Alligata Server for managing SMS messages, remember also to set the smsbox-port variable in the Core group (see Section 9.1). Which variables you need to include in an SMSC group depends on the protocol used by the relevant SMSC. Figure 9.3 provides a list of which protocols support which variables. For full details of each protocol, please consult the documentation for the relevant SMSC. AT is the protocol that the Alligata Server uses to send and receive SMS messages via a GSM wireless modem using AT commands. Using a GSM modem circumvents the need for a subscription to an SMSC. Certain mobile phones that incorporate a GSM modem can also be linked to a computer workstation and used to send and receive SMS messages in the same way as a modem. Modems supported by the Alligata Server include the Wavecom WM02 and the Nokia Premicell. Phones that can be used as modems include the Nokia 7110. If you do not want to use the Alligata Server's SMS features, you do not need any SMSC groups in your configuration file. Figure 9.3: SMSC group protocol-specific variables SMSC protocol Value of smsc variable Variables. Those in parentheses are optional. CIMD cimd host, port, smsc-username, smsc-password CIMD2 cimd2 host, port, smsc-username, smsc-password, (keepalive) EMI emi phone, device, smsc-username, smsc-password EMI IP emi_ip host, port, smsc-username, smsc-password, connect-allow-ip, (receive-port), (our-port) SMPP IP smpp host, port, smsc-password, system-id, system-type, address-range, (receive-port) SEMA X.28 sema device, smsc-nua, home-nua, (wait-report) OIS ois host, port, receive-port, (ois-debug-level) AT at device, modemtype, (pin)
group = smsc Group. Introduces the SMSC group. (Required.) smsc = smsc_type SMSC Type. Identifies the SMSC type. Currently available types are cimd, cimd2, emi, emi_ip, smpp, sema, at and ois. See Figure 9.3. (Required.) Example: smsc = emi smsc-id = string SMSC Identifier. Provides a name by which the SMSC can be referred to elsewhere. This name can be used to associate the SMSC with particular SMS services and users, via the accepted-smsc, forced-smsc and default-smsc variables in the SMS Service and Send SMS User groups (see Sections 9.3.3 and 9.3.4). The value of smsc-id may contain any alphanumeric characters, and is case-insensitive. Example: smsc-id = smsc1 denied-prefix = list_of_telephone_code_prefixes Denied Telephone Prefix List. Lists prefixes of telephone numbers to which messages are not to be sent via this SMSC. Numbers in the list are separated by semicolons ;. The denied-prefix variable may be needed because some SMSCs do not allow messages to be sent to users on different telephone networks to their own. denied-prefix and preferred-prefix can also be useful to direct calls to the cheapest SMSC according to their destination code. Example: denied-prefix = 0898;0999 preferred-prefix = list_of_telephone_code_prefixes Preferred Telephone Prefix List. Lists prefixes of telephone numbers that should, if possible, be sent messages via this SMSC. Numbers in the list are separated by semicolons ;. It is possible for a telephone code prefix to be listed as preferred in more than one SMSC group. Where this is the case, the Alligata Server chooses one of these SMSC groups at random. Where a telephone number's prefix is not listed as preferred in any SMSC group, the Alligata Server chooses a group at random from all available SMSC groups. Example: preferred-prefix = 01487;01223 host = IP_address/host_name Examples: host = 10.0.0.20 host = acomputer.acompany.net port = port_number SMSC Host Port. Identifies the port number on the SMSC host machine used for communication. (Required.) Example: port = 13004 our-port = port_number Local Port. Identifies the port on the Alligata Server's host machine used for communication with the SMSC. Currently only the EMI IP protocol supports this. Example: our-port = 13005 receive-port = port_number Receive Port. Used with protocols that accept different send and receive ports, namely EMI IP, SMPP IP and OIS. Example: receive-port = 13006 smsc-username = user_name SMSC User Name. The Alligata Server's account user name on the SMSC's host machine. Example: smsc-username = ally smsc-password = password SMSC Password. The Alligata Server's account password on the SMSC's host machine. Example: smsc-password = PINEapple device = device_name System Device. When the Alligata Server is used with a GSM modem or the EMI or X.28 protocols, this identifies the device associated with the modem. Example: device = /dev/ttyS0 connect-allow-ip = list_of_IP_addresses Allowed IP Connections. Specifies IP addresses of SMSCs to be allowed to connect to the Alligata Server. Used by EMI IP. Example: connect-allow-ip = 10.0.0.20 10.0.0.21 smsc_nua = X.121_address SMSC address using X.121 protocol. Used by SEMA X.28. Example: smsc_nua = 000001220900 home_nua = X.121_address Radio PAD (Product Assembler/Disassembler) address using X.121 protocol. Used by SEMA X.28. Example: home_nua = 000001220900 wait_report = digit_(0_or_1) Wait Report. Used by SEMA X.28. Example: wait_report = 1 phone = telephone_number The SMSC's telephone number. Used only by EMI. Example: phone = 44999123456 keepalive = number The frequency of 'alive' messages in seconds. Used only by CIMD2. system_id = string System ID. Used only by SMPP IP. system_type = string System Type. Used only by SMPP IP. address_range = range Address range. Used only by SMPP IP. modemtype = string The type of modem being used to send SMS messages by the AT protocol. Modems currently supported are as follows: Currently supported modems Modem modemtype value Wavecom WM02 wavecom Nokia Premicell premicell Siemens M20T siemens Siemens TC35 siemens-tc35 Phone with GSM modem nokiaphone
(The Nokia Premicell does not support user data headers (UDHs), so cannot be used for over-the-air configuration messages.) Used only by AT. Example: modemtype = wavecom
pin = number Personal Identification Number. An optional variable used only by AT. Use this variable if the SIM card inserted in your GSM modem requires a PIN for activation.
9.3.3 SMS Service Group An SMS Service group defines an action to be performed by the SMS Box in response to a keyword and parameters in incoming SMS messages. If you are using the Alligata Server for SMS messaging, remember to include an SMS Box group and at least one SMSC group in the configuration. You also need to set the smsbox-port variable in the Core group (see Section 9.1). You can include as many SMS Service groups in the configuration as you like. Each group defines a single SMS service. For instructions on how to implement SMS services, see Section 13. group = sms-service Group. Introduces the SMS Service group. (Required.) keyword = word Service Keyword. Defines the keyword that triggers the service. (Required.) The keyword can only be a single word, without spaces, and must always be the first word in incoming messages. keyword is case-sensitive. For example, frog, Frog and FROG are treated as different keywords. If keyword has the value default, then the SMS Service will be applied to all incoming messages that do not contain recognised keywords. Example: keyword = football aliases = word#1;word#2, etc. Service Keyword Aliases. Defines alternative keywords that will trigger the service. Multiple aliases must be separated by semicolons ;. Each alias must be a single keyword, containing no spaces. Example: aliases = Football;FOOTBALL url = url Retrieval URL. Specifies a URL from which to fetch data. The URL can include parameters that are extracted from the incoming SMS message. These parameters are expanded by the SMS Box before the request is sent to the World Wide Web. Possible parameters are as follows: Possible parameters in the URL template %s The next word from the incoming SMS message, starting with the second word (since the first word is the keyword). Characters that can be ambiguous in URLs are converted into hexadecimal ASCII codes, for example + is converted into %2B. After each %s, the URL parser moves on to the next word in the message. %S As %s, but * is converted to ~ (tilde). This can be useful for users whose mobile phones do not allow ~ to be entered. In addition, potentially ambiguous characters are not encoded. %r All the remaining words in the message. For example, if the message is 'foo bar foobar baz', and bar has already been parsed by a %s, then %r denotes foobar baz (foo, of course, being the keyword). %a All words in the incoming SMS message, including the first word. %t The time the message was sent, formatted as YYYY-MM-DD[space]HH:MM, for example 2000-07-28 15:56. %p The telephone number of the recipient of the SMS message. %P The telephone number of the sender of the SMS message. %q As %p, except that a leading 00 is replaced with +. %Q As %P, except that a leading 00 is replaced with +.
These parameters can also be used with the file and text variables. See Section 13.1 for examples of how parameters can be used. If an SMS Service group contains a url variable, it cannot also contain a file or a text (see below). There can only be one url in an SMS Service group. url can be used in conjunction with prefix and suffix to retrieve a section of a Web page. Example: url = http://www.awebsite.net/cgi/salary?user=%s&password=%s&employee=%r
file = file_name Retrieval File. Specifies a file on a local disk from which to fetch data. The whole of the file is retrieved, except for the last character (usually a line feed). If an SMS Service group contains a file, it cannot also contain a url or a text. There can only be one file in an SMS Service group. file supports all the parameters listed under url. Examples: file = /replies/areply.txt file = /info/%s text = character_string Reply Text. Specifies a static text message to be sent to the client. If an SMS Service group contains a text, it cannot also contain a url or a file. There can only be one text in an SMS Service group. text supports all the parameters listed under url. Examples: text = All is well over here. text = You wrote: %r. prefix = character_string suffix = character_string Retrieval Prefix and Suffix. Used in conjunction with url. The Alligata Server retrieves all text between (but not including) the prefix and the suffix in the target Web page. Tags are stripped out. If the target page contains more than one occurrence of the prefix or suffix, then the Alligata Server retrieves everything between the first occurrence of the prefix and the first succeeding occurrence of the suffix. Examples: prefix = <!--begin today's weather--> <!--end today's weather--> faked-sender = telephone_number Faked Sender Number. Specifies the number shown as the sender's telephone number in outgoing SMS messages for this service. faked-sender will override any sender numbers specified elsewhere (for example, the global-sender variable in an SMS Box group). Note that most SMSCs will replace the faked-sender number with their own. Example: faked-sender = 44998123456 max-messages = number Maximum Reply Messages. Specifies the maximum number of individual SMS messages allowed in a single reply. If max-messages is not set in the configuration file, it defaults to a value of 1. If max-messages is set to 0, then no replies will be sent, other than error messages. Example: max-messages = 8 split-chars = list_of_characters Message Split Characters. Specifies characters that can be used to split a long outgoing message into several shorter ones. The maximum length of a single SMS message will vary depending on whether it uses a 7-bit or an 8-bit format, and whether it has a user data header (UDH). A 7-bit message usually has a maximum length of 160 characters, an 8-bit message a maximum length of 140 characters. Messages over the maximum length for a single message are split as specified in the configuration file. Where split-chars is not specified, the Alligata Server uses any character to split the message. The Alligata Server only splits messages where necessary. For example, if the semicolon ; is specified as a split character, then a message of 200 characters containing six semicolons will be split into just two shorter messages, not seven. Example: split-chars = ;:. split-suffix = character_string Message Split Suffix. Where a long message is split into two or more shorter ones, specifies a string to appear at the end of each message (except the last). Example: split-suffix = -cont.- omit-empty = a numeric value Omit Empty Messages. If set to a number other than 0, stops messages containing no data being sent to the user. Example: omit-empty = 1 header = character_string Reply Header. Specifies a string to appear at the beginning of outgoing messages. In the case of split messages, the string appears on every message. Example: header = Today's weather... footer = character_string Reply Footer. Specifies a string to appear at the end of outgoing messages. In the case of split messages, the string appears on every message. Example: footer = -- sent by the Alligata Server -- accepted-smsc = list_of_smsc_identifiers Accepted SMSC identifiers. Only messages from SMSCs with these identifiers (see smsc-id in Section 9.3.2) are allowed to use this service. Multiple values should be separated by semicolons ;. Example: accepted-smsc = smsc1;smsc2 concatenation = 0_or_1 If set to 1, allows concatenation of multiple SMS messages in the client device. Example: concatenation = 1
9.3.4 Send SMS User Group The Alligata Server allows you to send SMS messages from a computer workstation using HTTP (see Section 13.2). To do this, you must configure at least one Send SMS user account. Each user account is defined in a separate Send SMS User group. group = sendsms-user Group. Introduces the Send SMS User group. (Required.) username = string Send SMS User Name. Specifies the account user name. (Required.) Example: username = colin password = string Send SMS Password. Specifies the account password. (Required.) Example: password = AVOcado user-deny-ip = List_of_IP_addresses Denied IP Addresses. Lists IP addresses from which SMS messages may not be sent using HTTP. Addresses in the list are separated by semicolons. An asterisk * can be used as a wildcard in place of any single group of digits. For example, *.*.*.* matches any IP address. Example: user-deny-ip = 0.0.0.0;10.0.0.6 user-allow-ip = List_of_IP_addresses Allowed IP Addresses. Lists IP addresses from which SMS messages may be sent using HTTP. Addresses are formatted in the same way as in user-deny-ip. user-allow-ip = 0.0.0.0;10.0.0.7 faked-sender = telephone_number Faked Sender Number. Specifies the telephone number shown as the sender's on client devices. Note that most SMSCs will replace this number with their own. faked-sender will override any sender numbers specified elsewhere (for example, the global-sender variable in the SMS Box group). Example: faked-sender = 44998123456 max-messages = number Maximum Messages. Specifies the maximum number of individual SMS messages into which a long message can be split. If max-messages is not set in the configuration file, it defaults to a value of 1. If max-messages is set to 0, then no messages will be sent. Example: max-messages = 8 split-chars = list_of_characters Message Split Characters. Specifies characters that can be used to split a long message into several shorter ones. The maximum length of a message is usually 140 or 160 characters, depending on the SMSC's protocol. Messages over this length are split as specified in max-messages and split-chars. If split-chars is not set, any character is used to split the message. The Alligata Server will only split messages where necessary. For example, if the semicolon ; is specified as a split character, then a message of 200 characters containing six semicolons will be split into just two shorter messages, not seven. Example: split-chars = .,': split-suffix = character_string Message Split Suffix. Where a long message is split into two or more shorter ones, specifies a string to appear at the end of each message (except the last). Example: split-suffix = -cont.- omit-empty = number Omit Empty Messages. If set to a number other than 0, stops messages containing no data being sent to the user. Example: omit-empty = 1 header = character_string message Header. Specifies a string to appear at the beginning of outgoing messages. In the case of split messages, the string appears on every message. Example: header = Message from your manager footer = character_string message Footer. Specifies a string to appear at the end of outgoing messages. In the case of split messages, the string appears on every message. Example: footer = -- Sent by Alligata Server -- forced-smsc = smsc_identifier Forced SMSC Identifier. Forces SMS messages to be sent via the specified SMSC. See smsc-id in Section 9.3.2. Example: forced-smsc = smsc1;smsc2 default-smsc = smsc_identifier Default SMSC Identifier. Specifies an SMSC via which messages are to be sent, unless an alternative SMSC is specified in the smsc parameter in the message itself (see Section 13.2.2). Example: default-smsc = smsc1 concatenation = 0_or_1 If set to 1, allows concatenation of multiple SMS messages in the client device. Example: concatenation = 1
9.4 Over-the-air Configuration Variables (OTA Configuration Group) The OTA Configuration group sets the variables for over-the-air configuration of WAP client devices. There are two ways of configuring a client device: from a workstation using an HTTP request, or from the client device via an SMS Service group. See Section 13.3 for instructions on how to configure a client device. group = otaconfig Group. Introduces the OTA Configuration group. (Required.) location = url Home URL. The home URL of the client device. (Required.) Example: location = http://www.awapsite.net/ service = string Title of the service as it will appear on client devices. (Required.) Example: service = Acme WAP Service ipaddress = IP_address IP address of the Alligata Server's Bearer Box. Example: ipaddress = 10.0.0.1 phonenumber = telephone_number Telephone number via which the client device establishes the point-to-point Protocol (PPP) connection with the Alligata Server. Example: phonenumber = 44998123456 bearer = string Bearer type, either data or sms. calltype = string Call type, either isdn or analogue. connection = string Connection type, either cont (continuous) or temp (temporary). Defaults to cont. pppsecurity = on or off Enables CHAP authentication if set to on. Otherwise enables PAP authentication. authentication = string Authentication mode, either normal or secure. secure enables WTLS security. Defaults to normal. login = user_name User login name. Example: login = colin secret = password User password. Example: password = KUMquat
10 Creating WAP Documents The Alligata Server allows you to offer users of mobile WAP devices an access point to the Mobile Internet. You do not need to provide any WAP content of your own. However, you will probably want to set up your own WAP services - either static WML decks, or Common Gateway Interface (CGI) applications that retrieve data and format it automatically as WML. In order to disseminate information on the Mobile Internet, all you need is space on the Internet from which a standard HTTP server such as Apache can retrieve data. In other words, serving WAP data is almost exactly the same as serving Web data. The only difference from the point of view of the content provider is that the data sent to the client must be in WML rather than HTML format. To all intents and purposes, WAP files are Web files, but in a different format to that understood by PC Web browsers. When the HTTP server to which your Internet space is connected receives a request for WAP data, it finds the relevant file and sends it - or, if it is a CGI application, its WML output - to the IP address that requested it. It sends it using HTTP, like a Web file. The IP address to which it sends it is that of a WAP gateway (for example, an installation of the Alligata Server). The gateway compresses the data and sends it over the wireless network to the client mobile device that sent the original WAP request. See Section 3 for more information about what the WAP gateway does. 11 Introduction to WML This section gives a summary of Wireless Markup Language (WML). WML is the formatting language used to encode WAP documents. Full details of WML can be found in the official WML specification on the WAP Forum's Web site at http://www.wapforum.org. here we aim to provide you with enough information to get started with WML and create some basic WML documents of your own. The Alligata Server package includes some example WML files, so that you can see how WML works in practice. WML is derived from Hypertext Markup Language (HTML), the tagging system used to format World Wide Web pages; if you are familiar with HTML, you should find WML fairly easy to learn. However, WML is tailored to display information on much smaller display areas than HTML, and to be compact enough to transmit efficiently, in compressed form, over low-bandwidth, high-latency wireless networks. Writing WML is straightforward: you can use either a text editor, or one of the increasing number of dedicated WML editors available on the market. To check the formatting of your WML, we recommend you get a WAP phone, or download one of several free WAP phone emulators from the World Wide Web. The rest of this section covers the main features of WML.
11.1 Content and Tags To begin with, here is some sample WML: the file logo.wml from the example site 'Static Simple' on the Alligata Server installation CD. If you installed the example WAP sites along with the Alligata Server, you can view this file by selecting 'Static Simple' from the 'Site Examples' menu (a full guide to the example sites is provided in Section 12): <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card id="foo" name="bar" title="Static WML" newcontext="true"> <p> <img src="3glab.wbmp" alt="3G Lab Logo" align="middle"/> <br/> This is static <big>WML</big> text. </p> </card> </wml> This file, like all WML documents, holds two main types of information: content and tags. Content is generally textual information to be displayed on the client's microbrowser. It is encoded as plain text using the Unicode 2.0 character set. The example file's content is the sentence 'This is static WML text'. Some characters are not included in the Unicode character set, or are problematic to display because they are used by WML for purposes other than text display (for example the less than < and greater than > symbols, which denote the start and end of tags). Such characters are represented by entity references which begin with an ampersand &, and end with a semicolon ;. Some of the most common entity references in WML are: &lt; less than < &gt; greater than > &apos; apostrophe ' &quot; quotation mark " &nbsp; non-breaking space Tags are the pieces of information held within angled brackets < >. Tags can do one of several things: they can describe to the microbrowser how to format content; tell it to display non-textual items where they occur; or describe an action for the microbrowser to perform in certain circumstances. Tags are not visible to the user of the client device. Many tags occur in pairs, with a start tag immediately before the section of the file they relate to, and a corresponding end tag after it. An end tag always has a forward slash / immediately after the opening angled bracket. In the example file, you can see that the letters 'WML' have a <big> tag before them, and a </big> tag after them. These tags tell the microbrowser to display the content between them in large text. So on your microbrowser, the sentence will look like this: This is static WML text. A tag that does not have a closing tag is called an empty tag - empty because it has no content or other tags inside it. An example is the tag <img alt="3G Lab Logo" src="3glab.wbmp" align="middle"/>. This tag tells the browser to display the image file 3glab.wbmp where it occurs. Note that an empty tag must end with a forward slash, so that the browser knows not to look for a companion end tag. In this respect WML differs from HTML, so if you are used to writing HTML, remember to include these slashes.
11.2 Elements and Attributes WML tags, like HTML tags, contain information about elements and attributes. An element is a structural unit of a WML document: every tag begins with an element indicator. In the example file (see Section 11.1), wml, card, p, img and big are all elements. An attribute provides information about a specific occurrence of an element. Attributes are included in an element's start tag, after the element indicator. In the example file in Section 11.1, the img element has several attributes associated with it. The attribute src="3glab.wbmp" tells the microbrowser to display the image 3glab.wbmp; alt="3G Lab Logo" tells it that if, for any reason, it can't display the image, it should display the text '3G Lab Logo' instead; and align="middle" tells the microbrowser to centre the image vertically on the card.
11.3 Cards and Decks Whereas HTML documents are organised into 'pages', WML documents are organised into units called 'cards' and 'decks'. A WML file is a deck, and a deck contains one or more cards. On loading a deck of several cards, a microbrowser will always display the first card by default. A card contains a 'screen's worth' of information. Because most WAP client devices have small display areas, the user will often have to scroll downwards to view the whole of a card; but the card should not be so long that they lose track of where they are. WML's navigation facilities enable you to jump from one card in a deck to another. Cards are marked up using the card element. There is no deck element - a deck comprises everything inside a file's wml element. See Section 11.5 for more information on the wml element.
11.4 XML Validation Tags <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> The tag <?xml version="1.0"?> tells the browser that the file is an XML document, complying with version 1.0 of the XML specification. XML is a markup language of which WML is a specialised subset. So every valid WML document is implicitly also a valid XML document. The second tag tells the browser where to find the Document Type Definition (DTD) for files of its type - in this case, WML files. A DTD is an electronic specification for a file's format, declaring what elements are allowed within what other elements, and what attributes each element is allowed to contain. If the structure of the file does not match the structures allowed by the DTD, then the browser knows that it contains errors, and may display a message warning the user of this. In practice, browsers are often tolerant of errors and will do their best to display files, even if they are not structurally valid. However, you should always try to structure your WML files properly - apart from being good practice, this guarantees that they will display as you intend on all WML-compliant browsers. These two tags are not WML tags, but validation tags instructing the browser to parse the rest of the file as WML.
11.5 The wml Element The top-level element in every WML deck is wml. The <wml> tag announces to the browser that everything following it should be parsed as WML data, up to the </wml> tag. Therefore, the first tag in a deck (after the validation tags) should be <wml>, and the last tag in the deck should be </wml>.
11.6 Paragraphs It is good practice to organise WML content into paragraphs. Paragraphs are defined by the p element. Note that in WML, unlike in HTML, each <p> tag must have a corresponding </p> closing tag. For example: <card> <p>This card is divided into paragraphs. This is the first paragraph.</p> <p>This is the second paragraph. It is also the last.</p> </card> By default, text between <p>...</p> tags is left-aligned. You can centre- or right-align it using the align attribute with the value center or right respectively. For example: <p align="right">This paragraph is right-aligned.</p>
11.7 Hyperlinks Like HTML, WML allows you to include hyperlinks in your documents. A hyperlink can carry the user to a different place in the current deck, a different deck on the same WAP site, or a different WAP site. How a hyperlink is activated by the user is a matter for the browser manufacturer. A typical implementation might provide two buttons on the device to move a highlight backwards and forwards between hyperlinks, and a third button to activate the highlighted link. The hyperlink element in WML is a (as in HTML, this stands for 'anchor'). It takes an attribute href, which indicates the destination of the link. For example: Great oaks from <a href="http://www.littleacorns.com">little acorns</a> grow. Here, the words 'little acorns' are a hyperlink taking the user to the WAP site www.littleacorns.com. On a browser, the hyperlink may be indicated by underlining, in which case the sentence above would be displayed like this: Great oaks from little acorns grow. To create hyperlinks between cards in the same deck, give each card a unique id attribute, and refer to that id in the href attribute of hyperlinks to it. In the href attribute, precede the destination card's name with a hash #: this indicates that the link is to a card rather than to a file. The example file below contains two cards, linked by referring to one another's id attributes. <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card id="card1"> <p> This is a WML card. </p> <p> <a href="#card2">Next card...</a> </p> </card> <card id="card2"> <p> And this is another. </p> <p> <a href="#card1">Previous card...</a> </p> </card> </wml> You can also link to a specific card in another deck by appending a hash # and the card's id to the URL. For example: <a href="anotherfile.wml#acertaincard">Go to that card</a> Here, the link 'Go to that card' takes the user to the card acertaincard in the deck anotherfile.wml.
11.8 Tasks (do Element) The do element allows you to incorporate simple interactive features into a WML card, without reference to any particular item on the card. How the user activates a do task depends on the device manufacturer's implementation of WML. The general idea is that a do function should be independent of where the user has scrolled to on the page, which hyperlink is currently highlighted, and so on. Typically, a do function will be activated by a physical button on the client device. A do element can perform one of four basic functions, depending on which of the following elements is present between its start and end tags. These elements are called 'tasks': go Navigates to another WAP deck, site or card, by means of an href attribute. prev Navigates to the previous URL on the client's history stack. noop Does nothing. This can be useful for certain purposes, for example, to override a default task set in the template element of a deck (see Section 11.10). refresh Resets the current deck to the state it was in when it was first loaded. As well as resetting the visual display of a deck, refresh can also be made to reset variables (see Section 11.11). Here is an example do statement: <do type="prev" label="Go Back" name="goback"> <prev/> </do> This do element includes three attributes: The type attribute gives the client browser an indication of what category of tasks the current task belongs to. Possible values include "accept", "prev", "help", "reset", "options" and "delete". Note that the type attribute has no bearing on the actual function of the task element: it simply allows the client browser to decide how to display it. For example, the Nokia 7110 WAP phone displays a do element of the prev type in the bottom right corner of the screen and associates it with the right navigation button. The label attribute tells the browser what wording to assign to the function on-screen. In some instances, a client device may automatically override a label attribute: for example, the Nokia 7110 phone always labels a do type="prev" function as 'Back', regardless of the content of the label attribute. The name attribute gives the do function an identifier by which scripting languages such as WMLScript can refer to it. Suppose a client device associates do type="prev" with its right navigation button, and accepts a WML-defined label attribute. On such a device, our example do function might appear as shown in the bottom right corner of Figure 11.1. Figure 11.1
11.9 Events WML allows you to specify automatic actions in a client device that are precipitated by particular 'events'. An 'event' must be associated with a particular element in a WML file - either card, wml or option. The response to an event is defined by the onevent element, which must occur within the element to which it relates. The type of event to respond to is indicated in the type attribute of the onevent element. Possible values for the type attribute are as shown in Figure 11.2. The action undertaken by the client device in response to an event must be defined by one of the task elements go, prev, noop or refresh. The task element must be situated within the onevent element. For example: <card> <onevent type="onenterbackward"> <go href="backwardpeople.wml"/> </onevent> You didn&apos;t enter this card backwards. </card> If a user arrives at this card via a hyperlink or a go task, they will see the message You didn't enter this card backwards. However, if the user arrives at the card via a prev task, they will be redirected to the file backwardpeople.wml. There is another way of handling an event that is shorter, but less flexible. Instead of using the onevent element, you can specify an action in the form of an attribute in the relevant card or wml element. For example, the sample WML above could be rewritten as follows, and would do exactly the same thing: <card onenterbackward="backwardpeople.wml"> You didn&apos;t enter this card backwards. </card> Note that the only kind of action possible using this method is a jump to a URL (in this case, backwardpeople.wml). This is equivalent to the go action. If you want to perform a prev, a noop or a refresh action, you have to use the longer method. Figure 11.2: WML event types <onevent type=> attribute value Occurs within element(s)... Function "ontimer" card, wml Executes the specified action when a timer expires. Timers are specified using the timer element. "onenterforward" card, wml Executes the specified action when the user arrives at the current card or deck via a hyperlink, a go task or any other method that involves moving forwards in the client microbrowser's history stack. "onenterbackward" card, wml Executes the specified action when the user arrives at the current card or deck via a prev task, or any other method that involves moving backwards in the client microbrowser's history stack. "onclick" option Executes the specified action when the user selects or deselects an option.
11.10 Templates Suppose you create a WML deck consisting of five cards, and you want a prev task on every card except the first. Rather than repeating the same do statement in each of the four cards - which is laborious for you as a WML author, and uses up precious bytes in the WML file - you can use the template element to specify a task to appear automatically on every card you want. Here is an example of a WML file that uses a template element: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <template> <do type="prev"> <prev/> </do> </template> <card id="card1"> <do type="prev"> <noop/> </do> Love speaks, even when the lips are closed. <br/> <a href="#card2"> Next proverb... </a> </card> <card id="card2"> It is an ill dog that deserves not a crust. <br/> <a href="#card3"> Next proverb... </a> </card> <card id="card3"> He who wants a mule without fault, must walk on foot. <br/> <a href="#card4"> Next proverb... </a> </card> <card id="card4"> Never cast a clout till May be out. <br/> <a href="#card5"> Next proverb... </a> </card> <card id="card5"> Scabby donkeys scent each other over nine hills. <br/> </card> </wml> When this file is viewed on a WAP microbrowser, every card except the first one has a 'Back' link on it - even though, in the WML source, none of them contains a prev task. The explanation for this is that the prev task is held in the template element at the beginning of the file, and is applied automatically to every card in the deck, except the first. The reason there is no 'Back' link on the first card is that the first card contains a noop task. Because a task defined in a card always overrides a default task of the same type as specified in the template, and because noop does nothing, this card displays nothing in place of a 'Back' link.
11.11 Variables One of the most interesting features of WML is its ability to process variables. If you have any programming experience, you will know that a variable is a 'label' for a numeric value or a string of characters in a computer program. A common use of variables is to store input from a user or another external source - in other words, information that can't be written into the program itself. Variables in WML enable you to implement interactive features into your cards and decks without getting involved in the complexities of scripting languages like WMLScript. Note that the only variables allowed in WML are strings. There are a number of ways in which you can specify variables. One of the most useful is via the input element, which allows the user to enter information into the client device's interface. Here is a very simple WML deck that writes a 'proverb' based on terms the user enters through the input element: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card id="card1" title="Proverb Wizard"> Name an animal: <input name="animal"/> Name a vegetable: <input name="vegetable"/> <a href="#card2"> View proverb... </a> </card> <card id="card2" title="Your proverb"> <do type="accept" label="Another?"> <go href="#card1"/> </do> A small $(animal) may eat a large $(vegetable). </card> </wml> When this file is opened on a microbrowser, the following card will be displayed: Figure 11.3 As can be seen, there are two input fields. These are created by the tags <input name="animal"/> and <input name="vegetable"/> in the WML source. The name attributes tell the browser to create the variables animal and vegetable respectively, based on what the user types into each field. To select a horse for the animal and a radish for the vegetable, enter horse into the first field and radish into the second field. (The actual mechanism for entering text will depend on your microbrowser. For example, it may present you with an Edit option that you activate by pressing one of the phone's navigation buttons.) The microbrowser display will now be as in Figure 11.4. Figure 11.4 Now, activate the 'View proverb...' link. A new card is loaded, showing a proverb based on the terms you entered in the first card (see Figure 11.5). Figure 11.5 In the source WML you can see how the terms entered in the first card were passed to the second card. The variables animal and vegetable were set in the tags <input name="animal"/> and <input name="vegetable"/>. The source text in the second card looks like this: A small $(animal) may eat a large $(vegetable). When the browser encounters a dollar symbol $, it knows that what follows in parentheses is a variable. So instead of displaying '(animal)' it looks for the variable called animal and displays its value - in this example, the string 'horse'. It does the same with the variable vegetable, substituting its name with 'radish'. (If you want to display a dollar symbol on the screen, use two dollar symbols $$ in your WML file.)
11.12 Timers You can incorporate a timer into a WML card or deck using the timer element. When a timer runs out, an action is performed as specified in the ontimer event handler. See Section 11.9 for more details about event handling. timer takes a value attribute, specifying how long the timer should run for. The value is expressed in tenths of a second. Here is an example timer implementation: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card id="wait"> <onevent type="ontimer"> <go href="#thankyou"/> </onevent> <timer value="40"/> <p> Please wait. </p> </card> <card id="thankyou"> <p> Thank you for waiting. </p> </card> </wml> When you first load this file you will see the message 'Please wait.' After about four seconds, the first card will time out and the second card will appear, showing the message 'Thank you for waiting.'
11.13 Images WML can include embedded images. These must be in two-colour wireless bitmap (WBMP) format. There are several free WBMP editors that can be downloaded from the World Wide Web. To embed an image in a file, use the img element with some or all of the attributes shown in Figure 11.6. For example: <img src="3glab.wbmp" alt="3G Lab Logo" align="middle"/> Figure 11.6: Image attributes Attribute (* = required) Function src *� Specifies the URL of the source file for the image. alt *� Specifies text for the browser to display if the image cannot be displayed. localsrc Specifies a local source for the image. vspace Specifies the amount of blank space to appear above and below the image in the microbrowser display. hspace Specifies the amount of blank space to appear to the left and the right of the image in the microbrowser display. align Specifies the vertical alignment of the image in relation to the surrounding text. Must have the value "top", "middle" or "bottom". To change the horizontal alignment of an image, enclose it in an appropriately formatted paragraph. For example: <p align="center"> <img src="image.wbmp" alt="An image"/> </p> height,width Specify the height and width of the image in pixels. This allows the browser to reserve space for it while it loads therest of the card. If these attributes are omitted, the image is displayed at its actual size, though the microbrowser will probably not reserve space for it while the card is loading. If the height and width attributes do not match the actual height and width of an image, the microbrowser either scales the image to match the attributes, or else ignores the attributes and shows the image at its actual size.
12 Example WAP Sites Included on the Alligata Server CD-ROM are five example WAP sites. If you installed the example sites along with the Alligata Server (see Sections 4 and 5), and you have an HTTP server such as Apache running on your computer, you can view them from a WAP phone or a WAP phone emulator. The example sites are illustrations of the kinds of service you can implement using WAP. You can create simple sites using just WML, or you can incorporate dynamic features into them using scripting languages like Perl and PHP. The most important thing to remember is to keep the files you serve as small and simple as possible. A compiled WML file should not be larger than 1400 bytes, which means the size of your source WML file should not exceed about 3000 characters. To view the example WAP sites: If you have not already done so, install the Alligata Server as described in Sections 4 and 5. If you are installing from a graphical user interface, select 'Alligata Server example sites' in the main installation dialog box. If you are installing from the command prompt, enter Y when you are asked, 'Install Alligata Server examples?'. Start the Bearer Box and the WAP Box using any of the methods described in Section 8.1. Start the Web server. For example, to start Apache: Linux users: Type /etc/rc.d/init.d/httpd start at the command prompt, and press ENTER. Solaris users: Type /etc/init.d/apache start at the command prompt, and press ENTER. Configure your WAP client device to use your installation of the Alligata Server as its WAP gateway. An example configuration is shown in Figure 12.1. Figure 12.1: Example WAP phone configuration Home URL: http://www.mysite.net Service name: Alligata IP address: 10.0.0.1 Dial-up phone number: 0999123456 Bearer type: data Call type: analogue Connection type: cont PPP security: off Authentication mode: normal Login: foo Password: bar
The login and password settings are those of your Point-to-Point Protocol (PPP) server.
On your WAP client device, navigate to the URL of the example sites index. By default this will be the URL of your Web server, followed by /wml/; for example, http://acomputer.asite.net/wml/. The card in Figure 12.2 is displayed. Figure 12.2: Site Examples index From this card, you can navigate to any of the example sites by selecting the relevant hyperlink. The example sites are described in Sections 12.1 to 12.5.
12.1 Example Site 1: Static WML (Simple) The simplest kind of WAP site consists of a set of static WML decks or cards. You can find examples of this kind of site by selecting 'Static Simple' or 'Static Complex' from the Site Examples index. The 'Static Simple' is discussed in Section 11.1. It is a single WML card that displays the message, 'This is static WML text.'
12.2 Example Site 2: Static WML (Complex) If you select 'Static Complex' from the Site Examples index page, you will be presented with the logo shown in Figure 12.3. Figure 12.3 After a few seconds the logo will disappear, to be replaced by a set of links (see Figure 12.4). Figure 12.4 If you follow a link, you will be taken to the corresponding piece of information. You can also use the link 'ACME home' to take you back to the home deck. (Since this is a prev task, it may simply be labelled 'Back' on your device's display - see Section 11.8.) If you select 'ACME Vacancies', the card in Figure 12.5 will appear on your screen. Figure 12.5 If you select a link from this card, you will be taken to information about the relevant post. For example, 'Head of Marketing' will show you the card in Figure 12.6. Figure 12.6 From here you can use the 'ACME Vacancies' link to return to the list of jobs. (Again, this a prev task, so your device may just label it 'Back'.) To go right back to the home deck, keep navigating backwards in the same way. From the home deck, you can navigate through any series of cards in the way just described. The first file that the microbrowser loaded when it visited the site Static Complex is called index.wml. Its source is as follows: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card id="logo" ontimer="#menu" title="Welcome to ACME" newcontext="true"> <timer value="30"/> <img alt="ACME corp" src="acmelogo.wbmp" align="middle"/> </card> <card id="menu" name="menu" title="the ACME menu"> <do type="prev" label="ACME home"> <prev/> </do> <a href="info.wml"> What is ACME? </a> <br/> <a href="contact.wml"> Contacting ACME </a> <br/> <a href="employ.wml"> ACME Vacancies </a> <br/> <a href="wpaper.wml"> ACME White Paper </a> </card> </wml> Remember that your microbrowser does not see this data but a compressed version of it that is less easy for a human being to decipher, but quicker to transmit and using less of the client device's limited memory. The first two tags in the file are the XML validation tags: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> As we saw earlier, every WML file needs to start with these tags, which specify which versions of XML and WML the file conforms to (see Section 11.4). Next comes the deck-level <wml> tag. Following that is the first card in the deck: <card id="logo" ontimer="#menu" title="Welcome to ACME" newcontext="true"> <timer value="30"/> <img alt="ACME corp" src="acmelogo.wbmp" align="middle"/> </card> This is the card containing the ACME logo. Because it is the first card in the deck, it is the one that appears by default when you load the file. Here is a description of the card item by item. First, you will see that the card element contains four attributes: id="logo" gives the card a name by which other cards or decks can refer to it. ontimer="#menu" tells the microbrowser that when the timer contained in the card runs out, it should load the card menu. The timer is defined in the timer element. title="Welcome to ACME" defines a title to appear at the top of the card in the microbrowser. newcontext="true" instructs the microbrowser to reset its 'context' when the card is loaded. A microbrowser's context consists of information it holds in its memory about recent events. Specifically, newcontext="true" removes all WML variables, clears the microbrowser's navigation history, and resets other information in the microbrower to its default value. precisely what information this is depends on the microbrowser. The next element is timer. It has the attribute value="30", which tells the microbrowser to wait about three seconds before performing the action specified in the card's ontimer attribute. Note that, because timer is an empty element - that is, one without a closing tag - its tag must end in a forward slash /. The remaining element in the card is img, with three attributes: alt="ACME corp" tells the microbrowser to display the text 'ACME corp' if it cannot load the image for any reason. src="acmelogo.wbmp" tells the microbrowser that the image to be displayed is the file acmelogo.wbmp. align="middle" tells the microbrowser to centre the image vertically, in relation to the surrounding text. img, like timer, is an empty element, so the tag needs a forward slash / at the end of it. Finally, the card ends with a </card> tag. The second card in the deck looks like this: <card id="menu" name="menu" title="The ACME Menu"> <do type="prev" label="ACME home"> <prev/> </do> <a href="info.wml"> What is ACME? </a> <br/> <a href="contact.wml"> Contacting ACME </a> <br/> <a href="employ.wml"> ACME Vacancies </a> <br/> <a href="wpaper.wml"> ACME White Paper </a> </card> This is the menu that appeared when the ACME logo card timed out. As you can see, it is a list of hyperlinks to other WML files, with each hyperlink being defined by its own a element. Note that the card begins with a do element, which implements a prev link to allow navigation back to the previous card. We selected the hyperlink 'ACME Vacancies' from this menu. As you can see from the source WML, that link goes to the file employ.wml, which looks like this: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <card id="employ" title="Vacancies"> <do type="prev" label="ACME home"> <prev/> </do> <a href="#job1"> Systems Analyst </a> <br/> <a href="#job2"> Head of Marketing </a> <br/> <a href="#job3"> Chief of Admin </a> <br/> <a href="contact.wml"> -=Contact ACME=- </a> </card> <card id="job1" title="Job: Systems Analyst"> <do type="prev" label="ACME Vacancies"> <prev/> </do> <p> A position has opened for a Systems Analyst. Please send us your CV if you think you are suitably skilled in Systems Analysis. </p> </card> <card id="job2" title="Job: Marketing Head"> <do type="prev" label="ACME Vacancies"> <prev/> </do> <p> ACME is looking for a new head of Marketing: someone who is living in Tibet, or can move there at short notice, with a 3rd tier university degree and at least five years&apos; experience in a marketing environment. Must be a people person. </p> </card> <card id="job3" title="Job: Chief Admin"> <do type="prev" label="ACME Vacancies"> <prev/> </do> <p> ACME is looking for a new chief of administration. If you are a talented manager with a head for figures, an eye for detail and a gift for coercion, we would like to hear from you. </p> </card> </wml> All the features of this file are described elsewhere in this guide. It is a deck of four cards, with the first card presenting hyperlinks to the other three. In the earlier example the link 'Head of Marketing' was chosen, which goes to the card job2. Note that, once again, every card in the deck has a <prev/> link to return to the previous card.
12.3 Example Site 3: Perl System Resource Monitor A WAP site does not need to consist just of static WML files: it can also contain scripts that generate WML decks on the fly. To generate WML dynamically, you can use any of the same scripting languages that are available to generate HTML pages on the World Wide Web. All you have to remember is to make your output as concise as possible (less than 3000 characters) and that it needs to be valid WML. One language already widely used for Web scripting is the Practical Extraction and Report Language (Perl). Perl's powerful text processing capabilities make it equally suitable for WAP scripting. You call a WAP script from a mobile device exactly as you would call a Web script from a desktop computer: the relevant URL just has to point to the script file rather than a WML deck. For example, http://www.awapsite.net/anyscript.pl could execute the Perl script anyscript.pl on the WAP site http://www.awapsite.net/. (Of course, the script's output needs to be in WML, in order to display on a WAP microbrowser.) To download Perl and to find out more about it, visit www.perl.com. Many books are also available on Perl programming. The Alligata Server's example Perl site retrieves system information from its host machine and sends it in WML format to the client device. Because the information is retrieved using Linux/UNIX commands, the Perl script must be running on a Linux or UNIX operating system. To view the Alligata Server example Perl site, select 'Sysinfo Perl' from the Site Examples index. You will see the card in Figure 12.7. Figure 12.7 From top to bottom, this information is as follows: Linux-2.2.16 Operating system 19 users Number of logins since the system was started up Up: 11 Days 7h54m Time the system has been running CPU: 24% AVG: 1.18 Current CPU load and load average RAM: 98% Amount of RAM used SWP: 8% Amount of swap space used The first item in the list is a hyperlink that takes you to a card showing the names of the users currently logged in to the server machine (see Figure 12.8). Figure 12.8 The WML generated by the Perl script for this file is as follows: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <template> <do type="prev" name="back" label="Back"> <prev/> </do> </template> <card id="main" title="apc.acompany.net" newcontext="true"> <p> <a href="#users"> Linux-2.2.16 19 users </a> </p> <p> Up: 11 Days 7h54m </p> <p> CPU: 24% AVG: 1.18 </p> <p> RAM: 98% SWP: 8% </p> </card> <card id="users" title="users logged in"> <p> atrull fturton ymuller </p> </card> </wml> 12.4
12.4 Example Site 4: PHP System Resource Monitor PHP is a server-side embedded scripting language optimised for use on the World Wide Web. Like Perl, it can be made to generate dynamic output in WML as easily as in HTML. Again, the important thing to remember is that a dynamically generated WML file, like a static WML file, must be less than about 3000 bytes long before compression. PHP is an open source programming language. You can learn about it at the PHP Web site at www.php.net. This site includes a complete online PHP manual, a Quick Reference Guide and a Frequently Asked Questions page. The Alligata Server package includes two example PHP sites. The first retrieves system information from its host machine's operating system using the uptime and free Linux/UNIX commands and the PHP fsockopen function. To view the PHP System Resource Monitor, select the link 'Sysinfo PHP' from the Site Examples index. You will see the site's main index card (see Figure 12.9). Figure 12.9 Follow any of the three links, 'Load/Uptime', 'Memory' or 'Port Status', to display the relevant card. Example cards are shown below. For ease of legibility, the content of these cards is shown in full, rather than on a microbrowser screen. The information in the 'Load/Uptime' card is explained in the right column; the information in the 'Memory' and the 'Port Status' cards is self-explanatory. Load/Uptime -- time: 2:40pm The time according to the system's clock up: 8 d 1:56 The amount of time the system has been running users: 7 The number of logins since the system was started up load (1): 2.91 The system's average load over the last minute load (5): 2.53 The system's average load over the last 5 minutes load (15): 2.08 The system's average load over the last 15 minutes Memory -- total: 192704 used: 189652 free: 3052 shared: 117292 buffers: 30056 cached: 28444 Port Status -- 21: open 22: open 23: open 53: closed 80: open The PHP-generated information is all held in a single WML deck: <?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> <head> <meta http-equiv="Cache-Control" content="max-age=0" forua="true"/> </head> <template> <do type="accept"> <go href="#"/> </do> <do type="prev" name="back" label="Back"> <prev/> </do> </template> <card id="init" newcontext="true"> <p align="center"> <b>System Resource Monitor:</b> </p> <p> <a href="#up">Load/Uptime</a> <br/> <a href="#mem">Memory</a> <br/> <a href="#ports">Port Status</a> <br/> </p> </card> <card id="up"> <p align="center"> <b>Load/Uptime</b> <br/> -- </p> <p align="left"> time: 12:29pm <br/> up: 8 d 1:56 <br/> users: 7 <br/> load (1): 2.91 <br/> load (5): 2.53 <br/> load (15): 2.08 <br/> </p> </card> <card id="mem"> <p align="center"> <b>Memory</b> <br/> -- </p> <p align="left"> total: 192704 <br/> used: 189652 <br/> free: 3052 <br/> shared: 117292 <br/> buffers: 30056 <br/> cached: 28444 <br/> </p> </card> <card id="ports"> <p align="center"> <b>Port Status</b> <br/> -- </p> <p align="left"> 21: open <br/> 22: open <br/> 23: open <br/> 53: closed <br/> 80: open <br/> </p> </card> </wml>
12.5 Example Site 5: 'PAT' PHP Mail The Alligata Server's second example PHP site, 'PAT', enables you to read your e-mail from a WAP client device. It uses PHP's IMAP functions to retrieve messages from your e-mail server, embeds them in WML, and sends them to your mobile device. Despite their name, IMAP functions in PHP can be used with protocols other than IMAP, namely POP3, NNTP and local mailbox access methods. Before PAT will work on your system, you need to make one edit to the file index.wml in the directory /home/httpd/alligata/wml/dynamic/complex/pat/ (Linux) or /opt/TGLBallex/alligata/wml/dynamic/complex/pat/ (Solaris). In the <go/> tag, insert the name of your e-mail server after server=. For example, if your e-mail server is imap.asite.net, the tag should be as follows: <go href="view.php3?username=$username&amp;password=$passwo rd&amp;server=imap.asite.net"/> To view the PAT mail site, select the link 'PAT: PHP mail' from the Site Examples index. You will see a login card: Figure 12.10 This card is from the file index.wml. Enter your e-mail user name and password and you will be taken to the top of your e-mail inbox: Figure 12.11 The inbox shows each message's number in the list and its subject. Owing to the size limitations of WML files, the inbox is divided into segments of five messages. To view the next five messages in the inbox, follow the hyperlink 'NEXT 5' at the bottom of the card. To view a message, select the hyperlinked number preceding it. The message is prefixed by details of the subject, the send date and time, and the sender: Figure 12.12 Figure 12.13 Where a message is longer than 700 characters, it is split into several smaller messages. PAT is composed of several files. These are summarised in Figure 12.14. Figure 12.14: Summary of PAT files File Function Main files: index.wml Contains the login card. Receives the user name and password from the user and invokes view.php3. view.php3 Invokes lib/mailbox.php3 to display the mailbox. message.php3 Invokes lib/mailmessage.php3 to display a message. Library files: lib/mailbox.php3 Sets up the class mailbox, which defines the contents of a mailbox. lib/mailmessage.php3 Sets up the class mailMessage, which defines the contents of a message. lib/mesgretrieve.php3 Prepares messages for WML display. lib/wmlheader.php3 Defines a header for a WML file. lib/escaper.php3 Converts escape characters.
13 SMS Messaging The Alligata Server enables you to use SMS in three ways: To implement dynamic services such as retrieval of information from Web pages, in response to keywords contained in incoming SMS messages from mobile phones. To send SMS messages to mobile phones from a personal computer, using HTTP commands. To configure WAP phones to use a particular WAP service from a computer workstation. Before you can set up SMS keyword services or send SMS messages from a computer, you need to create an SMS Box group and an SMSC group in the configuration file (see Section 9). You must also have a subscription to an SMSC or a connection to a GSM modem, as explained in Section 9.3.2. Some example settings are shown in Figure 13.1. Figure 13.1: Example SMS Box and SMSC group configuration settings group = smsbox bearerbox-host = localhost sendsms-port = 13013 global-sender = 123 log-file = /alligata/admin/smsbox.log log-level = 0 group = smsc smsc = at modemtype = wavecom device = /dev/ttyS2
13.1 Implementing SMS Keyword Services Once you have configured an SMS Box group and an SMSC group in the configuration file, you need to create an SMS Service group for each service you want to implement. An example SMS Service group is shown in Figure 13.2. (See Section 9.3.3 for explanations of the configuration variables.) Figure 13.2: Example SMS Service group configuration settings group = sms-service keyword = proverb aliases = Proverb;PROVERB;potd;Potd;POTD url = http://www.awebsite.net/potd.html prefix = <!--beginprov--> suffix = <!--endprov--> split-chars = ;:. split-suffix = -cont- header = "Today's proverb -- " max-messages = 10 This group sets up an SMS service that returns a proverb from the Web page http://www.awebsite.net/potd.html when it receives the message 'proverb' from a mobile device. From the Web page, it retrieves everything between (but not including) the strings <!--beginprov--> and <!--endprov-->. The content of potd.html could look like this: <html> <head> <title>SMS proverb of the day</title> </head> <body bgcolor="#FFFFFF" text="#000000"> <!--beginprov--> A cat in gloves catches no mice. <!--endprov--> </body> </html> In this case, a user sending the message 'proverb' to the Alligata Server would receive the reply message Today's proverb -- A cat in gloves catches no mice. The Alligata Server does not require the prefix and suffix of the message to be in comments <!--...-->, but bear in mind that if they are not, they will be visible in the Web page if it is viewed from a desktop browser. The maximum length of an SMS message is usually 140 or 160 characters (depending on whether it is in 7-bit or 8-bit format). If the text retrieved by the Alligata Server is longer than this limit, the Alligata Server splits it into several messages. To do this, it uses the variables split-chars and split-suffix. The message is split at an occurrence of one of the characters specified in split-chars, and all sections of the message except the last have the text specified in split-suffix appended to them. The Alligata Server splits the message at the nearest previous occurrence of a split character to the maximum message length. For example, suppose the proverb in potd.html is a particularly long one: <html> <head> <title>SMS proverb of the day</title> </head> <body bgcolor="#FFFFFF" text="#000000"> <!--beginprov--> Monday's child is fair of face, Tuesday's child is full of grace; Wednesday's child is full of woe, Thursday's child has far to go; Friday's child is loving and giving, Saturday's child works hard for its living; and the child that is born on the Sabbath day, is fair and wise and good and gay. <!--endprov--> </body> </html> In this instance, the message needs to be split, and the user will probably receive it in three smaller messages: Message 1: Today's proverb -- Monday's child is fair of face, Tuesday's child is full of grace; Wednesday's child is full of woe, Thursday's child has far to go; -cont.- Message 2: Today's proverb -- Friday's child is loving and giving, Saturday's child works hard for its living; -cont.- Message 3: Today's proverb -- and the child that is born on the Sabbath day, is fair and wise and good and gay. The string -cont.- in the first and second messages indicates that they are part of a longer message, more of which is to follow. It is specified using the split-suffix configuration variable. Note that the incoming SMS message must only contain the keyword, unless the SMS service allows parameters after it. Parameters are discussed in Section 13.1.1.
13.1.1 SMS Service Parameters The configuration variables url, file and text can include parameters that the Alligata Server substitutes with terms from the incoming message. Each parameter is indicated by a percent character % followed by a letter. The parameters you can use are listed in full in Section 9.3.3. Parameter values should be included in incoming messages after the service keyword, using the following syntax: keyword parameter#1 parameter#2, etc. As an example, suppose your company has created a CGI server application that returns an employee's salary. You want the Personnel department to be able to gain access to this information from their SMS phones, but no one else. In this case, you could configure the SMS Service group shown in Figure 13.3. Figure 13.3: Example SMS Service group for a salary retrieval application keyword = salary aliases = Salary;SALARY url = http://intranet.awebsite.net/cgi/salary?user=%s&password=%s&employee=%r header = "Salary info -- " When the Alligata Server receives an SMS message starting with the keyword 'salary' (or one of its aliases), it replaces the first %s in url with the next word in the message after the keyword; replaces the second %s with the next word after that; and replaces the %r with the rest of the message. For example, if the CGI account has the user name personnel and the password STARfruit, then a Personnel member can access the salary details of the employee Emma Thompson by sending the Alligata Server the following SMS message: salary personnel STARfruit emma thompson Upon receiving this message, the Alligata Server sends the following HTTP GET request: http://intranet.awebsite.net/cgi/salary?user=personnel& password=STARfruit&employee=emma+thompson When the HTTP reply arrives, the Alligata Server converts it into an SMS message or messages, and sends it back to the Personnel member's mobile phone.
13.2 Sending SMS Messages Using HTTP For every user you want to be able to send SMS messages using HTTP, you need to define a Send SMS User group in the configuration file. An example Send SMS User group is shown in Figure 13.4. Figure 13.4: Example Send SMS User group group = sendsms-user username = colin password = AVOcado user-allow-ip = 10.0.0.5 max-messages = 10 split-chars = .;, split-suffix = -cont.- header = "Msg from Colin -- " This configuration group allows the user colin with the password AVOcado to send SMS messages from the IP address 10.0.0.5. As with SMS keyword services, outgoing messages that are over the maximum length of a single SMS message can be split into several smaller messages, up to the maximum specified in max-messages. The variables split-chars, split-suffix and header work exactly as in SMS Service groups (see Section 13.1). http://hostname:port/cgi-bin/sendsms? username=username& password=password& from=sender's_number& to=receiver's_number& text=message_text The elements in bold italic type should be replaced with the relevant information. For example: http://localhost:13013/cgi-bin/sendsms?username=colin& password=AVOcado&from=0999666666&to=0898999999&text= All+sales+staff+return+to+office+immediately The URL should contain no carriage returns and no spaces. Spaces in the message should be represented by plus signs +.
13.2.1 User Data Headers (<literal moreinfo="none">udh</literal> parameter) An SMS message can include a user data header (UDH) that contains non-textual information for use by a mobile phone. For example, a UDH can tell a phone to handle the main body of the message in a particular way, such as storing it as a ring tone or as a graphical image to appear when the phone is switched on. For information on the format of UDH messages for a particular phone, consult the phone's documentation or visit the manufacturer's Web site. When you send an SMS message from a computer workstation using HTTP, you can include a UDH by using the optional udh parameter. For example: http://localhost:13013/cgi-bin/sendsms?username=colin& password=AVOcado&from=0999666666&to=0898999999&text= %52%62%1a%bb%31%0d%21%84%77%ba%f7%f2&udh=%31%a7%99%f3%80%db All non-alphanumeric characters in the message text and the UDH value must be in hexadecimal format and preceded by a percent sign %.
13.2.2 <literal moreinfo="none">smsc</literal> Parameter You can use the optional smsc parameter to force an SMS message to be sent via a particular SMSC. The smsc parameter should have the value set by the smsc-id variable in the relevant SMSC group of the configuration file (see Section 9.3.2). For example: http://localhost:13013/cgi-bin/sendsms?username=colin& password=AVOcado&from=0999666666&to=0898999999&text= All+sales+staff+return+to+office+immediately&smsc=smsc5
13.2.3 SMS Messaging Using HTML Forms Typing complex URLs into a browser's 'Location' box can be tedious, and if you expect to be sending a lot of SMS messages, it is worth creating an HTML form for the task. Use the HTTP GET method, and define variables in HTML input objects. Constant values can be embedded in hidden objects. Variable names should be specified in the name attributes of the relevant elements, and the corresponding values in value attributes. For example: <html> <head> <title>SMS Message Sender</title> </head> <body bgcolor="#FFFFFF" text="#000000"> <h1>SMS Message Sender</h1> <form name="sendsms" method="get" action="http://localhost:13013/cgi-bin/sendsms"> <input type="hidden" name="username" value="tester"> <input type="hidden" name="password" value="foobar"> <input type="hidden" name="from" value="0999666666"> <p> Telephone number:<br> <input type="text" size="30" name="to"> </p> <p> Message:<br> <textarea cols="25" rows="5" name="text"> </textarea> </p> <p> User Data Header (optional):<br> <input type="text" size="30" name="udh"> </p> <input type="submit" value="Send Message"> <br> </form> </body> </html> The appearance of this form in a Web browser is shown in Figure 13.5. Figure 13.5: Example HTML form for SMS messaging
13.3 Over-the-air (OTA) Configuration of WAP Client Devices Using SMS Changing the settings for a WAP service provider from a mobile device can be laborious, with up to a dozen variables to alter on each device. If you are a system administrator needing to configure all your company's WAP phones to the same service, the process becomes particularly time-consuming. However, the Alligata Server allows you to automate device configuration by defining automatic WAP service settings in the configuration file. By sending a single SMS-format message to each phone from a computer workstation, you can add a whole configuration to its settings. It is also possible for the user of a client device to invoke the OTA configuration themselves. This enables a user to add WAP services to their mobile phone with a minimum of effort. The Alligata Server's OTA configuration feature is currently known to work on the Nokia 7110, Nokia 6210 and Nokia 9110i phones. In order to implement OTA configuration, you need to set up three configuration groups in the configuration file: an OTA Configuration group, containing the settings to be sent to the client device a Send SMS User group, setting up a user account for sending of OTA messages an SMS Service group, pointing to the Alligata Server's sendota CGI application For details of configuration groups and variables, see Section 9. An example set of configuration groups for OTA configuration is shown in Figure 13.6. To configure a WAP client device over the air (system administrator): Send a message to the Alligata Server via HTTP using the following syntax: http://hostname:port/cgi-bin/sendota? username=username&password=password&phonenumber=destination_phone_number For example: http://localhost:13013/cgi-bin/sendota?username=otauser& password=foo&phonenumber=449999123456 The client device will receive a message containing the appropriate configuration information. To configure a WAP client device over the air (client): Send an SMS message to the Alligata Server's telephone number consisting of the keyword for the OTA configuration service. For example, for the configuration in Figure 13.6: ota After a while, you will receive an SMS message from the Alligata Server containing the new settings. How long this message takes to arrive depends on the capabilities and load of your SMSC. Use the relevant feature of your device to add the configuration settings to your list of WAP providers and, if required, make the new service your default one. Figure 13.6: Example settings for OTA configuration group = sms-service keyword = ota # In one line! url = "http://localhost:13013/cgi-bin/sendota? username=otauser&password=GRAPefruit&phonenumber=%p" group = otaconfig location = "http://www.asite.net" service = Company Home ipaddress = 100.100.100.100 phonenumber = 01487772268 bearer = data calltype = analogue connection = cont pppsecurity = off authentication = normal login = phoneuser secret = barfoo group = sendsms-user username = otauser password = GRAPefruit user-deny-ip = "" user-allow-ip = "" max-messages = 2 concatenation = 1
Appendix: Troubleshooting Guide If you encounter any problems while running the Alligata Server, in the first instance you should check the log files for information. By default, the log files are held in the directory /var/log/alligata. You can view the log files by using the UNIX less command (for example, less /var/log/alligata/bearerbox.log). To watch a log file update while the Alligata Server is running, press SHIFT+F from within less. Problem Possible Cause Solution The Bearer Box will not start. The configuration file contains errors. Read Section 9 for information on how to edit the configuration file. Note that when you first install the Alligata Server, it will not be connected to an SMSC or a GSM modem. Therefore, if the configuration file contains any SMS variables, the Alligata Server may not start. The WAP Box will not start. There are errors in the WAP Box configuration group. Read Section 9 for information on how to edit the configuration file. The SMS Box will not start. Your computer is not connected to an SMSC or a GSM modem. If you are subscribed to an SMSC, check that you are correctly linked to it and that you have configured the SMS Box and SMSC configuration groups properly (see Section 9). If you are using a GSM modem, check that it is correctly connected to the computer and that the SMS Box and SMSC configuration groups are properly configured. There are errors in the SMS Box or SMSC configuration groups. Read Section 9 for information on how to edit the configuration file. The Alligata Server example sites cannot be viewed from a WAP client device. The example sites have not been installed. Rerun the installation program and install the example sites. (You do not need to reintall the Alligata Server.) See Sections 4 and 5 for installation instructions. There is no HTTP server running on the same computer as the example sites. Start your Web server and ensure that the example sites are in the correct directory for the server to find them (for example, in Linux, Apache looked by default in the directory /home/httpd. See Section 12 for instructions on viewing the example sites). If you have not installed a Web server, you can install the Apache server by rerunning the Alligata Server installation program and selecting the 'Apache Web server' option. (You do not need to reinstall the whole of the Alligata Server.) See Sections 4 and 5 for installation instructions. The message '[OK]' was displayed when each Alligata Server box was started, but the Alligata Server is not responding to any WAP or SMS requests. The Alligata Server may have been forced to close down by an error. Check the Alligata Server log files for information about whatever caused the program to close down. When the Bearer Box was instructed to start, the message 'Could not connect to the port' was displayed. The Bearer Box is already running. At the Linux command prompt, type ps -ef | grep box This will output a list that includes all Alligata Server processes. If any of the processes are named 'bearerbox', then the Bearer Box is already running. Outgoing SMS messages are not being sent by the Bearer Box. The connection to your SMSC or GSM modem is faulty. Check the connection to your SMS Centre or GSM modem. Ensure that the SMS Box and SMSC groups in the configuration file are properly set up. An SMS Service group is misconfigured. Check in the configuration file that the relevant SMS Service group is properly configured. A common problem is that the max-messages variable is set too loiw. If an outgoing message needs splitting into more messages than allowed by max-messages, not all the messages will be sent. Over-the-air (OTA) SMS configuration messages are not reaching the target mobile phone. The variable max-messages in the OTA configuration group is set too low in the configuration file. (OTA configuration messages are usually too long to fit in a single SMS message.) Set the variable max-messages in the OTA configuration group to a value of 2 or higher.
gateway-1.4.5/doc/alligata/11-4.png0000644000175000017500000001352407344776077015331 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ ;ÍÖ7þ pHYsããUG‰ðgAMA± üaãIDATxÚí]={ÛH’îÞçžpÔ`dOD*š™HT4žHt4“IÊ6;»lìèî¢ÝŸ°7:mt›ÉŽn.²­'2&"YŽD"¢¾ªîØøj4Š9xEÓ >~»ª«ª?@9çdÀáâO»ÎÀ€ÇÅ@ðc øÀ1|à>p 8‚ÁŽàÇ@ðc øÀ1|à>p 8‚ÁŽàÇ@ðc øÀño»Î@büŠxÄcN8‰âHî–ÃÇ"8Ê#8á^uñª¦wc”‡Á¥”8„ÁÅýÔ¡°?¢ŽÊóá'…ê7£l–³ë¢+`ëðäÄ<’<%Äàž•8Æêœ5Áb¿à>|ªÔ’ƒÅñƒ´lgñõ%¢éä¾@0VA*ÖqzY%`¸©UU{(£â˜ÂVjÝØ¨J%=œÇJªrÌ­%,÷Œ£HJ`,3 ~Áâ:O\+psN)Ù*@‚“êEœ’{땃¤Ü+Žâ]ÜË\dk„ƒÊþÆOÇ›Êf‚¼ð!œÿÊ‹<¥¯¸Ò¨+äIŠZ”U¤¥)É¢Èæ¨ª@SyU?ËNÔ–¶%œó¢àgvÅmR]§RÌtª6¨( ‡E+ê¹Äós=Àèɨ5å Ž‰øþÒÃ¥pÌ”‰©äSŠ2ä <%Ï1œHëÓ©E©VlGXúÀ²&Z Zz…åí…ªÞ¥Þoòl2y:YošÍû÷þ-Ðzïƒø¢‚;Ñâ0³˜-Su\JÅ%×–BÝš4P´ñóWBOMn7 3i ”Z¢ÞK›ÎctäM&£ISQ¶5²€ÝùÝ|ùeÉy%™Vì¦ 9)3èÛ2(‹4µ„- “©Å›3[bi''ôˆl4®;’3WÛFD¦Š¢©1U Ž*ÞÁЇ„cžëÙçÂB‚c2÷ç·Ÿoƒ/Z¹©Ÿ ¯w ­]¡”™,ÕZÍÐÚÒ¢¦£5ûLÈèXªïª:ׯDÏ–dƒ¼hb#ïÀîÄM'§ö÷¬'ØÿâßÌo‚0Fs[‚Ú¤(D&X•À™‹®Ÿ‡–s¶lç-†ÔU+æ<ß§æ¦uÍX·h—${Ì»Þѳ©*í:¥U£¢ÁBö?‹F—+OÝS ®#v¦¼ænFsÿš\+jÒöz…Òl‚ƈ4ÙJÓ,×¥®öÍõ§(æ¯Üާq®f$-J²¼S½ˆDbðt઄”‡$T’V‡‚ƒ Àvw%ÍEéÝg©MíÞ,eäe„ôåóKýØÕÇ—ùvô®xZ{¹˜¾½šÿl>ÄÜäç§Ÿ×9?/NÄN*o”þ{™> KÖk>sÅ—F¦¹Ô‘ðI×éQCp…Èn"µ‚Hš†rD€Fd¡Hg’S¦?kV®>½LyÉ”£Ò`¬“GÔ’ì|m ¤ªr¬QUМé%  \F5¬-Öâ1Åkâmj¥a‘5 &U†‘¼©“‰Å(jEDFe%Ï1Ëÿ(Ña%!UÐ'ª á§<˜þLK<ÝÎSÊ–<§ž­zâ2)ý¨Õ}iö¦ZtWÊ#åäX¢ëÂÓµ·ŠÚZ´G&‚U¸¸œ])ÇòÖFr«ÂÍí¬:Ùf;—H‰ÈVÀœ”ù^¹Ê‘-l(°òsA¢¤Ä‹>³ðÝŒ*ZF“8jÒ‹’e·ClAò\¹ º\—VSB,7M­åµû‹  ”©ÝaÁFØ.Be"8L%˜$\*ÍœÄYš{ÿ6eÔ]Нéô÷çPSÔð•i|À%}>}›È.‚¹ìÈ›Œ½IíµæAw-»ÈRt¬ÂÅËaON˜é]ú‹˜p»® ÁQQ¶e§‚8h“úc˜?[0©¶cµu† †Í¦*9ÂÈâe®š§‚UÜYz´(%rO©èTÉ“M"9‰/½‹áÖ½@™ âgÃpM$‹”¹º/Ÿ_¦Ay›€Qñ()„ÍA+³mÜ"ºdë^Üœº>¥j ƒ#‰ÔV ›’«¶Aœª£¥áž¦OgIé™ûDd)ân‘¬ˆDÊNohAEo<Ã[ÐU>U•³D™=e9–¤ZEƒûĹê©Òû´9¹ø>£¢7ò[ •jãý“fdÆ#áèJͳ†¸6 rÇ`â±ýŸÞ}Óˆl„¸ZEcÉ4À阃«O//NLAœ0†ì{xÌQ­Òlba=„½†HÖòËòúî:|ÓY4²—P„±:õvÁÖ¬Ü^™Ó%‘,ØézÇ£cÕ„£«U4çºJÎ ‹Ý(¶ E÷DQóÈ®VÑhBçNàl½Û!Áv¤ª?²[abYÁ:’Å;Lº°;T¬h'¿h6`6¼Éc爭´¨…—'ú wŽc²ÔxëtSßÚ =  Š­Ú`N3II'XÇž˜ûŠ.ía%Áf!Ý9 'è0tš(6|KÏI÷äFEGH™cIûiÚ:…*•³Û0beÓ#KvïqmÐ~!´Ò ±Íxÿ¦ ŒvAÝü`£¦.UÔíšgóUC“_‹ÐS ÁMý¡Öݺ1Ýꂃƒ­Š® lTõ¶fÂpáÀn:xT+ƹþTóx›ªŽöd®@`3ª²²?Ø¿÷o~¿á!qåúzëéÞ;ìþÃâ"ÛLÄäÿÑhtüôØ|a;+z`·°[ª§ŽàDR‡Þ£ÞÁn™Ž‚»NN° Ðóƒ+ –+6º¸¨ðw¹…b­SÑÍPÐ+ ïlØW äÅõÁ,óm¸C-‚”–Þp» ƒ¹‘öëçüÄêa³a8w\ dk÷ꀚ6Ô¬¢K8Öט´™tK²•=w¦Íä]bŽª Á¹sìs[šN‹Œ=6ä4üZ©:T©”{}¨Ò~·â™zTÓuêªN³œL\›[ó]ÌÛ" CÖ(Y—ÕĤŽ+ÂÙŸ¹‘²³œHX{¯.Û‚ºá­Æ¹Æ~²öqÅ{C6µVT›èñ.Ùùì´.ÖÝ;´53Kõuw1%mû}›–xÇ»ìݘ¡6~0.“]7âΰǼ¿xÈÞ)jô[^¡nWhøj;N¢‚›'Ý–ö“ÂJÃÚq†uêJ4 YmÆ —©è.ÓH*ûƒñM+þœÇ$YãŽÈ—c¨W96¹ç®ÔÚöïûHw,Ζð\oúÕÔüò††lÍkÕZÐ[Æ69î§&7\èSæ¶÷ÁÙrúðÈEØYÃ|½D¥ÓÒ·þPr‘}Îa£'BYé[Q‚¡ÝTÏ.´{±Ö€]¢Ó »Š Õú ^ !þb_ò©£J“².*Z¸¾ „¸ŸNƒ¥_F4 Ur¹–ðËtGi˜I†¥J;p ½1©&(ž£'U›rîR¦cr'ô©”žû·ìd·öÝXÆÞ$ø¬gÈ>h¸¶v:ŒÍ«0j·÷b.Œ =¼ûí5 =žEú7î–pؘ‘¥wÅç¶‹g–^n™²96 ö‚Åb¨ÒÆÏ1®²SqùÅÉ¥zïjµí°4öE÷6@ñÕïò?‹!‘¦P%5TcÕÙ­ˆìŸ€Ú «Šå@*[mE;”T«x}]J×a1\ÛBøZ¤¶_"žy­vûæ³R‚ÁÇb”$HvØö3t™ßhð[ë»ïR4»úoeÖÿ5œfxóÙÍÝ¿kVfûƒ‡ùÁ[M^=šZÑb½h6ñŽÆÞØ|mMp‘üÇëlè¡ÐôJ™çý`£”Â覱…i}c·Wì&ù×ÃD0ÝÝÂß²@ùʰ«šÈzŠMmðíòvîÏñšØrYÜb>òÀü–{­ïÑw±‡y.<=öÜš•ßMm0s|ÂUˆ3Ñe}4‰7) ¯—ÝRÑJY÷4ºšUÀ>ÁÆÊªiƒ)¡ƒ îU¢ÕÝŠ¤¶¿°£æOæ$c!Ãi]yùüR¸Â™‰©æi²ýœú¾¿È¿gÁcgÀ¡6iõ* pH@‡E[…#kVYQ\·Ú,µJª*[úšh2Tˆ. ‰ßd'ÂÆ6ØaTxJÂSÎõj˜lôª>ƒÝFꓪ.å«éÚ2vaã'ÕI°K•¯ÔÄÚ2Ì,Ø­ÍLʈçšÚô°CqÈÅÐæšAw išö#­K·užþ ÖUò—ÝéPÃGô¾Óä³–(Vž:¡î&Þ|Æ\OÒ"Qëè•î=§ý”]ZødŽ:5ëD¦DŠGÅ–Ø™£°!˜ôTå'ˆYÎL¨Qј3—2ÎÔÓhFÊj¨ÚÒƒÕÉN8*‡^”MuµBahR'T¬Wd´v-PQÚhÌ ¨–DôÉæs#V´Ë<æ…« ×#q®iÚ–lµÀf£.L­yR•ÒgI¡ØõFll)Á¦Þ$‰e¸\Ü/äë„yYÓ2 åÅüñ¨åxÉ.õ@äjr¤¨Ÿáï=ñFÞˆ®H¸Šð†qÙøÍG€*cûÛÁ2ÏQÓK,ikÁ® G_¸Þ˜k»3w«•`"ÖŽöC?ƒ(Y]˜éKàÕæX­kšýY™£â 9N«nWG}.ŸúJÉÊ¿ŒJNn-pá¬mÁ.^Av±K, &’ãÀ#hŒÅúˆ¼Ú ØX/G±%8…X’ð\$»(»@móÆÞ–`"8@ŠAŽC¾“×½ç4A¿‘ÉfÁpa‰lèþˆì¾–Œc`w€ÜhŸ {‚%ÂUFaÈCGQÍ¥œèêv'ubãHË:µEâ¼ð%ÁbñJ-%ŠªXìL~J: !‰¬Bc‚%"ø‹Ñ¬Î_œ4ÂêPgˆ3ãB2ð¯pÿÌ›qKªEC3‹×Åg’b- ‘ìc¹ÿÓk%Á’¤ÄuÑÔGbÎ- ~Ä¢ÞäÀÉf4A®ˆL^2)$ÃâA v |Å7ð$À 2í05õa@?Ðp¥»2D«(üAÀ±Ƽ‹v8Ðx؆þT#ÆÒÃo¡J= Þ¡«Š†œù¾Ï#õ· –¨DxDX÷H-n»ÉzÓe.üdé"ê´Ô¯>€ª 5"R±É2IKLþÄòZqÉ1¸' $P’ çç瓯'›ÊKW †<Ë@ò'² „…qHB‚“a™Èx–B)ñêᣈ1oòÌóF°{¼d'ô¬)­•üK÷ ŒÞ@£µ ç„ax=¿¾]Üþõ¿þ:Û#ÍèD0ðì"£„Á÷dk(åʰý#yÜ“)Ót%h¾X ¨1ð„g/Î^¿ÞVFëÇ_­Hšqo¬¡òX;òkÅ+QF!†ŠÂùõÿ]_}sõêß_¥õ¾ :ÿ³ÇÁ/‹År¹„ "ú °“Ñ~ž+1ªC }ºö+ÔÎÄk {7_Üùþ7˜²÷t“­ÑƼÜÞÝ¢Ù!ó¹"![Poóß³¢Ž+ÒµWÑa„Jh%Æ¡ÿÀÃÌ(A':Fð êË{2¢ ÄsÚƒ*ª¶¬Ó±çÿº¸†ÄPà.‡@͵ºKˆ|~xÿ¤M˜”®ðbÞ×§ã£xdb¢‚ops‘cØ ð¤@6ˆÄ* bœ{MÅp(%WH«…K n‰•Æí”Ƕ‹ªF4P•N˜WÜûjzúÃųIÕð{|¸°2VK"Ì1p¹SZô‰÷é_áí|Ž£EP¿áƒýôçŸNf³þK0TÁéwÓÙéìïþÁ]t“<±þÐ8ö§îÈ£hš@DŸ0â‰ÆˆzJ“qt¨ð¡d ,À ãcÏ }ú7² #ÂéÞûÝ^Eƒó*%.aÂãKz÷S²Ä9Œ0¾#46*¨¤×0ml¸ô°wYÐÖæÙ‹3ðñ'ÏF;dÎ@Àä«É‹óï¯ß«pìrzw=÷çëž#”¬+ƒ Ð§Óéë7¯¯.¯æ ‡V oQj9Áô€RÂÞŠFðô°ÿ Añ‚¡·º©M*Ê„ámë“£Éî$Ø!“ñxúÝéÕ?/)÷äè!šf7kŠ0×7êac„ýÇóóÏŽON޾žô_9ëWõ§óŸ¦ßL/ÿyõáß+ÏV$.~èr–Äò„Ó¯.QQ¼´|T¨‹«°6G˜>=†î^íU4h•ÙìäÃ/ï—÷>ýõN†,xòI¾‹bD„ˆÐr3hoœÍÎFÏF ö÷‹] ÏóŽ_{lvz6×û_Þó 0äŒbôö*‰Ýê2@±rÞB‡óx:Ù=’Õ¡»PÄ7.ÿçòíÛ¿A(^5ÔR_f¥ îb-»›@RO¿Ÿ~;y~B€•|©Íˆèõ]}óñæú_×þÝ|?ù\ª1vÅÚrÒ?¦,È…ZúìÅìõ¼™}ºS‚‰êox÷îÝÛ·oe_&îtJN#Ig"œƒ–ç÷3àõø›cY´5úß-ØØÉ·w·‹ÛÎü·9F¸´€¼*¥TÃiLÏ~˜ýå?ÿU#=ÿèð;ëúúúòï—ªsIêÞdX(6±`zh``Ø•"«Fì»ÔVAJ³ˆFÁŸn>ßPPË`Ir«ÛhÑéñh ¼¾úùÕéÉ)²»‰z¿‰Awâa|Ymi°5¤¼¯S‰€rKdÍ…#WQ>Ÿ}„O?ëi’¬ýP2ØZžL¿ÊRÚÔý76ªRF¤i© ÐÇÑ€Ä!FOÅ@£'ž´2þˆÐÇå|F®w ©·Aj'_cÕF² 6«ÕaØl:ÂRbt§C:‰Uµn˜WjãèӸ耆/ưo>p 8‚ÁŽàÇ@ðc øÀñÿa)þ·Òo¹©IEND®B`‚gateway-1.4.5/doc/alligata/nearlydone.png0000644000175000017500000006456207344776077017117 0ustar toljtolj‰PNG  IHDRX¦/tmtIMEÑ /ø`^á pHYs Œ Œs®[gAMA± üaiIDATxÚìy×}ß_ßsî콋ÝÅ@Üo¦h]‘,É2#‹V鈻"'åP‘UI¥RI•ýG*ñrRJ•Ë²éØ±eˉUvI–l+”lŠ¢I]$A$'ìb±÷îÜ}ç÷zvgçžžÙkvûû©j¶§çõ{=»ýïëßï÷Œ@ÿΟ?¿ÝݶãÇ‹ÛÝ`;4BB ÐÈÕ›ž{î¹íîètžzê© .4ØáرcÛÝG¨D„êøP¹æ®t™ÛîÞ‚Îåé§Ÿö³[c¥€A®÷®bvõæ;q@ ‚-åx9m7²!o)ÝXïyÛG/îÖö0[ƒ¼þ&h‰Ò;Õ$»µ°Ñn»8BÐlS©‹ª¶Œ5·Ô{^ºsEã­v¬¦ymÚ½Òƒ6`{#BÑ–ÚÄêMU¤úíDMëYs{Í£ûéUuç+Q¯5Àö!›HiŒV1õ°TÉ*4ÃO›iñÙŸmdÉ¿85Ø­%y;vì˜Ï\À:¡KP½¨Q!Ø\Š9©Å„œå„|ŠnQž®¢5:'ÈÙ`Û‚M§“sRK`MSè_¶kNÖÜg§œv ä|éD° Øa4M„ð³}Ç­;³þQ¶8BÐq”Þ,Z¨Ò¹ÇÒWldëNÕ¨×TõDhã©ÑÒ˜êÖÛ „l)õÀÏ„d©êøÜØô¸m¼±8êsm¶L4BB Ð@!€@!h „ „@ 4BB Ð@!€@!h „ „@ 4BB Ð@!€@!h „ „@ 4BB Ð@ÁVs¼…íëlv‹‡°©Ýk¼ñÕê'ëÚf«½î•þzÔÜ^¯YŸg¯fƒ¥¯úü 7ª¬­“ÜÆQÖIƒñ6þ\:y»;Çùóç O该ø|Ñ^·7{¤Ò~ahM¸5ŸZi7ê=g­õÆX³Íž­ö¶¸¥QïÄ¿ˆšg`gýuÂ΢úëdÍïé¬þ·õ¦«¿ò7xµf;¥_Ûëõ­^êu¾tKÓ£4`Óö×ÿm½¦gjpVÛ«# léàõœºÆî¶æ¹múÞêÝX‹¿H¥;4þÍ©×f=*D±éq«‡ïÿkýÀ‚¢xÝ©~Rïùz¾‡6ðõ(5>-KKÃ,<ñs”¶Ûoú.?¦°ú@ ÎjÓá48\¡åR»VÇè¿« }g½sÒÒhûW«Õ_W?€õN]q¼Õθ?“¶ÿ¸ÚB:ˆš]>÷d3ãÿòºž3Ðvû›ñ…º´Ù6¦U›žšŸ¬Ï#ú¤ô´´ô­ó¼m`kí5Xú–uö§ô[Ñzþ 6ü]M‚Ngc/Ü"–Ôû6½g u Ÿ³¸ë¤©Çméèç@¥ûø÷ÓëïóÖ´Óê»jZÉÆûןýñóËàsOÿ¿œþ68B°=”Þ#ôù—߯Bwëa3®G+j–žœ¶»©—Ñ–÷ÙÉõt¸¥Õ ×sÒÚÛa+×OëŽlMÿòLßU´s¼V¹êƇ>î£Ös‡\›|N”ùìvgN»µ8Ót°5ÌNûe›„t(M§¼*ö,}u£ÚÞÊË_=mÞØó:ð‚^ïcmÜgÿS£ëìf,ƒ¦FA§Óª]ðójƒõŒ6Ö3ùi­´3>;Ö8be£:¶ÎÁ6fYOûÞy?qUm ¶3ý7¨Žt"W d%‚Q=yµÎJÐgÃêŘÔëê:×ÿó¿ŽŸnû?3-ÃzƒmÜÉŠ²ôyƒõ ý Öÿ ŽM?&ŸC¨×¥ö~9ÌÛƒMë‚–Ù¹ë‚-#P×ñ¦3´`ÛÁz„@] „ „°ñjVpI„`Û4BB Ð@!€@!h „ „@ 4BB Ð@!€@!h „ „@ 4BB Ð@!€@!h „ „@ 4BB Ð@!€@!häz/å×·»o Cù=öþíîlp„ „@ 4BB Ð@!€@!h „ „@ 4BB Ð@!€@!h „ „@ 4BB Ð@!€@!h „¼Ý›Ž*:²à„EK\Ep$Ñ­¹[Þ–èÛrŽl:¢éâK @w¤s]’‘̘lÆ%3.aÉöôÏès…úo'yt˜·e’@Bú1c+9[ÎÚJÖ–\&dm™4Rw €]„p#0·K6ûT=!ëƒjŽÄOIóÈÊ‘l5z# ^ÚRÓ–’¶åt‰Ú s mW⺮à2Øm@wŠàŽ„2CZv– ­¾Æè޼hjK–ºljËüÕ!9äÂæ_Ûšv$„ÄÜ#±¥#ÑŰd ¬‘„Ù®Hj·`isFdÖåÉv–ª€î$úTý¾®¹zh8Ò¼š7CsFxÁÔLW´¡|Ð áN"i)K¦Ö£äK7ºL˜Ñ׳ÝÓz˜Ä¶Z€; Ý‘~¼4”wʾ¾ÜÌÅž_¹‘‹æ?¡‚Љܲ¥,›jÉáV>n çÚS£;±EïUó ÙèSò}%S£sÔÙÁíî#ìT „Š&Ú]’Ù§rÙÐrš`Ëu’ö…RçS=Y%´®žÛ¾hGe3"ZQÉìUô.Å '’àÊ‚Óôíšd…Ó—2ÝÛ=Ø‘@·ru^å3+&™1ÉŠH='ÍSG\þ`-»Ì•"í!ÜDH¢Â’Ý£è${ Åè–uRAòyãš·þö©‰¤©Nê±kÙ®í+ìT „ YºOóúÕ|·¢wɆì¹=?ï5ÉòÊžŽä¸,çÈ®—2á¸BÞ‘éÃ-—¯ ‘w$×2¶l»ý?m!ÜÆÈê ¨ùa-Û¯ä4‰¶ë¿Ø®˜µå¼-‘°ÞòF9[öÖyXYÒ¡ðÜ*©üéx«D8ÜRòÿ·]çTÑ‘øBN6 !ç­Ö»aûùëUôÑPf,”‰®®ü@ÖmÉÔR–š²”e‹ž(ÜÒyÚÆ j5"¸Ñ ‰vH²5ÑŽHÿ_´hD[!Ó™ö*ÚÐX ¬ÁØu@[†ëŸê韖‰Éý¸l©·òÑY#²lª)[±:»È'Ù;~ÏR6b²éݶ4½%,ømKË+Õô©¸aÅIÿ ciº ;a O§ï '{dÝt¥#t)“˜1Â9[&Áèdµ «šÍ‘Pf–!ñã‰"Ÿ¼5]1ij“ùØ’¥Îá,ˆ`ã¦# H@}¡‰éßáèÙ&R¾‹éÞY3¤ÛR'‹_¨d‘øŒ$²®xbM¾h„æÌ)ߢ©p |€À!l)ßpêhl1cÉo¦{oç#Þ=¿N_¥VœA-·7” ¥é¹ ¸†#Mäcô¸£Ó¸ømw #€6¢K6OÅçIù~¸8¼l©–ÛÑúG‚—yU¶-Ó£è!Ñ*¤mdmåJ6q#'-·;^Â`‹Ö…´d–;Ÿî]²Tg}S‡^ú¯CâTØ"´Ñ®¹³åðø”Âs— ¹ª"¢²à¨‚-xÅÕ AžQÉJxiû²à*<´e¥»$—³‰kÙDާj¨„°.YK¹È%З…"©‹ˆfH²yÕPÉäµÓD‹„Š\š"Ú¢ÀÃUo¢µ°¿àEŸÖlª,ÅÂeÕ®ÐN¡…š©ú†#Íá‰|lJäl €ÖE¯(&óz¡½j¾[6Èi‚Ík§ñ$g“e)0¥Ùþ¦#åž­Ÿµåy#´liK¦b¸’ÝÙ¹Ð!@[ ,ÙCjvDËô«yU´eOxnèxµ¢5Ý•çº#‘/t]–÷Š®emžØn9bÖ?ƒïÆgS‘ðm!l©Ýh(3JªYÏs6¿BM5R/ï!êOÎ3É˲ç5ÕŠ³¦#VÔjñæEWoº¬ðÜñ ­y-ÃäÀ!lÉΰ–½'>ß§äëY·9#Þ3U/¼³HÒRÏ$¦õðîNÎ+ÔVÝʲÔvw6a#"/<Ýt·7R}“ùèvwv³PE‡ q¿šßJÅ$SéèZrÐ2;A-‡å½ô;Yd¡-íðÍ\\`lo8—x‰j¡NÂC·¢ËùØæ¥Ûk"ÏÊà郞Ñy5,Æäa2܆ªc.¢É;ëZ)©Û%]|m©\¯’×¼e˜6ï<À6Ò©B˜3Ù•öÊ›L±ù³½«°(°¾0;1È~zœõG¶ ¦+\Év]ÏÅÁÒr'¦µZÓ¤G£‹ÃZvZÜÖ#ÓzØ]_õ•g"Z ÙèUôbš<鸚†(”¤:®P ¨¡'ÞJOöC¬KÝ‚y™ )\Þ‘k ! Ù&zŠ.½°8r;ß²H«‚C¶²_Í k¹„¬ó1¢íGN=­âr%•ï/ßÍñ²/ìÕõ~ÝUó*y ‹<ý‘Õó»°»é0!ÌšìO_ãBhÔO!ï³”g}‰½9ËþÅl4ÞBûm!xåÖNuÍwÉzã=Wô¿t­à݃¤–ÇBi2”[¶IC½DŒYd%õÕZnúêÌj®d‹ë½Õ 7éHïØ¤^ÀvÐIBH^ðO^c?žàR§Él¼‹íM°‘8SE–2ØDŠÝ\b·Ó¬pI¦}®.°ß™}þ6°YÓ¤¤U½Š~ ’ÜNj cGIHfŒÈÅt÷¼jÚ,5µGËí'ÉDª¢½ÑYùõή˜µ•B~ÊTù¬©Í«ÖÐ…´ýbvc1£¿ÛÉë À:é$!|ñ&{é6S$öî}ìñq6+ !å˘ìò<û?çÙ­äÊÆ·—Ø¿Ê~í4‹4­DÖaÑÐr#É~%× }‚|VÚR¦È­\lÖ™ Ó'dÁíWIÿRCZ."šÅ;p.¹1w-¼E`®*:럨¤¾e,¥°ân’×]#ñã‹îvø°ÅtŒÎdØ7ÞbCö™ûÙ¡^SȧöØñögþ:ûÁÄŠ5êÞõl×­|ŒºjîêÔ~Ø@:F§Òìs§ËTðú"{æ{}š¥ V±à­å²óìûo³ŸhÉÊ‚Kf«û¿tBÖC«ED]&ä9gË[NZ‰Ê¢©å¹òñUÝÌWÒ±c’é0ÞXÜH?Nëá)=Ìos¾1ÃÎL±›ËlYç¢n–˜<Ò¿ˆÂº4öð;=ÊÆº ›]/>ŰĂ冷Ö<4Ià[™žÙ8)tK3ª!ïeaî·¤QúêZÔŒ7¢¦Æv"#„ﻋ ¬gÉ™ì[—Ø÷n°´î÷í/ÞbïÚßÔ’ÔÅ%³Gчµl?™?Ñv½ë{ÊÒ¦m‰ä$i©dÅH-Gà3–þ2IKÈJvÉæ¼Z4Ë2:xrÃl–½p“½4É#}ì:Rb9,©óÇdŠ=û6{ç8ŸìkÅ×IbLÌÔ +Ⱦ–죞7–@r–Qž)è¥'ÊFH²¼8Už>!­¥'–½Å.š),pÁCIQb °‹è!O¬ Z³Ó샇¸jvis¤¤v)SY6UÛÓ¼õg3ëSô}á© ùª7S½3Ýe·Éjž›fù&Ÿò­p îc§†ØÞUEd‚Àÿ/@3m>Ьµ äÕš eª»¡;âÙd=”˜K=<[¢o(õè0!|}†}òDx<ú‘îͼòƒ…Õîõ„¸7:=Æþà~­&I^ŒF–ø4éOï+Y¹Í¶Á#ÔDB1öh™½¡4¯/*8¤¬¯§ú/¦»íÒIÔe}íûáŸã]{³ÀÓ"ß»ŸÝ;̵P®ßÕ»3—(=®[3…ƒlhÒª7¢ öéîÙÑPjk’`çÒaBøøxTµÿ>û‰añ/&̳Kr¶ÔÉ>õ0ûí±;µbFÈx›a=Ê^›æû|ún¹6Epâ²9¬eGyXÍZ&ƒË„«ÙîJ¼¼Àþç9žàX:Úf>ÌãÑ¡ S ÙU¥$™Œ©,\ûã°™˜³åhUlÏÛµ‹k“pÞ×µ°7œDÚ4¥Ã„P~ýˆõİðzRø j¶z>o,Î~æ û_çøÜc57<ùùGw±—'Ùï¾Ä~õA> ÙÞyܘlvÉéß «±ª=Ù’©½™îYSAÓaß¿Á¾ù[Ì•4$²GØÇóì’½« ìú¯'Nþ5k­Ž 7‚#1vl€äQ?%–ÑtÄI=Ú£TN G¤Ji,ЭwE– ‚à‡ÎÂûºô_$Aøò gÎà“~I>;™3JúI¾ê™«lº–)¼•dIƒG Ð>ÿû<ûï¯ðÄÄ} ?‡æÊ'™Q?ÉL(zŸ’K–":b /Ž+Ì£còûæ%öÿ®”%EÃû…ã|­Œ©4{þ&¯¡J™5ëv‚uvš[ÃC½ì‰ÃìîÞÂfêÁåtbLãó±¥»Çy®½™ªšRs˜Ÿt–þüˆÐåõèæWòá>2yÿ ó¹sL/ºÃ¸Ê÷ÖÂ¥}j_ÌѼ«tLf²çýb’u"NŠ"ôª¢ZzËòð $4îs&?Ö[sBX™ž%S}u¹ÿV.z×\Ÿš+4ÌòJžÝ^%yÍ•6PÁ…|á³o³‡F¸´ûƒÄòj¦KbîÉø|Q×sŽ €j¶\M‡]˜eß¹ÆãGr^ñ”£ýì—ïc}á^%ÿ¹5¬¹÷&òß ýˆ±?Â{8¤¹áÒ”¹ŒÉÛiLLã+TRÚ§ÓÌŽóÂ➇³c!^OÓvŹø›éÞ”¥”ݜͲ/ŸÝ ,Òy ì¯>èÿ6H¼LíptiXË’ö*ù^E§-~Þ. Ž*:a‘ÇÍò"¥²E["Þ¼Þ)jv[+„I‡q¾|{e%âP/¿ÖÇïo•Æ:þ§ãÒ£wò¿¸W(”»œÈ Y»¼zsÝ« ÄÓ;…U÷–5ùþJíôó Èö½´þº/Á'–'“kûßZæ+’"ö„ù(ÚÓ7Êm"¯æ]þ¹Ð'Eñpt),Y…õ7r¶R¸ ê¸B¡:kiø’ä-XˆÛŒ€]ÆÆ¡&:=J¾K6 Gš5B–½ºÂÃ|–½1Ë®-²áËGXåúA’ ¬]ý¯gìœíÆäJøfÒÕ‹W`j„¬IaU£W×Är0º¶ÉÃÉ5!ÌYüAý¼4ÏW· ƒxb½g?7XÕšœÔÙÿ½À2k2î?t0úø ý±1aoØJÈ\ª³¶}#ëþæ[ +UñôÉðÓã—Ÿ?ÿ·og¾q§Þö”¤ôÑ1¾xõöëË:Cg†äÿÙëµ{²KÿÚ#B\S»vzÿo=>ô­ÿx†/jX$¢°÷àÝûòÙGÌ[¼ÌÍ’Î~ít½BÞ>fÕ×~UÉ“yÙ¿9Èâž3ŽËìÞnñ ޼ž½÷í§/”½¾@<<ʾq±ötæÉõRŸO ´øÁ@°hGÁ9_¼Û[ßà\ªïZ6aã*Iüþà••õå Ð…¸àùúªÀyøå|Õ¤ßÍŽôÑnv+ú‰1+^Ò©¬Í¾xEÎÚ%ó¢g¦Ên4–rwïÊ\ëË·×Öì ñÅJ™ò‘MaÚ<>eíG‡}ûòZ¶¾öv±OŸŽô=ÐϾxÒz°Y åºyÛ¦Oäánë‰=e>lXŽí}û'*ߣ[Üû6 $HíE—Jjˆ.÷Ù¦#Ždx÷[ìZBºž>Ö=½GËÐ¥óÅÅ=SzdíÊJjñ§¯ñp’R¡*Þ´;ÜËg+¢¹Ã½Ë‰AöØØ«§†þóE÷7 …ôyRÁß8/½0_´rq®nöٯ„Kù²¨Î½ ž\_İyݲ¦ÜÕ]¶œ!©õÙi¿çHÙ££ìÉcâ`ä£#ÖN°aÉ{Rö¥´r bü—{­|>rÙrÎ'MÈSŠíòðѵ¼"¼Îí–1X—æðÛ~âh8=ÎDMïã½fD‹?„Œ­,™ê’¥-›jÚVLdß‚AkBH–á‘ÄÌH(mº©àR$ÈVÛµKóìþ=|q÷Ó£ì{o×(ËÉqH&-üò ë;3ªUÚÞ‹·ê&NŒÄW’p‹ßê+r¬%9¡õáJÃ@M3È>yb-%1mð"g>«¦Ñ±>r„}à I?7lýÎ)7îãçm÷·¯J¢î»Ç8WK_2÷w¯š·òñ²7Ð÷‰çoð¶9#4o„.¥GcKwE– 0 [™ÒîVôQoĺ#ålyƈL棳FŠØÝ´&„ûÂé±0ŸW¼”î®TA¾u¡F^ ωvÏ¿(ÿ«Óì/ßd/MÖ^”æ­yëÚÒ_}·û¯>x7{`˜‰åÝ›LqgVSCÜRË/–,‡D¢B2\€¼ÑO&Ù7Þª-i¢À'Ⱦc/;>XcBêþ¶¿™Ì>}Š=¾—ÔôPÔú­¾Tøæ1*±?yЩVÁÿz9ÿ¥ëñ²S½¬³g®°ï^«ý@Ø}{ØÇޱ±.>“üíË<%qj'e+¯,Lå#öÜÑjV¥ô ]<Y^¶ÔëÙ®«Ù.È!`·ÒšŠ, ÞM¦ùXÛt=!~‹®ÂæLöôËì'ØOñô†ÏÜÇu‚L©æL¦ÆÝ>Oùµû=ûÙG®%È›³j‰ GyäñÊÏF/l$xß0Ú$èXw=÷6ïÉ=HêhŸDˆgŽÆy¾YÀÞ²ÌzñÙë¾Ié?u{ç8µ ο¿Û ûÇûÜŸßÃÔòݧuá —Ü?»[K!å{íûÛ+µH¨w÷ñ% z&˜NíKS|–˜ÚÍksÔ^Ñ™I=z&9øSÝS z%ñ¥-ò= }<œzyyÐgy6ØY´&„y厔R³ìÖC{¸ÒL,W.êNZò•sìì½wqwxr§{'óìf’‡€Ò5}*UJWüï\ãîS'WÃÉ–V¥)0ák’‡б˜Â#Gž¹ÊÅø¡ö³w³‘ØÚÕŸ„”øO,5‰'h^ån2‘bà n}Ô•DöÄ‘‚ 2^•îi!öd$TöãŒÎ¾~›ýñMñ|jõ{¹@rÒ?š`×–*-q0ÊOìãã ¯6jî=}“?ZšÌGý¼vm¦Oì §gP¥’úwñ¹Pr- ¹•ô‰t9¾0Ëoy—ìöðÐ{‡ø#gñ_¾ÍE´ôÞ™0jêÑ1 J|çjYÐ&]ñߵϒ/ò$ZóYöK§ø»BåCë­ÝóóÙÇçnø²ƒ°*séU…Ñp;A˜$_»Í¾rS¸–yJ;œ+ ü䜟åµfJ{Rп=%;!Ã)Ù¶$0 hÃãt¸hKW4=Î" ‡e8>Iù¯Ùh´g"F’v$HĦ"TÆmÖdI'Yð`yõú àä¾öðÍéß7/P?½pó}&´zR4 %“ ð3.ÝLŠ€ˆ,|cˆ±Î˜¤í Þ¢ÛûôÀ@·s8‚ Ȥ­œ°¼ËŸ,&ÏkñëÂCv€7“¼%1nŒsªgÞü€>Y8¯Ç+ÿ"QrHài¾¼ïŽü¿ÐÜl—ŠÄ–b­$½U_”¯à ‹–¼. š>ÛhuðzŽ$-Tfë±q2I;¦V&)6fÙ µuÎ5Œ»®.‚‚w<}«oð¨JJ L†uÃÙfëÔð´ßK✬QQS9[êD„KÐWôXûçAÙRt 9ÚÛ²®pÅPé°RåC±å‘Êô»ózâT!é5ˆØÜ¯˜(ëŽ/DZœ€-aùHõ‚Y°åœ+˜ë5/úùüµÜ–,Ú"ùŽÍe(rt°Úí=¬'·Vô)\âv( Rvsó™)²àWŸPó|žñEÚß\z),t_fÝ6ý_³–²`7UŒA¤‡èp• ì] ÖÒ­3ÅDmJ+TT Á à„ªb—R´gKcÐ<>ãH7¬È¼%k¤P‹kZ Ÿ–UàTH²ü£ã«Uc*`é`B*òt y\@òƒç\nκU¬™Â4šM*¬Ž‡~‹ §ˆ— ’ËÿÉ,õè  -î'Å[c’– 9\éäh_`üÎÊ^Õ§*|–l*0 A¤§è|¹¬o zõûuÛ‹,õâ~RŒôô)–¾cJ÷Ù÷3£&æS¼I5Ä Û M›ÑYS)MZoLÇõAÌÐ\èAËŽxY¥âu…\#ø¿³ZrÁ–ÝöcÍ’tuðGwP¿µ÷väNÅGàÉDWV”øª¡~QH½;c"F}õ!ê‡_ Ød êŸ>%¢»#Aš —rç%¾zp¡iCõëñtwÓÛáûÄœ©€Ì¢ "Ò§t^£\m§²;’»f¨uK6o‹‘W-xÚ¯_ žÔ' g´d$ çEÏ,“€LÀgwÖ È™=JvDÐKY0†%[>ULÎY¯z MRAé~™Lº.hµãQ©0€öÜòíE‰#3¬,UçÌG¹!‰ñâ¼ýxâ†ÂvÅZ>›uÅóÅÄ´¥x˜2 Hÿ²qTÎ~*9{,?´Tݶ¢>qÎy@]æz;Àóú²ëŒ RἨçS¿ÿ©êyg\ C ë‹úÎH!É›Ü͹P:㈴8xA»ñZæˆBš2~i7™í¼”!9…9‹2Ãê0>¼ Â“œÂ§&Ie­9å Ì`ñmÑò¹Î ¡îñ+Ž4oÉóV$ïò͆!‚ô,œSwm@0ŸNÍÌšÊ%#FÂ8}®ž5?ÆÙ$û-ßøAO‡ ó:y_{¸|QFeoKZŠ7#·ã…K’p#p;f“ÅV@Y“y"¿:é²D„ðΙd‘»Yµ¼!íïWW’ÜK§ë ¤ñ.E£ "r7Ðy!œ¶¢ƒ¡ÎÚ•Àx;"ùí‘‚æòºÇå],]ÑãKRÆÓ¾Äxàãœåœz…CËw·’;žh¶”vcö¥Ã18 ç$y;Á‘ÌÈ(ç®.ʩ߽äÈWt„Ði1¢õx–¼b­µ}§I¹swP0îQrð³ã‘¢ ôðµ½ÿAv3èé{:/„—?YH=¨.Òõ…‰¡P;x ‹z §®Ã^%sMWWÜÖe•’ú–” V‚·I’„w“€äãóE—_´å92a^–ÝÈ^D<„5HÕ‚aÑHóŒ¶Ûf Œøã‰ùÿœß¾Aþ¦+k„gµø¹]r®ýŠ ÍàSLKvP éç%å³@Z¤ð (ŸWî®ü€1<6ï ˶´äH9GÐ}®É˜¸k.¼qÐûrSKú8®U"œ¥ƒÒQëó“Wa‰*‡Bè±MXäÖ0%X‹v5äAz–®!Æ±ì æòû£¡õ¦w­r͈÷ƒ´ÈDWœÞJ f<,9V]xÅ ÍãrŽâ·ìˆšÇïõ$– ˘‰ŒVîv#¡\…æÒ1+u¯…}ÊÛØÒ·–ß;lÌ·‡æ Û¬ìŠ ²õéVÔ¨GÑ'‹ÉEGÚ¯d†E½™Õ¾uP$ƒðxaÀ­’+9\nŒ´`DC­bª†4¨]Ö%q’ËŽT ËÖ{öƒ•TÂÀ™AÁHp¨©Èz]ºµ­|¡É9hésº›>±êbKC$²# ?›éPÑ< Z—Œøy-^´ÉÑdõ´j[Ø­)\K«¡k  ºÇÍ[‘i+ºb‹†×¨m=Ê”`‹Ú¨¤©¬#Ü5-ÚÜ\ D¤Ïéz!¸Š9Rö3çìQŸŠqÞjGI¢·#ΘÑi3–R»‰ÂºpþI¹æ ¾áRœá¢¿ ÅW£UëQªê¹_ÍŒ E¾¹À}|Qø¢ÐJÏaAÞdƒêAC2®¯sz<†` F’7%Æcè€ MwgÙh/`ü€L;:>ãŒés[ʺ¨`ÞãËãVxÚßÉß«dÕ&Z59ûavdÆTÖ”5Ø”\x@]j²ù°0¶Ï¸¼H¡p¸åÃ;lEˆÀø,í ´Ï‡Å²Òj‚Ü8Ü>ØÙ®Înø´áSª[A¤Øè'¨BI/ê*<÷Ac@ÙÐl w.¶ÁžEƒ‚–”¦¦D0Tðp|q‡œo2ÆDó¸%[ZSAöDrÆ–êjmz u$²4ïYÃ[isH^>³æhèPÂi:i„»à‰ú2ãÁF„u%Æ%ŒËÉôÙP)Ùî+%Ü×¢-ÿ_>½€Á¢‚ÜlæW~pN…¶K9Çx{\Òš´Œ±ö¡øâÉB*ç ŽIñöu¥ZÁ§‚æÍ‡=žÂ„BlßúF„­á?VýÂ4¥@S!ÔHÃRÇ]øUem™% ˜ÂLOÂSI¸)ßFä|áÈ‘¦’±«†ºî›Bé9z~î+œvlÁ$Z€}uxÜ_ÒcG¬yð.%'Ý™øÞtÁŽœÓ ¶¼a:„%¶¯îåà í•ü¢& ’äb(½’§ 5’‚Ÿ«SÐ¥OÎõi°ÝIÀ%—jt¬j+‚ HÐóB˜w„‹zü^%ÛR²9ˆÜ½JfJÎñ§ŠÉŠb¡`¿Òw¶?ç&ò¢k«¦ZðIìc Ö?âH^£_úYš¥nI¬Îânµ›BÙHz^=Š>žÈ:âèJœ·[r‡ãífDÖû(3T^HL$“·…Tð£ìð´©l‰8–Ö ƒwX«ý!‚ô#ý`@Ã.êÙ‘uÌXÒTæ ©ŒÓYM+ÏBÛ»*ˆ ‚4¦„°tºzµ“Ú4¦R¡  ~«,d)ш¡ "‚ô+=<5J‡q"2éÉ`‰Ú„Tlµæ‹îq—ôøi-YQVÆ H Á `wº˜Äþì‚ }L/ !w+y 6,Lp¶ÂÙQÖmUÿlŸÉ»¤6ÍuCÉ{µ“(¦Íèn%wÃRò®°Ù÷ ]dß¾}›=„>¦éS§Nmö(õ°u…‹°HŒö¡5ÖV9'v lµ?CЖÏZ›sÅRq휳Fžì3mD§-\DúŸÓ§Ooöd3ÙZBÈPÄz`ò’œ9$š*1|ߢá (Rá lˆ_Ár®qÄ‚Ëg7'àÔ‰BÊüAšàí·ßÞì! ëgKaØ2ÂäQI'-#X§IÏ瓬ð0ŽôÑå@í a+yØ6|άªóÙE¯Ýª7‚ ÈÖg3…°Ô2iT4Æ¥b’·ø†aŸ v^©îhÀ]È^¨yVX‰4³ÂAu° Bn/Î9£¢6.iIÞ¬.¹ZîÄôXÝãó®VO÷9PA+|Ý]ýAn²¡B(³Þ `LÉùaQ¿­mWÇ‚Ã˹BIö@íL¢|k÷p@¤«ìß¿c‚!×¼ìPþ+†h"b#„¡Èà”\Ø&TΦoö0⊿`GV1ëºÇáÜ&‚ )¿ Sh¤ïé®ö°t0"êO$çŸMOP—UÖÑ\þªû(;üÖòÄ[KŸå®Q0‚¨‚Ò[ì¿Eù;ÕÛ¥Š=k^þ~«#©¸bùIšášc«¸ÒgtË2tÌýJ„¥}ÃãfÌè%=¶h˦Ïâ„'‚ô4ån¬™)ÍÒÕõ¶[u{kž¹ƒcCúÎ !MQ*gŒ®LHEp„W¸l¨×Mµàò¨Ò´$ w.ÿk3ºÕêð§j «~gÍK£ ö1BŽö(¹}Ê Ïø`þÎëñVÄÆvçÒwlÊš¿»ŽyµÞzz`Fáœ2Ão/M› ª ‚Ü´$ £åúW¡…¯Þ+´Ig!xÁCñÅ«zìœo¾ž'‚ =AõÊÜêŒ"U&-åÓŒ%¤âðvFÒæ™«§F×=6¤wéŒÆ8û£ìPÞ0AúŒzbP3V¥ÁµVxËšÁ/ÍŒ¤™c×Ü¿™w~¢3B8gE6ûFAd=à4&‚ rWƒBˆ ‚ÜÕt,}")Dc¼ÜêQ×\± ¥m–fFåK¯k:c¬¤„¨Ì wË9ºø°gãÝ,ß7³A°u7ác‘“Ýè+ Üé´¾¼Ù#EéI:&„sø+G‡ï7=»ùC$–íú‡ß8ö/%J‹êÏžù6CÓ~}Y¹}ò§¯üÕ¡—¸Çòœz»)œô½‹oÍÙoÝ÷bÁ1êíÆ3Ü…ÂÜKïümÁ­»Ï¦ËëG¾)³<¨]Íà³}ïþÿúúféa°Á:r7Ó1!|09õç^ÿïÙãÍòåÉ'¥v oùDÒXšMK±—ßýî 3Wsÿ„yõ—ÿ„e˜” þëåw~tõýzg~åà 1>’wÌsùÙ¯ò½z»=5¼ïww¥×ò › C3NøóÏ¿67Ss‡‰mß=üÕÍ&Ò«lñÿÿd茲4³+:òÞ™Ù«Í5úñÃâ-!,q&?s½Î,߈”XuEsÆJƒk­ØZi#ï v›P:öAv¸ë‹…¹z7²ŽiY¤3Á2cr’gÙ‹ù-5­/Š1‘ÝÐæÀ‚ RNgDhRZ0rºgµtÔ•â‚ÂI¢ºhå»t{`U#¬Xï¯`F»t]A¤WèŒîR‡¯éKõ¢9ê±b3vq*:t&?ÓÒÍóxzÏO޼Rï¯bÌöÝ.]Aé :#„»ÕÑi}¥U!Îæg÷ÄÆßœý¬÷öæÌ±y#ÓxŸe«`¸·,8È”‘“£r’"‹sÞŒ¾2gdòŽÞf‚œ9ÎGb|d<’¼úþŠU\²óšcÂׂu|€Í@ST\P¢œ¤p⨜ònz6ÜüÌ9zÁ1ªòþ`çýñmËŸÌ^‡±uc`‚ [ÎáŽèð¹ÜÌ:žãW´…Ýê0MÑÕâö™Š?7q¸ñ> óï,œv<ư#:ô‡÷þúÑ‘ûĨåS àM‰®iKß¿ô¿ÿ~õKVáö>÷húž'|cæØ.¿[þNJŒ¾ïw¶?v:šc ˆN™ Y‚{Ï9Æg+_ŸþôæO,ßJ¬YÔ+)Dz¥\Øa@TaÃõýœ£­¾¯òò}‰É—&Ÿ|,½.-³‚å;~øÏÃàNs­+w*{í?®}øñò…Ì-ÁãhöO¼@Ópaú··?öíϨ¹fÇÿA¶Â{ccoÌ|²Ž/åo<=r@`X« S”{㇒;pùz;ÜûÒØCwêdžG=1¸çŸÿƒëúÒ_ÿ·–ÎÎ9Ÿ 8šÙ¥Ž<3rÿWvyqòÉ¿>ùÚïízöãåóWŠ 5Oøü¶G¥v® ¡Ä Ïúã¿9$Æ6÷ùwN¼z6?g¶zH‚WÀ#î‰ýÒÐÞï<ô2XÏ¿<ñêë3Ÿ‚X>?þð7ï{dRfù¹•ðýî£ßâæLnæå÷þž uîÈðÁ?;øÂ.uô½…“ÿxöÍs…YvÖÖJõÿ³wàMVmÏÞ«i“¦éHÓIéR ŒÅQx™ (¨( ò"¯ ßW´¾¨ˆ¢((à 8Y*{(mÒB'méHGÚ$mÒì=¾Cû}5mó¤+˜Šçwåê•&ç9Ïyî\×óÏÿäÜ÷‡°T‰5ˆdrgÒR…I·áÎþtIèПÄ×"t=˜êû;ôš¬Ôã < „À6 ¨œj¬ÇVj%sHÉ,þA!ªuêuSÑa¤w§{'axBáìH\zª!÷íüƒÎÖÇê°ƒÀãPMÖÆ„Ùû“W)ÌÚ÷ Wë\_l…ÝþœCdnL˜5-pä×羪¸ CHŽTZtJ•®XUw¬îÆGÅÇ…¥~žøb<ëü–âãÀJZ¶7ó~°8lÕZ)ÒUÜUÕϺ² º4þåÈ)?$¯ÞY~fsÑQ`+Ë$`0ñ1ØLw¢ñé@ È@ÀBÜO¹ÒÍœÄK~È ¸­wjÐ`PÁ bp¯FaQø„f³úýÂ#H€Í&õú¼ý&›5ŠP׃bfL,uJÀyç)z*Àí§¾()x1{çÏãVŸkÌ?Ûx<<e¨x ¡^@õRç¼Rf”_Ôñ ë~O}ÈÛS—?sfý3×>Òx~ÒÛ¿Œÿ×pßp4êÿª:G¨³š¢|/† ŒáOÆàsš+€ÑFÐæ…Ža«êºíPHå. Kù¨è¨K$añc¹1 „TN{:邤p¶ ¹·×âK ½ûÔ{‡]ª ƒe§úÇR\—ÔÖ¨ï qîŠè©,Þ2°ð€# £s«uR›“OÒ[Í-fP8ÅP¯—Ûìv‰A)3ª´V“ܤU›ÿX*ä³Z+BxæÁdPô„ Š/0©ÍFĤþaláqk´V#—Ä\qcÏñú›î;LæÆûxÁÏY;x†Ì¤Zš9óʇåꆮmÌvë¾Êtàí€níóšÞjÚ\|´F×ä²ÃHzÀâgƒ'Bº•S«k>\›í²åìÑÛ_ÒY‡ýñ iZ•€ì(ûUW~÷úKÙ;Ásï|$ò'âGLåT©%ÎŽ°@)pQæ¶‘~‘—&¿»-q øÉàÏËØº8{û=M£s²ø×ŸÄôb€=j±èœWrvâÉ Ä;-¢ÄSk×fM |¤Û“8Qפ%jWâÑØGy uj]£AñTP"R'UZøêp¨&³É¨š4‚MDÜO ÈóŒà¤*ôRCA¡²öª¬Äe‰pê§‚“vÞ;3è·•š†¹¡c‘:Ìn.§áHN  ä!ÆBFåTj$V÷£QèruãUi ¸MÏ$ûé×›Ê*4T—ÉÀ2µ8‚ÁÇ¡±Þ 8µÕn³#'2 ¨Ü»ªz«ÃÖdP3ñT÷½0øh:?OQåòÝÖÔ@r¾Yg3Ý–WE1‘ú1ØL ðv[ïþ¦í.‡4H+<ø~ñÐsÂÚ,ãGdÜS7û›%+ó õf´™ÿE*’C H?ñÀÔ(°z÷´ü†Cc¢Ë£ŸÂ"Ö+^»ùõYñä€!Ë¢_6á èÚÕWKUâvS(Ò4=ÁNÂz­ìgÕŒÓM‘Ñ&lµúæ)ün!G áÉ’î*Úê òÁ¬¤wÃ6ÛmÝî?ì RW¯s½¨FS°]k³ŽîTݦv‡]jRù“X / pú+„¾:—ÄiÿøùŠˆ%¤ ™7=(ñ¤8wùÝ£¼ø]å¥3 ·¿³ruÌt‰ùZÎׯÿßVø_"½­î—·p_‡†'i{¼s/0|D ^éTÞ¥o˜¬fÕè‹<#Ú uà[ˆ¥»E­=Á`5QpÄþ÷@ ŸþN†P9@$œKz‚Û÷‚kÛ–fïŒc…™°nJÀP  O<ž²ø•9/¿±Çè´¹|¾H#Ù üåp8ìn Á´ƒEcÜdbØP›ÝŽÃôbƸmÒÙÍí`ºÛ‹Õæ°‘àÖäïA}XͯFÛyß “ݲ·:ýLcÞ›ñ³ŽMXw§Eà ú¼ôÄöÒSrsç|A‰¡Åj·…Ñüïõ2ånà‚¾_IÀåd/0‹m‚ãÑØ–Àå’Ñ>ƒÃàØºsš¦K0­uãÚœºK€Š‹u-þd85 @þôW#è<‘NÖuj‘I Æ±>ªÎf ¥q4} ™=˜”§¨îT½Åd·ŠtMB:÷¡B2–¸yØÂ“‹ÙQ,ÃŒa>8•—ð|ægHØv£Ý „ð£’__Á¢1d68õÓÜ‘tþ±ºë_UœÏ–•í–¾ž@6ú-„t¾ó’QÀ%IáØ³o®ô?ï]ðDàðÿüRªªÂ}'aÞP¶pmÞÞo+/:/–Ôhe“†’pvuF÷J¤àˆ)ÜØ¥QS’ü"¯7—ï.?{º!Ïå¼¥Çê;Â7|QXÊD^¼ÆbüªâÜ)qRmù;Ó/!¤ãÈ\è\§×µVã{EGŽ×ÝÜ2|Ñ…IïdÈJã?’.)L=÷–ËÁ šM¤î2EtoVl4'ú?q³bY‚#µYiùó[DröAô|™MÞçB›ž6d^ªÜEIÁÒë;³šÊL- ‹§ñzR7@zú%„ žÑnéºþ„% f-¦¨\¥E/7k¤Fe$ƒ??tÜÁšÌ¬“#l0(¸D&ùaI\à1óBÇnöÜÑÚìWs¾®è¢ý@«"韎X „qZú{<5èyr@·£W¦K ']x§PYÓµ ìóñ°ç€[yåCo‡ @¼O¿„0˜êW­‘:¯”Á ÐsCÇ. ›èqEZ¼!oº´DŽôtðÈaþ3 Ä/ËÎ\´X§“[¶`ŠŸ·£áâ˜Á1ÿçï*/vM(Z5ÔG¸7ù5‰‘+¯ôì©…4e_”ÞRrÌe•!•{`ü`¯7—{;N2 è— ©þuz¹ó½ž€Áùh±Ìàj­ìã’_säm·c …D™åꆽɫâY¡þdÌödr“Ýú £s½nc¶÷à÷ÂÙ¡ÉàJ÷U¦»L«¡ú};æÕßësTÝxn¬gG8#$©BÛˆ¤‚L<åÇq«ï´ˆŽ×ÞHæÆx)Š2°è×BÍHz@•¶Ñùžk´[v”ŸN>³á¶¢êxÊú†. û$ r¶'¾xxüÚ“â[I§×ܩX…¦1šØëx0~,Ú]´6#½5Oaw[DÁ c Ï5ÜF*u¶0,Ec1|X|´ÛÌ÷Þ‚Gc“ü¢Ó ‘*ÆÍ ƒEc×Üú®Û*Þò÷¡ŽÎ=-¾íèb’ê ŠWnì:)ÎÝ•´l–`ôÕWŸŽr¸${Ç%i¡KŸT¥‘ŽãƸ¤D®i"/ÞMƒ&ƒÚt?±„%è­Ý¨Gde%c@âX!§rÕ–ž/í9D |í8„P—Ä6™3ø’¤ª 8Ó/á‰au] ,Q0ÅoMÌSiCæÛöãõ7²›ËO5ä…ؘ0wÕ iv×M—Ê5 _²7ö p8èV‰BjÐlRQØL<hX­Næ¾7úý¢ÛX…S¹g¨8"ŸÌ®ÒHP4ú¾ÚuZˆÔð‹à*ªµÒGùkÒwGHÑÀ=½ZÛA¢ü q3ÿ<ºT-þ¼ôÄñº›mdN‰sß-84'd̳a)ëcg]Ü\t´L-n?°VÛ䃧¼‘A!1´‘£ãIH.ítCÞ7£_½89…§|Pt¤ÿg´y:•¾ ,KÆd&•Ëw[·a"ÊMÚ^ö @ 9}Â*Çh·ÔvÌÑ–5µºfÊžß"º,-Ršÿ¨·ÙdTŸ—ääD†RýÊUbiÇÛ -X Æ+S£àÔl"•Ob«-b— .KЦ]ÚA¸§i(é’49pÀ´J·G@ 1ú.<t^UÇÜ €Ü¬y;ÿ@ÊÙ·ødŸË“7-~¼m™ O]3xú…IiéÑóoo.>¦ì¸[Pƒ¾iNïAS¡i4Ú¬£¸QH ì(G±ªî×ú›@1h º÷ùõhëè–Ç­!°}äá ñî¾2é»Süê r—+_ò•¢ÙW?ÊñùˆNM|k® ùô£7 yæ‹òÓÏe~V¢®ïº¾Fg3ºß&þÁ¡0ëÕd.‹š ÄÛ}Kž²8,•ïE!ìN˜íU/ qÛ(6ÈûÜU;à#úGÀ`í»Ájâ’˜.›Yí¶½B@ã Z§µõ6Óƒ )ü…è»?ˆ`4ê*GcPòdPâüÐq#ý"öV¥¬ÉÌn*S[ ¯DMy}Г“x {+ÓOŠs#ìtlƒa¸W¢°£ôTŠì—I/¿~ë{‘VfGu6jX4&†ôIâb‰u´îR?TQaÒØè<$±4ÛmכʗFL&bp“xC@|º›ãþÃáf+ÝZ]Þ:| ø8èx2’aµ8l¹ŠÊ”­l¦`Ô‰ú\¯„@}Âh?]Räœ`ŽCcÿ?kqøDp×ÞsïüË7vÖêšÛÌßé†<ðR¹ Â&l±ø½G|~÷Äg¥'œ“íÊ5žÜ¥¶W(-ºç³¶–øBú”w¿¯¸x@”Ùhhcs88 6ŠÁŸ/;3xT‹Yç¾àÆ@LbY!|2©Íe§Á×…¾¿×ç쫺ÜíØÌ6 øÁ! nL(1*_Èúr–`t7Љ§ø#8BÀ®ò³lmuÌô[òÊ=÷Îy+Ú2 è‡#¤|¯í`h¬Û·3ƒRüï§å)Ízç)Ptk}–Ô夸ÖáÚ¬N)çå*¯ ! ^/6ãÓéA‰ ÃSVD?¡³šdF%!Ð6žš!+Y’µƒBš¸Ä}?z«©DU—Ìô=‚ÛS˜µi…[‚îÉâ B³^HóGj`sØç€Gº ! ¦ú•k:/³¬ÓËçflIJiè3sÉiOˆo[9‹20qÓÐù ³nöÕ®Éîv­U&ÖËMÞX/3ŽEç·ÿ{©±°@Q#¤s¹$ƒ»£ÝQTïºw¶Ù¤ÏÜ“OŠs?¾8˜â ¢Ü =‘7K0fmî>Õ]r½Îf:Ópû¹ð‰?‰2TW¹dJÀP?"£ÙífO‰¾áKÂ'-»¹ûÏŽ5 <ú¸XF@½_ »!1<«¹ô¿…‡ødŸoF­X5øž7?½wÌJ Žøæíý9ò —;ëôÍ^Y8:Ü7bCü?&ðbÛ±>Á`¨Z«AaÖÐñ¤åQ‡´ç»Íjw]; ˜]*Ž´ È|µNöFì 2Ž€tÒ:ï“K¦ò‡‘±ˆmÚÙ_uø·=£—ñH,÷kVA`©xâú¸DäÒà*vZþ¬püŸj€ôÑ ¨‰AIÃñ˜5bxÊŒà¤Eá©döÏ¢Œo+.´ˆl(Çæ¢#×d%ÏÇ¿®PUs¸&ëHíucÇb›V»Ýв ¨\¤`L<¥}B‚%ú¨HÃ2`jí ÏM3Žþ*MÚ"e-ð©W ÇÀ‘MÝð\D*­†´0<%»¹ ÉÀÞ¨8²ÄØ¢4ëÞºýÓþ±ÿ £ùX|,W^a°YÚg‰IXüh¿è­ÃƒÓcÍÂS,«ËÛSšLêE™ŸíJzåâä´£µ7Î7Þ‘U².»_8¨‹Ž- › ¤ùÿ/{÷U•è|j&eÒ{O€$¤€¥Š (àØu×oY?Œ»OýVt-OÑÕ}XVc{»âª‹è®ÅBIPº¡B&…ôÞ&e2%Sß™¹a¼Nˤ˜™áüÎçw¹sÛœ›ÜÎsÏÙqq_io£ZÿÓÆ…!÷¶„ÜÍ““ª'ÏÖ÷‹$ö.HkÈŸ Odß^°lljŽò’îºF…”|´4ÿ˜9á©s#&ï«=þ^ÕÑCKŸ:¿ò%{û ‰I~;ñƒàñF„Ÿ×Ÿ)l½l=ŸdO›ªÇÁHE¤*ó·²ý»Ê¿Šô⨙¥ôw'vû5Šo¯ZNãó†3ŽSë5¤n$àòf„Nü²©Èæ2':Êf~ýã턉üÍ^·¯î¸¹ß8’|[N½±½ø£EQÙ³ÃR盆=jQvP}ô@ó¹FE—ËÏøâ¾!?…yZ®Uí©.Ücjhê/ðò[/OþJèèSé5›OîÞqñã[â®›–2'|²Ö mWõžê¨ÜV¼÷¬´šÔ—Úæx×õòΜ3 $õ¤>íÈÇO Ä&åÈŸïRËÈË™%eÎä‘¶‹¤¯:Ö!éê ›üÞg¯ñ„¯–eñV³²ûýšïÉËz-A× aØÈ´*™ÃA$È5òöWËpÊm¼Û¯U‘ÊâÈv pqAßžnè…Ë_„ŠüwNÿm¸(`XOð8¼ÿèæÿiqôÔÍ'^sUç80bB#R3ûÕ±—sB’ –íøcÚÍñ¾a¦æ$vñ¸\o¾05 fGÎÆ#KŸÖs ·çÀ=Ù BÅÆ½ã°û³ÒªEß=Éî-lZHrÁÒ§„¾æ9?Ë«éo_5åÍܼùß<Ö¤”nHš÷þõ·þ^u¸²¯%Â;pKê2_¾è…ÒÏ>÷™ÿãÍ;³ƒFs`…í—ï;óvIÏà3òÅQù³·,ŠÊ¶^òDGù­…Ï3ãÿÅú„YötŠôˆ÷[Õßzÿ™ÿ;ÔZ¬6e¡Ÿ@ô‡Ô;r6 ¹¶‡ƒø æû;¿BRðãÝwó;"¸éØË×ðxË6|0¬ƒÌÏÏÖòîÌ]Ÿˆó Í Š'ý£v.ú"¾à†ÈÌNµlJP"3‡\Ç¿m¾ç„…$“ÄËc¦‘ùþBŸÑL¯Z±µè]’‚¤ª”SÑ×\)kyôüû‡–>å/°ÜòÑö’‚¤ê–,Žœšâggl#gºà¶â½šÏ ¸¼É±J­ºNÞñjÙ— "3nŽ1¶Îåp§'õiÞ¨ÝÜ%oŠÍykvžùŸ]²Ö¶+{ÅʫÒ€Ì J ×îDqx¿Vµ»ìkR$óÛU½Ï\ú䱬u¤j˜œÌ1ùÇ1y/ý¢ñLƒ¼SÈãÏO]5•Ôœ4Ÿ=Ö&ñ…Q>AõòN±ÀûWÉ üÂÙ#U˘ÞúÄ9{æÞ÷lÉ'O\øWm{¼3+0޼؀NóNÕ¡kOpL# ’¸Jõ!»èÓ(?m8UÞÛÄçò²‚VÄÌúï(ûªÑ8ºÅÿ(rH<.÷ÖøÙ$ŠØû•iT’ãàäcݼ³°íòÒCO©ôÚÎcã=jù—ME¥= dݬàÄÕq3Iö[c«²çß '›ä]<Ó®WÇÎôˆö7þx²£\À#¥_,­%Q½)y>ù£¼ú5J!ÏXVŽAÒÛ´¿áL¯FAŠ+7v°åâ®òŸ £¸§ºàüÊI 3·F·O½ãÛ– k þªºú}-Ã}rÊ‘—‹~ynÚjô¼©c—Ÿà'³o²5ļ¿Ð÷¥™w1÷Hã|Cw;;Æ7„½À‘ÖKL$€Ì K%Ÿ5œ!µ:æ]!—ÿä•L…¬ZÖÞúóžÒH„Z©Û LÍO˜Á’H2YŒ³èÃm›zÇ Q™dšäèοyyÖïH]–IÁ•±3Ö'Î%§;+”V™×º#iÞÊØéS ¯åçûòÌ­×%©Ëþè#¥øG“©P–ôÖ3)¸&~Öº„\SÕ-³Wÿªé,ùÈ$ÃnOœ;/"ðѶRóלä#ÿ1mŌЉ¦íww ü4Ž•žcø¨öIAüg­ 9Ø: àÚã.AØ$—l)&¯š«YEd'=’µ.ØVzó…·ÅçFû“é@¡ïú„9¬ö5Ó}KfâžÔå¹áÆ ìÓ(ÍwY„¾[R—3_(ZKGT®y]µé£7sóZU=ÇÚ$df²Ô$q${1–+b¦3Mc|¢Õq3ׯç*´ƒ»Ø’ºlCâ<Ž©Yй(ARjyLŽÍý’ÀÛœ²˜$–B§Þrò é@_ùš]äukül~°ýêê¸YäÅ1³¹Q+CnjsDâó¡Œ5LýÁ Ô \-1¯‡3o›gØ©òèŒ5Q¿}ê†EÑY.ø pw ¯›Ï-?ü4y}PsÔÕÇò3oV|+ékâs¹J_é46åÿ3þÏÊo'ÜøüŒ;IÄv©e¿éÝê‹{¤·ÊáqyäEês$õí-cs×Ì¿uz]aÛe‡GªÂÃ}ÀC¹Ëw„±¾!éqcÅ+rÔ3ç¥5¯—C&EMÙ˜´`¬6»4jÚžëÿ›T¿˜ÌFâçÉ«b|‚óN¿Õ£–çz£W­¸òJg6»)yáœð´ªþ¶J?ßßð£eL™@vÊúN”ìôúˆÉ{ëŽk ºÕÏÝ9aá©ÿå8þ0þÜ%WÄNg·uJzÛŽ}þBŸÇ²Öù D£ß&#- &ÕFÆL¡ø{Õá6eïÄ€È} ¶’!©oQt¶3›òú¸îøöâ}ý¬ç2-\2‘¼8¦¶ìù÷¤ÜêåÿdñÞ+²Ö7+¿û¤îä§7<ã2äN<nÙõIý‰ïš/‰MIóæGfŒÃIô¾UyðÙ’O>¬ùaIÔ”g¦oâŸåè?ßåÔ˜Pß´œÛzvJ§~<{íÖŒÕÎï×`|ò²\7°5sÍË×ÝEæ~°èãð‘\Î]j„î¦QÑõÜ¥ÿ¨õÚD¿ð‡3×ò8.x¢n’xx=Ô\65õâ WÇÍ*h+q~E½AÿvåÁ½µÇ¼ù^}ÞßS]x^ZÓ£‘ÿGn]#ÔôzÃÐMEÚ¦¿M›œmjÂBvº³ô³²¾&—÷`ÆêdqÄ0V¾š˜¤zç|; Z½Î`jjç ±YûëÍ`ê×mdëx"w©~ßzù®¯‘ R{$k­ØÔQÙñvɚ¿4+ºí­•ägŒ¨yûíGwîžµ…ýVˆHLªqzŽáî“»ÛU½ÓWh6I´Ö è`›xó„­%E]ƒOþ9ó6ëæ-&Š#…\¾Æ ûŸó yÆçñÉ?E|§ÊÙ_èC>~IOý©ÎŠ[ ž­îo#3ýø¢q˜˜?ØsÛ‹¥Ÿ3í9ù\®@Ô£¶¬·)µ8óó‘ÄårE¦¾xÔ:ͪ#Ïžê¨0Ì(úŠð îR#¬µ¼W]H^_6iôÚÒW‘,$•ªÃ­—˜8±iFèD¦ó—“ÍJ)û­•±3GO!YxVZÝ è"itwÊ’xß0g†Ô™Ñ$ºON3F^­Êž!×͌ߒºœdU¥¬¥´·‘ÀúĹ Â3Ù¯OðhÖº$q„J§9Ðt®¬·IÄÞŸ¾j~xFVPÂ=)ÆÍ’m^ê©'›]?k^x{õ›b¦“¤'GN’ÛÁ_ÖÈÖÌXãBÖ=ØR¬5è…¾Û¦Ý1†çÀmoä•––²gæåSN™VuAZ£3üô¼¹X蓜L®ø¤NSÖ×è+ðŽõ ©5y‰ÓbÎK«tšHï sÍìbOÔÔIÊ”à$¹VU%k%Ó3_ïï•õ51½ÆLŒ#5BŽqx‡¶y‡'È I&ÁVušÝo'É¡ Ý5ª«Oß›M N¶®S’ckVHIмkψDo•ÌØj¼_ØDqÇØñiW¥i‰´0Q€ƒ2Ñt祵r­’ÏãgÆ›û~#ÉLŽœ©&Æù†N2=ÈOJ©´×Øûhf`B¨È¿[Ý_Ü]KþíBöHŠ‘U›ª§Ñ8ÍŸ6IdêY”ÙY±CÕKæÏ7=eOþþ(2¯šÈ´à$½‡çç瓟‰DâàS¤§§“˜Ÿ%ÇKüÒ˜k¹vÝ{q—‘‘a÷–ݸ]¼Lu4vO]Ñ6ØQg¸±Âªîá´F'5-W‚–Iš\×#M«·IME˜ézéOÍ,™9ÝÒ–nN kŽ¡®³Úbš-Ðø²¬‰¶Hë[l}ÓFôµUV39ji·„ÓÍžÓ!mêà49.±ñeúP m6öÅÑH{$œöœö®ÆvÖ?µœf¢±«Ö<³ºë {S¼«ó%]ƒ…yµx õ5:¸Ë­Q—@Õ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!P ATCÕ„@5!PMàê€k\~~¾«À!ü‚òòò\}C@Â/H"‘¸ú†€ï€jB ‚¨† ª!€jB ‚¨† ª!€jB ºXƒq•žžîêCpk\.·´´ÔÕGÓ4œ&àüiBÂxC¤§É#à4 Üp………®>N“GÖiBÕ„@5!P e€ sì5'#K2o™'ÀšuáŒm¹Yœ¯Qn§ÒIìbA‰yîï‚háäo¦gý»¡±*@öv<îÂê‰, y4eîq' ·F^ÕæŸÖÿkäJÇ.öEÓb>Ãæ[6§‡d±Í!gZÌaïΙPÂ:ö,BÑ¢dÌ%iQ˜6KØæº6§]Uþ¨½˜«¹Í›9ì·`d,ÒqL Óæ6Ï´N;sŠÛûÀ©g³W2EgïWÆÉû¥®-!ÐÂæ×Nìk¢«ðÚgóZiïªçü÷UC¾ksS8ã£t-}×€ ZxÄ/¤1§šƒ¿ßGs›Ëæ½V{Û“ûitÞu.,!PÍsÛ¹yÇMs,s‹%Ü|ãŒQô‚K¸°üÑXèeqyE…`¸œ3sÙ²Wå±Nž¯œV ¬þÇ¡ìíbüË5B ÅMC5q4Ø×Ö1|¦Âz›3Ùm78Nÿ‰óK­gqðeªó%ã̯ŒÍSãÚòGlþjÙl/ŽÆÃb]Jo¯b¯4åw~›ÃšààŒ;}:8Ã/ð!WáàÖ(€« €jB ‚¨†Æ2àãÛ#à4yœ¦ÑC¸âr¹®>N“GÀi+BWh¡îpš<NÓXÁw„@5!P ATCÕl7–ÉÏÏwõÁµ »ÀýÙ¼¼—Õ‡Ê=šSÕå•ë÷"ÏûÞþ£Ò”.tù‰sÚ³æÌ6mÙ’®Zê¨ÍõÝ«Tž§ójØü‰¬`Ó·sÓúÒµ£Ðí«¶æC }….rJ,éÚ¥6ʵ¹ÆnÖÌsèŠîõnèÜpÍ<}û öÊUM|éÒü+cñ}ÞÛÅÚ¨mlåÓ2|¨îc×®±·»Ï_»3ôMo¯¶s%K]–Z¹T{ÎÎ¥ÊÕö­ ´v |ºˆÏ—òåõ}èºÄ/ópž¹±’Êb K ÎÙ¹Tß^”wT5 ]V¾4W¾p÷“=ÔÀp#[2Àå±™ö Î¡âvˆËÞé¨{'& Maê+Ì`×V‰Æµx¹TçO߇vÚ·…tŽúÔÏ\1\ê4½ñè„mU+žUnÆW’Ë–â50[;Àîd€éÍB0]h6|#ÇÝ¿l]$txñüî»'_m]ÅÆªîÄzýÓó­ë„Gî_¾Ýº„]¨½•ÒKevåů¿m]Â.Œx lèöÆ `&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†` ÁFØgúaoª¾‘ãþå[_€;4üµ²¯?ü±u‘ÐÍ—Úù^hf ‚ 0`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†`ÿÌp<Oô}ƒôà À•Ô~±û)¥í™û¦+Ð…†`ã~ðÜ[>ùô_m/l¨ê× Gé|IÜžX3eÔÚ<•pƒÆøÔ¢rùèùïË?ÚÕ,x¸x±Ý9§ôr›¦·À}Int³/µç?Oi·Ã…Å óÀMY¾ Ý™ÒÆ`u{Êáq;vp›F¸3{5K7ÚíÞu!ùc77bÊÛH£Þ:>tõx mìåC§TŸ Î 7hxð¶’˳ï¡ËÿN˜Ò×—./®‰æí÷ºogRJ¡ÁXl×mZ_8Ùu€2]h6ü>ðÝ¿l]$I^<¿ûîÉW[Wq+ªnäxýÓó­ë$ÃýË·[—p[jïÄòRù¼øõ·9‹ß?{ºõÜœåï…&ÚÝ“/§-øãÏ[×~‹˜¦‡n]µŒBC0†` Á‚ 0`j½zónëh`ªœÒ+Ã{#À »Ì­ ïŠ3 XÞ¦¤/«2¼L¯rJexÜ M¯ï¿ýfð³ nœÞ–S"Ÿ;§ Á‚ 0`f‹G|3Næ_¾•.Žó¯‡÷¿Ï]ƒ·Öå50`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C°/¶.€yøðçœÅïŸ=½ùvë¸-Ì#wO¾œ¶à??l]û-`šf¶Ã¬Ék`&ÀL€!˜C0†`F¡éõêÍ»ò ßûÍÖ5Þ:-0½Êù|ñünò›Æ,E€)éËð§ô¼c¼Ì€v†¥w?˜a—–Þ]`ªœ2,½{#ÀÔ:eXzwE€Az÷F€!˜C0†` ÁÜ Í#¾'‹ó¯ûgO·.qŽ?~,Ïq÷Ã/>tB½»'_~÷ä«­«¸Ã~ýá­‹$Œ¯f8ÀÀn…†` Á‚ 0`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†` Á‚ ­ìñxܺHzùJ³Wõ½ÐïߺNšî¾þïÖ%°½Ú/v÷»’»òêÍ»­K`¼†` Á‚­àûgO/ÿ-µÎÁ)åék½_'ü+´/ß–§£|ž]èúf¢mùûÀ—ÍïeÀÎÓOMôé¡Î™'7à›ë[sybaæË.Fßü0ÇŠ]è¢xh]Á¾tãº?ýÝþãPx¹Û Ï£­÷l®¼Ý¾‰5µvæXµn\Ü5qyžËX^©Ôîú+¶{½Úàl›.t}[:g熷ÆÎÍuöº'¶ZÔáz„™+ØrúÑ£ëv)û6×ѾÜ.²E˜c£ÐõUyξæ·o%ÝÍòÔ–³° Ö˜¥l3ˆužÒùPýëÞi¯3û67¢ ÝZÃßÝõžÚFí Ô;~ ôx<>¼ÿݧ‘&¸Þhó«7ï^ÿôüàóÀ7o]h Ò–7r|–t•Y“/LhY“.4«m}‡ ìPÕ(ôÖEÒË(ôÓ…†`Ã-0°[Z`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†` Á‚ 0`&ÀL€!˜C0†` Á‚ý л¡ÒIEND®B`‚gateway-1.4.5/doc/alligata/nopro.png0000644000175000017500000005632507344776077016112 0ustar toljtolj‰PNG  IHDRs¨;!’)tIMEÑ GÏ pHYs  ÒÝ~ügAMA± üa\dIDATxÚí½ œյ↑‡ÁqxÂFdzÀ÷sbTɉ$ÿ z5pïôž4^•\ ‘#¼äbøGôO"ñœ¨œ\Œùç܈1QÌM”Ècšæ!‚Ìaq0H÷í½»kjº««wíÚUÕ=½¾Ÿù MOwuUuÕo¯½öz3 B/‘°w€ ˆ>) Aú!e!B?¤,A臔… ý²¡R‚ ôCÊB„~HY‚Ð) Aú!e!B?¤,A臔… ý²¡R‚ ôCÊB„~HY‚Ð) Aú!e!B?¤,A臔… ý²¡R‚ ôCÊB„~HY‚Ð) Aú!e!B?¤,A臔… ý²¡R‚ ôCÊB„~HY‚Ð) Aú!e!B?¤,A臔… ý²¡R‚ ôCÊB„~HY‚Ð) Aú!e!B?¤,A臔… ý²¡R‚ ôCÊB„~HY‚Ð) Aú!e!B?¤,A臔… ý²¡R‚ ôCÊB„~ú…½AøH…Äkºâº?—”… œ_”ó;v8ÀÃ2^PPêí#ºN¤·§øÜ½ú²D~‘© %ü™(µhÓÀÔƒË P_N8•RœÎ,›"e!ˆ0Á;¹?@%¿“¥ &‰”4±@Õø˜ÿWÆB XÁ_9˜oøF¤,((%g åÆÈ@CLsPDŽ¥~{÷­Ä-KWÆ_IYÂw„šTòß]!2à}~ ƒ q»Û>HYÂ/p²0`´ÿjÒÍåãcîvõc¡GR‚ÐL‚"ü#íù$%i²„6p¾õGPL)9Ä¥¤;ì#Í ) Ah`0À•>hJW“Bò•x”… 4P`hÚÔ±Ô4§Óû¶Âƒ”… ¼RîYVú†šX!e!¯tñ·AnÝŸìø4/]°!e! ü àiË%Øö>û UQ   Í²Aú•/õuYR‚ÐÅQK~p6pôF_œûdBÊBÚØ™ë) Ah$gÔÉ_ÃÞÃÀ e!mœ—ëÃÃÞÃÀ µ!‚ð„(S" ¬Tæzñh€Ö°w8HYÂ5(%#†¸¯ÕTÎ3ò?ëÇ;¤,‘Ó0©äUÔ¼DÜŽØöá) A؃ rŽ’aâL_Bêó+D¤,‘Ä')Ií‘/…) QŒˆºÖçð²ø•ÇT’²D¡Sν$•©Þ›òxG¦»X¡CÊBô)*øêo—’|[ö…½@ÊB0bw8Ÿ×”Þ¬Gn€ÝaïC²…D0NVŸèæÖJ1, ) ‘ϘQ$ç¤Ì“üÇÚYô ì/ÀZ¶^ e!ò4IÎåK³yb•˜ê`6'M{V·°|†”…È PDF¥²oüF´=¶´"-Ð}¦mX²¡³›/r5ì¹BµÙùÜ:±>>YÙ:ù) 4b²ãª… )í½Ð4$ˆ¤æ­”üq““²RàPy‘ÅŸÒÎ5åhØ{U ”r7JU®˜ Ô÷=ùä&'e!rƒæ÷¥|¨ìN]Á´lì7bÖ31—_ö(—ø<¬ªKÊB8×÷ÞT¥$–—WpC> ¢#y+ñ¤,DVʹWåÀ[4ññQgsÀÙr =y®)R¼֯ØHšâBJ†»ï¸ˆßÅ{ùäLq€”…°¡’σ~önÈ#úÙÒÏRÏIù ²´=>o3?X¹®U·S HåIYBL÷§HŸƒÔý鱡r!R¸.sR†`dŬ$„CTÉÛ&AA"ŠžtQnR" „bö*,BijHÍ€OÃ6µ@ÊBø‚©#òYüŃYEITêíêR’) ¡ ÜU)½zÚ·òa6¡@}RDl!e!¼’oíüƶýõ Hƒ”…PA˜'Õy9Í9–ñŒUlé´{—•â±5tAÊB¸Ã¡¥vÄÝ.š² K¡rÜy ) !E΢Ù±Ö:’ŒÂ‡”…ș묗.’çGV"tHYˆÔò\gˆb"m¤&}R‰‹x+2ä9uä íÛ !e!¨Ô-+û6‡}P„”ó F”¿#e!²Rá}ºHVú(¢-IZ]R"+{jôm¼*}Œ!ŽÕªHYˆ¬tójr—Mp-áL`Pª`UÎIR‰£¯qe 0Æ›Ä á«×Ã>"?p˜6f«;U(¥Ü*ê>{ØÙö¾ç%]àh tîNþ·ýäƒ3΂a—Aå PQö.†¨ÿìEb ´ç™Y)ÎZJ¦D‡5×Å“ j –hãPÂËùÁçV‰—ÌRR–^´¿»Á4%!1  ™“î‡!“ÃÞé08ǹx!Ï;‰ªT•\DÊÃNÝYfr“éÉ,»UªuÚKÊÂèåðÑÛR‚’FéP˜ü=fÅ_ו›W%£Å¤oÏ* ×’(× O0UûŠ]YâݰíØ÷k¯ÛA}¹ü \öñ^š_Õ´©.îÊ ¡&•\M¨ÆFŠÚƒÛuÞ]û5lªû¼}+ŒþÔ>öQùÒuú¶¼u@jÅ«,¿ ï-T™þ8€¶Ï§­pÍ¿B¤ï–T+å²¢Qsµ”óf¦#IMt“°óøélèý5вʯ—‚ëú ¸˜X5‚S¡?ùìg±%Ì5)ÛòWívo”Y×+FeÙÿ l}ÐégÙ­(ã¤IÞÀécâá•YªµŽö8еòŸ(fAª!D¡ Að>ò¢S–®ðÆ×lžTãnϱÄÓÝŸl†–K¹fpƒuÏ…}´žñOSÞ÷'¤E”ÑœXP‹;^ÀÁînkä[€âR–x7¼|uºéj2y”q±£­ÐúÏphCŽ—Õ.Ñ_û˜UñÃ+!:þù¤)¢Œf1¸QDŸ³CùÝ™¨¸”eóB g‚fÅO¸Ó+¨/¸Agûåúß@ù¹a¶üóÑHù`§?6¹ße4ó„‚ëšXDÊb¥pÍÏ5„Ÿ ôÞNÆKù(¸þ¥°\¼3£ZÇ|³e‡?;<„{”³ ¢¦Y²ßôD:'ìX#SC¾ÅCØ—jxVp‘²l¸ >maðn¿|µNSbËb8ðÛ¬Íó žN±úØîóÍ \?U½wØÔ‘C©bÝ©à*Xln7Ÿ0þ¥@R³Q,ñ,h°˜²¢°jƒ¶ Îzo„S–;æŒ –XQÓ–Á©®¬–˾_Ø›ó.´»Na¬ž5døì2P¶Xã)£ ´ªsÌ.r¤ )–ÙÐú/éÏàËÿ&uIyIPÌFˆ®\Q°gœê0Š”(雉HûðÙn©×ãx0h,TÍöš­>Š×!W£OjŠ (lTŠî#pí/sßÛG[áƒgÒG9-´¬‚‹VzÔ";f´û©K‰(›¤æ—Áovÿ+°÷ײjbßò#£F^ çÏU™±–«ÊJÖAQØ,8©9ôTÛé5ñnغØM1™ñ¦ú ·<¢»¼‰~,ÕöXTýr¢’ç Ä”< ’UW ªèC.ôÁJS¡PZ£ˆâUýxU'H¯r $#ü߬M%0ËÄØ.·…²|ü6œsmŽhÏN̤ò¿ÌQê­2û¬À‘pã5…4ʾn¯>Þ>|¡>qîWÙZžŒ3î2~ nÁCÞë×¾3*RªqÀ0þŒ[£UkjbQ(‹3­OBÛ?ôY_û³Îd¢ >æÛ(53G„”äIÕU3WàODt•å,4åý5¾ —0àK.7‹;¾Á‡¥ŸŠTôÞ¢p) ?‹Ρ(ÚÁÁ¶ê[ž¶ *³ÔéâÈa^X,D$s·ÍcÜá7\šK¨þÁhŠ k?üþ›,9cÔW²¾æ—ÛLh•^ù(^›ÇÀ7ëmbóR6dYQðfC9$·œ[¶Ãù y,5ÅÍŸô3†pMœú/žï­nvûh+¼{—ú܇-0baG&ï€~ÙGöÏ»˜KîðFvaà‡âÌhÚ2»Íº/©§k$4ºRǦ|¥H•%MVðâs »þðíl¯ï¦Gôø ü¸gôöœ¶‘²®º¯ªCåõLA𗹌ô·™M8ßÍ¦ÐØònæUÍ{ÞN0élè½ØEƒÚ¹_ñss_ƒ«Y¥¸îxç®d,¯2û_INˆNuÁrÓâÂ’‘sœ9¨º´LÔ‘šïÀˆkµy²p;Ùz¿ s¹©÷=î ï'§à-‘bT–ƇٚåE+\ÜGª{ö½KÕ?ýÃç“Ê’è†-Ëe—!òç$éÍÜ`‘AÁTÁïQ-E·«-»|½<«—æ«3Å¢S–Ãï€a0}}¯ûùn€ëþ `»ÄF™ÜÎUé`ø&Røƒ·ÄËWÃ%+r,Šç9Cr¹[¤eÅmÍóñÿÌ Aš»\®ÂœTý ‹xŒo!Râ?Ö÷@›ù ‘ B£}-Ïþ@®ø?r¡bƒÆAùh8ø¦â> ž¹™}ÖyÐÑ mOÂÑ6y]Ï^((“.æ-f—T‰&¹ â<ñùLve@Q¾ê)~u8'í¼TËDIvª~ÊøNE§,VPVžèýÌg!Š ÊA×^•ÏÅ›pdj"6ìRØýKfþ*»OJ‹jRERPÝ\¬¹¶É —0…Mú´cx\ó Œº J„vú¹tµ(”ûE›èªÐŽOEº6$x±÷Ý–ÄÑuýu*Ÿ[:fü¾ç¿f¨N²$s&ƒ'ç”Ç–-âåg@x~dfŽbMçØ–£øÙøtOòùÓŸAÉYÉÎÜ¢F¶¥Àœàm£›×+tÊûjWÉ+:?‹Éÿêýß—Ýo¡t›ç+ÄïvIºZh6ŠpõD7 кü 8[9yV+"¸³’?Pð •ù¼ Tk~î´Š‡:²÷E8ô¶£Hb¿¬Ñ"à¥ê[øÑÉ/G\F•¸¬@ÑÚ,™ó µJØÊfKÚÊÔî_ÀŽ%‡k¹˜jâ}ZöV®øýœíYLPÁm§íhï 6µ¿®!ÔHd<×Ü#{æ]E÷¿ç2­¹’/34Ej³¤ÉÊ_2^ð/?–X*Â!tPJ„ËÁ×{)˘Y°sUrèÆß8;¬]‘H6®IMLŽæ’•Ƈe—–§þ =Êç;hå}ø¼žÎ¹<í¬¼Ëë²ÏGyxÎyrçRYÆi;¬Ðˆ„½!pfÆ3™ÈeÿC.†zÜí*û`Nþ>`šà óÞ~~)wšàóen©}•wS­Ñël oY¬(+¢_Âo.e&žFY±‚ãÄÛ·ÂÆûr¯R5Jç q9»)¨EB{ŠÑf™›ñL¶ñM›ÛþÃqk#”BQ2s‘ªf÷ªshû¯ÛX>[ʹé>”/g¨yLÜâ`°dKײŔ•Š'¤çÿwïäHJžZy½\lËTîÏÑPU”VÕ3r¶LŒXŽHÔsȯWO1*Ëõn^ü\.L„'ª(ŒŸV'.2d2›ê[}™8°»UÕ}DyŽJny…â|/û!ÿá¿È.‰¶-AOH?qëƒì·C;º8— ¸ÑçÌóæ™eC¯|P)g5Þ;ª+Ít«Hɸ̲™ºE§,™S¡c¹Þ2)—Ãeøµ°çY×{ròHúJÇàš^žÈ¿©Ž*Rƒ‰ów0íY†Ä®låKF „{À° ‹'ØÒ¸”µÜµÍxÄy¸ JÆ•¹Œ±â'#.ªßfE„ètX‚tÄxV™ª5%L›¢S–åÏäŒùü¹Ì–¡“aO®d‚“êÞ oU߂ͽ×8ð¾{KÖ¥VÑ­"’šÍY ×°¬àÕ'3q++û__SLü–%š9ûÔQL_ãžWçÊ~ñ¯,gÉ«v¥: {Ý×èÓB7ÿ±FFŠPY¾˜ñÌ/$Þu¦£·EWøÉà “o­¦å9j\Zm×4•T.²­ÌQ»ÑR^V€G÷àŒ)0Š$8ƒûÃßçní²‹ÿˆäÌqY É:œçæ²\òÀey§†(+åªFŸ¯Ä‹PYÔ˜ ð“ìU+rxcúLÇ6’⣷Õw»Ër­rYyÛ-¢yó‡™ûàFV€79ÈO>ma+å2í.­=‰ Ã!ú¹ÄgÅùÉ”4[ðÌ¿žýÏŠqÕYWN_IN}fódyFf+Þ“’)}Ù‰ssf;¯?ôžÖIx‚ßBxªÄ{¼_¢·²’çìû5‹îsK<5oíäßB§\Öëf‰|+AkþÉ ‰²tî†ÅÈÏ]ÝNÊ5店µyr·{÷°í\_¥/\[ÒÅÖWÕÇdEи”W ýYî• >¾è³³!kÇ<Ñ˲(ËÝÿÙóÇšæÃ.³ T÷2!ÊÆ^no_é¾úa;Ÿ^åt{÷IYnBnZP/݃<ƹìS"/ ªCSœ5xÕv²Æ¡Y[ÄÛ–ÍÏ4Oò­|1^Íx£jÏ$êæ©=òµ…òâØ’=•û¤¬>ma¡ÀÁ”°;È}(7d—¼­dÚ”ïº=ϳùNæ¥l•ÈÕèËd¹ÜˬHÖ+ÊÉöÏÇ•«’åb3/Šržãkºø”Gré!ÞÍwúª¬bd¶?ù¯d·.EVtžìÂVçÒi²â@Z,œÂ­®URkÿ +‡7f­öìF€¿fïO¼×e”ÄþÞ¯Œžü!H³RÖåž"y9G³=ûMyÊSkörö~IA+‹soCyYÞ±p/J½#hNùÜoYHAš¸t»ïd¸e±×Þ…Bf‹à w½WòH«õ]égÞ€X2za¶s•‰Ã,HeASÅ9˜Ê(eÝ3]eÜ,øþ»êþ(PéÇR¶ðÒü‚eZ„‚ò¶Ë¬“ý¯Úp2\P@Ó2¿‚ADʈ`¼JÞ0³ÔMÞ@NDʈ÷üÕÂS´BsNã/YáÚßYË“Õ `43¬Î¹;ŠWÛw[ºåÕK³”BÄl<Ö`¼ÒT¹ïrÕÀ–!>DQ˜²àåûö­9^3úA7Ù8ôŽÊ»lý&Dz'؆Õo‡¶{-{ šŠöêuÝÌóÙ>qù®8¯V•·^Û³ª`ÐX2ÅÆ%Êå?“9*]f`¶Ž²‚—èþ—ÙÖ¿ËŒsÔÍq7Λü²”«ð¦Ñ­äÁ-å™.•ÒËn)$e‰ó2±Îà·%­—ö7TÞ5p¬Í“YzHg›:QΊH·¿ÞãrWð°ËáÌsؤà÷u++ê9™WàI8÷+0êïrX¯ìü¤ŠàLZÀ´à“ͬâßGoçJ4î˜Â, [6À§Y”Åá‚Ã1ÜÁ×ÃZaW°*ñ£‡_ çÞ GepÐn|ØëF<‚fÚ·g5OÎÌU0ƒ«Y–ùTÇrvi¥0P˜ª¿ÍÚ6º­V…ßó,ûÁ¯rò÷ôÔL£Z¢<pODÓ§^Ø.­,‘TãëÃáƒMl<<çZVoM&,§I¹Cu·âÔ Ûü °«b)°:™àp'_z wX\Ä¢ZýäEžLq¼…B¬x€§qÌ,›¬8,#Ké¼û|½kܲ)™Q¶6¦xËØ[d èYÁ“¹y!4 eÍatŘɛϕóœ ÑaºÓRð,gñJ‚«ÏRÎW*ù7º'—ÃÉZ ðÒÇ™¬Hµ}:9Ç ÔÆ.gÔÜ·¶q9ÍÇfŸh€(µ3«ÕãlÇI…ëí5…vKZ°Û3›½dr}JqrV8¾àoRvX¼sW¯€O³Ï^Q¯¯k`ÂJ<êËÛ·²µˆ)ßÓ`WþGà%x}¯Ï":׈Æzí¼§¼¦ µKzVy>•p@üûf_ŽÂÙÉrÀ}Z=ð¥›MeŸî9»!û¹j_žª6^Çç~•9¿]]Çx›Ï Ö/Áª)gò:nÞË..gÚ… à ÿí!,:nËâ±p6IðdŠ2—ja>û~Í.éÀúÃèÅe‰ðšÃU©Ù×Q(áʉ£_Óò^ž¼€F»l/†_sÎ̽7Ü_‚Ýp·5ΆùÓ,¨ÉxùjÙP œ¨n‹' µ/-¤ày¨˜—­|ú“vOä¯G u…E,d<)¸Ïxa«-É‹þ0—=¦é ˆæú,¥Ü†¼‰ûŠD¢ÔÆ\½òÐNÁ‰åúëÒ´Wä´kíxw>Û ϸߦÜ\¡ óîu©œÅ_tU‡ÁxãkR!ÅÁ;nqj0}}/Y¹ƒ§bh/Äy¦ã6¯àŠ–šx’D¸ƒYѦàЦ,ÆúU>ý1xÙˆžæàÜÙǽ—¯¶9qx«¨¹ñÞxu†Ó½áÖÕò¸ã_?|^e'm… -»æ 6ð­ýœé¸ÅÓuýozÍÔ&ñÛûïüù¸'%^s—A2k-k=‹VYÎãvÊy©ÿvñ¢Îáá8èm¼þ|¯½•8æ–ôgÎ8KvgðŠÿý7¬ WÍá78|êTÈV)DÕ;[rz¦õF©åt–æ¸5J™¯íú—z™x y©Oœ)g Q»æ_µUürFÆÉ˜oxõ³ æ•#¬§w?¯äœÉ–³Q^æÒ‰m±µlˆThFÚ.©>%=Üý“ã_•§BçfŒ`MNó𜽎i½ò²­ˆ›ã¸^—ü°—óòL¹]’È,&¸o—¬z¥ÇéÌ ±žÞ ž”å<>²²Y"áR¦ÿfÿŒ‹íI·ã¤XRÅ7fêË]Ë“Çr50S› !ƒ2Öw·¯ÌúâR‰T #žKp[9{šÓ_¶á¸Íì?ÉS%-+£NÚkcƒHf¨}ø‚§ý<+»²ˆ°Ú‘IÉ8NH=¶F¯âͺ”z'ºB]Y2«JÊÊËWçö“ŸêJ¿””B_ÆÎ†ñs{¶ÙÎüW8¾Ñ¹8®òT(3 7å`Ž9ß燙”5÷8ý5æ³ãÖà†@Ú뇬@ïN/hÝ+ýFW•–Ð õâ“bÆs³þµ›ïL„/Å^`™=”Z´Dô[]CÇx¸íÇ)éÑ+7ŠÊ¢&+ÀS×d–ß2‹3â݈և²U)¢N­öË Ç"O9×»÷¨,™NçMÈåüS^Ñ´eÅaÕÙoƒ ´k~ž¾unîy5Üγ~"ýJJÿÏžöí‚Û{ EøugfEÅS¥†pF²jº0Ь#x_r9ð©g•QñàV«ÊJ×ÙÔ5[AQðè0ÃÍ®¿Ž-r‹Å£¯Ûys%d…Eô­Q܇ó2¶î`*ãñŽp´·qOšñtN¬àÄy}ÔWƒ­¹éëÓee¡o²bu¹’ù1ñ÷¢ûç~5Ý`Ùµf{êàA¿Uí—Xp>—ò™7rSqˆê*k›¥<#¯é t1+ùöwxßf:B[£v +/äqˆ¶ú_žÂº“xbŮޭí@-PÞ‡´ÜB´L呹rv·=¢gõwP \œ«\–¯ ÞB™]Ù'åš±*s,õE»µVù € ¬Ò¸·’À™çD|»‘cÛ¬›{©‡¢pBeÎçÑ–Ùé&Ù ”åÊÞÿM¸™s•®S†÷í¾mbpG}…-Ájéû+ôE¤fl/Íá¬Mã}…x;Î)éÏ|ษªÙNÅS´ïמN‚HJ<®TÒËø°HÎôsuY|š‚ûF²lžsí÷œà÷]dsý‹¯à¨œ¾‹Ž"WZz¿*SÎ#`<”d¿\£;KgpÆ^ÆÜÌÇ\èØrû€7W¿Üà"Hɼ3_¾šìÉãle8“6Ôà°æÐ¥ /¯!Ù#YPV¼T‡Ä©Ç…ß…¿ý+ #+þ,82ÛâtµìŠF0Yç^V$³M<Ê ^Û×üÜFVº;’_Ž»’]hºxt/Í0­|¾r÷‡äw6KmÆ3¹y»s‘4¼‚Ü—ÿÍÆD/å‰a™©Fjàýù^f¼H£ó2t§­¤¢íã0«s³ýó¨Gï= RlÉ,Ú¨PÄÌ'ƒÅv|-C{ؾÉÛî;4¼ã˜>f"Rj•ÃQS¢eú­–¯àäÙo°‹wq½LêµR}Á}Üä8?r§,™>gWÞ']öB\lÍBàú‚ãíäoÛÆÌh¼|ÚÊ¢*ý渡@ZÊ‚ƒ%`Øål™<™ãæFÜÎ×xj±è“Á’MV@"ÚÈ n]Âÿ”+²I€ƒÜ‰²‡¶8k ð°LåÂ}ùÏÅwÛcðùQ ²µ3¥»T•swq®¦ùMì®PÏûOäiÜøö•.âtmA«júz'qټе•”­ ëî_°2…i¯¬ùNÖJ‹¢˜¶µæ.ªÆ–ÙéÉØeí7ܦ_YBk+Ì /‰&UWºLqœ^½ñµ^ÏØz¦,(§@7Ï€Éô¼¸P– »ú¿ui¶Xk[¸Å6š6 4ÐôØý¬T…d[XþÛKöBƒeýu.¶3æ§yÇú/÷*ìžÍ4 4XröKp ¯í'ýžÝ¶zÀ·>i? 4É5|ÎiÙŠc1/GÔ k~BO,I>P]s v‰Óì,ô3ñF®X8™âÛYn LºßÉ7o%[“l烙œãשbÜþRïi‘W›¥Ã18iµãÔp–+n}½8¢þíïÒoõL‹4M˜‹ƒ¯!pe¦I2¼.G)£à>îx=ãu{ðmʼnON6<ùÙ*éÊß¶‚:ÿõú(¢1qa³œ´{rˆRg6³j1ž5f‰¼Á¸U™Žm°yûÂþæ"8ÿ[NÆ¡ðõÖH¯âž|²9}…xÓB§·Èk X –̼»|C9‰!,-è‡a•w9®tˆÁIaŠ­ÜQèã·á½…ö—3=Éx/ æÞ3dÍ…²ˆVl™öÁ%½µJÔ”ƒêªäÔ¿¼“½‡‚Ï»œ*¼ºõS¢ù}ýK¬(ŒŒýàë½”ÅaqÄàµN]•öÁAÏÙÑ?xLÒÍä’¹mÌ¿ègyƒ—ÌV ¯Éý¯°¤vWjür×ÈÔ™ e´í§È1³Üm°ÜC$®+ªÔ”x÷¼Ì6Hƒy9…½žw E=_ÃÔ‡`ý†Ü/K«µ“-šC¡º:,g”çXʬΠ- e'Svà¿ù?!r1ëÙµÆÝŠ˜h®š-ëC±eß‹9¼h°8¤>ÛXu—R>‰A|î”åý, Öj¾ÀóóIñ²v;µ5XdÂmÙý‹‚©Æ¾K5ë2òµe è(ðÏäÃE¾IÌ6‰j&ÑEIíÀ‹ÏZȾv‰¶`¶òT‡Êáü¿ç”d¼æ Þ ötªc¦u;9KΩ’ ¸2X2YÏ´€fÂ'›]OyÀM”Cæ'¢‚zGq DŽb®¼[®tý ˆv@*‘røœ+5ÿz!ÿTjÓµVå”ä¤&…Ú÷bn ÿܯöȇ™1ˆV ŽÊérîçÆÙâ0—‰vøoqKšÑÙÝü”~Ìkšvù£Ý^ ÐØâ\"ÔVy WÊ…í<ÂLÝÏö°u™iŽ®¢Ò¸(ÅæLú++Kœ§fß =ä=u5‘±·(ysÐ ÍYvÀšñŒ—ˆÈT1†p{ÄœÝÒ”¾&uZŽráþH_ëoåâá¶8—ƒð•nž°zà׋\¸ÏcnîU;9Ûö5êˆ/švõdF1º_t’-©»ôK¼Mšt)š÷ïÎwÜx†UòÎ]lÜv#‹×á8»Z꾞–!üGXˆÇR•ñ”çM(Áz ¶ð¯Í. ìúF[éÜ틎˜”eù«coñä’« UVÄ…§ž7Ô¥¯b••.•¥ña§‹,Ó/+šËÇÈ/(ÙÈj¸-ó/2èÖ‘/**I`S!±v«àCà]}ùéf‚pô /‰Rb~´wAnÌÖ…tK¦á)#±+Õ€=ŽÄœ`gK°¶ ŽÛKϽ´Œ_äxœCeY‰ÃâMßÉ]ï’ÕÿôúnA_Ûi–­¼õrfª—’+2*BuϾHOŒè`.+áŽmæ0æ5×/Ö×øå öî:-¨ÙÝ+((S—Ù8P¶=u¿Ì1zTòö.¡xÈÜ"Š˜žâk±{s½Xo¯¡Õh]¢Aê%V-Ö©Ù$ nZ¨9¢¥E¶òz-5p¬Î2:x OÕ]ÛI óÚñª,1±R_äK7¼;ßæVÁ/8[ý×S]Nû.(Õa ’(8wq*¡—³|‹=Úʲ.<Þü¶~44r½´ˆ ©Hnagv°ÓEu>]æ©GYB_ó{ÏWC—tƒ‚´87³SöŒ,S»BÑ”îÔùQX*rîÖ(Ã)ɺvæÓm%”+§a[™ 7./+¢7®i†àÁ YÊ‚òí‚ü$õ@§²ަÚAŽàVŒv‰éÊhÇë@kF­c4}ê¡äÕ°`{N„mò‰·ðµš fœû ê Ê ¸"[ÁGçX”’³§±Æ•z§3®¨àúJïÒM·öÙP&qKW°r®/C욊¸Å¡¢¯-™Îü©rúMP"¯ÍKÊ1€Ãšeš¸ª™ Ź[«vpž²õA ÛqÈ>•e¹~ô7Ø[ÂÊϨHùãýkià˜å±_Êb¥«·[¤‚³_àÞ#“àzòwQfO·1æåÇì8ã=VÅ®²~P±’‚·YÀ©•ºd½ív&q(5ºÄ\ɶü¹³ÑÝÛG„²¤ÑÉvñä£Zéw%xøŒ+ÇA¦ˆœå¦RE$?d¿°}8OÑ_› ɩǜL/xéÜ–Æ07 xΪ BVJy\¼°J¼[÷Á“6=AYLörûå|¹·úk¥ñ…Pe¥‹G  (&^ÉñVhr…bùWˆTÌôr@çrøáY»jT^m½ï’A>”NªŸÅvÿoèc˜º2"WÃTàw¯$ï+mGå¸Éã!œÐrÄ;šrL…”Óm]vâd€f»?I63–Ä! gyiµß?z›-)»iŒˆŒöB[þ”ñL˜ÊR*ííVuRVÿC¯ºM§Üü>Æ( ½èÄîgþ*ßšÖ¯B$ô:3ß½OÀ»nc–“0P«á€2Šbj›'á–¬ar¨2»[R•ÜF÷QIc¯ÇNfÚ™$=«ð÷JCÍËW÷Œ?¥Ca†› E|Î]]PL^ºÔ~®3 Ú%¼ å<ðÜyÔ?Èㆽ­s–hÃù×þ—™C·»ƒ)‘¼ƒ)ßÿ¾²?K™ÚДoÚ›¤Ï~ÂCÉe¼>~ÿÍžÛæÚ_ºËL÷cÕ9Á'¥{ò@PÙºâ¢_ós ë¬çI¸êe’×µwktUÿ±s7ô*µ¶(?d:û³W¿.qÕV##ä¯Xƒ/h©Ý‡¥aÜ®¿@üœ:ß‚ª[Á(‘}{‚/Íx¨œ¾5¼Þá!mò©O~³óQèÜ“þä ørô÷–òá¦ÊÇ×tñ’”%¶Vö( ßÔwä§aÏ/YI<ØÒ\"(+%¤¶:!U²«oƒƒCé×Ðl·ºþÀvŸ+?òXù†ŽÎÛ Á™S!-Ž™Ô[·uv@kT‹•òQ0üZ8÷†¬-®NŸ’µvqÂtu~‡´y¤›»l«¯…¦,_vyê½Lˆ<‚ÊW½mA Ëy¨)ÑUV‹c¥”ç¦:‡Ÿ‹,µ5õîV—Ko"rNjîañò ½6ˆ×]€Á)ÙHðÑq¯Ä+C[r«èFïÞŽA2ÑÛÛ÷çw'&k€œwÇŠŒ¦È_Y?eÔ=Ljv<ª¹ü-jjç=½:øE;‘:-<øCr•6äxWÔð!Îÿ ©ƒ½õUèÊoYK€œÇˆ¡)9P÷ò íZι–ý(Wº•OËÅ+¼º±w²²tsAq»‚YHʼn0(.b­Ô û‚ÚU5Äz*äª,áL9“s¦ÞúäfBûeÒö#‰?ÛÖ´2•7xí|XÐ$xÀ¾rxhÊÒ­Z#ê"¹€whÀ¥}=*a?7XÔüµ¢P†La½`\×hVX:E‚¥¨_k’èv³ªàŒ³XJQE•b³÷läaŃ4©„>‘õÚåÙ®,nxä›R½©µSÊ+‡k‰aQXû’7n‚ñßvíA¨äñ²2Ëky»&8Õ•µÐ—F"¼ÇcVJÎÄl Öé¦p²-¡Ù,ûR],Ôó[&ò÷Œ$çä·²ÈËJ)o_'_Ê«ƒKÀI¤n @VJ%‚ókk0Ñûá}ÕNíaÆàÎÔ·5qÚ•„Öï*¿ÍãAÛSMΖ¾7ºSZ_ ‡¬—ó¸W»Ð'Ôj†gh6KCååCÁàs:W…bÃTÜË?¸)îU¨DóIY”Û×›ãn2m¤ šÂª)éå0G¸¹ŒCŽg9ȃSÂmmá:ðJùe!Ú×+Ïþ|-Á[@Tð{f8åŠ>”ɸRH…¨ömq9æ}.sœJ÷î’´Ý.f51kÁ ¯\YØ#Dè¸r…¯,PâÀ³XÇÊMV/k©ù¬&åÜÇlE˜ LU¢5!áȉ+k7/”¸¸|Æ3ƒúò]a®ãx™ã‚WqW‹ÛÛ\§³B÷yâÊ­–/Ê|`ÿ´ÏÔ'ìŠ+£·'ÜAž諚˜.Q\º¤Õ(B\Õ*Ë#e~­¿"‘†_@¸í‘” Þœ_ä'Äûòy7_Þ¥µ­bÚ®šsŠÍ»Y vóâüRàWÿ{|L®-ð@£_SW“Q4hœ›àW|‹Õ»«D>³ÇÍ‹óNYGyÜê`n¿„ꦶÿo»· „y2ZÓhï_sE¡&çzöDwáúY29Ê‹<Ê”)˺y™Ÿ½nÞ"eŒ¾»ô(Oôð#Ð>ÂcL«û–/Œa§Ë×çµ²Äü(ÿ¯i·‰3ÚøúŽrrjν- }'ôrÔ}uÑPAœ/µòÉѸ|JÍPèFV)W0ɶúæI™â­d'QШ­oŒ²˜tp¸ÄœË½¡8EîŒÛâ •|ä×¾ÃþÕ—*ªv„-[”F¬ÂSQ}»¥ý‚÷˜±là™=Áç¢,ƒB-¿jÞè×<ꛬŒ˜¬¬ˆó ½Ë_äŒ3L›£eÆ×CseŸØ¬Zvº€•ÅÄÚ~RQÐ;ôÛ¼øÎ8•e;‡-j·lÜûÚÊE~æ.¼çÏfG¥ê™û¨Š(N¸¨½zÒÃTNRX#)—–Û ²FO¢,+Ð7”%nË5júSC,y_-,ôÊŠ(ãòqØéHñÔ§Ûî鎕nî¶“i‰›>¨,yÅ8ÿe¥FwK£r²ÒÅÕ¤½pŠB©éNßËoJðÆÞ3ÝHYü%€0?1ÏÚª/`¿Nõ"6o¯Žžù†³î@ʳcNÀ…AA¥8ˆXmù.ˆÎ²øËÙ|Ê(¾L¦e¨©t?«õÐëc˜Š#&ài³oÓ÷—Ÿ&O;Ï&ÓZIÊâ/'‚ºt €Kø½ó¦/®š„å-åüÌëc˜¾?I“z¯pùáëNôVÏ}…²AÊâ/íÁÚÃ¥)}ù“Ò ‘ŽßKðÄ Ò]¤™<˜r“M†²­~Š•¸voËpò²øËû<–/à´=Ô—/ñÛþO.¯!ÉýìrYÆÐˆÕêÉç,ï› ˆ‡7¶£õñ—Qù2iAû^#Y!rAÊâ;ݼ"DKmð27ÕÒ¯?'× öë^á&ú*¤,Ñ °‘»'‚§FÚ{RâøW’BR–àµ8C—¨ÜËd’¬n e ”n^k.xJä^–­/R"¤Ý& R– ù<ŒÝçíí&—-áR–  ¾§R°”áÝ“íÞ2Óˆâ„âY‚£`bà»ø²·$™ñ ÔKn!e ‚Jžô|‚½<úÞÇz ·w6¡ )‹/ˆÞ€!öÍh綆‚(ì¸Ðò_W-f„”EfkÔ{zyoZ¶Û¢,d°ª²¨c6-ö¯þ®$¢h›«ž$Ùˆs{G8ƒ$ý¾‘ )‹ *xü{/®‘}Žqد» âû)e¡%!BR–¬˜ýÏÏI™'ù@¿á÷úYPö(ÿˆrŠa!<@ÊÒƒ¨uZ™³+Ǹˆt¨v#Qc+µ.#¼QìÊ"&8•\Sò¡n`wš~`…[DJ‚P¦•%ƒÇñ àpÝ®©n;‡øÍ¬×]B!RDÊRÎ+Q_áM ÊŽ¶§¤¤ïU·'+}_YÊyL}1&Â1ËŽjé²H…EŸUÔ‘/òJô~ ŠééLy[ ‚èkÊbúPüHÒI뢇• òœ¾£,ƒ¹…2R“SVˆÍhB‚WœìŒ¨ò0뱮ш„ XY*¹‘"Y;Z¶Ðû9¹E OY„‘R-=ëq"hŒ|DÆAE!)K¹tM¶.žü‚jò 9Y " CYd&> n•ìø”‚Ð"lòZY"Ü5ë“ÒÍË í¡™Aäyª,¨)Sx¨[6gŠ(&@‚BùIÞ)K„)Ù´Þ«1ù¥,•gÑ”vîCñ^‘ ˆÈe©ä½‡3ý)¢PÈnrÊDA¾² ¸Ä®²A;×”£aïA „©,ÂM{^Æóʽr‚ÈBS4U®ì=ýIðŽ|ä%ˆ>@8ÊRÛÛTšò>9S¢¯´²”sSÅêUi!M!ˆ>G Ê‚3 :Ë¢òQ€?Ñ܇ ú"Á)Ë(€‹R»¹¦ÐºAôUR– xš2p—JŒ·ø#¢„²ŒJÉÊ^ÞÕœ\*Ñçñ]YóIPŸþPö A ¾+Ë•|õ§5ìã$"HüU4X6©BŇ¿ÊB«?QœDÂÞ‚ ú ¤,A臔… ý²¡R‚ ôÓ¯Ÿ–ëD¾²f¯€gÃÞ ¢è ›E¼]ÃÞ)Öœ~¨æôذ÷‚(F‚È/»Ð¨ ò¨v$vœ°ýÓ¤øùeFÛ/­^»° „-02>¬Ò8[Ëno2vŠ'&zßÚ`àî K«š—hÙ7ô]Éí‰O>Šûhü%eÁ/czõŽ@«õÂM°Óö/KŒu±ê Þ?¡tüÚ†ÓëûÍùAâÛ»k–jÙë/´^±Þx}º9t]É(÷·ÃÃa¿1šÿfÀGuküÆ>%6qvÃçkÏŒ—éÚà´êwÐ `ωpA['ªaï…¿a³T$†ˆ¯¶^è÷g‰!eT8¿,Úúáák?%ºsõKV?pz¾÷£ÃÄ&²ítÀ±žäÛ÷¸“„l›Ù”Ø­öÞ"ù^©üTÂ,ˆhkó2c§çmåàÖcÕc*"·@kóø&;3ÿî4áFð·xÒËÍXÝCbûw’ð”實H¾—`Ö†ðßÇ«3þ<ÿD >Z‚ ”ñ]YL—dty`ô9V ‚p‹ïÊbÆzü2òZdz:òoâAÀ4AXñ]Y.6jăöÄ'ωÄIñà 00€#Âÿ•åtÒåLÐáöÈâÁÍñø8‚ lñ]Y*"3Ø?^ãéÝPÖÉ?wR€ID/ˆga³’è¶f*©:ÛÏ׆ ~yhwíÒ†m·(¿=öþÅŒïÊ‹Ž‚§_ °Ñk3ÊJlÊh ìýá$-Ÿ…Šÿ·û hßitvHñíõp2°ÔO´µYצ>1ºÃ>¢ñWYÌj¿Š¼Ø!m*iÊLŠŸo:t ‹zCCàudjâRõYFƇ}7ñ-3ߪ"2 Ïä¦DˉÄÉœ(åRËäuIËÖ¥pK6}Y_´oë÷n+¹qÄäuOo»bZbÂ*X;ǘ¹ æ8´…§,fý„À–œQÙZ yOõY˜¬ÔnM^ÍÏÌ1îJ^‘v±Mø'¼åVGF¶ cÕó¦~—M=jžjh}pNbÂùp®˜‰(×+‘±Î˜¦Àz”¶ä]]ÖYµõGO2Ó©$õ"‰ ožíðÁú’wñªÐbQÌCÇ¿°¸?lšù4¼”ö®Ýô L#VSPg}æëÍKÖ•l°?|c#nžD[¶¾Yþbüìð­·oö3`=pöÿm½fÁxf®%;Ÿ¹ÓF›Jnü%Üü@â©}÷ãxÍC6¨àM=)áäÇôÛÏdý+}¡–‚õYê`êUÑ-LVÊ:×5N]V"ëhÀë',#ŸW9þ¬mm>ýùÿ'ܤÏÅ_S›Pä,V²8>jKšEý¡ªqÉ|cÅñ¯“S1ëÚ¦ÞÿÓ—“0büº†ÏÖ÷›ãqã±>jÊO"w.‹leð⊊P¹šîC‹LŒ±‰³×¶^yOü2[ÿKg|ýèÄhH¹r¹¾ øwÇûÚ_e驟Pây[nൖ²Ye[ Ÿ›çàeÁdådRVü—xÙÕÃØ5ÍáHοÜEÀ-DŸü §ŸŽM˜›ô¤´ÜÁ¦`º/¤ °uCdÚ¼¶›ÐÚç“£Ù ;!sôfž «[Áƒ ¾¬-ýÍ‹Ç'2_Æaͱš1b8¸mö²ÈKRà<¨+Ö¢¶Nœ_èܲðƒ¬†Û¾øSDþï{Œ»æNÝß°|lgbËã“Xí>Úæäö1º?¬ú V¨–‚•Õ‰…¢ƫÇ˲^ŽÑ==Œ:ãÿª}Wñ‹kˆoa²Â•k]Ë8Ó³ãx/= ŠÞFs¸WÎVD‹9ÚüÒ£Ã2§iº@ efZËì?'*FLy?Ýüëý%L› _{¦qÔÿ.ùÝ=Æ+ç–¯ýq[óf}Tõð«Uþv©–B&(ôÂe€Fµ÷˯E¼ñžÇÁ/5í{»þ$|Æø)õÆØ–‡Å m~¸­½6ñ¼ßŸ˜ ¼ìgFw%½*xø%3XºBáFùf9w'*fÖnµŠËœÄ„h¼nnôÐ ñKWëpß–&nD[Ïyƒ>*‹rý<³8ý[P{x­ñÖâ)Çð±[‰¡Z ™|7ñ-ñ`)¨ç"YÁû¯9´_´ßö Ÿ¯í‘•`½õ%ó’–Ë„›Â*¯“•î¶9A>~8Gf¸¸˜7Ð\´é^üyibβ&Cæ÷SYÜ×O05…®'*ØÒà‰ |ŒÏ¸Òª¥ÉèÈw€Ï,4 cé|¨ÇùˆØÕ9‘;Ï6e’÷‡ŸwÉ«Ój)h„‡#󙩇@ŒTðn…á¾¶õ;õ •K-‰HŠn}\áÂ\³Kǯ5§Ã½´~8'®8¥Zo¼;/”h<º”Ô‰ÕÖÚ˜Û{âl‘V:–*‡, öÅpÞ>Êü²YÌl]sØ– °õÑØiñ_æL‰g&qoð|ÞŒ³Æ×㻜׽6•$“Ó¬ëgEKÊvÛ¢¼ÙR(ÞieÑÖfá>‹E+oKhëùg^3O—üJa÷.Ipçˆu÷ªÇü ñÊûõ@ãµ·x|Âüñ’ŒnÝŽøÏ'ó?Ë:îdæ ™Ösøì_ߪº6ú#ãâÁý‰ÛÔ¶LD'pH¹½äa6Ùá3Ûdu|‹0ç˜&¾Ÿ1“&ð•øúœѦD‹xP¸µtÂÏ^ZÉW|=rMr)tÛüzcb½1–ݽ'Jÿ/–˯‡Nß!lH4º}ï£JÌ©·Ä¦'w¯™Åì™°RyNLï½4¬r&Ïcýþðhã0<üƒm3Åó?=õ=µÝð^ß/e1ËðHf¾0gJd;#\pÂÉ<)ñW™†O>ñyü+¾Fò˜w¤änßèÓ1×%xLYgÏRèéu ·e »pÈU˜¿˜á<¥…ñÃÈ÷ÅïÑ’h#‹ŸèNõÑ4¢-ÌÍZ·ü¦ñ¨ÂÖ„MݶQœ:æFËåDEI¿ÿ¤¾‹üNT^]õËÏ’¬ŸPæ.®ÏȀ؀=ýÐö ™S:V“…I;–ßrÆ÷]mŠj)˜hJ³à×nl¿é©Ñ^4•eö¼BrPf½³Lr·+•éùUäõi¼šÉJã91CÁIÐtðT‰Æ¤3ñ–u]yåéûăãPî“6iO‚^*unÌ€–25OSt[³—Jõ¾Í†Dý„äÒ¯,h¸®N,Ü~Qº[ŸQˆÄ“má¼,f´´©LyjzJ+™4-ðÌ/×t¹Ã¬×‘Âû¢µY1€ µ9þéjËeÖ‡ +ÁÅ??‹»ú iÑ·=Rξô…Z ù‚gO3æ `:ȼ“Z¼Æ†#¢fã;à½>,·zÔg»~)KOý„\0íç¥iŠC¤œ¼¾x<5Dá#†E]0]„Aäˆ(ÙøùŒ/ÊbNì-ÛIñó“Ñ·ïMÓûH9«¾ÔÇ÷J®(S-¢#ááÓ+§t狲˜{Ëïö%‰G{¢§ËºW· JÓ+B_~Õ:Ú|ß‹[pP ª¥@x%¹>f¬}X˜^9µÆ ¾(‹Lý–š]2“Õ›sË¥ó§˜Ni‹ãónަœüelÚ±tÕR( ܆)Cª€ï×O2´u° ”Eº~²ÈÓ6AM¢Ð±#g…Í›â[ æ)sÒ$Se‹j)ƒH…ñÍA<¾(‹«ú ÂxùcÛ4kŒœYtG¬±©x9|%N‹dש–B“¹RN†OkCRõ¬d&-žœ¸-1=-]hY“‘³Lžª¥PÔø¼RžÏ˜‰°ðEYrÖO°E$­kg&­þ]Zºû}¡Z EJ(=Åó‡d6†¿•G7¥?Ñý¹ê'8ðØ—x`ªõI|¦ÃP‰ü¡Z ‡jDïë&ÅÏÀø «ö`ðüÆ`é…NLåZY÷Kåcßù@ä5Þ¿wAs‡~eQ^]O¶×¬~Ä,Š'…§˜™°rAÙÒhìÕ{w¹ ÞTÒ<”?P.3AŒZOk³dŒHÙ=õ»Éî_;?Þ¯0z6ƒp€§–Œ¨)ÉÆl¼KÑ÷áæ°ŽÅï‰R°>ؼf²gmY§)"¬M¤±\²d¥ä ž5µ0î6SZÙ”hiiTK¡Àiø8¼5…‹IeË¢ú~„½SÁ1½fŽÄI‘íÏê]¼o„Ô«_YæÇ¿)êäœà%‡—Ú¥É>Øüt m¼ÿAã§f÷oÖ&f h)ûAâÔ®mh§Á;Ó¬¯ÌŽ™ðzküÆMJ ¯D0” sôŸ{°i¦Cdí<¸iDt]L,ô”uVmýQ=*}j)ôLerx±¸äÂÞ5ß±ñäñ¼ÏnFy+p„Ùøä*X/&8¬nóK÷w¦)¶l”z p…¾f|T"u6Sŵ|7h _Áš59Ëî’ëðë?¾(6msN[FÖùÆŠ¼=|ÍÊ"Y?Á Kb†ióÚn1åYn¼Ü4·ìKVÔšÓ™‹ˆ¬nÓÌe•†ç(ù!6Ç"Ô°ÔÉqÅô&¸/jYp0-±(VSŸ\6åÃꛑåùøšý,2õlÁIOM|†ýE¤æ)œIÞ–˜Ž¿{*B5?óhl@ÎDÄ4¨–BáÂÊ Öðôޤ¦lTð&ÌH\öq¨€’úü©ÿyÕø-=Δֆu-ãê#Óä7⥥™4Û,·Æo<°ú .4–šóêÚž¸jÊ»p¢4V=f,ü.5î^×8qY‰J¨ÕR(Dp¬¾jò–Ý©àieoBÃé§!rÙzÐP©70Ì`¿í);]mÞ‡ÛYk4ÿ¾ævÑM šm/…‚EZ3^OÉÅy+'JgFw)Ùª¥P€ àX²SlÊ Ê€—JC|‹hÀ^@09ˆÿÌ´ÓEîý%¹ÈOŠŸ²"ŠÆ†‚feqU?Á(±ˆ˜f÷.k3¶´^a&(º-RÙƒ·Î)D°.¢BR3F©ä}U3ÕíÃ…[[bgƒ§,\vCͬÝ¢¬€ñ,îê'ˆ•ùžÉdYgtçã|Œº\TKXo¼‹ËdÜT»ø™5»p8r.@g%UŒ2žóüN“÷Uë‡9ìf#î+5Ök“­w>+ß´/…0›Y|Av¤¶C³Ÿ%Y(ÿôkÎ6WÑzÚ÷‡#M³ÖÄ_¶ÍãëG³4–Ýù»äÒcÍÔ¡ðÂbkÌ¥Í,’rÊh ðÔ.Á{hí3l¤?ÌI(vz}ã“a©·|÷KPæãk´ù¥ú~sÔ6‚É<™úì¹ˆЪø£f½~dOëßâdr548_LøW| ¾_Ÿ|ŠO‘V%–;û_’µ¨–B~ƒÃ†¸$pŒQ“œ1Y¦)8“*¬&w'ž{~q§ÚÇç%e…W‰÷pt*‹dý¶ÔoŽÙÂ}Á,O™|%«%Sñ’y΢Yûǵƒ†³u´Zˆ:Ž.8 ×5NU›I…H,ÊnŸhìUµI[]®}Œ=â}ã›R}ÍÃB§²¸ZÖe,±f š ‰=uàärÿ.žœ°¯”œŠÙF“P†+â·–ÚÛW' “§»mNÁÕâa£2ßù§a¥ÚVÁz±…?6MˇˆPÊb.ëJÈãµµç±ò”|-)V=æªñ[/dNmØ bâ…ž•È–­ø®ÛK–<ƒ;Rú}küF_Ï&¡ ûÒ½Õ¯¯0¾üÚXφ}4®1›¢HJcFâòXí…À£IóÄXÓ©,j½iYj¢1Öl<«®_P{غîƒñsñ_Y™æjP¢Z ~ ·C!­Öè籚:à…MÃ>1*$C"TMj6¨ó(°9Æ]aJ­\½im¡‰ˆ¿ñq*ºŸe¨•´‰¶²…ç⬥`ö“Ëg“ÍœJ›1Ó®0ÓJÌÎ~…_lÞ¦ØÀD\ØhûçÃë8&XXlBëFqñ•øú†Ä Î Iit€éý ÿ.ÂÄ”fá_ÇßlœDÑ?þB~ B;Ú”ÅUý¼.çCýâÉ ×{ª¬³ªy‰È=Ëtnã3õÆåøWVˆ8åèå I{$cüÍéw!}k@t¡õ0ùUäu!î ¢Ç;Ô^…èû%ßûØžü„v´)‹é4ý…¶ … Ÿ¯]P{˜M|R…|XÓmsV0Å¿âkð•øzs¡ZL‘p›Î»§æì3$Ýê%êq™l5ô4÷€œì™T¢Ð‡Øw‚˜ñŸ®¦ ~£MY$ë'àçžÈ‚h㮞§âÛ×Ä_võY/Æÿ–)%nmN$G@tÁ…Né%5—ñd¯Õ÷›ójë…C›ïî|ãcµL\B/fü§Ûrk¾¢MYäë'°ôÂÈ4æšóš 7¡ ³8>Oòƒð•sk?Àw±ÿ”uâvpkRkFE< 7óT{›&Ùd켿ä±ú~÷áïâ\…ÉCò3ª@ãÚ»ú «¡°´ò Qž2¾Å9¯‡÷‚؃¯ì)^Ù8L>Ǥ˜'áfÇsu–P@K}Bí¡Uz¢ t£MYzê'HâûYl›&¬‰XÍÔ™5ö…ãXtÿé§yƒfÏ£e$“ˆ˜Añ* ž¨dß%#äØlTÀ½m€}¹©°¿ ú„òh®¢ Ðùil]Öd˜Ý'Yá¸èqëŠò<¸ Ÿ1ÓÃñ•õÆX…䈼ZížXâÀå[¾b–$Cuî„¿xz»ør §KŸG²HÖOpàö’‡Ÿižt…œ¶¢üùZ¶tz݈ñë’¥UúÃ3ç+{ M_Cq²"øé:ù…rÂÙ@Ýÿ—ø[a\O¼’5Š2i¸±£ •ŒéÐëÉëQ‡!Â[æFõgbgê¯U‰QØÓ“âxð5øJµ㯪i}†#M³Ø?'amügZ6ˆSW¦û†6RÆŒWš’ÊldÃM˜}ƾ°÷. ›‰›ÇÁÑm,Ô(6å2ós¾¶#¤B-z”ÅmýüúYmmkxKªAo}¿ûpkøÛÀ‚¯ÁWâë>ÌmŒX§8X ¢\ylâl4 ½X.¢2¾Y+Ç;¶F‡Šþޱ1Ò&ÀJ1©í[×81íëˆnYç¶¡¨FôÔîgõØ\&·#ã‰o›M…¼þ1òˆ«µxoÜCÓÃ?¯½f9{ê$™°rus{žÈ[ìÌYÓ¼K[Œƒ¥xCî‹?…†ÎÓŒ;Ô!0ð»‰oŽ|‡ ­©IëR¸e‰±ÎKú¸5‹uìœÎÏóöÅZÄ gDí³÷y.þÚ®¶KŒåõ0Kç¦9‘¿÷h²™àiÔ¸xç ÊrküFa'³Ì(iedçÙóÚn1™Å¡d,è?-mÛ« ŸÑu±TÈ3ÈK\_|ÅYKG×%Æ:©—Н/‘´e+"ðzî`Ïã“ñêÓê0$K™=ïÊS–Ÿ.(c®œ£mˆLó¾Áµ‰çcº£ryžDC¬º>>©Q¿ GÙùmõj—¬ ª^Ýb÷> Ê2*„²¨u`z^ô›ðèÛ»›_ºÇ¸ÓÜkÕÊMqšªš—Ì7V({¹ò4mÆOÊŒþZÊtF[ýÝOüN«¶þ/œ¿Ôµy5[ØÁB%ïKî|ÍS‹''Öœ~Èã‚ÑDN<Óx¾X§Cymˆoq{mãá³V¢âð[Â,~®)ž‰D%»¾W3Ñú`FŠÕþ0´ñþŸ2ëÃq>Å–«aÖ€–K'æ÷F[7Jv#‰ÕNo”ïQŸ‰m’— ŠÎ¡™O®9­¼É^;me–šr¨jýÝ-[Ù·6qöb˜-žfæÁm³•÷5r>Á9÷þÞQ\æµ1åYöýV×/(›^µõGO:;ò˜a›XÁYO0µBÛç‡%ÓùÞ>pz~§qHam¿“äú&¬gÖôI?1–ÎLppÓåÃü²ðçÄ'¬eß×Üì\8„ñfdyNŸîŒÄåó`¥Y¯~]ãÔªÄmÀƒ9”¯L/‰v^•ÅL¦â½/ë\½OÙÓÆÝ¬t³Ë\¶JÚô;•‰Ÿ˜S$€Ë¤ÞŸò9h_Ó¾A…SšÍÜ%MŠïG›±açZ‘Œc‚FÁ²~Šñãøõ9ôHg~ýÆakµ"­Œµ‚aÂÂéuûŒ}ÖFˆóã߬H ‰M›ÇdH<Õð¾ÂqèbH]œçk:ép!¸²®µvÜÏ…29K͸U. $ cç·Õ3WîIVRg(¼°úØ«oÏ[‹Ý&ãðð§Þkº’£hH¦†¥PÖž½*‹Jý~ŽîIÜ¥¶–d‚’´Þ˜6²eØ*ã ë—Jdò¦ñ(^xñy‰õ®ï7çâÖGð/5ú”ø„¹ôSÿçÅ¿Çî–5gß#ß`³&µœâ6–¹{RTg)vÖ ¤ä¸*ìß²NëF/¸ŸëáÝõ0 ¶%Z3 Hô*1qåàcFJ““}¡Â| õiYÉÃO¥\ u3'áÚùèÆ7cÞ7Bä;8]Ÿ[æÑ×÷»/ìÝaî€Òñ¬‘K´ùÉE¼ioß8:rGúý™ZðzÓXâ= $?Aûîæø ‘¬Kï•ÍTFóÒÄ¢¼Ê"e){ؘß–yŽ•ð“¹Ú˜Ù P`­ UE‚’ó¼w‚æ:¸DÞ²/þcö/26Š©ë›äÚ¹d¡ØdøÌ Eü„½/9 e)î/y,Y¤ö1upÝÒðùÚd†æg|Ël$‡”¥ˆ@ýs¢b­Ñ¼¸ˆ—ÉRo,›ô®°Ïá#¤,EÚ"Ô­†Ñã>Õ°? åL„°¾.%3óaý‚ðR–âbNbލD 'afíÖ… ç&ILmH¼`v¡ën›CÝ ‹Z*F˜·ö±djVN¬Ù^‚u-ú’÷ˆü†”¥HaE[àùžÛ>âùbü^Ö\DÖë·Ä¦Ô÷D^ð6åÚD!BÊRÔàTåîÄ"Ao…ÇžuÆŸg…¯E­f;PDÌr‚<†íæÌ8.Ò”¢…”…àöKü.(™©«fª™à“L4%ŠR¢‡ñ²:£–’OJV¨—&ÚÊÌœ_E^ßh$5!HY'¬Sà¹vÖ\Ûü%‚”… ýP< Aú!e!B?¤,A臔… ý²¡R‚ ôCÊB„~HY‚Ð) Aú!e!B?¤,A臔… ýüÿ9€´‘ÕìÆIEND®B`‚gateway-1.4.5/doc/alligata/11-1.png0000644000175000017500000001330307344776077015321 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ ,¿Rƒþ pHYsÓÓŽ{¸®gAMA± üaRIDATxÚí]»{ܶ–öË÷q\SY©fT%®4ª’TWIg¥»]ìn»ÈÕîV÷þ qy«Õ­öv²«ÍV–«›TUQ*q*ËÉJà {rÀ>æEó7úF>@?œƒƒs@rÎÉ€þâßv›Å@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üs|±ë !¯‡<â„“0 ån9},„£<„sðîU'àѯª{7F qlPJ‰C|(î§… üéuTž?)ìT¿eë´œ]W]['8€ñPòƒ{Vâ©sÖ‹ý‚ûPð©Rˆ'æçÒ¢ùsÔ—dˆ&GûÁØ©ØÄéE€á¦ÖDT롌Š[` [i ´³Y•Jz8”Te˜[KX$î…¡”ÀHf@ý$‚Åuž¸VáæœR²U€ÇÍ‹8÷ÖI¸WÇÄp/!ëØ"Tð™ªúuŸ¸Ó£éôéd½n6kì=x·@ëƒâ‹ VìD‹ÃÌbºNÕqU)%—”\[uoèÒ@aÐÚå/…žš0Üjof:“(´D»—6ËèØNÇÓº¢lkd»‹»ÅòÓ’ó Œ3­ØMrrRfзEPib [&S‹º3["i'ÇôˆlÔn;’³‘¶M EScªBU½!t‚ 1ÆÜ‘kŸ ŽÈÂ[Ü~¼õ?ùhå&ãy½“ëírµÌd娍Ör†Ö–5­ØgBJÇR}WÙ¹6&zº&käEy/ø»Sw<›žÙß³š`ï“÷añÁ|i41G±%¨«Bd‚• œY°èº<´ð˜³eû؈(k1$Cµ|γýqbnZ·ŒuæpI²ËÜÉÈ=>š©Ú®RZ*,dï£èt¹2ðÔ=¥à:bgÂkæf4ó/×åZiT“¶×”fÔF¨ÉV’f±.iß\/E>Åv<2-ƒÄiQ’æêU$ƒÒÁP% < ’´*Tìû>ö»+i.ÊÑ}šÚÄîMÓYD^JH_~{©»úíe¶†½†K C+Ï ?ÎÞ\-~6b£øçÍÏ늟?žŠ”*Þ0ù…½L 8"ë5Ÿ™êË–‘iCêPŒI×éQApÈn,µ‚Hš¸r„ƒFd!OgœS¦—5-aW7/^Rõ¨4k5"ª Iv¶5PRÖ8Ö(«hÎôÐ.¥Ökþ˜â5mjµaï‘5 &U¡¼©“òÅ(j…GFe%Ë1Ëþ(Ða.Uѧª¢á§<˜üLj<ÙΜSÈ–<§š­zâ2)ý¨Õ}iú¦štWÊ#åøXì¢ëÊÓµ·òÚZôG&‚•»¸˜])ÇòÖFr£ÊÍì,;Ùf;“HÈ–Àœ”ù^™Æ‘Ím(°âsA¢¤Ä —>³»U´ô>Æ~Ô8Š’f·…oA/y¦Þ ]¬KË)!‚›¤Ö€òÊýyP ÊÔŠˆ>`ÁNØÎCe"8H$˜Ä\*ÍûYêþmê¨.ÚT_ÝéyÞÚ}»Nn§…e–àxCïw×Úd«F]53òìf:ø ¢…‡ÎhdEªrж0þj~Ù>Ãm(1hѺû S³×ÒIâŸiÀÛ?.ÄT®.©öYVHp¬%e†ðF¡÷^f†,Ïiܰäåúô4 ™kÙõv“«rñçbá- ¥¨éÂ*7'ø€-@ÙÏ؈»Ó‰;­¼Ö<é®aˆlÀÆnº0æe[ÄÁ]q€5¦Í&:bàvÛ(²¢Aülˆ0,-¬üPWÄ R»÷Ášh†–9Ï\žü„ ù×É]JUS\N°˜I4§¶RØÒc|z¨Œf°‰1´Nç›~dåÉ*%8$¡'“7ôz¹)d/ÑÆ™n¾ªnšÍ.ÉYãLnV‡EAI˹$åã`>q®"UzLÛ˜° žäBCæ BÝB³KZfr;Þ4`Æ%îèR æiC<Ïmá@ÞÆ_·.ìÝúm.©Ìä¶)¬Fh#Ä_”_êö2ÏÌ9 ªÌ…ÒÓ ³æ«¤¹ ¹K[2gH[ÑkRÑQÞ ¯ö]5vÁä£Aš›ˆl5º` ‹€R¹Šæ\WÉ© `d­­Ë<®«Àpá ÇiðÐb$\nE£ a˜þ̇bjEcô« /lf³l´IsˬÛûšJƒ ·ËÛÅýM°R‘†dºˆ4´šÈÑc”MàjÙÔòÁ€;bÓññ„U<ÉRîèP´ã_´XEȣ͡"«pžÅ³I…Ó †Xa Êœ—@Ë9Yj¾u²©o ú¹[wwTŸbMâtPÉ»D›Ê/%xÒ=‡aá (Þ'Íß°‘ìr‚åäç¢áP>V¸7cÿ¶hà1µw®e¢XÛ©´† ¡õ†ÑmbKç4*.ó˜æ„n'¬§œÙ.<9Ù“£|H¸ò¦u˾)XÌ»«×퇷¶Ï@ás`ù3u—SWAèmUtÞ±±óx°ž‡–OŒÙŸ¹sÂÒ¨öIWy²â9e¥ÝÃxpWÏ’ìIðJ¡pb¥Åu¯U¹ñàöbÚ¸ ›ô<ç8¶s´]Nxçñ`ó³h–‰ÛßÔ~PÔ¬ø5`·TO•Çã`^_È<þe~$Ë&…²£6i&U˜BÙMuƒ+SÃsl… v“N{ÏqåY¥ñ`ïÁûðç‡`Å™¯¯ÈqÐOžm°ÆkÞ×>'ëÕJ5€äÝéÉщùÚòIwbÅæ~¸+ËÖŠØ~6Îê*Yo…[èhóŒŽ_dÄú$Á‡ˆÂ {®;™ÍÌ×ïl8Tà)ªvf™§ì s¯åÓf‡ÿa ÂÛaVÑÇû ù~¥3Ëøø¨H"³;³ˆ(Éaö‡’ÏJ„òé•*ìÌÈÚ3/ügƒªáŒqFB®±¿^Òúò·—úŒŽ²H\Ùóí†X©áù]›'ç qܲHðv©h”Ò¦¯z± 6hkfVZյ·e×V†` þçÆk“öÛg¢¶†nauwÞÉt™}@Íp!'!Uë7Ô ãl¤{-ÑÆmX;lãøØ­ˆ|VZ‰š*:nK–OÌebs•k27¾©õOÄ 0Kp.¦Ì«õ…Íê •×–uÆ•)7[›´pz^?4Ai4 _†åÝâZhú2¤„¼üîr×yÞö„ãÂhÁG„ÝÙ—3óûuJ%˜¾õ‡â8xCáÂÞMçàúÛ–tX°`샷ôØÝÊŸ.´{±Ö€-¡ð1üVÏ[8­leš”µQÑbzÎ@ñÞ ç‹fÉ—5ÇÁJ' +Fo¥RªÞj\Á±1šdx›Ë0`[P5]Äuªß¸cX¡¸i Æ×PÊbu'l2² /-VÐ1r³'ã%¼ÛõÁÔÐ@†yÑ[FZˆã—“V£ÜŠv(±Pñ6ÔkµcØw“å}0ß­0˜Uû…ìú¿%0XÑ „8¯‰kË(,ÇØ‡Æ¨çS+n;`k°á×H0¨hºžN9`ïÐÊÈ"r=XË{œ|)ó¨å+Þiz™Y’¼_øâyä`×eþ\y­ïñ7SÅ-µ2²L3‡Á_° ðI´XYÏÆâMJÃ#Â[‚&i\†Ö‘RðOwãØxÏÐÖŠ¦Âu÷(­öVô µû ;j¾0'ú`ž´•ü㣅+Ýe¦¦ê:Dö= F˜¦1[³`¡Ê›—•¡Œ½{OØ,Z)]ã]¼u…io*4#?a=ÿtè Ä€Æã&;6öÁèŽÆ‘’fg¢o7¯?;°[B}R9婱z\[:>lÆIU<¢j¬”îÒõgÀó¯¶ÛuÍ$hêA¡”x®©M;§ÜXÌ®© ˜¢!MÅ{ϤëD¥8ˆ£òaž~ ;u*µjÁ ¬ð,h£Núà‘« iRÏ{Esû‰|ötN„S6õ¢ì‚Ë‘kŸƒ£_ÞªôyÁÕ1ËÉqUìPh)Œ³Le>'Ÿ?û%.'Íl´,-"ÊÖ`©¹zOöY5ú JÙÞ'»N«ú¬ˆ³s™KsðÎgo€Kù?ßþq;Ÿý"72H޶-t·Sˆœ’¿­dŒ•ýQ&ÿŒìºc6±”àÒÇG,ƒåýý|0ïD?W?ÐÆÃ† DJv© "7q'–U/áà>qÇH° ñ†éç77ƒGŸËJö7ƒežÃº—XÒÖ€]A-ξ¹6 ¶¿´Z‚‰˜ ížø!“‡ö³sÕº¦éŸ¥9ÊŸá´ìvUÔgòÉÃì¡ü¹s'+²:k›C°Ë€WÝZìK‚‰äØ÷‚Ðçr}Dn²ñËQlNΗ$Æ¥’]”] ¶¾‰`K0 Å ÇoºðZ+d4Á~#•ÍürÞ±lèã¾nHéÇÀp€Ühž {‚%‚U„AÀ…aÅ¥œèêv'm¢s$uØ"QVøbg±øŸPK‰¢*Rkç+ ‰šÕ’È2Ô&X"„O„fuöâ¸ÛX?¤ÎàE .â9ùV’z3nA³¨ifñ*ÿL\­Å$â},ó?¹V,IЇ.ú uCÌY¢!ÁA$ÚMœt£ 2U dò‚‡BR,öb²CG7\È´Ã,gû Ø:xµ]¸ ƒOïû°»`ÌÐîƒ4v†©?到öøŠã·4W Ã;´•`È™çyWDEø¹ X¨aõú*5Lär[WΪ/–¡¸âòï—³g³ù÷óö™lN0zµ–¾d¾½?=à[æ/Q­È´”cûeuªú`I3lC«aã…Dü]²×Kë™å BTÔÂJ­› .`[J¹ÔÕ ©kŽ¥—½µC€éw¿¾›Ïçí;©æ©—@ò”¦’ˆTâîPJ8~ч²°5N•‹G&¬æ­\Pj>€®ÁJXŠÚþŸ( Wx‚ ]~ª“Ž%X¯%'þÅC~w÷P«“£¶=qS‚#ì/áO¶Ð@`Ñ|Ö#ý; EÌ9Ö%î(U!$7$ÐPÂáì »½½e ƒD‡ê/ªE[…ó‚r;Ó•†Öëƒ?·µ4 ¼J©E¯ä*6#­êùŽP"ùJÚœ¢7B§•xYÏÔð”8¾.©fyì{Í aúú*ßÈŽƒˆç"|‹»Yl`Æ ©ØCÞ(•¶bP·  'n™Ã}0Kê¸ÀRMD²ÈåäPù¥)§c1aDT±KFØïâœ"Œ±ÉÑx¼ò‚ëÿ ë]ñxŸubCnгC4³T¹\LÀ#”óÙY,‚Z^-ýF –¤öFè#§êE½øM#|8 \¶ ÞÜÏ¿++4£¹ŠB *¡q‡Þ#"0£èèÃ7¨/÷ɘ‚‹ÍiZ¨hÚ²Ì&®÷ûý5$öˆzw9Z®å´Ð]Bäóý»÷ mÂŒ ¥Ôýêlr| E!.*ø†a.r J dƒH¬?Âg¯©˜Å fà iµpiÁ-±ÑŒZå±)Á¢é TA£æw¿œ}ÿã³IÕô{|¸°2VK"Ì1îs¹SZô‰{ó¯àv±ÀÙ"¨ß°`?ýå§Óù|ÿ%šàì›Ùülþ·ÿà#&¹¸è›DÞl4v)š&ÐÑ'Œ¸¢3¢®ÒdTX`¨™G¨ °ÂøÄuƒßßÞÙ…1iýn®¢að*%.fÂåKz÷žS²Ä9Ñ¿#46*¨8j˜t6\Ž0º¬æÓ kóÅó0ÆŸwÈœ%€€é—ÓççÏß]¿Sî< xÄéÝõÂ[¬]xŽP²#é …æâpôV”Îzãï—zµpŽÎÓqûÕo ·‡²AÁÒ“ÛZÜ/®ÉºÕiVšÌŽ–W :Lö:.s_|{öúõë“ã´KÏÙlvñúâêòjzhú¥–óL¨%tá­h¥‡ýø/Å˵Çq ]/Ï ê„1ÚÖ§ÇÓÝI°C¦“É웳«^Rî2ÊÙC4ÉnÚ8n®;nÔ9 Gûçç?¼89==þjºÿÊY U:ÿiöõìòŸWïÿ÷- åÙŠbˆŒ8‹}ybЯ.Q^¼¤~”«‹+·6G˜==n_ÍU4h•ùüôý¯ï–ýíNº,x\€8ßù n "´ÜúÛæ/æ/ÆGcPû‡Å®„ëº'''.›Ÿ‚Íõî×wüÝ 9£è½½Š}·º ÄPì\¸·pÀy2›ŽlïÉj.þËÿ¹|óæß¤Ñ«¦ZêK¬´É=B¬e¸ $õì»9è·ÓoOA°‘ µÙ Q?ÐÕ~ûpý¯kïîÆ~²\ª3‰µåäø˜²¬#SThéÏçÿñzþÝÙN &*ÞðöíÛ7oÞÈX&ît N#q0ÎAËó»9ðzòõ ˆ,Úû¬ ²ùþíÝíýí=TÎâz¸4‡¼ª¥DÃiLÏ¿Ÿÿõ?ÿ M¿“Ȱ³®¯¯/ÿ~©‚KR÷ÆÓB±‹ƒÐuA£À®Y5#àÐ¥¶ Rš…7 ¾ùp|CE-ý%ɬn£y§'ã ðúêçWg§gÈní¾‹9Y¢0ž€l¶À4ØR^×™ÀT@ ú%²æÊ«¨ŸHÂÍo7ÀzA’­j{«³ÓÙ³™¬¥®îßÙ¬J鑦¥‚Â1~„$N1z*&=q¥•ñ9BŸ—󹾿»—z¤vú6ýñx,+ª[­¶i³É K‰aÒ9 ˆ­ªuÇ¥:Ç>Í‹°Ô|1Ö€CÃ@pÏ1Üs ÷Á=Ç@pÏ1Üs ÷ÿN‚°<]i/IEND®B`‚gateway-1.4.5/doc/alligata/done.png0000644000175000017500000006400707344776077015676 0ustar toljtolj‰PNG  IHDRX¦/tmtIMEÑ .á{o  pHYs Œ Œs®[gAMA± üag–IDATxÚìÝypœç}ðç½÷ĆER¼EÝ”"+¾jÇvÕ±âñQ§ÉÔi'•êxÚétÚ™äN›?œvÜ™Lœ(Mš8qÚx’¶¶c'qe'²ìH¾$Q%‘O‘âö~ïþžwÅïî¾ ,€öû˜³X¼ûî³ y¿ø=ïs0ÐÁúßùóç·»Ûàøñãâv·`;! £! £! £ÉÕw=ÿüóÛÝ*hwO=õÔ… êpìØ±ín#@%AªÇ‡Ê¾‡ÒÇÜv·Ú×3Ï<ä°úI Ð&äZ?À§ì&µú;q:‚¶ÔñãÇ[x|ñ§u;^b+_KËŸ6‰¼ñS´-J£Ò ãß0T„°] Su¡VzOñ˜Ò¯´ªc¯"+ÎVýt [[ëll9l%T„°mŠAUë©þkEaWël…Û…Ä*}vßFÖ9ÛæµZA›¨tŒVõÔÃ:‘Pý£­Éâ³ljŽ;p ´ }Õ5Š „ÍUœ“dBNi5VýÓvîZljà ½˜ª Ð>„°éšš“°ûq»_“³ƒÿót¶Õ‚uþúÄ`h#­M¸b}Ù’ó|,æTì8¨¡øv–?)=,ÈE»Š,,½Xz¶u·­þÙ|[¾Ýï1TB–òRëvÃÃêŒm©uÂ:÷WŸ­Ncê7»áO } k:‚:‚ 1ômìbBèhBèhBèhBèhBèhBèhBèhBèhBhìx‰­|Òÿ´% ƶ!»Ý€*öú¸õG›ØAM…킊꩎½ŠP¬( ·«kÇâ=µZé·¥*ýiõù«ð±Í¶:*BX§ÒŒô½í{Ã÷ Õ¾ëdÀÇ®¯µ((;*Bh±àÛCÙQr#O×ÚÖÂn…ŠÚÂFº"[ÛY((‚°c `ûUôUnÙckA×hGA×(ÔS,ж±tÛš,ÕÏ‚8ÜÝP@YXza¯xý¨(ílô ³ŠSU W©ÿðú­uXÀÖîAi¸»! ±Z1P}Eö<Ò÷`߇ûޝ©óØàm¨s$RpwC×(l:ÌɃv†Š6]ðnI€­‡ €­€üƒ¶…®QèhBèhBèhB€¦÷ÃÖ;6r ©ùéVn×·+ÕÙ€¢­Þ½ìÚØ¶/j‹a° @ÓZ;Ïz{G‘` ‹/Ì ï(¨Z¬ÖævË‹ú{ãÕßï~“Z¸]_EËkÝöm^ýû6À÷vÀ÷9`Ö½býv®£y¾»6ùu°º¿èõý::*B€Vª¿§]Ã:£áÞxµ–«sæ–o××ì[Ñðm©óò×qæàwy“[þFÃæo—®*ä×QÿÝð­há‹ÝqP´ÒVîð¹6µIÕ ÅÏÖ†ëy¶¤Í¾G®ûÙšîІÏRg›ÆMja‡÷£"Øtùs»þÞxϼ]ï×Y »V€Õùéæµ¡…Ï»½[5p¦Ó 6]Kj²†]aµð°(vå•¶°ÖóÖïülùF€ŸeƒÏ»½©­z±ÚÉÐ5 °uÖ‘CmþW|i ƒu—, ‡¿Ó·;·á+má/b#§jI@ýw ó!ÀæÚàzÓ¾½v¥C!J«ßßXqXÅñ-_Û÷y›íõ݉з©ë¸3H×hÃ+ެ³_UÀæ|Wë4•ø¯¥Î«k‡Òv‹ ¬ê }þùçŸzê© .lwÛ Mù/䨱ctþ[‚޲ÙÒÕ*…Ï¢gžyæé§Ÿ®¾Ä€®Q€@Jí\B€B îhB€j“ ˆ°>BèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBèhBØjÇýîßšçÝî7`=-oáñÅŸ?­ï‘;ñð%ow ãœ?¾pƒ>I‹·7[ñ¹vâÇ÷–½K» U뀊ÚKuÑÖ°’købÅYq£ô§·«Ÿ´¢l­ÓªuœÜ÷Uø>°Îëm¶ ßä†o{ýV쨡”Öm7X 2ÈCHÅOvú>iðV5{rß37ûÕz± ÛÙ°IüÅ´9T„ÐF6òÑÙÔc}³°øÙ]ëTŸb}'øu¨þQK¢(ÈI6é©¶*Bhwõ+’bê´ö“7H_b O¾‘WQÿ±Û‰^MèdBhw‹¤õõÅ{JK[ÑU¸¾V5{ò¼ŠZ òB‚¿€Ý ]£°c´viDUÇÕ[ÕìÉ[[_n„o§n ÏІPB[+½Þæ›%Õƒ Ò0–*ÎP}|çhöä-ï­8-«›Ç¾/§ô´ëÈB –D`Uÿß{þùçŸzê© .lwÛ Mù/䨱ctþ[€vPø,zæ™gž~úéê+耎† €Ž† €Ž† €Ž† €Ž† €Ž†y„°m6²\5 °æKõº-¬öÊݾg¨ß ,0 °; a«ou6«ª ×y,ì8è…íQ± f­Íÿêl³W'~|ׂYw;î´WÑòЦ@›CEÛ,àæY´åmkxÝ‘MmÉR—Mm™ÿ«:‡<Ø‚g[Ã'Ø‘„;‰ÄÜ#±¥#ÑŰd ¬^„Ù®Hi·`isFdÖåÉv%@áNÒ§ê÷uÍÕŠ@ÑæÐ¼š3 ¦fº¢ähA¸“$-eÉÔz”|é.fôðål÷´¦ðCÙÐŒÜItGúñÒPÞ)ûóåf.öý…‘¹X¡ÿ)ÐáNB!·l)˦Zrp+70ç`½Ð5ºŒõ(z¯šOÈFŸ’ï+é˜; æ¨Üî6ìTÂ6¥‰v—dö©<ö´œ&ØrÉûB©ó©ž¬ƒ_%ÀzàÓsûQÁí¨lFD+*™½ŠÞ¥tC\Yp>\“ì±púR¦{»_ÀŽ„ ÜRTÕy+ŸY1ÉŒIVD²è6ež"8¢àò/Öô`¹2†È¬‚pQD…%»GÑ)öŠÑ-딂TçIŒgÞÆÏO§Hšê¤»–íÚî× °S![ŒJº/óúÕ|·¢wɆìU{Ak:’å-{f8’㲜#»Þ” ÇòŽLÿŽh¹|_ˆ¼#¹®±eÛè[Ôƒë† l1*õÔü°–íWršÄ¶×±]1kËy[¢`3¼ír¶ìíó°²¥Cá¶U²ò§ãíáð’’ÿ»í9§ŠŽÄ7r²é%ä¼Ýšv áúQñ׫裡ÌX(]ÝùJ·%SKYjÊR–-º¡ð’ÎË6þÕ©æóB7"Z!ÑI¶&ÚÉâÿн¢Œ­PÑ™öV´¡×b`&Øu„Mãù§zù§eb²Aß.[ê­|tÖˆ,›jÊV¬ö^ä“Ê;~ÍR6b²é]¶4½-,øeKË[ª;émRqÊSþ^Kã¡«;‚° T'‡Ów…“=²nºÒŒº”IÌáœ-S`´sZP©šÍ‘Pf–¡ðã3DÞykºbÒÔ&ó±%K5ÂYþB “ ÑD‡òïpt‰Ê&J¾‹éÞY3¤ÛR;‡_AT²(üF’ YW¼°¦_4Bsfˆ’oÑÔ p|б„ Pò§ŽÆ3–üfº÷v>â]ók÷]jUÁÔr{CéÑPšn ‚k8ÒD>F_wtz <ü¶»mAXO—lžŠÏSòýpqxÙR-·­ó/.óUÙF´L¢‡D«0m#k+W²‰¹8e¹Ýö°Å„5Q–ìÑrçÓ½K–êl¬ëЛ~ÀW¡p*Ü#t§í{°åðñ)…Û.rU‹ˆÊ‚£ ¶à-®V䕬„7m_\…mYi.EàålâZ6‘ãS5À‚°¦¬¥\䨄¢¨‹ˆfH²ùª¡’É×N- *ªÒÑ>\Eð:Z Ç ÞèSßS•M±pYu W8Oá ¾Sõ Gš1ÂùØ”ÉÙ2" aMzí«h”@1™¯Ú«æ»eƒª1M°ùÚi|‚³ÁÎDz€˜ÒèxÓ‘òŸ­Ÿµåy#´liK¦b¸’ÝÞ¹mAØ„°d©Ù-Ó¯æUÑ–ÞáÙÒgà‹¨kPÓ]¹­;Õ…®ËòÞ¢kY›Ol·1ë…ŸÁ㽩˜ð°ÂÆ(íFC™ñPzPÍj¼Ÿ³AøÖT£ôò¾DÝá“ó GòfÙó5ÕŠ½¦#V¬Õâõ‹®^ tYá¶ã-´æE@‹!ë¡ØÖ²÷Äçû”|ýü£ÒmÎϘáY=œ´UË)Ôg¢  Í!ë¡|¼gªÖð΢¤¥žILëáÝ=9¯°¶êžP–¥¶»)­ƒ ¬'"ñ…§öFªo2ÝîÆnUt¨ îWó{C©˜d*m½–@ÓvBZË{Óïd‘…¶´Á7sq±½át\âKT 5&ÑJÈF¯¢§ÉS‰«Ó…’郎+ÔÐ o§'>Z‡²0oË“)KÉ9²Î'鋺¦·µ¯w¦ |ìæ¥,•¿qÙŒJ|K *û”Àû ìh턦Ã^¾Íþæ2›J1£*uæ²ìò{î:{ç>öC¬KÝ‚y3$J¸¼#û!•Môu(ºôÂâÈí|Ó!­ ••ýjnXË%d/#ÚAâÔË*WRùÑñòÃoö…½ºß¯»Z¼JÞÂ"ŸþÈjÕ»»[›aÖdúB£öøª}–òì¯/±7gÙ¿x€Æ›8ÿºÞrk§ºæ»d½þ‘Ž+ߺVð®AÒ™ÇBi*( eÙ&½Ñ›ˆQgÖ#•’úêZnújÏj®ä×{¨AÕ¤#½c“Z °Ú)©ü“ר'xÔi2ïb{l$ÎT‘¥ 6‘b7—Øí4+|$Ó1WØï¿Ì>÷جnRʪ^E?Iî 'µºcG)HfŒÈÅt÷¼jxZ:Õ-·?œ¤"RíVÏʯõîŠY[)ÌÁO™*ï5µùª5ômaÚ~qvcqFql;ï3 °Aí„/Þd/ÝfŠÄÞ½=>ΆceCc(ù2&»<ÏþÏyv+¹rçÛKì_e¿všE®DÖœ°hh¹ƒ‘d¿’«3}‚ꬴ¥L‘[¹Ø¬2ëNŸ·_¥üK i¹ˆh¯À¹T¹kÃ[檢³ñŽJj[ÆR ;î&ùºk~|ÓÝ6ßC`‹µMÎdØ×ßbCö™ûÙ¡^>.¦‚È»öØñögþ:ûÁÄJix~–}÷mö¡C>iž"8ýj~,” ¥Ã«ÛU »ò¶¼diTüÝÖ£)K1œ;ôF%ko(M_aÉÊ;Ò‚¡Ý´c”R…ú¬¸”ZÕˆÉì’M*²— ­Ñ\Æ"ªÞÌД¥ü[6UÃ1© Ž¶ ÂW¦øÈ—Ï=R9ôvнz‡½5Ï“Òðzï4™÷…jÒÊœ ªŸ½ÂØÃöÄÖ÷Ì_DÔPó£Zz@Í…%»bª€Ë/’Éx[™3ÂsF(çH~AJ+‰¹ƒZž’Lw¤—“ô¯™¶í;Y'e°dŽ¥¼‹ŽQ•ÅU6eCQ>EÄ“´”;:µ-AÙ¬IvŸ’¥xÖÒu¦ñQó®g»nåcÔTsWOíh¡¶ ©4ûìé²¼¾Èž½Æ^ŸfiƒUìxk¹ìÛÅ<ûÞÛìã'š* eÁ¥b«×鄬‡Vu™wäœ-gl9ii*‹¦–çÉÇwu¯Ó_IÏ“L‡ ôÀâôí´žÒÃü2ç3ìÌ»¹Ì–uêfI‘GùQX—Æa§GÙXWánןbXb¡î¤¦ú>5Eà[™žÙ8%tS=ª!ï e¡ï·0I£ô§k£f¼WÔ°ð؉Ú&ßwX]œ%g²o^bß½ÁÒzЇ¿x‹½kâ¢..™=Š>¬eû©øm×û|OYÚ´-Qœ$-•J1 BËxe°”%TJvÉæ¼Z4ËftðÉ ³YöÂMöÒ$éc׈ËaIM¦Øso³wŽóÎÞ¸Vü9E색¿a¥•€¯%û¨åõ#*Ë(Ÿ)èMO”dyãTùô imzbÙCìòQ3… .øPR,±»HÛáxbåÆBŽýÑ«¼x¢*0ªð0  ;ëo¿”çcm>v¼ú'…Y 1ÙLð¥Røê0ô±¾djù%ŸÉë<¡°,Ë:F§„%k,”ÙN-[Ú›©žÒZ£*ðﯱïßàkT·_Yoˆ÷‹RþDWûƽ<Å®.²rÛ—(¼„ÃÑå.Ù¨~q”‚?Z2jw„RÈ ª¹Q-3ÊPå§ Žø…ç&ªl­xífÿ:Ø Ú& (ð¾øsös‡Ù½C¬'ÌçNPD¥ÒO&Ø?Üä½ µœf<ÄS³K«è#¥´K™Ê²©Ú^æm|&Uf}о/œ¢t¡ºêÍTïÅLwÙŠÛTjž›fù&ïò­¨;ÜÇN ±=¼©ŠÈÿ[@3mþ*²ÖÊh o­™ÑP¦ºº#žMö×JA‰¹ÔÂ#±%ú ¤ÔÒfAøú ûä‰ðxô#Ü›yå «Íë ñÚèôûƒWø56_I¾,ñnÒŸÞW\tfå2[+Ð)бGËì ¥ùú¢‚CÉúzªÿbºÛ.íD]ÖÙW/°Nð>Þµ |Zä{÷³{‡yʵۣzWæ¥ÏëúNá 24iùÏÑût÷ìh(µ5“v®6 ÂÇÇ£ªýû÷ÙO ‹1až]’³¥• eáS³ßþ»ã7f„ ¯s3ì£GÙkÓü˜OßÃK®VP'.›ÃZv”«Y›Éà2áj¶»2//°ÿyŽOp,í í ³fŽñÑ¡….ÐìjRRLÆTöÿuØLÌÙrH´*îÏÛþ‹kSpÞ×µ°7œÄ´ €†Ú,%á×XO ¯'…߸ f«ûóÆâìg²ÿuŽ÷=V»áÅÏ?º‹½<É~÷%ö«òNÈõ½/‚“Í.Ù üäÃj¬êšlÉÔÞL÷¬¥ é°ïÝ`ßx‹-æJN$²GØÇóÙ{WØõ%¾ž8Õ¯YkmਠðBp$ÆŽ °“ƒ|ÔOIÉh:â¤íQ*»…#Re4t+Æ]‘%¤ @í„÷ué¿<.H‚ð¥ΜÁ;ý>>’|n.2g”´“êªg¯²i¿¢ðV’% >…ŽùßçÙ…OLÜ—òÔ<ù$3Já'™ EïSòaÉRDG¬±Â‹ã T f‹£còûÆ%öÿ®”MŠ  ïŽó½2¦Òìû7ùª”‘Y³f#èEæ¥á¡^öÄavwoánjÁåtbLãý±¥‡Çù\{3UÕ;:¤æÐ# P{áÏ]^‹þa~e>ÜGF"ït>{ŽéÅê0®²Ã½þA¸”gÉ<Â{‡Ù·®ð9ø_yƒ}®r6Á[í“r.$Ú|ÙkY+¥ ÖÌ Ê#|+¿:[ƒ²íÏ_g/Ü*ÓfŸ<ÉGÁüÞË|e¸:ùWÊuù,ûW§ØµöÞìgÖ™Ë9òO–‡IL'J²Pc±Å—–+ZÜð%xK¯ñë‹)KÍy«Ûûq)AÃ’­ 6ýMâBÑÛℽ¹q»R¡"¸OŽPH¹·r¢¹Ö°'GØW&ŒçæJæçQÎýà–Oïha¢Åþn¾%Åx‚ÏÁ¸8Ç|ß•WëM¢Ö²ôù÷fS„%s]ˆ¶+¼•éYY½e.Ëþð ¢Ò‹‚Q…wr~÷:Ÿa]­Ì²Î{Yo.±_y€²ŸN=g„¾»0z4¶4J®vŠºÂËIS}+Ó]ú^¤­š+¯Îò•Á{æL-oK5gI–D¶äÍ2T¼y K¾ÑSc÷ ØMÚ(Fò½*}4‹Tü•fŠ*²O¹ß›w×ÖÌäK¬Éþ5Ö‚w}NØÁ„¶wÝî‘•Q*–+Ì›}Q‚ч»*P]ÈW/Ò²}j¾z4Š/Ý‘îè‘=Ì¿¹â³/ÍWd8ìG5§ÏDõû£3ì_>Du¡ËW‘Ï,óAªÝ²Ñ¯æ(“ÁéUô!5wÇ7k„t¾ubÙËq™p)Óýz²Oof­Íø$zÃæIZêDž/zðKzUí¥ ‚0©{ýœÂø£‰P¥¥ïM°„ÌŠÁ×¥ñ¡%¾A˜\í9¤ºâu"É˲û†Jr¼Ix:ã[Í¡KÙD\6F’T`ÕÚk"ïÈóFh"£ãsÞJÙìÆrÍé溪ÀjÔþ³Ó|óÅÕµ qH_“zÍͧ¨©çR}tÍ–vf¦,õl²Ï¤å¶)-‡O0¸¼À÷Ž ¢j4Î>}j_ÌѼOé˜Ìd¯ö‹IÖ‰8%ŠÐ«ŠjéxX®7¯ ¡ñª1gòçzk®"+Pѳdª¯.÷ßÊEïïšëSs¥†Y¾’g··¼V•ÖIÁÖ¢ºð¹·ÙC#<Úƒ¡°¼šé’˜{2>_Ìõœ##ªmyš»0˾}Éy‹§íg¿|ë ÷*ÆøÅ­aͽ7‘ÿÎlèFŒýÞÂ!Í —N™Ë˜ü<õÅ4¾CEaJûtšàxC`^XÜóPbv,Ä×Ó´]ñF.þfº7e)e$g³ìKg·" R:(û«„Í ïS;]Ö²‡½J¾WÑéž —G°ÈÇÍòEJe‹î‰xßòõN±Ö(ì"[„Iã|ùöÊJäP/¿Öǯo•ŽuüOÇ¥Gïäq¯PXîr"'díòóÔê{ì^Ý ž)¬VoY“¯øO?¯@eßK˃TVõ(úÙäÀD>Z¹Ý5þ+¯ó[éì4/Gâk÷ÞJlÌ[‰Æ¯>¦ŸMáY#“Ì!-7¨æŽD—ÞðB½ú`Ù[4 [Ñ»d£ÛÛQ\Š@‰a&ìf[„ô©ýåsì'“Å%4ù„¹zª‚¬|”“q÷d|íÃ]wʇˆNgÖ¢´BxõS>c®…%ŠÕ“O¦Øß\æ1Ùa{â|ñ6ÊNjCÉò¤Y[ziyˆb YQ2ï¢Ý·®°3w6úntil8Æ¿öv±¾Èʲj¶7êu"É3ïÆrÙEЬÁ§áSRû_¸É¡ª´0¦ˆRp Â;Né¯ : /\ú<’¶šÌªW² J»êq¢qÉÜIí ¥"_4Óð Ó´>)?|v…¥Lzm†½r{-É»÷³»Ö®{Mä5Ûµ$¿Oâk;mI¬8ÜŸ"Áw3 IäKÏÌfÖ‚„JÃâi‡¢|~á[s+߆eQyxP„Ü3ȳ¤—I–§²_ùú ï¥\÷pPÊ¿=ìþaáÄÀà 8”àϵhš“9¥l2U{”s¯Nñ¿®/ñ{èõ^YdïÜLJ¿îKðŽåÉäÚñ·–ùN‡”ˆ=aþ*ÚÃ'o”—‰|5ïòß ý¦¨F<] KVaÿœ­.‚:®PXµtø’ämXˆËŒ°Ë´&5ÑéQò]²i8Ò¬²ìÕæ³ìYvm‘}äß>Â*ÏŠaíÓÿzÆÎÙnLöIÂ7“®^ü¦“Ð }v5*¸º¸–ƒÑµc(N¬aÎâ_ÔÎKó|w *O ²÷ìçVu&'uö/°ŒÁÖŠ¿÷:}|Ðþؘ°7l%dÕYÛ¾‘uó-á……•Æ‹ªxúdøÀéñËOŽŸÿÛ·3_¿Æ§Þö’¢ôÑ1¾yµökËCï Åÿs×ùÔɇGøtþ®šWéµÑ³çÞœ±J>Jbzà yìòm:ø E\û•‰Þ†…sß½‘ÿVÚ̆‚>){•üx8=¨ææÍðÕlײ©®|pÞJò­øÎÍðŸ=Í+•Ò8 ¨°{pO±OòbZÈØB¬ªEY[ø‹É’×§Ò¼¤ó•ÖaaºÍÞœ]»¿4ÉÞ‹®Q7—å›ÝŸ¹ÍW4ýðáµÝ‘˜·³Òß]çË™6‹"ðÝûÅwŒSÿÙ¸óä¨=ÌãÉ-Vœ½L ³/Þë~ø‡ædžwížìÒ¿úˆ—ŔŮÞÿ[}ó?žá›Eöþ¼y_:ëóŒy‹/s³¤³_;]k!o>CßÔæ1mT€°Ë­?ûýXlq–3´W“ýsFx%s&ûöUžTĸ.{l/ﬣ°S«ž‹j—þ_ŠÓK¯Œ-s*õÏ÷W~4ÿdѼ– ­}nš_ÿó5žXùܧ¸* Ë¡òë¥FÂR_8ôè;Z²f7•¡íN3#G(®Þ±—}èPßhèßd³‡jçN¿* ‡äÉ< ‰ìßdq¯2ŽËìÞnñó޼ž½÷íg.”=€þ€xx”}ý¢ÿôÎSÕKm>1Ðä/ ³¬'Á9_¼ÛÛßà\ªïZ6aÇURøýÁ++ûËÐq¡æë«šÎ‡_¾ÁwMúðÝìHög·¢Ÿ³â%ÊÚì Wä¬]Ò/zfªìBc©»{WúZ_¾½¶`OˆoæPj*Àl ÓæãSÖ¾uØ·.¯ÍÖboûô)áHßýì '­M´\7oÛôy¸ÛzbOY6¬ Gö¾ý‰•Ñ-^ûÖQ2HíE—JÖ7\^g›Žh8’á]#lâÕìM!}ž>Ö=½GËÐGç‹‹{¦ôÈÚ'+¥ÅŸ¾Æ‡“”Uñ¢Ýá^ÞëXQQñA4wxírb=6öê©¡ÿ|ÑýÍãBaú<¥àoœ—^˜/´rq®æì=*¿ .åËFuîMðÉõE†Í×-kè®î²í )­ÏN}$‘=:Êž<&F>:b}þ0yïBʾ”VDŒÿr •÷G.[Îù¤Éò”²]>|´ÎZ޾Ζ1X—æðË~âh8=ΈšÞ¯KôN#ZüKÈØÊ’©.YÚ²©¦mÅÄì{è Í!• $fFBiÓ•( ¡B°º\»4ÏîßÃ7w?=ʾû¶Ï²œÌ+ _¹ÍÎM»ºÿðýwÝþÀÀ'É”…_ºa}{FµJÏ÷â­š'Fâ+“p‹_ê+:Ö¿29¡€Úp¥î@>šf}òÄڔĴÁ9 ¸j=×Gް4é熭ß9导ÇyÛýí«Ò¨ûßî1NÆÕÒŽû»WÍ[ùxÙèï‰ïßàó@jé°_<Åsu‘¯¶ú™û(ØæŒÐ¼º”N-ÝY. „QØJ—v·¢z¯Xw¤œ-Ï‘É|tÖ!`wk.÷…ÓcaÞ¯x)Ý]™‚üÞŸy<'Ø=CüCù_fù&{iÒCJš·æ­kKõî¿úàÝìa&–7o2Å+³ZN ñ¢ÎübÉvH*ÃTýd’}ý-ÿH>q‚ ÁwìeÇËÆ˜Pº¿lŒLHfŸ>ÅßKiz(jýÖ‰@)H¾qGŒJìOtªSð¿^Îñz¼ì­^ÖÙ³WØw®ùÿM ì¾=ìcÇØXïIþÖe>%q'e+¯,Lå#öÜÑüV¥;é‹rñ`dyÙR¯g»®f»‡°[5„‡"Ë‚w‘éF>æs™®'Ä/ÑUT„9“=ó2ûÄ öSc|zÃgîã9AE¥æLÆçjŸ‡ü³û=ûÙG®M'gÕ‰ GùÈòÊŸ^¸“jÄû†ù MBÏõw×ÙóoóöP\ÑE“ñ™…£q>_‚JÀÞ²™õ=ãs×M¤¤ÿÔ=ìãtYpþýÝÖX8hx<Þçþü¦–>­ Ÿ¿äþÙ­ØÚÔJ¾×î°¿½â?„pwßÂð¨WÓ[ûÒï%¦ófŒµ>joÑ™I=z&9øSÝSuZ%ñ­-ò= }<œzyy0àòl;KsA‘W®H)¾Ën=´‡'ÍÄrå¦î”%_>Ç~0ÁÞ{¯OòéÞÉ<»™äC@é3}*U9”>ñ¿}×pŸ:¹21œÊÁÒUi "|oBªá†b,¦ð‘#Ï^åaüÐûÙ»ÙHlíÓŸ‚’ø/,5‰O<м•»©ˆëáå`€5E%‘=q¤‚Œ/ŽÊN÷41öd$TöíŒÎ¾v›ýñMñ|jõ睊’þÑ»¶TYÑÒ3Fùûø87[è¦÷éõiöå³ü`ºG¨lŒËƒ6Ì ?mÔÜ{ú&´44™yÀ²Îé{ÃéY#T†TNý»Çx_(U- ¹•éôq|a–_ ò>²ØÃ‡~Ü;Ä¿r?øåÛñßµ÷R?ä)´æ³ì—NñG…Ê_Zwhíš_pT>>#P9øðûСâb.½ª0^Ï LŠÀ¯Þf_¾)\HË|J;½9Wø›s~–¯5SÚ’BþèáTèÝè)yuŽËý3+4_=Çg}Ñ„ÜÄÊ!Ñz´{úÙÙñ´Ý[w´NsjK¦—ø§ç¡ÈÒD.:mT•ôqüäQöÁƒ|}Úä8) ©¼£æÂg±æõIR¡V¬ÃèÛÑ8=Â'×á‡eYHñIõ"!ý[,‡c¼Ú£š¯ür/ߘáSÈ)bÅ͸¼h=5écÇx¡¹jÁ`“yvW¤ñC f ÷ܲû×wœïÍ…®e{Ù`S |‰µ s|i‚Òže´‹¯²öÀÿ·§<Ý麓æ4¼xke Õ‚T)V¡7h,hSŽ"Ê“ñyª [óÞ´‡æ‚ðíl|,”¼Í ë¹sfy`R¯Úœy3è«Ù̱.v°·,_׋—A_»È‹:çÏä+”öùõéQüãÕsç7ÂôJR£Ñ`QIäÁ\þ¼Syáé³â¿>ä¾«ß ù](´\v;ïNäÜ )ù¥Eû¥%åfÆÍS~NÌñ´ççx•¬¯Ž…¡0£Ô‹óAGúyV¬Cù·œç½ÇT;RY¼°º ýfŽðRµJL6ÇÃÍ!ÿ…2ØŒv™æ‚boÞ ÷+üs6"™õLÍá‰<ÝÊz›¶ëN ­ŽüÍçØ•òÉx÷óñ/çgùáë~Õ}:G†5щéˆdED«¸©SÆV G¤æ®¤ÛRÞ‘Ê–·®ãÖ2»8ßø0ÊïÓ£÷9Œ½° ŸyÅ=cýª±/¬ïð«k¦c_NçgpÒ’guwFwó¦ÀngÙõ;|TËD’-d×¶Z¤üëRùø—û†Øá¾µM*˜Wþ&u>f*Íÿ¸ºÀwä 7°´vŒ*¼ÈþäÉê~Q‰¹÷Çç4±ÆD”Úè!a1Ø4€¢¹ ´]áÇ‹CïíŸ{Ÿ¡¢àjYú²½4‘²°V½àºBÊVnåâ·«ç]0>“Ž}õBÙja=aö+ðzë—Ø{îbO.›ï­ô—>%? æéF¸¸m¬ŸÂtrJDÝ•“¦2c„ÌPʪ;müû7Y:ÀR2ìá‘ã'k gù8Íû* $ózt©$¤ £€õOÜŠ5k4™Ï…¿˜zíð‘DT_šçQÇÃ2ÇÁÒYÓpJ>jÕûø.®îñøb³ý¢ðÿÙ;óIÎóŒ×}tuõ5=ÓsíÎÌÎj5{h%íêXÉNV±‘CF" 01cr€ ‰‚mBP!‰óI HlìÈD؉$㘈H²ÐµÒfW«=gÏ9{Ž>ë¾ò~Õ³³st÷tÏtϵïb¶·§ªº¾¨§Ÿï{Av+M>ä]á͹¾GÓIþŽh±´£µ–좨=Rù'ÓCÖ ùq}êÇȲV¥î øž‡{If¯J½ržúÕarû.0~š7á9Þ% ëpLC‘@³Ú/J9¼1)Ú> fqÊŠÜ4£yG\9Á ’s6»öyáRv¬½Û"0@0ppæÓS¤DÎêšm `ã~y€áDyÁ ÏèDó@ ë„í€}ìŒPa,(hZµ¤ªÂºGÕ¹A¹H¯w†ÓÞˆéGÙ~¬'pÖߘë;ÍÁóTf››^s«ZÆ&î4ùISÏ )ðÍ8ÒU ~‡zŒ³äR¿¤Å9‹ÙðJˆ"l ¥iÁ¼n¨£ZÌ[:ezvššÕÖ>KB¢º[•±ÍQ¿¸I,`¾Z™lâP‚zþ0 òÒïé­›5[>ÁÎJ¸[iðÛ%Ë«ð®§FIqì^I‰æàî­û¦‘yf,IŠ Èîb¡ð†Ï~TL_Ñãàð`‹r¶ØÀÒ‘ÐçËÉ•³‘–KZ(8y‚ÿÊ0™]ì¢þ&yR9ç ’ï—Ëá”ì†$0 hÃãt8cK9W4=Î" ‡Kp|’ò_µÑhOŒ$- &HĦ"¬ŒÛ¬Ê¬N²àÁòêµ3ÀÉ}õ¡…éßׯP?½²ð>Z½Ž)’I…ø—’"àÄz ¾1ÄX§WÒåR‚·èÝ=0Ð9Ad²¡œ°¢ËŸ+'/kñëÂC¶ƒ7“¼%1nŒsVϼù}®ÜqY¯üˆDÅ!§ùâÁeù¡¹Ù+•ïÍÆšIz[ýÑ |%O˜±ä¹piÐôÙz«ƒ· $ia`¶í#“´½êÊ$Åṳ́¶Î¥ºq7pÂÅEPðŽço÷ îQII°n8Ûhžöá{Iœ³S‚Õ#j*gK­ˆp úºÛøyA¶-H޶Æv…¼+\7T:¬Tù`ln_deúÝe=ñi)éÕ‰ØÜ_-0QÖ=ÏFšœ€­`ùHuÖŠdm¹à ¦Çz Æ‹žž^VËM`É¢ÝÉ!’ïØX†"G‹ÝÞÃzrkEŸÂGÜ ¢AÊ^>5DüjjžÏ3¾H»à›+›Â‚A÷eÖÝ ÿ[Á„¥dí†ŠÑ ‚ì Z\%${ˆÕtëB9Q]‡Ò H08¡€Z±K%Ú³©kÐ<>çHSVdÚ’5ÒN¨É5-À–TàìTH²ü#}‹UcVÀÒA¿Tæé@ó¸€ä=1Î-¹Ü¤u»Y#…i4›TXí ýNÏ$—ÿà ê‘^@»OŠ·z%--r¸ÒÉѾÀø­•½UwUø¸ØÙP`‚ ÈŽ¢õå²¼ôÕï×l /²Ôs‡H1Òó³¤@ZzÙ*”î³ïäzIL§x“ª‹¶3£¦R&š´Þ˜Ž[Ejª´ðz$Mš Äkí+3î}êü¾H‘ Ó62],ž)uLÚ‘;šq¬‡úùURp®^@ÚbÀ‚º‰;„Ïýúc$jt¼H•V¡Ä¸OtLHŒCm%Wx'×]pùŸ Ad»Ñz!쵪É|}R¹PNV?æD?1C“%¢«˜sÄkz,¯)„àÁÿ]Ô’Y[v7Óxj‚¤«ƒÿ;9HýÆÈÈ7ŽÀ“ŽÎ/*4(ñ Cý¤”*{Ë£?F}ùAêŸ Ø:ä êŸ>"¢;˜ Í„+¹ó¿úàƒÆ ¥SÔ#¬ÇÓíMo‡ï“¦^0*ˆ È.¥õBåª;•ý‘ÂMC­Y²yOŒlÕài¿¯v10xRŸ-u\Ð’-@*œ½0G2A?·¯j@&È|F4(ùnA¯dqÀ5ÌÚò§åä¤ñV_C“Ô@Pú7®‘I׬V=• h/ÍÝYP”8Ò1㕥꜀y¿Ð%1^œ·O$¦¶-ÖÐòÙ¼+^.'Æ,ÅÔ Av/›×I@åìÏ&'N»fW·­¨MœsîWg3¼Qkx^_3b­QA*œõ|ê÷&U=—ÇÅ0T °nFÔ÷EJIÞäæBéœ#^Ñâàíúk™Ý iÊøùýd¶ójŽä,Ê «Ã¬ðÁàžä~v€äPV›S ß-Ÿk­ê?ïHÓ–ƒô‚ìzZ/„%—?WJ= Îе…‰¡P;Ø2¢ÞÄ©k0¢änêê¼Ûœ¢,RQߊòÁJð6é±@’ðH>>_vù[ž$†àeÙÍìEÄÓAØXƒT-ȈFš7àjÛmÖÀˆŸHLÿçô úBAv7mY#¼¨%ÀÏ Ë…WmŸbš²ƒI?¯(ŸÒ’ …W@ù¼¥îÊÃc‹ž0gK³ŽTpÝçŒQsáÀAï—šZÒÇq­á,TŽ’XœŸÌ¸ KT9BmÀ"·°†)Áš±¨!‡ ²ci‹‚`œÊwj.(ššoz×,7h¹np?H‹LtÅéà­”`ÆÃ’c« ¯x£y\ÁAüæQóxøo-‰åÂ2f"㇕»ÝH(W¡¹tAÌ*ÝkaŸ¥mléÛËou€6çÛCcÐ¬ìŠ ²ýiWÔ¨GÑçÊÉG:¤ä2¢ÞÈjß:(’Ax¦Ôá®’+9\nÌFZ0¢¡V1«.#hP»¼Kâ$ç©–!­õì+©„3‚‘à,PS‘õÚ4´í|¡)8hÙå´7}" êbK]$²#?éPÑ8 ZWøe-¾4h“£Éê#hÕž°[S¸–VE×@Au›¶"cVtÞ ¯^Ûz0”)ÁêµISYG¸kZ´‡9!¸@ˆ È.§íy„à*&IÙÏHœ³»E½_*Çyk#ŠH½qÜŒŽ™Ñ°”Ú ëÂùäRš7øºKqp†Q=~E‹/F«Ö¢RÕóšëÊ|c€w ðEá“R3=‡Av&›”P’sØ.éñX‚Ñ)IÞ”¡64mÜò²Ñ^Àø™vt|Æ Óçr¶”wPÁ¢Ç/[ái_¤x¯’WhÕäì{ùîqSYSÖà†äÒýêlƒÍ‡ý€±}Æ `#…Âáƒ,ÞaW„ØŒÏÒ¾@û|X,›!­&ÈÀaø`gÛZ8»qànÃ]ªYAd±ÙO:P…Š"Žê*<÷Ac@ÙÐl ËÛ`O¢A AK*SU"*x(>3(Œ1Ñs®”*¸BcR¼}X_­‚àSAó¦ÃOaB!¶o}W„­á«vašJ ©j$Èa¥ã.üWem™% ˜ÂLOÂSI¸)¿ÈøÂQ M%c7 u݃BÙqìø¹¯pÚ± “jö±[ÔáqUå±êÁÃJAZžøÞ4kG.i‰¬-ošNa‰mÇ«ùqð Hö*~QIr1”^ÅS†IÁÏÅ)èÊs}l·C’FpÉ•Z-«ÚŠ ²CØñBXt„Q=~¯’o*ÙDî^%7$áØOËÉÅBÁ~¥—·?ç&rTm¨¦ZðIìc Ö?âH^£_ùY™¥nK¬Îân·A!‚l&;^=Š>SìÈ;âáè|œ·›r‡ãDs"뽟ëZZHL$“w„Tðý|fÌT¶EKó„Á;¬µñ!‚ìFvƒ »f¨ïæ»×1cISAš7feœÎbZ!x&Ú«‚‚ H}vƒV†!¬«W;©Mc*+Äo1€…,%1TAAÝÊž¥Ã8™ôd°{E­_*7[óE÷¸«zü¼–\QVÆ H A§`w¾œÄþì‚ »˜$„ÜíäXذ0ÁÙ gGY·Yý³}¦è’Ú4· ¥èUO¢3£û•”¥]a«Ç ‚´‘í+„tX„Ebܰ­©°¶Ê9‘°S`³ý‚€¶|Ö Ø‚+VŠkœ5ò`Ÿ1#:fáÒ ‚ È.g{ !CëÉKrf—hªÄð9|“†/ H…3°} ~%W(¸BÎK.oxœÝpž€PgK)ó Av;ÛBÖN'oôH:iÁ: z>Ÿd…‡Ép¤.jW [ÉÃkÃçÌUu>›¢ìm´ê ‚ ²ýÙJ!¬´Lê>©œä-¾nØ'¨W©;0eW ²jžV"ÍìpAdl‚Û‹sN¨õIZ’7W—Ç\,wbz¬îñEW«§û¨ nwW?$A¤lªʬ×)Cr1#êwô/ MâêXpxW¨È¨I”oí‚ ²6CŠ,É¥=rIålz¡‡Wöø¬™wļ#è‡s›‚ ÈæÓ^!dé,àp„t{7hÍåçyÊŠÌØRÙå= sÕA­¤]BÈÐAZ0)9@–ö 7£WõØŒ-›>‹ž‚ È6¡õBOåì#Ñù~© ްä × õ–©–\õAÙn´X9:8 *ó<ãƒù»¬Ç§¬ˆíÎAíJ+…PaÝã±™I›µå‹ZbÒŒà ‚ ²Íi™vðÖ‰ä”Ðïæ2cf%AÙ´FÁ ‹ÏÜÐc—´xãõ<AdËiÆ8ûý|WÑ0AÙY´F'­ÈVAAÖNc"‚ w5(„‚ È]MË¢F“B4ÆËÍUrÍy«TyÍÒLœbé5ÂMÇù”•Y¡þnG÷ö¬¿›å»Óf>¶ïâ&Ü–n9ÉÑõ¾²ÀHÇô¹­¾RAIË„ðoŽédæ¨éÙ"±ü+·Þûú©©¨PZTöÔ·šökËÈíã?}ñ¯Ž½ðpÇ=–çÔÚMá¤ïŽþ|ÒÈó¾çJŽQk7žá®”&ŸóoKnÍ}¶¸-¯>ù ™åAíªîwÌö½£ÿõµ­¾RAIË„ðäÐw.½úßg?ä‹KíÞò‰¤±4›–b/¼õí)³Puÿ„yù—þ˜e˜” þÛµ7tãZg~ñȳ1>RtÌKʼn¯}øÝZ»}6sðwö¤×ò [ C3Nø³Óß»X¯ºÃáÄžoÿòV_&‚ ÈN¥5BÈÒÌp´ûíì…³ù5íúµ¾ãâm!¬p¡8~«Æ,_·”XtE“Æ|Ïš·µÊ‹¢cÔÙ­_éhÙl'0êÑÒd­¬cFAY¤5Á2½r’gÙÑâTSGésbLd7µ90‚ ‚,¥5"4 te‚îYMu½œU8©CTg¬b›†V5е~ f´MŸ‹ ‚ìZ#„Ãjæ¦>[+š£óv9g—‡¢]ŠãMØ8'Ò~ò䋵~Û!ÆlßmÓG#‚ ;‚Öá~µgLŸoV‹Å‰±¾×'>nÇØ^?5mäêï3g• ÷Ž‘™¢Ýr²GNRdqÎ×ç'\ÑÑ7˜`gŽó‘鋤À/¾?o•gí¢æ˜ðµ`7°hŠŠ J”“Nì‘SCþè¦gøàgÁÑKŽP+Ç;Šï‘Xþ\þ\[;. Ad;Ð!Œf.Æ×ñ¿®e÷«š¢W?ˆ7ÎP4ótÿñúûŒ–¦ßÌžw<®a0Úõ÷~ád÷Ñ1jyàxSâ„›Úì÷®þï¿ßøÅ¬UúѧIßS焯Ÿúþµ·–¾“£Ofîû­½Þ£ö¤Å(¢³Ä†‚,ÁØ Žññüè«cýÏôÙ¹Û‰•"˃z%…(C¯±” ;tˆ*¼p}¿àh‹ï«¼|_bàùÇM€–YÁò?ü3Áeð §¹VÖ*|š¿ù7ßû`îJî¶àq4û'‡Ÿ¥iø`ú7÷>ú­Ó?Ð\³å Aí@k„ðÞXïkã®ãÀ«Å©'º kµaŠr$Þ,¹ïû×Þ¬µÃ=±ÞÏ÷>øwŸþØð¨Ç:üó‰ß¿¥ÏþÅ™¾;{qÚ(øTÀÑ̰ÚýT÷Ñ/ ?ùÜÀã}î•ßþÜs—¯—³UOøÌž‡¥ö- ¡Ä O÷û£Ã¿Þ%Æ6yú¥³/_,ŽÃ™Á„-’àðˆb½ŸéyéÁÀzþåÙ—_ÿÄò™¾‡¾qßs “2Ë×É­„ï p¯ü&Ç0 ã/¼ý÷T¨sOfŽüé‘g‡Õž·³çþáâë—JpÙy[«Üj8$!(ÝRb$Þ2ù~eÞÒ^<ý¯oL}'ÌH ;ÜÐõ=Jǃ©Á·³ZþBÙ´@Á6 (×JÙu;Zžz^úŒÀòíB*œz}é“ÕúíúŽýùÑ߆{#ßyø+¯ý?{çÖäÕöqžì°B#„)2´*¢â«¶ö³V}-Új§Zëk}ëè[µ´¶Z[[­mj[G]­{¢" "(SB$@öO¾#|H´¡z~W.®NÎ9ÏÍu=ÿüOÎ}ŸÚìu¹l­ÙŠ‚Àã`eÆÚØ{–JêOòUhì_¬/Å£å¹7‘¹6vú$¿¡?”û¾ì‚ÄAr¤Ü¤‘+4…Šê£Õ7>/<6/8éë¸×bXç7VÒlµ¼Ÿó«Éj©P‹]Å]EÍô+›À“$Nt'<>rqÄÄ¥ý&ýVq啌mv‹Îè,FîÁêèmYÅ~Á5 ño†Mø5aÙö’3 Ž[ \&ƒy†û”Îb¸#<ŠÿôzA{`àÉ{Ú@Àà"~ã8±À9·õ6 juR D NåÒ(Ì Ó`T~šØÑ`ƒA¹*g¯ÁbgøVw¢˜Oýfèk<{Ú•@i:9 ±^ìiVCé¶¡¯Q3ÐH…Q{^”ëü]À_6·ñ&3€ºaÐÜg|&_ÛrIœß™q­ò2eå¼&¹ûóˆ· #áTQ>°Ât<©@^ùèv3A ˆËé! ¥ûÈZeëJfq¨gØaã}¢…:éÛý&^í,=—+èlʰ‰u "•§4\&…Ler@ü–»9ߢµSò„Ð9íå¼ YÒï9>“œöe‰ª®K“Aݬ—%…+röìöÖùºÜ.½€ È+ÁI|ÌNû"GÚYnú¢(ïµÌíûF-;W—{¶îxôZ”!¤¯Ò õ<ª:Û2üÂYy<é} o/\Þ0â̪¯}¤ñü¸uŒþÏ`ÏÄíÿªšG¨1Â\† ˜áCÆà³Ê5³ ¥ûÎÉô/TTwØ!ŸÊžœøyÁ»*HÂâG²#“ùcxTï–8´ÒQþ ^BW¯Å“@{/ê…OòÙUAÅ Hò‰ñ£Ø/©¬!PßÂìÅY¼!¤oÑ Ž0˜Î®Ðˆ-6>Ik6ÊŒ p*“®FÛhAQ‘N.Ñ+ÔfC£A­4>Ü*ä³B-BxæÑdPtŠ'0© z‡Iýƒ<øûG-W›õlsñ]Çjn:ï0 ìãY~hÌŠþS%Å*·iÓ®|V¢¬m߯ˆš÷ÜOÞèÖîïh͆…G*5õv; £û~3<áÓ}©ÞUš†CU™v[ξ-îuYo²¢Ï^H)SÛ©„º¡¿•_ù}Ô»¯gnÏ]ó/@ ¿‘^p„Tïr¥ÈÖæÉÀÎKß2Ô+ìÒø¶Ä-?ÃÜÙi›çgn+UÕÙ&K€_}HL†Ø#™Ic»“³ ÏûÇÝ‘ âN­8T•1Áï©;Œ÷¿&.RÚë`ŸæÄn(8<ìÔÊ:ôÿ8G”«%à£ÃÁÊôz½b’ÿ¢Ã󤀅˜:ÚÔÚtfGìy?Ò÷ééÒh Õˆ„mIOpûN¾¶åÌíѬÀÃcVNð´aŠÿÐc‰«_™™öÅ¢»ô6‡ËWk€4R”V+ê¤L Xã$Ãâfµ (Ó…ãæEg'_v¶€éè,b‹ÕB‚Gs@ 'ƒžú°@šW¥ºí¹Ô´»"õL]Îû1ÓŽYyG&ˆdú}ïĶ{§móE:™µÓ|J»˜r×wAT°»Ø Ì"Ò$BxËâÙÝ2Úmpœn›¦iLSݸf§n âḂ —F!ÈAO…0”Îh$í—™j4‹çN j,† š·Ê¤õ#{ôgùçH+ÚTo1 f¦žOg?6BHÆ7š+3ØYÅbH†_$ÃÔàþIœØWÒ·:êµ¢zÔ+(a?É‹Dû«&kÆ•MYeC½Â^ ·oäòrµøPeÆÞŠ+2›2.÷”5átî9·.R郀ëZ›û;Oió:â†0ðäv$OüOÔ”óuwæ¥oI“ÜuÔø| 7ji8rç‡^ðÛâSv÷µRðÄp—E ®‹U¨¨^–õãñšîI‡@ Çž !¸½©Ê´ýB,’éÿJðØwáÍû+Ò­/^f5Þ_1ñƒ˜™f«9½þn¶ô¡ Ô’H¦¶7r9\ð»T¶Êg'bð &Ó‡ È¥xì,9·O¢ööéƒ@?/úÓö,‚ñ%{€¡§°‡†Ò¹G«¯_v>SR¬GMÝ@7z,„t®í–QÀ%Qþȳï/í÷?ŸL~ÎoðÇyÜSÔ ðú0vö@þŠœÝ?Ý¿h»YP©–Œ÷HÂõÙÝÝ<+‘‚#&²£ÞŸïv½¡dgÉÙÓµ9v×-{ ¾C-¼mmg’jtÒ·nì8)ÌÞ¿p:oøoW_âr¸ ó›Kâ|»>©\%ÅŽt.HˆJMýXNŒ“õ:¥éAb; KК;P/ ŽèA`;(‚Í ……§l(8Üó-½Jß Á’±‰Aa÷¯MÇ0 ê.ö @ 9ÝÂ@ª·5UµÎÑnÔ«ª4 74W&¸,.ÖÛ¬×+Ï‹r‡z‡Q½JBqë/Ûêt2,ã’¥Q0´‘Ê%y(MB» .‹ &]ZJ÷-UÕµKšì;`š¤ÎÕ³€@ ÝžP:§¼uî Ñ¨Z—»?ñì.Ùýòøõ‹"žmÞfÂÂS—÷Ÿ|a\ Gzúüº…Gå­O ªÕÊ­é=jÊTuz‹y;ÜQÔÍZ¨¨þ³æ&PA ‚Aºž_߆æ€nõº5¶ãxzàB\{î#ôAº/„¯]£Ý/¹rÁŒ«_åøzÈ«§Æ®™ÅK8ýôÚõ^ü¶äôËé[‹”5í÷×h,zçÇÄ?:¤FÍÁÊô…áx;oÉÀSæ'1ð](„Ý#jR™µ<»9€B]c·»jü €þ0XÔŠêÌ6‰i·™µÔj¥<š·[Ó²¶Öbxt!…@ Ý÷¡ ß:­´MåhŒ†E <ï7'hÔP¯ÐÝå©*Ó3ë‹•&Ý[áÞí÷ü8Nìîû©'…ÙÀ¶yo­aˆK¢ðͽS‰>QßÅ¿ùî­_j êÖÖ¨aL$Ãÿ˸ùëHõ GýPqD©Ae¡s‰¥µ\¯/y#t<ƒÇâÓáܬV'GéViê±²yððï ãÉŽ «ÉjÉ–ÞOæ'Vª%ÓxÃNÔd»$ÔÒ×è¾F0¸©¢Ûs‚ýoÌôù!cÁ]{Wéù7ol¯Ò44›¿Óµ9àÁ§²“ƒÇl2ÿ“§’¿¾{bë½¶Év%ªÞ<¥¶KÈMšW2¶m{5uÂG¿”]Ü/H¯ÓÉÀܬV+ƒ gpçðGN &3jœ÷܈I+KöpÔæÛâÓàãÂÏÐã5Y{Ê/w87£Å>FxL(ÒË_Íøn:ox ;œ‰§ø8p„€%g=´e‘“o5ÞßUzÎUц@ >E!Í÷u+Cc¶Z~*»ÐŸéŸèó -OnÔÚ."MõeHXP—“Â[‡ª2Ú¤œ—(\&„€mãKi_Mö›’¸8â9Ù ÑËÁ ¶±ðÔ4IÑ‚Œo0nÈWq œ÷£5ŠÕ ì~¿8p{R£:%ÿ@S@Îl2!4jù4G ,Vô¸0 <è8Òå ëG°ûí*;o·¥Â¤]y{oós'@ž(º)„@õ*QµÝfY­mœ•¶ygÀú/Îä%¤ä8!¼nåD,þy¿¸õçHšW?¿&¹Û¾V™PÛhpÅ~™QìÈp:·å×KuùyÒJ>Í&±Ü©àŽ´bGéÙƒr4»g:<)ÌþjðüŠ'ˆ†ãVÈXNôtÞˆÙ{TfgÉõ‹áLíí—CÆþ.HS´Þad— ¾½ˆŒ§‡=Åy†,·ðæÎ¿;ÖÒ÷èæfõAì2‰á ÷>Î?È%»ÿ8lñâð‰À÷¼×ÊîK(8âû·÷f5–Ù­ØY­mpÉÆÑÁž¡«cþ5†ÕòˆrSU›uR£ŠŽ'- 6°© ¸7‘aB-fÔ~í4`v©8"Ð* óÉ{QSÉ8‚£ACéœ/‡,˜ÈDÆ:lÓÂÞòËÀ¿í¾Cb9ß³ KÅWEO%:.M®bç°E/ñGÿý¡†@ >H7!ê-ÒÉi8"ÓªF O™?/$Éì±OöSÙÅ<™ÀâfÝXpøš¤èEþ¨Ã£Wæ+*Uf®º®o]lÓŒ¢f7 ÊvTŒ‰§´,èQ°DwÕÑô€ š:ÓsÒŒ†#Ÿrƒº@^|ªÉžÂ1pä?“V¿šD«$Í IÌl(vdà@oTY¤—Éš5·ß;òßÁ4ŸÏ f7–é,¦–Ub?Ü+bóàù`8`¬YxŠÉj¶ÛaKªC½A9/}ëŽø·.ŽO9Ruã|ݱ^!iwú˜€ÕêöYÁѹÁcø4Ÿó)jŒèÃÎñ\ +pKÜ« g ¨Í—߬‚Ã`Ý äÉ ›B@õò$ÒJ§loó:¸Ýç˪¶Þ=~¼æ–m™1³½,.5wöÍ ÌOÜðÔ\»=Ÿ~zó¡­ÿÛÞÀGUzŸ%“IÂdOHHIØeQY, ˆPPЧÒgë§Ö¦í«~Zk]^¥HmûžÛ«Šq{}Åj.¯î¸&Z6‘]H1 IÈžLöL2™å™ ã8™,$13áü¾ÎÇÏÍ»œ¹Ìÿœ;çžc·›¬›¦ß,=,öô©:m–Åqi%k_ìa±ƒu…-U‘†˜À°Šv/j7YLýûŸ/½}}ò¢Vç<“»½»M͉¾$:ÐPÚê¸úE]þò]›îK_ûÅ÷·Ö¨=]ÔR-ª’‰#¢æDOœ–øBþ'o—~‘½ì÷‡V=ÞCñ •‰¼¦òUY¸aÌüëÇÌ¿ý’«DÕSãí÷E{GEâ+Èo§Þ˜µlóÞš¼õÅgÛŒâ¥M M¸,6åò‘“_?³çå‚Ïv.ýÝ‘•Ot·ß(½AäwÞ0ìõ3ß)9]y²ë|‘=Uí =ŒT$ª2ÿuê½gò>ˆ ŠÐô«™ “ñÇ{·„ô6Šo£¹UãÒ=/f¶uŠºQ€Z3;zÂûe½.³·æÔœÝóvbô¡÷O]÷zñW¿q"ù6ìnÓ±×–ÄO“²Ð9ìQ…©þÕÂ϶—>ÛV§SkSßýE¯¯Â5ÝjißZ˜½ÕÙÐ44 ("ÐÐuyñ-¡¶£©ÝÖyû¾-›¿ñýїΙxYìd‹ÝRÝÞ¸¿&ã±m‡Œ…¢.xõÎ=ﺤµ¶ÿ:0ìô3E=©ÉÒÿñD±ÌÔÿÛçëÌÍâÑ—%›ûVÈO«Žß=eÕîšÜ†ÞnðjD@ЃSoÐktOå}àñT¹©þ•¢ÏÅ£ëZvki[?æÙÒÞÜã âK@QkõSyÛUy^žm±´‹Êbÿv ôíé‡;ùn´>ôÑY?ŠÕ‡]Ð]•fbè¨×þòªQÓoßû´¯:ÇôAè jf?Øýą̈ä¬e›>éÚ¤gs’niÔê ­.%,aóÌ[>]ú°Me¿>ë'K}ý:Œ.˜ÏÉi<û½O6þëøÅ&.ßsÞ†%ñS».¹·&ïºì?)ãÿ%G}ºìቡ£ú½ß‚–Ê»ü÷ÎÊcfgŽÐÿ,eÅæ™ëujïÃA¼Zôù­{þ,RðE¿þþèKû¾#ëw?ùFñÞAÍ7¿zA…ÌÌ̼ åÀŸùËí£C¢Ó"’ÄÄ„Ðø€n>ôõÚ€+ãÒjÍÍÓ"Æ*sÄçøÇåGÓ“n¿Xa²aäò„b~¨.x …i4·Ýsð¯"EU)%,átSy~sÅýG^Ù¹ôw¡ž[þ¬ú„HAQugˆ›=qD7cõ…¨ n<¶m{ùáµfrx¢Éb.n­yêÔû‹âR¯Mœ=¸\­ROLnêl ¢:@nþ„×$Î|a^†ëÏºŽæ¿eW›ÇFšÎ[(2-bŒøìkˆm±´o9õ¡¨ŠùÕí¿ÿêÍÒ׉ªáÌÈq*ç˜*Ç÷ÆwÏ(m­Õi´óbS®ŽŸ.jNÛËí®ÊÕkuñÁ%­µ†€ Œ[4fD¬{aŒæf¥†wÃØË¶^þ‹GN¼ùÛ£ÿ{¦¥º¸µ6=<ɵX‡µó¥‚oœÙ«rŽ€(â*%4A좩ÓôVéþ¼Æ2­Z“9fEÂì0]ðžšSœuŒn1>4^I£V_—4OD‘û~›;ÛsƒWˆ—yðÚG³«N.Ýù»v›¥¶ÃÑÃxƒ¹õý²ƒ9 ¥bÝôȱ«GÏÙïq+M ÿWº¯¬µNãÜõêÄ9!ú÷Î~¹¯&/@#Ž^Ò1ãÕëÇ-_Ä£¥Ó¤Ó8Ž•]eÏm,{¯ô@cg›8\óc'-5sà——ÀÿùKzøÉþg»Ž Ôj騒÷a™É(>Ç—ÄM}îôÇÅm5*縵Ϝھaâ²µù:ù–˜s˸E"6VìÚ,jT®Õ8~qæ¼;³*O<žó®ûfEh}tÕÆ(o£)uS»Ýñû_s§©ÉÜæþl‡­óoÙÇê‹UÎ2·dŽº2>ýžCuÛáòØIo-þÍÁº¯•²¹¼ôõÎ]Wo5NכݦtÕÖÒÙîÈWQon]ºsãac‘kÎe1“Þ_ò€û2…-UWíØèzÉ¢ÎwmâÌw¿÷ÀŽŠãÏä}kÅ­…YGV>.ްritÓô›>®8º6ë?ÚÏÿ^«Q©šö/âáã÷|÷ü´ÕègÇ. Á‘M½1ÂÛó¡º'æÜ¦\#ý̼;B¢Üø´ò+%D@ÎIo—µ:åYZ{×ä•J…¬°¹ºòÛ=¥‰µ"Q· p6?QKÉä1Îb°V¿qúMWƧ‰i‘£Îþá“s,ê²J ®Lœ}ÃØËÅĵù_ \kÝ”¼`eâ,•³†Wñíýê4Ê¥× “¨Ë~ Ÿ:JÿΉ×D†>tlÛ×Í•Ïçòfñ¾·®¼/!8ª×ÀpÇå¯n½Y²÷“ò£bb}ò‚…q©C°G½/äïxäÄ›/úçÕñÓ~?k½Êq/GË‘º> õQÅá{mm·šœºöžÔÕ}߯Ýq7äÉVkÇ=ikž¼ô61Gð¯þϼdð9©ú›³muüêf›eìˆØ{ÓÖjT>¸£îÃ…õPsÒÙ@4P«[=znVÕ‰¾¯h³Û^Ìß±íÌî m`Óͯl-Ì>b,jèlú— Cϯk„V»ÍfゥH›¥CéoÓ«¾65q#vúhÎÛ§šÊ4jͯRW3Œ¼€•Ï'¦¨Þõ½‹‹Íjw¶ íæõ²Ùî×íÝÙ¯[ÿÖ€áÈ_j„ŸWž¼mïÓbBÔÀîK_kpvT¶§:wMöÊÛê»[+y„#¢ŠZ«oüìÑ-s7¸?¥7ˆjœMe¿cß–êöF•ó'4¯·$vUÚV£46 Òè²*O¬;wàoÒ®ïÚ¼ÅÃCœN­í´[ÿýÈßuÇýøâO½¶OÇ9T,^þ‰†’ýµ§¿ŸõHaK•˜9B«cˆ1hÏõÜöxÎ;J{N­Z o0{ÖÛL–ŽŸxAyÉ}¤V«õξxÌÖÎUŸ>²¿æ´£0è+†©žn®x¹0[<Þ/;Øi³Ü=e•ÈBQ©ÚUù•'^ÍŽž tþ²¯öt¹ÉèþÔÊÄÙWš&²ð±°´­N¤Ñ¯N ‰éKaDPM¢ÍÚñVéJÁÄ£ÒÔÐ뺩áIR–‹¬Êo®Èi<+ pÃØËŦõe¿š€ûÓ×%F¶[;·—>ÕX¦×èîš²jaljzĘ;':6+¶ùUC‰Øìꤹ b'¹¯~MÂ,‘ô¢ä"¹{øöЕØÚ¯R×$G‰uwT³Ømáº3nÄ_ð[Ž y999î³²³³32†¨g³¥ý¨±Èjÿæ~sƒ.xfä8ñ‰/ê4§šÎ†%Gn.4L K8b,ì°vÆE¸jfÇŠÎNR¦E&·ZÚ š+ÅôGç׎ë{§šÊ”^c&‡5B•cx‡ªÒÖ&`fÔ8l%ç§Ýûí9t´¾¨ýüÝ÷.3"Çu­Sв•·EJ<ëÏHDoA³£Ô¤1 ñ*GǧuùÎ9"Òbôa=‹ÝzÄx¦ÕbÒj´iáI®¾ßD2‹’+ÕÄÑ!Ñ—8oäG)§ÑÑûhZø˜h}h½¹åXýñç¨à(±GqE©ªÚÎ:¦µsc.Ñ;{U¶&V¬ioó:ï²ß?:¯Y‘É=ôž™™)Þ!¹¹¹=¼Š)S¦ˆ”÷RÏKÀwMù,Ÿ]?ýéO="/55µÛKvCöá嬣¹×ù̧«ÎuÔ먰šT•#mE_Gœ[¸9·ü\ñÄçzœsõ*££©ˆ2]bü¦™¥2§ÞXQ¯ªp›c/®-ô˜vîxxÖD+Œ%Þ^‚s#¶35]fªÌÆú\U½ûœcYª¬çcbp<œ/ª¶´Ê˾TƆ\Uƒûœêº³ÕnZT ÊÄÙº3®™…u_»oJs~~nݹƒyþðÚKj‹T ¹4 €O„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©„©øº¸ÈeffúºÐ‚ß¡ŒŒ _zAâ;”››ëë"@/ø 5‚ 5‚ 5‚ 5‚ 5‚ 5‚ 5‚ 5‚ 5‚ 5ºXÚ2eН‹à×ÔjuNNޝKᳩg}?›B 5:  gÓ àÒ(à/²³³}]à"qAgAAAe …ÔÔT9Ý5'K*O¹&€aªë{xpßÞ§Õ7èÃ3Ž „,úxŽ~Á`½ÏÝ·3|¿;riòòø>«üÙõÿÀ0%bÉý=ìTó^Ÿò:Ý+mö:ÓcŽûîú²‘¢Fy)^¯¹?\Ä<ÒqPÞó^·ÙóÌ®içJñîÎÓAžVý8ûñ„¥FYôãž'ª‰¸è¹Ä{*ºnÓc¦rry´ˆñIiU!$áõœñ˜éúþÛÃ*ÀpÔõÍìÑFºçUº;¼žAºÍ šPqi€AG¤F¤F¤FcøC±ƒ…³iàB )µZíë" ΦÁBbHqO0X8› ¿¤F¤F¤F¤æ½±Lff¦¯ †‹ »ø?/A˜‘‘áëRaØ£a7€áÂKæææúºTöhØ `¸à7B€ÔB€ÔB€ÔBÕÿŸ=ë\\IEND®B`‚gateway-1.4.5/doc/alligata/licences.png0000644000175000017500000001062307344776077016531 0ustar toljtolj‰PNG  IHDRâjñÔ©$tIMEÑ 1F‘AÌ pHYs  ÒÝ~ügAMA± üaPLTEÖÖÖÿÿÿ–––ˆˆˆýýýÃÃÃ,?$ŸIDATxÚ틚›¼EÏùûþ|ÚIÉ’lCL.›½¾v.ØÆ ’‘bBÈq»ÝþgùWúC`øUlœÿ÷«øÝg™E¹+þóòûõÏCq!Ü”âr*Æ£©ø×²¨¯ÈãQßK\ƒ Wzh/Ør¼»»jZ?t¤“PŠËíö#Z±<—úkëÈ#Åɾº¤=Õ†£ŽÝÖRWê ÒÚÃÓvG§¥»áYgACñ2™ ¸øß³{<óâ¶}†J§²9ºgÛŒØÿ5üpœ+^&mY¾ŠúyéÖïÅoÕ5¸+²®çQR\+ú°Í–ekQO‰ò(/¶žµæ²•ÜKUo]mk»õ¨~fG· ¡êó}†ô£äë|±ââÊê!x(~ž«ÁNŽË‘­OûÅ ^kЇj¤”ª-©º$¶Ýõ<µå¶©zR_ Z´Ç[}7†¾ÝÉWñ¯á»cýº8W¼õÛ\fæð½bsä_DLK¢[Qûe[ÖïÚºl·™¬`¨K®X÷v™+:G·Ö©çº^»ç*v‚²a©‡¢}®»u|'"fËÇhù íµ°Ùž¥ØUÛ?:«x¤ÝyŠËm}·«§¸˜³7Š]µ«G\=zøêúµâü*®[qCªž/ÆKúõˆâ¸Ý¹õß×Äwœb‰n'ÖIFßµèó7cþ†D̳¢è[O)õ^EÜó¤›ÑƒÖõ³ku«cû`û¶ÔF0Jþ褔ìèíN¿ÝÚè¼»5w!9“¯â­ÞÎ.ò¶‰z¡¯˜|NñƒAÅðP1DŸ¬;Å?õØwòŠlˆ3ŽLÌÒßtžâ*ÞÙé2?„ÀY\–ò`¯¤†èQ=p[¯üºÚÙ{¹…êV–ê“v›ŠÇÖŒx‹ãéÙ&òª{¤ã]•àw*~/jžþ\ÅdT ÃCÅðP1¸Tm-:ެïpŠâ±U!>ZqÙ¯•G¯ã ¥vuC½M¡‰÷'Kß;¨8Îh_õü»ž²/ëiS‡æÖ1¹Qàn²*ć*¶kHuÎW7'YJC±ªÓ½Åz(^®®G)výÔ[Š?¢jh|ôuþ\\×)¥ZâCûÁLÄo9¤Ø ZSq³­`ð¥n%nwºbû{úšäµ >Ç›_YKy¢ØM•»&êÃë;ÄZ{wÔ£ŠÏÍ9S±±ÒZÙAOéf üíÖº—ý¹èŸó¶JÕV•ÝðØ(Ø×+n¿.6×çk úÙ[â³u÷Ý­¹} ž7/Á‡^ÅçuîzŠß ߣ†‡Šá¡bx¨*†‡Šá¡bx¨*†‡Šá¡bx¨*†‡Šá¡bxNɆØO¿NÜî½ý.NɆ؉?h´JÅû9%b”:ê2 ¦ø6èuá»ky´¯­Íq玺› 1 *oãê×’¥{=êŸNH²“u¼6D%tÝW¯üMÔñi€Dÿuq/â8Ó׆ÐÛël1¢ƒÕ,ÿ‚ïnÍ€‘W¹#­õê{5Ê[·8c®¸&|*†‡Šá¡bx¨*†‡Šá¡bx¨*†‡Šá¡bx¨*†‡ŠáiöL ¬•älÎóí8ƒ±[ÇÃ]òÔ ‹1ÒˆÐ8ƒ¯RLŽpDq–_pð±}sµ³¦ƒß7Ít¨[wnL<ýçâ{ìb*B*[°z¾ÚÂf¬Ú7i1͆ó :Ýœ¦m|`¹^Â_‰~µx_íµX+.ªÎ%¯AŽß‚3Gqõhoµ…:·"®¹$¿ ¯àœƒŠ›uwµ…’L°£Š%ýJÕžŠ[yEeL,9~µ…-ßÁî;ÒbÚ:oºàÞÝúÒnŸœbRCÅðP1V1™ÃCÅðP1g­Š¡8ê2¦¸ÔŠÝpíPîUJð-Qìû3ÞJG±ýÝ]õïdg¨ü»ND­ØþH‹ž’%*é*îµ24Qõ¿_uW±YÙÁݺ¤k4,Û(}ñ:6É4xίë÷Šƒ›œä¶ÇN§ÒkÅäY˜ŒÖoZ«‚ïnÌû‡‘Šá¡bx¨*†‡Šá¡bx¨*†‡Šá¡bx¨*†‡Šá¡bx¨*†ç¥Ù9ýzep»Wôö»xi¨|މ°“|‹}íSñ?Ÿó#¯S\ÇsFûòGê¿2ëU\nwd4âyNX¢»áó®@­øG³!fà" •N¤Ú j-걬·ºü3B__Çö\\–‹x,b.:T> ˜_Ê› 4r7¤:Q®B¥øÇ+6ƒõñŠ“ÞRñïuy\ÄcÙ3¨èO­ aê·Óûºée°Š¼â4âyNX"èm•­Pt]—@¿..÷‹øû׆h·rá‰úOùy±â{›ß±ýµæiûî–˜w·nƒTñ»O>2ä=jÄ?ÅÿþþhäZ÷#Wä~i`¨*†‡Šá¡bx¨*†‡Šá¡bx¨*†‡Šá¡bx¨*†‡Šá ?õççw3DŠŸèÏa¦ƒ¹Š®;‰™¨ø#¡bx¨ž—*–þ˪íq*ž„r ÁO-v+–º©x:‘bs¼W±TþmFÔnKaZ=9FK±üþpÿblÜ9¬ø¡RäþíVKª'ÇËÍZp¿ŠoT*>‹¶bíu¢âûmW¥x+Lª'LjËö´¸˜xŒ¿¹%~z¢¾ÕWñŠOÀ+–å«¿tí ¾£–η¤zrŒ¶b™9Qo¯‹å÷Fn­˜wÔ§ÒP¼ÞQßæÜQ'ÑqÐf*þì¼é¡âï å óŽ2üK<§+~âÓaÞ=6 Ìt(~öcŸÈóÌt@+ðP1ÇJBqâ”lIaŠ#BSGÑÔ˜jG5oƒ`àAAŒ1wäÚ×ÂB‚#²ðËKÿ³Vnâ'ÈóÜh—ke&ÇFµ–3´µ´¨ioÅ6R:–ê›Ê޵1ÑÓ-Y£.šØÈkÁ°;udzé¹ý5« ö>{ïïýÀ—Fs[‚Ú¸)D%X™À™‹nï‡îsîØ>6"ÊZ ‰«–¯yvŽ»i.Jï>Mmb÷¦é,"¯@HŸ=ºL>_}x&[øé£×W^'|zvyuó,ÝìE>½Îl¾Z¼°¹ùL',®!+²§g¯¯nâK”*Þ0õ/ÁHû°½D¦ù²÷È4—:>é¶#*ÂÙ¥VI“PŽЈ*äéLš)}“º„ þ^h_U«!=<>ÕÎΪËh1¨ñkÙÁe Í™ÞRŒo-Öü>Åkìmjõ±Èš“*‚P^ÔIÅbµ""£ª’å˜e¿+¬‚¯ ‘@˜”Kù™hbjÉer¢¹ýZú1†òÊWÌX[­exZyl÷Å! ºm<]¡¨¨­Åxd"X…‹I!»RŽå5¬d#2m!›5iô<[•¥%ܘ ÉÐo88éÊÃ*jKsXñ± QRâEHŸYønF-£q5΢¤Ùm[H$#ùÚ¸¨Ì0\XTYùúöZ'ZÞcãs%”©ÝaÁAØ.Be"8H$˜Ä\*ÍÇYê{ÿ†û7wö¼%UÙŽºøÚÒ …&^Ý¥’]'·ÑÂÎ2KpüAw·Ú„µT˖ʶqK™Ut«ªWU¬î€R:£‘©XÈi(‡çóËݵ‹ Ú7Y]v-¯hª\´ o~)þ£ruIu̲B‚ãd-1Âa3ËÆªTzù18iåä³n ×jnƒ]X±îUt ˜B•‹ÿ,ÞzŠš~ ¡òCï=ºÑ±í ìg lĸӉ;­<×<é®aŠlÀÎn—º0æe[&ÄÎ}ßâaïâ+qñð—Ü6+ jLº“:âÙ—û¾Ùà@ˆ,F‘ âZø©& –Vw“$´BGÕB\N°˜I´ ö°¦å!½£Ç‘!¥‡$T~p2yCÛ{uóB:•q¾ü^Ke˜”o ›2Ûœ¾7Dø{À –òV>ƒûĹÒòéœöÕ‡gOÏRþk-·Òæà¼‹œ$—vÛ”ÇdÆ%áèR æiC\›YŒ$ª|Õ…Oß›‘ÈZR•/0sÅ|} 9†ºW?0„6BüMùÙ¡nˆ§æl§:=q›ÉÏúÞö¡¥Â½eyÜÌ¥ Ë/<ì ‘3¤­è5©è(ïg)Šq&†1EÓ Ø›ßR™Ò7VÐOX$”J ƦÖGRÀÒmW(íU_å%Z☕³èØê|C¹ŠF:ÃpÜ47`d] mm¿µytò­ûHÂIJ‚õà¼É3<öÑ.Zd¿Wï’ÝŒ§dƒ›Dt±år¦»€š ïÌëÒ²ÌhF.ósáò»ò—°‡eùÇ"ÊYv#«t^iºpé-Þ"Øê‰6ª=ïÜn*Ö€º€v¿˜½ÎìR6=y0aÏ¢}c*5DSm£>UýÑ «¿ï*ׇ…§d5sz|ècQ¼6hÓø¥*øÀaX8A‡!\Lñå‡g_Ï|‡d—«h9ùy0¦ŽÃBh=GÁe3¤³+õ†¢’½öæOþÝâè 1‹ÐSÅœ¬BÏyZ?r’G›ÇÔ…­Š®4ª2 ùŒðé{3B_–2‡À •GæŠæòWÌW8ÿùÀP='«jVe<§Ã€Ì¤HøòÏRñ¬GáUH¹dwûhþéÓ„ͼÙ&kUb6ÉøÈIÝé¤wúè!¢mÂßV9°Z+FÙS ‡Û-ì–ê©"8öƒõ);#+]äjvÝÖ…}ô 9ÆÑs\yTC7É–욟¡&±Û¸2{ÝÅóÁrÅæBûêê¦ô±Oóƒše¶±áùüü%O©õhþéÓæmÜ%þ.·ÐÑåùàõr±ZðM@F©Ð%]Ø-öKpa>dÏu'³“™ùÜÚFÖ‘&ö/…]§eE¤r1¥ò1X-ûÖ“dCÏØµGù“ Ç—ãÿ:Qa›­èãÃ…| ¿ÒÍ1>>*ŠØ÷ (F(Ÿ^©’Á!|䨲vË­he›É5öãµ9ɯà[Ë~©´f žqæ˜8R[ºÍHiç&ikf²Öù`ì‹ÚQú‡ÎTtaÕ0%£0ƒky®¹e™à»hÎÃCÍ@'aNé—IO唌L‚¶åúÁÄ"U|¤hUªÉb%±hs†¼óm-#à¨Ùm‰šÇ}ÉfÜé’µ±£–:R˜ Îå”…]™Np÷JòkÖBØYÕAF?ïW˜Q–(•`ZøÖŠC>XGÝì܃ZÇ·C”úÁÖ—1ì-ð:é…„{>FîŸæòÁ÷ž;;™™ßU*Áe§òÁÇîZ=Lk?A:°»#”ibf¡¢K ¯¼êI¶¿—`É#j†*•Nrˆw‡R)Uo5®àØø|°a²Ï0à®`hiêT¿qǰ„Cq×°|«é€.QÊbõ l\e§èô0 ™C2Ë ÛWu§ù`óóm…§ró¢ã%¼Û½»–tüb¤]½Àl§ùà>¥å3Ÿ6º´ÜŠv(±Pñ ,óÁùìo·ùàþ¡àµÚuÜ›ò@Å÷úÄ7ð28ù௠™õË`˜“Å@ˆó(²’çƒ$løÆóÈö‹RÁrJÇPùà¼Æ9}1ÒÃÉç¬ÊSŽ6ü ¢“2t¦Í‹EëHÞ‹0 ¥»@+#‹H?ºÎt ƒÊ÷ 9Mª¤jŠMoUC8€Æ¶œCVK_<|l-2¯õ}ðýTlaîˆN£¦Kú´‚ß`à“h±²~0‹7)ߤGŠD´„Ö™R‘l éa¼ÅBv+«b ¦„‚º”‰V{+zÚÃ…50 NúʳG—OqZV*%lŽ)Çn‘}Ï‚ÆdÀ¡6eõ.†p(@‡EK%¥Í*+Š«V›¥VEeM2,Xd“ `ý&;6ŽÁŽFOIxÊ™¬†ÉF/ËÂìÖ‚PŸà a£«ä UkËØ…ŸT%Á#ª|¥:ÖV!…»fÐÔƒB)ñÜR›ìv(N¹±˜]S1鎢!w"ªÍ×iê<}%Ö%ñ{Äô5üŠì;·ÅŠK'tdÅAÁlä CZj½Ò½çäÃaÊ.Íý¦ö:ëD&DŠ[¿Š-±1CaM0é©Êßì.f99®BEcÍF”qõv;ýÆHQUŸô`u¼ö¾ùýåÅÃ_ ŸÂ°B”ÞJ€Ì3Z¹¨Š(u3È«e}rqèìÄŠ1—¹ÁÆÏd$.4MÛ­è6êÒaiõ‹*•>ó<:Å®;fK 6e“$ÖÁzõi%_'Ì‹†–…(n~à‡ ˆ”ìRDnâN,Oª~Âß½çŽÝ1Ý`â; Ó«_în’´*c%Û›Á²ÎaÝS,ikÀ® g_ŒÜ ›T¦SW«”`"æB{ç~ÈÃä†CûÙ¹j]Óô×ÒåÈpZv¹*ê3õäavW~‹Ü¸—Y­Í!ØeÀ+Èn-v‰%ÁDrì{Aƒ±X‘—[ÇÞÜÙÛ œ\,Ix.’]”] ¶þ`oK0_@ŠAŽ^ÿuï £ ©jæ ˆîÈôp°dÓòCójØ,l‚ ( +NåDW·{é#iëĉ²Â‹Åÿ„ZJU‘Z;_QHˆŒ´$² µ –á'B³:{r|Ž]0æGh÷»aêO9"l=1ü+T©+ÐáÚJ0ÔÌó<ªŸµ¿ÆExDX÷H-~ÅëM;”à+KQ‡%~uº‚6ˆHÅ&Û$i1ùÛkÃ%Çàž€@K‚l\\\L¿vU—¶ uò×¾äOÞ T ¢€N„¥"ãi ¥Ä«›CÆÜé‰ëŽaóäÈŽéÙR(F+ù“lAå¡¡_8&‚ëÅõrµüëŸÿ:™Ø#Íø¦•ø†!°‹Œ7àò¡ŠØC)W†%èçÉãÞ?lÀÇ$6Ò1Pÿ³}AJ€wøäñ“—/ï*‡Ñøö7Û[’€fÜiA¨,¶ŽüÖ¶”(£CGáüú_×Wß]=ÿïçI¿oƒ·ÇÁ/V«Õz½†Dä 0É8~ÞHbTB }ºõ+ÔÆØk ¿¼]¬n=ï;,Ù½ßåhÔ9€—åíÍYÏ áQìâE’Mõdsé ˆÏºrV° xýiŠ3.ÿv9{8›ÿ8o_ÉæcTkíKFá¯÷ø–õÛÎF¦¥Ó8.ƒ¬S5Kšá3ôêv^(Äÿ„à¡Kš`i]"sâ~ƒµˆã†Rë&Î|–R.uuBê–c©Àåhí`úí¯oçóyûAª9Á@ÔCê%<¥©$b•„;”Ž_ô¡,¬DSâ‘›£y+Ü5¸ k°Ö¢5dü' à  hÆŸ¤c Ö[IÁ‰ÿ†øwu»‚Vœ´‰›áx ¿²‡ÛŠæ«éÃP Àü ÇV Ä²)„ä†:ÊQœTcËå’V¨¿¨JÜ¢ø”¿™¢DGºÑÐzýäOÆm-͆¯Rj1*¹‰ÆHë†z½#”H¾‘6§0h…/ë!#PÃSâøn¸¦šåq8á53„éë«z#Cè!ÏEú7³ØÀŒAS¹‡¼Q*màmA%ÀHܲ†-Æ`4 ×Ôq;¥šˆd‘ËÉ¡ŠKSNÇbˆ*¨b—ŒpÜÅ9E˜ÿb““ñxã×ÿÀл bŸubCî0²C4³T¹È.Q†û|x‹ –7k?¯Ô’ÔÞÂýÂ%ßLú‘F>ì![Po‹ßWóÃÊÅ Íh®¢ƒ“JhÅÆ¡÷…˜Q‚N tŒá/¨/÷Þ˜‚‹Íiz¨èÚ²Ì&®÷Ûê û‚z79z®å´Ð}BÔóÝÛw mÂŒ tƒ¯s¿=Ÿ<8ƒ[!!*ø n.r Ü) "± üŸ½¦b:ƒ–3¤ÕÂ¥·ÆN3jUǦ‹®F4PN˜WÜýãìüǧc¬&UÓïñ5âÂÊØ¬‰0ǸÏåFi=Ò{îÍ¿ƒåb³EP¿áýü_?ŸÍç‡/ÁÐgßÏæçó¿¿ù;¡›äâ¢ly³ÑØ¥hšÀDï1âŠÁˆºJ“qt¨ð†¡e¾@[€Æ'®üö&ðÞË!Œ¤}ö»¹ŠçT4J\Ì„Ë×ôö§d#rb|GhlTPqÖ0l¸ô0»¬fè kóÉã'àãOOÆ{dÎ@ÀôÓÇß^¿Uá< xÄéíõÂ[lCxŽP²# …梻ˆŠ F+wÊ\ Êg½ñw_ÖFµpŽÎýqûU_ —‡{ƒ*‚¥'5ŒxŸC°Z\“m¯Ó¬4™-;¯æ :LŽ:.sŸ<:õêÕéƒS´KPÏÙlöòÕ˫˫è¡ è[”ZÎ0= •0„·¡ø61ØŽÿP¼`gè£nb“Š6!Dx›ÀúôÁtìéd2ûþüê—”»Œ†röMª›6E‡ëuŒ0È1ÂþÓÅÅOONÏÎ|;=|å¬\ÕŸ/~ž}7»üÇÕ»¾WžmH \ü`ÄYËN¿:EEñ’öQ¡.®ÂÚ`vÿZ¸}S4WÑ Uæó³w¿¾]ò8èèw2dÁãˆëOŠ"BËÍa¼ýiþdþd|2µ\ìJ¸®{zzúÒeóó3°¹Þþú–Á°CÎ(†0AooâØ­.1»á-t8Og3Бí#Y-ftˆøÆåÿ]¾~ý‹ïÒèUS-õ%a6Úä!Ö2Ý’zþÃôÛÙ£3ìäGHm¶ADÖtõûï¯ÿ}íÝ®À÷“÷¥ã‘X[NúÇ”e™¢‘@K?y<ù?¯æ?œï•`¢ò oÞ¼yýúµÌeâF§à0'á´<˜¯§ß‚È¢­qøiÁ:À$›ï/o—«å gñû#\Z@^µR¢á´†¦ç?Îÿò§¿@×ï$óßvN–L™]___þíR%—¤î§…â ¡ë‚F])²jFÀ±Km¤4‹h|óþø††Zûk’YÝF‹NOÆàõù‹ççgçÈný¾‹Iwâf<Ùmi°5¤¼¯3©€rú%²æÆƒ«hŸHÂ͇`=É ÉÞ-ƒ£ÕùÙìáL¶RW×ïlV¥ŒHÓRA¡¡‰SŒî‹‰F÷\ie|Ðçå|D®W·+©·Aj§ßb×Dz¡ºÕj;˜6›Ì°”&ÝéElUmæØ•ê‡4/zÀPóÅXŽ Á=Ç@pÏ1Üs ÷Á=Ç@pÏ1Üsü?³ÊG÷IEND®B`‚gateway-1.4.5/doc/alligata/12-8.png0000644000175000017500000001252107344776077015332 0ustar toljtolj‰PNG  IHDR ›jtIMEÑ )¯‚gn pHYsÓÓŽ{¸®gAMA± üaàIDATxÚí]½—Û8’îù=ʨÈÞHêhæxÕ¶wc”ˆÁ¥”D„Á‡â~QØÀŸÑGÕùð“ÂNý›Q¶N+ÚwÕUpçðrr‘)ž 1¸g%¹>gM°Ü/¹Ï$Ÿ:5 3q°:Öí¬ž£¿C´8‚ÜWÆF IÅ O¯k 7­&¢[eTÞS¸“Ö@{›U©¥Gˆ\KU‰¹µ„åòžy–) ÌUôO"Y\çIXîÎ)%w `Ó¼HTso»q‚{ͱ!~„{ÙYÇ¡ò€ÏäÁ¤¯lîB0Ç?óÅ/‚±,ŽQÚÄJhºBž”¨e›Š´6%U›9jªÐB^õϺ-¥».DUð7v廤ºN¥šéBmPYËV4‘8flÆ÷Ç;S¾%Á9IÒ$Y&œ/“T`¦F™,°L¥œR¶Až£Â ò"lj´=VÔjÅÝ+ ¬ZR¥— µWxÞÎ(|Tõ#ß§§ÓSõm³¹ÁÉÇä hý˜€ø¢‚•;Ñâp³¸Y§ú¸®”†K®­…¾7ti 0èÖåo„š4ܶ6ÞÜt5Pk=Èv¯lº˜Ñq<Ž§ÛŠ²¯‘ì.®ËOK!xf2­Ù-Š*RæÐ·uÐia {¦RËû3[re'zd6¶n;г‘µÈ\ ÅRcºB"]½t‚<„cñ(öÏ…K‚yFb†w]$‹«Wé§­ÜÂOP×G•Þ®RËLUŽjmfhmiQ×Ñ–}.lèXjïj:×ÇD·áßؽu¤ï`wgÓsÿ{¶«èäSònñ.å©2šX¤Ù’Ôšª™`Mç,º.­=ݱ}ìD^¶ W­šór\˜›Þ-cÝ£EB‘³x2ŠOÎtm·)­ ròAvºBxúžJp#¹³àµt3ZúWér½4ªKÛÛ Ê² ¶FfÉV‘f½.YßÂ.E5õv<ÍK-ƒ˜´(ÙäÚU$ƒÒ«Â©à„kIkC Áišb¿»Ræ¢òî7©-ìÞM:ëÈ«RRîÞŠæ’5ž²™dÓßÏ^¾Züɧ˜M˜I“yªßœ|ÿõËW?oÜHîùƒÚ.7”‘µ±¾E©úÊed–KIŸtŽ-óŒ#»Fj%‘´åÈÌB•΢š6 Y‘°:æ´c<¢@?›`Ë´6,C^¥„Œ¯-Öê1Í«ñ6­üøGd]ƒIÅ9ÏÔM£XŒ¦VFdtVœÌ1+¶`•¶×µc¼Þi]R\X=¡µ§©vjîM—×ޮȞJÊ:Óª±©<ÖÇLˆ®+ÏV(:jëѹÖáâzv•«{xÉNª¬;š‚û„­/ÈkÝÙz¹ûî59¤• Å&»dª{nÒg¾›s¸PEM•Õ²Ke+ëU—¶vœµ'xv·½§¶[nýAu,“Ø vÂ~*—óB‚‰áRkfgÙÞûwÔ‚C n{UïhÓÛJmÅÐɉå4²Š&b÷»kiíÙªU¶þòáo3wÉÛ~Ð!Bç4²rÝK9Í”ãðl~Ñ%«>ݤÿ ½Z+M"ÛýŽ•Áë_ŸËÿ¨\cÒ³l‘`3XK6 áN°õjíN[|ÝØSE»/uìlÊÛ!ê\ü{±HÐRôôUE|¸=õÐ ´ýlØI<ÄÓÖkÝŽ‡È޶üUý]²÷~ל¿¡ g\•m5¨ öhBïýúZû€—øm1m¶ÐC–ëÃD âçC„‹`eaUå”rìâ;äí7,'G+¨­¶‰Žì¹W$«‘àŒdÚ.&oØ›áï<g6y¢êoÛÔöwq:!¯™ â9˜Ù,Áà> #¿v,ôN^N«\”£2yîŠpt#ÁbÓoâ¶$gj£éÛ>Çâ’ÖjÏ$uÒ_:³z»Úü—t\â(KSNZ¹iCæ#k÷š¯ÎlU,ì9z6VÍ8Zuu), ÷z†0wdôI–÷iÛâ´æd T i/zÝFV¥§-Ç®n{¤ÌÝÇõŠ cÓ Gï¥è-AXG£cÓj#Àò !î·ðÃmÖèØöñ†f&t‰aƒ}ûÕu|¸%ÜxN~÷Žd —B8vvK¦Ãm`_UÔ‹Ö´Í/ZL1Giýà©3"º ®ÙæÛ¶gÞgžÅ¹Ýœä^ÃyÃ…WÉÕ"Yð×O´QëygëÑ•Áàp«¨bʦO&¬åY´f Öó­‹M{+°{ðð”¼ú`Aï&~µ78»]*¿‘à¡ éààxq‚ ‡Š u.Œd7¬œÝÁS¿5„¡ -‡Ù9 Xt ÁAA;|Uô€&A ]æd)Ô?h4÷£vb¥ÇuÁÈ:T»Û®þ.„®ùà÷ªž6‚<ìPåQÂï5ÁM:à@í®7Ï‹–olºø ÐàïŠn±h•FáãF°¢(yy{0Ëñdƒüƒ GŽæ'‚á|héCÝ*:p|¸Pá·šHÎÇGeû.H@=2õôJ› #ëÈÑ6 äœÑPïØßx¥uÀk}×¥^ü$Øzgf°ª AE[ì÷f—€~Ñe¶ÅÖTôqaK‚ÃÌcƒ›à ŸÁŠ>6øKpÞ½¢÷ñ`Z»ê FÖÐè{S‚ƒÐ?šŸ.ô[X+àŽP«¢;Mº A«ƒA“&e]T´\ò*P|0¨ôÁžïüÝ:’%,­»C£”êU[8vŽ&9LóàßtM×qá3Öñ ‡ú¦Œ¯= ‘ÅöNØedÕ^žy¼e< gTfOšWxw냩£ùޱ)ÄfqÒv4[Ñ%ž˜è µËjûw“Í}05«@k³ê°°ñþßf8¬hB\ÕÄÁĺc4 VäìC ZüàjêYËmî >ü: MÃtÊF'#‹(?:XËŠ|ió¨bçâ”tó5³òMþ7‹T¾8šï»Ì¿”–õ=ùjª¹¥^F–‹`1øã+ŽO¢e}2ã †µ¼ì!C»I—Ù6« ºüiy©†€CBW+šJC<êþÑ$ZÝ­è µ‡ ?jŽ9…>XØmEöG¿@ôm£ºjǶï•W)¼®\U^gÁ Á ׂZzgØëJu_bS¤¼h¹ç>¬gý†{…-ܵ+‹UÛÁÓ/ÿßo}®<`±söÁŽFOIºÙfM"—Õ úyW‹;Ù‹_ËOÙ;5"Zb·xŠm<¢ÚW ÖÖN¨Êe …J&e§»OÍîõgF§ÜxÌ®il hHSµ* F2Q¢-(ª§$¬8@Qm=Dª“‹E¯TU×Ä?~ô_©ƒÔ¼8h{ãû(fŠNj¢WmÉJ×™R3營‹öw>1µ]®íPªÿ$…ÅBeê'ÊY°ÛŠ’ì*€øzNŽkQј¹eB¯nGÌKlk[«”Ýù{¨yI}u o½¨2JÛî¨#J=elÝãÇ Áð‡dËèSŒ]g/VôˆÅ,æ«Ô^h¶µÀ·…~ïÛcjÍI)¶”ÔÂ7ì´÷3Içckg­ÔªIvã1›xJpãâ”–|yóñF-',ì#À‰úê‡þNd;¾ R±Kc¹I<ñ¼è^ëñýxéŠðU†kæ öö¼%{v.kØ¿<óœm{‰'m;°+©ÅÙ£xÂ& Áþ—¶K0‘s¡ž¤<ÍÌÛ…±b•­9Öï5ÝüÙ˜£ê %N›n×F})Ÿö›’µ™Õœ¼³ÀuD´¶9$» xÙÕìæÖiîB;æ‰MÑã4átÆòýˆê]áGý.Zq`Æ}Tž!+‡ô™be¨ÝÞnð’`à˜)9æbׯuBI66²Y1\Š)ɶ?¢†ï¤×¥â8 6vφ?Á |Åyƹà$ϲ–K±Õí^ÚDï(꺰Eò²ð™`±ü_PK‰¦*—;ÍOE'!¤#‘MØš`… >9šÕå‹M·±~„IŸ!ê^4çT[ÉÆÊ¸5ÍbK3K´ÅÝLµÖO0ûXéq­"X‘d\ÛI½%æ<±#Á·‚\¶›éG”ªÈ5…l°8ˆð;+ÑCI€!e:bž³ýîí~p+²UÆ?ñ4Ma8ŽÁ˜¡Ý4ŽÂÔŸfäX{ cø-Ui,ÑãºJ0ä,I‘éÏ2]b‚2<"­{¦2½úˆ0ü‰ñm¢»F<¤ä^ù-h V'¢›ª“¢ÆÔO¬¯•Pƒ{B5 •óôéÓéÓ¾òÒM‚syJ—©âO²‹3¹rN8IáCŠ-ËñŒXa+)‰/ ÛÓßMuC>|² =k eo¥>Å”QÇ T9Z«pçürqyusõ׿üu2ñ Fºq¯£ø»È aP€ôc YÄJ…6,¥~.”•&|H"+øN?¥Ü<')@‹>yüäùsßµ}‹oŠ $͸7·‚Pe¬ùµm›kQF!††"Äåÿ]¾zôêÙŸí¾ :H0ˆï‡‹'À/æ777Ëå61Jx$ý¼‘ Äè5­™#Ë‘ˆÔÌ/, hø«ëÅÍu’<”ã}öF½x¹º¾B³CåsEDn\¼\±™éå«´›(Ô¶­œu, ^~\fòŠ‹¿_̾œÍ¿wÏäîcTk™*Fá;ùw|«üZ™6r¬ã2È:¥#mlãQØF5ŽI?¢@ D“ƒ&XY—Èœ,/ÏPQË8n¦´ná\À¶’r¥« R×+®zëˆÓo~z3ŸÏ»wR» @>”^ÉÓšJÁ(¨"Ü¡•°YèCOÖ´Ô¸Rk*A¾:šU¹ Ôà>€®ÁJXÊÚPñŸ<ËVx‚¤C~º“6l×’Fd¾3ùßõ ÔêäaמxW‚sì/áOµP.±Îh5ë¹ýe²ŸÖ%ñˆ«ª’›h(GpŽP]]]1ÐA²ÃÊì…ªdåVµ0u›•†ÖëÇt2žtâ ^•ÔbTreŒÆÜj†v¾s”H±R6§ì0h%ëž’(³%µ,à ¯¹!MßTçKyÄ 9|‹»Y„G7ŵǪF¨´ƒº•=qÇvèƒÑ€\Ò(î´j"ŠE¡&d:.MË {G£˜Œ°ßÅ9E8þÅ&ÇãUÂ/ÿ›C×»âÆßg½Ø· èY¤! šY©\dW€(C9¿<çÀ"¨åÕ2ÍÁ«µ¤´·4B? Å7SÎEn‘dÈÔÛâ×›ù·YëË ÝØ]Eó •Ð82ÆaòYðÌ(I':Æð ê+¾?¦ ÄŒ9c¬ÏW-`6‰“_n.!±Ï¨pWD åzN Ý'd>ß¾y Ò&ÍJQJã/Î''gPdb¢‚ops‘cØ PR DbÅÓŸ½¦ÒidP3p…²Z„²à–ØhFò¸+Á²é TA£“效7;ÿöû1f“êé÷¸Œ¸´2VK"Í1‘ µSYô~üþ_üj±ÀÙ"¨ß°`?üþ‡³ùüð%šàì«Ùü|þ×ÿ#t“b|é›äÉl4Ž)š&ÐÑûŒÄ²3¢±Öd*,0ÔÌg¨ °ÂÄ$Žù/¯yòNuaDú ÝG¿wWÑàüŠF‰3LÄbI¯ß J–Ø#ó ã;Rc£‚2£†Eg#”‡€£Ëz†¾´6Ÿ<~>þôáxÌyBÝ?}üæòçÁ#A¯/ÉÂÄv¤› kIê$Ph1º‹¨Ø ·Š§,¦ ìpÖ›xûyIP±aT çè<wûÍŽÃí1 x?Ka©Œß,.ɺÕY¬ÆÆ ‘j¼–/1ÕëÄ,~òõù‹/NONÑ.=@>g³ÙóÏ_]¼Z€Z¾E©‚ƒéQ<°°V4ƒÒÃ~üÇAñ ûq\º~=ƒ¬B¤· ¬OO¦û“àˆL'“ÙWç¯þyAEÌh¦fÑ"»›Æ¡ ã;p£Ï‘9FØ¿{úô»'§gg'_L_9ÛWõ‡§?ÌÍ.þùêíÿ¾Wž­—.> fbyÒé×—è(^Q?:Ô%tX[ ÌœB w¯ŠÝU4h•ùüìíOo–úÚ YS“ïê ‘a "µÜúÛïæOæOÆÇ ö‹]…8ŽOOOŸÇl~~6×›ŸÞˆÏ`ÈÅ&è핉ÝÚ2` ÙåB†·Ðá<Í@Gvdu˜Ñ!ãÿsñòåßÒ”+£WOµ´_ ³²&÷H±VÃM ©çßÌA¿}}B€ü©-Wˆõ]ýîçw—ÿºL®o¸#Eg<’ï–Sþ1eå@¦¬$ÐÒOÏŸÿç‹ù7ç{%˜èñ†×¯_¿|ùReâΨæ4bá´<¿™¯§NAdÑÖ8üaÁmFqš¦W×W7W7P9‹_á²òº– gU0=ÿvþ㟄¦ßËÈ×9YjÈìòòòâïzpIé^3-»X0ã400 ì*‘Õ3Ž]j› ¤YF£€à÷ïÞßPQËtIJo·±¢Ó“ñx}ö§gçgç} ‡÷1éN&‘P͘[CÉ+ð:“˜Jh÷`X"ë®Ù¹Êúù€$¼ÿù=°^Œ ©Ö5ƒ½ÕùÙìË™ª¥¾îßÛ¬J‘¦•‚B?Ggf<ó3îÇÊÊø-ž—ó¹¾¹¾Qz¤vú6ýñx¬*ª_­v Óf‹– aÒ åP«jÝ1WªwÒ¼è€[ÀÖ+€ÁG xàà#ªú õîyóóùý9ÈzÓj6 Øÿä¯ÖO>ˆ/*Xžˆ‡žÅ|›Êã²QjN©9·òÚ0¤Â ï¿jiÜpkl¼ èéL[ Òzàý^ØtžK§Þ|>7e[# Ø]Ý®¶l £¤Ò’Ý”!§$e}[i‘¦–°%a¢´¸?³%vrB¯Fã¾#8›(ß‘®£(jL6ˆ#›7‚A0ô¡ ×u½‰g_‹qßhíϧ‹WÒôIöózõsößT©çå¸É¦$åc’×Ä \]zm-Ô•Ž`0©Â0ŒÄEœ³MRË]n²*UÌå~èÙªi\Ù‚ +EJúH„”åœU<³¹9õ7Un–WÙ±ÄÇG³ÆË)îÒw-Ô–Ž` •ì 9NDt2~Ò¶.4eQ ø÷¾UÂ*sªÕ«¬v{âSÐÒ ·:/HTj³óPiU´p/'Žò$L–g·GçQsT6}šXGLz´7¦2õW·‡4µb¢NX1±±³t‡©“„K©™GZ'ËÆ e*±®eí)lJvYЉI´‡`·ÕA/ÁÉuÜÍ´É>Œ ½ŒªhTÑ-.¤GåPr'¨ eÏ#fŸ¥ÖÈŠåÌå4‡gË«k^AM3UÒV>Zw®e¢±¨rÍùû^ÿö¼Q~ƒ'Ñxbc÷{m¬O,Õ$’ncç]ŒÁ•ÐÄØ Ðù¢W¿¯Vþ T\_ÂÝ¡âKå8iܹjí Ò~VŒÌ=ŒÏÕ;:ZÆ@ªÂ< vëaÅŽv .˶*ÈÒ9Aj%õÉ×/ £/°cÃAƒxpª#(×GŽº Rl¦¢žàXZXå>âr¢â{Ò!ÎýŽ­Œ¬Z‚Åêe¢D-dy‰wtÄ>!ô³Ê±åRƒú1˜19NodÇPùWú˜Ýf|Ñ'QgáŽ3‚QðÊTWfï§–h»d¿–`ÆÊ«BZú®Ò†ÓÛÆèžeÎ.•´O?°ÈbÆZ¯¢ùó})r Àb“*܃@4Š(œ:¸‰e½«²ÀpÇ ÌuƒèÞ³>°8çÁv¨ƒYégÇ´*uò]£ò¢]jr$:@°›óVÆV#¦ÞU™Áh~œ¯1á íø©ƒ{ÍE ‰öe(E‚»… ×Ûõj³ w¡|d‘*´z)ÖP^ r@¦¡ÝŸ,^ö¨;¿6ó ÖE»É²KeÉCFÁ<9nŠZ‚UYõ3 ÇñÊjÍZZ3_LO6ƒp=ÁÇ·#ЈÐZÑtøÆÔà1>áʰðL˜ž. Å?}{¥þ¬\¢Lê-iZwbaÚÚÅö±Œt5J[§ Žž,c ì¡\§Æ\&‚“y°Õr¬»D¥ÖmÊÓpصFýºè¸Ã½èp›B yŒyÇ*í´Æ«È,t´áñÑ~ýX¾mô€eá¢DvëŠÒ[ò…¢*˱OÜZo`lŒ³]H&¹-î iðìèžæ§+£zTƃ³{³Åƒ…>j`½d§9Žj9ÄŸõO6lw»vØ?»Êþdx†t 6œ*ÄSÚF+¸ÞÈâõú.FÔ"BÊL‘Q‚ǧ½&kw\Ñ1p]•â% ÉÞǬ¸M¨e¬´Exµ¯ˆ¬}úhcÀ]FJ;#KÙ3Ó-Ý61ÅJ[„WûŠÈÚG O'Ü m‚ rKgc¶|ë q35:¥N‘ªvh8MbÒèj·³cSOS—SŒ8¡Is—0Oãy0¨èÊíË(¢Q·;¥NˆÝŽh¨¢û¶^ߣ7ʆê”n=Á¥E½†…{d—äÆ#µ)jU4¥5oQ°F:Ö=³Kªæ-MOùSÂS¸0f…}fI.4N"Õ uGU⸖§ïpó`Qr¸Ð»ç-,ôoȪ%Øÿä¿ûý¾S§†àûD5Áoñ¥àz+z¤ðèáZpT?Ï *y´ÜV?)>bÈ·8jM’ãõCÜ4jW[š‚~µ«oC¬À¸`_ж´ynldY¾¶vDŸ¨xç6‡…™¤õdUqÅ‘ëäJ"òÛÃr¶ºWÉìG]Z-VÚÙˆZ½íPZ#ÅO/®È1EI'j»·KÛkÑúm”ÄÖv%å žð¯|¡\š§ÎUhˆ~w“._¨éŠ‘‚­?N=·Púý¨õ Õma•Û¶+Úus*Þʬ*ìÏlóün/»I×µr£#…£ö§ö;(°{WzÅ!ÔÂÈÒÁ\KëˆÕ<¨£¹«Êï9¹-ÕuÚ 7®5ÊMö›7–PÀ³á×ðgÚÆÇò-ï¡/{Ä~cU1ØôÂãD'#‹ð䥤é¼wÿì6-V•ݺöx”rôìæª¤U_½ÿ‰X¯»ÛÚp-V{õ^Û&—®/—ZYº·bHØ_ašØrÙ¬þ<òlÚPH•Æ>ûfÎS\oâÍïÏáSºÎÈrÁvÜp⣆‰²>[Lù›”ÆðžŠVŠ(Ûæ¹‹« È—0>ÌrlèhES>Óõðp¬K0XÑ£Ô-,OlpãÂÌÔâøpª/ˆÞÚ-,—ðºtVÒîVk=Yþ"ŽQK·FÁ£ÒqV–Š”=+¦—rд¼½¡Åú\ñÞ¤·¿=.1µíìÉr\ÊgJb;ñaHDz𨌂è‚-°‹k;”/¹éð'TΕFk«*·p#5®7¡(ù ›éLÉîí/…¬tÒÛÏ`†nB ‰]Ê×ë ‹côr6OAX1@çPi=% ÙåÇ‘MíÐr$þÑÃÿRKñµ\;eÚñ}⹂Nšx¯LÔò©3ÕÿŽúz¢'À1.íP*ÿã’„3ñ3£°ò-„Ze—ÃCÍÚÙŠ–õ›P—É·Û‘äC®´õ †ß- –&õ5XÔlYf”š®(~=U,qÇ Áð’ͽOSwf)ÁÆ1Øõ\/Üê‹f7|Wè÷º=–V_”úNX!µð ‰jºËé|¤$VJ­¸°ëZ5ÅRè¢IÛp»ù´á» cVê­º=.TËŒw,jùT`—z rÆwR¦0?áe…»îH¸‹(¨ç8×aïn¶¤>=áÖ¤·ƒe£¦§XÒÖ‚]N-®¾˜x3w†!Â8;d¸šQ‚ _ í‡~QòŽWÝÓXcqšÿY[£r†§u—3Q_¨§ú¾9¿Œ*2·¸Žp2›ƒ³‹`]c¸xÓ6Áqà‡ Æ|L±WøI?€xð·àWÈò5®`e¨mn7ØL8Çágbãu؃¼= šà¸‘«fÉpI—$«ó¾ã³.á¨Âp€á!1c5ì €ñ8ŒÂ…$Ž"錨êö }¢w¤mÚ"qQø’E6üß”Zš<Ï˽ó%…„ˆ˜{G"ëИ`þb4«‹''Æx§Bæà9ãR1ðéú¹WWt‹†f3ùÝ’f­^“¤¹…ÓsÁ‚¤dnªz!îˆ9KP¹ Ç1 æý¦FúÑ…{2«ÞkžcñHš¥z"¸a\¦ñ—4Í0ÐòÍg*¢]þA_€cŒù Ú}Þ=nÐ;ãÒŸzÄØz cøÉ1£Ç+t•`¨™ïû,’Û`‹ò-œ¸uÔâ÷I²ß´CÝ ütÓbd¶t^=€®  "B±‰6I[LüÄöÚ1Á1LO@H %A6žòW/o>Š\×›?ð¼)$ÏN€ì„žŒB>Z‰¿4eTó×­UȆáÍêf½Yÿå?ÿ2›Ù:#õ褢`%.Ü@ð)€*b¥L– Ÿc¾ÄÄÁû‡|Lb'&ÒÑü`_à€ ÇÀ>~ôøùsÛ€Ú¡wšÞ24cj¬8¡ŠÈ&òÙü#–¢ŒB …±›ÿ»¹~xýìßž¥ý¾ :ÿ£·Ç`^n6›ív _AaqÂçyሑ5œ3Ðl^!“Y#høõíjsëû±dï~Ÿ£Qï^Ö·k4;D=ww~$œÇX°É½~œl&¦ü»ªœåÌ Þ~ÚFüŒ«¿^-¾^,¿_v¯d{‚¡6«_W`[‰ï›õè1Ìa¤ÊMàTÊ©ô@9Pà])´‚GŽš`´?~÷¡ÂÂ,Âþ B,Üqí0J*÷Ižœ~Ï5N,%ZòåË—gçg³]u[‚cT§ðŸwCµ¢åª+ŸÐKQ?³Ï [oЦˆ8h¼“ðG:¨–×ëµëºBŸEꋪ˜x±©r®VùÁó†ÆÍ§`6íjˆ´$xÝ\!;\Ï›"õÞ©u‚Äß“ÇvÂ$áÊ }¸8L@JçÄ ¼hK•©•{íà–Q ë-^%æÐ0âîa²›Ø hÎ5]³A¥í\h[P  ¨;Ö°½ŠѾØRÇî¤j"‚E&ÖDÒmIòõ\ ª Š=ã1 Ò ¸³ÓéÎoþ;ÜZ “é Û‹‰q§€‘…ÛY ™…ÊEvˆ2Üç×—!°jy· b0:A- íÍm”ÏŒÊ}{ñ“Æ ùp€{ô@½­~Û,¿Œ›êÑ^EÃ(†ŒNB–ØþgÆ`[q:q<…OP_Þ½)%–X[ôPÞµEXÌ<ÿ×Í öõ&9z®å²ÐC‚×óí›· mÜŒ t‡o˜ò¾ºœ]À-ƒs|Â,9†/îȑ؅AŒæR¾ZÆ…–3„Ÿ ÷Ñ;ͤSÛÌ»Þ6*èt8O ÌûrqùýÓ)V“Ê×—Bu…•±Û>‹`‰Ât¤÷¼ÿ ׫.&@ý†7öã¿þx±\¿C\|³X^.ÿöúol‚V´‡{"¸³Ø_L¦EÓÆ zÏ%Œ¨'5C{oZæ3´XalæyᯯCÿŸŒt޶WÑ07—0á±-½}Ë(ÙâˆF8ýçTTJ&& h1ËúÜÚ„0Lç¦dÎ@ÀüËù£'Þܼ‘Þ xÂèíÍÊ_e‡+Ù‰˜+‚Bó0Ê‹Š F+oîz”7éûyKP±¡Ó—pÜŸvß´%Ápy¸7¨"XzBÃ`_‹ÂÍê†d½N‰¿Ñt°è¼ÙüÙ壎çz¿½|ñâÅùÙ9Ú¥§¨çb±xþâùõÕõ ôÐô-J-c!˜ÐJèáÙÑîÒñŸ/SŸÖ¤ÙÓû¼MN"®®›ŸÍ'Á™Ïf‹o.¯ÿ~E™çÒH,.¡iuóÆ!Ÿå3u^/ópƒ°?ýýN¸,XrI½Ë1½„k¹%Œ·?,/OLAퟻžçŸŸ?÷ÜååØ\oþñ†}F·€‹œQôpÞÞ%®=UHvCÆ=\8á<_,@Gv÷Æ·\Ñ!êFÄÕÿ\½zõ2BaôÊ•xêŽ!;eíkI½ün úíâÛ ìä'Hm±AxPtõ»÷ïnþyãßn`î'îKƾõ˜˜SWÆš8»© ´ôãGËçÿþbùÝåA &ÒýúõëW¯^‰P&:ÙHk‚ú}W‚Ó›ñ9D·¦ÁÖò ¼.8ærz0,‘Õ7\yû|ôA>¼ÿ¬§bÑû¡ep´º¼X|½­Ô×õû ˜Cx¤i¡ pŽ£‰+Pîóu(÷ * Making release 1.1.5. 2001-05-28 Uoti Urpala * gw/urltrans.c: Fixed handling of unrecognized %-escapes in sms-service URLs (for example, "%x" was supposed to stay unchanged, became "%%" instead). 2001-05-27 Richard Braakman * doc/userguide/userguide.xml: Added big table of smsc_* features, to get an overview of which smsc driver supports what. It's still mostly empty. 2001-05-26 Richard Braakman * gw/urltrans.c: Fixed bug in find_default_translation() that would make the smsbox panic if there was no default. 2001-05-24 Paul Keogh * gw/bb_http.c, gw/bb_boxc.c, gw/bb_smscconn.c, bearerbox.c: Added support for the cgi-bin/status.xml HTTP status command. Status is returned as a well-formed XML document. 2001-05-22 Uoti Urpala * gwlib/http.c: Fixed two bugs with redirects. One happened when the redirect URL was recognized as unsupported/invalid (f0o://bar), the other when Kannel didn't get a proper HTTP reply from the server it was redirected to. 2001-05-18 Lars Wirzenius * gw/smsc_at.c: Initialize some local variables to shut off compiler warnings and (possibly) fix bugs. 2001-05-17 Uoti Urpala * gw/urltrans.c: Added a new sms-service escape, %i, that adds the smsc-id of the message. * doc/userguide/userguide.xml: Documented above change. 2001-05-17 Richard Braakman * gwlib/thread.h: Wrap gw_claim_area() around mutex_create(), so that the user of the mutex shows up in the report of leaked or damaged memory areas. * checks/check_fakewap.sh, checks/check_http.sh: Use port 8040 instead of 8080, it's more likely to be free. 2001-06-17 Jarkko Kovala * doc/userguide/userguide.xml: Documentation for the ssl-certkey-file variable. 2001-05-16 Richard Braakman * gw/smsc.c, gw/smsc_p.h, gw/smsc_cimd2.c, gwlib/cfg.def: Added configuration variable "sender-prefix" for CIMD2. * doc/userguide/userguide.xml: Documented new variable. 2001-05-16 Kalle Marjola * gw/bb_smscconn.c, gw/bb_boxc.c: now that we have octstr_format, fixed buffer overflow problems pointed out by Alexei Pashkovsky 2001-05-16 Uoti Urpala * gw/bb_boxc.c: In boxc_sender(), flush outgoing data before doing list_consume()s than can block indefinitely. 2001-05-14 Lars Wirzenius * gw/smsc_smpp.c: Made system-id variable obsolete (i.e., if used, the user is warned and told to use smsc-username instead). Things should still work, and this allows us to remove the variable in a future version. * */*.conf: Renamed system-id to smsc-username in sample config files. * doc/userguide/userguide.xml: Updated to correspond to this. 2001-05-14 Lars Wirzenius * test/fakewap.c: Applied (after two months of waiting!) Neil Hunter's patch for making fakewap more suitable for benchmarking WAP gateways. 2001-05-14 Lars Wirzenius * benchmarks/bench_sms.conf: Add smsc-username, which is now used instead of system-id. * checks/check_list.c: #undef strcmp so that stupid glibc bug won't cause half a dozen of warnings for a single call. 2001-05-14 Derry Hamilton * gw/smsbox.c: Wrapped the ssl_certkey_file declaration in ifdefs, like the code that uses it so that we don't have gcc complaining about unused variables. 2001-05-14 Nick Clarey * gw/smsc_at.c: 7-bit messages plus UDH now encoded correctly. Thanks to Paul Keogh for the patch, as well as Richard Braakman for supervising the change to the UDL calculation code. 2001-05-11 Uoti Urpala * gw/urltrans.c: accept-x-kannel-headers and assume-plain-text were set incorrectly. 2001-05-09 Uoti Urpala * gw/smsc_emi2.c: Fixed formatting of a message field (%04d vs %4d). Spotted by Andreas Fink. * gw/smsbox.c: Fixed a nasty typo in the previous change. 2001-05-09 Uoti Urpala * gw/smsbox.c: Return meaningful HTTP status codes when replying to requests to sendsms-port. 2001-05-08 Uoti Urpala * gwlib/conn.c: Added missing unlock_out(conn) to conn_flush(). Found by Michael Mulcahy. Since conn_flush() is currently unused this didn't cause any Kannel bugs. 2001-05-07 Jarkko Kovala * config.in, config.h.in: Added autoconfiguration for libssl and a --disable-ssl option. Checks for libssl libraries and compiles it in if found and not disabled. Also checks if the OpenSSL libraries are multithread- enabled. * gw/smsbox.c, gw/smskannel.conf, gwlib/cfg.def: Added configuration of a global SSL certificate and key file with variable 'ssl-certkey-file'. * gwlib/conn.[ch]: Added support for client-side thread-safe use of SSL; new interface conn_open_ssl() similar to conn_open_tcp(). Also initialization functions for some stuff needed for SSL and interfaces to use global certificates and to get certificates from remote hosts. * gwlib/http.[ch]: Changed the http_start_request interface to accept variable certkeyfile for call-specific certificate & private key files. Changed to initialize the SSL stuff from conn.c at startup. * gw/smsbox.c gw/smsc_http.c, gw/wap-appl.c, test/test_http.c, gwlib/xmlrpc.c: Changed calls to http_start_request to use the new interface. gateway-1.4.5/doc/ChangeLog-0.13.10000644000175000017500000106455010106446071014733 0ustar toljtolj2000-12-13 Richard Braakman * Making release 0.13.1. 2000-12-13 Richard Braakman * Updated NEWS file. Compare 0.13 with 0.12 series instead of with 0.11 series, on the assumption that people who use development versions will still read the release notes for stable versions. * Documented --with-malloc=slow. 2000-12-11 Aarno Syvänen * wap/wsp_unit.c: Added handling of S_Unit_Push.req 2000-12-11 Richard Braakman * gw/smsc_smpp.c: Made smpp_reopen() work, and not crash. Made it not destroy the smsc structure when it fails, because that's not part of the interface. * gw/smsc.c: Made smsc_reopen() also lock the smsc structure. * gwlib/socket.c: In read_available(), pass the actual value of the largest fd used to select, rather than FD_SETSIZE. * gw/urltrans.c: encode_for_url returns an Octstr, but callers treated it as char *. Fixed that. Free URLTranslation->keyword with octstr_destroy, not gw_free. * gw/smsc_smpp.c: Removed unused lists sent_mt and delivered_mt. 2000-12-11 Lars Wirzenius * gwlib/octstr.c: octstr_format(): Implement %% in format strings. 2000-12-08 Aarno Syväen * wap/wsp_push_client.c, wap/wap_events.def: Really resolve a conflict. 2000-12-09 Lars Wirzenius * wap/wsp_push_client.c, wap/wsp_push_client_states.def, wap/wsp_server_push_states.def, wap/wsp_session.c: Commented things out so that things will at least compile and pass "make check". I assume Aarno forgot to add one or two files or other changes when he committed and that things do compile in *his* work directory. 2000-12-08 Aarno Syvänen * wap/server_push_machine.def, wsp_server_push_states.def: Two new modules to handle wsp push. * gw/wap_push_ota.c|h: These files are used, for now, only for debugging * wap/wap_events.def: For TR-Abort.ind, added the field ir_flag. This tells are the indicator responder or initiator and TR-Invoke.cnf, added field addr_tuple, which tells the session to which the event should be sent. * wap/wtp.h: More readable strings instead of magic numbers. * wap/wsp_push_client.c: Added calls to disconnect and suspend a session. Combined indications and dispatching. Separate abort functions for the initiator and the responder. * wap/wsp.h: Added definition of server push machine. * wap/wsp_server_session_machine.def: Added list for push machines. Renamed macro METHODMACHINES to MACINESLIST. * wap/wsp_session.c: Added statics to handle wsp push. In function find_session_machine, added handling of push events. Destroying both method and push machines. * wap/wtp_init.c, wap/wtp_resp.c: Assign values of new flags. * wap/wap.h: Added a new interface function wap_push_ota_dispatch_ event. * wap/wsp_push_client_machine.def: Added session_id. 2000-12-08 Richard Braakman * gw/bb_smsc.c, function sms_receiver: Made the increase in sleep times much slower (multiply by 2 instead of by 100). This avoids having the bearerbox sleep a whole second just because the SMSC took longer than 0.01 seconds. This scenario is pretty common on dialup links. 2000-12-07 Lars Wirzenius * contrib/{fortune.cgi,ping.cgi,sendsms,smstomail.cgi}: Added some sample services that can be used with Kannel. They're unlikely to be useful in real life, but might be amusing to test. 2000-12-07 Lars Wirzenius * gw/smskannel.conf: Removed the "www" example service, since people seem not to remove it from production installations. They should, since it's potentially a security problem. 2000-12-06 Richard Braakman * gw/wapbox.c: Memory cleanup: Call close_connection_to_bearerbox() when exiting, and destroy the bearerbox_host string. 2000-12-06 Lars Wirzenius * gw/smsbox.c: Removed compilation warning about `catref' being possibly used without initialization in send_message. While doing this, fixed some formatting (long lines, comment style), frivolous argument order changes, and renamed catref to msg_sequence, so as to use the same name everywhere. Also removed the commented-out part that disabled catenation on messages with UDH. It was enabled since the code before the rewrite didn't seem to deal with this case properly, and I hadn't time to find out the correct way to handle this. 2000-12-06 Richard Braakman * Not Finnish and not independent. (Ruled by a queen) * Applied Mikael Gueck's cleanup patch for SMPP. * gw/smsc_smpp.c: Fixed memory leak in data_receive(), spotted by Milko Videv. * gw/smsc_smpp.c: Fixed minor compiler warnings, deleted unused functions charset_smpp_to_iso(), charset_iso_to_smpp(), and actively_unbind(). * gw/smsc_smpp.h: Deleted declarations of unused functions. Deleted translation_table (no longer used) 2000-12-06 Yann Muller * gw/smsbox.c: Corrected reference number for concatenation UDH, recalculate UDH length after adding concatenation info and adjust if UDH was empty. Commented out reset of 'catenate' if UDH is already present. * gw/smsc_at.c: fixed the length of the user data in pdu_encode(). 2000-12-05 Lars Wirzenius * gw/wapbox.c: Converted to use bearerbox communication stuff from gw/shared.c (and therefore Connection) instead of using old plain socket stuff. Among other things, this kills one thread (empty_queue_thread). * gw/shared.c: Check for write errors and don't report messages that were sent. * checks/check_fakewap.sh: Set log level to 0 and shorten sleeps between box startups. * gw/smsbox.c: Don't use \0 in format string, use %c and argument 0 instead. \0 has a tendency to cut C strings short... 2000-12-05 Lars Wirzenius * gw/shared.[ch]: Moved bearerbox communication stuff from smsbox.c to shared.c, so that it can easily be used by wapbox as well. * gw/smsbox.c: Related changes. * gw/wapbox.c: Renamed "running" to "running_ok", until the wapbox will use program_status from shared.c. 2000-12-05 Lars Wirzenius * gw/smsc.c: Removed calls to str_find_substr. * gwlib/utils.[ch]: Removed now-unused str_find_substr function. 2000-12-05 Lars Wirzenius * gw/urltrans.[ch]: Removed urltrans_accepted_smsc(), since it wasn't being used. Made the accepted SMSC list in an URLTranslation be a List. This allows us to kill one more call to str_find_substr. * gwlib/octstr.[ch]: Wrote octstr_item_match. 2000-12-05 Lars Wirzenius * gwlib/octstr.[ch]: Wrote octstr_split. * gw/urltrans.c: Use a Dict to look up the URLTranslation, instead of a linear search from the whole list. This is somewhat faster and results in cleaner code. 2000-12-05 Lars Wirzenius * gwlib/gwstr.[ch], gwlib/conffile.c: Moved trim_ends to conffile.c, and the other functions were no longer used, so removed the gwstr module. * gwlib/gwlib.h, gwlib/socket.h: Removed include for gwstr.h. 2000-12-04 Lars Wirzenius * gw/urltrans.c: Made urltrans_get_pattern return an Octstr, instead of a C string. * gw/smsbox.c: Related changes. 2000-12-04 Lars Wirzenius * gw/urltrans.[ch]: Change function call interfaces to use Octstr instead of C strings. * gw/smsbox.c: Related changes. * gw/smsbox.c: When checking whether sendsms is allowed, call is_allowed_ip properly, with deny_ip, not instead of allow_ip. 2000-12-04 Lars Wirzenius * gw/urltrans.[ch]: Reformatted for new coding style. 2000-12-04 Lars Wirzenius * gw/smsbox.c: Fixed the PAM code to use warning and error, instead of printf. 2000-12-04 Lars Wirzenius * gw/smsbox.c: Reformatted the PAM code. Hopefully it still works. 2000-12-04 Lars Wirzenius * gw/smsbox.c: Rearranged code for clarity, plugged a memory leak and fixed a memory freeing bug (memory was being freed twice). 2000-12-04 Lars Wirzenius * gw/smsbox.c: Merged smsbox_req.c into smsbox.c, because they called each other backwards and forwards and the merged file is small enough to be manageable, so there's no point in keeping them separate. * gw/smsbox.h, gw/smsbox_req.[ch]: Removed. 2000-12-04 Lars Wirzenius * gw/smsbox_req.c: Rearranged code to be somewhat clearer. * gw/smsbox.c: Removed ancient file comment. 2000-12-04 Lars Wirzenius * gw/smsbox_req.c: Rewrote SMS splitting so that it is hopefully now somewhat more understandable. 2000-12-04 Lars Wirzenius * gw/smsc_emi.c: Avoid NULL pointer dereference if sender has not been set. Thanks to Armin Hurm for finding this. 2000-12-04 Lars Wirzenius * doc/userguide/userguide.xml: Explain the syslog-level variable for wabpox. 2000-12-04 Lars Wirzenius * README: Moved information from doc/platforms/FAQ.solaris to README, because the goal is to reduce the number of places one has to look for documentation, not increase it. Whoever put the file in CVS didn't even document it in the ChangeLog. * doc/platforms/FAQ.solaris: Removed. 2000-12-01 Richard Braakman * gw/heartbeat.c: Fix busy-loop in heartbeat thread. 2000-12-01 Lars Wirzenius * contrib/php-admin/*: Added PHP administration stuff and sendota/sendvcard/etc stuff from Bjarne Saltbaek. 2000-12-01 Lars Wirzenius * configure.in: Accept libxml 2.2.10. (Untested, since I don't have 2.2.10 yet.) 2000-11-29 Richard Braakman * wap/wap_events.*: Gave events pretty names, for logging. ("TR-Invoke.cnf" instead of "TR_Invoke_Cnf"). 2000-11-29 Richard Braakman * wap/wap_events.def, wap/wsp_push_client.c, wap/wsp_push_client_states.def: Brought Push-related events in line with the scheme used by other WSP events. 2000-11-29 Richard Braakman * gwlib/gwpoll.h, gwlib/gwthread-pthread.h: FreeBSD compatibility fix. Specify "no timeout" on poll by using INFTIM, if it's available, rather than using a random negative value. 2000-11-29 Aarno Syvänen *wap/wsp_push_client_states.def: Changed names of dispatching functions to locally used ones. 2000-11-29 Yann Muller * gw/smsc_at.c: removed the UDHL from the encoding of the PDU. The length should already be in the UDH. 2000-11-28 Richard Braakman * wap/wsp_session.c, wap/wsp_server_session_states.def, wap/wsp_server_method_states.def: Renamed static functions so that they do not start with "wsp_", to avoid confusion. (In the future the client side will have its own versions of these, and names with wsp_ look like they are global.) 2000-11-28 Richard Braakman * wap/wap_events.def: Added WSP client-side events (not used yet). * Renamed "session_id" to "session_handle" for WSP session events that are used by both client and server side. The client side does not know the session id until after it is connected, so it can not use that as a handle. * Made "method" an OCTSTR field instead of INTEGER. Now the application layer need no longer worry about method encoding values. This is a first step toward supporting extended methods, which have no fixed number. * Renamed S_MethodInvoke_Ind fields to be closer to the spec. * Introduced OPTIONAL_OCTSTR, and require that OCTSTR and ADDRTUPLE fields never be NULL. wap_event_assert now checks this. HTTPHEADER, CAPABILITIES, and OPTIONAL_OCTSTR fields can be NULL. All uses have been checked to see if they can deal with this, and some have been adjusted. * wap/wap_events.def: Formalized distinction between fields in the spec and fields added by Kannel. * wap/wsp_push_client.c: In push_client_machine_find_or_create, add default case to handle unexpected event types, and always destroy "pdu" variable (to avoid gcc warnings). * wap/wsp_push_client.h: Define INTEGER fields as long, just like everywhere else. 2000-11-28 Lars Wirzenius * gw/smsbox.[ch], gw/smsbox_req.[ch]: Call function to write message to bearerbox directly, instead of via function pointer. 2000-11-28 Kalle Marjola * gw/smsbox_req.c: fixed that sendsms user is again shown (it disappeared during some authorization work, I guess) * gw/urltrans.c|h: added function urltrans_username 2000-11-28 Aarno Syvänen * gw/wapbox.c: Initialize and shutdown the push client. 2000-11-28 Aarno Syvänen * wap/wsp_push_client*: Added client push machine. Wtp responder will send class 1 transaction messages to this as long as wsp client session machine is not implemented. * wap/wap_events.def: Added some push events * wap/wap.h, wtp_resp.c, wtp_resp_states.def: Sending events from wtp responder to push client implemented. 2000-11-28 Lars Wirzenius * gwlib/log.[ch]: Added a log_ prefix to functions, except for the actual message printing ones. Those are used in too many places to warrant a change. * checks/check_*.c, gw/bearerbox.c, gw/smsbox.c, gw/wapbox.c, gwlib/utils.c, test/drive_wapbox.c, test/test_http.c, test/test_http_server.c, test/wml_tester.c: Related changes. 2000-11-28 Lars Wirzenius * gw/smsbox_req.c: Deal with failed requests in the proper manner, which does not include segfaulting. 2000-11-28 Lars Wirzenius * checks/check_sendsms.sh: Wait a couple of seconds before making http requests so that the smsbox has time to start up properly. * gw/html.c: Moved the html prefix and suffix stripping function into smsbox_req.c, since it doesn't really do anything with html, just octstrs. Cleaned up url_result_thread slightly. 2000-11-28 Lars Wirzenius * gw/smsbox_req.c: Accept WML responses as well as plain text and HTML responses. 2000-11-28 Paul Keogh * gwlib/gwmem-check.c: Removed compiler warning of "gwmem-check.c(370) : unary minus operator applied to unsigned type, result still unsigned." 2000-11-27 Lars Wirzenius * gw/smsbox_req.c: Made obey_request return an Octstr, instead of a C string. 2000-11-27 Lars Wirzenius * gw/smsbox_req.c: Formatted to follow coding style. 2000-11-27 Lars Wirzenius * gw/smsbox.c, gw/smsbox_req.c: Changed the thread structure for smsbox so that threads are not created dynamically for each new message, but instead threads are created at startup and messages are passed around between then via queues. * gw/urltrans.c: Fixed memory leak by remembering to destroy the deny_ip string as well. 2000-11-27 Kalle Marjola * doc/userguide/userguide.xml: corrected explanation of smsc-id in sendsms interface chapter 2000-11-24 Richard Braakman * Added Suspend/Resume support. (Not well tested yet) * wap/wsp_pdu.def: Note that the capabilities field in a Resume PDU is reserved. * wap/wsp_server_method_states.def: Explain why we don't decrement N_Methods. 2000-11-24 Kalle Marjola * gw/smsc.c: oops, did fix to wrong place, silly me 2000-11-24 Lars Wirzenius * gwlib/gwmem-check.c: Add casts to avoid comparing pointers and integers. 2000-11-24 Richard Braakman * gw/heartbeat.[ch]: New files, contain heartbeat code shared between wapbox and smsbox. * gw/wapbox.c, gw/smsbox.c: Use shared heartbeat code. * gw/smsbox.c: Use Connection for the link with the bearer box. Made bb_host an Octstr. * gw/smsbox_req.c: write_msg() cannot fail, so don't check return codes. * gwlib/conn.c: Memory leak debugging: all callers of unlocked_get claim the result as theirs. * gwlib/http.c: Fix memory leak in read_chunked_body_crlf(). * configure.in, config.h.in: Added --with-malloc=slow, which does a more careful (but much slower) check in find_area(). This can sometimes report problems that would otherwise cause a segfault. * gwlib/gwmem.h, gwlib/gwmem-check.c: Implement --with-malloc=slow. Also do the careful check if the pointer looks like one of our standard fill patterns. * gwlib/octstr.c: Added seems_valid() call in octstr_dump(). * gwlib/http.c: Get rid of clients_in_fdset list. This removes a race condition that would cause occasional segmentation faults, but leaves us with some "memory leaks". (They aren't really, but are reported as such.) * gw/smsc_emi.c: Converted previous patch to our coding style wrt parenthesis usage. emi_open_session: Added missing final return. emi_fill_ucp60_login: Made ia5passwd dynamically allocated, since variable-length arrays are not standard C. 2000-11-24 Kalle Marjola * gw/smsc.c, gw/smsc_emi.c: applied authentication patch by Joerg Pommnitz 2000-11-23 Richard Braakman * wap/wsp.h, wsp/wsp_headers.c, wap/wsp_session.c: Changed some "XXX" comments. * wap/wsp_pdu.h, wap/wsp_server_method_states.def, wap/wsp_unit.c: Introduced GET_METHODS and POST_METHODS identifiers to avoid using 0x40 and 0x60 as magic numbers. 2000-11-23 Yann Muller * gw/smsc_at.c: reverted default GSM alphabet patch and added call to charset_latin1_to_gsm(). 2000-11-23 Richard Braakman * gw/smsbox.c: Moved http_proxy_ variables into init_smsbox, since they are used only there. Made http_proxy_host an Octstr. * gw/smsbox.c: Wait for http_request_thread to terminate, when shutting down the box. * gw/smsbox_req.[ch], gw/smsbox.c: Added smsbox_req_shutdown(), so that it can clean up its copy of global_sender. 2000-11-23 Lars Wirzenius * gwlib/http.c: Deal with HTTP version numbers above 1.1 also on the server side. Use a single function for the checking that is used by both the client and server. 2000-11-23 Richard Braakman * wap/wtp_init.c, wap/wtp_init_states.def, wap/wtp_resp.c, wap/wtp_resp_states.def: Added static send_abort() and send_ack() functions, to simplify the state machine definitions. 2000-11-23 Kalle Marjola * doc/userguide/userguide.xml: some corrections to just written 2000-11-23 Richard Braakman * gw/smsc_at.c, gw/smsbox_req.c: Replaced some strcpys with pointer assignments. * doc/userguide/userguide.xml: Replaced an & with & so that it compiles. * checks/check_sendsms.sh: Reduced sleep after starting bearerbox, because it starts up faster now. Added "sleep 5" before killing bearerbox, because smsbox segfaults if it's still busy when the bearerbox goes away. 2000-11-23 Yann Muller * doc/userguide/userguide.xml: Added Stipe Tolj's explanations for multiple OTA configs. 2000-11-23 Kalle Marjola * doc/userguide/userguide.xml: Added some explanation of SMS and what is an SMS gateway - might need editing, but neverthless there is some text * doc/userguide/sms-gateway.fig: New picture to support that explanation 2000-11-22 Richard Braakman * gw/smsc.c, gw/smsc_cimd.c: Reformatted. 2000-11-22 Lars Wirzenius * test/drive_wapbox.c: Killed a memory leak by destroying a temporary octet string. * gwlib/gwmem-check.c: When dumping allocated areas, dump the first few bytes of the area. * gwlib/http.c: Destroy HTTPClients before destroying the fdset. 2000-11-22 Kalle Marjola * doc/userguide/userguide.xml: Moved some explanations to correct places, to avoid mixed up context 2000-11-22 Richard Braakman * gwlib/fdset.c: When destroying an fdset with active fd's, close them first and signal that event. 2000-11-22 Lars Wirzenius * doc/userguide/userguide.xml: Add notes about HTTP proxy username and password. 2000-11-21 Richard Braakman * wmlscript/wserror.c, wmlscript/wslexer.c: Fixed some assertions with side effects. 2000-11-21 Richard Braakman * gw/html.c, convert_html_entity(): Made conversion of entities like Ӓ work. 2000-11-21 Richard Braakman * gw/html.c, gw/msg.c: Reformatted. 2000-11-21 Richard Braakman * gw/cgi.[ch]: Removed, they are no longer used. * gw/smsbox.c, gw/smsbox_req.[ch]: Removed inclusion of cgi.h. 2000-11-21 Richard Braakman * gwlib/gwthread-pthread.c, gwlib/conn.c, gwlib/list.c, gwlib/utils.c (roundup_div): Formatted according to our coding style. All of gwlib/ is now converted. 2000-11-21 Lars Wirzenius * gwlib/http.c: Made persistent connection detection work with HTTP/1.0 responses and responses with the "Connection: close" header. Also removed an extra "Using proxy" report. * ChangeLog: Indented the first line of the previous log entry properly. (8, not 4) 2000-11-21 Yann Muller * gwlib/utils.[ch], gw/smsbox_req.c: moved roundup_div() from smsbox_req.c to utils.c so it can be used from other files. * gw/smsc_at.c: fix for 7 bit encoded PDU's with a UDH. * gw/smsbox_req.c: maxdatalength fix in do_split_send(). 2000-11-21 Lars Wirzenius * checsk/check_fakesmsc.sh: Sleep before starting background processes, so that the previous ones have time to start up properly. * ChangeLog: Indented the previous log entry properly. (8, not 4) 2000-11-21 Yann Muller * gw/smsbox_req.c: sendota patched (Stipe Tolj) to accept more that one OTA configuration. 2000-11-20 Richard Braakman * Turned WTP and WSP protocol stacks into a library. Source files moved to a directory called "wap", which generates libwap.a. The interface to this library is specified in wap/wap.h. The application layer remains in gw/. * In WAPAddrTuple, rename "client" and "server" to "remote" and "local", to prevent confusion in client-side code. * While moving files to wap/, renamed declaration files to ".def", and made filenames use _ instead of - as separator. Also put "server" in the name of some WSP files, to make room for future "client" files. * Sanitized header files that include other header files. Now each header only includes what it needs. * Layers can be started independently, and use configurable dispatch functions. * wap/timers.c, wap/wsp_strings.c: Allow nested initializations and shutdowns, because layers that use them can be started independently. * WTP layer now uses datagram events instead of Msg structures for its lower level. * wtp_send.c converted to wtp_pack.c, because it no longer does its own sending. * wtp_tid.c uses WAPAddrTuple instead of its own structure. * gw/wap-appl.c, gw/wapbox.c: Use the new interface. 2000-11-20 Lars Wirzenius * gwlib/dict.c: Avoid an extra list_search if we know the list was empty. 2000-11-20 Richard Braakman * Making release 0.13. 2000-11-20 Richard Braakman * gwlib/dict.c: Made it initialize empty table entries with NULL instead of empty lists, to save memory. * gwlib/http.c: Fix memory leak in send_request() when retrying a request. * gwlib/http.c: Make sure that a retried request really gets a _new_ connection. Otherwise it could be rejected just because two connections have timed out. 2000-11-19 Derry Hamilton * solaris/prototype: Updated the prototype to reflect the newer install style. 2000-11-17 Kalle Marjola * gw/bb_smsc.c (sms_receiver): usleep limit to avoid portability problems, patch by Jarkko Oikarinen 2000-11-16 Richard Braakman * gwlib/http.c: Responses with status 1xx, 204, or 304 are defined as having no message body, so don't expect one. 2000-11-16 Richard Braakman * gwlib/http.c: Removed calls to conn_unregister that were followed by calls to conn_destroy. It's redundant, and in one case the connection might be NULL. * gwlib/conn.c: Add some conn != NULL assertions. 2000-11-16 Yann Muller * gw/smsc_at.c: In function at_open_connection() added parity line for this modem type. In function at_open() adding sleep period only for this modem type, may be expanded. In function pdu_extract() changed skipping of 00 sequence for the specific modem types. (patch by Stipe Tolj) 2000-11-15 Richard Braakman * gw/wsp-session.c: Address tuples are now included in events sent from WTP to WSP, so the code for looking up tuples based on WTP handles is no longer needed. * gw/wtp_resp.[ch]: Removed now-unused functions wtp_resp_get_address_tuple, find_resp_machine_using_mid, and resp_machine_has_mid. 2000-11-15 Kalle Marjola * gw/bb_boxc.c: added wapbox load based balancing, based on ofiginal patch by Rishi Lal and Priya Patil 2000-11-15 Kalle Marjola * gw/smsc_wrapper.c, gw/smscconn_p.h: Added. * gw/smscconn.c: moved wrapping stuff into smsc_wrapper.c, and private structure data into private header smscconn_p.h so that caller (main bearerbox) does not need to worry about that 2000-11-14 Richard Braakman * doc/CodingStyle: Document our practice of having include files include other files. 2000-11-14 Lars Wirzenius * gwlib/http.c: Simplified code a bit by combining the two different states (reading_body and reading various parts of a chunked body) into one. 2000-11-14 Lars Wirzenius * gwlib/http.c: Implemented, I hope, proxy_add_authentication(), but I can't test it, since I don't have a proxy that requires authentication. If it doesn't work, hopefully people will tell me. 2000-11-14 Lars Wirzenius * gwlib/http.[ch]: Wrote function http_add_basic_auth. * test/test_http.c: Added code to optionally use Basic Auth with requests. 2000-11-14 Lars Wirzenius * gwlib/http.c: Report when connections to servers are opened and when a proxy is being used (via debug). * test/test_http.c: More informative output with -h. 2000-11-14 Yann Muller * gw/smsc_at.c: phone numbers starting with '+' or '00' are coded as international numbers, others are left with the default (Unknown). 2000-11-13 Lars Wirzenius * gw/smsbox.c, gw/wapbox.c, gwlib/http.[ch], test/test_http.c: Changed the HTTP proxy configuration interface so that the access to the proxy can be authenticated. The actual implementation is still lacking, but the interface changed to http_use_proxy() is done. 2000-11-13 Lars Wirzenius * Makefile.in: Use $(DESTDIR) in the install targets. 2000-11-13 Richard Braakman * configure.in, config.h, gwlib/gwassert.h: Use NO_GWASSERT instead of NDEBUG. Have gwassert.h define NO_GWASSERT if NDEBUG is defined. * gw/smsc_cimd2.c, gwlib/conn.c, gwlib/gwlib.h, gwlib/octstr.c: Use NO_GWASSERT instead of NDEBUG. 2000-11-10 Lars Wirzenius * gwlib/http.c: Implemented persistent connections on the client end. 2000-11-10 Richard Braakman * gwlib/gwlib.c: Call gwlib_protected_shutdown() last, because the protected functions are used by other shutdown functions. Thanks to Paul Keogh for pointing this out. * gwlib/gwmem.h, gwlib/gwmem-check.c, gwlib/gwlib.c: Added gwmem_shutdown() function, to be called after gw_check_leaks(). This makes it possible to check for leaks without shutting down. * doc/userguide/userguide.xml: Document the configure options added below. 2000-11-10 Lars Wirzenius * gwlib/http.c: Implemented persistent connections on the server end. 2000-11-10 Richard Braakman * configure.in: Added --with-defaults to make it possible to configure for speed or for debugging, with one option. Added --disable-assertions to set NDEBUG. Made --with-malloc and --disable-assertions use the default set by --with-defaults. Changed some whitespace to make ./configure --help align nicely. * config.h.in: Added NDEBUG option * gwlib/gwthread-pthread.c: Include "gwlib/gwlib.h", not . The latter made "make depend" skip the inclusion. This fixes the problem of needing to run "make clean" after switching malloc wrappers. * gwlib/thread.[ch]: Remove mutex_try_lock(). It's not longer used, and it had portability issues. * gwlib/conn.c: If conn_set_output_buffering is called, react to the new buffer size immediately. * gwlib/conn.[ch]: Remove conn_wait_multi(). It's not used and will not be needed by the new HTTP design. * gwlib/conn.c: Fix conn_flush to conform to its description and to manage its lock right. * gwlib/conn.c: Make unbuffered connections the default. 2000-11-10 Kalle Marjola * gw/smscconn.h|c: Added. New SMSC connection interface with stub of upcoming connection module (and wrapper for old system) 2000-11-10 Lars Wirzenius * gwlib/http.[ch]: Killed http_get and http_post, since they're now obsolete and unused. http_get_real remains until numhash.c and smsbox_req.c are converted. 2000-11-10 Lars Wirzenius * gw/wap-appl.c: Reformatted. 2000-11-10 Lars Wirzenius * gw/wap-appl.c: Changed thread structure so that there is a static number of thread regardless of how many requests are made. This should make things a bit faster when the load is heavy. * gwlib/http.[ch]: Wrote function http_client_signal_shutdown, to allow the wapbox to shutdown. 2000-11-10 Lars Wirzenius * gw/wap-appl.c: Rearranged code in preparation for changing the thread structure so that a new thread is not started for each request. 2000-11-10 Lars Wirzenius * gwlib/http.[ch]: Updated documentation, moved HTTP_PORT to .c, since no-one else needs to know it. 2000-11-09 Yann Muller * gw/smsc_at.c: encode 7 bit messages in the default GSM alphabet (thanks to Mike Gaertner). 2000-11-08 Richard Braakman * gw/wap-appl.c: Deal with client_SDU_size being 0, which means there is no limit. Thanks to Ruud Schramp for pointing this out. Also made connectionless mode set it to 0 instead of an arbitrary value. 2000-11-08 Lars Wirzenius * Makefile.in, configure.in: Made "make install" work in a more sensible way, at least as far as the Filesystem Hierarchy Standard (pretty much all Linux systems, and mostly BSD systems as well) is concerned. /usr/bin and /usr/sbin are now used properly, and manual pages are installed as well. Also, the User Guide is installed in a more sensible way. * debian/rules: Updated accordingly. 2000-11-08 Lars Wirzenius * checks/check_sendsms.sh: Remove log files if check was successful. 2000-11-08 Kalle Marjola * gw/bb_boxc.c: fixed error that caused bearerbox to possibly segfault when connection from illegal IP was tried * gw/smsbox_req.c: make sure that UDH length is set properly 2000-11-07 Lars Wirzenius * gwlib/http.c: Bugfix. Destroy the new_server_sockets list. 2000-11-07 Lars Wirzenius * gwlib/http.c: Massive rearranging and some renaming, but no real changes. The code is now much cleaner and easier to understand. 2000-11-07 Tuomas Luttinen * gwlib/octstr.c: Added some protection against endless loops in strip-functions for special cases. * gw/wml_compiler.c: Memory leak with malformed variable fixed. Also fixed the bug that reserved words cannot be variable names, eg $(password). 2000-11-07 Lars Wirzenius * gwlib/http.[ch]: Removed old server API. 2000-11-07 Lars Wirzenius * test/drive_wapbox.c: Converted to use new HTTP server API. 2000-11-07 Richard Braakman * gwlib/http.c: Fix memory leak in client_read_body. Make server_thread not warn if gwthread_poll fails with EINTR. * gwlib/conn.[ch]: Added conn_read_error(), and a read_error field to the Connection structure. Added conn_read_everything(). * gwlib/http.c: In client_read_body, use conn_read_everything instead of conn_inbuf_length and conn_read_fixed. This way it will detect end-of-file. * gw/wapbox.c: Make send_heartbeat_thread() not send more heartbeats than twice the usual frequency. (We can live with sleep() not being exact, but when the wapbox is run inside a debugger it tends to go wild.) 2000-11-07 Lars Wirzenius * checks/check_sendsms.sh: Sleep for five seconds before starting smsbox; this prevents the smsbox from crashing before the bearerbox is ready to accept its connection. * gw/smsbox.c: Adapted to new HTTP server API. * gwlib/http.c: Bugfix. If we fail to re-use a connection, and re-open it, we must then quit the handler for the old connection. 2000-11-07 Lars Wirzenius * checks/check_sendsms.sh: Wrote. 2000-11-07 Lars Wirzenius * checks/check_fakesmsc.sh: Wrote. 2000-11-06 Tuomas Luttinen * gw/wml_compiler.c: Variables with syntax errors are now discarded with warning instead giving up with the hole WML source. Some memory leak still exists. Also an unknown tag produces a warning in the log. 2000-11-06 Lars Wirzenius * gw/smsc_at.c: Applied fix from Paul Keogh to hex number conversion. 2000-11-06 Lars Wirzenius * utils/kannel-redhat.init.d: New file from Fabrice Gatille. 2000-11-06 Lars Wirzenius * configure{,.in}, config.h.in: Add support for PAM enable and disable. * gw/smsbox_req.c: Fixed the PAM stuff so that it will compile with the new gwmem.h protectors against malloc and friends. 2000-11-06 Lars Wirzenius * README, doc/userguide/userguide.xml: Moved information on how to use configure from README to User Guide. 2000-11-06 Lars Wirzenius * Bearerbox converted to use with ne HTTP server API, with help from Kalle Marjola. * gw/bb_http.c: Only use one thread to handle HTTP requests. Added function httpadmin_stop to help with shutdown synchronization issues. * gw/bearerbox.[ch]: In signal handler, call bb_shutdown, instead of set_shutdown_status. This point may need to be implemented better later. Call httpadmin_stop in main. * gwlib/http.c: Have http_close_all_server kill the server threads as well, including killing the FDSet poller thread. 2000-11-06 Kalle Marjola * gw/smsc_emi.c (emi_open_ip): check if allow_ip set. Thanks for Juho-Pekka Virolainen for noticing this. 2000-11-06 Yann Muller * gw/smsc_at.c: fixed Premicell bug. Added sleep(1) for nokiaphone. 2000-11-05 Richard Braakman * gwlib/http.c: Make the interface of client_read_body() match the rest of the design. This makes the http module work with HTTP/1.1 servers again. 2000-11-03 Tuomas Luttinen * gw/wml_compiler.c: A conformance patch: card and template elements cannot have 2 or more do elements of the same name, PI are ignored, unknown tags and CDATA are now processed. Also some code was cleaned into the new coding standard. 2000-11-03 Richard Braakman * gw/wsp_headers.c: If an Expires header has an invalid date, then encode it as a date far in the past. We can't just skip the header because RFC2068 says such a response should be treated as already expired, and we have to tell the client to do that. * gw/wsp_headers.c: Make sure that a Multi-octet-integer is always at least one octet long, even if its value is 0. 2000-11-03 Kalle Marjola * gw/smsbox.c: changed 'sent..' log event to clearly state that it only means that the message was sent to bearerbox, not further 2000-11-03 Lars Wirzenius * checks/check_list.c: Fixed synchronization problems that occasionally caused it to randomly fail. The list code itself was OK, but the checking code did not synchronize thread startups correctly. 2000-11-03 Lars Wirzenius * test/test_http.c: Change the error message when there are no command line arguments from "Floating point exception (core dumped)" to the standard help text. 2000-11-03 Lars Wirzenius * test/test_http_server.c: Converted to use the new HTTP server interface. This displayed bugs in shutdown situations for the new HTTP code. * gwlib/http.c: Fixed bugs in shutting down. 2000-11-03 Lars Wirzenius * test/test_http_server.c: Reformatted to coding style. 2000-11-03 Lars Wirzenius * gwlib/http.[ch]: First cut at changing the HTTP server side interface to be more sensible about the number of threads. Doesn't work quite well yet (i.e., if I change test/test_http_server.c, make check fails), but I want it committed for now. Shouldn't harm anyone, as long as they don't use it. 2000-11-02 Paul Keogh * gw/cookies.c: Fix for some cookie management bugs. 2000-11-01 Richard Braakman * gwlib/gwthread-pthread.c: Fix memory leak if poll() was interrupted. 2000-11-01 Richard Braakman * gw/smsc_emi.c: Cleaned up a bit, made thread-safe. * gw/smsc_p.h, gw/smsc.c: Declare and initialize new EMI fields. 2000-11-01 Richard Braakman * gwlib/octstr.c: Make octstr_read_file use a smaller buffer, to reduce stack usage. 2000-11-01 Lars Wirzenius * gw/wap-appl.c: Implement magic URL kannel:alive, based on patch from Neil Hunter. 2000-11-01 Lars Wirzenius * gwlib/gwlib.h, gwlib/list.c: Move around include for gwmem.h so it comes after thread.h, because thread.h includes pthread.h, and Cygwin's pthread.h includes malloc.h, which gets annoyed by the macros gwmem.h defines. 2000-11-01 Kalle Marjola * gwlib/conffile.c (config_sanity_check): fixed that 'otaconfig' is accepted, too, thanks to Philip Psiloinis for pointing this out * gw/bb_smsc.c: make sure that lists are emptied 2000-11-01 Yann Muller * gw/smsc_at.c: handles message lengths of 8*n+1 properly. Added comments to encode7bituncompressed(). 2000-10-31 Richard Braakman * gwlib/fdset.c: Handle EINTR. 2000-10-31 Richard Braakman * Moved wap_addr functions from wapbox.c to new file wap_addr.c, and created wap_addr.h for it. 2000-10-31 Richard Braakman * gwlib/conn.[ch]: Make it possible to change the callback info efficiently, by calling conn_register again with the same fdset. * gwlib/fdset.c: Fiddled with poller loop to deal with callback functions doing strange things to the poll array while it's being scanned. 2000-10-31 Lars Wirzenius * gwlib/http.c: Now uses FDSet, instead of explicit waits, and now again does concurrent transactions as a side effect, but only does one transaction per HTTP connection. The code is in need of cleaning up quite a bit, but should work, except for not destroying the FDSet at shutdown. 2000-10-31 Richard Braakman * gwlib/conn.c: Implement conn_unregister() too. 2000-10-31 Lars Wirzenius * gwlib/http.c: Converted HTTP transaction handling into a state machine, so that FDSets can be easily be used with HTTP. 2000-10-30 Lars Wirzenius * gwlib/gwstr.[ch]: Removed unused functions strndup and str_reverse_case_seek. The rest of this module will go away once smsbox is re-written to use Octstr. 2000-10-30 Richard Braakman * gw/wap-appl.c: Support for X-WAP.TOD header, needed for WAP 1.1 conformance. (requirement UACache-0010) * gw/wsp_headers.c: Special encoding for X-WAP.TOD, which is an application-specific header with a field encoding that does not match the application-specific-value rule. (This is a contradiction in the spec). * gwlib/http.[ch]: Make http_header_remove_all report how many headers it removed. 2000-10-30 Aarno Syvänen * gw/wtp_resp_state-decl.h: Added timeout to state RESULT_WAIT: Now we wait for result only for AEC_MAX timer periods. * gw/wtp.c, gw/wtp_resp.c, gw/wtp_resp_state-decl.h: Added class transaction handling. Not much tested, yet. 2000-10-27 Lars Wirzenius * README.*: Moved information into README. There's no point in having lots of small files. 2000-10-27 Lars Wirzenius * gw/bb_http.c: Add Content-Type header to bearerbox admin interface replies. 2000-10-27 Kalle Marjola * gw/smsbox_req.c: fixed bug created by applying a few day old fix... 2000-10-26 Richard Braakman * test/test_headers: Fix memory leaks introduced by http_header_combine test. 2000-10-26 Richard Braakman * gwlib/fdset.[ch]: New module for polling large sets of file descriptors efficiently. Not used yet, intended for HTTP module. * gwlib/gwlib.h: include fdset.h * gwlib/conn.[ch]: Added conn_register and conn_unregister, to use Connections with FDSets. * gwlib/list.[ch]: Wrap list_create just like octstr_create, so that the memory leak listing shows who called list_create. 2000-10-26 Lars Wirzenius * gwlib/dict.c: Initialize hash table elements to be Lists, instead of garbage. * test/test_dict.c: Wrote. * gwlib/http.c: Cleanups: Wait for read_response_thread to terminate at http_shutdown and destroy the started_requests_queue. Also re-implemented the HTTPSocket pool with dict, so that it no longer does linear searches; the code is a bit simpler now as well. * test/test_http.c: Use http_destroy_headers instead of list_destroy. This also fixes a memory leak of one header. 2000-10-26 Lars Wirzenius * gwlib/octstr.c: Give unsigned int as the type to expect to va_arg when converting %u and %hu and similar cases. 2000-10-26 Richard Braakman * gw/wap-appl.c: Use http_header_combine instead of http_append_headers to combine session and request headers, to get the semantics right according to WAE section 8. * gwlib/http.c: Implemented http_header_combine. * test/test_headers.c: Added a test of http_header_combine. 2000-10-26 Lars Wirzenius * gwlib/dict.[ch]: Wrote. * gwlib/gwlib.h: Include dict.h. 2000-10-26 Kalle Marjola * gwlib/conffile.c (config_sanity_check): make sure that there are smsc group(s) and sms-service group(s) if there is smsbox set. 2000-10-26 Lars Wirzenius * gwlib/http.c: Converted to use conn.c. This is a minimal change, and does not yet do multiple transactions in parallel. 2000-10-26 Lars Wirzenius * gw/smsbox.c: Get client IP using http_socket_ip, instead of http_socket_fd. http_socket_fd will be reserved for getting the file descriptor for the HTTP server port only, and may ultimately go away completely. * gw/smsbox_req.c: Bugfix. We gave the allow list as the deny list when checking for sendsms client authorization. 2000-10-26 Kalle Marjola * doc/userguide/userguide.xml: added (m) 'mandatory' and (c) 'conditionally mandatory) markings to all configuration file variables. 2000-10-26 Kalle Marjola * gw/smsbox_req.c: fixed that messages with no translation are handled correctly 2000-10-25 Lars Wirzenius * gw/wml_definitions.h: Commented out OPAQUE, since Cygwin (via some Windows header) defines it, and it isn't being used, anyway. This is an intermin solution, a better one would be to add something like a WML_ or WBXML_ prefix to all those tokens. * gw/wtp_resp_state-decl.h: Renamed WAIT_TIMEOUT to WAIT_TIMEOUT_STATE to get rid of name conflicts with Cygwin headers. * gwlib/socket.c, test/fakewap.c: Removed an include for netinet/tcp.h, which seems to a) not be needed under Linux and b) be unknown to Richard Stevens, so presumably it is non-portable. If it proves to be necessary, we'll add it to configure and include it conditionally. * Thanks to Stipe Tolj for pointing these out. 2000-10-25 Lars Wirzenius * configure{,.in}: Check for pthread_exit instead of pthread_create, when looking for a Posix thread implementation. HP-UX has trouble finding pthread_create, because it is an inline function. 2000-10-25 Richard Braakman * wmlscript/wsstree.[ch], wmlscript/wslexer.c: Fix parsing of integer literal -2147483648. This was done by storing numbers as unsigned longs and introducing an explicit sign field. 2000-10-24 Richard Braakman * gwlib/octstr.c: Add support for formats u, o, x, and X. (test_cimd2 needs X.) * test/test_cimd2.c: Fix errors in octstr_format calls. 2000-10-24 Richard Braakman * wmlscript/wsstdlib.c: Corrected "Phonebook" to "PhoneBook". 2000-10-24 Kalle Marjola * doc/userguide/userguide.xml: filled SMPP smsc group fields, thanks for Mikael Gueck for patch. 2000-10-24 Lars Wirzenius * Finished first phase of reducing the number of threads doing HTTP requests. This phase implements a new interface (http_start_request and http_receive_response, with the http_get and http_post functions being wrappers around these). The goal is to have a static number of threads, internal to the HTTP implementation, doing all HTTP requests at once, instead of having a new thread for each HTTP request. This phase makes that happen, but is implemented so that HTTP requests are done serially, not in parallel. The next phase is to re-write the I/O parts of the HTTP implementation so that HTTP requests are done in parallel once again, using the conn.c module. * gwlib/http.[ch]: Many internal changes. * test/test_http.c: Use the new interface, instead of the http_get wrapper. 2000-10-24 Kalle Marjola * gw/urltrans.c: oops, forgot to switch reservations 2000-10-24 Kalle Marjola * gw/urltrans.c: added missing (disappeared?) room reservation for %q and %Q in get_pattern, and added note why sender and receiver is switched. Thanks for Juho-Pekka Virolainen for noticing this. 2000-10-24 Yann Muller * gw/smsc_at.c: Added support for Falcom A2D modem, thanks to Mike Gaertner. Also changed the default protocol identifier and coding scheme. Preliminary support for Nokia 7110 as SMSC. 2000-10-23 Lars Wirzenius * gwlib/gwmem.h, gwlib/protected.h: Wrote macros to make it harder to call the wrapped functions directly. * gwlib/gwmem-check.c, gwlib/gwmem-native.c, gwlib/protected.c: Call the wrapped functions anyway. :) * gw/bb_smsc.c, test/fakesmsc.c, test/fakewap.c, test/test_cimd2.c, test/wml_tester.c: Use wrappers instead of direct calls to the wrapped functions. * wmlscript/wmlsc.c: Undefine the accident protectors and call the wrapped functions directly. This needs to be fixed later. 2000-10-23 Lars Wirzenius * gwlib/utils.[ch]: Wrote gw_isdigit and gw_isxdigit as wrappers around isdigit and isxdigit, to compensate for broken platforms where they are not available as functions. * gw/smsc_cimd2.c, gw/wsp_headers.c, gwlib/octstr.[ch]: Use gw_isdigit and gw_isxdigit instead of isdigit and isxdigit together with octstr_check_range. 2000-10-23 Lars Wirzenius * configure{.in,}: Don't compile start-stop-daemon, unless the --enable-start-stop-daemon option is used. * gw/smsc_at.c, gw/smsc_emi.c, gw/smsc_sema.c: Define CRTSCTS as zero if it is not defined. * gwlib/socket.c: Allocate the 64 kilobyte buffer dynamically, instead of from the stack. * These changes were prompted by a report of HP/UX compilation changes by Timo Siirainen. 2000-10-23 Lars Wirzenius * ChangeLog: Formatted long lines. 2000-10-23 Kalle Marjola * doc/userguide/userguide.xml: added missing EMI variable connect-allow-ip 2000-10-23 Aarno Syvänen * gw/wtp_resp_state-decl.h: Spec does not say what to do when state is RESULT_RESP_WAIT and event receiving an invoke. Yet 0.12 logs already have these events. Handled event same way when state is RESULT_WAIT. 2000-10-23 Richard Braakman * Made gwthread_poll() actually return the results. 2000-10-23 Richard Braakman * Bugfix: HTTP POST requests have a Content-Length again. Thanks to Stipe Tolj for spotting the problem. 2000-10-20 Kalle Marjola * doc/userguide/userguide.xml: wrote appendix B, using fake SMS center. 2000-10-19 Kalle Marjola * doc/userguide/userguide.xml: added notes on 'required components' for SMS gateways 2000-10-19 Kalle Marjola * gw/wapbox.c: send that wakeup when bearerbox exits, too. 2000-10-19 Kalle Marjola * gw/wapbox.c: modified send_heartbeat to use gwthread_sleep instead of ordinary sleep, so we can use gwthread_wakeup to wake it up when wapbox is killed - now wapbox dies when it catches kill, not after 0-30 seconds. 2000-10-18 Tuomas Luttinen * gw/wml_compiler.c: Now checks also attributes for texts that could be placed in the string table. Also removes non alphanumerical characters from the start and the end of the strings. * gwlib/octstr.[ch]: octstr_strip_nonalphanums added. 2000-10-18 Richard Braakman * gwlib/conn.[ch]: Added conn_wait_multi(). Untested. Fine-tuned the locking in conn_wait. * gwlib/gwthread-pthread.c, gwlib/gwthread.h: Added gwthread_poll(). Untested. 2000-10-18 Richard Braakman * gwlib/charset.c, gwlib/conffile.c, gwlib/counter.c, gwlib/counter.c, gwlib/gwmem-check.c, gwlib/gwmem-native.c, gwlib/gwstr.c, gwlib/parse.c, gwlib/protected.c, gwlib/socket.c, gwlib/thread.c: Reformatted. 2000-10-18 Richard Braakman * configure.in, config.h.in: New test for HAVE_SYS_POLL_H. * gwlib/gwpoll.h, gwlib/gwpoll.c: Files that either include sys/poll.h or define poll() themselves. * gwlib/gwlib.h: Include gwpoll.h. * gwlib/conn.c, gwlib/gwthread-pthread.h: Do not include sys/poll.h directly, let gwlib/gwlib.h do it. 2000-10-18 Richard Braakman * gw/bb_udp.c, gwlib/http.c: Corrected some stray free() calls to gw_free(). 2000-10-18 Kalle Marjola * gw/bearerbox.c: Use new report_version in HTTP admin status, too. 2000-10-18 Lars Wirzenius * gw/shared.[ch]: Added function version_report_string so that the report_version() info can be reported via HTTP as well. 2000-10-18 Kalle Marjola * gw/smsc_fake.c: fixed that message sending is not tried with closed socket, but error is returned instead * gw/bb_*.c: added missing queueing information to status: now all lists are added together before reporting queue lengths 2000-10-18 Aarno Syvänen * gw/wtp_init_state-decl.h, wtp_resp_state-decl.h: Add a comment tell- ing which CR is implemented. Now all deviations from June 2000 con- formance release are explained. 2000-10-18 Kalle Marjola * gw/bearerbox.c: updated 'status' to tell number of messages still queued in main queues (internal specific queues are not yet counted) * gw/bb_*.c: Did initial code changes for 'xmlstatus' query, although it does not return anything yet. 2000-10-18 Lars Wirzenius * gw/urltrans.c: Fix off-by-one error in is_safe array size in encode_for_url(). 2000-10-18 Lars Wirzenius * gw/bearerbox.c, gw/smsbox.c, gw/wapbox.c: Added missing #include "shared.h". 2000-10-17 Lars Wirzenius * gwlib/gwlib.c: Reformatted to new coding style. * gw/shared.[ch]: New files to hold the function report_versions (and other functions in the future). This function reports the version of Kannel that starts up, and the host it runs on, and the version of libxml. * gw/bearerbox.c, gw/smsbox.c, gw/wapbox.c: Call report_versions. 2000-10-17 Tuomas Luttinen * gw/urltrans.c: Changed the logic in the encode_for_url so that the safe ones are listed and the save characters being alphanums and marks "-", "_", ".", "!", "~", "*", "'", "(", ")". Also UTF-8 with full spectrum of Unicode should work now. 2000-10-17 Kalle Marjola * gw/smsbox.c: Added requested event of sent message 2000-10-16 Lars Wirzenius * gwlib/log.c: Reformatted. Also made kannel_syslog's mapping of Kannel's log level to syslog log levels actually work. 2000-10-16 Lars Wirzenius * checks/check_counter.c, checks/check_date.c, checks/check_list.c, checks/check_octstr.c, gwlib/log.c, gwlib/log.h, gwlib/utils.c: Renamed the log level enums to have a GW_ prefix, to avoid problems with broken compilers that define ERROR themselves or in some header. 2000-10-16 Lars Wirzenius * config.h.in, configure{,.in}: Check for the magic compiler (not preprocessor) symbols __func__ (standard in the 1999 version of the standard) and __FUNCTION__ (popular extension to the 1989 version of the standard). Define __func__ as __FUNCTION__ or "unknown" depending on what is available. * gwlib/gwassert.h, gwlib/gwmem.h, gwlib/octstr.c: Use __func__ instead of __FUNCTION__. 2000-10-16 Lars Wirzenius * config.h.in, configure{,.in}, gwlib/gw-getopt.h: Check for a prototype for getopt in stdio.h and unistd.h as well, and only use our own one if we fail to find anything. This should make Kannel compile on Solaris again. 2000-10-16 Aarno Syvänen * gw/wtp_resp_state-decl.h: Removed CR inside a string. 2000-10-13 Tuomas Luttinen * gw/wml_compiler.c: parse_entities added as a fast patch to fullfill WAP 1.1 conformance with WML entities. 2000-10-13 Lars Wirzenius * gwlib/gw-getopt.h: Wrote. This header makes sure getopt() and the corresponding variables are declared properly so that any program that includes gwlib/gwlib.h can use getopt without worrying. This should make it unnecessary to clutter all programs with #if HAVE_GETOPT_H stuff. * gwlib/gwlib.h: Include gw-getopt.h. * wmlscript/wmlsc.c, wmlscript/wmlsdasm.c: Make sure gwlib.h is included. 2000-10-13 Lars Wirzenius * gwlib/http.c: Disable the start_request_thread as well. It caused "make check" to fail (I ran it in the wrong directory *sigh*). * test/test_http.c: Use http_get until http_start_get and http_receive_result work properly. 2000-10-13 Lars Wirzenius * gwlib/http.c: Disable the kludge_do_one_request thread, since it isn't killed (or joined) properly. 2000-10-12 Kalle Marjola * doc/userguide/userguide.xml: added new example: multi-operator SMS Kannel. 2000-10-12 Lars Wirzenius * gwlib/http.[ch]: Added a prototype implementation for the new start/receive-result interface to HTTP requests (see functions http_start_get and http_receive_result). Don't use this yet, it needs to be implemented properly. * test/test_http.c: Modified to use the new interface. 2000-10-12 Richard Braakman * gwlib/gwassert.h: Added parentheses around the panic(...), 0 expressions in the assert macros, to get the originally intended meaning. 2000-10-12 Richard Braakman * wmlscript/wserror.c: Corrected a stray va_arg(ap, char). (va_arg should always get the type as it is after promotion, and char is promoted to int.) 2000-10-12 Lars Wirzenius * gwlib/http.c: When we are the server side, and the client uses HTTP 1.0, we will close the connection. If the client uses HTTP 1.1, we keep it open. * gw/smsbox.c: Remove the workaround for the missing feature now implemented. 2000-10-12 Kalle Marjola * gw/bearerbox.c, gw/bb_boxc.c, gw/bb_udp.c, gw/bb_smsc.c: Startup improved; not based on 'hopefully they will get up by that time' system but intra-thread wakeup call. Now the bearerbox starts up very quickly. 2000-10-11 Tuomas Luttinen * gw/urltrans.c: Fixed the bug 111 by adding the unwise characters and special characters like delete (0x7f) and other between 0x00 and 0x1f into the unsafe ones. * gw/wml_compiler.c (string_table_apply): Fixed a bug where an extra string end was added in a case that two (or more) substrings are replaced with the 2nd (3rd...) being the first to be replaced. 2000-10-11 Lars Wirzenius * gw/wapbox.c: Formatted to follow coding style. 2000-10-11 Lars Wirzenius * gw/wapbox.c: Simplified the main loop. Also removed the initialization of ret (which was done at the definition of the variable, tens of lines above, which is bad style). Removed comments at end of braces, which is also bad style (if it is not obvious what the braces end, the loop or whatever construct is too long or indentation is broken). 2000-10-11 Aarno Syvänen * gw/wapbox.c: Separate conditions event == NULL and event_is_for_ responder in code selecting to which wtp process an incoming event belongs. 2000-10-11 Peter Gronholm * gw/control.html: Updated the example file to reflect the new http interface administration commands. 2000-10-11 Kalle Marjola * gw/bb_http.c: fixed that query parsing value '0' is not accepted, only '1' * doc/userguide/userguide.xml: added notes about sms-service 'default' 2000-10-10 Richard Braakman * wmlscript/{ws.c, wsgram.y, wsstree.[ch]}: Remove WsPair and replace it with more specific types WsVarDec and WsFormalParm. This gets rid of an assumption that a long will fit in a (void *) field, which tends not to be true on 64-bit platforms. 2000-10-10 Richard Braakman * wmlscript/wsencode.c: Fix va_arg type bug for all platforms, not just sparc. Removed SPARC_ABI conditionals. 2000-10-10 Lars Wirzenius * debian/postinst: Don't use /var/log/kannel as home directory for user kannel. 2000-10-10 Lars Wirzenius * debian/postinst: Now updates rc.d links and starts Kannel. * debian/postrm: Wrote. Removes rc.d links. 2000-10-10 Richard Braakman * gw/wsp-method-state.h: Fixed state transition for TR-Abort.Ind, in state REPLYING. Thanks to Aymerick Jéhann for noticing. 2000-10-10 Lars Wirzenius * gw/wtp_init_state-decl.h: Fixed misspelled INITIATOR_RESULT_WAIT. 2000-10-10 Lars Wirzenius * debian/rules: "clean" doesn't run "make clean" unless Makefile exists. 2000-10-10 Lars Wirzenius * debian/init: start kannel boxes as user "kannel" instead of root. run_kannel_box needs to run as root to create the pid file. * debian/postinst: Wrote. Creates user kannel and make /var/log/kannel be owned by kannel. * utils/run_kannel_box.c: Added --no-extra-args option, so that we can run other programs than Kannel boxes (su, in this case, to switch users). 2000-10-10 Aarno Syvanen * gw/wtp_init_state-decl.h: Prevent RCR growing greater than its maximum allowed value. 2000-10-10 Kalle Marjola * gwlib/octstr.c: fixed bug in octstr_str_compare 2000-10-10 Kalle Marjola * gwlib/socket.c: moved 'errno' from second call to first one in connect_to_server to avoid tempering with it before we report the error. 2000-10-10 Lars Wirzenius * gwlib/gwthread.h: Removed unnecessary and bad ## operator from gwthread_create wrapper macro. It pasted together two string literals, creating an invalid pre-processing token, thus causing small red daemons to fly out of my nose, flapping their wings furiously, and thus causing a small wind to blow in Rio de Janeiro, turning the page of the book being read by a local critic and causing him to complain in his article about the book that it was repetitive. Be careful with those undefined behaviors, folks, you never know what will happen. * gw/wap-appl.c, gw/wsp.h: Added function wsp_http_map_destroy, from Paul Keogh. * gw/wapbox.c: Call wsp_http_map_destroy at shutdown. 2000-10-09 Richard Braakman * wmlscript/wsopt.c: Add an optimization to remove useless tobool conversions. 2000-10-09 Richard Braakman * wmlscript/wsstree.c: Always convert the result of an && or || operator to boolean, because the spec requires it for typeof(). 2000-10-09 Aarno Syvänen * gw/wtp_init.c, wtp_resp.c: When the state machines cannot handle an event, we ignore it and log an error message. Timer will abort this tranaction. 2000-10-09 Richard Braakman * gw/smsc_cimd2.c: Converted to new formatting style. 2000-10-09 Aarno Syvänen * gw/wtp_state-decl.h: Incorporated CR-Nokia-WTP-20-March-2000/2. In plain words, when load is heavy, Ack(TidOK) may be delayed so much that initiator will retransmit it and the responder will re- ceive the original when its state is RESULT_WAIT. This Ack must be ignored. This corrects bug reported by David. 2000-10-09 Richard Braakman * wmlscript/wsgram.y: Compile unary + such that it performs the required type conversions. 2000-10-09 Richard Braakman * wmlscript/wsasm.c: Fixed error in jump distance calculation when jumping backward over a forward jump. This messed up "continue" statements among other things. 2000-10-09 Richard Braakman * Renamed Msg type smart_sms to sms. 2000-10-09 Richard Braakman * gwlib/octstr.c: Rearranged immutable octstrs so that seems_valid() correctly flags freed octstrs again. Added !immutable assertions to octstr_grow and octstr_set_char. Reformatted octstr_append_from_hex. * test/test_http.c: Fixed memory leak in case of server not responding. 2000-10-09 Aarno Syvänen * gw/wtp_init.c: Remove an unused variable. 2000-10-06 Richard Braakman * gwlib/utils.c: Changed kannel_cfmakeraw() comments to match reality. 2000-10-06 Aarno Syvänen * gw/wtp*: Reformat (except wtp_pdu.*). * gw/wtp_resp_state-decl.h: More comments. * gw/wtp_init.c, gw/wtp_init_state-decl.h: wtp had a tid of its own, so no mutexes are needed here. 2000-10-06 Richard Braakman * gw/smsc.c: Reactivate the code that sets the timestamp on an sms message, if the SMSC didn't set it. Thanks to Jarkko Kovala for noticing. 2000-10-06 Richard Braakman * Making release 0.11.3 2000-10-06 Richard Braakman * doc/userguide/userguide.xml: Terminate OTA CGI table so that it compiles. * gw/smsbox.c, gw_smsbox_req.[ch]: Give smsbox_req_sendota() a "client_ip" parameter so that it can call authorise_user correctly. * gw/smsbox_req.c: smsbox_req_sendota(): Remove unused variables. Use octstr_create("") instead of the no longer existing octstr_create_empty(). * gw/bb_boxc.c: Fix memory leak in route_msg() when routing WAP packet but no wapboxes are connected. * gwlib/http.c: Fixed silly bug in http_remove_hop_headers that would make the wapbox panic if a server used the Connection: header. Fixed memory leak in same function. 2000-10-05 Yann Muller * gw/smsbox_req.c/h: added smsbox_req_sendota() to send OTA config messages. * smsbox.c: calls smsbox_req_sendota() if cgi address matches '/cgi-bin/sendota'. * doc/userguide/userguide.xml: added info about config and usage of OTA. * gwlib/octstr.c/h: added octstr_append_from_hex(). 2000-10-05 Kalle Marjola * doc/userguide/userguide.xml: language corrected. 2000-10-05 Richard Braakman * Added seems_valid assertion to end of octstr_format(). * gw/wap-appl.c: Fixed silly mistake that caused random panics. 2000-10-05 Richard Braakman * gw/wap-appl.c: Bugfix, don't panic if resp_headers is NULL (i.e. the HTTP request failed). * gw/fakewap.c: Correctly encode requests with urls longer than 128 bytes. 2000-10-05 Kalle Marjola * test/fakesmsc.c: use info level to inform that all messages have been sent. 2000-10-05 Richard Braakman * wmlscript/*: Reformatted. 2000-10-05 Kalle Marjola * gw/smsbox_req.c: made sure that when max_msgs == 0 then no messages are sent. 2000-10-05 Richard Braakman * gw/wsp_headers.c: Bugfix in pack_integer_string, use ULONG_MAX instead of UINT_MAX and include the right header file. 2000-10-04 Richard Braakman * gw/wap-appl.c: Pass the status code we really got from the server to the client, instead of only accepting code 200 (HTTP_OK). Use 502 (Bad Gateway) if the actual lookup failed. Use http_get and http_post instead of http_get_real and http_post_real. Together with the header encoding patch earlier today, these changes allow HTTP redirection to work. * gw/wap-appl.c, gwlib/http.h: Use symbolic names for HTTP status codes. * gw/wsp_headers.c: Correct small bug that made wsp_headers_pack encode the content-type twice if separate_content_type was on. 2000-10-04 Richard Braakman * gwlib/gwmem.h, gwlib/gwmem-check.c: Let gw_claim_area return the pointer it gets, and let it accept NULL pointers. This makes it easier to use in wrapper macros. * gwlib/octstr.[ch]: Wrap octstr_create, octstr_create_from_data, octstr_copy, and octstr_duplicate so that they "claim" the Octstr they return for their caller. This information will show up in the gw_check_leaks() output, making memory leaks much easier to trace. * gw/wsp_headers.c, gwlib/http.c: Fix memory leaks found this way. 2000-10-04 Richard Braakman * Encode response headers and send them to the client: * gw/wsp_headers.[ch]: Added wsp_headers_pack. Fixed some bugs in wsp_headers_unpack. Replaced a few magic numbers with names. Reformatted. * checks/check_headers.sh, test/test_headers.c, test/header_test: New files. Exercise header code by packing and unpacking a set of headers that try to cover all possibilities. * test/fakewap.c: Be less strict in checking Reply packet, because it can no longer assume the response headers are empty. (Implementing full parsing wouldn't be worth the effort.) * gw/wap-appl.c: Added http_remove_hop_headers and used it to delete hop-by-hop headers when forwarding HTTP headers to client or server. (The hop-by-hop headers are for one connection only, for example Transfer-Encoding.) * gw/wap-appl.c: When applying a content converter to the response body, update the response headers to reflect this. * gw/wap-appl.c: Fill in the response_headers field of S_MethodResult_Req and S_Unit_MethodResult_Req events, now that they're used. * gw/wap-events-def: In the S_MethodResult_Req, response_headers is a HTTPHEADER, not an OCTSTR. Removed response_type field from the MethodResult events, it's not used and the information is present in response_headers. * gw/wsp-method-state.h, gw/wsp-session-state.h, gw/wsp-unit.c: Renamed unpack_headers to wsp_headers_unpack to match function naming convention. Use wsp_headers_pack instead of wsp_encode_http_headers. * gw/wsp-strings.def: Introduce some new tables used for header encoding. * gw/wsp.c, gw/wsp.h: Deleted wsp_encode_http_headers, it's obsoleted by wsp_headers_pack. * gw/wsp.c: Changed wsp_convert_http_status_to_wsp_status to handle all defined status values. * gwlib/http.[ch]: Added several utility functions used by header packing. Minor formatting corrections. * gwlib/octstr.c: Added assertions to octstr_append* functions to prevent segfault. 2000-10-04 Kalle Marjola * gwlib/conffile.c|h: added new function 'config_sanity_check' to check configuration files for basic errors (like empty lines in the middle of groups). * gw/*box.c: modified to use that new function 2000-10-04 Kalle Marjola * gw/smsc.c, gw/smsc_p.h, gw/smsc_emi.c: added configuration variable 'connect-allow-ip' currently used by emi_ip in certain situations - banned connect from other IPs, so you have to set this variable if you still want to use emi_ip with receive port. * gwlib/socket.c: removed loist of 'errno' from error, to minimize double system error outputs. 2000-10-03 Kalle Marjola * gw/smsbox.c: Fixed that we tried to close non-opened http-server-socket, which caused PANIC. 2000-10-03 Kalle Marjola * gw/bb_smsc.c: Fixed a nice bug that appeared only with severe load. 2000-10-03 Kalle Marjola * gw/bb-smsc.c: added SMS multi-send. This is achieved via multiple phone numbers at 'to' field in send-SMS request, each separated with space (currently, possibly changed later). This is not a complete multi-send at SMSC protocol level - the message is splitted into several ones in bearerbox before sending it to SMSC. Note that 'preferred-prefix' and 'denied-prefix' only care about the FIRST phone number in such a message (anyway, use smsc ID instead) * doc/userguide/userguide.xml: added notes on multi-send 2000-10-03 Lars Wirzenius * debian/changelog: Added new entry for newer upstream version number. * debian/copyright: fixed spelling of Wapit (used to be WapIT). * debian/conffiles: New file, lists the files in the Debian package that are marked as configuration files. * debian/init: No longer automatically copied from utils/kannel-init.d, since we can't guarantee that would be the right thing to do for a Debian package. Updated to work on Debian (box path was wrong). * debian/kannel.conf: Re-wrote to work with newer config file syntax. * debian/kannel.wapconf: Removed, no longer needed. * debian/rules: fixed so it works with current Kannel. Also added manual page installation, etc. * gw/kannel.8, utils/run_kannel_box.8, utils/seewbmp.1, wmlscript/wmlsc.1, wmlscript/wmlsdasm.1: Wrote skeletal manual pages for various parts of Kannel that are installed by the Debian package. 2000-10-03 Richard Braakman * gw/wsp_headers.c: Bugfix in multi_octet_integer for integers exactly as large as a long. * gwlib/date.c: Bugfixes for parsing non-recommended (but still standard) date formats. * gwlib/parse.c: Bugfixes in parse_peek_char and parse_get_uintvar. * utils/run-checks: Don't report success if a test failed silently. Add the name of the failing check to check.log. 2000-10-03 Tuomas Luttinen * gw/wml_definitions.h: some data types unified. * gw/wml_compiler.c: Code updated to the new coding style. Old character set conversion code mostly removed, some skeletons still in the closet. Hash table code added, wml_init and wml_shutdown written, but not yet used or tested. * gwlib/octstr.[ch]: octstr_hash_key-function added. 2000-10-03 Kalle Marjola * test/fakesmsc.c: Updated to use general Kannel command line interface - now use options -p, -i and -m to set various fakesmsc settings. Also changed messages to 'debug' level so that there is some use for -v argument. 2000-10-03 Richard Braakman * gw/wsp-strings.c: Correct silly mistake in string_to_number. 2000-10-03 Kalle Marjola * gw/smsbox.c, gw/smsbox_req.c|h: added new smsbox configuration variable 'sendsms-chars' which is used to prevent garbage requests. NOTE: if you are running SMS services, you should check this out! (see user guide) * gw/smsbox_req.c: allowed 'user' and 'password' in place of 'username' and 'password' in sendsms request. * doc/userguide/userguide.xml: userguide upgraded to reflect these. 2000-10-02 Paul Keogh * gw/cookies.c: Updated comment and fixed bug in get_cookies() 2000-10-02 Kalle Marjola * gw/smsbox_req.c: fixed possible crash (panic) with malformed http request 2000-10-02 Kalle Marjola * doc/userguide/userguide.xml: added 'pin' to GSM Phone smsc, did some output formatting. 2000-10-02 Richard Braakman * doc/userguide/userguide.xml: Explained CIMD2 keepalive option. 2000-10-02 Kalle Marjola * README: updated. Removed old references to test_wml, ooutdated libxml version etc. * doc/userguide/userguide.xml: some fix 2000-09-30 Kalle Marjola * doc/userguide/userguide.xml: some update 2000-09-30 Kalle Marjola * doc/userguide/userguide.xml: little update for SMS center groups. Still missing values and meanings for some attributes. 2000-09-29 Richard Braakman * gw/wtp_init.c, gw/wtp_resp.c: Fixed some compiler warnings. 2000-09-29 Kalle Marjola * doc/userguide/userguide.xml: It has been done. Now (practically) all data is rendered into XML and there is list of examples and other things. However, we are missing settings for some SMS centers and their exact names and things like that, help needed. 2000-09-29 Kalle Marjola * doc/userguide/userguide.xml: rest of the newconf.txt moved into this, and some of it edited to XML * doc/userguide/newconf.txt: removed 2000-09-29 Kalle Marjola * doc/userguide/userguide.xml: moved rest of the newconf.txt main things into it, but not yet formatted. 2000-09-29 Richard Braakman * doc/*: Ran spelling checker over most documents. 2000-09-29 Kalle Marjola * doc/userguide/userguide.xml: updating, moved all data from newbb.txt into this and did some reorganisating. Started to insert entire newconf.txt into this. * doc/userguide/newconf.txt: some data already moved to User Guide * doc/userguide/newbb.txt: removed * gw/*kannel.conf, README: updated file references 2000-09-28 Kalle Marjola * doc/userguide/userguide.xml: fixed mismatch and put some extra words about 'my_conf.conf'. More update coming tomorrow... 2000-09-28 Aarno Syvänen * gw/wsp-session.c: Calling wtp_resp_dispatch event and wtp_resp_get_ address_tuple * gw/wsp-session|method-state.h : Calling wtp_resp_dispatch_event * gw/wap-events-def.h: Added event TR-Invoke.cnf * gw/wtp.c|h: Added new external function wtp_event_id_for_responder. This checks first bit of tid. Added helper functions unpack_invoke, unpack_ack and unpack_abort. * gw/wtp_resp.c|h, gw/wtp.c|h: Transferring responder machine code to a separate module (we have an iniator, too). * gw/wtp_resp.c: Most error checking transferred to the function rep_machine_find_or_create. Refer to WTP, 10.2, table 33 when comment- ing. * gw/wtp_init.c|h, gw/init_state-decl.h, gw/init_machine-decl.h: Wrote code for wtp iniator (for classes 0 and 1). * gw/wapbox.c: Sending incoming message to the iniator or the responder, depending on the first bit of the tid. Shutting down and iniating the iniator and responder, too. * gw/wtp_send.c|h: New functions add_responder_address and add_ iniator_address (to avoid void pointer). In functions, use field of a machine type instead of the machine itself, if possible. Added function wtp_send_invoke to the interface, removed do_not_start * gw/wtp_resp_state-decl.h: Renamed wtp_state-decl.h. Reformatted comments. Use variable name resp_machine instead of machine every- where. Make use of the new wtp_send interface. Do not turn u_ack flag, but ack_pdu_sent (this bug is pointed out out by Huang Li), when ack pdu was send. Used constant ACKNOWLEDGEMENT everywhere in wtp_send_calls. Noticed invalid use of 'resent' in the specs. Rid-flag is not turned when ack is sent, because the iniator does not use this flag (only rid of result message is used by it. This is pointed out by Huang Li, too). * gw/wtp_tid.c|h: Used variable resp_machine (and corresponding type) everywhere 2000-09-29 Richard Braakman * checks/check_date.c: Wrote. * checks/test_dates: Test material for testing dates. * gwlib/date.[ch]: Added date_parse_http(). Fixed some bugs in date_format_http() uncovered by check_date. 2000-09-28 Lars Wirzenius * gwlib/socket.c: udp_bind: Recognize interf "*" as an alias for INADDR_ANY, so that Kannel again follows documentation. 2000-09-27 Richard Braakman * gw/wsp-strings.c: Changed everything in order to get case-insensitive string lookup working right. Converted to new formatting rules. * gw/wsp-strings.h, gw/wsp-strings.def: Improved comments. 2000-09-27 Lars Wirzenius * gw/wtp_state-decl.h: Removed handling of event RcvInvoke in state RESULT_RESP_WAIT, since that was neither in the spec and seems to do nothing useful. 2000-09-27 Lars Wirzenius * gw/smsbox.c, gw/wapbox.c, doc/userguide/newconf.txt: Added configuration variable http-proxy-exceptions. 2000-09-27 Tuomas Luttinen * configure[.in]: Support for libxml1 removed, only 2.2.0 and up now. 2000-09-27 Richard Braakman * gw/smsc_emi.c: Correct calculation of message length for UDH messages. 2000-09-27 Lars Wirzenius * gw/wapbox.c: moved http-proxy-host and http-proxy-port into "core" from "wapbox" section. (That's where they were for the smsbox as well.) Also added the code that actually makes use of the proxy support, by calling http_use_proxy. * gwlib/http.c: Allow the list of exceptions to be NULL, to simplify the case when no exceptions are wanted. Also report when a proxy is being used. 2000-09-27 Richard Braakman * gw/wsp.c: Encode all known content types, not just the most common ones. * gw/wsp-strings.def: s/applicatoin/application in one of the content types. 2000-09-26 Lars Wirzenius * gw/wap-appl.c: Added Via header to HTTP requests. * gwlib/socket.[ch]: Wrote function get_official_name. * gwlib/octstr.c: Don't call gwlib_assert_init, instead assert that octstr itself has been initialized. This is necessary because socket.c now needs to use octet strings before gwlib has been fully initialized. 2000-09-26 Richard Braakman * Making release 0.11.2. 2000-09-26 Lars Wirzenius * gw/smsbox_req.c: smsbox used to dump core if the sendsms username was incorrect, now it correctly returned authorization failure. Fixes bug report 105 from Paul Keogh. 2000-09-26 Lars Wirzenius * test/fakesmsc.c: Initialize the third parameter to accept correctly. I wonder why this has ever worked. 2000-09-26 Kalle Marjola * gw/smsbox_req.c, gw/urltrans.c: set so that message without any content is passed to default service group, not ignored. Fixed request count, too. 2000-09-25 Richard Braakman * gwlib/conn.c: Make conn_read_line() work more than once. Thanks to mulix@actcom.co.il for reporting this. * gw/wtp_send.[ch], gw/wtp_state-decl.h: Removed "event" parameter from wtp_send_abort and wtp_send_ack. There were assertions for this (otherwise unused) parameter which caused the function to fail if the event was for example a timeout. 2000-09-25 Lars Wirzenius * checks/check_http.sh: Check for "ERROR:" in log file. * gw/html.h: Include gwlib/gwlib.h, not octstr.h. * test/test_http.c: Add -q option. * gwlib/http.c: Bugfix. Format string said %s when it should have said %S. 2000-09-25 Kalle Marjola * gw/smsbox*.*: activated sendsms-user allow/deny-ip strings * gw/urltrans.c|h: appropriate modifications to that file * doc/userguide/userguide.xml: started to write a new chapter about SMS Kannel setup 2000-09-25 Kalle Marjola * gw/bb_udp.c, gwlib/socket.c|h, test/test_udp.c: inserted interface-name patch by Andreas Fink. 2000-09-25 Lars Wirzenius * doc/userguide/newconf.txt: Added slightly better descriptions from Paul Keogh for SMS2000 config variables. 2000-09-25 Kalle Marjola * doc/userguide/userguide.xml, doc/userguide/newconf.txt: updated to include notes about SMSC ID use. * gw/bb_smsc.c, gw/smsc.c|h, gw/smsc_p.h: added preferred-id and denied-id configuration variable for SMS routing 2000-09-25 Kalle Marjola * gwlib/utils.c: added str_find_substr * gw/urltrans.c|h: added 'smsc' to find_translations, and forced-smsc, default-smsc and accepted-smsc for translation groups. Accepted-smsc is now in full use, so if you need sms-services linked to used SMSC, use it (and smsc-id for corresponding SMSC) * gw/smsbox_req.c: set smsc_id for send-sms requests * doc/userguide/newconf.txt: added new attributes here 2000-09-25 Kalle Marjola * gwlib/utils.c (get_and_set_debugs): fixed '--' parsing 2000-09-22 Kalle Marjola * gwlib/utils.c: set that command line option '--' ends option parsing. Thanks to Kari Lempiainen for finding this, although I added one 'break' to it, too. 2000-09-22 Richard Braakman * gw/timers.c: Correctly record elapse-event in gwtimer_start. Oops. This also fixes a memory leak. 2000-09-22 Richard Braakman * gwlib/protected.[ch]: Removed gw_getlocale(). Despite protection, toggling locale settings is inherently not thread-safe. * gwlib/date.[ch]: Started file for date handling functions. Contains date_format_http(). It is a reimplementation of rfc2068_date_format() but does not use setlocale trickery. * Removed rfc2068_date_format() from gwlib/utils.[ch] and made gw/wsp_headers.c call the new function. 2000-09-22 Richard Braakman * gw/wsp-session.c: Corrected capabilities negotiation. This is not the promised rewrite, and its replies are still longer than they need to be, but it follows the standard now. * gw/wsp_caps.[ch]: Added helper function wsp_cap_get_server_sdu. 2000-09-22 Kalle Marjola * gw/smsbox_req.c: edited access log entries, now the HTTP request status is logged etc. 2000-09-22 Kalle Marjola * gw/smsbox.c: added opening/closing of access log * gw/smsbox_req.c: added access log entries for requests (send-sms and MO), and modified the entire MO SMS lifetime so that 'request failed' replies to max-messages = 0 translations still get that answer * gw/smsc.c|h: changed so that smsc_send_message does not destroy the msg * gw/bb_smsc.c: updated access log entry * doc/userguide/newconf.txt: added access-log into variables. Still missing smsc-id, as the implementation is not finalized. 2000-09-21 Kalle Marjola * gwlib/accesslog.c|h: added first version of access log system * smsc.c|h: added SMSC Id (a bit like name but user defined) * gw/msg-decl.h: added SMSC Id to SMS messages * gw/bb_smsc.c, gw/bearerbox.c: added access log entries for incoming/outgoing SMS messages * gw/smsbox_req.c: added 'smsc' entry for send-sms interface, but not yet supported. 2000-09-21 Lars Wirzenius * gwlib/http.c: Use octstr_case_search instead of octstr_convert_range and octstr_search to check whether a URL begins with "http://". 2000-09-21 Lars Wirzenius * checks/check_octstr.c: Wrote. * gwlib/octstr.[ch]: Wrote new function octstr_case_search. 2000-09-21 Lars Wirzenius * gwlib/octstr.c: octstr_compare: Fixed behavior when either argument was a zero length octet string. It used to always return zero, now it returns -1 or 1 if the other argument is not a zero length octet string. * gwlib/octstr.[ch]: Wrote octstr_case_compare. 2000-09-21 Lars Wirzenius * gwlib/octstr.c: Reformatted to new code layout. 2000-09-21 Lars Wirzenius * gw/wapbox.c: Start the WAP application layer before the heartbeat thread. This prevents a race condition at startup. 2000-09-21 Richard Braakman * gw/timers.c: In TimerHeap struct, rename "heap" field to "tab". There's something confusing about heap->heap[index]. * gw/timers.c: Simplified main loop in the timer thread. Made it process all elapsed timers before releasing its lock -- should be faster if a bunch of timers elapse at once. 2000-09-20 Richard Braakman * gw/wsp_headers.c: Try to skip over unknown code pages more intelligently. 2000-09-20 Richard Braakman * gw/timers.[ch], gw/wtp.c: Renamed timer_* to gwtimer_* to avoid name conflict with system functions. Sigh. 2000-09-20 Richard Braakman * gw/timers.c: Reformatted according to new layout standard. 2000-09-20 Richard Braakman * gw/timers.c: Implement the heap structure using a C array, instead of using List. This has less overhead and removes the need for list_swap. * gw/list.[ch]: Remove list_swap. 2000-09-20 Richard Braakman * gw/timers.[ch]: Removed timersets from the interface. The choice of what timers should be handled by a single thread is a performance issue, not an interface issue. All timers are now handled by a single timer thread. The choice of output list is now specified per timer, instead of per timer set. Added timer_init and timer_shutdown functions that should be called before creating any timers. * gw/wapbox.c, gw/wtp.c: Adjust to new timers interface. 2000-09-19 Richard Braakman * gw/timers.c, gw/timers.h: New timers. Faster, better, and they actually time out. * gw/wtp_timer.c, gw/wtp_timer.h: Removed. (Remnants of old timer code). * gw/wapbox.c: Removed references to old timer code. It's now completely hidden in the wtp layer. Other layers can get their own timers. * gw/wtp.c: Use new timers. Added some convenience functions (start_timer_A and start_timer_R). Handle TimerTO_* events. There's no start_timer_W yet because we don't use it yet. * gw/wtp.h: Use new timers. * gw/wap-events-def.h: TimerTO_* events get a machine handle instead of a dummy field, so that the WTP layer knows which machine timed out. * gw/wtp_state-decl.h: Use new timers, by calling the convenience functions. There's no real timer code left in the state machines. * gw/list.c, gw/list.h: Made list_delete_matching and list_delete_equal return the count of items deleted. Getting that info from an atomic operation is useful for the timer code. Also added list_swap function. 2000-09-19 Richard Braakman * gw/wtp.[ch], gw/wtp_machine_decl.h: Removed unused field type LIST from state machines. 2000-09-19 Lars Wirzenius * gwlib/list.[ch]: Removed list_cat function, as it is now unused. 2000-09-19 Tuomas Luttinen * gw/wml_compiler.c: Added wml_init and wml_shutdown that do nothing yet, removed call to list_cat. * gw/wml_compiler.h: Added prototypes for wml_init and wml_shutdown. 2000-09-18 Richard Braakman * gw/smsc_smpp.c: Make charset_iso_to_smpp and charset_smpp_to_iso work with character values > 128. Bugfix suggested by Philip Chr. Psiloinis. 2000-09-18 Lars Wirzenius * doc/CodingStyle: Added example of coding style. 2000-09-18 Lars Wirzenius * ChangeLog, debian/init, gw/bb_boxc.c, gw/bb_http.c, gw/html.h, gw/msg.c, gw/urltrans.c, gwlib/conffile.c, gwlib/conffile.h, gwlib/gwassert.h, gwlib/gwstr.h, gwlib/gwthread-pthread.c, gwlib/http.c, gwlib/http.h, gwlib/list.c, gwlib/list.h, gwlib/log.h, gwlib/octstr.c, gwlib/octstr.h, gwlib/socket.c, gwlib/thread.c, gwlib/thread.h, gwlib/utils.c: Folded some long lines (see utils/find-long-lines). 2000-09-18 Lars Wirzenius * gwlib/octstr.c: Shut up char/unsigned char implicit conversion warning by adding a cast. 2000-09-18 Derry Hamilton * gwlib/thread.h: changed the call to mutex_init_static_real to actually pass the mutex when MUTEX_STATS are required. 2000-09-18 Kalle Marjola * gwlib/utils.c (get_and_set_debugs): PANIC if unknown option is encountered, to avoid misuse of options. 2000-09-18 Kalle Marjola * gw/bb_http.c (httpd_serve): when receiving an unknown command, tells the received url back to caller 2000-09-18 Kalle Marjola * gw/smsbox.c (init_smsbox): fixed bug reported by Paul Keogh. * gw/bearerbox.c: some fix to shutdown order 2000-09-14 Lars Wirzenius * utils/source-stats: Wrote. 2000-09-14 Lars Wirzenius * config.h.in, configure.in, configure, gwlib/socket.[ch], gwlib/getnameinfo.h: Killed the getnameinfo implementation. Yet another non-standard function that we don't even refer to anymore. 2000-09-14 Lars Wirzenius * gwlib/log.[ch]: Removed the `forced' log level, since it is pointless and unused. 2000-09-14 Lars Wirzenius * config.h.in, configure, configure.in, gwlib/utils.[ch]: Always use kannel_cfmakeraw, instead of the libc one. This simplifies configuration, and lets us not have to worry about having another cfmakeraw in a non-glibc library that does something else than the glibc one. Or about the glibc one changing behavior sometime in the future. (Oh the joys of using extensions to the standard libraries...) 2000-09-14 Lars Wirzenius * gw/wap-appl.c, gw/wsp.h: Added function wap_appl_get_load, which gives a current load average for the application layer (which is essentially the only sensible place to look for load averages), defined as the sum of the length of request queue and number of HTTP fetches that are currently happening. The old getloadavg method is deleted, but if this one proves to be completely unworkable, we can always salvage the code from CVS. On the other hand, this method actually works on systems that don't have a getloadavg, and works even on systems where getloadavg is defined differently (imagine running two different wapboxes). * gw/wapbox.c: Use wap_appl_get_load instead of getloadavg. * configure{,.in}: Removed checks for getloadavg. 2000-09-14 Lars Wirzenius * gwlib/http.c: Ran through astyle to get formatting right. 2000-09-14 Lars Wirzenius * gwlib/http.c: Removed internal function octstr_str_ncompare, replacing it with calls to octstr_search and octstr_create_immutable. Die *_cstr, die! 2000-09-14 Lars Wirzenius * gwlib/octstr.[ch]: Added `pos' argument to octstr_search to let caller specify from where the search in the haystack starts. Also, octstr_format now understands %c. * gw/html.c, gw/smsc_at.c, gw/wap-appl.c, gw/wsp_headers.c, gwlib/http.c, gwlib/octstr.c, test/drive_wapbox.c, test/test_cimd2.c: Use octstr_search instead of octstr_search_cstr and various functions instead of octstr_append_cstr. * gw/wml_compiler.c: Fix call to octstr_search. 2000-09-14 Lars Wirzenius * gwlib/octstr.[ch]: Removed the octstr_create_limited, because it had so limited use. 2000-09-14 Lars Wirzenius * test/test_http_server.c: Catch SIGTERM and die immediately. * checks/check_http.sh: Wrote. 2000-09-14 Lars Wirzenius * gw/smsbox.c, gw/wapbox.c, doc/userguide/newconf.txt: Added HTTP proxy support to configuration files. No way to test it, right now, but will eagerly await bug reports. 2000-09-14 Lars Wirzenius * gwlib/list.c: Don't do the atomic operation locks for list_lock and list_unlock: they're unnecessary for atomicity and cause deadlocks. Thanks to Kalle Sandström for noting this. * gwlib/octstr.c: Silence compiler warning regarding using a plain char as an index to an array (in reality, argument to isdigit), by typecasting a pointer. If we used fewer C strings, this would be less of a problem... 2000-09-11 Lars Wirzenius * README: Fixed download URL, re-formatted and removed the outdated claim that it is a very raw draft. * doc/CodingStyle: Added note about the official formatting style, as discussed on devel@kannel.org. Also added a note about memory allocation policy as far as function interfaces are concerned, a note to avoid #if, and something about abstract data types and naming conventions related to that. * doc/dialup.txt, Makefile.in, configure.in, doc/arch/arch-bearerbox.xml, doc/arch/arch-bib.xml, doc/arch/arch.xml: Shortened long lines. * gwlib/list.[ch]: Changed the interface of the list_destroy function by adding a second argument, which is a pointer to an item destroying function. * checks/check_list.c, gw/cookies.c, gw/bb_boxc.c, gw/bb_smsc.c, gw/bearerbox.c, gw/numhash.c, gw/smsbox.c, gw/smsbox_req.c, gw/smsc.c, gw/smsc_cimd2.c, gw/urltrans.c, gw/wap-appl.c, gw/wapbox.c, gw/wml_compiler.c, gw/wsp-session.c, gw/wsp-unit.c, gw/wsp_caps.c, gw/wtp.c, gw/wtp_pdu.c, gw/wtp_tid.c, gw/wtp_timer.c, gwlib/http.c, gwlib/parse.c, test/drive_wapbox.c, test/test_cimd2.c, test/test_http.c, test/test_http_server.c: Updated calls to list_destroy to work with its new interface. * gw/msg.[ch], gw/wap-events.[ch]: Added functions *_destroy_item, for use with new list_destroy. * gw/wap-appl.c: Add X-WAP-Client-SDU-Size header. * gwlib/octstr.[ch]: Added functions octstr_format and octstr_format_append. Also added "immutable octet strings", for wrapping around C string literals, which required adding octstr_init and octstr_shutdown. See the header for more info. Also added some consts here and there. * gwlib/gwlib.c: Call octstr_init and octstr_shutdown. * test/test_octstr_format.c, test/test_octstr_immutables.c: New test programs. 2000-09-04 Richard Braakman * gw/wapbox.c, gw/smsbox.c, gw/bearerbox.c: Handle only signals for the main thread, so that each signal is received exactly once. 2000-09-04 Richard Braakman * Changes prompted by code review: * gwlib/gwthread.h, gwlib/gwthread-pthread.h: Rename Threadfunc to gwthread_func_t. * gwlib/parse.h, gwlib/parse.c, gw/wsp_headers.c: Rename Context to ParseContext. * gwlib/gwmem-check.c: Give symbolic names to the memory-filling patterns it uses. * gwlib/conn.h: Improve comments. 2000-09-04 Richard Braakman * Making release 0.11.1. 2000-09-04 Derry Hamilton * gw/wml_compiler.c: reformatted my earlier patch. 2000-09-03 Lars Wirzenius * gw/wml_compiler.c: Removed unnecessary call to gw_assert: list_create is defined as always returning non-NULL, so it's not necessary to check it. (Or if we do, we should check it everywhere.) * gwlib/list.c: Removed unused variable from lock(). Also re-did the change to list_len in my own coding style, just to be pedantic. * I assume these were leftovers from Derry's debugging. 2000-09-01 Derry Hamilton * gwlib/list.c: Added a test for NULL list to list_len since some things want the length of NULL lists. * gw/wml_compiler.c: string_table_build no longer tries to add strings to the stringtable if the list is NULL. 2000-08-31 Lars Wirzenius * wmlscript/wsencode.c: Added a typecast to convert a va_arg call that fetches an int to convert the value to an unsigned char *. 2000-08-31 Lars Wirzenius * gwlib/http.c: Improved (but still did not write properly) HTTP Content-Type header parsing. Fix suggested by Joerg Pommnitz, though re-did the patch to add some error checking. * test/test_http.c: Parse and report Content-Type. Also, http_get_real now wants a non-NULL request header list. Give it that. * test/test_http_server.c: Report a character set (UTF-8, though it doesn't really matter) so that the parsing can be tested. 2000-08-31 Lars Wirzenius * configure.in: Tweaked the libxml checking. It should now be slightly cleaner and should work with upcoming 2.2.x versions of the library without changing configure.in. Thanks to Geir Johannessen, whose mail prompted me to look at this, even though I didn't use his patch directly. 2000-08-31 Lars Wirzenius * gw/wsp.[ch]: Minor cleanups: Removed unused constants, added a comment for assertions, etc. 2000-08-31 Lars Wirzenius * gw/wapbox.[ch]: Moved WB_DEFAULT_TIMER_TICK and CONNECTIONLESS_PORT defines from .h to .c, since they're only used inside .c. * gw/wsp-method-state.h: Formatting change (comments should be indented similarly to the code they describe). Also, bug fixes: several comparisons had a single equals (i.e., assignment) instead of two (i.e., comparison). 2000-08-31 Lars Wirzenius * gw/wapbox.c, gw/log.c: Moved syslog opening internals to log.c, where it belongs. Introduced new function set_syslog to do this. * gw/log.c: Cleaned up formatting, etc, a bit. syslog support (internals of kannel_syslog (now static, btw)) is compiled on all platforms, not just SunOS. * gw/log.h: Added note that opening and closing of log files is not thread safe. 2000-08-31 Lars Wirzenius * gwlib/list.[ch]: Some further cleanups: - list_delete_all and list_extract_all were named in a misleading way; renamed to *_matching instead, and all calls fixed as well; argument `cmp' renamed to `matches' for clarity's sake - some assertions uncommented and fixed to compare a pointer explicity to NULL, instead of implicitly - code changed to call delete_items_from_list, instead of doing the same thing manually - list_lock and list_unlock use the single-operation lock * checks/check_list.c, gwlib/http.c: Related changes. 2000-08-31 Lars Wirzenius * gwlib/list.c: list_len is now protected by locks. 2000-08-31 Lars Wirzenius * test/test_list.c: Removed. * checks/check_list.c: Wrote. 2000-08-30 Lars Wirzenius * gw/bb_udp.c, gw/cookies.c, gw/html.c, gw/msg.c, gw/smsbox_req.c, gw/smsc_at.c, gw/smsc_cimd2.c, gw/smsc_ois.c, gw/smsc_sema.c, gw/smsc_smpp.c, gw/wap-appl.c, gw/wml_compiler.c, gw/wsp-session.c, gw/wsp-unit.c, gw/wsp.c, gw/wsp_caps.c, gw/wsp_headers.c, gw/wsp_pdu.c, gw/wtp_pdu.c, gwlib/conn.c, gwlib/http.c, gwlib/http.h, gwlib/octstr.c, gwlib/octstr.h, gwlib/parse.c, gwlib/socket.c, test/fakewap.c, test/test_cimd2.c: Cleanups based on a (brief) code review. Lots of small changes pretty much everywhere, but nothing really big. * Renamed octstr_search_*_from to octstr_search_*, because there's no point in having two almost equivalent functions. * Renamed octstr_*_blank to octstr_*_blanks, to be grammattically correct. * Killed octstr_create_empty, replaced it with octstr_create(""). * Other minor differences, see the diff if you're interested. 2000-08-30 Tuomas Luttinen * gw/wml_compiler.c: The octet string memory leaks in the string table code plugged. 2000-08-29 Tuomas Luttinen * gw/wml_compiler.c: Plugging the huge memory leaks of the string table code started. No more leaks due lists or mutexes. Some leaks with octstr:s also plugged, some still remain. 2000-08-28 Tuomas Luttinen * gw/wml_compiler.c: The patch by Aarno was removed because it caused problems like "WARNING: WSP: All converters for `text/vnd.wap.wml' failed.", segmentation fault on variables and maybe others. 2000-08-26 Derry Hamilton * solaris/mk-solaris-package.sh: Now compiles for a bare Solaris 7 box, doesn't assume LD_LIBRARY_PATH 2000-08-24 Kalle Marjola * gw/bb_udp.c (udp_receiver): trap ECONNREFUSED too (hey it was missing from Man page) and just continue * gw/bb_boxc.c: extend wapbox_list lock to prevent packet routing to exiting wapboxes 2000-08-23 Richard Braakman * gw/wap-appl.c: Make sure content.url and content.body have valid values even if request method is not supported. * gw/wsp_pdu.c, gw/wtp_pdu.c: Make sure REST fields are always filled, even if packet contains bad length info. This fixes a crashing bug discovered by OUSPG. * test/fakewap.c: Fix small memory leak. * test/udpfeed.c: New test program, reads a bunch of files and sends each in a single UDP packet. Useful for feeding OUSPG's test set to Kannel. * gw/wapbox.c: Catch SIGQUIT and use it to report memory usage. Useful for detecting memory leaks. * gw/gwmem-check.c: Bugfix to allow gw_check_leaks() to be called multiple times in one run. * gw/wsp-unit.c: Fix memory leaks. 2000-08-22 Aarno Syvänen * gw/wml_compiler.c: Fixed some memory leaks 2000-08-22 Derry Hamilton * solaris/etc/kannel.conf: By default do not permit admin connections Mon Aug 21 18:39:30 2000 Lars Wirzenius * test/test_counter.c: Removed, as this is now replaced by chec/check_counter.c. Mon Aug 21 18:32:04 2000 Lars Wirzenius * README, Makefile.in: Added some automatic checking as "make check". See the README for more info. * utils/run-checks, checks/*: New files. 2000-08-21 Paul Keogh * gwlib/counter.[ch]: Added counter_set method. 2000-08-18 Richard Braakman * gwlib/gwthread-pthread.c: In gwthread_shutdown, don't delete the tsd_key. It's still needed by gwthread_self(), which can still be called. This might fix the problem of wapboxes that refuse to die. * gw/wsp-strings.c: Make wsp_##name##_to_string not crash if the string was not found. * gw/wsp_headers.c: Have unpack_all_parameters() stop at the end of its string, rather than reporting a bogus error. Also fixed a memory leak in header unpacking. 2000-08-18 Derry Hamilton * solaris/mk-solaris-package.sh: Changed default optimisation level. * solaris/etc/kannel.conf: Kannel needs an admin port to start 2000-08-16 Derry Hamilton * solaris/*: Added packaging information for Solaris 2000-08-14 Peter Grönholm * gw/wml-definitions.h: A typo corrected in URL value code table. Now URLs ending with .net/ work, too. Two other typos: Content- Type and Expires use capital letters. 2000-08-10 Tuomas Luttinen * gw/wml_compiler.c (check_variable_syntax): Escaping now possible with one letter acronyms 'e', 'u' and 'n'. 2000-08-07 Tuomas Luttinen * gw/wml_compiler.c: A little bit of code cleaning, changing return types to null where a status is not needed. 2000-08-06 Derry Hamilton * config.h.in, wmlscript/wsencode.c: Fixed the WMLScript compiler errors under Solaris SPARC. The SPARC ABI requires that function parameters be int aligned. 2000-08-04 Tuomas Luttinen * test/decompile.[ch]: A patch by Chris Wulff applied. * gw/wml_definitions.h: STRING_TABLE_MIN defined * gw/wml_compiler.c: The first attemp to use string table more efficiently. For a reason or another hangs up when compiled with checking-malloc on the check phase into a allocation lock. * gw/wml_compiler.c: The patch to fix a bug in the libxml-1.8.6 is removed. * configure[.in]: The flag HAVE_LIBXML_1_8_6 is removed, now takes only 1.8.7 and up. 2000-08-04 Richard Braakman * gw/wap-appl.c: In X-WAP-Gateway header, use "Kannel/0.11" instead of "Kannel 0.11", to comply with HTTP/1.1 recommendations for version strings. 2000-08-02 Richard Braakman * Making development release 0.11. 2000-08-02 Richard Braakman * Applied Joerg Pommnitz's patch for Crypto library support in the WMLScript compiler. 2000-08-02 Richard Braakman * Folded in POST_SUPPORT. Duplication of code is Bad. 2000-08-01 Richard Braakman * gw/smsc_cimd2.c: Be forgiving of cimd2 calls while the socket is not open. This is necessary because of the changed thread structure in the new bearerbox. 2000-08-01 Richard Braakman * gw/smsbox_req.c: When logging "message sent", use errno 0 instead of 1. (?) * doc/userguide/newconf.txt: Change recommended unified-prefix string for Finland, because smscenters no longer accept "00" prefix as of today. 2000-08-01 Richard Braakman * gw/smsc_cimd2.c: When complaining about format of sender number, actually log the sender number rather than the receiver number. 2000-07-27 Richard Braakman * gw/smsc_cimd2.c: When pending_smsmessage receives an unexpected response packet, report it instead of crashing. 2000-07-24 Richard Braakman * gw/wsp_headers.c: Mostly rewritten. Now decodes all header types defined by WSP 1.1. This means that the headers sent by the phone are all passed to the HTTP server. Previously, only a few commonly-appearing ones were (partially) decoded. Uses wsp-strings.def instead of inlined string tables. Uses new gwlib parse module to scan octstr contents. "Works for me" status. Will be more thoroughly tested after the decoding code is complete. * gw/wsp_headers.h: Changed interface of unpack_headers. It now takes a content_type_present flag parameter, instead of having a separate unpack_post_headers function. * gw/wsp-strings.c: Support for NUMBERED tables, which assign non-sequential numbers to the strings in a table. * gw/wsp-strings.h: Support for NAMED tables, which assign an enum value to each entry in a string table. * gw/wsp-strings.def: Define lots of new string tables, for use by the wsp_header module. * gw/wapbox.c: Init and shutdown newly used wsp-strings module. * gw/wsp-method-state.h, gw/wsp-session-state.h, gw/wsp-unit.c: Use new unpack_headers interface. * gwlib/octstr.c: In octstr_insert, assert that ostr2 is not inserted past the end of ostr1. (This assumption was already there; it's just made explicit now.) Removed unused octstr_get_digit_from function. octstr_parse_long does the same thing. New octstr_append_decimal function. * gwlib/protected.c, gwlib/protected.h: Added gw_getlocale, for use by rfc2068_date_format function. * gwlib/utils.c, gwlib/utils.c: New rfc2068_date_format function, to convert a unix timeval to a common textual format. (The RFC2068 format also fits the RFC822 format). * gwlib/parse.c, gwlib/parse.h: New module to make it easier to parse octstrs without passing lots of length and offset variables around. * gwlib/gwlib.h: Include new parse.h. Move inclusion of protected.h to end, so that it can use Octstr in its function prototypes. 2000-07-24 Tuomas Luttinen * gw/smsbox_req.c: Removed function smsbox_req_sendota that used nonexistent octstr-function so that the CVS version didn't compile. 2000-07-23 Tuomas Luttinen * configure.[in]: libxml 2.2.1 added. 2000-07-21 Paul Keogh * gw/bb_udp.c: Added check for NULL ptr return from udpc_create() in function add_service() to prevent subsequent NULL dereference and crash. 2000-07-21 Yann Muller * gw/smsbox_req.c, smsbox_req.h: messages with or without UDH are now handled in the same way, they can all be sent as multiple messages or concatenated messages if too long. * gw/smsc_at.c: Receiver address fix by Paul Keogh and Marcus Shawcroft. Better support for UDH. * gw/urltrans.c, urltrans.h: Added the concatenation option for SMS messages. * doc/userguide/newconf.txt, userguide.xml: Added a note about the concatenation and removed the limitation about UDH. 2000-07-20 Richard Braakman * gw/wtp.c: Fixed memory leak in wtp_unpack_wdp_datagram. Simplified the code a bit. * gw/wtp.c: Made wtp_unpack_wdp_datagram_real not crash when receiving an invalid PDU. * gw/wtp_pdu.c: In wtp_pdu_unpack, simply free a PDU with unknown type instead of trying to destroy it. None of its fields were set anyway. * test/fakewap.c: Actually test separation when -s flag is given. The test is wrong, though, it sends bad packets. Not going to fix that now. 2000-07-19 Tuomas Luttinen * configure[.in]: libxml 1.8.9 and 2.2.0 added. Fixes bug #97. 2000-07-18 Richard Braakman * gw/html.c: Fix skipping of quoted strings (bug #89, reported by Paul Keogh). * gw/smsbox.c: Avoid memory leak in http_request_thread(). Fixes bug#101, reported by Paul Keogh. 2000-07-18 Richard Braakman * gw/smsc_ois.c: Fixed some warnings. 2000-07-18 Kalle Marjola * gwlib/gwthread-pthread.c, gwlib/http.c: Fized bugs #98 and #100 reported by Paul Keogh. 2000-07-18 Paul Keogh * gw/urltrans.c: Fixed memory leak in destroy_onetrans(). 2000-07-17 Paul Keogh * gwlib/counter.[ch]: Added counter_decrease() function. 2000-07-15 Derry Hamilton * config.h.in,configure,configure.in: Removed checks for integer lengths as it broke more than it might have fixed. 2000-07-14 Paul Keogh * gwlib/http.c: Fixed a bug in the HTTP POST which prevented interop with some versions of Apache and ultimately crashed. 2000-07-13 Derry Hamilton * gw/wapbox.c,gw/wapkannel.conf,gwlib/log.c: first implementation of syslog support under Solaris. 2000-07-13 Kalle Marjola * */*: Making out release 0.10.2 2000-07-13 Tuomas Luttinen * gw/wml_compiler.c (wml_compile): Compiler now checks that the output from libxml is not a NULL pointer. 2000-07-13 Derry Hamilton * config.h.in,configure,configure.in: configure now checks for the 32-bit type and defines kint32 and kuint32 as appropriate in preparation for 64-bit kannel on Alpha and UltraSPARC since the compiler types int32 and uint32 are not supported everywhere. * gwlib/http.h: Added the function definition for http_charset_accepted rather than leaving it to be implicitly defined. 2000-07-13 Yann Muller * gw/smsc_at.c: removed two unused variables. 2000-07-12 Tuomas Luttinen * gw/wml_compiler.c: Little bug fixes with variables: - no more empty string before variable reference to string table - double $ won't eat a character after them, fixes #94 - a little memory leak mentioned below corrected 2000-07-12 Kalle Marjola * gw/bb_http.c: oops, return value for HTTP admin was not checked, now fixed * gw/bearerbox.c: added compiler options KANNEL_NO_SMS and KANNEL_NO_WAP 2000-07-11 Tuomas Luttinen * gw/wml_compiler.c: Bug #86 fixed. A memory leak with $ characters fixed. Another one still remains with mix of $ characters and variables. 2000-07-11 Yann Muller * doc/userguide/newconf.txt: Added configuration information to use a GSM modem as an SMSC. 2000-07-10 Yann Muller * gw/smsc_at.c: now removes SMSC address at beginning of PDU sent by the Wavecom. Better handling of messages with UDH (no 7bit encoding of UDH yet). 2000-07-10 Kalle Marjola * gw/urltrans.c (find_translation): fixed string matching of sms-services. 2000-07-07 Tuomas Luttinen * configure: Now support for libxml 1.8.8 and 2.1.1. * gw/wml_compiler.c: Support for libxml version 2 and above now ready. * gw/wml_compiler.c (parse_attribute): Patch by Holger Casties applied to eliminate a segmentation fault with NULL pointer passed as a second argument to strcmp. 2000-07-07 Kalle Marjola * doc/dialup.txt: updated to reflect current configuration, and added data on how to get it work with Siemens S25i from Matthias Wutke 2000-07-07 Aarno Syvänen * gw/wtp.c: Bugfixes in the separation code * test/fakewap.c: Added sending of a concatenated message, for testing separation. 2000-07-07 Kalle Marjola * gw/bb_boxc.c: hopefully fixed a little bug/feature in connection closing 2000-07-06 Richard Braakman * Making release 0.10.1. * Extended NEWS. Removed NEWS.devel, we won't need it until we start on 0.11. 2000-07-06 Kalle Marjola * gw/smsc_ois.c: (hopefully) fixed warnings from FreeBSD 2000-07-06 Kalle Marjola * gw/bearerbox.c: added --suspended and --isolated command-line option names (same as -S and -I) * gw/smsbox.c: fix in command line parsing * doc/userguide/newbb.conf: added data on those new options 2000-07-06 Kalle Marjola * gw/smsbox.c: modified so that if the HTTP-sendsms interface is defined, the smsbox won't start if it fails to init it. Use new command line option -H or --tryhttp to override this feature 2000-07-05 Kalle Marjola * doc/userguide/newconf.txt: oops, forgot admin-username. And returned sample smsc-groups * gw/smsc.c, gw/smsc_p.h, gw/smsc_ois.c: Added support for SEMA SMS2000 (G6.0) OIS 5.0 over X.25, under name OIS, by Jouko Koski. 2000-07-03 Richard Braakman * gw/wml_definitions.h: Applied patch by brennon loh york hong to fix compilation of pages with multiselect. 2000-07-03 Paul Keogh * gwlib/http.c,gwlib/http.h,gw/wsp_headers.h,gw/wsp_headers.c, gw/wsp_unit.c,gw/wsp_session_state.h,gw/wsp_method_state.h, gw/wap-appl.c: Added support for HTTP POST under #ifdef POST_SUPPORT. Also enabled runtime cookies under #ifdef COOKIE_SUPPORT. 2000-06-30 Aarno Syvänen * wsp-unit.c: Fixed some memory leaks 2000-06-30 Aarno Syvänen * wtp_tid.c|h, wtp_state-decl.h: Tid was not cached when tid verification was invoked because of a failed tid validation test. So after every validation all following tids were verified. Added to the the module wtp_tid an external function wtp_tid_set_by machine, which stored tid after validation. 2000-06-30 Richard Braakman * gw/wml_compiler.c: In parse_octet_string, one extra byte was skipped after a variable reference, including the special "$$" sequence. Fixed. 2000-06-30 Richard Braakman * gwlib/http.c: Change some of the locking according to Joerg Pommnitz's suggestions, to deal more smoothly with slow connects. 2000-06-30 Derry Hamilton * Makefile.in: made .depend depend on config.h. This should allow changing between checked and unchecked malloc without manual intervention. 2000-06-30 Richard Braakman * gwlib/gwmem-check.c: Fix call to free() in drop_from_free_ring(). This fixes a memory leak. 2000-06-29 Paul Keogh * gwlib/list.c: Removed unnecessary calls to lock() and unlock() in the list_cat() function as the called functions do the required locking. Locking the same lock twice causes a panic(). 2000-06-29 Richard Braakman * gw/wsp-session.c: Fixed memory leak in new capability code. 2000-06-29 Richard Braakman * gw/wap-appl.c: Applied fix suggested by Lim YoungLan, to make sure S-MethodInvoke.res is sent before any S-MethodResult, even if fetch_thread() is very fast. 2000-06-28 Richard Braakman * wmlscript/wsstdlib.c: Applied Joerg Pommnitz's patch to support WTAI standard library function calls, after converting it to the local indentation style. 2000-06-27 Kalle Marjola * doc/userguide/userguide.xml: did some updating, still needs to integrate newconf.txt and newbb.txt into it, but that some other day 2000-06-27 Paul Keogh * gw/cookies.c: Added a check for valid WSP session machine to prevent possible crash. 2000-06-26 Derry Hamilton * gw/cookies.c: casted char to int for several isspace() etc. calls. Stops the compiler complaining under Solaris. 2000-06-26 Kalle Marjola * Making out stable release 0.10, branched as 'release_0_10' 2000-06-26 Kalle Marjola * gw/smsc_smpp.c: small fix by Mikael Gueck 2000-06-21 Kalle Marjola * gw/bb_boxc.c: added on-line information about connected boxes in status query 2000-06-20 Kalle Marjola * README: added notes of what need to be done if Kannel version is upgraded from some old version 2000-06-20 Kalle Marjola * Making out development release 0.9.3, canditate as production release 0.10 2000-06-20 Kalle Marjola * gwlib/utils.c, gwlib/utils.h: moved #ifdef of cfmakeraw into header file so that it will compile in (my) system with cfmakeraw * gw/bb_boxc.c: updated output information of bocx_status * gw/bb_smsc.c: fixed compiler warning 2000-06-19 Kalle Marjola * gw/bb_boxc.c: fixed one very-infrequently striking lockout during shutdown * README.docbook: user --disable-docs, not --without-docs 2000-06-19 Derry Hamilton * gw/wsp-session.c: included limits.h to get LONG_MAX * gwlib/utils.c,gwlib/utils.h: created kannel_cfmakeraw() * gw/smsc_emi.c: removed cfmakeraw stub * gw/smsc_emi.c,gw/smsc_at.c,gw/smsc_sema.c: converted calls to cfmakeraw to kannel_cfmakeraw. 2000-06-19 Kalle Marjola * gw/wsp-session.c, gw/wsp_pdu.c: inserted patch from Joerg Pommnitz, now Kannel hopefully works better with Motorola Timeport. 2000-06-19 Kalle Marjola * gwlib/http.c: parse_url() modified to change start of the url tolower() so that comprasion to http:// succeeds even with HTTP:// 2000-06-19 Kalle Marjola * gw/bb_smsc.c: added suspend-mode to sms_router to synchronize start-up 2000-06-19 Yann Muller * gw/smsc.c, gw/smsc_p.h, gw/smsc_at.c: Applied Denis Hennessy's patch to support Siemens M20: connect at 19200 baud, added a 'pin = xxxx' entry to the conf file, fixed missing trailing null char in encode_pdu, added a dummy receiver address since smsbox requires one, added the dummy "00" SC prefix for the M20 (like the wavecom). 2000-06-17 Richard Braakman * Replaced capabilities parsing. New file gw/wsp_caps.[ch] defines a structure to represent capabilities, and some operations on it. WSP layer passes capability requests up to the Application layer, which can respond to some and ignore others. WSP layer then completes the capabilities reply when it generates the ConnectReply PDU. See negotiate_capabilities() function in wap-appl.c for more info. * Added CAPABILITIES type to wap-events and wsp-session-machine. * Added request_caps and reply_caps fields to WSP session machine, removed most of the other capability-related fields except client_SDU_size and MOR_push (which are the only ones we support and need to remember). * gwlib/octstr.[ch]: New function octstr_extract_uintvar. * gw/wsp-session.c: unpack_caps, unpack_uint8, and unpack_uintvar removed. * Removed unused SESSION_MACHINE type from wap-events. * test/drive_wapbox: Supply the same capability values as the Motorola Timeport does, for testing. * Corrected: gw/cookies.c:88: warning: char format, Octstr arg (arg 3) 2000-06-17 Richard Braakman * test/drive_wapbox.c: Defined wtp_types enum, because we can no longer steal the values we need from wtp.h. 2000-06-16 Aarno Syvänen * wtp.c: Fixed bug pointed out by Joerg Pommnitz * removed debug functions * wtp.c | wapbox.c: Code for separation added. Must test it ... 2000-06-16 Kalle Marjola * gw/cookies.c: changed strnicmp to strcasecmp, as nicmp is not supported in standard C libraries * gw/urltrans.c: fixed find-operations * gw/bb_smsc.c: added smsc_status 2000-06-16 Yann Muller * gw/smsc.c, gw/smsc_p.h: Added modemtype configuration parameter for the AT SMSC. * gw/smsc_at.c: Added support for Nokia PremiCell GSM modem. The parameter modemtype in kannel.conf can be set to 'wavecom' or 'premicell'. 2000-06-16 Paul Keogh * gw/cookies.c: updates after review by Richard Braakman. Also some additional includes. * gw/cookies.h: As for cookies.c * gw/wsp-session-machine.h: Added COOKIES field to session MACHINE * gw/wsp-session.c: Added cookie support to machine_create(), machine_destroy (). Also added id_belongs_to_session() function for use by cookie functions. * gw/wsp.h: Added cookie support to struct WSPMachine. 2000-06-15 Kalle Marjola * gw/smsbox_req.c: fixed bug in http2-conversion, and set that 'request failed' is send back to the phone (no more 'nothing') 2000-06-15 Richard Braakman * gw/wsp-strings.*: Interface for tables of constant strings defined in WSP. Not used yet. * gw/wsp-session.c: Got rid of append_uint8 and append_octstr; use basic octstr functions instead. 2000-06-15 Richard Braakman * gw/wap-appl.c: In fetch_thread(), explicitly set content.charset to an empty octstr if the http fetch failed, otherwise it remains uninitialized and causes a crash when octstr_destroy is called on it. Thanks to Paul Keogh for finding this. * gw/wsp-session.c: In wsp_disconnect_other_sessions(), use "Disconnect_Event" instead of "Disconnect". The latter is a PDU type, not an event type. Thanks to Paul Keogh for finding this. 2000-06-15 Aarno Syvänen * wtp.c: Bugfixes in error handlin * wtp_pdu.c: wtp_pdu_unpack must return NULL when header is not valid 2000-06-14 Richard Braakman * Filled in WSP state tables. Defined lots of new events. Sanitized event routing: WTP to WSP events get an addr_tuple. WSP to WTP events get a "handle" (as defined in the spec) which happens to be equal to the mid. WSP to APPL events contain the session id, and possibly a transaction id (as defined in the spec), which can be returned in the APPL to WSP events. No more mid or msmid fields. The transaction id is set equal to the handle gotten from the WTP layer, because that one's already unique. * Still missing: Push and Suspend/Resume. * gw/wap-appl.c: Handle all the new S- events and send back the proper replies. * gw/wsp-session.c: Moved method machines into the session machines. They can only be addressed via a session id and transaction id. The session machine can send events to all its method machines. Also added support functions for the WSP state tables. Implemented pre- and post- state machine checks, for more accurate handling of events without sessions, etc. * gw/wsp.h: Defined an enum for all the possible abort values. * test/drive_wapbox.c: Really disconnect clients after the right number of page fetches. (Used to do this only once per client.) 2000-06-14 Yann Muller * smsc_at.c: Fixed a memory leak in pdu_extract. Removed unused variables. 2000-06-14 Kalle Marjola * gw/html.c: fixed parsing bug in html_to_sms * utils/kannel-init.d: made to worship new configuration files 2000-06-14 Aarno Syvänen * wtp_send.c|h: wtp_do_not_send uses WAPAddrTuple type, too * wtp.c: Reimplement error handling 2000-06-14 Kalle Marjola * gw/smsbox_req.c: fixed split-send Octstr-wise, now it should work with CIMD2, too (and other new SMSC protocols?) 2000-06-14 Kalle Marjola * gw/bb_smsc.c: modified sleep in smsc receive to variable length, to increase performance 2000-06-14 Yann Muller * smsc_at.c: New SMSC for wireless modems (AT commands). * smsc.c, smsc_p.h: Added support for new AT SMSC. 2000-06-13 Kalle Marjola * gw/bb_boxc.c: (somehow) fixed pointer error pointed out by Paul Keogh. 2000-06-13 Richard Braakman * gw/wap-appl.c: Query list of charsets from the WML compiler, and use that instead of accessing the table as an extern. * gw/wml_compiler.[ch]: Added wml_charsets function. * gw/wap-appl.c: Continued simplifying fetch_thread, broke out a number of smaller functions. Made converters table only list actual converters, eliminated convert_to_self. * gw/wap-events-def.h: Made response_type an octstr. Convert it to the WSP encoding in the WSP layer, not the application layer. Moved encode_content_type function to wml.c. * gwlib/http.c: Reindented http_something_accepted and istrdup to fit with the rest of the code. * gwlib/http.h: Added prototype for http_charset_accepted. * gw/wap-appl.c: Created "content" struct to describe content body and meta-info. Made convert functions use it. Split off content conversion into a separate function that uses the table. 2000-06-12 Richard Braakman * Started simplifying fetch_thread function. * Add "X-WAP-Gateway: Kannel XXX" to requests, where XXX is the version number. 2000-06-12 Richard Braakman * Renamed http2 to http everywhere, because the old http code is completely gone. Removed --with-http2 configuration option. 2000-06-12 Tuomas Luttinen * gw/wml_compiler.c: Character set and string table length changed from chars to uintvars. Now WML compiler can handle string table length greater than 127. 2000-06-12 Richard Braakman * Making development release 0.9.2. * Commented-out some excessive logging. 2000-06-12 Aarno Syvänen * wtp_state-decl.h: TR-Abort.ind when timer counter has expired 2000-06-10 Richard Braakman * gwlib/gwmem-check.c: New implementation. This fixes the speed bottleneck that the old gwmem-check was, and it provides better checking and some extra features. * gwlib/gwmem.h: Slight changes for the new gwmem-check. New functions gw_check_area_size and gw_check_claim_area, which do not have macro wrappers yet. * gwlib/thread.[ch]: Add support for statically allocated Mutex structures. They are needed to break some dependency loops between the various wrappers (log.c needed protected.c, protected.c needed Mutex, Mutex needed gwmem, gwmem needed log.c) which made it impossible to shut them down correctly. * gwlib/protected.c, gwlib/gwmem-check.c: Use the new static mutexes. 2000-06-09 Tuomas Luttinen * gwlib/http2.c: A http request headers patch applied. * gw/wap-appl.c: A http request headers patch applied. * gw/wml_definitions.c: Character set conversion pathes added, see below. * gw/utf8map_iso8859-7.h: A conversion table for greek character set. * gw/utf8map_win1253.h: A character set added. * gw/utf8map_win1251.h: A russian character set added. * gw/utf8map_koi8r.h: A russian character set added. * gw/wml_compiler.c: A memory allocation loop removed from parse_attribute. 2000-06-09 Richard Braakman * gw/wap-appl.c: In fetch_thread, also clean up "url" octstr. This fixes the last big memory leak. I now get only a handful of leaked areas after 100 requests. 2000-06-09 Richard Braakman * gw/wsp-session.c: Fixed two of the memory leaks, still hunting for others. 2000-06-09 Richard Braakman * gwlib/http2.c: Fixed header_is_called() to return 0 for no match and 1 for match; simplified it in the process. I think this was the original intent, and it matches the function name. By a roundabout path this fixes the lack of "Accept: text/vnd.wap.wml" and such in the HTTP request headers Kannel generates. Adapted http2_header_find_first() to the new interface of header_is_called(). 2000-06-09 Richard Braakman * gw/wsp_pdu.c: Allow REST fields to be NULL when packing (treat them as length 0 strings). This was already done for OCTSTR fields. Thanks to Paul Keogh for fixing this. * gw/wtp_pdu.c: Make the same change for REST and OCTSTR fields as above. It's going to be difficult to keep this code in sync. 2000-06-09 Richard Braakman * gwlib/socket.c: Make read_available assert that fd >= 0, because otherwise it just segfaults. * gwlib/http2.c: Make pool_socket_is_alive return "not alive" for sockets < 0. This does not fix the whole problem but it keeps the wapbox from crashing here. * gwlib/list.c: Fix bug in delete_items_from_list which would corrupt the list in some cases. 2000-06-09 Kalle Marjola > * gw/bb_*.c: removed START and EXIT debug info as they are in new thread wrapper, too * gw/bb_boxc.c: fixed bugs in wdp-router and wapbox quit, and re-synchronized shutdown * gw/bearerbox.c, gw/bb_http.c: removed core_threads as new thread wrapper can be used to handle that. Fri Jun 9 08:31:18 2000 Lars Wirzenius * Separated the method state machine from the session state machine, to keep state tables in the source closer to the spec and to allow multiple fetches per client. * gw/wsp-method-machine.h, gw/wsp-session-machine.h: Split out from gw/wsp_machine-decl.h, now removed. * gw/wsp-method-state.h, gw/wsp-session-state.h: Split out from gw/wsp_state-decl.h, now removed. * gw/wsp-session.c: Added handling of WSPMethodMachines and correct routing of WAPEvents between the session and method state machines. This is a bit ugly, though. * gw/wap-appl.c, gw/wap-events-def.h, gw/wsp.h, gw/wtp.c: Related changes. Fri Jun 9 06:20:12 2000 Lars Wirzenius * gw/wtp.c: Combined wtp_machine_create and wtp_machine_create_empty. Fri Jun 9 05:39:06 2000 Lars Wirzenius * gw/wsp-session.c, gw/wsp_machine-decl.h, gw/wsp_state-decl.h: Removed `unused' field from WSPMachine, using state == NULL_STATE instead. Fri Jun 9 05:32:38 2000 Lars Wirzenius * gw/wap-events-def.h, gw/wtp.c, gw/wsp_state-decl.h: Removed unused exit_info and exit_info_present fields from WAPEvents. Fri Jun 9 05:28:12 2000 Lars Wirzenius * gw/wtp_state-decl.h: Enabled sending of TR-Abort.ind events to WSP. * gw/wtp.c: Removed (now unused) variable current_primitive. Fri Jun 9 05:18:07 2000 Lars Wirzenius * gw/wap-events-def.h: Finished breaking up pack_wsp_event into smaller functions. Fri Jun 9 05:10:20 2000 Lars Wirzenius * gw/wtp.c, gw/wap-events-def.h: Removed event TR_Invoke_Cnf since it wasn't used and is only generated on the client side. Fri Jun 9 04:58:02 2000 Lars Wirzenius * gw/wap-events-def.h, gw/wtp.c: Removed unused fields wsp_pdu and wsp_tid from various events. Then removed code that set and copied them between events. Fri Jun 9 07:44:25 2000 Lars Wirzenius * gw/wtp.c, gw/wtp_state-decl.h: Beginning the breaking up of pack_wsp_event function into smaller, more well defined ones. Fri Jun 9 06:48:42 2000 Lars Wirzenius * gw/wap-appl.c: Combine headers for HTTP request after the actual list of headers has been collected. Fri Jun 9 02:58:00 2000 Lars Wirzenius * Implemented WSP connectionless service. This meant moving things around a bit. The basic approach is to treat connectionless mode as a level in the protocol stack that is parallel to WTP and session oriented WSP. That is, connectionless mode gets events directly from wapbox.c and feeds them to wap-appl.c, and vice versa for replies. * gw/bb_udp.c: Read from port 9200 as well. * gw/wap-events-def.h: Added events S_Unit_MethodInvoke_Ind and S_Unit_MethodResult_Req. * gw/wapbox.c: Deal with connectionless packets as well. Feed them to wsp-unit.c. Also: trace packets received and sent, except for heartbeat packets. * wsp-session.c: The session oriented mode of WSP. I just moved relevants parts of wsp.c here and renamed them to use the wsp_session prefix. * gw/wsp-unit.c: The connectionless mode of WSP. * gw/wsp.c: Kept only stuff shared by wsp-session and wsp-unit. * gw/wap-appl.c: Deal with both S-MethodInvoke.ind and S-Unit-MethodInvoke.ind events. Fri Jun 9 02:46:53 2000 Lars Wirzenius * gw/wap-events.[ch]: Changed the WAPEvent sub-structures to be held inside a union, to reduce amount of space used. Related changes everywhere WAPEvents are used. 2000-06-08 Richard Braakman * test/drive_wapbox.c: Added option -g N to try more than one page fetch per WSP session. Improved tid checking so that it will catch the tid inversion bug (fixed below) in the future. * gw/wapbox.c: Make wap_addr_tuple_duplicate handle a NULL argument by returning NULL, like most other _duplicate functions. * gwlib/http2.c: Make http2_append_headers copy the headers it appends, so that http2_destroy_headers can safely be called on the result. 2000-08-07 Aarno Syvänen * wtp_state-decl.h: Removed machine_mark_unused calls 2000-06-07 Richard Braakman * gw/wtp_send.c: Invert the MSB of the received tid when sending, to comply with WTP 8.8.1. This fixes a bug introduced two days ago. 2000-06-07 Richard Braakman * gw/wtp.c: Also destroy the event queue at shutdown. 2000-06-07 Richard Braakman * gwlib/gwthread-pthread.c: Fixed silly bug in yesterday's patch. 2000-06-07 Derry Hamilton * test/fakewap.c: Running fakewap too quickly messes up thread-control signal handling under Solaris. Ignore SIGALRMs, they are not meant for us. 2000-06-06 Richard Braakman * gwlib/gwthread-pthread.c: Information for main thread is now allocated statically, so that we don't have to deallocate it at shutdown. This way we can keep it around so that gwthread_self continues to work as expected even during shutdown. 2000-06-06 Richard Braakman * Making development release 0.9.1. 2000-06-06 Richard Braakman * gwlib/gwlib.c: Patch gwlib_assert_init so that it works if NDEBUG is on. * gwlib/octstr.c: Patch seems_valid macro so that it does nothing if NDEBUG is on. 2000-06-06 Tuomas Luttinen * gw/wsp.c: append_uintvar removed, calls to it were changed to octstr_append_uintvar. * gw/utf8map_win1257.h: A new file from the Latvian localisation patch. * utils/win1257unicode.txt: A new file from the Latvian localisation patch. * utils/utf8map.pl: A new file from the Latvian localisation patch. * gw/wml_definitions.h: Latvian localisation patch applied. * gw/wml_compiler.c: Latvian localisation patch applied. Tue Jun 6 15:43:31 2000 Lars Wirzenius * gw/wsp_state-decl.h: Bugfix. The mid for a S_MethodInvoke_Ind was copied from a tid. Oops. Tue Jun 6 15:11:14 2000 Lars Wirzenius * wap-events-def.h, gw/wsp.c, gw/wtp.c: Some events are generated by WTP immediately before it kills the WTPMachine. We used to fetch the address information for those WTP transactions from the WTPMachine after the machine had been killed. This was a bug. I changed the relevant events to supply the necessary information in the event, so that the WTPMachine is no longer needed. Tue Jun 6 12:28:48 2000 Lars Wirzenius * gw/wap-appl.c, gw/wap-events-def.h, gw/wap-events.c, gw/wap-events.h, gw/wapbox.c, gw/wapbox.h, gw/wsp.h, gw/wsp_machine-decl.h, gw/wtp.c, gw/wtp.h, gw/wtp_machine-decl.h, gw/wtp_send.c, gw/wtp_tid.c: Made more use of WAPAddrTuple. Tue Jun 6 11:37:22 2000 Lars Wirzenius * gw/wap-appl.c, gw/wap-events-def.h, gw/wap-events.[ch]: Replaced member `machine' (a pointer to a WTPMachine) to `mid' and `tid' (integers), so as to remove direct references to WTPMachines from outside the WTP layer. * gw/wtp.[ch]: Added function wtp_get_address_of for finding the address of a machine given its id (mid). * gw/wapbox.[ch]: Added data types WAPAddr and WAPAddrTuple, for holding addresses of phone and gateway, and functions for creating and destroying them. * gw/wsp_state-decl.h: Made use of mid instead of machine. * gw/wsp.c: Made light use of WAPAddrTuple. Made use of mid everywhere, instead of pointers to WTPMachines. Tue Jun 6 08:44:13 2000 Lars Wirzenius * test/decompile.c: Added return type (void) to function OutputEncodedString. 2000-06-05 Richard Braakman * gw/wsp_pdu.[ch]: Added wtp_pdu_append_tpi function. * gw/wtp_send.c: Continued conversion to use of wtp_pdu. Next step is to handle resends better, but that requires changes to the state machines. 2000-06-05 Richard Braakman * gwlib/conn.[ch]: Change conn_flush interface so that it can block, and tries to send all queued output. This makes it more useful for threads that only want to do output and do not want to wake up for input. * gwlib/gwthread-pthread.c: Make gwthread_pollfd return -1 when poll() fails with EINTR, instead of 0, so that 0 can be relied on to mean timeout. 2000-06-05 Richard Braakman * gwlib/conn.c: Implemented conn_open_tcp(). Fixed conn_read_withlen, which I broke a few days ago. * gwlib/conn.c: Split the single Connection lock into two locks, one for reading and one for writing. This allows reader and writer threads to work without fighting over one lock. Only conn_wait needs both locks. * test/drive_wapbox.c: Take advantage of some new octstr functions. 2000-06-05 Richard Braakman * gwlib/gwthread.h, gwlib/gwthread-pthread.c: Renamed gwthread_join_all to gwthread_join_every, and added a gwthread_join_all that joins ALL threads. Added gwthread_wakeup_all to match. * gwlib/gwthread-pthread.c: Fix use of pipe(); reading and writing fd's were reversed. 2000-06-05 Richard Braakman * gw/wsp.c: Installed Joerg Pommnitz's patch for correct parsing of WSP capabilities. 2000-06-05 Tuomas Luttinen * test/decompile.[ch]: A WML decompiler by Chris Wulff, Vanteon. * test/wml_tester.c: A patch by Chris Wulff, Vanteon added to produce pure binary files. A little cleanup. 2000-06-05 > * gw/bb_smsc.c: changed sleep(1) to usleep. A bit more busier loop, that new interface is really needed * gw/numhash.c: removed some warnings Mon Jun 5 10:32:41 2000 Lars Wirzenius * gw/wtp.c: Fixed bug that was caused by not duplicating an octet string while copying it. Also fixed a memory leak. * gw/wtp_pdu.[ch]: Added function wtp_pdu_create. Also added wrappers around wtp_pdu.h to prevent problems when including many times, and added an include for gwlib/gwlib.h, so that the caller does not have to deal with that. * gw/wtp_send.c: Started conversion to using wtp_pdu.c instead of packing everything by hand. The basic PDUs are now converted. The negative ACK and some other ones are not, because I wasn't certain how they work, right now, and am too tired to understand the spec (probably too tired to hack, but I ran a fakewap test after each change to make sure I didn't break things too badly). Sun Jun 4 07:32:59 2000 Lars Wirzenius * Re-vamped the WTP layer to use a thread structure similar to WSP. All code referring to segmentation and re-assembly has been deleted (this was simpler for me - it wasn't used anyway, and we can dig it out of CVS if we want it later). Error handling also suffered, but on the other hand, the current structure should be easier to make robust. * gw/wap-events-def.h: Events generated from PDUs now have the address of the client and the gateway included in the event. This means we can use a trivial wtp_dispatch_event function interface, without having to carry around the addressing information separately. Other events that the WTP layer may receive include a `mid' (machine id) field for finding the correct WTPMachine. The ultimate goal it so make the WTPMachine data type hidden within WTP, so that there are no direct pointers to the machines. * gw/wapbox.c, gw/wsp.c, gw/wsp_state-decl.h: Use wtp_dispatch_event to send an event. * gwlib/gwthread-pthread.c: Commented out call to pthread_setspecific that was hanging shutdown. The real reason is probably somewhere else, but I didn't find it, so this workaround is used to make things at least seemingly work. Sun Jun 4 04:38:02 2000 Lars Wirzenius * gw/wsp.c, gw/wsp_state-decl.h: Use WSP_PDU's, instead of packing things ourselves, as far is possible. Some fields have special packing encodings, those we do partly ourselves still. * gw/wsp_pdu.c: Don't crash if OCTSTR field is NULL, just ignore it. Sun Jun 4 03:45:45 2000 Lars Wirzenius * gw/wap-events.c: wap_event_dump now reports name of Octstr fields. * gw/wsp_pdu.c: bit position is advanced correctly when unpacking a Uintvar. Also, dump tells when the dump ends. * gw/wsp_state-decl.h: Duplicate the URL octet string. Sun Jun 4 02:36:10 2000 Lars Wirzenius * gw/wsp_pdu.[ch]: Added function wsp_pdu_create, which creates an (empty) PDU of the desired type. Made the warning about an unknown PDU type in wsp_pdu_destroy be a panic instead. * gw/wsp.c, gw/wsp_state-decl.h: Converted to use wsp_pdu.[ch] for unpacking. We have issues with packing: at least some fields need to be packed in a special way, and this needs to be handled in a clean way. Sun Jun 4 01:03:55 2000 Lars Wirzenius * gwlib/protected.[ch]: Added wrapper for gethostbyname. * gwlib/socket.c: Made use of wrapper. Sun Jun 4 00:52:22 2000 Lars Wirzenius * gwlib/protected.[ch]: Wrote thread-safe wrappers around standard library functions gmtime, localtime, and rand. Note that this is just a beginning, we should wrap many more functions. * gw/urltrans.c, gwlib/gwlib.[ch], gwlib/log.c: Made use of the wrappers. Sun Jun 4 00:20:19 2000 Lars Wirzenius * gw/numhash.c: Added typecasts to silence compiler warnings. Kalle, please fix it properly so it uses unsigned chars. Sun Jun 4 00:06:23 2000 Lars Wirzenius * gw/wap-events.c: Added assertions to wap_event_name. Added calls to wap_event_assert. Event duplication now also works for NULL arguments. Fixed wap_event_assert (i.e., reduced the number of checks it makes - it was overly aggressive). * gw/wsp.c: Added calls to wap_event_assert. 2000-06-03 Richard Braakman * gwlib/octstr.[ch]: Added octstr_append_uintvar. * gw/wsp_pdu.[ch], gw/wsp_pdu.def: Do the same for WSP PDU's. * gw/wtp_pdu.c: Bugfixes. * test/test_pdu.c: Test WSP data too. 2000-05-31 Richard Braakman * gwlib/octstr.[ch]: Added octstr_get_bits and octstr_set_bits. * gw/wtp_pdu.[ch], gw/wtp_pdu.def: Deliberate preprocessor abuse to automate PDU packing and unpacking. First draft; works for simple test cases, needs more documentation. Not used by anything else yet. * test/test_pdu.c: Test program for above. 2000-05-31 Tuomas Luttinen * gw/wml_compiler.c (string_table_add): A bug fixed. The string didn't match any in the table, since it didn't have a termination character at the end of it as those in the table. Also string has to be destroyed if it has already a duplicate in the table. 2000-05-30 Kalle Marjola * gw/bb_smsc.c: added white and black lists. * doc/userguide/newconf.txt: added 'documentation' about white and black lists 2000-05-30 Kalle Marjola * gw/numhash.h|c: exported numhash from old smsgateway and edited it to work with new http2 and Octstrings, plus removed some functions. Next: implement white/black-list 2000-05-29 Richard Braakman * gw/smsbox_req.c: Fixed silly mistake. 2000-05-29 Richard Braakman * gwlib/conn.c: Implemented conn_read_packet(). 2000-05-29 Richard Braakman * gw/bb_boxc.c: If listening socket cannot be opened, handle it by panicking rather than segfaulting. 2000-05-29 Tuomas Luttinen * gw/wml_compiler.c: #ifdefs added to supprt libxml2. Does compile, but does not work with it, yet. WapIT -> Wapit * gw/wml_definitions.h: WapIT -> Wapit * gw/wml_compiler.h: WapIT -> Wapit * configure.in: libxml2 added. 2000-05-29 Richard Braakman * gw/smsc.c: Made bearerbox not crash if "smsc" field is missing from smsc config. * gwlib/gwthread-pthread.c: Comment around previous change was inaccurate; it was an fd leak on Linux too. 2000-05-29 Derry Hamilton * gwlib/gwthread-pthread.c: Added some system cleanups to delete_threadinfo. Threads are not always processes! 2000-05-29 Kalle Marjola * gw/bb_boxc.c: fixed possible problem in box shutdown and added multiple wapbox routing. It is, however, not done according to load levels, just random distribution. Load balancing later. 2000-05-29 Richard Braakman * test/fakewap.c: Use gwthread_join_all to wait for client threads to terminate. 2000-05-29 Richard Braakman * gwlib/gwthread-pthread.c: In new_thread, free its argument a bit earlier, to avoid a race with gw_check_leaks. (This caused seemingly random memory leak reports). * gwlib/conn.c: Use gwthread_pollfd instead of calling poll directly. 2000-05-29 Richard Braakman * gwlib/gwthread-pthread.c: Made gwthread_create fail gracefully if there are more active threads than the module can handle, rather than panicking. Sat May 27 06:39:51 2000 Lars Wirzenius * gw/wap-events.[ch]: Added wap_event_assert function. Sat May 27 02:50:09 2000 Lars Wirzenius * gwlib/gwthread.[ch]: Added function gwthread_join_all, which joins all threads running a specific function. * gw/wap-appl.c, gw/wapbox.c, gw/wsp.c: Use gwthread_join_all to synchronize shutdown properly. Sat May 27 02:05:41 2000 Lars Wirzenius * gw/wap-events.c: Only the fields for the correct event type are dumped by wap_event_dump. * gw/wapbox.c: Uncommented code to get heartbeat-freq setting from config. Added some shutdown code. NOTE: The wapbox does not currently shutdown correctly. Thread termination synchronization is not done and this causes a segfault at the end. Will hack that next. * gw/wap-appl.c: Event queue is emptied and destroyed at shutdown. * gw/wsp.c, gw/wsp_state-decl.h, gw/wtp_state-decl.h: Work started on making a global event queue for all WSPMachines. wsp_dispatch_event now the only external method for sending events to WSP. Its interface has been changed so that it only gets the event and will look inside the event to find addressing info - the WTPMachine is no longer needed to be given as the argument for this. A number of previously available functions are now static and must only be used from within the WSP layer. Sat May 27 02:02:33 2000 Lars Wirzenius * gwlib/gwthread.h, gwlib/gwthread-pthread.c: Name of function made as the name of the thread. Fri May 26 21:05:29 2000 Lars Wirzenius * utils/start-stop-daemon.c: Added pid_is_cmd for FreeBSD. Fri May 26 21:01:41 2000 Lars Wirzenius * gwlib/http2.c: Compare header names case-insensitively. Fri May 26 20:47:06 2000 Lars Wirzenius * gw/wap-appl.h: Moved to gw/wsp.h. Don't want a zillion small .h files, after all. * gw/wsp.h: Added prototypes for the application layer. 2000-05-26 Richard Braakman * gwlib/conn.c: Converted conn_claim() stuff to use new thread interface. * gwlib/gwthread-pthread.c: Bugfix, make sure the main thread can still safely call gwthread_self after shutdown, so that gwmem layer can log stuff. * gwlib/thread.c: Converted mutex->owner to use new thread interface. Fri May 26 20:34:01 2000 Lars Wirzenius * gw/wap-appl.[ch]: Wrote. This is the new application layer. This version is ugly - essentially I just moved code in here from the old wsp_http.c - but I want to clean it up before I break it further. * gw/wsp_state-decl.h: Use S_MethodInvoke_Ind instead of S_MethodInvoke_Res and wap_appl_dispatch instead of wsp_http_thread. * gw/wap-events-def.h: Added S_MethodInvoke_Ind, removed most fields from S_MethodInvoke_Res, since they're now unnecessary. * gw/wapbox.c: Starts the application layer. * gw/wsp.c: Added #include for wap-appl.h. * gw/wsp.h: Removed prototype for wsp_http_thread. * gw/wsp_http.c: Removed. Fri May 26 19:05:09 2000 Lars Wirzenius * gw/wap-events.[ch], gw/wap-events-def.h: Combined WTPEvent and WSPEvent into a unified WAPEvent. This makes it slightly easier to find the events (no need to wonder whether a TR-Invoke.ind is a WTP or WSP event, for example), and reduces code duplication a bit. * gw/wsp_events-decl.h, gw/wtp_events-decl.h: Removed. * Lots of files: WTPEvent and WSPEvent and related function calls changed to WAPEvent and its functions. * gwlib/http2.c: http2_header_dump works now even with a NULL argument. 2000-05-26 Richard Braakman * gwlib/gwthread.h: New thread interface. Encapsulates thread creation, and provides features for interruptible sleeping and blocking. Can eventually be extended to wrap all of pthreads, if desired. * gwlib/gwthread-pthread.c: Implementation of thread interface with pthreads. * gwlib/gwlib.h: Include gwthread.h too. * gwlib/gwlib.c: Initialize and shut down gwthread module along with the rest. * gw/bb_boxc.c, gw/bb_http.c, gw/bb_smsc.c, gw/bb_udp.c, gw/bearerbox.c, gw/smsbox.c, gw/smsbox_req.[ch], gw/wapbox.c, gw/wsp.h, gw/wsp_http.c, gw/wsp_state-decl.h, test/drive_wapbox.c, test/fakewap.c, test/test_counter.c, test/test_http2.c, test/test_http2_server.c, test/test_list.c: Use gwthread_create instead of start_thread. Thread functions are now void functions instead of (void *) functions, so removed all the "return NULL" and changed the declarations. Use long instead of pthread_t as the thread identifier. Use gwthread_join instead of pthread_join. * gwlib/log.c: Use gwthread_self() instead of pthread_self() to get the thread number to log. * gwlib/thread.[ch]: Removed start_thread function. Fri May 26 17:14:18 2000 Lars Wirzenius * doc/arch/wapbox-arch.fig: New figure showing the planned wapbox architecture. (Not visible in the actual documentation yet, though.) Fri May 26 16:59:03 2000 Lars Wirzenius * gwlib/http2.c: Destroy temporary header list in http2_type_accepted. Thu May 25 21:46:04 2000 Lars Wirzenius * gwlib/http.[ch], test/test_http.c: Removed. * gwlib/http2.[ch]: Added a number of header handling functions. Also added many assertions. * gw/wsp.[ch], gw/wsp_headers.[ch], gw/wsp_http.c, gw/wsp_state-decl.h: Converted to use http2 instead of http for header handling. 2000-05-25 Kalle Marjola * gw/bb_smsc.c: fixed some lock-ups during violent shutdown 2000-05-25 Richard Braakman * test/fakewap.c: Sanitized tid handling. It's now local to the client thread, rather than global. Each client should have its own tid space anyway. Thu May 25 18:45:15 2000 Lars Wirzenius * gwlib/gwlib.[ch]: gwlib_shutdown now always calls gw_check_leaks, to check for memory leaks. Added function gwlib_assert_init, to allow gwlib code to verify that gwlib has been initialized. * gw/bearerbox.c, gw/smsbox.c, gw/wapbox.c, test/drive_wapbox.c, test/fakesmsc.c, test/fakewap.c, test/test_cimd2.c, test/test_counter.c, test/test_http.c, test/test_http2.c, test/test_http2_server.c, test/test_list.c, test/test_mem.c, test/test_msg.c, test/test_udp.c, test/test_urltrans.c, test/wml_tester.c: Fixed to call gwlib_init and gwlib_shutdown instead of gw_init_mem and gw_check_leaks. * gwlib/octstr.c: Call gwlib_assert_init in seems_valid. Thu May 25 16:52:22 2000 Lars Wirzenius * gw/bb_smsc.c: Removed unused variable `ret'. 2000-05-25 Kalle Marjola * gw/smsc.c, gw/smsc.h, gw/smsc_p.h, gw/bb_smsc.c: removed old dial-prefix (use global unified-prefix) and route-prefix, and added new denied-prefix and preferred-prefix, see details from documentation * doc/userguide/newconf.txt: added notes of preferred-preix and denied-prefix 2000-05-25 Kalle Marjola * gw/smsc.h|c: got rid of bb_msg * gw/bb_smsc.c: modified to use just plain Msg * gw/bb_msg.*, gw/boxc.*, gw/wdp_udp.*: removed, not used anymore 2000-05-25 Kalle Marjola * gw/bb_smsc.c: added number normalization/unifying, via configuration variable unified-prefix. * doc/userguide/newconf.txt: added explanation of unified-prefix 2000-05-25 > * gw/*box.c: changed default configuration file to be kannel.conf. Please note that there is NO such file, but two sample files, smskannel.conf and wapkannel.conf 2000-05-24 > * doc/userguide/userguide.xml: Removed old configuration file things, read the newconf.txt file. Did same to HTTP adminstration notes, read file newbb.txt * doc/arch/arch-bearerbox.xml: Rewrote to reflect the new bearerbox. Have to do it a bit more deeply someday, however. And pictures, too. * gw/wsp.c: Applied a short WSP header patch by Joerg Pommnitz to handle broken headers from Timeport * test/simple.smsconf: removed 2000-05-24 Richard Braakman * gw/wsp_http.c: Fixed Accept header scanning in wsp_http_thread. 2000-05-24 > * doc/userguide/newconf.txt: added documentation about new configuration file * doc/userguide/newbb.txt: added documentation about new bearerbox * gw/bearerbox.c: moved new bearerbox into final name, old bearerbox removed from the project * gw/smskannel.conf, gw/wapkannel.conf: added new sample configurations * gw/kannel.*conf: removed old configuration defination files * test/sample.*conf: removed old sample configurations * gw/smsbox.c, gw/urltrans.c, gw/wapbox.c: edited to use new configuration file * README: updated 2000-05-24 Richard Braakman * test/test_cimd2.c: Written a while ago, added to CVS today. Might be useful for people doing speed tests of sms handling. 2000-05-23 > * gwlib/http2.c|h: moved destroying functions here, and changed so that http2_socket_host does not duplicate the octstr but returns reference * gw/bb_http.c: check for password of the admin * gw/smsbox*.c moved cgi and destroy functions to http2 2000-05-23 > * gw/bb_http.c: check for allow/deny IP for http admin 2000-05-23 > * gwlib/socket.h|c: added host_ip to get, well, host IP. That needed mutex because ntoa operation is not thread-safe, so added socket_init and shutdown, too * gwlib/gwlib.c: calls to socket_init and shutdown * gwlib/http2.c: get client host IP * gwlib/utils.c|h: added is_allowed_ip function * gw/bb_core.c: options -S and -I to start new bearerbox in suspended or isolated state * gw/bb_boxc.c: check for client allowed/denied IP 2000-05-23 Richard Braakman * test/drive_wapbox.c: Fix free-port-hunting code for fake httpd. 2000-05-23 Richard Braakman * gw/smsc_cimd2.c: The maximum message length was always set to 140. It should be 160 for normal (non-UDH, non-8bit) messages. Fixed. 2000-05-22 > * gwlib/utils.c|h, gw/bearerbox.c: moved normalize_number to utils module from old bearerbox * gwlib/http2.h|c: first version of http2_socket_ip, although not yet working with servers, beware 2000-05-22 Richard Braakman * gwlib/conn.h, gwlib/conn.c: Made output buffering explicit instead of hidden in the interface. (We can't hide it with 100% correctness if there are multiple threads using the Connection, not all of which are in a conn_wait loop). Added conn_output_buffering and conn_flush functions. * test/drive_wapbox.c: Made the fake httpd return a real wml page, for better testing. (This exercises the WML compiler). Cleaned up some memory leaks. 2000-05-22 Richard Braakman * gwlib/conn.h, gwlib/conn.c: Extended to handle end-of-file better. Added conn_eof function. * test/drive_wapbox.c: Use conn_eof. 2000-05-22 Richard Braakman * test/drive_wapbox.c: Make setting the U/P flag optional, with the -U flag, because Kannel no longer (erroneously) requires it. Also have its internal httpd supply a Content-Type header. 2000-05-22 > * gwlib/http2.c|h: implemented function http2_destroy_headers * gw/bb_core.c: some update to status information * gw/bb_http.c: fixed last memory leaks, now the new system should not leak memory at all. Still misses cgibin arguments because of the lack of operations in http2. 2000-05-18 Richard Braakman * wmlscript/wsfalloc.c: Make ws_f_malloc return blocks aligned to sizeof(long), to prevent unaligned accesses. This should fix the bug reported by Lim YoungLan, but I can't test that here. 2000-05-17 > * gwlib/counter.c|h: renamed counter_get as counter_increase and added function counter_value. * test/test_*.c, gw/wsp.c: changed counter functions * gw/smsc.c, gw/smsc_fake.c: started a project that smsc_close will eventually free all memory it has reserved. Fake does this already, rest do not, and close is a bit weird for those right now. * gw/bb_*.c: added counters for messages, fixed some timing problems. 2000-05-17 Tuomas Luttinen * gw/wml_compiler.c: Now variables use the string table. Some fixing for reducing numbers of the memory allocations and reallocations is needed. 2000-05-17 > * gw/bb_*.c: Some final cleanup added * gw/smsc_fake.c: smsc_close now destroyes eveyrhing. Should add this functionality to other SMSCes, too, and rename it as _destroy 2000-05-17 Richard Braakman * test/drive_wapbox.c: Memory leak now fixed. Added includes needed by accept(). 2000-05-17 Aarno Syvänen * wtp_state-decl.h: Two bugfixes: rid to 0, when the result is sent first time (thanks to Oliver Lau), conditions checking whether u/p-flag is up corrected. 2000-05-16 > * gwlib/list.c|h: added function list_producer_count * gw/bb_*.c: smsc thingies are now somehow working. Does not work very well with multiple smsces, however. 2000-05-16 Tuomas Luttinen * gw/wml_compiler.c: Memory leaks with variables removed. String table code mostly done, nrext thing is to start to use it. * gwlib/octstr.[ch]: octstr_create_tolower removed as unnecessary. 2000-05-15 Richard Braakman * gwlib/conn.[ch]: Found some more things to fix while writing drive_wapbox. Interface is almost stable now. * gwlib/thread.c: Added some assertions for mutex not being NULL. 2000-05-15 Richard Braakman * test/drive_wapbox.c: A tool to run the wapbox in isolation, for easy profiling. 2000-05-15 > * gw/bb_*.c: Now most memory leaks are fixed, the new bearerbox dies quite nicely and can handle exiting wapboxes and new connections. Still needs much testing and there is some mysterios things not freed at the end, so back to work. Mon May 15 16:07:00 2000 Lars Wirzenius * gw/wsp_http.c: Report character set when fetch is successful. * gwlib/http2.c: Fix parsing of character set from Content-Type. * test/test_http2.c: Report reply headers. Mon May 15 15:59:32 2000 Lars Wirzenius * gw/wsp_http.c: Do not require resp_headers to be non-NULL. Instead, only destroy it if it is non-NULL. Fixes bug #69 by Kalle Marjola. Mon May 15 15:06:16 2000 Lars Wirzenius * gw/wsp_http.c: Undid broken changes to how HTTP headers are generated. * gwlib/http2.c: Dump to log file the headers used in the request. 2000-05-15 Richard Braakman * wsp_http.c: octstr_destroy(key_os) and (value_os) moved into the loop, so that it's not a memory leak. 2000-05-11 Aarno Syvänen * wsp_http.c: Using octstr_compare instead of strstr in conditional header addition. There was some curious problem with strstrs. * wsp.c: Changed Can't handle event error code to 0xEO. This is user protoerr. Fri May 12 Derry Hamilton * fakewap.c: Added -F switch which enables continue on fail rather than exit on fail. (Stress testing) 2000-05-11 > * gw/bb_*.c: suspend and isolate status now in work. System still leaks memory somewhere and some things are missing, but WAP browsing works fine with new bearerbox. 2000-05-11 Richard Braakman * configure.in, configure: Made it not look for getloadavg.c on systems that have no getloadavg(). 2000-05-11 > * gw/bb_http.c: Oooops, added * gw/bb_*.c: added signal trapping and (shutdown) flow-control. Still need some new List operations to free all memory while exiting. 2000-05-10 > * gw/bb_*.c: and more, now some HTTP adminstration 'works' (implementation partial in other modules) Tue May 9 Derry Hamilton * gw/wapbox.c,configure.in,configure: Updated getloadavg bits to search for getloadavg, rather than just assume that it exists on Solaris. * utils/start-stop-daemon.c: Fixed typo. Tue May 9 23:03:26 2000 Lars Wirzenius * gwlib/gwmem-check.c: Fixed so that fill doesn't have a pointer alignment bug. Tue May 9 22:53:22 2000 Lars Wirzenius * gwlib/http2.c: Bugfix. Host header should include port number if the URL had a non-default one. Tue May 9 20:53:25 2000 Lars Wirzenius * gw/wsp_http.c: Report status code returned by http2_get_real if it fails. * gwlib/http2.c: Added includes for sys/types.h and sys/socket.h. This should silence warnings about accept being undeclared. Tue May 9 20:01:45 2000 Lars Wirzenius * configure.in: Make it allow random junk before the version number in the output of xml-config. Based on patch from Gus . 000-05-09 Derry Hamilton * gwlib/socket.c: Changed the calls to info to calls to error when something has gone wrong. * gwlib/list.c: Added gw_asserts to some of the list functions. The problem is higher up, though. * gw/wsp_http.c: Added gw_asserts to some of the URL handling a call to an invalid protocol causes problems. Tue May 9 19:31:44 2000 Lars Wirzenius * utils/start-stop-daemon.c: Hand-applied patch from David Reid for FreeBSD support. No way to test if I did it correctly, hopefully kannel-nag or a FreeBSD user will complain. 2000-05-09 Richard Braakman * gw/smsc.c: system-type and address-range are also required for SMPP configurations. 2000-05-09 > * gw/bb_*.c: something new, many things still missing 2000-05-09 Richard Braakman * gwlib/conn.c, gwlib/conn.h: Added octstr_read_withlen and octstr_write_withlen. Also fixed errors in unlocked_get(). 2000-05-09 Derry Hamilton * gw/wapbox.c, configure.in, configure, utils/start-stop-daemon.c: Cleaned up SunOS definition 2000-05-08 Derry Hamilton * gw/wapbox.c: Implemented load reporting for Solaris 2000-05-08 Richard Braakman * Made all sig_atomic_t variables volatile, because there is no reason to use sig_atomic_t otherwise. 2000-05-08 Richard Braakman * gwlib/conn.c: Commented static functions. Added unlocked_outbuf_len and unlocked_inbuf_len helper functions. Added unlocked_try_write helper function, to implement output buffering. Implemented conn_wait. 2000-05-08 Richard Braakman * test/fakewap.c: Fixed -n flag. 2000-05-07 Derry Hamilton * gwlib/socket.c: Fixed tv_usec > 1000000 handling. 2000-05-05 > * gw/bb_smsc.c: Now it is half done. However, the old smsc_interface should be redone, now idea to use old rq-items anymore in new design. Back to work on Monday * gw/bb_*.c: fixed some places causing warnings 2000-05-05 Aarno Syvänen * wtp_tid.c|h: Module now uses list standard functions * wtp_state-decl.h: Commented 2000-05-04 > * gw/bb_core.c: logfiles * gw/bb_boxc.c: added basic routing thingies, now it only needs some load balancing to wap side, otherwise this module is about complete.. oh I forgot the dynamic configuration, but that later - the old one does not have it either * gw/bb_udp.c: added routing, now this function is about ready, except dynamic configuration and some testing etc. 2000-05-04 Richard Braakman * gwlib/conn.c, gwlib/conn.h: Got rid of network_long functions. The interface is so awkward that it's just as easy for the caller to fill a 4-octet buffer and provide that. * gwlib/octstr.h, gwlib/octstr.c: Added functions octstr_write_data and octstr_append, used by the new Connection code. * gwlib/http2.c: Removed static octstr_append, superseded by the one in the octstr module. * gwlib/conn.c, gwlib/conn.h: conn_read interface was not useful. Renamed to conn_read_fixed(), made it return exactly the number of bytes specified. * gwlib/conn.c code fleshed out some more, but several functions still not implemented. 2000-05-04 Richard Braakman * gw/wsp_http.c: In wsp_http_thread(), do not destroy charset until after it is used by the converters. Thu May 4 18:35:24 2000 Lars Wirzenius * Making *DEVELOPMENT* release 0.9. This is not stable, don't use it in production use. 2000-05-04 Kalle Marjola * gw/bb_core.c, gw/bb_boxc.c, gw/bb_udp.c, gw/bb_smsc.c, gw/new_bb.h: added first version of the new bearerbox. WAP-browsing works, but bearerbox is missing signal handling, HTTP adminstration, log files, SMSC support, wapbox routing and many, many more things. * gw/new_kannel.conf: new configuration file type used by the new bearerbox. Documentation later. * Makefile.in: added target for bb_core, the new bearerbox proto 2000-05-04 > * gwlib/conffile.c|h: more changes so that all functions needing ConfigGroup work with NULL argument, returning just NULL 2000-05-03 Steffen Weinreich * smsc_emi.c: Fixed the EMI code for UDH and added an initialisation for the TRN counter. This fixes the error with negative TRN if there wasnt a message received before the first send 2000-05-03 Tuomas Luttinen * gw/wsp_http.c: Added the charset support here too. Now it's still needed in html2. * test/wml_tester.c: Rewrote most of the main-function, started using getopt for options. The charset stuff was added too. * gw/wml_definitions.h: The pile of definitions and static arrays just grew too huge. Added an own file for them. * gw/wml_compiler.[ch] : The WML compiler now recognises the most common character sets from ISO-8859-series(1-9) and UTF-8. It is now easy to add new 8-bit character sets into it. 2000-05-03 Richard Braakman * inet_aton is not used anywhere. Removed definition from gwlib/socket.c, and removed all configure checks for its existence. * Removed unused linger() code from tcpip_connect_to_server. We have CVS for storing dead code. 2000-05-03 Richard Braakman * configure.in, config.h.in, configure: Added --enable-mutex-stats option. * gwlib/thread.c, gwlib.thread.h, gwlib/gwmem-check.c: If mutex stats are enabled, log statistics about mutex usage. * gwlib/thread.c: Make mutex_try_lock silently ignore recursive locks again. Wed May 3 15:04:57 2000 Lars Wirzenius * contrib/html2wml.pl: Added script to convert WML to HTML, by Taneli Leppä. This is not used yet - Kannel lacks a way to add external converters (see the status page for the relevant project). But I guess I should archive it in my mail inbox. * README.src: documented the contrib directory. 2000-05-03 Richard Braakman * doc/CodingStyle: Added note about not putting large arrays on the stack. Maybe we can fix the pthread_attr_setstacksize problem this way. Wed May 3 12:20:32 2000 Lars Wirzenius * gwlib/gwlib.c: New file to hold new functions gwlib_init and gwlib_shutdown. * gwlib/gwlib.h: Added prototypes for gwlib_init and gwlib_shutdown. * gw/wapbox.c: Call gwlib_init (instead of gw_init_mem) and gwlib_shutdown. * gw/wsp_http.c: Removed commented out code that called old WML compiler. Converted to use new HTTP code. Tue May 2 22:01:06 2000 Lars Wirzenius * gw/bearerbox.c: sendsms_thread in internal smsbox commented out, because it was pointless converting it to the new HTTP, since it will disappear in the re-write. * gw/smsbox.c, gw/smsbox_req.c: Converted to use new HTTP. * gw/http2.[ch]: Wrote function http2_socket_fd. http2_server_send_reply modified to accept NULL arguments for headers and body. * gwlib/socket.[ch]: Wrote function socket_get_peer_ip. Tue May 2 20:19:45 2000 Lars Wirzenius * gw/html.[ch]: Converted html_ functions to use Octstr instead of C string. * gw/smsbox.c: Undid rpr's undoing of my change to get rid of send_hearbeat's static variable. It's a memory leak. We don't want memory leaks. In this case, it is of a fixed size, but it's annoying in the gw_check_leaks report. Also added calls to http2_init and http2_shutdown. * gw/smsbox_req.c: function obey_request converted to use http2 and Octstr. * gwlib/http2.c: Removed verbose "Re-using old socket" message. Also removed redundant checking of http2_get's return value in http2_get_real. * gwlib/octstr.[ch]: Wrote octstr_search_cstr_from. 2000-05-02 Richard Braakman * gwlib/conn.h, gwlib.conn.c: Initial framework for Connection module. 2000-05-02 Richard Braakman * gw/smsc_cimd2.c: Do not specify sms sender on outgoing messages. Explanation is in the code. 2000-05-02 Aarno Syvänen * wtp.c: In function add_segment_to_message, removed a static variable. in function tell_about_error, fixed a memory leak, 2000-05-02 > * doc/userguide/userguide.xml: added notes on UDH sending 2000-05-02 Aarno Syvänen * wsp_state-decl.h: Commented how implementation state machine corresponds ones defined by the specs. 2000-05-02 > * gwlib/conffile.c|h: modified some functions to work even with NULL arguments, to reduce checking in calling functions 2000-04-27 Richard Braakman * gwlib/thread.c: Unlike every other C library function, the pthread functions return their error code rather than setting errno. Changed all uses of errno in this file to use the returned values instead. While I was there, made all functions use the same indentation width (the file was mixed). * gwlib/thread.c: Made mutex_try_lock panic if it managed to lock the same mutex twice, rather than trying to cope. This is consistent with mutex_lock, and helps us stay portable. * gw/smsbox_req.c: Removed unused call to pthread_self. * gwlib/log.c: Cast pthread_self() to long rather than to int, for printing. 2000-04-27 Richard Braakman * gwlib/octstr.c, gwlib/octstr.h: New functions octstr_binary_to_base64 and octstr_base64_to_binary. Also made octstr_grow reserve space for the terminating NUL, so that the caller doesn't have to and can't forget. 2000-04-27 Richard Braakman * gwlib/list.c: Make list_destroy() silently ignore a NULL argument, like all the other destroy functions. 2000-04-27 Richard Braakman * gwlib/gwmem-check.c: In fill(), do arithmetic with long * instead of void *. 2000-04-27 > * gw/smsc_sema.c: some fixes and updates by Hao Shi 2000-04-27 Richard Braakman * gwlib/gwmem.h: Move prototype declarations out of the #if construct, because all of them are compiled though only one set is used. 2000-04-26 Richard Braakman * gw/smsc_cimd2.c: Wrote. Support for CIMD2 servers. * gw/smsc.c: Added CIMD2 hooks to all the multiplexer functions. Added support for "keepalive" option with CIMD2 needs. Fixed memory leak when smscenter_receive_message fails. * gw/smsc_p.h: Added SMSC_TYPE_CIMD2, and cimd2 fields to the shared structure. Added prototypes for cimd2 interface. * gw/kannel.conf: Add example configuration group for CIMD2. * doc/CodingStyle: Add bb.sms.cimd2 to the list of debug areas. * gwlib/charset.c, gwlib/charset.h: Wrote. Contains functions for converting between ISO-Latin-1 and the GSM default alphabet. Used by CIMD2 code. * gwlib/gwlib.h: Include "charset.h" as well. Wed Apr 26 16:40:41 2000 Lars Wirzenius * Making relase 0.8. Wed Apr 26 15:34:17 2000 Lars Wirzenius * gwlib/gwmem.h: Fixed prototypes for native wrapper. * gwlib/socket.c: Commented out SO_LINGER settings and added more detailed error reporting. 2000-04-26 > * gw/bearebox.c: added VERSION to status query * gw/boxc.c: commented out debug print of 0 load factor * gw/smsc_sema.c: new version by Hao Shi * test/sample.conf: made it to work along with configuration rename by Lars Sun Apr 23 23:44:30 2000 Lars Wirzenius * README.autoconf: Obsolete, thus removed. Sun Apr 23 23:37:40 2000 Lars Wirzenius * config.h.in, configure.in: Made it configure-time selectable whether to use the debugging features of gwmem or not. * gwlib/gwmem.c: Removed. Actually, split into gwmem-native.c and gwmem-check.c. * gwlib/gwmem.h, gwmem-native.c, gwmem-check.c: Separated the checking and non-checking implemenations. The term `native' is chosen to allow for a third option: `fast'. This will not do checking, but will reduce the number of actual malloc calls made. * gwlib/gwstr.c: Replaced includes with a simple "gwlib.h", so as to make sure config.h is included properly. * gwlib/octstr.c, test/test_mem.c: Fixed to conform to new interface of gw_assert_allocated. Sun Apr 23 22:38:18 2000 Lars Wirzenius * gw/wtp_send.c: When re-sending a message, create a duplicate of the message to be sent. Related to PR¤44 by Paul Keogh. Sun Apr 23 21:45:36 2000 Lars Wirzenius * test/wapbox_feeder.c: Obsolete, thus removed. Sat Apr 22 23:47:33 2000 Lars Wirzenius * configure.in, config.h.in: Added option --enable-http2. Files that start using http2.h should do it conditionally based on USE_HTTP2. This allows us to easily switch between the old and new implementations. Sat Apr 22 23:35:27 2000 Lars Wirzenius * gwlib/http2.[ch]: Implemented GET CGI argument parsing. Sat Apr 22 22:55:05 2000 Lars Wirzenius * gwlib/http2.[ch]: Moved PoolSocket's out of .c into .h and renamed them to HTTPSocket. This is because the server also needs to use them to keep implementation work easy. Thus, the server is represented as an HTTPSocket, not an int. Re-arranged some of the internal functions in .c regarding this. Oh yes, I implemented a bit of the server side part of the protocol as well. Need to do CGI argument parsing still. * test/test_http2_server.c: Wrote test program for server side. Sat Apr 22 21:07:11 2000 Lars Wirzenius * gwlib/gwmem.[ch]: Now report the name of the calling function as well as the file and source line (this requires a compiler that supports __FUNCTION__). Also, added gw_assert_allocated for checking that a pointer points at an allocated area. * gwlib/octstr.c, test/test_mem.c: Made use of gwlib/octstr.c. Sat Apr 22 19:28:52 2000 Lars Wirzenius * gwlib/gwmem.c: Turned memory checks back on by default. * gwlib/http2.c: If reading the status fails, close the connection and open a new one. If that also fails, *then* report to caller. It seems sometimes at least Apache manages to close the connection (even though it hasn't been idle for several milliseconds) *after* we have sent the request. This masks such a temporary error from the library user. Also, bug fix: We look for an *unused* PoolSocket instead of a used when, when allocating. * test/test_http2.c: Made it possible to run many threads do many client operations. Sat Apr 22 02:57:22 2000 Lars Wirzenius * test/run-http2-tests, test/test_http.c: Added -s option to old HTTP tester as well, and made test/run-http2-tests compare the results of the old and new ones as well as lynx. Sat Apr 22 02:40:38 2000 Lars Wirzenius * gwlib/http2.[ch]: Wrote. This is the beginning of the new HTTP implementation. * test/http2-test-urls, test/run-http2-tests, test/test_http2.c: Testing harness for the new HTTP implementation. * gwlib/octstr.h: Fixed comment explaining error return. 2000-04-20 Richard Braakman * Made read_to_eof set its output parameter to NULL on error, instead of leaving garbage in it. This fixes PR#52 reported by Paul Keogh. 2000-04-20 Richard Braakman * doc/arch/.cvsignore, doc/userguide/.cvsignore: New files. * gw/smsc_smpp.c, gw/smsc_smpp.h: Got rid of all uses of uint32_t. * gwlib/octstr.c: Got rid of all uses of uint32_t. * gwlib/utils.c, gwlib/utils.h: Provided encode_network_long and decode_network_long to help the functions that (erroneously) used uint32_t as an "exactly 4 octets" type. * gwlib/gwstdint.h: Removed. No code refers to uint32_t (or any of its cousins) anymore. This fixes PR#50, reported by David Reid. * config.h.in, configure.in, README.autoconf: Removed tests for uint32_t and stdint.h. Re-ran autoconf. 2000-04-20 Richard Braakman * gwlib/octstr.h, gwlib/octstr.c: Removed octstr_cat_char, all callers to it really wanted octstr_append_char and have been changed. 2000-04-19 Tuomas Luttinen * gw/wml_compiler.c: Now uses the struct to carry WML binary, the headers and string table. 2000-04-18 Tuomas Luttinen * gw/wml_compiler.c: type conflict with output_char corrected, calls to octstr_cat_char removed. 2000-04-18 Richard Braakman * gwlib/octstr.c, gwlib/octstr.h: Added octstr_append_from_socket. Corrected EINTR handling in octstr_write_to_socket. * gwlib/socket.c: Made read_available() cope with EINTR. 2000-04-18 Sanna Seppanan * gwlib/list.h,c Added list_cat. It joins two lists to one. Mon Apr 17 20:25:19 2000 Lars Wirzenius * test/test_list.c: Fixed more pthread_t vs long warnings. 2000-04-17 Sanna Seppanen * gwlib/octstr.h,c: Added octstr_get_digit_from(). Searches long int from octstr. Sat Apr 15 19:45:50 2000 Lars Wirzenius * utils/daily-patch: Skip changes to gateway/configure. Sat Apr 15 19:19:08 2000 Lars Wirzenius * gwlib/log.[ch]: Added function close_all_logfiles based on patch from Paul Keogh. Sat Apr 15 18:31:55 2000 Lars Wirzenius * gwlib/thread.c: mutex_lock now checks that it doesn't lock the mutex twice and panics if it does. Sat Apr 15 18:01:39 2000 Lars Wirzenius * gw/smsc_emi.c: If B115200 is not defined, use B38400 instead. This compiles, but I can't test it right now. Sat Apr 15 17:40:18 2000 Lars Wirzenius * test/test_list.c: More fixes to correct assumptions that pthread_t == long. Sat Apr 15 17:30:51 2000 Lars Wirzenius * config.h.in, configure.in: Fixed --enable-docs option and added (under protest but under pressure) a --enable-localtime option for outputting time stamps in configuration files as local time instead of GMT. 2000-04-14 Richard Braakman * gwlib/thread.c: Got rid of some #ifdefs by assuming HAVE_PTHREAD_H. * test/list.c: Fixed one more pthread_t == long assumption. Thu Apr 13 21:01:20 2000 Lars Wirzenius * gwlib/thread.h: Removed obsolete definitions for pthread_t etc on systems without . * test/test_list.c: Fixed so it won't assume pthread_t is a long or compatible with a long. Thu Apr 13 18:35:15 2000 Lars Wirzenius * Making release 0.7.1. Thu Apr 13 17:14:40 2000 Lars Wirzenius * gw/bearerbox.c: Commented out extraneous debugging message. * gw/wsp.c: Function transaction_belongs_to_session: Check that neither machine is unused. * test/fakesmsc.c: Always try reading at least once, even if timeout has already occured. This helps in high-load situations. * test/fakewap.c: Print "finished session" messages even if interval is very small. 2000-04-13 Richard Braakman * gw/smsc_cimd.c: Fixed message text loading for messages with both UDH and normal text. 2000-04-13 > * gw/bearerbox.c: tried to fix saturation problem; failed but now works a bit better. Also added max-queue variable reading, it had been lost in some point. I will try to fix saturation later on * gw/smsbox.c: removed that thread-safe heartbeat thingy, it is of no use (sorry Liw :) Wed Apr 12 2000 Derry Hamilton * gwlib/octstr.[ch]: Function octstr_append_char added. * gw/wml_compiler.c: Attribute values are now searched for text that can be replaced with one byte value codes. Wed Apr 12 00:30:54 2000 Lars Wirzenius * test/fakewap.c, test/test_http.c, test/test_urltrans.c, utils/start-stop-daemon.c: Changed references to to , except in start-stop-daemon, where is still needed because of getopt_long. Thanks to kean.leong.ang@my.arthurandersen.com for noticing this (and providing a patch, even though I did it slightly differently). Tue Apr 11 21:57:17 2000 Lars Wirzenius * gw/bearerbox.c: Try harder to read from smsbox to avoid the problem of not noticing smsbox heartbeats when incoming traffic is too fast. * gw/smsbox.c: Panic if bearerbox connection fails. * test/fakesmsc.c: Rewritten so as not to busy loop. 2000-04-11 Richard Braakman * gwlib/socket.c, gwlib/socket.h: Added socket_query_blocking and socket_set_blocking functions. Untested. 2000-04-11 Richard Braakman * gwlib/thread.c: Made mutex_destroy silently handle a NULL mutex, like other destroy functions. * gw/smsc.c: In smscenter_destruct(), also destroy smsc->mutex, to fix memory leak. (Thanks to Paul Keogh) 2000-04-10 Richard Braakman * gwlib/octstr.c: Corrected off-by-one errors in octstr_convert_range and octstr_check_range. 2000-04-10 Richard Braakman * gwlib/octstr.c: In octstr_search_char_from, don't assert that pos <= ostr->len. Just return -1 in that case. This preserves the old behaviour, and makes the function easier to use. 2000-04-10 Richard Braakman * gw/wsp_http.c: Made convert_to_self call octstr_duplicate rather than returning its argument directly. Its caller expects to be able to free the argument. 2000-04-10 Richard Braakman * gwlib/octstr.c, gwlib/octstr.h: Reimplemented octstr_search_str as octstr_search_cstr, removing the old one. Added octstr_search (for two Octstrs). Reimplemented octstr_search_char_from to use memchr instead of the octstr_get_char interface, for speed. 2000-04-10 Sanna Seppanen * gwlib/octstr.c,h: octstr_search_str()-function memory-leak fixed. If it is still somehow suspicious, please fix it! I do use it in my implementations. Sun Apr 9 20:42:08 2000 Lars Wirzenius * Makefile.in: Added nag target. * utils/find-long-lines: Wrote. * test/test_udp.c, test/test_list.c, test/fakewap.c, test/fakesmsc.c: Re-formatted some long lines. * gw/wsp.[ch], gw/wsp_machine-decl.h: Wrote function wsp_machine_mark_unused. This marks a WSPMachine as unused. * gw/wsp.c: wsp_machine_destroy now removes the machine from the list of WSPMachines. wsp_shutdown and same_client changed correspondingly. wsp_handle_event calls wsp_machine_destroy if it notices the machine becomes unused. * gw/wsp_state-decl.h: Changed to use wsp_machine_mark_unused instead of mucking around with the client_port field. * gw/wtp.c: wtp_handle_event removes machine if it notices it is unused. Sun Apr 9 02:18:38 2000 Lars Wirzenius * More memory leak fixes, now in bearerbox. Now it should be possible to run heavy and long time stress tests on all three boxes. * gw/bb_msg.[ch]: Wrote function rq_destroy. * gw/bearerbox.c: Wrote function destroy_bb. Added functions for freeing memory at end of main. * gw/wdp_udp.c: Octstr with client address now freed. * Some other changes as well. * gw/wtp.c: Bugfix. timer field of WTPMachine set to NULL after having been destroyed, so that wtp_machine_destroy doesn't try to destroy it a second time. * gw/wtp_timer.c: wtp_timer_destroy is now safe to call with NULL. (All our other _destroy functions are, so this one should also be.) * gwlib/gwmem.c: forget() does not fill the area any more, because this causes problems with realloc. This is a workaround, and needs to be handled better when I'm awake. Sun Apr 9 00:33:59 2000 Lars Wirzenius * Memory leak fixes. * gw/wapbox.c: Destroy received messages after they have been processed. Also destroy event created from the incoming message if no WTP machine for processing it can be found. * gw/wsp.c: Destroy handled events in wsp_handle_event. Destroy temporary Octstrs for holding the binary data of capabilities and headers. * gw/wsp_http.c: One more place where the content type returned by http_get_u wasn't destroyed. Also, the event wsp_http_thread gets as an argument is destroyed properly, and (bugfix!) not used after being destroyed. * gw/wsp_state-decl.h: Correctly duplicate data for event to be sent to wsp_http_thread. * gw/wtp_tid.c: Removed comments from around cache_item_destroy and used it to destroy the tid cache at shutdown. * gw/wtp_timer.c: wtp_timer_destroy and wtp_timer_stop now destroy the event associated with the timer. * Also made some other changes: * gw/wtp_send.c: Removed unnecessary error checkings for packing functions. * gw/wtp_timer.c: Made the global variable `timers' into a static. * gwlib/http.[ch]: Wrote header_duplicate. * gwlib/octstr.c: octstr_duplicate now returns NULL for a NULL argument, instead of crashing. Sat Apr 8 22:31:45 2000 Lars Wirzenius * gw/smsbox.c: Added informational message that smsbox is terminating. * gw/wapbox.c: Added more destruction and freeing things to end of main. This helps debugging memory leaks. * gw/wtp.h, gw/wtp_tid.h, gw/wtp_timer.h, gw/wtp_timer.c: Added shutdown functions. * test/wml_tester.c: Added call to gw_check_leaks to help debug memory leaks (none found in WML compiler, however). * gw/wsp.h, gw/wsp.c: Removed `next' element of WSPEvent structure, since it was unused. Also added a wsp_event_duplicate function. * gw/wsp.c: Really implemented wsp_machine_destroy. It's now used by the wsp_shutdown function, the client_port element is still set to -1 to signal an unused WSPMachine. * gw/wsp_http.c: Memory leak fixes. The type string returned by http_get_u is now freed, as is the data it returns and the Octstr copy made of it. * gw/wtp.c: Memory leak fixes. Implemented wtp_machine_destroy as a static function. Changed initializations of OCTSTR and WSP_EVENT type fields in WTPMachine so that empty things aren't allocated unnecessarily (and then leaked by overwriting the pointer without freeing the always unused empty things allocated). * gw/wtp_send.c: Possible memory leak fixes (though not necessarily actual, but that might be a problem in my testing): destroy Octstrs before overwriting the pointer with a new one. * gw/wtp_state-decl.h: Memory leak fixes: freeing things before overwriting the pointer to them. In some cases not allocating a thing that isn't going to be used at all. * gwlib/http.c: Memory leak fixes. * gwlib/octstr.[ch]: Commented out octstr_search_str since it isn't being used and seems suspicious. Also fixed seems_valid_real to report the name of the function as the name of the function instead of reporting the name of the file as the name of the function. 2000-04-08 Richard Braakman * gwlib/gwassert.h: Updated NDEBUG version of gw_asswert_place to match normal version. 2000-04-08 Richard Braakman * gw/wtp_timer.c: Removed debugging output again for normal operations. 2000-04-08 Richard Braakman * gwlib/octstr.c: More assertions. 2000-04-08 Richard Braakman * gw/wtp_timer.c: Converted to use generic List code. This should fix a number of bugs in the timer code. Also changed to a single indentation style, and made all log messages full sentences. Restored some debugging output about timers because I'm debugging them. * gw/wtp.c: In pack_wsp_event, call octstr_duplicate on exit_info instead of sharing it between the WSP and WTP events. (The WTP event will be destroyed soon afterwards, taking its octstrs with it). * gw/wtp_tid.c: In cache_item_create_empty, initialize item->next too. Also initialize source_address and destination_address to NULL instead of to empty octstrs (prevents memory leak). In tid_cached, use a temporary variable when returning the tid, to avoid accessing a cache element after releasing the lock. Sat Apr 8 01:01:00 2000 Lars Wirzenius * gw/smsbox.c, gw/urltrans.c, gw/wapbox.c, gw/wsp.c, gw/wsp.h, gwlib/log.c, Fixed some memory leaks. smsbox now report no allocated areas after serving 1000 "nop" services. Fri Apr 7 19:20:41 2000 Lars Wirzenius * gw/bearerbox.c, gw/boxc.c, gw/smsbox.c, gw/smsbox_req.c, gw/wapbox.c, gw/wsp.c, gw/wsp_http.c, gw/wsp_state-decl.h, gw/wtp.c, gw/wtp_send.c, gw/wtp_state-decl.h, gw/wtp_tid.c, gw/wtp_timer.c, gwlib/http.c: Removed hopefully unnecessary debugging output to make it possible to run things in heavy production use. Fri Apr 7 17:25:39 2000 Lars Wirzenius * gwlib/gwmem.c: gw_free: Removed #if 0 around call to real free. * test/fakewap.c: Bugfix. Length of UDP packet was computed incorrectly, causing wapbox to get rather confused. (That's also a bug, but will be fixed later.) 2000-04-07 Aarno Syvänen * wtp.c, wtp_state-decl.h: Included wtp_timer_destroy call in function machine_mark_unused, so that a timer created is always destroyed when a transaction ends. Fri Apr 7 15:08:50 2000 Lars Wirzenius * gwlib/gwassert.h: Made gw_assert_place also report the actual place its called from. * gwlib/octstr.c: Made seems_valid_real report the calling function name also, and re-wrote the assertions so that it is easier to see which condition failed. Added some assertions as well. 2000-04-06 Richard Braakman * gwlib/octstr.c, gwlib/octstr.h: Added new functions octstr_binary_to_hex, octstr_hex_to_binary, octstr_parse_long, octstr_check_range, and octstr_convert_range. They compile fine and have been tested a little, but none of them have been used in real code yet -- use with care. Thu Apr 6 17:52:16 2000 Lars Wirzenius * gw/wsp_http.c: Add X_Network_Info and X-WAP-Session-ID headers. 2000-04-05 Aarno Syvänen * wsp*, wtp*: Changed primitive event names to conform even more closely names used by the specifications. Wed Apr 5 18:38:20 2000 Lars Wirzenius * README.docbook: Added note about transfig being needed. Wed Apr 5 18:20:52 2000 Lars Wirzenius * csdr.[ch] renamed to wdp_udp.[ch] and other files modified accordingly. 2000-04-05 Richard Braakman * wmlscript/wsint.h: Restored "extern int yylex()" declaration. That at least shuts up -Wall, and there is no clean solution because we have to deal with Bison output. 2000-04-04 Aarno Syvänen * wtp_send.c|h: Changed tid type to int * wapbox.c|h: Select connectionless requests out before calling wtp. They made mess of wtp error handling mechanism. Tue Apr 4 17:55:10 2000 Lars Wirzenius * utils/kannel-log-summary: Wrote. Requires AWK. Improvements welcome. Tue Apr 4 14:57:55 2000 Lars Wirzenius * gw/urltrans.c: Changed to use List. Tue Apr 4 14:42:54 2000 Lars Wirzenius * gw/urltrans.c, gw/wsp_headers.c, gw/wsp_headers.h, gwlib/octstr.c, gwlib/octstr.h: Removed OctstrList, use plain List instead. Tue Apr 4 14:15:27 2000 Lars Wirzenius * gw/bb_msg.c, gw/bearerbox.c, gw/boxc.c, gw/msg.c, gw/smsbox.c, gw/smsbox_req.c, gw/wapbox.c, gw/wsp.c, gw/wsp_http.c, gw/wtp.c, gw/wtp_send.c, gw/wtp_send.h, gw/wtp_timer.c, gwlib/http.c: Changed calls to assert to calls to gw_assert. Mon Apr 3 21:58:19 2000 Lars Wirzenius * gw/smsbox.c: Fixed a memory leak in error conditions. Also rewrote send_heartbeat so it doesn't use a static variable. * gwlib/gwmem.c: Make filling allocated and freed memory areas optionsl. There is a bug somewhere that causes filling of freed memory areas to crash. Mon Apr 3 21:02:49 2000 Lars Wirzenius * test/test_urltrans.c: Wrote. Useful for testing memory leaks. * gw/msg.[ch]: Used long instead of int32. * gw/smsbox.c: Fixed output restriction format in debugging statement. Also added a call to gw_check_leaks so that memory leaks can be reported. * gw/urltrans.c: urltrans_destroy now works even when called a NULL argument. Also, fixed a couple of memory leaks: urltrans_destroy frees the actual list header node as well, urltrans_find frees the temporary list of words, and destroy_onetrans frees the username and password fields. (The work on gwmem.c starts paying.) * gwlib/gwassert.h: Added a gw_assert_place macro so that the caller can set explicitly the place reported. * gwlib/gwmem.[ch]: Record location where memory allocation is made, so that gw_check_leak can report it. * gwlib/octstr.c: seems_valid reports the place it is called from in the assertion error messages, not the places where gw_assert fails. * test/test_http.c: Added -r option for repeating the fetch. Mon Apr 3 18:55:46 2000 Lars Wirzenius * gwlib/socket.c: Changed certain AF_INET constants back to PF_INET. I'm stupid. * test/fakewap.c: Added 'c:' to getopt arguments and made -h work. Thanks to Adam Kelly. * gwlib/list.c: list_destroy destroys the condition variable for the list as well. Thanks to Paul Keogh. Mon Apr 3 18:52:48 2000 Lars Wirzenius * gwlib/gwassert.h: Remove unnecessary and disfunctional #ifndef wrapper. 2000-04-03 Richard Braakman * gwlib/octstr.c: Made octstr_write_to_socket() retry after EINTR. 2000-04-03 Richard Braakman * gwlib/gwstr.c, gwlib/gwstr.h: Removed split_words(), it has been superseded by octstr_split_words(). * gwlib/gwstr.c, gwlib/gwstr.h: Removed url_decode(), it has been superseded by octstr_url_decode(). * gw/urltrans.h: Removed bogus paragraph from the function comment for urltrans_get_pattern. 2000-04-03 Richard Braakman * wmlscript/wsint.h: Always define WsInt32 to long and WsUInt32 to unsigned long, rather than looking for a type of exactly four bytes. * wmlscript/wslexer.c: Pass ws_stream_getc a pointer to 'WsUInt32', like it asks, rather than 'unsigned int', which might be smaller. * wmlscript/wmlsdasm.c: Print a v_int constant as a long, rather than int. * config.h.in, configure.in, configure: Completely got rid of SIZEOF_INT and SIZEOF_LONG constants. 2000-03-31 Aarno Syvänen * wtp.c: Tell_about_error: remove debuggung statements causing segfaults. In addition, locks to serialise reassemby. 2000-03-31 Richard Braakman * gwlib/octstr.c: Made octstr_decode_url not segfault on empty octstrs. Added assertions. Fri Mar 31 04:58:20 2000 Lars Wirzenius * gwlib/gwmem.c: Formatting and other minor changes. Fri Mar 31 03:35:59 2000 Lars Wirzenius * gw/csdr.[ch]: Changed to use Octstrs and udp_* functions from gwlib. * gwlib/socket.c: Changed udp_create_address so that it accepts "*" as a hostname alias for INADDR_ANY. Fri Mar 31 02:17:52 2000 Lars Wirzenius * gwlib/socket.c: Changed PF_INET to AF_INET. * test/fakewap.c: Made command line parsing much more user friendly. Also started cleaning up the implementation, so that it, for example, uses gwlib and avoids using quite as many magic numbers and convoluted logic, but got bored and decided to do something else instead. Current version works, however. Removed some unwanted Windows stuff (the goal is to make gwlib work in Windows and make fakewap use that). Removed unnecessary option to set sender port number. Fri Mar 31 00:31:21 2000 Lars Wirzenius * debian/*: Added Debian packaging files. The Debian package is not yet official, but these files allow one to build a Debian package. * Makefile.in, configure.in: Check whether start-stop-daemon already exists and use the system one if it does (it only exists on Debian, though). * utils/kannel-init.d: Changed location of box programs and configuration files. 2000-03-30 Tuomas Luttinen * gw/wml_compiler.c: Memory leaks stiched. * gwlib/octstr.[ch]: octstr_str_compare added. 2000-03-30 > * gw/cgi.*: changed argument list value into Octstr to allow UDH-fields to have %00 on them * gw/bearerbox.c, gw/smsbox*.c: fixed cgiarg uses * gwlib/octstr.c|h: added function octstr_url_decode (copied from gwstr) 2000-03-30 Richard Braakman * gwlib/socket.c: Cast sockaddr arguments for recvfrom() and sendto() to (struct sockaddr *). 2000-03-30 Richard Braakman * gwlib/socket.c: Tidied up gethostnameinfo(), removed excessive use of __ in names. 2000-03-30 > * gwlib/octstr.c: removed wrong assertion from octstr_truncate Thu Mar 30 06:51:03 2000 Lars Wirzenius * gwlib/octstr.[ch]: Changed octstr_create_from_data and octstr_get_many_chars to get void* instead of char*. * gwlib/socket.[ch]: Wrote some generic UDP socket handling things. Thu Mar 30 05:28:02 2000 Lars Wirzenius * acconfig.h, config.h.bot, config.h.top, stamp-h.in: Removed as unnecessary. * config.h.in, configure.in, gwlib/conffile.h, gwlib/log.c: Cleaned up by removing unnecessary checks. For example, since we *require* an ANSI C compiler anyway, there's no point in checking for const. Thu Mar 30 04:47:25 2000 Lars Wirzenius * gwlib/gwmem.c: Added some code to keep track of memory allocations and to check that frees free freeable memory. * lotsafiles: Added a gw_init_mem call to the beginning of each (relevant) main function. Thu Mar 30 03:10:21 2000 Lars Wirzenius * gw/wsp.c: Made use of Counters. Thu Mar 30 03:05:53 2000 Lars Wirzenius * gwlib/counter.[ch]: Wrote. * test/test_counter.c: Wrote. Thu Mar 30 02:25:51 2000 Lars Wirzenius * lotsafiles: Made minor tweaks to make things compile on my machine with CFLAGS='-Wall -O2 -g -Wbad-function-cast -Wcast-align -Wsign-compare -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations' (which is getting pretty aggressive). Thu Mar 30 01:27:40 2000 Lars Wirzenius * Changed msg_dump and octstr_dump to take a "level" argument. This allows them to indent dumps within dumps correctly. Related changes at callers. Thu Mar 30 01:04:34 2000 Lars Wirzenius * gw/wsp.c, gw/wsp.h, gw/wsp_machine-decl.h: Changed METHOD_MACHINE and SESSION_MACHINE macros so that their users provide all punctuation. This will more easily allow certain nifty stuff in the future. Thu Mar 30 00:57:58 2000 Lars Wirzenius * utils/attgetopt.c: Added AT&T's public domain implementation of getopt(3). * Makefile.in, config.h.in, configure.in, utils/start-stop-daemon.c: Modified to check for and use getopt, getopt_long, and getopt_h, and to use attgetopt.c if no system getopt is found. Thu Mar 30 00:24:52 2000 Lars Wirzenius * daily-patch: Added a summary to beginning of report. Thu Mar 30 00:01:35 2000 Lars Wirzenius * Makefile.in: Removed -I options from CFLAGS. We're supposed to refer to header files in other ways than assuming -I. You need to re-run configure (or at least config.status). * lotsafiles: Changed header file references to include directory names where necessary. Wed Mar 29 23:42:40 2000 Lars Wirzenius * gwlib/gwmem.c: Added some asserts. Also, gw_malloc now fills the memory area with 0xbabecafe so as to make sure it is _NOT_ all bits zero. Wed Mar 29 23:29:26 2000 Lars Wirzenius * gwlib/octstr.[ch]: Added gw_asserts and cleaned up formatting. Wed Mar 29 23:01:15 2000 Lars Wirzenius * gwlib/list.c: Changed assert to gw_assert. * test/test_list.c: Cleanups. Wed Mar 29 21:59:53 2000 Lars Wirzenius * Makefile.in: Removed installation of test_wml, since it's obsolete. * configure.in, config.h.in: Check specifically for 1.8.6 of libxml. * gw/wml_compiler.c: Use kludge around 1.8.6 bugfix conditionally. 2000-03-29 Richard Braakman * gwlib/gwassert.h: New file, defines gw_assert() macro which calls panic() when an assertion fails, instead of writing to stdout. stdout is not available when kannel runs as a daemon. * Makefile.in: Put libgwlib.a after libwmlscript.a in the libs line, because libwmlscript.a now needs the panic symbol from libgwlib.a. * gwlib/gwlib.h: Include gwassert.h by default. * gwlib/gwmem.c, gwlib/octstr.c, wmlscript/*: Use gw_assert() instead of assert(). Wed Mar 29 20:44:52 2000 Lars Wirzenius * gw/msg.c: Cleanups. No need to check that msg_create returns non-NULL (it panics, if it fails). Use octstr_duplicate instead of doing it manually with octstr_copy. * gw/wtp_send.c: Bugfix. wtp_send_result used to return the same message copy that it passed on to put_msg_in_queue. The caller would then make a duplicate. This is a race condition: sometimes the message in the queue would be processed and destroyed before the caller had time to duplicate the message. Changed it so that wtp_send_result makes the duplicate itself, since that is the only reasonable way to avoid the race condition. * gw/wtp_state-decl.h: Changed to use result from wtp_send_result directly, instead of duplicating it. Wed Mar 29 19:44:05 2000 Lars Wirzenius * test/test_list.c: Fixed warnings. 2000-03-29 Aarno Syvänen * wtp.c: Added locks for serialising reassembly 2000-03-29 > * gw/*box*.c: fixed some udh-things like it is now possible to send UDH without text field * gw/smsc_cimd.c: fixed that it discarded message without text file, but with udh field 2000-03-29 Richard Braakman * gwlib/octstr.c: Added static octstr_grow() call for other octstr methods to use. This gets rid of some duplicate code. Tue Mar 28 21:16:35 2000 Lars Wirzenius * doc/CodingStyle: Added various stuff. 2000-03-29 Sanna Seppanen * gwlib/http.c: restored the old file to fix the GET functionality 2000-03-29 Richard Braakman * gwlib/octstr.c: Small changes to deal with the possibility of ostr->data being NULL if ostr->size is 0. 2000-03-29 Richard Braakman * gwlib/gwmem.c: Add assertion (size > 0) to gw_malloc. 2000-03-29 > * gw/smsbox_req.c: some simple truncation to UDH sending (not sufficient but should help a bit) and little flag fix * gw/smsc_sema.c: fix of 120 char problem by Hao Shi 2000-03-29 Richard Braakman * gw/smsc_smpp.h: Removed definitions of unused empty structures smpp_pdu_unbind, smpp_pdu_unbind_resp, smpp_pdu_enquire_link, and smpp_pdu_enquire_link_resp. 2000-03-29 Sanna Seppanen * gwlib/http.c: http_get_u() deleted a bunch of duplicate code. GET query is sent as a message body. 2000-03-28 Aarno Syvänen * wtp*, wsp*: Changed primitive names. Now they conform with ones used by the specifications. Tue Mar 28 16:14:49 2000 Lars Wirzenius * gwlib/list.[ch]: added functions list_delete_all, list_delete_equal, and list_extract_all. Also added a typedef for the comparision function type used by several list functions. * test/test_list.c: Wrote additional test for the new functions. 2000-03-28 Aarno Syvänen * wtp_state-decl.h: Allocated memory for resent messages * wapbox.c: Deallocate memory reserved for messages. (Based on tips from Paul Keogh) In addition, added timer mutex iniatilisation. * wtp.c: Added locks for machines. Added structure segments for making reassembly thread safe. 2000-03-28 Richard Braakman * utils/start-stop-daemon.c: Put conditional OSLinux || OSHURD around the definitions for pid_is_user and pid_is_cmd, because those functions are not defined for OSSunos. This is probably not the last of the changes needed; we'll see. 2000-03-28 > * gw/smsbox_req.c: added UDH sending code alpha test. Use field 'udh' in sendsms http interface * gw/smsbox.c: fixed one mutex problem which only occured if there was some problems * gw/msg.h: marked that most functions do not fail, but panic * gw/msg-decl.h: removed plain_sms, which was not used anymore 2000-03-27 Aarno Syvänen * wtp*: Added some comments. Made code review changes. Added code for timers (This is, how ever, still commented out. It must be tested with a new version of fakewap.). Corrected some of memory leaks pointed out by Paul Keogh. * wtp.c: Added lock for the global wtp transaction identifier. 2000-03-27 > * gw/bearerbox.c: changed 'http-port' into 'http-admin-port', to lessen confusion. Old name still works, too. * gw/bb.h: modified default http-admin-port to 13000 and wapbox-port to 13002 to keep ports close to each other * */*.conf: changed that name and port in configuration files * doc/userguide/userguide.xml: renamed variables updated in userguide. * gw/smsc_cimd_c: commented out that the connection dies if the expected string is not received, as this caused problems with slower link * gwlib/utils.h: added -D option in output 2000-03-25 Derry Hamilton * Makefile.in: Added -Iutils to CFLAGS * utils/start-stop-daemon.c: Added short option only stuff. Cast pid_t to int so that printf gets it right * utils/kannel-nag: Now asks for bash specifically rather than assuming that /bin/sh is actually bash * gw/smsc_sema.c: Replaced bzero with memset * gw/wml_compiler.c: Cast arguments to isalpha and isalnum to int (are char) * gwlib/http.c: similar, for isspace Fri Mar 24 16:43:16 2000 Lars Wirzenius * Making release 0.7. Fri Mar 24 14:52:19 2000 Lars Wirzenius * gwlib/http.c: Changed it so that binary images also work. * test/test_http.c: Wrote. 2000-03-24 Sanna Seppänen * gwlib/http.c: tested and debugged httprequest_replace_header(). Fri Mar 24 12:38:33 2000 Lars Wirzenius * configure.in, configure: Check that gnome-xml is at least 1.8.6. 2000-03-24 Sanna Seppänen * gwlib/http.c,h: header_destroy returns now a pointer to the next header. tested and debugged httprequest_remove_header(). Thu Mar 23 19:58:44 2000 Lars Wirzenius * gw/bb_msg.h, gw/bearerbox.c, gw/msg.c, gw/msg.h, gw/urltrans.h, gw/wsp.c, gw/wsp.h, gw/wtp.c, gw/wtp.h, gwlib/http.h: Removed commas from end of enum definitions. These would be very useful (since some of them are generated automatically), but they're against the C specification (and I distinctly remembered they were not). Thanks to Markku Rossi for putting me straight. Thu Mar 23 19:37:03 2000 Lars Wirzenius * gw/wml_compiler.[ch]: Removed kludge to not use the new WML compiler when libxml is not installed while compiling. The new WML compiler is becoming required by this change - if you don't have libxml already, install it, or you lose. * gw/wsp_http.c: Don't use the old compiler at all. Thu Mar 23 19:22:18 2000 Lars Wirzenius * README: Changed requirement for libxml to at least 1.8.6, since 1.8.5 resulted in problems (last character of WML source was mangled). 2000-03-23 Tuomas Luttinen * gw/wml_compiler.c: The global variable for the binary removed, now should be thread safe. * test/wml_tester.c : Minor formatting changes. 2000-03-23 Sanna Seppanen *gwlib/http.c: corrected error in httprequest_add_header. hope it'll work now. Tue Mar 21 16:46:04 2000 Lars Wirzenius * doc/CodingStyle: Modified the description of using panic. 2000-03-23 * gwlib/log.c|h: added negation to -D (debug place) command line option, which is used with starting '-' * gwlib/utils.h, doc/CodingStyle: commented -D option 2000-03-23 Sanna Seppanen * gwlib/http.c, http.h: added comments. 2000-03-22 Richard Braakman * gw/smsc_cimd.c: Removed some bogus errno values in error messages. 2000-03-22 Sanna Seppanen * gwlib/http.c: htp_get_u: After furthed investigation, zero-valued "Content-Length" header is valid, changing back. 2000-03-22 Sanna Seppanen * gwlib/http.c: A minor fix to header_pack(). Check the sprintf return value. header_create() return NULL if fails. * gwlib/http.c: htp_get_u: zero-valued "Content-Length" header from phone won't be sent to web server. 2000-03-22 Derry Hamilton * gwlib/http.h: Modified the definition of header_dump to match that in gwlib/http.c 2000-03-21 Sanna Seppanen * gwlib/http.c: internal_base6t4() uses rint(). alpha doesn't recognize it, so implemented it as round_to_closest_integer(). 2000-03-21 Sanna Seppanen * gwlib/http.c: Rewrote httprequest_get_header_value(). 2000-03-21 Sanna Seppanen * gwlib/http.c: Rewrote httprequest_remove_header(). 2000-03-21 Sanna Seppanen * gwlib/http.c: Rewrote httprequest_replace_header(). 2000-03-21 Sanna Seppanen * gwlib/http.c: Corrected some debug sentences. Harvest of code review: the return type of header_dump() changed to void. rewrited httprequest_add_header(). 2000-03-21 Richard Braakman * gw/smsc_emi.c: small changes, in preparation for large changes. 2000-03-21 Sanna Seppanen * gwlib/http.c: Changed socklen_t to int according to manual in httpserver_get_request. 2000-03-21 Tuomas Luttinen * gw/wml_compiler.c: More little fixes from the code review, also a bug fix. 2000-03-21 Richard Braakman * gw/smsc_cimd.c, gw/smsc_emi.c, gw/smsc_fake.c, gw/smsc_p.h, gw/smsc_sema.c, gw/smsc_smpp.c: Removed unused field "latency". 2000-03-21 Tuomas Luttinen * gwlib/octstr.c: a bug fixed in the octstr_delete; now the \0-character is added in the end. Tue Mar 21 14:41:01 2000 Lars Wirzenius * utils/kannel-nag, utils/changelog-report, utils/daily-patch: Added to CVS so that interested people can look at them. Don't run them without asking. 2000-03-21 Richard Braakman * gw/bearerbox.c: Deleted assertion in http_admin_command. It is valid for `list' to be NULL if there are no CGI arguments. 2000-03-21 Richard Braakman * utils/kannel-init.d: Added some configuration options at the top. It now controls my local Kannel setup without problems. Tue Mar 21 13:43:50 2000 Lars Wirzenius * gw/wtp.c: Converted to use new list instead of (broken) old custom list. 2000-03-21 Richard Braakman * utils/run_kannel_box.c: Make it remove its pidfile when it dies. * utils/kannel-init.d: New script file to start and stop Kannel (suitable for use in /etc/init.d) * utils/start-stop-daemon.c, utils/start-stop-daemon.8: Utility used by kannel-init.d, taken from dpkg source. * Makefile.in: Added entry for start-stop-daemon. Tue Mar 21 12:57:35 2000 Lars Wirzenius * gwlib/list.[ch]: Wrote function list_extract_first. * gw/wsp.c: Modified to use list_extract_first instead of doing it manually with list_lock/unlock and list_len and list_get and list_delete. Tue Mar 21 12:38:52 2000 Lars Wirzenius * gw/wsp.c, gw/wsp_machine-decl.h, gw/wsp_state-decl.h: Converted more lists to use gw/list.h. While debugging this (hey, 0 is not true, is it?) also implemented wsp_machine_dump. * gw/list.[ch]: NOTE: Changed interface to list_search (comparison function must now return true (non-zero) for item). Also wrote list_search_all. 2000-03-20 Tuomas Luttinen * gw/wml_compiler.h: Minor code review fixes. The third argument of wml_compile (Octstr **scripts) were deleted. * gw/wml_compiler.c: Lots of little code review fixes, yet more to come. Added a patch to remove a bug in the variable handling. Functions text_strip_blank and text_shrink_blank moved into the octstr.[ch]. * gw/wsp_http.c: Changed to use wml_compile with two arguments. * gwlib/octstr.[ch]: octstr_strip_blank and octstr_shrink_blank moved from wml_compiler.c. * test/wml_tester.c: Changed to use wml_compile with two arguments. 2000-03-20 * gwlib/http.c: fixed bug in header_pack pointed out by Paul Keogh. Also fixed a major too-early free in request_wrap, which caused segmentation faults in heavy load. * gw/*.*: some little fixes/comments Mon Mar 20 16:56:36 2000 Lars Wirzenius * gw/wapbox.c, gw/wsp.c, gw/wsp.h, gw/wsp_machine-decl.h, gw/wtp.c, gw/wtp.h, gw/wtp_machine-decl.h, : Converted from hand-made lists to the new generic list. At least partially. * gwlib/list.[ch]: Added a list_search function (untested as yet, though). Mon Mar 20 15:45:43 2000 Lars Wirzenius * gwlib/list.[ch], test/test_list.c: Wrote a generic dynamic list implementation. There can be only one, code duplication leads to bugs. This is not yet used anywhere, except the test program, but I'll start working on converting the wapbox to this next. Mon Mar 20 15:10:52 2000 Lars Wirzenius * gw/wapbox.c: Function empty_queue_thread: Removed timestamp variable that isn't used anymore. * gw/wsp.c, gw/wtp.c: Marked some places with comments about problems, since I had no time to fix the problems yet. * gwlib/gwmem.c: gw_realloc now checks that the size is non-zero and panics if it is zero. realloc(foo, 0) is equivalent to free(foo), but this is obscure enough that using it for that is rather likely to be a bug. * gwlib/octstr.c: Made octstr_dump use unsigned chars. Sat Mar 18 10:40:24 CET 2000 Patrick Schaaf * gw/wsp_http.c: map-url logging tamed, minor code cleanup. Fri Mar 17 17:49:38 2000 Lars Wirzenius * Making release 0.6.1. 2000-03-17 * gw/*.*, gwlib/*.*: numerous little code lookup fixes 2000-03-17 Richard Braakman * gw/smsc_p.h, gw/smsc_sema.h, gw/smsc_smpp.[ch], gw/smsc_interface.def: Got rid of obsolete sms_msg.c and sms_msg.h. 2000-03-17 Richard Braakman * Added .cvsignore files to all directories. 2000-03-17 Richard Braakman * wmlscript/wsopt.c: Compress "const_es; return" to "return_es", and leave it out entirely at the end of a function (where returning the empty string is the default). Fri Mar 17 10:55:37 2000 Lars Wirzenius * gw/wsp_http.c: Protect calls to wml_compiler with a mutex to work around a bug in the compiler that makes it unsafe with threads. This is just a stopgap measure, until the compiler can be fixed properly. 2000-03-17 Richard Braakman * wmlscript/wsopt.c: Remove dead code after returns, not just after jumps. 2000-03-16 Richard Braakman * wmlscript/*: Stylistic changes. * wmlscript/wsbc.c: Minor bugfix in verification of bytecode. 2000-03-16 Richard Braakman * utils/run_kannel_box.c: Clean up compiler warnings, fix minor bug found by rpr. 2000-03-15 Markku Rossi * wmlscript/wsopt.c: Fixed some bugs from the assembler stream handling. 2000-03-13 * README: Added notes of smsc_interface.def 2000-03-10 Tuomas Luttinen * gw/wml_compiler.c (parse_octet_string): bug fix with parsing $-characters. Tried to allocate a huge block and wapbox went down on it. Fri Mar 10 16:48:35 2000 Lars Wirzenius * Making release 0.6. 2000-03-10 Markku Rossi * wmlscript/: Fixed some warnings. 2000-03-10 Sanna Seppanen * gwlib/http.c: httprequest_execute: memory freeing functions added. also changed some error() to warning() -functions Fri Mar 10 14:52:19 2000 Lars Wirzenius * gw/smsc_emi.c, gw/wsp.c, gwlib/gwmem.c, gwlib/http.c, gwlib/thread.c, test/test_wml.c: Fixed int/pointer size and int/size_t size differences in various places. 2000-03-10 Richard Braakman * utils/run_kannel_box.c: New utility, a wrapper that runs as a daemon and spawns a given box. If the box dies, the wrapper will spawn a new one. It will die and kill its box if it gets SIGINT, SIGQUIT, or SIGTERM. * Makefile.in: add a line for run_kannel_box.c Fri Mar 10 13:34:59 2000 Lars Wirzenius * configure.in: Check for xmlDocGetRootElement instead of xmlParseMemory so as to find only newer versions of libxml. (Fix from Ben Fowler .) * gwlib/conffile.c: Removed spurious Ctrl-M from end of line. (From Ben Fowler.) 2000-03-10 * gw/smsc_interface.def, gw/sms_msg.h: more data about SMSC interface 2000-03-10 * gw/bearerbox.c, gw/kannel.conf, test/sample.conf: renamed wap-port to wapbox-port and sms-port to smsbox-port, to avoid any future confusion. Old names still work. * gw/smsc_sema.c: added a name to smsc Thu Mar 9 11:05:14 CET 2000 Patrick Schaaf * gw/wapbox.c, gw/kannel.wapconf: cleanup, removed test-heartbeat-thread logging support from source and config. Thu Mar 9 19:17:43 2000 Lars Wirzenius * gw/bearerbox.c: Commented out an assert that seems to be too much. * gw/smsbox.c: Added a missing mutex_lock to main_loop. Thu Mar 9 17:48:33 2000 Lars Wirzenius * Makefile.in: Moved -D_REENTRANT to before @CFLAGS@ so that someone can undefine it when calling configure.in, if they really want it. (Also defined to 1, not empty, just in case.) 2000-03-09 Derry Hamilton * Makefile.in: Added -D_REENTRANT to CFLAGS 2000-03-09 * gwlib/octstr.c: fixed stupid error in octstr_recv Wed Mar 8 16:53:24 2000 Lars Wirzenius * gw/wtp.c: Fixed or commented away broken list handling. * gwlib/octstr.[ch]: Fixed octstr_search_char_from. Also changed its prototype so that the character is passed as an int, since this does not cause problems with 8-bit characters on platforms where the char type is signed. 2000-03-08 Tuomas Luttinen * gw/wml_compiler.c: Bug fix: no more squares (ie tabulator characters) in the compiler output. 2000-03-08 * gw/smsbox_req.c: started re-working on UDHs, all new code commented out, yet * gw/bb_msg.c, gw/boxc.c: added assertions and some extra checking * gw/urltrans.c: fixed an error in 'default' rule finding code * gw/smsc_sema.h: commented out a function prototype not implemented Tue Mar 7 16:40:49 CET 2000 Patrick Schaaf * gwlib/http.{c,h}: Added httprequest_replace_header() function, use it to overwrite (instead of duplicate) existing user defined headers. This gets rid of the duplicate User-Agent: header, which convinces some sites to send wml instead of html. 2000-03-07 Tuomas Luttinen * gw/wml_compiler.c (text_shrink_blank): A little bug fix. The first white space character in a row of them is now converted into a space, the rest are deleted before compiling. 2000-03-07 * gw/kannel.*conf: fixed hearbeat as heartbeat * gw/bearerbox.c, gw/boxc.c: fixed some memory leaks pointed out by Paul Keogh, and added many assertions. Tue Mar 7 12:51:35 2000 Lars Wirzenius * gwlib/thread.c: Added missing #include for . Sun Mar 5 12:53:14 CET 2000 Patrick Schaaf * gw/wapbox.c, gw/wsp_http.c, gwlib/octstr.*: more or less completed URL mapping functionality; see gw/kannel.wapconf for a short description of the facilities. The device-home setting for Motorola Timeport should work correctly now. Sun Mar 5 10:55:00 CET 2000 Patrick Schaaf * gw/wsp_http.c: change #if 1 to #if HAVE_LIBXML, to really not break compilation when libxml is missing. 2000-03-03 Sanna Seppanen * gwlib/http.c: http_get_u: Should not crash anymore due trying to free memory twice Fri Mar 3 15:50:33 2000 Lars Wirzenius * README: Added note about CFLAGS settings for development. Fri Mar 3 14:31:28 2000 Lars Wirzenius * gwlib/octstr.c, test/wml_tester.c: Minor fixes to silence warnings. Fri Mar 3 13:32:30 2000 Lars Wirzenius * gwlib/thread.c (mutex_destroy): Destroy the pthread_mutex_t when the Mutex object is destroyed. * gwlib/thread.c (start_thread): Destroy thread attributes after thread has been started. * gw/wsp_http.c: Enabled Tuomas's compiler by default. 2000-03-03 * gw/smsc_sema.c: fixed loads of warnings, and one suspicious looking comprasion/assignment list 2000-03-02 * gw/*.*conf: renamed old bearerbox.conf, smsbox.smsconf and wapbox.wapconf as kannel.conf, kannel.smsconf and kannel.wapconf. * gw/*box.c: modified default configuration files accordingly * README, doc/dialup.txt: updated documentation accordingly * gw/smsc.c, gw/smsc_p.h: added calls to SEMA SMS2000 code * gw/smsc_sema.c|h: added support code to SEMA SMS2000 via X28 link by Hao Shi Thu Mar 2 12:36:22 2000 Lars Wirzenius * doc/userguide/userguide.xml: Fixed syntax error (added missing end tags). 2000-03-01 * README: added notes of the new sample files * test/sample.*conf: new simple sample configuration files 2000-03-01 Markku Rossi * wmlscript/wslexer.c, wmlscript/wsstree.h: Fixed some warnings. * wmlscript/wsgram.y: Fixed empty statements. 2000-02-28 Tuomas Luttinen * gwlib/octstr.c&h: octstr_create(char *)->octstr_create(const char *) * gw/wml_compiler.c: Bug fixes: entities are now supported, no more changing URLs into lower case. A bug removed from variable syntax check. at Feb 26 16:57:40 CET 2000 Patrick Schaaf * gw/wsp_http.c, gw/wsp.h, gw/wapbox.c: added configuration options device-home and map-url; see gw/wapbox.wapconf for a description of how they work. Sat Feb 26 11:29:10 CET 2000 Patrick Schaaf * gw/wsp.c, gw/wsp_http.c: hacked to start working with Motorola Timeport / Phone.com browser. Negotiated client SDU of 3 is changed to 1350, and DEVICE:home URL is rewritten to something else (set DEVICE_HOME_OUT define at top of wsp_http.c to change destination to something sensible). Needs work to make the stuff configurable. 2000-02-25 Sanna Seppänen * gwlib/http.c: modified http_post.c. Sending entity length. 2000-02-25 Tuomas Luttinen * gw/wml_compiler.c : Now first version of the new compiler with variable support. The WML document is first stripped from extra whitespace in the beginning and end to avoid parsing errors by gnome-XML. * gwlib/octstr.h/c : int octstr_search_char_from(Octstr *ostr, char ch, size_t pos) added. Does the same as octstr_search_char, except start from the position pos. The latter is now implemented as a call to the former with argument pos == 0. 2000-02-23 * gwlib/octstr.c: modified octstr_recv to fail if receives "garbage" (first length byte something else than 0); this is a hack to avoid too large allocations caused by garbage on the line. Side-effect is that now the octstr length is limited to 16777216 bytes when transfered via TCP/IP, but I think that we can accept that... 2000-02-22 * gwlib/octstr.c: fixed octstr_dump to show characters in 'partial' lines, too, and not to show 'empty' last line * gw/smsbox.c: changed default configuration file to be as 'smsbox.smsconf' 2000-02-21 Tuomas Luttinen * gw/wml_compiler.c: Some more bug fixes. (parse_document): Check added for an empty document (== null pointer). * test/wml_tester.c: Now a log file can specified a s an argument. * test/test_wml.c: Same as above. Mon Feb 21 15:20:39 2000 Lars Wirzenius * README, doc/userguide/userguide.xml: Documented requirement to use at least version 1.8.1 of libxml. 2000-02-21 Aarno Syvänen * test/fakewap.c: commented tid verification protocol used by the program 2000-02-21 * gw/smsc_smpp.c: added receive-port, so that transmit/receive ports can be different ones. * gw/bearerbox.conf, gw/smsc.c: renamed 'backup-port' as 'receive-port', old name still functions in the config files, but causes warning message. smsc_emi.c still uses 'backup-port' name, but life is hard. 2000-02-21 Tuomas Luttinen * gwlib/octstr.c: octstr_ncompare doens't anymore check whether ostr1 is bigger or smaller than ostr2. It should not anyway. * gw/wml_compiler.c: Many bug fixes to the attribute encoding. Some possible memory leaks also removed. Fri Feb 18 21:20:46 2000 Lars Wirzenius * gwlib/http.c: Undid changes by Sanna, since they were crashing some HTTP calls, and I didn't find the problem within an hour or two of debugging. Sorry. Fri Feb 18 20:07:29 2000 Lars Wirzenius * gwlib/utils.c: Don't report debug places unless they're set. Fri Feb 18 20:05:40 2000 Lars Wirzenius * gw/wsp_http.c: Strip type parameters. This is ugly, but at least it will work somewhat if they are there. Fri Feb 18 19:54:12 2000 Lars Wirzenius * gwlib/octstr.c: octstr_dump now also prints the printable characters of the string as themselves, so that it becomes easier to read the output. The hexacodes are still printed for all characters, of course. Fri Feb 18 16:40:44 2000 Lars Wirzenius * gw/wsp_http.c: Remove temporary files. Oops. 2000-02-18 Tuomas Luttinen * gw/wml_compiler.c (parse_text): Empty strings are no more coded. * gw/wml_compiler.c (parse_attribute): Fixed bug with the coded_length. Still something wrong with attribute value encoding with one byte. Thu Feb 17 20:27:54 2000 Lars Wirzenius * Makefile.in: Removed superfluous libtest.a, which was causing trouble with some compilations, making test/wml_compiler pick up a random main function. * test/test_wml.c: Output with octstr_dump and octstr_pretty_print instead of binary if several arguments on command line. * test/wml_tester.c: Fixed so that it always has a main function. 2000-02-17 Tuomas Luttinen * gwlib/octstr.h&c: argument changed from char * to const char * on functions octstr_create_tolower and octstr_create_from_data. * test/wml_tester.c: Ouput now uses the fancy otcstr-output functions. * gw/wml_compiler.c: Now adds STR_END to the end of the attribute value fields and text fields Thu Feb 17 17:35:11 2000 Lars Wirzenius * doc/userguide/userguide.xml: Filled in some more. Now most details should be copied from the sample configuration files, but things are still not explained in a coherent or understandable manner. * gwlib/log.c: debug() doesn't print the place anymore. This makes debug output readable again. 2000-02-17 * gw/bearerbox.c, gw/bb.h: added max thread BB_DEFAULT.. value, instead of hardcoded number 2000-02-17 Tuomas Luttinen * gw/wml_compiler.c (parse_document): Standard headers now : WBXML version 1.1, WML 1.1 Public ID, Charset=ISO-8859-1, String table length=0. 2000-02-17 Aarno Syvänen * wtp_tid.c : Fixed a bug in the function tid_cached. Tid_in_window rewritten for simplicity. 2000-02-16 Sanna Seppanen * gwlib/http.c: created the new function httpresponse_wrap, copy of httprequest_wrap using octstr. haven't tested it with chunked entities. 2000-02-16 * gw/wsp.c (unpack_caps): fix Wed Feb 16 14:38:06 2000 Lars Wirzenius * test/fakewap.c: Changed test for SOL_TCP to actually test the macro. * README: Added note about CFLAGS may need to be pre-set before running configure. 2000-02-16 Aarno Syvänen * test/fakewap.c: This version was used for testing of wtp error handling and tid verification. Its interface will be simplified. Tid_new flag is a now a command line parameter, and it can be turned off. 2000-02-16 * gw/wsp.c (unpack_caps): fixed one defination error, added extra debug for unknown capabilities Wed Feb 16 00:04:03 2000 Lars Wirzenius * doc/userguide/userguide.xml: Started filling in. Nothing useful yet, I think. Tue Feb 15 15:01:45 2000 Lars Wirzenius * doc/CodingStyle: Documented usage of debug(). * Lots of files: Removed #if 0 wrappers around calls to debug that are now unwanted (the wrappers, not the calls). Tue Feb 15 14:14:11 2000 Lars Wirzenius * Changed interface to debug() function: Added a new first argment `place', which tells where the function is being called from. Then added the function set_debug_places (and made relevant changes to gwlib/utils.c:get_and_set_debugs), which sets the places which should actually be logged. This makes it run-time configurable what debugging output gets printed. Also changed all calls to debug, to make things compile. The place is "xxx" everywhere for now, will start changing that next. 2000-02-15 Tuomas Luttinen * gw/wml_compiler.c (parse_attribute): A little more stable compiler; doesn't crash when founds an empty attribute text value. Tue Feb 15 11:16:18 2000 Lars Wirzenius * gw/wml_compiler.c: #include "config.h". 2000-02-15 Tuomas Luttinen * gw/wml_compiler.c (wml_compile): A little bug fix. (**wml_scripts now exists, so caller won't try to delete unexistent octet string.) Tue Feb 15 11:07:00 2000 Lars Wirzenius * gw/wsp.c: Broke out wsp_http_thread function into gw/wsp_http.c to make it easier to keep the code clean. The old code was rather, er, kludgey. * gw/wsp_http.c: Moved wsp_http_thread() and dependent functions here and started reorganizing it for cleanliness. Mon Feb 14 16:56:14 2000 Lars Wirzenius * gwlib/octstr.c: Added "return -1" at end, since something had to be returned and it wasn't returning anything at the moment. 2000-02-14 Tuomas Luttinen * gw/wml_compiler.c: At the moment does not accept variables at all. 2000-02-14 Aarno Syvänen * wtp*: Compiled with -pedantic. Some of warnings removed. * wtp_events-decl.h: Added field no_cache_supported to the event RcvInvoke. * wtp.c: Argument machine added to function wtp_tid_is_valid * wtp_machine-decl.h: Field wsp_event added to wtp_machine * wtp.c|h corresponding change to type declarations, constructors, destructors and debugging functions * wtp_state-decl.h: wsp_event stored until tid is validated * wtp_tid.c|h: Added code for tid validation 2000-20-03 Sanna Seppanen * gwlib/octstr.h: gwlib/octstr.c: minor fixes. * gw/smsc_cimd.c: bzero() -functions changed to memset() Thu Feb 3 18:40:38 2000 Lars Wirzenius * gw/wsp.c: Fixed unpack_uintvar to handle multiple bytes. This was embarrassing. 2000-02-03 Aarno Syvänen * wtp_send.c: added static functions message_rid, set_rid for changing retransmission status of an entire message. * wtp_events-decl.h: New event RcvErrorPDU added * wtp.c: Tell_about_error returns an event when an illegal header is received. Wtp_unpack_wdp_datagram returns event RcvErrorPDU when this happens, ditto event unpacking functions. Function machine_find_or_ create handles this event, too. * wtp_state-decl.h: Added rows for handling same event. * wtp_send.c: Added function do_not_start for handling aborts not feeded to the state machine. Some redundant code added, perhaps, but this is simpler than changing all wtp_send_abort calls. 2000-02-02 Tuomas Luttinen * gw/wml_compiler.c (parse_attribute): Little bug fix: end tag added to attribute lists. 2000-20-02 Sanna Seppanen * gwlib/octstr.h, gwlib/octstr.c: added search functions for given char & string. 2000-02-02 Derry Hamilton * gw/smsc.c, gw/smsc_cimd.c, gw/smsc_emi.c, gw/wml.c, utils/OTAbitmap.c, utils/wbmp.c: all bzero functions changed to memset. 2000-02-02 Tuomas Luttinen * gw/wml_compiler.c : Basic functions in order, can be used with basic WML pages without variables. * test/wml_tester.c : Little fixes to output format Wed Feb 2 13:52:14 2000 Lars Wirzenius * Makefile.in: Added a .c.o implicit rule. This is provided by all makes automatically, but not all of them make the object file go to the same directory as the source file, and instead put them into the current working directory. The rest of our Makefile assumes the latter behavior. 2000-02-02 * gw/bearerbox.c: updated XML to be synchronized with Plectra 2000-01-31 Markku Rossi * wmlscript: Lots of code review changes. Implemented IEEE 754 binary floating point encoding and decoding. Implemented WMLScript byte-code disassembler. * configure.in: Ported to NetBSD. 2000-01-30 Patrick Schaaf * gw/wapbox.c: synchronize put_msg / remove_msg using a mutex, removing the need for usleep(10ms). Consequently, make heartbeat message send a thread of its own. Set test-heartbeat-thread to 1 in wapbox.wapconf to see lots of debugging output. * gw/wapbox.wapconf: add documentation about temporary test-heartbeat-thread setting. 2000-01-30 Patrick Schaaf * gw/wapbox.c: fixed race condition when starting empty_queue_thread. BTW, that function seems to burn CPU like hell. 2000-01-28 Tuomas Luttinen * gw/wml_compiler.c : Some little fixes. * test/wml_tester.c : Some bug fixes, no more core dump, not working yet correctly thou. 2000-1-28 Aarno Syvänen * wtp.c: Important trivial change: error message "no concatenation supported" changed to "no connectionless mode nor concatenation supported" Fri Jan 28 17:13:47 2000 Lars Wirzenius * Making release 0.5. Fri Jan 28 17:10:12 2000 Lars Wirzenius * gw/wsp.c, gw/wsp.h, gw/wsp_events-decl.h, gw/wsp_state-decl.h, gwlib/http.c, gwlib/http.h: Use HTTP headers from Connect or Get PDUs (and add WML and WMLScript content types if they aren't already, and the compiled forms are). Fri Jan 28 13:14:52 2000 Lars Wirzenius * gw/wapbox.c: Only dump non-heartbeat messages. * gw/wsp_events-decl.h, gw/wsp_machine-decl.h: Now these headers check at top of file that the required macros are defined and complain with #error otherwise. Related changes to files that include the headers. * gw/wsp.c: Headers from Connect PDU are stored in the WSPMachine, and used in the HTTP request. * gwlib/http.c: Removed User-Agent header from those we add to the request. 2000-01-27 Sanna Seppanen *gwlib/http.c, gwlib/http.h implementation of http_post. all bzero -functions changed to memset. *gwlib/http.c, gwlib/http.h http_get changed to use http_get_u with NULL header pointer. Thu Jan 27 20:09:23 2000 Lars Wirzenius * gw/wtp.c, gw/wtp.h: Fixed locking of WTPMachine list (the previous code had race conditions in it). Introduced wtp_init function. * gw/wsp.c, gw/wsp.h: Similarly for WSPMachine list (it was unlocked completely) and wsp_init. Also minor cleanup. * gw/wapbox.c: Call wtp_init and wsp_init at startup. 2000-01-27 Tuomas Luttinen * gw/wml_compiler.c : some little bug fixes * test/wml_tester.c : A tester for the new WML compiler added. 2000-1-27 Aarno Syvänen * wtp_state-decl.h: Added rows receiving RcvInvoke when the state is RESULT_RESP_WAIT. In this case, we simulate a timer: we resend MAX_RCR times and then abort the transaction. * wtp_machine-decl.h: Attribute result, for result message, added. * wtp.c: Constructors, destructors and debugging functions for wtp machine rewritten with the previous attribute added. * wtp_send.c|h: function wtp_resend_result added. Function send_result now returns the sent message. Thu Jan 27 17:34:53 2000 Lars Wirzenius * gw/bearerbox.c, gw/html.c, gw/smsbox.c, gw/smsc_emi.c, gw/wml.c, gwlib/gwstr.c, gwlib/http.c: Applied Solaris portability fixes from Derry Hamilton . Thu Jan 27 16:19:35 2000 Lars Wirzenius * gw/wtp.c: Fixed check for length of Abort PDU. Two equals signs were missing, probably a typo. Thu Jan 27 15:37:14 2000 Lars Wirzenius * gw/wsp.c, gw/wsp_state-decl.h: If client sends new Connect PDU, disable all old sessions. Thu Jan 27 14:01:50 2000 Lars Wirzenius * gwlib/socket.c, gwlib/thread.c: Hopefully silenced compiler warnings on non-Linux platforms. Thu Jan 27 13:47:34 2000 Lars Wirzenius * gw/msg.c, gw/wtp.h, gwlib/socket.h: Added includes for , which is required for on some platforms (Linux makes it harder to write this portably, since it works with or without it). Thu Jan 27 13:43:12 2000 Lars Wirzenius * gw/wsp.c: Don't set client address to NULL, just set client port to -1, when disabling a session. Thu Jan 27 13:40:44 2000 Lars Wirzenius * configure.in, configure, README: Added check for zlib and documented it in README. Wed Jan 26 23:03:30 2000 Lars Wirzenius * gw/wsp.c: Mark WSPMachine unused in case of unhandled event. Wed Jan 26 22:19:21 2000 Lars Wirzenius * gwlib/octet.[ch], gw/boxc.c, gw/wapbox.c: Added a wait time argument to read_available, since sometimes we do want to wait for data a bit. This matters in the wapbox, since now it can wait for data without busylooping too tightly (only once per second), but it will still notice when SIGINT is received (with up to a one second wait). * gw/csdr.c: If we get ECONNREFUSED, re-try the recvfrom. The error is caused by a previous syscall for sending a packet to an unknown destination, but because it's not possible to wait until the error is received, network latencies being rather long, the error is received by a later syscall. We just ignore it now. * gw/wsp.c: Handle "application/vnc.wap.wmlc" by passing it directly to the user. * test/fakewap.c: Added calculation of average number of messages per second, and minor error message fixes. Wed Jan 26 20:44:26 2000 Lars Wirzenius * gw/wsp.c: If an unhandled event is TR-Invoke.ind, then send a TRAbort.req to WTP so that the phone will know something's wrong. * gw/wtp_send.c: Don't pack user_data into Abort PDU, since it isn't in TRAbort event anymore. (Related to Aarno's change below.) 2000-01-26 Aarno Syvänen * wtp_events-decl.h: Added event TRInvokeRequire, removed user_data from TRAbort * wtp_state-decl.h: Handling event TRAbort fixed. Wed Jan 26 18:14:39 2000 Lars Wirzenius * gw/wapbox.c: Fixed SIGINT reactions so it doesn't wait until bearerbox breaks connection when wapbox stops sending heartbeat messages after SIGINT. Wed Jan 26 17:57:32 2000 Lars Wirzenius * gw/wsp.c, gw/wsp_state-decl.h: Fixed compile time warnings about unused or uninitialized variables. Had to comment out Reconnect handling, because it doesn't seem to work at all, and I don't have time to investigate. Wed Jan 26 16:28:05 2000 Lars Wirzenius * gw/wml_compiler.[ch]: Comment out everything if HAVE_LIBXML is not defined by configure. This is needed until everyone doing development has libxml installed. Wed Jan 26 15:13:25 2000 Lars Wirzenius * configure.in: Check for gnome-xml library, which is needed by the new WML compiler. * README: Documented need for the gnome-xml library. (Sorry about that, I promise not to document anything again.) 2000-01-26 Tuomas Luttinen * octstr.h: functions added: octstr_create_tolower, octstr_ncompare * octstr.c: implementation of the new functions octstr_create_tolower, octstr_ncompare added. * gw/wml_compiler.h: header for the new WML compiler added * gw/wml_compiler.c: the new WML compiler added 2000-01-26 Aarno Syvänen * Oops, segmentation work stopped * wtp_state-decl.h: Added timer rows (now only missing event is Error PDU) * wtp_send.c: Added parameter abort_reason to parameter list of wtp_send_abort (so that function call conforms closely with specs.) * wtp.c: Locks added to functions wtp_machine_mark_unused, wtp_machine_destroy, wtp_machine_create_empty and wtp_machine_find. Wed Jan 26 12:01:17 2000 Lars Wirzenius * gw/csdr.c, test/udp_send.c: Added missing casts to (struct sockaddr *) for some socket operation calls. Wed Jan 26 11:44:12 2000 Lars Wirzenius * README: Added "touch .depend; make depend" to building instructions. Not all makes build missing include files automatically. 2000-01-25 * gw/urltrans.c: added some missing initializations which caused sendsms to crash * gw/wsp_headers.s: added some code to fool code reviewer Tue Jan 25 17:27:53 2000 Lars Wirzenius * gwlib/http.c: Commented out gw_free calls for error situations, where it causes a segfault for some reason. This is not a fix, it is an ugly workaround, but it should avoid the problem until we have time to review the whole memory allocation/freeing situation. (The gateway is already leaking memory a lot.) Tue Jan 25 17:14:12 2000 Lars Wirzenius * gwlib/thread.c: Added comments to explain how mutex_try_lock works, and fixed a bug that left the mutex locked in case of recursive locks. Tue Jan 25 16:51:43 2000 Lars Wirzenius * gw/wsp.c, gw/wsp_state-decl.h, gwlib/octstr.c: Applied patch from francois-xavier.hannedouche@philips.com to provide partial support for Post PDU with only one argument. Also adds support for enabling a reconnection. Tue Jan 25 14:59:05 2000 Lars Wirzenius * utils/seewbmp.c: Added to CVS. Simple debugging tool written by Richard Braakman. * Makefile.in: Related changes. 2000-01-25 * gw/bb_msg.c: Fixed error in rq_pull_smg_class, which caused failure with 2 wapboxes. Hopefully did not break SMS portion. * gw/csdr.c: commented out octstr_dump of each incoming message * gw/*.*conf: edited them so that no-one can use them without editing, should handle loads of basic questions in devel-list * gw/*box.c: put an appropriate error message 2000-01-25 * gw/bearerbox.c: One fix more, now the internal smsbox does not consume all the CPU it can 2000-01-25 * gw/bearerbox.c: Some optimization to queue watchers, now it should not do updates with no effect, hopefully reducing CPU usage in a long run. Mon Jan 24 21:23:43 2000 Lars Wirzenius * README: Updated a bit. Mon Jan 24 21:01:50 2000 Lars Wirzenius * Makefile.in: Fixed install target. * VERSION: Marked as non-release version. Mon Jan 24 20:53:47 2000 Lars Wirzenius * gw/wsp.c, gw/wsp.h, gw/wsp_events-decl.h, wsp_state-decl.h: WSP now obeys client SDU size limit. Had to add a pointer to the session machine to a WSP event, which caused non-local trivial changes. 2000-01-24 Sanna Seppanen *gwlib/http.h: function added: header_dump. *gwlig/http.c: implementation of header_dump Mon Jan 24 19:06:58 2000 Lars Wirzenius * configure.in, configure: Look for -lresolv if it is necessary. (From Derry Hamilton ) * gwlib/socket.c: Portability kludge for Solaris. Should be fixed later. (Likewise from Derry.) * test/fakewap.c: Moved definition of `ret' inside #ifdef so that it doesn't cause an "unused variable" warning. 2000-01-24 * gwlib/http.h|c: added functions header_pack and header_destroy and fixed header_dump * gw/wsp.c: moved header code into separate module, and modified the interface * gw/wsp_headers.c|h: added, now decodes header into HTTPHeader struct. Decoding only partial, but at least headers sent by the 7110 are decoded. 2000-01-21 Sanna Seppanen * gwlib/http.h: function added: http_get_u. * gwlib/http.h: implemented http_get_u. shortened code for some functions. Fri Jan 21 19:05:35 2000 Lars Wirzenius * Making release 0.4. * The gateway is now called Kannel. Whee! * Changed wapgateway.org to kannel.org, since the name of the domain is changing. Fri Jan 21 18:36:33 2000 Lars Wirzenius * configure.in, configure, Makefile.in, README.docbook: Added --enable-docs and --without-docs options. Fri Jan 21 14:18:24 2000 Lars Wirzenius * wmlscript/wsgram.c, wmlscript/wsgram.h: Added to CVS. These are the files that Bison generates. Fri Jan 21 13:42:57 2000 Lars Wirzenius * VERSION: Bumbped to 0.3. Forgot to do that for the release. Stupid me. * Makefile.in, doc/arch/arch.xml: Put version number (from VERSION) into DocBook documents. * doc/arch/*.xml: Minor corrections. 2000-01-21 * gw/smsc.c: added comments of where to add new SMSCes * gw/smsc_emi.c: fixed error in return values in submit_message * gw/smsc_interface.def: ADDED interface definitions * gw/wsp.c: removed some warnings * test/fakewap.c: threaded fakewap from Antti Saarenheimo 2000-01-20 * gw/wsp.c: now decodes all headers sent by 7110 except that strange 0x01 0x00 at the end of it (against spesifications?). No real implementation for that information, yet. 2000-01-20 * gw/bearerbox.c: added missing accept_pending initialization and commented SIGINT handling procedure * gw/wsp.h: moved WSP header definitions to wsp.c * gw/wsp.c: initial header decoding, only debug output yet, and only decodes some common headers Wed Jan 19 13:22:13 2000 Lars Wirzenius * doc/dialup.txt: Added. E-mail from Roger Willcocks describing how to set up a dialup line for use with the gateway. Wed Jan 19 13:18:22 2000 Lars Wirzenius * gwlib/gwlib.h: Added #include "config.h". Wed Jan 19 11:38:05 2000 Lars Wirzenius * gwlib/http.c: Applied parts of patch from Erik Bos. We're going to do the header addition stuff in another way soon ourselves. Wed Jan 19 10:33:39 2000 Lars Wirzenius * configure.in: Added check for inet_aton in arpa/inet.h, using GW_HAVE_FUNC_FROM. This should make things work for Solaris. Wed Jan 19 10:21:39 2000 Lars Wirzenius * gw/wsp.c: Silence WMLScript compiler tracing info. * gwlib/getnameinfo.h: Bugfix: use #ifdef, not #if, to test whether a macro is defined. 2000-01-18 mikael.gueck@wapit.com * gw/smsc_cimd.c: submit_sms UDH-enabling fix Tue Jan 18 16:02:49 2000 Lars Wirzenius * Release 0.3. 2000-01-18 * test/fakewap.c: Added new program by Antti Saarenheimo Tue Jan 18 14:06:09 2000 Lars Wirzenius * wmlscript/wmlsc.c, wmlscript/wsalloc.c, wmlscript/wsstream_data.c: Put in patch from Markku Rossi, to fix bug in function that compiles from data instead of file, and various helpfulness to wmlsc. * gw/wsp.c: Use internal WMLScript compiler. Tue Jan 18 12:55:36 2000 Lars Wirzenius * gw/wsp.c: Use WMLScript compiler as an external process. This works, the internal one has problems (or else I have problems using it). * gw/wsp_state-decl.h: Commented out, at least temporarily, rows that handle method invocations before session has been opened. Mon Jan 17 17:47:37 2000 Lars Wirzenius * gw/wsp.c: Added WMLScript compilation (untested, though), and fixed server transaction ID generation (they weren't generated, nor used properly). 2000-01-17 Aarno Syvänen * wtp.c: Removed goto branches made unnecessary by introduction of gw_malloc. Unused variables removed, too. * Segmentation work began. Mon Jan 17 15:38:15 2000 Lars Wirzenius * AUTHORS, wmlscript/*, configure.in, Makefile.in: Added WMLScript compiler from Marko Rossi. Mon Jan 17 14:42:50 2000 Lars Wirzenius * wapbox.c: Added signal handlers for SIGINT, SIGHUP, and SIGPIPE. Mon Jan 17 11:33:22 2000 Lars Wirzenius * Makefile.in, configure.in, configure: Added support docdir and "make install-docs". * gwlib/getnameinfo.h: Define NI_ macros unless they're already defined. 2000-01-14 * gw/*box.c: Added SIGPIPE as ignored signal Thu Jan 13 19:12:11 2000 Lars Wirzenius * gw/wtp.c: Renamed memory_error to pdu_too_short error, since it wasn't a memory allocation error. Changed the user visible error message also. Thu Jan 13 18:39:46 2000 Lars Wirzenius * Makefile.in: Added stuff to compile documents. * configure.in, configure: Added stuff to check for jade and docbook stuff. * doc/*/Makefile: Removed. Thu Jan 13 17:28:50 2000 Lars Wirzenius * gw/wsp.c: Enabled code to use external WML compiler. Name of compiler is "./test_wml" or given in the TEST_WML environment variable. This is a temporary solution until the new compiler works. * Makefile.in: Added (trivial) install target. 2000-01-13 * gw/bearerbox.c: added XML getstatus cgi-bin - many fields missing, but basic data should be available Thu Jan 13 12:19:15 2000 Lars Wirzenius * gw/bearerbox.c, gw/msg.c, gw/smsbox_req.c, gw/wtp_send.c, gwlib/octstr.c, gwlib/octstr.h, gw/wtp_state-decl.h, gw/wsp.c: Removed some now unnecessary error checking. Since we use gw_malloc, octet string functions (among others) won't fail, so there's no need to check and handle that. This simplifies code a bit. * gw/wsp.c: Added (currently commented out) code to run WML compiler as a separate process, to work around a bug that crashes it sometimes when compiling several pages during a session. (New compiler being written from scratch, so I didn't want to debug the current one too much.) * gwlib/thread.h: Added "include #config.h"" so that we a definition for HAVE_PTHREAD_H is included properly. This fixes the bug that reported thread id always is 0. 2000-01-12 * gw/bearerbox.c: added some usleeps Wed Jan 12 16:06:01 2000 Lars Wirzenius * Making release 0.2.2. Wed Jan 12 15:16:49 2000 Lars Wirzenius * lots of small changes in lots of files: Changed the gateway to systematically use gw_malloc and friends instead of malloc and friends directly. It shall henceforth be considered an error for anything but gwlib/gwmem.c to call malloc or friends directly. (Six unchecked malloc calls found during this cleanup.) This does mean that the gateway won't report an out-of-memory condition to the phone, but at this point that's a better option than randomly using or not using gw_malloc and randomly checking or not checking whether it succeeded. 2000-01-11 * gw/wsp.c|h: capabilities client|server SDU size, method|push MOR and protocol options (partially) now supported. Note tested, and I think that rest of the system ignores SDU settings, fix that later. 2000-01-10 * gw/wsp.*: continued capability work 2000-01-10 Aarno Syvänen * wtp_events-decl.h: added user_data to primitive TRAbort (WSP PDU will use it). * wtp_send.c: Corresponding change to function pack_abort. Module reorganised by adding static functions tell_send_error, insert_pdu_ type, indicate_simple_message, insert_tid, insert_rid, insert_abort_ type, insert_ack_type * wtp.c: Function wtp_machine_find_or_create reorganised. Now it can handle event RcvAbort, too. Function wtp_unpack_wdp_datagram reorganised by adding static functions deduce_tid, message_header_ fixed, deduce_pdu_type, single_message, protocol_version, unpack_ack, unpack_abort, unpack_invoke and tell_about_error. Mon Jan 10 15:48:17 2000 Lars Wirzenius * gw/wml.c: Applied patch from Petri Ahonen with fixes to WML encoding. Mon Jan 10 11:02:33 2000 Lars Wirzenius * config.h.in, gw/bearerbox.c, gw/smsc_emi.c, gw/smsc_smpp.c, gw/wapbox.c, gw/wsp.c, gwlib/thread.c: Silenced compiler warnings when compiling with -Wall. Mon Jan 10 10:10:22 2000 Lars Wirzenius * Removed automake. Automake makes huge, complicated Makefiles that I am rather reluctant to decipher, and I would have had to do that to incorporate WMLScript compiler source. So I removed the Makefile.am's and made a Makefile.in by hand. Mon Jan 10 07:36:36 2000 Lars Wirzenius * gw/wsp.c: Fixed function wsp_http_thread so that is handles WBMP images correctly (i.e., sends them to the phone). 2000-01-07 * gw/wsp*.c: initial code to handle capabilities. Not finished. * gw/wapbox.c: removed double logging (use log-file in configuration) * gw/bearerbox.c: fixed WAP routing (no more crashes because of WAP traffic while connected to SMSC) Fri Jan 7 18:06:38 2000 Lars Wirzenius * gw/boxc.c, gwlib/http.c, gw/wapbox.c, gw/wtp.c: Made sure variables are initialized (compiled with gcc -Wall -O2, which hasn't been done for a while), or removed unused variables. * gw/wsp_events-decl.h, gw/wsp_state-decl.h: Added response_type member to SMethodResultRequest so that the Content-Type header can be communicated to the phone. * gw/wsp.c: Set response_type according to what the HTTP server returns as Content-Type. Also, don't blindly assume everything is WML. Fri Jan 7 14:47:09 2000 Lars Wirzenius * Making release 0.2. Fri Jan 7 12:01:09 2000 Lars Wirzenius * AUTHORS, NEWS, README, Release-0.2, VERSION, gw/bearerbox.conf: Preparing for release. * Makefile.am, Makefile.in: Removed stuff from EXTRA_DIST. * doc/fakewap-packets.txt: Wrote. This explains the packets that the upcoming fakewap program will use. 2000-01-05 * gw/bearerbox.c: fixed memmove calls (thanks to Yuri for pointing them out) 2000-01-04 * gw/wapbox.c: removed automatic logfile opening and instead added configuration variable log-file and log-level. Also added standard command line options identical to smsbox and bearerbox. * gw/wml.c: removed duplicate of 'write_variable_value' function (original in gwlib/utils.c) 2000-01-03 * gw/wapbox.c (send_heartbeat): added heartbeat sending. And changed bearerbox port and host information to default values, not undefined. Patvched some files to make it work Thu Dec 30 17:51:28 1999 Patrick Schaaf * gw/boxc.c, gwlib/http.c, gwlib/socket.{c,h}: reverted introduction of gw_getnameinfo() in favour of getnameinfo, which is now "emulated" properly. Thu Dec 30 18:47:19 1999 Lars Wirzenius * gw/wsp.c: WML page is now fetched from the URL specifed in the Get PDU and compiled, then sent to phone. Is this a WAP gateway yet? Thu Dec 30 17:55:22 1999 Lars Wirzenius * Makefile, */Makefile: Removed from CVS, since they're supposed to be generated, and not included in the distribution. 1999-12-30 * gw/smsbox.smsconf: improved documentation * gw/bearerbox.conf: ditto Thu Dec 30 17:04:40 1999 Lars Wirzenius * */Makefile, configure: Ran automake and autoconf and configure, thus some file re-generated. * NEWS, AUTHORS: Added empty ones. automake requires them. Thu Dec 30 16:57:50 1999 Lars Wirzenius * Applied patch from bof@bof.de for autoconf support. Renamed LICENSE to COPYING, and various other similar minor changes. 1999-12-30 * gwlib/socket.c: added that missing reuseaddr to connect_with_port * gw/smsbox_req.c: oops, did not return all working code, now it should work as it did earlier * gw/smsc_emi.c: some little fixes to udh messages 1999-12-30 * more autoconf: compiles on libc5 and libc6 Linux, and Solaris 2.6 with gcc. See README.autoconf 1999-12-29 * converted to use automake/autoconf: ./configure && make Wed Dec 29 22:06:22 1999 Lars Wirzenius * gw/wsp.c: Three bugs in Reply PDU fixed: status code should be encoded (200 is encoded as 0x20); the length of the content type field should be included; and the high bit of the octet that tells the content type should be set. After these modifications, a trivial "Hello, world" WML page is now successfully transferred to a 7110 phone. Yesh. Any year now we will really have a WAP gateway. 1999-12-29 Aarno Syvänen * wtp.c, wtp_send.c: Added label WTP and function names in error messages. * wtp_state-decl.h: More rows added. Now all events expect timer and error are handled. * wtp_send.c: Added abort_type in the argument list of the function send_abort. * wsp_state-decl.h: Added rows for handling Get and Disconnect PDUs when the state is NULL_STATE (these are needed for restarting the wapbox. 1999-12-28 * gwlib/log.*: added log level 'forced' and updated documentary in header file. 1999-12-28 Aarno Syvänen * wtp_send.c: bug fixing in functions send_ack and send_abort 1999-12-22 Aarno Syvänen * spaces around assignment operators added * wtp.c: function machine_find_or_create rewritten. We should not create a new machine when we are not receiving an invoke pdu. * wtp.c, wtp_events-decl.h: TRResult has now wsp_tid amongst its attributes * wsp_events-decl.h: Superflous events removed * wtp_send.c: Internal function wtp_add_datagram_address added, send* functions changed respectively. Added functions send_ack and send_abort * wtp_machine-decl.h: added attribute tid_ve, which tells are we doing tid verification or normal acknowledgement * wtp_state-decl.h: added rows for handling receiving invoke pdu, when state is result_wait 1999-12-22 * gw/smsc.c, conf-files: changed SMSC configuration vairable username and password into smsc-username and smsc-password with future HTTP adminstration in mind. 1999-12-22 * gw/smsbox_req.c (do_split_send): returned old code until Mikael fixes his new one. 1999-12-21 * gw/smsbox_req.c: fixed default username printing problem. Still waiting for Mikael to fix that split_send, it is not working properly right now. * gw/bearerbox.c: little modifications to debug output Tue Dec 21 15:17:32 1999 Lars Wirzenius * README.docbook: Wrote. Includes instructions for getting Docbook working (on Debian and Red Hat; patches for other systems most welcome). * gw/wml.c, gw/wml.h, test/test_wml.c: Added to gateway module from old smsgateway module. Code written by Peter Grönholm. Implements WML compiler. * gw/msg.c, gw/wsp.c, gw/wtp.c: Dumping function only prints out the relevant parts of the structure, not all fields. * gw/anything-related-to-wapbox-wtp-or-wsp: Removed extra debugging stuff to make log files more readable even during debugging. (Put'em back if you need'em.) * gw/wapbox.c: Emptying the queue of message going to the bearer box is in its own thread. * gw/wsp.c, gw/wsp_events-decl.h, gw/wsp_state-decl.h: Implemented some more of the WSP. Now a Get PDU is parsed and a new thread is spawned to do the HTTP fetch (which at the moment just reads from a hardcoded file, but that's trivially fixable later). The thread then sends back a Reply PDU with the contents of the (compiled) WML page. However, the phone doesn't accept it yet, something strange is going on. * gwlib/octstr.[ch]: Wrote function octstr_read_file, which reads the contents of a file into an octet string. 1999-12-20 * gwlib/socket.*: added function connect_to_server_with_port which binds our end of the socket to given port number. * gw/smsc_emi.c, gw/smsc.c: added 'our-port' configuration variable to the EMI IP code. 1999-20-12 Mikael Gueck * gw/smsbox_req.c: Dropped in a replacement for split_send() still without the vital UDH part. Hopefully didn't miss any features. Fri Dec 17 20:08:56 1999 Lars Wirzenius * gw/wtp_state-decl.h: State RESULT_RESP_WAIT actually sends the TRResultConfirmation event to WSP. * gw/wsp_state-decl.h: State CONNECTING_2 implemented. This required rather a little work, since there is no action. :-) * gw/wsp_state-decl.h: State CONNECTED implemented, sort of. Well, not really. What happens is that the phone sends a Get PDU, and we receive it and unpack it in this state, do the http_get call, and dump with debug() the result to the log file. This is enough to make sure that the PDU is unpacked correctly and the protocol works well enough that the phone thinks the session is open and it can make S-MethodInvokes. Whee. The next step is to implement things correctly, so that events are handled while the URL fetch is happening, and so on. * gw/wsp.c: Fixed unpack_octstr (it used offset 0, instead of what it got as an argument). Changed wsp_dispatch_event so that it tries to find an existing, correct WSPMachine instead of always creating a new one. Made wsp_unpack_connect_pdu an internal function, since it's not going to be used from outside wsp.c. Fri Dec 17 17:25:18 1999 Lars Wirzenius * gw/wsp.c: use TID of the machine that receives the event, instead of generating a new one. 1999-16-12 Aarno Syvänen * wtp.c: Fixing still wtp_machine_find_create. Now it can handle many events. Wed Dec 15 18:43:27 1999 Lars Wirzenius * gw/wapbox.c: Dump message to be sent to bearerbox, for debugging. * gw/wsp.c: Fixed generation of variable length integers for WSP PDU's. Old code didn't even resemble correct working. 1999-14-12 Aarno Syvänen * wtp_send.c: in function wtp_pack_result, fix errors in packing wtp pdu fields. Tue Dec 14 17:05:05 1999 Lars Wirzenius * gw/wtp_send.c: Set destination address as the phone, not the gateway (and source address as the gateway, not the phone) when sending a message to the phone. Tue Dec 14 16:34:39 1999 Lars Wirzenius * gw/wsp.c, gw/wtp.c: Fixed calls to mytex_try_lock (which returns -1, not EBUSY, when the lock failed). Mon Dec 13 20:47:28 1999 Lars Wirzenius * gw/bb_msg.c, gw/bb_msg.h, gw/bearerbox.c, gw/smsbox.c, gw/smsc.c, gw/smsc_p.h, gw/wapbox.c, gw/wsp.c, gw/wsp.h, gw/wsp_machine-decl.h, gw/wtp.c, gw/wtp.h, gw/wtp_machine-decl.h, gwlib/thread.c, gwlib/thread.h: Replaced pthread_mutex_t with Mutex (defined in gwlib/thread.h), so that the evil kludge to work around pthread_mutex_trylock can be hidden inside gwlib/thread.c. This required touching lightly lots of code, but it should work now. Sorry if I broke anything. Mon Dec 13 19:31:56 1999 Lars Wirzenius * gw/wapbox.c, gw/wapbox.h (new file): Wrote functions for keeping a queue of messages to be sent to the bearer box. * gw/wtp_send.c: Made use of the message enqueueing function. Mon Dec 13 18:43:54 1999 Lars Wirzenius * gw/wsp.c: WSPMachine now remembers its own address and port as well as the client's; also added session_id field. * gw/wsp.c: Wrote code for creating WSP PDU's. Now creates a trivial ConnectionReply PDU. * gw/wsp_events-decl.h, gw/wsp_state-decl.h: Added field `machine' to SConnectResponse event to store the machine to which the SConnectResponse handler should send WTP requests. This is a kludge but it was (temporarily) easier to do than fixing wtp_find_or_create_machine. * gw/wsp_state-decl.h: Implemented most of SConnectResponse. * gw/wtp.c, gw/wtp.h: : Wrote function wtp_machine_create, which gets all relevant information via the argument list. This is mostly just reorganizing and renaming the internal name_machine function. This involved changing wtp_machine_find_or_create as well. * gw/wtp.c: Removed locking of WTPMachine list, since it was incorrect and needs to be re-done in a different way. The current code has no locking, but at least it works if we're really, really careful. * gw/wtp_send.c: Commented away the calls to msg_destroy and octstr_destroy, since they caused segmentation faults (free called to often, or too early). This means yet another memory leak, but that's OK for now. We'll have to design a sensible way of dealing with memory de-allocation anyway. Mon Dec 13 16:36:34 1999 Lars Wirzenius * Makefile: test programs are also removed by "make clean". * gw/wapbox.c: Uses a log file (wapbox.log). Debug messages tweaked. * gw/wtp.c: Minor tweaking and bug fixing. Fixed wtp_next_tid: It shouldn't get the next or current tid as its argument, but use a static variable instead. wtp_event_destroy is commented out to avoid problems with freeing things too early. wtp_event_dump output tweaked so it's clearer. All debug messages say they come from WTP now; this helps reading long log files. WTPMachine.tcl is now set. Log file functions now don't get `errno' as their argument when it's not relevant (this cleans up log files quite a bit). New debugging message sprinkled all over the code. Added kludge to wtp_handle_event to avoid problem with pthread_mutex_trylock (see comment). Fixed problem wtp_handle_event so it uses machine->state and event->type (instead of separate variables that need to be kept up to date separately). * gw/wtp.h: Fixed prototype for wtp_tid_next. * gw/wtp_state-decl.h, state LISTEN: Actually sends the WSPEvent it generates to WSP, using wsp_dispatch_event (new function, see below). * gw/wtp_machine-decl.h: Added field `locker' as part of kludge for pthread_mutex_trylock. * gw/wsp.c: Lots of changes. Keeps list of WSPMachines (but doesn't use it yet). WSPEvent dumping improved. Wrote function wsp_dispatch_event to make it simpler for WTP to send events (current version doesn't yet try to find the correct WSPMachine, but always creates a new one). Lots of debugging messages sprinkled throughout the code. Added similar pthread_mutex_trylock kludge as for WTP in wsp_handle_event. Fixed bug in identifying the type of a WSP packet (got 0 and 1 wrong, stupid me). * gw/wsp.h: Added prototype for wsp_dispatch_event and missing #defines for WSPMachine definition. * gw/wsp_events-decl.h: Added event SConnectResponse. * gw/wsp_state-decl.h: NULL_STATE now implemented (only a lot of states more...). * gw/wsp_machine-decl.h: Added new fields for client address and port (for wsp_dispatch_event routing), locker (for kludge) and next (for keeping a list of WSPMachines). * gwlib/thread.c: Removed unnecessary empty lines from end. 1999-07-12 Aarno Syvänen * wtp.c: fixed locking bugs in functions wtp_machine_* * wtp.c, wtp.h, wtp_state-decl.h: fixed wsp handle * changing debugging functions all the time 1999-03-12 Aarno Syvänen * gwlib/thread.c: added function mutex_destroy * wtp.c: Added (uncommented) list locks in functions wtp_machine_*. Now these functions panic when mutexes are not iniatilized. * wtp.h: updated external function comments 1999-01-12 Aarno Syvänen * wtp.c: fixed a bug in wtp_machine_find (now it actually does find a machine) * wtp.c: implemented wtp_tid_next and added global variable gen_tid (it is used as a transaction handle). * purely estetical changes everywhere (prettier comments, etc.) 1999-30-11 Aarno Syvänen * wtp_state-decl.h: added event receive abort pdu Tue Nov 30 17:37:58 1999 Lars Wirzenius * gw/wsp.c: Replaced call to malloc with call to gw_malloc. Tue Nov 30 17:13:36 1999 Lars Wirzenius * gw/wtp.c, gw/wtp.h, gw/wtp_machine-decl.h: Added event queues to WTPMachine and wtp_handle_event. Tue Nov 30 16:33:29 1999 Lars Wirzenius * gw/wsp.c, gw/wsp.h: Implemented wsp_handle_event (doesn't really work yet, needs wsp_state-decl.h first). * gwlib/thread.[ch]: Added mutex_try_lock. Tue Nov 30 14:51:01 1999 Lars Wirzenius * Makefile: fixed "make depend" to add the directory of the object file to the .depends file. 1999-11-30 Aarno Syvänen * wsp_events-decl.h: added fields for wsp pdu type and event handle (unnecessary but mandatory). WSPEvent data structure represents both WTP primitive and WSP event. Mon Nov 29 19:33:42 1999 Lars Wirzenius * gw/wtp.h: wtp_handle_event will call wsp_handle_event (not yet written) instead of returning the WSPEvent, changed the return type to void. Moved WTPTimer definition back to wtp_timer.h. Simplified code by only using the pthreads version places where there was a choice. Added wtp_machine_create and wtp_tid_next prototypes. * gw/wtp.c, gw/wtp_timer.h, gw/wapbox.c, gw/wtp_machine-decl.h: Related changes. * gw/wtp_send.c: Added static to local function. * gw/wsp_state-decl.h: Replaced pseudo code function with more detailed code to generate events for WTP. 1999-11-29 * gw/smsbox_req.c: added that 'return' to smsbox request if max-messages was set to '0' Mon Nov 29 17:17:44 1999 Lars Wirzenius * gw/bearerbox.conf: Replaced interface-name's IP number with *, so that it works on other machines as well. * gw/wsp.c, gw/wsp.h, gw/wsp_machine-decl.h, gw/wsp_state-decl.h: Wrote. * gw/wtp.c, gw/wtp.h: Moved and renamed things for wsp stuff. * 1999-11-29 Aarno Syvänen *header files reorganized so that (most) types are defined in wtp.h *wtp_send.c: added a prototype result PDU packing function 1999-11-29 * gwlib/octstr.c, gw/*box.c: modified octstr_recv to return 1 for data and 0 for EOF. Changed boxes accordingly 1999-11-29 * gwlib/*: renamed gwlog as log and separated socket functions to own module 'socket.c'. Renamed remaining wapitlib as 'utils' * */*.c, */*.h: removed last wapitlib.h references 1999-11-29 * gw/smsbox_req.c: added sender username for sendsms request log output * gw/urltrans.c: fixed swapped receiver and sender * gwlib/*.*: split wapitlib into several parts, some splitting still possibly. All projects should work but those including wapitlib.h should be converted to use gwlib.h instead 1999-11-26 * gwlib/gwmem.*, gwlib/gwlib.h: Added new dynamic memory handling functions. All programs should be modified to use these. They simply PANIC if the allocation fails, so need to check their return value. 1999-11-26 Aarno Syvänen *wtp_state-decl.h: Added new rows in the state table (enough to run wtp proto). 1999-11-25 Aarno Syvänen *wtp.c: Fixed another bug in the function handle_event. No it generates only one indication, even though it receives many invoke messages. 1999-11-25 * gwlib/gwlib.h: added general gwlib header, which includes all parts of gwlib * */*.c: modified most of the modules to use new gwlib.h. Old ones still work Thu Nov 25 15:49:13 1999 Lars Wirzenius * gw/smsc_p.h: Added a missing include for signal.h to get the sig_atomic_t typedef. 1999-11-24 * gw/smsc.c: delayed re-open calls, with panic-option * gw/bearerbox.c: added load of mutex lockings * gw/smsbox_req.c, gw/urltrans.*: added 'footer' and 'header' service configurations * utils/makedist: partial update 1999-11-24 Mikael Gueck * gw/csdr.c, gw/boxc.c: Solaris compatibility hack, later to wapitlib.c. Wed Nov 24 13:31:44 1999 Lars Wirzenius * Makefile, Rules.mk, doc/*/Makefile: Modifications so it works on Red Hat and gets timestamps OK. Wed Nov 24 12:30:46 1999 Lars Wirzenius * gw/wapbox.c: wapbox.conf renamed to wapbox.wapconf. 1999-11-23 Aarno Syvänen * header files: fixed few bugs in files wtp_machine-decl.h and wtp_state-decl.h * wtp.c: fixed bugs in various functions Tue Nov 23 12:07:03 1999 Lars Wirzenius * Makefile: Added more stuff for docs. * Rules.mk, doc/*/Makefile: Moved common stuff to new Rules.mk, which is included by the individual makefiles. * doc/*/*.xml: Converted to use the SGML identifier of DocBook, instead of the XML one, because we have the SGML version of DocBook on Red Hat machines. 1999-11-22 * gwlib/wapitlib.*: added function check_ip * gw/bearerbox.*, gw/boxc.*, gw/smsbox.*: added configuration strings allowed-hosts, denied-hosts, http-allowed-hosts and http-denied-hosts. * gw/bearerbox.c, gw/smsc.*: added 'bacup' default router to SMSCes, and set that non-answering SMSC gets back in line - in time. * gw/bb.h: changed default heartbeat-frequency to 30 seconds. Mon Nov 22 11:37:39 1999 Lars Wirzenius * doc/userguide: Wrote draft outline of user's guide. * Makefile: Added stuff for docs. 1999-11-19 Aarno Syvänen * header files: add header files for wsp events and wtp state machine * wtp.c: add wsp event manipulating functions and a wtp state machine handling function 1999-11-19 * gw/bearerbox.c: separated 'sendsms' to port of the internal SMS Box, if any. And fixed number normalization, it failed in some cases. (MG: does CIMD strip the first character in receiever number?) 1999-11-19 * gw/smsbox_req.c: returned info about new service starting, fixed some bugs * gw/bearerbox.c: fixed mutex deadlock in internal sms box and heartbeat bug in sms and wap boxes. * gw/boxc.c: commented ack/nack things out as they are not currently supported 1999-11-19 * gw/smsc_*.*: removed last submit_smsmessage and receive_smsmessages. The EMI code still needs some fixing but should work now. * gw/bb_msg.*: removed client_data as it is not ever used. * gw/smsc.c, gw/bearerbox.c: fixed reconnecting procedures. 1999-11-19 * gw/csdr.c, gw/csdr.h: modified to add 'routing_info' for received messages, and to save own IP and port when started. All other gethostyname-calls removed. Not tested, however. 1999-11-19 * gw/smsbox_req.c, gw/smsbox_re.h, gw/smsbox.c: Did some bugfixing and updated header file comments (documentation) Fri Nov 19 11:13:17 1999 Lars Wirzenius * gw/msg.c: msg_pack and msg_unpack handle NULL octstr-fields. 1999-11-19 * gw/csdr.(c|h): added csdr_is_to_us to check whether a wdp_datagram should be routed through a specific CSDRouter. 1999-11-18 * gw/bearerbox.c: added wdp_datagram routing functions, and means to get rid of old information and simple re-routing for messages after a wap box fails * gw/bb_msg.c, gw/bb_msg.h: added function rq_change_destination for wdp_datagram routing use 1999-11-18 * gwlib/http.c, gw/smsbox_req.c: Content-Type fetching in http_get works, interface changed. 1999-11-18 * gw/smsbox_req.c, gw/smsbox.c: Modified send_message to use octstrings instead of char *. UDH part not yet ready. * gwlib/octstr.c, gwlib/octstr.h: Added function octstr_truncate Thu Nov 18 15:13:44 1999 Lars Wirzenius * doc/arch/arch-smsbox.xml: Fixed DocBook syntax errors. * gw/msg.c, gw/msg.h, test/test_msg.c: Wrote function msg_duplicate. * Makefile: Fixed typo in libtest.a rule. 1999-11-17 Aarno Syvänen * wtp.c: some bug fixing in function wtp_unpack_wdp_datagram 1999-11-17 * wapitlib.c, wapitlib.h: added functions mutex_lock and mutex_unlock, which loack/unlock given mutex and panic if fail - as panic is acceptable as mutex fails only because of coding error (too early call or out-of-sequence call) * bearerbox.c, smsbox.c, bb_msg.c: modified to use new mutex_lock and unlock functions 1999-11-17 * gw/bearerbox.c: fixed heartbeat bug * gw/smsbox.c: added debug information 1999-11-17 * gwlib/wapitlib.c: catched signal interrupts in read * gw/bearerbox.c: internal sms box implemented. Still some problems when the system wents down * gw/boxc.c, gw/smsbox_rew.c: updates * gw/smsc_cimd.c: quick hack to connect CIMD 1.37. Partial. MG, fix this. 1999-11-17 * smsbox_req.c: added username 'default', which is used, if no username is specified in 'sendsms' http-request * smsbox.smsconf: documentation updated accordingly Tue Nov 16 17:32:34 1999 Lars Wirzenius * gw/csdr.c: Fixed bug that prevented client address from being queryed. (Server address still isn't set correctly.) 1999-11-16 * doc/arch/arch-bearerbox.xml: updated to reflect current version Tue Nov 16 15:40:59 1999 Lars Wirzenius * Makefile: Added compilation of test programs. * test/test_msg.c: Added a call to msg_dump.c. Tue Nov 16 14:57:55 1999 Lars Wirzenius * Moved a number of files from smsgateway here. Tue Nov 16 13:11:13 1999 Lars Wirzenius * Massive reorganization of the directory tree. Almost all files moved to subdirectories. Makefile somewhat rewritten. 1999-11-16 * bearerbox.c, boxc.c, smsbox.c, smsbox_req.c, smsbox_rq.h, Makefile: Preparing bearerbox for internal SMS Box. Tue Nov 16 12:21:41 1999 Lars Wirzenius * Makefile, fakesmsc.c, http.c, wapitlib.h: Solaris support modified from patch by Steve Kennedy . 1999-11-16 * smsbox_req.c, smsbox_reg.h, smsbox.c, Makefile: separated request handling to own module so that it can be used as thread in bearerbox (implemented later) * bearerbox.c: someone has messed with print_threads 1999-11-15 * smsc*.(c|h), *box.c: getting rid of the SMSMessage structure and pending_* plus adding better UDH support. However, I'm having second thoughts about having two sms types... 1999-11-15 * bearerbox.c, control.html, bearerbox.conf: added new adminstration command 'disconnect' * boxc.c, boxc.h: added 'client_ip' information 1999-11-15 * control.html: added simple control tool * bearerbox.c, bearerbox.conf, fake.conf: added simple HTTP-adminstration and watching routines * smsbox.c: updated comments 1999-11-15 * bearerbox.c, boxc.c: Basic routing for WAP messages. Does not work with connectioned sessions, if there are more than one WAP BOX. Tough. Fixed later. * bb_msg.c, bb_msg.h: initiated better routing systems for WAP-messages, but implementation not ready * smsbox.c: file urltrans-request fixed. 1999-11-15 Mikael Gueck * csdr.c: send and receive UDP datagrams. * smsc_smpp.c: 8bit receive related fixes. 1999-11-15 * smsbox.smsconf, simple.smsconf: renamed previous smsbox.conf as .smsconf so that they are distinguished from bearerbox configuration * smsbox.c: fixing 'file' urltransh-requests. Still some bugs * bearerbox.c: WAP-packets are sent onward.. routing still missing Mon Nov 15 12:04:37 1999 Lars Wirzenius * wapbox.c, wapbox.conf: Wrote. This is the main module of the WAP box. * wapbox_feeder.c: Trivial test program for wapbox.c. * Makefile: related changes. * octstr.c: removed debugging message telling argument was NULL. Now a NULL argument is silently ignored. * msg.c: Added name of message type to message dump. 1999-11-12 * bearerbox.c, boxc.c: ready for WAP invasion (ok, still missing routing functions and sending is currently set off) Fri Nov 12 17:30:08 1999 Lars Wirzenius * Makefile: added "make depend". This only works with GNU make, shame on me. 1999-11-12 * html.c: modified html_strip_suffix_and_prefix to use str_case-str * urltrans.c, smsbox.c: fixed aliases * wapitlib.c, bearerbox.c: modified select to understand certain signals Fri Nov 12 17:06:52 1999 Lars Wirzenius * wapitlib.c and .h: Added str_case_str. 1999-11-12 * smsc.h, smsc.c, bearerbox.c: added re-connecting functions to smsc_get_message, and changed interface a bit * smsbox.c, smsbox.conf: fixed multiple sms sending. Changed that when 'split-chars' are used, the splitting character is included in previous part, not the following one. * simple.conf: two sample sendsms users 1999-11-12 * bb_msg.h, bb_msg.c: added functions _last_mod and _oldest_message for better queue control, and total number of added messages to queue length * bearerbox.c, boxc.c: some performance fixes 1999-11-12 * Release-0.1: added file to list modifications to SMSGateway 0.6 This is updated as the gateway is improved. * octstr.c, octstr.h: added function octstr_replace, so that unnecessary destroy/create can be avoided Fri Nov 12 02:00:00 1999 Mikael Gueck * http.(c|h), *box.c: httpserver_get_request now returns the client IP. * lots of other unspecified stuff 1999-11-11 * octstr.c, octstr.h: added octstr_create_limited * many modules: changed bearerbox and smsbox to use Msg instead of SMSMessage. As these are not quite perfect currently, the system does not work well right now. Waiting for patches from other participants. Thu Nov 11 19:41:40 1999 Lars Wirzenius * msg.c: Fixed warning of unused variable and erroneous packing of of strings. Wrote msg_dump. * octstr.c: octstr_dump can be called with a NULl argument. 1999-11-11 * msg.h, msg.c: added function msg_type. * octstr.h, octstr.c: functions octstr_duplicate, octstr_send ja octstr_recv added. * unlimited number of improvements, bugfixing and enhancements in other modules. Too many. 1999-11-09 * initial release. Copied several files from old smsgateway project, added new protypes and commented thigns out so that they can be compiled. This does NOT do anything, yet. * VERSION: version 0.1 setgateway-1.4.5/doc/ChangeLog-1.3.10000644000175000017500000002521010203150325014630 0ustar toljtolj2003-02-17 Stipe Tolj * doc/userguide/userguide.xml: minor xml fixes. 2003-02-16 Bruno Rodrigues * userguide.xml: some xml fixes. Cleaning of debian chapter and added new packages's information. Standardization of configuration blocks, xml samples and shell commands. Fixed logrotate sample 2003-02-16 Stipe Tolj * gw/smsc/smsc_emi2.c: fixed assigning of non existent field in EMI/UCP driver. Thanks to "Michael Mulcahy" for reporting and Alexander for providing a patch. [Msg-ID: <200302031916.32796.a.malysh@centrium.de>] * configure[.in]: Modified doc building checking. Alan provided this patch, thanks a lot. Now docs are only build if all requiries are meet. [Msg-ID: <1044948632.1131.71.camel@terpsichore>] * gwlib/pki.h: fixed minor compiler warning 2003-02-15 Stipe Tolj * doc/userguide/userguide.xml: fixed malformed xml tag from previous commit. 2003-02-15 Bruno Rodrigues * configure, configure.in: added detection of OPENSSL_THREADS to enable compiling kannel with openssl 0.9.7 2003-02-15 Stipe Tolj * gw/*.conf: harmonized the example config files. Deleted specially developer specific config values that are of no use for a normal user. * gw/wap_push_ppg.c, gw/wap_push_ppg_pushuser.c: fixed some minor parts of Aarno's PPG SMSC routing patch. * doc/userguide/userguide.xml: added documentation sections about new 'default-smsc' for the ppg group and 'default-smsc' and 'forced-smsc' for the wap-push-user group. 2003-02-14 Bruno Rodrigues * debian/*: created kannel-devel-* package files - to build them you need to copy control.devel and changelog.devel to control and changelog respectivly. 2003-02-14 Stipe Tolj * doc/userguide/userguide.xml: Alan provided some documentation about log file roation. [Msg-ID: <1044948652.1108.73.camel@terpsichore>] 2003-02-14 Stipe Tolj * gw/wap_push_ppg_pushuser.c, gwlib/cfg.def: bouncing back to use unique config directives for 'wap-push-user' and 'sendsms-user' groups for specifying forced smsc-ids. 2003-02-14 Stipe Tolj * gw/smsc_smpp.c, doc/userguide/userguide.xml: Changed default behaviour of the 'source-addr-autodetect' to yes. Alex suggested this. If the feature is not needed, it can be turned off by setting the config directive to 'no'. 2003-02-13 Aarno Syvänen * PPG SMSC routing patch: * gw/wap_ppg_push_machine.def: Added a field for smsc id. * gw/wap_push_ota.c: Forward smsc id to wsp. * gw/wap_push_ppg.c: Read smsc id from config or from cgi variable and forward it to ota. Formatted. * gw/wap_push_ppg_pushuser.[c|h]: Read smsc id from config file. Added a public function wap_push_ppg_pushuser_smsc_id_get for this purpose. * gw/wapbox.c: Forward smsc id to bearerbox. * gwlib/cfg.def: Configuration variables forced_smsc_id and default_ smsc_id. * wap/wap_events.def: Smsc id to all relevant wap events. Formatted. * wap/wsp_unit.c: Forward smsc id to wdp. * Make check bugfix: * checks/check_sendsms.sh: Better echoing when a failure occurs. * checks/check_smpp.sh: Ditto. Test will end, changed log item to be grepped. * gwlib/socket.c: Removed an error message. Caller can log this. * test/drive_smpp.c: Formatted. 2003-02-07 Stipe Tolj * gw/smsc/smsc_cimd2.c: missed the 'ts = NULL' for the sake of the for() loop. 2003-02-07 Stipe Tolj * gw/smsc/smsc_cimd2.c: fixed now dependency things for previous urltrans fix. Thanks to "Dariusz Markowicz" . 2003-02-06 Stipe Tolj * gwlib/http.c: bouncing back to "HTTP/1.x %d Foo" style. Bruno has requested this and it's seems nothing speaks against serving Foo. * gw/urltrans.c: fixed a bug in case sms.msgdata is empty we don't want to pass this to octstr_split_words(). Patch provided by "Dariusz Markowicz" . [Msg-ID: <01f801c2c87c$cfde56b0$1900000a@toster>] Couldn't this be avoided by dealing with a NULL'ed octstr inside octstr_split_words() itself?! * gw/bboxc.c: fixed the unnecessary mutex locking in case we deal with a wapbox connection. Thanks Robert for pointing this out. * gwlib/cfg.def, gw/wap_push_ppg_pushuser.c: added smsc-id value handling for the 'wap-push-user' group. The transportation of the value up to the bearerbox sending routine has to be implemented yet. 2003-02-04 Bruno Rodrigues * userguide.xml: fixed table 5.2 and 5.3 for emi2 smsc 2003-02-04 Bruno Rodrigues * VERSION: fix back to "cvs". Stipe will change to 1.3.1 when tagging * config.guess, config.sub: these are autogenerated by autoconf, but it seems better to leave them on CVS 2003-02-02 Bruno Rodrigues * test/run-http2-tests: renamed to test/run-http2-tests.sh * Makefile.in: like "checks", have a "tests" that includes test executables and scripts * Makefile.in: Added install-test, install-checks and install-contrib * Makefile.in: install *.conf examples in install-docs * Makefile.in: install docs with INSTALL_DATA to have 644 permissions * Makefile.in: added make target "debian" * debian: make kannel-docs with documentation and kannel-extra with test, checks and contrib files * debian: bumped Standards-Version to latest 3.5.8 * debian/.cvsignore: ignore kannel-docs and kannel-extra directories * debian/conffiles: now empty. New Standards-Version have assumes /etc/* as conffiles * debian/docs: added other doc files * debian/postinst, debian/postrm: updated to new standards version: no need for making /usr/doc -> /usr/share/doc link anymore now update-rd.d. They are automatic now * debian/rules: updated to new Standards * debian/*: added logrotate config file 2003-01-29 Stipe Tolj * gw/smsc/smsc_at2.c: fixed double-increment bug for outgoing messages counter. Thanks to Paul for pointing on this. 2003-01-29 Stipe Tolj * gwlib/http.c: fixed the missing HTTP Server identifier from previous commit. 2003-01-29 Stipe Tolj * gwlib/http.c: fixed a keep-alive lookup problem when using a HTTP proxy. Thanks to "Michael Mulcahy" for reporting this. 2003-01-29 Stipe Tolj * gw/smsc/smpp_pdu.c: added missed fix from Alexanders previous patch. 2003-01-28 Stipe Tolj * gw/smsbox.c: add debug info about ammount of outstanding HTTP reqeusts in the retry queue. 2003-01-28 Stipe Tolj * gw/smsc/smpp_pdu.c: added Alexander's optional PDU parameters robustness patch. [Msg-ID: <200301252018.01219.a.malysh@centrium.de>] * gw/smsc/smsc_oisd.c, gw/smsc/smsc.c, gw/smsc/smsc_p.h: added new OIS direct module provided by Dariusz Markowicz . [Msg-ID: <02a301c2c56d$fa354f20$d4e34cd5@oem>] 2003-01-27 Stipe Tolj * gw/smsc/smsc_http.c: fixed a missing octstr_duplicate() bug in kannel_receive_sms(). Thanks to Angel for this patch. [Msg-ID: ] * gw/smsc/smsc_cimd2.c: added validity setting within CIMD2 module. Patch submitted by Nicholas Rahn . [Msg-ID: <1043677000.2194.41.camel@frisbee.mnc.ch>] * gw/smsc/smsc_cimd2.c: added non-activated RPI (reply path indicator) as default. This is common in the other modules too. Allow alphanumeric source addresses. Patch by "Arne K. Haaje" [Msg-ID: <3E313D1E.2060903@eurobate.com>] 2003-01-25 Stipe Tolj * gw/wap_push_pap_compiler.c: fixed infinite loop bug if /TYPE=xxx is missing in the PAP document. Thanks to Paul for pointing this out. 2003-01-24 Stipe Tolj * gw/bb_boxc.c, gw/smsbox.c: fixed a un-locked mutex bug while waiting for smsbox indenitificatio msgs. Bug identified and patch provided by "Robert Galach" . [Msg-ID: <018001c2c158$f864beb0$3200000a@tenbit.com>] 2003-01-21 Stipe Tolj * gw/smsc/smpp_pdu.c: fixed a bug in smpp_pdu_unpack() when an PDU contains optional parameters with len < 0, octstr_copy() would definetly crash. * gw/smsc/smsc_emi2.c: fixed double counter increase bug for incoming messages. 2003-01-21 Stipe Tolj * gw/smsc/smsc_http.c: added proxying of the smsc-id attribute to the attached smsbox instance. This allows spreading load from one smsbox to several bearerbox instances. 2003-01-15 Stipe Tolj * doc/userguide/userguide.xml: fixed out-dated 'msg-id-type' directive explanation. Thanks to Mauricio Ramos . 2003-01-13 Stipe Tolj * gw/wap-appl.c: fixed memory leak in set_referer_url(). Patch provided by Vjacheslav Chekushin . Thanks 2003-01-12 Bruno Rodrigues * ChangeLog: fix spaces ;) Sorry, I'm too used to debian's changelog * debian/changelog: fix changing day but not month and year 22003-01-11 Bruno Rodrigues * debian/*: updated to generate packages for 1.3.0 * test/.cvsignore: ignore new wapproxy file * ChangeLog: fix spaces ;) 2003-01-09 Andreas Fink * gw/cfg.def: added wait-ack-expire variable as otherwhise it wont work on a clean compilation 2003-01-09 Stipe Tolj * gw/wap-appl.c: fixed assertion panic in case HTTP method is not supported. Thanks to Vjacheslav Chekushin . 2003-01-07 Stipe Tolj * test/wapproxy.c: fixed compiler warning. 2003-01-07 Stipe Tolj * solaris/pkginfo.[tmpl]: removed pkginfo and added pkginfo.tmpl. Suggested by Alan McNatty . 2003-01-06 Stipe Tolj * README, README.MACOSX: moved information from MacOS X specific README file to the global README. There is no need for a specific OS dependend README file for such minimal informations. 2003-01-05 Stipe Tolj * Making development release 1.3.0. gateway-1.4.5/doc/ChangeLog-1.4.00000644000175000017500000003074510203150325014641 0ustar toljtolj2004-11-18 Stipe Tolj * gw/bb_smscconn.c: fixing bug #160, causing segfault on cygwin while using uninited rwlock functions. 2004-11-15 Alexander Malysh * doc/examples/dlr-*.conf: fixed group name from e.g. dlr-mysql -> dlr-db. Thanks to James Coleman jamesc_at_doolin.com for pointing to this. 2004-11-05 Alexander Malysh * gwlib/utils.c: fixes daemon mode (make sure stdin/stdout/sdterr are opened and do chdir("/")) and change user code (set supplementary group id's and don't destroy passwd struct). * doc/userguide/userguide.xml: documented the fact that daemon mode changes CDW to `/'. 2004-11-05 Alexander Malysh * gwlib/protected.c: fixed linux version of gw_gethostbyname when gethostbyname_r failed. Also free buffer on error. Bug: #157. 2004-11-03 Alexander Malysh * gwlib/dbpool_pgsql.c: fixed double free (PGFinish will destroy connection for us). 2004-10-31 Alexander Malysh * gw/msg.c: fixed double free in 'msg_unpack'. 2004-10-28 Stipe Tolj * gwlib/utils.[ch]: source code reformating of get_and_set_debugs(). No logic change. Added global arguments to header file. * test/fakesmsc.c: switching from -p to -r for port, since utils.c uses -p for pid-file creation. This broke current cvs to use an other port then the default 10000 to connect to the smsc_fake module of bearerbox. * doc/userguide/userguide.xml: fixing the command line arguments list for fakesmsc to reflect the change from -p to -r for the port. 2004-10-21 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed bug #129 (Incorrect handling of GSM_ADDR_TON_ALPHANUMERIC for destination address). 2004-10-13 Kalle Marjola * test/test_ppg.c: Added support for X-WAP-Initiator-URI, use -I option. * doc/userguide/userguide.xml: updated accordingly * utils/run-check: fixed check so that it works in bash 2004-10-06 Alexander Malysh * configure.in, configure: added check for 'sem_init' in librt. This needs on Solaris & HP-UX. 2004-09-28 Stipe Tolj * doc/userguide/userguide.xml: added section for account %o escape code for the sms-service url translation. 2004-09-28 Stipe Tolj * gw/urltrans.c: fixed comment block for new account %o escape code. Thanks to the eagle'd eyes of Alex. :p * gw/smsc/smsc_http.c: added credits to Alex for his improvements to the code and fixes. 2004-09-28 Stipe Tolj * gw/smsc/smsc_http.c: fixing 3united (formerly Xidris) HTTP interface for binary MT messages. We passed URL-encoced binary string, but server side expected HEX encoded (2 char per byte) version. 2004-09-28 Stipe Tolj * gw/urltrans.c: added a fix by Alex that prevents panic'ing while msg text is NULL and adding '%o' as escape code for MO msgs representing the msg->sms.account field. Which is interpreted as the operator ID for aggregator specific MO messages. ie. Xidris HTTP SMSC module. Thanks to Tobias for this. 2004-09-27 Stipe Tolj * gw/smsc/smsc_http.c: fixed a binary MT bug (when DC_8BIT ahs been set) and various improvements for passing parameters to the HTTP request. Added credits to Tobias Weber who did improvements on the code. 2004-09-27 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed stupid bug that dlr lookup was made with source instead of destination address (in dlr source and destination switched). 2004-09-25 Alexander Malysh * gwlib/gw-rwlock.c, gw/smsc/smsc_at.h: fixed compiler warnings. 2004-09-18 Alexander Malysh * gw/smsc/smsc_at.c: added new function 'at2_error_string' and teached smsc_at to use it. Thanks to almado.de for provided patch! 2004-09-16 Alexander Malysh * gwlib/xmlrpc.c: fixed memory leak. 2004-09-10 Alexander Malysh * gwlib/gwlib.h: added 'gw-prioqueue.h'. fixed compile error. 2004-09-08 Alexander Malysh * gw/sms.[ch], gw/smsc/smsc_at.[ch], gw/smsc/smsc_emi.c: applied patch that adds usage of priority queue and priority flag in smsc_at & smsc_emi. This patch makes it possible to prioritize messages and to ensure that older messages will be sent first. [Msg-ID: ]. 2004-09-04 Stipe Tolj * doc/userguide/userguide.xml: fixing jade compiler error of Alex's previous commit for priority flag. 2004-09-03 Stipe Tolj * gw/smsc/smsc_http.c: upgradding bruNET response parsing to comply with more recent interface verions (v2.0+) where bruNET delivers 'MessageId' in the HTTP response body. 2004-09-03 Alexander Malysh * gw/smsc/smsc_smpp.c, gw/msg-decl.h, gw/smsbox.c: applied patch that allows setting of sms priority flag in smsbox and smpp module. Also fixes wrong priority setting in smpp module. * doc/userguide/userguide.xml: describe 'priority' flag and some missing params. 2004-09-01 Stipe Tolj * doc/userguide/userguide.xml: moved EMI/UCP specific 'throughput' to general section, since this is within the SMSCConn structure itself. Added 'smasi' features to the check lists. 2004-08-30 Alexander Malysh * gwlib/gw-rwlock.[ch]: fixed includes. we don't define HAVE_CONFIG_H so gw-config.h should be always included. 2004-08-30 Alexander Malysh * gw/smsc/smsc_smpp.c: added ESME dlr bit to DLR processing (some smsc's sent us esm_class=0x08 and it's IMO ok). 2004-08-30 Alexander Malysh * doc/userguide/userguide.xml: removed centrium references and changed email addr. 2004-08-28 Alexander Malysh * gw/bb_smscconn.c, gw/msg-decl.h, gw/msg.[ch], gw/sms.h, gw/smsbox.c, gw/smscconn.c, gw/wapbox.c, gw/smsc/smsc_http.c, gw/smsc/smsc_soap.c, utils/mtbatch.c: applied patch that implements concatenation of large sms inside bearerbox and does care of a sending all message parts over one smsc link. Now we have a problem with concatenated large sms that bearerbox will try to load balance those over diff. smsc links and such messages arrive as junk (all parts of concatenated large sms must go through the same smsc). 2004-08-28 Alexander Malysh * gw-config.h.in, configure.in, configure: changed 'HAVE_PTHREAD_RWLOCK_T' to more generic 'HAVE_PTHREAD_RWLOCK'. * gwlib/gw-rwlock.[ch]: added "ugly" rwlock emulation code if no pthread_rwlock support detected. This emulation code uses List and works in all cases where rwlock used in kannel. 2004-08-26 Stipe Tolj * gw/wap-appl.c: fixing a memory leak while not destroying a created octstr if wml_compile() fails. Thanks again to Slava for the patch. [Msg-ID: <412B46C9.1030800@lmt.lv>] 2004-08-26 Stipe Tolj * gw/wml_compiler.c: fixed PANIC inside octstr_create in wml compiler with certain DOCTYPE definitions. Thanks to Slava for the patch. [Msg-ID: <412B44E4.9080204@lmt.lv>] 2004-08-26 Stipe Tolj * wap/wsp_string.c: fixed a mis-interpretated datatype change from rev 1.3 to 1.4. Thanks to Slava for this hint and patch. [Msg-ID: <412ADEEE.2030608@lmt.lv>] 2004-08-25 Alexander Malysh * gwlib/semaphore.c: changed 'HAVE_SEMAPHORE_H' to 'HAVE_SEMAPHORE' and removed workaround for DARWIN. * configure, configure.in, gw-config.h.in: changed 'HAVE_SEMAPHORE_H' to 'HAVE_SEMAPHORE' and added configure check for working sem_init and friends. 2004-08-24 Alexander Malysh * Makefile.in: remove 'gwlib/gw_uuid_types.h' by distclean too. 2004-08-23 Stipe Tolj * configure[.in]: fixing pthread lib settings for FreeBSD 5.2.1. We need to add -lc_r and -lkse to LIBS for the freebsd platform. 2004-08-20 Stipe Tolj * test/test_prioqueue.c: fixed compiler warning. 2004-08-20 Stipe Tolj * gwlib/gw-prioqueue.c: some source beautifying ;) no logic change. * test/test_prioqueue.c: adding Alex's simple test program for testing the generic priority queue he introduced to gwlib. 2004-08-19 Alexander Malysh * gw/smsc/smsc_at.c: fixed segfault when modemtype is set to 'auto' or 'autodetect'. Fixed '+CPIN', some modem needs '"'. 2004-08-19 Alexander Malysh * gwlib/gw-prioqueue.[ch]: implemented very simple priority queue ala Robert Sedgewick. Behavior like kannel's list. Thanks to 'almado.de' for the idea. 2004-08-18 Stipe Tolj * gw/smsc/smsc_smpp.c: some typo fixes, no logic change. 2004-08-17 Bruno Rodrigues * utils/mtbatch.1: added manpage for mtbatch * all: re-"released" 1.4.0 - moved branch tag 2004-08-17 Stipe Tolj * gw/shared.c: fix compiler warning for tcc. * wmlscript/ws.[ch]: fix const compiler warning for tcc. 2004-08-16 Andreas Fink * gwlib/semaphore.c: dont use native semaphores on MacOS X to avoid a "not implemented" error 2004-08-12 Alexander Malysh * gwlib/utils.c: fixed warning about format attributes. 2004-08-12 Alexander Malysh * gwlib/gwthread-pthread.c: declared 'tsd_key' and 'threadtable_lock' static, because those are local symbols and don't exported to the world. * gwlib/gwthread.h: added 'gw-config.h' and 'sys/poll.h' to includes, so we can include 'gwlib/gwthread.h' alone. 2004-08-11 Stipe Tolj * various files: a generic spellchecking patch to fix mis-spelling. Mainly this fixes bad-english comments in source files. Thanks a lot to Pedro for the provided patch. NO LOGIC CHANGE! [Msg-ID: <411A3291.4090906@netcabo.pt>] 2004-08-11 Stipe Tolj * gw/smsc/smpp_pdu.c: fixing a warning statement, for nulterminated string length checking of PDU elements. This should be not confusing users. Thanks to Alan McNatty for pointing to this. 2004-08-09 Alexander Malysh * gwlib/gw-rwlock.c: catch 'pthread_rwlock_init' errors too. 2004-08-08 Alexander Malysh * gwlib/log.c: more fixes for compiler format warnings. 2004-08-08 Alexander Malysh * gw-config.h.in: define 'PRINTFLIKE' here, so we ca use this everywhere. * gwlib/log.h: removed 'PRINTFLIKE' and 'PRINTFLIKE2' from here and fixed functions declaration. * gw/bb_alog.c, gwlib/accesslog.h, wap/wsp_headers.c, wmlscript/wserror.h: fixed compiler format warnings. 2004-08-08 Alexander Malysh * gwlib/gw-rwlock.[ch], gw/dlr_mem.c, gw/bb_smscconn.c: got rid of PTHREAD_RWLOCK_INITIALIZER because it's not on opengroup standard (PTHREAD_RWLOCK_INITIALIZER is deleted for alignment with IEEE Std 1003.1j-2000). 2004-08-08 Bruno Rodrigues * gw/smsbox.c: fix double encoding when transcoding from UCS2 to UTF-8 or ISO-8859-1 2004-08-07 Stipe Tolj * doc/userguide/userguide.xml: parsed the beast via aspell and got rid of some grammer and spelling issues. 2004-08-07 Alexander Malysh * gw/sms.c: fixed whitespaces. 2004-08-05 Alexander Malysh * gw/gw/bb_smscconn.c: applied patch that makes it possible to start/stop/restart of all smscconn's that have equal smsc-id's instead of only one. [Msg-Id: ]. 2004-07-20 Alexander Malysh * gwlib/date.c: fixed 'date_parse_iso' and 'date_create_iso'. date_create_iso: 'Z' at the and means UTC time and not local time. date_parse_iso: never works?! 2004-07-18 Alexander Malysh * gw/smsc/smsc_smpp.c: fixed bug #143. 2004-07-14 Stipe Tolj * Making development release 1.3.2. gateway-1.4.5/doc/examples/0000755000175000017500000000000013312227710014245 5ustar toljtoljgateway-1.4.5/doc/examples/dlr-sqlite3.conf0000644000175000017500000000160211535767012017267 0ustar toljtolj# # DLR with SQLite3 support configuration # # Example defining a SQLite3 database connection resource and # the required table and field values. # group = sqlite3-connection id = mydlr database = /path/to/file # max count of connections that will be opened for dbpool # default is 1 max-connections = 1 # # Create the required table for the DLR support in the database # with something similar like this: # # CREATE TABLE dlr ( # smsc varchar(40), # ts varchar(40), # destination varchar(40), # source varchar(40), # service varchar(40), # url varchar(255), # mask int(10), # status int(10), # boxc varchar(40) # ) # group = dlr-db id = mydlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc gateway-1.4.5/doc/examples/modems.conf0000644000175000017500000000534011350355357016413 0ustar toljtolj# Modems configuration # # Example and default values # # group = modems # id = "my-id" # name = "my-name" # detect-string = "MODEM" # detect-string2 = "" [Default] # init-string = "AT+CNMI=1,2,0,0,0" [Default] # speed = 9600 [Default] # enable-hwhs = "AT+IFC=2,2" [Default] # need-sleep = false [Default] # no-pin = false [Default] # no-smsc = false [Default] # sendline-sleep = 100 [Default, miliseconds] # keepalive-cmd = "AT" [Default] # broken = false [Default] # message-storage = "SM" # enable-mms = false [Default] # If modemtype=auto, try everyone and defaults to this one group = modems id = generic name = "Generic Modem" group = modems id = wavecom name = Wavecom detect-string = "WAVECOM" group = modems id = premicell name = Premicell detect-string = "PREMICEL" no-pin = true no-smsc = true group = modems id = siemens_tc35 name = "Siemens TC35" detect-string = "SIEMENS" detect-string2 = "TC35" init-string = "AT+CNMI=3,2,0,1,1" speed = 19200 enable-hwhs = "AT\\Q3" need-sleep = true reset-string = "AT+CFUN=1" keepalive-cmd = "AT+CSQ" group = modems id = siemens_m20 name = "Siemens M20" detect-string = "SIEMENS" detect-string2 = "M20" speed = 19200 enable-hwhs = "AT\\Q3" keepalive-cmd = "AT+CBC;+CSQ" need-sleep = true group = modems id = siemens_sl45 name = "Siemens SL45" detect-string = "SIEMENS" detect-string2 = "SL45" init-string = "AT+CNMI=1,2,2,2,1" keepalive-cmd = "AT+CBC;+CSQ" speed = 19200 enable-hwhs = "AT\\Q3" need-sleep = true message-storage = "SM" group = modems id = nokiaphone name = "Nokia Phone" detect-string = "Nokia Mobile Phone" need-sleep = true keepalive-cmd = "AT+CBC;+CSQ" enable-mms = true group = modems id = falcom name = "Falcom" detect-string = "Falcom" #no-smsc = true group = modems id = ericsson_r520m name = "Ericsson R520m" detect-string = "R520m" init-string = "AT+CNMI=3,2,0,0" group = modems id = ericsson_t68 name = "Ericsson T68" detect-string = "T68" init-string = "AT+CNMI=3,3" keepalive-cmd = "AT+CBC;+CSQ" broken = true group = modems id = sonyericsson_gr47 name = "Sony Ericsson GR47" detect-string = "GR47" message-storage = "ME" # use this init-string for non sim-buffering init-string = "AT+CNMI=3,2,0,0" # use this init-string for sim-buffering #init-string = "AT+CNMI=3,1,0,0" reset-string = "ATZ" broken = true group = modems id = alcatel name = "Alcatel" detect-string = "Alcatel" init-string = "AT+CNMI=3,2,0,0" group = modems id = sonyericsson_T630-T628 name = "Sony Ericsson T630-T628? init-string = "AT+CNMI=2,3,2,0,0;+CMGF=0? keepalive-cmd = "AT+CBC;+CSQ;+CMGF=0? broken = true group = modems id = sonyericsson_p1i name = "Sony Ericsson P1i" detect-string = "Sony Ericsson P1i" init-string = "ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0" message-storage = "SM" reset-string = "ATZ" broken = true gateway-1.4.5/doc/examples/dlr-cassandra.conf0000644000175000017500000000224512634542335017646 0ustar toljtolj# # DLR with Cassandra support configuration # # Example defining a Cassandra connection resource and # the required table and field values. # group = cassandra-connection id = mydlr host = localhost #username = foo #password = bar #database = dlr # max count of connections that will be opened for dbpool # default is 1 max-connections = 1 # # Create the required keyspace and table for the DLR support, # with something similar like this: # # CREATE KEYSPACE kannel \ # WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 }; # # USE kannel; # # CREATE TABLE dlr ( # smsc text, # ts text, # destination text, # source text, # service text, # url text, # mask text, # status int, # boxc text, # PRIMARY KEY (smsc, ts) # ); # # If 'ttl' is set in seconds, then this is the time to live (TTL) for # a specific DLR entry in the keystore. (i.e. 7d = 60480s) group = dlr-db id = mydlr table = kannel.dlr ttl = 604800 field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc gateway-1.4.5/doc/examples/dlr-oracle.conf0000644000175000017500000000161610146107746017154 0ustar toljtolj# # DLR with Oracle support configuration # # Example defining a Oracle database connection resource and # the required table and field values. # group = oracle-connection id = mydlr username = foo password = bar tnsname = bla # max count of connections that will be opened for dbpool # default is 1 max-connections = 1 # # Create the required table for the DLR support in the database # with something similar like this: # # CREATE TABLE dlr ( # smsc varchar(40), # ts varchar(40), # destination varchar(40), # source varchar(40), # service varchar(40), # url varchar(255), # mask int(10), # status int(10), # boxc varchar(40) # ) # group = dlr-db id = mydlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc gateway-1.4.5/doc/examples/store-redis.conf0000644000175000017500000000146112633562133017364 0ustar toljtolj# # Message storage with Redis support configuration # # Example defining a Redis database connection resource and # the storage name. # # If 'hash = yes' is set in the 'group = store-db' context, the # messages are stored in the redis hash space with the msg UUID # as key. This makes the contents of the redis hash more 'readable', # but also adds complexity to the IO calls towards redis. # So the trade-off scenario is: # # hash = no (default) -> faster, msg objects in store are "string blobs" # hash = yes -> slower, msg objects in store are "readable" # group = redis-connection id = redis_id host = localhost port = 6379 #password = foo database = 0 # max count of connections that will be opened for dbpool # default is 1 max-connections = 1 group = store-db id = redis_id table = store1 #hash = no gateway-1.4.5/doc/examples/dlr-sdb.conf0000644000175000017500000000373610052415075016455 0ustar toljtolj# # DLR with LibSDB support configuration # # Example defining a LibSDB resource (as an abstraction of a real database) # and the required table and field values. # # As of LibSDB 0.5.0 the following database types are supported with # the associated URL resource scheme: # # mysql:host=XXX:db=XXX:uid=XXX:pwd=XXX # postgres:host=XXX:db=XXX:port=XXX # oracle:uid=XXX:pwd=XXX OR oracle:uid=username/password@instance # sqlite:db=/full/path/to/db # lago:host=XXX:port=XXX:db=XXX:uid=XXX:pwd=XXX # mimer:db=XXX:uid=XXX:pwd=XXX # odbc:dsn=postgresql # sdbd:host:port:url=XXX # text:/path/to/db/ (note trailing slash) # # Beware that you have the DB support build in your LibSDB installation # when trying to use a specific DB type within the URL. # # LibSDB is available at http://siag.nu/libsdb/ # group = sdb-connection id = pgdlr url = "postgres:host=localhost:db=myapp:port=1234" max-connections = 1 # # Create the required table for the DLR support in the database # with something similar like this, i.e. for MySQL: # # CREATE TABLE dlr ( # smsc varchar(40), # ts varchar(40), # destination varchar(40), # source varchar(40), # service varchar(40), # url varchar(255), # mask int(10), # status int(10), # boxc varchar(40) # ) # # For Postgres: # # CREATE TABLE dlr ( # smsc VARCHAR(48), # ts VARCHAR(48), # destination VARCHAR(48), # source VARCHAR(48), # service VARCHAR(48), # url VARCHAR(255), # mask INTEGER, # status INTEGER, # boxc VARCHAR(48)); # # Other DB types may vary. Consult your DB admin for help in creating # the appropriate table space and connection details for the real DB. # group = dlr-db id = pgdlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc gateway-1.4.5/doc/examples/dlr-mysql.conf0000644000175000017500000000553512634542430017055 0ustar toljtolj# # DLR with MySQL support configuration # # Example defining a MySQL database connection resource and # the required table and field values. # group = mysql-connection id = mydlr host = localhost username = foo password = bar database = dlr # max count of connections that will be opened for dbpool # default is 1 max-connections = 1 # # Create the required table for the DLR support in the database # with something similar like this: # # DROP TABLE IF EXISTS dlr; # SET character_set_client = utf8; # CREATE TABLE dlr ( # smsc VARCHAR(40) DEFAULT NULL, # ts VARCHAR(65) DEFAULT NULL, # destination VARCHAR(40) DEFAULT NULL, # source VARCHAR(40) DEFAULT NULL, # service VARCHAR(40) DEFAULT NULL, # url VARCHAR(255) DEFAULT NULL, # mask INT(10) DEFAULT NULL, # status INT(10) DEFAULT NULL, # boxc VARCHAR(40) DEFAULT NULL, # KEY dlr_smsc_index (smsc), # KEY dlr_ts_index (ts) # ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # group = dlr-db id = mydlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc # # Advanced configuration for TTL (time-to-live) of DLR records: # # MySQL has no direct support for expiring rows in a table, unlike other Non-SQL # counterparts like Redis or Cassandra. Therefore DLR entries in the table that # have NEVER received any final DLR from the upstream SMSC will keep persistent # in the table. The user needs to perform external clean-up procedures, i.e. by # removing all entries that are older then a particular time interval using a # cron job. # # We present here the concept of using MySQL 5.1+ internal events to clean-up # the table. To enhance the configuration the following steps need to be # performed: # # 1. Add a dlr.timestamp field sets the current timestamp automatically. # Alter the table as follows: # # > ALTER TABLE dlr ADD COLUMN timestamp TIMESTAMP NOT NULL \ # DEFAULT CURRENT_TIMESTAMP AFTER boxc; # # Every entry is then "tagged" with the current timestamp, and can be # evaluated for the clean-up process by this creation date. # # 2. Activate the event scheduler in MySQL: # # > SET GLOBAL event_scheduler = ON; # # [Reference: https://dev.mysql.com/doc/refman/5.5/en/events-configuration.html] # # 3. Create the event schedule itself for the DLR clean-up: # # > CREATE EVENT IF NOT EXISTS dlr_clean \ # ON SCHEDULE EVERY 6 HOUR \ # DO \ # DELETE FROM dlr WHERE TIME_TO_SEC(dlr.timestamp) + 604800 < TIME_TO_SEC(CURRENT_TIMESTAMP); # # Which creates an event, running every 6 hours (hence 4 times a day), # deleting ANY records in the DLR table that are older then 7 days # (604800 seconds). Adopt the schedule to your needs, i.e. avoiding # clean-up at load peak times. # gateway-1.4.5/doc/examples/kannel.conf0000644000175000017500000001011007523570220016361 0ustar toljtolj# # THIS IS A SAMPLE CONFIGURATION FOR KANNEL # # For any modifications to this file, see Kannel User Guide # If that does not help, send email to users@kannel.org # group = core admin-port = 13000 admin-password = bar #status-password = foo #admin-deny-ip = "" #admin-allow-ip = "" #log-file = "/tmp/kannel.log" #log-level = 0 #access-log = "access.log" #http-proxy-host = "127.0.0.1" #http-proxy-port = 8080 #http-proxy-exceptions = "127.0.0.1" #http-proxy-username = "user" #http-proxy-password = "password" #ssl-certkey-file = "mycertandprivkeyfile.pem" # Smsbox related #smsbox-port = 13001 #box-deny-ip = "*.*.*.*" #box-allow-ip = "127.0.0.1" #unified-prefix = "00358,0" #white-list = "http://127.0.0.1/white-list.txt" #black-list = "http://127.0.0.1/black-list.txt" #store-file = "kannel.store" # Wapbox related #wapbox-port = 13002 #udp-deny-ip = "*.*.*.*" #udp-allow-ip = "127.0.0.1" #wdp-interface-name = "*" # SMSC CONNECTIONS - GLOBAL FIELDS #group = smsc #smsc = #smsc-id = ID #denied-smsc-id = "X;Y" #allowed-smsc-id = "Z" #preferred-smsc-id = "W" #allowed-prefix = "040;050" #denied-prefix = "060;070" #alt-charset = # SMSC Nokia CIMD2 #group = smsc #smsc = cimd2 #host = #port = #smsc-username = #smsc-password = #keepalive = #sender-prefix = # SMSC EMI #group = smsc #smsc = emi2 #smsc = emi_ip to use the old implementation #host = #port = #smsc-username = #smsc-password = #device = /dev/ #phone = #our-port = #receive-port = #connect-allow-ip = #keepalive = #flow-control = # SMSC SMPP #group = smsc #smsc = smpp #host = #port = #receive-port = #smsc-username = #smsc-password = #system-type = #address-range = # SMSC SEMA #group = smsc #smsc = sema #device = /dev/tty0 #smsc_nua = (X121 smsc address) #home_nua = (x121 radio pad address) #wait_report = 0/1 (0 means false, 1 means true) # SMSC OIS #group = smsc #smsc = ois #host = 103.102.101.100 #port = 10000 #receive-port = 10000 #ois-debug-level = 0 # SMSC GSM #group = smsc #smsc = at #modemtype = wavecom | premicell | siemens | siemens-tc35 | falcom | nokiaphone | ericsson #device = /dev/ttyS0 #pin = 2345 #validityperiod = 167 # SMSC Fake #group = smsc #smsc = fake #host = #port = #connect-allow-ip = # SMSC HTTP #group = smsc #smsc = http #system-type = kannel #send-url = #port = #connect-allow-ip = #username = #password = # SMSBOX SETUP group = smsbox bearerbox-host = localhost sendsms-port = 13013 #sendsms-chars = "0123456789 +-" #global-sender = 12345 #log-file = "/tmp/smsbox.log" #log-level = 0 #access-log = "access.log" #white-list = #black-list = #reply-couldnotfetch = #reply-couldnotrepresent = #reply-requestfailed = #reply-emptymessage = # SEND-SMS USERS group = sendsms-user username = tester password = foobar #user-deny-ip = "" #user-allow-ip = "" # this sender is for Kannel relay testing (http_smsc) group = sendsms-user username = kannel password = rL4y user-deny-ip = "*.*.*.*" user-allow-ip = "127.0.0.1" #name = service_kannel #forced-smsc = ID #default-smsc = ID #faked-sended = #max-messages = 1 #concatenation = 1 #split-chars = #split-suffix = #omit-empty = #header = #footer = #allowed-prefix = #denied-prefix = #white-list = #black-list = # SMS SERVICES #group = sms-service #name = nothing #keyword = nop #aliases = "noppy;niente" #text = "You asked nothing and I did it!" #get-url = "http://" #post-url = "http://" #file = "/tmp/" #accepted-smsc = ID #allowed-prefix = #denied-prefix = #catch-all = false #send-sender = false #strip-keyword = false #faked-sender = #max-messages = 1 #accept-x-kannel-headers = false #assume-plain-text = false #concatenation = false #split-chars = #split-suffix = "+" #omit-empty = true #header = #footer = #prefix = #suffix = #white-list = #black-list = # SMS SERVICE GET-URL EXAMPLE #group = sms-service #keyword = relay #get-url = "http://localhost/service?phone=%p&text=%r&binary=%b&smsc=$i&time=%t # SMS SERVICE black-list #group = sms-service #keyword = black-list #text = "You are not alowed to use this service, Go away!" # SMS SERVICE Default # there should be default always group = sms-service keyword = default text = "No service specified" gateway-1.4.5/doc/examples/dlr-redis.conf0000644000175000017500000000170012316551250017001 0ustar toljtolj# # DLR with Redis support configuration # # Example defining a Redis database connection resource and # the required table and field values. # group = redis-connection id = redisdlr host = localhost port = 6379 #password = foo database = 0 # max count of connections that will be opened for dbpool # default is 1 max-connections = 1 group = dlr-db id = redisdlr # For Redis storage "table" is used as a key prefix for DLRs in the # format ::: (dst is not used on all smsc types). # It is also used as a key prefix storage of the number of pending DLRs # in the format
:Count. # If 'ttl' is set in seconds, then this is the time to live (TTL) for # a specific DLR entry in the keystore. (i.e. 7d = 60480s) table = dlr ttl = 604800 field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxc gateway-1.4.5/doc/ChangeLog-1.1.10000644000175000017500000002363707525470177014670 0ustar toljtolj2001-02-01 Richard Braakman * Making release 1.1.1. 2001-02-01 Uoti Urpala * gw/urltrans.c: Bugfix, find_default_translation() now returns NULL if no default was given. 2001-02-01 Richard Braakman * gw/smsbox.c: cleanup. send_message does not destroy its msg anymore, leaves that to caller (fixes memory leaks). obey_request always destroys the pattern it creates. obey_request_thread actually sends "Requests failed" messages and is simplified a little. 2001-02-01 Richard Braakman * gw/smsc_cimd2.c: Update to version 2-0 en. Added definitions for new parameter numbers 26, 28, 44, and 62. Corrected range of "status report request" parameter from 0..32 to 0..63. 2001-01-31 Uoti Urpala * gw/wap-appl.c: Fixed an uninitialized variable. * test/test_http_server.c: Fixed double octstr_destroy(). 2001-01-31 Richard Braakman * gwlib/octstr.c: Made octstr_destroy() call seems_valid even if the octstr is immutable. This should catch double destroy calls in the future. * gwlib/gwthread-pthread.c: In gwthread_wakeup() and gwthread_join(), assert that the thread number >= 0. 2001-01-31 Uoti Urpala * gw/bb_udp.c, gw/wap_push_ota.c: Fixed double octstr_destroy() calls. 2001-01-31 Uoti Urpala * gwlib/http.c: Don't try to wake up the server thread at shutdown if it was never created. 2001-01-31 Peter Grönholm * doc/userguide/userguide.xml: Wrote section 'Using pre-compiled binary packages'. 2001-01-31 Lars Wirzenius * gwlib/utils.c: Rewrote the is_allowed_ip implementation to use Octstr instead of C strings. Removed the now-unused check_ip function. * checks/check_ipcheck.c: Wrote. 2001-01-30 Lars Wirzenius * gwlib/utils.[ch]: Made is_allowed_ip accept Octstr arguments instead of char *. Dies, cstr, die. * gw/bb_boxc.c, gw/bb_http.c, gw/bb_udp.c, gw/smsbox.c, gw/smsc_emi.c, gw/smsc_fake.c: Fixed the calls to is_allowed_ip to follow new calling convention. 2001-01-30 Lars Wirzenius * Makefile.in: Moved the wildcard patterns to the beginning, where they are more visible. Should've done this when I first wrote them. * gw/smsbox.c: Fix memory leak. * gw/smsc_fake.c: don't call octstr_get_cstr with NULL argument. (Should fix is_allowed_ip instead.) * gw/urltrans.c: Look up the keyword in a case insensitive manner. Thanks to Peter for pointing this out. * gwlib/gwmem.h: Introduced the gw_claim_area_for macro. It is the same as gw_claim_area, except it gets the position as arguments, instead of figuring it out itself. * gwlib/cfg.[ch]: Used gw_claim_area_for to claim the return value of cfg_get. 2001-01-29 Richard Braakman * gwlib/dict.c: Make dict_keys() lock its dictionary. 2001-01-29 Kalle Marjola * Makefile.in: clean now deletes */*.o, too. 2001-01-29 Lars Wirzenius * gwlib/protected.h: Undefine the protection macros before defining them, to avoid problems with multiple definitions on platforms that define them as macros instead of (or in addition to) functions. 2001-01-26 Lars Wirzenius * gwlib/octstr.[ch], gw/smsbox.c: Killed the almost-unused function octstr_replace and converted the only place it was being used anymore to create a new Octstr instead. 2001-01-26 Lars Wirzenius * AUTHORS, ChangeLog, NEWS, checks/check_fakesmsc.sh, checks/check_fakewap.sh, checks/check_sendsms.sh, checks/check_smpp.sh, doc/arch/arch.xml, gw/bb_smscconn.c, gw/bearerbox,.c gw/smsbox.c, gw/smsc.c gw/urltrans.[ch], gw/wapbox.c, gwlib/http.c, gwlib/octstr. test/drive_smpp.c, test/test_http.c, test/test_octstr_format.c: Edited some long lines to be shorter than 80 characters. There's still lots more, find them with utils/find-long-lines. 2001-01-26 Lars Wirzenius * gw/alt_charsets.h, gw/bb.h, gwlib/accesslog.h, gwlib/gwlib.h, gwlib/gwmem.h, gwlib/socket.h, gwlib/utils.h, test/decompile.h, utils/OTAbitmap.h, utils/wbmp.h: Removed leading underscore from symbols. It is reserved to the C implementation and is not to be used by application code. * gwlib/socket.[ch]: Removed unused functions socket_query_blocking, read_line, and read_to_eof. * gwlib/utils.[ch]: Removed unused function print_std_args_usage. * gwlib/gw_inet.[ch], gw/wap_push_ota.c: Removed the (unused) gw_inet_ntop wrapper. 2001-01-26 Lars Wirzenius * doc/userguide/userguide.xml: Documented the "phone" option in EMI over modem. 2001-01-26 Lars Wirzenius * The standard library function inet_ntoa is not thread safe. Instead of writing a wrapper, I decided it's better to convert to using the gw_netaddr_to_octstr implementation Derek Hamilton wrote for us. * gwlib/protected.h: Added a macro to trap inet_ntoa calls. * gw/smsc_ois.c, gwlib/socket.c, test/test_cimd2.c: Converted use of inet_ntoa to gw_netaddr_to_octstr. * gwlib/socket.[ch]: Removed the unused function socket_get_peer_ip and slighly change the use of whitespace in the gw_netaddr_to_octstr to follow project coding style. 2001-01-26 Uoti Urpala * gw/urltrans.c: Converted to use octstr_create_urlcoded instead of file-specific function. 2001-01-25 Uoti Urpala * gw/smsc.c, gw/smsc_p.h, gw/smsc_fake.c, gw/smsc_fake2.c, gw/smscconn.c, gw/smscconn_p.h, test/fakesmsc.c, test/fakesmsc2.c: Removed the old fakesmsc and replaced it with the new one. Note that the new version is used differently from the old one! * gw/smskannel.conf, checks/check_fakesmsc.sh, checks/check_sendsms.sh: Changed the examples and checks to use new fakesmsc. * doc/userguide/userguide.xml: Changed the documentation to describe the new fakesmsc. * gw/smsc_cimd.c: Fixed a possible NULL reference. * gw/smsc_cimd2.c: Added a missing #include . 2001-01-25 Lars Wirzenius * gw/bb_udp.c, gwlib/cfg.def: Applied and adapted patch from Laurent Foulonneau to implement UDP packet filtering based on sender IP number. * doc/userguide/userguide.xml: Documented the new options. 2001-01-25 Lars Wirzenius * gw/smsc.c, gw/smsc_at.c, gw/smsc_p.h, gwlib/cfg.def: Applied and slightly adapted patch from Bjarne Saltbæk for implementing a validity period option for the GSM phone driver. * doc/userguide/userguide.xml: Documented the new option. 2001-01-24 Lars Wirzenius * doc/arch/arch.xml: Added missing . * gwlib/http.c: Added creation of http exceptions list. 2001-01-24 Uoti Urpala * gw/smsbox.c, gw/smsc.c, gw/smsc_p.h: Fixed memory leaks. 2001-01-24 Uoti Urpala * gw/smscconn.c, gw/bb_smscconn.c: Fixed memory leaks 2001-01-24 Lars Wirzenius * gw/bb_boxc.c, gw/bb_http.c, gw/bb_udp.c, gw/bearerbox.[ch]: Killed memory leaks due to unfreed configuration data. 2001-01-24 Uoti Urpala * test/fakesmsc2.c, gw/smsc_fake2.c: Several fake2 changes, added send/receive udh, possibility to restrict connections based on IP. Messages on command line need to be written differently. * gwlib/octstr.[ch]: Added octstr_create_urlcoded() function. 2001-01-23 Lars Wirzenius * Ran some compiles with stricter warning options than -Wall. This resulted in a few minor changes. * gw/bb_smscconn.c: Removed the function smsc2_addwdp, since it is unused and the wapbox is the better place to do WAP-on-SMS anyway. * gw/smpp_pdu.c: Cast the return value of octstr_len in an assert that compares it to an unsigned long. This is a bit ugly, but - in my humble opinion - better than a warning about comparing signed and unsigned. Reasonable minds differ. * gwlib/gwthread.h: Removed duplicate prototype for gwthread_dumpsigmask. * gwlib/socket.c: Made gw_netaddr_to_octstr4 and gw_netaddr_to_octstr6 static, since they're not to be used from outside socket.c. * test/decompile.c: Made a number of functions static. I don't understand why some functions are declared in decompile.h (or why decompile.h exists in the first place), but presumably there is a good reason for this. Removed the Read_zero_index function, since it was unused. * test/test_cimd2.c, test/test_headers.c, test/test_pdu.c, test/test_wakeup.c, test/udpfeed.c, utils/seewbmp.c: Use a return statement instead of calling exit. Stylistic change. * utils/run_kannel_box.c: Make main_loop return instead of calling exit directly. Stylistic change. 2001-01-23 Lars Wirzenius * doc/arch/arch.xml: Fixed references to figures. 2001-01-23 Lars Wirzenius * gw/bb_boxc.c, gw/bb_smscconn.c, gw/bb_udp.c, gw/bearerbox.[ch], gw/smsc.[ch], gw/smsc_emi.c, gw/smsc_fake2.c, gw/smsc_p.h, gw/smsc_wrapper.c, gw/smscconn.[ch], gw/smscconn_p.h: Converted the bearerbox to use the new configuration file interface. This resulted in large, but simple changes in many files. * gwlib/cfg.def: Added variable 'phone' to an smsc group. Not documented anywhere, it seems. * gwlib/gwlib.h, gwlib/conffile.[ch]: Removed the old configuration file interface. 2001-01-23 Lars Wirzenius * gwlib/cfg.c: Implemented a check that makes sure a CfgGroup is only queried for variables that it can legally contain. This showed some bugs, which have been corrected by the changes below. * gwlib/cfg.[ch]: Wrote function cfg_get_group_name, needed by urltrans.c changes. * gw/urltrans.c: Fixed the code so it doesn't try to get the value of every variable from every group. The resulting code should be somewhat cleaner and easier to follow, as well. * gw/wapbox.c: Don't query the variable "heartbeat-freq", because it isn't documented anywhere, no other box uses it, and there is no need to make the value configurable. 2001-01-23 Kalle Marjola * gw/bearerbox.c: switched smsbox/smsc startup to avoid hangup with bad luck gateway-1.4.5/doc/ChangeLog-1.1.30000644000175000017500000002463207525470177014666 0ustar toljtolj2001-03-20 Richard Braakman * Making release 1.1.3. 2001-03-19 Tuomas Luttinen * gw/wml_compiler.c: Fixed a warning. * checks/check_compiler.sh: A simple script added that takes a WML source, runs it through the WML compiler and the decompiler and diffes the original file to the output and reports an error if they do differ. * test/testcase.wml: A testcase for the check_compiler added. 2001-03-19 Uoti Urpala * gw/smsc_http.c: Shutdown state was not initialized. Fixed. 2001-03-19 Richard Braakman * gwlib/http.c: Made parse_http_version() thread-safe. (There is no guarantee that assignment of pointers or longs is atomic.) 2001-03-19 Kalle Marjola * gw/bearerbox.c: commented gwthread_join_all() away and now all checks pass. Have to investigate this more... 2001-03-19 Richard Braakman * wap/wsp_session.c: Fix TR_Invoke_Cnf case in find_session_machine(), spotted by zig cats. 2001-03-19 Kalle Marjola * doc/userguide/userguide.xml: added HTTP SMSC chapter * gw/smskannel.conf: added sms-service and send-sms for relay use * gw/other_smskannel.conf: Added. For client Kannel in Kannel relay tests * gw/smsc_http.c: little bugfizes/updates * checks/check_httpsmsc_kannel.sh. Added. Note that currently there is a BUG in gwlib/http.c and/or gw/smsc_http.c and this tests always FAILS as client bearerbox (using other_smskannel.conf) never exits (HTTP client side thread does not die?) 2001-03-19 Kalle Marjola * gw/http.c: Bugfix. Make shutdown work for multiple servers 2001-03-19 Kalle Marjola * gw/smsc_http.c: Added. New module to handle HTTP based SMS Center connections or other gateways (relay gateways). Currently only supports 'kannel' as relay gateway * gw/smscconn.c, gw/smscconn_p.h: modified to understand new SMSCConn type * gwlib/cfg.def: accept new configuration variable 'send-url' used with smsc_http 2001-03-19 Kalle Marjola * gwlib/utils.c|h: added new function connect_denied(..), which is like the old is_allowed_ip(..) except that deny-ip is no longer used as it is expected to be "*.*.*.*" and no allow-ip means localhost. This function will hopefully eventually replace all old ip-checkings, to tighten basic security 2001-03-19 Kalle Marjola * gw/bb_smscconn.c (sms_router): Bugfix. Now hopefully router does not get stuck again if the list is successfully emptied 2001-03-16 Kalle Marjola * gwlib/http.c: Bugfix: wakeup server when new port added, so that it is added to select 2001-03-16 Tuomas Luttinen * test/decompile.c (DTDTypeList): Added the URLs for those DTDs whose URL was easily located. * test/decompile.c (Read_termstr_rtn): Bug fix: double the dollar signs, since dollar is escaped as $$ in WML. 2001-03-16 Nick Clarey * gw/smsc_at.c: Repaired a bug in at_reopen which would cause failed smsc_at connections to be reopened continuously, and repaired a bug in at_close which could possibly cause memory leakage. Also fixed bugs in both which didn't reset the smsc's file descriptor correctly in case of failed closes. 2001-03-16 Tuomas Luttinen * gw/wml_definitions.h: The WBXML_CHILD_BIT was changed into WBXML_CONTENT_BIT for clarity. * gw/wml_compiler.c (only_blanks): A patch provided by Bernard Valton that prevents white space counted as element content. Also changed the WBXML_CHILD_BIT into WBXML_CONTENT_BIT for clarity. 2001-03-16 Richard Braakman * gw/wap-appl.c: Fixed memory leak of request_headers in request_data. Made return_result not destroy the WAP event passed to it (caller should do that). Memory management in this file is still icky. * gw/wapbox.c: Always destroy a msg after processing it, this fixes a memory leak handling admin messages. 2001-03-16 Kalle Marjola * gwlib/octstr.h|c: added %E to octstr_format, which takes an Octstr and URL-encodes it into string * test/test_octstr_format.c: added test for that format 2001-03-16 Richard Braakman * When logging errors, do not report errno if it's not relevant. Fixed 25 counts of this, leaving 81 valid uses. * Updated NEWS file to prepare for 1.1.3. * test/test_http_server.c: Run client_thread in a separate thread. This makes check_http.sh not fail. (sigterm was calling http_close_all_ports while the main thread itself was in port_get_request). 2001-03-15 Uoti Urpala * test/test_smsc.c: Fixed a memory allocation bug. 2001-03-15 Tuomas Luttinen * test/wml_tester.c: I refined the command line arguments a bit. Now the output is either a normal dump, the dump with source or the binary only. The output can be directed into a file that can then contain the binary only if that was the selected output. * test/decompile.c: Now decompiler accepts input from stdin. Added for piping to make writing tests easier. 2001-03-15 Lars Wirzenius * Changed the HTTP server side code so that it allows easily processing requests to different ports in different ways. * gwlib/http.[ch]: Renamed http_open_server to http_open_port, and http_close_all_servers to http_close_all_ports, since the concept of "server" is a bit confusing when used this way. Port is clearer. * gwlib/http.[ch]: Added port argument to http_accept_request so that the caller can specify which port she's interested in. This then required some changes in the internals of http.c because the clients_with_requests list had to be replaced with port specific lists, and this required some inter-thread communication, which was a bit tricky to get working (and it therefore likely to be buggy in non-obvious ways). Also added new function, http_close_port, to allow closing only a specific port. * gw/bb_http.c, gw/smsbox.c, test/drive_wapbox.c, test/test_http_server.c, test/test_smsc.c: Changed calls to http code based on interface code. 2001-03-15 Uoti Urpala * gwlib/http.c, gwlib/http.h: Changed http_start_request and http_receive_result to identify the request with a void pointer from the caller. * gw/smsbox.c, gw/wap-appl.c, test/test_http.c: Related changes. 2001-03-13 Lars Wirzenius * benchmarks/bench_sms.sh: Only plot the "submit" events; in long runs, the different graphs were on top of each other anyway. 2001-03-13 Lars Wirzenius * Various improvements to "make bench". * benchmarks/bench_http.sh, benchmarks/bench_sms.sh, benchmarks/run-benchmarks: Implemented --fast option. * benchmarks/functions.inc: Isolated common script stuff into a single file to make maintenance easier and scripts clearer. * test/test_smsc.c: Measure round trip times for requests and replies. Started coding "sustained level" benchmark; not useable yet, though. * gwlib/http.c: Commented out unused static functions. 2001-03-12 Uoti Urpala * gw/smsc_fake.c: Added test for errno == EINTR after gwthread_pollfd(). 2001-03-07 Derry Hamilton * mk-solaris-package.sh, prototype.tmpl, prototype: modified mk-solaris to create packages with the actual version rather than just assume that it is cvs. Modified prototype to be prototype.tmpl and mk-solaris now uses it to generate the correct prototype. 2001-03-05 Lars Wirzenius * benchmarks/bench_http.sh: Removed unnecessary cruft. Set number of HTTP requests made to 100 000 instead of 1000. * benchmarks/bench_http.txt, benchmarks/bench_sms.txt, benchmarks/report-begin.txt: Added missing . * benchmarks/bench_sms.sh: Set number of requests to 100 000 instead of 1000. * gwlib/http.c: Disabled re-use of TCP connections for HTTP transactions. There is a bug somewhere that makes this crash. * test/test_http.c: Allow client to queue multiple requests into a queue (up to MAX_IN_QUEUE #define in test_http.c), instead of doing the next one only after the response to the previous one has finished. 2001-03-01 Uoti Urpala * gw/smsbox.c: Added a temporary half-fix for a bug that could cause NULL references with sms-service HTTP requests. Has to be fixed properly later. 2001-03-01 Lars Wirzenius * test/test_http.c: Reformatted to follow current coding style. 2001-03-01 Lars Wirzenius * Implemented the beginnings of a framework for automated benchmarks. * Makefile.in: "make bench" now runs the automated benchmark. "make clean" removes the cruft. * benchmarks/.cvsignore, benchmarks/bench_http.sh, benchmarks/bench_http.txt, benchmarks/bench_sms.sh, benchmarks/bench_sms.conf, benchmarks/bench_sms.txt, benchmarks/report-begin.txt, benchmarks/report-end.txt, benchmarks/run-benchmarks: Wrote. * test/test_smsc.c, test/timestamp.c: Wrote. * test/test_http_server.c: Added option -l for setting logfile name. 2001-03-01 Kalle Marjola * gw/bb_boxc.c, gw/shared.c: Fix, modified so that error in read causes connection to be broken, instead of possible trap in infinite loop. Pointed out by Paul Keogh. 2001-03-01 Uoti Urpala * gwlib/http.c: Don't panic or crash if request contains spaces. 2001-02-28 Kalle Marjola * gw/bb_udp.c: 'bugfix': modified so that all errors just make receiver to continue, instead of exiting loop 2001-02-28 Richard Braakman * gw/smsc_at.c: Made pdu_extract deal with the SMSC address field possibly being bad or too short. Also made hexchar() take an int as argument, instead of char (which might be signed). toupper() is defined as taking an int, anyway. 2001-02-27 Kalle Marjola * gw/drive_smpp.c: modified to accept Msg 'admin', too * gw/bb_boxc.c: unused variable removed 2001-02-27 Kalle Marjola * gw/bb_boxc.c: Modified to use Conn instead of raw TCP/IP with sms|wapbox connections * gw/msg[-decl].h: added new message type 'admin' for shutdown/suspend use. * gw/smsbox.c: modified to die when shutdown command received. Needs to implement suspend/shutdown, still * gw/wapbox.c: modified to die when shutdown command received and to ignore non-wdp messages * gwlib/octstr.h|c: removed now non-used octstr_send and octstr_recv 2001-02-27 Richard Braakman * Ran spelling check over userguide.xml. gateway-1.4.5/doc/ChangeLog-1.1.60000644000175000017500000024307410203150325014645 0ustar toljtolj2002-03-28 Stipe Tolj * Re-Making release 1.1.6. 2002-03-27 Bruno Rodrigues * gw/smsc_at2.c: small fix 2002-03-27 Bruno Rodrigues * doc/userguide/userguide.xml: changed at2 speed information 2002-03-27 Bruno Rodrigues * test/test_http_server.c: Disable SSL checking if #SSL is disabled in configure * NEWS, Changelog: some minor fixes ;) * gw/smsc_at2.[ch]: changed speed behaviour. If speed is unset in smsc group, kannel try to use modem->speed and if it fails, autodetects 2002-03-27 Bruno Rodrigues * gwlib/http.c: Disabled keepalive until someone fixes it for good 2002-03-27 Stipe Tolj * test/test_http_server.c: included SSL support for HTTP test server 2002-03-27 Stipe Tolj * config*, wap/cookies.[ch], gw/wap-appl.c: revised the cookie support for WSP and added --enable-cookies configure option. 2002-03-27 Stipe Tolj * gwlib/cfg.c: fixed release showstopper from previous multiple include fix from Bruno. 2002-03-26 Stipe Tolj * Making release 1.1.6. 2002-03-26 Stipe Tolj * Updated NEWS to prepare for 1.1.6. 2002-03-26 Bruno Rodrigues * gwlib/cfg.c: fixed bug when including several include files * gw/urltrans.c: added seconds to "%t" 2002-03-26 Stipe Tolj * checks/check_ppg.sh: checking test_http_server output seems not necessary in this case and more verbose error output 2002-03-26 Stipe Tolj * gw/smsc_emi2.c: fixing timestamp issue for the 0-based months, now conversion function gets the right value 2002-03-26 Stipe Tolj * checks/check_[fakesmsc|pph].sh: need some time before trying to grep around in the logs and decide if things are doing well 2002-03-26 Stipe Tolj * gw/pushkannel.conf: adjusted log-file entries for make checking 2002-03-26 Stipe Tolj * gwlib/date.c: bounced back to rev 1.8 to satisfy "make -s check" run in preparation of new release 2002-03-26 Stipe Tolj * gw/dlr.c: fixed another kannel-nag warning about unused vars in dlr_find_mysql() 2002-03-25 Stipe Tolj * gwlib/octstr.c: added support for Linux on PowerPC and S390 architectures, patch submitted by "Jacob Vennervald Madsen" [Msg-ID: ] 2002-03-25 Stipe Tolj * gw/dlr.c: fixed kannel-nag compile warning in dlr_find_mysql() 2002-03-24 Stipe Tolj * gw/dlr.c: fixed SQL statement in dlr_flush() for MySQL storage 2002-03-24 Stipe Tolj * gw/bearerbox.[ch], gw/dlr.c: fixed the way mutex are locked for flushing the DLR queue 2002-03-24 Stipe Tolj * gw/bb_http.c, gw/bearerbox.c, gw/dlr.[ch], doc/userguide/userguide.xml: added '/flush-dlr' HTTP administration command to flush the DLR queue 2002-03-24 Stipe Tolj * gw/bearerbox.c, gw/dlr.[ch]: added DLR information to the status page 2002-03-24 Stipe Tolj * gw/dlr.c: added octstr_get_cstr() wrapping for global Octstr* of the SQL statements 2002-03-24 Stipe Tolj * gw/dlr.c: removed call to mysql_get_proto_info() 2002-03-24 Stipe Tolj * gw/dlr.c: fixed a typo in dlr_init() from the previous commit. 2002-03-24 Stipe Tolj * gw/dlr.[ch]: restructuring the DLR MySQL support to fit the new general MySQL connection configuration sections. * gwlib/cfg.def: changed config directives to support general MySQL connections using 'mysql-connection' groups and added 'dlr-storage' type indicator to core group. * configure[.in], aclocal.m4: added mysql-4.x detection routine, changed --enable-mysql-dlr to --with-dlr[=TYPE] to support general DLR storage types, re-arranged configure groups, beautified configure ouput * doc/userguide/userguide.xml, doc/dlr-mysql.conf: added documentation about the new general MySQL connection groups and the specific definitions for external DLR storage support. 2002-03-22 Stipe Tolj * gw/smsc_at2.[ch]: splitted .c to header and source file, run through astyle and edited both by hand. 2002-03-22 Stipe Tolj * gwlib/cfg.def, gw/smsc_smpp.c: added manual NPI and TON defining support via configuration directives, patch by Alex Judd [Msg-ID: ] 2002-03-22 Stipe Tolj * doc/modems.conf, doc/userguide/userguide.xml, gw/smsc_at2.c, gwlib/cfg.def: added SIM buffering pool patch, contributed by Oded Arbel , forwarded by Andrea [Msg-ID: <20020321103746.QED1149.fep31-svc.tin.it@[127.0.0.1]>] 2002-03-22 Stipe Tolj * gw/smsc_at2.c: fixed timestamp issue in at2, patch contributed by Oded Arbel [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B166E88@exchange.m-wise.com>] 2002-03-22 Stipe Tolj * doc/userguide/userguide.xml, gw/smsc_smpp.c, gwlib/socket.c: added support for multi-homed bearerbox machines to select outgoing ethernet device, patch contributed by Simon Beale [Msg-ID: <006801c1d101$86f525f0$c80a0a0a@ngame.com>] 2002-03-21 Stipe Tolj * gw/smsc_cgw.c: bug and stability fixes, patch contributed by "Anders Lindh" [Msg-ID: <002401c1d039$7a92f850$8078a8c0@alindh>] 2002-03-21 Bruno Rodrigues * gw/smsbox.c: Fixed sms.service display in bearerbox_access.log: it were only displayed in get/post url, not in text * gw/urltrans.[ch], gwlib/cfg.def: added default-sender to sendsms-user to be used if from field is unset and per-user * doc/userguide/userguide.xml: added default-sender information * doc/userguide/userguide.xml: Added an id parameter to a section title, to fix the link warning * gw/smsbox.c: Added X-Kannel-SMSC to smsbox -> appl HTTP POST 2002-03-20 Stipe Tolj * gw/smsc_at2.c: fixed compiler warning 2002-03-19 Bruno Rodrigues * gw/smsc_at2.c: fix warning 2002-03-17 Bruno Rodrigues * doc/modems.cfg: Changed T68 initstring * doc/modems.cfg, gw/smsc_at2.c: Added broken boolean value to handle Ericsson T68 brokenness. Probably will be removed when I or somebody else talk with Ericsson and understand what happened with that phone. Behaviour: accept +CMT: without ","; compare the +CMT value with the the full string length, instead of ony the PDU part. (There's still missing the +CNMA response that I cannot send to this mobile) * doc/userguide/userguide.xml, gw/smsc_at2.c: changed alt-dcs to boolean * gw/smsc_at2.c: reset keepalive time when sending a message * gw/smsc_at2.c: fix keepalive initialization when keepalive is not defined in configuration * gw/smsc_at2.c: fix panic when not autodetecting. I really thought that octstr_destroy would set the octstr to null * gw/smsc_at2.c: fix autodetect_modem to read every modem group (i=1) * gw/smsc_at2.c: at2_read_modems won't output some debugs when using idnumber (autodetect), because at2_detect_modem do the output * gwlib/cfg.def: fix a small memory leak * gw/smsc_at2.c: removed checks from cfg_get_bool, because it always sets the value to 0 or 1 * gw/smsc_at2.c: fix parsing alphanumeric sender when receiving message * gw/smsc_at2.c: activate +MMS (More Message to Send) when there's more than one message to send 2002-03-14 Bruno Rodrigues * gwlib/cfg.[ch]: added cfg_get_configfile to return the config filename of the Cfg grp we are using; fixed a small glitch * gwlib/cfg.def: added modems multi-group variables * doc/modems.conf: added a default configuration with modem definitions, the same values that were hard-coded in smsc_at2. Should be included in main kannel.conf, using include = "modems.conf" * gw/smsc_at2.c: removed hard-coded modem definitions and added reading the modems.conf groups included in kannel.conf * doc/userguide/userguide.xml: added information for modems group 2002-03-14 Bruno Rodrigues * gw/smsc_emi2.c: force sending a UCP-31 after login (thus reseting the last_activity_time) - sometimes emi2 login and don't send keepalives, specially if it can't connect at the first time 2002-03-14 Bruno Rodrigues * gw/smsc_emi2.c: added a missing octdestroy and changed dcs encoding behaviour: if dcs equals to default + 8bit, we don't need to add a DCS in XSER, the MCLs=1 is enough (Should fix complaint from Avner Sternheim ) 2002-03-13 Bruno Rodrigues * gw/smsc_at2.c: fixed a bug when keepalive field is undefined 2002-03-13 Jörg Pommnitz * fix AT2 to work with Wavecom modem again. This should not hurt anything else. 2002-03-12 Bruno Rodrigues * gw/smsc_at2.c: fixed a typo, removed ceil function and fixed len in alphanumeric text 2002-03-12 Bruno Rodrigues * gw/smsc_at2.c: increased timeout when sending the +CPIN? command; added a colon to +CMT so kannel doesn't interpret +CMTI; added alphanumeric sender interpretation to received messages; added interpretation of international sender to received messages, adding a '+' on it; added setting pid field in message received; 2002-03-09 Bruno Rodrigues * gw/smsc_emi2.c, gwlib/cfg.h: fixed some compilation warnings 2002-03-08 Andreas Fink * gw/smsc_at2.c: fixed a bug for +CPIN which wasnt waiting for OK after +CPIN answer. This was screwing up AT command answers and Siemens TC35 couldnt get initialized anymore. 2002-03-08 Bruno Rodrigues * doc/userguide/userguide.xml: added mysql config information from Oded Arbel patch [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B166DF5@exchange.m-wise.com>] 2002-03-08 Bruno Rodrigues * gwlib/cfg.h: removed two warnings 2002-03-08 Bruno Rodrigues * gw/bearerbox.c, gwlib/cfg.def: Added mysql-* configuration variables to define the hostname, user, password and database name (It's still missing documentation about mysql) - Oded Arbel Patch * gw/emimsg.c, gw/emimsg.h, gw/smsc_at2.c, gw/smsc_emi2.c: Uniformization of log files: now AT2 and EMI2 always say "AT2[name]: something" and "EMI2[name]: something". * gw/smsc_emi2.c: Added name to privdata. Name is equal to smsc-id or, if undefined, is [[our-host|kannel]:[our-port|*]->]host:port. (Sorry for passing "whoami" Octstr through some functions, but later we should remove all debug() from them and only debug() at the parent and make all function "childs" return -1 or something) * gw/smsc_at2.c: Added name to privdata. Name is equal to smsc-id or, if undefined, is device-name as before * gw/smsc_emi2.c, gwlib/cfg.def: Added our-host configuration value to define kannel local ip * gw/smsc_emi2.c, gwlib/cfg.def: Added alt-host and alt-port configuration value. If main connection fails, emi2 switch to a alternate connection. Both are optional and emi2 defaults to original host/port. (ex: if our_port is undef, emi2 switches to alt-host:port) (should be used with retry = true) * gw/smsc_emi2.c: Always set status=RECONNECTING on entering open_send_connection and status=ACTIVE on successful connection * gw/smsc_emi2.c: Don't set why_killed=SMSC_KILLED_PASSWORD when retry is true, because emi2 won't be really killed * gw/smsbox.c: Added octstr_destroy to sendsms_url and sendota_url * gw/urltrans.c: Added %u value to sms-service, dumping UDH * gwlib/cfg.def: Fixed a bug in Stipe Tolj patch that were creating a new Octstr for each config line read * gw/http.c: Added a new header to kannel "httpd": "Server: Kannel-VERSION" * doc/userguide/userguide.xml: added a missing 2002-03-07 Andreas Fink * gw/smsc_http.c: Made kannel accept a more structured reply besides "Sent". Used by some sms aggregators. 2002-03-07 Stipe Tolj * gw/wap_push_ppg.c, test/test_ppg.c, wap/wsp_strings.def: corrected MMS related well known values and stuff that is required to use the PPG part for the M.notification-ind processing. 2002-03-07 Stipe Tolj * gw/cfg.[ch]: implemented inclusion feature for configuration file processing. Now you may use 'include = "foobar.conf"' anywhere in the config file to include sub-configuration parts. * doc/userguide/userguide.xml: added section which describes the new 'include' configuration directive. 2002-03-03 Bruno Rodrigues * gw/smsc_emi2.c: keepalive time is now only updated after sending an operation 51 or the keepalive itself * doc/userguide/userguide.xml: added my-number information to at2 group * gw/smsc_emi2.c: added my-number configuration to emi2. Sometimes, the large account number is not the same as the short number. * doc/userguide/userguide.xml: added my-number information to emi2 group * gw/msg-decl.h, gw/smsbox.c, gw/urltrans.c: added charset field to message. If undefined, kannel should assume default charsets by looking at coding value * gwlib/cfg.def, gw/smsbox.c: added mo-recode boolean value to ask smsbox to try to recode a UCS2 received message to iso-8859-1. * gw/smsbox.c: commented the debug lines in charset_processing. It works, we don't need them anymore * gw/urltrans.c: added variables %c for coding and %C for charset * gwlib/octstr.c: added check to avoid converting from utf-8 to utf-8 * doc/userguide/userguide.xml: added mo-recode information to smsbox group, and %c and %C information 2002-03-03 Bruno Rodrigues * gw/smsc_at2.c: applied sms-center configuration for at2, based on patch privided by Oded Arbel [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B166D5E@exchange.m-wise.com>] * gw/smsbox.c: fixed a panic when text is empty and kannel try to print it * gw/smsc_at2.c: set keepalive to 0 if not defined in configuration; close device after auto-detecting modem; return ok(4) when receive the +CPIN:READY reply * gw/smsc_at2.c, gw/smsc_emi2.c: set retry to 0 if not defined in configuration 2002-02-25 Bruno Rodrigues * contrib/web/*: Added a form and a php file to send messages. Includes text, mwi, NSM, Wap related and Siemens MMC. There's still some portuguese strings in it and it misses to java applets, but it's usable. I just hope that there's no problem with copyrights... .(and yes, you can send a mp3 via sms to a Siemens SL45i) 2002-02-25 Bruno Rodrigues * Changelog: fixed spaces in my last entries. * gw/smsc_at2.c: fixed a bug introduced by my last patch that even on successful modem connection, kannel would still stay inside the connection cicle (a missing "break" command). * gw/smsc_at2.c: Changed a possible bug. On timeout, at2_wait_modem_command returned -10, and every other line shows that it should be -1; * gw/smsc_at2.c: When auto-detecting speed, try 57600 too (if defined) Siemens SL45 only uses 57600. :) * gw/msg-decl.h, gw/smsbox.c, gw/smsc_emi2.c, gw/smsc_at2.c: added pid http argument. Pid is used to send Sim Toolkit Messages. A get like: ...&pid=127&coding=2&alt-dcs=1&mclass=3 passes without error on emi but not yet on at2. (I'm checking on that) * gw/msg-decl.h, gw/smsbox.c, gw/smsc_emi2.c, gw/smsc_at2.c: added alt-dcs http argument. Like the configuration variable in AT2, this is used to force the 0X or FX kind of DCS when sending the message. (Fixes a bug when sending flash messages to old mobiles). * gw/smsc_at2.c: Added my-number configuration variable, so the message appears in logs with the correct number instead of "1234" * gw/smsc_at2.c: Added keepalive configuration variable. From this many seconds, kannel sends an AT command and if it fails, reconnect to the modem (We could later use other command instead of a simple AT, to check if we are still connected to the GSM Network :) ) * doc/userguide/userguide.xml: Added pid, alt-dcs and at2-keepalive info; Separated at and at2 in feature tables 2002-02-23 Stipe Tolj * gw/smsc_emi2.c: removed unused variable `retry' to make kannel-nag script happy again. 2002-02-22 Bruno Rodrigues * gw/smsc_emi2.c, gw/smsc_at2.c, gwlib/cfg.def: Added retry configuration boolean value to force these to smsc to always try to reconnect. The idea is that if the connection went ok once, it should retry it. Example: M20 sometimes don't start. EMI with multiple smsc's or a bad terminated connection could reply with a "Too many sessions". * gw/smsc_at2.c: In initialization, the modem could be probbed for speed and modemtype. Changed code to exit or retry if one of these fail; in detect_speed, if every speed probe fail, speed would be 0. Now it returns an error * doc/userguide/userguide.xml: added retry configuration information 2002-02-22 Bruno Rodrigues * gw/smsbox.c: fixed a bug when reply_requestfailed message was used, because the memory wasn't duplicated and is deleted later 2002-02-21 Stipe Tolj * gw/smsc_at2.c: fixing memory leak reported by: "Oded Arbel" [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B166D80@exchange.m-wise.com>] * gw/smsbox.c, gwlib/http.c: fixing memory leaks reported by: "Nektarios K. Papadopoulos" [Msg-ID: <3C73F986.58353A9F@inaccessnetworks.com>] 2002-02-20 Stipe Tolj * gw/smsc_at2.c: fixing a list_search() mistake reported by: "Nektarios K. Papadopoulos" [Msg-ID: <3C72B61A.1BC22DD7@inaccessnetworks.com>] 2002-02-20 Stipe Tolj * gwlib/conn.c: fixing mutex race condition in conn_register() suggested by: Uoti Urpala [Msg-ID: <3C724267.1040508@netikos.com>] 2002-02-20 Stipe Tolj * gwlib/conn.c: fixing major bug in poll_callback() that caused heavy CPU cycling impact on Linux and system error on Solaris and Cygwin while handling the poll in/out. suggested by: Uoti Urpala [Msg-ID: <3C724267.1040508@netikos.com>] 2002-02-18 Stipe Tolj * gw/smsbox.c: fixed bug in smsbox_req_sendota() reported by Peter Löfman [Msg-ID: <004e01c1b32b$98c8b2e0$9d0a70c2@mtel.mtel.aland.fi>] 2002-02-12 Andreas Fink * gwlib/octstr.c: removed annoying info message for making gwlib be better usable for command line tools. 2002-02-10 Stipe Tolj * gw/smsc_ois.c: removed unused ois_convert_from_iso88591() for the sake of kannel-nag 2002-02-08 Stipe Tolj * gw/smsc_at2.c: added Alcatel support as AT GSM modem SMSC submitted by: Olivier Durécu [Msg-ID: <3C63AA61.7000208@ms.alcatel.fr>] 2002-02-07 Stipe Tolj * gwlib/octstr.c: removed unused variable from octstr_read_pipe() in order to make kannel-nag run happily. 2002-02-07 Stipe Tolj * doc/userguide/userguide.xml: added documentation for "exec" sms-service * gwlib/cfg.def: added "exec" translation type to sms-service multi * gwlib/octstr.[ch]: added function octstr_read_pipe() to read everything from a file descriptor to an octstr. * gw/smsbox.c: added translation type TRANSTYPE_EXECUTE and the corresponding popen() logic to execute shell commands for sms-services. * gw/urltrans.[ch]: added translation type TRANSTYPE_EXECUTE 2002-02-07 Stipe Tolj * STATUS: added Oded Arbel's fix for timestamp issue in at2 * gw/smsc_ois.c: Applied patch for handling 7bit encoded messages submitted by: Oded Arbel [Msg-ID: <1013025181.2798.3.camel@preceptor.m-wise.co.il>] 2002-01-31 Stipe Tolj * gw/bearerbox.c, gw/smsbox.c: added SIGQUIT signal handling in signal_handler() to call gw_check_leaks() like in gw/wapbox.c. 2002-01-31 Stipe Tolj * gw/smsbox.c: applied missinc forced-smsc patch for sendota service in smsbox_req_sendota(), sumbited by Indrek Mandre [Msg-ID: ] 2002-01-31 Andreas Fink * gwlib/gwlib.h: included string.h to avoid compilation warnings 2002-01-29 Stipe Tolj * STATUS: added Alex Judd's smsc_smpps.c TON patch and added an open issue for re-connect trying of smsc_emi2.c * gw/smsc_smpp.c: Applied patch for checking host config directive submited by Alex Judd [Msg-ID: ] Applied patch fixing timestamping of messages submited by "Angel Fradejas" [Msg-ID: ] 2002-01-29 Stipe Tolj * gwlib/thread.c: minimal debug output change in mutex_unlock_real() to be of same style as others. 2002-01-29 Stipe Tolj * STATUS: added file to hold any relevant information about open issues, release showstoppers and patches that have been proposed and have to be reviewed. Any CVS commiter may grap open issues and work on this, please update status information as frequently as possible to hold this file up to date. 2002-01-29 Stipe Tolj * gwlib/conn.c, gwlib/thread.[ch]: revised Andreas changes for the debugging code of mutexes to be more gwlib/gwassert.h style. This should help in reading the logs more cleanly. 2002-01-28 Andreas Fink * gwlib/thread.c/h: some debugging code for Mutex problems. seems to fix a problem on solaris for no obvious reasons 2002-01-28 Andreas Fink * gw/smsc_smpp.c: fixed SMPP for unicode sending * gwlib/conn.c: reported better where mutex fails 2002-01-28 Stipe Tolj * gw/bb_udp.c: bind to WTLS ports 9202 and 9203 only in case we have HAVE_WTLS_OPENSSL defined, otherwise kwtls may be used to bind to those. * gw/shared.c: added WTLS reporting in version_report_string() 2002-01-28 Stipe Tolj * configure{,.in}: modified --with-wtls implementation to be more --with-ssl style and moved it to the end. * gw/pki.[ch], gw/wapbox.c, wtls-secmgr.c, wtls.c, wtls_pdu.c, gw/wtls_pdusupport.c, wtls_statesupport.c: make at least the whole thing compile and build using --with-wtls=openssl. 2002-01-27 Stipe Tolj * gw/smsbox.c: added multi-cast support in smsbox_req_handle(), see [Msg-ID: <3C45F6E8.F677C8D1@wapme-systems.de>] 2002-01-27 Stipe Tolj * gw/wap_ota_prov.h: moved to gw/ota_prov_attr.h and added MMSURL type * gw/ota_prov.c, gw/smsbox.c: changed header include to ota_prov_attr.h. * gw/ota_compiler.c: added MMSURL type. 2002-01-27 Stipe Tolj * gw/ota_prov.[ch]: fixed typo in ota_tokenize_bookmarks(). Removed static function declarations from header file. 2002-01-27 Stipe Tolj * doc/userguide/userguide.xml: updated SMPP documentation for port = 0 * gw/smsc_smpp.c: applied patch to allow disabling of SMPP threads, using values for the ports, suggested by Nisan Bloch [Msg-ID: <5.1.0.14.0.20020117224637.00a845b0@amagoblin.ialien.co.za>] 2002-01-27 Stipe Tolj * gwlib/date.c: applied fix to solve date_convert_universal() misbehaviour, suggested by "Angel Fradejas" [Msg-ID: ] 2002-01-27 Stipe Tolj * doc/userguide/userguide.xml: added 'ota-bookmark' documentation 2002-01-27 Stipe Tolj * Incorporated a patch for fixing GSM 7 bit escape issue, submited by "Oded Arbel" [Msg-ID: <2CFC21DAF860CC49AF57333C4459DD4B166D19@exchange.m-wise.com>] * gw/shared.c: added extract_msgdata_part_by_coding() * gw/sms.[ch]: added sms_msgdata_len() * gw/smsc_at2.c: using sms_msgdata_len() now for length calculation 2002-01-26 Stipe Tolj * doc/userguide/userguide.xml: Updated changes to OTA documentation * gw/ota_prov.[ch]: Added OTA provisioning routines in an own module so we keep smsbox.c more clean from those. Fixes a bug in ota_tokenize_settings(), previously in smsbox_req_sendota() which did not set PPP authentication and WTLS flags accordingly. Seems the logic for the two parameters have been swapped. * gw/smsbox.c: harmonized the literal names for the two options in sending OTA messages, via Aarno's OTA xml compiler or via the configuration groups in the config file. The 'otaconfig' group has changed to 'ota-setting' group so we have the same "terms" for both methods. *** BEWARE: this breaks backward compatibility with the previous gw/cfg.def rules for 'otaconfig' groups! *** Added 'ota-bookmark' group logic to smsbox_req_sendota(). * gwlib/cfg.def: changed declaration of 'otaconfig' group to 'ota-setting' group to be harmonized with the OTA compiler CGI type names and added 'ota-bookmark' group for OTA bookmarks. 2002-01-25 Aarno Syvänen * gw/ota_compiler.[ch]: Added compiler for XML OTA configuration documents * test/test_ota.c: Added a test program for it * gw/settings.dtd: Added a DTD for OTA compiler * test/test_http.c: Better debugging. Added an option for reading the test message from a file; useful when it contains lots of unsafe characters * gwlib/charset.c: In function charset_to_utf8: If the original charset is utf8, return immediately (to still an annoying error message) * gw/wap_push_pap_compiler.c: Remove one use of string library (we should use octstr instead). Updated the interface comment. * test/test_pap.c: Added test program for pap compiler * gwlib/cfg.def: Added configuration variable no_sep. Some network programs misshandle escaped characters. * gw/smsc_http.c: Implement no_sep option: URL and text as a numeric hex string * gw/smsbox.c: Dump a message with UDH, too. Added calling of the ota compiler. * doc/userguide/userguide.xml: Updated push and OTA documentation * test/test_ppg.c: -H and -r options work again. Added option -k, for sending Connection header. 2002-01-23 Stipe Tolj * configure.in: added another docbook.dsl path to test for, there are for some BSD systems, reported by "Bernino Lind" [Msg-ID: ] * configure: the resulting outout of configure.in produced by autoconf 2.13. * Makefile.in: changed target .xml.ps to call true(1) without absolute path. Some systems have /bin/true (i.e. Linux), some have /usr/bin/true (i.e. Cygwin). Usually true(1) should be in $PATH and hence we don't need any absolute path here I guess. 2002-01-23 Stipe Tolj * Makefile.in: fixed tab layout error from previous commit (Andreas) for target pkg. This has broken make. * solaris/mk-solaris-package.sh: fixing obviously type in referencing var VERSION. Andreas, this needs to be some more stylisher code here?! 2002-01-23 Andreas Fink * Makefile.in, solaris/mk-solaris-package.sh, solaris/pkginfo, solaris/pkginfo.tmpl: updated packaging for solaris8. You now can type "make pkg" * gw/smsc_at2.c: fixed memory leaks as inidcated by Oded Arbel 2002-01-22 Stipe Tolj * configure.in: added /usr/local tree checking for docbook.dsl. Reported by "Bernino Lind" [Msg-ID: ] * configure: the resulting outout of configure.in produced by autoconf 2.13. 2002-01-18 Tuomas Luttinen * gwlib/http.c (http_header_find_first): A bug corrected so that the function returns "" instead of " ". 2002-01-18 Stipe Tolj * configure.in: added EXE_EXT variable to be used for systems that have executable extensions, i.e. Cygwin 1.x. This makes certain Makefile targets working more cleanly. * configure: the resulting outout of configure.in produced by autoconf 2.13. * Makefile.in: added @EXE_EXT@ substitution tags for the executable extensions. 2002-01-17 Andreas Fink * gw/smsc_emi2.c fixed small and rare memory leak * gw/smsc_smpp.c corrected sender of DLR * gw/bb_store.c removed compiler warnings * gwlib/conn.c typecast to get rid of CRYPTO_set_id_callback warnings * gw/smscconn_p.h added smsc_cgw prototype 2002-01-16 Stipe Tolj * doc/userguide/userguide.xml: fixed a typo 2002-01-16 Stipe Tolj * gw/smsc_cgw.c: applied patch for trn bug fix and minor changed send in by Anders Lindh [Msg-ID: <004601c19eb0$5769f8c0$8078a8c0@alindh>] 2002-01-16 Stipe Tolj * gwlib/list.h: added declaration of new function list_append_unique() * gwlib/list.c: added implementation of new func list_append_unique() 2002-01-16 Stipe Tolj * doc/userguide/userguide.xml: fixed a typo in smsc_http.c module documenation block, where "username" and "password" where used instead of "smsc-username" and "smsc-password". 2002-01-16 Tuomas Luttinen * gwlib/http.c (client_is_persistent): A function added to the HTTP server to define whether the connection from the client is persistent or not. The value is stored into the client object and used to decide whether to close or reuse the client. (http_send_reply): Added a check to the outgoing headers to cut the connection if there is "Connection: close" header. 2002-01-15 Stipe Tolj * gw/urltrans.c: fixed a bug while sending an empty SMS message and servicing it with the default sms-service and using the %k escape code. Reported by Angel Fradejas . [Msg-ID: ] 2002-01-15 Stipe Tolj * gw/smsbox.c: fixed a bug regarding MWI messages reported by Bernino Lind [Msg-ID: ] caused by the commit to revision 1.162. 2002-01-15 Stipe Tolj * gw/smsc_cgw.c: added interface implementation to Sonera ContentGateway. Contributed by Anders Lindh . [Msg-ID: <000a01c19931$f126e5b0$8078a8c0@alindh>] * gw/smscconn.c: added call to smsc_cgw_create() * gwlib/cfg.def: added "appname" configuration directive for smsc group. * doc/userguide/userguide.xml: added "appname" documentation to smsc group. 2002-01-09 Andreas Fink * gw/smsc_at2.c: fixed missing parameter 2002-01-09 Andreas Fink * gw/smsc_at2.c, gw/smsc_emi2.c, gw/smsc_smpp.c, gw/wap_push_pap_compiler.c gwlib/conn.c, gwlib/conn.h, gwlib/date.c, gwlib/gwthread-pthread.c gwlib/http.c. gwlib/thread.c, test/test_smsc.c, test/test_udp.c minor cleanups to remove some compilation warnings. 2002-01-08 Andreas Fink * gw/smsc_at2.c: cleaned up a few things. introduced line sleep to replace old debugging sleep(1)'s in the code. 2002-01-04 Andreas Fink * gw/smsc_emi2.c: fixed a PANIC situation after idle expired 2002-01-03 Andreas Fink * gwlib/thread.c: changed mutex_unlock to report calling location in case of failure 2002-01-03 Stipe Tolj * gw/smsc_smpp.c: fixed an NULL pointer assertion reported by Stefan Cars . [Msg-ID: Pine.BSF.4.21.0112312155080.28423-100000@jocke.transit.net] 2002-01-03 Stipe Tolj * doc/userguide/userguide.xml: added documentation entries for "sendsms-url" and "sendota-url" directives within the smsbox group. Added optional (o) flag to all ssl-enabling boolean directives. 2002-01-03 Stipe Tolj * aclocal.m4: added file for autoconf macros. Included AC_CHECK_VERSION macro which is capable of comparing installed and required version strings for software dependencies, libxml2 in our case. * configure.in: changed the way libxml2 version is checked. We not use AC_CHECK_VERSION from the aclocal.m4 file. This obsoletes the changequote() calls which are not supported for autoconf 2.5x, hence we are now 2.52 compatible. Rearranged --with-ssl and --enable-ssl to ensure the right lib and header include paths are displayed. Minor additional changes. * configure: the resulting outout of configure.in produced by autoconf 2.13. (autoconf 2.52 also works) 2001-12-31 Stipe Tolj * gw/smsbox.c: changed hardcoded HTTP return status values to use HTTP_* enum defines instead. Added config directive to set sendsms and sentota request URLs, defaulting to /cgi-bin/sendsms and /cgi-bin/sendota respectivly. The user may change these with "sendsms-url" and "sendota-url" directives within the smsbox group. * gw/wap_push_ppg.c: substituted hardcoded HTTP return values with HTTP_* enum defines. * gw/wap_push_ppg_pushuser.c: same as wap_push_ppg.c * gwlib/cfg.def: added allowed directives "sendsms-url" and "sendota-url" to the smsbox group. * gwlib/http.h: added a couple of additional HTTP_* return values specified in HTTP/1.1 from RFC2616. * test/drive_wapbox.c: substituted hardcoded HTTP return values with HTTP_* enum defines. * test/test_ppg.c: same as drive_wapbox.c 2001-12-28 Stipe Tolj * configure.in: fixing the ls option --full-time which is not supported on Solaris 2.6. * configure: the resulting output of configure.in produced by autoconf 2.13. 2001-12-27 Stipe Tolj * configure.in: re-wrote checking for openssl library and headers and a couple of cosmetic clean-ups and re-arrangement of single checking routines. Added Solaris pkgadd support definitions. * configure: the resulting output of configure.in produced by autoconf 2.13. * gw/shared.c: added mysql version output in version_report_string() 2001-12-25 Stipe Tolj * gwlib/conn.c: remoted label error for conn_wrap_fd() in case the ssl specific code causes an connection error. This also fixes an warning message while compiling. 2001-12-25 Stipe Tolj * utils/attgetopt.c: exclude implementation of getopt() if config.h has HAVE_GETOPT_IN_STDIO_H defined. This fixes make run bug for Solaris 2.6 (at least). 2001-12-25 Stipe Tolj * configure.in: fixed -L/ linked flag option for configure's --with-mysql option [thanks to Abd Rahman Johari for pointing this out] * configure: resulting output of fixed configure.in 2001-12-23 Stipe Tolj * utils/kannel-nag: changed cvsroot and added output support for different platforms 2001-12-23 Stipe Tolj * configure.in: added options --with-mysql and --enable-mysql-dlr * configure: resulting output of configure.in * config.h.in: added #define HAVE_MYSQL and MYSQL_DIR * gw/bb_box.c: fixed undefined reference error for conn_get_ssl() 2001-12-21 Stipe Tolj * doc/userguide/userguide.xml: added documentation for the introduced configuration directives "smsbox-port-ssl" and "wapbox-port-ssl" in the core group. * gw/bb_boxc.c: added parameters for calling ssl-enabled box connection using boolean configuration directives "smsbox-port-ssl" for bearerbox to smsbox communication and "wapbox-port-ssl" for bearerbox to wapbox communication. Changed the way boxc_status() displays the current status of kannel's boxes, including ssl information for internal conn. * gw/bb_http.c: Commented out call to use_global_server_certkey_file() within httpadmin_start(), this is now done globaly by conn_config_ssl(). * gw/bearerbox.c: added checking in starter() if corresponding cert and key files are specified in the conf file for ssl-enabled inter-box connections. Changed the way the status is displayed. * gw/shared.c: added OpenSSL version string within widely used version_report_string(). Added information that established inter-box connections are ssl-enabled if so. * gw/shared.h: changed declaration of connect_to_bearerbox() to include ssl flag. * gw/smsbox.c: added handling for "smsbox-port-ssl" conf directive. * gw/wapbox.c: added handling for "wapbox-port-ssl" conf directive. * gwlib/cfg.def: added "smsbox-port-ssl" and "wapbox-port-ssl" to allow boolean configuration of ssl-enabled internal box connections. * gwlib/conn.c: changed the way ssl connections are established in conn_wrap_fd() and checked. Fixes also a not previosly detected bug, that causes non-ssl enabled connections on the same port as wanted for ssl, hence SSL_accept() = -1 was not handled correctly. Fixed a potential (non-reported) bug in conn_destroy() that causes errors if we call unlocked_write() in case of ssl-enabled connection. Added function conn_get_ssl() to return the corresponding pointer. * gwlib/conn.h: included declaration of conn_config_ssl() and conn_get_ssl(). * gwlib/gwlib.h: added header file inlusion for ssl.h. * gwlib/http.c: added information to display if HTTP clients are using ssl to connect to an ssl-enabled HTTP server. Fixed potential bug if client_create() is called, but the previous ssl-enabled conn_wrap_fd() has failed, now we check. * gwlib/http.h: added response code for HTTP_BAD_REQUEST. * gwlib/ssl.c: added file to hold all ssl specific code. * gwlib/ssl.h: added file for declaration of all code implemented in ssl.c. 2001-12-20: Andreas Fink * gw/smsc_emi2.c: fixed a problem resulting in timing out at high load. *gw/bb_smscconn.c, gw/msg-decl.h, gw/smsbox.c: introduced field "account" for accounting purposes. *docs/userguide/userguide.xml: updated documentation for &access=... 2001-12-19 Andreas Fink *configure.in: added changes made to configure too. 2001-12-18 Andreas Fink * gw/dlr.c: corrected missing comma 2001-12-18 Andreas Fink * configure: include mysqlclientlib into linking if on the system to make dlr with mysql happy * gw/dlr.c: use a mutex with mysql variant to avoid mysql errors because two commands execute at exactly the same time under high load. Some other cleanups. * gwlib/cfg.def: some config stuff for future modules 2001-12-13 Aarno Syvänen * test/test_ppg.c: Reading a configuration file, using it. This is for future, command line should work, too. Return 1 for abnormal exit and 0 otherwise. * gw/wap_push_ppg.c: A bug and bad design spotted by Jörg Pomnitz correct- ed: do not overload required attributes, use address type for selecting the bearer. Corrected use of any values: in this case, revert to default bearer and network, depending on address type (GSM+CSD or GSM+SMS). IP bearer should work again. * gw/wapbox.c: Related change. Another bugfix. * wap/wsp_unit.c: Related change. * gw/wap_push_ota.c: Related change. * gw/wap_ppg_push_machine.def: Related change. Another bugfix. * checks/check_ppg.sh: Added a shell script for testing ppg. * test/*.txt: Files used by this shell script * gwlib/conn.c: Removed a debug message telling about initialisation of SSL libraries (caller can log this). Make check expect only error logg- ing (problem here are test functions using gwlib). 2001-12-13 Jörg Pommnitz * gw/smsc_emi2.c: fix bug that could cause SMSC flooding under heavy load. 2001-12-12 Jörg Pommnitz * gw/smsbox.c: fix charset handling for sendsms POST requests and use octstr_case_compare when comparing Content-Types (Quote RFC2045, page 12: Matching of media type and subtype is ALWAYS case-insensitive). 2001-12-11 Jörg Pommnitz * gwlib/octstr.c: libxml seems to dislike a conversion from utf-8 to utf-8, so this works around this problem. 2001-12-10 Jörg Pommnitz * gw/smsbox.c: rewrite of charset_processing * gwlib/octstr.c, gwlib/octstr.h: new function octstr_recode 2001-12-07 Tuomas Luttinen * gwlib/charset.[ch]: Function charset_shutdown added to release the libxml charset aliases. * gwlib/gwlib.c (gwlib_shutdown): Call to the charset_shutdown added. 2001-12-07 Jörg Pommnitz * gwlib/conn.c: fix error handling in conn_open_ssl 2001-12-07 Stipe Tolj * gw/smsc_at2.c: fixed a typo for the ericsson R520m, reported by Bob Pepin 2001-12-06 Jörg Pommnitz * gwlib/cfg.def: introduce new config option ssl-trusted-ca-file * gwlib/conn.c: implement client side SSL certificate verification * doc/userguide/userguide.xml: document new option ssl-trusted-ca-file 2001-12-06 Jörg Pommnitz * gwlib/conn.c, gwlib/conn.h: new function void conn_config_ssl (CfgGroup *grp); to uniformly configure the SSL * gw/bearerbox.c, gw/smsbox.c, gw/wapbox.c: use conn_config_ssl to configure SSL code. 2001-12-05 Stipe Tolj * gw/smsc_smpp.c: fixed bug in smsc-id setting, reported by Indrek Mandre 2001-12-05 Jörg Pommnitz * gwlib/conn.c: fix longstanding bug in SSL locking. This fixes the crashes in gwlib_shutdown() 2001-12-05 Jörg Pommnitz * gw/smsc_emi2.c: code cleanup/reorganization, new feature "idle-timeout" * gwlib/cfg.def: add new smsc config option "idle-timeout" * doc/userguide/userguide.xml: document new config option "idle-timeout" 2001-12-05 Andreas Fink * gw/smsc_smpp.c, gw/smpp_pdu.h: introduced some constants for number type 2001-11-30 Jörg Pommnitz * gw/wap_push_ppg.c: fix octstr_destroy of uninitialized username 2001-11-28 Stipe Tolj * gwlib/conn.c: fixed the SSL server shutdown bug reported by Aarno. 2001-11-23 Aarno Syvänen * gw/wap_push_ppg.c: Added calling of SL compiler. Bugfixes. Specially, Kannel again uses international phone number format. (And will use now on: this is a requirement of pap compiler, which needs an unique client identifier.) * gw/wml_compiler.c: To avoid conflicts, give new name (containing st) to parsing functions operating on compiler data structure containing string tables. * gw/wap_push_sl_compiler.[ch]: Added SL compiler * gw/wap_push_si_compiler.c, gw/xml_shared.[ch]: Transferred parsing functions operating on compiler data structures not containing a string to xml_shared. * test/test_ppg.c: Added content type for SL and sia. * test/test_sl.c: Added test program for SL compiler. * gw/wap_push_ppg_pushuser.c: A bugfix: Do not check whitelist and black- list when we have an IP address. Another. * gw/wap_push_pap_compiler.c: A related change. A problem noticed by Jörg Pomnitz: Do not reject a pap document without qos element (it is optional) Instead, set default bearer and network based on address type (GSM+CSD for IP addresses. GSM+SMS for MSISDN addresses) * wap/wap_events.def: Ditto. * gwlib/charset.c: Removed debug message from charset_init. Make check assumes error logging only. * gwlib/cfg.def: Added attribute for server size configuration files. Added first part of test_ppg configuration. 2001-11-22 Jörg Pommnitz * doc/userguide/userguide.xml: fix doc to get through Jade. 2001-11-22 Andreas Fink * gw/smsc_smpp.c: set number plan indicator and type of number for international numbers and alphanumeric ones. 2001-11-20 Stipe Tolj * gateway/doc/userguide/userguide.xml: added documentation about SSL specific configuration directives and changed some typing from PPG part for cosmetical reasons. 2001-11-15 Tuomas Luttinen * gw/wml_definitions.h, gw/wml_compiler.c: Removed the windows character set registration from this module; it shouldn't have been here in the first place. * gwlib/gwlib.c (gwlib_init): Added a call to charset_init. * gwlib/charset.[ch]: New function charset_init added that registers windows charsets into the libxml character set aliases. * gw/xml_shared.c: Added #include to eliminate a compiler warning. 2001-11-14 Jörg Pommnitz * gw/wap_push_ppg.c: fix octstr_destroy of uninitialized username * gw/smsc_at2.c: new function: at2_octstr_destroy(Octstr *ostr) that makes function pointers work when octstr_destroy is a macro * gwlib/octstr.c.debug,gwlib/octstr.h.debug: debug versions of gwlib/octstr.[ch] 2001-11-13 Jörg Pommnitz * test/test_ppg.c, gw/smsc_emi.c: minor fixes to get through Intel C/C++ compiler for Linux 5.0.1 2001-11-12 Jörg Pommnitz * gw/bb_smscconn.c: fix status reporting without a SMSC connection id (might legally be NULL). 2001-11-12 Aarno Syvänen * gw/wap_push_pap_compiler.c: More debugging statements 2001-11-12 Aarno Syvänen * doc/userguide/userguide.xml: Documented ppg authentication configuration. 2001-11-09 Jörg Pommnitz * gateway/gw/wap_push_ppg.c: change Content-Transfer-Encoding to "binary" after successful decoding. 2001-11-09 Aarno Syvänen * gw/wap_push_pap_compiler.c: Accept lowercase versions of bearer and net- work * gw/wap_push_ppg_pushuser.c: Drop a strange warning 2001-11-09 Aarno Syvänen * gw/pushkannel.conf: Updated the sample configuration file * test/test_ppg.c: Handle http level responses. Added a switch for sending authorization in headers. Response server challenge with authorization. * test/test_http_server.c: Answer whitelist and blacklist requests with a hardcoded response. * gw/wap_push_ppg_pushuser.c: Rewrote. Do not close connection ever. Treat username and password as a pair. * gw/wap_push_ppg.c: Fixed a memory leak. A bugfix. * gwlib/cfg.def: Added configuration variables. 2001-11-08 Jörg Pommnitz * gateway/gw/wap_push_ppg.c, gateway/test/test_ppg.c: Add support for BASE64 encoded WAPPush content. 2001-11-08 Andreas Fink * gw/smpp_pdu.c, gw/smpp_pdu.def, gw/smsc_smpp.c Added patch from Nisan to support delivery reports on SMPP 2001-10-31 Aaarno Syvänen * gwlib/cfg.def: Added new configuration variables. * gw/pushkannel.conf: Updated sample configuration file. * gw/wap_push_ppg.c: A bugfix: Reject a push attempt without headers. This was spotted by Jong Hien Zin. Reject a PAP document when network or bearer is required (by setting corresponding attribute) but not set. This was spotted by Stipe Tolj. Reject other application ids than push.sia when push is confirmed. This was spotted Jong Hien Zin. * gw/wap_push_ppg_pushusers.[ch]: Added pi authentication. Not tested, yet. * gwlib/dict.c: Dict_destroy now ignores silently NULL input. * test/test_ppg.c: Change the hardcoded document. Now is is SI over SMS. 2001-10-29 Andreas Fink * gw/smsc_at2.c: changed default speeds for siemens to 19200 also updated so Siemens do a sleep wait after opening the port as suggested by "Alexei Pashkovsky" 2001-10-26 Stipe Tolj * gw/wap_ota_prov.h: added file containing WAP OTA configuration message tokens for the WBXML encoding. * gw/smsbox.c: refined static Octstr *smsbox_req_sendota() to use official WAP OTA configuration specification to support all new handsets capable of receiving OTA configuration messages via SMS bearer. 2001-10-24 Stipe Tolj * gw/connc.c: fixed a typo in void use_global_client_certkey_file(Octstr *certkeyfile) * doc/userguide.xml: fixed some minor typos in new PPG documentation 2001-10-24 Aarno Syvänen * gw/wap_push_ppg.c: A bugfix. And another: do not send password/username pairs to lower layers. Some authentication code. * wap/wap_events.def: Removing username/password pairs from events. * gw/wap_push_ota.c, wap/wsp_unit.c: Related changes. 2001-10-19 Stipe Tolj * README: replaced kannel.org with kannel.3glab.org to make the current home of Kannel more clear. Added a note that Win32 systems are supported too using Cygwin 1.x and pthreads-win32 library. 2001-10-19 Stipe Tolj * gw/bb_boxc.c: changed conn_wrap_fd() prototype call (see gwlin/conn.c) * gw/bb_http.c: required additions in httpadmin_start() to detect in the config file (core group) if the admin HTTP server should use SSL, indicated by "admin-port-ssl = yes", then load the global server certificate and key. Changed http_open_port() prototype call (see gwlib/http.c) * gw/cert.pem: added x509 PEM encoded sample public certificate used in gw/smskannel-ssl.conf. * gw/key.pem: added x509 PEM encoded sample private key used in gw/smskannel-ssl.conf. * gw/smsbox.c: required additions in init_smsbox() to detect in the config file (smsbox group) if the sendsms HTTP server should use SSL, indicated by "sendsms-port-ssl = yes", then load the global server certificate and key. Changed http_open_port() prototype call (see gwlib/http.c) * gw/smsc_emi2.c: changed conn_wrap_fd() prototype call (see gwlin/conn.c) * gw/smsc_fake.c: changed conn_wrap_fd() prototype call (see gwlin/conn.c) * gw/smsc_http.c: changed http_open_port() prototype call (see gwlib/http.c) * gw/smskannel-ssl.conf: added sample configuration file for SSL enabled HTTP servers using sample certificate (cert.pem) and key (key.pem). * gw/wap_push_ppg.c: changed http_open_port() prototype call (see gwlib/http.c) * gwlib/cfg.def: added "admin-port-ssl" to core group and "sendsms-port-ssl" to smsbox group. Changed "ssl-certkey-file" to "ssl-client-certkey-file" to make it more semantic and added "ssl-server-cert-file" and "ssl-server-key-file" within the core group for the server side. * gwlib/conn.c: added global server SSL context, X509 cert and RSA key for server side. Changed conn_wrap_fd() to include ssl enable or disable flag and included the SSL magic here. Added tmp_rsa_callback() function for the private RSA key. Added server side mutex. Added server_ssl_int() function which initialized server side SSL stuff. Added server_shutdown_ssl() function which is used for server side shutdown. Changed use_client_certkey_file() prototype to use_global_client_certkey_file() to be more semantic. Added use_global_server_certkey_file() routine to load global server certificate and private key. * gwlib/conn.h: changed prototype definition for conn_wrap_fd(). Added prototype definitions for openssl_locking_function(), server_init_ssl(), server_shutdown_ssl(). Changed prototype name use_client_certkey_file() to use_global_client_certkey_file(). Added prototype definition for use_global_server_certkey_file(). * gwlib/http.c: added int ssl to struct server to reflect if this server is SSL enabled. Added array int ssl[MAX_SERVERS] within server_thread() to reflect which servers are SSL enabled and how conn_wrap_fd() has to be called. Changed http_open_port() to include boolean flag if this port is used for an SSL enabled server. Added server_ssl_init() call within http_init(). Added server_shutdown_ssl() all within http_shutdown(). * gwlib/http.h: changed prototype definition for http_open_port(). * test/drive_smpp.c: changed conn_wrap_fd() prototype call (see gwlin/conn.c) * test/drive_wapbox.c: changed http_open_port() prototype call (see gwlib/http.c) and conn_wrap_fd() prototype call (see gwlin/conn.c) * test/test_http_server.c: changed http_open_port() prototype call (see gwlib/http.c) * test/test_smsc.c: changed http_open_port() prototype call (see gwlib/http.c) and conn_wrap_fd() prototype call (see gwlin/conn.c) 2001-10-18: Aarno Syvänen * doc/arch/arch.xml: Documented sessionless wsp and unconfirmed push architecture. * doc/userguide/userguide.xml: Documented use of Nokia Toolkit as a part of push server developing enviroment. 2001-10-18 Andreas Fink * gw/dlr.c: added support for MySQL based delivery reports * gw/smsc_emi2.c: fixed delivery report failure if text contained slashes. They are now replaced with a dot 2001-10-17 Jörg Pommnitz * doc/userguide/userguide.xml: fix doc to get through Jade. 2001-10-17 Nick Clarey * smsc_at.c: Added change from Matt Flax which logs retry failures correctly. 2001-10-17 Aarno Syvänen * gw/wapbox.c: Added ppg configuration group. This is passed to the ppg module. Currently enough for a ppg working with a trusted pi. * gwlib/cfg.def: Added ppg configuration group definitions. * gw/wap_push_ppg.c: Read ppg group. Use it for program control. * gw/wap_push_ppg.h: Changed the prototype of function wap_push_ppg_ init. * gw/pushkannel.conf: Updated the sample configuration file. * doc/userguide/userguide.xml: Document ppg configuration group. 2001-10-16 Bruno Rodrigues * smsc_emi2.c: corrected a bug when username and keepalive aren't defined and timeout would be undefined * smsc_at2.c: changed position of speed config reading to be able to force a serial speed 2001-10-16 Aarno Syvänen * gw/wap_push_pap_compiler.c: Reject wrong address type for a bearer (a phone number for IP bearer, IP address for SMS). * gw/wap_push_pap_compiler.h: Tell this in the module comment. 2001-10-15 Jörg Pommnitz * doc/userguide/userguide.xml,doc/arch/arch.xml: fix doc to get through Jade. 2001-10-12 Aarno Syvänen * gw/wap_push_ota.c, gw/wap-appl.c, gw/wap_push_pap_compiler.c, gw/wap_push_si_compiler.c, gw/wap_push_ppg.c: Better module comments. 2001-10-12 Aarno Syvänen * gwlib/dict.c: A bugfix in function dict_put_once. * gw/wap_push_pap_compiler.c: Reject unparsable phone numbers properly. (Global phone number is here an unique identifier, so we must insist it.) * gw/wap_push_ppg.c: Stylised warnings. Updated comments. Add calling of dict_put_once. 2001-10-11 Bruno Rodrigues * dlr: Changed Delivery Reports Code. Instead of having a DLR sms- -service, each service has a dlr-url field where is defined the url to get when a delivery report arrives. DLR are routed based on the existing field "name" of sendsms-user. * userguide.xml: documentation for delivery reports and some minor corrections * bb_smscconn.c: added dlrmask field to alog; added code to expect a report type of sms and write to log correctly * bb_store.c: when loading store, ignore all delivery report kind of messages. SMSC wouldn't sent them to us anyway. * dlr.c: removed keyword and id variables and added service and url. Service is the service name (defined by name= on sendsms-user or sms-service groups) and url is the url to fetch. Added DLR_BUFFERED awareness (don't delete dlr if it's expecting DLR_SUCCESS or DLR_FAIL. dlr message text now contains the url, if given by dlrurl CGI parameter. later the text will be replaced by smsc text reply (if any) plus '/' separator plus this url. * dlr.h: added DLR_BUFFERED, DLR_SMSC_SUCCESS and DLR_SMSC_FAIL * msg-decl.h, shared.c, smsbox.c: replaced dlr_id and dlr_keyword for dlr_url * msg.h: added message type 3: report * smsbox.c: if it's a http get for a delivery-report, don't log nor reply back to user. * smsc_cimd2.c: added & 0x03 to mantain compatibility. Someone please encode the DLR_SMSC_* and DLR_BUFFERED * smsc_emi2.c: added DLR_BUFFERED awareness and code to generate delivery-reports when message hits SMSC (ACK) or fails (NACK). If SMSC replyes with text, include it on delivery message as "smsc-text"/"given-url" * urltrans.c: added a new dict with the service names to able delivery reports to search back for which service the original message was sent. Added urltrans_find_service. Changed get_pattern to be aware of delivery reports and return correct values (pattern would be the dlr-url); added %n (service name), %d (dlr value) and %A (smsc reply on delivery report) * : It's still missing some kind of DLR_SMSC_FAIL reports when a message cannot be routed 2001-10-11 Andreas Fink * smsc_at2.c: fixed bugs while sending SMS, autosensing speed * config.guess, config.sub: updated to detect MacOS X correctly Note: MacOS X doesnt support signals being sent to threads so we cant disable them. 2001-10-10 Aarno Syvänen * doc/userguide/userguide.xml: Some corrections. * doc/arch/arch.xml: Wrote document about push architecture. 2001-10-08 Bruno Rodrigues * gwlib/http.c: When url was like http://user:pass@site, the first colon was changed to @ to differentiate from the colon for port number. Now the code replaces it back to colon and replaces password with "*". (unfortunatly keeps the same amount of chars) * gw/smsc_at2.c: added a select command before the read, so kannel delays some time if there's nothing to read (copy from old at). This way, at2 doesn't eat my cpu :) * gw/smsc_emi2.c: delay in x miliseconds was incorrect. Fixed. 2001-10-08 Bruno Rodrigues * gw/smsc_emi2.c, gwlib/cfg.def: Added "throughput" (messages per second) variable to configuration. Delays 1/throughtput seconds between sending messages. * gw/smsc_emi2.c, gwlib/cfg.def: Added "window" configuration that defines the window size when using windowed flow-control (flow- control=0). Defaults to 100, like before. * gw/bb_boxc.c, shared.c, shared.h, smsc_cimd.c, smsbox.c, smsc_cimd2, smsc_emi.c, smsc_emi2.c, smsc_fake.c, smsc_ois.c, smsc_smpp.c, wapbox.c, gwlib/conn.c, conn.h, http.c, socket.c, socket.h, test/drive_smpp.c, drive_wapbox.c, fakesmsc.c, test_cimd2.c, test_smsc.c: Added preliminary our_host parameter to later someone code our_host config parameters. Will be needed if we want to fix our ip-address when we have ip aliases or to define the ip we listen to (instead of ANY) to limit connections: bind bearerbox to localhost only, for example. 2001-10-08 Bruno Rodrigues * gw/smsc_emi2.c: Support ACK without timestamp. Note that if smsc doesn't send timestamp in ACK, delivery reports wouldn't work. 2001-10-03 Aarno Syvänen * doc/userguide/userguide.xml: Added documentation for push proxy gateway 2001-09-27 Aarno Syvänen * gw/wap_push_ppg.c: Removed #if 0 -code. Send username-password-pair to OTA layer. Accept GSM SMS bearer. Correct comparisions between signed and unsigned types. Remove MIME headers. Committed bugfixes by Bernard Valton. Do confirmed push when preferconfirmed QoS is request- ed, because Kannel supports confirmed push (a suggestion by Bernard Valton). * test/test_ppg.c: Added HTTP status checking. Added an option for interval between pushes. * gw/wap_push_ota.c: Send username-password-pair to WSP layer. Accept GSM SMS bearer. * wap/wsp_unit.c: Send username-password-pair to wdp layer. Accept GSM SMS bearer. * wap/wap_events.def: Added username-password pair to events. Added bearer and network fields to events. * gw/wapbox.c: Added an ability to send SMS message from wapbox. It is splitted when necessary. * gw/smsbox.c, gw/shared.[ch]: Transferred SMS message splitting code to the module shared. * gw/bb_boxc.c: Accept sms messages from wapbox, route them to smsc. * gw/wap_push_pap_compiler.c: Correct comparisions between signed and unsigned types. A bugfix. * gw/wap_push_si_compiler.c: Correct comparisions between signed and unsigned types. * gw/xml_shared.h: Added missing declarations. * test/test_http_server.c: Better debugging of received requests. * gw/wap_push_pap_mime.c: MIME parser expected a surplus crlf. Correct- ed this. Accept lower case versions of the headers. * gw/smsc_http.c: Added new configuration variables no-sender and no- coding to make URLs simpler. * gw/cfg.def: Added these variables. * gwlib/dict.[ch]: Currently outcommented code for dict_put_once. This function puts key to the dict, and doing this again is an error. * checks/check_httpsmsc_kannel.sh: Corrected an infinite loop. * gw/pushkannel.conf: Added sample configuration for push. 2001-09-21 Bruno Rodrigues * gw/smsbox.c: Forced 7bits coding if coding=DC_UNDEF and udh is empty. Fixed bug in text concatenation 2001-09-21 Bruno Rodrigues * gw/smsbox.c: Fixed a bug in reply-* octstr. Smsbox panics on second error reply 2001-09-20 Bruno Rodrigues * gw/smsbox.c: Check for msgdata=NULL when loggin to alog * gwlib/http.c: Added sms-service basic authentication. url = "http://user:pass@host:port/path/file". Added parsing to parse_url and used existent http_add_basic_auth call * gw/smsc_emi2.c: when using flow-control (stop-and-wait), if a -31 message is not ack, make write=1 again to restart sending messages 2001-09-19 Bruno Rodrigues * gw/bb_store.c: Fixed two bugs that don't close store.lock when store_dump is called. One was (introduced by me) in store_rename and the other was a missing close in store_dump to close old file. * gw/smsc_emi2.c: Removed alert (31) sending just after login and forced it in send_loop. This way, first message received will be correctly processed. 2001-09-19 Bruno Rodrigues * gw/sms.c: fields_to_dcs correctly encodes mclass=MC_UNDEF and don´t set bit "mclass present" * gw/smsc_at.c, smsc_at2.c, smsc.c, smsc_p.h, docs/userguide: Added alt-dcs configuration field to smsc = at, to use the 0xFX mode if set. Removed fixed mode=1 when modem = SIEMENS * gw/Smsc_emi.c: Corrected a bug. Old flag_8bit != 0 should be coding = DC_7BITS 2001-09-17 Bruno Rodrigues * gw/sms.c: Fixed a bug in mode=1 dcs encoding and some other in dcs_to_fields ('cause mclass and coding starts with 1, not 0) * gw/bb_store.c: When I added a line saying which store file was kannel reading, I had a mistake. Instead of printint the filename, I was printing the file. Ops, sorry. Fixed now. 2001-09-14 Andreas Fink * gw/smsc_at2.c added some callbacks to bb_smscconn_sent and bb_smscconn_send_failed as suggested by Paul Keogh 2001-09-12 Bruno Rodrigues * bb_store.c: don't try to rename store.lock to store.lock.bak if store.lock does not exists 2001-09-10 Andreas Fink * gw/smsc_at2.c gw/smsc_emi2.c incoming messages where counted twice. 2001-09-10 Andreas Fink * gw/smsc_at2.c made the counters really count the SMSC ID is now set on incoming 2001-09-07 Andreas Fink * gw/smsc_at2.c some systems dont have SSIZE_MAX defined so I presume its larger than 1024 in those cases On my system SSIZE_MAX is INT_MAX which is ((int)(~0U>>1)) 2001-09-07 Andreas Fink * gw/smsc_at2.c fixed to wait for OK while sending AT+CNMS to acknowledge the received packet. Changed the doc 2001-09-06 Bruno Rodrigues * userguide.xml, bb_smscconn.c, control.html, msg-decl.h, sms.c, smsbox.c, smsc_http.c, smsc_ois.c: replaced "class" to "mclass" to avoid future C++ conflits * gw/http.c: in http_status_class, changed int class to sclass * gw/smsc_at2.c: removed some unused variables and added some '(' ')' to clean gcc warnings 2001-09-06 Andreas Fink * gw/smsc_at2.c fixed some oddities left over from the old driver. debugged for nokia and siemens. enabled hardware handshake for better performance. 2001-09-05 Andreas Fink * Makefile.in, docs/*/*.xml: Corrected Makefiles, xml and other files so now all documentation should compile * Makefile.in: Added RTF generation of documentation; install-docs now install userguide, alligata and wtls files; tweaks in jade lines * configure.in (and configure): changed --disable-ssl code, ssl is still enable per-default, but before --enable-ssl would triger incorrectly --disable-ssl; * debian/changelog, debian/rules: some tweaks to generate CVS deb file * user2.1.xml and wtls.xml: moved to own directories and renamed user2.1 to alligata. Present on doc/alligata and doc/wtls * Makefile.in: added "convert" dependency to generated .ps files from .png to be able to compile documents and done some tweaks to xml * gw/smsbox.c: charset_processing now returns -1 for error and 0 for ok 2001-09-02 Bruno Rodrigues * userguide.xml: Written information about latest patch. Added "Installing Kannel from DEB packages" section. Added info about removing prefixes using unified-prefix. Corrected some glitches. Added status.[txt|html|xml] information. Corrected validity and deferred text (it's minutes, not seconds). Added modem types table (well, just the table, we could add a list of tested modems in there). Splitted "feature list". One list have the "user" features (what matters for who is using kannel. The other have "internal features" (what matters for coders/administrators). Added X-Kannel headers list. * gw/control.html: Added new fields to form and included some javascript (I hope it's ok) to select host and port to compose URL. * gw/smsbox.c: Added charset processing to sms-service (and hopefully to sendsms push). Tested sms-service functionality. * gw/smsbox.c: Unicode Patch: I need help to test and improve the code using other charsets. * doc/kannel.conf: Added ALL possible fields, commented, so it's easier to see what we want and uncomment it. 2001-09-01 Bruno Rodrigues * gw/smsbox.c, gw/msg-decl.h, gw/smsc_*.c: "charset", "class" and "coding" patch. Use class to define Message Class (older flash). Use coding to select manually 7/8bit or UCS2. Use charset to tell kannel which charset the text is. * gw/smsbox.c, gw/smsc_emi2.c, gw/msg-decl.h: Removed mwimessages (udh string will be included on userguide) * gw/smsbox.c, gw/msg-decl.h: Added compress field (compress code not yet included) * gw/sms.c, gw/smsc.h: Added fields_to_dcs and dcs_to_fields to encode/decode DCS field according to ETSI GSM 03.38 in new sms.c. Added MC_*, MWI_* and DC_* * gw/smsbox.c: Added reply-requestfailed and reply-emptymessage configuration strings. * gw/smsc_*.c: coding (older flag_8bit) is retro-compatible. * gw/smsbox.c, gw/urltrans.c: If unset, defaults to 7 bit, or 8 bit if udh is set. * gw/smsbox.c: charset defines which charset text field is. default to ISO-8859-1 for coding=DC_7BIT, UTF16BE for DC_UCS2 (%00%33%00%34) or raw (ignored) for DC_8BIT * gw/smsc_emi2.c: Tested in emi2. * gw/smsc_at.c: Changed dcs processing using fields_to_dcs. * gw/smsc_at.c: Added validity field to AT code. If unset, uses older validity configuration value. * gw/smsc_at.c: If modem is a Siemens, use Fx mode of DCS. * gw/smsc_cimd.c: If message is empty, in cimd, change to a one-space message. (Can't cimd send empty messages ?) * gw/smsc_emi.c: In old emi, is DCS defined in XSER2 like in emi2 ? * gw/urltrans.c: Added allowed/denied-prefix to sms-service too. Just like accepted-smsc, if a number prefix is denied on one service, kannel will search for other service. This way, we can have one service for 91 started numbers and other for other prefixes. * gw/urltrans.c: Added black/white list to urltranslations. If rejected, search for a "black-list" service (just like default works) * Just try http://...&class=0&text=%00%33&coding=3 http://...&class=0&text=ãáç&coding=3&charset=ISO-8859-1 2001-08-31 Bruno Rodrigues * gw/bb_smscconn.c: If message is NACKed, write it to store so message got out of queue. * gw/smsbox.c, gwlib/cfg.def: Added white/black-list send filter to sms-user and global smsbox. * gw/smscconn.c, gw/smsc.c: Added allowed-prefix send filter to smsc (besides denied-prefix) * gw/bb_smscconn.c: Added more fields to bearerbox_access.log * gw/: Added dlr.h and dlr.c from Andreas Fink as of Message-Id: [delivery reports (update)] * Corrected some glitches, cleaning some warnings when using gcc -Wall 2001-08-30 Andreas Fink * gw/bearerbox.c, gw/emimsg.c, gw/msg-decl.h, gw/smsbox.c, * gw/smsc_cimd2.c: Added delivery report mechanism. * to use it: ask for a DLR by specifying &dlrmask = * 0 = no dlr, 1 = success, 2 = failure, 3 both. * and &dlrid= a unique application specific ID. * the DLR is treated as an incoming message of the style: * "DLR 1/2 uniqueid smscname" (1 = success, 2 = failure). * gw/smsc_http.c: if charset is specified 7 bit is assumed. * make it work with kannel/kannel SMSC links so concatenation * works again in that case. 2001-08-28 Andreas Fink * gw/smsc_emi2.c: fixed alphanumeric sender ID to use GSM character set (added charset_latin1_to_gsm(str);) 2001-08-21 Aarno Syvänen * gw/wap_push_ppg.c: Implement response-result * wap/wap_events.def, gw/wap_push_pap_compiler.c: Corresponding changes * gw/wap_push_ppg.c, gw/wap_push_pap.c: Merge these modules * gw/wapbox.c: Corresponding changes 2001-08-15 Aarno Syvänen * test/test_mime.c: Added a program for testing the mime parser * test/test_si.c: Added a program to test the si compiler * gw/wap_push_ppg.c: Send no X-Wap-Application-Id header, when push application id is wml.ua. * gw/wap_push_pap_mime.c: Bugfixes. Return NULL instead of contents when parsing not successfull. * gw/wap_push_pap.c: Change code accordingly. Set ppg listening port to 8080. 2001-08-13 Bruno Rodrigues * smsc_emi2.c: Added waiting for first alert command and fixed other small issue that, when using stop-and-wait flow-control, messages stayed on queue if received a message between a send and a ack wait. 2001-08-13 Andreas Fink * gw/smsc_at: added new modem type siemens-tc35 2001-08-08 Aarno Syvänen * test/test_ppg.c: Better help. Added option to set push application id. Set content type default to si. * gw/wml_definitions.h, gw/xml_definitions.h: Created a file for definitions common to all xml compilers. * gw/wap_push_pap_compiler.c: A bugfix * gw/shared.[ch], gw/wap_push_pap_compiler.c: Transferred OSI date validation. Made it more picky. * gw/wap_push_si_compiler.[ch]: Wrote si tokenizer * gw/wap_push_ppg.c: Added calling of the si compiler. Set push application id wml.ua, when this header is missing or unparsable. * gw/xml_shared.[ch], gw/wml_compiler.c: Transferred function common to xml compilers to a specific file. * gw/wap_push_pap.c: Called push server listening port to 8080. 2001-08-02 Tuomas Luttinen * gw/wml_compiler.c (parse_attribute): A bug reported by Bernard Valton fixed: unknown attribute is encoded with LITERAL and a string table reference. 2001-08-01 Tuomas Luttinen * gwlib/charset.h: Updated the comments about the supported character sets. 2001-07-31 Bruno Rodrigues * bearerbox.c, smsbox.c: added alog_reopen to HUP signal handler. * smsbox.c: removed "include " -> not needed anymore; set sms_type to mt_push when receiving messages through http interface: When I restarted kannel, all messages on store were returned to the default service instead of beeing retransmitted. * smsc_at.c: added some ATI queries to modem; On the while loop to retransmit PDU, added sending AT+CMGS; removed \n from AT:command; Added "Read from modem" debug dump; * smsc_emi2.c: accept XSER 02 with DCS, but didn't yet convert it to other fields (flash, encoding, etc); Added wait-ack configuration to define for how long to wait for (N)ACKs (default still 60 secongs). * smsc_emi2.c: added flow-control configuration. If unset or 0, stays in windowed mode (I'll do later the code to define the window value). If 1, uses stop-and-wait flow control. 2001-07-28 Bruno Rodrigues * bb_http.c: There were two cgi-bin/status.xml. * utils.c: if first parameter in unified-prefix is a -, that means to remove the other prefixes from number 2001-07-27 Jörg Pommnitz * add X-Kannel-From header to HTTP GET requests from smsbox (configurable in the config file, use the send-sender=1 option). 2001-07-23 Bruno Rodrigues * userguide.xml: in emi2 section, username and password ain't mandatory. * smsbox.c, userguide.xml: There are at least two messages replied back to user via SMS that should be configurable. I've activated reply-couldnotfetch and reply-couldnotrepresent and added them to smsbox group variables. 2001-07-22 Bruno Rodrigues * smsbox.c, smsc_emi2.c, userguide.xml: Added "validity" and "deferred" SMS fields. 2001-07-22 Bruno Rodrigues * smsc_emi2.c, userguide.xml: receive-port now is optional 2001-07-19 Bruno Rodrigues * userguide.xml: removed some extra characters. * smsbox.c, smsc_emi2.c: corrected some bugs. 2001-07-19 Jörg Pommnitz * add User-Agent header to HTTP requests from smsbox. 2001-07-19 Jörg Pommnitz * fix userguide.xml to get through Jade. 2001-07-19 Bruno Rodrigues * gw/msg-decl.h, gw/smsbox.c and gw/smsc_emi2.c: Changed "flash" to "flag_flash" and added flag_mwi, mwimessages and flag_unicode. * gw/smsbox.c: Added code to process the mwi and unicode flags. Checked the flash code. Removed the "empty string from provider" to allow sending messages without text. Added some missing octstr_destroy in flags processing. * gw/smsc_emi2.c: Added code to encode DCS using flash, mwi and unicode flags. Corrected a typo :). * doc/userguide/userguide.xml: Added description for flash, mwi and unicode flags. * Note: not testet yet the X-Kannel replies and concatenation. :( 2001-07-19 Aarno Syvänen * test/test_ppg.c: Changed content type testing. Bug fixes. * gw/wap_push_ppg.c: Fixed a memory leak. * gw/wap_push_pap.c: Handle various push content type errors. * gw/wap_push_pap_compiler.c: Handle an empty attribute. 2001-07-18 Bruno Rodrigues * gw/smsc_emi2.c: Added the "keepalive" code. If you want to keep your connection always opened, set "keepalive" in conf file and kannel will send alert commands to keep it alive. * doc/userguide/userguide.xml: added the "keepalive" description. 2001-07-18 Yann Muller * doc/userguide/user2.1.xml, wtls.xml: applied fix by Jörg Pommnitz to generate HTML docs. 2001-07-17 Aarno Syvänen * test/test_ppg.c: Added parameter for content type. Some of these (nil, multipart) are for testing. A bugfix. * gw/wap_push_pap.c: Fixed a memory leak. * gw/wap_push_ppg.c: Added handling of a SI source (this is not compiled yet). Accept all content types, compiling only wap related ones. NOT_SPECIFIED is handled like UNCONFIRMED (suggestion by Bernard Valton). Regard the message non-transformable when we have no content type. Fixed a memory leak. A bugfix. Committed bugfixes by Bernard Valton. 2001-07-16 Andreas Fink * doc/userguide/userguide.xml: Updated the information about the libxml version requierd to 2.2.5. 2001-07-11 Aarno Syvänen * test/test_ppg.c: Made help more helpful 2001-07-11 Aarno Syvänen * gw/wap_push_ppg.c: Committed bug fixes made by Bernard Valton 2001-07-10 Aarno Syvänen * gw/wap_push_ppg.c: Committed bug fixes made by Bernard Valton. Fixed a memory leak. 2001-07-10 Aarno Syvänen * test/test_ppg.c: Fixed a memory leak * gw/wap_push_pap.c: Do not panic when the order of command line files is wrong. Tobias Seelig spotted this problem. * gw/wap_push_pap_compiler.c: Fixed a memory leak. 2001-07-09 Yann Muller * doc/userguide/user2.1.xml,wtls.xml,images/*: Documentation for Alligata (3G Lab's version of Kannel) in XML format. 2001-07-06 Yann Muller * gw/wapbox.c, wap/wtls*.c, gwlib/pki.c: separated wtls specific code with #defines. 2001-07-06 Andreas Fink * config.h.in, configure.in: added options for wtls. * wap/wtls*: all WTLS files (state machines, PDUs...) * wap/wap_event.*: added WTLSPDUS definitions and events. * gw/wapbox.c: load the certificates and keys for WTLS, inititialise, dispatch datagrams according to port in main(). * gw/bb_upd.c: add_services for WTLS ports. * gwlib/cfg.def: added certificates options to the wapbox config. * gwlib/pki.[ch]: support functions for keys (incomplete). 2001-07-05 Aarno Syvänen * test/test_ppg.c: Added a simple pi for testing ppgs * gw/wap_push_pap.c: Added communications with pi * wap/wap_events.def: Added an event Bad_Message_Response. Corrected definitions of Push_response * gw/wap_push_pap_compiler.c: Rewrote. Corrected bugs spotted by Bernard Walton * gw/wap_push_ppg.h: Added x000 pap result codes to enumerations * gw/wap_push_ppg.c: Added descriptions of aforementioned codes. Corrected a bug spotted by Bernard Walton * gw/wap_push_mime.c: Corrected handling of optional headers 2001-06-22 Dave Holland * configure.in, configure: added reference to html and tex stylesheets for RH7.1 (and hopefully future versions) 2001-06-11 Aarno Syvänen * gw/wap_push_pap.c: Testing normally disabled 2001-06-11 Aarno Syvänen * gw/wap_push_pap_mime.[ch]: Added MIME parser for PAP module (no multipart push messages yet) * gw/wap_push_pap.c: Added calling of MIME parser and header handl- ing * gw/wap_push_pap_compiler.c: Corrected erroneous logic in enumer- ations checking. 2001-06-04 Lars Wirzenius * gw/smsc_smpp.c: Check for smpp->receiver instead of smpp->transmitter in smsc_smpp_create(). Pointed out by Le Nhu Hai. 2001-06-01 Jarkko Kovala * gwlib/http.c, gwlib/gwthread-pthread.c: Move the OpenSSL ERR_remove_state() from the http code to the gwthread code. gateway-1.4.5/test/0000755000175000017500000000000013312227712012643 5ustar toljtoljgateway-1.4.5/test/test_http.c0000644000175000017500000004007013310706244015026 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_http.c - a simple program to test the new http library * * Lars Wirzenius */ #include #include #include #include #include "gwlib/gwlib.h" #include "gwlib/http.h" #define MAX_THREADS 1024 #define MAX_IN_QUEUE 128 static long max_requests = 1; static double interval = 0; static int method = HTTP_METHOD_GET; static char **urls = NULL; static int num_urls = 0; static int verbose = 1; static Octstr *auth_username = NULL; static Octstr *auth_password = NULL; static Octstr *msg_text = NULL; static Octstr *ssl_client_certkey_file = NULL; static Octstr *extra_headers = NULL; static Octstr *content_file = NULL; /* if set use POST method */ static Octstr *method_name = NULL; static int file = 0; static List *split = NULL; static int follow_redirect = 1; static int escape_codes = 0; static Octstr *post_content_create(void) { Octstr *content; if ((content = octstr_read_file(octstr_get_cstr(content_file))) == NULL) panic(0, "Cannot read content text"); debug("", 0, "body content is"); octstr_dump(content, 0); return content; } static void url_pattern(Octstr *url) { Octstr *temp; const char *pattern; size_t n; temp = octstr_duplicate(url); octstr_truncate(url, 0); pattern = octstr_get_cstr(temp); while (*pattern != '\0') { n = strcspn(pattern, "%"); octstr_append_data(url, pattern, n); pattern += n; gw_assert(*pattern == '%' || *pattern == '\0'); if (*pattern == '\0') break; pattern++; switch (*pattern) { case 'r': octstr_format_append(url, "%ld", gw_rand()); break; case 'I': { uuid_t uid; char id[UUID_STR_LEN + 1]; uuid_generate(uid); uuid_unparse(uid, id); octstr_append_cstr(url, id); } break; /* XXX add more here if needed */ case '%': octstr_format_append(url, "%%"); break; default: warning(0, "Unknown escape code (%%%c) within URL, skipping!", *pattern); octstr_format_append(url, "%%%c", *pattern); break; } /* switch(...) */ pattern++; } /* while ... */ octstr_destroy(temp); } static void start_request(HTTPCaller *caller, List *reqh, long i) { Octstr *url, *content = NULL; long *id; if ((i % 1000) == 0) info(0, "Starting fetch %ld", i); id = gw_malloc(sizeof(long)); *id = i; url = octstr_create(urls[i % num_urls]); if (file) { octstr_append(url, octstr_imm("&text=")); octstr_append(url, msg_text); } /* add the extra headers that have been read from the file */ if (split != NULL) http_header_combine(reqh, split); /* * if a body content file has been specified, then * we assume this should be a POST */ if (content_file != NULL) { content = post_content_create(); method = HTTP_METHOD_POST; } /* apply any escape codes */ if (escape_codes) url_pattern(url); /* * if this is a POST request then pass the required content as body to * the HTTP server, otherwise skip the body, the arguments will be * urlencoded in the URL itself. */ http_start_request(caller, method, url, reqh, content, follow_redirect, id, ssl_client_certkey_file); debug("", 0, "Started request %ld with url:", *id); octstr_url_decode(url); octstr_dump(url, 0); octstr_destroy(url); octstr_destroy(msg_text); octstr_destroy(content); } static int receive_reply(HTTPCaller *caller) { void *id; int ret; Octstr *final_url; List *replyh; Octstr *replyb; Octstr *type; Octstr *charset; Octstr *os; id = http_receive_result(caller, &ret, &final_url, &replyh, &replyb); octstr_destroy(final_url); if (id == NULL || ret == -1) { error(0, "http GET failed"); gw_free(id); return -1; } debug("", 0, "Done with request %ld", *(long *) id); gw_free(id); http_header_get_content_type(replyh, &type, &charset); debug("", 0, "Content-type is <%s>, charset is <%s>", octstr_get_cstr(type), octstr_get_cstr(charset)); octstr_destroy(type); octstr_destroy(charset); if (verbose) debug("", 0, "Reply headers:"); while ((os = gwlist_extract_first(replyh)) != NULL) { if (verbose) octstr_dump(os, 1); octstr_destroy(os); } gwlist_destroy(replyh, NULL); if (verbose) { debug("", 0, "Reply body:"); octstr_dump(replyb, 1); } octstr_destroy(replyb); return 0; } static void client_thread(void *arg) { List *reqh; unsigned long i; long succeeded, failed; HTTPCaller *caller; char buf[1024]; long in_queue; Counter *counter = NULL; caller = arg; succeeded = 0; failed = 0; reqh = gwlist_create(); sprintf(buf, "%ld", (long) gwthread_self()); http_header_add(reqh, "X-Thread", buf); if (auth_username != NULL && auth_password != NULL) http_add_basic_auth(reqh, auth_username, auth_password); in_queue = 0; counter = counter_create(); for (;;) { i = counter_increase(counter); if (i >= max_requests) goto receive_rest; start_request(caller, reqh, i); if (interval > 0) gwthread_sleep(interval); ++in_queue; if (receive_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } receive_rest: while (in_queue > 0) { if (receive_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } counter_destroy(counter); http_destroy_headers(reqh); http_caller_destroy(caller); info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed); } static void split_headers(Octstr *headers, List **split) { long start; long pos; *split = gwlist_create(); start = 0; for (pos = 0; pos < octstr_len(headers); pos++) { if (octstr_get_char(headers, pos) == '\n') { Octstr *line; if (pos == start) { /* Skip empty lines */ start = pos + 1; continue; } line = octstr_copy(headers, start, pos - start); start = pos + 1; gwlist_append(*split, line); } } } static void help(void) { info(0, "Usage: test_http [options] url ..."); info(0, "where options are:"); info(0, "-v number"); info(0, " set log level for stderr logging"); info(0, "-q"); info(0, " don't print the body or headers of the HTTP response"); info(0, "-r number"); info(0, " make `number' requests, repeating URLs as necessary"); info(0, "-t number"); info(0, " run `number' threads, that make -r `number' requests"); info(0, "-i interval"); info(0, " make one request in `interval' seconds"); info(0, "-p domain.name"); info(0, " use `domain.name' as a proxy"); info(0, "-P portnumber"); info(0, " connect to proxy at port `portnumber'"); info(0, "-E regex"); info(0, " proxy exceptions as regex value"); info(0, "-S"); info(0, " use HTTPS scheme to access SSL-enabled proxy server"); info(0, "-e domain1:domain2:..."); info(0, " set exception list for proxy use"); info(0, "-u filename"); info(0, " read request's &text= string from file 'filename'. It is"); info(0, " url encoded before it is added to the request"); info(0, "-H filename"); info(0, " read HTTP headers from file 'filename' and add them to"); info(0, " the request for url 'url'"); info(0, "-B filename"); info(0, " read content from file 'filename' and send it as body"); info(0, " of a POST method request (default: GET if no -B is set)"); info(0, "-m method"); info(0, " use a specific HTTP method for request to server"); info(0, "-s"); info(0, " use HTTPS scheme to access SSL-enabled HTTP server"); info(0, "-c ssl_client_cert_key_file"); info(0, " use this file as the SSL certificate and key file"); info(0, "-C ssl_ca_file"); info(0, " use this file as the SSL certificate authority"); info(0, "-f"); info(0, " don't follow redirects"); info(0, "-V"); info(0, " evaluate for URL escape code patterns (%r - random number,"); info(0, " %I - UUID string)"); } int main(int argc, char **argv) { int i, opt, num_threads; Octstr *proxy; List *exceptions; long proxy_port; int proxy_ssl = 0; Octstr *proxy_username; Octstr *proxy_password; Octstr *exceptions_regex; char *p; long threads[MAX_THREADS]; time_t start, end; double run_time; FILE *fp; int ssl = 0; Octstr *ca_file; gwlib_init(); proxy = NULL; proxy_port = -1; exceptions = gwlist_create(); proxy_username = NULL; proxy_password = NULL; exceptions_regex = NULL; num_threads = 1; file = 0; fp = NULL; while ((opt = getopt(argc, argv, "hv:qr:p:P:Se:t:i:a:u:sc:H:B:m:fVC:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'q': verbose = 0; break; case 'r': max_requests = atoi(optarg); break; case 't': num_threads = atoi(optarg); if (num_threads > MAX_THREADS) num_threads = MAX_THREADS; break; case 'i': interval = atof(optarg); break; case 'u': file = 1; fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Cannot open message text file %s", optarg); msg_text = octstr_read_file(optarg); if (msg_text == NULL) panic(0, "Cannot read message text"); debug("", 0, "message text is"); octstr_dump(msg_text, 0); octstr_url_encode(msg_text); fclose(fp); break; case 'h': help(); exit(0); case 'p': proxy = octstr_create(optarg); break; case 'P': proxy_port = atoi(optarg); break; case 'S': proxy_ssl = 1; break; case 'e': p = strtok(optarg, ":"); while (p != NULL) { gwlist_append(exceptions, octstr_create(p)); p = strtok(NULL, ":"); } break; case 'E': exceptions_regex = octstr_create(optarg); break; case 'a': p = strtok(optarg, ":"); if (p != NULL) { auth_username = octstr_create(p); p = strtok(NULL, ""); if (p != NULL) auth_password = octstr_create(p); } break; case 's': ssl = 1; break; case 'c': octstr_destroy(ssl_client_certkey_file); ssl_client_certkey_file = octstr_create(optarg); break; case 'H': fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Cannot open header text file %s", optarg); extra_headers = octstr_read_file(optarg); if (extra_headers == NULL) panic(0, "Cannot read header text"); debug("", 0, "headers are"); octstr_dump(extra_headers, 0); split_headers(extra_headers, &split); fclose(fp); break; case 'B': content_file = octstr_create(optarg); break; case 'm': method_name = octstr_create(optarg); break; case 'f': follow_redirect = 0; break; case 'V': escape_codes = 1; break; #ifdef HAVE_LIBSSL case 'C': ca_file = octstr_create(optarg); conn_use_global_trusted_ca_file(ca_file); octstr_destroy(ca_file); break; #endif case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (optind == argc) { help(); exit(0); } #ifdef HAVE_LIBSSL /* * check if we are doing a SSL-enabled client version here * load the required cert and key file */ if (ssl || proxy_ssl) { if (ssl_client_certkey_file != NULL) { conn_use_global_client_certkey_file(ssl_client_certkey_file); } else { panic(0, "client certkey file need to be given!"); } } #endif if (method_name != NULL) { method = http_name2method(method_name); } if (proxy != NULL && proxy_port > 0) { http_use_proxy(proxy, proxy_port, proxy_ssl, exceptions, proxy_username, proxy_password, exceptions_regex); } octstr_destroy(proxy); octstr_destroy(proxy_username); octstr_destroy(proxy_password); octstr_destroy(exceptions_regex); gwlist_destroy(exceptions, octstr_destroy_item); urls = argv + optind; num_urls = argc - optind; time(&start); if (num_threads == 1) client_thread(http_caller_create()); else { for (i = 0; i < num_threads; ++i) threads[i] = gwthread_create(client_thread, http_caller_create()); for (i = 0; i < num_threads; ++i) gwthread_join(threads[i]); } time(&end); run_time = difftime(end, start); info(0, "%ld requests in %f seconds, %f requests/s.", (max_requests * num_threads), run_time, (max_requests * num_threads) / run_time); octstr_destroy(ssl_client_certkey_file); octstr_destroy(auth_username); octstr_destroy(auth_password); octstr_destroy(extra_headers); octstr_destroy(content_file); gwlist_destroy(split, octstr_destroy_item); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_regex.c0000644000175000017500000001333013227613126015163 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_regex.c - test regex module * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" #include "gwlib/regex.h" #if defined(HAVE_REGEX) || defined(HAVE_PCRE) int main(int argc, char **argv) { Octstr *re, *os, *sub; Octstr *tmp; regex_t *regexp; regmatch_t pmatch[REGEX_MAX_SUB_MATCH]; int rc; gwlib_init(); get_and_set_debugs(argc, argv, NULL); if (argc < 4) panic(0, "Syntax: %s \n", argv[0]); os = octstr_create(argv[1]); re = octstr_create(argv[2]); sub = octstr_create(argv[3]); info(0, "step 1: generic functions"); /* compile */ if ((regexp = gw_regex_comp(re, REG_EXTENDED)) == NULL) panic(0, "regex compilation failed!"); debug("regex",0,"RE: regex <%s> has %ld subexpressions.", octstr_get_cstr(re), (long)regexp->re_nsub); /* execute */ rc = gw_regex_exec(regexp, os, REGEX_MAX_SUB_MATCH, &pmatch[0], 0); if (rc == REG_NOMATCH) { info(0, "RE: regex <%s> did not match on string <%s>.", octstr_get_cstr(re), octstr_get_cstr(os)); } else if (rc != 0) { Octstr *err = gw_regex_error(rc, regexp); error(0, "RE: regex <%s> execution failed: %s", octstr_get_cstr(re), octstr_get_cstr(err)); octstr_destroy(err); } else { int i; char *rsub; debug("regex",0,"RE: regex <%s> matches.", octstr_get_cstr(re)); debug("regex",0,"RE: substring matches are:"); for (i = 0; i <= regexp->re_nsub; i++) { if (pmatch[i].rm_so != -1 && pmatch[i].rm_eo != -1) { Octstr *s = octstr_copy(os, pmatch[i].rm_so, pmatch[i].rm_eo - pmatch[i].rm_so); debug("regex",0,"RE: %d: <%s>", i, octstr_get_cstr(s)); octstr_destroy(s); } } rsub = gw_regex_sub(octstr_get_cstr(sub), octstr_get_cstr(os), REGEX_MAX_SUB_MATCH, &pmatch[0]); debug("regex",0,"RE: substituted string is <%s>.", rsub); gw_free(rsub); } info(0, "step 2: wrapper functions"); debug("regex",0,"RE: regex_match <%s> on <%s> did: %s", octstr_get_cstr(re), octstr_get_cstr(os), gw_regex_match(re, os) ? "match" : "NOT match"); debug("regex",0,"RE: regex_match_pre on <%s> did: %s", octstr_get_cstr(os), gw_regex_match_pre(regexp, os) ? "match" : "NOT match"); tmp = gw_regex_subst(re, os, sub); debug("regex",0,"RE: regex_subst <%s> on <%s> rule <%s>: %s", octstr_get_cstr(re), octstr_get_cstr(os), octstr_get_cstr(sub), octstr_get_cstr(tmp)); octstr_destroy(tmp); tmp = gw_regex_subst_pre(regexp, os, sub); debug("regex",0,"RE: regex_subst_pre on <%s> rule <%s>: %s", octstr_get_cstr(os), octstr_get_cstr(sub), octstr_get_cstr(tmp)); gw_regex_destroy(regexp); octstr_destroy(tmp); octstr_destroy(re); octstr_destroy(os); gwlib_shutdown(); return 0; } #endif gateway-1.4.5/test/header_test0000644000175000017500000002170610073524043015061 0ustar toljtolj| Accept: */* | Accept: text/* | Accept: text/html < Accept: */*; q=0.5, text/html; level =1; q=0.8 ;foo=bar > Accept: */*; q=0.5 > Accept: text/html; level=1; q=0.8; foo="bar" < Accept: application/vnd.wap.something; charset = iso-8859-1; q=1.0 > Accept: application/vnd.wap.something; charset=iso-8859-1 # Test Constrained-charset | Accept-Charset: iso-8859-5 # Test general form with unknown charset and q-value | Accept-Charset: unicode-1-1; q=0.8 # Test general form with known charset > MAX_SHORT_INTEGER | Accept-Charset: big5 < Accept-Charset: big5; q =0.900 > Accept-Charset: big5; q=0.9 < Accept-Charset: big5; q =1.000 > Accept-Charset: big5 # Test general form with known charset and q-value < Accept-Charset: us-ascii;q=0 > Accept-Charset: us-ascii; q=0.0 < Accept-encoding: compress, gzip > Accept-Encoding: compress > Accept-Encoding: gzip < Accept-encoding: | Accept-Encoding: * < Accept-encoding: compress;q=0.5, gzip;q=1.0 # WSP cannot encode q-values with accept-encoding. > Accept-Encoding: compress > Accept-Encoding: gzip < Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0 > Accept-Encoding: gzip > Accept-Encoding: identity # Since WSP cannot encode q-values here, the *;q=0 entry is skipped. < Accept-language: da, en-gb;q=0.8, en;q=0.7 > Accept-Language: da > Accept-Language: en-gb; q=0.8 > Accept-Language: en; q=0.7 | Accept-Language: zx | Accept-Language: *; q=0.0 | Accept-Language: zx; q=0.6 # Test language with code > MAX_SHORT_INTEGER | Accept-Language: vo | Accept-Language: vo; q=0.003 | Accept-Ranges: bytes < Accept-Ranges: Bytes > Accept-Ranges: bytes | Accept-Ranges: none | Accept-Ranges: foo | Age: 5868 | Age: 2147483647 < Allow: GET, head, PUT > Allow: GET > Allow: HEAD > Allow: PUT | Allow: something < Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==, Digest username = "frank", uri= "http://somewhere.org/test;q=0.4", realm ="No, where; near", Digest username = "peter", opaque = "something else; see?", testing = "bla" > Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== > Authorization: Digest username="frank", uri="http://somewhere.org/test;q=0.4", realm="No, where; near" > Authorization: Digest username="peter", opaque="something else; see?", testing="bla" # Some entries are commented out, pending a query about the grammar. < Cache-Control: no-cache, no-store, max-age=5000, max-age=0, max-age=2147483647 > Cache-Control: no-cache > Cache-Control: no-store > Cache-Control: max-age=5000 > Cache-Control: max-age=0 > Cache-Control: max-age=2147483647 < Cache-Control: max-stale, max-stale=5000, max-stale=0, max-stale=2147483647 > Cache-Control: max-stale > Cache-Control: max-stale=5000 > Cache-Control: max-stale=0 > Cache-Control: max-stale=2147483647 < Cache-Control: min-fresh= 5000, min-fresh =0, min-fresh= 2147483647 > Cache-Control: min-fresh=5000 > Cache-Control: min-fresh=0 > Cache-Control: min-fresh=2147483647 < Cache-Control: no-transform, only-if-cached > Cache-Control: no-transform > Cache-Control: only-if-cached #< Cache-Control: foo = bar #> Cache-Control: foo=bar #< Cache-Control: gnu = "Debian GNU/Linux; potato's revenge" #> Cache-Control: gnu="Debian GNU/Linux; potato's revenge" < Cache-Control: public, private = "Allow, Content-length", private = "foo" > Cache-Control: public > Cache-Control: private="Allow, Content-Length" > Cache-Control: private="foo" < Cache-Control: private="*", no-cache="Accept-Language, *", no-store > Cache-Control: private="*" > Cache-Control: no-cache="Accept-Language, *" > Cache-Control: no-store < Cache-Control: no-transform, must-revalidate, proxy-revalidate > Cache-Control: no-transform > Cache-Control: must-revalidate > Cache-Control: proxy-revalidate #< Cache-Control: s-maxage=5000, s-maxage=0, s-maxage=2147483647 #> Cache-Control: s-maxage=5000 #> Cache-Control: s-maxage=0 #> Cache-Control: s-maxage=2147483647 | Cache-Control: foo | Connection: close < Connection: X-WAP-TOD, content-length > Connection: X-WAP-TOD > Connection: content-length | Content-Base: http://foo.org/bar;foo,bar | Content-Encoding: gzip < Content-Encoding: compress;q=0.5, gzip;q=1.0 > Content-Encoding: compress;q=0.5 > Content-Encoding: gzip;q=1.0 < Content-Language: mi, en > Content-Language: mi > Content-Language: en | Content-Language: zx | Content-Length: 5000 | Content-Location: file://etc/passwd | Content-MD5: IgVS2+4DTgdCvoq1jRif1w== # We don't have decode support for Content-Range. #| Content-Range: bytes 50-100/2000 # WSP grammar cannot encode the * entries anyway. #| Content-Range: bytes 50-100/* #| Content-Range: bytes */50 #| Content-Range: bytes */* < Content-Type: text/html; charset=ISO-8859-4 > Content-Type: text/html; charset=iso-8859-4 | Date: Tue, 15 Nov 1994 08:12:31 GMT < Date: Sunday, 06-Nov-94 08:49:37 GMT > Date: Sun, 06 Nov 1994 08:49:37 GMT < Date: Sun Nov 6 08:49:37 1994 > Date: Sun, 06 Nov 1994 08:49:37 GMT | Etag: "floop" | Etag: W/"xyzzy" | Etag: "" | Expires: Tue, 15 Nov 1994 08:12:31 GMT < Expires: Sunday, 06-Nov-94 08:49:37 GMT > Expires: Sun, 06 Nov 1994 08:49:37 GMT < Expires: Sun Nov 6 08:49:37 1994 > Expires: Sun, 06 Nov 1994 08:49:37 GMT | From: devel@kannel.org | Host: www.kannel.org | If-Match: * | If-Match: W/"xyzzy" | If-Match: "foobar" | If-Modified-Since: Tue, 15 Nov 1994 08:12:31 GMT < If-Modified-Since: Sunday, 06-Nov-94 08:49:37 GMT > If-Modified-Since: Sun, 06 Nov 1994 08:49:37 GMT < If-Modified-Since: Sun Nov 6 08:49:37 1994 > If-Modified-Since: Sun, 06 Nov 1994 08:49:37 GMT | If-None-Match: * | If-None-Match: W/"xyzzy" | If-None-Match: "foobar" | If-Range: W/"xyzzy" | If-Range: "foobar" | If-Range: Tue, 15 Nov 1994 08:12:31 GMT < If-Range: Sunday, 06-Nov-94 08:49:37 GMT > If-Range: Sun, 06 Nov 1994 08:49:37 GMT < If-Range: Sun Nov 6 08:49:37 1994 > If-Range: Sun, 06 Nov 1994 08:49:37 GMT | If-Unmodified-Since: Tue, 15 Nov 1994 08:12:31 GMT < If-Unmodified-Since: Sunday, 06-Nov-94 08:49:37 GMT > If-Unmodified-Since: Sun, 06 Nov 1994 08:49:37 GMT < If-Unmodified-Since: Sun Nov 6 08:49:37 1994 > If-Unmodified-Since: Sun, 06 Nov 1994 08:49:37 GMT | Last-Modified: Tue, 15 Nov 1994 08:12:31 GMT < Last-Modified: Sunday, 06-Nov-94 08:49:37 GMT > Last-Modified: Sun, 06 Nov 1994 08:49:37 GMT < Last-Modified: Sun Nov 6 08:49:37 1994 > Last-Modified: Sun, 06 Nov 1994 08:49:37 GMT | Location: http://www.kannel.org/status.shtml | Max-Forwards: 50 | Pragma: no-cache | Pragma: foo="bar" < Pragma: gnu="nasty; string, \"tester", bar=foo > Pragma: gnu="nasty; string, \"tester" > Pragma: bar="foo" < Proxy-Authenticate: Basic realm="WallyWorld", Digest uri= "http://somewhere.org/test;q=0.4", realm ="No, where; near", Digest username = "peter", opaque = "something else; see?", testing = "bla", realm = "need one" > Proxy-Authenticate: Basic realm="WallyWorld" > Proxy-Authenticate: Digest realm="No, where; near", uri="http://somewhere.org/test;q=0.4" > Proxy-Authenticate: Digest realm="need one", username="peter", opaque="something else; see?", testing="bla" < Range: bytes=15-100, 23-42 > Range: bytes = 15-100 > Range: bytes = 23-42 < Range: bytes = -500, -20,-1,0-10 > Range: bytes = -500 > Range: bytes = -20 > Range: bytes = -1 > Range: bytes = 0-10 | Range: bytes = 50- < Range: bytes = 50-,10-20 > Range: bytes = 50- > Range: bytes = 10-20 | Referer: foo/bar | Retry-After: Tue, 15 Nov 1994 08:12:31 GMT < Retry-After: Sunday, 06-Nov-94 08:49:37 GMT > Retry-After: Sun, 06 Nov 1994 08:49:37 GMT < Retry-After: Sun Nov 6 08:49:37 1994 > Retry-After: Sun, 06 Nov 1994 08:49:37 GMT | Retry-After: 5000 | Server: kannel/2.0 | Transfer-Encoding: chunked < Transfer-Encoding: foo; level=3; gnu=bar, Chunked, somethingelse > Transfer-Encoding: foo; level=3; gnu=bar > Transfer-Encoding: chunked > Transfer-Encoding: somethingelse | Upgrade: IRC/6.9 | User-Agent: UP/1.0.1, Mozilla 7.0 < Vary: content-type, content-language > Vary: Content-Type > Vary: Content-Language | Vary: * < Via: 1.0 ricky, 1.1 ethel, 1.1 fred, 1.0 lucy > Via: 1.0 ricky > Via: 1.1 ethel > Via: 1.1 fred > Via: 1.0 lucy | Via: WAP/1.1 localhost # Warnings are translated from 3-digit codes to 2-digit codes because # WSP only encodes 2 digits. < Warning: 110 www.kannel.org "Response is stale" "Tue, 15 Nov 1994 08:12:31 GMT" > Warning: 10 www.kannel.org "Response is stale" < Warning: 112 www.kannel.org "Disconnected operation", 299 www.kannel.org "something else" > Warning: 12 www.kannel.org "Disconnected operation" > Warning: 99 www.kannel.org "something else" < WWW-Authenticate: Basic realm="WallyWorld", Digest uri= "http://somewhere.org/test;q=0.4", realm ="No, where; near", Digest username = "peter", opaque = "something else; see?", testing = "bla", realm = "need one" > WWW-Authenticate: Basic realm="WallyWorld" > WWW-Authenticate: Digest realm="No, where; near", uri="http://somewhere.org/test;q=0.4" > WWW-Authenticate: Digest realm="need one", username="peter", opaque="something else; see?", testing="bla" | Content-Disposition: attachment; name="foo"; filename="foo.jpg" < Content-Disposition: form-data; differences=content-length; padding=9 > Content-Disposition: form-data; differences=Content-Length; padding=9 gateway-1.4.5/test/decompile.h0000644000175000017500000002363213227613126014766 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * decompile.h - Declarations and types used by decompile.c * * Author: Chris Wulff, Vanteon (cwulff@vanteon.com) * */ #ifndef DECOMPILE_H_INCLUDED #define DECOMPILE_H_INCLUDED /* Global Tags */ #define TAG_SWITCH_PAGE 0x00 #define TAG_END 0x01 #define TAG_ENTITY 0x02 #define TAG_STR_I 0x03 #define TAG_LITERAL 0x04 #define TAG_EXT_I_0 0x40 #define TAG_EXT_I_1 0x41 #define TAG_EXT_I_2 0x42 #define TAG_PI 0x43 #define TAG_LITERAL_C 0x44 #define TAG_EXT_T_0 0x80 #define TAG_EXT_T_1 0x81 #define TAG_EXT_T_2 0x82 #define TAG_STR_T 0x83 #define TAG_LITERAL_A 0x84 #define TAG_EXT_0 0xc0 #define TAG_EXT_1 0xc1 #define TAG_EXT_2 0xc2 #define TAG_OPAQUE 0xc3 #define TAG_LITERAL_AC 0xc4 /* Codepage tag masks */ #define CODEPAGE_TAG_MASK ((WBXML_TAG) 0x3f) #define CODEPAGE_TAG_HAS_CONTENT ((WBXML_TAG) 0x40) #define CODEPAGE_TAG_HAS_ATTRS ((WBXML_TAG) 0x80) /* Sizes */ #define SWITCHPAGE_SIZE 2 /* Codepage Tag Types */ typedef enum tagCP_TYPES { CP_TAG_TAG, CP_TAG_ATTRSTART, CP_TAG_ATTRVALUE } CP_TAG_TYPE; /* Datatypes */ typedef int BOOL; #define FALSE 0 #define TRUE 1 typedef unsigned char WBXML; typedef WBXML* P_WBXML; typedef P_WBXML* PP_WBXML; typedef unsigned char WBXML_TAG; typedef WBXML_TAG* P_WBXML_TAG; typedef unsigned char WBXML_CODEPAGE; typedef unsigned long WBXML_LENGTH; typedef enum { NODE_CODEPAGE_TAG, NODE_CODEPAGE_LITERAL_TAG, NODE_ATTRSTART, NODE_ATTRSTART_LITERAL, NODE_ATTRVALUE, NODE_ATTREND, NODE_STRING, NODE_DTD_TYPE, NODE_STRING_TABLE, NODE_VARIABLE_STRING, NODE_VARIABLE_INDEX } WBXML_NODE_TYPE; typedef struct tagWBXML_NODE { void* m_prev; /* (P_WBXML_NODE) the previous sibling */ void* m_next; /* (P_WBXML_NODE) the next sibling */ void* m_child; /* (P_WBXML_NODE) the first child */ void* m_parent; /* (P_WBXML_NODE) the parent */ WBXML_NODE_TYPE m_type; /* type of this node */ WBXML_CODEPAGE m_page; /* the codepage for this node */ void* m_data; /* type specific node data */ } WBXML_NODE; typedef WBXML_NODE* P_WBXML_NODE; typedef enum { VAR_ESCAPED, VAR_UNESCAPED, VAR_UNCHANGED } WBXML_VARIABLE_TYPE; typedef unsigned char WBXML_U_INT8; typedef WBXML_U_INT8* P_WBXML_U_INT8; #define MAX_MB_U_INT32_BYTES 4 typedef unsigned char WBXML_MB_U_INT32[MAX_MB_U_INT32_BYTES]; typedef WBXML_MB_U_INT32* P_WBXML_MB_U_INT32; extern const WBXML_MB_U_INT32 ZERO_WBXML_MB_U_INT32; typedef WBXML_MB_U_INT32 WBXML_STRING_INDEX; typedef WBXML_STRING_INDEX* P_WBXML_STRING_INDEX; typedef unsigned char* WBXML_BYTES; typedef WBXML_BYTES* P_WBXML_BYTES; typedef WBXML_MB_U_INT32 WBXML_DTD_TYPE; typedef struct tagDTD_NODE_DATA { WBXML_DTD_TYPE m_dtdnum; /* DTD number */ WBXML_MB_U_INT32 m_index; /* DTD string table index (for DTD# 0) */ } DTD_NODE_DATA; typedef struct tagWBXML_INFO { P_WBXML m_start; /* Beginning of the binary buffer */ P_WBXML m_curpos; /* Current binary buffer position */ WBXML_LENGTH m_length; /* Length of the binary data */ P_WBXML_NODE m_tree; /* WBXML parse tree */ P_WBXML_NODE m_curnode; /* current parse tree node */ WBXML_CODEPAGE m_curpage; /* the current codepage */ } WBXML_INFO; typedef WBXML_INFO* P_WBXML_INFO; typedef struct tagWBXML_STRING_TABLE { WBXML_MB_U_INT32 m_length; WBXML_BYTES m_strings; } WBXML_STRING_TABLE; typedef WBXML_STRING_TABLE* P_WBXML_STRING_TABLE; typedef enum tagWBXML_PARSE_ERROR { ERR_END_OF_DATA, ERR_INTERNAL_BAD_PARAM, ERR_TAG_NOT_FOUND, ERR_FILE_NOT_FOUND, ERR_FILE_NOT_READ, ERR_NOT_ENOUGH_MEMORY } WBXML_PARSE_ERROR; typedef enum tagWBXML_PARSE_WARNING { WARN_FUTURE_EXPANSION_EXT_0, WARN_FUTURE_EXPANSION_EXT_1, WARN_FUTURE_EXPANSION_EXT_2 } WBXML_PARSE_WARNING; typedef struct tagDTD_TYPE_LIST { long m_id; char* m_name; } DTD_TYPE_LIST; typedef struct tagCODEPAGE_TAG_NAME_LIST { long m_dtd_id; char* m_name; WBXML_CODEPAGE m_page; WBXML_TAG m_tag; } CODEPAGE_TAG_NAME_LIST; typedef CODEPAGE_TAG_NAME_LIST* P_CODEPAGE_TAG_NAME_LIST; typedef struct tagCODEPAGE_ATTRSTART_NAME_LIST { long m_dtd_id; char* m_name; char* m_valueprefix; WBXML_CODEPAGE m_page; WBXML_TAG m_tag; } CODEPAGE_ATTRSTART_NAME_LIST; typedef CODEPAGE_ATTRSTART_NAME_LIST* P_CODEPAGE_ATTRSTART_NAME_LIST; typedef struct tagCODEPAGE_ATTRVALUE_NAME_LIST { long m_dtd_id; char* m_name; WBXML_CODEPAGE m_page; WBXML_TAG m_tag; } CODEPAGE_ATTRVALUE_NAME_LIST; typedef CODEPAGE_ATTRVALUE_NAME_LIST* P_CODEPAGE_ATTRVALUE_NAME_LIST; /* Flow Control Prototypes */ void Message(char* msg); void ParseError(WBXML_PARSE_ERROR error); void ParseWarning(WBXML_PARSE_WARNING warning); WBXML_LENGTH BytesLeft(P_WBXML_INFO buffer); BOOL IsTag(P_WBXML_INFO buffer, WBXML_TAG tag); BOOL IsCodepageTag(P_WBXML_INFO buffer, CP_TAG_TYPE type); BOOL Is_attrValue (P_WBXML_INFO buffer); BOOL Is_extension (P_WBXML_INFO buffer); BOOL Is_string (P_WBXML_INFO buffer); BOOL Is_switchPage (P_WBXML_INFO buffer); BOOL Is_inline (P_WBXML_INFO buffer); BOOL Is_tableref (P_WBXML_INFO buffer); BOOL Is_entity (P_WBXML_INFO buffer); BOOL Is_pi (P_WBXML_INFO buffer); BOOL Is_opaque (P_WBXML_INFO buffer); BOOL Is_zero (P_WBXML_INFO buffer); /* Basic Type Decoder Prototypes */ void Read_u_int8 (P_WBXML_INFO buffer, P_WBXML_U_INT8 result); void Read_mb_u_int32 (P_WBXML_INFO buffer, P_WBXML_MB_U_INT32 result); void Read_bytes (P_WBXML_INFO buffer, WBXML_LENGTH length, P_WBXML_BYTES result); void ReadFixedTag (P_WBXML_INFO buffer, WBXML_TAG tag); WBXML_TAG ReadCodepageTag (P_WBXML_INFO buffer, CP_TAG_TYPE type); /* Basic Type Conversion Prototypes */ long mb_u_int32_to_long(P_WBXML_MB_U_INT32 value); /* Document Structure Decoder Prototypes */ void Read_start (P_WBXML_INFO buffer); void Read_strtbl (P_WBXML_INFO buffer); void Read_body (P_WBXML_INFO buffer); void Read_element (P_WBXML_INFO buffer); void Read_content (P_WBXML_INFO buffer); WBXML_TAG Read_stag (P_WBXML_INFO buffer); void Read_attribute (P_WBXML_INFO buffer); void Read_attrStart (P_WBXML_INFO buffer); void Read_attrValue (P_WBXML_INFO buffer); void Read_extension (P_WBXML_INFO buffer); void Read_string (P_WBXML_INFO buffer); void Read_switchPage (P_WBXML_INFO buffer); void Read_inline (P_WBXML_INFO buffer); void Read_tableref (P_WBXML_INFO buffer); void Read_entity (P_WBXML_INFO buffer); void Read_entcode (P_WBXML_INFO buffer); void Read_pi (P_WBXML_INFO buffer); void Read_opaque (P_WBXML_INFO buffer); void Read_version (P_WBXML_INFO buffer); void Read_publicid (P_WBXML_INFO buffer); void Read_charset (P_WBXML_INFO buffer); void Read_termstr (P_WBXML_INFO buffer); void Read_termstr_rtn(P_WBXML_INFO buffer, char** result); void Read_index (P_WBXML_INFO buffer, P_WBXML_MB_U_INT32 result); void Read_length (P_WBXML_INFO buffer, P_WBXML_MB_U_INT32 result); void Read_zero (P_WBXML_INFO buffer); void Read_pageindex (P_WBXML_INFO buffer, P_WBXML_U_INT8 result); #endif /* _DECOMPILE_H_INCLUDED_ */ gateway-1.4.5/test/test_cfg.c0000644000175000017500000000650513227613126014616 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include "gwlib/gwlib.h" int main(int argc, char **argv) { Cfg *cfg; int ret = 1; Octstr *name; int i; gwlib_init(); get_and_set_debugs(argc, argv, NULL); if (argc < 2) panic(0, "Syntax: %s \n", argv[0]); for (i = 1; i < argc; ++i) { name = octstr_create(argv[i]); cfg = cfg_create(name); octstr_destroy(name); ret = cfg_read(cfg); info(0, "cfg_read returned %d", ret); if (ret == 0) cfg_dump(cfg); cfg_destroy(cfg); } info(0, "Shutting down."); gwlib_shutdown(); return ret; } gateway-1.4.5/test/test_pcre.c0000644000175000017500000001030713227613126015003 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_pcre.c - test pcre module * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" #include "gwlib/pcre.h" #ifdef HAVE_PCRE int main(int argc, char **argv) { Octstr *re, *os; pcre *regexp; int ovector[PCRE_OVECCOUNT]; int rc; gwlib_init(); get_and_set_debugs(argc, argv, NULL); os = octstr_create(argv[1]); re = octstr_create(argv[2]); info(0, "step 1: generic functions"); /* compile */ if ((regexp = gw_pcre_comp(re, 0)) == NULL) panic(0, "pcre compilation failed!"); /* execute */ rc = gw_pcre_exec(regexp, os, 0, 0, ovector, PCRE_OVECCOUNT); if (rc == PCRE_ERROR_NOMATCH) { info(0, "RE: pcre <%s> did not match on string <%s>.", octstr_get_cstr(re), octstr_get_cstr(os)); } else if (rc < 0) { error(0, "RE: pcre <%s> execution failed with error %d.", octstr_get_cstr(re), rc); } else { info(0, "RE: pcre <%s> matches.", octstr_get_cstr(re)); } info(0, "step 2: wrapper functions"); debug("pcre",0,"RE: pcre_match <%s> on <%s> did: %s", octstr_get_cstr(re), octstr_get_cstr(os), gw_pcre_match(re, os) ? "match" : "NOT match"); debug("pcre",0,"RE: pcre_match_pre on <%s> did: %s", octstr_get_cstr(os), gw_pcre_match_pre(regexp, os) ? "match" : "NOT match"); octstr_destroy(re); octstr_destroy(os); gwlib_shutdown(); return 0; } #endif gateway-1.4.5/test/udpfeed.c0000644000175000017500000001251413227613126014431 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* udpfeed.c - blindly send UDP packets to a certain port * * This little tool reads a bunch of files and sends each of them * to a given port as a single UDP packets. It's useful for running * sets of test packets to see if any of them will crash the gateway. * By default, it sends them at one-second intervals. */ #include #include "gwlib/gwlib.h" #define UDP_MAXIMUM (65535 - 40) static unsigned char usage[] = "\ Usage: udpfeed [options] files...\n\ \n\ where options are:\n\ \n\ -h help\n\ -g hostname name of IP number of host to send to (default: localhost)\n\ -p port port number to send to (default: 9200)\n\ -i interval delay between packers (default: 1.0 seconds)\n\ \n\ Each file will be sent as a single packet.\n\ "; static Octstr *hostname; static int port = 9200; /* By default, the sessionless WSP port */ static double interval = 1.0; /* Default interval (seconds) between packets */ static long maxsize = UDP_MAXIMUM; /* Maximum packet size in octets */ static void help(void) { info(0, "\n%s", usage); } static void send_file(int udpsock, char *filename, Octstr *address) { Octstr *contents; contents = octstr_read_file(filename); if (contents == NULL) { info(0, "Skipping \"%s\".", filename); return; } info(0, "Sending \"%s\", %ld octets.", filename, octstr_len(contents)); if (octstr_len(contents) > maxsize) { octstr_truncate(contents, maxsize); warning(0, "Truncating to %ld octets.", maxsize); } udp_sendto(udpsock, contents, address); octstr_destroy(contents); } int main(int argc, char **argv) { int opt; Octstr *address; int udpsock; gwlib_init(); /* Set defaults that can't be set statically */ hostname = octstr_create("localhost"); while ((opt = getopt(argc, argv, "hg:p:i:m:")) != EOF) { switch(opt) { case 'g': octstr_destroy(hostname); hostname = octstr_create(optarg); break; case 'p': port = atoi(optarg); break; case 'i': interval = atof(optarg); break; case 'm': maxsize = atol(optarg); if (maxsize > UDP_MAXIMUM) { maxsize = UDP_MAXIMUM; warning(0, "-m: truncated to UDP maximum of" "%ld bytes.", maxsize); } break; case 'h': help(); exit(0); break; case '?': default: error(0, "Unknown option '%c'", opt); help(); exit(1); break; } } address = udp_create_address(hostname, port); udpsock = udp_client_socket(); if (udpsock < 0) exit(1); for ( ; optind < argc; optind++) { send_file(udpsock, argv[optind], address); if (interval > 0 && optind + 1 < argc) gwthread_sleep(interval); } octstr_destroy(address); octstr_destroy(hostname); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_dict.c0000644000175000017500000001152713227613126015002 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_dict.c - test Dict objects * * Lars Wirzenius * Stipe Tolj */ #include "gwlib/gwlib.h" #define HUGE_SIZE 200000 int main(void) { Dict *dict1, *dict2; Octstr *key; unsigned long i; List *keys; gwlib_init(); debug("",0,"Dict populate phase."); dict1 = dict_create(HUGE_SIZE, octstr_destroy_item); dict2 = dict_create(HUGE_SIZE, octstr_destroy_item); for (i = 1; i <= HUGE_SIZE; i++) { Octstr *okey, *oval; uuid_t id1, id2; char key[UUID_STR_LEN + 1]; char val[UUID_STR_LEN + 1]; uuid_generate(id1); uuid_generate(id2); uuid_unparse(id1, key); uuid_unparse(id2, val); okey = octstr_create(key); oval = octstr_create(val); dict_put(dict1, okey, oval); dict_put(dict2, oval, okey); } if (dict_key_count(dict1) == HUGE_SIZE) info(0, "ok, got %d entries in dict1.", HUGE_SIZE); else error(0, "key count is %ld, should be %d in dict1.", dict_key_count(dict1), HUGE_SIZE); if (dict_key_count(dict2) == HUGE_SIZE) info(0, "ok, got %d entries in dict2.", HUGE_SIZE); else error(0, "key count is %ld, should be %d in dict2.", dict_key_count(dict2), HUGE_SIZE); debug("",0,"Dict lookup phase."); keys = dict_keys(dict1); while ((key = gwlist_extract_first(keys)) != NULL) { Octstr *oval1, *oval2; if ((oval1 = dict_get(dict1, key)) != NULL) { if ((oval2 = dict_get(dict2, oval1)) != NULL) { if (octstr_compare(oval2, key) != 0) { error(0, "Dict cross-key check inconsistent:"); error(0, "dict1: key <%s>, value <%s>", octstr_get_cstr(key), octstr_get_cstr(oval1)); error(0, "dict2: key <%s>, value <%s>", octstr_get_cstr(oval1), octstr_get_cstr(oval2)); } } else { error(0, "dict2 key %s has NULL value.", octstr_get_cstr(key)); } } else { error(0, "dict1 key %s has NULL value.", octstr_get_cstr(key)); } octstr_destroy(key); } gwlist_destroy(keys, NULL); dict_destroy(dict1); dict_destroy(dict2); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_pap.c0000644000175000017500000001100113227613126014622 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_pap.c: A simple program to test pap compiler * * By Aarno Syvänen for Wiral Ltd */ #include #include "gwlib/gwlib.h" #include "gw/wap_push_pap_compiler.h" #include "wap/wap_events.h" static void help (void) { info(0, "Usage test_pap [option] pap_source"); info(0, "where options are"); info(0, "-h print this text"); info(0, "-v level set log level for stderr logging"); info(0, "-l log wap event to this file"); } int main(int argc, char **argv) { int opt, ret; Octstr *pap_doc, *log_file; WAPEvent *e; log_file = NULL; gwlib_init(); while ((opt = getopt(argc, argv, "h:v:l:")) != EOF) { switch (opt) { case 'h': help(); exit(1); break; case 'v': log_set_output_level(atoi(optarg)); break; case 'l': octstr_destroy(log_file); log_file = octstr_create(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping"); break; } } if (optind >= argc) { error(0, "Missing arguments"); help(); panic(0, "Stopping"); } if (log_file != NULL) { log_open(octstr_get_cstr(log_file), GW_DEBUG, GW_NON_EXCL); octstr_destroy(log_file); } pap_doc = octstr_read_file(argv[optind]); if (pap_doc == NULL) panic(0, "Cannot read the pap document"); e = NULL; ret = pap_compile(pap_doc, &e); if (ret < 0) { debug("test.pap", 0, "Unable to compile the pap document, rc %d", ret); return 1; } debug("test.pap", 0, "Compiling successfull, wap event being:\n"); wap_event_dump(e); wap_event_destroy(e); octstr_destroy(pap_doc); gwlib_shutdown(); return 0; } gateway-1.4.5/test/http2-test-urls0000644000175000017500000000023207100163500015554 0ustar toljtoljhttp://localhost http://www.kannel.org http://www.wapit.com http://www.wapit.com/~liw/hello.wml http://www.wapit.com/~liw/cgi-bin/rafla.cgi?pattern=pihvi gateway-1.4.5/test/test_xmlrpc.c0000644000175000017500000003246113227613126015364 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_xmlrpc.c: A simple program to test XML-RPC parsing * * Stipe Tolj */ #include #include #include #include #include "gwlib/gwlib.h" #include "gwlib/http.h" #include "gwlib/xmlrpc.h" #define MAX_THREADS 1024 #define MAX_IN_QUEUE 128 static Counter *counter = NULL; static long max_requests = 1; /*static int verbose = 1;*/ static Octstr *auth_username = NULL; static Octstr *auth_password = NULL; static Octstr *ssl_client_certkey_file = NULL; static Octstr *extra_headers = NULL; static Octstr *content_file = NULL; static Octstr *url = NULL; static int file = 0; static XMLRPCDocument *msg; static void start_request(HTTPCaller *caller, List *reqh, long i) { long *id; if ((i % 1000) == 0) info(0, "Starting fetch %ld", i); id = gw_malloc(sizeof(long)); *id = i; /* * not semd the XML-RPC document contained in msg to * the URL 'url' using the POST method */ xmlrpc_send_call(msg, caller, url, reqh, id); debug("", 0, "Started request %ld.", *id); /* debug("", 0, "Started request %ld with url:", *id); octstr_url_decode(url); octstr_dump(url, 0); */ } static int receive_reply(HTTPCaller *caller) { void *id; int ret; Octstr *final_url; List *replyh; Octstr *replyb; Octstr *output; XMLRPCDocument *xrdoc; /* Octstr *type, *os_xrdoc, *os; Octstr *charset; */ id = http_receive_result(caller, &ret, &final_url, &replyh, &replyb); octstr_destroy(final_url); if (id == NULL || ret == -1) { error(0, "http POST failed"); gw_free(id); return -1; } debug("", 0, "Done with request %ld", *(long *) id); gw_free(id); /* http_header_get_content_type(replyh, &type, &charset); debug("", 0, "Content-type is <%s>, charset is <%s>", octstr_get_cstr(type), octstr_get_cstr(charset)); octstr_destroy(type); octstr_destroy(charset); if (verbose) debug("", 0, "Reply headers:"); while ((os = gwlist_extract_first(replyh)) != NULL) { if (verbose) octstr_dump(os, 1); octstr_destroy(os); } if (verbose) { debug("", 0, "Reply body:"); octstr_dump(replyb, 1); } */ xrdoc = xmlrpc_parse_response(replyb); debug("", 0, "Parsed xmlrpc"); if ((xmlrpc_parse_status(xrdoc) != XMLRPC_COMPILE_OK) && ((output = xmlrpc_parse_error(xrdoc)) != NULL)) { /* parse failure */ error(0, "%s", octstr_get_cstr(output)); octstr_destroy(output); return -1; } else { /*parse proper xmlrpc */ if (xmlrpc_is_fault(xrdoc)) { Octstr *fstring = xmlrpc_get_faultstring(xrdoc); debug("xr", 0, "Got fault response with code:%ld and description: %s", xmlrpc_get_faultcode(xrdoc), octstr_get_cstr(fstring)); octstr_destroy(fstring); http_destroy_headers(replyh); octstr_destroy(replyb); return -1; } /* os_xrdoc = xmlrpc_print_response(xrdoc); debug("xr", 0, "XMLRPC response:"); octstr_dump(os_xrdoc, 0); */ } http_destroy_headers(replyh); octstr_destroy(replyb); return 0; } static void client_thread(void *arg) { List *reqh; long i, succeeded, failed; HTTPCaller *caller; char buf[1024]; long in_queue; caller = arg; succeeded = 0; failed = 0; reqh = gwlist_create(); sprintf(buf, "%ld", (long) gwthread_self()); http_header_add(reqh, "X-Thread", buf); if (auth_username != NULL && auth_password != NULL) http_add_basic_auth(reqh, auth_username, auth_password); in_queue = 0; for (;;) { while (in_queue < MAX_IN_QUEUE) { i = counter_increase(counter); if (i >= max_requests) goto receive_rest; start_request(caller, reqh, i); #if 1 gwthread_sleep(0.1); #endif ++in_queue; } while (in_queue >= MAX_IN_QUEUE) { if (receive_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } } receive_rest: while (in_queue > 0) { if (receive_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } http_caller_destroy(caller); info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed); } static void help(void) { info(0, "Usage: test_xmlrpc [options] xml_source"); info(0, "where options are:"); info(0, "-u URL"); info(0, " send XML-RPC source as POST HTTP request to URL"); info(0, "-v number"); info(0, " set log level for stderr logging"); info(0, "-q"); info(0, " don't print the body or headers of the HTTP response"); info(0, "-r number"); info(0, " make `number' requests, repeating URLs as necessary"); info(0, "-p domain.name"); info(0, " use `domain.name' as a proxy"); info(0, "-P portnumber"); info(0, " connect to proxy at port `portnumber'"); info(0, "-S"); info(0, " use HTTPS scheme to access SSL-enabled proxy server"); info(0, "-e domain1:domain2:..."); info(0, " set exception list for proxy use"); info(0, "-s"); info(0, " use HTTPS scheme to access SSL-enabled HTTP server"); info(0, "-c ssl_client_cert_key_file"); info(0, " use this file as the SSL certificate and key file"); } int main(int argc, char **argv) { int i, opt, num_threads; Octstr *proxy; List *exceptions; long proxy_port; int proxy_ssl = 0; Octstr *proxy_username; Octstr *proxy_password; Octstr *exceptions_regex; char *p; long threads[MAX_THREADS]; time_t start, end; double run_time; Octstr *output, *xml_doc; int ssl = 0; gwlib_init(); proxy = NULL; proxy_port = -1; exceptions = gwlist_create(); proxy_username = NULL; proxy_password = NULL; exceptions_regex = NULL; num_threads = 0; file = 0; while ((opt = getopt(argc, argv, "hvr:t:p:u:P:Se:a:sc:")) != EOF) { switch (opt) { case 'h': help(); exit(1); break; case 'v': log_set_output_level(atoi(optarg)); break; case 'r': max_requests = atoi(optarg); break; case 't': num_threads = atoi(optarg); if (num_threads > MAX_THREADS) num_threads = MAX_THREADS; break; case 'p': proxy = octstr_create(optarg); break; case 'u': url = octstr_create(optarg); break; case 'P': proxy_port = atoi(optarg); break; case 'S': proxy_ssl = 1; break; case 'e': p = strtok(optarg, ":"); while (p != NULL) { gwlist_append(exceptions, octstr_create(p)); p = strtok(NULL, ":"); } break; case 'E': exceptions_regex = octstr_create(optarg); break; case 'a': p = strtok(optarg, ":"); if (p != NULL) { auth_username = octstr_create(p); p = strtok(NULL, ""); if (p != NULL) auth_password = octstr_create(p); } break; case 's': ssl = 1; break; case 'c': octstr_destroy(ssl_client_certkey_file); ssl_client_certkey_file = octstr_create(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping"); break; } } if (optind >= argc) { error(0, "Missing arguments"); help(); panic(0, "Stopping"); } #ifdef HAVE_LIBSSL /* * check if we are doing a SSL-enabled client version here * load the required cert and key file */ if (ssl || proxy_ssl) { if (ssl_client_certkey_file != NULL) { conn_use_global_client_certkey_file(ssl_client_certkey_file); } else { panic(0, "client certkey file need to be given!"); } } #endif if (proxy != NULL && proxy_port > 0) { http_use_proxy(proxy, proxy_port, proxy_ssl, exceptions, proxy_username, proxy_password, exceptions_regex); } octstr_destroy(proxy); octstr_destroy(proxy_username); octstr_destroy(proxy_password); octstr_destroy(exceptions_regex); gwlist_destroy(exceptions, octstr_destroy_item); counter = counter_create(); xml_doc = octstr_read_file(argv[optind]); if (xml_doc == NULL) panic(0, "Cannot read the XML document"); /* * parse the XML source */ msg = xmlrpc_parse_call(xml_doc); if ((xmlrpc_parse_status(msg) != XMLRPC_COMPILE_OK) && ((output = xmlrpc_parse_error(msg)) != NULL)) { /* parse failure */ error(0, "%s", octstr_get_cstr(output)); octstr_destroy(output); } /* * if no POST is desired then dump the re-formated XML */ if (url != NULL) { time(&start); if (num_threads == 0) client_thread(http_caller_create()); else { for (i = 0; i < num_threads; ++i) threads[i] = gwthread_create(client_thread, http_caller_create()); for (i = 0; i < num_threads; ++i) gwthread_join(threads[i]); } time(&end); run_time = difftime(end, start); info(0, "%ld requests in %f seconds, %f requests/s.", max_requests, run_time, max_requests / run_time); octstr_destroy(url); } else { output = xmlrpc_print_call(msg); if (output != NULL) { octstr_print(stderr, output); octstr_destroy(output); } } counter_destroy(counter); octstr_destroy(auth_username); octstr_destroy(auth_password); octstr_destroy(ssl_client_certkey_file); octstr_destroy(extra_headers); octstr_destroy(content_file); xmlrpc_destroy_call(msg); octstr_destroy(xml_doc); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_hash.c0000644000175000017500000001073513245353052015001 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_hash.c - test MD5 and SHA1 routines. * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" #ifdef HAVE_LIBSSL #if OPENSSL_VERSION_NUMBER < 0x10100000L static Octstr *our_hash_func(Octstr *os) { /* use openssl's SHA1 */ EVP_MD_CTX mdctx; const EVP_MD *md; unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len; md = EVP_get_digestbyname("sha1"); EVP_MD_CTX_init(&mdctx); EVP_DigestInit_ex(&mdctx, md, NULL); EVP_DigestUpdate(&mdctx, octstr_get_cstr(os), octstr_len(os)); EVP_DigestFinal_ex(&mdctx, md_value, &md_len); EVP_MD_CTX_cleanup(&mdctx); return octstr_create_from_data((char*) md_value, md_len); } #else static Octstr *our_hash_func(Octstr *os) { unsigned char hash[20]; memset(hash, 0, sizeof(hash)); SHA1((const unsigned char *)octstr_get_cstr(os), octstr_len(os), hash); return octstr_create_from_data((const char*)hash, sizeof(hash)); } #endif #endif int main(int argc, char **argv) { Octstr *data, *enc; gwlib_init(); get_and_set_debugs(argc, argv, NULL); if (argc < 2) panic(0, "Syntax: %s \n", argv[0]); data = octstr_create(argv[1]); enc = md5(data); debug("",0,"MD5:"); octstr_dump(enc, 0); octstr_destroy(enc); enc = md5digest(data); debug("",0,"MD5 (digest):"); octstr_dump(enc, 0); #ifdef HAVE_LIBSSL OpenSSL_add_all_digests(); octstr_destroy(enc); enc = our_hash_func(data); debug("",0,"SHA1:"); octstr_dump(enc, 0); octstr_binary_to_hex(enc, 0); debug("",0,"SHA1 (digest):"); octstr_dump(enc, 0); #endif octstr_destroy(data); octstr_destroy(enc); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_smsc.c0000644000175000017500000005144313227613126015025 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include #include "gwlib/gwlib.h" #include "gw/smsc/smpp_pdu.h" #include /*********************************************************************** * Configurable stuff. */ /* * The port at which our HTTP server emulator listens. */ static long http_port = 8080; /* * The HTTP admin port and password for Kannel, needed to do shutdown. */ static long admin_port = 13000; static char *admin_password = "bar"; /* * The port at which the SMPP SMS center emulator listens. */ static long smpp_port = 2345; /* * Number of messages to use in the "Send N messages as fast as possible" * benchmark. */ static long num_messages = 1; /*********************************************************************** * Events and event queues. */ typedef List EventQueue; typedef struct Event { enum event_type { got_smsc, deliver, deliver_ack, http_request, http_response, submit, got_enquire_link } type; long id; long time; Connection *conn; /* SMPP: Connection for response PDU */ long sequence_number; /* SMPP: Sequence number of resp PDU */ /* HTTP related stuff */ HTTPClient *client; Octstr *body; } Event; static Counter *event_id_counter = NULL; static const char *eq_type(Event *e) { #define TYPE(name) case name: return #name; switch (e->type) { TYPE(got_smsc) TYPE(deliver) TYPE(deliver_ack) TYPE(http_request) TYPE(http_response) TYPE(submit) TYPE(got_enquire_link) } #undef TYPE return "unknown"; } static Event *eq_create_event(enum event_type type) { Event *e; e = gw_malloc(sizeof(*e)); e->type = type; e->time = date_universal_now(); e->id = counter_increase(event_id_counter); e->conn = NULL; e->sequence_number = -1; e->client = NULL; e->body = NULL; return e; } static Event *eq_create_submit(Connection *conn, long sequence_number, Octstr *body) { Event *e; gw_assert(conn != NULL); gw_assert(sequence_number >= 0); e = eq_create_event(submit); e->conn = conn; e->sequence_number = sequence_number; e->body = octstr_duplicate(body); return e; } static Event *eq_create_http_request(HTTPClient *client, Octstr *body) { Event *e; gw_assert(client != NULL); gw_assert(body != NULL); e = eq_create_event(http_request); e->client = client; e->body = octstr_duplicate(body); return e; } static void eq_destroy_event(Event *e) { octstr_destroy(e->body); gw_free(e); } static EventQueue *eq_create(void) { return gwlist_create(); } static void eq_add_producer(EventQueue *eq) { gwlist_add_producer(eq); } static void eq_remove_producer(EventQueue *eq) { gwlist_remove_producer(eq); } static void eq_destroy(EventQueue *eq) { gwlist_destroy(eq, NULL); } static void eq_append(EventQueue *eq, Event *e) { gwlist_produce(eq, e); } static Event *eq_extract(EventQueue *eq) { return gwlist_consume(eq); } static void eq_log(Event *e) { info(0, "Event %ld, type %s, time %ld", e->id, eq_type(e), e->time); } static void eq_init(void) { event_id_counter = counter_create(); } static void eq_shutdown(void) { counter_destroy(event_id_counter); } static long eq_round_trip_time(Event *e) { long now, then; now = date_universal_now(); if (octstr_parse_long(&then, e->body, 0, 10) == -1) return 0; return now - then; } /*********************************************************************** * SMS center emulator, declarations. */ struct smsc_emu_arg { Semaphore *sema; EventQueue *eq; }; static EventQueue *undelivered_messages = NULL; /*********************************************************************** * SMS center emulator, SMPP internals. */ enum { MAX_THREADS = 2 }; enum { SMPP_MAX_QUEUE = 10 }; struct smpp_emu_arg { EventQueue *eq; Connection *conn; long id; Semaphore *ok_to_send; long writer_id; int quit; }; static Counter *smpp_emu_counter = NULL; static void smpp_emu_writer(void *arg) { Event *e; SMPP_PDU *pdu; Octstr *os; struct smpp_emu_arg *p; p = arg; for (;;) { semaphore_down(p->ok_to_send); e = eq_extract(undelivered_messages); if (e == NULL) break; e->time = date_universal_now(); eq_log(e); pdu = smpp_pdu_create(deliver_sm, counter_increase(smpp_emu_counter)); pdu->u.deliver_sm.source_addr = octstr_create("123"); pdu->u.deliver_sm.destination_addr = octstr_create("456"); pdu->u.deliver_sm.short_message = octstr_format("%ld", e->time); os = smpp_pdu_pack(NULL, pdu); conn_write(p->conn, os); octstr_destroy(os); smpp_pdu_destroy(pdu); eq_destroy_event(e); } } static void smpp_emu_handle_pdu(struct smpp_emu_arg *p, SMPP_PDU *pdu) { SMPP_PDU *resp; Octstr *os; resp = NULL; switch (pdu->type) { case bind_transmitter: resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter.sequence_number); break; case bind_receiver: resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number); eq_append(p->eq, eq_create_event(got_smsc)); gw_assert(p->writer_id == -1); p->writer_id = gwthread_create(smpp_emu_writer, p); if (p->writer_id == -1) panic(0, "Couldn't create SMPP helper thread."); break; case submit_sm: eq_append(p->eq, eq_create_submit(p->conn, pdu->u.submit_sm.sequence_number, pdu->u.submit_sm.short_message)); break; case deliver_sm_resp: eq_append(p->eq, eq_create_event(deliver_ack)); semaphore_up(p->ok_to_send); break; case enquire_link: eq_append(p->eq, eq_create_event(got_enquire_link)); resp = smpp_pdu_create(enquire_link_resp, pdu->u.enquire_link.sequence_number); break; case unbind: resp = smpp_pdu_create(unbind_resp, pdu->u.unbind.sequence_number); break; default: error(0, "SMPP: Unhandled PDU type %s", pdu->type_name); break; } if (resp != NULL) { os = smpp_pdu_pack(NULL, resp); conn_write(p->conn, os); octstr_destroy(os); smpp_pdu_destroy(resp); } } static void smpp_emu_reader(void *arg) { Octstr *os; long len; SMPP_PDU *pdu; struct smpp_emu_arg *p; p = arg; len = 0; while (!p->quit && conn_wait(p->conn, -1.0) != -1) { for (;;) { if (len == 0) { len = smpp_pdu_read_len(p->conn); if (len == -1) { error(0, "Client sent garbage, closing connection."); goto error; } else if (len == 0) { if (conn_eof(p->conn) || conn_error(p->conn)) goto error; break; } } gw_assert(len > 0); os = smpp_pdu_read_data(p->conn, len); if (os != NULL) { len = 0; pdu = smpp_pdu_unpack(NULL, os); if (pdu == NULL) { error(0, "PDU unpacking failed!"); octstr_dump(os, 0); } else { smpp_emu_handle_pdu(p, pdu); smpp_pdu_destroy(pdu); } octstr_destroy(os); } else if (conn_eof(p->conn) || conn_error(p->conn)) goto error; else break; } } error: if (p->writer_id != -1) gwthread_join(p->writer_id); } static void smpp_emu(void *arg) { EventQueue *eq; struct smsc_emu_arg *p; int fd; int new_fd; Octstr *client_addr; long i; long num_threads; struct smpp_emu_arg *thread[MAX_THREADS]; p = arg; eq = p->eq; eq_add_producer(eq); semaphore_up(p->sema); /* * Wait for SMPP clients. */ fd = make_server_socket(smpp_port, NULL); if (fd == -1) panic(0, "Couldn't create SMPP listen port."); num_threads = 0; for (;;) { new_fd = gw_accept(fd, &client_addr); if (new_fd == -1) break; octstr_destroy(client_addr); if (num_threads == MAX_THREADS) { warning(0, "Too many SMPP client connections."); (void) close(new_fd); } else { thread[num_threads] = gw_malloc(sizeof(*thread[0])); thread[num_threads]->conn = conn_wrap_fd(new_fd, 0); thread[num_threads]->eq = eq; thread[num_threads]->quit = 0; thread[num_threads]->writer_id = -1; thread[num_threads]->ok_to_send = semaphore_create(SMPP_MAX_QUEUE); thread[num_threads]->id = gwthread_create(smpp_emu_reader, thread[num_threads]); if (thread[num_threads]->id == -1) panic(0, "Couldn't start SMPP subthread."); ++num_threads; } } for (i = 0; i < num_threads; ++i) { thread[i]->quit = 1; gwthread_wakeup(thread[i]->id); gwthread_join(thread[i]->id); conn_destroy(thread[i]->conn); semaphore_destroy(thread[i]->ok_to_send); gw_free(thread[i]); } eq_remove_producer(eq); } /*********************************************************************** * SMS center emulator, generic interface. */ static long smpp_emu_id = -1; /* * Start all SMS center emulators. */ static void smsc_emu_create(EventQueue *eq) { struct smsc_emu_arg *arg; gw_assert(smpp_emu_id == -1); arg = gw_malloc(sizeof(*arg)); arg->sema = semaphore_create(0); arg->eq = eq; smpp_emu_id = gwthread_create(smpp_emu, arg); if (smpp_emu_id == -1) panic(0, "Couldn't start SMPP emulator thread."); semaphore_down(arg->sema); semaphore_destroy(arg->sema); gw_free(arg); } static void smsc_emu_destroy(void) { eq_remove_producer(undelivered_messages); gw_assert(smpp_emu_id != -1); gwthread_wakeup(smpp_emu_id); gwthread_join(smpp_emu_id); } static void smsc_emu_deliver(void) { eq_append(undelivered_messages, eq_create_event(deliver)); } static void smsc_emu_submit_ack(Event *e) { SMPP_PDU *resp; Octstr *os; resp = smpp_pdu_create(submit_sm_resp, e->sequence_number); os = smpp_pdu_pack(NULL, resp); conn_write(e->conn, os); octstr_destroy(os); smpp_pdu_destroy(resp); } static void smsc_emu_init(void) { smpp_emu_counter = counter_create(); undelivered_messages = eq_create(); eq_add_producer(undelivered_messages); } static void smsc_emu_shutdown(void) { counter_destroy(smpp_emu_counter); eq_destroy(undelivered_messages); } /*********************************************************************** * HTTP server emulator. */ static List *httpd_emu_headers = NULL; struct httpd_emu_arg { int port; Semaphore *sema; EventQueue *eq; }; /* * This is the HTTP server emulator thread. */ static void httpd_emu(void *arg) { HTTPClient *client; Octstr *ip; Octstr *url; List *headers; Octstr *body; List *cgivars; struct httpd_emu_arg *p; EventQueue *eq; p = arg; eq = p->eq; eq_add_producer(eq); semaphore_up(p->sema); for (;;) { client = http_accept_request(p->port, &ip, &url, &headers, &body, &cgivars); if (client == NULL) break; eq_append(eq, eq_create_http_request(client, http_cgi_variable(cgivars, "arg"))); octstr_destroy(ip); octstr_destroy(url); http_destroy_headers(headers); octstr_destroy(body); http_destroy_cgiargs(cgivars); } eq_remove_producer(eq); gw_free(p); } /* * Thread id for HTTP server emulator thread. It is needed for proper * shutdown. */ static long httpd_emu_tid = -1; /* * Start the HTTP server emulator thread and return when it is * ready to accept clients. */ static void httpd_emu_create(EventQueue *eq) { struct httpd_emu_arg *arg; int ssl = 0; /* indicate if SSL-enabled server should be used */ if (http_open_port(http_port, ssl) == -1) panic(0, "Can't open HTTP server emulator port %ld.", http_port); gw_assert(httpd_emu_tid == -1); arg = gw_malloc(sizeof(*arg)); arg->port = http_port; arg->sema = semaphore_create(0); arg->eq = eq; httpd_emu_tid = gwthread_create(httpd_emu, arg); if (httpd_emu_tid == -1) panic(0, "Can't start the HTTP server emulator thread."); semaphore_down(arg->sema); semaphore_destroy(arg->sema); } /* * Terminate the HTTP server emulator thread. Return when the thread * is quite dead. */ static void httpd_emu_destroy(void) { gw_assert(httpd_emu_tid != -1); http_close_all_ports(); gwthread_join(httpd_emu_tid); httpd_emu_tid = -1; } /* * Send a reply to an HTTP response. */ static void httpd_emu_reply(Event *e) { http_send_reply(e->client, HTTP_OK, httpd_emu_headers, e->body); } static void httpd_emu_init(void) { httpd_emu_headers = http_create_empty_headers(); http_header_add(httpd_emu_headers, "Content-Type", "text/plain"); } static void httpd_emu_shutdown(void) { http_destroy_headers(httpd_emu_headers); } /*********************************************************************** * Main program for N SMS messages benchmark. */ static void kill_kannel(void) { Octstr *url; Octstr *final_url; List *req_headers; List *reply_headers; Octstr *reply_body; int ret; url = octstr_format("http://localhost:%ld/shutdown?password=%s", admin_port, admin_password); req_headers = http_create_empty_headers(); http_header_add(req_headers, "Content-Type", "text/plain"); ret = http_get_real(HTTP_METHOD_GET, url, req_headers, &final_url, &reply_headers, &reply_body); if (ret != -1) { octstr_destroy(final_url); http_destroy_headers(reply_headers); octstr_destroy(reply_body); } octstr_destroy(url); http_destroy_headers(req_headers); } /* * This will try to have as large a sustained level of traffic as possible. */ enum { MAX_IN_AVERAGE = 100 }; enum { MAX_RTT = 1 }; enum { MAX_WAITING = 100 }; static void sustained_level_benchmark(void) { EventQueue *eq; Event *e; long i; long num_deliver; long num_submit; long rtt; long times[MAX_IN_AVERAGE]; long next_time; double time_sum; long num_unanswered; eq = eq_create(); httpd_emu_create(eq); smsc_emu_create(eq); /* Wait for an SMS center client to appear. */ while ((e = eq_extract(eq)) != NULL && e->type != got_smsc) debug("test_smsc", 0, "Discarding event of type %s", eq_type(e)); debug("test_smsc", 0, "Got event got_smsc."); eq_destroy_event(e); /* * Send message when there are at most MAX_WAITING unanswered messages * and current average round trip time is less than MAX_RTT. */ num_submit = 0; for (i = 0; i < MAX_IN_AVERAGE; ++i) times[i] = 0; next_time = 0; time_sum = 0.0; num_unanswered = 0; num_deliver = 0; while (num_submit < num_messages) { for (;;) { if (num_deliver >= num_messages || num_unanswered >= MAX_WAITING) break; if (time_sum / MAX_IN_AVERAGE >= MAX_RTT && num_unanswered > 0) break; smsc_emu_deliver(); ++num_unanswered; ++num_deliver; } e = eq_extract(eq); if (e == NULL) break; eq_log(e); switch (e->type) { case deliver_ack: break; case http_request: httpd_emu_reply(e); break; case submit: rtt = eq_round_trip_time(e); time_sum -= times[next_time]; times[next_time] = rtt; time_sum += times[next_time]; debug("", 0, "RTT = %ld", rtt); next_time = (next_time + 1) % MAX_IN_AVERAGE; ++num_submit; --num_unanswered; smsc_emu_submit_ack(e); break; case got_enquire_link: break; default: debug("test_smsc", 0, "Ignoring event of type %s", eq_type(e)); break; } eq_destroy_event(e); } kill_kannel(); debug("test_smsc", 0, "Terminating benchmark."); smsc_emu_destroy(); httpd_emu_destroy(); eq_destroy(eq); } /* * This will send `num_messages' SMS messages as quickly as possible. */ enum { MAX_IN_QUEUE = 1000 }; static void n_messages_benchmark(void) { EventQueue *eq; Event *e; long i; long num_submit; long num_in_queue; long num_deliver; eq = eq_create(); httpd_emu_create(eq); smsc_emu_create(eq); /* Wait for an SMS center client to appear. */ while ((e = eq_extract(eq)) != NULL && e->type != got_smsc) debug("test_smsc", 0, "Discarding event of type %s", eq_type(e)); debug("test_smsc", 0, "Got event got_smsc."); eq_destroy_event(e); /* Send the SMS messages, or at least fill the send queue. */ for (i = 0; i < num_messages && i < MAX_IN_QUEUE; ++i) smsc_emu_deliver(); num_in_queue = i; num_deliver = i; /* * Wait for results to be processed. When send queue is not full, * fill it. */ num_submit = 0; while (num_submit < num_messages && (e = eq_extract(eq)) != NULL) { while (num_deliver < num_messages && num_in_queue < MAX_IN_QUEUE) { smsc_emu_deliver(); ++num_in_queue; ++num_deliver; } eq_log(e); switch (e->type) { case deliver_ack: break; case http_request: httpd_emu_reply(e); break; case submit: debug("", 0, "RTT = %ld", eq_round_trip_time(e)); smsc_emu_submit_ack(e); ++num_submit; --num_in_queue; break; case got_enquire_link: break; default: debug("test_smsc", 0, "Ignoring event of type %s", eq_type(e)); break; } eq_destroy_event(e); } kill_kannel(); debug("test_smsc", 0, "Terminating benchmark."); smsc_emu_destroy(); httpd_emu_destroy(); eq_destroy(eq); } /*********************************************************************** * Main program. */ int main(int argc, char **argv) { int opt; char *main_name; int i; static struct { char *name; void (*func)(void); } tab[] = { { "n_messages", n_messages_benchmark }, { "sustained_level", sustained_level_benchmark }, }; gwlib_init(); eq_init(); httpd_emu_init(); smsc_emu_init(); main_name = "n_messages_benchmark"; while ((opt = getopt(argc, argv, "m:r:")) != EOF) { switch (opt) { case 'm': main_name = optarg; break; case 'r': num_messages = atoi(optarg); break; } } for (i = 0; (size_t) i < sizeof(tab) / sizeof(tab[0]); ++i) { if (strcmp(main_name, tab[i].name) == 0) { tab[i].func(); break; } } smsc_emu_shutdown(); httpd_emu_shutdown(); eq_shutdown(); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_headers.c0000644000175000017500000001573513227613126015477 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_headers.c - test wsp header packing and unpacking. * * Richard Braakman */ #include #include #include #include "gwlib/gwlib.h" #include "wap/wsp_headers.h" #include "wap/wsp_strings.h" /* Test the http_header_combine function. */ static void test_header_combine(void) { List *old; List *new; List *tmp; old = http_create_empty_headers(); new = http_create_empty_headers(); tmp = http_create_empty_headers(); http_header_add(old, "Accept", "text/html"); http_header_add(old, "Accept", "text/plain"); http_header_add(old, "Accept-Language", "en"); http_header_add(old, "Accept", "image/jpeg"); http_header_combine(tmp, old); if (gwlist_len(tmp) != 4) { error(0, "http_combine_header with an empty 'old' did not just append."); } http_header_combine(old, new); if (gwlist_len(old) != 4) { error(0, "http_combine_header with an empty 'new' changed 'old'."); } http_header_add(new, "Accept", "text/html"); http_header_add(new, "Accept", "text/plain"); http_header_combine(old, new); if (gwlist_len(old) != 3 || octstr_compare(gwlist_get(old, 0), octstr_imm("Accept-Language: en")) != 0 || octstr_compare(gwlist_get(old, 1), octstr_imm("Accept: text/html")) != 0 || octstr_compare(gwlist_get(old, 2), octstr_imm("Accept: text/plain")) != 0) { error(0, "http_header_combine failed."); } http_destroy_headers(old); http_destroy_headers(new); http_destroy_headers(tmp); } static void split_headers(Octstr *headers, List **split, List **expected) { long start; long pos; *split = gwlist_create(); *expected = gwlist_create(); start = 0; for (pos = 0; pos < octstr_len(headers); pos++) { if (octstr_get_char(headers, pos) == '\n') { int c; Octstr *line; if (pos == start) { /* Skip empty lines */ start = pos + 1; continue; } line = octstr_copy(headers, start, pos - start); start = pos + 1; c = octstr_get_char(line, 0); octstr_delete(line, 0, 2); if (c == '|') { gwlist_append(*split, line); gwlist_append(*expected, octstr_duplicate(line)); } else if (c == '<') { gwlist_append(*split, line); } else if (c == '>') { gwlist_append(*expected, line); } else if (c == '#') { /* comment */ octstr_destroy(line); } else { warning(0, "Bad line in test headers file"); octstr_destroy(line); } } } } int main(int argc, char **argv) { Octstr *headers; List *expected; List *split; Octstr *packed; List *unpacked; Octstr *filename; long i; int mptr; gwlib_init(); wsp_strings_init(); mptr = get_and_set_debugs(argc, argv, NULL); if (argc - mptr <= 0) panic(0, "Usage: test_headers [options] header-file"); filename = octstr_create(argv[mptr]); headers = octstr_read_file(octstr_get_cstr(filename)); split_headers(headers, &split, &expected); packed = wsp_headers_pack(split, 0, WSP_1_2); unpacked = wsp_headers_unpack(packed, 0); if (gwlist_len(unpacked) != gwlist_len(expected)) { error(0, "Expected %ld headers, generated %ld.\n", gwlist_len(expected), gwlist_len(unpacked)); } else { for (i = 0; i < gwlist_len(unpacked); i++) { Octstr *got, *exp; got = gwlist_get(unpacked, i); exp = gwlist_get(expected, i); if (octstr_compare(got, exp) != 0) { error(0, "Exp: %s", octstr_get_cstr(exp)); error(0, "Got: %s", octstr_get_cstr(got)); } } } test_header_combine(); octstr_destroy(headers); octstr_destroy(filename); gwlist_destroy(split, octstr_destroy_item); gwlist_destroy(expected, octstr_destroy_item); octstr_destroy(packed); gwlist_destroy(unpacked, octstr_destroy_item); wsp_strings_shutdown(); gwlib_shutdown(); return 0; } gateway-1.4.5/test/settings4.txt0000644000175000017500000000132607424243130015331 0ustar toljtolj gateway-1.4.5/test/decompile.c0000644000175000017500000012635013227613126014762 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * decompile.c - A program to test the WML compiler. This tool was written * from the WBXML 1.2 and WML 1.1 specs. * * Author: Chris Wulff, Vanteon (cwulff@vanteon.com) * */ #include #include #include #include #include "decompile.h" const WBXML_MB_U_INT32 ZERO_WBXML_MB_U_INT32 = {0,0,0,0}; long dtd_id; #define INDENT_SIZE 4 DTD_TYPE_LIST DTDTypeList[] = { {1, "UNKNOWN"}, {2, "-//WAPFORUM//DTD WML 1.0//EN\"\n" "\"http://www.wapforum.org/DTD/wml.xml"}, {3, "-//WAPFORUM//DTD WTA 1.0//EN"}, {4, "-//WAPFORUM//DTD WML 1.1//EN\"\n" "\"http://www.wapforum.org/DTD/wml_1.1.xml"}, {5, "-//WAPFORUM//DTD SI 1.0//EN\"\n" "\"http://www.wapforum.org/DTD/si.dtd"}, {6, "-//WAPFORUM//DTD SL 1.0//EN\"\n" "\"http://www.wapforum.org/DTD/sl.dtd"}, {7, "-//WAPFORUM//DTD CO 1.0//EN"}, {8, "-//WAPFORUM//DTD CHANNEL 1.1//EN"}, {9, "-//WAPFORUM//DTD WML 1.2//EN\"\n" "\"http://www.wapforum.org/DTD/wml12.dtd"}, {0, NULL} }; /************************************** * DTD Public Type 4 (WML 1.1) Tables * **************************************/ CODEPAGE_TAG_NAME_LIST CodepageTagNames[] = { {4, "a", 0, 0x1c}, {4, "anchor", 0, 0x22}, {4, "access", 0, 0x23}, {4, "b", 0, 0x24}, {4, "big", 0, 0x25}, {4, "br", 0, 0x26}, {4, "card", 0, 0x27}, {4, "do", 0, 0x28}, {4, "em", 0, 0x29}, {4, "fieldset", 0, 0x2a}, {4, "go", 0, 0x2b}, {4, "head", 0, 0x2c}, {4, "i", 0, 0x2d}, {4, "img", 0, 0x2e}, {4, "input", 0, 0x2f}, {4, "meta", 0, 0x30}, {4, "noop", 0, 0x31}, {4, "p", 0, 0x20}, {4, "postfield", 0, 0x21}, {4, "pre", 0, 0x1b}, {4, "prev", 0, 0x32}, {4, "onevent", 0, 0x33}, {4, "optgroup", 0, 0x34}, {4, "option", 0, 0x35}, {4, "refresh", 0, 0x36}, {4, "select", 0, 0x37}, {4, "setvar", 0, 0x3e}, {4, "small", 0, 0x38}, {4, "strong", 0, 0x39}, {4, "table", 0, 0x1f}, {4, "td", 0, 0x1d}, {4, "template", 0, 0x3b}, {4, "timer", 0, 0x3c}, {4, "tr", 0, 0x1e}, {4, "u", 0, 0x3d}, {4, "wml", 0, 0x3f}, {6, "TAG_05", 1, 0x05}, {6, "TAG_06", 1, 0x06}, {6, "TAG_07", 1, 0x07}, {0, NULL, 0, 0} }; CODEPAGE_ATTRSTART_NAME_LIST CodepageAttrstartNames[] = { {4, "accept-charset", NULL, 0, 0x05}, {4, "accesskey", NULL, 0, 0x5e}, {4, "align", NULL, 0, 0x52}, {4, "align", "bottom", 0, 0x06}, {4, "align", "center", 0, 0x07}, {4, "align", "left", 0, 0x08}, {4, "align", "middle", 0, 0x09}, {4, "align", "right", 0, 0x0a}, {4, "align", "top", 0, 0x0b}, {4, "alt", NULL, 0, 0x0c}, {4, "class", NULL, 0, 0x54}, {4, "columns", NULL, 0, 0x53}, {4, "content", NULL, 0, 0x0d}, {4, "content", "application/vnd.wap.wmlc;charset=", 0, 0x5c}, {4, "domain", NULL, 0, 0x0f}, {4, "emptyok", "false", 0, 0x10}, {4, "emptyok", "true", 0, 0x11}, {4, "enctype", NULL, 0, 0x5f}, {4, "enctype", "application/x-www-form-urlencoded", 0, 0x60}, {4, "enctype", "multipart/form-data", 0, 0x61}, {4, "format", NULL, 0, 0x12}, {4, "forua", "false", 0, 0x56}, {4, "forua", "true", 0, 0x57}, {4, "height", NULL, 0, 0x13}, {4, "href", NULL, 0, 0x4a}, {4, "href", "http://", 0, 0x4b}, {4, "href", "https://", 0, 0x4c}, {4, "hspace", NULL, 0, 0x14}, {4, "http-equiv", NULL, 0, 0x5a}, {4, "http-equiv", "Content-Type", 0, 0x5b}, {4, "http-equiv", "Expires", 0, 0x5d}, {4, "id", NULL, 0, 0x55}, {4, "ivalue", NULL, 0, 0x15}, {4, "iname", NULL, 0, 0x16}, {4, "label", NULL, 0, 0x18}, {4, "localsrc", NULL, 0, 0x19}, {4, "maxlength", NULL, 0, 0x1a}, {4, "method", "get", 0, 0x1b}, {4, "method", "post", 0, 0x1c}, {4, "mode", "nowrap", 0, 0x1d}, {4, "mode", "wrap", 0, 0x1e}, {4, "multiple", "false", 0, 0x1f}, {4, "multiple", "true", 0, 0x20}, {4, "name", NULL, 0, 0x21}, {4, "newcontext", "false", 0, 0x22}, {4, "newcontext", "true", 0, 0x23}, {4, "onenterbackward", NULL, 0, 0x25}, {4, "onenterforward", NULL, 0, 0x26}, {4, "onpick", NULL, 0, 0x24}, {4, "ontimer", NULL, 0, 0x27}, {4, "optional", "false", 0, 0x28}, {4, "optional", "true", 0, 0x29}, {4, "path", NULL, 0, 0x2a}, {4, "scheme", NULL, 0, 0x2e}, {4, "sendreferer", "false", 0, 0x2f}, {4, "sendreferer", "true", 0, 0x30}, {4, "size", NULL, 0, 0x31}, {4, "src", NULL, 0, 0x32}, {4, "src", "http://", 0, 0x58}, {4, "src", "https://", 0, 0x59}, {4, "ordered", "true", 0, 0x33}, {4, "ordered", "false", 0, 0x34}, {4, "tabindex", NULL, 0, 0x35}, {4, "title", NULL, 0, 0x36}, {4, "type", NULL, 0, 0x37}, {4, "type", "accept", 0, 0x38}, {4, "type", "delete", 0, 0x39}, {4, "type", "help", 0, 0x3a}, {4, "type", "password", 0, 0x3b}, {4, "type", "onpick", 0, 0x3c}, {4, "type", "onenterbackward", 0, 0x3d}, {4, "type", "onenterforward", 0, 0x3e}, {4, "type", "ontimer", 0, 0x3f}, {4, "type", "options", 0, 0x45}, {4, "type", "prev", 0, 0x46}, {4, "type", "reset", 0, 0x47}, {4, "type", "text", 0, 0x48}, {4, "type", "vnd.", 0, 0x49}, {4, "value", NULL, 0, 0x4d}, {4, "vspace", NULL, 0, 0x4e}, {4, "width", NULL, 0, 0x4f}, {4, "xml:lang", NULL, 0, 0x50}, {6, "ATTR_06", NULL, 1, 0x06}, {6, "ATTR_07", NULL, 1, 0x07}, {6, "ATTR_08", NULL, 1, 0x08}, {6, "ATTR_11", NULL, 1, 0x11}, {6, "ATTR_12", NULL, 1, 0x12}, {6, "ATTR_13", NULL, 1, 0x13}, {6, "ATTR_14", NULL, 1, 0x14}, {6, "ATTR_15", NULL, 1, 0x15}, {6, "ATTR_21", NULL, 1, 0x21}, {6, "ATTR_22", NULL, 1, 0x22}, {6, "ATTR_23", NULL, 1, 0x23}, {6, "ATTR_24", NULL, 1, 0x24}, {6, "ATTR_28", NULL, 1, 0x28}, {6, "ATTR_29", NULL, 1, 0x29}, {6, "ATTR_45", NULL, 1, 0x45}, {6, "ATTR_61", NULL, 1, 0x61}, {6, "ATTR_62", NULL, 1, 0x62}, {6, "ATTR_63", NULL, 1, 0x63}, {6, "ATTR_64", NULL, 1, 0x64}, {6, "ATTR_6A", NULL, 1, 0x6A}, {6, "ATTR_6B", NULL, 1, 0x6B}, {6, "ATTR_6C", NULL, 1, 0x6C}, {6, "ATTR_70", NULL, 1, 0x70}, {6, "ATTR_71", NULL, 1, 0x71}, {6, "ATTR_73", NULL, 1, 0x73}, {6, "ATTR_74", NULL, 1, 0x74}, {0, NULL, NULL, 0, 0} }; CODEPAGE_ATTRVALUE_NAME_LIST CodepageAttrvalueNames[] = { {4, ".com/", 0, 0x85}, {4, ".edu/", 0, 0x86}, {4, ".net/", 0, 0x87}, {4, ".org/", 0, 0x88}, {4, "accept", 0, 0x89}, {4, "bottom", 0, 0x8a}, {4, "clear", 0, 0x8b}, {4, "delete", 0, 0x8c}, {4, "help", 0, 0x8d}, {4, "http://", 0, 0x8e}, {4, "http://www.", 0, 0x8f}, {4, "https://", 0, 0x90}, {4, "https://www.", 0, 0x91}, {4, "middle", 0, 0x93}, {4, "nowrap", 0, 0x94}, {4, "onenterbackward", 0, 0x96}, {4, "onenterforward", 0, 0x97}, {4, "onpick", 0, 0x95}, {4, "ontimer", 0, 0x98}, {4, "options", 0, 0x99}, {4, "password", 0, 0x9a}, {4, "reset", 0, 0x9b}, {4, "text", 0, 0x9d}, {4, "top", 0, 0x9e}, {4, "unknown", 0, 0x9f}, {4, "wrap", 0, 0xa0}, {4, "www.", 0, 0xa1}, {0, NULL, 0, 0} }; /************************** * Node Tree Construction * **************************/ /* * Function: NewNode * * Description: * * Allocate and initialize a new node. This links the new node * as the first child of the current node in the buffer. This causes * child nodes to be linked in reverse order. If there is no current * node, then the new node will be linked in as the first child at the * top of the tree. * * Parameters: * * buffer - WBXML buffer to link the new node into * type - Type of node to allocate * * Return value: * * P_WBXML_NODE - A pointer to the newly allocated node. * */ static P_WBXML_NODE NewNode(P_WBXML_INFO buffer, WBXML_NODE_TYPE type) { if (buffer) { P_WBXML_NODE newnode = malloc(sizeof(WBXML_NODE)); if (newnode) { newnode->m_prev = NULL; newnode->m_child = NULL; if (buffer->m_curnode) { /* Insert this node as the first child of the current node */ newnode->m_parent = buffer->m_curnode; newnode->m_next = buffer->m_curnode->m_child; if (buffer->m_curnode->m_child) { ((P_WBXML_NODE)buffer->m_curnode->m_child)->m_prev = newnode; } buffer->m_curnode->m_child = newnode; } else { /* Insert this node at the top of the tree */ newnode->m_parent = NULL; newnode->m_next = buffer->m_tree; if (buffer->m_tree) { buffer->m_tree->m_prev = newnode; } buffer->m_tree = newnode; } newnode->m_page = buffer->m_curpage; newnode->m_type = type; newnode->m_data = NULL; } else { ParseError(ERR_NOT_ENOUGH_MEMORY); } return newnode; } else { ParseError(ERR_INTERNAL_BAD_PARAM); } return NULL; } /* * Function: FreeNode * * Description: * * Free a node, all its children and forward siblings. * * Parameters: * * node - The node to free * */ static void FreeNode(P_WBXML_NODE node) { if (node) { if (node->m_child) { FreeNode(node->m_child); } if (node->m_next) { FreeNode(node->m_next); } free(node); } } static void AddDTDNode(P_WBXML_INFO buffer, const WBXML_DTD_TYPE dtdnum, const WBXML_MB_U_INT32 index) { P_WBXML_NODE newnode = NewNode(buffer, NODE_DTD_TYPE); newnode->m_data = malloc(sizeof(DTD_NODE_DATA)); memcpy( &( ((DTD_NODE_DATA*)newnode->m_data)->m_dtdnum ), &(dtdnum[0]), sizeof(WBXML_MB_U_INT32) ); memcpy( &( ((DTD_NODE_DATA*)newnode->m_data)->m_index ), &(index[0]), sizeof(WBXML_MB_U_INT32) ); dtd_id = (long) dtdnum[0]; } static void AddStringTableNode(P_WBXML_INFO buffer, const P_WBXML_STRING_TABLE strings) { P_WBXML_NODE newnode = NewNode(buffer, NODE_STRING_TABLE); newnode->m_data = malloc(sizeof(WBXML_STRING_TABLE)); memcpy( newnode->m_data, strings, sizeof(WBXML_STRING_TABLE) ); } static void AddCodepageTagNode(P_WBXML_INFO buffer, WBXML_TAG tag) { P_WBXML_NODE newnode = NewNode(buffer, NODE_CODEPAGE_TAG); newnode->m_data = malloc(sizeof(WBXML_TAG)); *((P_WBXML_TAG)newnode->m_data) = tag; } static void AddCodepageLiteralTagNode(P_WBXML_INFO buffer, WBXML_MB_U_INT32 index) { P_WBXML_NODE newnode = NewNode(buffer, NODE_CODEPAGE_LITERAL_TAG); newnode->m_data = malloc(sizeof(WBXML_MB_U_INT32)); memcpy( ((P_WBXML_MB_U_INT32)newnode->m_data), &index, sizeof(WBXML_MB_U_INT32) ); } static void AddAttrStartNode(P_WBXML_INFO buffer, WBXML_TAG tag) { P_WBXML_NODE newnode = NewNode(buffer, NODE_ATTRSTART); newnode->m_data = malloc(sizeof(WBXML_TAG)); *((P_WBXML_TAG)newnode->m_data) = tag; } static void AddAttrStartLiteralNode(P_WBXML_INFO buffer, WBXML_MB_U_INT32 index) { P_WBXML_NODE newnode = NewNode(buffer, NODE_ATTRSTART_LITERAL); newnode->m_data = malloc(sizeof(WBXML_MB_U_INT32)); memcpy( ((P_WBXML_MB_U_INT32)newnode->m_data), &index, sizeof(WBXML_MB_U_INT32) ); } static void AddAttrValueNode(P_WBXML_INFO buffer, WBXML_TAG tag) { P_WBXML_NODE newnode = NewNode(buffer, NODE_ATTRVALUE); newnode->m_data = malloc(sizeof(WBXML_TAG)); *((P_WBXML_TAG)newnode->m_data) = tag; } static void AddAttrEndNode(P_WBXML_INFO buffer) { P_WBXML_NODE newnode = NewNode(buffer, NODE_ATTREND); newnode->m_data = NULL; } static void AddStringNode(P_WBXML_INFO buffer, char* string) { P_WBXML_NODE newnode = NewNode(buffer, NODE_STRING); newnode->m_data = strdup(string); } static void AddVariableStringNode(P_WBXML_INFO buffer, char* string, WBXML_VARIABLE_TYPE type) { /* TODO: add this node */ } static void AddVariableIndexNode(P_WBXML_INFO buffer, char* string, WBXML_VARIABLE_TYPE type) { /* TODO: add this node */ } /**************** * Flow Control * ****************/ void Message(char* msg) { printf("%s\n", msg); } void ParseError(WBXML_PARSE_ERROR error) { switch (error) { case ERR_END_OF_DATA: Message("Input stream is incomplete (EOF)."); break; case ERR_INTERNAL_BAD_PARAM: Message("Internal error: Bad parameter."); break; case ERR_TAG_NOT_FOUND: Message("Tag not found."); break; case ERR_FILE_NOT_FOUND: Message("File not found."); break; case ERR_FILE_NOT_READ: Message("File read error."); break; case ERR_NOT_ENOUGH_MEMORY: Message("Not enough memory"); break; default: Message("Unknown error."); break; } exit(error); } void ParseWarning(WBXML_PARSE_WARNING warning) { switch (warning) { case WARN_FUTURE_EXPANSION_EXT_0: Message("Token EXT_0 encountered. This token is reserved for future expansion."); break; case WARN_FUTURE_EXPANSION_EXT_1: Message("Token EXT_1 encountered. This token is reserved for future expansion."); break; case WARN_FUTURE_EXPANSION_EXT_2: Message("Token EXT_2 encountered. This token is reserved for future expansion."); break; default: Message("Unknown warning."); break; } } WBXML_LENGTH BytesLeft(P_WBXML_INFO buffer) { if (buffer) { WBXML_LENGTH bytesRead = (buffer->m_curpos - buffer->m_start); if (bytesRead >= buffer->m_length) { return 0; } else { return (buffer->m_length - bytesRead); } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } return 0; } BOOL IsTag(P_WBXML_INFO buffer, WBXML_TAG tag) { BOOL result = FALSE; if (buffer) { if (BytesLeft(buffer) >= sizeof(WBXML_TAG)) { result = ((*((WBXML_TAG*) buffer->m_curpos)) == tag); } else { /* No more data, so nope, not this tag */ result = FALSE; } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } return result; } BOOL IsCodepageTag(P_WBXML_INFO buffer, CP_TAG_TYPE type) { WBXML_U_INT8 result = *(buffer->m_curpos); /* NOTE THAT THESE ARE NOT UNIQUE! */ switch (type) { case CP_TAG_TAG: return TRUE; case CP_TAG_ATTRSTART: return ((result & 0x80) != 0x80); case CP_TAG_ATTRVALUE: return ((result & 0x80) == 0x80); default: return FALSE; } } BOOL Is_attrValue (P_WBXML_INFO buffer) { WBXML_INFO tmpbuffer; memcpy(&tmpbuffer, buffer, sizeof(WBXML_INFO)); tmpbuffer.m_curpos += SWITCHPAGE_SIZE; return ((Is_switchPage(buffer) && IsCodepageTag(&tmpbuffer, CP_TAG_ATTRVALUE)) || IsCodepageTag(buffer, CP_TAG_ATTRVALUE) || Is_string(buffer) || Is_extension(buffer) || Is_entity(buffer) || Is_pi(buffer) || Is_opaque(buffer)); } BOOL Is_extension (P_WBXML_INFO buffer) { WBXML_INFO tmpbuffer; memcpy(&tmpbuffer, buffer, sizeof(WBXML_INFO)); tmpbuffer.m_curpos += SWITCHPAGE_SIZE; return ((Is_switchPage(buffer) && (IsTag(&tmpbuffer, TAG_EXT_0) || IsTag(&tmpbuffer, TAG_EXT_1) || IsTag(&tmpbuffer, TAG_EXT_2) || IsTag(&tmpbuffer, TAG_EXT_T_0) || IsTag(&tmpbuffer, TAG_EXT_T_1) || IsTag(&tmpbuffer, TAG_EXT_T_2) || IsTag(&tmpbuffer, TAG_EXT_I_0) || IsTag(&tmpbuffer, TAG_EXT_I_1) || IsTag(&tmpbuffer, TAG_EXT_I_2))) || (IsTag(buffer, TAG_EXT_0) || IsTag(buffer, TAG_EXT_1) || IsTag(buffer, TAG_EXT_2) || IsTag(buffer, TAG_EXT_T_0) || IsTag(buffer, TAG_EXT_T_1) || IsTag(buffer, TAG_EXT_T_2) || IsTag(buffer, TAG_EXT_I_0) || IsTag(buffer, TAG_EXT_I_1) || IsTag(buffer, TAG_EXT_I_2))); } BOOL Is_string (P_WBXML_INFO buffer) { return (Is_inline(buffer) || Is_tableref(buffer)); } BOOL Is_switchPage (P_WBXML_INFO buffer) { return IsTag(buffer, TAG_SWITCH_PAGE); } BOOL Is_inline (P_WBXML_INFO buffer) { return IsTag(buffer, TAG_STR_I); } BOOL Is_tableref (P_WBXML_INFO buffer) { return IsTag(buffer, TAG_STR_T); } BOOL Is_entity (P_WBXML_INFO buffer) { return IsTag(buffer, TAG_ENTITY); } BOOL Is_pi (P_WBXML_INFO buffer) { return IsTag(buffer, TAG_PI); } BOOL Is_opaque (P_WBXML_INFO buffer) { return IsTag(buffer, TAG_OPAQUE); } BOOL Is_zero(P_WBXML_INFO buffer) { BOOL result = FALSE; if (buffer) { if (BytesLeft(buffer) >= 1) { result = ((*buffer->m_curpos) == 0); } else { ParseError(ERR_END_OF_DATA); } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } return result; } /*********************** * Basic Type Decoders * ***********************/ void Read_u_int8(P_WBXML_INFO buffer, P_WBXML_U_INT8 result) { if (buffer && result) { if (BytesLeft(buffer) >= 1) { *result = *(buffer->m_curpos); (buffer->m_curpos)++; } else { ParseError(ERR_END_OF_DATA); } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } } void Read_mb_u_int32(P_WBXML_INFO buffer, P_WBXML_MB_U_INT32 result) { if (buffer && result) { int i; for (i = 0; i < MAX_MB_U_INT32_BYTES; i++) { if (BytesLeft(buffer) >= 1) { (*result)[i] = *(buffer->m_curpos); (buffer->m_curpos)++; if ( !( (*result)[i] & 0x80 ) ) break; } else { ParseError(ERR_END_OF_DATA); } } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } } void Read_bytes(P_WBXML_INFO buffer, WBXML_LENGTH length, P_WBXML_BYTES result) { if (buffer && result) { if (BytesLeft(buffer) >= length) { *result = (WBXML_BYTES) malloc(length*sizeof(unsigned char)); memcpy(*result, buffer->m_curpos, length); buffer->m_curpos += length; } else { ParseError(ERR_END_OF_DATA); } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } } void ReadFixedTag(P_WBXML_INFO buffer, WBXML_TAG tag) { if (buffer) { if (BytesLeft(buffer) >= sizeof(WBXML_TAG)) { if ((*((WBXML_TAG*) buffer->m_curpos)) == tag) { buffer->m_curpos += sizeof(WBXML_TAG); } else { ParseError(ERR_TAG_NOT_FOUND); } } else { ParseError(ERR_END_OF_DATA); } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } } WBXML_TAG ReadCodepageTag (P_WBXML_INFO buffer, CP_TAG_TYPE type) { WBXML_TAG tag = 0; if (buffer) { if (BytesLeft(buffer) >= sizeof(WBXML_TAG)) { tag = *((WBXML_TAG*) buffer->m_curpos); switch (type) { case CP_TAG_TAG: buffer->m_curpos += sizeof(WBXML_TAG); break; case CP_TAG_ATTRSTART: if ((tag & 0x80) != 0x80) { buffer->m_curpos += sizeof(WBXML_TAG); } else { ParseError(ERR_TAG_NOT_FOUND); } break; case CP_TAG_ATTRVALUE: if ((tag & 0x80) == 0x80) { buffer->m_curpos += sizeof(WBXML_TAG); } else { ParseError(ERR_TAG_NOT_FOUND); } break; default: ParseError(ERR_TAG_NOT_FOUND); break; } } else { ParseError(ERR_END_OF_DATA); } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } return tag; } /************************** * Basic Type Conversions * **************************/ long mb_u_int32_to_long(P_WBXML_MB_U_INT32 value) { long result = 0; if (value) { int i; for (i = 0; i < MAX_MB_U_INT32_BYTES; i++) { result <<= 7; result |= ((*value)[i] & 0x7f); if ( !( (*value)[i] & 0x80 ) ) break; } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } return result; } static void OutputEncodedString(const unsigned char* str) { /* Work our way down the string looking for illegal chars */ while (*str != 0) { if ((*str < 0x20) || (*str > 0x7F)) { /* Out of range... encode */ printf("&#x%02x;", *str); } else { switch (*str) { case '<': case '>': case '&': case '\'': case '\"': /* Special symbol... encode */ printf("&#x%2x", *str); break; default: printf("%c", *str); break; } } str++; } } /******************************* * Document Structure Decoders * *******************************/ void Read_start (P_WBXML_INFO buffer) { Read_version(buffer); Read_publicid(buffer); Read_charset(buffer); Read_strtbl(buffer); Read_body(buffer); } void Read_strtbl (P_WBXML_INFO buffer) { WBXML_STRING_TABLE result; Read_mb_u_int32(buffer, &(result.m_length)); Read_bytes(buffer, mb_u_int32_to_long(&(result.m_length)), &(result.m_strings)); AddStringTableNode(buffer, &result); } void Read_body (P_WBXML_INFO buffer) { while (Is_pi(buffer)) { Read_pi(buffer); } Read_element(buffer); while (Is_pi(buffer)) { Read_pi(buffer); } } void Read_element (P_WBXML_INFO buffer) { WBXML_TAG stagvalue = 0; if (Is_switchPage(buffer)) { Read_switchPage(buffer); } stagvalue = Read_stag(buffer); /* move the current node down to this one in the tree */ if (buffer->m_curnode) buffer->m_curnode = buffer->m_curnode->m_child; else buffer->m_curnode = buffer->m_tree; if ((stagvalue & CODEPAGE_TAG_HAS_ATTRS) == CODEPAGE_TAG_HAS_ATTRS) { do { Read_attribute(buffer); } while (!IsTag(buffer, TAG_END)); ReadFixedTag(buffer, TAG_END); AddAttrEndNode(buffer); } if ((stagvalue & CODEPAGE_TAG_HAS_CONTENT) == CODEPAGE_TAG_HAS_CONTENT) { while (!IsTag(buffer, TAG_END)) { Read_content(buffer); } ReadFixedTag(buffer, TAG_END); } /* move the current node back up one */ buffer->m_curnode = buffer->m_curnode->m_parent; } void Read_content (P_WBXML_INFO buffer) { if (Is_string(buffer)) { Read_string(buffer); } else if (Is_extension(buffer)) { Read_extension(buffer); } else if (Is_entity(buffer)) { Read_entity(buffer); } else if (Is_pi(buffer)) { Read_pi(buffer); } else if (Is_opaque(buffer)) { Read_opaque(buffer); } else { /* Assume it is an element */ Read_element(buffer); } } WBXML_TAG Read_stag (P_WBXML_INFO buffer) { if (IsCodepageTag(buffer, CP_TAG_TAG)) { WBXML_TAG tag = ReadCodepageTag(buffer, CP_TAG_TAG); AddCodepageTagNode(buffer, tag); return tag; } else if (IsTag(buffer, TAG_LITERAL)) { WBXML_MB_U_INT32 index; ReadFixedTag(buffer, TAG_LITERAL); Read_index(buffer, &index); AddCodepageLiteralTagNode(buffer, index); } else { ParseError(ERR_TAG_NOT_FOUND); } return 0; } void Read_attribute (P_WBXML_INFO buffer) { Read_attrStart(buffer); while (Is_attrValue(buffer)) { Read_attrValue(buffer); } } void Read_attrStart (P_WBXML_INFO buffer) { if (Is_switchPage(buffer)) { WBXML_TAG tag; Read_switchPage(buffer); tag = ReadCodepageTag(buffer, CP_TAG_ATTRSTART); AddAttrStartNode(buffer, tag); } else if (IsCodepageTag(buffer, CP_TAG_ATTRSTART)) { WBXML_TAG tag; tag = ReadCodepageTag(buffer, CP_TAG_ATTRSTART); AddAttrStartNode(buffer, tag); } else if (IsTag(buffer, TAG_LITERAL)) { WBXML_MB_U_INT32 index; ReadFixedTag(buffer, TAG_LITERAL); Read_index(buffer, &index); AddAttrStartLiteralNode(buffer, index); } else { ParseError(ERR_TAG_NOT_FOUND); } } void Read_attrValue (P_WBXML_INFO buffer) { if (Is_switchPage(buffer)) { WBXML_TAG tag; Read_switchPage(buffer); tag = ReadCodepageTag(buffer, CP_TAG_ATTRVALUE); AddAttrValueNode(buffer, tag); } else if (IsCodepageTag(buffer, CP_TAG_ATTRVALUE)) { WBXML_TAG tag; tag = ReadCodepageTag(buffer, CP_TAG_ATTRVALUE); AddAttrValueNode(buffer, tag); } else if (Is_string(buffer)) { Read_string(buffer); } else if (Is_extension(buffer)) { Read_extension(buffer); } else if (Is_entity(buffer)) { Read_entity(buffer); } else if (Is_opaque(buffer)) { Read_opaque(buffer); } else { ParseError(ERR_TAG_NOT_FOUND); } } void Read_extension (P_WBXML_INFO buffer) { if (Is_switchPage(buffer)) { Read_switchPage(buffer); } if (IsTag(buffer, TAG_EXT_I_0)) { char* str = NULL; ReadFixedTag(buffer, TAG_EXT_I_0); Read_termstr_rtn(buffer, &str); AddVariableStringNode(buffer, str, VAR_ESCAPED); } else if (IsTag(buffer, TAG_EXT_I_1)) { char* str = NULL; ReadFixedTag(buffer, TAG_EXT_I_1); Read_termstr_rtn(buffer, &str); AddVariableStringNode(buffer, str, VAR_UNESCAPED); } else if (IsTag(buffer, TAG_EXT_I_2)) { char* str = NULL; ReadFixedTag(buffer, TAG_EXT_I_2); Read_termstr_rtn(buffer, &str); AddVariableStringNode(buffer, str, VAR_UNCHANGED); } else if (IsTag(buffer, TAG_EXT_T_0)) { WBXML_MB_U_INT32 index; ReadFixedTag(buffer, TAG_EXT_T_0); Read_index(buffer, &index); AddVariableIndexNode(buffer, index, VAR_ESCAPED); } else if (IsTag(buffer, TAG_EXT_T_1)) { WBXML_MB_U_INT32 index; ReadFixedTag(buffer, TAG_EXT_T_1); Read_index(buffer, &index); AddVariableIndexNode(buffer, index, VAR_UNESCAPED); } else if (IsTag(buffer, TAG_EXT_T_2)) { WBXML_MB_U_INT32 index; ReadFixedTag(buffer, TAG_EXT_T_2); Read_index(buffer, &index); AddVariableIndexNode(buffer, index, VAR_UNCHANGED); } else if (IsTag(buffer, TAG_EXT_0)) { ReadFixedTag(buffer, TAG_EXT_0); ParseWarning(WARN_FUTURE_EXPANSION_EXT_0); } else if (IsTag(buffer, TAG_EXT_1)) { ReadFixedTag(buffer, TAG_EXT_1); ParseWarning(WARN_FUTURE_EXPANSION_EXT_1); } else if (IsTag(buffer, TAG_EXT_2)) { ReadFixedTag(buffer, TAG_EXT_2); ParseWarning(WARN_FUTURE_EXPANSION_EXT_2); } else { ParseError(ERR_TAG_NOT_FOUND); } } void Read_string (P_WBXML_INFO buffer) { if (Is_inline(buffer)) { Read_inline(buffer); } else if (Is_tableref(buffer)) { Read_tableref(buffer); } else { ParseError(ERR_TAG_NOT_FOUND); } } void Read_switchPage (P_WBXML_INFO buffer) { WBXML_U_INT8 pageindex; ReadFixedTag(buffer, TAG_SWITCH_PAGE); Read_pageindex(buffer, &pageindex); /* Use the new codepage */ buffer->m_curpage = pageindex; } void Read_inline (P_WBXML_INFO buffer) { ReadFixedTag(buffer, TAG_STR_I); Read_termstr(buffer); } void Read_tableref (P_WBXML_INFO buffer) { WBXML_MB_U_INT32 index; ReadFixedTag(buffer, TAG_STR_T); Read_index(buffer, &index); } void Read_entity (P_WBXML_INFO buffer) { ReadFixedTag(buffer, TAG_ENTITY); Read_entcode(buffer); } void Read_entcode (P_WBXML_INFO buffer) { WBXML_MB_U_INT32 result; Read_mb_u_int32(buffer, &result); } void Read_pi (P_WBXML_INFO buffer) { ReadFixedTag(buffer, TAG_PI); Read_attrStart(buffer); while (Is_attrValue(buffer)) { Read_attrValue(buffer); } ReadFixedTag(buffer, TAG_END); } void Read_opaque (P_WBXML_INFO buffer) { WBXML_MB_U_INT32 length; WBXML_BYTES data; ReadFixedTag(buffer, TAG_OPAQUE); Read_length(buffer, &length); Read_bytes(buffer, mb_u_int32_to_long(&length), &data); } void Read_version (P_WBXML_INFO buffer) { WBXML_U_INT8 result; Read_u_int8(buffer, &result); } void Read_publicid (P_WBXML_INFO buffer) { if (Is_zero(buffer)) { WBXML_MB_U_INT32 index; Read_index(buffer, &index); AddDTDNode(buffer, ZERO_WBXML_MB_U_INT32, index); } else { WBXML_MB_U_INT32 result; Read_mb_u_int32(buffer, &result); AddDTDNode(buffer, result, ZERO_WBXML_MB_U_INT32); } } void Read_charset (P_WBXML_INFO buffer) { WBXML_MB_U_INT32 result; Read_mb_u_int32(buffer, &result); } void Read_termstr_rtn(P_WBXML_INFO buffer, char** result) { #define STRING_BLOCK_SIZE 256 int buflen = STRING_BLOCK_SIZE; char* strbuf = (char*) malloc(buflen); BOOL doubled = FALSE; int i = 0; if (!result) ParseError(ERR_INTERNAL_BAD_PARAM); while ( (BytesLeft(buffer) >= 1) && (*(buffer->m_curpos) != 0) ) { if (i>=buflen) { buflen += STRING_BLOCK_SIZE; strbuf = realloc(strbuf, buflen); } if (*(buffer->m_curpos) != '$' || doubled == TRUE) { strbuf[i] = *(buffer->m_curpos); buffer->m_curpos++; i++; if (doubled == TRUE) doubled = FALSE; } else { strbuf[i] = *(buffer->m_curpos); i++; doubled = TRUE; } } strbuf[i] = 0; buffer->m_curpos++; if (*result) free(*result); *result = strbuf; } void Read_termstr (P_WBXML_INFO buffer) { char* strbuf = NULL; Read_termstr_rtn(buffer, &strbuf); AddStringNode(buffer, strbuf); free(strbuf); } void Read_index (P_WBXML_INFO buffer, P_WBXML_MB_U_INT32 result) { Read_mb_u_int32(buffer, result); } void Read_length (P_WBXML_INFO buffer, P_WBXML_MB_U_INT32 result) { Read_mb_u_int32(buffer, result); } void Read_zero (P_WBXML_INFO buffer) { WBXML_U_INT8 result; Read_u_int8(buffer, &result); if (result != (WBXML_U_INT8) 0) { ParseError(ERR_TAG_NOT_FOUND); } } void Read_pageindex (P_WBXML_INFO buffer, P_WBXML_U_INT8 result) { Read_u_int8(buffer, result); } static void Init(P_WBXML_INFO buffer) { buffer->m_start = NULL; buffer->m_curpos = NULL; buffer->m_length = 0; buffer->m_tree = NULL; buffer->m_curnode = NULL; buffer->m_curpage = 0; } static size_t BufferLength(P_WBXML_INFO buffer) { size_t ret; while (buffer->m_curpos != '\0') buffer->m_curpos++; ret = buffer->m_curpos - buffer->m_start; buffer->m_curpos = buffer->m_start; return ret; } static void Free(P_WBXML_INFO buffer) { if (buffer->m_start) { free(buffer->m_start); buffer->m_start = NULL; } buffer->m_curpos = NULL; buffer->m_length = 0; FreeNode(buffer->m_tree); buffer->m_tree = NULL; } static long FileSize(FILE* file) { long curpos = ftell(file); long endpos; fseek(file, 0, SEEK_END); endpos = ftell(file); fseek(file, curpos, SEEK_SET); return endpos; } static void ReadBinary(P_WBXML_INFO buffer, FILE* file) { char buf[4096]; int m = 1; long n; if (buffer && file) { if (file != stdin) { buffer->m_length = FileSize(file); buffer->m_start = (P_WBXML) malloc(buffer->m_length); buffer->m_curpos = buffer->m_start; if (!buffer->m_start) { fclose(file); ParseError(ERR_NOT_ENOUGH_MEMORY); } if (fread(buffer->m_start, 1, buffer->m_length, file) != buffer->m_length) { fclose(file); ParseError(ERR_FILE_NOT_READ); } else { fclose(file); } } else { while ((n = fread(buf, 1, sizeof(buf), file)) > 0) { buffer->m_start = (P_WBXML) realloc(buffer->m_start, sizeof(buf) * m); memcpy(buffer->m_start + (sizeof(buf) * (m - 1)), buf, sizeof(buf)); m++; } buffer->m_length = BufferLength(buffer); buffer->m_curpos = buffer->m_start; } } else { ParseError(ERR_INTERNAL_BAD_PARAM); } } static const char* DTDTypeName(long dtdnum) { int i = 0; /* Search the DTD list for a match */ while (DTDTypeList[i].m_name) { if (DTDTypeList[i].m_id == dtdnum) { break; } i++; } return DTDTypeList[i].m_name; } static const char* CodepageTagName(WBXML_CODEPAGE page, WBXML_TAG tag) { int i = 0; /* Strip flags off of the tag */ tag = (WBXML_TAG) (tag & CODEPAGE_TAG_MASK); /* Search the tag list for a match */ while (CodepageTagNames[i].m_name) { if ((CodepageTagNames[i].m_dtd_id == dtd_id) && (CodepageTagNames[i].m_page == page) && (CodepageTagNames[i].m_tag == tag)) { break; } i++; } return CodepageTagNames[i].m_name; } static const char* CodepageAttrstartName(WBXML_CODEPAGE page, WBXML_TAG tag, char** value) { int i = 0; /* Check Parameters */ if (!value) { ParseError(ERR_INTERNAL_BAD_PARAM); } /* Search the tag list for a match */ while (CodepageAttrstartNames[i].m_name) { if ((CodepageAttrstartNames[i].m_dtd_id == dtd_id) && (CodepageAttrstartNames[i].m_page == page) && (CodepageAttrstartNames[i].m_tag == tag)) { break; } i++; } /* Duplicate the value because it may be concatenated to */ if (CodepageAttrstartNames[i].m_valueprefix) { *value = strdup(CodepageAttrstartNames[i].m_valueprefix); } else { *value = NULL; } /* Return the tag name */ return CodepageAttrstartNames[i].m_name; } static void CodepageAttrvalueName(WBXML_CODEPAGE page, WBXML_TAG tag, char** value) { int i = 0; /* Check Parameters */ if (!value) { ParseError(ERR_INTERNAL_BAD_PARAM); } /* Search the tag list for a match */ while (CodepageAttrvalueNames[i].m_name) { if ((CodepageAttrvalueNames[i].m_dtd_id == dtd_id) && (CodepageAttrvalueNames[i].m_page == page) && (CodepageAttrvalueNames[i].m_tag == tag)) { break; } i++; } /* concatenate the value */ if (CodepageAttrvalueNames[i].m_name) { if (*value) { *value = realloc(*value, strlen(*value) + strlen(CodepageAttrvalueNames[i].m_name) + 1); strcat(*value, CodepageAttrvalueNames[i].m_name); } else { *value = strdup(CodepageAttrvalueNames[i].m_name); } } } static const char* GetStringTableString(P_WBXML_NODE node, long index) { /* Find the string table node */ P_WBXML_NODE pStringsNode = node; while (pStringsNode->m_parent) { pStringsNode = pStringsNode->m_parent; } while (pStringsNode->m_next) { pStringsNode = pStringsNode->m_next; } while (pStringsNode->m_prev && pStringsNode->m_type != NODE_STRING_TABLE) { pStringsNode = pStringsNode->m_prev; } if (pStringsNode->m_type != NODE_STRING_TABLE) { return "!!NO STRING TABLE!!"; } /* Find the indexed string */ if ((index >= 0) && (index < mb_u_int32_to_long(&((P_WBXML_STRING_TABLE)pStringsNode->m_data)->m_length))) { return (const char*) &(((P_WBXML_STRING_TABLE)pStringsNode->m_data)->m_strings[index]); } else { return "!!STRING TABLE INDEX TOO LARGE!!"; } } static void DumpNode(P_WBXML_NODE node, int indent, BOOL *inattrs, BOOL hascontent, char** value) { P_WBXML_NODE curnode = node->m_child; WBXML_TAG nodetype = 0; long dtdnum = 0; BOOL bAttributesFollow = FALSE; BOOL bHasContent = FALSE; int i; if (!(*inattrs)) { for (i=0; im_type != NODE_ATTRVALUE) && (*value)) { printf("=\""); OutputEncodedString((unsigned char*) *value); printf("\""); free(*value); *value = NULL; } } switch (node->m_type) { case NODE_DTD_TYPE: printf("\nm_data)->m_dtdnum ); if ( dtdnum == 0) { printf("\"%s\">\n\n", GetStringTableString(node, mb_u_int32_to_long(&((DTD_NODE_DATA*)node->m_data)->m_index)) ); } else { printf("\"%s\">\n\n", DTDTypeName(dtdnum) ); } break; case NODE_CODEPAGE_TAG: nodetype = *((P_WBXML_TAG)node->m_data); if ((nodetype & CODEPAGE_TAG_MASK) == nodetype) { printf("<%s/>\n", CodepageTagName(node->m_page, nodetype)); } else { if ((nodetype & CODEPAGE_TAG_HAS_CONTENT) == CODEPAGE_TAG_HAS_CONTENT) { bHasContent = TRUE; } if ((nodetype & CODEPAGE_TAG_HAS_ATTRS) == CODEPAGE_TAG_HAS_ATTRS) { printf("<%s", CodepageTagName(node->m_page, nodetype)); bAttributesFollow = TRUE; } else { printf("<%s>\n", CodepageTagName(node->m_page, nodetype)); } } break; case NODE_CODEPAGE_LITERAL_TAG: printf("<%s>\n", GetStringTableString(node, mb_u_int32_to_long(((P_WBXML_MB_U_INT32)node->m_data))) ); break; case NODE_ATTRSTART: printf(" %s", CodepageAttrstartName(node->m_page, *((P_WBXML_TAG)node->m_data), value) ); break; case NODE_ATTRSTART_LITERAL: printf(" %s", GetStringTableString(node, mb_u_int32_to_long(((P_WBXML_MB_U_INT32)node->m_data))) ); break; case NODE_ATTRVALUE: CodepageAttrvalueName(node->m_page, *((P_WBXML_TAG)node->m_data), value); break; case NODE_ATTREND: if (!hascontent) { printf("/"); } printf(">\n"); *inattrs = FALSE; break; case NODE_STRING: if (*inattrs) { /* concatenate the value */ if (*value) { if (node->m_data) { *value = realloc(*value, strlen(*value) + strlen((char*) node->m_data) + 1); strcat(*value, (char*) node->m_data); } } else { if (node->m_data) { *value = strdup((char*) node->m_data); } } } else { OutputEncodedString((unsigned char*) node->m_data); printf("\n"); } break; case NODE_VARIABLE_STRING: /* TODO: output variable string */ break; case NODE_VARIABLE_INDEX: /* TODO: output variable string */ break; default: break; } indent += INDENT_SIZE; if (curnode) { while (curnode->m_next) curnode = curnode->m_next; while (curnode) { DumpNode(curnode, indent, &bAttributesFollow, bHasContent, value); curnode = curnode->m_prev; } } indent -= INDENT_SIZE; /* Output the element end if we have one */ if ((nodetype & CODEPAGE_TAG_HAS_CONTENT) == CODEPAGE_TAG_HAS_CONTENT) { for (i=0; im_type) { case NODE_CODEPAGE_TAG: printf("\n", CodepageTagName(node->m_page, *((P_WBXML_TAG)node->m_data)) ); break; case NODE_CODEPAGE_LITERAL_TAG: printf("\n", GetStringTableString(node, mb_u_int32_to_long(((P_WBXML_MB_U_INT32)node->m_data))) ); break; default: break; } } } static void DumpNodes(P_WBXML_INFO buffer) { P_WBXML_NODE curnode = buffer->m_tree; BOOL bAttrsFollow = FALSE; char* value = NULL; if (curnode) { while (curnode->m_next) curnode = curnode->m_next; while (curnode) { DumpNode(curnode, 0, &bAttrsFollow, FALSE, &value); curnode = curnode->m_prev; } } } int main(int argc, char** argv) { WBXML_INFO buffer; FILE* file; if (argc < 2) { file = stdin; } else { file = fopen(argv[1], "r"); if (!file) { ParseError(ERR_FILE_NOT_FOUND); } } Init(&buffer); ReadBinary(&buffer, file); Read_start(&buffer); DumpNodes(&buffer); Free(&buffer); return 0; } gateway-1.4.5/test/test_cimd2.c0000644000175000017500000006756013227613126015065 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* test_cimd2.c - fake cimd2 smsc * * This program pretends to be an CIMD 2 SMS center, accessible via IP. * It is used to test the Kannel smsc_cimd2 code. * * Richard Braakman */ /* Note: The CIMD2 parsing code was written as a prototype, and currently * its main use is to exercise the *real* CIMD2 code in gw/smsc_cimd2.c. * Please don't use this code for anything real. * Richard Braakman */ /* * TODO: If log level is high and activity level is low, there will be * "SND" log entries for packets that are not sent, which is confusing * and should be fixed. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" enum { TIMESTAMP_MAXLEN = 13 }; unsigned char *progname; /* Set up a fake account for Kannel to use */ unsigned char *username = "foo"; unsigned char *password = "bar"; int port = 6789; /* This can be useful to get past protocol-ID checks when testing spew. */ unsigned char *intro = ""; enum ACT { ACT_listen = 0, ACT_reply = 1, ACT_deliver = 2, ACT_flood = 3 }; enum SPEW { SPEW_nothing = 0, SPEW_binary = 1, SPEW_characters = 2, SPEW_packets = 3 }; enum LOG { LOG_nothing = 0, LOG_data = 1, LOG_packets = 2, LOG_sms = 3 }; enum CHK { CHK_nothing = 0, CHK_packets = 1, CHK_sums = 2, CHK_protocol = 3, CHK_sms = 4 }; int activity = ACT_listen; int spew = SPEW_nothing; int logging = LOG_nothing; int checking = CHK_nothing; int max_deliveries = -1; int deliveries = 0; time_t start_time = 0; int sockfd = -1; Octstr *inbuffer; Octstr *outbuffer; /* Maximum reasonable outbuffer size. It can go above this, but we don't * deliberately add data when it's already more than this. */ enum { OUTBUFFER_LIMIT = 65536 }; /* Test dependencies on neatly-sized read and write chunks, by using * a deliberately evil buffer size. 1021 is the largest prime smaller * than 1024. */ enum { EVIL_BUFSIZE = 1021 }; enum CHARS { STX = 2, ETX = 3, TAB = 9, LF = 10, CR = 13 }; static void usage(FILE *out) { fprintf(out, "Usage: %s [options...]\n" " --help Print this message\n" " --user USER Allow clients to log in with username USER (default %s)\n" " --password PASS Allow clients to log in with password PASS (default %s)\n" " --intro INTRO Send INTRO string before anything else (default nothing)\n" " --port PORT TCP port to listen on (default %d)\n" " --activity ACT Activity level of test server (default %d)\n" " ACT = 0 send nothing, just listen\n" " ACT = 1 send valid replies, do not initiate any transactions\n" " ACT = 2 attempt to deliver a random SMS every few seconds (NI)\n" " ACT = 3 deliver many random SMSes, measure throughput (NI)\n" " --spew SPEW Flood client, overrides --activity (default %d)\n" " SPEW = 0 don't spew, use --activity instead\n" " SPEW = 1 spew random binary gunk at client\n" " SPEW = 2 spew random data of the right character set at client (NI)\n" " SPEW = 3 spew valid packets with random contents at client (NI)\n" " --logging LOG Log level of test server (default %d)\n" " LOG = 0 log nothing\n" " LOG = 1 log all data\n" " LOG = 2 log summaries of valid packets\n" " LOG = 3 log successfully sent and received SMSes (NI)\n" " --checking CHK Check level of test server (default %d)\n" " CHK = 0 check nothing\n" " CHK = 1 signal invalid packets (NI)\n" " CHK = 2 signal checksum errors (NI)\n" " CHK = 3 signal protocol errors (NI)\n" " CHK = 4 signal invalid SMS contents (NI)\n" " --max MAX With high activity values, stop after MAX deliveries\n" " NI means Not Implemented\n" , progname, username, password, port, activity, spew, logging, checking); } static void pretty_print(unsigned char *data, size_t length) { size_t i; int c; for (i = 0; i < length; i++) { c = data[i]; switch(c) { default: if (isprint(c)) putchar(c); else printf("<%d>", c); break; case TAB: fputs("", stdout); break; case LF: fputs("\n", stdout); break; case CR: fputs("", stdout); break; case STX: fputs("", stdout); break; case ETX: fputs("\n", stdout); break; } } fflush(stdout); } static void read_data(Octstr *in, int fd) { unsigned char buf[EVIL_BUFSIZE]; int ret; ret = read(fd, buf, sizeof(buf)); if (ret > 0) { octstr_append_data(in, buf, ret); if (logging == LOG_data) pretty_print(buf, ret); } else if (ret == 0) { fprintf(stderr, "Client closed socket\n"); exit(0); } else { if (errno == EINTR || errno == EAGAIN) return; error(errno, "read_data"); exit(1); } } static void write_data(Octstr *out, int fd) { unsigned char buf[EVIL_BUFSIZE]; int len; ssize_t ret; len = sizeof(buf); if (len > octstr_len(out)) len = octstr_len(out); if (len == 0) return; octstr_get_many_chars(buf, out, 0, len); ret = write(fd, buf, len); if (ret > 0) { if (logging == LOG_data) pretty_print(buf, ret); octstr_delete(out, 0, ret); } else if (ret == 0) { warning(0, "empty write"); } else { if (errno == EINTR || errno == EAGAIN) return; error(errno, "write_data"); exit(1); } } static void gen_message(Octstr *out); /* Return the minimum interval (in microseconds) after which we will * want to be called again. This value is only used if we _don't_ * generate data this time through. */ static long gen_data(Octstr *out) { unsigned char buf[EVIL_BUFSIZE]; size_t i; long interval = -1; static int last_sms; /* Used by ACT_deliver */ time_t now; if (max_deliveries < 0 || deliveries < max_deliveries) { switch (activity) { case ACT_deliver: now = time(NULL); if (last_sms == 0) last_sms = now; while (last_sms < now) { if (random() % 7 == 1) { gen_message(out); last_sms = now; } else last_sms++; } interval = 1000000; break; case ACT_flood: gen_message(out); break; } } switch (spew) { case SPEW_binary: for (i = 0; i < sizeof(buf); i++) { buf[i] = random() % 256; } octstr_append_data(out, buf, sizeof(buf)); break; } return interval; } /******************************* CIMD 2 specific code ************************/ int awaiting_response = 0; /* buf must be at least TIMESTAMP_MAXLEN bytes long. */ static void make_timestamp(unsigned char *buf, time_t fortime) { /* Is there a thread-safe version of gmtime? */ struct tm tm = gw_gmtime(fortime); sprintf(buf, "%02d%02d%02d%02d%02d%02d", tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } static void send_packet(Octstr *out, int opcode, int sequence, ...) { va_list ap; int parm; unsigned char *value; int checksum; int old_len, new_len; if (activity == ACT_listen) return; old_len = octstr_len(out); octstr_format_append(out, "%c%02d:%03d%c", STX, opcode, sequence, TAB); va_start(ap, sequence); for (parm = va_arg(ap, int); parm != 0; parm = va_arg(ap, int)) { value = va_arg(ap, unsigned char *); octstr_format_append(out, "%03d:%s\11", parm, value); } va_end(ap); /* Calculate checksum */ checksum = 0; for (new_len = octstr_len(out); old_len < new_len; old_len++) { checksum = (checksum + octstr_get_char(out, old_len)) & 0xff; } octstr_format_append(out, "%02X%c", checksum, ETX); } static void send_error(Octstr *out, int opcode, int sequence, unsigned char *errorcode, unsigned char *errortext) { if (logging == LOG_packets) printf("SND: ERROR, %s\n", errortext); send_packet(out, opcode, sequence, 900, errorcode, 901, errortext, 0); } static int eat_char(Octstr *packet, int ch) { if (octstr_get_char(packet, 0) == ch) { octstr_delete(packet, 0, 1); return 0; } return -1; } static Octstr *eat_string_parm(Octstr *packet, int parm, int maxlen) { long start, datastart; long tab; Octstr *result; Octstr *parmheader; parmheader = octstr_format("%c%03d:", TAB, parm); start = octstr_search(packet, parmheader, 0); if (start < 0) { octstr_destroy(parmheader); return NULL; } datastart = start + octstr_len(parmheader); tab = octstr_search_char(packet, TAB, datastart + 1); if (tab < 0) { tab = octstr_len(packet); } result = octstr_copy(packet, datastart, tab - datastart); octstr_delete(packet, start, tab - start); octstr_destroy(parmheader); return result; } static long eat_number(Octstr *ostr) { long result; long pos; pos = octstr_parse_long(&result, ostr, 0, 10); if (pos < 0) return INT_MIN; octstr_delete(ostr, 0, pos); return result; } static long eat_int_parm(Octstr *packet, int parm, int maxlen) { Octstr *value; long result; value = eat_string_parm(packet, parm, maxlen); if (!value) return INT_MIN; result = eat_number(value); if (octstr_len(value) > 0) result = INT_MIN; octstr_destroy(value); return result; } static void eat_checksum(Octstr *packet) { int len; int ch1, ch2, ch3; len = octstr_len(packet); if (len < 3) return; ch1 = octstr_get_char(packet, len - 3); ch2 = octstr_get_char(packet, len - 2); ch3 = octstr_get_char(packet, len - 1); if (isxdigit(ch3) && isxdigit(ch2) && ch1 == TAB) octstr_delete(packet, len - 3, 3); } static void handle_login(Octstr *packet, Octstr *out, int sequence) { Octstr *user = eat_string_parm(packet, 10, 32); Octstr *pass = eat_string_parm(packet, 11, 32); if (user == NULL) user = octstr_create(""); if (pass == NULL) pass = octstr_create(""); if (logging == LOG_packets) printf("RCV: Login user '%s', password '%s'\n", octstr_get_cstr(user), octstr_get_cstr(pass)); if (octstr_str_compare(user, username) == 0 && octstr_str_compare(pass, password) == 0) { if (logging == LOG_packets) printf("SND: Login OK\n"); send_packet(out, 51, sequence, 0); } else { send_error(out, 51, sequence, "100", "invalid login"); } octstr_destroy(user); octstr_destroy(pass); } static void handle_logout(Octstr *packet, Octstr *out, int sequence) { if (logging == LOG_packets) printf("RCV: Logout\n"); if (logging == LOG_packets) printf("SND: Logout OK\n"); send_packet(out, 52, sequence, 0); } static void handle_submit(Octstr *packet, Octstr *out, int sequence) { Octstr *dest_addr = eat_string_parm(packet, 21, 20); Octstr *orig_addr = eat_string_parm(packet, 23, 20); long DCS = eat_int_parm(packet, 30, 3); Octstr *UDH = eat_string_parm(packet, 32, 280); Octstr *text = eat_string_parm(packet, 33, 480); Octstr *textb = eat_string_parm(packet, 34, 280); long valid_rel = eat_int_parm(packet, 50, 3); Octstr *valid_abs = eat_string_parm(packet, 51, 12); long proto_id = eat_int_parm(packet, 52, 3); long delivery_rel = eat_int_parm(packet, 53, 3); Octstr *delivery_abs = eat_string_parm(packet, 54, 12); long reply_path = eat_int_parm(packet, 55, 1); long SRR = eat_int_parm(packet, 56, 2); long cancel = eat_int_parm(packet, 58, 1); long tariff_class = eat_int_parm(packet, 64, 2); long service_desc = eat_int_parm(packet, 65, 1); long priority = eat_int_parm(packet, 67, 1); List *other_dests = gwlist_create(); Octstr *tmp; while ((tmp = eat_string_parm(packet, 21, 20))) gwlist_append(other_dests, tmp); if (logging == LOG_packets) { int i; printf("RCV: Submit to %s", octstr_get_cstr(dest_addr)); for (i = 0; i < gwlist_len(other_dests); i++) { printf(", %s", octstr_get_cstr(gwlist_get(other_dests, i))); } printf("\n"); if (orig_addr) printf(" From: %s\n", octstr_get_cstr(orig_addr)); if (DCS > INT_MIN) printf(" Data coding: %ld\n", DCS); if (UDH) printf(" User data header: %s\n", octstr_get_cstr(UDH)); if (text) printf(" Text: %s\n", octstr_get_cstr(text)); if (textb) printf(" Text (binary): %s\n", octstr_get_cstr(textb)); if (valid_rel > INT_MIN) printf(" Validity period: %ld (relative)\n", valid_rel); if (valid_abs) printf(" Validity period: %s (absolute)\n", octstr_get_cstr(valid_abs)); if (proto_id > INT_MIN) printf(" Protocol ID: %ld\n", proto_id); if (delivery_rel > INT_MIN) printf(" First delivery: %ld (relative)\n", delivery_rel); if (delivery_abs) printf(" First delivery: %s (absolute)\n", octstr_get_cstr(delivery_abs)); if (reply_path == 0) printf(" Reply path disabled\n"); else if (reply_path == 1) printf(" Reply path enabled\n"); else if (reply_path > INT_MAX) printf(" Reply path: %ld\n", reply_path); if (SRR > INT_MAX) printf(" Status report flags: %ld\n", SRR); if (cancel == 0) printf(" Cancel disabled\n"); else if (cancel == 1) printf(" Cancel enabled\n"); else if (cancel > INT_MAX) printf(" Cancel enabled: %ld\n", cancel); if (tariff_class > INT_MAX) printf(" Tariff class: %ld\n", tariff_class); if (service_desc > INT_MAX) printf(" Service description: %ld\n", service_desc); if (priority > INT_MAX) printf(" Priority: %ld\n", priority); } if (!dest_addr) { send_error(out, 53, sequence, "300", "no destination"); } else if (gwlist_len(other_dests) > 0) { send_error(out, 53, sequence, "301", "too many destinations"); /* TODO: Report many other possible errors here */ } else { unsigned char buf[TIMESTAMP_MAXLEN]; make_timestamp(buf, time(NULL)); if (logging == LOG_packets) printf("SND: Submit OK\n"); send_packet(out, 53, sequence, 21, octstr_get_cstr(dest_addr), 60, buf, 0); } octstr_destroy(dest_addr); octstr_destroy(orig_addr); octstr_destroy(UDH); octstr_destroy(text); octstr_destroy(textb); octstr_destroy(valid_abs); octstr_destroy(delivery_abs); gwlist_destroy(other_dests, octstr_destroy_item); } static void handle_enquire(Octstr *packet, Octstr *out, int sequence) { Octstr *dest_addr = eat_string_parm(packet, 21, 20); Octstr *timestamp = eat_string_parm(packet, 60, 12); if (logging == LOG_packets) printf("RCV: Enquire status, dest='%s', time='%s'\n", dest_addr ? octstr_get_cstr(dest_addr) : "", timestamp ? octstr_get_cstr(timestamp) : ""); if (!dest_addr) { send_error(out, 54, sequence, "400", "no destination"); } else if (!timestamp) { send_error(out, 54, sequence, "401", "no timestamp"); } else { if (logging == LOG_packets) printf("SND: Respond: status unknown\n"); send_packet(out, 54, sequence, 21, octstr_get_cstr(dest_addr), 60, octstr_get_cstr(timestamp), 61, "0", 0); } octstr_destroy(dest_addr); octstr_destroy(timestamp); } static void handle_delivery_request(Octstr *packet, Octstr *out, int sequence) { long mode = eat_int_parm(packet, 68, 1); if (logging == LOG_packets) { switch (mode) { case 0: printf("RCV: Delivery request, messages waiting?\n"); break; case 1: printf("RCV: Delivery request, one message\n"); break; case 2: printf("RCV: Delivery request, all messages\n"); break; case INT_MIN: printf("RCV: Delivery request, no mode\n"); break; default: printf("RCV: Delivery request, mode %ld\n", mode); } } if (mode == INT_MIN) mode = 1; switch (mode) { case 0: if (logging == LOG_packets) printf("SND: Respond: 0 messages\n"); send_packet(out, 55, sequence, 66, "0", 0); break; case 1: send_error(out, 55, sequence, "500", "no messages available"); break; case 2: send_error(out, 55, sequence, "500", "no messages available"); break; default: send_error(out, 55, sequence, "501", "bad mode"); break; } } static void handle_cancel(Octstr *packet, Octstr *out, int sequence) { long mode = eat_int_parm(packet, 59, 1); Octstr *timestamp = eat_string_parm(packet, 60, 12); Octstr *destination = eat_string_parm(packet, 21, 20); if (logging == LOG_packets) { printf("RCV: Cancel"); if (mode != INT_MIN) printf(", mode %ld", mode); if (destination) printf(", dest '%s'", octstr_get_cstr(destination)); if (timestamp) printf(", time '%s'", octstr_get_cstr(timestamp)); printf("\n"); } if (mode < 0 || mode > 2) send_error(out, 56, sequence, "602", "bad mode"); else { if (logging == LOG_packets) printf("SND: OK\n"); send_packet(out, 56, sequence, 0); } } static void handle_set(Octstr *packet, Octstr *out, int sequence) { Octstr *pass = eat_string_parm(packet, 11, 32); if (pass) { if (logging == LOG_packets) printf("RCV: Set password to '%s'\n", octstr_get_cstr(pass)); send_error(out, 58, sequence, "801", "changing password not allowed"); } else { if (logging == LOG_packets) printf("RCV: Set, unknown parameters\n"); send_error(out, 58, sequence, "3", "cannot set"); } } static void handle_get(Octstr *packet, Octstr *out, int sequence) { long number = eat_int_parm(packet, 500, 3); if (logging == LOG_packets) printf("RCV: Get parameter #%ld\n", number); if (number == INT_MIN) { send_error(out, 59, sequence, "900", "missing parameter"); } else if (number == 501) { unsigned char buf[TIMESTAMP_MAXLEN]; make_timestamp(buf, time(NULL)); if (logging == LOG_packets) printf("SND: OK, SMSC timestamp is '%s'\n", buf); send_packet(out, 59, sequence, 501, buf, 0); } else { send_error(out, 59, sequence, "900", "unknown parameter"); } } static void handle_alive(Octstr *packet, Octstr *out, int sequence) { if (logging == LOG_packets) printf("RCV: Alive?\n"); if (logging == LOG_packets) printf("SND: Alive.\n"); send_packet(out, 90, sequence, 0); } static void handle_deliver_response(Octstr *packet, Octstr *out, int sequence) { awaiting_response = 0; if (logging == LOG_packets) printf("RCV: Deliver response\n"); deliveries++; if (max_deliveries > 0 && deliveries == max_deliveries) { time_t elapsed = time(NULL) - start_time; printf("LOG: %ld deliveries in %ld seconds\n", (long) max_deliveries, (long) elapsed); } /* No need to respond to a response */ } static void handle_deliver_status_report_response(Octstr *packet, Octstr *out, int sequence) { awaiting_response = 0; if (logging == LOG_packets) printf("RCV: Deliver status report response\n"); /* No need to respond to a response */ } static void handle_alive_response(Octstr *packet, Octstr *out, int sequence) { awaiting_response = 0; if (logging == LOG_packets) printf("RCV: Alive.\n"); /* No need to respond to a response */ } static void handle_nack(Octstr *packet, Octstr *out, int sequence) { awaiting_response = 0; if (logging == LOG_packets) printf("RCV: NACK\n"); /* TODO: We should retransmit if we get a nack, but there's * no record of what request we sent. */ } typedef void (*packet_handler)(Octstr *, Octstr *, int); struct { int opcode; packet_handler handler; } handlers[] = { { 1, handle_login }, { 2, handle_logout }, { 3, handle_submit }, { 4, handle_enquire }, { 5, handle_delivery_request }, { 6, handle_cancel }, { 8, handle_set }, { 9, handle_get }, { 40, handle_alive }, { 70, handle_deliver_response }, { 73, handle_deliver_status_report_response }, { 90, handle_alive_response }, { 99, handle_nack }, { -1, NULL }, }; static void parse_packet(Octstr *packet, Octstr *out) { int opcode, sequence; int i; eat_checksum(packet); opcode = eat_number(packet); if (opcode < 0 || eat_char(packet, ':') < 0) return; sequence = eat_number(packet); if (sequence < 0) return; for (i = 0; handlers[i].opcode >= 0; i++) { if (handlers[i].opcode == opcode) { (handlers[i].handler)(packet, out, sequence); break; } } if (handlers[i].opcode < 0) { /* Loop failed */ if (logging == LOG_packets) printf("RCV: unknown operation %ld\n", (long) handlers[i].opcode); send_error(out, 98, sequence, "1", "unexpected operation"); } } /* Parse the data stream for packets, and send out replies. */ static void parse_data(Octstr *in, Octstr *out) { int stx, etx; Octstr *packet; for (;;) { /* Look for start of packet. Delete everything up to the start * marker. (CIMD2 section 3.1 says we can ignore any data * transmitted between packets.) */ stx = octstr_search_char(in, STX, 0); if (stx < 0) octstr_delete(in, 0, octstr_len(in)); else if (stx > 0) octstr_delete(in, 0, stx); etx = octstr_search_char(in, ETX, 0); if (etx < 0) return; /* Incomplete packet; wait for more data. */ /* Copy the data between stx and etx */ packet = octstr_copy(in, 1, etx - 1); /* Then cut the packet (including stx and etx) from inbuffer */ octstr_delete(in, 0, etx + 1); parse_packet(packet, out); octstr_destroy(packet); } } static void random_address(unsigned char *buf, int size) { int len = random() % size; while (len--) { *buf++ = '0' + random() % 10; } *buf++ = '\0'; } static void random_message(unsigned char *buf, int size) { int len = random() % size; while (len--) { do { *buf = random() % 256; } while (*buf == STX || *buf == ETX || *buf == TAB); buf++; } *buf++ = '\0'; } static void random_hex(unsigned char *buf, int size) { int len = random() % size; /* Make even */ len -= (len % 2); while (len--) { int c = random() % 16; if (c < 10) *buf++ = c + '0'; else *buf++ = c - 10 + 'a'; } *buf++ = '\0'; } static void gen_message(Octstr *out) { static int send_seq = 0; unsigned char dest[21]; unsigned char orig[21]; unsigned char scts[TIMESTAMP_MAXLEN]; unsigned char message[481]; unsigned char udh[281]; if (awaiting_response == 1) return; random_address(dest, sizeof(dest)); random_address(orig, sizeof(orig)); make_timestamp(scts, time(NULL)); random_message(message, sizeof(message)); if (random() % 2 == 0) random_hex(udh, sizeof(udh)); else *udh = 0; if (logging == LOG_packets) printf("SND: Deliver message (random)\n"); if (*udh) { send_packet(out, 20, send_seq, 21, dest, 23, orig, 60, scts, 32, udh, 33, message, 0); } else { send_packet(out, 20, send_seq, 21, dest, 23, orig, 60, scts, 33, message, 0); } send_seq += 2; if (send_seq > 255) send_seq = 0; awaiting_response = 1; } /************************** CIMD 2 specific code ends ************************/ static void main_loop(void) { fd_set readfds, writefds; int n; static int reported_outfull = 0; int interval = -1; inbuffer = octstr_create(""); outbuffer = octstr_create(intro); start_time = time(NULL); for (;;) { if (octstr_len(outbuffer) < OUTBUFFER_LIMIT) { interval = gen_data(outbuffer); } else if (!reported_outfull) { warning(0, "outbuffer getting full; waiting..."); reported_outfull = 1; } FD_ZERO(&readfds); FD_SET(sockfd, &readfds); if (octstr_len(outbuffer) > 0) { FD_ZERO(&writefds); FD_SET(sockfd, &writefds); n = select(sockfd+1, &readfds, &writefds, NULL, NULL); } else { struct timeval tv; struct timeval *tvp; if (interval >= 0) { tv.tv_sec = 0; tv.tv_usec = interval; tvp = &tv; } else { tvp = NULL; } n = select(sockfd+1, &readfds, NULL, NULL, tvp); } if (n < 0) { if (errno == EINTR) { warning(errno, "main loop, select"); continue; } error(errno, "main loop, select"); sleep(1); continue; } if (n > 0) { if (FD_ISSET(sockfd, &readfds)) { read_data(inbuffer, sockfd); parse_data(inbuffer, outbuffer); } if (octstr_len(outbuffer) > 0 && FD_ISSET(sockfd, &writefds)) { write_data(outbuffer, sockfd); } if (octstr_len(outbuffer) < OUTBUFFER_LIMIT) { reported_outfull = 0; } } } } static struct { unsigned char *option; void *location; int number; } options[] = { { "--user", &username, 0 }, { "--password", &password, 0 }, { "--port", &port, 1 }, { "--intro", &intro, 0 }, { "--activity", &activity, 1 }, { "--spew", &spew, 1 }, { "--logging", &logging, 1 }, { "--checking", &checking, 1 }, { "--max", &max_deliveries, 1 }, { NULL, NULL, 0 }, }; static int wait_for_client(int port) { struct sockaddr_in sin; socklen_t addrlen; int listenfd; int clientfd; Octstr *addr; listenfd = make_server_socket(port, NULL); if (listenfd < 0) { fprintf(stderr, "%s: failed to open socket at port %d\n", progname, port); exit(1); } do { addrlen = sizeof(sin); clientfd = accept(listenfd, (struct sockaddr *)&sin, &addrlen); if (clientfd < 0) { error(errno, "failed to accept new connection"); } } while (clientfd < 0); if (socket_set_blocking(clientfd, 0) < 0) { panic(0, "failed to make client socket nonblocking"); } addr = gw_netaddr_to_octstr(AF_INET, &sin.sin_addr); info(0, "Accepted client from %s:%d", octstr_get_cstr(addr), ntohs(sin.sin_port)); octstr_destroy(addr); close(listenfd); return clientfd; } int main(int argc, char *argv[]) { int i; int opt; gwlib_init(); progname = argv[0]; srandom(0); /* Make "random" data reproducible */ for (i = 1; i < argc; i++) { for (opt = 0; options[opt].option; opt++) { if (strcmp(argv[i], options[opt].option) == 0) { if (i + 1 >= argc) { fprintf(stderr, "%s: missing argument to %s", progname, argv[i]); exit(2); } if (options[opt].number) { * (int *) options[opt].location = atoi(argv[i+1]); } else { * (char **) options[opt].location = argv[i+1]; } i++; break; } } if (options[opt].option) continue; if (strcmp(argv[i], "--help") == 0) { usage(stdout); exit(0); } if (argv[i][0] == '-') { fprintf(stderr, "%s: unknown option %s\n", progname, argv[i]); usage(stderr); exit(2); } } sockfd = wait_for_client(port); main_loop(); return 0; } gateway-1.4.5/test/test_ppg.c0000644000175000017500000010411413227613126014640 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * A very simple push initiator for testing a push proxy gateway * * Read pap control content and push content from files, pack them into a PAP * protocol MIME message and invoke push services specified by an url. Use a * hardcoded message boundary (asdlfkjiurwgasf), for simpler command line * interface. * Repetitions and use of multiple threads can be requested, in addition of * setting of some headers. * * By Aarno Syv�nen for Wiral Ltd and Global Networks Inc. */ #define MAX_THREADS 1024 #define MAX_IN_QUEUE 128 #include #include #include #include "gwlib/gwlib.h" #include "gw/wap_push_pap_compiler.h" static long max_pushes = 1; static int verbose = 1, use_hardcoded = 0, num_urls = 0, use_headers = 0, use_config = 0, accept_binary = 0, use_numeric = 0, use_string = 0, use_content_header = 0, add_epilogue = 0, add_preamble = 0, use_dlr_mask = 0, use_dlr_url = 0; static double wait_seconds = 0.0; static Counter *counter = NULL; static char **push_data = NULL; static char *boundary = NULL; static Octstr *content_flag = NULL; static Octstr *appid_flag = NULL; static Octstr *appid_string = NULL; static Octstr *content_header = NULL; static Octstr *content_transfer_encoding = NULL; static Octstr *connection = NULL; static Octstr *delimiter = NULL; static Octstr *initiator_uri = NULL; static Octstr *dlr_mask = NULL; static Octstr *dlr_url = NULL; enum { SSL_CONNECTION_OFF = 0, DEFAULT_NUMBER_OF_RELOGS = 2}; /* * Configuration variables */ static int pi_ssl = SSL_CONNECTION_OFF; static long retries = DEFAULT_NUMBER_OF_RELOGS; static Octstr *ssl_client_certkey_file = NULL; static Octstr *push_url = NULL; static Octstr *pap_file = NULL; static Octstr *content_file = NULL; static Octstr *username = NULL; static Octstr *password = NULL; static void read_test_ppg_config(Octstr *name) { Cfg *cfg; CfgGroup *grp; cfg = cfg_create(name); if (cfg_read(cfg) == -1) panic(0, "Cannot read a configuration file %s, exiting", octstr_get_cstr(name)); cfg_dump(cfg); grp = cfg_get_single_group(cfg, octstr_imm("test-ppg")); cfg_get_integer(&retries, grp, octstr_imm("retries")); cfg_get_bool(&pi_ssl, grp, octstr_imm("pi-ssl")); #ifdef HAVE_LIBSSL if (pi_ssl) { ssl_client_certkey_file = cfg_get(grp, octstr_imm("ssl-client-certkey-file")); if (ssl_client_certkey_file != NULL) { conn_use_global_client_certkey_file(ssl_client_certkey_file); } else { error(0, "cannot set up SSL without client certkey file"); exit(1); } } #endif grp = cfg_get_single_group(cfg, octstr_imm("configuration")); push_url = cfg_get(grp, octstr_imm("push-url")); pap_file = cfg_get(grp, octstr_imm("pap-file")); content_file = cfg_get(grp, octstr_imm("content-file")); if (!use_hardcoded) { username = cfg_get(grp, octstr_imm("username")); password = cfg_get(grp, octstr_imm("password")); } cfg_destroy(cfg); } static void add_delimiter(Octstr **content) { if (octstr_compare(delimiter, octstr_imm("crlf")) == 0) { octstr_format_append(*content, "%c", '\r'); } octstr_format_append(*content, "%c", '\n'); } static void add_push_application_id(Octstr *appid_flag, Octstr **content, int use_string) { if (use_string) { *content = octstr_format("%S\r\n", appid_string); return; } if (octstr_compare(appid_flag, octstr_imm("any")) == 0) { if (!use_numeric) *content = octstr_create("X-WAP-Application-Id: http://www.wiral.com:*\r\n"); else *content = octstr_create("X-WAP-Application-Id: 0\r\n"); } else if (octstr_compare(appid_flag, octstr_imm("ua")) == 0) { if (!use_numeric) *content = octstr_create("X-WAP-Application-Id: http://www.wiral.com:wml.ua\r\n"); else *content = octstr_create("X-WAP-Application-Id: 2\r\n"); } else if (octstr_compare(appid_flag, octstr_imm("mms")) == 0) { if (!use_numeric) *content = octstr_create("X-WAP-Application-Id: mms.ua\r\n"); else *content = octstr_create("X-WAP-Application-Id: 4\r\n"); } else if (octstr_compare(appid_flag, octstr_imm("scrap")) == 0) { if (!use_numeric) *content = octstr_create("X-WAP-Application-Id: no appid at all\r\n"); else *content = octstr_create("X-WAP-Application-Id: this is not a numeric header\r\n"); } } static void add_dlr_mask(List **push_headers, Octstr *value) { http_header_add(*push_headers, "X-Kannel-DLR-Mask", octstr_get_cstr(value)); } static void add_dlr_url(List **push_headers, Octstr *value) { http_header_add(*push_headers, "X-Kannel-DLR-Url", octstr_get_cstr(value)); } static void add_part_header(Octstr *content_keader, Octstr **wap_content) { if (use_content_header) { octstr_append(*wap_content, content_header); } add_delimiter(wap_content); } static void add_content_type(Octstr *content_flag, Octstr **content) { if (*content == NULL) *content = octstr_create(""); if (octstr_compare(content_flag, octstr_imm("wml")) == 0) octstr_append_cstr(*content, "Content-Type: text/vnd.wap.wml\r\n"); else if (octstr_compare(content_flag, octstr_imm("si")) == 0) octstr_append_cstr(*content, "Content-Type: text/vnd.wap.si\r\n"); else if (octstr_compare(content_flag, octstr_imm("sl")) == 0) octstr_append_cstr(*content, "Content-Type: text/vnd.wap.sl\r\n"); else if (octstr_compare(content_flag, octstr_imm("multipart")) == 0) octstr_append_cstr(*content, "Content-Type: multipart/related; boundary=fsahgwruijkfldsa\r\n"); else if (octstr_compare(content_flag, octstr_imm("mms")) == 0) octstr_append_cstr(*content, "Content-Type: application/vnd.wap.mms-message\r\n"); } static void add_content_transfer_encoding_type(Octstr *content_flag, Octstr *wap_content) { if (!content_flag) return; if (octstr_compare(content_flag, octstr_imm("base64")) == 0) octstr_append_cstr(wap_content, "Content-transfer-encoding: base64"); add_delimiter(&wap_content); } static void add_connection_header(List **push_headers, Octstr *connection) { if (!connection) return; if (octstr_compare(connection, octstr_imm("close")) == 0) http_header_add(*push_headers, "Connection", "close"); else if (octstr_compare(connection, octstr_imm("keep-alive")) == 0) http_header_add(*push_headers, "Connection", "keep-alive"); } static void transfer_encode (Octstr *cte, Octstr *content) { if (!cte) return; if (octstr_compare(cte, octstr_imm("base64")) == 0) { octstr_binary_to_base64(content); } } /* * Add boundary value to the multipart header. */ static Octstr *make_multipart_value(const char *boundary) { Octstr *hos; hos = octstr_format("%s", "multipart/related; boundary="); octstr_append(hos, octstr_imm(boundary)); octstr_append(hos, octstr_imm("; type=\"application/xml\"")); return hos; } static Octstr *make_part_delimiter(Octstr *boundary) { Octstr *part_delimiter; part_delimiter = octstr_create(""); add_delimiter(&part_delimiter); octstr_format_append(part_delimiter, "%s", "--"); octstr_append(part_delimiter, boundary); add_delimiter(&part_delimiter); return part_delimiter; } static Octstr *make_close_delimiter(Octstr *boundary) { Octstr *close_delimiter; close_delimiter = octstr_create(""); add_delimiter(&close_delimiter); octstr_format_append(close_delimiter, "%s", "--"); octstr_append(close_delimiter, boundary); octstr_format_append(close_delimiter, "%s", "--"); /*add_delimiter(&close_delimiter);*/ return close_delimiter; } static List *push_headers_create(size_t content_len) { List *push_headers; Octstr *mos; mos = NULL; push_headers = http_create_empty_headers(); if (use_hardcoded) http_header_add(push_headers, "Content-Type", "multipart/related;" " boundary=asdlfkjiurwgasf; type=\"application/xml\""); else http_header_add(push_headers, "Content-Type", octstr_get_cstr(mos = make_multipart_value(boundary))); if (use_headers) http_add_basic_auth(push_headers, username, password); add_connection_header(&push_headers, connection); if (use_dlr_mask) add_dlr_mask(&push_headers, dlr_mask); if (use_dlr_url) add_dlr_url(&push_headers, dlr_url); octstr_destroy(mos); /* add initiator... */ if (initiator_uri) http_header_add(push_headers, "X-Wap-Initiator-URI", octstr_get_cstr(initiator_uri)); return push_headers; } static Octstr *push_content_create(void) { Octstr *push_content, *wap_content; Octstr *wap_file_content, *pap_content, *pap_file_content, *bpos, *bcos; wap_content = NULL; push_content = NULL; if (use_hardcoded) { push_content = octstr_create("\r\n\r\n" "--asdlfkjiurwgasf\r\n" "Content-Type: application/xml\r\n\r\n" "" "" "" "" "
" "
" "" "" "
" "
\r\n\r\n" "--asdlfkjiurwgasf\r\n" "Content-Type: text/vnd.wap.si\r\n\r\n" "" "" "" "" "Want to test a fetch?" "" "\r\n\r\n" "--asdlfkjiurwgasf--\r\n\r\n" ""); } else { add_push_application_id(appid_flag, &wap_content, use_string); add_content_type(content_flag, &wap_content); add_content_transfer_encoding_type(content_transfer_encoding, wap_content); add_part_header(content_header, &wap_content); /* Read the content file. (To be pushed)*/ if ((wap_file_content = octstr_read_file(octstr_get_cstr(content_file))) == NULL) panic(0, "Stopping"); if (accept_binary) { octstr_delete_matching(wap_file_content, octstr_imm(" ")); octstr_delete_matching(wap_file_content, octstr_imm("\n")); octstr_delete_matching(wap_file_content, octstr_imm("\r")); if (!octstr_is_all_hex(wap_file_content)) panic(0, "non-hex chars in the content file, cannot continue"); octstr_hex_to_binary(wap_file_content); } transfer_encode(content_transfer_encoding, wap_file_content); octstr_append(wap_content, wap_file_content); octstr_destroy(wap_file_content); /* Read the control file. (To control pushing)*/ pap_content = octstr_format("%s", "Content-Type: application/xml"); add_delimiter(&pap_content); add_delimiter(&pap_content); if ((pap_file_content = octstr_read_file(octstr_get_cstr(pap_file))) == NULL) panic(0, "Stopping"); octstr_append(pap_content, pap_file_content); octstr_destroy(pap_file_content); if (wap_content == NULL || pap_content == NULL) panic(0, "Cannot open the push content files"); push_content = octstr_create(""); if (add_preamble) octstr_append(push_content, octstr_imm("the parser should discard this")); octstr_append(push_content, bpos = make_part_delimiter(octstr_imm(boundary))); /*octstr_append(push_content, octstr_imm("\r\n"));*/ /* Do we accept an additional * clrf ? */ octstr_append(push_content, pap_content); octstr_append(push_content, bpos); octstr_destroy(bpos); octstr_append(push_content, wap_content); octstr_append(push_content, bcos = make_close_delimiter(octstr_imm(boundary))); if (add_epilogue) { octstr_append(push_content, octstr_imm("\r\n")); octstr_append(push_content, octstr_imm("the parser should discard this")); } octstr_destroy(bcos); octstr_destroy(pap_content); octstr_destroy(wap_content); } return push_content; } static void make_url(Octstr **url) { if (use_config && !use_headers) { octstr_append(*url, octstr_imm("?username=")); octstr_append(*url, username ? username : octstr_imm("default")); octstr_append(*url, octstr_imm("&password=")); octstr_append(*url, password ? password: octstr_imm("default")); } } static void start_push(HTTPCaller *caller, long i) { List *push_headers; Octstr *push_content; long *id; push_content = push_content_create(); push_headers = push_headers_create(octstr_len(push_content)); if (verbose) { debug("test.ppg", 0, "we have push content"); octstr_dump(push_content, 0); debug("test.ppg", 0, "and headers"); http_header_dump(push_headers); } id = gw_malloc(sizeof(long)); *id = i; make_url(&push_url); debug("test.ppg", 0, "TEST_PPG: starting to push job %ld", i); http_start_request(caller, HTTP_METHOD_POST, push_url, push_headers, push_content, 0, id, ssl_client_certkey_file); debug("test.ppg", 0, "push done"); octstr_destroy(push_content); http_destroy_headers(push_headers); } /* * Try log in defined number of times, when got response 401 and authentica- * tion info is in headers. */ static int receive_push_reply(HTTPCaller *caller) { void *id; long *trid; int http_status, tries; List *reply_headers; Octstr *final_url, *auth_url, *reply_body, *os, *push_content, *auth_reply_body; WAPEvent *e; List *retry_headers; http_status = HTTP_UNAUTHORIZED; tries = 0; id = http_receive_result(caller, &http_status, &final_url, &reply_headers, &reply_body); if (id == NULL || http_status == -1 || final_url == NULL) { error(0, "push failed, no reason found"); goto push_failed; } while (use_headers && http_status == HTTP_UNAUTHORIZED && tries < retries) { debug("test.ppg", 0, "try number %d", tries); debug("test.ppg", 0, "authentication failure, get a challenge"); http_destroy_headers(reply_headers); push_content = push_content_create(); retry_headers = push_headers_create(octstr_len(push_content)); http_add_basic_auth(retry_headers, username, password); trid = gw_malloc(sizeof(long)); *trid = tries; http_start_request(caller, HTTP_METHOD_POST, final_url, retry_headers, push_content, 0, trid, NULL); debug("test.ppg ", 0, "TEST_PPG: doing response to %s", octstr_get_cstr(final_url)); octstr_destroy(push_content); http_destroy_headers(retry_headers); trid = http_receive_result(caller, &http_status, &auth_url, &reply_headers, &auth_reply_body); if (trid == NULL || http_status == -1 || auth_url == NULL) { error(0, "unable to send authorisation, no reason found"); goto push_failed; } debug("test.ppg", 0, "TEST_PPG: send authentication to %s, retry %ld", octstr_get_cstr(auth_url), *(long *) trid); gw_free(trid); octstr_destroy(auth_reply_body); octstr_destroy(auth_url); ++tries; } if (http_status == HTTP_NOT_FOUND) { error(0, "push failed, service not found"); goto push_failed; } if (http_status == HTTP_FORBIDDEN) { error(0, "push failed, service forbidden"); goto push_failed; } if (http_status == HTTP_UNAUTHORIZED) { if (use_headers) error(0, "tried %ld times, stopping", retries); else error(0, "push failed, authorisation failure"); goto push_failed; } debug("test.ppg", 0, "TEST_PPG: push %ld done: reply from, %s", *(long *) id, octstr_get_cstr(final_url)); gw_free(id); octstr_destroy(final_url); if (verbose) debug("test.ppg", 0, "TEST_PPG: reply headers were"); while ((os = gwlist_extract_first(reply_headers)) != NULL) { if (verbose) octstr_dump(os, 0); octstr_destroy(os); } if (verbose) { debug("test.ppg", 0, "TEST_PPG: reply body was"); octstr_dump(reply_body, 0); } e = NULL; if (pap_compile(reply_body, &e) < 0) { warning(0, "TEST_PPG: receive_push_reply: cannot compile pap message"); goto parse_error; } switch (e->type) { case Push_Response: debug("test.ppg", 0, "TEST_PPG: and type push response"); break; case Bad_Message_Response: debug("test.ppg", 0, "TEST_PPG: and type bad message response"); break; default: warning(0, "TEST_PPG: unknown event received from %s", octstr_get_cstr(final_url)); break; } octstr_destroy(reply_body); wap_event_destroy(e); http_destroy_headers(reply_headers); return 0; push_failed: gw_free(id); octstr_destroy(final_url); octstr_destroy(reply_body); http_destroy_headers(reply_headers); return -1; parse_error: octstr_destroy(reply_body); http_destroy_headers(reply_headers); wap_event_destroy(e); return -1; } static void push_thread(void *arg) { HTTPCaller *caller; long succeeded, failed, in_queue; unsigned long i; caller = arg; succeeded = 0; failed = 0; in_queue = 0; i = 0; for (;;) { while (in_queue < MAX_IN_QUEUE) { i = counter_increase(counter); if (i >= max_pushes) goto receive_rest; start_push(caller, i); if (wait_seconds > 0) gwthread_sleep(wait_seconds); ++in_queue; } while (in_queue >= MAX_IN_QUEUE) { if (receive_push_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } } receive_rest: while (in_queue > 0) { if (receive_push_reply(caller) == -1) ++failed; else ++succeeded; --in_queue; } http_caller_destroy(caller); info(0, "TEST_PPG: In thread %ld %ld succeeded, %ld failed", (long) gwthread_self(), succeeded, failed); } static void help(void) { info(0, "Usage: test_ppg [options] push_url [content_file pap_file]"); info(0, " or"); info(0, "Usage: test_ppg [options] [conf_file]"); info(0, "Implements push initiator for wap push. Push services are "); info(0, "located in push_url, push content in the file content file."); info(0, "File pap_file contains pap control document that controls"); info(0, "pushing"); info(0, "If option -H is not used, command line has either three or one"); info(0, "arguments:"); info(0, " a) the url of the push proxy gateway"); info(0, " b) a file containing the content to be pushed"); info(0, " c) a pap document controlling pushing"); info(0, " or"); info(0, " a) a test configuration file, containing all these"); info(0, "Option -H cannot be used with a configuration file. If it is"); info(0, "used, the push url is the only argument."); info(0, "Options are:"); info(0, "-h"); info(0, "print this info"); info(0, "-c content qualifier"); info(0, "Define content type of the push content. Wml, multipart, nil,"); info(0, "scrap, sl, and si accepted. Si is default, nil (no content"); info(0, " type at all) and scrap (random string) are used for debugging"); info(0, "-a application id"); info(0, "Define the client application that will handle the push. Any,"); info(0, "ua, mms, nil and scrap accepted, default ua."); info(0, "-n"); info(0, "if set, use numeric appid values instead of string ones. For"); info(0, "instance, '4' instead of 'mms.ua'. Default is off."); info(0, "-s string"); info(0, "supply a message header as a plain string. For instance"); info(0, "-s x-wap-application-id:mms.ua equals -a ua. Default is"); info(0, "x-wap-application-id:mms.ua."); info(0, "-I string"); info(0, "supply an initiator header as a plain string. For instance"); info(0, "-I x-wap-application-id:http://foo.bar equals -I http://foo.bar"); info(0, "-S string"); info(0, "supply an additional part header (for push content) as a string."); info(0, "For instance, -S Content-Language: en. Default no additional part"); info(0, "headers."); info(0, "-b"); info(0, "If true, send username/password in headers. Default false"); info(0, "-v number"); info(0, " Set log level for stderr logging. Default 0 (debug)"); info(0, "-q"); info(0, " Do not print debugging information"); info(0, "Default: print it"); info(0, "-r number"); info(0, " Make `number' requests. Default one request"); info(0, "-i seconds"); info(0, " Wait 'seconds' seconds between pushes. Default: do not wait"); info(0, "-e transfer encoding"); info(0, " use transfer encoding to send push contents."); info(0, " Currently supported is base64."); info(0, "-k connection header"); info(0, "Use the connection header. Keep-alive and close accepted,"); info(0, "default close"); info(0, "-H"); info(0, "Use hardcoded MIME message, containing a pap control document."); info(0, "In addition, use hardcoded username/password in headers (if "); info(0, "flag -b is set, too"); info(0, "Default: read components from files"); info(0, "-t"); info(0, "number of threads, maximum 1024, default 1"); info(0, "-B"); info(0, "accept binary push content. Default: off."); info(0, "Binary content consist of hex numbers. In addition, crs, lfs and"); info(0, "spaces are accepted, and ignored."); info(0, "-d value"); info(0, "set delimiter to be used. Accepted values crlf and lf. Default crlf."); info(0, "-E"); info(0, "If set, add a hardcoded epilogue (epilogue is to be discarded anyway)."); info(0, "Default off."); info(0, "-p"); info(0, "If set, add hardcoded preamble. Default is off."); info(0, "-m value"); info(0, "If set, add push header X-Kannel-DLR-Mask: value"); info(0, "Default off."); info(0, "-u value"); info(0, "If set, add push header X-Kannel-DLR-Url: value"); info(0, "Default off."); } int main(int argc, char **argv) { int opt, num_threads; time_t start, end; double run_time; long threads[MAX_THREADS]; long i; Octstr *fos; gwlib_init(); num_threads = 1; while ((opt = getopt(argc, argv, "HhBbnEpv:qr:t:c:a:i:e:k:d:s:S:I:m:u:")) != EOF) { switch(opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'q': verbose = 0; break; case 'r': max_pushes = atoi(optarg); break; case 'i': wait_seconds = atof(optarg); break; case 't': num_threads = atoi(optarg); if (num_threads > MAX_THREADS) num_threads = MAX_THREADS; break; case 'H': use_hardcoded = 1; break; case 'c': content_flag = octstr_create(optarg); if (octstr_compare(content_flag, octstr_imm("wml")) != 0 && octstr_compare(content_flag, octstr_imm("si")) != 0 && octstr_compare(content_flag, octstr_imm("sl")) != 0 && octstr_compare(content_flag, octstr_imm("nil")) != 0 && octstr_compare(content_flag, octstr_imm("mms")) != 0 && octstr_compare(content_flag, octstr_imm("scrap")) != 0 && octstr_compare(content_flag, octstr_imm("multipart")) != 0) { octstr_destroy(content_flag); error(0, "TEST_PPG: Content type not known"); help(); exit(1); } break; case 'a': appid_flag = octstr_create(optarg); if (octstr_compare(appid_flag, octstr_imm("any")) != 0 && octstr_compare(appid_flag, octstr_imm("ua")) != 0 && octstr_compare(appid_flag, octstr_imm("mms")) != 0 && octstr_compare(appid_flag, octstr_imm("nil")) != 0 && octstr_compare(appid_flag, octstr_imm("scrap")) != 0) { octstr_destroy(appid_flag); error(0, "TEST_PPG: Push application id not known"); help(); exit(1); } break; case 'n': use_numeric = 1; break; case 's': appid_string = octstr_create(optarg); use_string = 1; break; case 'S': content_header = octstr_create(optarg); use_content_header = 1; break; case 'e': content_transfer_encoding = octstr_create(optarg); if (octstr_compare(content_transfer_encoding, octstr_imm("base64")) != 0) { octstr_destroy(content_transfer_encoding); error(0, "TEST_PPG: unknown content transfer" " encoding \"%s\"", octstr_get_cstr(content_transfer_encoding)); help(); exit(1); } break; case 'k': connection = octstr_create(optarg); if (octstr_compare(connection, octstr_imm("close")) != 0 && octstr_compare(connection, octstr_imm("keep-alive")) != 0) { octstr_destroy(connection); error(0, "TEST_PPG: Connection-header unacceptable"); help(); exit(1); } break; case 'h': help(); exit(1); case 'b': use_headers = 1; break; case 'B': accept_binary = 1; break; case 'd': delimiter = octstr_create(optarg); if (octstr_compare(delimiter, octstr_imm("crlf")) != 0 && octstr_compare(delimiter, octstr_imm("lf")) != 0) { octstr_destroy(delimiter); error(0, "illegal d value"); help(); exit(1); } break; case 'E': add_epilogue = 1; break; case 'p': add_preamble = 1; break; case 'I': initiator_uri = octstr_create(optarg); break; case 'm': use_dlr_mask = 1; dlr_mask = octstr_create(optarg); break; case 'u': use_dlr_url = 1; dlr_url = octstr_create(optarg); break; case '?': default: error(0, "TEST_PPG: Invalid option %c", opt); help(); error(0, "Stopping"); exit(1); } } if (optind == argc) { help(); exit(1); } push_data = argv + optind; num_urls = argc - optind; if (content_flag == NULL) content_flag = octstr_imm("si"); if (appid_flag == NULL) appid_flag = octstr_imm("ua"); if (appid_string == NULL) appid_string = octstr_imm("x-wap-application-id: wml.ua"); if (content_header == NULL) use_content_header = 0; if (dlr_mask == NULL) use_dlr_mask = 0; if (dlr_url == NULL) use_dlr_url = 0; if (delimiter == NULL) delimiter = octstr_imm("crlf"); if (use_hardcoded) { username = octstr_imm("troo"); password = octstr_imm("far"); } if (push_data[0] == NULL) { error(0, "No ppg address or config file, stopping"); exit(1); } use_config = 0; if (!use_hardcoded) { if (push_data[1] == NULL) { info(0, "a configuration file input assumed"); read_test_ppg_config(fos = octstr_format("%s", push_data[0])); octstr_destroy(fos); use_config = 1; } } if (!use_config) push_url = octstr_format("%s", push_data[0]); if (!use_hardcoded && !use_config && push_data[1] != NULL) { if (push_data[2] == NULL) { error(0, "no pap control document, stopping"); exit(1); } else { info(0, "an input without a configuration file assumed"); content_file = octstr_create(push_data[1]); pap_file = octstr_create(push_data[2]); debug("test.ppg", 0, "using %s as a content file", push_data[1]); debug("test.ppg", 0, "using %s as a control file", push_data[2]); } } boundary = "asdlfkjiurwghasf"; counter = counter_create(); time(&start); if (num_threads == 0) push_thread(http_caller_create()); else { for (i = 0; i < num_threads; ++i) threads[i] = gwthread_create(push_thread, http_caller_create()); for (i = 0; i < num_threads; ++i) gwthread_join(threads[i]); } time(&end); run_time = difftime(end, start); info(0, "TEST_PPG: %ld requests in %f seconds, %f requests per second", max_pushes, run_time, max_pushes / run_time); octstr_destroy(content_flag); octstr_destroy(appid_flag); octstr_destroy(content_header); octstr_destroy(content_file); octstr_destroy(pap_file); octstr_destroy(ssl_client_certkey_file); octstr_destroy(username); octstr_destroy(password); octstr_destroy(push_url); octstr_destroy(connection); octstr_destroy(delimiter); octstr_destroy(dlr_mask); octstr_destroy(dlr_url); counter_destroy(counter); gwlib_shutdown(); exit(0); } gateway-1.4.5/test/test_radius_acct.c0000644000175000017500000001716313227613126016342 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_radius_acct.c - program to test RADIUS accounting proxy thread * * Stipe Tolj */ #include #include #include "gwlib/gwlib.h" #include "radius/radius_pdu.h" /* * Updates the internal RADIUS mapping table. Returns 1 if the * mapping has been new and put into the table, otherwise if it's * a duplicate returns 0. */ static int update_table(RADIUS_PDU *pdu, Dict **table) { Octstr *client_ip, *msisdn; Octstr *type; int ret = 0; client_ip = msisdn = NULL; /* only add if we have a Accounting-Request PDU */ if (pdu->type == 0x04) { /* check if we have a START or STOP event */ type = dict_get(pdu->attr, octstr_imm("Acct-Status-Type")); /* grep the needed data */ client_ip = dict_get(pdu->attr, octstr_imm("Framed-IP-Address")); msisdn = dict_get(pdu->attr, octstr_imm("Calling-Station-Id")); if (octstr_compare(type, octstr_imm("1")) == 0) { /* START */ if (dict_get(*table, client_ip) == NULL) { dict_put(*table, client_ip, msisdn); info(0, "RADIUS: Mapping `%s <-> %s' added.", octstr_get_cstr(client_ip), octstr_get_cstr(msisdn)); ret = 1; } else { warning(0, "RADIUS: Duplicate mapping for `%s <-> %s' received", octstr_get_cstr(client_ip), octstr_get_cstr(msisdn)); } } else if (octstr_compare(type, octstr_imm("2")) == 0) { /* STOP */ msisdn = dict_get(*table, client_ip); dict_remove(*table, client_ip); } else { error(0, "RADIUS: unknown Acct-Status-Type `%s' received.", octstr_get_cstr(type)); } } octstr_destroy(client_ip); octstr_destroy(msisdn); return ret; } static void server(int lport, int pport) { int i; int ss, cs; /* server and client socket */ Octstr *data, *from, *addr; /* pid_t pid = getpid(); */ Dict *radius_table; /* create client binding */ cs = udp_client_socket(); addr = udp_create_address(octstr_create("localhost"), pport); /* create server binding */ ss = udp_bind(lport, "0.0.0.0"); if (ss == -1) panic(0, "Couldn't set up server socket for port %d.", lport); /* init hash table */ radius_table = dict_create(30, (void (*)(void *))octstr_destroy); i = 1; while (1) { RADIUS_PDU *pdu, *r; Octstr *rdata; int forward = 0; /* get request */ if (udp_recvfrom(ss, &data, &from) == -1) panic(0, "Couldn't receive request data from NAS"); info(0, "Got data from NAS <%s:%d>", octstr_get_cstr(udp_get_ip(from)), udp_get_port(from)); /* debug("",0,"Saving PDU packet"); f = fopen(octstr_get_cstr(octstr_format("/tmp/radius-pdu.%ld.%d", pid, i)), "w"); octstr_print(f, data); fclose(f); */ pdu = radius_pdu_unpack(data); info(0, "PDU type: %s", pdu->type_name); /* XXX authenticator md5 check does not work?! */ /* radius_authenticate_pdu(pdu, data, octstr_imm("radius")); */ /* store to hash table if not present yet */ forward = update_table(pdu, &radius_table); /* create response PDU for NAS */ r = radius_pdu_create(0x05, pdu); /* * create response authenticator * code+identifier(req)+length+authenticator(req)+(attributes)+secret */ r->u.Accounting_Response.identifier = pdu->u.Accounting_Request.identifier; r->u.Accounting_Response.authenticator = octstr_duplicate(pdu->u.Accounting_Request.authenticator); rdata = radius_pdu_pack(r); /* creates response autenticator in encoded PDU */ radius_authenticate_pdu(r, &rdata, octstr_imm("radius")); /* forward request to remote RADIUS server only if table updated */ if (forward) { if (udp_sendto(cs, data, addr) == -1) panic(0, "Couldn't send to remote RADIUS."); if (udp_recvfrom(cs, &data, &from) == -1) panic(0, "Couldn't receive from remote RADIUS."); info(0, "Got data from remote RADIUS <%s:%d>", octstr_get_cstr(udp_get_ip(from)), udp_get_port(from)); } /* send response to NAS */ if (udp_sendto(ss, rdata, from) == -1) panic(0, "Couldn't send response data to NAS."); radius_pdu_destroy(pdu); radius_pdu_destroy(r); octstr_destroy(rdata); i++; debug("",0,"Mapping table contains %ld elements", dict_key_count(radius_table)); } } int main(int argc, char **argv) { int lport, pport; gwlib_init(); if (argc != 3) panic(0, "usage: test_radius_acct "); lport = atoi(argv[1]); pport = atoi(argv[2]); server(lport, pport); return 0; } gateway-1.4.5/test/blacklist.txt0000644000175000017500000000003207511025613015347 0ustar toljtolj+35897734896 +35893781250 gateway-1.4.5/test/test_octstr_format.c0000644000175000017500000000720513227613126016743 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_octstr_format.c - simple testing of octstr_format() */ #include "gwlib/gwlib.h" int main(void) { Octstr *os, *os2, *os3, *os4, *os5; unsigned long long n = 18446744073709551615ull; gwlib_init(); os = octstr_format("hi, %% %-5.*s, <%*s>, %-5d + %05d = %d, -%5.2f", 3, "world", 3, "", 1, 2, 3, 3.1415927); octstr_dump(os, 0); os2 = octstr_format("<%S>", os); octstr_dump(os2, 0); octstr_format_append(os2, "yeehaa!"); octstr_dump(os2, 0); os3 = octstr_format("NULL=%p &os=%p", (void *) NULL, (void *) &os); octstr_dump(os3, 0); os4 = octstr_format("Encode %E and limited %-10.10E", os, os); octstr_dump(os4, 0); os5 = octstr_format("Encode %%llu: %llu", n); octstr_dump(os5, 0); octstr_destroy(os); octstr_destroy(os2); octstr_destroy(os3); octstr_destroy(os4); octstr_destroy(os5); gwlib_shutdown(); return 0; } gateway-1.4.5/test/hello.wml0000644000175000017500000000034110176323212014462 0ustar toljtolj

Hello, world.

gateway-1.4.5/test/test_mime.c0000644000175000017500000002773513227613126015016 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_mime.c: A simple program for testing the mime parser * * We add carriage returs to the source, so that output of some editors are * acceptable and remove them from component files, in case someone likes to * compile them (come on, this is only a test program). * We panic on errors, so that this function can be used by a shell script * for testing purposes. * * By Aarno Syvänen for Wiral Ltd */ #include #include "gwlib/gwlib.h" #include "gw/wap_push_pap_mime.h" static void prepend_crlf(Octstr **os) { octstr_insert(*os, octstr_imm("\r\n"), 0); } static void append_crlf(Octstr *os) { octstr_append(os, octstr_imm("\r\n")); } static void add_crs(Octstr *os) { long i; Octstr *nos; if (os == NULL) return; nos = octstr_format("%c", '\r'); i = 0; while (i < octstr_len(os)) { if (octstr_get_char(os, i) == '\n') { octstr_insert(os, nos, i); ++i; } ++i; } octstr_destroy(nos); } static void remove_crs(Octstr *os) { long i; if (os == NULL) return; i = 0; while (i < octstr_len(os)) { if (octstr_get_char(os, i) == '\r') { octstr_delete(os, i, 1); --i; } ++i; } } static int skip_tail(Octstr **os, int delimiter) { long delimiter_pos; if ((delimiter_pos = octstr_search_char(*os, delimiter, 0)) == -1) return 0; octstr_delete(*os, delimiter_pos, octstr_len(*os) - delimiter_pos); return 1; } static void help(void) { info(0, "Usage: test_mime [options] source_file"); info(0, "Parse source file into component parts."); info(0, "Source file has the following format:"); info(0, " boundary=;"); info(0, " content=;"); info(0, "Content headers are added into the content_file. This file has"); info(0, "following format:"); info(0, " headers=;"); info(0, " content=;"); info(0, "And options are"); info(0, " -h"); info(0, "print this info"); info(0, " -d filename"); info(0, "store push data to file filename. Default test/data.txt"); info(0, " -c filename"); info(0, "store push control message to file filename. Default"); info(0, " test/pap.txt"); info(0, " -s"); info(0, "write push control message and push data to standard output"); info(0, "Default write it to the file."); } int main(int argc, char **argv) { Octstr *mime_content, *pap_content, *push_data, *rdf_content, *boundary, *push_content_file = NULL, *this_header, *pap_osname, *data_osname; List *content_headers, *source_parts; char *pap_content_file, *push_data_file, *rdf_content_file; int ret, std_out, opt, d_file, c_file; FILE *fp1, *fp2, *fp3; gwlib_init(); std_out = 0; d_file = 0; c_file = 0; data_osname = NULL; pap_osname = NULL; while ((opt = getopt(argc, argv, "hd:sc:")) != EOF) { switch(opt) { case 'h': help(); exit(1); break; case 'd': d_file = 1; data_osname = octstr_create(optarg); break; case 'c': c_file = 1; pap_osname = octstr_create(optarg); break; case 's': std_out = 1; break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping"); break; } } if (optind >= argc) { help(); panic(0, "missing arguments, stopping"); } if (!c_file) pap_content_file = "test/pap.txt"; else pap_content_file = octstr_get_cstr(pap_osname); if (!d_file) push_data_file = "test/data.txt"; else push_data_file = octstr_get_cstr(data_osname); rdf_content_file = "test/rdf.txt"; mime_content = octstr_read_file(argv[optind]); if (mime_content == NULL) { octstr_destroy(mime_content); error(0, "No MIME source"); panic(0, "Stopping"); } source_parts = octstr_split(mime_content, octstr_imm("content=")); if (gwlist_len(source_parts) == 1) { /* a hack to circumvent a bug */ error(0, "Badly formatted source:"); octstr_destroy(mime_content); gwlist_destroy(source_parts, octstr_destroy_item); panic(0, "Stopping"); } boundary = gwlist_extract_first(source_parts); octstr_delete(boundary, 0, octstr_len(octstr_imm("boundary="))); if (skip_tail(&boundary, ';') == 0) { error(0, "Cannot determine boundary, no delimiter; possible"); octstr_dump(boundary, 0); goto no_parse; } octstr_destroy(mime_content); mime_content = gwlist_extract_first(source_parts); if (skip_tail(&mime_content, ';') == 0){ error(0, "Cannot determine mime content, no delimiter"); octstr_dump(mime_content, 0); goto no_parse; } prepend_crlf(&mime_content); add_crs(mime_content); append_crlf(mime_content); ret = mime_parse(boundary, mime_content, &pap_content, &push_data, &content_headers, &rdf_content); if (ret == 0) { error(0, "Mime_parse returned 0, cannot continue"); goto error; } remove_crs(pap_content); if (!std_out) { fp1 = fopen(pap_content_file, "a"); if (fp1 == NULL) { error(0, "Cannot open the file for pap control message"); goto error; } octstr_print(fp1, pap_content); debug("test.mime", 0, "pap control message appended to the file"); fclose(fp1); } else { debug("test.mime", 0, "pap control message was"); octstr_dump(pap_content, 0); } remove_crs(push_data); if (!std_out) { fp2 = fopen(push_data_file, "a"); if (fp2 == NULL) { error(0, "Cannot open the push data file"); goto error; } push_content_file = octstr_create(""); octstr_append(push_content_file, octstr_imm("headers=")); while (gwlist_len(content_headers) > 0) { octstr_append(push_content_file, this_header = gwlist_extract_first(content_headers)); octstr_format_append(push_content_file, "%c", ' '); octstr_destroy(this_header); } octstr_append(push_content_file, octstr_imm(";\n")); octstr_append(push_content_file, octstr_imm("content=")); octstr_append(push_content_file, push_data); octstr_append(push_content_file, octstr_imm(";\n")); octstr_print(fp2, push_content_file); debug("test.mime", 0, "push content appended to the file"); fclose(fp2); } else { debug("test.mime", 0, "Content headers were"); http_header_dump(content_headers); debug("test.mime", 0, "And push content itself"); octstr_dump(push_data, 0); } if (rdf_content != NULL) remove_crs(rdf_content); if (!std_out && rdf_content != NULL) { fp3 = NULL; if (rdf_content != NULL) { fp3 = fopen(rdf_content_file, "a"); if (fp3 == NULL) { error(0, "Cannot open the rdf file"); goto cerror; } octstr_print(fp3, rdf_content); debug("test.mime", 0, "push caps message appended to the file"); fclose(fp3); } } else { if (rdf_content != NULL) { debug("test.mime", 0, "push caps message was"); octstr_dump(rdf_content, 0); } } octstr_destroy(boundary); octstr_destroy(mime_content); octstr_destroy(pap_content); octstr_destroy(push_data); octstr_destroy(rdf_content); octstr_destroy(pap_osname); octstr_destroy(data_osname); http_destroy_headers(content_headers); gwlist_destroy(source_parts, octstr_destroy_item); octstr_destroy(push_content_file); gwlib_shutdown(); info(0, "MIME data parsed successfully"); return 0; no_parse: octstr_destroy(mime_content); octstr_destroy(pap_osname); octstr_destroy(data_osname); gwlist_destroy(source_parts, octstr_destroy_item); octstr_destroy(boundary); gwlib_shutdown(); panic(0, "Stopping"); error: octstr_destroy(mime_content); gwlist_destroy(source_parts, octstr_destroy_item); octstr_destroy(boundary); octstr_destroy(pap_content); octstr_destroy(push_data); octstr_destroy(pap_osname); octstr_destroy(data_osname); http_destroy_headers(content_headers); octstr_destroy(rdf_content); gwlib_shutdown(); panic(0, "Stopping"); cerror: octstr_destroy(mime_content); gwlist_destroy(source_parts, octstr_destroy_item); octstr_destroy(boundary); octstr_destroy(pap_content); octstr_destroy(push_data); octstr_destroy(push_content_file); octstr_destroy(pap_osname); octstr_destroy(data_osname); http_destroy_headers(content_headers); octstr_destroy(rdf_content); gwlib_shutdown(); panic(0, "Stopping"); /* return after panic always required by gcc */ return 1; } gateway-1.4.5/test/test_msg.c0000644000175000017500000000775613227613126014656 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_msg.c - test message manipulation * * This file is a test program for the message manipulation functions in * msg.h and msg.c. * * Lars Wirzenius */ #include "gw/msg.h" #include "gwlib/gwlib.h" int main(void) { Msg *msg, *msg2; Octstr *os; gwlib_init(); info(0, "Creating msg."); msg = msg_create(heartbeat); msg->heartbeat.load = 42; msg_dump(msg, 0); info(0, "Packing msg."); os = msg_pack(msg); octstr_dump(os, 0); info(0, "Unpacking msg to msg2."); msg2 = msg_unpack(os); info(0, "msg2->heartbeat.load: %ld", (long) msg2->heartbeat.load); info(0, "Destroying msg and msg2."); msg_destroy(msg); msg_destroy(msg2); info(0, "Creating sms."); msg = msg_create(sms); msg->sms.sender = octstr_create("123"); msg->sms.receiver = octstr_create("456"); msg->sms.msgdata = octstr_create("hello, world"); info(0, "Packing sms."); os = msg_pack(msg); octstr_dump(os, 0); info(0, "Duplicating msg."); msg2 = msg_duplicate(msg); msg_dump(msg2, 0); msg_destroy(msg2); info(0, "Unpacking sms."); msg2 = msg_unpack(os); info(0, "msg2:"); info(0, " sender: %s", octstr_get_cstr(msg->sms.sender)); info(0, " receiv: %s", octstr_get_cstr(msg->sms.receiver)); info(0, " msgdata : %s", octstr_get_cstr(msg->sms.msgdata)); return 0; } gateway-1.4.5/test/test_sl.c0000644000175000017500000001210713227613126014470 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_sl.c: A simple program to test sl tokenizer * * By Aarno Syvänen for Wiral Ltd */ #include #include "gwlib/gwlib.h" #include "gw/wap_push_sl_compiler.h" Octstr *charset = NULL; Octstr *file_name = NULL; static void help (void) { info(0, "Usage test_sl [option] sl_source"); info(0, "where options are"); info(0, "-h print this text"); info(0, "-f file output binary to the file"); info(0, "-c charset charset given by http"); info(0, "-v level set log level for stderr logging"); } int main(int argc, char **argv) { int opt, file, have_charset, ret; FILE *fp; Octstr *output, *sl_doc, *sl_binary; gwlib_init(); file = 0; have_charset = 0; fp = NULL; while ((opt = getopt(argc, argv, "hf:c:v:")) != EOF) { switch (opt) { case 'h': help(); exit(1); break; case 'f': file = 1; file_name = octstr_create(optarg); fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Cannot open output file"); break; case 'c': have_charset = 1; charset = octstr_create(optarg); break; case 'v': log_set_output_level(atoi(optarg)); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping"); break; } } if (optind >= argc) { error(0, "Missing arguments"); help(); panic(0, "Stopping"); } sl_doc = octstr_read_file(argv[optind]); if (sl_doc == NULL) panic(0, "Cannot read the sl document"); if (!have_charset) charset = NULL; ret = sl_compile(sl_doc, charset, &sl_binary); output = octstr_format("%s", "sl compiler returned %d\n", ret); if (ret == 0) { if (fp == NULL) fp = stdout; octstr_append(output, octstr_imm("content being\n")); octstr_append(output, sl_binary); } if (file) octstr_pretty_print(fp, output); else { debug("test.sl", 0, "sl binary was"); octstr_dump(sl_binary, 0); } if (have_charset) octstr_destroy(charset); if (file) { fclose(fp); octstr_destroy(file_name); } octstr_destroy(sl_doc); octstr_destroy(sl_binary); octstr_destroy(output); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_mime_multipart.c0000644000175000017500000001124713227613126017106 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_mime_multipart.c - test MIME multipart convertion routines. * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" #include "gwlib/mime.h" static void help(void) { info(0, "Usage: test_mime_multipart [options] mime-encoded-file ..."); info(0, "where options are:"); info(0, "-v number"); info(0, " set log level for stderr logging"); info(0, "-n number"); info(0, " perform opertion n times"); } int main(int argc, char **argv) { Octstr *filename = NULL; unsigned long num = 1, j; int opt; Octstr *mime, *mime2; MIMEEntity *m; gwlib_init(); while ((opt = getopt(argc, argv, "hv:n:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'n': num = atoi(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (optind == argc) { help(); exit(0); } filename = octstr_create(argv[argc-1]); mime = octstr_read_file(octstr_get_cstr(filename)); for (j = 1; j <= num; j++) { info(0,"MIME Octstr from file `%s':", octstr_get_cstr(filename)); octstr_dump(mime, 0); m = mime_octstr_to_entity(mime); mime_entity_dump(m); mime2 = mime_entity_to_octstr(m); info(0, "MIME Octstr after reconstruction:"); octstr_dump(mime2, 0); if (octstr_compare(mime, mime2) != 0) { error(0, "MIME content from file `%s' and reconstruction differs!", octstr_get_cstr(filename)); } else { info(0, "MIME Octstr compare result has been successfull."); } octstr_destroy(mime2); mime_entity_destroy(m); } /* num times */ octstr_destroy(filename); gwlib_shutdown(); return 0; } gateway-1.4.5/test/smstestppg.txt0000644000175000017500000000107410360454102015612 0ustar toljtolj
gateway-1.4.5/test/dlr-receiver.py0000644000175000017500000000332710041010624015571 0ustar toljtolj# # Copyright (c) 2004 MNC S.A. # # This program is open-source and released under # the Kannel Software License, Version 1.0. Please see # LICENSE from the main Kannel distribution sources. # import sys import re from socket import * port = 6666 # you may optionally specify on commandline the port to use if len( sys.argv ) == 2: port = int( sys.argv[1] ) # create the socket which will represent the server endpoint sock = socket( AF_INET, SOCK_STREAM, 0 ) # allow socket to reuse a port address not fully closed; necessary # when relaunching the server program quickly several times; see # http://hea-www.harvard.edu/~fine/Tech/addrinuse.html sock.setsockopt( SOL_SOCKET, SO_REUSEADDR, 1 ) # assign the local address to the socket (127.0.0.1 specifies to only # accept connections from the local machine, not from the network sock.bind( ( '127.0.0.1', port ) ) # tell that we're willing to accept new connections */ sock.listen( 1 ) print 'Listening for connections on port %d...' % port while 1: # accept the incoming connection, obtaining the file-descriptor # representing the connection fd, addr = sock.accept() # read data sent by the client buf = '' while 1: data = fd.recv( 10000 ) # print received data on console while it's received sys.stdout.write( data ) buf += data match = re.search( r'\r\n\r\n', buf ) if match: break print '-=-=--' response = "HTTP/1.1 200 OK\r\n" response += "Connection: close\r\n" response += "\r\n" response += "Ok." fd.send( response ) # we're done fd.close() gateway-1.4.5/test/test_wakeup.c0000644000175000017500000000714013227613126015347 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include #include "gwlib/gwlib.h" static void thread1(void *arg) { pid_t pid; debug("test", 0, "Sleeping"); pid = getpid(); debug("test", 0, "Thread1 pid %ld", (long)pid); gwthread_sleep(600); debug("test", 0, "Woke up"); } static void thread2(void *arg) { pid_t pid; debug("test", 0, "Sleeping"); pid = getpid(); debug("test", 0, "Thread2 pid %ld", (long)pid); gwthread_sleep(600); debug("test", 0, "Woke up"); } int main(void) { pid_t pid; long t1, t2; int ret; gwlib_init(); pid = getpid(); debug("test", 0, "Parent pid %ld", (long)pid); t1 = gwthread_create(thread1, NULL); t2 = gwthread_create(thread2, NULL); sleep(1); gwthread_wakeup(t1); ret = gwthread_cancel(t2); debug("test", 0 ,"gwthread_cancel returns: %d", ret); gwthread_wakeup_all(); gwthread_join_all(); gwlib_shutdown(); return 0; } gateway-1.4.5/test/html-test-10000644000175000017500000000023607014252375014653 0ustar toljtolj This is a test. ÅÄÖåäö. ÅÄÖåäö &unknown entity A very good test, no? gateway-1.4.5/test/test_boxc.c0000644000175000017500000001167613227613126015017 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_boxc.c - test boxc connection module of bearerbox * * Stipe Tolj */ #include "gwlib/gwlib.h" #include "gw/msg.h" #include "gw/shared.h" static void help(void) { info(0, "Usage: test_boxc [options] ..."); info(0, "where options are:"); info(0, "-v number"); info(0, " set log level for stderr logging"); info(0, "-h hostname"); info(0, " hostname where bearerbox is running (default: localhost)"); info(0, "-p number"); info(0, " port for smsbox connections on bearerbox host (default: 13001)"); info(0, "-c number"); info(0, " numer of sequential connections that are made and closed (default: 1)"); } /* global variables */ static unsigned long port = 13001; static unsigned int no_conn = 1; static Octstr *host; static void run_connects(void) { unsigned int i; Msg *msg; for (i = 1; i <= no_conn; i++) { /* connect to Kannel's bearerbox */ connect_to_bearerbox(host, port, 0, NULL); /* identify ourself to bearerbox */ msg = msg_create(admin); msg->admin.command = cmd_identify; msg->admin.boxc_id = octstr_create("test-smsbox"); write_to_bearerbox(msg); /* do something, like passing MT messages */ /* close connection and shutdown */ close_connection_to_bearerbox(); } } int main(int argc, char **argv) { int opt; gwlib_init(); host = octstr_create("localhost"); while ((opt = getopt(argc, argv, "v:h:p:c:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'h': octstr_destroy(host); host = octstr_create(optarg); break; case 'p': port = atoi(optarg); break; case 'c': no_conn = atoi(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (!optind) { help(); exit(0); } run_connects(); octstr_destroy(host); gwlib_shutdown(); return 0; } gateway-1.4.5/test/si.txt0000644000175000017500000000053610206656203014023 0ustar toljtolj You have 4 new emails gateway-1.4.5/test/drive_wapbox.c0000644000175000017500000004371513227613126015515 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* drive_wapbox.c - test wapbox through its bearerbox and http interfaces * * This program starts a wapbox and pretends to be both the bearer box * and the http server, so that it can test and benchmark the wapbox in * isolation. * * Richard Braakman */ #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "gw/msg.h" /* These should really be in a header file */ enum wsp_types { Bad_PDU = -1, Connect_PDU = 0x01, ConnectReply_PDU = 0x02, Redirect_PDU = 0x03, Reply_PDU = 0x04, Disconnect_PDU = 0x05, Push_PDU = 0x06, ConfirmedPush_PDU = 0x07, Suspend_PDU = 0x08, Resume_PDU = 0x09, Get_PDU = 0x40, Options_PDU = 0x41, Head_PDU = 0x42, Delete_PDU = 0x43, Trace_PDU = 0x44, Post_PDU = 0x60, Put_PDU = 0x61 }; enum wtp_types { INVOKE = 1, RESULT = 2, ACK = 3 }; #define WSP_VERSION 0x10 #define TIMEOUT 10.0 /* seconds */ static long max_requests = 1; static long max_clients = 1; static long req_per_session = 1; static unsigned short http_port; static int wapbox_port = 30188; static Octstr *http_url = NULL; static int verbose_debug = 0; static int user_ack = 0; static long requests_complete = 0; static volatile sig_atomic_t dying = 0; enum WTP_type { TR_Invoke = 1, TR_Result = 2, TR_Ack = 3, TR_Abort = 4 }; struct client_status { /* True if we expect a WTP reply */ int wtp_invoked; /* Transaction number for WTP level */ int wtp_tid; /* current tid if wtp_invoked, else next tid to use */ /* True if we're connected at the WSP level */ /* Equal to 2 if we're trying to disconnect */ int wsp_connected; /* -1 if we're not connected */ long wsp_session_id; /* Number of successful page fetches this session */ int pages_fetched; /* Source port to use for this client; should be unique. */ unsigned short port; }; typedef struct client_status Client; static Client *clients; List *ready_clients; static unsigned long get_varint(Octstr *pdu, int pos) { int c; long result = 0; do { c = octstr_get_char(pdu, pos++); result = (result << 7) | (c & 0x7f); } while (c & 0x80); return c; } static void http_thread(void *arg) { HTTPClient *client; Octstr *ip; Octstr *url; List *headers; Octstr *body; List *cgivars; Octstr *reply_body = octstr_create( "\n" "\n" "\n" "\n" "

Hello, world.

\n" "
\n"); List *reply_headers = gwlist_create(); int port; port = *(int *) arg; gw_free(arg); gwlist_append(reply_headers, octstr_create("Content-Type: text/vnd.wap.wml")); for (;!dying;) { client = http_accept_request(port, &ip, &url, &headers, &body, &cgivars); if (client == NULL) break; http_send_reply(client, HTTP_OK, reply_headers, reply_body); http_destroy_headers(headers); octstr_destroy(ip); octstr_destroy(url); octstr_destroy(body); http_destroy_cgiargs(cgivars); } octstr_destroy(reply_body); http_destroy_headers(reply_headers); } static long http_thread_id; static int start_http_thread(void) { unsigned short port; int *port_copy; int ssl = 0; /* indicate if SSL-enabled server should be used */ for (port = 40000; port < 41000; port += 13) { if (http_open_port(port, ssl) != -1) break; } if (port == 41000) panic(0, "No ports available for http server"); port_copy = gw_malloc(sizeof(*port_copy)); *port_copy = port; http_thread_id = gwthread_create(http_thread, port_copy); if (http_thread_id == -1) panic(0, "Cannot start http thread"); return port; } static Connection *start_wapbox(void) { int wap_socket; int wapbox; wap_socket = make_server_socket(wapbox_port, NULL); if (wap_socket < 0) panic(0, "Couldn't make wapbox port\n"); wapbox = accept(wap_socket, NULL, NULL); if (wapbox < 0) panic(errno, "Wapbox could not connect\n"); close(wap_socket); return conn_wrap_fd(wapbox, 0); } static void initialize_clients(void) { long i; ready_clients = gwlist_create(); clients = gw_malloc(max_clients * sizeof(*clients)); for (i = 0; i < max_clients; i++) { clients[i].wtp_invoked = 0; clients[i].wtp_tid = 0; clients[i].wsp_connected = 0; clients[i].wsp_session_id = -1; clients[i].pages_fetched = 0; clients[i].port = i; gwlist_append(ready_clients, &clients[i]); } } static void destroy_clients(void) { gw_free(clients); gwlist_destroy(ready_clients, NULL); } static Client *find_client(unsigned short port) { /* It's easy and fast since we assign ports in linear order */ if (port >= max_clients) return NULL; return clients + port; } static void client_done(Client *client) { requests_complete++; gwlist_append(ready_clients, client); } static void increment_tid(Client *client) { if (client->wtp_tid == 0x7fff) client->wtp_tid = 0; else client->wtp_tid++; } /* Set the U/P flag on an Invoke PDU */ static void set_user_ack(Octstr *pdu) { octstr_set_bits(pdu, 3 * 8 + 3, 1, 1); } static Octstr *wtp_invoke_create(int class) { Octstr *pdu; /* data describes a TR-Invoke PDU, with GTR=1 and TTR=1 (segmentation * not supported), and Transaction class 0 (which we replace below) */ static unsigned char data[] = { 0x0e, 0x00, 0x00, 0x00 }; gw_assert(class >= 0); gw_assert(class <= 2); pdu = octstr_create_from_data(data, sizeof(data)); octstr_set_char(pdu, 3, class); if (user_ack) set_user_ack(pdu); return pdu; } static Octstr *wtp_ack_create(void) { static unsigned char data[] = { 0x18, 0x00, 0x00 }; return octstr_create_from_data(data, sizeof(data)); } static void add_wsp_connect(Octstr *pdu) { static unsigned char data[] = { Connect_PDU, WSP_VERSION, 68, 0x00, 0x03, 0x80, 0x90, 0x00, 0x03, 0x81, 0x90, 0x00, 0x02, 0x82, 0x30, 0x02, 0x83, 0x01, 0x02, 0x84, 0x01, 0x28, 0x85, 0x50, 0x58, 0x2d, 0x55, 0x50, 0x2d, 0x41, 0x47, 0x45, 0x54, 0x00, 0x51, 0x58, 0x2d, 0x55, 0x50, 0x2d, 0x47, 0x45, 0x54, 0x4e, 0x4f, 0x54, 0x49, 0x46, 0x59, 0x00, 0x70, 0x58, 0x2d, 0x55, 0x50, 0x2d, 0x41, 0x50, 0x4f, 0x53, 0x54, 0x00, 0x09, 0x86, 0x02, 0x78, 0x2d, 0x75, 0x70, 0x2d, 0x31, 0x00 }; octstr_append_data(pdu, data, sizeof(data)); } static void add_wsp_get(Octstr *pdu) { Octstr *urlbuf; octstr_append_char(pdu, Get_PDU); if (http_url) { octstr_append_uintvar(pdu, octstr_len(http_url)); octstr_append(pdu, http_url); } else { urlbuf = octstr_format("http://localhost:%ld/hello.wml", (long) http_port); octstr_append_uintvar(pdu, octstr_len(urlbuf)); octstr_append(pdu, urlbuf); octstr_destroy(urlbuf); } } static void add_wsp_disconnect(Octstr *pdu, long session_id) { octstr_append_char(pdu, Disconnect_PDU); octstr_append_uintvar(pdu, session_id); } static void set_tid(Octstr *pdu, int tid) { int c; /* Tid wraps at 15 bits. */ tid &= 0x7fff; c = octstr_get_char(pdu, 1); c = (tid >> 8) | (c & 0x80); octstr_set_char(pdu, 1, c); octstr_set_char(pdu, 2, tid & 0xff); } static int get_tid(Octstr *pdu) { return octstr_get_bits(pdu, 8, 16); } static int wtp_type(Octstr *pdu) { return octstr_get_bits(pdu, 1, 4); } static Msg *wdp_create(Octstr *data, Client *client) { Msg *msg; msg = msg_create(wdp_datagram); msg->wdp_datagram.source_address = octstr_create("127.0.0.1"); msg->wdp_datagram.source_port = client->port; msg->wdp_datagram.destination_address = octstr_create("127.0.0.1"); msg->wdp_datagram.destination_port = 9201; msg->wdp_datagram.user_data = octstr_duplicate(data); return msg; } static void send_pdu(Octstr *pdu, Connection *boxc, Client *client) { Msg *msg; Octstr *data; if (verbose_debug) { debug("test", 0, "Sending:"); octstr_dump(pdu, 0); } msg = wdp_create(pdu, client); data = msg_pack(msg); conn_write_withlen(boxc, data); octstr_destroy(data); msg_destroy(msg); } static void send_invoke_connect(Connection *boxc, Client *client) { Octstr *pdu; gw_assert(client != NULL); gw_assert(client->wtp_invoked == 0); gw_assert(client->wsp_connected == 0); pdu = wtp_invoke_create(2); set_tid(pdu, client->wtp_tid); add_wsp_connect(pdu); send_pdu(pdu, boxc, client); octstr_destroy(pdu); client->wtp_invoked = 1; } static void send_invoke_get(Connection *boxc, Client *client) { Octstr *pdu; gw_assert(client != NULL); gw_assert(client->wtp_invoked == 0); gw_assert(client->wsp_connected == 1); pdu = wtp_invoke_create(2); set_tid(pdu, client->wtp_tid); add_wsp_get(pdu); send_pdu(pdu, boxc, client); octstr_destroy(pdu); client->wtp_invoked = 1; } static void record_disconnect(Client *client) { client->wsp_connected = 0; client->wsp_session_id = -1; client->pages_fetched = 0; increment_tid(client); } static void send_invoke_disconnect(Connection *boxc, Client *client) { Octstr *pdu; gw_assert(client != NULL); gw_assert(client->wtp_invoked == 0); gw_assert(client->wsp_connected == 1); /* Kannel can't handle it as class 1 yet, so send class 0 */ pdu = wtp_invoke_create(0); set_tid(pdu, client->wtp_tid); add_wsp_disconnect(pdu, client->wsp_session_id); send_pdu(pdu, boxc, client); octstr_destroy(pdu); record_disconnect(client); client_done(client); } static void handle_connect_reply(Connection *boxc, Client *client, Octstr *pdu) { Octstr *ack; gw_assert(client); gw_assert(client->wtp_invoked); gw_assert(!client->wsp_connected); if (octstr_get_char(pdu, 3) != ConnectReply_PDU) { error(0, "Unexpected CONNECT reply"); octstr_dump(pdu, 0); return; } ack = wtp_ack_create(); set_tid(ack, client->wtp_tid); send_pdu(ack, boxc, client); octstr_destroy(ack); client->wtp_invoked = 0; increment_tid(client); client->wsp_connected = 1; client->wsp_session_id = get_varint(pdu, 4); send_invoke_get(boxc, client); } static void handle_get_reply(Connection *boxc, Client *client, Octstr *pdu) { Octstr *ack; gw_assert(client); gw_assert(client->wtp_invoked); gw_assert(client->wsp_connected); if (octstr_get_char(pdu, 3) != Reply_PDU) { error(0, "Unexpected GET reply"); octstr_dump(pdu, 0); return; } ack = wtp_ack_create(); set_tid(ack, client->wtp_tid); send_pdu(ack, boxc, client); octstr_destroy(ack); client->wtp_invoked = 0; increment_tid(client); client->pages_fetched++; if (client->pages_fetched == req_per_session) { send_invoke_disconnect(boxc, client); } else { client_done(client); } } static void handle_reply(Connection *boxc, Msg *reply) { Client *client; Octstr *wtp; int type; int dumped = 0; gw_assert(reply != NULL); gw_assert(reply->type == wdp_datagram); client = find_client(reply->wdp_datagram.destination_port); if (client == NULL) panic(0, "got packet for nonexisting client %ld", (long) reply->wdp_datagram.destination_port); wtp = reply->wdp_datagram.user_data; type = wtp_type(wtp); if (verbose_debug) { debug("test", 0, "Received:"); octstr_dump(wtp, 0); dumped = 1; } if (client->wtp_invoked == 0) { error(0, "Got packet for client that wasn't waiting"); if (!dumped) { octstr_dump(wtp, 0); dumped = 1; } return; } /* Server should invert the MSB of the tid in its replies */ if (get_tid(wtp) != (client->wtp_tid ^ 0x8000)) { error(0, "Got packet with wrong tid %d, expected %d.", get_tid(wtp), client->wtp_tid ^ 0x8000); if (!dumped) { octstr_dump(wtp, 0); dumped = 1; } return; } /* We're going to be stupid here, and assume that replies that * look vaguely like what we expect are actually what we wanted. */ if (client->wsp_connected == 0 && type == RESULT) { handle_connect_reply(boxc, client, wtp); } else if (client->wsp_connected == 1 && type == RESULT) { handle_get_reply(boxc, client, wtp); } else if (client->wsp_connected == 2 && type == ACK) { record_disconnect(client); client_done(client); } else { error(0, "Got unexpected packet"); if (!dumped) { octstr_dump(wtp, 0); dumped = 1; } } } static void start_request(Connection *boxc, Client *client) { gw_assert(client != NULL); gw_assert(client->wsp_connected != 2); gw_assert(client->wtp_invoked == 0); if (client->wsp_connected == 0) { send_invoke_connect(boxc, client); } else { send_invoke_get(boxc, client); } } static long run_requests(Connection *boxc) { int requests_sent; Octstr *data; Msg *msg; int ret; requests_sent = 0; requests_complete = 0; while (requests_complete < max_requests) { data = conn_read_withlen(boxc); if (!data) { Client *client; if (requests_sent < max_requests && (client = gwlist_extract_first(ready_clients))) { start_request(boxc, client); requests_sent++; } ret = conn_wait(boxc, TIMEOUT); if (ret < 0 || conn_eof(boxc)) panic(0, "Wapbox dead."); if (ret == 1) break; /* Timed out. */ } else { msg = msg_unpack(data); if (!msg) { octstr_dump(data, 0); panic(0, "Received bad data from wapbox."); } if (msg->type == wdp_datagram) handle_reply(boxc, msg); msg_destroy(msg); } octstr_destroy(data); } if (requests_complete < max_requests) info(0, "Timeout. %ld requests unsatisfied.", max_requests - requests_complete); return requests_complete; } static void help(void) { info(0, "Usage: drive_wapbox [options...]\n"); info(0, " -r requests Stop after this many; default 1."); info(0, " -c clients # of concurrent clients; default 1."); info(0, " -w wapport Port wapbox should connect to; default 30188"); info(0, " -u url Use this url instead of internal http server"); info(0, " -g requests Number of requests per WSP session; default 1"); info(0, " -U Set the User ack flag on all WTP transactions"); } int main(int argc, char **argv) { int opt; struct timeval start, end; Connection *boxc; long completed; double run_time; gwlib_init(); while ((opt = getopt(argc, argv, "hv:r:c:w:du:Ug:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'r': max_requests = atol(optarg); break; case 'c': max_clients = atol(optarg); break; case 'w': wapbox_port = atoi(optarg); break; case 'u': http_url = octstr_create(optarg); break; case 'U': user_ack = 1; break; case 'h': help(); exit(0); case 'd': verbose_debug = 1; break; case 'g': req_per_session = atoi(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (!http_url) http_port = start_http_thread(); boxc = start_wapbox(); initialize_clients(); if (gettimeofday(&start, NULL) < 0) panic(errno, "gettimeofday failed"); completed = run_requests(boxc); if (gettimeofday(&end, NULL) < 0) panic(errno, "gettimeofday failed"); conn_destroy(boxc); run_time = end.tv_sec - start.tv_sec; run_time += (double) (end.tv_usec - start.tv_usec) / 1000000.0; /* We must have timed out. Don't count the waiting time. */ if (completed < max_requests) run_time -= TIMEOUT; info(0, "%ld request%s in %0.1f seconds, %0.1f requests/s.", completed, completed != 1 ? "s" : "", run_time, max_requests / run_time); dying = 1; http_close_all_ports(); if (!http_url) gwthread_join(http_thread_id); destroy_clients(); octstr_destroy(http_url); gwlib_shutdown(); return 0; } gateway-1.4.5/test/drive_smpp.c0000644000175000017500000003731013227613126015166 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * drive_smpp.c - SMPP server for testing purposes * * Lars Wirzenius */ #include #include #include #include #include "gwlib/gwlib.h" #include "gw/smsc/smpp_pdu.h" #include "gw/msg.h" static int quitting = 0; static Octstr *smsc_system_id; static Octstr *smsc_source_addr; static Counter *message_id_counter; static Octstr *bearerbox_host; static int port_for_smsbox; static Counter *num_to_esme; static long max_to_esme; static Counter *num_from_bearerbox; static Counter *num_to_bearerbox; static Counter *num_from_esme; static time_t start_time = (time_t) -1; static time_t first_to_esme = (time_t) -1; static time_t last_to_esme = (time_t) -1; static time_t last_from_esme = (time_t) -1; static time_t first_from_bb = (time_t) -1; static time_t last_to_bb = (time_t) -1; static long enquire_interval = 1; /* Measured in messages, not time. */ static void quit(void) { quitting = 1; gwthread_wakeup_all(); } typedef struct { Connection *conn; int transmitter; int receiver; long version; } ESME; static ESME *esme_create(Connection *conn) { ESME *esme; esme = gw_malloc(sizeof(*esme)); esme->conn = conn; esme->transmitter = 0; esme->receiver = 0; esme->version = 0; return esme; } static void esme_destroy(ESME *esme) { if (esme != NULL) { conn_destroy(esme->conn); gw_free(esme); } } static SMPP_PDU *handle_bind_transmitter(ESME *esme, SMPP_PDU *pdu) { SMPP_PDU *resp; esme->transmitter = 1; esme->version = pdu->u.bind_transmitter.interface_version; resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter.sequence_number); #if 0 /* XXX system_id is not implemented in the PDU at the moment */ resp->u.bind_transmitter_resp.system_id = octstr_duplicate(smsc_system_id); #endif return resp; } static SMPP_PDU *handle_bind_receiver(ESME *esme, SMPP_PDU *pdu) { SMPP_PDU *resp; esme->receiver = 1; esme->version = pdu->u.bind_receiver.interface_version; resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number); #if 0 /* XXX system_id is not implemented in the PDU at the moment */ resp->u.bind_receiver_resp.system_id = octstr_duplicate(smsc_system_id); #endif return resp; } static SMPP_PDU *handle_submit_sm(ESME *esme, SMPP_PDU *pdu) { SMPP_PDU *resp; unsigned long id; debug("test.smpp", 0, "submit_sm: short_message = <%s>", octstr_get_cstr(pdu->u.submit_sm.short_message)); id = counter_increase(num_from_esme) + 1; if (id == max_to_esme) info(0, "ESME has submitted all messages to SMSC."); time(&last_from_esme); resp = smpp_pdu_create(submit_sm_resp, pdu->u.submit_sm.sequence_number); #if 0 /* XXX message_id is not implemented in the PDU at the moment */ resp->u.submit_sm_resp.message_id = octstr_format("%ld", counter_increase(message_id_counter)); #endif return resp; } static SMPP_PDU *handle_deliver_sm_resp(ESME *esme, SMPP_PDU *pdu) { return NULL; } static SMPP_PDU *handle_unbind(ESME *esme, SMPP_PDU *pdu) { SMPP_PDU *resp; resp = smpp_pdu_create(unbind_resp, pdu->u.unbind.sequence_number); return resp; } static SMPP_PDU *handle_enquire_link(ESME *esme, SMPP_PDU *pdu) { return smpp_pdu_create(enquire_link_resp, pdu->u.enquire_link.sequence_number); } static SMPP_PDU *handle_enquire_link_resp(ESME *esme, SMPP_PDU *pdu) { return NULL; } static struct { unsigned long type; SMPP_PDU *(*handler)(ESME *, SMPP_PDU *); } handlers[] = { #define HANDLER(name) { name, handle_ ## name }, HANDLER(bind_transmitter) HANDLER(bind_receiver) HANDLER(submit_sm) HANDLER(deliver_sm_resp) HANDLER(unbind) HANDLER(enquire_link) HANDLER(enquire_link_resp) #undef HANDLER }; static int num_handlers = sizeof(handlers) / sizeof(handlers[0]); static void handle_pdu(ESME *esme, SMPP_PDU *pdu) { SMPP_PDU *resp; Octstr *os; int i; debug("test.smpp", 0, "Handling SMPP PDU of type %s", pdu->type_name); for (i = 0; i < num_handlers; ++i) { if (handlers[i].type == pdu->type) { resp = handlers[i].handler(esme, pdu); if (resp != NULL) { os = smpp_pdu_pack(NULL, resp); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(resp); } return; } } error(0, "Unhandled SMPP PDU."); smpp_pdu_dump(octstr_imm(""), pdu); } static void send_smpp_thread(void *arg) { ESME *esme; Octstr *os; SMPP_PDU *pdu; unsigned long id; esme = arg; id = 0; while (!quitting && counter_value(num_to_esme) < max_to_esme) { id = counter_increase(num_to_esme) + 1; while (!quitting && counter_value(num_from_esme) + 500 < id) gwthread_sleep(1.0); if (quitting) break; pdu = smpp_pdu_create(deliver_sm, counter_increase(message_id_counter)); pdu->u.deliver_sm.source_addr = octstr_create("456"); pdu->u.deliver_sm.destination_addr = octstr_create("123"); pdu->u.deliver_sm.short_message = octstr_format("%ld", id); if (esme->version > 0x33) pdu->u.deliver_sm.receipted_message_id = octstr_create("receipted_message_id\0"); os = smpp_pdu_pack(NULL, pdu); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(pdu); if (first_to_esme == (time_t) -1) time(&first_to_esme); debug("test.smpp", 0, "Delivered SMS %ld of %ld to bearerbox via SMPP.", id, max_to_esme); if ((id % enquire_interval) == 0) { pdu = smpp_pdu_create(enquire_link, counter_increase(message_id_counter)); os = smpp_pdu_pack(NULL, pdu); conn_write(esme->conn, os); octstr_destroy(os); smpp_pdu_destroy(pdu); debug("test.smpp", 0, "Sent enquire_link to bearerbox."); } } time(&last_to_esme); if (id == max_to_esme) info(0, "All messages sent to ESME."); debug("test.smpp", 0, "%s terminates.", __func__); } static void receive_smpp_thread(void *arg) { ESME *esme; Octstr *os; long len; long sender_id; SMPP_PDU *pdu; esme = arg; sender_id = -1; len = 0; while (!quitting && conn_wait(esme->conn, -1.0) != -1) { for (;;) { if (len == 0) { len = smpp_pdu_read_len(esme->conn); if (len == -1) { error(0, "Client sent garbage, closing connection."); goto error; } else if (len == 0) { if (conn_eof(esme->conn) || conn_error(esme->conn)) goto error; break; } } gw_assert(len > 0); os = smpp_pdu_read_data(esme->conn, len); if (os != NULL) { len = 0; pdu = smpp_pdu_unpack(NULL, os); if (pdu == NULL) { error(0, "PDU unpacking failed!"); octstr_dump(os, 0); } else { handle_pdu(esme, pdu); smpp_pdu_destroy(pdu); } octstr_destroy(os); } else if (conn_eof(esme->conn) || conn_error(esme->conn)) goto error; else break; } if (!quitting && esme->receiver && sender_id == -1) sender_id = gwthread_create(send_smpp_thread, esme); } error: if (sender_id != -1) { quit(); gwthread_join(sender_id); } esme_destroy(esme); quit(); debug("test.smpp", 0, "%s terminates.", __func__); } static void smsbox_thread(void *arg) { Connection *conn; Msg *msg; Octstr *os; Octstr *reply_msg; unsigned long count; msg = msg_create(sms); msg->sms.sender = octstr_create("123"); msg->sms.receiver = octstr_create("456"); msg->sms.msgdata = octstr_create("hello world"); reply_msg = msg_pack(msg); msg_destroy(msg); gwthread_sleep(1.0); conn = conn_open_tcp(bearerbox_host, port_for_smsbox, NULL); if (conn == NULL) { gwthread_sleep(2.0); conn = conn_open_tcp(bearerbox_host, port_for_smsbox, NULL); if (conn == NULL) panic(0, "Couldn't connect to bearerbox as smsbox"); } while (!quitting && conn_wait(conn, -1.0) != -1) { for (;;) { os = conn_read_withlen(conn); if (os == NULL) { if (conn_eof(conn) || conn_error(conn)) goto error; break; } msg = msg_unpack(os); if (msg == NULL || msg->type == wdp_datagram) error(0, "Bearerbox sent garbage to smsbox"); if (msg->type == sms) { if (first_from_bb == (time_t) -1) time(&first_from_bb); count = counter_increase(num_from_bearerbox) + 1; debug("test.smpp", 0, "Bearerbox sent sms #%ld <%s> to smsbox, sending reply.", count, octstr_get_cstr(msg->sms.msgdata)); if (count == max_to_esme) info(0, "Bearerbox has sent all messages to smsbox."); conn_write_withlen(conn, reply_msg); counter_increase(num_to_bearerbox); } msg_destroy(msg); octstr_destroy(os); time(&last_to_bb); } } error: conn_destroy(conn); octstr_destroy(reply_msg); debug("test.smpp", 0, "%s terminates.", __func__); } static void accept_thread(void *arg) { int fd; int new_fd; int port; socklen_t addrlen; struct sockaddr addr; long smsbox_thread_id; port = *(int *) arg; fd = make_server_socket(port, NULL); if (fd == -1) panic(0, "Couldn't create SMPP listen port."); smsbox_thread_id = -1; for (;;) { if (gwthread_pollfd(fd, POLLIN, -1.0) != POLLIN) break; addrlen = sizeof(addr); new_fd = accept(fd, &addr, &addrlen); if (start_time == (time_t) -1) time(&start_time); gwthread_create(receive_smpp_thread, esme_create(conn_wrap_fd(new_fd, 0))); if (smsbox_thread_id == -1) smsbox_thread_id = gwthread_create(smsbox_thread, NULL); } debug("test.smpp", 0, "%s terminates.", __func__); } static void handler(int signal) { panic(0, "Caught signal %d.", signal); } static void help(void) { info(0, "drive_smpp [-h] [-v level][-l logfile][-p port][-m msgs][-c config]"); } int main(int argc, char **argv) { struct sigaction act; int port; int opt; double run_time; char *log_file; char *config_file; gwlib_init(); act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); port = 2345; smsc_system_id = octstr_create("kannel_smpp"); smsc_source_addr = octstr_create("123456"); message_id_counter = counter_create(); bearerbox_host = octstr_create("127.0.0.1"); port_for_smsbox = 13001; max_to_esme = 1; num_to_esme = counter_create(); num_from_esme = counter_create(); num_to_bearerbox = counter_create(); num_from_bearerbox = counter_create(); log_file = config_file = NULL; while ((opt = getopt(argc, argv, "hv:p:m:l:c:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'h': help(); exit(0); case 'm': max_to_esme = atoi(optarg); break; case 'p': port = atoi(optarg); break; case 'l': log_file = optarg; break; case 'c': config_file = optarg; break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (log_file != NULL) log_open(log_file, GW_DEBUG, GW_NON_EXCL); if (config_file != NULL) { Cfg *cfg; Octstr *tmp = octstr_create(config_file); cfg = cfg_create(tmp); octstr_destroy(tmp); if (cfg_read(cfg) == -1) panic(0, "Errors in config file."); smpp_pdu_init(cfg); cfg_destroy(cfg); } info(0, "Starting drive_smpp test."); gwthread_create(accept_thread, &port); gwthread_join_all(); debug("test.smpp", 0, "Program exiting normally."); run_time = difftime(last_from_esme, first_to_esme); info(0, "Number of messages sent to ESME: %ld", counter_value(num_to_esme)); info(0, "Number of messages sent to smsbox: %ld", counter_value(num_from_bearerbox)); info(0, "Number of messages sent to bearerbox: %ld", counter_value(num_to_bearerbox)); info(0, "Number of messages sent to SMSC: %ld", counter_value(num_from_esme)); info(0, "Time: %.0f secs", run_time); info(0, "Time until all sent to ESME: %.0f secs", difftime(last_to_esme, start_time)); info(0, "Time from first from bb to last to bb: %.0f secs", difftime(last_to_bb, first_from_bb)); info(0, "Time until all sent to SMSC: %.0f secs", difftime(last_from_esme, start_time)); info(0, "SMPP messages SMSC to ESME: %.1f msgs/sec", counter_value(num_to_esme) / run_time); info(0, "SMPP messages ESME to SMSC: %.1f msgs/sec", counter_value(num_from_esme) / run_time); octstr_destroy(smsc_system_id); octstr_destroy(smsc_source_addr); octstr_destroy(bearerbox_host); counter_destroy(num_to_esme); counter_destroy(num_from_esme); counter_destroy(num_to_bearerbox); counter_destroy(num_from_bearerbox); counter_destroy(message_id_counter); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_charset.c0000644000175000017500000000716113227613126015507 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_charset.c - charset mapping tests * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" int main(int argc, char **argv) { Octstr *os1, *os2; gwlib_init(); os1 = octstr_create(""); octstr_append_from_hex(os1, "411810124550421715161a"); os2 = octstr_duplicate(os1); debug("", 0, "Orginal GSM charset data:"); octstr_dump(os1, 0); charset_gsm_to_utf8(os1); debug("", 0, "Same data mapped to URT-8 charset:"); octstr_dump(os1, 0); charset_utf8_to_gsm(os1); debug("", 0, "Same data mapped back again to GSM charset:"); octstr_dump(os1, 0); if (octstr_compare(os1, os2) != 0) panic(0, "Data is not the same after re-mapping!"); else debug("",0,"Data is same, ok."); octstr_destroy(os1); octstr_destroy(os2); gwlib_shutdown(); return 0; } gateway-1.4.5/test/fakewap.c0000644000175000017500000013420013227613126014430 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * fakewap.c - simulate wap clients talking directly to wap gw. * * This module can be built also in Windows where you should * add unzipped ".\wininc" to your include directories. * * The protocol: * * * A) Fakewap -> Gateway * * WTP: Invoke PDU * WSP: Connect PDU * * B) Gateway -> Fakewap * * WTP: Result PDU * WSP: ConnectReply PDU * * C) Fakewap -> Gateway * * WTP: Ack PDU * * D) Fakewap -> Gateway * * WTP: Invoke PDU * WSP: Get/Post PDU (data: URL) * * E) Gateway -> Fakewap * * WTP: Result PDU (data: WML page) * WSP: Reply PDU * * F) Fakewap -> Gateway * * WTP: Ack PDU * * G) Fakewap -> Gateway * * WTP: Invoke PDU * WSP: Disconnect PDU * * * Packets A-C open a WAP session. Packets D-F fetch a WML page. * Packet G closes the session. * * The test terminates when all packets have been sent. * * Tid verification uses following protocol (at WTP level only): * * A) Fakewap -> Gateway * * Either WSP Connect PDU with tid_new flag set on or same PDU with a * *seriously* wrapped up tid (only WTP header affected). Seriously * means tid being out of the window: * * |----------------------------| * tid space * * |-------------| * wrapping up * tid window * * B) Gateway -> Fakewap * * Ack PDU, tid verification flag set on. * * C) Fakewap -> Gateway * * Ack PDU, tid verification flag set on (this means a positive * answer). * * Antti Saarenheimo for WapIT Ltd. */ #define MAX_SEND (0) /* Versions: * v1.0 - added WSP GET result reassembly * v1.1 - added WSP POST - options -P, -C, -w * v1.2 - added source address (-I) option * v1.3 - send Nack for lost segments, reassembly fixes * v1.4 - parse WSP message and save only the received payload to the output file * v1.5 - support for connectionless get/post * v1.6 - robustness fixes for Post (resend group segments if no ack), packet loss simulation */ static char usage[] = "\ fakewap version 1.6\n\ Usage: fakewap [options] url ...\n\ \n\ where options are:\n\ \n\ -h help\n\ -g hostname hostname or IP number of gateway (default: localhost)\n\ -p port port number of gateway (default: 9201)\n\ -m max maximum number of requests fakewap will make (default: 1)\n\ -i interval interval between requests (default: 1.0 seconds)\n\ -c threads number of concurrent clients simulated (default: 1)\n\ -V protoversion protocol version field, as an integer (default: 0)\n\ -T pdu-type PDU type, as an integer (default: 1)\n\ -t tcl transaction class, as an integer (default: 2)\n\ -n set tid_new flag in packets, forces gateway to flush cache\n\ (default: off)\n\ -s test separation, by concatenating ack and disconnect pdus\n\ (default: off)\n\ -d difference difference between successive tid numbers (default: 1)\n\ -F Accept failure and continue rather than exiting\n\ -A agent user agent\n\ -C content-type Specify content type: text, mms\n\ -D level debug level (0=none(default), 1=brief, 2=verbose\n\ -I addr[:port] Specify source address\n\ -M mode Transaction mode: 0=connectionless, 1=connection-oriented\n\ -P in-file Post data from file\n\ -w out-file Write received data to file\n\ -l loss-precent Simulate packet loss\n\ \n\ The urls are fetched in random order.\n\ "; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "wap/wsp_pdu.h" #define GET_WTP_PDU_TYPE(hdr) ((hdr[0] >> 3) & 0x0f) static int get_wtp_pdu_type(Octstr *hdr) { return (octstr_get_char(hdr, 0) >> 3) & 0x0f; } #define WTP_PDU_INVOKE 1 #define WTP_PDU_RESULT 2 #define WTP_PDU_ACK 3 #define WTP_PDU_ABORT 4 #define WTP_PDU_SEGM_INVOKE 5 #define WTP_PDU_SEGM_RESULT 6 #define WTP_PDU_NACK 7 #define WSP_PDU_CONNECT 1 #define WSP_PDU_REPLY 4 #define WSP_PDU_DISCONNECT 5 #define WSP_PDU_GET 0x40 #define WSP_PDU_POST 0x60 #define TXN_MODE_CONNECTION_LESS 0 #define TXN_MODE_CONNECTION_ORIENTED 1 #define SAR_SEGM_SIZE 1200 #define SAR_GROUP_LEN 4 #define SAR_MAX_RETRIES 3 #define WAP_MSG_RECEIVE_TIMEOUT 10 /* ** Common parameters */ char **urls; int num_urls; Octstr *hostname = NULL; Octstr *gateway_addr = NULL; double interval = 1.0; unsigned short port = 0; int max_send = 1; unsigned short tid_addition = 1; Mutex *mutex; int threads = 1; int num_sent = 0; time_t start_time, end_time; double totaltime = 0, besttime = 1000000L, worsttime = 0; int brief; /* enable brief debug */ int verbose = 0; int nofailexit = 0; int test_separation = 0; char* infile; char* outfile; const char* content_type; struct sockaddr_in src_addr; int transaction_mode; int packet_loss; /* packet loss rate 0-99 */ Octstr *useragent; /* * PDU type, version number and transaction class are supplied by a * command line argument. WSP_Concat is a concatenation of WTP_Ack and * WSP_Disconnect PDUs. */ unsigned char WSP_Connect[] = { /* WSP part */ 0x01, /* PDU type */ 0x10, /* Version 1.0 */ 0x0a, /* Capability length */ 0x0d, /* Headers length = 13 */ /* Capabilities */ 0x04, 0x80, 0xc0, 0x80, 0x00, /* Client SDU */ 0x04, 0x81, 0xc0, 0x80, 0x00, /* Server SDU */ /* Headers */ 0x80, 0x80, /* Accept: *\* */ }; unsigned char WSP_ConnectReply[] = {0x16, 0x80, 0x00, 0x02 }; unsigned char WSP_Get[] = {0x40}; /* This used to also expect a content-type of 0x94, but that's too difficult * to check now that Kannel does full header encoding. */ unsigned char WSP_Reply[] = {0x16, 0x80, 0x00, 0x04, 0x20 }; unsigned char WSP_Disconnect[] = {0x05}; unsigned char WSP_Post[] = { /* wsp post */ 0x60 }; unsigned char WSP_Concat[] = {0x00, 0x03, 0x18, 0x00, 0x00, 0x05, 0x0E, 0x00, 0x00, 0x00, 0x05 }; unsigned char WTP_Ack[] = {0x18, 0x00, 0x00 }; unsigned char WTP_TidVe[] = {0x1C, 0x00, 0x00 }; unsigned char WTP_Abort[] = {0x20, 0x00, 0x00, 0x00 }; unsigned char WTP_Invoke_Cl0[] = { /*wtp invoke,ttr*/ 0x0a, /*tid*/ 0x00, 0x00, /*ack+class0*/ 0x10 }; unsigned char WTP_Invoke_Cl2[] = { /*wtp invoke,ttr*/ 0x0a, /*tid*/ 0x00, 0x00, /*ack+class2*/ 0x12 }; unsigned char WTP_Invoke_Cl2MaxGrp[] = { /*wtp invoke*/ 0x0E, /*tid*/ 0x00, 0x00, /*ack/class2:*/ 0x12, /*tti max-group: 4200*/ 0x13, 0x04, 0x10, 0x68 }; unsigned char WTP_Result[] = {0x10, 0x80, 0x00 }; unsigned char WTP_Segm_Result[] = {0x30, 0x80, 0x00 }; unsigned char WTP_Segm_Ack[] = {0x98, 0x00, 0x00, 0x19, 0x00 }; unsigned char WTP_Nack[] = { /* wtp nack */ 0x38, /* tid */ 0x00, 0x00, /*num missing*/ 0x00 }; unsigned char WTP_Segm_Invoke[] = { /* wtp segm invoke*/ 0x28, /* tid */ 0x00, 0x00, /* psn */ 0x00 }; /* ** In this case it does not matter what is the byte order */ #define SET_GTR( hdr ) hdr[0] |= 0x04 #define SET_TID( hdr, tid) \ hdr[1] |= (0x7f & ((tid) >> 8)); \ hdr[2] = (char)(tid) #define GET_TID( hdr ) (((hdr[1] & 0x7f) << 8) + hdr[2]) #define CONSTRUCT_EXPECTED_REPLY_HDR( dest, template, tid ) \ if (sizeof(dest) < sizeof(template)) panic(0,"fakewap: buffer overflow.");\ memcpy( dest, template, sizeof(template));\ SET_TID( dest, tid ) static void set_tid(Octstr *hdr, int tid) { int c; c = octstr_get_char(hdr, 1); c |= 0x7f & (tid >> 8); octstr_set_char(hdr, 1, c); octstr_set_char(hdr, 2, (unsigned char) tid); } /* Use this only on Invoke packets, the others have no tid_new field */ static void set_tid_new(Octstr *hdr) { int c; c = octstr_get_char(hdr, 3); c |= 0x40; octstr_set_char(hdr, 3, c); } #ifndef min #define min(a,b) (a < b ? a : b) #endif /* ** if -v option has been defined, function prints the trace message and ** the first bytes in the message header */ static void print_msg( const char * trace, unsigned char * msg, int msg_len ) { int i; if (verbose) { mutex_lock( mutex ); printf( "%s (len %d): ", trace, msg_len ); for (i = 0; i < msg_len && i < 16; i++) printf( "%02X ", msg[i] ); printf( "\n"); mutex_unlock( mutex ); } } /* ** function prints the trace message and the first bytes in the message header */ static void print_data( const char * trace, unsigned char * msg, int msg_len ) { int i; if (verbose) { mutex_lock( mutex ); printf( "%s (len %d): ", trace, msg_len ); for (i = 0; i < msg_len && i < msg_len; i++) printf( "%c", isprint(msg[i]) ? msg[i] : '_'); printf( "\n"); mutex_unlock( mutex ); } } /* Choose a random message from a table of messages. */ static char *choose_message(char **urls, int num_urls) { /* the following doesn't give an even distribution, but who cares */ return urls[gw_rand() % num_urls]; } /* returns next tid, given current tid. Every thread has its own * port, so has its own tid space. */ static unsigned short next_tid(unsigned short old_tid) { return (old_tid + tid_addition) % (1 << 15); } /* ** Function stores WAP/WSP variable length integer to buffer and returns ** actual len */ static int StoreVarInt( unsigned char *buf, unsigned long varInt ) { int i, len = 1, non_zero_bits = 7; /* ** Skip all zero high bits */ while ((varInt >> non_zero_bits) != 0) { non_zero_bits += 7; len++; } /* ** Read the higest bits first. */ for (i = 0; i < len; i++) { buf[i] = ((unsigned char)(varInt >> (non_zero_bits-7)) & 0x7f) | 0x80; non_zero_bits -= 7; } buf[len-1] &= 0x7f; return len; } /* ** Function length of WAP/WSP variable length integer in the buffer */ static int ReadVarIntLen( const unsigned char *buf ) { int len = 1; while (buf[len-1] & 0x80) len++; return len; } /* ** Retrieve value of WAP/WSP variable length integer in the buffer */ static int ReadVarIntVal( const unsigned char *buf ) { int len = 1; int value = buf[0] & 0x7F; while (buf[len-1] & 0x80) { len++; value <<= 7; value |= buf[len-1] & 0x7F; } return value; } /* ** Function sends message to WAP GW */ static int wap_msg_send( int fd, unsigned char* wtp_hdr, int wtp_hdr_len, unsigned short tid, int tid_new, unsigned char* wsp_hdr, int wsp_hdr_len, unsigned char* data, int data_len ) { int ret; Octstr *datagram; datagram = octstr_create(""); if (wtp_hdr != NULL) { octstr_append_data(datagram, (char*)wtp_hdr, wtp_hdr_len); set_tid(datagram, tid); if (get_wtp_pdu_type(datagram) == WTP_PDU_INVOKE) { /* request ack every time */ int c; c = octstr_get_char(datagram, 3); octstr_set_char(datagram, 3, c | 0x10); if (tid_new) set_tid_new(datagram); } } if (wsp_hdr != NULL) octstr_append_data(datagram, (char*)wsp_hdr, wsp_hdr_len); if (data != NULL) octstr_append_data(datagram, (char*)data, data_len); #if 0 debug("fakewap", 0, "Sending WDP datagram:"); octstr_dump(datagram, 0); #endif ret = udp_sendto(fd, datagram, gateway_addr); if (ret == -1) { error(0, "fakewap: Sending to socket failed"); return -1; } if (brief) { if (wsp_hdr!=NULL) { int wsp_pdu; if (transaction_mode==TXN_MODE_CONNECTION_ORIENTED) wsp_pdu = wsp_hdr[0]; else wsp_pdu = wsp_hdr[1]; switch (wsp_pdu) { case WSP_PDU_CONNECT: debug("fakewap", 0, "Sent WSP_CONNECT packet"); break; case WSP_PDU_DISCONNECT: debug("fakewap", 0, "Sent WSP_DISCONNECT packet"); break; case WSP_PDU_GET: debug("fakewap", 0, "Sent WSP_GET packet"); break; case WSP_PDU_POST: debug("fakewap", 0, "Sent WSP_POST packet"); break; default: debug("fakewap", 0, "Sent WSP ??? packet"); break; } } else { switch (get_wtp_pdu_type(datagram)) { case WTP_PDU_INVOKE: debug("fakewap", 0, "Sent WTP_INVOKE packet"); break; case WTP_PDU_ACK: debug("fakewap", 0, "Sent WTP_ACK packet"); break; case WTP_PDU_ABORT: debug("fakewap", 0, "Sent WTP_ABORT packet"); break; case WTP_PDU_SEGM_INVOKE: debug("fakewap", 0, "Sent WTP_SEGM_INVOKE packet"); break; case WTP_PDU_NACK: debug("fakewap", 0, "Sent WTP_NACK packet"); break; default: debug("fakewap", 0, "Sent ??? packet"); break; } } } if (verbose) { octstr_dump(datagram, 0); } octstr_destroy(datagram); return ret; } /* ** Function receives a wap wtl/wsp message. If the headers has been ** given, it must match with the received message. ** Return value: ** > 0 => length of received data ** == 0 => got acknowlengement or abort but not the expected data ** < 0 => error, */ static int wap_msg_recv( int fd, const unsigned char* hdr, int hdr_len, unsigned short tid, unsigned char * data, int data_len, int timeout, int udp_flags ) { int ret; unsigned char msg[1024*64]; int msg_len = 0; int fResponderIsDead = 1; /* assume this by default */ Octstr *datagram, *dummy; /* ** Loop until we get the expected response or do timeout */ for (;;) { time_t calltime; time(&calltime); if (timeout != 0) { ret = read_available(fd, timeout * 1000 * 1000); if (ret <= 0) { info(0, "fakewap: Timeout while receiving from socket.\n"); if(nofailexit){ continue; }else{ return fResponderIsDead ? -1 : 0; } /* continue if we got ack? */ } } ret = udp_recvfrom_flags(fd, &datagram, &dummy, udp_flags); /* drop packet if packet loss simulation is enabled */ if ((packet_loss > 0) && !(udp_flags&MSG_PEEK) && ((gw_rand() % 100) < packet_loss)) { time_t currtime; time(&currtime); octstr_destroy(datagram); octstr_destroy(dummy); timeout -= (int)(currtime - calltime); debug("fakewap", 0, "Dropped packet, new timeout %d", timeout); continue; } if (ret == 0) { octstr_get_many_chars((char*)msg, datagram, 0, octstr_len(datagram)); msg_len = octstr_len(datagram); } octstr_destroy(datagram); octstr_destroy(dummy); if (ret == -1) { error(0, "fakewap: recv() from socket failed"); return -1; } if (hdr != NULL) { /* ** Ignore extra header bits, WAP GWs return different values */ if ((msg_len >= hdr_len) && (GET_WTP_PDU_TYPE(msg) == GET_WTP_PDU_TYPE(hdr)) && (hdr_len <= 3 || !memcmp( msg+3, hdr+3, hdr_len-3 ))) { break; } /* ** Handle TID test, the answer is: Yes, we have an outstanding ** transaction with this tid. We must turn on TID_OK-flag, too. ** We have a separate tid verification PDU. */ else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_ACK && GET_TID(msg) == tid) { print_msg( "Received tid verification", msg, msg_len ); wap_msg_send( fd, WTP_TidVe, sizeof(WTP_TidVe), tid, 0, NULL, 0, NULL, 0 ); } else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_ABORT) { print_msg( "Received WTP Abort", msg, msg_len ); } else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_RESULT) { break; } else if (GET_WTP_PDU_TYPE(msg) == WTP_PDU_SEGM_RESULT) { break; } else { print_msg( "Received unexpected message", msg, msg_len ); } fResponderIsDead = 0; } else { hdr_len = 0; break; } } print_msg( "Received packet", msg, msg_len ); print_data( "Received data", msg, msg_len ); if (data != NULL && msg_len > hdr_len) { data_len = min( data_len, msg_len ); memcpy( data, msg, data_len); } else data_len = 0; return data_len; } static int get_next_transaction(void) { int i_this; mutex_lock( mutex ); i_this = num_sent + 1; if (max_send == MAX_SEND || num_sent < max_send) num_sent++; mutex_unlock( mutex ); return i_this; } int send_post(int fd, unsigned short tid, int tid_new, char* url) { unsigned char wtphdr[32]; unsigned char msgbuf[32*1024]; unsigned char contentlen_buf[8]; unsigned char reply_hdr[32]; long timeout = WAP_MSG_RECEIVE_TIMEOUT; /* wap gw is broken if no input */ /* open post input file */ int infd = open(infile, O_RDONLY); if (infd < 0) panic(0, "fakewap: failed to open input file %s, errno %d", infile, errno); /* get size of input file */ struct stat fstats; int ret = fstat(infd, &fstats); if (ret) panic(0, "fakewap: failed to get file stats, errno %d", errno); if (fstats.st_size == 0) panic(0, "fakewap: input file is empty"); if (((transaction_mode==TXN_MODE_CONNECTION_LESS) && (fstats.st_size > (int)sizeof(msgbuf))) || ((transaction_mode==TXN_MODE_CONNECTION_ORIENTED) && (fstats.st_size > 256*SAR_SEGM_SIZE))) { panic(0, "fakewap: input file size (%ld) is too large", fstats.st_size); } int nsegs = (fstats.st_size-1) / SAR_SEGM_SIZE; int tpi, gtr, ttr; int psn = 0; /* build WTP header */ tpi = 1; ttr = (nsegs==0) ? 1 : 0; gtr = (ttr) ? 0 : 1; memcpy(wtphdr, WTP_Invoke_Cl2MaxGrp, sizeof(WTP_Invoke_Cl2MaxGrp)); wtphdr[0] = (tpi << 7) | (WTP_PDU_INVOKE << 3) | (gtr << 2) | (ttr << 1); /* build WSP POST message */ Octstr *postmsg; postmsg = octstr_create(""); if (transaction_mode==TXN_MODE_CONNECTION_LESS) { msgbuf[0] = tid; octstr_append_data(postmsg, (char*)msgbuf, 1); } memcpy(msgbuf, WSP_Post, sizeof(WSP_Post)); octstr_append_data(postmsg, (char*)msgbuf, sizeof(WSP_Post)); /* add uri, content type, user agent, content length, accept */ int url_len = strlen(url); int off = StoreVarInt( msgbuf, url_len ); int content_type_len = strlen(content_type) + 1; /* +1 for eos */ int contentlen_len; char acceptAll[] = { 0x80, 0x80 }; contentlen_buf[0] = 0x8d; /* hdr type - content-length */ if (fstats.st_size <= 127) { contentlen_buf[1] = 0x80 | (char)fstats.st_size; contentlen_len = 2; } else { contentlen_buf[1] = 2; contentlen_buf[2] = (char)(fstats.st_size >> 8); contentlen_buf[3] = (char)(fstats.st_size); contentlen_len = 4; } off += StoreVarInt( &msgbuf[off], content_type_len+octstr_len(useragent)+contentlen_len+sizeof(acceptAll) ); memcpy( &msgbuf[off], url, url_len ); off += url_len; memcpy( &msgbuf[off], content_type, content_type_len ); off += content_type_len; memcpy( &msgbuf[off], octstr_get_cstr(useragent), octstr_len(useragent) ); off += octstr_len(useragent); memcpy( &msgbuf[off], contentlen_buf, contentlen_len ); off += contentlen_len; memcpy( &msgbuf[off], acceptAll, sizeof(acceptAll) ); off += sizeof(acceptAll); octstr_append_data(postmsg, (char*)msgbuf, off); /* add payload */ if (transaction_mode==TXN_MODE_CONNECTION_LESS) { ret = read(infd, msgbuf, sizeof(msgbuf)); } else { ret = read(infd, msgbuf, SAR_SEGM_SIZE); } if (ret <= 0) panic(0, "fakewap: input file read error, errno %d", errno); debug("fakewap", 0, "Sending WSP_POST, url %s, Content-Type %s, User-Agent %s, Content-Length %lu", url, content_type, octstr_get_cstr(useragent) + 1, fstats.st_size ); if (transaction_mode==TXN_MODE_CONNECTION_LESS) { ret = wap_msg_send( fd, NULL, 0, tid, tid_new, (unsigned char*)octstr_get_cstr(postmsg), octstr_len(postmsg), msgbuf, ret ); if (ret == -1) { error(0, "fakewap: failure sending connection-less wtp invoke"); goto send_post_exit; } } else { int retry = 0; while (retry++ < SAR_MAX_RETRIES) { ret = wap_msg_send( fd, wtphdr, sizeof(WTP_Invoke_Cl2MaxGrp), tid, tid_new, (unsigned char*)octstr_get_cstr(postmsg), octstr_len(postmsg), msgbuf, ret ); if (ret == -1) { error(0, "fakewap: failure sending connection-oriented wtp invoke"); goto send_post_exit; } /* receive invoke ack */ CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Ack, tid ); ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Ack), tid, msgbuf, sizeof(msgbuf), timeout, 0 ); if (ret < 0) { if (retry>=SAR_MAX_RETRIES) { error(0, "fakewap: failure receiving WTP Ack, psn %u, giving up", psn); goto send_post_exit; } warning(0, "fakewap: timeout receiving WTP Ack, resend wtp invoke"); continue; } debug("fakewap", 0, "Received WTP_ACK, psn 0"); break; } } if (transaction_mode==TXN_MODE_CONNECTION_ORIENTED) { while (!ttr) { int grppktnum = 0; /* packet in the group */ unsigned char grpwtphdr[SAR_GROUP_LEN][32]; unsigned char grpmsgbuf[SAR_GROUP_LEN][SAR_SEGM_SIZE]; int grpmsglen[SAR_GROUP_LEN]; int grpsize = 0; /* build segments for a new group */ gtr = 0; while (!gtr && !ttr) { psn++; /* create wtp header */ memcpy(grpwtphdr[grppktnum], WTP_Segm_Invoke, sizeof(WTP_Segm_Invoke)); tpi = 0; ttr = (nsegs==psn) ? 1 : 0; gtr = ttr ? 0 : (psn+1)%SAR_GROUP_LEN ? 0 : 1; grpwtphdr[grppktnum][0] = (tpi << 7) | (WTP_PDU_SEGM_INVOKE << 3) | (gtr << 2) | (ttr << 1); grpwtphdr[grppktnum][3] = psn; /* read payload from file */ grpmsglen[grppktnum] = read(infd, (char*)grpmsgbuf[grppktnum], SAR_SEGM_SIZE); if (grpmsglen[grppktnum] <= 0) panic(0, "fakewap: input file read error, errno %d", errno); grppktnum++; grpsize++; } int retry = 0; while (retry++ < SAR_MAX_RETRIES) { /* send a group of WTP Segmented Invoke messages */ for (grppktnum = 0; grppktnum < grpsize; grppktnum++) { debug("fakewap", 0, "Sending WTP_SEGM_INVOKE, psn %u, payload len %d", psn-grpsize+grppktnum+1, grpmsglen[grppktnum]); ret = wap_msg_send( fd, grpwtphdr[grppktnum], sizeof(WTP_Segm_Invoke), tid, tid_new, NULL, 0, grpmsgbuf[grppktnum], grpmsglen[grppktnum] ); if (ret == -1) { error(0, "fakewap: failure sending wtp invoke"); goto send_post_exit; } } if (ttr) { /* receive WTP Result */ CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Result, tid ); ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Result), tid, msgbuf, sizeof(msgbuf), timeout, MSG_PEEK ); } else { /* receive segm invoke ack for the group */ CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Segm_Ack, tid ); reply_hdr[4] = psn; ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Segm_Ack), tid, msgbuf, sizeof(msgbuf), timeout, 0 ); } if (ret < 0) { if (retry>=SAR_MAX_RETRIES) { error(0, "fakewap: failure receiving WTP Segm Ack, psn %u, giving up", psn); goto send_post_exit; } warning(0, "fakewap: failure receiving WTP Segm Ack, psn %u, retrying", psn); continue; } if (ttr) { debug("fakewap", 0, "Received WTP_RESULT"); } else { debug("fakewap", 0, "Received WTP_ACK, psn %d", psn); } break; } /* while (retry) */ } /* while (!ttr) */ } /* if (transaction_mode==CONNECTION_ORIENTED) */ send_post_exit: octstr_destroy(postmsg); close(infd); return ret; } /* ** Function (or thread) sets up a dgram socket. Then it loops: WTL/WSP ** Connect, Get a url and Disconnect until all requests are have been done. */ static void client_session( void * arg) { int fd; int ret; int url_len = 0, url_off = 0; double nowsec, lastsec, tmp, sleepTime; long uSleepTime; struct timeval now; struct timezone tz; char * url; unsigned char sid[20]; int sid_len = 0; unsigned char buf[64*1024]; unsigned char reply_hdr[32]; long timeout = WAP_MSG_RECEIVE_TIMEOUT; /* wap gw is broken if no input */ static unsigned short tid = 0; unsigned short old_tid; int tid_new = 0; int connection_retries = 0; int i_this; fd = udp_client_socket(); if (fd == -1) panic(0, "fakewap: Couldn't create socket."); if (src_addr.sin_addr.s_addr!=INADDR_ANY || src_addr.sin_port!=0) if (bind(fd, (const struct sockaddr *)&src_addr, (int)sizeof(src_addr)) == -1) panic(0, "fakewap: Couldn't bind socket, errno %d", errno); /* ** Loop until all URLs have been requested */ for (;;) { /* * Get start time of this request */ gettimeofday(&now, &tz); lastsec = (double) now.tv_sec + now.tv_usec / 1e6; /* * Get next transaction number or exit if too many transactions */ i_this = get_next_transaction(); if (max_send != MAX_SEND && i_this > max_send) break; if (transaction_mode==TXN_MODE_CONNECTION_ORIENTED) { /* * Connect, save sid from reply and finally ack the reply */ old_tid = tid; tid = next_tid(old_tid); tid_new = (tid < old_tid); /* Did we wrap? */ WSP_Connect[3] = 2 + octstr_len(useragent); /* set header length */ memcpy( buf, WSP_Connect, sizeof(WSP_Connect)); memcpy( &buf[sizeof(WSP_Connect)], octstr_get_cstr(useragent), octstr_len(useragent) ); ret = wap_msg_send( fd, WTP_Invoke_Cl2, sizeof(WTP_Invoke_Cl2), tid, tid_new, buf, sizeof(WSP_Connect)+octstr_len(useragent), NULL, 0 ); if (ret == -1) panic(0, "fakewap: Send WSP_Connect failed"); CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WSP_ConnectReply, tid ); ret = wap_msg_recv( fd, reply_hdr, sizeof(WSP_ConnectReply), tid, buf, sizeof(buf), timeout, 0 ); if (ret == -1) panic(0, "fakewap: Receive WSP_ConnectReply failed"); if (ret > 2) { sid_len = ReadVarIntLen(&buf[4]); memcpy( sid, &buf[4], sid_len); debug("fakewap", 0, "Received WSP_ConnectReply, SessID %d", ReadVarIntVal(&buf[4])); } /* ** Send abort and continue if we get an unexpected reply */ if (ret == 0) { if (connection_retries++ > 3) { panic(0, "fakewap: Cannot connect WAP GW!"); } wap_msg_send( fd, WTP_Abort, sizeof(WTP_Abort), tid, tid_new, NULL, 0, NULL, 0 ); continue; } else { connection_retries = 0; } ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new, NULL, 0, NULL, 0 ); if (ret == -1) panic(0, "fakewap: Send WTP_Ack failed"); } /* ** Send WSP Get or Post for a given URL */ old_tid = tid; tid = next_tid(old_tid); tid_new = (tid < old_tid); /* Did we wrap? */ url = choose_message(urls, num_urls); url_len = strlen(url); url_off = StoreVarInt( buf, url_len ); memcpy( buf+url_off, url, url_len ); buf[url_len+url_off] = 0x80; /* Accept: *\* */ buf[url_len+url_off+1] = 0x80; /* Accept: *\* */ /* send WSP Post if an input file is specified */ if (infile) { ret = send_post(fd, tid, tid_new, url); } else /* send WSP Get */ { if (transaction_mode==TXN_MODE_CONNECTION_LESS) { unsigned char wsphdr[32]; wsphdr[0] = tid; memcpy(&wsphdr[1], WSP_Get, sizeof(WSP_Get)); ret = wap_msg_send( fd, NULL, 0, tid, tid_new, wsphdr, sizeof(WSP_Get)+1, buf, url_len+url_off+2 ); } else { ret = wap_msg_send( fd, WTP_Invoke_Cl2, sizeof(WTP_Invoke_Cl2), tid, tid_new, WSP_Get, sizeof(WSP_Get), buf, url_len+url_off ); } if (ret == -1) break; } Octstr* wspreply = octstr_create(""); if (transaction_mode==TXN_MODE_CONNECTION_LESS) { /* Connectionless - receive WSP Reply */ reply_hdr[0] = tid; ret = wap_msg_recv( fd, reply_hdr, 1, tid, buf, sizeof(buf), timeout, 0 ); if (ret == -1) break; octstr_append_data(wspreply, (char*)&buf[1], ret-1); } else { /* Connection-Oriented - reassemble WSP Reply from WTP segments */ int gtr = 0, ttr = 0, psn, gtr_psn = -1, ttr_psn = -1; unsigned char segment_data[256][1500]; int segment_len[256]; int data_offset; memset(segment_len, 0, sizeof(segment_len)); while (!ttr) { CONSTRUCT_EXPECTED_REPLY_HDR( reply_hdr, WTP_Result, tid ); ret = wap_msg_recv( fd, reply_hdr, sizeof(WTP_Result), tid, buf, sizeof(buf), timeout, 0 ); timeout = WAP_MSG_RECEIVE_TIMEOUT; if (ret == -1) break; gtr = (buf[0] & 0x04) ? 1 : 0; ttr = (buf[0] & 0x02) ? 1 : 0; if (GET_WTP_PDU_TYPE(buf) == WTP_PDU_RESULT) { psn = 0; data_offset = 3; debug("fakewap", 0, "Received WTP_RESULT pdu, gtr %d, ttr %d, payload len %d", gtr, ttr, ret - data_offset); } else /* segmented result */ { psn = buf[3]; data_offset = 4; debug("fakewap", 0, "Received WTP_SEGM_RESULT pdu, psn %d, gtr %d, ttr %d, payload len %d", psn, gtr, ttr, ret - data_offset); } segment_len[psn] = ret - data_offset; if (segment_len[psn] > 1500) panic(0, "fakewap: Segment %d exceeds 1500 bytes!?!", psn); memcpy(segment_data[psn], &buf[data_offset], segment_len[psn]); if (gtr || ttr || (psn < gtr_psn)) { if (gtr || ttr) gtr_psn = psn; if (ttr) ttr_psn = psn; /* check for lost segments and send NACK */ unsigned char lost_segs[256]; int i, num_lost = 0; for (i = 0; i <= gtr_psn; i++) if (!segment_len[i]) lost_segs[num_lost++] = i; if (num_lost > 0) { /* send NACK since some segments got lost */ memcpy(buf, WTP_Nack, sizeof(WTP_Nack)); buf[3] = num_lost; memcpy(buf+sizeof(WTP_Nack), lost_segs, num_lost); debug("fakewap", 0, "Sending WTP_NACK pdu, num_lost %d, lost_seg0 %d", num_lost, lost_segs[0]); ret = wap_msg_send( fd, buf, sizeof(WTP_Nack)+num_lost, tid, tid_new, NULL, 0, NULL, 0 ); ttr = 0; } else if (psn > 0) { /* send WTP Ack for a group of segments */ WTP_Segm_Ack[4] = gtr_psn; debug("fakewap", 0, "Sending WTP_ACK pdu, gtr_psn %d", gtr_psn); ret = wap_msg_send( fd, WTP_Segm_Ack, sizeof(WTP_Segm_Ack), tid, tid_new, NULL, 0, NULL, 0 ); } else { /* send regular WTP Ack for first segment */ debug("fakewap", 0, "Sending WTP_ACK pdu, psn 0"); ret = wap_msg_send( fd, WTP_Ack, sizeof(WTP_Ack), tid, tid_new, NULL, 0, NULL, 0 ); } if (ret == -1) break; if ((ttr_psn >= 0) && (num_lost==0)) { /* received all segments */ ttr = 1; } } } if (!ttr) { panic(0, "fakewap: Failed to receive entire message!?!"); break; } for (psn = 0; psn <= gtr_psn; psn++) octstr_append_data(wspreply, (char*)segment_data[psn], segment_len[psn]); } /* validate WSP Reply */ WSP_PDU* wsppdu = wsp_pdu_unpack(wspreply); if (!wsppdu) panic(0, "fakewap: Failed to unpack wsp message!?!"); if (wsppdu->type != Reply) { error(0, "fakewap: Received WSP message type %u is not Reply!?!", octstr_get_char(wspreply, 0)); } else { struct Reply* wspreply = &wsppdu->u.Reply; int status; if (wspreply->status <= 0x4f) status = (wspreply->status >> 4) * 100 + (wspreply->status & 0x0f); else if ((wspreply->status & 0xf0) == 0x50) status = 431 + (wspreply->status & 0x0f); else status = (wspreply->status >> 4) * 100 - 100 + (wspreply->status & 0x0f); if (status != 200) { warning(0, "fakewap: Warning - received reply with status %d", status); } else { info(0, "fakewap: Received WSP Reply with status code 200OK"); } /* if output file arg was specified write the received wsp payload to file */ if (outfile) { int outfd = creat(outfile, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); if (outfd < 0) { panic(0, "fakewap: failed to create output file %s, errno %d", outfile, errno); } ret = write(outfd, octstr_get_cstr(wspreply->data), octstr_len(wspreply->data)); if (ret < 0) { panic(0, "fakewap: failed to write to output file %s, errno %d", outfile, errno); } close(outfd); debug("fakewap", 0, "Wrote %d bytes of response payload to output file %s", ret, outfile); } } if (transaction_mode==TXN_MODE_CONNECTION_ORIENTED) { /* ** Finally disconnect with the sid returned by connect reply */ { ret = wap_msg_send( fd, WTP_Invoke_Cl0, sizeof(WTP_Invoke_Cl0), tid, tid_new, WSP_Disconnect, sizeof(WSP_Disconnect), sid, sid_len ); if (ret == -1) break; } } /* ** Get end time of the request */ gettimeofday(&now, &tz); nowsec = (double) now.tv_sec + now.tv_usec / 1e6; tmp = nowsec - lastsec; /* Duration of request */ sleepTime = interval-tmp; /* Amount of time left to sleep */ uSleepTime = sleepTime * 1e6; mutex_lock( mutex ); if (tmp < besttime) besttime = tmp; if (tmp > worsttime) worsttime = tmp; totaltime += tmp; mutex_unlock( mutex ); if (brief == 1) { info(0, "fakewap: finished session # %d", i_this); } /* ** If we've done all the requests, then don't bother to sleep */ if (i_this >= max_send) break; if (tmp < (double)interval) { usleep( uSleepTime ); } } close(fd); /* The last end_time stays */ mutex_lock( mutex ); time(&end_time); mutex_unlock( mutex ); } static void help(void) { info(0, "\n%s", usage); } /* The main program. */ int main(int argc, char **argv) { int i, opt; double delta; int proto_version, tcl, tid_new; #ifdef SunOS struct sigaction alrm; alrm.sa_handler = SIG_IGN; sigaction(SIGALRM,&alrm,NULL); #endif gwlib_init(); proto_version = 0; tcl = 2; tid_new = 0; hostname = octstr_create("localhost"); /* restart args scanning */ optind = 1; /* reset globals */ interval = 1.0; port = 0; max_send = 1; tid_addition = 1; threads = 1; num_sent = 0; totaltime = 0; besttime = 1000000L; worsttime = 0; brief = 0; verbose = 0; test_separation = 0; infile = NULL; outfile = NULL; content_type = "text/plain"; src_addr.sin_family = AF_INET; src_addr.sin_addr.s_addr = INADDR_ANY; src_addr.sin_port = 0; transaction_mode = TXN_MODE_CONNECTION_ORIENTED; packet_loss = 0; /* create default user agent header prepend with a9, and end with 0 */ const char firstchar[] = {0xa9, 0}; /* code value for user agent header */ Octstr* temp = octstr_create("fakewap"); useragent = octstr_create(firstchar); octstr_append_data(useragent, octstr_get_cstr(temp), octstr_len(temp) ); octstr_append_data(useragent, "\0", 1 ); while ((opt = getopt(argc, argv, "Fhc:g:p:m:i:t:V:t:nsd:A:C:D:I:M:P:w:l:")) != EOF) { switch (opt) { case 'g': octstr_destroy(hostname); hostname = octstr_create(optarg); break; case 'p': port = atoi(optarg); break; case 'm': max_send = atoi(optarg); break; case 'i': interval = atof(optarg); break; case 'c': threads = atoi(optarg); break; case 'V': proto_version = atoi(optarg); break; case 't': tcl = atoi(optarg); break; case 'n': tid_new = 1; break; case 's': test_separation = 1; break; case 'd': tid_addition = atoi(optarg); break; case 'D': brief = (atoi(optarg) >= 1); verbose = (atoi(optarg) >= 2); break; case 'h': help(); exit(0); break; case 'F': nofailexit=1; break; case 'w': outfile = optarg; break; case 'A': octstr_destroy(useragent); octstr_destroy(temp); /* create user agent header prepend with a9, and end with 0 */ useragent = octstr_create(firstchar); temp = octstr_create(optarg); octstr_append_data(useragent, octstr_get_cstr(temp), octstr_len(temp) ); octstr_append_data(useragent, "\0", 1 ); break; case 'C': if (!strcmp("mms", optarg)) content_type = "application/vnd.wap.mms-message"; else content_type = "text/plain"; break; case 'I': { unsigned int byte0, byte1, byte2, byte3, srcport; int ret = sscanf(optarg, "%u.%u.%u.%u:%u", &byte0, &byte1, &byte2, &byte3, &srcport); if (ret!=4 && ret!=5) panic(0, "fakewap: invalid source address %s", optarg); src_addr.sin_addr.s_addr = htonl(byte0<<24 | byte1<<16 | byte2<<8 | byte3); if (ret==5) src_addr.sin_port = htons(srcport); break; } case 'M': transaction_mode = atoi(optarg); if ((transaction_mode!=0) && (transaction_mode!=1)) { error(0, "fakewap: invalid transaction mode %s", optarg); return -1; } break; case 'P': infile = optarg; break; case 'l': packet_loss = atoi(optarg); if ((packet_loss < 0) && (packet_loss >=99)) { error(0, "fakewap: invalid packet loss rate %s, expect 0-99", optarg); return -1; } break; case '?': default: error(0, "fakewap: Unknown option %c", opt); help(); panic(0, "fakewap: Stopping."); } } time(&start_time); if (optind >= argc) panic(0, "%s", usage); if ((!brief) && (!verbose)) { log_set_output_level (GW_INFO); } if (port==0) { if (transaction_mode==TXN_MODE_CONNECTION_LESS) port = 9200; else port = 9201; } WTP_Invoke_Cl2[3] |= (proto_version&3)<<6; /* WTP_Invoke_Cl2[0] += (pdu_type&15)<<3; */ WTP_Invoke_Cl2[3] |= tcl&3; WTP_Invoke_Cl2[3] |= (tid_new&1)<<5; gateway_addr = udp_create_address(hostname, port); urls = argv + optind; num_urls = argc - optind; srand((unsigned int) time(NULL)); mutex = (Mutex*)mutex_create(); info(0, "fakewap: starting"); if (threads < 1) threads = 1; /* ** Start 'extra' client threads and finally execute the ** session of main thread */ for (i = 1; i < threads; i++) gwthread_create(client_session, NULL); client_session(NULL); /* Wait for the other sessions to complete */ gwthread_join_every(client_session); info(0, "fakewap: complete."); info(0, "fakewap: %d client threads made total %d transactions.", threads, num_sent); delta = difftime(end_time, start_time); info( 0, "fakewap: total running time %.1f seconds", delta); info( 0, "fakewap: %.1f messages/seconds on average", num_sent / delta); info( 0, "fakewap: time of best, worst and average transaction: " "%.1f s, %.1f s, %.1f s", besttime, worsttime, totaltime / num_sent ); octstr_destroy(hostname); octstr_destroy(gateway_addr); mutex_destroy(mutex); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_urltrans.c0000644000175000017500000001037613227613126015732 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_urltrans.c - a simple program to test the URL translation module * * Lars Wirzenius */ #include #include #include "gwlib/gwlib.h" #include "gw/urltrans.h" static void help(void) { info(0, "Usage: test_urltrans [-r repeats] foo.smsconf pattern ...\n" "where -r means the number of times the test should be\n" "repeated."); } int main(int argc, char **argv) { int i, opt; long repeats; URLTranslationList *list; URLTranslation *t; Cfg *cfg; Octstr *name; gwlib_init(); repeats = 1; while ((opt = getopt(argc, argv, "hr:")) != EOF) { switch (opt) { case 'r': repeats = atoi(optarg); break; case 'h': help(); exit(0); case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (optind + 1 >= argc) { error(0, "Missing arguments."); help(); panic(0, "Stopping."); } name = octstr_create(argv[optind]); cfg = cfg_create(name); octstr_destroy(name); if (cfg_read(cfg) == -1) panic(0, "Couldn't read configuration file."); list = urltrans_create(); if (urltrans_add_cfg(list, cfg) == -1) panic(0, "Error parsing configuration."); while (repeats-- > 0) { for (i = optind + 1; i < argc; ++i) { Msg *msg = msg_create(sms); msg->sms.msgdata = octstr_create(argv[i]); t = urltrans_find(list, msg); info(0, "type = %d", urltrans_type(t)); msg_destroy(msg); } } urltrans_destroy(list); cfg_destroy(cfg); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_ota.c0000644000175000017500000001226513227613126014642 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_ota.c: A simple program to test ota tokenizer * * By Aarno Syvänen for Wiral Ltd */ #include #include "gwlib/gwlib.h" #include "gw/ota_compiler.h" Octstr *charset = NULL; Octstr *file_name = NULL; static void help (void) { info(0, "Usage test_ota [options] ota_source"); info(0, "where options are"); info(0, "-h - print this text"); info(0, "-f - output binary to file"); info(0, "-c - charset given by http"); info(0, "-v - set log level for stderr logging"); } int main(int argc, char **argv) { int opt, file, have_charset, ret; FILE *fp; Octstr *ota_doc, *ota_binary; file = 0; have_charset = 0; fp = NULL; gwlib_init(); while ((opt = getopt(argc, argv, "hf:c:v:")) != EOF) { switch (opt) { case 'h': help(); exit(1); break; case 'f': file = 1; file_name = octstr_create(optarg); fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Cannot open output file"); break; case 'c': have_charset = 1; charset = octstr_create(optarg); break; case 'v': log_set_output_level(atoi(optarg)); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping"); break; } } if (optind >= argc) { error(0, "Missing arguments"); help(); panic(0, "Stopping"); } ota_doc = octstr_read_file(argv[optind]); if (ota_doc == NULL) panic(0, "Cannot read the ota document"); if (!have_charset) charset = NULL; /* run compiler */ ret = ota_compile(ota_doc, charset, &ota_binary); debug("test.ota", 0, "ota compiler returned %d", ret); if (ret == 0) { if (fp == NULL) fp = stdout; if (file) { octstr_print(fp, ota_binary); } else { debug("test.ota", 0, "ota binary was"); octstr_dump(ota_binary, 0); } } if (have_charset) octstr_destroy(charset); if (file) { fclose(fp); octstr_destroy(file_name); } octstr_destroy(ota_doc); if (ret == 0) octstr_destroy(ota_binary); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_store_dump.c0000644000175000017500000000736413227613126016244 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Simple tool that prints out content of a kannel storefile. * * Tobias Weber * Stipe Tolj */ #include "gwlib/gwlib.h" #include "shared.h" #include "bearerbox.h" static int counter = 0; static void print_msg(Msg *msg) { counter++; msg_dump(msg, 0); } /* void function to make gwlib happy */ static int check_args(int i, int argc, char **argv) { return -1; } int main(int argc, char **argv) { int cf_index; Octstr *type; gwlib_init(); cf_index = get_and_set_debugs(argc, argv, check_args); if (argv[cf_index] == NULL) panic(0, "Usage: %s ", argv[0]); type = octstr_create("file"); /* init store subsystem */ store_init(NULL, type, octstr_imm(argv[cf_index]), -1, msg_pack, msg_unpack_wrapper); /* pass every entry in the store to callback print_msg() */ store_load(print_msg); info(0, "Store file contains %d msg entries", counter); info(0, "Shutting down."); gwlib_shutdown(); return 1; } gateway-1.4.5/test/timestamp.c0000644000175000017500000001201413227613126015013 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * timestamp.c - Convert a textual timestamps to seconds since epoch * * Read textual timestamps, one per line, from the standard input, and * convert them to integers giving the corresponding number of seconds * since the beginning of the epoch (beginning of 1970). Both the input * and the results should be in UTC. * * Lars Wirzenius */ #include #include "gwlib/gwlib.h" static Octstr *read_line(FILE *f, Octstr *buf) { Octstr *os; char cbuf[8*1024]; size_t n; long pos; pos = octstr_search_char(buf, '\n', 0); while (pos == -1 && (n = fread(cbuf, 1, sizeof(cbuf), f)) > 0) { octstr_append_data(buf, cbuf, n); pos = octstr_search_char(buf, '\n', 0); } if (pos == -1) { pos = octstr_len(buf); if (pos == 0) return NULL; } os = octstr_copy(buf, 0, pos); octstr_delete(buf, 0, pos + 1); return os; } static int remove_long(long *p, Octstr *os) { long pos; pos = octstr_parse_long(p, os, 0, 10); if (pos == -1) return -1; octstr_delete(os, 0, pos); return 0; } static int remove_prefix(Octstr *os, Octstr *prefix) { if (octstr_ncompare(os, prefix, octstr_len(prefix)) != 0) return -1; octstr_delete(os, 0, octstr_len(prefix)); return 0; } static int parse_date(struct universaltime *ut, Octstr *os) { if (remove_long(&ut->year, os) == -1 || remove_prefix(os, octstr_imm("-")) == -1 || remove_long(&ut->month, os) == -1 || remove_prefix(os, octstr_imm("-")) == -1 || remove_long(&ut->day, os) == -1 || remove_prefix(os, octstr_imm(" ")) == -1 || remove_long(&ut->hour, os) == -1 || remove_prefix(os, octstr_imm(":")) == -1 || remove_long(&ut->minute, os) == -1 || remove_prefix(os, octstr_imm(":")) == -1 || remove_long(&ut->second, os) == -1 || remove_prefix(os, octstr_imm(" ")) == -1) return -1; return 0; } int main(void) { struct universaltime ut; Octstr *os; Octstr *buf; gwlib_init(); buf = octstr_create(""); while ((os = read_line(stdin, buf)) != NULL) { if (parse_date(&ut, os) == -1) panic(0, "Bad line: %s", octstr_get_cstr(os)); printf("%ld %s\n", date_convert_universal(&ut), octstr_get_cstr(os)); octstr_destroy(os); } log_set_output_level(GW_PANIC); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_si.c0000644000175000017500000001210713227613126014465 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_si.c: A simple program to test si tokenizer * * By Aarno Syvänen for Wiral Ltd */ #include #include "gwlib/gwlib.h" #include "gw/wap_push_si_compiler.h" Octstr *charset = NULL; Octstr *file_name = NULL; static void help (void) { info(0, "Usage test_si [option] si_source"); info(0, "where options are"); info(0, "-h print this text"); info(0, "-f file output binary to the file"); info(0, "-c charset charset given by http"); info(0, "-v level set log level for stderr logging"); } int main(int argc, char **argv) { int opt, file, have_charset, ret; FILE *fp; Octstr *output, *si_doc, *si_binary; gwlib_init(); file = 0; have_charset = 0; fp = NULL; while ((opt = getopt(argc, argv, "hf:c:v:")) != EOF) { switch (opt) { case 'h': help(); exit(1); break; case 'f': file = 1; file_name = octstr_create(optarg); fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Cannot open output file"); break; case 'c': have_charset = 1; charset = octstr_create(optarg); break; case 'v': log_set_output_level(atoi(optarg)); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping"); break; } } if (optind >= argc) { error(0, "Missing arguments"); help(); panic(0, "Stopping"); } si_doc = octstr_read_file(argv[optind]); if (si_doc == NULL) panic(0, "Cannot read the si document"); if (!have_charset) charset = NULL; ret = si_compile(si_doc, charset, &si_binary); output = octstr_format("%s", "si compiler returned %d\n", ret); if (ret == 0) { if (fp == NULL) fp = stdout; octstr_append(output, octstr_imm("content being\n")); octstr_append(output, si_binary); } if (file) octstr_pretty_print(fp, output); else { debug("test.si", 0, "si binary was"); octstr_dump(si_binary, 0); } if (have_charset) octstr_destroy(charset); if (file) { fclose(fp); octstr_destroy(file_name); } octstr_destroy(si_doc); octstr_destroy(si_binary); octstr_destroy(output); gwlib_shutdown(); return 0; } gateway-1.4.5/test/sl.txt0000644000175000017500000000030507406110105014012 0ustar toljtolj gateway-1.4.5/test/test_mem.c0000644000175000017500000000614613227613126014636 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_mem.c - test memory allocation functions. * * Lars Wirzenius */ #include "gwlib/gwlib.h" int main(void) { void *p; long i; gwlib_init(); p = gw_malloc(100); gw_free(p); gw_check_leaks(); p = gw_malloc(100); gw_check_leaks(); gw_free(p); gw_check_leaks(); for (i = 0; i < 1000; ++i) { p = gw_malloc(100); debug("", 0, "i = %ld", i); } gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_hmac.c0000644000175000017500000001143313245353052014762 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_hmac.c - calculates the HMAC-SHA1 hash value * * This algorithm is used in the OTA Prov architecture for bootstrap * securtiy by means of a shared secret. * * References: * - WAP-184-PROVBOOT-20010314a.pdf (Provisioning Bootstrap), WAP Forum * - HMAC: Keyed-Hashing for Message Authentication”, Krawczyk, H., * Bellare, M., and Canetti, R., RFC 2104 * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" #ifdef HAVE_LIBSSL #include #endif #ifndef EVP_MAX_MD_SIZE #define EVP_MAX_MD_SIZE 1 #endif int main(int argc, char **argv) { Octstr *data, *filename, *mac, *key; unsigned char macbuf[EVP_MAX_MD_SIZE], *p; int mac_len; #ifdef HAVE_LIBSSL HMAC_CTX *ctx; #endif gwlib_init(); get_and_set_debugs(argc, argv, NULL); if (argc < 3) panic(0, "Syntax: %s \n", argv[0]); key = octstr_create(argv[1]); filename = octstr_create(argv[2]); data = octstr_read_file(octstr_get_cstr(filename)); if (data == NULL) panic(0, "Cannot read file."); debug("",0,"Dumping file `%s':", octstr_get_cstr(filename)); octstr_dump(data, 0); #ifdef HAVE_LIBSSL #if OPENSSL_VERSION_NUMBER < 0x10100000L HMAC_Init(ctx, octstr_get_cstr(key), octstr_len(key), EVP_sha1()); #else ctx = HMAC_CTX_new(); #endif p = HMAC(EVP_sha1(), octstr_get_cstr(key), octstr_len(key), octstr_get_cstr(data), octstr_len(data), macbuf, &mac_len); #if OPENSSL_VERSION_NUMBER < 0x10100000L HMAC_cleanup(ctx); #else HMAC_CTX_free(ctx); #endif #else macbuf[0] = 0; mac_len = 0; p = macbuf; warning(0, "No SSL support. Can't calculate HMAC value."); #endif mac = octstr_create_from_data(p, mac_len); octstr_binary_to_hex(mac, 0); debug("",0,"HMAC of file `%s' and key `%s' is:", octstr_get_cstr(filename), octstr_get_cstr(key)); octstr_dump(mac, 0); octstr_destroy(data); octstr_destroy(mac); octstr_destroy(key); gwlib_shutdown(); return 0; } gateway-1.4.5/test/drive_smpp.conf0000644000175000017500000000142412366721100015661 0ustar toljtoljgroup = core admin-port = 13000 smsbox-port = 13001 admin-password = bar log-file = "check_smpp_bb.log" box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" access-log = /dev/stdout group = smsc smsc = smpp smsc-id = smpp host = 127.0.0.1 port = 2345 system-type = "VMA" address-range = "" smsc-username = "foo" smsc-password = "bar" group = smsc smsc = smpp smsc-id = smpp host = 127.0.0.1 receive-port = 2345 system-type = "VMA" address-range = "" smsc-username = "foo" smsc-password = "bar" group = smpp-tlv name = my_receipted_message_id tag = 0x001E type = octetstring length = 65 #smsc-id = smpp group = smsbox bearerbox-host = 127.0.0.1 sendsms-port = 13013 global-sender = 123 log-file = "smsbox.log" group = sms-service keyword = default text = "No service specified" gateway-1.4.5/test/test_http_server.c0000644000175000017500000004075413227613126016430 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_http.c - a simple program to test the http library, server end * * Lars Wirzenius */ #include #include #include #include #include "gwlib/gwlib.h" #include "gwlib/http.h" #define MAX_THREADS 1024 Octstr *whitelist, *blacklist; Octstr *reply_text = NULL; int verbose, port; int ssl = 0; /* indicate if SSL-enabled server should be used */ static volatile sig_atomic_t run; static List *extra_headers = NULL; static void split_headers(Octstr *headers, List **split) { long start; long pos; *split = gwlist_create(); start = 0; for (pos = 0; pos < octstr_len(headers); pos++) { if (octstr_get_char(headers, pos) == '\n') { Octstr *line; if (pos == start) { /* Skip empty lines */ start = pos + 1; continue; } line = octstr_copy(headers, start, pos - start); start = pos + 1; gwlist_append(*split, line); } } } static void client_thread(void *arg) { HTTPClient *client; Octstr *body, *url, *ip; List *headers, *resph, *cgivars; HTTPCGIVar *v; Octstr *reply_body, *reply_type; unsigned long n = 0; int status, i; while (run) { client = http_accept_request(port, &ip, &url, &headers, &body, &cgivars); n++; if (client == NULL) break; info(0, "Request for <%s> from <%s>", octstr_get_cstr(url), octstr_get_cstr(ip)); if (verbose) debug("test.http", 0, "CGI vars were"); /* * Don't use gwlist_extract() here, otherwise we don't have a chance * to re-use the cgivars later on. */ for (i = 0; i < gwlist_len(cgivars); i++) { if ((v = gwlist_get(cgivars, i)) != NULL && verbose) { octstr_dump(v->name, 0); octstr_dump(v->value, 0); } } if (arg == NULL) { reply_body = octstr_duplicate(reply_text); reply_type = octstr_create("Content-Type: text/plain; " "charset=\"UTF-8\""); } else { reply_body = octstr_duplicate(arg); reply_type = octstr_create("Content-Type: text/vnd.wap.wml"); } resph = gwlist_create(); gwlist_append(resph, reply_type); status = HTTP_OK; /* check for special URIs and handle those */ if (octstr_compare(url, octstr_imm("/quit")) == 0) { run = 0; } else if (octstr_compare(url, octstr_imm("/whitelist")) == 0) { octstr_destroy(reply_body); if (whitelist != NULL) { if (verbose) { debug("test.http.server", 0, "we send a white list"); octstr_dump(whitelist, 0); } reply_body = octstr_duplicate(whitelist); } else { reply_body = octstr_imm(""); } } else if (octstr_compare(url, octstr_imm("/blacklist")) == 0) { octstr_destroy(reply_body); if (blacklist != NULL) { if (verbose) { debug("test.http.server", 0, "we send a blacklist"); octstr_dump(blacklist, 0); } reply_body = octstr_duplicate(blacklist); } else { reply_body = octstr_imm(""); } } else if (octstr_compare(url, octstr_imm("/save")) == 0) { /* safe the body into a temporary file */ pid_t pid = getpid(); FILE *f = fopen(octstr_get_cstr(octstr_format("/tmp/body.%ld.%ld", pid, n)), "w"); octstr_print(f, body); fclose(f); } else if (octstr_compare(url, octstr_imm("/redirect/")) == 0) { /* provide us with a HTTP 302 redirection response * will return /redirect/ for the location header * and will return /redirect/ if cgivar loop is set to allow looping */ Octstr *redirect_header, *scheme, *uri, *l; pid_t pid = getpid(); uri = ((l = http_cgi_variable(cgivars, "loop")) != NULL) ? octstr_format("%s?loop=%s", octstr_get_cstr(url), octstr_get_cstr(l)) : octstr_format("%s%ld", octstr_get_cstr(url), pid); octstr_destroy(reply_body); reply_body = octstr_imm("Here you got a redirection URL that you should follow."); scheme = ssl ? octstr_imm("https://") : octstr_imm("http://"); redirect_header = octstr_format("Location: %s%s%s", octstr_get_cstr(scheme), octstr_get_cstr(http_header_value(headers, octstr_imm("Host"))), octstr_get_cstr(uri)); gwlist_append(resph, redirect_header); status = HTTP_FOUND; /* will provide 302 */ octstr_destroy(uri); } else if (octstr_compare(url, octstr_imm("/mmsc")) == 0) { /* fake a M-Send.conf PDU which is using MMSEncapsulation as body */ pid_t pid = getpid(); FILE *f; gwlist_destroy(resph, octstr_destroy_item); octstr_destroy(reply_body); reply_type = octstr_create("Content-Type: application/vnd.wap.mms-message"); reply_body = octstr_create(""); octstr_append_from_hex(reply_body, "8c81" /* X-Mms-Message-Type: m-send-conf */ "98632d3862343300" /* X-Mms-Transaction-ID: c-8b43 */ "8d90" /* X-Mms-MMS-Version: 1.0 */ "9280" /* Response-status: Ok */ "8b313331373939353434393639383434313731323400" ); /* Message-Id: 13179954496984417124 */ resph = gwlist_create(); gwlist_append(resph, reply_type); /* safe the M-Send.req body into a temporary file */ f = fopen(octstr_get_cstr(octstr_format("/tmp/mms-body.%ld.%ld", pid, n)), "w"); octstr_print(f, body); fclose(f); } if (verbose) { debug("test.http", 0, "request headers were"); http_header_dump(headers); if (body != NULL) { debug("test.http", 0, "request body was"); octstr_dump(body, 0); } } if (extra_headers != NULL) http_header_combine(resph, extra_headers); /* return response to client */ http_send_reply(client, status, resph, reply_body); octstr_destroy(ip); octstr_destroy(url); octstr_destroy(body); octstr_destroy(reply_body); http_destroy_cgiargs(cgivars); gwlist_destroy(headers, octstr_destroy_item); gwlist_destroy(resph, octstr_destroy_item); } octstr_destroy(whitelist); octstr_destroy(blacklist); debug("test.http", 0, "Working thread 'client_thread' terminates"); http_close_all_ports(); } static void help(void) { info(0, "Usage: test_http_server [options...]"); info(0, "where options are:"); info(0, "-t number"); info(0, " set number of working threads to use (default: 1)"); info(0, "-v number"); info(0, " set log level for stderr logging (default: 0 - debug)"); info(0, "-l logfile"); info(0, " log all output to a file"); info(0, "-f file"); info(0, " use a specific file content for the response body"); info(0, "-r reply_text"); info(0, " defines which static text to use for replies"); info(0, "-h"); info(0, " provides this usage help information"); info(0, "-q"); info(0, " don't be too verbose with output"); info(0, "-p port"); info(0, " bind server to a specific port"); info(0, "-s"); info(0, " be an SSL-enabled server"); info(0, "-c ssl_cert"); info(0, " file of the SSL certificate to use"); info(0, "-k ssl_key"); info(0, " file of the SSL private key to use"); info(0, "-w white_list"); info(0, " file that is used for whitelist"); info(0, "-b black_list"); info(0, " file that is used for blacklist"); info(0, "-H filename"); info(0, " read HTTP headers from file 'filename' and add them to"); info(0, " the request for url 'url'"); info(0, "specific URIs with special functions are:"); info(0, " /quite - shutdown the HTTP server"); info(0, " /whitelist - provides the -w whitelist as response"); info(0, " /blacklist - provides the -b blacklist as response"); info(0, " /save - save a HTTP POST request body to a file /tmp/body.."); info(0, " where is the process id and is the received request number"); info(0, " /redirect/ - respond with HTTP 302 and the location /redirect/"); info(0, " where is the process id. if a cgivar loop= is given"); info(0, " then HTTP responses will end up in a loop."); info(0, " /mmsc - fake a MMSC HTTP interface for M-Send.req PDUs send by a"); info(0, " mobile MMS-capable device, responds with a M-Send.conf PDU and"); info(0, " saves the M-Send.req body to a file /tmp/mms-body.. in"); info(0, " MMSEncapsulation encoded binary format"); } static void sigterm(int signo) { run = 0; debug("test.gwlib", 0, "Signal %d received, quitting.", signo); } int main(int argc, char **argv) { int i, opt, use_threads; struct sigaction act; char *filename; Octstr *log_filename; Octstr *file_contents; #ifdef HAVE_LIBSSL Octstr *ssl_server_cert_file = NULL; Octstr *ssl_server_key_file = NULL; #endif char *whitelist_name; char *blacklist_name; int white_asked, black_asked; long threads[MAX_THREADS]; FILE *fp; gwlib_init(); act.sa_handler = sigterm; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); port = 8080; use_threads = 1; verbose = 1; run = 1; filename = NULL; log_filename = NULL; blacklist_name = NULL; whitelist_name = NULL; white_asked = 0; black_asked = 0; reply_text = octstr_create("Sent."); while ((opt = getopt(argc, argv, "hqv:p:t:f:l:sc:k:b:w:r:H:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'q': verbose = 0; break; case 'h': help(); exit(0); case 'p': port = atoi(optarg); break; case 't': use_threads = atoi(optarg); if (use_threads > MAX_THREADS) use_threads = MAX_THREADS; break; case 'c': #ifdef HAVE_LIBSSL octstr_destroy(ssl_server_cert_file); ssl_server_cert_file = octstr_create(optarg); #endif break; case 'k': #ifdef HAVE_LIBSSL octstr_destroy(ssl_server_key_file); ssl_server_key_file = octstr_create(optarg); #endif break; case 's': #ifdef HAVE_LIBSSL ssl = 1; #endif break; case 'f': filename = optarg; break; case 'l': octstr_destroy(log_filename); log_filename = octstr_create(optarg); break; case 'w': whitelist_name = optarg; if (whitelist_name == NULL) whitelist_name = ""; white_asked = 1; break; case 'b': blacklist_name = optarg; if (blacklist_name == NULL) blacklist_name = ""; black_asked = 1; break; case 'r': octstr_destroy(reply_text); reply_text = octstr_create(optarg); break; case 'H': { Octstr *cont; fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Cannot open header text file %s", optarg); cont = octstr_read_file(optarg); if (cont == NULL) panic(0, "Cannot read header text"); debug("", 0, "headers are"); octstr_dump(cont, 0); split_headers(cont, &extra_headers); fclose(fp); octstr_destroy(cont); break; } case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (log_filename != NULL) { log_open(octstr_get_cstr(log_filename), GW_DEBUG, GW_NON_EXCL); octstr_destroy(log_filename); } if (filename == NULL) file_contents = NULL; else file_contents = octstr_read_file(filename); if (white_asked) { whitelist = octstr_read_file(whitelist_name); if (whitelist == NULL) panic(0, "Cannot read the whitelist"); } if (black_asked) { blacklist = octstr_read_file(blacklist_name); if (blacklist == NULL) panic(0, "Cannot read the blacklist"); } #ifdef HAVE_LIBSSL /* * check if we are doing a SSL-enabled server version here * load the required cert and key file */ if (ssl) { if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) { conn_use_global_server_certkey_file(ssl_server_cert_file, ssl_server_key_file); octstr_destroy(ssl_server_cert_file); octstr_destroy(ssl_server_key_file); } else { panic(0, "certificate and public key need to be given!"); } } #endif if (http_open_port(port, ssl) == -1) panic(0, "http_open_server failed"); /* * Do the real work in a separate thread so that the main * thread can catch signals safely. */ for (i = 0; i < use_threads; ++i) threads[i] = gwthread_create(client_thread, file_contents); /* wait for all working threads */ for (i = 0; i < use_threads; ++i) gwthread_join(threads[i]); octstr_destroy(reply_text); gwlist_destroy(extra_headers, octstr_destroy_item); debug("test.http", 0, "Program exiting normally."); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_prioqueue.c0000644000175000017500000000766013227613126016100 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_prioqueue.c - test priority queue objects * * Alexander Malysh , 2004 */ #include "gwlib/gwlib.h" #include "gwlib/gw-prioqueue.h" static int my_cmp(const void *a, const void *b) { return octstr_compare((Octstr*) a, (Octstr*) b); } static void my_dump(const void *a, long index) { debug("", 0, "dump(%p, %ld) called", a, index); debug("", 0, "value=%s", octstr_get_cstr((Octstr*) a)); } int main() { Octstr *os; long i; gw_prioqueue_t *queue; gwlib_init(); /* os = octstr_imm("iareanmsgotx"); */ os = octstr_imm("123456789"); queue = gw_prioqueue_create(my_cmp); for (i=0; i < octstr_len(os); i++) { char a[2]; a[0] = octstr_get_char(os, i); a[1] = '\0'; gw_prioqueue_insert(queue, octstr_create(a)); } gw_prioqueue_foreach(queue, my_dump); while ((os = gw_prioqueue_remove(queue))) { debug("", 0, "%s", octstr_get_cstr(os)); octstr_destroy(os); } debug("", 0, "gw_prioqueue_len=%ld", gw_prioqueue_len(queue)); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_conn.c0000644000175000017500000000726313227613126015016 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_conn.c - test generic gwlib/conn.c functions * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" int main(int argc, char **argv) { Connection *conn; Octstr *host = NULL; int port, i; gwlib_init(); get_and_set_debugs(argc, argv, NULL); if (argc < 3) panic(0, "Syntax: %s \n", argv[0]); host = octstr_create(argv[1]); port = atoi(argv[2]); i = 50; debug("",0,"Connecting to host '%s', port %d, looping %i times.", octstr_get_cstr(host), port, i); for (i = 0; i <= 50; i++) { conn = conn_open_tcp(host, port, NULL); if (conn == NULL) { panic(0, "Couldn't connect."); } debug("",0,"%d: connected.", i); gwthread_sleep(0.2); debug("",0,"%d: closing.", i); conn_destroy(conn); } octstr_destroy(host); gwlib_shutdown(); return 0; } gateway-1.4.5/test/mime-multipart.txt0000644000175000017500000000136511032710523016351 0ustar toljtoljContent-Type: multipart/related; start=; boundary=my_boundary X-Some-Header: Some-Value MIME-Version: 1.0 --my_boundary Content-Type: text/plain this is the text in this entity --my_boundary Content-Type: multipart/mixed; boundary=mms_boundary MIME-Version: 1.0 --mms_boundary Content-Type: text/plain this is the mms message text --mms_boundary Content-Type: application/xml
--mms_boundary-- --my_boundary-- gateway-1.4.5/test/bookmark.txt0000644000175000017500000000054407424243130015213 0ustar toljtolj gateway-1.4.5/test/test_pdu.c0000644000175000017500000001141713227613126014645 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_pdu.c - test gw/wtp_pdu packing and unpacking. * * Richard Braakman */ #include #include #include #include "gwlib/gwlib.h" #include "wap/wtp_pdu.h" #include "wap/wsp_pdu.h" int main(int argc, char **argv) { int i; Octstr *packet = NULL; Octstr *newpacket = NULL; WTP_PDU *pdu = NULL; Octstr *wsp_data = NULL; WSP_PDU *wsp = NULL; gwlib_init(); for (i = 1; i < argc; i++) { octstr_destroy(packet); packet = NULL; octstr_destroy(newpacket); newpacket = NULL; octstr_destroy(wsp_data); wsp_data = NULL; wtp_pdu_destroy(pdu); pdu = NULL; wsp_pdu_destroy(wsp); wsp = NULL; packet = octstr_read_file(argv[i]); pdu = wtp_pdu_unpack(packet); if (!pdu) { warning(0, "Unpacking PDU %s failed", argv[i]); continue; } debug("test", 0, "PDU %s:", argv[i]); wtp_pdu_dump(pdu, 0); newpacket = wtp_pdu_pack(pdu); if (!newpacket) { warning(0, "Repacking PDU %s failed", argv[i]); continue; } if (octstr_compare(packet, newpacket) != 0) { error(0, "Repacking PDU %s changed it", argv[i]); debug("test", 0, "Original:"); octstr_dump(packet, 1); debug("test", 0, "New:"); octstr_dump(newpacket, 1); continue; } if (pdu->type == Invoke) { wsp_data = pdu->u.Invoke.user_data; } else if (pdu->type == Result) { wsp_data = pdu->u.Result.user_data; } else { continue; } wsp_data = octstr_duplicate(wsp_data); wsp = wsp_pdu_unpack(wsp_data); if (!wsp) { warning(0, "Unpacking WSP data in %s failed", argv[i]); continue; } wsp_pdu_dump(wsp, 0); octstr_destroy(newpacket); newpacket = wsp_pdu_pack(wsp); if (!newpacket) { warning(0, "Repacking WSP data in %s failed", argv[i]); continue; } if (octstr_compare(wsp_data, newpacket) != 0) { error(0, "Repacking WSP data in %s changed it", argv[i]); debug("test", 0, "Original:"); octstr_dump(wsp_data, 1); debug("test", 0, "New:"); octstr_dump(newpacket, 1); continue; } } octstr_destroy(packet); octstr_destroy(newpacket); wtp_pdu_destroy(pdu); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_uuid.c0000644000175000017500000000675413227613126015033 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_uuid.c - some generic tests on the uuid routines of gwlib * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" int main(int argc, char **argv) { Octstr *os; char id[UUID_STR_LEN + 1]; uuid_t uid; gwlib_init(); debug("uuid",0,"Creating UUID"); uuid_generate(uid); debug("uuid",0,"Parse into char"); uuid_unparse(uid, id); debug("uuid",0,"Create Octstr"); os = octstr_create(id); debug("uuid",0,"UUID is: %s", octstr_get_cstr(os)); debug("uuid",0,"Removing dashes"); octstr_replace(os, octstr_imm("-"), octstr_imm("")); debug("uuid",0,"UUID is: %s", octstr_get_cstr(os)); octstr_destroy(os); uuid_clear(uid); gwlib_shutdown(); return 0; } gateway-1.4.5/test/fakesmsc.c0000644000175000017500000003244413227613126014615 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * fakesmsc.c - simulate an SMS center, using a trivial protocol * * The protocol: * * Client sends each message on its own line (terminated with \r\n or \n). * The line begins with 3 space-separated fields: * sender's phone number, receiver's phone number, * type of message. Type of message can be one of "text", "data", or * "udh". If type == "text", the rest of the line is taken as the message. * If type == "data", the next field is taken to be the text of the * message in urlcoded form. Space is coded as '+'. If type == "udh", * the following 2 fields are taken to be the UDH and normal portions * in urlcoded form. Space is again coded as '+'. * The server sends replies back in the same format. * * Lars Wirzenius, later edition by Kalle Marjola * Largely rewritten by Uoti Urpala */ static char usage[] = "\n\ Usage: fakesmsc [-H host] [-r port] [-i interval] [-m max] [-z ] ... \n\ \n\ * 'host' and 'port' define bearerbox connection (default localhost:10000),\n\ * 'interval' is time in seconds (floats allowed) between generated messages,\n\ * 'max' is the total number sent (-1, default, means unlimited),\n\ * bitmask of which elements to add randomized numbers for MO messages,\n\ * 1: src no, 2: recv no, 4: last text element,\n\ * where the given static elements in are used as constant prefixes,\n\ * is message to send, if several are given, they are sent randomly.\n\ \n\ msg format: \"sender receiver type(text|data|ucs2|udh-data|udh-text|route|dlr-mask) [udhdata|route|dlrmask] msgdata\"\n\ \n\ Type \"text\" means plaintext msgdata, \"data\" urlcoded, \"udh\" url-encoded udh+msg,\n\ \"ucs2\" unicode url-encoded msgdata and \"route\" means smsbox-id routed plaintext msgdata\n\ Examples: \n\ \n\ fakesmsc -m 1 \"123 345 udh %04udh%3f message+data+here\"\n\ fakesmsc -m 1 \"123 345 route smsbox1 message+data+here\"\n\ fakesmsc -i 0.01 -m 1000 \"123 345 text nop\" \"1 2 text another message here\"\n\ fakesmsc -z 7 -m 1000 \"123 345 text nop \"\n\ \n\ Server replies are shown in the same message format.\n"; #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #define IN_BUFSIZE 256 /* Buffer size for stdin */ #define IN_TIMEOUT 1 /* Timeout for stdin */ static int port = 10000; static Octstr *host; static long max_send = LONG_MAX; static double interval = 1.0; static int sigint_received; static int rnd = 0; static void signal_handler(int signum) { if (signum == SIGINT) sigint_received = 1; else panic(0, "Caught signal with no handler?!"); } static void setup_signal_handlers(void) { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); } /* Choose a random message from a table of messages. */ static Octstr *choose_message(Octstr **msgs, int num_msgs) { /* the following doesn't give an even distribution, but who cares */ return msgs[gw_rand() % num_msgs]; } /* Get current time, as double. */ static double get_current_time(void) { struct timezone tz; struct timeval now; gettimeofday(&now, &tz); return (double) now.tv_sec + now.tv_usec / 1e6; } /* our arguments */ static int check_args(int i, int argc, char **argv) { if (strcmp(argv[i], "-r")==0 || strcmp(argv[i], "--port")==0) port = atoi(argv[i+1]); else if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "--host")) host = octstr_create(argv[i+1]); else if (strcmp(argv[i], "-m")==0 || strcmp(argv[i], "--messages")==0) { max_send = atoi(argv[i+1]); if (max_send < 0) max_send = LONG_MAX; } else if (strcmp(argv[i], "-i")==0 || strcmp(argv[i], "--interval")==0) interval = atof(argv[i+1]); else if (strcmp(argv[i], "-z")==0 || strcmp(argv[i], "--randomize")==0) { rnd = atoi(argv[i+1]); if (rnd < 0 || rnd > 7) rnd = 0; } else { panic(0, "%s", usage); return 0; } return 1; } /* randomization of message elements */ static Octstr *randomize(Octstr *os) { Octstr *msg = octstr_create(""); List *words = octstr_split_words(os); int i; /* randomize source and receiver number */ octstr_format_append(msg, "%S", gwlist_get(words, 0)); if (rnd & 0x1) octstr_format_append(msg, "%d", gw_rand()); octstr_format_append(msg, " %S", gwlist_get(words, 1)); if (rnd & 0x2) octstr_format_append(msg, "%d", gw_rand()); for (i = 2; i < gwlist_len(words); i++) octstr_format_append(msg, " %S", gwlist_get(words, i)); if (rnd & 0x4) octstr_format_append(msg, " %d", gw_rand()); octstr_append_char(msg, 10); /* End of line */ gwlist_destroy(words, octstr_destroy_item); return msg; } /* The main program. */ int main(int argc, char **argv) { Connection *server; Octstr *line; Octstr **msgs; int i; int mptr, num_msgs; long num_received, num_sent; double first_received_at, last_received_at; double first_sent_at, last_sent_at; double start_time, end_time; double delta; int interactive, maxfd; char *cptr; char buffer[IN_BUFSIZE]; fd_set rset; struct timeval alarm; FILE *fp; gwlib_init(); setup_signal_handlers(); host = octstr_create("localhost"); start_time = get_current_time(); mptr = get_and_set_debugs(argc, argv, check_args); num_msgs = argc - mptr; interactive = 0; msgs = NULL; fp = NULL; if (num_msgs <= 0) { interactive = 1; num_msgs = 0; info(0, "Entering interactive mode. Type your message on the command line"); /* set up file pointer to stdin */ fp = stdin; /* initialize set for select */ FD_ZERO(&rset); } else { msgs = gw_malloc(sizeof(Octstr *) * num_msgs); for (i = 0; i < num_msgs; i ++) { msgs[i] = octstr_create(argv[mptr + i]); octstr_append_char(msgs[i], 10); /* End of line */ } info(0, "Host %s Port %d interval %.3f max-messages %ld", octstr_get_cstr(host), port, interval, max_send); srand((unsigned int) time(NULL)); } info(0, "fakesmsc starting"); server = conn_open_tcp(host, port, NULL); if (server == NULL) panic(0, "Failed to open connection"); num_sent = 0; num_received = 0; first_received_at = 0; first_sent_at = 0; last_received_at = 0; last_sent_at = 0; /* infinitely loop */ while (1) { /* Are we on interactive mode? */ if (interactive == 1) { /* Check if we need to clean things up beforehand */ if ( num_msgs > 0 ) { for (i = 0; i < num_msgs; i ++) octstr_destroy(msgs[i]); gw_free(msgs); num_msgs = 0; } /* we want either the file pointer or timer */ FD_SET(fileno(fp), &rset); /* get the largest file descriptor */ maxfd = fileno(fp) + 1; /* set timer to go off in 3 seconds */ alarm.tv_sec = IN_TIMEOUT; alarm.tv_usec = 0; if (select(maxfd, &rset, NULL, NULL, &alarm) == -1) goto over; /* something went off, let's see if it's stdin */ if (FD_ISSET(fileno(fp), &rset)) { /* stdin is readable */ cptr = fgets(buffer, IN_BUFSIZE, stdin); if (!cptr) goto over; if( strlen( cptr ) < 2 ) goto rcv; } else { /* timer kicked in */ goto rcv; } num_msgs = 1; msgs = gw_malloc(sizeof(Octstr*)); msgs[0] = octstr_create(cptr); } /* if we still have something to send as MO message */ if (num_sent < max_send) { Octstr *os = choose_message(msgs, num_msgs); Octstr *msg = rnd > 0 ? randomize(os) : os; if (conn_write(server, msg) == -1) panic(0, "write failed"); ++num_sent; if (num_sent == max_send) info(0, "fakesmsc: sent message %ld", num_sent); else debug("send", 0, "fakesmsc: sent message %ld", num_sent); if (rnd > 0) octstr_destroy(msg); last_sent_at = get_current_time(); if (first_sent_at == 0) first_sent_at = last_sent_at; } rcv: do { delta = interval * num_sent - (get_current_time() - first_sent_at); if (delta < 0) delta = 0; if (num_sent >= max_send) delta = -1; conn_wait(server, delta); if (conn_error(server) || conn_eof(server) || sigint_received) goto over; /* read as much as the smsc module provides us */ while ((line = conn_read_line(server))) { last_received_at = get_current_time(); if (first_received_at == 0) first_received_at = last_received_at; ++num_received; if (num_received == max_send) { info(0, "Got message %ld: <%s>", num_received, octstr_get_cstr(line)); } else { debug("receive", 0, "Got message %ld: <%s>", num_received, octstr_get_cstr(line)); } octstr_destroy(line); } } while (delta > 0 || num_sent >= max_send); } over: conn_destroy(server); /* destroy the MO messages */ for (i = 0; i < num_msgs; i ++) octstr_destroy(msgs[i]); gw_free(msgs); end_time = get_current_time(); info(0, "fakesmsc: %ld messages sent and %ld received", num_sent, num_received); info(0, "fakesmsc: total running time %.1f seconds", end_time - start_time); delta = last_sent_at - first_sent_at; if (delta == 0) delta = .01; if (num_sent > 1) info(0, "fakesmsc: from first to last sent message %.1f s, " "%.1f msgs/s", delta, (num_sent - 1) / delta); delta = last_received_at - first_received_at; if (delta == 0) delta = .01; if (num_received > 1) info(0, "fakesmsc: from first to last received message %.1f s, " "%.1f msgs/s", delta, (num_received - 1) / delta); info(0, "fakesmsc: terminating"); return 0; } gateway-1.4.5/test/test_dbpool.c0000644000175000017500000004503413227613126015336 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_dbpool.c - test DBPool objects * * Stipe Tolj * Alexander Malysh */ #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #ifdef HAVE_DBPOOL #define MAX_THREADS 1024 static void help(void) { info(0, "Usage: test_dbpool [options] ..."); info(0, "where options are:"); info(0, "-v number"); info(0, " set log level for stderr logging"); info(0, "-h hostname"); info(0, " hostname to connect to"); info(0, "-u username"); info(0, " username to use for the login credentials"); info(0, "-p password"); info(0, " password to use for the login credentials"); info(0, "-d database"); info(0, " database to connect to (for oracle tnsname) or file to open (for sqlite)"); info(0, "-s number"); info(0, " size of the database connection pool (default: 5)"); info(0, "-q number"); info(0, " run a set of queries on the database connection pool (default: 100)"); info(0, "-t number"); info(0, " how many query client threads should be used (default: 1)"); info(0, "-S string"); info(0, " the SQL string that is performed while the queries (default: SHOW STATUS)"); info(0, "-T type"); info(0, " the type of database to use [mysql|oracle|sqlite|cassandra]"); } /* global variables */ static unsigned long queries = 100; static Octstr *sql; static unsigned int pool_size = 5; static enum db_type database_type = DBPOOL_MYSQL; static void (*client_thread)(void*) = NULL; #ifdef HAVE_MYSQL static void mysql_client_thread(void *arg) { unsigned long i, succeeded, failed; DBPool *pool = arg; List *result; DBPoolConn *pconn; succeeded = failed = 0; info(0,"Client thread started with %ld queries to perform on pool", queries); for (i = 1; i <= queries; i++) { pconn = dbpool_conn_consume(pool); if (pconn == NULL) continue; #if 1 /* selects */ if (dbpool_conn_select(pconn, sql, NULL, &result) == 0) { long i,j; for (i=0; i < gwlist_len(result); i++) { List *row = gwlist_get(result, i); for (j=0; j < gwlist_len(row); j++) debug("", 0, "col = %ld value = '%s'", j, octstr_get_cstr(gwlist_get(row,j))); gwlist_destroy(row, octstr_destroy_item); } succeeded++; } else { failed++; } gwlist_destroy(result, NULL); dbpool_conn_produce(pconn); #else /* only updates */ debug("", 0, "rows processed = %d ", dbpool_conn_update(pconn, sql, NULL)); dbpool_conn_produce(pconn); #endif } info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed); } static DBConf *mysql_create_conf(Octstr *user, Octstr *pass, Octstr *db, Octstr *host) { DBConf *conf; conf = gw_malloc(sizeof(DBConf)); conf->mysql = gw_malloc(sizeof(MySQLConf)); conf->mysql->username = octstr_duplicate(user); conf->mysql->password = octstr_duplicate(pass); conf->mysql->database = octstr_duplicate(db); conf->mysql->host = octstr_duplicate(host); conf->mysql->port = 3306; return conf; } #endif #ifdef HAVE_ORACLE #include static DBConf *oracle_create_conf(Octstr *user,Octstr *pass, Octstr *db) { DBConf *conf; conf = gw_malloc(sizeof(DBConf)); conf->oracle = gw_malloc(sizeof(OracleConf)); conf->oracle->username = octstr_duplicate(user); conf->oracle->password = octstr_duplicate(pass); conf->oracle->tnsname = octstr_duplicate(db); return conf; } struct ora_conn { /* environment handle */ OCIEnv *envp; /* context handle */ OCISvcCtx *svchp; /* error handle */ OCIError *errhp; }; static void oracle_client_thread(void *arg) { DBPool *pool = arg; DBPoolConn *pconn = NULL; int i; List *result; for (i = 1; i <= queries; i++) { pconn = dbpool_conn_consume(pool); if (pconn == NULL) continue; #if 1 /* selects */ if (dbpool_conn_select(pconn, sql, NULL, &result) == 0) { long i,j; for (i=0; i < gwlist_len(result); i++) { List *row = gwlist_get(result, i); for (j=0; j < gwlist_len(row); j++) debug("", 0, "col = %ld value = '%s'", j, octstr_get_cstr(gwlist_get(row,j))); gwlist_destroy(row, octstr_destroy_item); } } gwlist_destroy(result, NULL); dbpool_conn_produce(pconn); #else /* only updates */ debug("", 0, "rows processed = %d ", dbpool_conn_update(pconn, sql, NULL)); dbpool_conn_produce(pconn); #endif } } #endif #ifdef HAVE_SQLITE #include static DBConf *sqlite_create_conf(Octstr *db) { DBConf *conf; conf = gw_malloc(sizeof(DBConf)); conf->sqlite = gw_malloc(sizeof(SQLiteConf)); conf->sqlite->file = octstr_duplicate(db); return conf; } static int callback(void *not_used, int argc, char **argv, char **col_name) { int i; for (i = 0; i < argc; i++) { debug("",0,"SQLite: result: %s = %s", col_name[i], argv[i]); } return 0; } static void sqlite_client_thread(void *arg) { unsigned long i, succeeded, failed; DBPool *pool = arg; char *errmsg = 0; succeeded = failed = 0; info(0,"Client thread started with %ld queries to perform on pool", queries); /* perform random queries on the pool */ for (i = 1; i <= queries; i++) { DBPoolConn *pconn; int state; /* provide us with a connection from the pool */ pconn = dbpool_conn_consume(pool); debug("",0,"Query %ld/%ld: sqlite conn obj at %p", i, queries, (void*) pconn->conn); state = sqlite_exec(pconn->conn, octstr_get_cstr(sql), callback, 0, &errmsg); if (state != SQLITE_OK) { error(0, "SQLite: %s", errmsg); failed++; } else { succeeded++; } /* return the connection to the pool */ dbpool_conn_produce(pconn); } info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed); } #endif #ifdef HAVE_SQLITE3 #include static DBConf *sqlite3_create_conf(Octstr *db) { DBConf *conf; conf = gw_malloc(sizeof(DBConf)); conf->sqlite3 = gw_malloc(sizeof(SQLite3Conf)); conf->sqlite3->file = octstr_duplicate(db); return conf; } static int callback3(void *not_used, int argc, char **argv, char **col_name) { int i; for (i = 0; i < argc; i++) { debug("",0,"SQLite3: result: %s = %s", col_name[i], argv[i]); } return 0; } static void sqlite3_client_thread(void *arg) { unsigned long i, succeeded, failed; DBPool *pool = arg; char *errmsg = 0; succeeded = failed = 0; info(0,"Client thread started with %ld queries to perform on pool", queries); /* perform random queries on the pool */ for (i = 1; i <= queries; i++) { DBPoolConn *pconn; int state; /* provide us with a connection from the pool */ pconn = dbpool_conn_consume(pool); debug("",0,"Query %ld/%ld: sqlite conn obj at %p", i, queries, (void*) pconn->conn); state = sqlite3_exec(pconn->conn, octstr_get_cstr(sql), callback3, 0, &errmsg); if (state != SQLITE_OK) { error(0, "SQLite3: %s", errmsg); failed++; } else { succeeded++; } /* return the connection to the pool */ dbpool_conn_produce(pconn); } info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed); } #endif #ifdef HAVE_CASS static void cass_client_thread(void *arg) { unsigned long i, succeeded, failed; DBPool *pool = arg; List *result; DBPoolConn *pconn; succeeded = failed = 0; info(0,"Client thread started with %ld queries to perform on pool", queries); for (i = 1; i <= queries; i++) { pconn = dbpool_conn_consume(pool); if (pconn == NULL) continue; #if 1 /* selects */ if (dbpool_conn_select(pconn, sql, NULL, &result) == 0) { long i,j; for (i=0; i < gwlist_len(result); i++) { List *row = gwlist_get(result, i); for (j=0; j < gwlist_len(row); j++) debug("", 0, "col = %ld value = '%s'", j, octstr_get_cstr(gwlist_get(row,j))); gwlist_destroy(row, octstr_destroy_item); } succeeded++; } else { failed++; } gwlist_destroy(result, NULL); dbpool_conn_produce(pconn); #else /* only updates */ debug("", 0, "rows processed = %d ", dbpool_conn_update(pconn, sql, NULL)); dbpool_conn_produce(pconn); #endif } info(0, "This thread: %ld succeeded, %ld failed.", succeeded, failed); } static DBConf *cass_create_conf(Octstr *user, Octstr *pass, Octstr *db, Octstr *host) { DBConf *conf; conf = gw_malloc(sizeof(DBConf)); conf->cass = gw_malloc(sizeof(CassConf)); conf->cass->username = octstr_duplicate(user); conf->cass->password = octstr_duplicate(pass); conf->cass->database = octstr_duplicate(db); conf->cass->host = octstr_duplicate(host); return conf; } #endif static void inc_dec_thread(void *arg) { DBPool *pool = arg; int ret; /* decrease */ info(0,"Decreasing pool by half of size, which is %d connections", abs(pool_size/2)); ret = dbpool_decrease(pool, abs(pool_size/2)); debug("",0,"Decreased by %d connections", ret); debug("",0,"Connections within pool: %ld", dbpool_conn_count(pool)); /* increase */ info(0,"Increasing pool again by %d connections", pool_size); ret = dbpool_increase(pool, pool_size); debug("",0,"Increased by %d connections", ret); debug("",0,"Connections within pool: %ld", dbpool_conn_count(pool)); } int main(int argc, char **argv) { DBPool *pool; DBConf *conf = NULL; /* for compiler please */ unsigned int num_threads = 1; unsigned long i; int opt; time_t start = 0, end = 0; double run_time; Octstr *user, *pass, *db, *host, *db_type; int j, bail_out; user = pass = db = host = db_type = NULL; gwlib_init(); sql = octstr_imm("SHOW STATUS"); while ((opt = getopt(argc, argv, "v:h:u:p:d:s:q:t:S:T:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'h': host = octstr_create(optarg); break; case 'u': user = octstr_create(optarg); break; case 'p': pass = octstr_create(optarg); break; case 'd': db = octstr_create(optarg); break; case 'S': octstr_destroy(sql); sql = octstr_create(optarg); break; case 's': pool_size = atoi(optarg); break; case 'q': queries = atoi(optarg); break; case 't': num_threads = atoi(optarg); break; case 'T': db_type = octstr_create(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (!optind) { help(); exit(0); } if (!db_type) { info(0, "No database type given assuming MySQL."); } else if (octstr_case_compare(db_type, octstr_imm("mysql")) == 0) { info(0, "Do tests for mysql database."); database_type = DBPOOL_MYSQL; } else if (octstr_case_compare(db_type, octstr_imm("oracle")) == 0) { info(0, "Do tests for oracle database."); database_type = DBPOOL_ORACLE; } else if (octstr_case_compare(db_type, octstr_imm("sqlite")) == 0) { info(0, "Do tests for sqlite database."); database_type = DBPOOL_SQLITE; } else if (octstr_case_compare(db_type, octstr_imm("sqlite3")) == 0) { info(0, "Do tests for sqlite3 database."); database_type = DBPOOL_SQLITE3; } else if (octstr_case_compare(db_type, octstr_imm("cassandra")) == 0) { info(0, "Do tests for cassandra database."); database_type = DBPOOL_CASS; } else { panic(0, "Unknown database type '%s'", octstr_get_cstr(db_type)); } /* check if we have the database connection details */ switch (database_type) { case DBPOOL_ORACLE: bail_out = (!user || !pass || !db) ? 1 : 0; break; case DBPOOL_SQLITE: case DBPOOL_SQLITE3: bail_out = (!db) ? 1 : 0; break; case DBPOOL_CASS: bail_out = (!host || !db) ? 1 : 0; break; default: bail_out = (!host || !user || !pass || !db) ? 1 : 0; break; } if (bail_out) { help(); panic(0, "Database connection details are not fully provided!"); } for (j = 0; j < 1; j++) { /* create DBConf */ switch (database_type) { #ifdef HAVE_MYSQL case DBPOOL_MYSQL: conf = mysql_create_conf(user,pass,db,host); client_thread = mysql_client_thread; break; #endif #ifdef HAVE_ORACLE case DBPOOL_ORACLE: conf = oracle_create_conf(user, pass, db); client_thread = oracle_client_thread; break; #endif #ifdef HAVE_SQLITE case DBPOOL_SQLITE: conf = sqlite_create_conf(db); client_thread = sqlite_client_thread; break; #endif #ifdef HAVE_SQLITE3 case DBPOOL_SQLITE3: conf = sqlite3_create_conf(db); client_thread = sqlite3_client_thread; break; #endif #ifdef HAVE_CASS case DBPOOL_CASS: conf = cass_create_conf(user,pass,db,host); client_thread = cass_client_thread; break; #endif default: panic(0, "ooops ...."); }; /* create */ info(0,"Creating database pool to `%s' with %d connections type '%s'.", (host ? octstr_get_cstr(host) : octstr_get_cstr(db)), pool_size, octstr_get_cstr(db_type)); pool = dbpool_create(database_type, conf, pool_size); debug("",0,"Connections within pool: %ld", dbpool_conn_count(pool)); if (dbpool_conn_count(pool) == 0) { panic(0, "Unable to start without DBConns..."); exit(1); } for (i = 0; i < num_threads; ++i) { if (gwthread_create(inc_dec_thread, pool) == -1) panic(0, "Could not create thread %ld", i); } gwthread_join_all(); info(0, "Connections within pool: %ld", dbpool_conn_count(pool)); info(0, "Checked pool, %d connections still active and ok", dbpool_check(pool)); /* queries */ info(0,"SQL query is `%s'", octstr_get_cstr(sql)); time(&start); for (i = 0; i < num_threads; ++i) { #if 0 if (gwthread_create(inc_dec_thread, pool) == -1) panic(0, "Couldnot create thread %ld", i); #endif if (gwthread_create(client_thread, pool) == -1) panic(0, "Couldnot create thread %ld", i); } gwthread_join_all(); time(&end); run_time = difftime(end, start); info(0, "%ld requests in %.2f seconds, %.2f requests/s.", (queries * num_threads), run_time, (float) (queries * num_threads) / (run_time==0?1:run_time)); /* check all active connections */ debug("",0,"Connections within pool: %ld", dbpool_conn_count(pool)); info(0,"Checked pool, %d connections still active and ok", dbpool_check(pool)); info(0,"Destroying pool"); dbpool_destroy(pool); } /* for loop */ octstr_destroy(sql); octstr_destroy(db_type); octstr_destroy(user); octstr_destroy(pass); octstr_destroy(db); octstr_destroy(host); gwlib_shutdown(); return 0; } #endif /* HAVE_DBPOOL */ gateway-1.4.5/test/test_octstr_dump.c0000644000175000017500000001045213227613126016416 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_octstr_dump.c - reads a file and performs dumping. * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" int main(int argc, char **argv) { Octstr *data, *filename, *hex; gwlib_init(); get_and_set_debugs(argc, argv, NULL); if (argc < 2) panic(0, "Syntax: %s \n", argv[0]); filename = octstr_create(argv[1]); data = octstr_read_file(octstr_get_cstr(filename)); if (data == NULL) panic(0, "Cannot read file."); /* * We test if this is a text/plain file with hex values in it. * Therefore copy the data and trail off any CR and LF from * beginning and end and test if the result is only hex chars. * If yes, then convert to binary before dumping. */ hex = octstr_duplicate(data); octstr_strip_crlfs(hex); if (octstr_is_all_hex(hex)) { debug("",0,"Trying to converting from hex to binary."); if (octstr_hex_to_binary(hex) == 0) { FILE *f = fopen(argv[2], "w"); debug("",0,"Convertion was successfull. Writing binary content to file `%s'", argv[2]); octstr_destroy(data); data = octstr_duplicate(hex); octstr_print(f, data); fclose(f); } else { debug("",0,"Failed to convert from hex?!"); } } debug("",0,"Dumping file `%s':", octstr_get_cstr(filename)); octstr_dump(data, 0); octstr_destroy(data); octstr_destroy(hex); gwlib_shutdown(); return 0; } gateway-1.4.5/test/wapproxy.c0000644000175000017500000005517513227613126014720 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wapproxy.c - an WDP, WSP, WTP layer proxy * * This module contains the main program for the WAP proxy box. * It's intention is to sit between a WTP initiator and WTP repsonder * and log all the UDP traffic that is send in a session. * * The architecture looks like this: * * ---------- UDP -------- UDP ------ * wap device ---> wapproxy ---> wap gw * ---------- <--- -------- <--- ------ * port 51000 p 9201 p 51000 port 9201 * (a) (b) * * This means wapproxy gets the UDP/WDP packets that are actually to * be transmitted to the real wap gw. It changes the source addr within * that packet to reflect wapproxy has send it and binds to the port the * wap device was sending the packet. Then the packet is send to the real * wap gw and wapproxy listens on the client source port (i.e. 51000) for * packets from the wap gw. When those are received the communication is * inverted, which means wapproxy changes again the source addr from the * value of wap gw to it's own and forwards the packet to the client source * addr port. * * Hence the wap device uses wapproxy transparently without knowing that * it is only a proxy and the packets are forwarded to other boxes. * * Stipe Tolj */ #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "msg.h" //#include "bearerbox.h" #include "shared.h" #include "wap/wap.h" #include "wap/wtp.h" #include "wap/wtp_pdu.h" /* globals */ static volatile sig_atomic_t udp_running; static List *udpc_list; static Octstr *interface_name = NULL; static Octstr *wapgw; static int verbose = 0; static int server_port = 0; List *incoming_wdp; List *outgoing_wdp; List *flow_threads; Counter *incoming_wdp_counter; Counter *outgoing_wdp_counter; enum { CONNECTIONLESS_PORT = 9200, CONNECTION_ORIENTED_PORT = 9201, WTLS_CONNECTIONLESS_PORT = 9202, WTLS_CONNECTION_ORIENTED_PORT = 9203 }; /* structure for a UDP connection */ typedef struct _udpc { int fd; Octstr *addr; Octstr *map_addr; List *outgoing_list; long receiver; } Udpc; /* forward declarations */ static void udpc_destroy(Udpc *udpc); /*------------------------------------------------------------- * analyze and dump functions * */ static WAPEvent *wdp_msg2event(Msg *msg) { WAPEvent *dgram = NULL; gw_assert(msg_type(msg) == wdp_datagram); if (msg->wdp_datagram.destination_port == server_port || msg->wdp_datagram.source_port == server_port || msg->wdp_datagram.destination_port == CONNECTION_ORIENTED_PORT || msg->wdp_datagram.source_port == CONNECTION_ORIENTED_PORT) { dgram = wap_event_create(T_DUnitdata_Ind); dgram->u.T_DUnitdata_Ind.addr_tuple = wap_addr_tuple_create( msg->wdp_datagram.source_address, msg->wdp_datagram.source_port, msg->wdp_datagram.destination_address, msg->wdp_datagram.destination_port); dgram->u.T_DUnitdata_Ind.user_data = octstr_duplicate(msg->wdp_datagram.user_data); } return dgram; } static void wdp_event_dump(Msg *msg) { WAPEvent *dgram; if ((dgram = wdp_msg2event(msg)) != NULL) /* wap_dispatch_datagram(dgram); */ wap_event_dump(dgram); wap_event_destroy(dgram); } static void wtp_event_dump(Msg *msg) { WAPEvent *dgram; List *events; long i, n; dgram = wdp_msg2event(msg); if (dgram == NULL) error(0, "dgram is null"); /* pdu = wtp_pdu_unpack(dgram->u.T_DUnitdata_Ind.user_data); if (pdu == NULL) { error(0, "WTP PDU unpacking failed, WAP event is:"); wap_event_dump(dgram); } else { wtp_pdu_dump(pdu, 0); wtp_pdu_destroy(pdu); } */ events = wtp_unpack_wdp_datagram(dgram); n = gwlist_len(events); debug("wap.proxy",0,"datagram contains %ld events", n); i = 1; while (gwlist_len(events) > 0) { WAPEvent *event; event = gwlist_extract_first(events); info(0, "WTP: %ld/%ld event %s.", i, n, wap_event_name(event->type)); if (wtp_event_is_for_responder(event)) /* wtp_resp_dispatch_event(event); */ debug("",0,"datagram is for WTP responder"); else /* wtp_initiator_dispatch_event(event); */ debug("",0,"datagram is for WTP initiator"); wap_event_dump(event); /* switch (event->type) { RcvInvoke: debug("",0,"XXX invoke"); break; RcvResult: debug("",0,"XXX result"); break; default: error(0,"unkown WTP event type while unpacking"); break; } */ i++; } wap_event_destroy(dgram); gwlist_destroy(events, NULL); } static void dump(Msg *msg) { switch (verbose) { case 0: break; case 1: msg_dump(msg, 0); break; case 2: wdp_event_dump(msg); break; case 3: msg_dump(msg, 0); wdp_event_dump(msg); break; case 4: wtp_event_dump(msg); break; case 5: msg_dump(msg, 0); wtp_event_dump(msg); break; case 6: wdp_event_dump(msg); wtp_event_dump(msg); break; case 7: msg_dump(msg, 0); wdp_event_dump(msg); wtp_event_dump(msg); break; } } /*------------------------------------------------- * receiver thread */ static void udp_receiver(void *arg) { Octstr *datagram, *cliaddr; int ret; Msg *msg; Udpc *conn = arg; Octstr *ip; gwlist_add_producer(incoming_wdp); gwlist_add_producer(flow_threads); gwthread_wakeup(MAIN_THREAD_ID); /* remove messages from socket until it is closed */ while (1) { if (read_available(conn->fd, 100000) < 1) continue; ret = udp_recvfrom(conn->fd, &datagram, &cliaddr); if (ret == -1) { if (errno == EAGAIN) /* No datagram available, don't block. */ continue; error(errno, "Failed to receive an UDP"); continue; } ip = udp_get_ip(cliaddr); msg = msg_create(wdp_datagram); msg->wdp_datagram.source_address = udp_get_ip(cliaddr); msg->wdp_datagram.source_port = udp_get_port(cliaddr); msg->wdp_datagram.destination_address = udp_get_ip(conn->addr); msg->wdp_datagram.destination_port = udp_get_port(conn->addr); msg->wdp_datagram.user_data = datagram; info(0, "datagram received <%s:%d> -> <%s:%d>", octstr_get_cstr(udp_get_ip(cliaddr)), udp_get_port(cliaddr), octstr_get_cstr(udp_get_ip(conn->addr)), udp_get_port(conn->addr)); dump(msg); /* * Descide if this is (a) or (b) UDP packet and add them to the * corresponding queues */ if (octstr_compare(conn->addr, conn->map_addr) == 0) { gwlist_produce(incoming_wdp, msg); counter_increase(incoming_wdp_counter); } else { gwlist_produce(outgoing_wdp, msg); counter_increase(outgoing_wdp_counter); } octstr_destroy(cliaddr); octstr_destroy(ip); } gwlist_remove_producer(incoming_wdp); gwlist_remove_producer(flow_threads); } /*--------------------------------------------- * sender thread */ static int send_udp(int fd, Msg *msg) { Octstr *cliaddr; int ret; cliaddr = udp_create_address(msg->wdp_datagram.destination_address, msg->wdp_datagram.destination_port); ret = udp_sendto(fd, msg->wdp_datagram.user_data, cliaddr); if (ret == -1) error(0, "could not send UDP datagram"); octstr_destroy(cliaddr); return ret; } static void udp_sender(void *arg) { Msg *msg; Udpc *conn = arg; gwlist_add_producer(flow_threads); while (1) { if ((msg = gwlist_consume(conn->outgoing_list)) == NULL) break; info(0, "sending datagram <%s:%ld> -> <%s:%ld>", octstr_get_cstr(msg->wdp_datagram.source_address), msg->wdp_datagram.source_port, octstr_get_cstr(msg->wdp_datagram.destination_address), msg->wdp_datagram.destination_port); dump(msg); if (send_udp(conn->fd, msg) == -1) { msg_destroy(msg); continue; } counter_increase(outgoing_wdp_counter); msg_destroy(msg); } gwthread_join(conn->receiver); udpc_destroy(conn); gwlist_remove_producer(flow_threads); } /*--------------------------------------------------------------- * create UDP connection */ static Udpc *udpc_create(int port, char *interface_name, Octstr *map_addr) { Udpc *udpc; Octstr *os; int fl; udpc = gw_malloc(sizeof(Udpc)); udpc->fd = udp_bind(port, interface_name); os = octstr_create(interface_name); udpc->addr = udp_create_address(os, port); udpc->map_addr = map_addr ? map_addr : udpc->addr; octstr_destroy(os); if (udpc->addr == NULL) { error(0, "updc_create: could not resolve interface <%s>", interface_name); close(udpc->fd); gw_free(udpc); return NULL; } fl = fcntl(udpc->fd, F_GETFL); fcntl(udpc->fd, F_SETFL, fl | O_NONBLOCK); os = udp_get_ip(udpc->addr); debug("wap.proxy",0, "bound to UDP <%s:%d>", octstr_get_cstr(os), udp_get_port(udpc->addr)); octstr_destroy(os); udpc->outgoing_list = gwlist_create(); return udpc; } static void udpc_destroy(Udpc *udpc) { if (udpc == NULL) return; if (udpc->fd >= 0) close(udpc->fd); octstr_destroy(udpc->addr); gw_assert(gwlist_len(udpc->outgoing_list) == 0); gwlist_destroy(udpc->outgoing_list, NULL); gw_free(udpc); } static int add_service(int port, char *interface_name, Octstr *map_addr) { Udpc *udpc; if ((udpc = udpc_create(port, interface_name, map_addr)) == NULL) goto error; gwlist_add_producer(udpc->outgoing_list); udpc->receiver = gwthread_create(udp_receiver, udpc); if (udpc->receiver == -1) goto error; if (gwthread_create(udp_sender, udpc) == -1) goto error; gwlist_append(udpc_list, udpc); return 0; error: error(0, "Failed to start UDP receiver/sender thread"); udpc_destroy(udpc); return -1; } /*------------------------------------------------------------- * main calling functions * */ static int udp_start(Cfg *cfg) { if (udp_running) return -1; debug("wap.proxy", 0, "starting UDP sender/receiver module"); udpc_list = gwlist_create(); /* have a list of running systems */ add_service(server_port, octstr_get_cstr(interface_name), NULL); /* wsp/wtp */ gwlist_add_producer(incoming_wdp); udp_running = 1; return 0; } static Udpc *udpc_find_mapping(Msg *msg, int inbound) { int i; Udpc *udpc; Octstr *addr; /* check if there is allready a bound UDP port */ gwlist_lock(udpc_list); for (i=0; i < gwlist_len(udpc_list); i++) { udpc = gwlist_get(udpc_list, i); /* decide if we compare against inbound or outbound traffic mapping */ addr = inbound ? udpc->map_addr : udpc->addr; if (msg->wdp_datagram.source_port == udp_get_port(addr) && octstr_compare(msg->wdp_datagram.source_address, udp_get_ip(addr)) == 0) { gwlist_unlock(udpc_list); return udpc; } } gwlist_unlock(udpc_list); return NULL; } /* * this function receives an WDP message and adds it to * corresponding outgoing_list. */ static int udp_addwdp_from_server(Msg *msg) { Udpc *udpc; Octstr *os; Octstr *source; if (!udp_running) return -1; assert(msg != NULL); assert(msg_type(msg) == wdp_datagram); octstr_destroy(msg->wdp_datagram.source_address); msg->wdp_datagram.source_address = octstr_create(octstr_get_cstr(msg->wdp_datagram.destination_address)); msg->wdp_datagram.source_port = msg->wdp_datagram.destination_port; if ((udpc = udpc_find_mapping(msg, 0)) == NULL) /* there should have been one */ panic(0,"Could not find UDP mapping, internal error"); /* insert the found mapped destination */ octstr_destroy(msg->wdp_datagram.source_address); octstr_destroy(msg->wdp_datagram.destination_address); msg->wdp_datagram.destination_address = udp_get_ip(udpc->map_addr); msg->wdp_datagram.destination_port = udp_get_port(udpc->map_addr); /* now search for our inbound UDP socket */ os = octstr_duplicate(interface_name); source = udp_create_address(os, server_port); msg->wdp_datagram.source_address = udp_get_ip(source); msg->wdp_datagram.source_port = udp_get_port(source); if ((udpc = udpc_find_mapping(msg, 0)) == NULL) panic(0,"Could not find main inbound UDP socket, internal error"); /* * ok, got the destination, got the socket, * now put it on the outbound queue */ gwlist_produce(udpc->outgoing_list, msg); octstr_destroy(os); return 0; } /* * this function receives an WDP message and checks if a UDP * service for this client has to be created */ static int udp_addwdp_from_client(Msg *msg) { Udpc *udpc; Octstr *map_addr; Octstr *os; Octstr *source; if (!udp_running) return -1; assert(msg != NULL); assert(msg_type(msg) == wdp_datagram); /* * Check if there is allready a bound UDP port for this mapping. * If not create a mapping and bind the mapped UDP port * The mapped port is simply 2x of the client port. */ if ((udpc = udpc_find_mapping(msg, 1)) == NULL) { info(0, "Creating UDP mapping <%s:%ld> <-> <%s:%ld>", octstr_get_cstr(msg->wdp_datagram.source_address), msg->wdp_datagram.source_port, octstr_get_cstr(msg->wdp_datagram.destination_address), msg->wdp_datagram.source_port*2); map_addr = udp_create_address(msg->wdp_datagram.source_address, msg->wdp_datagram.source_port); add_service(msg->wdp_datagram.source_port * 2, octstr_get_cstr(interface_name), map_addr); /* now we should find it in the udpc_list */ if ((udpc = udpc_find_mapping(msg, 1)) == NULL) panic(0,"Could not find UDP mapping, internal error"); } /* now swap the message addressing */ octstr_destroy(msg->wdp_datagram.source_address); octstr_destroy(msg->wdp_datagram.destination_address); os = octstr_duplicate(interface_name); source = udp_create_address(os, msg->wdp_datagram.source_port * 2); msg->wdp_datagram.source_address = udp_get_ip(source); msg->wdp_datagram.source_port = udp_get_port(source); msg->wdp_datagram.destination_address = octstr_duplicate(wapgw); msg->wdp_datagram.destination_port = CONNECTION_ORIENTED_PORT; octstr_destroy(os); gwlist_produce(udpc->outgoing_list, msg); return -1; } static int udp_shutdown(void) { if (!udp_running) return -1; debug("bb.thread", 0, "udp_shutdown: Starting avalanche"); gwlist_remove_producer(incoming_wdp); return 0; } static int udp_die(void) { Udpc *udpc; if (!udp_running) return -1; /* * remove producers from all outgoing lists. */ debug("bb.udp", 0, "udp_die: removing producers from udp-lists"); while ((udpc = gwlist_consume(udpc_list)) != NULL) { gwlist_remove_producer(udpc->outgoing_list); } gwlist_destroy(udpc_list, NULL); udp_running = 0; return 0; } /*------------------------------------------------------------- * main consumer threads * */ static void wdp_router(void *arg) { Msg *msg; gwlist_add_producer(flow_threads); while (1) { if ((msg = gwlist_consume(outgoing_wdp)) == NULL) break; gw_assert(msg_type(msg) == wdp_datagram); udp_addwdp_from_server(msg); } udp_die(); gwlist_remove_producer(flow_threads); } static void service_router(void *arg) { Msg *msg; gwlist_add_producer(flow_threads); while (1) { if ((msg = gwlist_consume(incoming_wdp)) == NULL) break; gw_assert(msg_type(msg) == wdp_datagram); udp_addwdp_from_client(msg); } udp_die(); gwlist_remove_producer(flow_threads); } /*------------------------------------------------------------- * main functions * */ static void help(void) { info(0, "Usage: wapproxy [options] host ..."); info(0, "where host is the real wap gw to forward to and options are:"); info(0, "-v number"); info(0, " set log level for stderr logging"); info(0, "-i interface"); info(0, " bind to the given interface for UDP server port (default: 0.0.0.0)"); info(0, "-p port"); info(0, " bind to the given port for UDP server port (default: 9201)"); info(0, "-m"); info(0, " dump WDP/UDP packets, msg_dump()"); info(0, "-e"); info(0, " dump WAP event packets, wap_event_dump()"); info(0, "-t"); info(0, " dump WTP PDUs, wtp_pdu_dump()"); } int main(int argc, char **argv) { int opt; Cfg *cfg = NULL; gwlib_init(); server_port = CONNECTION_ORIENTED_PORT; while ((opt = getopt(argc, argv, "v:meti:p:")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'm': verbose += 1; break; case 'e': verbose += 2; break; case 't': verbose += 4; break; case 'h': help(); exit(0); case 'i': interface_name = octstr_create(optarg); break; case 'p': server_port = atoi(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (optind == argc) { help(); exit(0); } /* get the host or IP of the real wap gw to forward the WDP packets */ wapgw = octstr_create(argv[optind]); /* if no interface was given use 0.0.0.0 */ if (!interface_name) interface_name = octstr_create("*"); report_versions("wapproxy"); /* initialize main inbound and outbound queues */ outgoing_wdp = gwlist_create(); incoming_wdp = gwlist_create(); flow_threads = gwlist_create(); outgoing_wdp_counter = counter_create(); incoming_wdp_counter = counter_create(); /* start the main UDP listening threads */ udp_start(cfg); gwlist_add_producer(outgoing_wdp); debug("bb", 0, "starting WDP routers"); if (gwthread_create(service_router, NULL) == -1) panic(0, "Failed to start a new thread for inbound WDP routing"); if (gwthread_create(wdp_router, NULL) == -1) panic(0, "Failed to start a new thread for outbound WDP routing"); gwthread_sleep(5.0); /* give time to threads to register themselves */ while (gwlist_consume(flow_threads) != NULL) ; udp_shutdown(); gwlist_remove_producer(outgoing_wdp); gwlist_destroy(flow_threads, NULL); gwlist_destroy(incoming_wdp, NULL); gwlist_destroy(outgoing_wdp, NULL); counter_destroy(incoming_wdp_counter); counter_destroy(outgoing_wdp_counter); octstr_destroy(interface_name); octstr_destroy(wapgw); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_radius_pdu.c0000644000175000017500000001124413227613126016212 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_radius_pdu.c - test RADIUS PDU packing and unpacking. * * Stipe Tolj */ #include #include #include #include "gwlib/gwlib.h" #include "radius/radius_pdu.h" int main(int argc, char **argv) { Octstr *data, *filename, *rdata; RADIUS_PDU *pdu, *r; gwlib_init(); data = filename = rdata = NULL; get_and_set_debugs(argc, argv, NULL); if (argc <= 1) { debug("",0,"Usage: %s [filename containing raw RADIUS PDU]", argv[0]); goto error; } filename = octstr_create(argv[1]); if ((data = octstr_read_file(octstr_get_cstr(filename))) == NULL) goto error; debug("",0,"Calling radius_pdu_unpack() now"); pdu = radius_pdu_unpack(data); debug("",0,"PDU type code: %ld", pdu->u.Accounting_Request.code); debug("",0,"PDU identifier: %ld", pdu->u.Accounting_Request.identifier); debug("",0,"PDU length: %ld", pdu->u.Accounting_Request.length); octstr_dump_short(pdu->u.Accounting_Request.authenticator,0, "PDU authenticator"); /* XXX authenticator md5 check does not work?! */ /* radius_authenticate_pdu(pdu, data, octstr_imm("radius")); */ /* create response PDU */ r = radius_pdu_create(0x05, pdu); /* create response authenticator * code+identifier(req)+length+authenticator(req)+(attributes)+secret */ r->u.Accounting_Response.identifier = pdu->u.Accounting_Request.identifier; r->u.Accounting_Response.authenticator = octstr_duplicate(pdu->u.Accounting_Request.authenticator); rdata = radius_pdu_pack(r); /* creates response autenticator in encoded PDU */ radius_authenticate_pdu(r, &rdata, octstr_imm("radius")); octstr_dump_short(rdata, 0, "Encoded Response PDU"); debug("",0,"Destroying RADIUS_PDUs"); radius_pdu_destroy(pdu); radius_pdu_destroy(r); error: octstr_destroy(data); octstr_destroy(rdata); octstr_destroy(filename); gwlib_shutdown(); return 0; } gateway-1.4.5/test/testcase.wml0000644000175000017500000000213607255450135015207 0ustar toljtolj

This is a testing page with lots of tests.

Try picking one up:

Do not panic.

gateway-1.4.5/test/run-http2-tests.sh0000755000175000017500000000107407615000617016211 0ustar toljtolj#!/bin/sh # # Compare lynx -source output and test_http output on a number of URLs. # # Lars Wirzenius for url in `cat test/http-test-urls` do echo "Testing $url..." lynx -source "$url" > lynx.tmp test/test_http -s "$url" > http.tmp test/test_http -s "$url" > http2.tmp if diff -u lynx.tmp http.tmp >/dev/null && diff -u lynx.tmp http2.tmp > /dev/null then : else echo "Lynx and test_http disagree. Oops." echo "URL is <$url>." echo "See lynx.tmp and http2.tmp." exit 1 fi done echo "All tests passed. Very good." rm -f lynx.tmp http.tmp http2.tmp gateway-1.4.5/test/chartest.html0000644000175000017500000000336507014252375015362 0ustar toljtolj Character test

Raw: ! " # $ % ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; = ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ

Code: ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~   ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ

Trivial names: & < > gateway-1.4.5/test/test_list.c0000644000175000017500000000764113227613126015034 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_list.c - test List objects * * Stipe Tolj */ #include "gwlib/gwlib.h" #define HUGE_SIZE 20 static int my_sort_cmp(const void *a, const void *b) { const Octstr *fa = a; const Octstr *fb = b; return octstr_compare(fa, fb); } int main(void) { List *list; char id[UUID_STR_LEN + 1]; int i; gwlib_init(); debug("",0,"List performance test."); list = gwlist_create(); /* generate UUIDs and populate the list */ debug("", 0, "Creating %d UUIDs for the list.", HUGE_SIZE); for (i = 0; i < HUGE_SIZE; i++) { Octstr *os; uuid_t uid; uuid_generate(uid); uuid_unparse(uid, id); os = octstr_create(id); gwlist_append(list, os); uuid_clear(uid); } debug("",0,"Objects in the list: %ld", gwlist_len(list)); /* try to sort */ debug("",0,"Sorting."); gwlist_sort(list, my_sort_cmp); debug("",0,"Sorting done."); for (i = 0; i < HUGE_SIZE; i++) { Octstr *os = gwlist_get(list, i); debug("",0,"After sort: %s %d", octstr_get_cstr(os), i); } gwlist_destroy(list, octstr_destroy_item); gwlib_shutdown(); return 0; } gateway-1.4.5/test/test_udp.c0000644000175000017500000001054013227613126014641 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_udp.c - program to test UDP packet functions * * This program implements a simple ping-pong server. * * Lars Wirzenius */ #include "gwlib/gwlib.h" #include static char usage[] = "\ Usage: test_udp client server_port\n\ test_udp server server_port\n\ "; #define PING "ping" #define PONG "pong" #define TIMES 10 static void client(int port) { int i, s; Octstr *ping, *pong, *addr, *from; s = udp_client_socket(); ping = octstr_create(PING); addr = udp_create_address(octstr_create("localhost"), port); if (s == -1 || addr == NULL) panic(0, "Couldn't set up client socket."); for (i = 0; i < TIMES; ++i) { if (udp_sendto(s, ping, addr) == -1) panic(0, "Couldn't send ping."); if (udp_recvfrom(s, &pong, &from) == -1) panic(0, "Couldn't receive pong"); info(0, "Got <%s> from <%s:%d>", octstr_get_cstr(pong), octstr_get_cstr(udp_get_ip(from)), udp_get_port(from)); } } static void server(int port) { int i, s; Octstr *ping, *pong, *from; s = udp_bind(port,"0.0.0.0"); pong = octstr_create(PONG); if (s == -1) panic(0, "Couldn't set up client socket."); for (i = 0; i < TIMES; ++i) { if (udp_recvfrom(s, &ping, &from) == -1) panic(0, "Couldn't receive ping"); info(0, "Got <%s> from <%s:%d>", octstr_get_cstr(ping), octstr_get_cstr(udp_get_ip(from)), udp_get_port(from)); if (udp_sendto(s, pong, from) == -1) panic(0, "Couldn't send pong."); } } int main(int argc, char **argv) { int port; gwlib_init(); if (argc != 3) panic(0, "Bad argument list\n%s", usage); port = atoi(argv[2]); if (strcmp(argv[1], "client") == 0) client(port); else server(port); return 0; } gateway-1.4.5/test/iptestppg.txt0000644000175000017500000000107710360454102015423 0ustar toljtolj

gateway-1.4.5/test/test_date.c0000644000175000017500000001032013227613126014762 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #include #include #include #include "gwlib/gwlib.h" int main(int argc, char **argv) { Octstr *s; struct universaltime ut; gwlib_init(); get_and_set_debugs(argc, argv, NULL); s = octstr_create("2009-02-10T10:02:03"); if (date_parse_iso(&ut, s) == -1) { panic(0, "date_parse_iso failed: %s", octstr_get_cstr(s)); } info(0, "%s : %04ld-%02ld-%02ldT%02ld:%02ld:%02ld", octstr_get_cstr(s), ut.year, ut.month+1, ut.day, ut.hour, ut.minute, ut.second); octstr_destroy(s); s = octstr_create("2009-02-10"); if (date_parse_iso(&ut, s) == -1) { panic(0, "date_parse_iso failed: %s", octstr_get_cstr(s)); } info(0, "%s : %04ld-%02ld-%02ldT%02ld:%02ld:%02ld", octstr_get_cstr(s), ut.year, ut.month+1, ut.day, ut.hour, ut.minute, ut.second); octstr_destroy(s); s = octstr_create("20090210T10:02:03"); if (date_parse_iso(&ut, s) == -1) { panic(0, "date_parse_iso failed: %s", octstr_get_cstr(s)); } info(0, "%s : %04ld%02ld%02ldT%02ld:%02ld:%02ld", octstr_get_cstr(s), ut.year, ut.month+1, ut.day, ut.hour, ut.minute, ut.second); octstr_destroy(s); s = octstr_create("20090210"); if (date_parse_iso(&ut, s) == -1) { panic(0, "date_parse_iso failed: %s", octstr_get_cstr(s)); } info(0, "%s : %04ld%02ld%02ldT%02ld:%02ld:%02ld", octstr_get_cstr(s), ut.year, ut.month+1, ut.day, ut.hour, ut.minute, ut.second); octstr_destroy(s); gwlib_shutdown(); return 0; } gateway-1.4.5/test/whitelist.txt0000644000175000017500000000003407511025532015415 0ustar toljtolj+358408676001 +358408201681 gateway-1.4.5/test/test_file_traversal.c0000644000175000017500000001425713227613126017064 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_file_traversal.c - simple file traversal testing */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #ifdef HAVE_NFTW #include #endif static Counter *counter; /* * This callback function for use with for_each_file() will unlink * the file, and hence removing all regular files within the DLR spool. */ #ifdef HAVE_NFTW static int count_file2(const char *filename, const struct stat *sb, int tflag, struct FTW *ftwbuf) { /* we need to check here if we have a regular file. */ if (tflag != FTW_F) return 0; counter_increase(counter); return 0; } #endif static int count_file(const char *filename, const struct stat *sb, int tflag, void *ftwbuf) { counter_increase(counter); return 0; } /* * The function traverses a directory structure and calls a callback * function for each regular file within that directory structure. */ #ifdef HAVE_NFTW static int for_each_file2(const Octstr *dir_s, int ignore_err, int(*cb)(const char *, const struct stat *, int, struct FTW *)) { int ret; ret = nftw(octstr_get_cstr(dir_s), cb, 20, FTW_PHYS); return ret; } #endif static int for_each_file(const Octstr *dir_s, int ignore_err, int(*cb)(const char *, const struct stat *, int, void *)) { DIR *dir; struct dirent *ent; int ret = 0; #ifndef _DIRENT_HAVE_D_TYPE struct stat stat; #endif if ((dir = opendir(octstr_get_cstr(dir_s))) == NULL) { error(errno, "Could not open directory `%s'", octstr_get_cstr(dir_s)); return -1; } while ((ent = readdir(dir)) != NULL) { Octstr *filename; if (!(strcmp((char*)ent->d_name, "." ) != 0 && strcmp((char*)ent->d_name, ".." ) != 0)) continue; filename = octstr_format("%S/%s", dir_s, ent->d_name); #ifdef _DIRENT_HAVE_D_TYPE if (ent->d_type == DT_DIR && for_each_file(filename, ignore_err, cb) == -1) { ret = -1; } else if (ent->d_type == DT_REG && cb != NULL) { cb(octstr_get_cstr(filename), NULL, 0, NULL); } #else if (lstat(octstr_get_cstr(filename), &stat) == -1) { if (!ignore_err) error(errno, "Could not get stat for `%s'", octstr_get_cstr(filename)); ret = -1; } else if (S_ISDIR(stat.st_mode) && for_each_file(filename, ignore_err, cb) == -1) { ret = -1; } else if (S_ISREG(stat.st_mode) && cb != NULL) { cb(octstr_get_cstr(filename), &stat, 0, NULL); } #endif octstr_destroy(filename); if (ret == -1 && ignore_err) ret = 0; else if (ret == -1) break; } closedir(dir); return ret; } int main(int argc, char **argv) { Octstr *os1; Octstr *os2; time_t start, diff; gwlib_init(); os1 = octstr_create(argv[1]); os2 = octstr_create(argv[2]); counter = counter_create(); start = time(NULL); for_each_file(os1, 1, count_file); diff = (time(NULL) - start); debug("",0,"file count: %ld in %lds", (long) counter_value(counter), (long) diff); #ifdef HAVE_NFTW counter_set(counter, 0); start = time(NULL); for_each_file2(os2, 1, count_file2); diff = (time(NULL) - start); debug("",0,"file count: %ld in %lds", (long) counter_value(counter), (long) diff); #endif counter_destroy(counter); octstr_destroy(os1); octstr_destroy(os2); gwlib_shutdown(); return 0; } gateway-1.4.5/test/wml_tester.c0000644000175000017500000001563613227613126015212 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wml_tester.c - a simple program to test the WML-compiler module * * Tuomas Luttinen */ #include #include #include "gwlib/gwlib.h" #include "gw/wml_compiler.h" typedef enum { NORMAL_OUT, SOURCE_OUT, BINARY_OUT } output_t; static void help(void) { info(0, "Usage: wml_tester [-hsbzr] [-n number] [-f file] " "[-c charset] file.wml\n" "where\n" " -h this text\n" " -s output also the WML source, cannot be used with b\n" " -b output only the compiled binary, cannot be used with s\n" " -z insert a '\\0'-character in the middle of the input\n" " -r run XML parser in relaxed mode to recover from errors\n" " -n number the number of times the compiling is done\n" " -f file direct the output into a file\n" " -c charset character set as given by the http"); } static void set_zero(Octstr *ostr) { octstr_set_char(ostr, (1 + (int) (octstr_len(ostr) *gw_rand()/ (RAND_MAX+1.0))), '\0'); } int main(int argc, char **argv) { output_t outputti = NORMAL_OUT; FILE *fp = NULL; Octstr *output = NULL; Octstr *filename = NULL; Octstr *wml_text = NULL; Octstr *charset = NULL; Octstr *wml_binary = NULL; int i, ret = 0, opt, file = 0, zero = 0, numstatus = 0, wml_strict = 1; long num = 0; /* You can give an wml text file as an argument './wml_tester main.wml' */ gwlib_init(); while ((opt = getopt(argc, argv, "hsbzrn:f:c:")) != EOF) { switch (opt) { case 'h': help(); exit(0); case 's': if (outputti == NORMAL_OUT) outputti = SOURCE_OUT; else { help(); exit(0); } break; case 'b': if (outputti == NORMAL_OUT) outputti = BINARY_OUT; else { help(); exit(0); } break; case 'z': zero = 1; break; case 'r': wml_strict = 0; break; case 'n': numstatus = octstr_parse_long(&num, octstr_imm(optarg), 0, 0); if (numstatus == -1) { /* Error in the octstr_parse_long */ error(num, "Error in the handling of argument to option n"); help(); panic(0, "Stopping."); } break; case 'f': file = 1; filename = octstr_create(optarg); fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Couldn't open output file."); break; case 'c': charset = octstr_create(optarg); break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (optind >= argc) { error(0, "Missing arguments."); help(); panic(0, "Stopping."); } if (outputti == BINARY_OUT) log_set_output_level(GW_PANIC); wml_init(wml_strict); while (optind < argc) { wml_text = octstr_read_file(argv[optind]); if (wml_text == NULL) panic(0, "Couldn't read WML source file."); if (zero) set_zero(wml_text); for (i = 0; i <= num; i++) { ret = wml_compile(wml_text, charset, &wml_binary, NULL); if (i < num) octstr_destroy(wml_binary); } optind++; output = octstr_format("wml_compile returned: %d\n\n", ret); if (ret == 0) { if (fp == NULL) fp = stdout; if (outputti != BINARY_OUT) { if (outputti == SOURCE_OUT) { octstr_insert(output, wml_text, octstr_len(output)); octstr_append_char(output, '\n'); } octstr_append(output, octstr_imm( "Here's the binary output: \n\n")); octstr_print(fp, output); } if (file && outputti != BINARY_OUT) { fclose(fp); log_open(octstr_get_cstr(filename), 0, GW_NON_EXCL); octstr_dump(wml_binary, 0); log_close_all(); fp = fopen(octstr_get_cstr(filename), "a"); } else if (outputti != BINARY_OUT) octstr_dump(wml_binary, 0); else octstr_print(fp, wml_binary); if (outputti != BINARY_OUT) { octstr_destroy(output); output = octstr_format("\n And as a text: \n\n"); octstr_print(fp, output); octstr_pretty_print(fp, wml_binary); octstr_destroy(output); output = octstr_format("\n\n"); octstr_print(fp, output); } } octstr_destroy(wml_text); octstr_destroy(output); octstr_destroy(wml_binary); } if (file) { fclose(fp); octstr_destroy(filename); } if (charset != NULL) octstr_destroy(charset); wml_shutdown(); gwlib_shutdown(); return ret; } gateway-1.4.5/test/test_octstr_immutables.c0000644000175000017500000000625313227613126017617 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * test_octstr_immutables.c - simple testing of octstr_imm() */ #include #include "gwlib/gwlib.h" int main(int argc, char **argv) { Octstr *os; gwlib_init(); if (optind >= argc) { os = octstr_imm("foo"); } else { os = octstr_imm(argv[optind]); } /* * Note: don't destroy this, check that the log file has no * memory leaks. */ octstr_dump(os, 0); gwlib_shutdown(); return 0; } gateway-1.4.5/VERSION0000644000175000017500000000105613312227404012734 0ustar toljtolj1.4.5 This file contains the version number of the gateway. It is stored on the first line. Nothing else should be there. Note that if you get this file from SVN, it will just say "svn-r" instead of a version number. This is intentional, it avoids confusion with real releases. Starting with version 0.8, version numbers that have an even second part are STABLE versions and those with odd ones are DEVELOPMENT versions. Thus, 1.0 is stable, 1.1 is development. Don't use development versions for production unless you really know what you do. gateway-1.4.5/addons/0000755000175000017500000000000013312227715013137 5ustar toljtoljgateway-1.4.5/addons/sqlbox/0000755000175000017500000000000013312227715014447 5ustar toljtoljgateway-1.4.5/addons/sqlbox/COPYING0000644000175000017500000000020211103644116015466 0ustar toljtoljSee file KannelLICENSE for details about the license agreement for using, modifying, copying or deriving work from this software. gateway-1.4.5/addons/sqlbox/bootstrap0000755000175000017500000000347511334244610016416 0ustar toljtolj#! /bin/sh set -x set -e # Check for automake amvers="no" if automake-1.11 --version >/dev/null 2>&1; then amvers="-1.11" elif automake-1.10 --version >/dev/null 2>&1; then amvers="-1.10" elif automake-1.9 --version >/dev/null 2>&1; then amvers="-1.9" elif automake-1.8 --version >/dev/null 2>&1; then amvers="-1.8" elif automake-1.7 --version >/dev/null 2>&1; then amvers="-1.7" elif automake-1.6 --version >/dev/null 2>&1; then amvers="-1.6" elif automake-1.5 --version >/dev/null 2>&1; then amvers="-1.5" elif automake --version > /dev/null 2>&1; then amvers="`automake --version | sed -e '1s/[^0-9]*//' -e q`" if expr "$amvers" "<" "1.5" > /dev/null 2>&1; then amvers="no" else amvers="" fi fi if test "$amvers" = "no"; then set +x echo "$0: you need automake version 1.5 or later" exit 1 fi # Check for libtool libtoolize="no" if glibtoolize --version >/dev/null 2>&1; then libtoolize="glibtoolize" elif libtoolize --version >/dev/null 2>&1; then libtoolize="libtoolize" fi if test "$libtoolize" = "no"; then set +x echo "$0: you need libtool" exit 1 fi # Remove old cruft set +x; for x in aclocal.m4 configure config.guess config.log config.sub config.cache config.h.in config.h compile libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 ltmain.sh libtool ltconfig missing mkinstalldirs depcomp install-sh; do rm -f $x autotools/$x; done; rm -Rf autom4te.cache; set -x if test ! -d autotools; then mkdir autotools; fi # Bootstrap package ${libtoolize} --copy --force if test -f "ltmain.sh"; then echo "$0: working around a minor libtool issue" mv ltmain.sh autotools/ fi aclocal${amvers} -I autotools autoconf autoheader #add --include-deps if you want to bootstrap with any other compiler than gcc #automake${amvers} --add-missing --copy --include-deps automake${amvers} --add-missing --copy gateway-1.4.5/addons/sqlbox/AUTHORS0000644000175000017500000000031311173046134015511 0ustar toljtoljRene Kluwen Stand alone module by Martín Conte Mac Donell Documentation and patches by Alejandro Guerrieri gateway-1.4.5/addons/sqlbox/KannelLICENSE0000644000175000017500000000521311204545563016610 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ gateway-1.4.5/addons/sqlbox/autotools/0000755000175000017500000000000013312227715016500 5ustar toljtoljgateway-1.4.5/addons/sqlbox/autotools/ltmain.sh0000755000175000017500000105377412327711710020342 0ustar toljtolj # libtool (GNU libtool) 2.4 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION=2.4 TIMESTAMP="" package_revision=1.3294 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${EGREP="/usr/bin/grep -E"} : ${FGREP="/usr/bin/grep -F"} : ${GREP="/usr/bin/grep"} : ${LN_S="ln -s"} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SED="/usr/bin/sed"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=: for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -e 's/\([\\"]\)/\\\1/g' \ -e 's/^/ fputs ("/' -e 's/$/\\n", f);/' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_emit_exe_manifest # emit a Win32 UAC manifest for executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_exe_manifest () { cat < EOF } # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization # -{shared,static}-libgcc, -static-{libgfortran|libstdc++} # link against specified runtime library # -fstack-protector* stack protector flags for GCC -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin| \ -shared-libgcc|-static-libgcc|-static-libgfortran|-static-libstdc++| \ -fstack-protector*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_apped perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper $cwrapper.manifest; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then # Create the UAC manifests first if necessary (but the # manifest files must have executable permission regardless). case $output_name in *instal*|*patch*|*setup*|*update*) func_emit_exe_manifest > $cwrapper.manifest func_emit_exe_manifest > $output_path/$objdir/$output_name.exe.manifest chmod +x $cwrapper.manifest chmod +x $output_path/$objdir/$output_name.exe.manifest ;; esac $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" func_append rmfiles " ${name}.manifest $objdir/${name}.manifest" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name $objdir/lt-${name}.manifest" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 gateway-1.4.5/addons/sqlbox/autotools/config.guess0000755000175000017500000013036112327711710021022 0ustar toljtolj#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-06-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gateway-1.4.5/addons/sqlbox/autotools/config.sub0000755000175000017500000010530112327711710020461 0ustar toljtolj#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-04-24' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or1k-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gateway-1.4.5/addons/sqlbox/autotools/depcomp0000755000175000017500000005064312327711710020063 0ustar toljtolj#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2012-03-27.16; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # A tabulation character. tab=' ' # A newline character. nl=' ' if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' "$nl" < "$tmpdepfile" | ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependent.h'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. # However on # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\': # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... # tcc 0.9.26 (FIXME still under development at the moment of writing) # will emit a similar output, but also prepend the continuation lines # with horizontal tabulation characters. "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form 'foo.o: dependent.h', # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ < "$tmpdepfile" > "$depfile" sed ' s/[ '"$tab"'][ '"$tab"']*/ /g s/^ *// s/ *\\*$// s/^[^:]*: *// /^$/d /:$/d s/$/ :/ ' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test "$stat" = 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' "$nl" < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gateway-1.4.5/addons/sqlbox/autotools/install-sh0000755000175000017500000003325612327711710020513 0ustar toljtolj#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-01-19.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for `test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gateway-1.4.5/addons/sqlbox/autotools/missing0000755000175000017500000002415212327711710020101 0ustar toljtolj#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2012-01-06.13; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: gateway-1.4.5/addons/sqlbox/Makefile.in0000644000175000017500000006543312327711710016525 0ustar toljtolj# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/sb-config.h.in \ $(top_srcdir)/configure $(top_srcdir)/rpm/sqlbox.spec.in \ AUTHORS COPYING ChangeLog INSTALL NEWS autotools/config.guess \ autotools/config.sub autotools/depcomp autotools/install-sh \ autotools/ltmain.sh autotools/missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = sb-config.h CONFIG_CLEAN_FILES = rpm/sqlbox.spec CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-dvi-recursive install-exec-recursive \ install-html-recursive install-info-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ distdir dist dist-all distcheck ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONVERT = @CONVERT@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CTLIB_INCLUDE = @CTLIB_INCLUDE@ CTLIB_LFLAGS = @CTLIB_LFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOCDRAFTS = @DOCDRAFTS@ DOCSTARGET = @DOCSTARGET@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ DVIPS = @DVIPS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FIG2DEV = @FIG2DEV@ GREP = @GREP@ GW_CONFIG = @GW_CONFIG@ HTML_DSL = @HTML_DSL@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ JADE = @JADE@ JADETEX = @JADETEX@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OLDJADE = @OLDJADE@ OPENSSL = @OPENSSL@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFJADETEX = @PDFJADETEX@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TEX_DSL = @TEX_DSL@ VERSION = @VERSION@ XML_DCL = @XML_DCL@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ rpm_requires = @rpm_requires@ rpm_suffix = @rpm_suffix@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ man1pages = gw/sqlbox.1 man5pages = gw/sqlbox.5 docsrcs = $(wildcard grep -l '/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) sb-config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) sb-config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) sb-config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod u+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile sb-config.h installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps-am: uninstall-am: .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ ctags-recursive install-am install-strip tags-recursive .PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ all all-am am--refresh check check-am clean clean-generic \ clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-lzma dist-shar dist-tarZ dist-xz \ dist-zip distcheck distclean distclean-generic distclean-hdr \ distclean-libtool distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ ps ps-am tags tags-recursive uninstall uninstall-am .xml.html: sed "s/#FIGTYPE#/.png/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp ${JADE} -V nochunks -t sgml -d $(HTML_DSL) $(XML_DCL) $*.tmp > $@ rm -f $*.tmp .xml.rtf: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp cd `dirname $<` && $(JADE) -o `basename $*`.rtf -t rtf -d $(TEX_DSL) $(XML_DCL) `basename $*`.tmp rm -f $*.tmp .xml.ps: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || \ ( echo Check `dirname $<`/`basename $*`.log for errors && false) rm -f $*.log cd `dirname $<` && $(DVIPS) -q -o `basename $*`.ps `basename $*`.dvi rm -f $*.dvi $*.tex $*.aux .xml.pdf: sed "s/#FIGTYPE#/.png/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true rm -f $*.log $*.dvi cd `dirname $<` && $(PDFJADETEX) `basename $*`.tex > /dev/null || true test -r $*.pdf || false rm -f $*.log $*.tex $*.aux $*.out .fig.png: $(FIG2DEV) -Lpng $< $@ .fig.ps: $(FIG2DEV) -Lps $< $@ .png.ps: $(CONVERT) $< $@ rpm: clean @echo "Preparing to build the RPM files" mkdir -p "$(rpmtemp)/${RPMPKG}" cp -R * "$(rpmtemp)/${RPMPKG}" tar -C "$(rpmtemp)" -c ${RPMPKG} -zf ${RPMPKG}.tar.gz rm -rf "$(rpmtemp)/${RPMPKG}" if [ -d $(rpmtemp) ]; then rmdir "$(rpmtemp)"; fi @echo "Building the RPM" rpmbuild -ta ${RPMPKG}.tar.gz rm -f ${RPMPKG}.tar.gz @echo "**********************************************************************" @echo "* Success!" @echo "* Your files are located under $(shell rpm --eval '%_rpmdir')" @echo "* The Kannel Group " @echo "**********************************************************************" @echo "Thank you for using Kannel." docs: figs ps $(docs) no-docs: figs: $(figs) ps: $(ps) pp: $(pres) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gateway-1.4.5/addons/sqlbox/aclocal.m40000644000175000017500000123002012327711710016303 0ustar toljtolj# generated automatically by aclocal 1.11.6 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, # Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010 Free Software Foundation, # Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010 Free Software Foundation, # Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2010 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES # -------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[123]]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; haiku*) version_type=linux need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ F* | *Sun*Fortran*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], [[If ld is used when linking, flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[[12]]*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS # Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) # ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3294 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4]) m4_define([LT_PACKAGE_REVISION], [1.3294]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4' macro_revision='1.3294' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.6], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.6])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, # 2010, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 12 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, # 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_MAINTAINER_MODE([DEFAULT-MODE]) # ---------------------------------- # Control maintainer-specific portions of Makefiles. # Default is to disable them, unless `enable' is passed literally. # For symmetry, `disable' may be passed as well. Anyway, the user # can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], [m4_case(m4_default([$1], [disable]), [enable], [m4_define([am_maintainer_other], [disable])], [disable], [m4_define([am_maintainer_other], [enable])], [m4_define([am_maintainer_other], [enable]) m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode's default is 'disable' unless 'enable' is passed AC_ARG_ENABLE([maintainer-mode], [ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful (and sometimes confusing) to the casual installer], [USE_MAINTAINER_MODE=$enableval], [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST([MAINT])dnl ] ) AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([acinclude.m4]) gateway-1.4.5/addons/sqlbox/configure0000755000175000017500000161364512327711710016374 0ustar toljtolj#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for sqlbox cvs. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and devel@kannel.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sqlbox' PACKAGE_TARNAME='sqlbox' PACKAGE_VERSION='cvs' PACKAGE_STRING='sqlbox cvs' PACKAGE_BUGREPORT='devel@kannel.org' PACKAGE_URL='' ac_unique_file="gw/sqlbox.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS rpm_requires rpm_suffix GW_CONFIG CTLIB_INCLUDE CTLIB_LFLAGS DOCDRAFTS DOCSTARGET XML_DCL TEX_DSL HTML_DSL CONVERT FIG2DEV DVIPS PDFJADETEX JADETEX JADE OLDJADE OPENSSL LIBOBJS INCLUDES CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC LIBTOOL host_os host_vendor host_cpu host build_os build_vendor build_cpu build MAINT MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM VERSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_maintainer_mode enable_shared enable_static with_pic enable_fast_install enable_dependency_tracking with_gnu_ld with_sysroot enable_libtool_lock with_cflags with_libs with_ssl enable_ssl enable_ssl_thread_test enable_docs enable_drafts with_ctlib with_mssql with_kannel_dir ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures sqlbox cvs to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/sqlbox] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of sqlbox cvs:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --disable-libtool-lock avoid locking (might break parallel builds) --enable-ssl enable SSL client and server support enabled --disable-ssl-thread-test disable the multithread test for the OpenSSL library this will force to continue even if the test fails --enable-docs enable building of documentation [enabled] --enable-drafts enable building of documentation drafts [disabled] Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-cflags=FLAGS use FLAGS for CFLAGS --with-libs=FLAGS use FLAGS for extra libraries --with-ssl=DIR where to look for OpenSSL libs and header files DIR points to the installation /usr/local/ssl --with-ctlib=DIR Include Ct-Lib support. DIR is the Ct-Lib install directory, defaults to /opt/sybase. --with-mssql=DIR Include FreeTDS Ct-Lib support. DIR is the FreeTDS install directory, defaults to /usr/local. --with-kannel-dir=DIR where to look for Kannel Gateway libs and header files DIR points to the installation /usr/local Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF sqlbox configure cvs generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------- ## ## Report this to devel@kannel.org ## ## ------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by sqlbox $as_me cvs, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in autotools "$srcdir"/autotools; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in autotools \"$srcdir\"/autotools" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. case $TERM in xterm|xterm*|vt220|vt220*|cygwin) T_MD=`echo dummy | awk '{ printf("%c%c%c%c", 27, 91, 49, 109); }'` T_ME=`echo dummy | awk '{ printf("%c%c%c", 27, 91, 109); }'` ;; vt100|vt100*) T_MD=`echo dummy | awk '{ printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }'` T_ME=`echo dummy | awk '{ printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }'` ;; default) T_MD='' T_ME='' ;; esac test -f config.nice && mv config.nice config.nice.old rm -f config.nice.old cat >config.nice<> config.nice fi done for arg in $0 "$@"; do echo "'$arg' \\" >> config.nice done echo '"$@"' >> config.nice chmod +x config.nice { $as_echo "$as_me:${as_lineno-$LINENO}: checking svn checkout revision" >&5 $as_echo_n "checking svn checkout revision... " >&6; } if test -d ".svn" then revision=`svnversion .` test -z "$revision" && revision="unknown" SVN_REVISION="$revision" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SVN_REVISION" >&5 $as_echo "$SVN_REVISION" >&6; } VERSION="svn-r$SVN_REVISION" SB_NAME="SqlBox" cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF nl=' ' echo "${nl}${T_MD}Configuring for Kannel sqlbox version $VERSION ...${T_ME}" am__api_version='1.11' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE=$SB_NAME VERSION=$VERSION cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' ac_config_headers="$ac_config_headers sb-config.h" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else USE_MAINTAINER_MODE=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 $as_echo "$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4' macro_revision='1.3294' ltmain="$ac_aux_dir/ltmain.sh" # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; pic_mode="$withval" else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' lt_prog_compiler_pic='-Xcompiler -fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ F* | *Sun*Fortran*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld='-rpath $libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; freebsd1*) ld_shlibs=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_flag_spec_ld='+b $libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; haiku*) version_type=linux need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: INCLUDES='-I$(top_srcdir)/gw -I$(top_builddir)/gw' ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5 $as_echo_n "checking for working volatile... " >&6; } if ${ac_cv_c_volatile+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { volatile int x; int * volatile y = (int *) 0; return !x && !y; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_volatile=yes else ac_cv_c_volatile=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5 $as_echo "$ac_cv_c_volatile" >&6; } if test $ac_cv_c_volatile = no; then $as_echo "#define volatile /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether closedir returns void" >&5 $as_echo_n "checking whether closedir returns void... " >&6; } if ${ac_cv_func_closedir_void+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_closedir_void=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include <$ac_header_dirent> #ifndef __cplusplus int closedir (); #endif int main () { return closedir (opendir (".")) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_closedir_void=no else ac_cv_func_closedir_void=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_closedir_void" >&5 $as_echo "$ac_cv_func_closedir_void" >&6; } if test $ac_cv_func_closedir_void = yes; then $as_echo "#define CLOSEDIR_VOID 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5 $as_echo_n "checking for error_at_line... " >&6; } if ${ac_cv_lib_error_at_line+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { error_at_line (0, 0, "", 0, "an error occurred"); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_error_at_line=yes else ac_cv_lib_error_at_line=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_error_at_line" >&5 $as_echo "$ac_cv_lib_error_at_line" >&6; } if test $ac_cv_lib_error_at_line = no; then case " $LIBOBJS " in *" error.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS error.$ac_objext" ;; esac fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if ${ac_cv_func_malloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 $as_echo_n "checking for working memcmp... " >&6; } if ${ac_cv_func_memcmp_working+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_memcmp_working=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Some versions of memcmp are not 8-bit clean. */ char c0 = '\100', c1 = '\200', c2 = '\201'; if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) return 1; /* The Next x86 OpenStep bug shows up only when comparing 16 bytes or more and with at least one buffer not starting on a 4-byte boundary. William Lewis provided this test program. */ { char foo[21]; char bar[21]; int i; for (i = 0; i < 4; i++) { char *a = foo + i; char *b = bar + i; strcpy (a, "--------01111111"); strcpy (b, "--------10000000"); if (memcmp (a, b, 16) >= 0) return 1; } return 0; } ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_memcmp_working=yes else ac_cv_func_memcmp_working=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 $as_echo "$ac_cv_func_memcmp_working" >&6; } test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac EXE_EXT="" case "$host" in *-sun-solaris*) CFLAGS="$CFLAGS -DSunOS=1" ;; *-cygwin*) EXE_EXT=".exe" LDFLAGS="$LDFLAGS -Wl,--enable-auto-import" ;; *apple-darwin*) # MacOS X # Lets try to find the newest installed SDK for compilation # so we know how to link against it. # If we find a SDK, we use that rather then the standard /usr # location libs and includes. found=0 SDK="" for loc in "MacOSX10.6.sdk" "MacOSX10.5.sdk" "MacOSX10.4u.sdk" "MacOSX10.4.0.sdk" "MacOSX10.3.9.sdk" \ "MacOSX10.3.0.sdk" "MacOSX10.2.8.sdk" "MacOSX10.1.5.sdk" do if test "$found" = "0" ; then if test -d "/Developer/SDKs/${E}" ; then found="1" SDK="${loc}" fi fi done if test "$SDK" != "" ; then CFLAGS="$CFLAGS -DDARWIN=1 -L/Developer/SDKs/${SDK}/usr/lib -I/Developer/SDKs/${SDK}/usr/include" else CFLAGS="$CFLAGS -DDARWIN=1" fi LIBTOOL="libtool -static -o" ;; *-linux-*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE" LDFLAGS="$LDFLAGS -rdynamic" ;; *-*-openbsd* | *-*-freebsd*) CFLAGS="$CFLAGS -pthread" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_exit in -lpthread" >&5 $as_echo_n "checking for pthread_exit in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_exit+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_exit (); int main () { return pthread_exit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_exit=yes else ac_cv_lib_pthread_pthread_exit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_exit" >&5 $as_echo "$ac_cv_lib_pthread_pthread_exit" >&6; } if test "x$ac_cv_lib_pthread_pthread_exit" = xyes; then : LIBS="$LIBS -lpthread"; pthread="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_exit in -lc_r" >&5 $as_echo_n "checking for pthread_exit in -lc_r... " >&6; } if ${ac_cv_lib_c_r_pthread_exit+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_exit (); int main () { return pthread_exit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_r_pthread_exit=yes else ac_cv_lib_c_r_pthread_exit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_exit" >&5 $as_echo "$ac_cv_lib_c_r_pthread_exit" >&6; } if test "x$ac_cv_lib_c_r_pthread_exit" = xyes; then : LIBS="$LIBS -lc_r"; pthread="yes" fi fi ;; *-interix3*) INSTALL="./install-sh" ;; esac # Check whether --with-cflags was given. if test "${with_cflags+set}" = set; then : withval=$with_cflags; CFLAGS="$CFLAGS $withval" fi # Check whether --with-libs was given. if test "${with_libs+set}" = set; then : withval=$with_libs; LIBS="$LIBS $withval" fi nl=' ' echo "${nl}${T_MD}Configuring OpenSSL support ...${T_ME}" # Check whether --with-ssl was given. if test "${with_ssl+set}" = set; then : withval=$with_ssl; if test -d "$withval"; then ssllib="$withval/lib"; sslinc="$withval/include" else as_fn_error $? "Unable to find OpenSSL libs and/or directories at $withval" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SSL support" >&5 $as_echo_n "checking whether to compile with SSL support... " >&6; } # Check whether --enable-ssl was given. if test "${enable_ssl+set}" = set; then : enableval=$enable_ssl; if test "$enableval" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } ssl=no else ssl=yes fi else ssl=yes fi if test "$ssl" = "yes" ; then if test "x$ssllib" = "x" && test "x$sslinc" = "x"; then for loc in /usr/lib /usr/local/ssl/lib /usr/local/openssl/lib; do if test -f "$loc/libssl.a"; then ssllib="$loc" fi done for loc in /usr/include/ssl /usr/include/openssl /usr/local/ssl/include \ /usr/local/openssl/include; do if test -d "$loc"; then sslinc="$loc" fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: trying $ssllib $sslinc" >&5 $as_echo "trying $ssllib $sslinc" >&6; } fi if test "x$ssllib" != "x" && test "x$sslinc" != "x"; then CFLAGS="$CFLAGS -I$sslinc" LIBS="$LIBS -L$ssllib" # Extract the first word of "openssl", so it can be a program name with args. set dummy openssl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_OPENSSL+:} false; then : $as_echo_n "(cached) " >&6 else case $OPENSSL in [\\/]* | ?:[\\/]*) ac_cv_path_OPENSSL="$OPENSSL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_OPENSSL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_OPENSSL" && ac_cv_path_OPENSSL="no" ;; esac fi OPENSSL=$ac_cv_path_OPENSSL if test -n "$OPENSSL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENSSL" >&5 $as_echo "$OPENSSL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$OPENSSL" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking openssl version" >&5 $as_echo_n "checking openssl version... " >&6; } openssl_version=`$OPENSSL version | awk '{print $2}'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $openssl_version" >&5 $as_echo "$openssl_version" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CRYPTO_lock in -lcrypto" >&5 $as_echo_n "checking for CRYPTO_lock in -lcrypto... " >&6; } if ${ac_cv_lib_crypto_CRYPTO_lock+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char CRYPTO_lock (); int main () { return CRYPTO_lock (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypto_CRYPTO_lock=yes else ac_cv_lib_crypto_CRYPTO_lock=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_CRYPTO_lock" >&5 $as_echo "$ac_cv_lib_crypto_CRYPTO_lock" >&6; } if test "x$ac_cv_lib_crypto_CRYPTO_lock" = xyes; then : LIBS="$LIBS -lcrypto" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5 $as_echo_n "checking for SSL_library_init in -lssl... " >&6; } if ${ac_cv_lib_ssl_SSL_library_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SSL_library_init (); int main () { return SSL_library_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ssl_SSL_library_init=yes else ac_cv_lib_ssl_SSL_library_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_library_init" >&5 $as_echo "$ac_cv_lib_ssl_SSL_library_init" >&6; } if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_connect in -lssl" >&5 $as_echo_n "checking for SSL_connect in -lssl... " >&6; } if ${ac_cv_lib_ssl_SSL_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SSL_connect (); int main () { return SSL_connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ssl_SSL_connect=yes else ac_cv_lib_ssl_SSL_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_connect" >&5 $as_echo "$ac_cv_lib_ssl_SSL_connect" >&6; } if test "x$ac_cv_lib_ssl_SSL_connect" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSSL 1 _ACEOF LIBS="-lssl $LIBS" fi for ac_header in openssl/x509.h openssl/rsa.h openssl/crypto.h \ openssl/pem.h openssl/ssl.h openssl/err.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the OpenSSL library is multithread-enabled" >&5 $as_echo_n "checking whether the OpenSSL library is multithread-enabled... " >&6; } if test "$cross_compiling" = yes; then : echo "Cross-compiling; make sure your SSL library is multithread-enabled" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define OPENSSL_THREAD_DEFINES #include int main(void) { #if defined(THREADS) exit(0); #elif defined(OPENSSL_THREADS) exit(0); #else exit(1); #endif } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LIBSSL 1" >>confdefs.h LIBS="$LIBS -lssl" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SSL support" >&5 $as_echo_n "checking whether to compile with SSL support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # Check whether --enable-ssl-thread-test was given. if test "${enable_ssl_thread_test+set}" = set; then : enableval=$enable_ssl_thread_test; if test "$enableval" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, continue forced" >&5 $as_echo "no, continue forced" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Either get a multithread-enabled SSL or configure with --disable-ssl" "$LINENO" 5 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi fi nl=' ' echo "${nl}${T_MD}Configuring DocBook support ...${T_ME}" # Extract the first word of "jade", so it can be a program name with args. set dummy jade; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OLDJADE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OLDJADE"; then ac_cv_prog_OLDJADE="$OLDJADE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OLDJADE="jade" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_OLDJADE" && ac_cv_prog_OLDJADE="no" fi fi OLDJADE=$ac_cv_prog_OLDJADE if test -n "$OLDJADE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OLDJADE" >&5 $as_echo "$OLDJADE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$OLDJADE" = "no" ; then # Extract the first word of "openjade", so it can be a program name with args. set dummy openjade; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JADE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JADE"; then ac_cv_prog_JADE="$JADE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JADE="openjade" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_JADE" && ac_cv_prog_JADE="no" fi fi JADE=$ac_cv_prog_JADE if test -n "$JADE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JADE" >&5 $as_echo "$JADE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else JADE=$OLDJADE fi # Extract the first word of "jadetex", so it can be a program name with args. set dummy jadetex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JADETEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JADETEX"; then ac_cv_prog_JADETEX="$JADETEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JADETEX="jadetex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_JADETEX" && ac_cv_prog_JADETEX="no" fi fi JADETEX=$ac_cv_prog_JADETEX if test -n "$JADETEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JADETEX" >&5 $as_echo "$JADETEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "pdfjadetex", so it can be a program name with args. set dummy pdfjadetex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PDFJADETEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PDFJADETEX"; then ac_cv_prog_PDFJADETEX="$PDFJADETEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PDFJADETEX="pdfjadetex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_PDFJADETEX" && ac_cv_prog_PDFJADETEX="no" fi fi PDFJADETEX=$ac_cv_prog_PDFJADETEX if test -n "$PDFJADETEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFJADETEX" >&5 $as_echo "$PDFJADETEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "dvips", so it can be a program name with args. set dummy dvips; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DVIPS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DVIPS"; then ac_cv_prog_DVIPS="$DVIPS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DVIPS="dvips" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_DVIPS" && ac_cv_prog_DVIPS="no" fi fi DVIPS=$ac_cv_prog_DVIPS if test -n "$DVIPS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DVIPS" >&5 $as_echo "$DVIPS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "fig2dev", so it can be a program name with args. set dummy fig2dev; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_FIG2DEV+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$FIG2DEV"; then ac_cv_prog_FIG2DEV="$FIG2DEV" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_FIG2DEV="fig2dev" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_FIG2DEV" && ac_cv_prog_FIG2DEV="no" fi fi FIG2DEV=$ac_cv_prog_FIG2DEV if test -n "$FIG2DEV"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FIG2DEV" >&5 $as_echo "$FIG2DEV" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "convert", so it can be a program name with args. set dummy convert; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CONVERT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CONVERT"; then ac_cv_prog_CONVERT="$CONVERT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CONVERT="convert" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CONVERT" && ac_cv_prog_CONVERT="no" fi fi CONVERT=$ac_cv_prog_CONVERT if test -n "$CONVERT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CONVERT" >&5 $as_echo "$CONVERT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi found="" for loc in /usr /usr/local /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/html/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/html/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/html/docbook.dsl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : HTML_DSL=$file; found=1 fi fi done fi done found="" for loc in /usr /usr/local /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/print/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/print/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/print/docbook.dsl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : TEX_DSL=$file; found=1 fi fi done fi done found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/dtds/decls/xml.dcl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/dtds/decls/xml.dcl \ ${loc}/share/dsssl/docbook-dsssl/dtds/decls/xml.dcl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : XML_DCL=$file; found=1 fi fi done fi done # Check whether --enable-docs was given. if test "${enable_docs+set}" = set; then : enableval=$enable_docs; if test "$enableval" = "yes" then DOCSTARGET="docs" else DOCSTARGET="no-docs" fi fi if test "x$HTML_DSL" = "x" -o "x$TEX_DSL" = "x" \ || test "$JADE" = "no" \ || test "$JADETEX" = "no" \ || test "$PDFJADETEX" = "no" \ || test "$DVIPS" = "no" \ || test "$FIG2DEV" = "no" \ || test "$CONVERT" = "no" \ || test "$DOCSTARGET" = "no-docs" then DOCSTARGET="no-docs" else DOCSTARGET="docs" fi case "$DOCSTARGET" in no-docs) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not building documentation." >&5 $as_echo "Not building documentation." >&6; } ;; docs) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Documentation will be built as well." >&5 $as_echo "Documentation will be built as well." >&6; } ;; esac DOCDRAFTS="IGNORE" # Check whether --enable-drafts was given. if test "${enable_drafts+set}" = set; then : enableval=$enable_drafts; if test "$enableval" = "yes" then DOCDRAFTS="INCLUDE" else DOCDRAFTS="IGNORE" fi fi if test "x$DOCSTARGET" = "xdocs" then case "$DOCDRAFTS" in INCLUDE) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Documentation will include drafts." >&5 $as_echo "Documentation will include drafts." >&6; } ;; esac fi nl=' ' echo "${nl}${T_MD}Configuring Kannel and DB dependancies ...${T_ME}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ct-Lib support" >&5 $as_echo_n "checking for Ct-Lib support... " >&6; } # Check whether --with-ctlib was given. if test "${with_ctlib+set}" = set; then : withval=$with_ctlib; if test "$withval" = "yes"; then withval=/opt/sybase fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then CTLIB_INCDIR=$withval/include CTLIB_LIBDIR=$withval/lib else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Invalid Ct-Lib directory - unable to find ctpublic.h" "$LINENO" 5 fi CTLIB_LFLAGS="-L$CTLIB_LIBDIR -lct -lcs -lsybtcl -lcomn -lintl" CTLIB_INCLUDE="-I$CTLIB_INCDIR" $as_echo "#define HAVE_CTLIB 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } have_db=yes ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : CTLIB_LFLAGS="$CTLIB_LFLAGS -ldl" fi fi fi if test "x$DBTYPE" = "x" ; then DBTYPE="ctlib" else DBTYPE="$DBTYPE-ctlib" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FreeTDS Ct-Lib support" >&5 $as_echo_n "checking for FreeTDS Ct-Lib support... " >&6; } # Check whether --with-mssql was given. if test "${with_mssql+set}" = set; then : withval=$with_mssql; if test "$withval" = "yes"; then withval=/usr/local fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then CTLIB_INCDIR=$withval/include CTLIB_LIBDIR=$withval/lib else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Invalid FreeTDS directory - unable to find ctpublic.h" "$LINENO" 5 fi CTLIB_LFLAGS="-L$CTLIB_LIBDIR -lct" CTLIB_INCLUDE="-I$CTLIB_INCDIR" $as_echo "#define HAVE_CTLIB 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } have_db=yes ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : CTLIB_LFLAGS="$CTLIB_LFLAGS -ldl" fi fi fi if test "x$DBTYPE" = "x" ; then DBTYPE="freetds" else DBTYPE="$DBTYPE-freetds" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --with-kannel-dir was given. if test "${with_kannel_dir+set}" = set; then : withval=$with_kannel_dir; gwloc="" if test -d "$withval" ; then gwloc="$withval" fi fi # Extract the first word of "gw-config", so it can be a program name with args. set dummy gw-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_GW_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $GW_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_GW_CONFIG="$GW_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$gwloc/bin:$gwloc:../gateway/gw/:$PATH" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_GW_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_GW_CONFIG" && ac_cv_path_GW_CONFIG="no" ;; esac fi GW_CONFIG=$ac_cv_path_GW_CONFIG if test -n "$GW_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GW_CONFIG" >&5 $as_echo "$GW_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$GW_CONFIG" = "no"; then found="" for loc in $pgsqlloc /usr /usr/local ; do if test "x$found" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Kannel include files in" >&5 $as_echo_n "checking for Kannel include files in... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $loc" >&5 $as_echo "$loc" >&6; } as_ac_File=`$as_echo "ac_cv_file_"$loc/include/kannel/gw-config.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/include/kannel/gw-config.h\"" >&5 $as_echo_n "checking for \"$loc/include/kannel/gw-config.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/include/kannel/gw-config.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/include/kannel -I$loc/include/kannel"; LDFLAGS="$LDFLAGS -L$loc/lib/kannel -lwap -lgwlib"; found=1 fi fi done; if test "x$found" != "x1" ; then as_fn_error $? "Unable to find gw-config.h, please provide a --with-kannel-dir= location" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking Kannel version" >&5 $as_echo_n "checking Kannel version... " >&6; } gw_version=`$GW_CONFIG --version` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_version" >&5 $as_echo "$gw_version" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking Kannel libs" >&5 $as_echo_n "checking Kannel libs... " >&6; } if ! $GW_CONFIG --libs &>/dev/null ; then LIBS="$LIBS `$GW_CONFIG --libs`" gw_libdir=`$GW_CONFIG --libs` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_libdir" >&5 $as_echo "$gw_libdir" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking Kannel includes" >&5 $as_echo_n "checking Kannel includes... " >&6; } if ! $GW_CONFIG --cflags &>/dev/null ; then CFLAGS="$CFLAGS `$GW_CONFIG --cflags`" gw_incdir=`$GW_CONFIG --cflags` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_incdir" >&5 $as_echo "$gw_incdir" >&6; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cfg_create in -lgwlib" >&5 $as_echo_n "checking for cfg_create in -lgwlib... " >&6; } if ${ac_cv_lib_gwlib_cfg_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgwlib $LDFLAGS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char cfg_create (); int main () { return cfg_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_gwlib_cfg_create=yes else ac_cv_lib_gwlib_cfg_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gwlib_cfg_create" >&5 $as_echo "$ac_cv_lib_gwlib_cfg_create" >&6; } if test "x$ac_cv_lib_gwlib_cfg_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGWLIB 1 _ACEOF LIBS="-lgwlib $LIBS" else as_fn_error $? "Kannel gwlib is required!" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Kannel's DB support" >&5 $as_echo_n "checking for Kannel's DB support... " >&6; } if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main( #if defined(HAVE_SQLITE3) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="sqlite3" rpm_requires="sqlite3-devel >= 1.8" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_SQLITE) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="sqlite" rpm_requires="sqlite2-devel >= 2.7" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_PGSQL) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="pgsql" rpm_requires="postgresql-devel >= 7.2" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_ORACLE) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="oracle" rpm_requires="oracle-instantclient-devel >= 8" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_MYSQL) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="mysql" rpm_requires="mysql-devel >= 3.23" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_SDB) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="sdb" rpm_requires="libsdb-devel >= 0.5" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } nl=' ' echo "${nl}${T_MD}Generating output files ...${T_ME}" ac_config_files="$ac_config_files Makefile gw/Makefile rpm/sqlbox.spec" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by sqlbox $as_me cvs, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ sqlbox config.status cvs configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_flag_spec_ld \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "sb-config.h") CONFIG_HEADERS="$CONFIG_HEADERS sb-config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "gw/Makefile") CONFIG_FILES="$CONFIG_FILES gw/Makefile" ;; "rpm/sqlbox.spec") CONFIG_FILES="$CONFIG_FILES rpm/sqlbox.spec" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010 Free Software Foundation, # Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # If ld is used when linking, flag to hardcode \$libdir into a binary # during linking. This must work even if \$libdir does not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi nl=' ' echo "${nl}${T_MD}License information ...${T_ME}" cat < | +--------------------------------------------------------------------+ Thank you for using Kannel. X gateway-1.4.5/addons/sqlbox/sb-config.h.in0000644000175000017500000000667111562447370017114 0ustar toljtolj/* sb-config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ #undef CLOSEDIR_VOID /* Defined to 1 */ #undef HAVE_CTLIB /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `gwlib' library (-lgwlib). */ #undef HAVE_LIBGWLIB /* Define to 1 if you have the `ssl' library (-lssl). */ #undef HAVE_LIBSSL /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_CRYPTO_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_ERR_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_PEM_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_RSA_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_X509_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Version number of package */ #undef VERSION /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to empty if the keyword `volatile' does not work. Warning: valid code using `volatile' can become incorrect without. Disable with care. */ #undef volatile gateway-1.4.5/addons/sqlbox/example/0000755000175000017500000000000013312227715016102 5ustar toljtoljgateway-1.4.5/addons/sqlbox/example/sqlbox.conf.example0000644000175000017500000000263011111426361021705 0ustar toljtoljgroup = sqlbox id = sqlbox-db smsbox-id = sqlbox #global-sender = "" bearerbox-host = localhost bearerbox-port = 13001 smsbox-port = 13005 smsbox-port-ssl = false sql-log-table = sent_sms sql-insert-table = send_sms log-file = "/var/log/kannel/kannel-sqlbox.log" log-level = 0 #ssl-client-certkey-file = "" #ssl-server-cert-file = "" #ssl-server-key-file = "" #ssl-trusted-ca-file = "" # Database connection examples. Please uncomment as needed # Example MYSQL Connection #group = mysql-connection #id = sqlbox-db #host = localhost #username = myuser #password = mypass #database = kannel # Example ORACLE Connection #group = oracle-connection #id = sqlbox-db #username = myuser #password = mypass #tnsname = //localhost:1521/XE # Example POSTGRESQL Connection #group = pgsql-connection #id = sqlbox-db #id = sqlbox-db #username = myuser #password = mypass #database = kannel #host = localhost # Example SDB Connection with some database URL examples # *** Note: Uncomment only _one_ "url" line *** #group = sdb-connection #id = sqlbox-db #url = mysql:host=localhost:db=kannel:uid=myuser:pwd=mypass #url = sqlite:db=/path/to/kannel.db #url = sqlite3:db=/path/to/kannel3.db # Example SQLITE 2 Connection #group = sqlite-connection #id = sqlbox-db #database = /path/to/kannel.db #max-connections = 1 # Example SQLITE 3 Connection #group = sqlite3-connection #id = sqlbox-db #database = /path/to/kannel.db #max-connections = 1 gateway-1.4.5/addons/sqlbox/README0000644000175000017500000000231511107147071015324 0ustar toljtoljOVERVIEW ======== Sqlbox is a special Kannel box that sits between bearerbox and smsbox and uses a database queue to store and forward messages. Sqlbox behaves similar to other Kannel boxes and share a compatible configuration file format and command line options. It works between bearerbox and smsbox, intercept all messages and use a couple of database tables to process messages. Messages are queued on a configurable table (defaults to send_sms) and moved to another table (defaults to sent_sms) afterwards. You can also manually insert messages into the send_sms table and they will be sent and moved to the sent_sms table as well. This allows for fast and easy injection of large amounts of messages into kannel. INSTALLATION ============ Please read the INSTALL file for further instructions. If in a hurry, the quick explanation is: ./bootstrap ./configure make And finally, as root: make install You need to have a compiled version of Kannel available in order to compile sqlbox. The Userguide has also valuable information about the install and configuration steps. HELP ==== The best to ask for help is on Kannel's mailing lists. Please visit Kannel's site for more information: http://www.kannel.org/ gateway-1.4.5/addons/sqlbox/NEWS0000644000175000017500000000012511111426361015135 0ustar toljtoljSqlBox Stand Alone Module Please read the ChangeLog file to see the latest changes. gateway-1.4.5/addons/sqlbox/doc/0000755000175000017500000000000013312227715015214 5ustar toljtoljgateway-1.4.5/addons/sqlbox/doc/userguide.xml0000644000175000017500000020751412327711710017741 0ustar toljtolj ]> sqlbox &version;×tamp; User's Guide SQL-Based queue engine for Kannel Rene Kluwen Sqlbox Author Chimit
rene.kluwen at chimit dot nl http://www.chimit.nl/
Martin Conte Mac Donell Standalone Version and Patches
reflejo at gmail dot com
Alejandro Guerrieri Maintainer, Documentation and Patches Magicom
aguerrieri at kannel dot org http://www.blogalex.com/
Abstract This document describes how to install and use sqlbox, the SQL-Based queue engine for Kannel. &version; ×tamp;
Introduction Sqlbox is a special Kannel box that sits between bearerbox and smsbox and uses a database queue to store and forward messages. Overview Sqlbox behaves similar to other Kannel boxes and share a compatible configuration file format and command line options. It works between bearerbox and smsbox, intercept all messages and use a couple of database tables to process messages. Messages are queued on a configurable table (defaults to send_sms) and moved to another table (defaults to sent_sms) afterwards. You can also manually insert messages into the send_sms table and they will be sent and moved to the sent_sms table as well. This allows for fast and easy injection of large amounts of messages into kannel. Features Modular architecture: Easily integrates into Kannel infrastructure. Compatible configuration file format and command line arguments. Supports most Kannel features. Requirements sqlbox is being developed on Linux and OSX systems, and should be fairly easy to export to other Unix-like systems. However, we don't yet support other platforms, due to lack of time, although it should be working without major problems on Windows (through Cygwin), Mac OSX, Solaris and FreeBSD. sqlbox requires the following software environment: Kannel libraries (gwlib) installed. C compiler and libraries for ANSI C, with normal Unix extensions such as BSD sockets and related tools. (GNU's GCC tool-chain is recommended) GNU Make. An implementation of POSIX threads ( pthread.h ). DocBook processing tools: DocBook style-sheets, jade, jadetex, etc; see README , section `Documentation', for more information (pre-formatted versions of the documentation are available, and you can compile Sqlbox itself even without the documentation tools). GNU autoconf Installing sqlbox This chapter explains how to build and install sqlbox from source or from a binary package. The goal of this chapter is to get the module compiled and all the files in the correct places; the next chapter will explain how to configure it. If you are upgrading from a previous version, please look at for any important information. Getting the source code The source code to Sqlbox is available for download at http://www.kannel.org/~aguerrieri/. It is available in various formats and you can choose to download either the latest release version or the daily snapshot of the development source tree for the next release version, depending on whether you want to use Sqlbox for production use or to participate in the development. If you're serious about development, you probably want to use CVS, the version control system used by the Kannel project. This allows you to participate in Sqlbox development much more easily than by downloading the latest release and integrating any changes you've made every day. CVS does that for you. (See the Kannel web site for more information on how to use CVS.) Finding the documentation The documentation for Sqlbox consists of two parts: User's Guide , i.e., the one you're reading at the moment. The README and various other text files in the source tree. You can also find general information on Kannel's website and information about existing problems at our bugtracker . We intend to cover everything you need to install and use Sqlbox is in User's Guide , but the guide is still incomplete in this respect. The README is not supposed to be very important, nor contain much information. Instead, it will just point at the other documentation. Compiling sqlbox If you are using Sqlbox on a supported platform, or one that is similar enough to one, compiling Sqlbox should be trivial. After you have unpacked the source package of your choose, or after you have checked out the source code from CVS, enter the following commands: ./bootstrap ./configure make The bootstrap script uses autoconf to generate the files needed to build the module. The configure script investigates various things on your computer for the Sqlbox compilation needs, and writes out the Makefile used to compile the module. make then runs the commands to actually compile it. If either command writes out an error message and stops before it finishes its job, you have a problem, and you either need to fix it yourself, if you can, or report the problem to the Kannel project. See for details. For detailed instruction on using the configuration script, see file INSTALL . That file is a generic documentation for configure . Sqlbox defines a few additional options: --with-kannel-dir= DIR Where to look for Kannel Gateway libs and header files DIR points to the Kannel installation directory. Defaults to /usr/local --disable-docs (default is --enable-docs) Use this option if you don't have DocBook installed and/or you want to save some time and CPU cycles. Pre-generated documentation is available on Kannel's site. Default behavior is to build documentation, b.e., converting the User Guide from the DocBook markup language to PostScript and HTML if DocBook is available. --enable-drafts (default is --disable-drafts) When building documentation, include the sections marked as draft . --with-ctlib=DIR Include Ct-Lib support. DIR is the Ct-Lib install directory, defaults to /opt/sybase. --with-freetds=DIR Include FreeTDS Ct-Lib support. DIR is the FreeTDS install directory, defaults to /usr/local. You may need to add compilations flags to configure: CFLAGS='-pthread' ./configure The above, for instance, seems to be required on FreeBSD. If you want to develop Sqlbox, you probably want to add CFLAGS that make your compiler use warning messages. For example, for GCC: CFLAGS='-Wall -O2 -g' ./configure (You may, at your preference, use even stricter checking options.) Installing Sqlbox After you have compiled Kannel, you need to install the sqlbox binary in a suitable place. This is most easily done by using make again: make bindir=/path/to/directory install Replace /path/to/directory with the pathname of the actual directory where the programs should be installed. This install the sqlbox binary: gw/sqlbox Using pre-compiled binary packages To be done Installing Sqlbox from RPM packages To be done Installing Sqlbox from DEB packages To be done Using sqlbox This chapter explains how to configure and run Sqlbox and also how to tell if it's running from Kannel's HTTP interface. There is only one configuration file for Sqlbox, and that file commands all aspects of its execution. Configuring Sqlbox The configuration file can be divided into two parts: sqlbox configuration and database connection. Details of each part are in appropriate sections later on this documentation. Configuration file syntax The syntax used for the configuration file is the same used in Kannel. Skip this section if you are already familiar with it. Otherwise, keep on reading: A configuration file consists of groups of configuration variables. Groups are separated by empty lines, and each variable is defined on its own line. Each group in Sqlbox configuration is distinguished with a group variable. Comments are lines that begin with a number sign ( # ) and are ignored (they don't, for example, separate groups of variables). A variable definition line has the name of the variable, and equals sign ( = ) and the value of the variable. The name of the variable can contain any characters except whitespace and equals. The value of the variable is a string, with or without quotation marks ( ) around it. Quotation marks are needed if the variable needs to begin or end with whitespace or contain special characters. Normal C escape character syntax works inside quotation marks. Perhaps an example will make things easier to comprehend: 01 # Sqlbox configuration 02 group = sqlbox 03 id = "my-sqlbox" 04 smsbox-id = "sqlbox" ... 11 log-level = 0 12 log-file = "/var/log/kannel/kannel-sqlbox.log" 13 14 #MySQL Connection 15 group = mysql-connection 16 id = "my-sqlbox" 17 host = localhost ... The above snippet defines an sqlbox instance with id my-sqlbox that identifies with bearerbox as sqlbox and also sets the log-level and file location. It also defines a MySQL connection to localhost. Lines 1 and 14 are comment lines. Line 13 separates the two groups. The remaining lines define variables. The group type is defined by the group variable value. The various variables that are understood in each type of configuration group are explained below. Some variable values are marked as 'bool'. The value for variable can be like true, false, yes, no, on, off, 0 or 1. Other values are treated as 'true' while if the variable is not present at all, it is treated as being 'false'. Inclusion of configuration files A configuration file may contain a special directive called include to include other file or a directory with files to the configuration processing. This allows to segment the specific configuration groups required for several services and boxes to different files and hence to have more control in larger setups. Here is an example that illustrates the include statement : group = sqlbox id = my-sqlbox smsbox-id = sqlbox ... log-file = "/var/log/kannel/kannel-sqlbox.log" log-level = 0 include = "dbconn.conf" Above is the main sqlbox.conf configuration file that includes the following dbconn.conf file with all required directives for the database connection. group = mysql-connection id = my-sqlbox host = localhost username = myuser password = mypass database = kannel The above include statement may be defined at any point in the configuration file and at any inclusion depth. Hence you can cascade numerous inclusions if necessary. At process start time inclusion of configuration files breaks if either the included file can not be opened and processed or the included file has been processed already in the stack and a recursive cycling has been detected. Sqlbox configuration The configuration file MUST always include an 'sqlbox' group for general configuration. This group should be the first group in the configuration file. As its simplest form, 'sqlbox' group looks like this: group = sqlbox id = sqlbox bearerbox-port = 13001 Naturally this is usually not sufficient for any real use. Thus, one or more of the optional configuration variables are used. In following list (as in any other similar lists), all mandatory variables are marked with (m), while conditionally mandatory (variables which must be set in certain cases) are marked with (c) .
Sqlbox Group Variables Variable Value Description group (m) sqlbox This is a mandatory variable smsbox-id (m) string This is the box id. global-sender number If no explicit number is given, this number is used when sending messages. bearerbox-host (m) host-name This is the host where bearerbox is running. bearerbox-port (m) port-number This is the port number used to connect to bearerbox. smsbox-port (c) port-number This is the port number to which the smsboxes, if any, connect. This can be anything you want. Must be set if you want to handle any SMS traffic. smsbox-port-ssl (o) bool If set to true, the smsbox connection module will be SSL-enabled. Your smsboxes will have to connect using SSL to sqlbox then. This is used to secure communication between sqlbox and smsboxes in case they are in separate networks operated and the TCP communication is not secured on a lower network layer. Defaults to "no". limit-per-cycle number Sqlbox processes this number of messages at a time. Note: Currently only the MySQL driver supports this configuration directive. Defaults to 10. If you raise this number high enough, you might want to increase max_allowed_packet in your MySQL configuration. save-dlr (o) bool Indicates whether to save dlr messages in the sql-log-table. Defaults to "yes". save-mo (o) bool Indicates whether to save mobile originated (MO) messages in the sql-log-table. Defaults to "yes". save-mt (o) bool Indicates whether to save mobile terminated (MT) messages in the sql-log-table. This applies to messages that are sent via smsbox as well as messages inserted in the sql-insert-table. Defaults to "yes". sql-log-table table-name Indicates the table where messages are copied after being sent. Defaults to sent_sms. sql-insert-table table-name Indicates the table where messages should be inserted to sent. Defaults to send_sms. log-file filename A file in which to write a log. This in addition to stdout and any log file defined in command line. log-level number 0..5 Minimum level of log-file events logged. 0 is for 'debug', 1 'info', 2 'warning, 3 'error' and 4 'panic' (see Command Line Options)
A sample more complex 'sqlbox' group could be something like this: group = sqlbox id = sqlbox-db smsbox-id = sqlbox #global-sender = "" bearerbox-host = localhost bearerbox-port = 13001 smsbox-port = 13005 smsbox-port-ssl = false sql-log-table = sent_sms sql-insert-table = send_sms log-file = "/var/log/kannel/kannel-sqlbox.log" log-level = 0 The DB Connection sqlbox needs a connection to a supported DB engine to operate. This connection is established at startup time and kept open until the box stops. At the moment, sqlbox supports MySQL, Oracle, PostgreSQL, LibSDB, MS-SQL, Sybase, Sqlite2 and Sqlite3, though only MySQL and PostgreSQL are tested enough to be considered stable. The process of configuring a DB connection is simple: You need to create a [engine]-connection section (where [engine] is the DB engine name, either mysql, oracle, pgsql, sdb, sqlite or sqlite3) and indicate a few parameters needed to establish the DB connection. MySQL Storage Uses a MySQL database to store the data. You need to specify the mysql-connection group. MySql Database connection configuration variables Variable Value Description group mysql-connection (m) This is a mandatory variable. id (m) string An id to identify which external connection should be used for Sqlbox storage. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. host (m) string The hostname where the MySQL engine is running. port number The port where the MySQL engine is running. username (m) string The username used to connect to the MySQL engine. password (m) string The password used to connect to the MySQL engine. database (m) string The database name to use to store the data. max-connections number Create a pool with this number of connections open.
Example configuration: group = mysql-connection id = my-sqlbox host = localhost username = foo password = bar database = kannel max-connections = 1
MS-SQL/Sybase Storage (using FreeTDS) Uses an MS-SQL or Sybase database to store the data. You need to specify the mssql-connection group. MS-SQL/Sybase Database connection configuration variables Variable Value Description group mssql-connection (m) This is a mandatory variable. id (m) string An id to identify which external connection should be used for Sqlbox storage. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. server (m) string The server definition used to connect to the MS-SQL/Sybase engine (this should be identical to the one defined on freetds.conf). username (m) string The username used to connect to the MS-SQL/Sybase engine. password (m) string The password used to connect to the MS-SQL/Sybase engine. max-connections number Create a pool with this number of connections open.
Example configuration: group = oracle-connection server = myserver username = foo password = bar max-connections = 1
Oracle Storage Uses an Oracle database to store the data. You need to specify the oracle-connection group. Oracle Database connection configuration variables Variable Value Description group oracle-connection (m) This is a mandatory variable. id (m) string An id to identify which external connection should be used for Sqlbox storage. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. tnsname (m) string The tnsname used to connect to the Oracle engine. username (m) string The username used to connect to the Oracle engine. password (m) string The password used to connect to the Oracle engine. max-connections number Create a pool with this number of connections open.
Example configuration: group = oracle-connection tnsname = //localhost:1521/XE username = foo password = bar max-connections = 1
PostgreSQL Storage Uses a PostgreSQL database to store the data. You need to specify the pgsql-connection group. PostgreSQL Database connection configuration variables Variable Value Description group pgsql-connection (m) This is a mandatory variable. id (m) string An id to identify which external connection should be used for Sqlbox storage. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. host (m) string The hostname where the PostgreSQL engine is running. username (m) string The username used to connect to the PostgreSQL engine. password (m) string The password used to connect to the PostgreSQL engine. database (m) string The database name to use to store the data. max-connections number Create a pool with this number of connections open.
Example configuration: group = pgsql-connection id = pg-sqlbox host = localhost username = foo password = bar database = kannel max-connections = 1
LibSDB Abstraction Layer Uses the LibSDB database abstraction layer to transparently connect to a database that stores the data. You need to specify the sdb-connection group. LibSDB Database connection configuration variables Variable Value Description group sdb-connection (m) This is a mandatory variable. id (m) string An id to identify which external connection should be used for Sqlbox storage. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. url (m) string The LibSDB URL used to connect to the database. See the LibSDB web site for information about how to construct the URL to connect to your particular DB engine. max-connections number Create a pool with this number of connections open.
Example configuration: group = sdb-connection id = sd-sqlbox #url = mysql:host=localhost:db=kannel:uid=myuser:pwd=mypass #url = sqlite:db=/path/to/kannel.db url = sqlite3:db=/path/to/kannel3.db max-connections = 1
Sqlite 2.x Storage Uses a Sqlite 2.x database to store the data. You need to specify the sqlite-connection group. Sqlite 2.x Database connection configuration variables Variable Value Description group sqlite-connection (m) This is a mandatory variable. id (m) string An id to identify which external connection should be used for Sqlbox storage. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. database (m) string The full path to the Sqlite 2.x database file used to store the data. Creates the file if it doesn't exists. lock-timeout string Time to wait for a lock to free before giving up. You may need to tweak this if you experience lock issues. The default is to let Sqlite 2.x do it's default behaviour. max-connections number Create a pool with this number of connections open.
Example configuration: group = sqlite-connection id = s2-sqlbox host = localhost database = /path/to/kannel.db lock-timeout = 5 max-connections = 1
Sqlite 3.x Storage Uses a Sqlite 3.x database to store the data. You need to specify the sqlite3-connection group. Sqlite 3.x Database connection configuration variables Variable Value Description group sqlite3-connection (m) This is a mandatory variable. id (m) string An id to identify which external connection should be used for Sqlbox storage. Any string is acceptable, but semicolon ';' may cause problems, so avoid it and any other special non-alphabet characters. database (m) string The full path to the Sqlite 3.x database file used to store the data. Creates the file if it doesn't exists. lock-timeout string Time to wait for a lock to free before giving up. You may need to tweak this if you experience lock issues. The default is to let Sqlite 3.x do it's default behaviour. max-connections number Create a pool with this number of connections open.
Example configuration: group = sqlite3-connection id = s3-sqlbox host = localhost database = /path/to/kannel3.db lock-timeout = 5 max-connections = 1
Running Sqlbox You need to start sqlbox after starting the bearerbox, otherwise it won't have a port open to connect to. The preferred way to do this is to include sqlbox into your Kannel's startup script. Starting the box If you want to start it from command line (for testing, for example), give the following command: /path/to/sqlbox -v 1 [config-file] The sets the logging level to INFO. This way, you won't see a large amount of debugging output (the default is DEBUG). Full explanation of Sqlbox command line arguments is below. [config-file] is the name of the configuration file you are using with Sqlbox. The basic distribution packet comes with a sample configuration file you can use with some minor tweakings (check on the /examples folder. Feel free to edit the file to suit your needs. Of course you need to have the bearerbox running before starting the box. Without the bearer box, sqlbox won't even start. Command line options Sqlbox accept certain command line options and arguments when they are launched. These arguments are: Sqlbox Command Line Options -v <level> Set verbosity level for stdout (screen) logging. Default is 0, which means 'debug'. 1 is 'info, 2 'warning', 3 'error' and 4 'panic' --verbosity <level>-D <places> Set debug-places for 'debug' level output. --debug <places>-F <file-name> Log to file named file-name, too. Does not overrun or affect any log-file defined in configuration file. --logfile <file-name>-V <level> Set verbosity level for that extra log-file (default 0, which means 'debug'). Does not affect verbosity level of the log-file defined in configuration file, not verbosity level of the stdout output. --fileverbosity <level>-H Only try to open HTTP sendsms interface; if it fails, only warn about that, do not exit. (smsbox only) --tryhttp-g Dump all known config groups and config keys to stdout and exit. --generate-u <username> Change process user-id to the given. --user <username>-p <filename> Write process PID to the given file. --pid-file <filename>-d Start process as daemon (detached from a current shell session). Note: Process will change CWD (Current working directory) to /, therefore you should ensure that all paths to binary/config/config-includes are absolute instead of relative. --daemonize-P Start watcher process. This process watch a child process and if child process crashed will restart them automatically. --parachute-X <scriptname> Execute a given shell script or binary when child process crash detected. This option is usable only with --parachute/-P. Script will be executed with 2 arguments: scriptname 'processname' 'respawn-count'. --panic-script <scriptname>
Database Tables Sqlbox creates it's DB tables on the fly if the tables are not present at that moment. If you're upgrading from a previous version, or happen to have tables with the same names as the ones Sqlbox uses, but having a different structure, this will probably cause problems and there's a good chance the process will panic and stop. In that case, rename/drop the offending tables or change the names Sqlbox uses by using the sql-log-table and sql-insert-table variables.
Inserting MT messages by SQL One of the nice features Sqlbox provides is the ability to insert MT messages into Kannel's queue by inserting rows into the send_sms table. Keep in mind that both tables have the same schema, but you only need to care about send_sms. Sqlbox will move messages to the sent_sms table autmatically after processing it. Database Structure The tables structure is as follows: Sqlbox Database structure Value Type Description sendsms equivalent sql_id BIGINT(20) This is the auto-incremented PRIMARY KEY and should be always left alone. Set it to NULL or do not include it in your INSERT query. - momt ENUM('MO', 'MT') Specifies if the message is either MO or MT. You should always use "MT" here. - sender VARCHAR(20) Phone number of the sender. If this variable is not set, sqlbox global-sender is used. from receiver VARCHAR(20) Phone number of the receiver. to msgdata TEXT Contents of the message, URL encoded as necessary. The content can be more than 160 characters, but then Kannel's sendsms-user group must have max-messages set more than 1. text udhdata BLOB Optional User Data Header (UDH) part of the message. Must be URL encoded. udh time BIGINT(20) An integer timestamp. You can uses UNIX_TIMESTAMP() on MySQL or any similar function here. You can also leave the field empty/alone if you don't care about having a timestamp on your messages. - smsc_id VARCHAR(255) Optional virtual smsc-id from which the message is supposed to have arrived. This is used for routing purposes, if any denied or preferred SMS centers are set up in SMS center configuration. This variable can be overridden on Kannel with a forced-smsc configuration variable. Likewise, the default-smsc variable can be used to set the SMSC if it is not set otherwise. smsc service VARCHAR(255) Optional. Service name from which the message is supposed to have arrived. This field is logged as SVC in the log file so it allows you to do some accounting on it if your front end uses the same username for all services but wants to distinguish them in the log. smsc account VARCHAR(255) Optional. Account name or number to carry forward for billing purposes. This field is logged as ACT in the log file so it allows you to do some accounting on it if your front end uses the same username for all services but wants to distinguish them in the log. In the case of a HTTP SMSC type the account name is prepended with the service-name (username) and a colon (:) and forwarded to the next instance of Kannel. This allows hierarchical accounting. account id BIGINT(20) Kannel's internal message identifier. This have no meaning when you're inserting your own messages, since Kannel doesn't have an identifier on your message yet. Leave it alone. - sms_type BIGINT(20) A numeric value indicating if it's an MO, MT or DLR message. ALWAYS INSERT A "2" HERE (Meaning: MT), OTHERWISE KANNEL'S QUEUE WILL GET CORRUPTED IF YOU RESTART IT AND YOU HAVE PENDING MESSAGES. - mclass BIGINT(20) Optional. Sets the Message Class in DCS field. Accepts values between 0 and 3, for Message Class 0 to 3, A value of 0 sends the message directly to display, 1 sends to mobile, 2 to SIM and 3 to SIM toolkit. mclass mwi BIGINT(20) Optional. Sets Message Waiting Indicator bits in DCS field. If given, the message will be encoded as a Message Waiting Indicator. The accepted values are 0,1,2 and 3 for activating the voice, fax, email and other indicator, or 4,5,6,7 for deactivating, respectively. To set number of messages, use mwi=[0-3]&coding=0&udh=%04%01%02%<XX>%<YY>, where YY are the number of messages, in HEX, and XX are mwi plus 0xC0 if text field is not empty. mwi coding BIGINT(20) Optional. Sets the coding scheme bits in DCS field. Accepts values 0 to 2, for 7bit, 8bit or UCS-2. If unset, defaults to 7 bits unless a udh is defined, which sets coding to 8bits. coding compress BIGINT(20) Optional. Sets the Compression bit in DCS Field. compress validity BIGINT(20) Optional. If given, Kannel will inform SMS Center that it should only try to send the message for this many minutes. If the destination mobile is off other situation that it cannot receive the sms, the smsc discards the message. Note: you must have your Kannel box time synchronized with the SMS Center. validity deferred BIGINT(20) Optional. If given, the SMS center will postpone the message to be delivered at now plus this many minutes. Note: you must have your Kannel box time synchronized with the SMS Center. deferred dlr-mask BIGINT(20) Optional. Request for delivery reports with the state of the sent message. The value is a bit mask composed of: 1: Delivered to phone, 2: Non-Delivered to Phone, 4: Queued on SMSC, 8: Delivered to SMSC, 16: Non-Delivered to SMSC. Must set dlr-url on sendsms-user group or use the sendsms dlr-url variable or Sqlbox column. dlr-mask dlr-url VARCHAR(255) Optional. If dlr-mask is given, this is the url to be fetched. (Must be url-encoded) dlr-url pid BIGINT(20) Optional. Sets the PID value. (See ETSI Documentation). Ex: SIM Toolkit messages would use something like pid=127, coding=1, alt-dcs=1, mclass=3 pid alt-dcs BIGINT(20) Optional. If unset, Kannel uses the alt-dcs defined on smsc configuration, or 0X per default. If equals to 1, uses FX. If equals to 0, force 0X. alt-dcs rpi BIGINT(20) Optional. Sets the Return Path Indicator (RPI) value. (See ETSI Documentation). rpi charset VARCHAR(255) Charset of text message. Used to convert to a format suitable for 7 bits or to UCS-2. Defaults to WINDOWS-1252 if coding is 7bits and UTF-16BE if coding is UCS-2. charset boxc_id VARCHAR(255) The bearerbox ID that should handle this message. You can usually leave this one alone. charset binfo VARCHAR(255) Optional. Billing identifier/information proxy field used to pass arbitrary billing transaction IDs or information to the specific SMSC modules. For EMI2 this is encapsulated into the XSer 0c field, for SMPP this is encapsulated into the service_type of the submit_sm PDU. binfo
Example As when you're using the sendsms interface, you don't need to specify all the columns in order to succesfully enqueue a message. Here's an example query you can use to send a simple message using Sqlbox: INSERT INTO send_sms ( momt, sender, receiver, msgdata, sms_type ) VALUES ( 'MT', '1234', '1234567890', 'Hello world', 2 ); The former example would send a message with text "Hello world" to number "1234567890". If possible, the sender would be set to "1234". You can add other parameters to specify routing, charset encoding and any other settings your setup may require. Just remember, try to keep it simple whenever possible
Getting help and reporting bugs This chapter explains where to find help with problems related to the gateway, and the preferred procedure for reporting bugs and sending corrections to them. The Kannel development mailing list is devel@kannel.org. To subscribe, send mail to devel-subscribe@kannel.org. This is currently the best location for asking help and reporting bugs. Please include configuration file and version number. Upgrading notes This appendix includes pertinent information about required changes on upgrades. As a general rule, always check the ChangeLog file before upgrading, because it may contain important information worth knowing before making any changes. Upgrading from different sqlbox versions Sqlbox is a simple module that usually upgrades easily and without requiring any other changes. In some cases, a change on the DB structure takes place and this requires changes on the DB schemas as well. Since sqlbox automatically generates its tables, the best approach for this kind of upgrades is to make sure that there's no messages pending, backup the tables contents (if there's no messages pending only the sent_sms table will have records), drop the tables and let sqlbox create the tables again. Alternatively you can check what changes are necessary and ALTER the tables yourself. gateway-1.4.5/addons/sqlbox/Makefile.am0000644000175000017500000000553012327711710016504 0ustar toljtoljman1pages = gw/sqlbox.1 man5pages = gw/sqlbox.5 docsrcs = $(wildcard grep -l ' $*.tmp ${JADE} -V nochunks -t sgml -d $(HTML_DSL) $(XML_DCL) $*.tmp > $@ rm -f $*.tmp .xml.rtf: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp cd `dirname $<` && $(JADE) -o `basename $*`.rtf -t rtf -d $(TEX_DSL) $(XML_DCL) `basename $*`.tmp rm -f $*.tmp .xml.ps: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || \ ( echo Check `dirname $<`/`basename $*`.log for errors && false) rm -f $*.log cd `dirname $<` && $(DVIPS) -q -o `basename $*`.ps `basename $*`.dvi rm -f $*.dvi $*.tex $*.aux .xml.pdf: sed "s/#FIGTYPE#/.png/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true rm -f $*.log $*.dvi cd `dirname $<` && $(PDFJADETEX) `basename $*`.tex > /dev/null || true test -r $*.pdf || false rm -f $*.log $*.tex $*.aux $*.out .fig.png: $(FIG2DEV) -Lpng $< $@ .fig.ps: $(FIG2DEV) -Lps $< $@ .png.ps: $(CONVERT) $< $@ rpm: clean @echo "Preparing to build the RPM files" mkdir -p "$(rpmtemp)/${RPMPKG}" cp -R * "$(rpmtemp)/${RPMPKG}" tar -C "$(rpmtemp)" -c ${RPMPKG} -zf ${RPMPKG}.tar.gz rm -rf "$(rpmtemp)/${RPMPKG}" if [ -d $(rpmtemp) ]; then rmdir "$(rpmtemp)"; fi @echo "Building the RPM" rpmbuild -ta ${RPMPKG}.tar.gz rm -f ${RPMPKG}.tar.gz @echo "**********************************************************************" @echo "* Success!" @echo "* Your files are located under $(shell rpm --eval '%_rpmdir')" @echo "* The Kannel Group " @echo "**********************************************************************" @echo "Thank you for using Kannel." docs: figs ps $(docs) no-docs: figs: $(figs) ps: $(ps) pp: $(pres) SUBDIRS = gw EXTRA_DIST = KannelLICENSE bootstrap gateway-1.4.5/addons/sqlbox/UPGRADE0000644000175000017500000000107211467071614015465 0ustar toljtolj***** IMPORTANT NOTICE ***** If you're upgrading from a version BEFORE 2010-11-11 (0.7.x and lower), please note that the format for the msgdata and udhdata columns is now url-encoded. That probably means that if you use inserts on send_sms to send MT, YOU WILL NEED TO MODIFY YOUR CODE TO URLENCODE THE MESSAGES FIRST. ***** OLDER COMMENTS ***** If you are upgrading from a previous sqlbox version before 2006-05-30, you will have to modify your existing sql table structure by issuing the following command: ALTER TABLE sent_sms MODIFY momt enum('MO','MT','DLR'); gateway-1.4.5/addons/sqlbox/gw/0000755000175000017500000000000013312227714015063 5ustar toljtoljgateway-1.4.5/addons/sqlbox/gw/sqlbox_sdb.h0000644000175000017500000000201112203523676017372 0ustar toljtolj#include "gwlib/gwlib.h" #ifdef HAVE_SDB #define SQLBOX_OTHER_SELECT_QUERY "SELECT sql_id, momt, sender, receiver, udhdata, \ msgdata, time, smsc_id, service, account, id, sms_type, mclass, mwi, coding, \ compress, validity, deferred, dlr_mask, dlr_url, pid, alt_dcs, rpi, \ charset, boxc_id, binfo, meta_data FROM %S" #define SQLBOX_OTHER_INSERT_QUERY "INSERT INTO %S (sql_id, momt, sender, \ receiver, udhdata, msgdata, time, smsc_id, service, account, sms_type, \ mclass, mwi, coding, compress, validity, deferred, dlr_mask, dlr_url, \ pid, alt_dcs, rpi, charset, boxc_id, binfo, foreign_id ) VALUES ( \ NULL, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, \ %S, %S, %S, %S, %S, %S, %S, %S, %S, %S)" #define SQLBOX_OTHER_DELETE_QUERY "DELETE FROM %S WHERE sql_id = %S" #include "gw/msg.h" #include "sqlbox_sql.h" void sql_save_msg(Msg *msg, Octstr *momt ); Msg *sdb_fetch_msg(); void sql_shutdown(); struct server_type *sqlbox_init_sdb(Cfg *cfg); #ifndef sqlbox_sdb_c extern #endif Octstr *sqlbox_id; #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_oracle.c0000644000175000017500000002731612203523676020101 0ustar toljtolj#include "gwlib/gwlib.h" #ifdef HAVE_ORACLE #include "gwlib/dbpool.h" #include #define sqlbox_oracle_c #include "sqlbox_oracle.h" #define sql_update dbpool_conn_update #define sql_select dbpool_conn_select static Octstr *sqlbox_logtable; static Octstr *sqlbox_insert_table; /* * Our connection pool to oracle. */ static DBPool *pool = NULL; void sqlbox_configure_oracle(Cfg* cfg) { DBPoolConn *pc; CfgGroup *grp; Octstr *sql; if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: Oracle: group 'sqlbox' is not specified!"); sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table")); if (sqlbox_logtable == NULL) { panic(0, "Parameter 'sql-log-table' not configured."); } sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table")); if (sqlbox_insert_table == NULL) { panic(0, "Parameter 'sql-insert-table' not configured."); } pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "Oracle: DBPool Error!"); return; } /* create send_sms && sent_sms tables if they do not exist */ sql = octstr_format(SQLBOX_ORACLE_CREATE_LOG_TABLE, sqlbox_logtable, sqlbox_logtable); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); octstr_destroy(sql); sql = octstr_format(SQLBOX_ORACLE_CREATE_INSERT_TABLE, sqlbox_insert_table, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); octstr_destroy(sql); /* * Oracle implementation using a sequence and a trigger for auto_increment fields. */ sql = octstr_format(SQLBOX_ORACLE_CREATE_LOG_SEQUENCE, sqlbox_logtable); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); octstr_destroy(sql); sql = octstr_format(SQLBOX_ORACLE_CREATE_INSERT_SEQUENCE, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); octstr_destroy(sql); sql = octstr_format(SQLBOX_ORACLE_CREATE_LOG_TRIGGER, sqlbox_logtable, sqlbox_logtable, sqlbox_logtable); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); octstr_destroy(sql); sql = octstr_format(SQLBOX_ORACLE_CREATE_INSERT_TRIGGER, sqlbox_insert_table, sqlbox_insert_table, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); octstr_destroy(sql); /* end table creation */ dbpool_conn_produce(pc); } #define octstr_null_create(x) ((x != NULL) ? octstr_create(x) : octstr_create("")) #define atol_null(x) ((x != NULL) ? atol(x) : -1) #define get_oracle_octstr_col(x) (octstr_create(octstr_get_cstr(gwlist_get(row,x)))) #define get_oracle_long_col(x) (atol(octstr_get_cstr(gwlist_get(row,x)))) Msg *oracle_fetch_msg() { Msg *msg = NULL; Octstr *sql, *delet, *id; List *res, *row, *binds = gwlist_create(); int ret; DBPoolConn *pc; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "Oracle: DBPool error!"); return; } sql = octstr_format(SQLBOX_ORACLE_SELECT_QUERY, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (sql_select(pc, sql, NULL, &res) != 0) { debug("sqlbox", 0, "SQL statement failed: %s", octstr_get_cstr(sql)); } else { if (gwlist_len(res) > 0) { row = gwlist_extract_first(res); id = get_oracle_octstr_col(0); /* save fields in this row as msg struct */ msg = msg_create(sms); /* we abuse the foreign_id field in the message struct for our sql_id value */ msg->sms.foreign_id = get_oracle_octstr_col(0); msg->sms.sender = get_oracle_octstr_col(2); msg->sms.receiver = get_oracle_octstr_col(3); msg->sms.udhdata = get_oracle_octstr_col(4); msg->sms.msgdata = get_oracle_octstr_col(5); msg->sms.time = get_oracle_long_col(6); msg->sms.smsc_id = get_oracle_octstr_col(7); msg->sms.service = get_oracle_octstr_col(8); msg->sms.account = get_oracle_octstr_col(9); /* msg->sms.id = get_oracle_long_col(10); */ msg->sms.sms_type = get_oracle_long_col(11); msg->sms.mclass = get_oracle_long_col(12); msg->sms.mwi = get_oracle_long_col(13); msg->sms.coding = get_oracle_long_col(14); msg->sms.compress = get_oracle_long_col(15); msg->sms.validity = get_oracle_long_col(16); msg->sms.deferred = get_oracle_long_col(17); msg->sms.dlr_mask = get_oracle_long_col(18); msg->sms.dlr_url = get_oracle_octstr_col(19); msg->sms.pid = get_oracle_long_col(20); msg->sms.alt_dcs = get_oracle_long_col(21); msg->sms.rpi = get_oracle_long_col(22); msg->sms.charset = get_oracle_octstr_col(23); msg->sms.binfo = get_oracle_octstr_col(25); msg->sms.binfo = get_oracle_octstr_col(26); if (gwlist_get(row,24) == NULL) { msg->sms.boxc_id= octstr_duplicate(sqlbox_id); } else { msg->sms.boxc_id= get_oracle_octstr_col(24); } /* delete current row */ delet = octstr_format(SQLBOX_ORACLE_DELETE_QUERY, sqlbox_insert_table); gwlist_append(binds, id); /* :1 */ #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet)); #endif sql_update(pc, delet, binds); octstr_destroy(id); gwlist_destroy(binds, NULL); octstr_destroy(delet); gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(res, NULL); } dbpool_conn_produce(pc); octstr_destroy(sql); return msg; } static Octstr *get_numeric_value_or_return_null(long int num) { return octstr_format("%ld", num); } static Octstr *get_string_value_or_return_null(Octstr *str) { return octstr_format("%S", str); } #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x)) #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x)) void oracle_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */) { Octstr *sql; Octstr *stuffer[30]; int stuffcount = 0; List *binds = gwlist_create(); DBPoolConn *pc; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "Oracle: DBPool Error!"); return; } sql = octstr_format(SQLBOX_ORACLE_INSERT_QUERY, sqlbox_logtable); gwlist_append(binds, momt); /* :1 */ gwlist_append(binds, st_str(msg->sms.sender)); /* :2 */ gwlist_append(binds, st_str(msg->sms.receiver)); /* :3 */ gwlist_append(binds, st_str(msg->sms.udhdata)); /* :4 */ gwlist_append(binds, st_str(msg->sms.msgdata)); /* :5 */ gwlist_append(binds, st_num(msg->sms.time)); /* :6 */ gwlist_append(binds, st_str(msg->sms.smsc_id)); /* :7 */ gwlist_append(binds, st_str(msg->sms.service)); /* :8 */ gwlist_append(binds, st_str(msg->sms.account)); /* :9 */ gwlist_append(binds, st_num(msg->sms.sms_type)); /* :10 */ gwlist_append(binds, st_num(msg->sms.mclass)); /* :11 */ gwlist_append(binds, st_num(msg->sms.mwi)); /* :12 */ gwlist_append(binds, st_num(msg->sms.coding)); /* :13 */ gwlist_append(binds, st_num(msg->sms.compress)); /* :14 */ gwlist_append(binds, st_num(msg->sms.validity)); /* :15 */ gwlist_append(binds, st_num(msg->sms.deferred)); /* :16 */ gwlist_append(binds, st_num(msg->sms.dlr_mask)); /* :17 */ gwlist_append(binds, st_str(msg->sms.dlr_url)); /* :18 */ gwlist_append(binds, st_num(msg->sms.pid)); /* :19 */ gwlist_append(binds, st_num(msg->sms.alt_dcs)); /* :20 */ gwlist_append(binds, st_num(msg->sms.rpi)); /* :21 */ gwlist_append(binds, st_str(msg->sms.charset)); /* :22 */ gwlist_append(binds, st_str(msg->sms.boxc_id)); /* :23 */ gwlist_append(binds, st_str(msg->sms.binfo)); /* :24 */ gwlist_append(binds, st_str(msg->sms.meta_data)); /* :25 */ gwlist_append(binds, st_str(msg->sms.foreign_id)); /* :26 */ #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, binds); while (stuffcount > 0) { octstr_destroy(stuffer[--stuffcount]); } dbpool_conn_produce(pc); octstr_destroy(sql); gwlist_destroy(binds, NULL); } void oracle_leave() { dbpool_destroy(pool); } struct server_type *sqlbox_init_oracle(Cfg* cfg) { CfgGroup *grp; List *grplist; Octstr *oracle_user, *oracle_pass, *oracle_tnsname, *oracle_id; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; struct server_type *res = NULL; /* * check for all mandatory directives that specify the field names * of the used Oracle table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: Oracle: group 'sqlbox' is not specified!"); if (!(oracle_id = cfg_get(grp, octstr_imm("id")))) panic(0, "SQLBOX: Oracle: directive 'id' is not specified!"); /* * now grap the required information from the 'oracle-connection' group * with the oracle-id we just obtained * * we have to loop through all available Oracle connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("oracle-connection")); while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, oracle_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "SQLBOX: Oracle: connection settings for id '%s' are not specified!", octstr_get_cstr(oracle_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(oracle_user = cfg_get(grp, octstr_imm("username")))) panic(0, "SQLBOX: Oracle: directive 'username' is not specified!"); if (!(oracle_pass = cfg_get(grp, octstr_imm("password")))) panic(0, "SQLBOX: Oracle: directive 'password' is not specified!"); if (!(oracle_tnsname = cfg_get(grp, octstr_imm("tnsname")))) panic(0, "SQLBOX: Oracle: directive 'tnsname' is not specified!"); /* * ok, ready to connect to Oracle */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->oracle = gw_malloc(sizeof(OracleConf)); gw_assert(db_conf->oracle != NULL); db_conf->oracle->username = oracle_user; db_conf->oracle->password = oracle_pass; db_conf->oracle->tnsname = oracle_tnsname; pool = dbpool_create(DBPOOL_ORACLE, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"SQLBOX: Oracle: database pool has no connections!"); octstr_destroy(oracle_id); res = gw_malloc(sizeof(struct server_type)); gw_assert(res != NULL); res->type = octstr_create("Oracle"); res->sql_enter = sqlbox_configure_oracle; res->sql_leave = oracle_leave; res->sql_fetch_msg = oracle_fetch_msg; res->sql_save_msg = oracle_save_msg; res->sql_fetch_msg_list = NULL; res->sql_save_list = NULL; return res; } #endif gateway-1.4.5/addons/sqlbox/gw/Makefile.in0000644000175000017500000004333212327711710017134 0ustar toljtolj# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ sbin_PROGRAMS = sqlbox$(EXEEXT) subdir = gw DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/sb-config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am_sqlbox_OBJECTS = sqlbox.$(OBJEXT) sqlbox_mssql.$(OBJEXT) \ sqlbox_mysql.$(OBJEXT) sqlbox_pgsql.$(OBJEXT) \ sqlbox_sdb.$(OBJEXT) sqlbox_sqlite.$(OBJEXT) \ sqlbox_sqlite3.$(OBJEXT) sqlbox_oracle.$(OBJEXT) \ sqlbox_sql.$(OBJEXT) sqlbox_OBJECTS = $(am_sqlbox_OBJECTS) sqlbox_LDADD = $(LDADD) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/autotools/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(sqlbox_SOURCES) DIST_SOURCES = $(sqlbox_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONVERT = @CONVERT@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CTLIB_INCLUDE = @CTLIB_INCLUDE@ CTLIB_LFLAGS = @CTLIB_LFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DOCDRAFTS = @DOCDRAFTS@ DOCSTARGET = @DOCSTARGET@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ DVIPS = @DVIPS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ FIG2DEV = @FIG2DEV@ GREP = @GREP@ GW_CONFIG = @GW_CONFIG@ HTML_DSL = @HTML_DSL@ INCLUDES = @INCLUDES@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ JADE = @JADE@ JADETEX = @JADETEX@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OLDJADE = @OLDJADE@ OPENSSL = @OPENSSL@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFJADETEX = @PDFJADETEX@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TEX_DSL = @TEX_DSL@ VERSION = @VERSION@ XML_DCL = @XML_DCL@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ rpm_requires = @rpm_requires@ rpm_suffix = @rpm_suffix@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ sqlbox_SOURCES = sqlbox.c sqlbox_mssql.c sqlbox_mysql.c sqlbox_pgsql.c sqlbox_sdb.c sqlbox_sqlite.c sqlbox_sqlite3.c sqlbox_oracle.c sqlbox_sql.c EXTRA_DIST = sqlbox_mssql.h sqlbox_mysql.h sqlbox_pgsql.h sqlbox_sdb.h sqlbox_sqlite.h sqlbox_sqlite3.h sqlbox_oracle.h sqlbox_sql.h all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gw/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu gw/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list sqlbox$(EXEEXT): $(sqlbox_OBJECTS) $(sqlbox_DEPENDENCIES) $(EXTRA_sqlbox_DEPENDENCIES) @rm -f sqlbox$(EXEEXT) $(LINK) $(sqlbox_OBJECTS) $(sqlbox_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox_mssql.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox_mysql.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox_oracle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox_pgsql.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox_sdb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox_sql.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox_sqlite.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlbox_sqlite3.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-sbinPROGRAMS ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gateway-1.4.5/addons/sqlbox/gw/sqlbox_mysql.h0000644000175000017500000000673312712577027020012 0ustar toljtolj#include "gwlib/gwlib.h" #if defined(HAVE_MYSQL) || defined(HAVE_SDB) #define SQLBOX_MYSQL_CREATE_LOG_TABLE "CREATE TABLE IF NOT EXISTS %S ( \ sql_id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY, \ momt ENUM('MO', 'MT', 'DLR') NULL, sender VARCHAR(20) NULL, \ receiver VARCHAR(20) NULL, udhdata BLOB NULL, msgdata TEXT NULL, \ time BIGINT(20) NULL, smsc_id VARCHAR(255) NULL, service VARCHAR(255) NULL, \ account VARCHAR(255) NULL, id BIGINT(20) NULL, sms_type BIGINT(20) NULL, \ mclass BIGINT(20) NULL, mwi BIGINT(20) NULL, coding BIGINT(20) NULL, \ compress BIGINT(20) NULL, validity BIGINT(20) NULL, deferred BIGINT(20) NULL, \ dlr_mask BIGINT(20) NULL, dlr_url VARCHAR(255) NULL, pid BIGINT(20) NULL, \ alt_dcs BIGINT(20) NULL, rpi BIGINT(20) NULL, charset VARCHAR(255) NULL, \ boxc_id VARCHAR(255) NULL, binfo VARCHAR(255) NULL, meta_data TEXT, \ priority BIGINT(20) NULL, foreign_id VARCHAR(255) NULL)" #define SQLBOX_MYSQL_CREATE_INSERT_TABLE "CREATE TABLE IF NOT EXISTS %S ( \ sql_id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY, \ momt ENUM('MO', 'MT') NULL, sender VARCHAR(20) NULL, \ receiver VARCHAR(20) NULL, udhdata BLOB NULL, msgdata TEXT NULL, \ time BIGINT(20) NULL, smsc_id VARCHAR(255) NULL, service VARCHAR(255) NULL, \ account VARCHAR(255) NULL, id BIGINT(20) NULL, sms_type BIGINT(20) NULL, \ mclass BIGINT(20) NULL, mwi BIGINT(20) NULL, coding BIGINT(20) NULL, \ compress BIGINT(20) NULL, validity BIGINT(20) NULL, deferred BIGINT(20) NULL, \ dlr_mask BIGINT(20) NULL, dlr_url VARCHAR(255) NULL, pid BIGINT(20) NULL, \ alt_dcs BIGINT(20) NULL, rpi BIGINT(20) NULL, charset VARCHAR(255) NULL, \ boxc_id VARCHAR(255) NULL, binfo VARCHAR(255) NULL, meta_data TEXT, \ priority BIGINT(20) NULL, foreign_id VARCHAR(255) NULL)" #define SQLBOX_MYSQL_SELECT_QUERY "SELECT sql_id, momt, sender, receiver, udhdata, \ msgdata, time, smsc_id, service, account, id, sms_type, mclass, mwi, coding, \ compress, validity, deferred, dlr_mask, dlr_url, pid, alt_dcs, rpi, \ charset, boxc_id, binfo, meta_data, priority FROM %S LIMIT 0,1" #define SQLBOX_MYSQL_SELECT_LIST_QUERY "SELECT sql_id, momt, sender, receiver, udhdata, \ msgdata, time, smsc_id, service, account, id, sms_type, mclass, mwi, coding, \ compress, validity, deferred, dlr_mask, dlr_url, pid, alt_dcs, rpi, \ charset, boxc_id, binfo, meta_data, priority FROM %S LIMIT 0,%ld" #define SQLBOX_MYSQL_INSERT_QUERY "INSERT INTO %S ( sql_id, momt, sender, \ receiver, udhdata, msgdata, time, smsc_id, service, account, sms_type, \ mclass, mwi, coding, compress, validity, deferred, dlr_mask, dlr_url, \ pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data, priority, foreign_id ) VALUES ( \ NULL, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, \ %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S)" #define SQLBOX_MYSQL_INSERT_LIST_QUERY "INSERT INTO %S ( sql_id, momt, sender, \ receiver, udhdata, msgdata, time, smsc_id, service, account, sms_type, \ mclass, mwi, coding, compress, validity, deferred, dlr_mask, dlr_url, \ pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data, priority, foreign_id ) VALUES %S" #define SQLBOX_MYSQL_DELETE_QUERY "DELETE FROM %S WHERE sql_id = %S" #define SQLBOX_MYSQL_DELETE_LIST_QUERY "DELETE FROM %S WHERE sql_id in (%S)" #endif /* HAVE_MYSQL || HAVE_SDB */ #ifdef HAVE_MYSQL #include "gw/msg.h" #include "sqlbox_sql.h" void sql_save_msg(Msg *msg, Octstr *momt); Msg *mysql_fetch_msg(); void sql_shutdown(); struct server_type *sqlbox_init_mysql(Cfg* cfg); #ifndef sqlbox_mysql_c extern #endif Octstr *sqlbox_id; #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_sqlite.c0000644000175000017500000002474412203523676020137 0ustar toljtolj#include "gwlib/gwlib.h" #ifdef HAVE_SQLITE #include "gwlib/dbpool.h" #include #define sqlbox_sqlite_c #include "sqlbox_sqlite.h" #define sql_update sqlite_update #define sql_select sqlite_select static Octstr *sqlbox_logtable; static Octstr *sqlbox_insert_table; /* * Our connection pool to sqlite. */ static DBPool *pool = NULL; /* *------------------------------------------------- * sqlite thingies *------------------------------------------------- */ #define octstr_null_create(x) ((x != NULL) ? octstr_create(x) : octstr_create("")) #define atol_null(x) ((x != NULL) ? atol(x) : -1) static int sqlite_update(DBPoolConn *conn, const Octstr *sql) { int state; char *errmsg = 0; //struct DBPoolConn *conn = (struct DBPoolConn*) theconn; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif state = sqlite_exec(conn->conn, octstr_get_cstr(sql), NULL, 0, &errmsg); if (state != SQLITE_OK) { error(0, "SQLITE: %s", errmsg); return -1; } return sqlite_changes(conn->conn); } sqlite_vm* sqlite_select(DBPoolConn *conn, const Octstr *sql) { int res; char *errmsg = 0; const char *query_tail = NULL; sqlite_vm *vm = NULL; //struct DBPoolConn *conn = (struct DBPoolConn*) theconn; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif res = sqlite_compile(conn->conn, octstr_get_cstr(sql), &query_tail, &vm, &errmsg); if (res != SQLITE_OK) { error(0, "SQLITE: Could not compile query: %s", errmsg); return NULL; } return vm; } void sqlbox_configure_sqlite(Cfg* cfg) { CfgGroup *grp; Octstr *sql; DBPoolConn *pc; if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: Sqlite: group 'sqlbox' is not specified!"); sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table")); if (sqlbox_logtable == NULL) { panic(0, "Parameter 'sql-log-table' not configured."); } sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table")); if (sqlbox_insert_table == NULL) { panic(0, "Parameter 'sql-insert-table' not configured."); } pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SQLITE: Database pool got no connection! DB update failed!"); return; } /* create send_sms && sent_sms tables if they do not exist */ sql = octstr_format(SQLBOX_SQLITE_CREATE_LOG_TABLE, sqlbox_logtable); sql_update(pc, sql); octstr_destroy(sql); sql = octstr_format(SQLBOX_SQLITE_CREATE_INSERT_TABLE, sqlbox_insert_table); sql_update(pc, sql); octstr_destroy(sql); /* end table creation */ dbpool_conn_produce(pc); } Msg *sqlite_fetch_msg() { int state; DBPoolConn *pc; char *errmsg = 0; const char *query_tail = NULL; sqlite_vm *res = NULL; int i, cols = 0, rows = 0; const char **row = NULL; const char **col_name = NULL; Msg *msg = NULL; Octstr *sql, *delet, *id; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SQLITE: Database pool got no connection! DB update failed!"); return NULL; } sql = octstr_format(SQLBOX_SQLITE_SELECT_QUERY, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif res = sql_select(pc, sql); do { state=sqlite_step(res, &cols, &row, &col_name); if (state==SQLITE_ROW){ rows++; id = octstr_null_create(row[0]); /* save fields in this row as msg struct */ msg = msg_create(sms); /* we abuse the foreign_id field in the message struct for our sql_id value */ msg->sms.foreign_id = octstr_null_create(row[0]); msg->sms.sender = octstr_null_create(row[2]); msg->sms.receiver = octstr_null_create(row[3]); msg->sms.udhdata = octstr_null_create(row[4]); msg->sms.msgdata = octstr_null_create(row[5]); msg->sms.time = atol_null(row[6]); msg->sms.smsc_id = octstr_null_create(row[7]); msg->sms.service = octstr_null_create(row[8]); msg->sms.account = octstr_null_create(row[9]); /* msg->sms.id = atol_null(row[10]); */ msg->sms.sms_type = atol_null(row[11]); msg->sms.mclass = atol_null(row[12]); msg->sms.mwi = atol_null(row[13]); msg->sms.coding = atol_null(row[14]); msg->sms.compress = atol_null(row[15]); msg->sms.validity = atol_null(row[16]); msg->sms.deferred = atol_null(row[17]); msg->sms.dlr_mask = atol_null(row[18]); msg->sms.dlr_url = octstr_null_create(row[19]); msg->sms.pid = atol_null(row[20]); msg->sms.alt_dcs = atol_null(row[21]); msg->sms.rpi = atol_null(row[22]); msg->sms.charset = octstr_null_create(row[23]); msg->sms.binfo = octstr_null_create(row[25]); msg->sms.meta_data = octstr_null_create(row[26]); if (row[24] == NULL) { msg->sms.boxc_id= octstr_duplicate(sqlbox_id); } else { msg->sms.boxc_id= octstr_null_create(row[24]); } } } while (state==SQLITE_ROW); sqlite_finalize(res, NULL); if ( rows > 0) { /* delete current row */ delet = octstr_format(SQLBOX_SQLITE_DELETE_QUERY, sqlbox_insert_table, id); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet)); #endif sql_update(pc, delet); octstr_destroy(id); octstr_destroy(delet); } octstr_destroy(sql); dbpool_conn_produce(pc); return msg; } static Octstr *get_numeric_value_or_return_null(long int num) { if (num == -1) { return octstr_create("NULL"); } return octstr_format("%ld", num); } static Octstr *get_string_value_or_return_null(Octstr *str) { if (str == NULL) { return octstr_create("NULL"); } if (octstr_compare(str, octstr_imm("")) == 0) { return octstr_create("NULL"); } octstr_replace(str, octstr_imm("\\"), octstr_imm("\\\\")); octstr_replace(str, octstr_imm("\'"), octstr_imm("\\\'")); return octstr_format("\'%S\'", str); } #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x)) #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x)) void sqlite_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */) { Octstr *sql; Octstr *stuffer[30]; int stuffcount = 0; DBPoolConn *pc; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SQLITE: Database pool got no connection! DB update failed!"); return; } sql = octstr_format(SQLBOX_SQLITE_INSERT_QUERY, sqlbox_logtable, st_str(momt), st_str(msg->sms.sender), st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time), st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type), st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress), st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url), st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset), st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data), st_str(msg->sms.foreign_id)); sql_update(pc, sql); while (stuffcount > 0) { octstr_destroy(stuffer[--stuffcount]); } octstr_destroy(sql); dbpool_conn_produce(pc); } void sqlite_leave() { dbpool_destroy(pool); } struct server_type *sqlbox_init_sqlite(Cfg* cfg) { CfgGroup *grp; List *grplist; Octstr *sqlite_db, *sqlite_id; Octstr *p = NULL; long pool_size; int lock_timeout; DBConf *db_conf = NULL; struct server_type *res = NULL; /* * check for all mandatory directives that specify the field names * of the used Sqlite table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: Sqlite: group 'sqlbox' is not specified!"); if (!(sqlite_id = cfg_get(grp, octstr_imm("id")))) panic(0, "SQLBOX: Sqlite: directive 'id' is not specified!"); /* * now grap the required information from the 'sqlite-connection' group * with the sqlite-id we just obtained * * we have to loop through all available Sqlite connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("sqlite-connection")); while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, sqlite_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "SQLBOX: Sqlite: connection settings for id '%s' are not specified!", octstr_get_cstr(sqlite_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(sqlite_db = cfg_get(grp, octstr_imm("database")))) panic(0, "SQLBOX: Sqlite: directive 'database' is not specified!"); if (cfg_get_integer(&lock_timeout, grp, octstr_imm("lock-timeout")) == -1 || lock_timeout == 0 ) lock_timeout = 0; /* * ok, ready to connect to Sqlite */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->sqlite = gw_malloc(sizeof(SQLiteConf)); gw_assert(db_conf->sqlite != NULL); db_conf->sqlite->file = sqlite_db; db_conf->sqlite->lock_timeout = lock_timeout; pool = dbpool_create(DBPOOL_SQLITE, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"SQLBOX: Sqlite: database pool has no connections!"); octstr_destroy(sqlite_id); res = gw_malloc(sizeof(struct server_type)); gw_assert(res != NULL); res->type = octstr_create("Sqlite"); res->sql_enter = sqlbox_configure_sqlite; res->sql_leave = sqlite_leave; res->sql_fetch_msg = sqlite_fetch_msg; res->sql_save_msg = sqlite_save_msg; res->sql_fetch_msg_list = NULL; res->sql_save_list = NULL; return res; } #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_mssql.h0000644000175000017500000000537212203523676017776 0ustar toljtolj#include "gwlib/gwlib.h" #if defined(HAVE_MSSQL) || defined(HAVE_SDB) #define SQLBOX_MSSQL_CREATE_LOG_TABLE "CREATE TABLE %S ( \ sql_id NUMERIC(10,0) IDENTITY NOT NULL PRIMARY KEY, \ momt VARCHAR(3) NULL CHECK (momt IN ( 'MO', 'MT', 'DLR') OR momt IS NULL), \ sender VARCHAR(20) NULL, receiver VARCHAR(20) NULL, \ udhdata VARCHAR(4000) NULL, msgdata VARCHAR(4000) NULL, xtime INTEGER NULL, \ smsc_id VARCHAR(255) NULL, service VARCHAR(255) NULL, account VARCHAR(255) NULL, \ id INTEGER NULL, sms_type INTEGER NULL, mclass INTEGER NULL, mwi INTEGER NULL, \ coding INTEGER NULL, compress INTEGER NULL, validity INTEGER NULL, deferred INTEGER NULL, \ dlr_mask INTEGER NULL, dlr_url VARCHAR(255) NULL, pid INTEGER NULL, alt_dcs INTEGER NULL, \ rpi INTEGER NULL, charset VARCHAR(255) NULL, boxc_id VARCHAR(255) NULL, \ binfo VARCHAR(255) NULL, meta_data VARCHAR(4000) NULL, foreign_id VARCHAR(255) NULL)" #define SQLBOX_MSSQL_CREATE_INSERT_TABLE "CREATE TABLE %S ( \ sql_id NUMERIC(10,0) IDENTITY NOT NULL PRIMARY KEY, \ momt VARCHAR(3) NULL CHECK (momt IN ( 'MO', 'MT', 'DLR') OR momt IS NULL), \ sender VARCHAR(20) NULL, receiver VARCHAR(20) NULL, \ udhdata VARCHAR(4000) NULL, msgdata VARCHAR(4000) NULL, xtime INTEGER NULL, \ smsc_id VARCHAR(255) NULL, service VARCHAR(255) NULL, account VARCHAR(255) NULL, \ id INTEGER NULL, sms_type INTEGER NULL, mclass INTEGER NULL, mwi INTEGER NULL, \ coding INTEGER NULL, compress INTEGER NULL, validity INTEGER NULL, deferred INTEGER NULL, \ dlr_mask INTEGER NULL, dlr_url VARCHAR(255) NULL, pid INTEGER NULL, alt_dcs INTEGER NULL, \ rpi INTEGER NULL, charset VARCHAR(255) NULL, boxc_id VARCHAR(255) NULL, \ binfo VARCHAR(255) NULL, meta_data VARCHAR(4000) NULL), foreign_id VARCHAR(255) NULL" #define SQLBOX_MSSQL_SELECT_QUERY "SELECT TOP 1 sql_id, momt, sender, receiver, udhdata, msgdata, \ xtime, smsc_id, service, account, id, sms_type, mclass, mwi, coding, compress, \ validity, deferred, dlr_mask, dlr_url, pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data \ FROM %S" #define SQLBOX_MSSQL_INSERT_QUERY "INSERT INTO %S (momt, sender, receiver, udhdata, msgdata, \ xtime, smsc_id, service, account, sms_type, mclass, mwi, coding, compress, validity, \ deferred, dlr_mask, dlr_url, pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data, foreign_id) VALUES (%S, \ %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S)" #define SQLBOX_MSSQL_DELETE_QUERY "DELETE FROM %S WHERE sql_id = %S" #endif /* HAVE_MSSQL || HAVE_SDB */ #ifdef HAVE_MSSQL #include "gw/msg.h" #include "sqlbox_sql.h" void sql_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */); Msg *mssql_fetch_msg(); void sql_shutdown(); struct server_type *sqlbox_init_mssql(Cfg *cfg); #ifndef sqlbox_mssql_c extern #endif Octstr *sqlbox_id; #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_sqlite3.c0000644000175000017500000002524311467071614020216 0ustar toljtolj#include "gwlib/gwlib.h" #ifdef HAVE_SQLITE3 #include "gwlib/dbpool.h" #include #define sqlbox_sqlite3_c #include "sqlbox_sqlite3.h" #define sql_update sqlite3_update #define sql_select sqlite3_select static Octstr *sqlbox_logtable; static Octstr *sqlbox_insert_table; /* * Our connection pool to sqlite3. */ static DBPool *pool = NULL; /* *------------------------------------------------- * sqlite3 thingies *------------------------------------------------- */ #define octstr_null_create(x) ((x != NULL) ? octstr_create(x) : octstr_create("")) #define atol_null(x) ((x != NULL) ? atol(x) : -1) static int sqlite3_update(DBPoolConn *conn, const Octstr *sql) { int state; char *errmsg = 0; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif state = sqlite3_exec(conn->conn, octstr_get_cstr(sql), NULL, 0, &errmsg); if (state != SQLITE_OK) { error(0, "SQLITE3: %s", sqlite3_errmsg(conn->conn)); return -1; } return sqlite3_changes(conn->conn); } sqlite3_stmt* sqlite3_select(DBPoolConn *conn, const Octstr *sql) { int res; sqlite3_stmt *stmt = NULL; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif res = sqlite3_prepare_v2(conn->conn, octstr_get_cstr(sql), -1, &stmt, NULL); if (res != SQLITE_OK) { error(0, "SQLITE3: Could not compile query: %s", sqlite3_errmsg(conn->conn)); return NULL; } return stmt; } void sqlbox_configure_sqlite3(Cfg* cfg) { CfgGroup *grp; Octstr *sql; DBPoolConn *pc; if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: Sqlite3: group 'sqlbox' is not specified!"); sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table")); if (sqlbox_logtable == NULL) { panic(0, "Parameter 'sql-log-table' configured."); } sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table")); if (sqlbox_insert_table == NULL) { panic(0, "Parameter 'sql-insert-table' configured."); } pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SQLITE3: Database pool got no connection! DB update failed!"); return; } /* create send_sms && sent_sms tables if they do not exist */ sql = octstr_format(SQLBOX_SQLITE3_CREATE_LOG_TABLE, sqlbox_logtable); sql_update(pc, sql); octstr_destroy(sql); sql = octstr_format(SQLBOX_SQLITE3_CREATE_LOG_TABLE, sqlbox_insert_table); sql_update(pc, sql); octstr_destroy(sql); /* end table creation */ dbpool_conn_produce(pc); } Msg *sqlite3_fetch_msg() { int state; DBPoolConn *pc; sqlite3_stmt *res = NULL; int rows = 0; Msg *msg = NULL; Octstr *sql, *delet, *id = NULL; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SQLITE3: Database pool got no connection! DB update failed!"); return NULL; } sql = octstr_format(SQLBOX_SQLITE3_SELECT_QUERY, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif res = sql_select(pc, sql); do { state=sqlite3_step(res); if (state==SQLITE_ROW){ rows++; id = octstr_null_create((char *)sqlite3_column_text(res, 0)); /* save fields in this row as msg struct */ msg = msg_create(sms); msg->sms.sender = octstr_null_create((char *)sqlite3_column_text(res, 2)); msg->sms.receiver = octstr_null_create((char *)sqlite3_column_text(res, 3)); msg->sms.udhdata = octstr_null_create((char *)sqlite3_column_text(res, 4)); msg->sms.msgdata = octstr_null_create((char *)sqlite3_column_text(res, 5)); msg->sms.time = atol_null((char *)sqlite3_column_text(res,6)); msg->sms.smsc_id = octstr_null_create((char *)sqlite3_column_text(res, 7)); msg->sms.service = octstr_null_create((char *)sqlite3_column_text(res, 8)); msg->sms.account = octstr_null_create((char *)sqlite3_column_text(res, 9)); /* msg->sms.id = atol_null((char *)sqlite3_column_text(res, 10)); */ msg->sms.sms_type = atol_null((char *)sqlite3_column_text(res, 11)); msg->sms.mclass = atol_null((char *)sqlite3_column_text(res, 12)); msg->sms.mwi = atol_null((char *)sqlite3_column_text(res, 13)); msg->sms.coding = atol_null((char *)sqlite3_column_text(res, 14)); msg->sms.compress = atol_null((char *)sqlite3_column_text(res, 15)); msg->sms.validity = atol_null((char *)sqlite3_column_text(res, 16)); msg->sms.deferred = atol_null((char *)sqlite3_column_text(res, 17)); msg->sms.dlr_mask = atol_null((char *)sqlite3_column_text(res, 18)); msg->sms.dlr_url = octstr_null_create((char *)sqlite3_column_text(res, 19)); msg->sms.pid = atol_null((char *)sqlite3_column_text(res, 20)); msg->sms.alt_dcs = atol_null((char *)sqlite3_column_text(res, 21)); msg->sms.rpi = atol_null((char *)sqlite3_column_text(res, 22)); msg->sms.charset = octstr_null_create((char *)sqlite3_column_text(res, 23)); msg->sms.binfo = octstr_null_create((char *)sqlite3_column_text(res, 25)); msg->sms.meta_data = octstr_null_create((char *)sqlite3_column_text(res, 26)); msg->sms.boxc_id = (sqlite3_column_text(res, 24) == NULL) ? octstr_duplicate(sqlbox_id):octstr_null_create((char *)sqlite3_column_text(res, 24)); } } while (state==SQLITE_ROW); sqlite3_finalize(res); if ( rows > 0) { /* delete current row */ delet = octstr_format(SQLBOX_SQLITE3_DELETE_QUERY, sqlbox_insert_table, id); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet)); #endif sql_update(pc, delet); octstr_destroy(id); octstr_destroy(delet); } octstr_destroy(sql); dbpool_conn_produce(pc); return msg; } static Octstr *get_numeric_value_or_return_null(long int num) { if (num == -1) { return octstr_create("NULL"); } return octstr_format("%ld", num); } static Octstr *get_string_value_or_return_null(Octstr *str) { if (str == NULL) { return octstr_create("NULL"); } if (octstr_compare(str, octstr_imm("")) == 0) { return octstr_create("NULL"); } octstr_replace(str, octstr_imm("\\"), octstr_imm("\\\\")); octstr_replace(str, octstr_imm("\'"), octstr_imm("\\\'")); return octstr_format("\'%S\'", str); } #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x)) #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x)) void sqlite3_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */) { Octstr *sql; Octstr *stuffer[30]; int stuffcount = 0; DBPoolConn *pc; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SQLITE3: Database pool got no connection! DB update failed!"); return; } sql = octstr_format(SQLBOX_SQLITE3_INSERT_QUERY, sqlbox_logtable, st_str(momt), st_str(msg->sms.sender), st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time), st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type), st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress), st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url), st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset), st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data)); sql_update(pc, sql); while (stuffcount > 0) { octstr_destroy(stuffer[--stuffcount]); } octstr_destroy(sql); dbpool_conn_produce(pc); } void sqlite3_leave() { dbpool_destroy(pool); } struct server_type *sqlbox_init_sqlite3(Cfg* cfg) { CfgGroup *grp; List *grplist; Octstr *sqlite3_db, *sqlite3_id; Octstr *p = NULL; long pool_size, lock_timeout; DBConf *db_conf = NULL; struct server_type *res = NULL; /* * check for all mandatory directives that specify the field names * of the used Sqlite3 table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: Sqlite3: group 'sqlbox' is not specified!"); if (!(sqlite3_id = cfg_get(grp, octstr_imm("id")))) panic(0, "SQLBOX: Sqlite3: directive 'id' is not specified!"); /* * now grap the required information from the 'sqlite3-connection' group * with the sqlite3-id we just obtained * * we have to loop through all available Sqlite3 connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("sqlite3-connection")); while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, sqlite3_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "SQLBOX: Sqlite3: connection settings for id '%s' are not specified!", octstr_get_cstr(sqlite3_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(sqlite3_db = cfg_get(grp, octstr_imm("database")))) panic(0, "SQLBOX: Sqlite3: directive 'database' is not specified!"); if (cfg_get_integer(&lock_timeout, grp, octstr_imm("lock-timeout")) == -1 || lock_timeout == 0 ) lock_timeout = 0; /* * ok, ready to connect to Sqlite3 */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->sqlite3 = gw_malloc(sizeof(SQLite3Conf)); gw_assert(db_conf->sqlite3 != NULL); db_conf->sqlite3->file = sqlite3_db; db_conf->sqlite3->lock_timeout = lock_timeout; pool = dbpool_create(DBPOOL_SQLITE3, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"SQLBOX: Sqlite3: database pool has no connections!"); octstr_destroy(sqlite3_id); res = gw_malloc(sizeof(struct server_type)); gw_assert(res != NULL); res->type = octstr_create("Sqlite3"); res->sql_enter = sqlbox_configure_sqlite3; res->sql_leave = sqlite3_leave; res->sql_fetch_msg = sqlite3_fetch_msg; res->sql_save_msg = sqlite3_save_msg; return res; } #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_pgsql.h0000644000175000017500000000540712203523676017764 0ustar toljtolj#include "gwlib/gwlib.h" #if defined(HAVE_PGSQL) || defined(HAVE_SDB) #define SQLBOX_PGSQL_CREATE_LOG_TABLE "CREATE TABLE %S (sql_id SERIAL PRIMARY KEY, \ momt VARCHAR(3) CHECK(momt IN ('MO', 'MT', 'DLR', NULL)) DEFAULT NULL, \ sender VARCHAR(20) NULL, receiver VARCHAR(20) NULL, udhdata VARCHAR(255) NULL, \ msgdata TEXT NULL, time BIGINT NULL, smsc_id VARCHAR(255) NULL, \ service VARCHAR(255) NULL, account VARCHAR(255) NULL, id BIGINT NULL, \ sms_type BIGINT NULL, mclass BIGINT NULL, mwi BIGINT NULL, coding BIGINT NULL, \ compress BIGINT NULL, validity BIGINT NULL, deferred BIGINT NULL, \ dlr_mask BIGINT NULL, dlr_url VARCHAR(255) NULL, pid BIGINT NULL, \ alt_dcs BIGINT NULL, rpi BIGINT NULL, charset VARCHAR(255) NULL, \ boxc_id VARCHAR(255) NULL, binfo VARCHAR(255) NULL, meta_data TEXT NULL, foreign_id VARCHAR(255) NULL)" #define SQLBOX_PGSQL_CREATE_INSERT_TABLE "CREATE TABLE %S (sql_id SERIAL PRIMARY KEY, \ momt VARCHAR(3) CHECK(momt IN ('MO', 'MT', NULL)) DEFAULT NULL, \ sender VARCHAR(20) NULL, receiver VARCHAR(20) NULL, udhdata VARCHAR(255) NULL, \ msgdata TEXT NULL, time BIGINT NULL, smsc_id VARCHAR(255) NULL, \ service VARCHAR(255) NULL, account VARCHAR(255) NULL, id BIGINT NULL, \ sms_type BIGINT NULL, mclass BIGINT NULL, mwi BIGINT NULL, coding BIGINT NULL, \ compress BIGINT NULL, validity BIGINT NULL, deferred BIGINT NULL, \ dlr_mask BIGINT NULL, dlr_url VARCHAR(255) NULL, pid BIGINT NULL, \ alt_dcs BIGINT NULL, rpi BIGINT NULL, charset VARCHAR(255) NULL, \ boxc_id VARCHAR(255) NULL, binfo VARCHAR(255) NULL, meta_data TEXT NULL, foreign_id VARCHAR(255) NULL)" #define SQLBOX_PGSQL_SELECT_QUERY "SELECT sql_id, momt, sender, receiver, udhdata, msgdata, \ time, smsc_id, service, account, id, sms_type, mclass, mwi, coding, compress, validity, deferred, \ dlr_mask, dlr_url, pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data FROM %S LIMIT 1 OFFSET 0" #define SQLBOX_PGSQL_INSERT_QUERY "INSERT INTO %S (momt, sender, receiver, udhdata, msgdata, \ time, smsc_id, service, account, sms_type, mclass, mwi, coding, compress, validity, deferred, \ dlr_mask, dlr_url, pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data, foreign_id) VALUES (%S, %S, %S, \ %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S)" #define SQLBOX_PGSQL_DELETE_QUERY "DELETE FROM %S WHERE sql_id = %S" #endif /* HAVE_PGSQL || HAVE_SDB */ #ifdef HAVE_PGSQL #include "gw/msg.h" #include "sqlbox_sql.h" #define sql_fetch_msg pgsql_fetch_msg #define sql_save_msg pgsql_save_msg #define sql_leave pgsql_leave void sql_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */); Msg *pgsql_fetch_msg(); void sql_shutdown(); struct server_type *sqlbox_init_pgsql(Cfg *cfg); void sqlbox_configure_pgsql(Cfg *cfg); #ifndef sqlbox_pgsql_c extern #endif Octstr *sqlbox_id; #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_sqlite.h0000644000175000017500000000520612203523676020134 0ustar toljtolj#include "gwlib/gwlib.h" #if defined(HAVE_SQLITE) || defined(HAVE_SDB) #define SQLBOX_SQLITE_CREATE_LOG_TABLE "CREATE TABLE %S ( \ sql_id INTEGER AUTOINCREMENT PRIMARY KEY, momt CHAR(3) NULL, sender VARCHAR(20) NULL, \ receiver VARCHAR(20) NULL, udhdata BLOB NULL, msgdata TEXT NULL, time BIGINT(20) NULL, \ smsc_id VARCHAR(255) NULL, service VARCHAR(255) NULL, account VARCHAR(255) NULL, \ id BIGINT(20) NULL, sms_type BIGINT(20) NULL, mclass BIGINT(20) NULL, mwi BIGINT(20) NULL, \ coding BIGINT(20) NULL, compress BIGINT(20) NULL, validity BIGINT(20) NULL, \ deferred BIGINT(20) NULL, dlr_mask BIGINT(20) NULL, dlr_url VARCHAR(255) NULL, \ pid BIGINT(20) NULL, alt_dcs BIGINT(20) NULL, rpi BIGINT(20) NULL, charset VARCHAR(255) NULL, \ boxc_id VARCHAR(255) NULL, binfo VARCHAR(255) NULL, meta_data TEXT NULL, foreign_id VARCHAR(255) NULL)" #define SQLBOX_SQLITE_CREATE_INSERT_TABLE "CREATE TABLE %S ( \ sql_id INTEGER AUTOINCREMENT PRIMARY KEY, momt CHAR(3) NULL, sender VARCHAR(20) NULL, \ receiver VARCHAR(20) NULL, udhdata BLOB NULL, msgdata TEXT NULL, time BIGINT(20) NULL, \ smsc_id VARCHAR(255) NULL, service VARCHAR(255) NULL, account VARCHAR(255) NULL, \ id BIGINT(20) NULL, sms_type BIGINT(20) NULL, mclass BIGINT(20) NULL, mwi BIGINT(20) NULL, \ coding BIGINT(20) NULL, compress BIGINT(20) NULL, validity BIGINT(20) NULL, \ deferred BIGINT(20) NULL, dlr_mask BIGINT(20) NULL, dlr_url VARCHAR(255) NULL, \ pid BIGINT(20) NULL, alt_dcs BIGINT(20) NULL, rpi BIGINT(20) NULL, charset VARCHAR(255) NULL, \ boxc_id VARCHAR(255) NULL, binfo VARCHAR(255) NULL, meta_data TEXT NULL, foreign_id VARCHAR(255) NULL)" #define SQLBOX_SQLITE_SELECT_QUERY "SELECT sql_id, momt, sender, receiver, udhdata, msgdata, \ time, smsc_id, service, account, id, sms_type, mclass, mwi, coding, compress, validity, \ deferred, dlr_mask, dlr_url, pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data FROM %S LIMIT 0,1" #define SQLBOX_SQLITE_INSERT_QUERY "INSERT INTO %S (sql_id, momt, sender, receiver, udhdata, msgdata, \ time, smsc_id, service, account, sms_type, mclass, mwi, coding, compress, validity, deferred, dlr_mask, \ dlr_url, pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data, foreign_id) VALUES (NULL, %S, %S, %S, %S, %S, %S, \ %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S)" #define SQLBOX_SQLITE_DELETE_QUERY "DELETE FROM %S WHERE sql_id = %S" #endif /* HAVE_SQLITE || HAVE_SDB */ #ifdef HAVE_SQLITE #include "gw/msg.h" #include "sqlbox_sql.h" void sql_save_msg(Msg *msg, Octstr *momt ); Msg *sqlite_fetch_msg(); void sql_shutdown(); struct server_type *sqlbox_init_sqlite(Cfg *cfg); #ifndef sqlbox_sqlite_c extern #endif Octstr *sqlbox_id; #endif gateway-1.4.5/addons/sqlbox/gw/Makefile.am0000644000175000017500000000046111204545563017123 0ustar toljtoljsbin_PROGRAMS = sqlbox sqlbox_SOURCES = sqlbox.c sqlbox_mssql.c sqlbox_mysql.c sqlbox_pgsql.c sqlbox_sdb.c sqlbox_sqlite.c sqlbox_sqlite3.c sqlbox_oracle.c sqlbox_sql.c EXTRA_DIST = sqlbox_mssql.h sqlbox_mysql.h sqlbox_pgsql.h sqlbox_sdb.h sqlbox_sqlite.h sqlbox_sqlite3.h sqlbox_oracle.h sqlbox_sql.h gateway-1.4.5/addons/sqlbox/gw/sqlbox_oracle.h0000644000175000017500000000750412203523676020103 0ustar toljtolj#include "gwlib/gwlib.h" #if defined(HAVE_ORACLE) || defined(HAVE_SDB) #define SQLBOX_ORACLE_CREATE_LOG_TABLE "CREATE TABLE \"%S\" (\"sql_id\" INTEGER NOT NULL PRIMARY KEY, \ \"momt\" VARCHAR2(3) NULL, \"sender\" VARCHAR2(20) NULL, \"receiver\" VARCHAR2(20) NULL, \ \"udhdata\" VARCHAR2(4000) NULL, \"msgdata\" VARCHAR2(4000) NULL, \"time\" INTEGER NULL, \ \"smsc_id\" VARCHAR2(255) NULL, \"service\" VARCHAR2(255) NULL, \"account\" VARCHAR2(255) NULL, \ \"id\" INTEGER NULL, \"sms_type\" INTEGER NULL, \"mclass\" INTEGER NULL, \"mwi\" INTEGER NULL, \ \"coding\" INTEGER NULL, \"compress\" INTEGER NULL, \"validity\" INTEGER NULL, \"deferred\" INTEGER NULL, \ \"dlr_mask\" INTEGER NULL, \"dlr_url\" VARCHAR2(255) NULL, \"pid\" INTEGER NULL, \"alt_dcs\" INTEGER NULL, \ \"rpi\" INTEGER NULL, \"charset\" VARCHAR2(255) NULL, \"boxc_id\" VARCHAR2(255) NULL, \ \"binfo\" VARCHAR2(255) NULL, \"meta_data\" VARCHAR2(4000) NULL, \"foreign_id\" VARCHAR2(255) NULL, \ CONSTRAINT c_%S_momt CHECK ( \"momt\" IN ( 'MO', 'MT', 'DLR', NULL)))" #define SQLBOX_ORACLE_CREATE_INSERT_TABLE "CREATE TABLE \"%S\" (\"sql_id\" INTEGER NOT NULL PRIMARY KEY, \ \"momt\" VARCHAR2(3) NULL, \"sender\" VARCHAR2(20) NULL, \"receiver\" VARCHAR2(20) NULL, \ \"udhdata\" VARCHAR2(4000) NULL, \"msgdata\" VARCHAR2(4000) NULL, \"time\" INTEGER NULL, \ \"smsc_id\" VARCHAR2(255) NULL, \"service\" VARCHAR2(255) NULL, \"account\" VARCHAR2(255) NULL, \ \"id\" INTEGER NULL, \"sms_type\" INTEGER NULL, \"mclass\" INTEGER NULL, \"mwi\" INTEGER NULL, \ \"coding\" INTEGER NULL, \"compress\" INTEGER NULL, \"validity\" INTEGER NULL, \"deferred\" INTEGER NULL, \ \"dlr_mask\" INTEGER NULL, \"dlr_url\" VARCHAR2(255) NULL, \"pid\" INTEGER NULL, \"alt_dcs\" INTEGER NULL, \ \"rpi\" INTEGER NULL, \"charset\" VARCHAR2(255) NULL, \"boxc_id\" VARCHAR2(255) NULL, \ \"binfo\" VARCHAR2(255) NULL, \"meta_data\" VARCHAR2(4000) NULL, \"foreign_id\" VARCHAR2(255) NULL, \ CONSTRAINT c_%S_momt CHECK ( \"momt\" IN ( 'MO', 'MT', NULL)))" #define SQLBOX_ORACLE_CREATE_LOG_SEQUENCE "CREATE SEQUENCE \"%S_seq\" START WITH 1 INCREMENT BY 1 NOMAXVALUE" #define SQLBOX_ORACLE_CREATE_INSERT_SEQUENCE "CREATE SEQUENCE \"%S_seq\" START WITH 1 INCREMENT BY 1 NOMAXVALUE" #define SQLBOX_ORACLE_CREATE_LOG_TRIGGER "CREATE TRIGGER \"%S_trg\" BEFORE INSERT ON \"%S\" \ FOR EACH ROW BEGIN SELECT \"%S_seq\".nextval INTO :new.\"sql_id\" FROM DUAL; END;" #define SQLBOX_ORACLE_CREATE_INSERT_TRIGGER "CREATE TRIGGER \"%S_trg\" BEFORE INSERT ON \"%S\" \ FOR EACH ROW BEGIN SELECT \"%S_seq\".nextval INTO :new.\"sql_id\" FROM DUAL; END;" #define SQLBOX_ORACLE_SELECT_QUERY "SELECT \"sql_id\", \"momt\", \"sender\", \"receiver\", \"udhdata\", \"msgdata\", \ \"time\", \"smsc_id\", \"service\", \"account\", \"id\", \"sms_type\", \"mclass\", \"mwi\", \"coding\", \"compress\", \ \"validity\", \"deferred\", \"dlr_mask\", \"dlr_url\", \"pid\", \"alt_dcs\", \"rpi\", \"charset\", \"boxc_id\", \ \"binfo\", \"meta_data\" FROM \"%S\" WHERE ROWNUM = 1" #define SQLBOX_ORACLE_INSERT_QUERY "INSERT INTO \"%S\" (\"momt\", \"sender\", \"receiver\", \"udhdata\", \"msgdata\", \ \"time\", \"smsc_id\", \"service\", \"account\", \"sms_type\", \"mclass\", \"mwi\", \"coding\", \"compress\", \"validity\", \ \"deferred\", \"dlr_mask\", \"dlr_url\", \"pid\", \"alt_dcs\", \"rpi\", \"charset\", \"boxc_id\", \"binfo\", \"meta_data\", \ \"foreign_id\") VALUES (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15, :16, :17, :18, :19, :20, :21, :22, :23, :24, :25, :26)" #define SQLBOX_ORACLE_DELETE_QUERY "DELETE FROM \"%S\" WHERE \"sql_id\" = :1" #endif /* HAVE_ORACLE || HAVE_SDB */ #ifdef HAVE_ORACLE #include "gw/msg.h" #include "sqlbox_sql.h" void sql_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */); Msg *oracle_fetch_msg(); void sql_shutdown(); struct server_type *sqlbox_init_oracle(Cfg *cfg); #ifndef sqlbox_oracle_c extern #endif Octstr *sqlbox_id; #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox.c0000644000175000017500000006503612204144443016545 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2004 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * sqlbox.c - main program of the sqlbox */ #include #include #include #include #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #include "gw/msg.h" #include "gw/sms.h" #include "gw/shared.h" #include "gw/bb.h" #include "sqlbox_sql.h" /* our config */ static Cfg *cfg; /* have we received restart cmd from bearerbox? */ static volatile sig_atomic_t restart_sqlbox = 0; static volatile sig_atomic_t sqlbox_status; #define SQL_DEAD 0 #define SQL_SHUTDOWN 1 #define SQL_RUNNING 2 static long sqlbox_port; static int sqlbox_port_ssl = 0; static long bearerbox_port; static Octstr *bearerbox_host; static int bearerbox_port_ssl = 0; static Octstr *global_sender; static long limit_per_cycle; static int save_mo, save_mt, save_dlr; #ifndef HAVE_MSSQL #ifndef HAVE_MYSQL #ifndef HAVE_PGSQL #ifndef HAVE_SDB #ifndef HAVE_SQLITE #ifndef HAVE_SQLITE3 #ifndef HAVE_ORACLE #error You need support for at least one DB engine. Please recompile Kannel. #endif #endif #endif #endif #endif #endif #endif Octstr *sqlbox_id; #define SLEEP_BETWEEN_EMPTY_SELECTS 1.0 #define DEFAULT_LIMIT_PER_CYCLE 10 typedef struct _boxc { Connection *smsbox_connection; Connection *bearerbox_connection; time_t connect_time; Octstr *client_ip; volatile sig_atomic_t alive; Octstr *boxc_id; /* identifies the connected smsbox instance */ } Boxc; /* * Adding hooks to kannel check config * * Martin Conte. */ static int sqlbox_is_allowed_in_group(Octstr *group, Octstr *variable) { Octstr *groupstr; groupstr = octstr_imm("group"); #define OCTSTR(name) \ if (octstr_compare(octstr_imm(#name), variable) == 0) \ return 1; #define SINGLE_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), group) == 0) { \ if (octstr_compare(groupstr, variable) == 0) \ return 1; \ fields \ return 0; \ } #define MULTI_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), group) == 0) { \ if (octstr_compare(groupstr, variable) == 0) \ return 1; \ fields \ return 0; \ } #include "sqlbox-cfg.def" return 0; } #undef OCTSTR #undef SINGLE_GROUP #undef MULTI_GROUP static int sqlbox_is_single_group(Octstr *query) { #define OCTSTR(name) #define SINGLE_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), query) == 0) \ return 1; #define MULTI_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), query) == 0) \ return 0; #include "sqlbox-cfg.def" return 0; } /**************************************************************************** * Character convertion. * * The 'msgdata' is read from the DB table as URL-encoded byte stream, * which we need to URL-decode to get the orginal message. We use this * approach to get rid of the table character dependancy of the DB systems. * The URL-encoded chars as a subset of ASCII which is typicall no problem * for any of the supported DB systems. */ static int charset_processing(Msg *msg) { gw_assert(msg->type == sms); /* URL-decode first */ if (octstr_url_decode(msg->sms.msgdata) == -1) return -1; if (octstr_url_decode(msg->sms.udhdata) == -1) return -1; /* If a specific character encoding has been indicated by the * user, then make sure we convert to our internal representations. */ if (octstr_len(msg->sms.charset)) { if (msg->sms.coding == DC_7BIT) { /* For 7 bit, convert to UTF-8 */ if (charset_convert(msg->sms.msgdata, octstr_get_cstr(msg->sms.charset), "UTF-8") < 0) return -1; } else if (msg->sms.coding == DC_UCS2) { /* For UCS-2, convert to UTF-16BE */ if (charset_convert(msg->sms.msgdata, octstr_get_cstr(msg->sms.charset), "UTF-16BE") < 0) return -1; } } return 0; } /* *------------------------------------------------- * receiver thingies *------------------------------------------------- * */ /* read from either smsbox or bearerbox */ static Msg *read_from_box(Connection *conn, Boxc *boxconn) { Msg *msg; while (boxconn->alive) { switch (read_from_bearerbox_real(conn, &msg, 1.0)) { case -1: /* connection to bearerbox lost */ return NULL; break; case 0: /* all is well */ return msg; break; case 1: /* timeout */ break; } } return NULL; } /* *------------------------------------------------- * sender thingies *------------------------------------------------- * */ /* send to either smsbox or bearerbox */ static int send_msg(Connection *conn, Boxc *boxconn, Msg *pmsg) { Octstr *pack; pack = msg_pack(pmsg); if (pack == NULL) return -1; if (conn_write_withlen(conn, pack) == -1) { error(0, "Couldn't write Msg to box <%s>, disconnecting", octstr_get_cstr(boxconn->client_ip)); octstr_destroy(pack); return -1; } octstr_destroy(pack); return 0; } static void smsbox_to_bearerbox(void *arg) { Boxc *conn = arg; Msg *msg, *msg_escaped; /* remove messages from socket until it is closed */ while (sqlbox_status == SQL_RUNNING && conn->alive) { //list_consume(suspended); /* block here if suspended */ msg = read_from_box(conn->smsbox_connection, conn); if (msg == NULL) { /* garbage/connection lost */ conn->alive = 0; break; } if (msg_type(msg) == sms) { debug("sqlbox", 0, "smsbox_to_bearerbox: sms received"); if (save_mt) { msg_escaped = msg_duplicate(msg); /* convert validity & deferred to minutes */ if (msg_escaped->sms.validity != SMS_PARAM_UNDEFINED) msg_escaped->sms.validity = (msg_escaped->sms.validity - time(NULL))/60; if (msg_escaped->sms.deferred != SMS_PARAM_UNDEFINED) msg_escaped->sms.deferred = (msg_escaped->sms.deferred - time(NULL))/60; gw_sql_save_msg(msg_escaped, octstr_imm("MT")); msg_destroy(msg_escaped); } } send_msg(conn->bearerbox_connection, conn, msg); /* if this is an identification message from an smsbox instance */ if (msg_type(msg) == admin && msg->admin.command == cmd_identify) { /* * any smsbox sends this command even if boxc_id is NULL, * but we will only consider real identified boxes */ if (msg->admin.boxc_id != NULL) { /* and add the boxc_id into conn for boxc_status() output */ conn->boxc_id = msg->admin.boxc_id; msg->admin.boxc_id = NULL; debug("sqlbox", 0, "smsbox_to_bearerbox: got boxc_id <%s> from <%s>", octstr_get_cstr(conn->boxc_id), octstr_get_cstr(conn->client_ip)); } } msg_destroy(msg); } conn->alive = 0; } static Boxc *boxc_create(int fd, Octstr *ip, int ssl) { Boxc *boxc; boxc = gw_malloc(sizeof(Boxc)); boxc->smsbox_connection = conn_wrap_fd(fd, ssl); boxc->bearerbox_connection = NULL; boxc->client_ip = ip; boxc->alive = 1; boxc->connect_time = time(NULL); boxc->boxc_id = NULL; return boxc; } static void boxc_destroy(Boxc *boxc) { if (boxc == NULL) return; /* do nothing to the lists, as they are only references */ if (boxc->smsbox_connection) conn_destroy(boxc->smsbox_connection); if (boxc->bearerbox_connection) conn_destroy(boxc->bearerbox_connection); octstr_destroy(boxc->client_ip); octstr_destroy(boxc->boxc_id); gw_free(boxc); } static Boxc *accept_boxc(int fd, int ssl) { Boxc *newconn; Octstr *ip; int newfd; struct sockaddr_in client_addr; socklen_t client_addr_len; client_addr_len = sizeof(client_addr); newfd = accept(fd, (struct sockaddr *)&client_addr, &client_addr_len); if (newfd < 0) return NULL; ip = host_ip(client_addr); // if (is_allowed_ip(box_allow_ip, box_deny_ip, ip) == 0) { // info(0, "Box connection tried from denied host <%s>, disconnected", // octstr_get_cstr(ip)); // octstr_destroy(ip); // close(newfd); // return NULL; // } newconn = boxc_create(newfd, ip, ssl); /* * check if the SSL handshake was successfull, otherwise * this is no valid box connection any more */ #ifdef HAVE_LIBSSL if (ssl && !conn_get_ssl(newconn->smsbox_connection)) return NULL; #endif if (ssl) info(0, "Client connected from <%s> using SSL", octstr_get_cstr(ip)); else info(0, "Client connected from <%s>", octstr_get_cstr(ip)); /* XXX TODO: do the hand-shake, baby, yeah-yeah! */ return newconn; } static void bearerbox_to_smsbox(void *arg) { Msg *msg, *msg_escaped; Boxc *conn = arg; while (sqlbox_status == SQL_RUNNING && conn->alive) { msg = read_from_box(conn->bearerbox_connection, conn); if (msg == NULL) { /* tell sqlbox to die */ conn->alive = 0; debug("sqlbox", 0, "bearerbox_to_smsbox: connection to bearerbox died."); break; } if (msg_type(msg) == admin) { if (msg->admin.command == cmd_shutdown || msg->admin.command == cmd_restart) { /* tell sqlbox to die */ conn->alive = 0; debug("sqlbox", 0, "bearerbox_to_smsbox: Bearerbox told us to shutdown."); break; } } if (msg_type(msg) == heartbeat) { // todo debug("sqlbox", 0, "bearerbox_to_smsbox: catch an heartbeat - we are alive"); msg_destroy(msg); continue; } if (!conn->alive) { msg_destroy(msg); break; } if (msg_type(msg) == sms) { msg_escaped = msg_duplicate(msg); if (msg->sms.sms_type != report_mo) { if (save_mo) { gw_sql_save_msg(msg_escaped, octstr_imm("MO")); } } else { if (save_dlr) { gw_sql_save_msg(msg_escaped, octstr_imm("DLR")); } } msg_destroy(msg_escaped); } send_msg(conn->smsbox_connection, conn, msg); msg_destroy(msg); } /* the client closes the connection, after that die in receiver */ conn->alive = 0; } static void run_sqlbox(void *arg) { int fd; Boxc *newconn; long sender; fd = (int)arg; newconn = accept_boxc(fd, sqlbox_port_ssl); if (newconn == NULL) { panic(0, "Socket accept failed"); return; } newconn->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL /* bb_our_host */); /* XXX add our_host if required */ sender = gwthread_create(bearerbox_to_smsbox, newconn); if (sender == -1) { error(0, "Failed to start a new thread, disconnecting client <%s>", octstr_get_cstr(newconn->client_ip)); //goto cleanup; } smsbox_to_bearerbox(newconn); gwthread_join(sender); boxc_destroy(newconn); } static void wait_for_connections(int fd, void (*function) (void *arg), List *waited) { int ret; int timeout = 10; /* 10 sec. */ gw_assert(function != NULL); while(sqlbox_status == SQL_RUNNING) { ret = gwthread_pollfd(fd, POLLIN, 1.0); if (sqlbox_status == SQL_SHUTDOWN) { if (ret == -1 || !timeout) break; else timeout--; } if (ret > 0) { gwthread_create(function, (void *)fd); gwthread_sleep(1.0); } else if (ret < 0) { if(errno==EINTR) continue; if(errno==EAGAIN) continue; error(errno, "wait_for_connections failed"); } } } /* * Identify ourself to bearerbox for smsbox-specific routing inside bearerbox. * Do this even while no smsbox-id is given to unlock the sender thread in * bearerbox. */ static void identify_to_bearerbox(Boxc *conn) { Msg *msg; msg = msg_create(admin); msg->admin.command = cmd_identify; msg->admin.boxc_id = octstr_duplicate(conn->boxc_id); send_msg(conn->bearerbox_connection, conn, msg); msg_destroy(msg); } static void bearerbox_to_sql(void *arg) { Boxc *conn = (Boxc *)arg; Msg *msg, *mack; while (sqlbox_status == SQL_RUNNING && conn->alive) { msg = read_from_box(conn->bearerbox_connection, conn); if (msg == NULL) { /* garbage/connection lost */ /* tell sqlbox to die */ conn->alive = 0; sqlbox_status = SQL_SHUTDOWN; debug("sqlbox", 0, "bearerbox_to_sql: connection to bearerbox died."); break; } if (msg_type(msg) == heartbeat) { // todo debug("sqlbox", 0, "bearerbox_to_sql: catch an heartbeat - we are alive"); msg_destroy(msg); continue; } /* if this is an identification message from an smsbox instance */ if (msg_type(msg) == admin && msg->admin.command == cmd_shutdown) { /* tell sqlbox to die */ conn->alive = 0; sqlbox_status = SQL_SHUTDOWN; debug("sqlbox", 0, "bearerbox_to_sql: Bearerbox told us to shutdown."); break; } if (msg_type(msg) == sms) { if (msg->sms.sms_type != report_mo) { if (save_mo) { gw_sql_save_msg(msg, octstr_imm("MO")); } } else { if (save_dlr) { gw_sql_save_msg(msg, octstr_imm("DLR")); } } /* create ack message */ mack = msg_create(ack); mack->ack.nack = ack_success; mack->ack.time = msg->sms.time; uuid_copy(mack->ack.id, msg->sms.id); send_msg(conn->bearerbox_connection, conn, mack); msg_destroy(mack); } msg_destroy(msg); } } static void sql_single(Boxc *boxc) { Msg *msg; while (sqlbox_status == SQL_RUNNING && boxc->alive) { if ((msg = gw_sql_fetch_msg()) != NULL) { if (charset_processing(msg) == -1) { error(0, "Could not charset process message, dropping it!"); msg_destroy(msg); continue; } if (global_sender != NULL && (msg->sms.sender == NULL || octstr_len(msg->sms.sender) == 0)) { msg->sms.sender = octstr_duplicate(global_sender); } /* convert validity and deferred to unix timestamp */ if (msg->sms.validity != SMS_PARAM_UNDEFINED) msg->sms.validity = time(NULL) + msg->sms.validity * 60; if (msg->sms.deferred != SMS_PARAM_UNDEFINED) msg->sms.deferred = time(NULL) + msg->sms.deferred * 60; send_msg(boxc->bearerbox_connection, boxc, msg); if (save_mt) { /* convert validity & deferred back to minutes * TODO clarify why we fetched message from DB and then insert it back here??? */ if (msg->sms.validity != SMS_PARAM_UNDEFINED) msg->sms.validity = (msg->sms.validity - time(NULL))/60; if (msg->sms.deferred != SMS_PARAM_UNDEFINED) msg->sms.deferred = (msg->sms.deferred - time(NULL))/60; gw_sql_save_msg(msg, octstr_imm("MT")); } } else { gwthread_sleep(SLEEP_BETWEEN_EMPTY_SELECTS); } msg_destroy(msg); } } static void sql_list(Boxc *boxc) { Msg *msg; List *qlist, *save_list; qlist = gwlist_create(); gwlist_add_producer(qlist); save_list = gwlist_create(); gwlist_add_producer(save_list); while (sqlbox_status == SQL_RUNNING && boxc->alive) { if ( gw_sql_fetch_msg_list(qlist, limit_per_cycle) > 0 ) { while((gwlist_len(qlist)>0) && ((msg = gwlist_consume(qlist)) != NULL )) { if (charset_processing(msg) == -1) { error(0, "Could not charset process message, dropping it!"); msg_destroy(msg); continue; } if (global_sender != NULL && (msg->sms.sender == NULL || octstr_len(msg->sms.sender) == 0)) { msg->sms.sender = octstr_duplicate(global_sender); } /* convert validity and deferred to unix timestamp */ if (msg->sms.validity != SMS_PARAM_UNDEFINED) msg->sms.validity = time(NULL) + msg->sms.validity * 60; if (msg->sms.deferred != SMS_PARAM_UNDEFINED) msg->sms.deferred = time(NULL) + msg->sms.deferred * 60; send_msg(boxc->bearerbox_connection, boxc, msg); /* convert validity & deferred back to minutes */ if (save_mt && msg->sms.validity != SMS_PARAM_UNDEFINED) msg->sms.validity = (msg->sms.validity - time(NULL))/60; if (save_mt && msg->sms.deferred != SMS_PARAM_UNDEFINED) msg->sms.deferred = (msg->sms.deferred - time(NULL))/60; gwlist_produce(save_list, msg); } /* save_list also deletes and destroys messages */ gw_sql_save_list(save_list, octstr_imm("MT"), save_mt); } else { gwthread_sleep(SLEEP_BETWEEN_EMPTY_SELECTS); } } gwlist_remove_producer(qlist); gwlist_remove_producer(save_list); gwlist_destroy(qlist, msg_destroy_item); gwlist_destroy(save_list, msg_destroy_item); } static void sql_to_bearerbox(void *arg) { Boxc *boxc; boxc = gw_malloc(sizeof(Boxc)); boxc->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL /* bb_our_host */); boxc->smsbox_connection = NULL; boxc->client_ip = NULL; boxc->alive = 1; boxc->connect_time = time(NULL); boxc->boxc_id = octstr_duplicate(sqlbox_id); if (boxc->bearerbox_connection == NULL) { boxc_destroy(boxc); return; } gwthread_create(bearerbox_to_sql, boxc); identify_to_bearerbox(boxc); if (gw_sql_fetch_msg_list == NULL || gw_sql_save_list == NULL || limit_per_cycle <= 1) { sql_single(boxc); } else { sql_list(boxc); } boxc_destroy(boxc); } static void sqlboxc_run(void *arg) { int fd; int port; /* we will use one thread for SQL sms injections */ gwthread_create(sql_to_bearerbox, NULL); port = (int)arg; fd = make_server_socket(port, NULL); /* XXX add interface_name if required */ if (fd < 0) { panic(0, "Could not open sqlbox port %d", port); } /* * infinitely wait for new connections; * to shut down the system, SIGTERM is send and then * select drops with error, so we can check the status */ wait_for_connections(fd, run_sqlbox, NULL); /* close listen socket */ close(fd); } /*********************************************************************** * Main program. Configuration, signal handling, etc. */ static void signal_handler(int signum) { /* On some implementations (i.e. linuxthreads), signals are delivered * to all threads. We only want to handle each signal once for the * entire box, and we let the gwthread wrapper take care of choosing * one. */ if (!gwthread_shouldhandlesignal(signum)) return; switch (signum) { case SIGINT: if (sqlbox_status == SQL_RUNNING) { error(0, "SIGINT received, aborting program..."); sqlbox_status = SQL_SHUTDOWN; } break; case SIGHUP: warning(0, "SIGHUP received, catching and re-opening logs"); log_reopen(); alog_reopen(); break; /* * It would be more proper to use SIGUSR1 for this, but on some * platforms that's reserved by the pthread support. */ case SIGQUIT: warning(0, "SIGQUIT received, reporting memory usage."); gw_check_leaks(); break; } } static void setup_signal_handlers(void) { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGPIPE, &act, NULL); } static void init_sqlbox(Cfg *cfg) { CfgGroup *grp; Octstr *logfile; long lvl; /* some default values */ sqlbox_port_ssl = 0; bearerbox_port = BB_DEFAULT_SMSBOX_PORT; bearerbox_port_ssl = 0; logfile = NULL; lvl = 0; /* * first we take the port number in bearerbox and other values from the * core group in configuration file */ grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")); if (cfg_get_integer(&bearerbox_port, grp, octstr_imm("bearerbox-port")) == -1) panic(0, "Missing or bad 'bearerbox-port' in sqlbox group"); #ifdef HAVE_LIBSSL cfg_get_bool(&bearerbox_port_ssl, grp, octstr_imm("smsbox-port-ssl")); conn_config_ssl(grp); #endif grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")); if (grp == NULL) panic(0, "No 'sqlbox' group in configuration"); bearerbox_host = cfg_get( grp, octstr_imm("bearerbox-host")); if (bearerbox_host == NULL) bearerbox_host = octstr_create(BB_DEFAULT_HOST); sqlbox_id = cfg_get(grp, octstr_imm("smsbox-id")); global_sender = cfg_get(grp, octstr_imm("global-sender")); if (cfg_get_integer(&sqlbox_port, grp, octstr_imm("smsbox-port")) == -1) sqlbox_port = 13005; /* setup limit per cycle */ if (cfg_get_integer(&limit_per_cycle, grp, octstr_imm("limit-per-cycle")) == -1) limit_per_cycle = DEFAULT_LIMIT_PER_CYCLE; /* set up save parameters */ if (cfg_get_bool(&save_mo, grp, octstr_imm("save-mo")) == -1) save_mo = 1; if (cfg_get_bool(&save_mt, grp, octstr_imm("save-mt")) == -1) save_mt = 1; if (cfg_get_bool(&save_dlr, grp, octstr_imm("save-dlr")) == -1) save_dlr = 1; /* setup logfile stuff */ logfile = cfg_get(grp, octstr_imm("log-file")); cfg_get_integer(&lvl, grp, octstr_imm("log-level")); if (logfile != NULL) { info(0, "Starting to log to file %s level %ld", octstr_get_cstr(logfile), lvl); log_open(octstr_get_cstr(logfile), lvl, GW_NON_EXCL); octstr_destroy(logfile); } sql_type = sqlbox_init_sql(cfg); if (sql_type == NULL) { panic(0, "No proper SQL server defined."); } gw_sql_enter(cfg); sqlbox_status = SQL_RUNNING; } static int check_args(int i, int argc, char **argv) { if (strcmp(argv[i], "-H")==0 || strcmp(argv[i], "--tryhttp")==0) { //only_try_http = 1; } else { return -1; } return 0; } int main(int argc, char **argv) { int cf_index; Octstr *filename; gwlib_init(); cf_index = get_and_set_debugs(argc, argv, check_args); setup_signal_handlers(); if (argv[cf_index] == NULL) { filename = octstr_create("sqlbox.conf"); } else { filename = octstr_create(argv[cf_index]); } cfg = cfg_create(filename); /* Adding cfg-checks to core */ cfg_add_hooks(sqlbox_is_allowed_in_group, sqlbox_is_single_group); if (cfg_read(cfg) == -1) panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(filename)); octstr_destroy(filename); report_versions("sqlbox"); init_sqlbox(cfg); sqlboxc_run((void *)sqlbox_port); cfg_destroy(cfg); if (restart_sqlbox) { gwthread_sleep(1.0); } gw_sql_leave(); gwlib_shutdown(); if (restart_sqlbox) execvp(argv[0], argv); return 0; } gateway-1.4.5/addons/sqlbox/gw/sqlbox_sqlite3.h0000644000175000017500000000514111535701311020204 0ustar toljtolj#include "gwlib/gwlib.h" #if defined(HAVE_SQLITE3) || defined(HAVE_SDB) #define SQLBOX_SQLITE3_CREATE_LOG_TABLE "CREATE TABLE IF NOT EXISTS %S ( \ sql_id INTEGER PRIMARY KEY AUTOINCREMENT, momt CHAR(3) NULL, sender VARCHAR(20) NULL, \ receiver VARCHAR(20) NULL, udhdata BLOB NULL, msgdata TEXT NULL, time BIGINT(20) NULL, \ smsc_id VARCHAR(255) NULL, service VARCHAR(255) NULL, account VARCHAR(255) NULL, \ id BIGINT(20) NULL, sms_type BIGINT(20) NULL, mclass BIGINT(20) NULL, mwi BIGINT(20) NULL, \ coding BIGINT(20) NULL, compress BIGINT(20) NULL, validity BIGINT(20) NULL, \ deferred BIGINT(20) NULL, dlr_mask BIGINT(20) NULL, dlr_url VARCHAR(255) NULL, \ pid BIGINT(20) NULL, alt_dcs BIGINT(20) NULL, rpi BIGINT(20) NULL, charset VARCHAR(255) NULL, \ boxc_id VARCHAR(255) NULL, binfo VARCHAR(255) NULL, meta_data TEXT NULL)" #define SQLBOX_SQLITE3_CREATE_INSERT_TABLE "CREATE TABLE IF NOT EXISTS %S ( \ sql_id INTEGER PRIMARY KEY AUTOINCREMENT, momt CHAR(3) NULL, sender VARCHAR(20) NULL, \ receiver VARCHAR(20) NULL, udhdata BLOB NULL, msgdata TEXT NULL, time BIGINT(20) NULL, \ smsc_id VARCHAR(255) NULL, service VARCHAR(255) NULL, account VARCHAR(255) NULL, \ id BIGINT(20) NULL, sms_type BIGINT(20) NULL, mclass BIGINT(20) NULL, mwi BIGINT(20) NULL, \ coding BIGINT(20) NULL, compress BIGINT(20) NULL, validity BIGINT(20) NULL, \ deferred BIGINT(20) NULL, dlr_mask BIGINT(20) NULL, dlr_url VARCHAR(255) NULL, \ pid BIGINT(20) NULL, alt_dcs BIGINT(20) NULL, rpi BIGINT(20) NULL, charset VARCHAR(255) NULL, \ boxc_id VARCHAR(255) NULL, binfo VARCHAR(255) NULL, meta_data TEXT NULL)" #define SQLBOX_SQLITE3_SELECT_QUERY "SELECT sql_id, momt, sender, receiver, udhdata, msgdata, \ time, smsc_id, service, account, id, sms_type, mclass, mwi, coding, compress, validity, deferred, \ dlr_mask, dlr_url, pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data FROM %S LIMIT 0,1" #define SQLBOX_SQLITE3_INSERT_QUERY "INSERT INTO %S (sql_id, momt, sender, receiver, udhdata, \ msgdata, time, smsc_id, service, account, sms_type, mclass, mwi, coding, compress, validity, \ deferred, dlr_mask, dlr_url, pid, alt_dcs, rpi, charset, boxc_id, binfo, meta_data) VALUES (NULL, \ %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S)" #define SQLBOX_SQLITE3_DELETE_QUERY "DELETE FROM %S WHERE sql_id = %S" #endif /* HAVE_SQLITE3 || HAVE_SDB */ #ifdef HAVE_SQLITE3 #include "gw/msg.h" #include "sqlbox_sql.h" void sql_save_msg(Msg *msg, Octstr *momt ); Msg *sqlite3_fetch_msg(); void sql_shutdown(); struct server_type *sqlbox_init_sqlite3(Cfg *cfg); #ifndef sqlbox_sqlite3_c extern #endif Octstr *sqlbox_id; #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_sql.c0000644000175000017500000000175711204545563017433 0ustar toljtolj#define sqlbox_sql_c #include "sqlbox_sql.h" struct server_type *sqlbox_init_sql(Cfg *cfg) { struct server_type *res = NULL; #ifdef HAVE_MSSQL res = (struct server_type *)sqlbox_init_mssql(cfg); if (res) { return res; } #endif #ifdef HAVE_MYSQL res = (struct server_type *)sqlbox_init_mysql(cfg); if (res) { return res; } #endif #ifdef HAVE_ORACLE res = (struct server_type *)sqlbox_init_oracle(cfg); if (res) { return res; } #endif #ifdef HAVE_PGSQL res = (struct server_type *)sqlbox_init_pgsql(cfg); if (res) { return res; } #endif #ifdef HAVE_SDB res = (struct server_type *)sqlbox_init_sdb(cfg); if (res) { return res; } #endif #ifdef HAVE_SQLITE res = (struct server_type *)sqlbox_init_sqlite(cfg); if (res) { return res; } #endif #ifdef HAVE_SQLITE3 res = (struct server_type *)sqlbox_init_sqlite3(cfg); if (res) { return res; } #endif return res; } gateway-1.4.5/addons/sqlbox/gw/sqlbox_pgsql.c0000644000175000017500000002550312203523676017756 0ustar toljtolj#include "gwlib/gwlib.h" #ifdef HAVE_PGSQL #include "gwlib/dbpool.h" #define sqlbox_pgsql_c #include "sqlbox_pgsql.h" #include #define sql_update pgsql_update #define sql_select pgsql_select #define exit_nicely(conn) do { PQfinish(conn); } while(0) static Octstr *sqlbox_logtable; static Octstr *sqlbox_insert_table; /* * Our connection pool to pgsql. */ static DBPool *pool = NULL; /* *------------------------------------------------- * Postgres SQL thingies *------------------------------------------------- */ static void pgsql_update(const Octstr *sql) { DBPoolConn *pc; PGresult *res; ExecStatusType status; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "PGSQL: Database pool got no connection! DB update failed!"); return; } res = PQexec(pc->conn, octstr_get_cstr(sql)); status = PQresultStatus(res); switch(status) { case PGRES_BAD_RESPONSE: case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: error (0, "PGSQL: %s", PQresultErrorMessage(res)); break; default: /* Don't handle the other PGRES_foobar enumerates. */ break; } dbpool_conn_produce(pc); } static PGresult *pgsql_select(const Octstr *sql) { PGresult *res = NULL; DBPoolConn *pc; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "PGSQL: Database pool got no connection! DB operation failed!"); return NULL; } res = PQexec(pc->conn, octstr_get_cstr(sql)); switch (PQresultStatus(res)) { case PGRES_EMPTY_QUERY: case PGRES_BAD_RESPONSE: case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: error(0, "PGSQL: %s", PQresultErrorMessage(res)); break; default: /* all other enum values are not handled. */ break; } dbpool_conn_produce(pc); return res; } void sqlbox_configure_pgsql(Cfg* cfg) { CfgGroup *grp; Octstr *sql; if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: PGSQL: group 'sqlbox' is not specified!"); sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table")); if (sqlbox_logtable == NULL) { panic(0, "No 'sql-log-table' not configured."); } sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table")); if (sqlbox_insert_table == NULL) { panic(0, "No 'sql-insert-table' not configured."); } /* create send_sms && sent_sms tables if they do not exist */ sql = octstr_format(SQLBOX_PGSQL_CREATE_LOG_TABLE, sqlbox_logtable); sql_update(sql); octstr_destroy(sql); sql = octstr_format(SQLBOX_PGSQL_CREATE_INSERT_TABLE, sqlbox_insert_table); sql_update(sql); octstr_destroy(sql); /* end table creation */ } static Octstr *get_numeric_value_or_return_null(long int num) { if (num == -1) { return octstr_create("NULL"); } return octstr_format("%ld", num); } static Octstr *get_string_value_or_return_null(Octstr *str) { if (str == NULL) { return octstr_create("NULL"); } if (octstr_compare(str, octstr_imm("")) == 0) { return octstr_create("NULL"); } octstr_replace(str, octstr_imm("\\"), octstr_imm("\\\\")); octstr_replace(str, octstr_imm("\'"), octstr_imm("\\\'")); return octstr_format("\'%S\'", str); } #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x)) #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x)) void pgsql_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */) { Octstr *sql; Octstr *stuffer[30]; int stuffcount = 0; sql = octstr_format(SQLBOX_PGSQL_INSERT_QUERY, sqlbox_logtable, st_str(momt), st_str(msg->sms.sender), st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time), st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type), st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress), st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url), st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset), st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data), st_str(msg->sms.foreign_id)); sql_update(sql); //debug("sqlbox", 0, "sql_save_msg: %s", octstr_get_cstr(sql)); while (stuffcount > 0) { octstr_destroy(stuffer[--stuffcount]); } octstr_destroy(sql); } void pgsql_leave() { dbpool_destroy(pool); } #define octstr_null_create(x) (octstr_create(PQgetvalue(res, 0, x))) #define atol_null(x) ((PQgetisnull(res, 0, x) == 0) ? atol(PQgetvalue(res, 0, x)) : -1) Msg *pgsql_fetch_msg() { Msg *msg = NULL; Octstr *sql, *delet, *id; PGresult *res; sql = octstr_format(SQLBOX_PGSQL_SELECT_QUERY, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif res = pgsql_select(sql); if (res == NULL) { debug("sqlbox", 0, "SQL statement failed: %s", octstr_get_cstr(sql)); } else { if (PQntuples(res) >= 1) { id = octstr_null_create(0); /* save fields in this row as msg struct */ msg = msg_create(sms); /* we abuse the foreign_id field in the message struct for our sql_id value */ msg->sms.foreign_id = octstr_null_create(0); msg->sms.sender = octstr_null_create(2); msg->sms.receiver = octstr_null_create(3); msg->sms.udhdata = octstr_null_create(4); msg->sms.msgdata = octstr_null_create(5); msg->sms.time = atol_null(6); msg->sms.smsc_id = octstr_null_create(7); msg->sms.service = octstr_null_create(8); msg->sms.account = octstr_null_create(9); /* msg->sms.id = atol_null(row[10]); */ msg->sms.sms_type = atol_null(11); msg->sms.mclass = atol_null(12); msg->sms.mwi = atol_null(13); msg->sms.coding = atol_null(14); msg->sms.compress = atol_null(15); msg->sms.validity = atol_null(16); msg->sms.deferred = atol_null(17); msg->sms.dlr_mask = atol_null(18); msg->sms.dlr_url = octstr_null_create(19); msg->sms.pid = atol_null(20); msg->sms.alt_dcs = atol_null(21); msg->sms.rpi = atol_null(22); msg->sms.charset = octstr_null_create(23); msg->sms.binfo = octstr_null_create(25); msg->sms.meta_data = octstr_null_create(26); if ((PQgetvalue(res, 0, 24)) == NULL) { msg->sms.boxc_id= octstr_duplicate(sqlbox_id); } else { msg->sms.boxc_id= octstr_null_create(24); } /* delete current row */ delet = octstr_format(SQLBOX_PGSQL_DELETE_QUERY, sqlbox_insert_table, id); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet)); #endif pgsql_update(delet); octstr_destroy(id); octstr_destroy(delet); } PQclear(res); } octstr_destroy(sql); //debug("sqlbox", 0, "sql_fetch_msg: %s", octstr_get_cstr(sql)); return msg; } struct server_type *sqlbox_init_pgsql(Cfg* cfg) { CfgGroup *grp; List *grplist; Octstr *pgsql_host, *pgsql_user, *pgsql_pass, *pgsql_db, *pgsql_id; Octstr *p = NULL; long pool_size, pgsql_port; int have_port; DBConf *db_conf = NULL; struct server_type *res = NULL; /* * check for all mandatory directives that specify the field names * of the used PGSQL table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: PGSQL: group 'sqlbox' is not specified!"); if (!(pgsql_id = cfg_get(grp, octstr_imm("id")))) panic(0, "SQLBOX: PGSQL: directive 'id' is not specified!"); /* * now grap the required information from the 'pgsql-connection' group * with the pgsql-id we just obtained * * we have to loop through all available PGSQL connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("pgsql-connection")); while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, pgsql_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "SQLBOX: PGSQL: connection settings for id '%s' are not specified!", octstr_get_cstr(pgsql_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(pgsql_host = cfg_get(grp, octstr_imm("host")))) panic(0, "SQLBOX: PGSQL: directive 'host' is not specified!"); if (!(pgsql_user = cfg_get(grp, octstr_imm("username")))) panic(0, "SQLBOX: PGSQL: directive 'username' is not specified!"); if (!(pgsql_pass = cfg_get(grp, octstr_imm("password")))) panic(0, "SQLBOX: PGSQL: directive 'password' is not specified!"); if (!(pgsql_db = cfg_get(grp, octstr_imm("database")))) panic(0, "SQLBOX: PGSQL: directive 'database' is not specified!"); have_port = (cfg_get_integer(&pgsql_port, grp, octstr_imm("port")) != -1); /* * ok, ready to connect to PGSQL */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->pgsql = gw_malloc(sizeof(PgSQLConf)); gw_assert(db_conf->pgsql != NULL); db_conf->pgsql->host = pgsql_host; db_conf->pgsql->username = pgsql_user; db_conf->pgsql->password = pgsql_pass; db_conf->pgsql->database = pgsql_db; if (have_port) { db_conf->pgsql->port = pgsql_port; } pool = dbpool_create(DBPOOL_PGSQL, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"SQLBOX: PGSQL: database pool has no connections!"); octstr_destroy(pgsql_id); res = gw_malloc(sizeof(struct server_type)); gw_assert(res != NULL); res->type = octstr_create("PGSQL"); res->sql_enter = sqlbox_configure_pgsql; res->sql_leave = pgsql_leave; res->sql_fetch_msg = pgsql_fetch_msg; res->sql_save_msg = pgsql_save_msg; res->sql_fetch_msg_list = NULL; res->sql_save_list = NULL; return res; } #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_sdb.c0000644000175000017500000003476512203523676017412 0ustar toljtolj#include "gwlib/gwlib.h" #ifdef HAVE_SDB #include "gwlib/dbpool.h" #include #define sqlbox_sdb_c #include "sqlbox_sdb.h" #define sql_update sdb_update #define sql_select sdb_select static Octstr *sqlbox_logtable; static Octstr *sqlbox_insert_table; /* * Our connection pool to sdb. */ static DBPool *pool = NULL; static struct sqlbox_db_fields *fields = NULL; static struct sqlbox_db_queries *queries = NULL; enum { SDB_MYSQL, SDB_ORACLE, SDB_POSTGRES, SDB_SQLITE, SDB_SQLITE3, SDB_OTHER }; static long sdb_conn_type = SDB_OTHER; /* *------------------------------------------------- * sdb thingies *------------------------------------------------- */ #define octstr_null_create(x) ((x != NULL) ? octstr_create(x) : octstr_create("")) #define atol_null(x) ((x != NULL) ? atol(x) : -1) #define get_sdb_octstr_col(x) (octstr_create(octstr_get_cstr(gwlist_get(row,x)))) #define get_sdb_long_col(x) (atol(octstr_get_cstr(gwlist_get(row,x)))) static int sdb_update(DBPoolConn *conn, const Octstr *sql) { int state; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif state = sdb_query(conn->conn, octstr_get_cstr(sql), NULL, NULL); if (state < 0) { error(0, "SDB: Error updating rows"); return -1; } return state; } static int sdb_select(DBPoolConn *conn, const Octstr *sql, int (*callback)(int, char **, void *), void *closure) { int state; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif state = sdb_query(conn->conn, octstr_get_cstr(sql), callback, closure); if (state < 0) { error(0, "SDB: Error selecting rows"); return -1; } return state; } void sdb_callback_addrow(int n, char **data, List **rows) { int i; List *row = gwlist_create(); for (i = 0; i < n; i++) { gwlist_insert(row, i, octstr_null_create(data[i])); } gwlist_append(*rows, row); } void sqlbox_configure_sdb(Cfg* cfg) { CfgGroup *grp; Octstr *sql; DBPoolConn *pc; if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: Sdb: group 'sqlbox' is not specified!"); sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table")); if (sqlbox_logtable == NULL) { panic(0, "Parameter 'sql-log-table' not configured."); } sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table")); if (sqlbox_insert_table == NULL) { panic(0, "Parameter 'sql-insert-table' not configured."); } pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SDB: Database pool got no connection! DB update failed!"); return; } /* create send_sms && sent_sms tables if they do not exist */ sqlbox_run_query(queries->create_log_table, sqlbox_logtable); sqlbox_run_query(queries->create_log_sequence, sqlbox_logtable); sqlbox_run_query(queries->create_log_trigger, sqlbox_logtable); sqlbox_run_query(queries->create_insert_table, sqlbox_insert_table); sqlbox_run_query(queries->create_insert_sequence, sqlbox_insert_table); sqlbox_run_query(queries->create_insert_trigger, sqlbox_insert_table); /* end table creation */ dbpool_conn_produce(pc); } Msg *sdb_fetch_msg() { Msg *msg = NULL; Octstr *sql, *delet, *id; List *res, *row; DBPoolConn *pc; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SDB: Database pool got no connection! DB update failed!"); return NULL; } res = gwlist_create(); gw_assert(res != NULL); sql = octstr_format(queries->select_query, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (sql_select(pc, sql, (void *)sdb_callback_addrow, &res) < 0) { debug("sqlbox", 0, "SQL statement failed: %s", octstr_get_cstr(sql)); } else { if (gwlist_len(res) > 0) { row = gwlist_extract_first(res); gw_assert(row != NULL); id = get_sdb_octstr_col(0); /* save fields in this row as msg struct */ msg = msg_create(sms); /* we abuse the foreign_id field in the message struct for our sql_id value */ msg->sms.foreign_id = get_sdb_octstr_col(0); msg->sms.sender = get_sdb_octstr_col(2); msg->sms.receiver = get_sdb_octstr_col(3); msg->sms.udhdata = get_sdb_octstr_col(4); msg->sms.msgdata = get_sdb_octstr_col(5); msg->sms.time = get_sdb_long_col(6); msg->sms.smsc_id = get_sdb_octstr_col(7); msg->sms.service = get_sdb_octstr_col(8); msg->sms.account = get_sdb_octstr_col(9); /* msg->sms.id = get_sdb_long_col(10); */ msg->sms.sms_type = get_sdb_long_col(11); msg->sms.mclass = get_sdb_long_col(12); msg->sms.mwi = get_sdb_long_col(13); msg->sms.coding = get_sdb_long_col(14); msg->sms.compress = get_sdb_long_col(15); msg->sms.validity = get_sdb_long_col(16); msg->sms.deferred = get_sdb_long_col(17); msg->sms.dlr_mask = get_sdb_long_col(18); msg->sms.dlr_url = get_sdb_octstr_col(19); msg->sms.pid = get_sdb_long_col(20); msg->sms.alt_dcs = get_sdb_long_col(21); msg->sms.rpi = get_sdb_long_col(22); msg->sms.charset = get_sdb_octstr_col(23); msg->sms.binfo = get_sdb_octstr_col(25); msg->sms.meta_data = get_sdb_octstr_col(26); if (gwlist_get(row,24) == NULL) { msg->sms.boxc_id= octstr_duplicate(sqlbox_id); } else { msg->sms.boxc_id= get_sdb_octstr_col(24); } /* delete current row */ delet = octstr_format(queries->delete_query, sqlbox_insert_table, id); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet)); #endif sql_update(pc, delet); octstr_destroy(id); octstr_destroy(delet); gwlist_destroy(row, octstr_destroy_item); } } gwlist_destroy(res, NULL); octstr_destroy(sql); dbpool_conn_produce(pc); return msg; } static Octstr *get_numeric_value_or_return_null(long int num) { if (num == -1) { return octstr_create("NULL"); } return octstr_format("%ld", num); } static Octstr *get_string_value_or_return_null(Octstr *str) { if (str == NULL) { return octstr_create("NULL"); } if (octstr_compare(str, octstr_imm("")) == 0) { return octstr_create("NULL"); } octstr_replace(str, octstr_imm("\\"), octstr_imm("\\\\")); octstr_replace(str, octstr_imm("\'"), octstr_imm("\\\'")); return octstr_format("\'%S\'", str); } #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x)) #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x)) void sdb_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */) { Octstr *sql; Octstr *stuffer[30]; int stuffcount = 0; DBPoolConn *pc; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SDB: Database pool got no connection! DB update failed!"); return; } sql = octstr_format(queries->insert_query, sqlbox_logtable, st_str(momt), st_str(msg->sms.sender), st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time), st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type), st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress), st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url), st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset), st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data), st_str(msg->sms.foreign_id)); sql_update(pc, sql); while (stuffcount > 0) { octstr_destroy(stuffer[--stuffcount]); } octstr_destroy(sql); dbpool_conn_produce(pc); } void sdb_leave() { dbpool_destroy(pool); } struct server_type *sqlbox_init_sdb(Cfg* cfg) { CfgGroup *grp; List *grplist; Octstr *sdb_url, *sdb_id; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; struct server_type *res = NULL; /* * check for all mandatory directives that specify the field names * of the used Sdb table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: Sdb: group 'sqlbox' is not specified!"); if (!(sdb_id = cfg_get(grp, octstr_imm("id")))) panic(0, "SQLBOX: Sdb: directive 'id' is not specified!"); /* * now grap the required information from the 'sdb-connection' group * with the sdb-id we just obtained * * we have to loop through all available Sdb connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("sdb-connection")); while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, sdb_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "SQLBOX: Sdb: connection settings for id '%s' are not specified!", octstr_get_cstr(sdb_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(sdb_url = cfg_get(grp, octstr_imm("url")))) panic(0, "SQLBOX: SDB: directive 'url' is not specified!"); queries = gw_malloc(sizeof(struct sqlbox_db_queries)); gw_assert(queries != NULL); if (octstr_search(sdb_url, octstr_imm("mysql:"), 0) == 0) { warning(0, "SQLBOX[sdb]: Please use native MySQL support, instead of libsdb."); sdb_conn_type = SDB_MYSQL; queries->create_insert_table = SQLBOX_MYSQL_CREATE_INSERT_TABLE; queries->create_insert_sequence = NULL; queries->create_insert_trigger = NULL; queries->create_log_table = SQLBOX_MYSQL_CREATE_LOG_TABLE; queries->create_log_sequence = NULL; queries->create_log_trigger = NULL; queries->select_query = SQLBOX_MYSQL_SELECT_QUERY; queries->delete_query = SQLBOX_MYSQL_DELETE_QUERY; queries->insert_query = SQLBOX_MYSQL_INSERT_QUERY; } else if (octstr_search(sdb_url, octstr_imm("oracle:"), 0) == 0) { sdb_conn_type = SDB_ORACLE; queries->create_insert_table = SQLBOX_ORACLE_CREATE_INSERT_TABLE; queries->create_insert_sequence = SQLBOX_ORACLE_CREATE_INSERT_SEQUENCE; queries->create_insert_trigger = SQLBOX_ORACLE_CREATE_INSERT_TRIGGER; queries->create_log_table = SQLBOX_ORACLE_CREATE_LOG_TABLE; queries->create_log_sequence = SQLBOX_ORACLE_CREATE_LOG_SEQUENCE; queries->create_log_trigger = SQLBOX_ORACLE_CREATE_LOG_TRIGGER; queries->select_query = SQLBOX_ORACLE_SELECT_QUERY; queries->delete_query = SQLBOX_ORACLE_DELETE_QUERY; queries->insert_query = SQLBOX_ORACLE_INSERT_QUERY; } else if (octstr_search(sdb_url, octstr_imm("postgres:"), 0) == 0) { sdb_conn_type = SDB_POSTGRES; queries->create_insert_table = SQLBOX_PGSQL_CREATE_INSERT_TABLE; queries->create_insert_sequence = NULL; queries->create_insert_trigger = NULL; queries->create_log_table = SQLBOX_PGSQL_CREATE_LOG_TABLE; queries->create_log_sequence = NULL; queries->create_log_trigger = NULL; queries->select_query = SQLBOX_PGSQL_SELECT_QUERY; queries->delete_query = SQLBOX_PGSQL_DELETE_QUERY; queries->insert_query = SQLBOX_PGSQL_INSERT_QUERY; } else if (octstr_search(sdb_url, octstr_imm("sqlite:"), 0) == 0) { sdb_conn_type = SDB_SQLITE; queries->create_insert_table = SQLBOX_SQLITE_CREATE_INSERT_TABLE; queries->create_insert_sequence = NULL; queries->create_insert_trigger = NULL; queries->create_log_table = SQLBOX_SQLITE_CREATE_LOG_TABLE; queries->create_log_sequence = NULL; queries->create_log_trigger = NULL; queries->select_query = SQLBOX_SQLITE_SELECT_QUERY; queries->delete_query = SQLBOX_SQLITE_DELETE_QUERY; queries->insert_query = SQLBOX_SQLITE_INSERT_QUERY; } else if (octstr_search(sdb_url, octstr_imm("sqlite3:"), 0) == 0) { sdb_conn_type = SDB_SQLITE3; queries->create_insert_table = SQLBOX_SQLITE3_CREATE_INSERT_TABLE; queries->create_insert_sequence = NULL; queries->create_insert_trigger = NULL; queries->create_log_table = SQLBOX_SQLITE3_CREATE_LOG_TABLE; queries->create_log_sequence = NULL; queries->create_log_trigger = NULL; queries->select_query = SQLBOX_SQLITE3_SELECT_QUERY; queries->delete_query = SQLBOX_SQLITE3_DELETE_QUERY; queries->insert_query = SQLBOX_SQLITE3_INSERT_QUERY; } else { sdb_conn_type = SDB_OTHER; queries->create_insert_table = NULL; queries->create_insert_sequence = NULL; queries->create_insert_trigger = NULL; queries->create_log_table = NULL; queries->create_log_sequence = NULL; queries->create_log_trigger = NULL; queries->select_query = SQLBOX_OTHER_SELECT_QUERY; queries->delete_query = SQLBOX_OTHER_DELETE_QUERY; queries->insert_query = SQLBOX_OTHER_INSERT_QUERY; } /* * ok, ready to connect to Sdb */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->sdb = gw_malloc(sizeof(SDBConf)); gw_assert(db_conf->sdb != NULL); db_conf->sdb->url = sdb_url; pool = dbpool_create(DBPOOL_SDB, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"SQLBOX: Sdb: database pool has no connections!"); octstr_destroy(sdb_id); res = gw_malloc(sizeof(struct server_type)); gw_assert(res != NULL); res->type = octstr_create("Sdb"); res->sql_enter = sqlbox_configure_sdb; res->sql_leave = sdb_leave; res->sql_fetch_msg = sdb_fetch_msg; res->sql_save_msg = sdb_save_msg; res->sql_fetch_msg_list = NULL; res->sql_save_list = NULL; return res; } #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_mssql.c0000644000175000017500000002426212203523676017770 0ustar toljtolj#include "gwlib/gwlib.h" #ifdef HAVE_MSSQL #include "gwlib/dbpool.h" #include #define sqlbox_mssql_c #include "sqlbox_mssql.h" #define sql_update dbpool_conn_update #define sql_select dbpool_conn_select static Octstr *sqlbox_logtable; static Octstr *sqlbox_insert_table; /* * Our connection pool to mssql. */ static DBPool *pool = NULL; void sqlbox_configure_mssql(Cfg* cfg) { DBPoolConn *pc; CfgGroup *grp; Octstr *sql; if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: MSSql: group 'sqlbox' is not specified!"); sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table")); if (sqlbox_logtable == NULL) { panic(0, "Parameter 'sql-log-table' not configured."); } sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table")); if (sqlbox_insert_table == NULL) { panic(0, "Parameter 'sql-insert-table' not configured."); } pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "MSSql: DBPool Error!"); return; } /* create send_sms && sent_sms tables if they do not exist */ sql = octstr_format(SQLBOX_MSSQL_CREATE_LOG_TABLE, sqlbox_logtable, sqlbox_logtable); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); octstr_destroy(sql); sql = octstr_format(SQLBOX_MSSQL_CREATE_INSERT_TABLE, sqlbox_insert_table, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); octstr_destroy(sql); dbpool_conn_produce(pc); } Octstr *get_column(Octstr *str) { Octstr *ret = octstr_create(octstr_get_cstr(str)); if (ret != NULL) octstr_strip_blanks(ret); return ret; } static Octstr *get_numeric_value_or_return_null(long int num) { if (num == -1) { return octstr_create("NULL"); } return octstr_format("%ld", num); } static Octstr *get_string_value_or_return_null(Octstr *str) { if (str == NULL) { return octstr_create("NULL"); } else if (octstr_compare(str, octstr_imm("")) == 0) { return octstr_create("NULL"); } octstr_replace(str, octstr_imm("\\"), octstr_imm("\\\\")); octstr_replace(str, octstr_imm("\'"), octstr_imm("\\\'")); return octstr_format("\'%S\'", str); } #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x)) #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x)) #define octstr_null_create(x) ((x != NULL) ? octstr_create(x) : octstr_create("")) #define atol_null(x) ((x != NULL) ? atol(x) : -1) #define get_mssql_octstr_col(x) (get_column(gwlist_get(row,x))) #define get_mssql_long_col(x) (atol(octstr_get_cstr(gwlist_get(row,x)))) Msg *mssql_fetch_msg() { Msg *msg = NULL; Octstr *sql, *delet, *id; List *res, *row; int ret; DBPoolConn *pc; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "MSSql: DBPool error!"); return; } sql = octstr_format(SQLBOX_MSSQL_SELECT_QUERY, sqlbox_insert_table); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (sql_select(pc, sql, NULL, &res) != 0) { debug("sqlbox", 0, "SQL statement failed: %s", octstr_get_cstr(sql)); } else { if (gwlist_len(res) > 0) { row = gwlist_extract_first(res); id = get_mssql_octstr_col(0); /* save fields in this row as msg struct */ msg = msg_create(sms); /* we abuse the foreign_id field in the message struct for our sql_id value */ msg->sms.foreign_id = get_mssql_octstr_col(0); msg->sms.sender = get_mssql_octstr_col(2); msg->sms.receiver = get_mssql_octstr_col(3); msg->sms.udhdata = get_mssql_octstr_col(4); msg->sms.msgdata = get_mssql_octstr_col(5); msg->sms.time = get_mssql_long_col(6); msg->sms.smsc_id = get_mssql_octstr_col(7); msg->sms.service = get_mssql_octstr_col(8); msg->sms.account = get_mssql_octstr_col(9); /* msg->sms.id = get_mssql_long_col(10); */ msg->sms.sms_type = get_mssql_long_col(11); msg->sms.mclass = get_mssql_long_col(12); msg->sms.mwi = get_mssql_long_col(13); msg->sms.coding = get_mssql_long_col(14); msg->sms.compress = get_mssql_long_col(15); msg->sms.validity = get_mssql_long_col(16); msg->sms.deferred = get_mssql_long_col(17); msg->sms.dlr_mask = get_mssql_long_col(18); msg->sms.dlr_url = get_mssql_octstr_col(19); msg->sms.pid = get_mssql_long_col(20); msg->sms.alt_dcs = get_mssql_long_col(21); msg->sms.rpi = get_mssql_long_col(22); msg->sms.charset = get_mssql_octstr_col(23); msg->sms.binfo = get_mssql_octstr_col(25); msg->sms.meta_data = get_mssql_octstr_col(26); if (gwlist_get(row,24) == NULL) { msg->sms.boxc_id = octstr_duplicate(sqlbox_id); } else { msg->sms.boxc_id = get_mssql_octstr_col(24); } /* delete current row */ delet = octstr_format(SQLBOX_MSSQL_DELETE_QUERY, sqlbox_insert_table, id); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet)); #endif sql_update(pc, delet, NULL); octstr_destroy(id); octstr_destroy(delet); gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(res, NULL); } dbpool_conn_produce(pc); octstr_destroy(sql); return msg; } void mssql_save_msg(Msg *msg, Octstr *momt /*, Octstr smsbox_id */) { Octstr *sql; Octstr *stuffer[30]; int stuffcount = 0; DBPoolConn *pc; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "MSSql: DBPool Error!"); return; } sql = octstr_format(SQLBOX_MSSQL_INSERT_QUERY, sqlbox_logtable, st_str(momt), st_str(msg->sms.sender), st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time), st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type), st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress), st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url), st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset), st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data), st_str(msg->sms.foreign_id)); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif sql_update(pc, sql, NULL); while (stuffcount > 0) { octstr_destroy(stuffer[--stuffcount]); } dbpool_conn_produce(pc); octstr_destroy(sql); } void mssql_leave() { dbpool_destroy(pool); } struct server_type *sqlbox_init_mssql(Cfg* cfg) { CfgGroup *grp; List *grplist; Octstr *mssql_user, *mssql_pass, *mssql_server, *mssql_database, *mssql_id; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; struct server_type *res = NULL; /* * check for all mandatory directives that specify the field names * of the used MSSql table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: MSSql: group 'sqlbox' is not specified!"); if (!(mssql_id = cfg_get(grp, octstr_imm("id")))) panic(0, "SQLBOX: MSSql: directive 'id' is not specified!"); /* * now grap the required information from the 'mssql-connection' group * with the mssql-id we just obtained * * we have to loop through all available MSSql connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("mssql-connection")); while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, mssql_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "SQLBOX: MSSql: connection settings for id '%s' are not specified!", octstr_get_cstr(mssql_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(mssql_user = cfg_get(grp, octstr_imm("username")))) panic(0, "SQLBOX: MSSql: directive 'username' is not specified!"); if (!(mssql_pass = cfg_get(grp, octstr_imm("password")))) panic(0, "SQLBOX: MSSql: directive 'password' is not specified!"); if (!(mssql_server = cfg_get(grp, octstr_imm("server")))) panic(0, "SQLBOX: MSSql: directive 'server' is not specified!"); if (!(mssql_database = cfg_get(grp, octstr_imm("database")))) panic(0, "SQLBOX: MSSql: directive 'database' is not specified!"); /* * ok, ready to connect to MSSql */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->mssql = gw_malloc(sizeof(MSSQLConf)); gw_assert(db_conf->mssql != NULL); db_conf->mssql->username = mssql_user; db_conf->mssql->password = mssql_pass; db_conf->mssql->server = mssql_server; db_conf->mssql->database = mssql_database; pool = dbpool_create(DBPOOL_MSSQL, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"SQLBOX: MSSql: database pool has no connections!"); octstr_destroy(mssql_id); res = gw_malloc(sizeof(struct server_type)); gw_assert(res != NULL); res->type = octstr_create("MSSql"); res->sql_enter = sqlbox_configure_mssql; res->sql_leave = mssql_leave; res->sql_fetch_msg = mssql_fetch_msg; res->sql_save_msg = mssql_save_msg; res->sql_fetch_msg_list = NULL; res->sql_save_list = NULL; return res; } #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox-cfg.def0000644000175000017500000000135413131504337017611 0ustar toljtolj/* ================================================================== * Sqlbox-cfg.def - Definition of configuration groups and variables * * Martin Conte * */ SINGLE_GROUP(sqlbox, OCTSTR(id) OCTSTR(smsbox-id) OCTSTR(global-sender) OCTSTR(bearerbox-host) OCTSTR(smsbox-port) OCTSTR(smsbox-port-ssl) OCTSTR(sql-log-table) OCTSTR(sql-insert-table) OCTSTR(log-file) OCTSTR(log-level) OCTSTR(bearerbox-port) OCTSTR(limit-per-cycle) OCTSTR(save-mo) OCTSTR(save-mt) OCTSTR(save-dlr) OCTSTR(ssl-client-certkey-file) OCTSTR(ssl-server-cert-file) OCTSTR(ssl-server-key-file) OCTSTR(ssl-trusted-ca-file) OCTSTR(ssl-client-cipher-list) OCTSTR(ssl-server-cipher-list) ) gateway-1.4.5/addons/sqlbox/gw/sqlbox_sql.h0000644000175000017500000000317512203523676017435 0ustar toljtolj#ifndef SQLBOX_SQL_H #define SQLBOX_SQL_H #include "gwlib/gwlib.h" #include "gw/msg.h" #include "sqlbox_mssql.h" #include "sqlbox_mysql.h" #include "sqlbox_oracle.h" #include "sqlbox_pgsql.h" #include "sqlbox_sdb.h" #include "sqlbox_sqlite.h" #include "sqlbox_sqlite3.h" struct server_type { Octstr *type; void (*sql_enter) (Cfg *); void (*sql_leave) (); Msg *(*sql_fetch_msg) (); void (*sql_save_msg) (Msg *, Octstr *); int (*sql_fetch_msg_list) (List *, long); void (*sql_save_list) (List *, Octstr *, int); }; struct sqlbox_db_queries { char *create_insert_table; char *create_insert_sequence; char *create_insert_trigger; char *create_log_table; char *create_log_sequence; char *create_log_trigger; char *select_query; char *delete_query; char *insert_query; }; struct server_type *sqlbox_init_sql(Cfg *cfg); #ifndef sqlbox_sql_c extern #endif struct server_type *sql_type; #define gw_sql_fetch_msg sql_type->sql_fetch_msg #define gw_sql_fetch_msg_list sql_type->sql_fetch_msg_list #define gw_sql_save_list sql_type->sql_save_list #define gw_sql_save_msg(message, table) \ do { \ octstr_url_encode(message->sms.msgdata); \ octstr_url_encode(message->sms.udhdata); \ sql_type->sql_save_msg(message, table); \ } while (0) #define gw_sql_enter sql_type->sql_enter #define gw_sql_leave sql_type->sql_leave /* Macro to run the queries to create tables */ #define sqlbox_run_query(query, table) \ if (query != NULL) { \ sql = octstr_format(query, table, table, table); \ sql_update(pc, sql); \ octstr_destroy(sql); \ } #undef SQLBOX_TRACE #endif gateway-1.4.5/addons/sqlbox/gw/sqlbox_mysql.c0000644000175000017500000003657612712577027020015 0ustar toljtolj#include "gwlib/gwlib.h" #ifdef HAVE_MYSQL #include "gwlib/dbpool.h" #include #define sqlbox_mysql_c #include "sqlbox_mysql.h" #define sql_update mysql_update #define sql_select mysql_select #define MYSQL_ERR_NOSUCHFIELD 1054 static Octstr *sqlbox_logtable; static Octstr *sqlbox_insert_table; /* * Our connection pool to mysql. */ static DBPool *pool = NULL; static void mysql_update(const Octstr *sql) { int state; DBPoolConn *pc; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "MYSQL: Database pool got no connection! DB update failed!"); return; } state = mysql_query(pc->conn, octstr_get_cstr(sql)); if (state != 0) error(0, "MYSQL: %s", mysql_error(pc->conn)); if (mysql_errno(pc->conn) == MYSQL_ERR_NOSUCHFIELD) { error(0, "Try to recreate insert and log tables. The structure may have changed. See ChangeLog."); } dbpool_conn_produce(pc); } static MYSQL_RES* mysql_select(const Octstr *sql) { int state; MYSQL_RES *result = NULL; DBPoolConn *pc; #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(sql)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "MYSQL: Database pool got no connection! DB update failed!"); return NULL; } state = mysql_query(pc->conn, octstr_get_cstr(sql)); if (state != 0) { error(0, "MYSQL: %s", mysql_error(pc->conn)); if (mysql_errno(pc->conn) == MYSQL_ERR_NOSUCHFIELD) { error(0, "Try to recreate insert and log tables. The structure may have changed. See ChangeLog."); } } else { result = mysql_store_result(pc->conn); } dbpool_conn_produce(pc); return result; } void sqlbox_configure_mysql(Cfg* cfg) { CfgGroup *grp; Octstr *sql; if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: MySQL: group 'sqlbox' is not specified!"); sqlbox_logtable = cfg_get(grp, octstr_imm("sql-log-table")); if (sqlbox_logtable == NULL) { panic(0, "No 'sql-log-table' not configured."); } sqlbox_insert_table = cfg_get(grp, octstr_imm("sql-insert-table")); if (sqlbox_insert_table == NULL) { panic(0, "No 'sql-insert-table' not configured."); } /* create send_sms && sent_sms tables if they do not exist */ sql = octstr_format(SQLBOX_MYSQL_CREATE_LOG_TABLE, sqlbox_logtable); sql_update(sql); octstr_destroy(sql); sql = octstr_format(SQLBOX_MYSQL_CREATE_INSERT_TABLE, sqlbox_insert_table); sql_update(sql); octstr_destroy(sql); /* end table creation */ } #define octstr_null_create(x) ((x != NULL) ? octstr_create(x) : octstr_create("")) #define atol_null(x) ((x != NULL) ? atol(x) : -1) Msg *mysql_fetch_msg() { Msg *msg = NULL; Octstr *sql, *delet, *id; MYSQL_RES *res; MYSQL_ROW row; sql = octstr_format(SQLBOX_MYSQL_SELECT_QUERY, sqlbox_insert_table); res = mysql_select(sql); if (res == NULL) { debug("sqlbox", 0, "SQL statement failed: %s", octstr_get_cstr(sql)); } else { if (mysql_num_rows(res) >= 1) { row = mysql_fetch_row(res); id = octstr_null_create(row[0]); /* save fields in this row as msg struct */ msg = msg_create(sms); /* we abuse the foreign_id field in the message struct for our sql_id value */ msg->sms.foreign_id = octstr_null_create(row[0]); msg->sms.sender = octstr_null_create(row[2]); msg->sms.receiver = octstr_null_create(row[3]); msg->sms.udhdata = octstr_null_create(row[4]); msg->sms.msgdata = octstr_null_create(row[5]); msg->sms.time = atol_null(row[6]); msg->sms.smsc_id = octstr_null_create(row[7]); msg->sms.service = octstr_null_create(row[8]); msg->sms.account = octstr_null_create(row[9]); msg->sms.sms_type = atol_null(row[11]); msg->sms.mclass = atol_null(row[12]); msg->sms.mwi = atol_null(row[13]); msg->sms.coding = atol_null(row[14]); msg->sms.compress = atol_null(row[15]); msg->sms.validity = atol_null(row[16]); msg->sms.deferred = atol_null(row[17]); msg->sms.dlr_mask = atol_null(row[18]); msg->sms.dlr_url = octstr_null_create(row[19]); msg->sms.pid = atol_null(row[20]); msg->sms.alt_dcs = atol_null(row[21]); msg->sms.rpi = atol_null(row[22]); msg->sms.charset = octstr_null_create(row[23]); msg->sms.binfo = octstr_null_create(row[25]); msg->sms.meta_data = octstr_null_create(row[26]); msg->sms.priority = atol_null(row[27]); if (row[24] == NULL) { msg->sms.boxc_id= octstr_duplicate(sqlbox_id); } else { msg->sms.boxc_id= octstr_null_create(row[24]); } /* delete current row */ delet = octstr_format(SQLBOX_MYSQL_DELETE_QUERY, sqlbox_insert_table, id); #if defined(SQLBOX_TRACE) debug("SQLBOX", 0, "sql: %s", octstr_get_cstr(delet)); #endif mysql_update(delet); octstr_destroy(id); octstr_destroy(delet); } mysql_free_result(res); } octstr_destroy(sql); return msg; } int mysql_fetch_msg_list(List *qlist, long limit) { Msg *msg = NULL; Octstr *sql, *delet, *id; MYSQL_RES *res; MYSQL_ROW row; int ret = 0; sql = octstr_format(SQLBOX_MYSQL_SELECT_LIST_QUERY, sqlbox_insert_table, limit); res = mysql_select(sql); if (res == NULL) { debug("sqlbox", 0, "SQL statement failed: %s", octstr_get_cstr(sql)); } else { ret = mysql_num_rows(res); if (ret >= 1) { while (row = mysql_fetch_row(res)) { /* save fields in this row as msg struct */ msg = msg_create(sms); /* we abuse the foreign_id field in the message struct for our sql_id value */ msg->sms.foreign_id = octstr_null_create(row[0]); msg->sms.sender = octstr_null_create(row[2]); msg->sms.receiver = octstr_null_create(row[3]); msg->sms.udhdata = octstr_null_create(row[4]); msg->sms.msgdata = octstr_null_create(row[5]); msg->sms.time = atol_null(row[6]); msg->sms.smsc_id = octstr_null_create(row[7]); msg->sms.service = octstr_null_create(row[8]); msg->sms.account = octstr_null_create(row[9]); msg->sms.sms_type = atol_null(row[11]); msg->sms.mclass = atol_null(row[12]); msg->sms.mwi = atol_null(row[13]); msg->sms.coding = atol_null(row[14]); msg->sms.compress = atol_null(row[15]); msg->sms.validity = atol_null(row[16]); msg->sms.deferred = atol_null(row[17]); msg->sms.dlr_mask = atol_null(row[18]); msg->sms.dlr_url = octstr_null_create(row[19]); msg->sms.pid = atol_null(row[20]); msg->sms.alt_dcs = atol_null(row[21]); msg->sms.rpi = atol_null(row[22]); msg->sms.charset = octstr_null_create(row[23]); msg->sms.binfo = octstr_null_create(row[25]); msg->sms.meta_data = octstr_null_create(row[26]); msg->sms.priority = atol_null(row[27]); if (row[24] == NULL) { msg->sms.boxc_id= octstr_duplicate(sqlbox_id); } else { msg->sms.boxc_id= octstr_null_create(row[24]); } gwlist_produce(qlist, msg); } } mysql_free_result(res); } octstr_destroy(sql); return ret; } static Octstr *get_numeric_value_or_return_null(long int num) { if (num == -1) { return octstr_create("NULL"); } return octstr_format("%ld", num); } static Octstr *get_string_value_or_return_null(Octstr *str) { if (str == NULL) { return octstr_create("NULL"); } if (octstr_compare(str, octstr_imm("")) == 0) { return octstr_create("NULL"); } /* todo: create a new string instead of inline replacing */ octstr_replace(str, octstr_imm("\\"), octstr_imm("\\\\")); octstr_replace(str, octstr_imm("\'"), octstr_imm("\\\'")); return octstr_format("\'%S\'", str); } #define st_num(x) (stuffer[stuffcount++] = get_numeric_value_or_return_null(x)) #define st_str(x) (stuffer[stuffcount++] = get_string_value_or_return_null(x)) void mysql_save_msg(Msg *msg, Octstr *momt) { Octstr *sql; Octstr *stuffer[30]; int stuffcount = 0; sql = octstr_format(SQLBOX_MYSQL_INSERT_QUERY, sqlbox_logtable, st_str(momt), st_str(msg->sms.sender), st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time), st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type), st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress), st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url), st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset), st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data), st_num(msg->sms.priority), st_str(msg->sms.foreign_id)); sql_update(sql); while (stuffcount > 0) { octstr_destroy(stuffer[--stuffcount]); } octstr_destroy(sql); } /* save a list of messages and delete them from the insert table */ void mysql_save_list(List *qlist, Octstr *momt, int save_mt) { Octstr *sql, *values, *ids, *sep; Octstr *stuffer[30]; int stuffcount = 0, first = 1; Msg *msg; values = save_mt ? octstr_create("") : NULL; ids = octstr_create(""); sep = octstr_imm(""); while (gwlist_len(qlist) > 0 && (msg = gwlist_consume(qlist)) != NULL) { if (save_mt) { /* convert into urlencoded tekst first */ octstr_url_encode(msg->sms.msgdata); octstr_url_encode(msg->sms.udhdata); octstr_format_append(values, "%S (NULL, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S, %S)", sep, st_str(momt), st_str(msg->sms.sender), st_str(msg->sms.receiver), st_str(msg->sms.udhdata), st_str(msg->sms.msgdata), st_num(msg->sms.time), st_str(msg->sms.smsc_id), st_str(msg->sms.service), st_str(msg->sms.account), st_num(msg->sms.sms_type), st_num(msg->sms.mclass), st_num(msg->sms.mwi), st_num(msg->sms.coding), st_num(msg->sms.compress), st_num(msg->sms.validity), st_num(msg->sms.deferred), st_num(msg->sms.dlr_mask), st_str(msg->sms.dlr_url), st_num(msg->sms.pid), st_num(msg->sms.alt_dcs), st_num(msg->sms.rpi), st_str(msg->sms.charset), st_str(msg->sms.boxc_id), st_str(msg->sms.binfo), st_str(msg->sms.meta_data), st_num(msg->sms.priority), st_str(msg->sms.foreign_id)); } octstr_format_append(ids, "%S %S", sep, msg->sms.foreign_id); msg_destroy(msg); if (first) { first = 0; sep = octstr_imm(","); } while (stuffcount > 0) { octstr_destroy(stuffer[--stuffcount]); } } if (save_mt) { sql = octstr_format(SQLBOX_MYSQL_INSERT_LIST_QUERY, sqlbox_logtable, values); octstr_destroy(values); sql_update(sql); octstr_destroy(sql); } sql = octstr_format(SQLBOX_MYSQL_DELETE_LIST_QUERY, sqlbox_insert_table, ids); octstr_destroy(ids); sql_update(sql); octstr_destroy(sql); } void mysql_leave() { dbpool_destroy(pool); } struct server_type *sqlbox_init_mysql(Cfg* cfg) { CfgGroup *grp; List *grplist; Octstr *mysql_host, *mysql_user, *mysql_pass, *mysql_db, *mysql_id; Octstr *p = NULL; long pool_size, mysql_port; int have_port; DBConf *db_conf = NULL; struct server_type *res = NULL; /* * check for all mandatory directives that specify the field names * of the used MySQL table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("sqlbox")))) panic(0, "SQLBOX: MySQL: group 'sqlbox' is not specified!"); if (!(mysql_id = cfg_get(grp, octstr_imm("id")))) panic(0, "SQLBOX: MySQL: directive 'id' is not specified!"); /* * now grap the required information from the 'mysql-connection' group * with the mysql-id we just obtained * * we have to loop through all available MySQL connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("mysql-connection")); while (grplist && (grp = (CfgGroup *)gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, mysql_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "SQLBOX: MySQL: connection settings for id '%s' are not specified!", octstr_get_cstr(mysql_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(mysql_host = cfg_get(grp, octstr_imm("host")))) panic(0, "SQLBOX: MySQL: directive 'host' is not specified!"); if (!(mysql_user = cfg_get(grp, octstr_imm("username")))) panic(0, "SQLBOX: MySQL: directive 'username' is not specified!"); if (!(mysql_pass = cfg_get(grp, octstr_imm("password")))) panic(0, "SQLBOX: MySQL: directive 'password' is not specified!"); if (!(mysql_db = cfg_get(grp, octstr_imm("database")))) panic(0, "SQLBOX: MySQL: directive 'database' is not specified!"); have_port = (cfg_get_integer(&mysql_port, grp, octstr_imm("port")) != -1); /* * ok, ready to connect to MySQL */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->mysql = gw_malloc(sizeof(MySQLConf)); gw_assert(db_conf->mysql != NULL); db_conf->mysql->host = mysql_host; db_conf->mysql->username = mysql_user; db_conf->mysql->password = mysql_pass; db_conf->mysql->database = mysql_db; if (have_port) { db_conf->mysql->port = mysql_port; } else { db_conf->mysql->port = 3306; } pool = dbpool_create(DBPOOL_MYSQL, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"SQLBOX: MySQL: database pool has no connections!"); octstr_destroy(mysql_id); res = gw_malloc(sizeof(struct server_type)); gw_assert(res != NULL); res->type = octstr_create("MySQL"); res->sql_enter = sqlbox_configure_mysql; res->sql_leave = mysql_leave; res->sql_fetch_msg = mysql_fetch_msg; res->sql_save_msg = mysql_save_msg; res->sql_fetch_msg_list = mysql_fetch_msg_list; res->sql_save_list = mysql_save_list; return res; } #endif gateway-1.4.5/addons/sqlbox/configure.in0000644000175000017500000004732012327711710016764 0ustar toljtoljdnl /* ==================================================================== dnl * The Kannel Software License, Version 1.0 dnl * dnl * Copyright (c) 2001-2010 Kannel Group dnl * Copyright (c) 1998-2001 WapIT Ltd. dnl * All rights reserved. dnl * dnl * Redistribution and use in source and binary forms, with or without dnl * modification, are permitted provided that the following conditions dnl * are met: dnl * dnl * 1. Redistributions of source code must retain the above copyright dnl * notice, this list of conditions and the following disclaimer. dnl * dnl * 2. Redistributions in binary form must reproduce the above copyright dnl * notice, this list of conditions and the following disclaimer in dnl * the documentation and/or other materials provided with the dnl * distribution. dnl * dnl * 3. The end-user documentation included with the redistribution, dnl * if any, must include the following acknowledgment: dnl * "This product includes software developed by the dnl * Kannel Group (http://www.kannel.org/)." dnl * Alternately, this acknowledgment may appear in the software itself, dnl * if and wherever such third-party acknowledgments normally appear. dnl * dnl * 4. The names "Kannel" and "Kannel Group" must not be used to dnl * endorse or promote products derived from this software without dnl * prior written permission. For written permission, please dnl * contact org@kannel.org. dnl * dnl * 5. Products derived from this software may not be called "Kannel", dnl * nor may "Kannel" appear in their name, without prior written dnl * permission of the Kannel Group. dnl * dnl * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED dnl * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES dnl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE dnl * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS dnl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, dnl * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT dnl * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR dnl * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, dnl * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE dnl * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, dnl * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. dnl * ==================================================================== dnl * dnl * This software consists of voluntary contributions made by many dnl * individuals on behalf of the Kannel Group. For more information on dnl * the Kannel Group, please see . dnl * dnl * Portions of this software are based upon software originally written at dnl * WapIT Ltd., Helsinki, Finland for the Kannel project. dnl */ dnl SqlBox - Open Source Kannel Extension for store messages dnl dnl Rene Kluwen dnl dnl Stand alone module by Martin Conte dnl dnl Documentation and additional patches by dnl Alejandro Guerrieri dnl Stipe Tolj dnl dnl This program is free software, distributed under the terms of dnl the GNU General Public License, with a few exceptions granted (see LICENSE) dnl AC_PREREQ(2.5) dnl Initialization AC_INIT([sqlbox],[cvs],[devel@kannel.org]) AC_CONFIG_SRCDIR([gw/sqlbox.c]) AC_CONFIG_AUX_DIR(autotools) AC_SET_TERMINAL_SEQUENCES() AC_CONFIG_NICE(config.nice) dnl Check version number. AC_MSG_CHECKING([svn checkout revision]) AC_SVN_REVISION(SVN_REVISION) AC_MSG_RESULT([$SVN_REVISION]) VERSION="svn-r$SVN_REVISION" SB_NAME="SqlBox" dnl Defines AC_DEFINE_UNQUOTED(VERSION, "$VERSION") AC_SUBST(VERSION) AC_CONFIG_SECTION([Configuring for Kannel sqlbox version $VERSION]) AM_INIT_AUTOMAKE([$SB_NAME], [$VERSION]) AC_CONFIG_HEADERS([sb-config.h]) AM_MAINTAINER_MODE AC_CANONICAL_HOST dnl Checks for programs. dnl AC_PROG_CC AC_PROG_LIBTOOL dnl add mmlib to the include path INCLUDES='-I$(top_srcdir)/gw -I$(top_builddir)/gw' AC_SUBST([INCLUDES]) dnl Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT dnl ommiting what kannel is already checking dnl AC_CHECK_HEADERS(sys/ioctl.h sys/time.h sys/types.h unistd.h sys/poll.h) dnl AC_CHECK_HEADERS(pthread.h getopt.h syslog.h iconv.h zlib.h execinfo.h stdlib.h) dnl AC_CHECK_HEADERS([sys/socket.h sys/sockio.h netinet/in.h]) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_STRUCT_TM AC_C_VOLATILE dnl Checks for library functions. AC_FUNC_CLOSEDIR_VOID AC_FUNC_ERROR_AT_LINE AC_FUNC_MALLOC AC_FUNC_MEMCMP dnl AC_TYPE_SIGNAL dnl AC_FUNC_STAT dnl AC_CHECK_FUNCS(gettimeofday select socket strdup getopt_long localtime_r gmtime_r backtrace srandom) dnl Flags for determined platform EXE_EXT="" case "$host" in *-sun-solaris*) CFLAGS="$CFLAGS -DSunOS=1" ;; *-cygwin*) EXE_EXT=".exe" LDFLAGS="$LDFLAGS -Wl,--enable-auto-import" ;; *apple-darwin*) # MacOS X # Lets try to find the newest installed SDK for compilation # so we know how to link against it. # If we find a SDK, we use that rather then the standard /usr # location libs and includes. found=0 SDK="" for loc in "MacOSX10.6.sdk" "MacOSX10.5.sdk" "MacOSX10.4u.sdk" "MacOSX10.4.0.sdk" "MacOSX10.3.9.sdk" \ "MacOSX10.3.0.sdk" "MacOSX10.2.8.sdk" "MacOSX10.1.5.sdk" do if test "$found" = "0" ; then if test -d "/Developer/SDKs/${E}" ; then found="1" SDK="${loc}" fi fi done if test "$SDK" != "" ; then CFLAGS="$CFLAGS -DDARWIN=1 -L/Developer/SDKs/${SDK}/usr/lib -I/Developer/SDKs/${SDK}/usr/include" else CFLAGS="$CFLAGS -DDARWIN=1" fi LIBTOOL="libtool -static -o" ;; *-linux-*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE" LDFLAGS="$LDFLAGS -rdynamic" ;; *-*-openbsd* | *-*-freebsd*) CFLAGS="$CFLAGS -pthread" AC_CHECK_LIB(pthread, pthread_exit, [LIBS="$LIBS -lpthread"; pthread="yes"], [AC_CHECK_LIB(c_r, pthread_exit, [LIBS="$LIBS -lc_r"; pthread="yes"])] ) ;; *-interix3*) INSTALL="./install-sh" ;; esac AC_ARG_WITH(cflags, [ --with-cflags=FLAGS use FLAGS for CFLAGS], CFLAGS="$CFLAGS $withval") AC_ARG_WITH(libs, [ --with-libs=FLAGS use FLAGS for extra libraries], LIBS="$LIBS $withval") dnl implement SSL stuff. dnl Implement the --with-ssl option. AC_CONFIG_SECTION([Configuring OpenSSL support]) AC_ARG_WITH(ssl, [ --with-ssl[=DIR] where to look for OpenSSL libs and header files DIR points to the installation [/usr/local/ssl]], [ if test -d "$withval"; then ssllib="$withval/lib"; sslinc="$withval/include" else AC_MSG_ERROR(Unable to find OpenSSL libs and/or directories at $withval) fi ]) dnl Implement --enable-ssl option. AC_MSG_CHECKING([whether to compile with SSL support]) AC_ARG_ENABLE(ssl, [ --enable-ssl enable SSL client and server support [enabled]], [ if test "$enableval" = no ; then AC_MSG_RESULT(disabled) ssl=no else ssl=yes fi ],[ ssl=yes ]) if test "$ssl" = "yes" ; then dnl test only if --with-ssl has not been used if test "x$ssllib" = "x" && test "x$sslinc" = "x"; then for loc in /usr/lib /usr/local/ssl/lib /usr/local/openssl/lib; do if test -f "$loc/libssl.a"; then ssllib="$loc" fi done for loc in /usr/include/ssl /usr/include/openssl /usr/local/ssl/include \ /usr/local/openssl/include; do if test -d "$loc"; then sslinc="$loc" fi done fi AC_MSG_RESULT(trying $ssllib $sslinc) fi dnl Implement the SSL library checking routine. dnl This will define HAVE_LIBSSL in config.h if test "x$ssllib" != "x" && test "x$sslinc" != "x"; then CFLAGS="$CFLAGS -I$sslinc" LIBS="$LIBS -L$ssllib" AC_PATH_PROG(OPENSSL, openssl, no) if test "$OPENSSL" = "yes"; then AC_MSG_CHECKING([openssl version]) openssl_version=`$OPENSSL version | awk '{print $2}'` AC_MSG_RESULT([$openssl_version]) fi AC_CHECK_LIB(crypto, CRYPTO_lock, [ LIBS="$LIBS -lcrypto" AC_CHECK_LIB(ssl, SSL_library_init, [ AC_CHECK_LIB(ssl, SSL_connect) AC_CHECK_HEADERS(openssl/x509.h openssl/rsa.h openssl/crypto.h \ openssl/pem.h openssl/ssl.h openssl/err.h) AC_MSG_CHECKING(whether the OpenSSL library is multithread-enabled) AC_TRY_RUN([ #define OPENSSL_THREAD_DEFINES #include int main(void) { #if defined(THREADS) exit(0); #elif defined(OPENSSL_THREADS) exit(0); #else exit(1); #endif } ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LIBSSL) LIBS="$LIBS -lssl" AC_MSG_CHECKING([whether to compile with SSL support]) AC_MSG_RESULT(yes) ], [ AC_ARG_ENABLE(ssl-thread-test, [ --disable-ssl-thread-test disable the multithread test for the OpenSSL library this will force to continue even if the test fails], [ if test "$enableval" = no ; then AC_MSG_RESULT([no, continue forced]) fi ], [ AC_MSG_RESULT(no) AC_MSG_ERROR(Either get a multithread-enabled SSL or configure with --disable-ssl) ]) ], echo "Cross-compiling; make sure your SSL library is multithread-enabled" ) ]) ]) fi dnl DocBook stuff AC_CONFIG_SECTION([Configuring DocBook support]) AC_CHECK_PROG(OLDJADE, jade, jade, no) if test "$OLDJADE" = "no" ; then AC_CHECK_PROG(JADE, openjade, openjade, no) else JADE=$OLDJADE fi AC_CHECK_PROG(JADETEX, jadetex, jadetex, no) AC_CHECK_PROG(PDFJADETEX, pdfjadetex, pdfjadetex, no) AC_CHECK_PROG(DVIPS, dvips, dvips, no) AC_CHECK_PROG(FIG2DEV, fig2dev, fig2dev, no) AC_CHECK_PROG(CONVERT, convert, convert, no) AC_SUBST(HTML_DSL) found="" for loc in /usr /usr/local /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/html/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/html/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/html/docbook.dsl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,HTML_DSL=$file; found=1) fi done fi done AC_SUBST(TEX_DSL) found="" for loc in /usr /usr/local /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/print/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/print/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/print/docbook.dsl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,TEX_DSL=$file; found=1) fi done fi done AC_SUBST(XML_DCL) found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/dtds/decls/xml.dcl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/dtds/decls/xml.dcl \ ${loc}/share/dsssl/docbook-dsssl/dtds/decls/xml.dcl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,XML_DCL=$file; found=1) fi done fi done dnl Implement --enable-docs option. AC_SUBST(DOCSTARGET) AC_ARG_ENABLE(docs, [ --enable-docs enable building of documentation @<:@enabled@:>@], [ if test "$enableval" = "yes" then DOCSTARGET="docs" else DOCSTARGET="no-docs" fi ]) if test "x$HTML_DSL" = "x" -o "x$TEX_DSL" = "x" \ || test "$JADE" = "no" \ || test "$JADETEX" = "no" \ || test "$PDFJADETEX" = "no" \ || test "$DVIPS" = "no" \ || test "$FIG2DEV" = "no" \ || test "$CONVERT" = "no" \ || test "$DOCSTARGET" = "no-docs" then DOCSTARGET="no-docs" else DOCSTARGET="docs" fi case "$DOCSTARGET" in no-docs) AC_MSG_RESULT(Not building documentation.) ;; docs) AC_MSG_RESULT(Documentation will be built as well.) ;; esac dnl Implement --enable-drafts option. AC_SUBST(DOCDRAFTS) DOCDRAFTS="IGNORE" AC_ARG_ENABLE(drafts, [ --enable-drafts enable building of documentation drafts @<:@disabled@:>@], [ if test "$enableval" = "yes" then DOCDRAFTS="INCLUDE" else DOCDRAFTS="IGNORE" fi ]) if test "x$DOCSTARGET" = "xdocs" then case "$DOCDRAFTS" in INCLUDE) AC_MSG_RESULT(Documentation will include drafts.) ;; esac fi AC_CONFIG_SECTION([Configuring Kannel and DB dependancies]) dnl Checking for Ct-lib support AC_MSG_CHECKING(for Ct-Lib support) AC_ARG_WITH(ctlib, [ --with-ctlib[=DIR] Include Ct-Lib support. DIR is the Ct-Lib install directory, defaults to /opt/sybase.], [ if test "$withval" = "yes"; then withval=/opt/sybase fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then CTLIB_INCDIR=$withval/include CTLIB_LIBDIR=$withval/lib else AC_MSG_RESULT(no) AC_MSG_ERROR(Invalid Ct-Lib directory - unable to find ctpublic.h) fi CTLIB_LFLAGS="-L$CTLIB_LIBDIR -lct -lcs -lsybtcl -lcomn -lintl" CTLIB_INCLUDE="-I$CTLIB_INCDIR" AC_DEFINE(HAVE_CTLIB, 1, [Defined to 1]) AC_MSG_RESULT(yes) have_db=yes dnl ctlib requires -ldl sometime AC_CHECK_FUNC(dlopen, , AC_CHECK_LIB(dl, dlopen, CTLIB_LFLAGS="$CTLIB_LFLAGS -ldl")) fi if test "x$DBTYPE" = "x" ; then DBTYPE="ctlib" else DBTYPE="$DBTYPE-ctlib" fi ],[ AC_MSG_RESULT(no) ]) AC_SUBST(CTLIB_LFLAGS) AC_SUBST(CTLIB_INCLUDE) dnl Checking for FreeTDS ct-lib support AC_MSG_CHECKING(for FreeTDS Ct-Lib support) AC_ARG_WITH(mssql, [ --with-mssql[=DIR] Include FreeTDS Ct-Lib support. DIR is the FreeTDS install directory, defaults to /usr/local.], [ if test "$withval" = "yes"; then withval=/usr/local fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then CTLIB_INCDIR=$withval/include CTLIB_LIBDIR=$withval/lib else AC_MSG_RESULT(no) AC_MSG_ERROR(Invalid FreeTDS directory - unable to find ctpublic.h) fi CTLIB_LFLAGS="-L$CTLIB_LIBDIR -lct" CTLIB_INCLUDE="-I$CTLIB_INCDIR" AC_DEFINE(HAVE_CTLIB, 1, [Defined to 1]) AC_MSG_RESULT(yes) have_db=yes AC_CHECK_FUNC(dlopen, , AC_CHECK_LIB(dl, dlopen, CTLIB_LFLAGS="$CTLIB_LFLAGS -ldl")) fi if test "x$DBTYPE" = "x" ; then DBTYPE="freetds" else DBTYPE="$DBTYPE-freetds" fi ],[ AC_MSG_RESULT(no) ]) AC_SUBST(CTLIB_LFLAGS) AC_SUBST(CTLIB_INCLUDE) dnl Need to check for kannel dnl Implement the --with-kannel-dir option AC_ARG_WITH(kannel-dir, [ --with-kannel-dir=DIR where to look for Kannel Gateway libs and header files DIR points to the installation [/usr/local] ] , [ gwloc="" if test -d "$withval" ; then gwloc="$withval" fi ]) AC_PATH_PROG(GW_CONFIG, gw-config, no, [$gwloc/bin:$gwloc:../gateway/gw/:$PATH]) dnl check for Kannel gw-config if test "$GW_CONFIG" = "no"; then found="" for loc in $pgsqlloc /usr /usr/local ; do if test "x$found" = "x" ; then AC_MSG_CHECKING([for Kannel include files in]) AC_MSG_RESULT($loc) AC_CHECK_FILE("$loc/include/kannel/gw-config.h", [CFLAGS="$CFLAGS -I$loc/include/kannel -I$loc/include/kannel"; LDFLAGS="$LDFLAGS -L$loc/lib/kannel -lwap -lgwlib"; found=1 ]) fi done; if test "x$found" != "x1" ; then AC_MSG_ERROR([Unable to find gw-config.h, please provide a --with-kannel-dir= location]) fi else dnl gw_config found AC_MSG_CHECKING([Kannel version]) gw_version=`$GW_CONFIG --version` AC_MSG_RESULT([$gw_version]) AC_MSG_CHECKING([Kannel libs]) if ! $GW_CONFIG --libs &>/dev/null ; then LIBS="$LIBS `$GW_CONFIG --libs`" gw_libdir=`$GW_CONFIG --libs` AC_MSG_RESULT([$gw_libdir]) fi AC_MSG_CHECKING([Kannel includes]) if ! $GW_CONFIG --cflags &>/dev/null ; then CFLAGS="$CFLAGS `$GW_CONFIG --cflags`" gw_incdir=`$GW_CONFIG --cflags` AC_MSG_RESULT([$gw_incdir]) fi fi AC_CHECK_LIB([gwlib], [cfg_create], [], [AC_MSG_ERROR([Kannel gwlib is required!])], [$LDFLAGS] ) AC_MSG_CHECKING(for Kannel's DB support) AC_TRY_RUN([#include "gw-config.h" int main( #if defined(HAVE_SQLITE3) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "sqlite3", [RPM Suffix]) AC_SUBST(rpm_requires, "sqlite3-devel >= 1.8", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_SQLITE) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "sqlite", [RPM Suffix]) AC_SUBST(rpm_requires, "sqlite2-devel >= 2.7", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_PGSQL) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "pgsql", [RPM Suffix]) AC_SUBST(rpm_requires, "postgresql-devel >= 7.2", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_ORACLE) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "oracle", [RPM Suffix]) AC_SUBST(rpm_requires, "oracle-instantclient-devel >= 8", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_MYSQL) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "mysql", [RPM Suffix]) AC_SUBST(rpm_requires, "mysql-devel >= 3.23", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_SDB) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "sdb", [RPM Suffix]) AC_SUBST(rpm_requires, "libsdb-devel >= 0.5", [RPM Requires]) ]) AC_MSG_RESULT([ok]) dnl Final Output AC_CONFIG_SECTION([Generating output files]) AC_CONFIG_FILES([Makefile gw/Makefile rpm/sqlbox.spec]) AC_OUTPUT dnl LICENSE notice AC_CONFIG_SECTION([License information]) cat < | +--------------------------------------------------------------------+ Thank you for using Kannel. X gateway-1.4.5/addons/sqlbox/acinclude.m40000644000175000017500000001274111464060103016635 0ustar toljtoljdnl acinclude.m4 -- local include for for autoconf dnl dnl This file is processed while autoconf generates configure. dnl This file is part of the Kannel WAP and SMS gateway project. dnl Check if installed version string is equal or higher then required. dnl This is used in a couple of tests to ensure we have a valid version dnl of a software package installed. The basic idea is to split the dnl version sequences into three parts and then test against eachother dnl in a whole complex if statement. dnl dnl AC_CHECK_VERSION(installed, required, [do-if-success], [do-if-tail]) dnl dnl Written by Stipe Tolj AC_DEFUN([AC_CHECK_VERSION], [ dnl split installed version string ac_inst_ver_maj=`echo $1 | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_inst_ver_mid=`echo $1 | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_inst_ver_min=`echo $1 | sed -e 's/^.*\..*\.\(.*\)$/\1/'` dnl split required version string ac_req_ver_maj=`echo $2 | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_req_ver_mid=`echo $2 | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_req_ver_min=`echo $2 | sed -e 's/^.*\..*\.\(.*\)$/\1/'` dnl now perform the test if test "$ac_inst_ver_maj" -lt "$ac_req_ver_maj" || \ ( test "$ac_inst_ver_maj" -eq "$ac_req_ver_maj" && \ test "$ac_inst_ver_mid" -lt "$ac_req_ver_mid" ) || \ ( test "$ac_inst_ver_mid" -eq "$ac_req_ver_mid" && \ test "$ac_inst_ver_min" -lt "$ac_req_ver_min" ) then ac_ver_fail=yes else ac_ver_fail=no fi dnl now see if we have to do something ifelse([$3],,, [if test $ac_ver_fail = no; then $3 fi]) ifelse([$4],,, [if test $ac_ver_fail = yes; then $4 fi]) ]) dnl Some optional terminal sequences for configure dnl Taken from the mod_ssl package by Ralf S. Engelschall. AC_DEFUN([AC_SET_TERMINAL_SEQUENCES], [ case $TERM in xterm|xterm*|vt220|vt220*|cygwin) T_MD=`echo dummy | awk '{ printf("%c%c%c%c", 27, 91, 49, 109); }'` T_ME=`echo dummy | awk '{ printf("%c%c%c", 27, 91, 109); }'` ;; vt100|vt100*) T_MD=`echo dummy | awk '{ printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }'` T_ME=`echo dummy | awk '{ printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }'` ;; default) T_MD='' T_ME='' ;; esac ]) dnl Display configure section name in bold white letters dnl if available on the terminal AC_DEFUN([AC_CONFIG_SECTION], [ nl=' ' echo "${nl}${T_MD}$1 ...${T_ME}" ]) dnl Check which SVN revision is and apply dnl the value to the given variable AC_DEFUN([AC_SVN_REVISION], [ if test -d ".svn" then revision=`svnversion .` test -z "$revision" && revision="unknown" $1="$revision" fi ]) dnl Available from the GNU Autoconf Macro Archive at: dnl http://www.gnu.org/software/ac-archive/htmldoc/ac_caolan_func_which_gethostbyname_r.html dnl Modified by Alexander Malysh for Kannel Project. AC_DEFUN([AC_FUNC_WHICH_GETHOSTBYNAME_R], [AC_CACHE_CHECK(for which type of gethostbyname_r, ac_cv_func_which_gethostname_r, [ AC_TRY_COMPILE([ #include ], [ char *name; struct hostent *he; struct hostent_data data; (void) gethostbyname_r(name, he, &data); ], ac_cv_func_which_gethostname_r=3, [ AC_TRY_COMPILE([ #include ], [ char *name; struct hostent *he, *res; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop); ], ac_cv_func_which_gethostname_r=6, [ AC_TRY_COMPILE([ #include ], [ char *name; struct hostent *he; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &h_errnop); ], ac_cv_func_which_gethostname_r=5 , ac_cv_func_which_gethostname_r=0)] )] )]) if test $ac_cv_func_which_gethostname_r -eq 6; then AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_6) elif test $ac_cv_func_which_gethostname_r -eq 5; then AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_5) elif test $ac_cv_func_which_gethostname_r -eq 3; then AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_3) elif test $ac_cv_func_which_gethostname_r -eq 0; then ac_cv_func_which_gethostname_r = no fi ]) dnl Creates a config.nice shell script that contains all given configure dnl options to the orginal configure call. Can be used to add further options dnl in additional re-configure calls. This is perfect while handling with a dnl large number of configure option switches. dnl This macro is taken from PHP5 aclocal.m4, Stipe Tolj. AC_DEFUN([AC_CONFIG_NICE], [ test -f $1 && mv $1 $1.old rm -f $1.old cat >$1<> $1 fi done for arg in [$]0 "[$]@"; do echo "'[$]arg' \\" >> $1 done echo '"[$]@"' >> $1 chmod +x $1 ]) AC_DEFUN([AC_CVS_DATE], [ cvs_date=`grep ChangeLog CVS/Entries | cut -f4 -d/` day=`grep ChangeLog CVS/Entries | cut -f4 -d/ | cut -c9-10 | tr " " "0"` month=`echo $cvs_date | cut -f2 -d' '` case $month in "Jan") month="01" ;; "Feb") month="02" ;; "Mar") month="03" ;; "Apr") month="04" ;; "May") month="05" ;; "Jun") month="06" ;; "Jul") month="07" ;; "Aug") month="08" ;; "Sep") month="09" ;; "Oct") month="10" ;; "Nov") month="11" ;; "Dec") month="12" ;; esac year=`echo $cvs_date | cut -f5 -d' '` $1="$year$month$day" ]) gateway-1.4.5/addons/sqlbox/INSTALL0000644000175000017500000001754111204545563015512 0ustar toljtoljBasic Installation ================== These are generic installation instructions. For platform specific instructions please see the files in the doc/platforms directory. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). 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 diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./bootstrap` to create the configuration scripts. You need to have autoconf installed to do this. 2. Type `./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. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 3. Type `make' to compile the package. 4. Optionally, type `make check' to run any self-tests that come with the package. 5. Type `make install' to install the programs and any data files and documentation. 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 also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== 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 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 `..'. If you have to use a `make' that does not supports 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. 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=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' 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. 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 `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 `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually 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. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM 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 host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. 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'. `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. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. gateway-1.4.5/addons/sqlbox/ChangeLog0000644000175000017500000001511212620332733016217 0ustar toljtolj2015-11-10 Rnne Kluwen - Initializing mysql port to 3306 if not set in config. Thanks to Vyronas Tsingaras for the patch. 2014-04-29 Stipe Tolj * doc/userguide.xml: move from DocBook V3.1 to V4.2 and fix various XML tag errors. No content change. * gw/Makefile.in, Makefile.in: automake generated files. * Makefile.am: add $(XML_DCL) reference to the xml.dcl file. * configure[.in]: we need the xml.dcl to be added to the jade execution to have a clean XML tag declaration, since we are in SGML mode here. 2013-08-18 Rene Kluwen Fixed a semantical error as where dlr's coming from smsbox were not saved in the log-table, even when save-dlr is true. 2013-08-11 Rene Kluwen Implemented configuration directives: limit-per-cycle (thanks to Alejandro Guerrieri for the original patch), save-dlr, save-mo, save-mt. Speed improvements for messages sent via the insert-table should be significant because we process batches of records both when selecting and inserting as well as deleting. Thanks to Rinor Hoxha for reviewing the patch. Besides, this patch allows for saving of the foreign id field in the sql log table (all database engines). This is backward incompatible. To continue a running installation perform: alter table [log-table|insert-table] add column (foreign_id VARCHAR(255) NULL); 2011-05-08 Rene Kluwen * gw/sqlbox.c fixed memory leak sending messages through the send_sms table 2011-03-09 Alex Guerrieri * gw/sqlbox_[mssql|mysql|oracle|pgsql|sdb|sqlite|sqlite3].h: Fixed segmentation fault when running on 64-bit environments. Thanks Andreas Fink for identifying the reason behind the problem. 2010-11-11 Alex Guerrieri * COMPATIBILITY BREAKER: Extended Stipe's patch to url-encode the udhdata field as well, making it possible to send wap-push and other binary messages from sqlbox. 2010-11-11 Alex Guerrieri * COMPATIBILITY BREAKER: Modified the format in which the msgdata field was stored on the database to be url-encoded. This avoids corrupting the data when saving it. Thanks Stipe Tolj for this patch. 2010-11-11 Alex Guerrieri * Fixes PostgreSQL code to properly evaluate null columns and avoid corrupting numeric fields on messages. 2010-11-02 Stipe Tolj * acinclude.m4: use the gateway version to have the terminal sequences and various other m4 functions available. * configure[.in]: make the output looks like the gateway version, with cleaner sections. Fixed cygwin platform builds. 2010-10-07 Stipe Tolj * autotools/*, aclocal.m4, configure, Makefile.in: add autotool build by bootstrap run for distribution. 2010-10-07 Stipe Tolj * gw/sqlbox_[pgsql|sqlite3].c: more compiler warning fixes. 2010-10-06 Stipe Tolj * gw/sqlbox.c, gw/sqlbox_[pgsql|sqlite3].c: fixed various compiler warnings. 2010-09-11 Alex Guerrieri * Fixed bug: Not all sms messages were acked properly before, leaving messages in the message store. Thanks Rene Kluwen for this patch. 2010-06-16 - Rene Kluwen * Fixed bug that sqlbox didn't disconnect from bearerbox when one of the attached smsboxes would disconnect. 2010-08-02 - Alejandro Guerrieri * Fixes bug that prevented single quotes to be used on message text and other fields. Thanks Rene Kluwen for this patch. 2009-12-28 - Alejandro Guerrieri * Added support for meta-data on all DB engines * Added support for automake 1.11 2009-05-19 - Alejandro Guerrieri * Added support for MS-SQL and Sybase * Added rpm target * Fixed tab->spaces across all code 2008-11-21 - Alejandro Guerrieri * Completed documentation on missing DB modules. * Added RPM support. Now it's possible to build RPM's natively by running "make rpm" instead of "make". * The module detects the DB engine compiled on Kannel and renames the RPM accordingly. 2008-11-18 Alex Guerrieri * REVISION 0.7.1 [CVS Tag: rev-0-7-1] * Added support for the LibSDB database abstraction library. DB support is now similar to Kannel's. * Extensive code reorganization to move the queries into the header files and allow reusing from the libsdb module. * Added examples for database connections on sample conf file. 2008-11-12 Alejandro Guerrieri * REVISION 0.7.0 [CVS Tag: rev-0-7-0] * Added support for Oracle, SQLite2 and SQLite 3. * Binary now install under sbin instead of bin, just like all the other Kannel "boxes". 2008-11-03 Alex Guerrieri * REVISION 0.6.0 [CVS Tag: rev-0-6-0] * Added documentation into the build process. * Unified CVS and Standalone versions into CVS. 2006-11-06 * Unicode support. Thanks to Cavit Dolgun 2006-06-20 * Postgres SQL driver fixed after a long period of being broken. Many thanks and credits go to Huberto Figuera 2006-06-14 * make patch failure fixed by Martin Conte 2006-05-30 * Applied patch of Martin for the bug: SQLbox is not reading smsbox-port. It is hardcoded to 13005. * Applied patch of Martin : Delivery reports are now stored as 'DLR' in the MOMT database field. This makes it easier to filter them out if you are only interested in MO messages while reading the sent_sms table. * Bug fixed by Rene Kluwen : sqlbox now reads the port value from the mysql-connection group. 2005-11-01 * Applied patch of Thomas Gottgens: The fields udhdata and msgdata are now created as blob and text fields. * Also some fields of Kannel.conf are renamed to match CVS HEAD revision of the gateway module. * mysql-username is now "username" * mysql-password is now "password" * mysql-host is now "host" 2005-09-29 * First repository release of sqlbox. gateway-1.4.5/addons/sqlbox/rpm/0000755000175000017500000000000013312227715015245 5ustar toljtoljgateway-1.4.5/addons/sqlbox/rpm/sqlbox.spec.in0000644000175000017500000000346211111426361020034 0ustar toljtolj%define version @PACKAGE_VERSION@ %define release @rpm_suffix@_%(echo @VERSION@ | cut -d- -f2) Summary: DB-Based Kannel Box for message queueing. Name: @PACKAGE_NAME@ Version: %{version} Release: %{release} License: Kannel Group: System Environment/Daemons URL: http://www.kannel.org/~aguerrieri/ Source0: sqlbox-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: bison, byacc, flex BuildRequires: kannel-devel, openssl-devel, zlib-devel BuildRequires: @rpm_requires@ %description Sqlbox is a special Kannel box that sits between bearerbox and smsbox and uses a database queue to store and forward messages. Messages are queued on a configurable table (defaults to send_sms) and moved to another table (defaults to sent_sms) afterwards. You can also manually insert messages into the send_sms table and they will be sent and moved to the sent_sms table as well. This allows for fast and easy injection of large amounts of messages into Kannel. %prep rm -rf %{buildroot} %setup -q %build %configure %{__make} %install %{__rm} -rf %{buildroot} %makeinstall %{__mkdir_p} %{buildroot}%{_sbindir} %{__mkdir_p} %{buildroot}%{_var}/log/kannel/ %{__mkdir_p} %{buildroot}%{_var}/spool/kannel/ %{__install} -D -m 0640 example/sqlbox.conf.example %{buildroot}%{_sysconfdir}/kannel/sqlbox.conf strip %{buildroot}%{_sbindir}/sqlbox %clean %{__rm} -rf %{buildroot} #%pre #%post #%preun #%postun %files %defattr(-, root, root, 0755) %doc AUTHORS COPYING ChangeLog NEWS README UPGRADE %attr(0640, kannel, kannel) %config(noreplace) %{_sysconfdir}/kannel/sqlbox.conf %{_sbindir}/* %attr(0750, kannel, kannel) %dir %{_var}/log/kannel/ %attr(0750, kannel, kannel) %dir %{_sysconfdir}/kannel/ %changelog * Wed Nov 19 2008 Alejandro Guerrieri - First RPM version for Sqlbox gateway-1.4.5/addons/opensmppbox/0000755000175000017500000000000013312227716015512 5ustar toljtoljgateway-1.4.5/addons/opensmppbox/COPYING0000644000175000017500000000020311453122245016533 0ustar toljtoljSee Kannel LICENSE file for details about the license agreement for using, modifying, copying or deriving work from this software. gateway-1.4.5/addons/opensmppbox/bootstrap0000755000175000017500000000347511405507746017473 0ustar toljtolj#! /bin/sh set -x set -e # Check for automake amvers="no" if automake-1.11 --version >/dev/null 2>&1; then amvers="-1.11" elif automake-1.10 --version >/dev/null 2>&1; then amvers="-1.10" elif automake-1.9 --version >/dev/null 2>&1; then amvers="-1.9" elif automake-1.8 --version >/dev/null 2>&1; then amvers="-1.8" elif automake-1.7 --version >/dev/null 2>&1; then amvers="-1.7" elif automake-1.6 --version >/dev/null 2>&1; then amvers="-1.6" elif automake-1.5 --version >/dev/null 2>&1; then amvers="-1.5" elif automake --version > /dev/null 2>&1; then amvers="`automake --version | sed -e '1s/[^0-9]*//' -e q`" if expr "$amvers" "<" "1.5" > /dev/null 2>&1; then amvers="no" else amvers="" fi fi if test "$amvers" = "no"; then set +x echo "$0: you need automake version 1.5 or later" exit 1 fi # Check for libtool libtoolize="no" if glibtoolize --version >/dev/null 2>&1; then libtoolize="glibtoolize" elif libtoolize --version >/dev/null 2>&1; then libtoolize="libtoolize" fi if test "$libtoolize" = "no"; then set +x echo "$0: you need libtool" exit 1 fi # Remove old cruft set +x; for x in aclocal.m4 configure config.guess config.log config.sub config.cache config.h.in config.h compile libtool.m4 ltoptions.m4 ltsugar.m4 ltversion.m4 ltmain.sh libtool ltconfig missing mkinstalldirs depcomp install-sh; do rm -f $x autotools/$x; done; rm -Rf autom4te.cache; set -x if test ! -d autotools; then mkdir autotools; fi # Bootstrap package ${libtoolize} --copy --force if test -f "ltmain.sh"; then echo "$0: working around a minor libtool issue" mv ltmain.sh autotools/ fi aclocal${amvers} -I autotools autoconf autoheader #add --include-deps if you want to bootstrap with any other compiler than gcc #automake${amvers} --add-missing --copy --include-deps automake${amvers} --add-missing --copy gateway-1.4.5/addons/opensmppbox/AUTHORS0000644000175000017500000000015111405507746016564 0ustar toljtoljRene Kluwen Developers wanted to maintain package and documentation. gateway-1.4.5/addons/opensmppbox/autotools/0000755000175000017500000000000013312227716017543 5ustar toljtoljgateway-1.4.5/addons/opensmppbox/autotools/ltmain.sh0000644000175000017500000060342611563321320021366 0ustar toljtolj# ltmain.sh - Provide generalized library-building support services. # NOTE: Changing this file will not affect anything until you rerun configure. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005 # Free Software Foundation, Inc. # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. basename="s,^.*/,,g" # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" # The name of this program: progname=`echo "$progpath" | $SED $basename` modename="$progname" # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 PROGRAM=ltmain.sh PACKAGE=libtool VERSION=1.5.22 TIMESTAMP=" (1.1220.2.365 2005/12/18 22:14:06)" # Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi # Check that we have a working $echo. if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then # Yippee, $echo works! : else # Restart under the correct shell, and then maybe $echo will work. exec $SHELL "$progpath" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat <&2 $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit $EXIT_FAILURE fi # Global variables. mode=$default_mode nonopt= prev= prevopt= run= show="$echo" show_help= execute_dlfiles= duplicate_deps=no preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 ##################################### # Shell function definitions: # This seems to be the best place for them # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $mkdir "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || { $echo "cannot create temporary directory \`$my_tmpdir'" 1>&2 exit $EXIT_FAILURE } fi $echo "X$my_tmpdir" | $Xsed } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. func_win32_libid () { win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \ $EGREP -e 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then win32_nmres=`eval $NM -f posix -A $1 | \ $SED -n -e '1,100{/ I /{s,.*,import,;p;q;};}'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $echo $win32_libid_type } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac CC_quoted="$CC_quoted $arg" done case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac CC_quoted="$CC_quoted $arg" done case "$@ " in " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$echo $CC_quoted` "* | "`$echo $CC_quoted` "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then $echo "$modename: unable to infer tagged configuration" $echo "$modename: specify a tag with \`--tag'" 1>&2 exit $EXIT_FAILURE # else # $echo "$modename: using $tagname tagged configuration" fi ;; esac fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" $show "(cd $f_ex_an_ar_dir && $AR x $f_ex_an_ar_oldlib)" $run eval "(cd \$f_ex_an_ar_dir && $AR x \$f_ex_an_ar_oldlib)" || exit $? if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else $echo "$modename: ERROR: object name conflicts: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" 1>&2 exit $EXIT_FAILURE fi } # func_extract_archives gentop oldlib ... func_extract_archives () { my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" my_status="" $show "${rm}r $my_gentop" $run ${rm}r "$my_gentop" $show "$mkdir $my_gentop" $run $mkdir "$my_gentop" my_status=$? if test "$my_status" -ne 0 && test ! -d "$my_gentop"; then exit $my_status fi for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac my_xlib=`$echo "X$my_xlib" | $Xsed -e 's%^.*/%%'` my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) extracted_serial=`expr $extracted_serial + 1` my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" $show "${rm}r $my_xdir" $run ${rm}r "$my_xdir" $show "$mkdir $my_xdir" $run $mkdir "$my_xdir" exit_status=$? if test "$exit_status" -ne 0 && test ! -d "$my_xdir"; then exit $exit_status fi case $host in *-darwin*) $show "Extracting $my_xabs" # Do not bother doing anything if just a dry run if test -z "$run"; then darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`$echo "X$darwin_archive" | $Xsed -e 's%^.*/%%'` darwin_arches=`lipo -info "$darwin_archive" 2>/dev/null | $EGREP Architectures 2>/dev/null` if test -n "$darwin_arches"; then darwin_arches=`echo "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= $show "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do mkdir -p "unfat-$$/${darwin_base_archive}-${darwin_arch}" lipo -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $rm "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we have a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print| xargs basename | sort -u | $NL2SP` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` lipo -create -output "$darwin_file" $darwin_files done # $darwin_filelist ${rm}r unfat-$$ cd "$darwin_orig_dir" else cd "$darwin_orig_dir" func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches fi # $run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # End of Shell function definitions ##################################### # Darwin sucks eval std_shrext=\"$shrext_cmds\" disable_libs=no # Parse our command line options once, thoroughly. while test "$#" -gt 0 do arg="$1" shift case $arg in -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) optarg= ;; esac # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in execute_dlfiles) execute_dlfiles="$execute_dlfiles $arg" ;; tag) tagname="$arg" preserve_args="${preserve_args}=$arg" # Check whether tagname contains only valid characters case $tagname in *[!-_A-Za-z0-9,/]*) $echo "$progname: invalid tag name: $tagname" 1>&2 exit $EXIT_FAILURE ;; esac case $tagname in CC) # Don't test for the "default" C tag, as we know, it's there, but # not specially marked. ;; *) if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$progpath" > /dev/null; then taglist="$taglist $tagname" # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $progpath`" else $echo "$progname: ignoring unknown tag $tagname" 1>&2 fi ;; esac ;; *) eval "$prev=\$arg" ;; esac prev= prevopt= continue fi # Have we seen a non-optional argument yet? case $arg in --help) show_help=yes ;; --version) $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" $echo $echo "Copyright (C) 2005 Free Software Foundation, Inc." $echo "This is free software; see the source for copying conditions. There is NO" $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." exit $? ;; --config) ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $progpath # Now print the configurations for the tags. for tagname in $taglist; do ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$progpath" done exit $? ;; --debug) $echo "$progname: enabling shell trace mode" set -x preserve_args="$preserve_args $arg" ;; --dry-run | -n) run=: ;; --features) $echo "host: $host" if test "$build_libtool_libs" = yes; then $echo "enable shared libraries" else $echo "disable shared libraries" fi if test "$build_old_libs" = yes; then $echo "enable static libraries" else $echo "disable static libraries" fi exit $? ;; --finish) mode="finish" ;; --mode) prevopt="--mode" prev=mode ;; --mode=*) mode="$optarg" ;; --preserve-dup-deps) duplicate_deps="yes" ;; --quiet | --silent) show=: preserve_args="$preserve_args $arg" ;; --tag) prevopt="--tag" prev=tag preserve_args="$preserve_args --tag" ;; --tag=*) set tag "$optarg" ${1+"$@"} shift prev=tag preserve_args="$preserve_args --tag" ;; -dlopen) prevopt="-dlopen" prev=execute_dlfiles ;; -*) $echo "$modename: unrecognized option \`$arg'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; *) nonopt="$arg" break ;; esac done if test -n "$prevopt"; then $echo "$modename: option \`$prevopt' requires an argument" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi case $disable_libs in no) ;; shared) build_libtool_libs=no build_old_libs=yes ;; static) build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` ;; esac # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= if test -z "$show_help"; then # Infer the operation mode. if test -z "$mode"; then $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2 $echo "*** Future versions of Libtool will require --mode=MODE be specified." 1>&2 case $nonopt in *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*) mode=link for arg do case $arg in -c) mode=compile break ;; esac done ;; *db | *dbx | *strace | *truss) mode=execute ;; *install*|cp|mv) mode=install ;; *rm) mode=uninstall ;; *) # If we have no mode, but dlfiles were specified, then do execute mode. test -n "$execute_dlfiles" && mode=execute # Just use the default operation mode. if test -z "$mode"; then if test -n "$nonopt"; then $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 else $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 fi fi ;; esac fi # Only execute mode is allowed to have -dlopen flags. if test -n "$execute_dlfiles" && test "$mode" != execute; then $echo "$modename: unrecognized option \`-dlopen'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$modename --help --mode=$mode' for more information." # These modes are in order of execution frequency so that they run quickly. case $mode in # libtool compile mode compile) modename="$modename: compile" # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) if test -n "$libobj" ; then $echo "$modename: you cannot specify \`-o' more than once" 1>&2 exit $EXIT_FAILURE fi arg_mode=target continue ;; -static | -prefer-pic | -prefer-non-pic) later="$later $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"` lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac lastarg="$lastarg $arg" done IFS="$save_ifs" lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"` # Add the arguments to base_compile. base_compile="$base_compile $lastarg" continue ;; * ) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` case $lastarg in # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly # in scan sets, and some SunOS ksh mistreat backslash-escaping # in scan sets (worked around with variable expansion), # and furthermore cannot handle '|' '&' '(' ')' in scan sets # at all, so we specify them separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") lastarg="\"$lastarg\"" ;; esac base_compile="$base_compile $lastarg" done # for arg case $arg_mode in arg) $echo "$modename: you must specify an argument for -Xcompile" exit $EXIT_FAILURE ;; target) $echo "$modename: you must specify a target with \`-o'" 1>&2 exit $EXIT_FAILURE ;; *) # Get the name of the library object. [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo xform='[cCFSifmso]' case $libobj in *.ada) xform=ada ;; *.adb) xform=adb ;; *.ads) xform=ads ;; *.asm) xform=asm ;; *.c++) xform=c++ ;; *.cc) xform=cc ;; *.ii) xform=ii ;; *.class) xform=class ;; *.cpp) xform=cpp ;; *.cxx) xform=cxx ;; *.f90) xform=f90 ;; *.for) xform=for ;; *.java) xform=java ;; *.obj) xform=obj ;; esac libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` case $libobj in *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; *) $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 exit $EXIT_FAILURE ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -static) build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done qlibobj=`$echo "X$libobj" | $Xsed -e "$sed_quote_subst"` case $qlibobj in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") qlibobj="\"$qlibobj\"" ;; esac test "X$libobj" != "X$qlibobj" \ && $echo "X$libobj" | grep '[]~#^*{};<>?"'"'"' &()|`$[]' \ && $echo "$modename: libobj name \`$libobj' may not contain shell special characters." objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$obj"; then xdir= else xdir=$xdir/ fi lobj=${xdir}$objdir/$objname if test -z "$base_compile"; then $echo "$modename: you must specify a compilation command" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi $run $rm $removelist trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" removelist="$removelist $output_obj $lockfile" trap "$run $rm $removelist; exit $EXIT_FAILURE" 1 2 15 else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $run ln "$progpath" "$lockfile" 2>/dev/null; do $show "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $echo "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit $EXIT_FAILURE fi $echo "$srcfile" > "$lockfile" fi if test -n "$fix_srcfile_path"; then eval srcfile=\"$fix_srcfile_path\" fi qsrcfile=`$echo "X$srcfile" | $Xsed -e "$sed_quote_subst"` case $qsrcfile in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") qsrcfile="\"$qsrcfile\"" ;; esac $run $rm "$libobj" "${libobj}T" # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. test -z "$run" && cat > ${libobj}T </dev/null`" != "X$srcfile"; then $echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then $show "$mv $output_obj $lobj" if $run $mv $output_obj $lobj; then : else error=$? $run $rm $removelist exit $error fi fi # Append the name of the PIC object to the libtool object file. test -z "$run" && cat >> ${libobj}T <> ${libobj}T </dev/null`" != "X$srcfile"; then $echo "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $run $rm $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then $show "$mv $output_obj $obj" if $run $mv $output_obj $obj; then : else error=$? $run $rm $removelist exit $error fi fi # Append the name of the non-PIC object the libtool object file. # Only append if the libtool object file exists. test -z "$run" && cat >> ${libobj}T <> ${libobj}T <&2 fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test ;; *) qarg=$arg ;; esac libtool_args="$libtool_args $qarg" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) compile_command="$compile_command @OUTPUT@" finalize_command="$finalize_command @OUTPUT@" ;; esac case $prev in dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. compile_command="$compile_command @SYMFILE@" finalize_command="$finalize_command @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then dlfiles="$dlfiles $arg" else dlprefiles="$dlprefiles $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" if test ! -f "$arg"; then $echo "$modename: symbol file \`$arg' does not exist" exit $EXIT_FAILURE fi prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat $save_arg` do # moreargs="$moreargs $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then pic_object= non_pic_object= # Read the .lo file # If there is no directory component, then add one. case $arg in */* | *\\*) . $arg ;; *) . ./$arg ;; esac if test -z "$pic_object" || \ test -z "$non_pic_object" || test "$pic_object" = none && \ test "$non_pic_object" = none; then $echo "$modename: cannot find name of object for \`$arg'" 1>&2 exit $EXIT_FAILURE fi # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. libobjs="$libobjs $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object non_pic_objects="$non_pic_objects $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" non_pic_objects="$non_pic_objects $non_pic_object" fi else # Only an error if not doing a dry-run. if test -z "$run"; then $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 exit $EXIT_FAILURE else # Dry-run case. # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` libobjs="$libobjs $pic_object" non_pic_objects="$non_pic_objects $non_pic_object" fi fi done else $echo "$modename: link input file \`$save_arg' does not exist" exit $EXIT_FAILURE fi arg=$save_arg prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit $EXIT_FAILURE ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) rpath="$rpath $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) xrpath="$xrpath $arg" ;; esac fi prev= continue ;; xcompiler) compiler_flags="$compiler_flags $qarg" prev= compile_command="$compile_command $qarg" finalize_command="$finalize_command $qarg" continue ;; xlinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $wl$qarg" prev= compile_command="$compile_command $wl$qarg" finalize_command="$finalize_command $wl$qarg" continue ;; xcclinker) linker_flags="$linker_flags $qarg" compiler_flags="$compiler_flags $qarg" prev= compile_command="$compile_command $qarg" finalize_command="$finalize_command $qarg" continue ;; shrext) shrext_cmds="$arg" prev= continue ;; darwin_framework|darwin_framework_skip) test "$prev" = "darwin_framework" && compiler_flags="$compiler_flags $arg" compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" prev= continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then compile_command="$compile_command $link_static_flag" finalize_command="$finalize_command $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 continue ;; -avoid-version) avoid_version=yes continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: more than one -exported-symbols argument is not allowed" exit $EXIT_FAILURE fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework|-arch|-isysroot) case " $CC " in *" ${arg} ${1} "* | *" ${arg} ${1} "*) prev=darwin_framework_skip ;; *) compiler_flags="$compiler_flags $arg" prev=darwin_framework ;; esac compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" ;; esac continue ;; -L*) dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2 absdir="$dir" notinst_path="$notinst_path $dir" fi dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "*) ;; *) deplibs="$deplibs -L$dir" lib_search_path="$lib_search_path $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) testbindir=`$echo "X$dir" | $Xsed -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; *) dllsearchpath="$dllsearchpath:$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework deplibs="$deplibs -framework System" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi deplibs="$deplibs $arg" continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. -model) compile_command="$compile_command $arg" compiler_flags="$compiler_flags $arg" finalize_command="$finalize_command $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) compiler_flags="$compiler_flags $arg" compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" continue ;; -module) module=yes continue ;; # -64, -mips[0-9] enable 64-bit mode on the SGI compiler # -r[0-9][0-9]* specifies the processor on the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler # +DA*, +DD* enable 64-bit mode on the HP compiler # -q* pass through compiler args for the IBM compiler # -m* pass through architecture-specific compiler args for GCC # -m*, -t[45]*, -txscale* pass through architecture-specific # compiler args for GCC # -pg pass through profiling flag for GCC # @file GCC response files -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*|-pg| \ -t[45]*|-txscale*|@*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" compiler_flags="$compiler_flags $arg" continue ;; -shrext) prev=shrext continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) # The PATH hackery in wrapper scripts is required on Windows # in order for the loader to find any dlls it needs. $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2 $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2 fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) $echo "$modename: only absolute run-paths are allowed" 1>&2 exit $EXIT_FAILURE ;; esac case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -Wc,*) args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'` arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" case $flag in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") flag="\"$flag\"" ;; esac arg="$arg $wl$flag" compiler_flags="$compiler_flags $flag" done IFS="$save_ifs" arg=`$echo "X$arg" | $Xsed -e "s/^ //"` ;; -Wl,*) args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'` arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" case $flag in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") flag="\"$flag\"" ;; esac arg="$arg $wl$flag" compiler_flags="$compiler_flags $wl$flag" linker_flags="$linker_flags $flag" done IFS="$save_ifs" arg=`$echo "X$arg" | $Xsed -e "s/^ //"` ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # Some other compiler flag. -* | +*) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac ;; *.$objext) # A standard object. objs="$objs $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then pic_object= non_pic_object= # Read the .lo file # If there is no directory component, then add one. case $arg in */* | *\\*) . $arg ;; *) . ./$arg ;; esac if test -z "$pic_object" || \ test -z "$non_pic_object" || test "$pic_object" = none && \ test "$non_pic_object" = none; then $echo "$modename: cannot find name of object for \`$arg'" 1>&2 exit $EXIT_FAILURE fi # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then dlfiles="$dlfiles $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. dlprefiles="$dlprefiles $pic_object" prev= fi # A PIC object. libobjs="$libobjs $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object non_pic_objects="$non_pic_objects $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" non_pic_objects="$non_pic_objects $non_pic_object" fi else # Only an error if not doing a dry-run. if test -z "$run"; then $echo "$modename: \`$arg' is not a valid libtool object" 1>&2 exit $EXIT_FAILURE else # Dry-run case. # Extract subdirectory from the argument. xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` if test "X$xdir" = "X$arg"; then xdir= else xdir="$xdir/" fi pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"` non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"` libobjs="$libobjs $pic_object" non_pic_objects="$non_pic_objects $non_pic_object" fi fi ;; *.$libext) # An archive. deplibs="$deplibs $arg" old_deplibs="$old_deplibs $arg" continue ;; *.la) # A libtool-controlled library. if test "$prev" = dlfiles; then # This library was specified with -dlopen. dlfiles="$dlfiles $arg" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. dlprefiles="$dlprefiles $arg" prev= else deplibs="$deplibs $arg" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi done # argument parsing loop if test -n "$prev"; then $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" fi oldlibs= # calculate the name of the file, without its directory outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` if test "X$output_objdir" = "X$output"; then output_objdir="$objdir" else output_objdir="$output_objdir/$objdir" fi # Create the object directory. if test ! -d "$output_objdir"; then $show "$mkdir $output_objdir" $run $mkdir $output_objdir exit_status=$? if test "$exit_status" -ne 0 && test ! -d "$output_objdir"; then exit $exit_status fi fi # Determine the type of output case $output in "") $echo "$modename: you must specify an output file" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac case $host in *cygwin* | *mingw* | *pw32*) # don't eliminate duplications in $postdeps and $predeps duplicate_compiler_generated_deps=yes ;; *) duplicate_compiler_generated_deps=$duplicate_deps ;; esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if test "X$duplicate_deps" = "Xyes" ; then case "$libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi libs="$libs $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; esac pre_post_deps="$pre_post_deps $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries case $linkmode in lib) passes="conv link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2 exit $EXIT_FAILURE ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; esac fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else compiler_flags="$compiler_flags $deplib" fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2 continue fi name=`$echo "X$deplib" | $Xsed -e 's/^-l//'` for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then library_names= old_library= case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` test "X$ladir" = "X$lib" && ladir="." lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'` ;; *) $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2 ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'` # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) xrpath="$xrpath $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) lib="$deplib" ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` if eval $echo \"$deplib\" 2>/dev/null \ | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then $echo $echo "*** Warning: Trying to link with static lib archive $deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because the file extensions .$libext of this argument makes me believe" $echo "*** that it is just a static archive that I should not used here." else $echo $echo "*** Warning: Linking the shared library $output against the" $echo "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. newdlprefiles="$newdlprefiles $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else newdlfiles="$newdlfiles $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else $echo "$modename: cannot find the library \`$lib' or unhandled argument \`$deplib'" 1>&2 exit $EXIT_FAILURE fi # Check to see that this really is a libtool archive. if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'` test "X$ladir" = "X$lib" && ladir="." dlname= dlopen= dlpreopen= libdir= library_names= old_library= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && dlfiles="$dlfiles $dlopen" test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 exit $EXIT_FAILURE fi # It is a libtool convenience library, so add in its objects. convenience="$convenience $ladir/$objdir/$old_library" old_convenience="$old_convenience $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then $echo "$modename: \`$lib' is not a convenience library" 1>&2 exit $EXIT_FAILURE fi continue fi # $pass = conv # Get the name of the library we link against. linklib= for l in $old_library $library_names; do linklib="$l" done if test -z "$linklib"; then $echo "$modename: cannot find name of link library for \`$lib'" 1>&2 exit $EXIT_FAILURE fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2 exit $EXIT_FAILURE fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. dlprefiles="$dlprefiles $lib $dependency_libs" else newdlfiles="$newdlfiles $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2 $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 abs_ladir="$ladir" fi ;; esac laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then $echo "$modename: warning: library \`$lib' was moved." 1>&2 dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$libdir" absdir="$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later notinst_path="$notinst_path $abs_ladir" fi fi # $installed = yes name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir"; then $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2 exit $EXIT_FAILURE fi # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then newdlprefiles="$newdlprefiles $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then newdlprefiles="$newdlprefiles $dir/$dlname" else newdlprefiles="$newdlprefiles $dir/$linklib" fi fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then newlib_search_path="$newlib_search_path $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath " in *" $dir "*) ;; *" $absdir "*) ;; *) temp_rpath="$temp_rpath $absdir" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes ; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then if test "$installed" = no; then notinst_deplibs="$notinst_deplibs $lib" need_relink=yes fi # This is a shared library # Warn about portability, can't link against -module's on # some systems (darwin) if test "$shouldnotlink" = yes && test "$pass" = link ; then $echo if test "$linkmode" = prog; then $echo "*** Warning: Linking the executable $output against the loadable module" else $echo "*** Warning: Linking the shared library $output against the loadable module" fi $echo "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) compile_rpath="$compile_rpath $absdir" esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names realname="$2" shift; shift libname=`eval \\$echo \"$libname_spec\"` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw*) major=`expr $current - $age` versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" soname=`$echo $soroot | ${SED} -e 's/^.*\///'` newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a" # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else $show "extracting exported symbol list from \`$soname'" save_ifs="$IFS"; IFS='~' cmds=$extract_expsyms_cmds for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else $show "generating import library for \`$soname'" save_ifs="$IFS"; IFS='~' cmds=$old_archive_from_expsyms_cmds for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a module then we can not link against # it, someone is ignoring the new warnings I added if /usr/bin/file -L $add 2> /dev/null | $EGREP ": [^:]* bundle" >/dev/null ; then $echo "** Warning, lib $linklib is a module, not a shared library" if test -z "$old_library" ; then $echo $echo "** And there doesn't seem to be a static archive available" $echo "** The link will probably fail, sorry" else add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$dir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then $echo "$modename: configuration error: unsupported hardcode properties" exit $EXIT_FAILURE fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && \ test "$hardcode_minus_L" != yes && \ test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) add_dir="$add_dir -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. $echo $echo "*** Warning: This system can not link to static lib archive $lib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then $echo "*** But as you try to build a module library, libtool will still create " $echo "*** a static module, that should work as long as the dlopening application" $echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then $echo $echo "*** However, this would only work if libtool was able to extract symbol" $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" $echo "*** not find such a program. So, this module is probably useless." $echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'` case " $xrpath " in *" $temp_xrpath "*) ;; *) xrpath="$xrpath $temp_xrpath";; esac;; *) temp_deplibs="$temp_deplibs $libdir";; esac done dependency_libs="$temp_deplibs" fi newlib_search_path="$newlib_search_path $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" if test "X$duplicate_deps" = "Xyes" ; then case "$tmp_libs " in *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; esac fi tmp_libs="$tmp_libs $deplib" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do case $deplib in -L*) path="$deplib" ;; *.la) dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$deplib" && dir="." # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 absdir="$dir" fi ;; esac if grep "^installed=no" $deplib > /dev/null; then path="$absdir/$objdir" else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -z "$libdir"; then $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi if test "$absdir" != "$libdir"; then $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2 fi path="$absdir" fi depdepl= case $host in *-*-darwin*) # we do not want to link against static libs, # but need to link against shared eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$path/$depdepl" ; then depdepl="$path/$depdepl" fi # do not add paths which are already there case " $newlib_search_path " in *" $path "*) ;; *) newlib_search_path="$newlib_search_path $path";; esac fi path="" ;; *) path="-L$path" ;; esac ;; -l*) case $host in *-*-darwin*) # Again, we only want to link against shared libraries eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"` for tmp in $newlib_search_path ; do if test -f "$tmp/lib$tmp_libs.dylib" ; then eval depdepl="$tmp/lib$tmp_libs.dylib" break fi done path="" ;; *) continue ;; esac ;; *) continue ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac case " $deplibs " in *" $depdepl "*) ;; *) deplibs="$depdepl $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) lib_search_path="$lib_search_path $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) tmp_libs="$tmp_libs $deplib" ;; esac ;; *) tmp_libs="$tmp_libs $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then tmp_libs="$tmp_libs $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 fi if test -n "$export_symbols" || test -n "$export_symbols_regex"; then $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 fi # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" objs="$objs$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) if test "$module" = no; then $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1 exit $EXIT_FAILURE else $echo $echo "*** Warning: Linking the shared library $output against the non-libtool" $echo "*** objects $objs is not portable!" libobjs="$libobjs $objs" fi fi if test "$dlself" != no; then $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2 fi set dummy $rpath if test "$#" -gt 2; then $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 fi install_libdir="$2" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 fi else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 IFS="$save_ifs" if test -n "$8"; then $echo "$modename: too many parameters to \`-version-info'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$2" number_minor="$3" number_revision="$4" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in darwin|linux|osf|windows|none) current=`expr $number_major + $number_minor` age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) current=`expr $number_major + $number_minor - 1` age="$number_minor" revision="$number_minor" ;; esac ;; no) current="$2" revision="$3" age="$4" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) $echo "$modename: CURRENT \`$current' must be a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) $echo "$modename: REVISION \`$revision' must be a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) $echo "$modename: AGE \`$age' must be a nonnegative integer" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE ;; esac if test "$age" -gt "$current"; then $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 $echo "$modename: \`$vinfo' is not valid version information" 1>&2 exit $EXIT_FAILURE fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header major=.`expr $current - $age` versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... minor_current=`expr $current + 1` verstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current"; ;; irix | nonstopux) major=`expr $current - $age + 1` case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do iface=`expr $revision - $loop` loop=`expr $loop - 1` verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) major=.`expr $current - $age` versuffix="$major.$age.$revision" ;; osf) major=.`expr $current - $age` versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do iface=`expr $current - $loop` loop=`expr $loop - 1` verstring="$verstring:${iface}.0" done # Make executables depend on our current version. verstring="$verstring:${current}.0" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. major=`expr $current - $age` versuffix="-$major" ;; *) $echo "$modename: unknown library version type \`$version_type'" 1>&2 $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 exit $EXIT_FAILURE ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi if test "$mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$echo "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if echo $p | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi removelist="$removelist $p" ;; *) ;; esac done if test -n "$removelist"; then $show "${rm}r $removelist" $run ${rm}r $removelist fi fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then oldlibs="$oldlibs $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` fi # Eliminate all temporary directories. # for path in $notinst_path; do # lib_search_path=`$echo "$lib_search_path " | ${SED} -e "s% $path % %g"` # deplibs=`$echo "$deplibs " | ${SED} -e "s% -L$path % %g"` # dependency_libs=`$echo "$dependency_libs " | ${SED} -e "s% -L$path % %g"` # done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do temp_xrpath="$temp_xrpath -R$libdir" case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) dlfiles="$dlfiles $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) dlprefiles="$dlprefiles $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework deplibs="$deplibs -framework System" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $rm conftest.c cat > conftest.c </dev/null` for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null \ | grep " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ | ${SED} 10q \ | $EGREP "$file_magic_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $echo $echo "*** Warning: linker path does not have real file for library $a_deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $echo "*** with $libname but no candidates were found. (...for file magic test)" else $echo "*** with $libname and none of the candidates passed a file format test" $echo "*** using a file magic. Last file checked: $potlib" fi fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"` for a_deplib in $deplibs; do name=`expr $a_deplib : '-l\(.*\)'` # If $name is empty we are operating on a -L argument. if test -n "$name" && test "$name" != "0"; then if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) newdeplibs="$newdeplibs $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval \\$echo \"$libname_spec\"` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval $echo \"$potent_lib\" 2>/dev/null \ | ${SED} 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then newdeplibs="$newdeplibs $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes $echo $echo "*** Warning: linker path does not have real file for library $a_deplib." $echo "*** I have the capability to make that library automatically link in when" $echo "*** you link to this library. But I can only do this if you have a" $echo "*** shared version of the library, which you do not appear to have" $echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $echo "*** with $libname but no candidates were found. (...for regex pattern test)" else $echo "*** with $libname and none of the candidates passed a file format test" $echo "*** using a regex pattern. Last file checked: $potlib" fi fi else # Add a -L argument. newdeplibs="$newdeplibs $a_deplib" fi done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ -e 's/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"` done fi if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \ | grep . >/dev/null; then $echo if test "X$deplibs_check_method" = "Xnone"; then $echo "*** Warning: inter-library dependencies are not supported in this platform." else $echo "*** Warning: inter-library dependencies are not known to be supported." fi $echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes fi ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then $echo $echo "*** Warning: libtool could not satisfy all declared inter-library" $echo "*** dependencies of module $libname. Therefore, libtool will create" $echo "*** a static module, that should work as long as the dlopening" $echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then $echo $echo "*** However, this would only work if libtool was able to extract symbol" $echo "*** lists from a program, using \`nm' or equivalent, but libtool could" $echo "*** not find such a program. So, this module is probably useless." $echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else $echo "*** The inter-library dependencies that have been dropped here will be" $echo "*** automatically added whenever a program is linked with this library" $echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then $echo $echo "*** Since this library must not contain undefined symbols," $echo "*** because either the platform does not support them or" $echo "*** it was explicitly requested with -no-undefined," $echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" dep_rpath="$dep_rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" if test -n "$hardcode_libdir_flag_spec_ld"; then eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" else eval dep_rpath=\"$hardcode_libdir_flag_spec\" fi fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names realname="$2" shift; shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do linknames="$linknames $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then $show "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $run $rm $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" if len=`expr "X$cmd" : ".*"` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then $show "$cmd" $run eval "$cmd" || exit $? skipped_export=false else # The command line is too long to execute in one step. $show "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex"; then $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' $show "$mv \"${export_symbols}T\" \"$export_symbols\"" $run eval '$mv "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) tmp_deplibs="$tmp_deplibs $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" else gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $convenience libobjs="$libobjs $func_extract_archives_result" fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" fi # Make a backup of the uninstalled library when relinking if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*" 2>/dev/null` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise. $echo "creating reloadable object files..." # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output output_la=`$echo "X$output" | $Xsed -e "$basename"` # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= delfiles= last_robj= k=1 output=$output_objdir/$output_la-${k}.$objext # Loop over the list of objects to be linked. for obj in $save_libobjs do eval test_cmds=\"$reload_cmds $objlist $last_robj\" if test "X$objlist" = X || { len=`expr "X$test_cmds" : ".*" 2>/dev/null` && test "$len" -le "$max_cmd_len"; }; then objlist="$objlist $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. eval concat_cmds=\"$reload_cmds $objlist $last_robj\" else # All subsequent reloadable object files will link in # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext k=`expr $k + 1` output=$output_objdir/$output_la-${k}.$objext objlist=$obj len=1 fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" if ${skipped_export-false}; then $show "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $run $rm $export_symbols libobjs=$output # Append the command to create the export file. eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\" fi # Set up a command to remove the reloadable object files # after they are used. i=0 while test "$i" -lt "$k" do i=`expr $i + 1` delfiles="$delfiles $output_objdir/$output_la-${i}.$objext" done $echo "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi # Append the command to remove the reloadable object files # to the just-reset $cmds. eval cmds=\"\$cmds~\$rm $delfiles\" fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then $show "${rm}r $gentop" $run ${rm}r "$gentop" fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$deplibs"; then $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 fi if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 fi if test -n "$rpath"; then $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 fi if test -n "$xrpath"; then $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 fi if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 fi case $output in *.lo) if test -n "$objs$old_deplibs"; then $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 exit $EXIT_FAILURE fi libobj="$output" obj=`$echo "X$output" | $Xsed -e "$lo2o"` ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $run $rm $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$echo "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` else gentop="$output_objdir/${obj}x" generated="$generated $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # Create the old-style object. reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" cmds=$reload_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $run eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" cmds=$reload_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" fi if test -n "$gentop"; then $show "${rm}r $gentop" $run ${rm}r $gentop fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;; esac if test -n "$vinfo"; then $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 fi if test -n "$release"; then $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 fi if test "$preload" = yes; then if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown && test "$dlopen_self_static" = unknown; then $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." fi fi case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'` finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'` ;; esac case $host in *darwin*) # Don't allow lazy linking, it breaks C++ global constructors if test "$tagname" = CXX ; then compile_command="$compile_command ${wl}-bind_at_load" finalize_command="$finalize_command ${wl}-bind_at_load" fi ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) new_libs="$new_libs -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$new_libs $deplib" ;; esac ;; *) new_libs="$new_libs $deplib" ;; esac done compile_deplibs="$new_libs" compile_command="$compile_command $compile_deplibs" finalize_command="$finalize_command $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) finalize_rpath="$finalize_rpath $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) perm_rpath="$perm_rpath $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*) testbindir=`$echo "X$libdir" | $Xsed -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; *) dllsearchpath="$dllsearchpath:$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; *) dllsearchpath="$dllsearchpath:$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" rpath="$rpath $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` fi dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then dlsyms="${outputname}S.c" else $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 fi fi if test -n "$dlsyms"; then case $dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${outputname}.nm" $show "$rm $nlist ${nlist}S ${nlist}T" $run $rm "$nlist" "${nlist}S" "${nlist}T" # Parse the name list into a source file. $show "creating $output_objdir/$dlsyms" test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ /* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ /* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ #ifdef __cplusplus extern \"C\" { #endif /* Prevent the only kind of declaration conflicts we can make. */ #define lt_preloaded_symbols some_other_symbol /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then $show "generating symbol list for \`$output'" test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` for arg in $progfiles; do $show "extracting global C symbols from \`$arg'" $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi if test -n "$export_symbols_regex"; then $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' $run eval '$mv "$nlist"T "$nlist"' fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $run $rm $export_symbols $run eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* ) $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' $run eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac else $run eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' $run eval 'grep -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' $run eval 'mv "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* ) $run eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' $run eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac fi fi for arg in $dlprefiles; do $show "extracting global C symbols from \`$arg'" name=`$echo "$arg" | ${SED} -e 's%^.*/%%'` $run eval '$echo ": $name " >> "$nlist"' $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" done if test -z "$run"; then # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $mv "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if grep -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else grep -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' else $echo '/* NONE */' >> "$output_objdir/$dlsyms" fi $echo >> "$output_objdir/$dlsyms" "\ #undef lt_preloaded_symbols #if defined (__STDC__) && __STDC__ # define lt_ptr void * #else # define lt_ptr char * # define const #endif /* The mapping between symbol names and symbols. */ " case $host in *cygwin* | *mingw* ) $echo >> "$output_objdir/$dlsyms" "\ /* DATA imports from DLLs on WIN32 can't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs */ struct { " ;; * ) $echo >> "$output_objdir/$dlsyms" "\ const struct { " ;; esac $echo >> "$output_objdir/$dlsyms" "\ const char *name; lt_ptr address; } lt_preloaded_symbols[] = {\ " eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms" $echo >> "$output_objdir/$dlsyms" "\ {0, (lt_ptr) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " fi pic_flag_for_symtable= case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";; esac;; *-*-hpux*) case "$compile_command " in *" -static "*) ;; *) pic_flag_for_symtable=" $pic_flag";; esac esac # Now compile the dynamic symbol file. $show "(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" $run eval '(cd $output_objdir && $LTCC $LTCFLAGS -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? # Clean up the generated files. $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" # Transform the symbol file into the correct name. case $host in *cygwin* | *mingw* ) if test -f "$output_objdir/${outputname}.def" ; then compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}.def $output_objdir/${outputname}S.${objext}%" | $NL2SP` else compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` fi ;; * ) compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%" | $NL2SP` ;; esac ;; *) $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 exit $EXIT_FAILURE ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "s% @SYMFILE@%%" | $NL2SP` fi if test "$need_relink" = no || test "$build_libtool_libs" != yes; then # Replace the output file specification. compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$output"'%g' | $NL2SP` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. $show "$link_command" $run eval "$link_command" exit_status=$? # Delete the generated files. if test -n "$dlsyms"; then $show "$rm $output_objdir/${outputname}S.${objext}" $run $rm "$output_objdir/${outputname}S.${objext}" fi exit $exit_status fi if test -n "$shlibpath_var"; then # We should set the shlibpath_var rpath= for dir in $temp_rpath; do case $dir in [\\/]* | [A-Za-z]:[\\/]*) # Absolute path. rpath="$rpath$dir:" ;; *) # Relative path: add a thisdir entry. rpath="$rpath\$thisdir/$dir:" ;; esac done temp_rpath="$rpath" fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do rpath="$rpath$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do rpath="$rpath$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $run $rm $output # Link the executable and exit $show "$link_command" $run eval "$link_command" || exit $? exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 $echo "$modename: \`$output' will be relinked during installation" 1>&2 else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $SP2NL | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g' | $NL2SP` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname $show "$link_command" $run eval "$link_command" || exit $? # Now create the wrapper script. $show "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` relink_command="$var=\"$var_value\"; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` fi # Quote $echo for shipping. if test "X$echo" = "X$SHELL $progpath --fallback-echo"; then case $progpath in [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; esac qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` else qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` fi # Only actually do things if our run command is non-null. if test -z "$run"; then # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) output_name=`basename $output` output_path=`dirname $output` cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $rm $cwrappersource $cwrapper trap "$rm $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 cat > $cwrappersource <> $cwrappersource<<"EOF" #include #include #include #include #include #include #include #include #include #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) /* -DDEBUG is fairly common in CFLAGS. */ #undef DEBUG #if defined DEBUGWRAPPER # define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__) #else # define DEBUG(format, ...) #endif const char *program_name = NULL; void * xmalloc (size_t num); char * xstrdup (const char *string); const char * base_name (const char *name); char * find_executable(const char *wrapper); int check_executable(const char *path); char * strendzap(char *str, const char *pat); void lt_fatal (const char *message, ...); int main (int argc, char *argv[]) { char **newargz; int i; program_name = (char *) xstrdup (base_name (argv[0])); DEBUG("(main) argv[0] : %s\n",argv[0]); DEBUG("(main) program_name : %s\n",program_name); newargz = XMALLOC(char *, argc+2); EOF cat >> $cwrappersource <> $cwrappersource <<"EOF" newargz[1] = find_executable(argv[0]); if (newargz[1] == NULL) lt_fatal("Couldn't find %s", argv[0]); DEBUG("(main) found exe at : %s\n",newargz[1]); /* we know the script has the same name, without the .exe */ /* so make sure newargz[1] doesn't end in .exe */ strendzap(newargz[1],".exe"); for (i = 1; i < argc; i++) newargz[i+1] = xstrdup(argv[i]); newargz[argc+1] = NULL; for (i=0; i> $cwrappersource <> $cwrappersource <> $cwrappersource <<"EOF" return 127; } void * xmalloc (size_t num) { void * p = (void *) malloc (num); if (!p) lt_fatal ("Memory exhausted"); return p; } char * xstrdup (const char *string) { return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL ; } const char * base_name (const char *name) { const char *base; #if defined (HAVE_DOS_BASED_FILE_SYSTEM) /* Skip over the disk name in MSDOS pathnames. */ if (isalpha ((unsigned char)name[0]) && name[1] == ':') name += 2; #endif for (base = name; *name; name++) if (IS_DIR_SEPARATOR (*name)) base = name + 1; return base; } int check_executable(const char * path) { struct stat st; DEBUG("(check_executable) : %s\n", path ? (*path ? path : "EMPTY!") : "NULL!"); if ((!path) || (!*path)) return 0; if ((stat (path, &st) >= 0) && ( /* MinGW & native WIN32 do not support S_IXOTH or S_IXGRP */ #if defined (S_IXOTH) ((st.st_mode & S_IXOTH) == S_IXOTH) || #endif #if defined (S_IXGRP) ((st.st_mode & S_IXGRP) == S_IXGRP) || #endif ((st.st_mode & S_IXUSR) == S_IXUSR)) ) return 1; else return 0; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise */ char * find_executable (const char* wrapper) { int has_slash = 0; const char* p; const char* p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char* concat_name; DEBUG("(find_executable) : %s\n", wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char)wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable(concat_name)) return concat_name; XFREE(concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable(concat_name)) return concat_name; XFREE(concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char* path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char* q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR(*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen(tmp); concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC(char, p_len + 1 + strlen(wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable(concat_name)) return concat_name; XFREE(concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal ("getcwd failed"); tmp_len = strlen(tmp); concat_name = XMALLOC(char, tmp_len + 1 + strlen(wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable(concat_name)) return concat_name; XFREE(concat_name); return NULL; } char * strendzap(char *str, const char *pat) { size_t len, patlen; assert(str != NULL); assert(pat != NULL); len = strlen(str); patlen = strlen(pat); if (patlen <= len) { str += len - patlen; if (strcmp(str, pat) == 0) *str = '\0'; } return str; } static void lt_error_core (int exit_status, const char * mode, const char * message, va_list ap) { fprintf (stderr, "%s: %s: ", program_name, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, "FATAL", message, ap); va_end (ap); } EOF # we should really use a build-platform specific compiler # here, but OTOH, the wrappers (shell script and this C one) # are only useful if you want to execute the "real" binary. # Since the "real" binary is built for $host, then this # wrapper might as well be built for $host, too. $run $LTCC $LTCFLAGS -s -o $cwrapper $cwrappersource ;; esac $rm $output trap "$rm $output; exit $EXIT_FAILURE" 1 2 15 $echo > $output "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='${SED} -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # Be Bourne compatible (taken from Autoconf:_AS_BOURNE_COMPATIBLE). if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variable: notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$echo are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then echo=\"$qecho\" file=\"\$0\" # Make sure echo works. if test \"X\$1\" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then # Yippee, \$echo works! : else # Restart under the correct shell, and then maybe \$echo will work. exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} fi fi\ " $echo >> $output "\ # Find the directory that this script lives in. thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` done # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $echo >> $output "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || \\ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $mkdir \"\$progdir\" else $rm \"\$progdir/\$file\" fi" $echo >> $output "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $echo \"\$relink_command_output\" >&2 $rm \"\$progdir/\$file\" exit $EXIT_FAILURE fi fi $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $rm \"\$progdir/\$program\"; $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } $rm \"\$progdir/\$file\" fi" else $echo >> $output "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $echo >> $output "\ if test -f \"\$progdir/\$program\"; then" # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $echo >> $output "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` export $shlibpath_var " fi # fixup the dll searchpath if we need to. if test -n "$dllsearchpath"; then $echo >> $output "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi $echo >> $output "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2*) $echo >> $output "\ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $echo >> $output "\ exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $echo >> $output "\ \$echo \"\$0: cannot exec \$program \$*\" exit $EXIT_FAILURE fi else # The program doesn't exist. \$echo \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$echo \"This script is just a wrapper for \$program.\" 1>&2 $echo \"See the $PACKAGE documentation for more information.\" 1>&2 exit $EXIT_FAILURE fi fi\ " chmod +x $output fi exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" func_extract_archives $gentop $addlibs oldobjs="$oldobjs $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do $echo "X$obj" | $Xsed -e 's%^.*/%%' done | sort | sort -uc >/dev/null 2>&1); then : else $echo "copying selected object files to avoid basename conflicts..." if test -z "$gentop"; then gentop="$output_objdir/${outputname}x" generated="$generated $gentop" $show "${rm}r $gentop" $run ${rm}r "$gentop" $show "$mkdir $gentop" $run $mkdir "$gentop" exit_status=$? if test "$exit_status" -ne 0 && test ! -d "$gentop"; then exit $exit_status fi fi save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do objbase=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase counter=`expr $counter + 1` case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done $show "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" $run ln "$obj" "$gentop/$newobj" || $run cp "$obj" "$gentop/$newobj" oldobjs="$oldobjs $gentop/$newobj" ;; *) oldobjs="$oldobjs $obj" ;; esac done fi eval cmds=\"$old_archive_cmds\" if len=`expr "X$cmds" : ".*"` && test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts $echo "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done for obj in $save_oldobjs do oldobjs="$objlist $obj" objlist="$objlist $obj" eval test_cmds=\"$old_archive_cmds\" if len=`expr "X$test_cmds" : ".*" 2>/dev/null` && test "$len" -le "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do eval cmd=\"$cmd\" IFS="$save_ifs" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$generated"; then $show "${rm}r$generated" $run ${rm}r$generated fi # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" $show "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"` relink_command="$var=\"$var_value\"; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e "$sed_quote_subst" | $NL2SP` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. if test -z "$run"; then for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` if test -z "$libdir"; then $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi newdependency_libs="$newdependency_libs $libdir/$name" ;; *) newdependency_libs="$newdependency_libs $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` if test -z "$libdir"; then $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi newdlfiles="$newdlfiles $libdir/$name" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'` eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` if test -z "$libdir"; then $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 exit $EXIT_FAILURE fi newdlprefiles="$newdlprefiles $libdir/$name" done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlfiles="$newdlfiles $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac newdlprefiles="$newdlprefiles $abs" done dlprefiles="$newdlprefiles" fi $rm $output # place dlname in correct position for cygwin tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; esac $echo > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $echo >> $output "\ relink_command=\"$relink_command\"" fi done fi # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $? ;; esac exit $EXIT_SUCCESS ;; # libtool install mode install) modename="$modename: install" # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. $echo "X$nonopt" | grep shtool > /dev/null; then # Aesthetically quote it. arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac install_prog="$arg " arg="$1" shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac install_prog="$install_prog$arg" # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= for arg do if test -n "$dest"; then files="$files $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) case " $install_prog " in *[\\\ /]cp\ *) ;; *) prev=$arg ;; esac ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` case $arg in *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") arg="\"$arg\"" ;; esac install_prog="$install_prog $arg" done if test -z "$install_prog"; then $echo "$modename: you must specify an install program" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi if test -n "$prev"; then $echo "$modename: the \`$prev' option requires an argument" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi if test -z "$files"; then if test -z "$dest"; then $echo "$modename: no file or destination specified" 1>&2 else $echo "$modename: you must specify a destination" 1>&2 fi $echo "$help" 1>&2 exit $EXIT_FAILURE fi # Strip any trailing slash from the destination. dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` test "X$destdir" = "X$dest" && destdir=. destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` # Not a directory, so check to see that there is only one file specified. set dummy $files if test "$#" -gt 2; then $echo "$modename: \`$dest' is not a directory" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. staticlibs="$staticlibs $file" ;; *.la) # Check to see that this really is a libtool archive. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi library_names= old_library= relink_command= # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) current_libdirs="$current_libdirs $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) future_libdirs="$future_libdirs $libdir" ;; esac fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/ test "X$dir" = "X$file/" && dir= dir="$dir$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. if test "$inst_prefix_dir" = "$destdir"; then $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2 exit $EXIT_FAILURE fi if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%" | $NL2SP` else relink_command=`$echo "$relink_command" | $SP2NL | $SED "s%@inst_prefix_dir@%%" | $NL2SP` fi $echo "$modename: warning: relinking \`$file'" 1>&2 $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 exit $EXIT_FAILURE fi fi # See the names of the shared library. set dummy $library_names if test -n "$2"; then realname="$2" shift shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. $show "$install_prog $dir/$srcname $destdir/$realname" $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $? if test -n "$stripme" && test -n "$striplib"; then $show "$striplib $destdir/$realname" $run eval "$striplib $destdir/$realname" || exit $? fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do if test "$linkname" != "$realname"; then $show "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" $run eval "(cd $destdir && { $LN_S -f $realname $linkname || { $rm $linkname && $LN_S $realname $linkname; }; })" fi done fi # Do each command in the postinstall commands. lib="$destdir/$realname" cmds=$postinstall_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$mode" = relink; then $run eval '(cd $output_objdir && $rm ${realname}T && $mv ${realname}U $realname)' fi exit $lt_exit } done IFS="$save_ifs" fi # Install the pseudo-library for information purposes. name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` instname="$dir/$name"i $show "$install_prog $instname $destdir/$name" $run eval "$install_prog $instname $destdir/$name" || exit $? # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` ;; *.$objext) staticdest="$destfile" destfile= ;; *) $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; esac # Install the libtool object if requested. if test -n "$destfile"; then $show "$install_prog $file $destfile" $run eval "$install_prog $file $destfile" || exit $? fi # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` $show "$install_prog $staticobj $staticdest" $run eval "$install_prog \$staticobj \$staticdest" || exit $? fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then file=`$echo $file|${SED} 's,.exe$,,'` stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin*|*mingw*) wrapper=`$echo $file | ${SED} -e 's,.exe$,,'` ;; *) wrapper=$file ;; esac if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then notinst_deplibs= relink_command= # Note that it is not necessary on cygwin/mingw to append a dot to # foo even if both foo and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. # # If there is no directory component, then add one. case $wrapper in */* | *\\*) . ${wrapper} ;; *) . ./${wrapper} ;; esac # Check the variables that should have been set. if test -z "$notinst_deplibs"; then $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2 exit $EXIT_FAILURE fi finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then # If there is no directory component, then add one. case $lib in */* | *\\*) . $lib ;; *) . ./$lib ;; esac fi libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 finalize=no fi done relink_command= # Note that it is not necessary on cygwin/mingw to append a dot to # foo even if both foo and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. # # If there is no directory component, then add one. case $wrapper in */* | *\\*) . ${wrapper} ;; *) . ./${wrapper} ;; esac outputname= if test "$fast_install" = no && test -n "$relink_command"; then if test "$finalize" = yes && test -z "$run"; then tmpdir=`func_mktempdir` file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'` outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$echo "X$relink_command" | $SP2NL | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g' | $NL2SP` $show "$relink_command" if $run eval "$relink_command"; then : else $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 ${rm}r "$tmpdir" continue fi file="$outputname" else $echo "$modename: warning: cannot relink \`$file'" 1>&2 fi else # Install the binary that we compiled earlier. file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'` ;; esac ;; esac $show "$install_prog$stripme $file $destfile" $run eval "$install_prog\$stripme \$file \$destfile" || exit $? test -n "$outputname" && ${rm}r "$tmpdir" ;; esac done for file in $staticlibs; do name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` # Set up the ranlib parameters. oldlib="$destdir/$name" $show "$install_prog $file $oldlib" $run eval "$install_prog \$file \$oldlib" || exit $? if test -n "$stripme" && test -n "$old_striplib"; then $show "$old_striplib $oldlib" $run eval "$old_striplib $oldlib" || exit $? fi # Do each command in the postinstall commands. cmds=$old_postinstall_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || exit $? done IFS="$save_ifs" done if test -n "$future_libdirs"; then $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 fi if test -n "$current_libdirs"; then # Maybe just do a dry run. test -n "$run" && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi ;; # libtool finish mode finish) modename="$modename: finish" libdirs="$nonopt" admincmds= if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for dir do libdirs="$libdirs $dir" done for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. cmds=$finish_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" || admincmds="$admincmds $cmd" done IFS="$save_ifs" fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $run eval "$cmds" || admincmds="$admincmds $cmds" fi done fi # Exit here if they wanted silent mode. test "$show" = : && exit $EXIT_SUCCESS $echo "X----------------------------------------------------------------------" | $Xsed $echo "Libraries have been installed in:" for libdir in $libdirs; do $echo " $libdir" done $echo $echo "If you ever happen to want to link against installed libraries" $echo "in a given directory, LIBDIR, you must either use libtool, and" $echo "specify the full pathname of the library, or use the \`-LLIBDIR'" $echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then $echo " - add LIBDIR to the \`$shlibpath_var' environment variable" $echo " during execution" fi if test -n "$runpath_var"; then $echo " - add LIBDIR to the \`$runpath_var' environment variable" $echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $echo " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $echo " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi $echo $echo "See any operating system documentation about shared libraries for" $echo "more information, such as the ld(1) and ld.so(8) manual pages." $echo "X----------------------------------------------------------------------" | $Xsed exit $EXIT_SUCCESS ;; # libtool execute mode execute) modename="$modename: execute" # The first argument is the command name. cmd="$nonopt" if test -z "$cmd"; then $echo "$modename: you must specify a COMMAND" 1>&2 $echo "$help" exit $EXIT_FAILURE fi # Handle -dlopen flags immediately. for file in $execute_dlfiles; do if test ! -f "$file"; then $echo "$modename: \`$file' is not a file" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi dir= case $file in *.la) # Check to see that this really is a libtool archive. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : else $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi # Read the libtool library. dlname= library_names= # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" continue fi dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. if test -f "$dir/$objdir/$dlname"; then dir="$dir/$objdir" else $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 exit $EXIT_FAILURE fi ;; *.lo) # Just add the directory containing the .lo file. dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` test "X$dir" = "X$file" && dir=. ;; *) $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -*) ;; *) # Do a test to see if this is really a libtool program. if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # If there is no directory component, then add one. case $file in */* | *\\*) . $file ;; *) . ./$file ;; esac # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` args="$args \"$file\"" done if test -z "$run"; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" $echo "export $shlibpath_var" fi $echo "$cmd$args" exit $EXIT_SUCCESS fi ;; # libtool clean and uninstall mode clean | uninstall) modename="$modename: $mode" rm="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) rm="$rm $arg"; rmforce=yes ;; -*) rm="$rm $arg" ;; *) files="$files $arg" ;; esac done if test -z "$rm"; then $echo "$modename: you must specify an RM program" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE fi rmdirs= origobjdir="$objdir" for file in $files; do dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` if test "X$dir" = "X$file"; then dir=. objdir="$origobjdir" else objdir="$dir/$origobjdir" fi name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` test "$mode" = uninstall && objdir="$dir" # Remember objdir for removal later, being careful to avoid duplicates if test "$mode" = clean; then case " $rmdirs " in *" $objdir "*) ;; *) rmdirs="$rmdirs $objdir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if (test -L "$file") >/dev/null 2>&1 \ || (test -h "$file") >/dev/null 2>&1 \ || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then . $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do rmfiles="$rmfiles $objdir/$n" done test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" case "$mode" in clean) case " $library_names " in # " " in the beginning catches empty $dlname *" $dlname "*) ;; *) rmfiles="$rmfiles $objdir/$dlname" ;; esac test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. cmds=$postuninstall_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" if test "$?" -ne 0 && test "$rmforce" != yes; then exit_status=1 fi done IFS="$save_ifs" fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. cmds=$old_postuninstall_cmds save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $show "$cmd" $run eval "$cmd" if test "$?" -ne 0 && test "$rmforce" != yes; then exit_status=1 fi done IFS="$save_ifs" fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then # Read the .lo file . $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" \ && test "$pic_object" != none; then rmfiles="$rmfiles $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" \ && test "$non_pic_object" != none; then rmfiles="$rmfiles $dir/$non_pic_object" fi fi ;; *) if test "$mode" = clean ; then noexename=$name case $file in *.exe) file=`$echo $file|${SED} 's,.exe$,,'` noexename=`$echo $name|${SED} 's,.exe$,,'` # $file with .exe has already been added to rmfiles, # add $file without .exe rmfiles="$rmfiles $file" ;; esac # Do a test to see if this is a libtool program. if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then relink_command= . $dir/$noexename # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then rmfiles="$rmfiles $objdir/lt-$name" fi if test "X$noexename" != "X$name" ; then rmfiles="$rmfiles $objdir/lt-${noexename}.c" fi fi fi ;; esac $show "$rm $rmfiles" $run $rm $rmfiles || exit_status=1 done objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then $show "rmdir $dir" $run rmdir $dir >/dev/null 2>&1 fi done exit $exit_status ;; "") $echo "$modename: you must specify a MODE" 1>&2 $echo "$generic_help" 1>&2 exit $EXIT_FAILURE ;; esac if test -z "$exec_cmd"; then $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$generic_help" 1>&2 exit $EXIT_FAILURE fi fi # test -z "$show_help" if test -n "$exec_cmd"; then eval exec $exec_cmd exit $EXIT_FAILURE fi # We need to display help for each of the modes. case $mode in "") $echo \ "Usage: $modename [OPTION]... [MODE-ARG]... Provide generalized library-building support services. --config show all configuration variables --debug enable verbose shell tracing -n, --dry-run display commands without modifying any files --features display basic configuration information and exit --finish same as \`--mode=finish' --help display this help message and exit --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] --quiet same as \`--silent' --silent don't print informational messages --tag=TAG use configuration variables from tag TAG --version print version information MODE must be one of the following: clean remove files from the build directory compile compile a source file into a libtool object execute automatically set library path, then run a program finish complete the installation of libtool libraries install install libraries or executables link create a library or an executable uninstall remove libraries from an installed directory MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for a more detailed description of MODE. Report bugs to ." exit $EXIT_SUCCESS ;; clean) $echo \ "Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $echo \ "Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -prefer-pic try to building PIC objects only -prefer-non-pic try to building non-PIC objects only -static always build a \`.o' file suitable for static linking COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $echo \ "Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $echo \ "Usage: $modename [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $echo \ "Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $echo \ "Usage: $modename [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $echo \ "Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) $echo "$modename: invalid operation mode \`$mode'" 1>&2 $echo "$help" 1>&2 exit $EXIT_FAILURE ;; esac $echo $echo "Try \`$modename --help' for more information about other modes." exit $? # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared disable_libs=shared # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static disable_libs=static # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: gateway-1.4.5/addons/opensmppbox/autotools/config.guess0000755000175000017500000012206511563321320022061 0ustar toljtolj#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-06-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown ## for Red Hat Linux if test -f /etc/redhat-release ; then VENDOR=redhat ; else VENDOR= ; fi # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha*:OpenVMS:*:*) echo alpha-hp-vms exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit 0 ;; DRS?6000:UNIX_SV:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7 && exit 0 ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c \ && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && exit 0 echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then # avoid double evaluation of $set_cc_for_build test -n "$CC_FOR_BUILD" || eval $set_cc_for_build if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; *:UNICOS/mp:*:*) echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*|*:GNU/FreeBSD:*:*) # Determine whether the default compiler uses glibc. eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #if __GLIBC__ >= 2 LIBC=gnu #else LIBC= #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC} exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; x86:Interix*:[34]*) echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' exit 0 ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-${VENDOR:-unknown}-linux-gnu exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 ;; ppc:Linux:*:*) echo powerpc-${VENDOR:-unknown}-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-${VENDOR:-unknown}-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu exit 0 ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-${VENDOR:-unknown}-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #ifdef __INTEL_COMPILER LIBC=gnu #else LIBC=gnuaout #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR:-pc}-linux-${LIBC}" && exit 0 test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit 0 ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) case `uname -p` in *86) UNAME_PROCESSOR=i686 ;; powerpc) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gateway-1.4.5/addons/opensmppbox/autotools/config.sub0000755000175000017500000007305511563321320021530 0ustar toljtolj#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003 Free Software Foundation, Inc. timestamp='2003-06-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k \ | m32r | m68000 | m68k | m88k | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | msp430 \ | ns16k | ns32k \ | openrisc | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | s390 | s390x \ | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \ | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xscale | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* \ | m32r-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | msp430-* \ | none-* | np1-* | nv1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | s390-* | s390x-* \ | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xps100-* | xscale-* | xstormy16-* \ | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nv1) basic_machine=nv1-cray os=-unicosmp ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; or32 | or32-*) basic_machine=or32-unknown os=-coff ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sh64) basic_machine=sh64-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: gateway-1.4.5/addons/opensmppbox/autotools/depcomp0000755000175000017500000003710011563321320021111 0ustar toljtolj#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2005-07-09.11 # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` tmpdepfile="$stripped.u" if test "$libtool" = yes; then "$@" -Wc,-M else "$@" -M fi stat=$? if test -f "$tmpdepfile"; then : else stripped=`echo "$stripped" | sed 's,^.*/,,'` tmpdepfile="$stripped.u" fi if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi if test -f "$tmpdepfile"; then outname="$stripped.o" # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mecanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # X makedepend shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes ;; esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. "$@" || exit $? IFS=" " for arg do case "$arg" in "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: gateway-1.4.5/addons/opensmppbox/autotools/install-sh0000755000175000017500000002202111563321320021534 0ustar toljtolj#!/bin/sh # install - install a program, script, or datafile scriptversion=2005-05-14.22 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit $?;; *) # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. test -n "$dir_arg$dstarg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then mkdircmd=: chmodcmd= else mkdircmd=$mkdirprog fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` shift IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift if test ! -d "$pathcomp"; then $mkdirprog "$pathcomp" # mkdir can fail with a `File exist' error in case several # install-sh are creating the directory concurrently. This # is OK. test -d "$pathcomp" || exit fi pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $mkdircmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 # Copy the file name to the temp name. $doit $cpprog "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" } } fi || { (exit 1); exit 1; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit 0 } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: gateway-1.4.5/addons/opensmppbox/autotools/missing0000755000175000017500000002540611563321320021141 0ustar toljtolj#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2005-06-08.21 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case "$1" in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: gateway-1.4.5/addons/opensmppbox/Makefile.in0000644000175000017500000005460312327711130017560 0ustar toljtolj# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = . am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ LIBOBJDIR = DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/sb-config.h.in \ $(top_srcdir)/configure $(top_srcdir)/rpm/opensmppbox.spec.in \ AUTHORS COPYING ChangeLog INSTALL NEWS autotools/config.guess \ autotools/config.sub autotools/depcomp autotools/install-sh \ autotools/ltmain.sh autotools/missing subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno configure.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = sb-config.h CONFIG_CLEAN_FILES = rpm/opensmppbox.spec SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ html-recursive info-recursive install-data-recursive \ install-exec-recursive install-info-recursive \ install-recursive installcheck-recursive installdirs-recursive \ pdf-recursive ps-recursive uninstall-info-recursive \ uninstall-recursive ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ { test ! -d $(distdir) \ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -fr $(distdir); }; } DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONVERT = @CONVERT@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CTLIB_INCLUDE = @CTLIB_INCLUDE@ CTLIB_LFLAGS = @CTLIB_LFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOCDRAFTS = @DOCDRAFTS@ DOCSTARGET = @DOCSTARGET@ DVIPS = @DVIPS@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FIG2DEV = @FIG2DEV@ GREP = @GREP@ GW_CONFIG = @GW_CONFIG@ GW_VERSION = @GW_VERSION@ HTML_DSL = @HTML_DSL@ INCLUDES = @INCLUDES@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ JADE = @JADE@ JADETEX = @JADETEX@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ OLDJADE = @OLDJADE@ OPENSSL = @OPENSSL@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFJADETEX = @PDFJADETEX@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TEX_DSL = @TEX_DSL@ VERSION = @VERSION@ XML_DCL = @XML_DCL@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ rpm_requires = @rpm_requires@ rpm_suffix = @rpm_suffix@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ man1pages = gw/opensmppbox.1 man5pages = gw/opensmppbox.5 docsrcs = $(wildcard grep -l '/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ list='$(SOURCES) $(HEADERS) sb-config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: ctags-recursive $(HEADERS) $(SOURCES) sb-config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) sb-config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) mkdir $(distdir) $(mkdir_p) $(distdir)/autotools $(distdir)/rpm @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test -d "$(distdir)/$$subdir" \ || $(mkdir_p) "$(distdir)/$$subdir" \ || exit 1; \ distdir=`$(am__cd) $(distdir) && pwd`; \ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ (cd $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$top_distdir" \ distdir="$$distdir/$$subdir" \ distdir) \ || exit 1; \ fi; \ done -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r $(distdir) dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && cd $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' distuninstallcheck: @cd $(distuninstallcheck_dir) \ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile sb-config.h installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive info: info-recursive info-am: install-data-am: install-exec-am: install-info: install-info-recursive install-man: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps-am: uninstall-am: uninstall-info-am uninstall-info: uninstall-info-recursive .PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am am--refresh check \ check-am clean clean-generic clean-libtool clean-recursive \ ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ dist-shar dist-tarZ dist-zip distcheck distclean \ distclean-generic distclean-hdr distclean-libtool \ distclean-recursive distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-strip installcheck installcheck-am installdirs \ installdirs-am maintainer-clean maintainer-clean-generic \ maintainer-clean-recursive mostlyclean mostlyclean-generic \ mostlyclean-libtool mostlyclean-recursive pdf pdf-am ps ps-am \ tags tags-recursive uninstall uninstall-am uninstall-info-am .xml.html: sed "s/#FIGTYPE#/.png/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp ${JADE} -V nochunks -t sgml -d $(HTML_DSL) $(XML_DCL) $*.tmp > $@ rm -f $*.tmp .xml.rtf: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp cd `dirname $<` && $(JADE) -o `basename $*`.rtf -t rtf -d $(TEX_DSL) $(XML_DCL) `basename $*`.tmp rm -f $*.tmp .xml.ps: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || \ ( echo Check `dirname $<`/`basename $*`.log for errors && false) rm -f $*.log cd `dirname $<` && $(DVIPS) -q -o `basename $*`.ps `basename $*`.dvi rm -f $*.dvi $*.tex $*.aux .xml.pdf: sed "s/#FIGTYPE#/.png/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true rm -f $*.log $*.dvi cd `dirname $<` && $(PDFJADETEX) `basename $*`.tex > /dev/null || true test -r $*.pdf || false rm -f $*.log $*.tex $*.aux $*.out .fig.png: $(FIG2DEV) -Lpng $< $@ .fig.ps: $(FIG2DEV) -Lps $< $@ .png.ps: $(CONVERT) $< $@ rpm: clean @echo "Preparing to build the RPM files" mkdir -p "$(rpmtemp)/${RPMPKG}" cp -R * "$(rpmtemp)/${RPMPKG}" tar -C "$(rpmtemp)" -c ${RPMPKG} -zf ${RPMPKG}.tar.gz rm -rf "$(rpmtemp)/${RPMPKG}" if [ -d $(rpmtemp) ]; then rmdir "$(rpmtemp)"; fi @echo "Building the RPM" rpmbuild -ta ${RPMPKG}.tar.gz rm -f ${RPMPKG}.tar.gz @echo "**********************************************************************" @echo "* Success!" @echo "* Your files are located under $(shell rpm --eval '%_rpmdir')" @echo "* The Kannel Group " @echo "**********************************************************************" @echo "Thank you for using Kannel." docs: figs ps $(docs) no-docs: figs: $(figs) ps: $(ps) pp: $(pres) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gateway-1.4.5/addons/opensmppbox/aclocal.m40000644000175000017500000100072511563321320017347 0ustar toljtolj# generated automatically by aclocal 1.9.6 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # serial 48 AC_PROG_LIBTOOL # AC_PROVIDE_IFELSE(MACRO-NAME, IF-PROVIDED, IF-NOT-PROVIDED) # ----------------------------------------------------------- # If this macro is not defined by Autoconf, define it here. m4_ifdef([AC_PROVIDE_IFELSE], [], [m4_define([AC_PROVIDE_IFELSE], [m4_ifdef([AC_PROVIDE_$1], [$2], [$3])])]) # AC_PROG_LIBTOOL # --------------- AC_DEFUN([AC_PROG_LIBTOOL], [AC_REQUIRE([_AC_PROG_LIBTOOL])dnl dnl If AC_PROG_CXX has already been expanded, run AC_LIBTOOL_CXX dnl immediately, otherwise, hook it in at the end of AC_PROG_CXX. AC_PROVIDE_IFELSE([AC_PROG_CXX], [AC_LIBTOOL_CXX], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[AC_LIBTOOL_CXX ])]) dnl And a similar setup for Fortran 77 support AC_PROVIDE_IFELSE([AC_PROG_F77], [AC_LIBTOOL_F77], [define([AC_PROG_F77], defn([AC_PROG_F77])[AC_LIBTOOL_F77 ])]) dnl Quote A][M_PROG_GCJ so that aclocal doesn't bring it in needlessly. dnl If either AC_PROG_GCJ or A][M_PROG_GCJ have already been expanded, run dnl AC_LIBTOOL_GCJ immediately, otherwise, hook it in at the end of both. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [AC_LIBTOOL_GCJ], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [AC_LIBTOOL_GCJ], [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ], [AC_LIBTOOL_GCJ], [ifdef([AC_PROG_GCJ], [define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[AC_LIBTOOL_GCJ])]) ifdef([A][M_PROG_GCJ], [define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[AC_LIBTOOL_GCJ])]) ifdef([LT_AC_PROG_GCJ], [define([LT_AC_PROG_GCJ], defn([LT_AC_PROG_GCJ])[AC_LIBTOOL_GCJ])])])]) ])])# AC_PROG_LIBTOOL # _AC_PROG_LIBTOOL # ---------------- AC_DEFUN([_AC_PROG_LIBTOOL], [AC_REQUIRE([AC_LIBTOOL_SETUP])dnl AC_BEFORE([$0],[AC_LIBTOOL_CXX])dnl AC_BEFORE([$0],[AC_LIBTOOL_F77])dnl AC_BEFORE([$0],[AC_LIBTOOL_GCJ])dnl # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl # Prevent multiple expansion define([AC_PROG_LIBTOOL], []) ])# _AC_PROG_LIBTOOL # AC_LIBTOOL_SETUP # ---------------- AC_DEFUN([AC_LIBTOOL_SETUP], [AC_PREREQ(2.50)dnl AC_REQUIRE([AC_ENABLE_SHARED])dnl AC_REQUIRE([AC_ENABLE_STATIC])dnl AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_LD])dnl AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl AC_REQUIRE([AC_PROG_NM])dnl AC_REQUIRE([AC_PROG_LN_S])dnl AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl # Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! AC_REQUIRE([AC_OBJEXT])dnl AC_REQUIRE([AC_EXEEXT])dnl dnl AC_LIBTOOL_SYS_MAX_CMD_LEN AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE AC_LIBTOOL_OBJDIR AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl _LT_AC_PROG_ECHO_BACKSLASH case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e 1s/^X//' [sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g'] # Same as above, but do not quote variable references. [double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g'] # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Constants: rm="rm -f" # Global variables: default_ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a ltmain="$ac_aux_dir/ltmain.sh" ofile="$default_ofile" with_gnu_ld="$lt_cv_prog_gnu_ld" AC_CHECK_TOOL(AR, ar, false) AC_CHECK_TOOL(RANLIB, ranlib, :) AC_CHECK_TOOL(STRIP, strip, :) old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru test -z "$AS" && AS=as test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$LD" && LD=ld test -z "$LN_S" && LN_S="ln -s" test -z "$MAGIC_CMD" && MAGIC_CMD=file test -z "$NM" && NM=nm test -z "$SED" && SED=sed test -z "$OBJDUMP" && OBJDUMP=objdump test -z "$RANLIB" && RANLIB=: test -z "$STRIP" && STRIP=: test -z "$ac_objext" && ac_objext=o # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then AC_PATH_MAGIC fi ;; esac AC_PROVIDE_IFELSE([AC_LIBTOOL_DLOPEN], enable_dlopen=yes, enable_dlopen=no) AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], enable_win32_dll=yes, enable_win32_dll=no) AC_ARG_ENABLE([libtool-lock], [AC_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes AC_ARG_WITH([pic], [AC_HELP_STRING([--with-pic], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [pic_mode="$withval"], [pic_mode=default]) test -z "$pic_mode" && pic_mode=default # Use C for the default configuration in the libtool script tagname= AC_LIBTOOL_LANG_C_CONFIG _LT_AC_TAGCONFIG ])# AC_LIBTOOL_SETUP # _LT_AC_SYS_COMPILER # ------------------- AC_DEFUN([_LT_AC_SYS_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_AC_SYS_COMPILER # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. AC_DEFUN([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` ]) # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. AC_DEFUN([_LT_COMPILER_BOILERPLATE], [ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $rm conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. AC_DEFUN([_LT_LINKER_BOILERPLATE], [ac_outfile=conftest.$ac_objext printf "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $rm conftest* ])# _LT_LINKER_BOILERPLATE # _LT_AC_SYS_LIBPATH_AIX # ---------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX], [AC_LINK_IFELSE(AC_LANG_PROGRAM,[ aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi],[]) if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ])# _LT_AC_SYS_LIBPATH_AIX # _LT_AC_SHELL_INIT(ARG) # ---------------------- AC_DEFUN([_LT_AC_SHELL_INIT], [ifdef([AC_DIVERSION_NOTICE], [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], [AC_DIVERT_PUSH(NOTICE)]) $1 AC_DIVERT_POP ])# _LT_AC_SHELL_INIT # _LT_AC_PROG_ECHO_BACKSLASH # -------------------------- # Add some code to the start of the generated configure script which # will find an echo command which doesn't interpret backslashes. AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH], [_LT_AC_SHELL_INIT([ # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` ;; esac echo=${ECHO-echo} if test "X[$]1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X[$]1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then # Yippee, $echo works! : else # Restart under the correct shell. exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} fi if test "X[$]1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null 2>&1 && unset CDPATH if test -z "$ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if (echo_test_string=`eval $cmd`) 2>/dev/null && echo_test_string=`eval $cmd` && (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null then break fi done fi if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$echo" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. echo='print -r' elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} else # Try using printf. echo='printf %s\n' if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL echo="$CONFIG_SHELL [$]0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$CONFIG_SHELL [$]0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "[$]0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} else # Oops. We lost completely, so just stick with echo. echo=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. ECHO=$echo if test "X$ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" fi AC_SUBST(ECHO) ])])# _LT_AC_PROG_ECHO_BACKSLASH # _LT_AC_LOCK # ----------- AC_DEFUN([_LT_AC_LOCK], [AC_ARG_ENABLE([libtool-lock], [AC_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) LD="${LD-ld} -64" ;; esac ;; esac fi rm -rf conftest* ;; AC_PROVIDE_IFELSE([AC_LIBTOOL_WIN32_DLL], [*-*-cygwin* | *-*-mingw* | *-*-pw32*) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; ]) esac need_locks="$enable_libtool_lock" ])# _LT_AC_LOCK # AC_LIBTOOL_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [AC_REQUIRE([LT_AC_PROG_SED]) AC_CACHE_CHECK([$1], [$2], [$2=no ifelse([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $rm conftest* ]) if test x"[$]$2" = xyes; then ifelse([$5], , :, [$5]) else ifelse([$6], , :, [$6]) fi ])# AC_LIBTOOL_COMPILER_OPTION # AC_LIBTOOL_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ------------------------------------------------------------ # Check whether the given compiler option works AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then ifelse([$4], , :, [$4]) else ifelse([$5], , :, [$5]) fi ])# AC_LIBTOOL_LINKER_OPTION # AC_LIBTOOL_SYS_MAX_CMD_LEN # -------------------------- AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [# find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} while (test "X"`$SHELL [$]0 --fallback-echo "X$teststring" 2>/dev/null` \ = "XX$teststring") >/dev/null 2>&1 && new_result=`expr "X$teststring" : ".*" 2>&1` && lt_cv_sys_max_cmd_len=$new_result && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done teststring= # Add a significant safety factor because C++ compilers can tack on massive # amounts of additional arguments before passing them to the linker. # It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi ])# AC_LIBTOOL_SYS_MAX_CMD_LEN # _LT_AC_CHECK_DLFCN # ------------------ AC_DEFUN([_LT_AC_CHECK_DLFCN], [AC_CHECK_HEADERS(dlfcn.h)dnl ])# _LT_AC_CHECK_DLFCN # _LT_AC_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # --------------------------------------------------------------------- AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF], [AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); exit (status); }] EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_AC_TRY_DLOPEN_SELF # AC_LIBTOOL_DLOPEN_SELF # ---------------------- AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [AC_REQUIRE([_LT_AC_CHECK_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_AC_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_AC_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi ])# AC_LIBTOOL_DLOPEN_SELF # AC_LIBTOOL_PROG_CC_C_O([TAGNAME]) # --------------------------------- # Check to see if options -c and -o are simultaneously supported by compiler AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O], [AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* ]) ])# AC_LIBTOOL_PROG_CC_C_O # AC_LIBTOOL_SYS_HARD_LINK_LOCKS([TAGNAME]) # ----------------------------------------- # Check to see if we can do hard links to lock some files if needed AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_REQUIRE([_LT_AC_LOCK])dnl hard_links="nottested" if test "$_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi ])# AC_LIBTOOL_SYS_HARD_LINK_LOCKS # AC_LIBTOOL_OBJDIR # ----------------- AC_DEFUN([AC_LIBTOOL_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir ])# AC_LIBTOOL_OBJDIR # AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH([TAGNAME]) # ---------------------------------------------- # Check hardcoding attributes. AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_AC_TAGVAR(hardcode_action, $1)= if test -n "$_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)" || \ test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \ test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existant directories. if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_AC_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_AC_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_AC_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_AC_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_AC_TAGVAR(hardcode_action, $1)]) if test "$_LT_AC_TAGVAR(hardcode_action, $1)" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi ])# AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH # AC_LIBTOOL_SYS_LIB_STRIP # ------------------------ AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP], [striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi ])# AC_LIBTOOL_SYS_LIB_STRIP # AC_LIBTOOL_SYS_DYNAMIC_LINKER # ----------------------------- # PORTME Fill in your ld.so characteristics AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_MSG_CHECKING([dynamic linker characteristics]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | [grep ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[123]]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; freebsd*) # from 4.6 on shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix3*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' shlibpath_overrides_runpath=no else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' shlibpath_overrides_runpath=yes case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi ])# AC_LIBTOOL_SYS_DYNAMIC_LINKER # _LT_AC_TAGCONFIG # ---------------- AC_DEFUN([_LT_AC_TAGCONFIG], [AC_ARG_WITH([tags], [AC_HELP_STRING([--with-tags@<:@=TAGS@:>@], [include additional configurations @<:@automatic@:>@])], [tagnames="$withval"]) if test -f "$ltmain" && test -n "$tagnames"; then if test ! -f "${ofile}"; then AC_MSG_WARN([output file `$ofile' does not exist]) fi if test -z "$LTCC"; then eval "`$SHELL ${ofile} --config | grep '^LTCC='`" if test -z "$LTCC"; then AC_MSG_WARN([output file `$ofile' does not look like a libtool script]) else AC_MSG_WARN([using `LTCC=$LTCC', extracted from `$ofile']) fi fi if test -z "$LTCFLAGS"; then eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" fi # Extract list of available tagged configurations in $ofile. # Note that this assumes the entire list is on one line. available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for tagname in $tagnames; do IFS="$lt_save_ifs" # Check whether tagname contains only valid characters case `$echo "X$tagname" | $Xsed -e 's:[[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]]::g'` in "") ;; *) AC_MSG_ERROR([invalid tag name: $tagname]) ;; esac if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null then AC_MSG_ERROR([tag name \"$tagname\" already exists]) fi # Update the list of available tags. if test -n "$tagname"; then echo appending configuration tag \"$tagname\" to $ofile case $tagname in CXX) if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_LIBTOOL_LANG_CXX_CONFIG else tagname="" fi ;; F77) if test -n "$F77" && test "X$F77" != "Xno"; then AC_LIBTOOL_LANG_F77_CONFIG else tagname="" fi ;; GCJ) if test -n "$GCJ" && test "X$GCJ" != "Xno"; then AC_LIBTOOL_LANG_GCJ_CONFIG else tagname="" fi ;; RC) AC_LIBTOOL_LANG_RC_CONFIG ;; *) AC_MSG_ERROR([Unsupported tag name: $tagname]) ;; esac # Append the new tag name to the list of available tags. if test -n "$tagname" ; then available_tags="$available_tags $tagname" fi fi done IFS="$lt_save_ifs" # Now substitute the updated list of available tags. if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then mv "${ofile}T" "$ofile" chmod +x "$ofile" else rm -f "${ofile}T" AC_MSG_ERROR([unable to update list of available tagged configurations.]) fi fi ])# _LT_AC_TAGCONFIG # AC_LIBTOOL_DLOPEN # ----------------- # enable checks for dlopen support AC_DEFUN([AC_LIBTOOL_DLOPEN], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP]) ])# AC_LIBTOOL_DLOPEN # AC_LIBTOOL_WIN32_DLL # -------------------- # declare package support for building win32 DLLs AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_BEFORE([$0], [AC_LIBTOOL_SETUP]) ])# AC_LIBTOOL_WIN32_DLL # AC_ENABLE_SHARED([DEFAULT]) # --------------------------- # implement the --enable-shared flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_SHARED], [define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([shared], [AC_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]AC_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]AC_ENABLE_SHARED_DEFAULT) ])# AC_ENABLE_SHARED # AC_DISABLE_SHARED # ----------------- # set the default shared flag to --disable-shared AC_DEFUN([AC_DISABLE_SHARED], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_SHARED(no) ])# AC_DISABLE_SHARED # AC_ENABLE_STATIC([DEFAULT]) # --------------------------- # implement the --enable-static flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_STATIC], [define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([static], [AC_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]AC_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]AC_ENABLE_STATIC_DEFAULT) ])# AC_ENABLE_STATIC # AC_DISABLE_STATIC # ----------------- # set the default static flag to --disable-static AC_DEFUN([AC_DISABLE_STATIC], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_STATIC(no) ])# AC_DISABLE_STATIC # AC_ENABLE_FAST_INSTALL([DEFAULT]) # --------------------------------- # implement the --enable-fast-install flag # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. AC_DEFUN([AC_ENABLE_FAST_INSTALL], [define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE([fast-install], [AC_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]AC_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]AC_ENABLE_FAST_INSTALL_DEFAULT) ])# AC_ENABLE_FAST_INSTALL # AC_DISABLE_FAST_INSTALL # ----------------------- # set the default to --disable-fast-install AC_DEFUN([AC_DISABLE_FAST_INSTALL], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_ENABLE_FAST_INSTALL(no) ])# AC_DISABLE_FAST_INSTALL # AC_LIBTOOL_PICMODE([MODE]) # -------------------------- # implement the --with-pic flag # MODE is either `yes' or `no'. If omitted, it defaults to `both'. AC_DEFUN([AC_LIBTOOL_PICMODE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl pic_mode=ifelse($#,1,$1,default) ])# AC_LIBTOOL_PICMODE # AC_PROG_EGREP # ------------- # This is predefined starting with Autoconf 2.54, so this conditional # definition can be removed once we require Autoconf 2.54 or later. m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP], [AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep], [if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi]) EGREP=$ac_cv_prog_egrep AC_SUBST([EGREP]) ])]) # AC_PATH_TOOL_PREFIX # ------------------- # find a file program which can recognise shared library AC_DEFUN([AC_PATH_TOOL_PREFIX], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="ifelse([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi ])# AC_PATH_TOOL_PREFIX # AC_PATH_MAGIC # ------------- # find a file program which can recognise a shared library AC_DEFUN([AC_PATH_MAGIC], [AC_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then AC_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# AC_PATH_MAGIC # AC_PROG_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([AC_PROG_LD], [AC_ARG_WITH([gnu-ld], [AC_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no]) AC_REQUIRE([LT_AC_PROG_SED])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix3*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux*) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; nto-qnx*) lt_cv_deplibs_check_method=unknown ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown ])# AC_DEPLIBS_CHECK_METHOD # AC_PROG_NM # ---------- # find the pathname to a BSD-compatible name lister AC_DEFUN([AC_PROG_NM], [AC_CACHE_CHECK([for BSD-compatible nm], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm fi]) NM="$lt_cv_path_NM" ])# AC_PROG_NM # AC_CHECK_LIBM # ------------- # check for math library AC_DEFUN([AC_CHECK_LIBM], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac ])# AC_CHECK_LIBM # AC_LIBLTDL_CONVENIENCE([DIRECTORY]) # ----------------------------------- # sets LIBLTDL to the link flags for the libltdl convenience library and # LTDLINCL to the include flags for the libltdl header and adds # --enable-ltdl-convenience to the configure arguments. Note that # AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, # it is assumed to be `libltdl'. LIBLTDL will be prefixed with # '${top_builddir}/' and LTDLINCL will be prefixed with '${top_srcdir}/' # (note the single quotes!). If your package is not flat and you're not # using automake, define top_builddir and top_srcdir appropriately in # the Makefiles. AC_DEFUN([AC_LIBLTDL_CONVENIENCE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl case $enable_ltdl_convenience in no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; "") enable_ltdl_convenience=yes ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" ])# AC_LIBLTDL_CONVENIENCE # AC_LIBLTDL_INSTALLABLE([DIRECTORY]) # ----------------------------------- # sets LIBLTDL to the link flags for the libltdl installable library and # LTDLINCL to the include flags for the libltdl header and adds # --enable-ltdl-install to the configure arguments. Note that # AC_CONFIG_SUBDIRS is not called here. If DIRECTORY is not provided, # and an installed libltdl is not found, it is assumed to be `libltdl'. # LIBLTDL will be prefixed with '${top_builddir}/'# and LTDLINCL with # '${top_srcdir}/' (note the single quotes!). If your package is not # flat and you're not using automake, define top_builddir and top_srcdir # appropriately in the Makefiles. # In the future, this macro may have to be called after AC_PROG_LIBTOOL. AC_DEFUN([AC_LIBLTDL_INSTALLABLE], [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl AC_CHECK_LIB(ltdl, lt_dlinit, [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], [if test x"$enable_ltdl_install" = xno; then AC_MSG_WARN([libltdl not installed, but installation disabled]) else enable_ltdl_install=yes fi ]) if test x"$enable_ltdl_install" = x"yes"; then ac_configure_args="$ac_configure_args --enable-ltdl-install" LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) else ac_configure_args="$ac_configure_args --enable-ltdl-install=no" LIBLTDL="-lltdl" LTDLINCL= fi # For backwards non-gettext consistent compatibility... INCLTDL="$LTDLINCL" ])# AC_LIBLTDL_INSTALLABLE # AC_LIBTOOL_CXX # -------------- # enable support for C++ libraries AC_DEFUN([AC_LIBTOOL_CXX], [AC_REQUIRE([_LT_AC_LANG_CXX]) ])# AC_LIBTOOL_CXX # _LT_AC_LANG_CXX # --------------- AC_DEFUN([_LT_AC_LANG_CXX], [AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([_LT_AC_PROG_CXXCPP]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}CXX]) ])# _LT_AC_LANG_CXX # _LT_AC_PROG_CXXCPP # ------------------ AC_DEFUN([_LT_AC_PROG_CXXCPP], [ AC_REQUIRE([AC_PROG_CXX]) if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP fi ])# _LT_AC_PROG_CXXCPP # AC_LIBTOOL_F77 # -------------- # enable support for Fortran 77 libraries AC_DEFUN([AC_LIBTOOL_F77], [AC_REQUIRE([_LT_AC_LANG_F77]) ])# AC_LIBTOOL_F77 # _LT_AC_LANG_F77 # --------------- AC_DEFUN([_LT_AC_LANG_F77], [AC_REQUIRE([AC_PROG_F77]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}F77]) ])# _LT_AC_LANG_F77 # AC_LIBTOOL_GCJ # -------------- # enable support for GCJ libraries AC_DEFUN([AC_LIBTOOL_GCJ], [AC_REQUIRE([_LT_AC_LANG_GCJ]) ])# AC_LIBTOOL_GCJ # _LT_AC_LANG_GCJ # --------------- AC_DEFUN([_LT_AC_LANG_GCJ], [AC_PROVIDE_IFELSE([AC_PROG_GCJ],[], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],[], [AC_PROVIDE_IFELSE([LT_AC_PROG_GCJ],[], [ifdef([AC_PROG_GCJ],[AC_REQUIRE([AC_PROG_GCJ])], [ifdef([A][M_PROG_GCJ],[AC_REQUIRE([A][M_PROG_GCJ])], [AC_REQUIRE([A][C_PROG_GCJ_OR_A][M_PROG_GCJ])])])])])]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}GCJ]) ])# _LT_AC_LANG_GCJ # AC_LIBTOOL_RC # ------------- # enable support for Windows resource files AC_DEFUN([AC_LIBTOOL_RC], [AC_REQUIRE([LT_AC_PROG_RC]) _LT_AC_SHELL_INIT([tagnames=${tagnames+${tagnames},}RC]) ])# AC_LIBTOOL_RC # AC_LIBTOOL_LANG_C_CONFIG # ------------------------ # Ensure that the configuration vars for the C compiler are # suitably defined. Those variables are subsequently used by # AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG], [_LT_AC_LANG_C_CONFIG]) AC_DEFUN([_LT_AC_LANG_C_CONFIG], [lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_AC_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}\n' _LT_AC_SYS_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE AC_LIBTOOL_PROG_COMPILER_NO_RTTI($1) AC_LIBTOOL_PROG_COMPILER_PIC($1) AC_LIBTOOL_PROG_CC_C_O($1) AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) AC_LIBTOOL_PROG_LD_SHLIBS($1) AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) AC_LIBTOOL_SYS_LIB_STRIP AC_LIBTOOL_DLOPEN_SELF # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4* | aix5*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) AC_LIBTOOL_CONFIG($1) AC_LANG_POP CC="$lt_save_CC" ])# AC_LIBTOOL_LANG_C_CONFIG # AC_LIBTOOL_LANG_CXX_CONFIG # -------------------------- # Ensure that the configuration vars for the C compiler are # suitably defined. Those variables are subsequently used by # AC_LIBTOOL_CONFIG to write the compiler configuration to `libtool'. AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG], [_LT_AC_LANG_CXX_CONFIG(CXX)]) AC_DEFUN([_LT_AC_LANG_CXX_CONFIG], [AC_LANG_PUSH(C++) AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([_LT_AC_PROG_CXXCPP]) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(allow_undefined_flag, $1)= _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(archive_expsym_cmds, $1)= _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= _LT_AC_TAGVAR(hardcode_minus_L, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(hardcode_automatic, $1)=no _LT_AC_TAGVAR(module_cmds, $1)= _LT_AC_TAGVAR(module_expsym_cmds, $1)= _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown _LT_AC_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_AC_TAGVAR(no_undefined_flag, $1)= _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Dependencies to place before and after the object being linked: _LT_AC_TAGVAR(predep_objects, $1)= _LT_AC_TAGVAR(postdep_objects, $1)= _LT_AC_TAGVAR(predeps, $1)= _LT_AC_TAGVAR(postdeps, $1)= _LT_AC_TAGVAR(compiler_lib_search_path, $1)= # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_AC_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_AC_SYS_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC _LT_AC_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) # We don't want -fno-exception wen compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration AC_PROG_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ grep 'no-whole-archive' > /dev/null; then _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_AC_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_AC_TAGVAR(archive_cmds, $1)='' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=yes else # We have old collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_AC_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; darwin* | rhapsody*) case $host_os in rhapsody* | darwin1.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' ;; esac fi ;; esac _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes if test "$GXX" = yes ; then lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds if test "X$lt_int_apple_cc_single_mod" = Xyes ; then _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else case $cc_basename in xlc*) output_verbose_link_cmd='echo' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' ;; *) _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac fi ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd[[12]]*) # C++ shared libraries reported to be fairly broken before switch to ELF _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | kfreebsd*-gnu | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_AC_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; hpux9*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[[-]]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' ;; *) _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix3*) _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' fi fi _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; linux*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc*) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC*) # Portland Group C++ compiler _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; openbsd2*) # C++ shared libraries are fairly broken _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd='echo' ;; osf3*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; cxx*) _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_AC_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; cxx*) _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ $rm $lib.exp' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_AC_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_AC_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The C++ compiler is used as linker so we must use $wl # flag to pass the commands to the underlying system # linker. We must also pass each convience library through # to the system linker between allextract/defaultextract. # The C++ compiler will combine linker options so we # cannot just pass the convience library names through # without $wl. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; esac _LT_AC_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_AC_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | grep -v '^2\.7' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. # So that behaviour is only enabled if SCOABSPATH is set to a # non-empty value in the environment. Most likely only useful for # creating official distributions of packages. # This is a hack until libtool officially supports absolute path # names for shared libraries. _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_AC_TAGVAR(GCC, $1)="$GXX" _LT_AC_TAGVAR(LD, $1)="$LD" AC_LIBTOOL_POSTDEP_PREDEP($1) AC_LIBTOOL_PROG_COMPILER_PIC($1) AC_LIBTOOL_PROG_CC_C_O($1) AC_LIBTOOL_SYS_HARD_LINK_LOCKS($1) AC_LIBTOOL_PROG_LD_SHLIBS($1) AC_LIBTOOL_SYS_DYNAMIC_LINKER($1) AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH($1) AC_LIBTOOL_CONFIG($1) AC_LANG_POP CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ldcxx=$with_gnu_ld with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld ])# AC_LIBTOOL_LANG_CXX_CONFIG # AC_LIBTOOL_POSTDEP_PREDEP([TAGNAME]) # ------------------------------------ # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP],[ dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... ifelse([$1],[],[cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <> "$cfgfile" ifelse([$1], [], [#! $SHELL # `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. # # This file is part of GNU Libtool: # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="$SED -e 1s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # The names of the tagged configurations supported by this script. available_tags= # ### BEGIN LIBTOOL CONFIG], [# ### BEGIN LIBTOOL TAG CONFIG: $tagname]) # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$_LT_AC_TAGVAR(archive_cmds_need_lc, $1) # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$_LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1) # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # LTCC compiler flags. LTCFLAGS=$lt_LTCFLAGS # A language-specific compiler. CC=$lt_[]_LT_AC_TAGVAR(compiler, $1) # Is the compiler the GNU C compiler? with_gcc=$_LT_AC_TAGVAR(GCC, $1) gcc_dir=\`gcc -print-file-name=. | $SED 's,/\.$,,'\` gcc_ver=\`gcc -dumpversion\` # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_[]_LT_AC_TAGVAR(LD, $1) # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_[]_LT_AC_TAGVAR(lt_cv_prog_compiler_c_o, $1) # Must we lock files when doing compilation? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_static, $1) # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_[]_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_[]_LT_AC_TAGVAR(export_dynamic_flag_spec, $1) # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_[]_LT_AC_TAGVAR(whole_archive_flag_spec, $1) # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_[]_LT_AC_TAGVAR(thread_safe_flag_spec, $1) # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_cmds, $1) old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_new_cmds, $1) # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_[]_LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1) # Commands used to build and install a shared archive. archive_cmds=$lt_[]_LT_AC_TAGVAR(archive_cmds, $1) archive_expsym_cmds=$lt_[]_LT_AC_TAGVAR(archive_expsym_cmds, $1) postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_[]_LT_AC_TAGVAR(module_cmds, $1) module_expsym_cmds=$lt_[]_LT_AC_TAGVAR(module_expsym_cmds, $1) # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=\`echo $lt_[]_LT_AC_TAGVAR(predep_objects, $1) | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=\`echo $lt_[]_LT_AC_TAGVAR(postdep_objects, $1) | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_[]_LT_AC_TAGVAR(predeps, $1) # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_[]_LT_AC_TAGVAR(postdeps, $1) # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=\`echo $lt_[]_LT_AC_TAGVAR(compiler_lib_search_path, $1) | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_[]_LT_AC_TAGVAR(allow_undefined_flag, $1) # Flag that forces no undefined symbols. no_undefined_flag=$lt_[]_LT_AC_TAGVAR(no_undefined_flag, $1) # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$_LT_AC_TAGVAR(hardcode_action, $1) # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1) # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_[]_LT_AC_TAGVAR(hardcode_libdir_separator, $1) # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$_LT_AC_TAGVAR(hardcode_direct, $1) # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$_LT_AC_TAGVAR(hardcode_minus_L, $1) # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$_LT_AC_TAGVAR(hardcode_shlibpath_var, $1) # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$_LT_AC_TAGVAR(hardcode_automatic, $1) # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$_LT_AC_TAGVAR(link_all_deplibs, $1) # Compile-time system search path for libraries sys_lib_search_path_spec=\`echo $lt_sys_lib_search_path_spec | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$_LT_AC_TAGVAR(fix_srcfile_path, $1)" # Set to yes if exported symbols are required. always_export_symbols=$_LT_AC_TAGVAR(always_export_symbols, $1) # The commands to list exported symbols. export_symbols_cmds=$lt_[]_LT_AC_TAGVAR(export_symbols_cmds, $1) # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_[]_LT_AC_TAGVAR(exclude_expsyms, $1) # Symbols that must always be exported. include_expsyms=$lt_[]_LT_AC_TAGVAR(include_expsyms, $1) ifelse([$1],[], [# ### END LIBTOOL CONFIG], [# ### END LIBTOOL TAG CONFIG: $tagname]) __EOF__ ifelse([$1],[], [ case $host_os in aix3*) cat <<\EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi EOF ;; esac # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || \ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ]) else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ])# AC_LIBTOOL_CONFIG # AC_LIBTOOL_PROG_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------------------- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_REQUIRE([_LT_AC_SYS_COMPILER])dnl _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' AC_LIBTOOL_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi ])# AC_LIBTOOL_PROG_COMPILER_NO_RTTI # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE # --------------------------------- AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_REQUIRE([AC_CANONICAL_HOST]) AC_REQUIRE([AC_PROG_NM]) AC_REQUIRE([AC_OBJEXT]) # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Transform an extracted symbol line into a proper C declaration lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32*) symcode='[[ABCDGISTW]]' ;; hpux*) # Its linker distinguishes data from code symbols if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" ;; linux*) if test "$host_cpu" = ia64; then symcode='[[ABCDGIRSTW]]' lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Try without a prefix undercore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext < $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if grep ' nm_test_var$' "$nlist" >/dev/null; then if grep ' nm_test_func$' "$nlist" >/dev/null; then cat < conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' cat <> conftest.$ac_ext #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[[]] = { EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext cat <<\EOF >> conftest.$ac_ext {0, (lt_ptr_t) 0} }; #ifdef __cplusplus } #endif EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_AC_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -f conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi ]) # AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE # AC_LIBTOOL_PROG_COMPILER_PIC([TAGNAME]) # --------------------------------------- AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC], [_LT_AC_TAGVAR(lt_prog_compiler_wl, $1)= _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)= AC_MSG_CHECKING([for $compiler option to produce PIC]) ifelse([$1],[CXX],[ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | os2* | pw32*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= ;; interix3*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix4* | aix5*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_AC_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; darwin*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files case $cc_basename in xlc*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; esac ;; dgux*) case $cc_basename in ec++*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | kfreebsd*-gnu | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; icpc* | ecpc*) # Intel C++ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC*) # Portland Group C++ compiler. _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; vxworks*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; interix3*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; darwin*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files case $cc_basename in xlc*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-qnocommon' _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; esac ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; newsos6) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; linux*) case $cc_basename in icc* | ecc*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_AC_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_AC_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) AC_MSG_RESULT([$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)]) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)"; then AC_LIBTOOL_COMPILER_OPTION([if $compiler PIC flag $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) works], _LT_AC_TAGVAR(lt_prog_compiler_pic_works, $1), [$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= _LT_AC_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_AC_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1)ifelse([$1],[],[ -DPIC],[ifelse([$1],[CXX],[ -DPIC],[])])" ;; esac # # Check to make sure the static flag actually works. # wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_AC_TAGVAR(lt_prog_compiler_static, $1)\" AC_LIBTOOL_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_AC_TAGVAR(lt_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_AC_TAGVAR(lt_prog_compiler_static, $1)=]) ]) # AC_LIBTOOL_PROG_LD_SHLIBS([TAGNAME]) # ------------------------------------ # See if the linker supports building shared libraries. AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) ifelse([$1],[CXX],[ _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix4* | aix5*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' else _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_AC_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw*) _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([[^ ]]*\) [[^ ]]*/\1 DATA/;/^I /d;/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' ;; *) _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ],[ runpath_var= _LT_AC_TAGVAR(allow_undefined_flag, $1)= _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_AC_TAGVAR(archive_cmds, $1)= _LT_AC_TAGVAR(archive_expsym_cmds, $1)= _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)= _LT_AC_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= _LT_AC_TAGVAR(thread_safe_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_minus_L, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(link_all_deplibs, $1)=unknown _LT_AC_TAGVAR(hardcode_automatic, $1)=no _LT_AC_TAGVAR(module_cmds, $1)= _LT_AC_TAGVAR(module_expsym_cmds, $1)= _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_AC_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_AC_TAGVAR(exclude_expsyms, $1)="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= # Just being paranoid about ensuring that cc_basename is set. _LT_CC_BASENAME([$compiler]) case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac _LT_AC_TAGVAR(ld_shlibs, $1)=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then _LT_AC_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>/dev/null` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_AC_TAGVAR(ld_shlibs, $1)=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_AC_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=no _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]] /s/.* \([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_AC_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; interix3*) _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then tmp_addflag= case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; esac _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test $supports_anon_versioning = yes; then _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ $echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then _LT_AC_TAGVAR(ld_shlibs, $1)=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_AC_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_AC_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)= _LT_AC_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(always_export_symbols, $1)=yes _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' else _LT_AC_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\[$]2 == "T") || (\[$]2 == "D") || (\[$]2 == "B")) && ([substr](\[$]3,1,1) != ".")) { print \[$]3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_AC_TAGVAR(archive_cmds, $1)='' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=yes else # We have old collect2 _LT_AC_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_AC_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_AC_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. _LT_AC_SYS_LIBPATH_AIX _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_AC_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='$convenience' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_AC_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes # see comment about different semantics on the GNU ld section _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; bsdi[[45]]*) _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_AC_TAGVAR(old_archive_cmds, $1)='lib /OUT:$oldlib$oldobjs$old_deplibs' _LT_AC_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' _LT_AC_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; darwin* | rhapsody*) case $host_os in rhapsody* | darwin1.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[[012]]) _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-undefined ${wl}dynamic_lookup' ;; esac fi ;; esac _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_automatic, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes if test "$GCC" = yes ; then output_verbose_link_cmd='echo' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else case $cc_basename in xlc*) output_verbose_link_cmd='echo' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' _LT_AC_TAGVAR(module_cmds, $1)='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds _LT_AC_TAGVAR(archive_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' _LT_AC_TAGVAR(module_expsym_cmds, $1)='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' ;; *) _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac fi ;; dgux*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; freebsd1*) _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu | dragonfly*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; openbsd*) _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi ;; os2*) _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_AC_TAGVAR(archive_cmds, $1)='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_AC_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_AC_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_AC_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_AC_TAGVAR(archive_cmds, $1)='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_AC_TAGVAR(no_undefined_flag, $1)=' -z text' if test "$GCC" = yes; then wlarc='${wl}' _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else wlarc='' _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine linker options so we # cannot just pass the convience library names through # without $wl, iff we do not link with $LD. # Luckily, gcc supports the same syntax we need for Sun Studio. # Supported since Solaris 2.6 (maybe 2.5.1?) case $wlarc in '') _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; *) _LT_AC_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; esac ;; esac _LT_AC_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_AC_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_direct, $1)=yes _LT_AC_TAGVAR(hardcode_minus_L, $1)=yes _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_AC_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_AC_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7*) _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_AC_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_AC_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' _LT_AC_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_AC_TAGVAR(link_all_deplibs, $1)=yes _LT_AC_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_AC_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_AC_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_AC_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_AC_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_AC_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_AC_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_AC_TAGVAR(ld_shlibs, $1)=no ;; esac fi ]) AC_MSG_RESULT([$_LT_AC_TAGVAR(ld_shlibs, $1)]) test "$_LT_AC_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no # # Do we need to explicitly link libc? # case "x$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_AC_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_MSG_CHECKING([whether -lc should be explicitly linked in]) $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_AC_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_AC_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_AC_TAGVAR(allow_undefined_flag, $1) _LT_AC_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_AC_TAGVAR(archive_cmds, $1) 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) then _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=no else _LT_AC_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_AC_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* AC_MSG_RESULT([$_LT_AC_TAGVAR(archive_cmds_need_lc, $1)]) ;; esac fi ;; esac ])# AC_LIBTOOL_PROG_LD_SHLIBS # _LT_AC_FILE_LTDLL_C # ------------------- # Be careful that the start marker always follows a newline. AC_DEFUN([_LT_AC_FILE_LTDLL_C], [ # /* ltdll.c starts here */ # #define WIN32_LEAN_AND_MEAN # #include # #undef WIN32_LEAN_AND_MEAN # #include # # #ifndef __CYGWIN__ # # ifdef __CYGWIN32__ # # define __CYGWIN__ __CYGWIN32__ # # endif # #endif # # #ifdef __cplusplus # extern "C" { # #endif # BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); # #ifdef __cplusplus # } # #endif # # #ifdef __CYGWIN__ # #include # DECLARE_CYGWIN_DLL( DllMain ); # #endif # HINSTANCE __hDllInstance_base; # # BOOL APIENTRY # DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) # { # __hDllInstance_base = hInst; # return TRUE; # } # /* ltdll.c ends here */ ])# _LT_AC_FILE_LTDLL_C # _LT_AC_TAGVAR(VARNAME, [TAGNAME]) # --------------------------------- AC_DEFUN([_LT_AC_TAGVAR], [ifelse([$2], [], [$1], [$1_$2])]) # old names AC_DEFUN([AM_PROG_LIBTOOL], [AC_PROG_LIBTOOL]) AC_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AC_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AC_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) AC_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) AC_DEFUN([AM_PROG_LD], [AC_PROG_LD]) AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) # This is just to silence aclocal about the macro not being used ifelse([AC_DISABLE_FAST_INSTALL]) AC_DEFUN([LT_AC_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj, no) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS) ]) AC_DEFUN([LT_AC_PROG_RC], [AC_CHECK_TOOL(RC, windres, no) ]) # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # # LT_AC_PROG_SED # -------------- # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. AC_DEFUN([LT_AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ]) # Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION so it can be traced. # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.9.6])]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 7 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE]) AC_SUBST([$1_FALSE]) if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 8 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf case $depmode in nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; none) break ;; esac # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. if depmode=$depmode \ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH]) ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 3 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [for mf in $CONFIG_FILES; do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # So let's grep whole file. if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 12 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.58])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl # test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AM_PROG_INSTALL_SH AM_PROG_INSTALL_STRIP AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl ]) ]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $1 | $1:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl install_sh=${install_sh-"$am_aux_dir/install-sh"} AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 AC_DEFUN([AM_MAINTAINER_MODE], [AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode is disabled by default AC_ARG_ENABLE(maintainer-mode, [ --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer], USE_MAINTAINER_MODE=$enableval, USE_MAINTAINER_MODE=no) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST(MAINT)dnl ] ) AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo done .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # We grep out `Entering directory' and `Leaving directory' # messages which can occur if `w' ends up in MAKEFLAGS. # In particular we don't look at `^make:' because GNU make might # be invoked under some other name (usually "gmake"), in which # case it prints its new name instead of `make'. if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then am__include=include am__quote= _am_result=GNU fi # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then am__include=.include am__quote="\"" _am_result=BSD fi fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_MKDIR_P # --------------- # Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. # # Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories # created by `make install' are always world readable, even if the # installer happens to have an overly restrictive umask (e.g. 077). # This was a mistake. There are at least two reasons why we must not # use `-m 0755': # - it causes special bits like SGID to be ignored, # - it may be too restrictive (some setups expect 775 directories). # # Do not use -m 0755 and let people choose whatever they expect by # setting umask. # # We cannot accept any implementation of `mkdir' that recognizes `-p'. # Some implementations (such as Solaris 8's) are not thread-safe: if a # parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' # concurrently, both version can detect that a/ is missing, but only # one can create it and the other will error out. Consequently we # restrict ourselves to GNU make (using the --version option ensures # this.) AC_DEFUN([AM_PROG_MKDIR_P], [if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then # We used to keeping the `.' as first argument, in order to # allow $(mkdir_p) to be used without argument. As in # $(mkdir_p) $(somedir) # where $(somedir) is conditionally defined. However this is wrong # for two reasons: # 1. if the package is installed by a user who cannot write `.' # make install will fail, # 2. the above comment should most certainly read # $(mkdir_p) $(DESTDIR)$(somedir) # so it does not work when $(somedir) is undefined and # $(DESTDIR) is not. # To support the latter case, we have to write # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), # so the `.' trick is pointless. mkdir_p='mkdir -p --' else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. for d in ./-p ./--version; do test -d $d && rmdir $d done # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. if test -f "$ac_aux_dir/mkinstalldirs"; then mkdir_p='$(mkinstalldirs)' else mkdir_p='$(install_sh) -d' fi fi AC_SUBST([mkdir_p])]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # ------------------------------ # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. AM_MISSING_PROG([AMTAR], [tar]) m4_if([$1], [v7], [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([acinclude.m4]) gateway-1.4.5/addons/opensmppbox/configure0000755000175000017500000261231312327711130017422 0ustar toljtolj#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for opensmppbox svn. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and devel@kannel.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} case X$ECHO in X*--fallback-echo) # Remove one level of quotation (which was required for Make). ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` ;; esac echo=${ECHO-echo} if test "X$1" = X--no-reexec; then # Discard the --no-reexec flag, and continue. shift elif test "X$1" = X--fallback-echo; then # Avoid inline document here, it may be left over : elif test "X`($echo '\t') 2>/dev/null`" = 'X\t' ; then # Yippee, $echo works! : else # Restart under the correct shell. exec $SHELL "$0" --no-reexec ${1+"$@"} fi if test "X$1" = X--fallback-echo; then # used as fallback echo shift cat </dev/null 2>&1 && unset CDPATH if test -z "$ECHO"; then if test "X${echo_test_string+set}" != Xset; then # find a string as large as possible, as long as the shell can cope with it for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if (echo_test_string=`eval $cmd`) 2>/dev/null && echo_test_string=`eval $cmd` && (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null then break fi done fi if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then : else # The Solaris, AIX, and Digital Unix default echo programs unquote # backslashes. This makes it impossible to quote backslashes using # echo "$something" | sed 's/\\/\\\\/g' # # So, first we look for a working echo in the user's PATH. lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$dir/echo" break fi done IFS="$lt_save_ifs" if test "X$echo" = Xecho; then # We didn't find a better echo, so look for alternatives. if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # This shell has a builtin print -r that does the trick. echo='print -r' elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && test "X$CONFIG_SHELL" != X/bin/ksh; then # If we have ksh, try running configure again with it. ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} export ORIGINAL_CONFIG_SHELL CONFIG_SHELL=/bin/ksh export CONFIG_SHELL exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} else # Try using printf. echo='printf %s\n' if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then # Cool, printf works : elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL export CONFIG_SHELL SHELL="$CONFIG_SHELL" export SHELL echo="$CONFIG_SHELL $0 --fallback-echo" elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && test "X$echo_testing_string" = 'X\t' && echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then echo="$CONFIG_SHELL $0 --fallback-echo" else # maybe with a smaller string... prev=: for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null then break fi prev="$cmd" done if test "$prev" != 'sed 50q "$0"'; then echo_test_string=`eval $prev` export echo_test_string exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} else # Oops. We lost completely, so just stick with echo. echo=echo fi fi fi fi fi fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. ECHO=$echo if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" fi tagnames=${tagnames+${tagnames},}CXX tagnames=${tagnames+${tagnames},}F77 test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='opensmppbox' PACKAGE_TARNAME='opensmppbox' PACKAGE_VERSION='svn' PACKAGE_STRING='opensmppbox svn' PACKAGE_BUGREPORT='devel@kannel.org' PACKAGE_URL='' ac_unique_file="gw/opensmppbox.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS rpm_requires rpm_suffix GW_CONFIG CTLIB_INCLUDE CTLIB_LFLAGS DOCDRAFTS DOCSTARGET XML_DCL TEX_DSL HTML_DSL CONVERT FIG2DEV DVIPS PDFJADETEX JADETEX JADE OLDJADE OPENSSL LIBOBJS INCLUDES LIBTOOL ac_ct_F77 FFLAGS F77 CXXCPP am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX CPP RANLIB AR ECHO LN_S EGREP GREP SED am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC GW_VERSION host_os host_vendor host_cpu host build_os build_vendor build_cpu build MAINT MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_maintainer_mode enable_shared enable_static enable_fast_install enable_dependency_tracking with_gnu_ld enable_libtool_lock with_pic with_tags with_cflags with_libs enable_pam with_ssl enable_ssl enable_ssl_thread_test enable_docs enable_drafts with_ctlib with_mssql with_kannel_dir ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP CXX CXXFLAGS CCC CXXCPP F77 FFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures opensmppbox svn to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/opensmppbox] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of opensmppbox svn:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --disable-libtool-lock avoid locking (might break parallel builds) --enable-pam enable PAM authentication [disabled] --enable-ssl enable SSL client and server support enabled --disable-ssl-thread-test disable the multithread test for the OpenSSL library this will force to continue even if the test fails --enable-docs enable building of documentation [enabled] --enable-drafts enable building of documentation drafts [disabled] Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-pic try to use only PIC/non-PIC objects [default=use both] --with-tags[=TAGS] include additional configurations [automatic] --with-cflags=FLAGS use FLAGS for CFLAGS --with-libs=FLAGS use FLAGS for extra libraries --with-ssl=DIR where to look for OpenSSL libs and header files DIR points to the installation /usr/local/ssl --with-ctlib=DIR Include Ct-Lib support. DIR is the Ct-Lib install directory, defaults to /opt/sybase. --with-mssql=DIR Include FreeTDS Ct-Lib support. DIR is the FreeTDS install directory, defaults to /usr/local. --with-kannel-dir=DIR where to look for Kannel Gateway libs and header files DIR points to the installation /usr/local Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor F77 Fortran 77 compiler command FFLAGS Fortran 77 compiler flags Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF opensmppbox configure svn generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------- ## ## Report this to devel@kannel.org ## ## ------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_f77_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_f77_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_f77_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_f77_try_compile # ac_fn_f77_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_f77_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_f77_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_f77_try_link cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by opensmppbox $as_me svn, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in autotools "$srcdir"/autotools; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in autotools \"$srcdir\"/autotools" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. am__api_version="1.9" # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t $srcdir/configure conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then # We used to keeping the `.' as first argument, in order to # allow $(mkdir_p) to be used without argument. As in # $(mkdir_p) $(somedir) # where $(somedir) is conditionally defined. However this is wrong # for two reasons: # 1. if the package is installed by a user who cannot write `.' # make install will fail, # 2. the above comment should most certainly read # $(mkdir_p) $(DESTDIR)$(somedir) # so it does not work when $(somedir) is undefined and # $(DESTDIR) is not. # To support the latter case, we have to write # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), # so the `.' trick is pointless. mkdir_p='mkdir -p --' else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. for d in ./-p ./--version; do test -d $d && rmdir $d done # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. if test -f "$ac_aux_dir/mkinstalldirs"; then mkdir_p='$(mkinstalldirs)' else mkdir_p='$(install_sh) -d' fi fi for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # test to see if srcdir already configured if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE=$SB_NAME VERSION=$VERSION cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} install_sh=${install_sh-"$am_aux_dir/install-sh"} # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. AMTAR=${AMTAR-"${am_missing_run}tar"} am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' ac_config_headers="$ac_config_headers sb-config.h" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else USE_MAINTAINER_MODE=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 $as_echo "$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac VERSION=`head -n 1 VERSION` if test "x$VERSION" = "xsvn"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking svn checkout revision" >&5 $as_echo_n "checking svn checkout revision... " >&6; } if test -d ".svn" then revision=`svnversion .` test -z "$revision" && revision="unknown" SVN_REVISION="$revision" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SVN_REVISION" >&5 $as_echo "$SVN_REVISION" >&6; } VERSION="$VERSION-r$SVN_REVISION" fi cat >>confdefs.h <<_ACEOF #define GW_NAME "OpenSMPPBox" _ACEOF cat >>confdefs.h <<_ACEOF #define GW_VERSION "$VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF nl=' ' echo "${nl}${T_MD}Configuring for opensmppbox version $VERSION ...${T_ME}" # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo done .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # We grep out `Entering directory' and `Leaving directory' # messages which can occur if `w' ends up in MAKEFLAGS. # In particular we don't look at `^make:' because GNU make might # be invoked under some other name (usually "gmake"), in which # case it prints its new name instead of `make'. if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then am__include=include am__quote= _am_result=GNU fi # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then am__include=.include am__quote="\"" _am_result=BSD fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf case $depmode in nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; none) break ;; esac # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. if depmode=$depmode \ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${lt_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else # Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done fi SED=$lt_cv_path_SED { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 $as_echo "$SED" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD-compatible nm" >&5 $as_echo_n "checking for BSD-compatible nm... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done test -z "$lt_cv_path_NM" && lt_cv_path_NM=nm fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } NM="$lt_cv_path_NM" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognise dependent libraries" >&5 $as_echo_n "checking how to recognise dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix4* | aix5*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump'. lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | kfreebsd*-gnu | dragonfly*) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix3*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be Linux ELF. linux*) lt_cv_deplibs_check_method=pass_all ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; nto-qnx*) lt_cv_deplibs_check_method=unknown ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line 4845 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; sparc*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) LD="${LD-ld} -m elf64_sparc" ;; *) LD="${LD-ld} -64" ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf case $depmode in nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; none) break ;; esac # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. if depmode=$depmode \ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu fi ac_ext=f ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_f77_compiler_gnu if test -n "$ac_tool_prefix"; then for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_F77+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$F77"; then ac_cv_prog_F77="$F77" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_F77="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi F77=$ac_cv_prog_F77 if test -n "$F77"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $F77" >&5 $as_echo "$F77" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$F77" && break done fi if test -z "$F77"; then ac_ct_F77=$F77 for ac_prog in g77 xlf f77 frt pgf77 cf77 fort77 fl32 af77 xlf90 f90 pgf90 pghpf epcf90 gfortran g95 xlf95 f95 fort ifort ifc efc pgfortran pgf95 lf95 ftn nagfor do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_F77+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_F77"; then ac_cv_prog_ac_ct_F77="$ac_ct_F77" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_F77="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_F77=$ac_cv_prog_ac_ct_F77 if test -n "$ac_ct_F77"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_F77" >&5 $as_echo "$ac_ct_F77" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_F77" && break done if test "x$ac_ct_F77" = x; then F77="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac F77=$ac_ct_F77 fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for Fortran 77 compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done rm -f a.out # If we don't use `.F' as extension, the preprocessor is not run on the # input file. (Note that this only needs to work for GNU compilers.) ac_save_ext=$ac_ext ac_ext=F { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU Fortran 77 compiler" >&5 $as_echo_n "checking whether we are using the GNU Fortran 77 compiler... " >&6; } if ${ac_cv_f77_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat > conftest.$ac_ext <<_ACEOF program main #ifndef __GNUC__ choke me #endif end _ACEOF if ac_fn_f77_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_f77_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_f77_compiler_gnu" >&5 $as_echo "$ac_cv_f77_compiler_gnu" >&6; } ac_ext=$ac_save_ext ac_test_FFLAGS=${FFLAGS+set} ac_save_FFLAGS=$FFLAGS FFLAGS= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $F77 accepts -g" >&5 $as_echo_n "checking whether $F77 accepts -g... " >&6; } if ${ac_cv_prog_f77_g+:} false; then : $as_echo_n "(cached) " >&6 else FFLAGS=-g cat > conftest.$ac_ext <<_ACEOF program main end _ACEOF if ac_fn_f77_try_compile "$LINENO"; then : ac_cv_prog_f77_g=yes else ac_cv_prog_f77_g=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_f77_g" >&5 $as_echo "$ac_cv_prog_f77_g" >&6; } if test "$ac_test_FFLAGS" = set; then FFLAGS=$ac_save_FFLAGS elif test $ac_cv_prog_f77_g = yes; then if test "x$ac_cv_f77_compiler_gnu" = xyes; then FFLAGS="-g -O2" else FFLAGS="-g" fi else if test "x$ac_cv_f77_compiler_gnu" = xyes; then FFLAGS="-O2" else FFLAGS= fi fi if test $ac_compiler_gnu = yes; then G77=yes else G77= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Autoconf 2.13's AC_OBJEXT and AC_EXEEXT macros only works for C compilers! # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} while (test "X"`$SHELL $0 --fallback-echo "X$teststring" 2>/dev/null` \ = "XX$teststring") >/dev/null 2>&1 && new_result=`expr "X$teststring" : ".*" 2>&1` && lt_cv_sys_max_cmd_len=$new_result && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done teststring= # Add a significant safety factor because C++ compilers can tack on massive # amounts of additional arguments before passing them to the linker. # It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Transform an extracted symbol line into a proper C declaration lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern int \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32*) symcode='[ABCDGISTW]' ;; hpux*) # Its linker distinguishes data from code symbols if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" ;; linux*) if test "$host_cpu" = ia64; then symcode='[ABCDGIRSTW]' lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`echo 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Try without a prefix undercore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if grep ' nm_test_var$' "$nlist" >/dev/null; then if grep ' nm_test_func$' "$nlist" >/dev/null; then cat < conftest.$ac_ext #ifdef __cplusplus extern "C" { #endif EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | grep -v main >> conftest.$ac_ext' cat <> conftest.$ac_ext #if defined (__STDC__) && __STDC__ # define lt_ptr_t void * #else # define lt_ptr_t char * # define const #endif /* The mapping between symbol names and symbols. */ const struct { const char *name; lt_ptr_t address; } lt_preloaded_symbols[] = { EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (lt_ptr_t) \&\2},/" < "$nlist" | grep -v main >> conftest.$ac_ext cat <<\EOF >> conftest.$ac_ext {0, (lt_ptr_t) 0} }; #ifdef __cplusplus } #endif EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_save_LIBS="$LIBS" lt_save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS="$lt_save_LIBS" CFLAGS="$lt_save_CFLAGS" else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed='sed -e 1s/^X//' sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' # Constants: rm="rm -f" # Global variables: default_ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a ltmain="$ac_aux_dir/ltmain.sh" ofile="$default_ofile" with_gnu_ld="$lt_cv_prog_gnu_ld" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$AR" && AR=ar test -z "$AR_FLAGS" && AR_FLAGS=cru test -z "$AS" && AS=as test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$DLLTOOL" && DLLTOOL=dlltool test -z "$LD" && LD=ld test -z "$LN_S" && LN_S="ln -s" test -z "$MAGIC_CMD" && MAGIC_CMD=file test -z "$NM" && NM=nm test -z "$SED" && SED=sed test -z "$OBJDUMP" && OBJDUMP=objdump test -z "$RANLIB" && RANLIB=: test -z "$STRIP" && STRIP=: test -z "$ac_objext" && ac_objext=o # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" fi for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac enable_dlopen=no enable_win32_dll=no # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; pic_mode="$withval" else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Use C for the default configuration in the libtool script tagname= lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}\n' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $rm conftest* ac_outfile=conftest.$ac_objext printf "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $rm conftest* lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag=' -fno-builtin' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:6951: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:6955: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; interix3*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; *) lt_prog_compiler_pic='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; darwin*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files case $cc_basename in xlc*) lt_prog_compiler_pic='-qnocommon' lt_prog_compiler_wl='-Wl,' ;; esac ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; linux*) case $cc_basename in icc* | ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 $as_echo "$lt_prog_compiler_pic" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7219: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:7223: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_prog_compiler_pic_works=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works" >&5 $as_echo "$lt_prog_compiler_pic_works" >&6; } if test x"$lt_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_prog_compiler_static_works=yes fi else lt_prog_compiler_static_works=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works" >&5 $as_echo "$lt_prog_compiler_static_works" >&6; } if test x"$lt_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:7323: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:7327: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= enable_shared_with_static_runtimes=no archive_cmds= archive_expsym_cmds= old_archive_From_new_cmds= old_archive_from_expsyms_cmds= export_dynamic_flag_spec= whole_archive_flag_spec= thread_safe_flag_spec= hardcode_libdir_flag_spec= hardcode_libdir_flag_spec_ld= hardcode_libdir_separator= hardcode_direct=no hardcode_minus_L=no hardcode_shlibpath_var=unsupported link_all_deplibs=unknown hardcode_automatic=no module_cmds= module_expsym_cmds= always_export_symbols=no export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= # Just being paranoid about ensuring that cc_basename is set. for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>/dev/null` in *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; interix3*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then tmp_addflag= case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; esac archive_cmds='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test $supports_anon_versioning = yes; then archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ $echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi else ld_shlibs=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_libdir_separator=':' link_all_deplibs=yes if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct=yes else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes # see comment about different semantics on the GNU ld section ld_shlibs=no ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes=yes ;; darwin* | rhapsody*) case $host_os in rhapsody* | darwin1.[012]) allow_undefined_flag='${wl}-undefined ${wl}suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) allow_undefined_flag='${wl}-undefined ${wl}dynamic_lookup' ;; esac fi ;; esac archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported whole_archive_flag_spec='' link_all_deplibs=yes if test "$GCC" = yes ; then output_verbose_link_cmd='echo' archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else case $cc_basename in xlc*) output_verbose_link_cmd='echo' archive_cmds='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' ;; *) ld_shlibs=no ;; esac fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; freebsd1*) ld_shlibs=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu | dragonfly*) archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_libdir_flag_spec_ld='+b $libdir' hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld='-rpath $libdir' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: link_all_deplibs=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; openbsd*) hardcode_direct=yes hardcode_shlibpath_var=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z text' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine linker options so we # cannot just pass the convience library names through # without $wl, iff we do not link with $LD. # Luckily, gcc supports the same syntax we need for Sun Studio. # Supported since Solaris 2.6 (maybe 2.5.1?) case $wlarc in '') whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; *) whole_archive_flag_spec='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; esac ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc=no else archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 $as_echo "$archive_cmds_need_lc" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; freebsd*) # from 4.6 on shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix3*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '#line 8734 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' shlibpath_overrides_runpath=no else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' shlibpath_overrides_runpath=yes case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || \ test -n "$runpath_var" || \ test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | grep "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-dld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-dld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif #ifdef __cplusplus extern "C" void exit (int); #endif void fnord() { int i=42;} int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; /* dlclose (self); */ } else puts (dlerror ()); exit (status); } EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4* | aix5*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler \ CC \ LD \ lt_prog_compiler_wl \ lt_prog_compiler_pic \ lt_prog_compiler_static \ lt_prog_compiler_no_builtin_flag \ export_dynamic_flag_spec \ thread_safe_flag_spec \ whole_archive_flag_spec \ enable_shared_with_static_runtimes \ old_archive_cmds \ old_archive_from_new_cmds \ predep_objects \ postdep_objects \ predeps \ postdeps \ compiler_lib_search_path \ archive_cmds \ archive_expsym_cmds \ postinstall_cmds \ postuninstall_cmds \ old_archive_from_expsyms_cmds \ allow_undefined_flag \ no_undefined_flag \ export_symbols_cmds \ hardcode_libdir_flag_spec \ hardcode_libdir_flag_spec_ld \ hardcode_libdir_separator \ hardcode_automatic \ module_cmds \ module_expsym_cmds \ lt_cv_prog_compiler_c_o \ exclude_expsyms \ include_expsyms; do case $var in old_archive_cmds | \ old_archive_from_new_cmds | \ archive_cmds | \ archive_expsym_cmds | \ module_cmds | \ module_expsym_cmds | \ old_archive_from_expsyms_cmds | \ export_symbols_cmds | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="${ofile}T" trap "$rm \"$cfgfile\"; exit 1" 1 2 15 $rm -f "$cfgfile" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ofile" >&5 $as_echo "$as_me: creating $ofile" >&6;} cat <<__EOF__ >> "$cfgfile" #! $SHELL # `$echo "$cfgfile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. # # This file is part of GNU Libtool: # Originally by Gordon Matzigkeit , 1996 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="$SED -e 1s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # The names of the tagged configurations supported by this script. available_tags= # ### BEGIN LIBTOOL CONFIG # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # LTCC compiler flags. LTCFLAGS=$lt_LTCFLAGS # A language-specific compiler. CC=$lt_compiler # Is the compiler the GNU C compiler? with_gcc=$GCC gcc_dir=\`gcc -print-file-name=. | $SED 's,/\.$,,'\` gcc_ver=\`gcc -dumpversion\` # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Must we lock files when doing compilation? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=\`echo $lt_predep_objects | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=\`echo $lt_postdep_objects | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=\`echo $lt_compiler_lib_search_path | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Compile-time system search path for libraries sys_lib_search_path_spec=\`echo $lt_sys_lib_search_path_spec | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # ### END LIBTOOL CONFIG __EOF__ case $host_os in aix3*) cat <<\EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi EOF ;; esac # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" || (rm -f "$cfgfile"; exit 1) mv -f "$cfgfile" "$ofile" || \ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" # Check whether --with-tags was given. if test "${with_tags+set}" = set; then : withval=$with_tags; tagnames="$withval" fi if test -f "$ltmain" && test -n "$tagnames"; then if test ! -f "${ofile}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: output file \`$ofile' does not exist" >&5 $as_echo "$as_me: WARNING: output file \`$ofile' does not exist" >&2;} fi if test -z "$LTCC"; then eval "`$SHELL ${ofile} --config | grep '^LTCC='`" if test -z "$LTCC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: output file \`$ofile' does not look like a libtool script" >&5 $as_echo "$as_me: WARNING: output file \`$ofile' does not look like a libtool script" >&2;} else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&5 $as_echo "$as_me: WARNING: using \`LTCC=$LTCC', extracted from \`$ofile'" >&2;} fi fi if test -z "$LTCFLAGS"; then eval "`$SHELL ${ofile} --config | grep '^LTCFLAGS='`" fi # Extract list of available tagged configurations in $ofile. # Note that this assumes the entire list is on one line. available_tags=`grep "^available_tags=" "${ofile}" | $SED -e 's/available_tags=\(.*$\)/\1/' -e 's/\"//g'` lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for tagname in $tagnames; do IFS="$lt_save_ifs" # Check whether tagname contains only valid characters case `$echo "X$tagname" | $Xsed -e 's:[-_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,/]::g'` in "") ;; *) as_fn_error $? "invalid tag name: $tagname" "$LINENO" 5 ;; esac if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "${ofile}" > /dev/null then as_fn_error $? "tag name \"$tagname\" already exists" "$LINENO" 5 fi # Update the list of available tags. if test -n "$tagname"; then echo appending configuration tag \"$tagname\" to $ofile case $tagname in CXX) if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu archive_cmds_need_lc_CXX=no allow_undefined_flag_CXX= always_export_symbols_CXX=no archive_expsym_cmds_CXX= export_dynamic_flag_spec_CXX= hardcode_direct_CXX=no hardcode_libdir_flag_spec_CXX= hardcode_libdir_flag_spec_ld_CXX= hardcode_libdir_separator_CXX= hardcode_minus_L_CXX=no hardcode_shlibpath_var_CXX=unsupported hardcode_automatic_CXX=no module_cmds_CXX= module_expsym_cmds_CXX= link_all_deplibs_CXX=unknown old_archive_cmds_CXX=$old_archive_cmds no_undefined_flag_CXX= whole_archive_flag_spec_CXX= enable_shared_with_static_runtimes_CXX=no # Dependencies to place before and after the object being linked: predep_objects_CXX= postdep_objects_CXX= predeps_CXX= postdeps_CXX= compiler_lib_search_path_CXX= # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o objext_CXX=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;\n" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[]) { return(0); }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $rm conftest* ac_outfile=conftest.$ac_objext printf "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $rm conftest* # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} compiler=$CC compiler_CXX=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` # We don't want -fno-exception wen compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' else lt_prog_compiler_no_builtin_flag_CXX= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`echo $ac_prog| $SED 's%\\\\%/%g'` while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do ac_prog=`echo $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | \ grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_CXX= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } ld_shlibs_CXX=yes case $host_os in aix3*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_CXX='' hardcode_direct_CXX=yes hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes if test "$GXX" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_CXX=yes else # We have old collect2 hardcode_direct_CXX=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_CXX=yes hardcode_libdir_flag_spec_CXX='-L$libdir' hardcode_libdir_separator_CXX= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_CXX=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_CXX='-berok' # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_CXX="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_CXX="-z nodefs" archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_CXX=' ${wl}-bernotok' allow_undefined_flag_CXX=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_CXX='$convenience' archive_cmds_need_lc_CXX=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_CXX=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_CXX=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_CXX='-L$libdir' allow_undefined_flag_CXX=unsupported always_export_symbols_CXX=no enable_shared_with_static_runtimes_CXX=yes if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_CXX=no fi ;; darwin* | rhapsody*) case $host_os in rhapsody* | darwin1.[012]) allow_undefined_flag_CXX='${wl}-undefined ${wl}suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_CXX='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) allow_undefined_flag_CXX='${wl}-undefined ${wl}dynamic_lookup' ;; esac fi ;; esac archive_cmds_need_lc_CXX=no hardcode_direct_CXX=no hardcode_automatic_CXX=yes hardcode_shlibpath_var_CXX=unsupported whole_archive_flag_spec_CXX='' link_all_deplibs_CXX=yes if test "$GXX" = yes ; then lt_int_apple_cc_single_mod=no output_verbose_link_cmd='echo' if $CC -dumpspecs 2>&1 | $EGREP 'single_module' >/dev/null ; then lt_int_apple_cc_single_mod=yes fi if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_cmds_CXX='$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' else archive_cmds_CXX='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring' fi module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds if test "X$lt_int_apple_cc_single_mod" = Xyes ; then archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib -single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs~$CC -dynamiclib $allow_undefined_flag -o $lib ${lib}-master.o $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' fi module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else case $cc_basename in xlc*) output_verbose_link_cmd='echo' archive_cmds_CXX='$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' module_cmds_CXX='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds archive_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj ${wl}-single_module $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds_CXX='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' ;; *) ld_shlibs_CXX=no ;; esac fi ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; freebsd[12]*) # C++ shared libraries reported to be fairly broken before switch to ELF ld_shlibs_CXX=no ;; freebsd-elf*) archive_cmds_need_lc_CXX=no ;; freebsd* | kfreebsd*-gnu | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions ld_shlibs_CXX=yes ;; gnu*) ;; hpux9*) hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: export_dynamic_flag_spec_CXX='${wl}-E' hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) archive_cmds_CXX='$rm $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "[-]L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then archive_cmds_CXX='$rm $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' hardcode_libdir_separator_CXX=: case $host_cpu in hppa*64*|ia64*) hardcode_libdir_flag_spec_ld_CXX='+b $libdir' ;; *) export_dynamic_flag_spec_CXX='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no ;; *) hardcode_direct_CXX=yes hardcode_minus_L_CXX=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; aCC*) case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | grep "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; interix3*) hardcode_direct_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` -o $lib' fi fi link_all_deplibs_CXX=yes ;; esac hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: ;; linux*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | grep "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' hardcode_libdir_flag_spec_CXX='${wl}--rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc*) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac archive_cmds_need_lc_CXX=no hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC*) # Portland Group C++ compiler archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_CXX='${wl}--export-dynamic' whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; esac ;; lynxos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; m88k*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; openbsd2*) # C++ shared libraries are fairly broken ld_shlibs_CXX=no ;; openbsd*) hardcode_direct_CXX=yes hardcode_shlibpath_var_CXX=no archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' export_dynamic_flag_spec_CXX='${wl}-E' whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd='echo' ;; osf3*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx*) allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && echo ${wl}-set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' hardcode_libdir_separator_CXX=: # Archives containing C++ object files must be created using # the KAI C++ compiler. old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; cxx*) allow_undefined_flag_CXX=' -expect_unresolved \*' archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname -Wl,-input -Wl,$lib.exp `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~ $rm $lib.exp' hardcode_libdir_flag_spec_CXX='-rpath $libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "ld" | grep -v "ld:"`; templist=`echo $templist | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; echo $list' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_CXX=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep "\-L"' else # FIXME: insert proper C++ library support ld_shlibs_CXX=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ archive_cmds_need_lc_CXX=yes no_undefined_flag_CXX=' -zdefs' archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' hardcode_libdir_flag_spec_CXX='-R$libdir' hardcode_shlibpath_var_CXX=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The C++ compiler is used as linker so we must use $wl # flag to pass the commands to the underlying system # linker. We must also pass each convience library through # to the system linker between allextract/defaultextract. # The C++ compiler will combine linker options so we # cannot just pass the convience library names through # without $wl. # Supported since Solaris 2.6 (maybe 2.5.1?) whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; esac link_all_deplibs_CXX=yes output_verbose_link_cmd='echo' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then no_undefined_flag_CXX=' ${wl}-z ${wl}defs' if $CC --version | grep -v '^2\.7' > /dev/null; then archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -shared $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' archive_expsym_cmds_CXX='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$rm $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd="$CC -G $CFLAGS -v conftest.$objext 2>&1 | grep \"\-L\"" fi hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag_CXX='${wl}-z,text' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. # So that behaviour is only enabled if SCOABSPATH is set to a # non-empty value in the environment. Most likely only useful for # creating official distributions of packages. # This is a hack until libtool officially supports absolute path # names for shared libraries. no_undefined_flag_CXX='${wl}-z,text' allow_undefined_flag_CXX='${wl}-z,nodefs' archive_cmds_need_lc_CXX=no hardcode_shlibpath_var_CXX=no hardcode_libdir_flag_spec_CXX='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator_CXX=':' link_all_deplibs_CXX=yes export_dynamic_flag_spec_CXX='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) archive_cmds_CXX='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_CXX='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; *) # FIXME: insert proper C++ library support ld_shlibs_CXX=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no GCC_CXX="$GXX" LD_CXX="$LD" cat > conftest.$ac_ext <&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no # The `*' in the case matches for architectures that use `case' in # $output_verbose_cmd can trigger glob expansion during the loop # eval without this substitution. output_verbose_link_cmd=`$echo "X$output_verbose_link_cmd" | $Xsed -e "$no_glob_subst"` for p in `eval $output_verbose_link_cmd`; do case $p in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" \ || test $p = "-R"; then prev=$p continue else prev= fi if test "$pre_test_object_deps_done" = no; then case $p in -L* | -R*) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$compiler_lib_search_path_CXX"; then compiler_lib_search_path_CXX="${prev}${p}" else compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$postdeps_CXX"; then postdeps_CXX="${prev}${p}" else postdeps_CXX="${postdeps_CXX} ${prev}${p}" fi fi ;; *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$predep_objects_CXX"; then predep_objects_CXX="$p" else predep_objects_CXX="$predep_objects_CXX $p" fi else if test -z "$postdep_objects_CXX"; then postdep_objects_CXX="$p" else postdep_objects_CXX="$postdep_objects_CXX $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling CXX test program" fi $rm -f confest.$objext # PORTME: override above test on systems where it is broken case $host_os in interix3*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. predep_objects_CXX= postdep_objects_CXX= postdeps_CXX= ;; solaris*) case $cc_basename in CC*) # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. postdeps_CXX='-lCstd -lCrun' ;; esac ;; esac case " $postdeps_CXX " in *" -lc "*) archive_cmds_need_lc_CXX=no ;; esac lt_prog_compiler_wl_CXX= lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | os2* | pw32*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_CXX='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_CXX='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all lt_prog_compiler_pic_CXX= ;; interix3*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_CXX=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_CXX='-fPIC' ;; esac else case $host_os in aix4* | aix5*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_CXX='-Bstatic' else lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_AC_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; darwin*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files case $cc_basename in xlc*) lt_prog_compiler_pic_CXX='-qnocommon' lt_prog_compiler_wl_CXX='-Wl,' ;; esac ;; dgux*) case $cc_basename in ec++*) lt_prog_compiler_pic_CXX='-KPIC' ;; ghcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; freebsd* | kfreebsd*-gnu | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then lt_prog_compiler_pic_CXX='+Z' fi ;; aCC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_CXX='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_static_CXX='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux*) case $cc_basename in KCC*) # KAI C++ Compiler lt_prog_compiler_wl_CXX='--backend -Wl,' lt_prog_compiler_pic_CXX='-fPIC' ;; icpc* | ecpc*) # Intel C++ lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-static' ;; pgCC*) # Portland Group C++ compiler. lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-fpic' lt_prog_compiler_static_CXX='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) lt_prog_compiler_pic_CXX='-W c,exportall' ;; *) ;; esac ;; netbsd*) ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) lt_prog_compiler_wl_CXX='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 lt_prog_compiler_pic_CXX='-pic' ;; cxx*) # Digital/Compaq C++ lt_prog_compiler_wl_CXX='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. lt_prog_compiler_pic_CXX= lt_prog_compiler_static_CXX='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC*) # Sun C++ 4.2, 5.x and Centerline C++ lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' lt_prog_compiler_wl_CXX='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler lt_prog_compiler_pic_CXX='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x lt_prog_compiler_pic_CXX='-pic' lt_prog_compiler_static_CXX='-Bstatic' ;; lcc*) # Lucid lt_prog_compiler_pic_CXX='-pic' ;; *) ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 lt_prog_compiler_pic_CXX='-KPIC' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) lt_prog_compiler_wl_CXX='-Wl,' lt_prog_compiler_pic_CXX='-KPIC' lt_prog_compiler_static_CXX='-Bstatic' ;; esac ;; vxworks*) ;; *) lt_prog_compiler_can_build_shared_CXX=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5 $as_echo "$lt_prog_compiler_pic_CXX" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } if ${lt_prog_compiler_pic_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_pic_works_CXX=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:11692: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:11696: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_prog_compiler_pic_works_CXX=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_CXX" >&5 $as_echo "$lt_prog_compiler_pic_works_CXX" >&6; } if test x"$lt_prog_compiler_pic_works_CXX" = xyes; then case $lt_prog_compiler_pic_CXX in "" | " "*) ;; *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; esac else lt_prog_compiler_pic_CXX= lt_prog_compiler_can_build_shared_CXX=no fi fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_CXX= ;; *) lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" ;; esac # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_prog_compiler_static_works_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_static_works_CXX=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_prog_compiler_static_works_CXX=yes fi else lt_prog_compiler_static_works_CXX=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works_CXX" >&5 $as_echo "$lt_prog_compiler_static_works_CXX" >&6; } if test x"$lt_prog_compiler_static_works_CXX" = xyes; then : else lt_prog_compiler_static_CXX= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_CXX=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:11796: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:11800: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_CXX=yes fi fi chmod u+w . 2>&5 $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 $as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' case $host_os in aix4* | aix5*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) export_symbols_cmds_CXX="$ltdll_cmds" ;; cygwin* | mingw*) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/;/^.* __nm__/s/^.* __nm__\([^ ]*\) [^ ]*/\1 DATA/;/^I /d;/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' ;; *) export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 $as_echo "$ld_shlibs_CXX" >&6; } test "$ld_shlibs_CXX" = no && can_build_shared=no # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_CXX" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_CXX=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_CXX in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_CXX pic_flag=$lt_prog_compiler_pic_CXX compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_CXX allow_undefined_flag_CXX= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_CXX 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc_CXX=no else archive_cmds_need_lc_CXX=yes fi allow_undefined_flag_CXX=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_CXX" >&5 $as_echo "$archive_cmds_need_lc_CXX" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; freebsd*) # from 4.6 on shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix3*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '#line 12332 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' shlibpath_overrides_runpath=no else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' shlibpath_overrides_runpath=yes case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_CXX= if test -n "$hardcode_libdir_flag_spec_CXX" || \ test -n "$runpath_var_CXX" || \ test "X$hardcode_automatic_CXX" = "Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_CXX" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, CXX)" != no && test "$hardcode_minus_L_CXX" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_CXX=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_CXX=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_CXX=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 $as_echo "$hardcode_action_CXX" >&6; } if test "$hardcode_action_CXX" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_CXX \ CC_CXX \ LD_CXX \ lt_prog_compiler_wl_CXX \ lt_prog_compiler_pic_CXX \ lt_prog_compiler_static_CXX \ lt_prog_compiler_no_builtin_flag_CXX \ export_dynamic_flag_spec_CXX \ thread_safe_flag_spec_CXX \ whole_archive_flag_spec_CXX \ enable_shared_with_static_runtimes_CXX \ old_archive_cmds_CXX \ old_archive_from_new_cmds_CXX \ predep_objects_CXX \ postdep_objects_CXX \ predeps_CXX \ postdeps_CXX \ compiler_lib_search_path_CXX \ archive_cmds_CXX \ archive_expsym_cmds_CXX \ postinstall_cmds_CXX \ postuninstall_cmds_CXX \ old_archive_from_expsyms_cmds_CXX \ allow_undefined_flag_CXX \ no_undefined_flag_CXX \ export_symbols_cmds_CXX \ hardcode_libdir_flag_spec_CXX \ hardcode_libdir_flag_spec_ld_CXX \ hardcode_libdir_separator_CXX \ hardcode_automatic_CXX \ module_cmds_CXX \ module_expsym_cmds_CXX \ lt_cv_prog_compiler_c_o_CXX \ exclude_expsyms_CXX \ include_expsyms_CXX; do case $var in old_archive_cmds_CXX | \ old_archive_from_new_cmds_CXX | \ archive_cmds_CXX | \ archive_expsym_cmds_CXX | \ module_cmds_CXX | \ module_expsym_cmds_CXX | \ old_archive_from_expsyms_cmds_CXX | \ export_symbols_cmds_CXX | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_CXX # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # LTCC compiler flags. LTCFLAGS=$lt_LTCFLAGS # A language-specific compiler. CC=$lt_compiler_CXX # Is the compiler the GNU C compiler? with_gcc=$GCC_CXX gcc_dir=\`gcc -print-file-name=. | $SED 's,/\.$,,'\` gcc_ver=\`gcc -dumpversion\` # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_CXX # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_CXX # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_CXX pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX # Must we lock files when doing compilation? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_CXX # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_CXX # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_CXX old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_CXX archive_expsym_cmds=$lt_archive_expsym_cmds_CXX postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_CXX module_expsym_cmds=$lt_module_expsym_cmds_CXX # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=\`echo $lt_predep_objects_CXX | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=\`echo $lt_postdep_objects_CXX | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_CXX # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_CXX # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=\`echo $lt_compiler_lib_search_path_CXX | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_CXX # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_CXX # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_CXX # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_CXX # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_CXX # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_CXX # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_CXX # Compile-time system search path for libraries sys_lib_search_path_spec=\`echo $lt_sys_lib_search_path_spec | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_CXX" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_CXX # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_CXX # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_CXX # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_CXX # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC=$lt_save_CC LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ldcxx=$with_gnu_ld with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld else tagname="" fi ;; F77) if test -n "$F77" && test "X$F77" != "Xno"; then ac_ext=f ac_compile='$F77 -c $FFLAGS conftest.$ac_ext >&5' ac_link='$F77 -o conftest$ac_exeext $FFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_f77_compiler_gnu archive_cmds_need_lc_F77=no allow_undefined_flag_F77= always_export_symbols_F77=no archive_expsym_cmds_F77= export_dynamic_flag_spec_F77= hardcode_direct_F77=no hardcode_libdir_flag_spec_F77= hardcode_libdir_flag_spec_ld_F77= hardcode_libdir_separator_F77= hardcode_minus_L_F77=no hardcode_automatic_F77=no module_cmds_F77= module_expsym_cmds_F77= link_all_deplibs_F77=unknown old_archive_cmds_F77=$old_archive_cmds no_undefined_flag_F77= whole_archive_flag_spec_F77= enable_shared_with_static_runtimes_F77=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o objext_F77=$objext # Code to be used in simple compile tests lt_simple_compile_test_code=" subroutine t\n return\n end\n" # Code to be used in simple link tests lt_simple_link_test_code=" program t\n end\n" # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $rm conftest* ac_outfile=conftest.$ac_objext printf "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $rm conftest* # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${F77-"f77"} compiler=$CC compiler_F77=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix4* | aix5*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } GCC_F77="$G77" LD_F77="$LD" lt_prog_compiler_wl_F77= lt_prog_compiler_pic_F77= lt_prog_compiler_static_F77= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_static_F77='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_F77='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_F77='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_F77='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_F77='-fno-common' ;; interix3*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared_F77=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_F77=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_F77='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_F77='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl_F77='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_F77='-Bstatic' else lt_prog_compiler_static_F77='-bnso -bI:/lib/syscalls.exp' fi ;; darwin*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files case $cc_basename in xlc*) lt_prog_compiler_pic_F77='-qnocommon' lt_prog_compiler_wl_F77='-Wl,' ;; esac ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_F77='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl_F77='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_F77='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static_F77='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl_F77='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static_F77='-non_shared' ;; newsos6) lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; linux*) case $cc_basename in icc* | ecc*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-fpic' lt_prog_compiler_static_F77='-Bstatic' ;; ccc*) lt_prog_compiler_wl_F77='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static_F77='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl_F77='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static_F77='-non_shared' ;; solaris*) lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' case $cc_basename in f77* | f90* | f95*) lt_prog_compiler_wl_F77='-Qoption ld ';; *) lt_prog_compiler_wl_F77='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl_F77='-Qoption ld ' lt_prog_compiler_pic_F77='-PIC' lt_prog_compiler_static_F77='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic_F77='-Kconform_pic' lt_prog_compiler_static_F77='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_pic_F77='-KPIC' lt_prog_compiler_static_F77='-Bstatic' ;; unicos*) lt_prog_compiler_wl_F77='-Wl,' lt_prog_compiler_can_build_shared_F77=no ;; uts4*) lt_prog_compiler_pic_F77='-pic' lt_prog_compiler_static_F77='-Bstatic' ;; *) lt_prog_compiler_can_build_shared_F77=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_F77" >&5 $as_echo "$lt_prog_compiler_pic_F77" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_F77"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_F77 works... " >&6; } if ${lt_prog_compiler_pic_works_F77+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_pic_works_F77=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_F77" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:13390: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:13394: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_prog_compiler_pic_works_F77=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_F77" >&5 $as_echo "$lt_prog_compiler_pic_works_F77" >&6; } if test x"$lt_prog_compiler_pic_works_F77" = xyes; then case $lt_prog_compiler_pic_F77 in "" | " "*) ;; *) lt_prog_compiler_pic_F77=" $lt_prog_compiler_pic_F77" ;; esac else lt_prog_compiler_pic_F77= lt_prog_compiler_can_build_shared_F77=no fi fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_F77= ;; *) lt_prog_compiler_pic_F77="$lt_prog_compiler_pic_F77" ;; esac # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_F77 eval lt_tmp_static_flag=\"$lt_prog_compiler_static_F77\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_prog_compiler_static_works_F77+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_static_works_F77=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_prog_compiler_static_works_F77=yes fi else lt_prog_compiler_static_works_F77=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works_F77" >&5 $as_echo "$lt_prog_compiler_static_works_F77" >&6; } if test x"$lt_prog_compiler_static_works_F77" = xyes; then : else lt_prog_compiler_static_F77= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_F77+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_F77=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:13494: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:13498: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_F77=yes fi fi chmod u+w . 2>&5 $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_F77" >&5 $as_echo "$lt_cv_prog_compiler_c_o_F77" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_F77" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag_F77= enable_shared_with_static_runtimes_F77=no archive_cmds_F77= archive_expsym_cmds_F77= old_archive_From_new_cmds_F77= old_archive_from_expsyms_cmds_F77= export_dynamic_flag_spec_F77= whole_archive_flag_spec_F77= thread_safe_flag_spec_F77= hardcode_libdir_flag_spec_F77= hardcode_libdir_flag_spec_ld_F77= hardcode_libdir_separator_F77= hardcode_direct_F77=no hardcode_minus_L_F77=no hardcode_shlibpath_var_F77=unsupported link_all_deplibs_F77=unknown hardcode_automatic_F77=no module_cmds_F77= module_expsym_cmds_F77= always_export_symbols_F77=no export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms_F77= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms_F77="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= # Just being paranoid about ensuring that cc_basename is set. for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs_F77=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_F77='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_F77='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_F77="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_F77= fi supports_anon_versioning=no case `$LD -v 2>/dev/null` in *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs_F77=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs_F77=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_F77=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_F77='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_F77=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, F77) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_F77='-L$libdir' allow_undefined_flag_F77=unsupported always_export_symbols_F77=no enable_shared_with_static_runtimes_F77=yes export_symbols_cmds_F77='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_F77='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_F77=no fi ;; interix3*) hardcode_direct_F77=no hardcode_shlibpath_var_F77=no hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' export_dynamic_flag_spec_F77='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_F77='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_F77='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then tmp_addflag= case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers whole_archive_flag_spec_F77='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; esac archive_cmds_F77='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test $supports_anon_versioning = yes; then archive_expsym_cmds_F77='$echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ $echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi else ld_shlibs_F77=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_F77='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs_F77=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_F77=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs_F77=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' else ld_shlibs_F77=no fi ;; esac ;; sunos4*) archive_cmds_F77='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_F77=no fi ;; esac if test "$ld_shlibs_F77" = no; then runpath_var= hardcode_libdir_flag_spec_F77= export_dynamic_flag_spec_F77= whole_archive_flag_spec_F77= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag_F77=unsupported always_export_symbols_F77=yes archive_expsym_cmds_F77='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L_F77=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct_F77=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_F77='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_F77='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_F77='' hardcode_direct_F77=yes hardcode_libdir_separator_F77=':' link_all_deplibs_F77=yes if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_F77=yes else # We have old collect2 hardcode_direct_F77=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_F77=yes hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_libdir_separator_F77= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_F77=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_F77='-berok' # Determine the default libpath from the value encoded in an empty executable. cat > conftest.$ac_ext <<_ACEOF program main end _ACEOF if ac_fn_f77_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_F77="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_F77='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_F77="-z nodefs" archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat > conftest.$ac_ext <<_ACEOF program main end _ACEOF if ac_fn_f77_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_F77='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_F77=' ${wl}-bernotok' allow_undefined_flag_F77=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_F77='$convenience' archive_cmds_need_lc_F77=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds_F77="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds_F77='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes # see comment about different semantics on the GNU ld section ld_shlibs_F77=no ;; bsdi[45]*) export_dynamic_flag_spec_F77=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_F77=' ' allow_undefined_flag_F77=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_F77='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds_F77='true' # FIXME: Should let the user specify the lib program. old_archive_cmds_F77='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path_F77='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes_F77=yes ;; darwin* | rhapsody*) case $host_os in rhapsody* | darwin1.[012]) allow_undefined_flag_F77='${wl}-undefined ${wl}suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_F77='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) allow_undefined_flag_F77='${wl}-undefined ${wl}dynamic_lookup' ;; esac fi ;; esac archive_cmds_need_lc_F77=no hardcode_direct_F77=no hardcode_automatic_F77=yes hardcode_shlibpath_var_F77=unsupported whole_archive_flag_spec_F77='' link_all_deplibs_F77=yes if test "$GCC" = yes ; then output_verbose_link_cmd='echo' archive_cmds_F77='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else case $cc_basename in xlc*) output_verbose_link_cmd='echo' archive_cmds_F77='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' module_cmds_F77='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds archive_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds_F77='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' ;; *) ld_shlibs_F77=no ;; esac fi ;; dgux*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_shlibpath_var_F77=no ;; freebsd1*) ld_shlibs_F77=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes hardcode_minus_L_F77=yes hardcode_shlibpath_var_F77=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu | dragonfly*) archive_cmds_F77='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds_F77='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds_F77='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_direct_F77=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes export_dynamic_flag_spec_F77='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_F77='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_direct_F77=yes export_dynamic_flag_spec_F77='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds_F77='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_F77='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_F77='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec_F77='${wl}+b ${wl}$libdir' hardcode_libdir_separator_F77=: case $host_cpu in hppa*64*|ia64*) hardcode_libdir_flag_spec_ld_F77='+b $libdir' hardcode_direct_F77=no hardcode_shlibpath_var_F77=no ;; *) hardcode_direct_F77=yes export_dynamic_flag_spec_F77='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_F77=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds_F77='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_F77='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld_F77='-rpath $libdir' fi hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: link_all_deplibs_F77=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds_F77='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no ;; newsos6) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: hardcode_shlibpath_var_F77=no ;; openbsd*) hardcode_direct_F77=yes hardcode_shlibpath_var_F77=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' export_dynamic_flag_spec_F77='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds_F77='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-R$libdir' ;; *) archive_cmds_F77='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_F77='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_minus_L_F77=yes allow_undefined_flag_F77=unsupported archive_cmds_F77='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds_F77='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag_F77=' -expect_unresolved \*' archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_F77=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag_F77=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_F77='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_F77='${wl}-rpath ${wl}$libdir' else allow_undefined_flag_F77=' -expect_unresolved \*' archive_cmds_F77='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_F77='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec_F77='-rpath $libdir' fi hardcode_libdir_separator_F77=: ;; solaris*) no_undefined_flag_F77=' -z text' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds_F77='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else wlarc='' archive_cmds_F77='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_F77='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec_F77='-R$libdir' hardcode_shlibpath_var_F77=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine linker options so we # cannot just pass the convience library names through # without $wl, iff we do not link with $LD. # Luckily, gcc supports the same syntax we need for Sun Studio. # Supported since Solaris 2.6 (maybe 2.5.1?) case $wlarc in '') whole_archive_flag_spec_F77='-z allextract$convenience -z defaultextract' ;; *) whole_archive_flag_spec_F77='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; esac ;; esac link_all_deplibs_F77=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds_F77='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_F77='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_direct_F77=yes hardcode_minus_L_F77=yes hardcode_shlibpath_var_F77=no ;; sysv4) case $host_vendor in sni) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds_F77='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds_F77='$CC -r -o $output$reload_objs' hardcode_direct_F77=no ;; motorola) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_F77=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_F77=no ;; sysv4.3*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_F77=no export_dynamic_flag_spec_F77='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_F77=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs_F77=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) no_undefined_flag_F77='${wl}-z,text' archive_cmds_need_lc_F77=no hardcode_shlibpath_var_F77=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds_F77='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_F77='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag_F77='${wl}-z,text' allow_undefined_flag_F77='${wl}-z,nodefs' archive_cmds_need_lc_F77=no hardcode_shlibpath_var_F77=no hardcode_libdir_flag_spec_F77='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator_F77=':' link_all_deplibs_F77=yes export_dynamic_flag_spec_F77='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds_F77='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_F77='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_F77='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_F77='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds_F77='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_F77='-L$libdir' hardcode_shlibpath_var_F77=no ;; *) ld_shlibs_F77=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_F77" >&5 $as_echo "$ld_shlibs_F77" >&6; } test "$ld_shlibs_F77" = no && can_build_shared=no # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_F77" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_F77=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_F77 in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_F77 pic_flag=$lt_prog_compiler_pic_F77 compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_F77 allow_undefined_flag_F77= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_F77 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc_F77=no else archive_cmds_need_lc_F77=yes fi allow_undefined_flag_F77=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_F77" >&5 $as_echo "$archive_cmds_need_lc_F77" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; freebsd*) # from 4.6 on shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix3*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '#line 14893 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' shlibpath_overrides_runpath=no else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' shlibpath_overrides_runpath=yes case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_F77= if test -n "$hardcode_libdir_flag_spec_F77" || \ test -n "$runpath_var_F77" || \ test "X$hardcode_automatic_F77" = "Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_F77" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, F77)" != no && test "$hardcode_minus_L_F77" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_F77=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_F77=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_F77=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_F77" >&5 $as_echo "$hardcode_action_F77" >&6; } if test "$hardcode_action_F77" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_F77 \ CC_F77 \ LD_F77 \ lt_prog_compiler_wl_F77 \ lt_prog_compiler_pic_F77 \ lt_prog_compiler_static_F77 \ lt_prog_compiler_no_builtin_flag_F77 \ export_dynamic_flag_spec_F77 \ thread_safe_flag_spec_F77 \ whole_archive_flag_spec_F77 \ enable_shared_with_static_runtimes_F77 \ old_archive_cmds_F77 \ old_archive_from_new_cmds_F77 \ predep_objects_F77 \ postdep_objects_F77 \ predeps_F77 \ postdeps_F77 \ compiler_lib_search_path_F77 \ archive_cmds_F77 \ archive_expsym_cmds_F77 \ postinstall_cmds_F77 \ postuninstall_cmds_F77 \ old_archive_from_expsyms_cmds_F77 \ allow_undefined_flag_F77 \ no_undefined_flag_F77 \ export_symbols_cmds_F77 \ hardcode_libdir_flag_spec_F77 \ hardcode_libdir_flag_spec_ld_F77 \ hardcode_libdir_separator_F77 \ hardcode_automatic_F77 \ module_cmds_F77 \ module_expsym_cmds_F77 \ lt_cv_prog_compiler_c_o_F77 \ exclude_expsyms_F77 \ include_expsyms_F77; do case $var in old_archive_cmds_F77 | \ old_archive_from_new_cmds_F77 | \ archive_cmds_F77 | \ archive_expsym_cmds_F77 | \ module_cmds_F77 | \ module_expsym_cmds_F77 | \ old_archive_from_expsyms_cmds_F77 | \ export_symbols_cmds_F77 | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_F77 # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_F77 # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # LTCC compiler flags. LTCFLAGS=$lt_LTCFLAGS # A language-specific compiler. CC=$lt_compiler_F77 # Is the compiler the GNU C compiler? with_gcc=$GCC_F77 gcc_dir=\`gcc -print-file-name=. | $SED 's,/\.$,,'\` gcc_ver=\`gcc -dumpversion\` # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_F77 # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_F77 # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_F77 pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_F77 # Must we lock files when doing compilation? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_F77 # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_F77 # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_F77 # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_F77 # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_F77 # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_F77 old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_F77 # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_F77 # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_F77 archive_expsym_cmds=$lt_archive_expsym_cmds_F77 postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_F77 module_expsym_cmds=$lt_module_expsym_cmds_F77 # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=\`echo $lt_predep_objects_F77 | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=\`echo $lt_postdep_objects_F77 | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_F77 # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_F77 # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=\`echo $lt_compiler_lib_search_path_F77 | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_F77 # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_F77 # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_F77 # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_F77 # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_F77 # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_F77 # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_F77 # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_F77 # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_F77 # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_F77 # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_F77 # Compile-time system search path for libraries sys_lib_search_path_spec=\`echo $lt_sys_lib_search_path_spec | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_F77" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_F77 # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_F77 # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_F77 # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_F77 # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" else tagname="" fi ;; GCJ) if test -n "$GCJ" && test "X$GCJ" != "Xno"; then # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o objext_GCJ=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}\n" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[] argv) {}; }\n' # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $rm conftest* ac_outfile=conftest.$ac_objext printf "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $rm conftest* # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${GCJ-"gcj"} compiler=$CC compiler_GCJ=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` # GCJ did not exist at the time GCC didn't implicitly link libc in. archive_cmds_need_lc_GCJ=no old_archive_cmds_GCJ=$old_archive_cmds lt_prog_compiler_no_builtin_flag_GCJ= if test "$GCC" = yes; then lt_prog_compiler_no_builtin_flag_GCJ=' -fno-builtin' { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:15670: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:15674: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag_GCJ="$lt_prog_compiler_no_builtin_flag_GCJ -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl_GCJ= lt_prog_compiler_pic_GCJ= lt_prog_compiler_static_GCJ= { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_static_GCJ='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_GCJ='-Bstatic' fi ;; amigaos*) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic_GCJ='-m68020 -resident32 -malways-restore-a4' ;; beos* | cygwin* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic_GCJ='-fno-common' ;; interix3*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared_GCJ=no enable_shared=no ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic_GCJ=-Kconform_pic fi ;; hpux*) # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_GCJ='-fPIC' ;; esac ;; *) lt_prog_compiler_pic_GCJ='-fPIC' ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl_GCJ='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static_GCJ='-Bstatic' else lt_prog_compiler_static_GCJ='-bnso -bI:/lib/syscalls.exp' fi ;; darwin*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files case $cc_basename in xlc*) lt_prog_compiler_pic_GCJ='-qnocommon' lt_prog_compiler_wl_GCJ='-Wl,' ;; esac ;; mingw* | pw32* | os2*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic_GCJ='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl_GCJ='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic_GCJ='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static_GCJ='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl_GCJ='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static_GCJ='-non_shared' ;; newsos6) lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; linux*) case $cc_basename in icc* | ecc*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-static' ;; pgcc* | pgf77* | pgf90* | pgf95*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-fpic' lt_prog_compiler_static_GCJ='-Bstatic' ;; ccc*) lt_prog_compiler_wl_GCJ='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static_GCJ='-non_shared' ;; esac ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl_GCJ='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static_GCJ='-non_shared' ;; solaris*) lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' case $cc_basename in f77* | f90* | f95*) lt_prog_compiler_wl_GCJ='-Qoption ld ';; *) lt_prog_compiler_wl_GCJ='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl_GCJ='-Qoption ld ' lt_prog_compiler_pic_GCJ='-PIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic_GCJ='-Kconform_pic' lt_prog_compiler_static_GCJ='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_pic_GCJ='-KPIC' lt_prog_compiler_static_GCJ='-Bstatic' ;; unicos*) lt_prog_compiler_wl_GCJ='-Wl,' lt_prog_compiler_can_build_shared_GCJ=no ;; uts4*) lt_prog_compiler_pic_GCJ='-pic' lt_prog_compiler_static_GCJ='-Bstatic' ;; *) lt_prog_compiler_can_build_shared_GCJ=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_GCJ" >&5 $as_echo "$lt_prog_compiler_pic_GCJ" >&6; } # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic_GCJ"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_GCJ works... " >&6; } if ${lt_prog_compiler_pic_works_GCJ+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_pic_works_GCJ=no ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic_GCJ" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:15938: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:15942: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_prog_compiler_pic_works_GCJ=yes fi fi $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_works_GCJ" >&5 $as_echo "$lt_prog_compiler_pic_works_GCJ" >&6; } if test x"$lt_prog_compiler_pic_works_GCJ" = xyes; then case $lt_prog_compiler_pic_GCJ in "" | " "*) ;; *) lt_prog_compiler_pic_GCJ=" $lt_prog_compiler_pic_GCJ" ;; esac else lt_prog_compiler_pic_GCJ= lt_prog_compiler_can_build_shared_GCJ=no fi fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic_GCJ= ;; *) lt_prog_compiler_pic_GCJ="$lt_prog_compiler_pic_GCJ" ;; esac # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl_GCJ eval lt_tmp_static_flag=\"$lt_prog_compiler_static_GCJ\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_prog_compiler_static_works_GCJ+:} false; then : $as_echo_n "(cached) " >&6 else lt_prog_compiler_static_works_GCJ=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" printf "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $echo "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_prog_compiler_static_works_GCJ=yes fi else lt_prog_compiler_static_works_GCJ=yes fi fi $rm conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_static_works_GCJ" >&5 $as_echo "$lt_prog_compiler_static_works_GCJ" >&6; } if test x"$lt_prog_compiler_static_works_GCJ" = xyes; then : else lt_prog_compiler_static_GCJ= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o_GCJ+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o_GCJ=no $rm -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out printf "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:16042: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:16046: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $echo "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o_GCJ=yes fi fi chmod u+w . 2>&5 $rm conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $rm out/ii_files/* && rmdir out/ii_files $rm out/* && rmdir out cd .. rmdir conftest $rm conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_GCJ" >&5 $as_echo "$lt_cv_prog_compiler_c_o_GCJ" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o_GCJ" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $rm conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag_GCJ= enable_shared_with_static_runtimes_GCJ=no archive_cmds_GCJ= archive_expsym_cmds_GCJ= old_archive_From_new_cmds_GCJ= old_archive_from_expsyms_cmds_GCJ= export_dynamic_flag_spec_GCJ= whole_archive_flag_spec_GCJ= thread_safe_flag_spec_GCJ= hardcode_libdir_flag_spec_GCJ= hardcode_libdir_flag_spec_ld_GCJ= hardcode_libdir_separator_GCJ= hardcode_direct_GCJ=no hardcode_minus_L_GCJ=no hardcode_shlibpath_var_GCJ=unsupported link_all_deplibs_GCJ=unknown hardcode_automatic_GCJ=no module_cmds_GCJ= module_expsym_cmds_GCJ= always_export_symbols_GCJ=no export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms_GCJ= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms_GCJ="_GLOBAL_OFFSET_TABLE_" # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. extract_expsyms_cmds= # Just being paranoid about ensuring that cc_basename is set. for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` case $host_os in cygwin* | mingw* | pw32*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; esac ld_shlibs_GCJ=yes if test "$with_gnu_ld" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec_GCJ='${wl}--rpath ${wl}$libdir' export_dynamic_flag_spec_GCJ='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | grep 'no-whole-archive' > /dev/null; then whole_archive_flag_spec_GCJ="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec_GCJ= fi supports_anon_versioning=no case `$LD -v 2>/dev/null` in *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix3* | aix4* | aix5*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs_GCJ=no cat <&2 *** Warning: the GNU linker, at least up to release 2.9.1, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to modify your PATH *** so that a non-GNU linker is found, and then restart. EOF fi ;; amigaos*) archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes # Samuel A. Falvo II reports # that the semantics of dynamic libraries on AmigaOS, at least up # to version 4, is to share data among multiple programs linked # with the same dynamic library. Since this doesn't match the # behavior of shared libraries on other platforms, we can't use # them. ld_shlibs_GCJ=no ;; beos*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then allow_undefined_flag_GCJ=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds_GCJ='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs_GCJ=no fi ;; cygwin* | mingw* | pw32*) # _LT_AC_TAGVAR(hardcode_libdir_flag_spec, GCJ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec_GCJ='-L$libdir' allow_undefined_flag_GCJ=unsupported always_export_symbols_GCJ=no enable_shared_with_static_runtimes_GCJ=yes export_symbols_cmds_GCJ='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS] /s/.* \([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW] /s/.* //'\'' | sort | uniq > $export_symbols' if $LD --help 2>&1 | grep 'auto-import' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds_GCJ='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs_GCJ=no fi ;; interix3*) hardcode_direct_GCJ=no hardcode_shlibpath_var_GCJ=no hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' export_dynamic_flag_spec_GCJ='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds_GCJ='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds_GCJ='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; linux*) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then tmp_addflag= case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers whole_archive_flag_spec_GCJ='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; esac archive_cmds_GCJ='$CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test $supports_anon_versioning = yes; then archive_expsym_cmds_GCJ='$echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ $echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -shared'"$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi else ld_shlibs_GCJ=no fi ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_GCJ='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | grep 'BFD 2\.8' > /dev/null; then ld_shlibs_GCJ=no cat <&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. EOF elif $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_GCJ=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs_GCJ=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-rpath,$libdir`' archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname,\${SCOABSPATH:+${install_libdir}/}$soname,-retain-symbols-file,$export_symbols -o $lib' else ld_shlibs_GCJ=no fi ;; esac ;; sunos4*) archive_cmds_GCJ='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; *) if $LD --help 2>&1 | grep ': supported targets:.* elf' > /dev/null; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs_GCJ=no fi ;; esac if test "$ld_shlibs_GCJ" = no; then runpath_var= hardcode_libdir_flag_spec_GCJ= export_dynamic_flag_spec_GCJ= whole_archive_flag_spec_GCJ= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag_GCJ=unsupported always_export_symbols_GCJ=yes archive_expsym_cmds_GCJ='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L_GCJ=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct_GCJ=unsupported fi ;; aix4* | aix5*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm if $NM -V 2>&1 | grep 'GNU' > /dev/null; then export_symbols_cmds_GCJ='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds_GCJ='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$2 == "T") || (\$2 == "D") || (\$2 == "B")) && (substr(\$3,1,1) != ".")) { print \$3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds_GCJ='' hardcode_direct_GCJ=yes hardcode_libdir_separator_GCJ=':' link_all_deplibs_GCJ=yes if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && \ strings "$collect2name" | grep resolve_lib_name >/dev/null then # We have reworked collect2 hardcode_direct_GCJ=yes else # We have old collect2 hardcode_direct_GCJ=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L_GCJ=yes hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_libdir_separator_GCJ= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols_GCJ=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag_GCJ='-berok' # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds_GCJ="\$CC"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then echo "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec_GCJ='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag_GCJ="-z nodefs" archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an empty executable. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'` # Check for a 64-bit object if we didn't find anything. if test -z "$aix_libpath"; then aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e '/Import File Strings/,/^$/ { /^0/ { s/^0 *\(.*\)$/\1/; p; } }'`; fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_libdir_flag_spec_GCJ='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag_GCJ=' ${wl}-bernotok' allow_undefined_flag_GCJ=' ${wl}-berok' # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec_GCJ='$convenience' archive_cmds_need_lc_GCJ=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds_GCJ="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) archive_cmds_GCJ='$rm $output_objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes # see comment about different semantics on the GNU ld section ld_shlibs_GCJ=no ;; bsdi[45]*) export_dynamic_flag_spec_GCJ=-rdynamic ;; cygwin* | mingw* | pw32*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. hardcode_libdir_flag_spec_GCJ=' ' allow_undefined_flag_GCJ=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds_GCJ='$CC -o $lib $libobjs $compiler_flags `echo "$deplibs" | $SED -e '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_From_new_cmds_GCJ='true' # FIXME: Should let the user specify the lib program. old_archive_cmds_GCJ='lib /OUT:$oldlib$oldobjs$old_deplibs' fix_srcfile_path_GCJ='`cygpath -w "$srcfile"`' enable_shared_with_static_runtimes_GCJ=yes ;; darwin* | rhapsody*) case $host_os in rhapsody* | darwin1.[012]) allow_undefined_flag_GCJ='${wl}-undefined ${wl}suppress' ;; *) # Darwin 1.3 on if test -z ${MACOSX_DEPLOYMENT_TARGET} ; then allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' else case ${MACOSX_DEPLOYMENT_TARGET} in 10.[012]) allow_undefined_flag_GCJ='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) allow_undefined_flag_GCJ='${wl}-undefined ${wl}dynamic_lookup' ;; esac fi ;; esac archive_cmds_need_lc_GCJ=no hardcode_direct_GCJ=no hardcode_automatic_GCJ=yes hardcode_shlibpath_var_GCJ=unsupported whole_archive_flag_spec_GCJ='' link_all_deplibs_GCJ=yes if test "$GCC" = yes ; then output_verbose_link_cmd='echo' archive_cmds_GCJ='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring' module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' else case $cc_basename in xlc*) output_verbose_link_cmd='echo' archive_cmds_GCJ='$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}`echo $rpath/$soname` $verstring' module_cmds_GCJ='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags' # Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds archive_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -qmkshrobj $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-install_name ${wl}$rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' module_expsym_cmds_GCJ='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}' ;; *) ld_shlibs_GCJ=no ;; esac fi ;; dgux*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_shlibpath_var_GCJ=no ;; freebsd1*) ld_shlibs_GCJ=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes hardcode_minus_L_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | kfreebsd*-gnu | dragonfly*) archive_cmds_GCJ='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds_GCJ='$rm $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds_GCJ='$rm $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_direct_GCJ=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes export_dynamic_flag_spec_GCJ='${wl}-E' ;; hpux10*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_GCJ='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_direct_GCJ=yes export_dynamic_flag_spec_GCJ='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes fi ;; hpux11*) if test "$GCC" = yes -a "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds_GCJ='$CC -shared ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_GCJ='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds_GCJ='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec_GCJ='${wl}+b ${wl}$libdir' hardcode_libdir_separator_GCJ=: case $host_cpu in hppa*64*|ia64*) hardcode_libdir_flag_spec_ld_GCJ='+b $libdir' hardcode_direct_GCJ=no hardcode_shlibpath_var_GCJ=no ;; *) hardcode_direct_GCJ=yes export_dynamic_flag_spec_GCJ='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L_GCJ=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else archive_cmds_GCJ='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_ld_GCJ='-rpath $libdir' fi hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: link_all_deplibs_GCJ=yes ;; netbsd*) if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds_GCJ='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; newsos6) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: hardcode_shlibpath_var_GCJ=no ;; openbsd*) hardcode_direct_GCJ=yes hardcode_shlibpath_var_GCJ=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' export_dynamic_flag_spec_GCJ='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds_GCJ='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-R$libdir' ;; *) archive_cmds_GCJ='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec_GCJ='${wl}-rpath,$libdir' ;; esac fi ;; os2*) hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_minus_L_GCJ=yes allow_undefined_flag_GCJ=unsupported archive_cmds_GCJ='$echo "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$echo DATA >> $output_objdir/$libname.def~$echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~$echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_From_new_cmds_GCJ='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag_GCJ=' -expect_unresolved \*' archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' fi hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator_GCJ=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag_GCJ=' ${wl}-expect_unresolved ${wl}\*' archive_cmds_GCJ='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec_GCJ='${wl}-rpath ${wl}$libdir' else allow_undefined_flag_GCJ=' -expect_unresolved \*' archive_cmds_GCJ='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linker_flags -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds_GCJ='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; echo "-hidden">> $lib.exp~ $LD -shared${allow_undefined_flag} -input $lib.exp $linker_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib~$rm $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec_GCJ='-rpath $libdir' fi hardcode_libdir_separator_GCJ=: ;; solaris*) no_undefined_flag_GCJ=' -z text' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds_GCJ='$CC -shared ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $CC -shared ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$rm $lib.exp' else wlarc='' archive_cmds_GCJ='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds_GCJ='$echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$rm $lib.exp' fi hardcode_libdir_flag_spec_GCJ='-R$libdir' hardcode_shlibpath_var_GCJ=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine linker options so we # cannot just pass the convience library names through # without $wl, iff we do not link with $LD. # Luckily, gcc supports the same syntax we need for Sun Studio. # Supported since Solaris 2.6 (maybe 2.5.1?) case $wlarc in '') whole_archive_flag_spec_GCJ='-z allextract$convenience -z defaultextract' ;; *) whole_archive_flag_spec_GCJ='${wl}-z ${wl}allextract`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $echo \"$new_convenience\"` ${wl}-z ${wl}defaultextract' ;; esac ;; esac link_all_deplibs_GCJ=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds_GCJ='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_GCJ='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_direct_GCJ=yes hardcode_minus_L_GCJ=yes hardcode_shlibpath_var_GCJ=no ;; sysv4) case $host_vendor in sni) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds_GCJ='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds_GCJ='$CC -r -o $output$reload_objs' hardcode_direct_GCJ=no ;; motorola) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct_GCJ=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var_GCJ=no ;; sysv4.3*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_GCJ=no export_dynamic_flag_spec_GCJ='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var_GCJ=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs_GCJ=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7*) no_undefined_flag_GCJ='${wl}-z,text' archive_cmds_need_lc_GCJ=no hardcode_shlibpath_var_GCJ=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_GCJ='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag_GCJ='${wl}-z,text' allow_undefined_flag_GCJ='${wl}-z,nodefs' archive_cmds_need_lc_GCJ=no hardcode_shlibpath_var_GCJ=no hardcode_libdir_flag_spec_GCJ='`test -z "$SCOABSPATH" && echo ${wl}-R,$libdir`' hardcode_libdir_separator_GCJ=':' link_all_deplibs_GCJ=yes export_dynamic_flag_spec_GCJ='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds_GCJ='$CC -shared ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_GCJ='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds_GCJ='$CC -G ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds_GCJ='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,\${SCOABSPATH:+${install_libdir}/}$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds_GCJ='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec_GCJ='-L$libdir' hardcode_shlibpath_var_GCJ=no ;; *) ld_shlibs_GCJ=no ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_GCJ" >&5 $as_echo "$ld_shlibs_GCJ" >&6; } test "$ld_shlibs_GCJ" = no && can_build_shared=no # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc_GCJ" in x|xyes) # Assume -lc should be added archive_cmds_need_lc_GCJ=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds_GCJ in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } $rm conftest* printf "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl_GCJ pic_flag=$lt_prog_compiler_pic_GCJ compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag_GCJ allow_undefined_flag_GCJ= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds_GCJ 2\>\&1 \| grep \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then archive_cmds_need_lc_GCJ=no else archive_cmds_need_lc_GCJ=yes fi allow_undefined_flag_GCJ=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $rm conftest* { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc_GCJ" >&5 $as_echo "$archive_cmds_need_lc_GCJ" >&6; } ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';' >/dev/null ; then # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix4* | aix5*) version_type=linux need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | grep yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$host_os in yes,cygwin* | yes,mingw* | yes,pw32*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $rm \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" ;; mingw*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` if echo "$sys_lib_search_path_spec" | grep ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH printed by # mingw gcc, but we are running on Cygwin. Gcc prints its search # path with ; separators, and with drive letters. We can handle the # drive letters (cygwin fileutils understands them), so leave them, # especially as we might pass files found there to a mingw objdump, # which wouldn't understand a cygwinified path. Ahh. sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`echo "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac ;; *) library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' ;; esac dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${versuffix}$shared_ext ${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' # Apple's gcc prints 'gcc -print-search-dirs' doesn't operate the same. if test "$GCC" = yes; then sys_lib_search_path_spec=`$CC -print-search-dirs | tr "\n" "$PATH_SEPARATOR" | sed -e 's/libraries:/@libraries:/' | tr "@" "\n" | grep "^libraries:" | sed -e "s/^libraries://" -e "s,=/,/,g" -e "s,$PATH_SEPARATOR, ,g" -e "s,.*,& /lib /usr/lib /usr/local/lib,g"` else sys_lib_search_path_spec='/lib /usr/lib /usr/local/lib' fi sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd1*) dynamic_linker=no ;; kfreebsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[123]*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; freebsd*) # from 4.6 on shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555. postinstall_cmds='chmod 555 $lib' ;; interix3*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be Linux ELF. linux*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # find out which ABI we are using libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) echo '#line 17453 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *64-bit*) libsuff=64 sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; esac fi rm -rf conftest* ;; esac # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff} $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; knetbsd*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='GNU ld.so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; nto-qnx*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; solaris*) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no export_dynamic_flag_spec='${wl}-Blargedynsym' runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' shlibpath_overrides_runpath=no else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' shlibpath_overrides_runpath=yes case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; uts4*) version_type=linux library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action_GCJ= if test -n "$hardcode_libdir_flag_spec_GCJ" || \ test -n "$runpath_var_GCJ" || \ test "X$hardcode_automatic_GCJ" = "Xyes" ; then # We can hardcode non-existant directories. if test "$hardcode_direct_GCJ" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_AC_TAGVAR(hardcode_shlibpath_var, GCJ)" != no && test "$hardcode_minus_L_GCJ" != no; then # Linking always hardcodes the temporary library directory. hardcode_action_GCJ=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action_GCJ=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action_GCJ=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_GCJ" >&5 $as_echo "$hardcode_action_GCJ" >&6; } if test "$hardcode_action_GCJ" = relink; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_GCJ \ CC_GCJ \ LD_GCJ \ lt_prog_compiler_wl_GCJ \ lt_prog_compiler_pic_GCJ \ lt_prog_compiler_static_GCJ \ lt_prog_compiler_no_builtin_flag_GCJ \ export_dynamic_flag_spec_GCJ \ thread_safe_flag_spec_GCJ \ whole_archive_flag_spec_GCJ \ enable_shared_with_static_runtimes_GCJ \ old_archive_cmds_GCJ \ old_archive_from_new_cmds_GCJ \ predep_objects_GCJ \ postdep_objects_GCJ \ predeps_GCJ \ postdeps_GCJ \ compiler_lib_search_path_GCJ \ archive_cmds_GCJ \ archive_expsym_cmds_GCJ \ postinstall_cmds_GCJ \ postuninstall_cmds_GCJ \ old_archive_from_expsyms_cmds_GCJ \ allow_undefined_flag_GCJ \ no_undefined_flag_GCJ \ export_symbols_cmds_GCJ \ hardcode_libdir_flag_spec_GCJ \ hardcode_libdir_flag_spec_ld_GCJ \ hardcode_libdir_separator_GCJ \ hardcode_automatic_GCJ \ module_cmds_GCJ \ module_expsym_cmds_GCJ \ lt_cv_prog_compiler_c_o_GCJ \ exclude_expsyms_GCJ \ include_expsyms_GCJ; do case $var in old_archive_cmds_GCJ | \ old_archive_from_new_cmds_GCJ | \ archive_cmds_GCJ | \ archive_expsym_cmds_GCJ | \ module_cmds_GCJ | \ module_expsym_cmds_GCJ | \ old_archive_from_expsyms_cmds_GCJ | \ export_symbols_cmds_GCJ | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_GCJ # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_GCJ # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # LTCC compiler flags. LTCFLAGS=$lt_LTCFLAGS # A language-specific compiler. CC=$lt_compiler_GCJ # Is the compiler the GNU C compiler? with_gcc=$GCC_GCJ gcc_dir=\`gcc -print-file-name=. | $SED 's,/\.$,,'\` gcc_ver=\`gcc -dumpversion\` # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_GCJ # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_GCJ # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_GCJ pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_GCJ # Must we lock files when doing compilation? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_GCJ # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_GCJ # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_GCJ # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_GCJ # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_GCJ # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_GCJ old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_GCJ # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_GCJ # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_GCJ archive_expsym_cmds=$lt_archive_expsym_cmds_GCJ postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_GCJ module_expsym_cmds=$lt_module_expsym_cmds_GCJ # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=\`echo $lt_predep_objects_GCJ | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=\`echo $lt_postdep_objects_GCJ | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_GCJ # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_GCJ # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=\`echo $lt_compiler_lib_search_path_GCJ | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_GCJ # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_GCJ # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_GCJ # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_GCJ # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_GCJ # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_GCJ # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_GCJ # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_GCJ # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_GCJ # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_GCJ # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_GCJ # Compile-time system search path for libraries sys_lib_search_path_spec=\`echo $lt_sys_lib_search_path_spec | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_GCJ" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_GCJ # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_GCJ # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_GCJ # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_GCJ # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" else tagname="" fi ;; RC) # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o objext_RC=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }\n' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext printf "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $rm conftest* ac_outfile=conftest.$ac_objext printf "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $rm conftest* # Allow CC to be a program name with arguments. lt_save_CC="$CC" CC=${RC-"windres"} compiler=$CC compiler_RC=$CC for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$echo "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` lt_cv_prog_compiler_c_o_RC=yes # The else clause should only fire when bootstrapping the # libtool distribution, otherwise you forgot to ship ltmain.sh # with your package, and you will get complaints that there are # no rules to generate ltmain.sh. if test -f "$ltmain"; then # See if we are running on zsh, and set the options which allow our commands through # without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. for var in echo old_CC old_CFLAGS AR AR_FLAGS EGREP RANLIB LN_S LTCC LTCFLAGS NM \ SED SHELL STRIP \ libname_spec library_names_spec soname_spec extract_expsyms_cmds \ old_striplib striplib file_magic_cmd finish_cmds finish_eval \ deplibs_check_method reload_flag reload_cmds need_locks \ lt_cv_sys_global_symbol_pipe lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ old_postinstall_cmds old_postuninstall_cmds \ compiler_RC \ CC_RC \ LD_RC \ lt_prog_compiler_wl_RC \ lt_prog_compiler_pic_RC \ lt_prog_compiler_static_RC \ lt_prog_compiler_no_builtin_flag_RC \ export_dynamic_flag_spec_RC \ thread_safe_flag_spec_RC \ whole_archive_flag_spec_RC \ enable_shared_with_static_runtimes_RC \ old_archive_cmds_RC \ old_archive_from_new_cmds_RC \ predep_objects_RC \ postdep_objects_RC \ predeps_RC \ postdeps_RC \ compiler_lib_search_path_RC \ archive_cmds_RC \ archive_expsym_cmds_RC \ postinstall_cmds_RC \ postuninstall_cmds_RC \ old_archive_from_expsyms_cmds_RC \ allow_undefined_flag_RC \ no_undefined_flag_RC \ export_symbols_cmds_RC \ hardcode_libdir_flag_spec_RC \ hardcode_libdir_flag_spec_ld_RC \ hardcode_libdir_separator_RC \ hardcode_automatic_RC \ module_cmds_RC \ module_expsym_cmds_RC \ lt_cv_prog_compiler_c_o_RC \ exclude_expsyms_RC \ include_expsyms_RC; do case $var in old_archive_cmds_RC | \ old_archive_from_new_cmds_RC | \ archive_cmds_RC | \ archive_expsym_cmds_RC | \ module_cmds_RC | \ module_expsym_cmds_RC | \ old_archive_from_expsyms_cmds_RC | \ export_symbols_cmds_RC | \ extract_expsyms_cmds | reload_cmds | finish_cmds | \ postinstall_cmds | postuninstall_cmds | \ old_postinstall_cmds | old_postuninstall_cmds | \ sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) # Double-quote double-evaled strings. eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" ;; *) eval "lt_$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" ;; esac done case $lt_echo in *'\$0 --fallback-echo"') lt_echo=`$echo "X$lt_echo" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` ;; esac cfgfile="$ofile" cat <<__EOF__ >> "$cfgfile" # ### BEGIN LIBTOOL TAG CONFIG: $tagname # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc_RC # Whether or not to disallow shared libs when runtime libs are static allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_RC # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # An echo program that does not interpret backslashes. echo=$lt_echo # The archiver. AR=$lt_AR AR_FLAGS=$lt_AR_FLAGS # A C compiler. LTCC=$lt_LTCC # LTCC compiler flags. LTCFLAGS=$lt_LTCFLAGS # A language-specific compiler. CC=$lt_compiler_RC # Is the compiler the GNU C compiler? with_gcc=$GCC_RC gcc_dir=\`gcc -print-file-name=. | $SED 's,/\.$,,'\` gcc_ver=\`gcc -dumpversion\` # An ERE matcher. EGREP=$lt_EGREP # The linker used to build libraries. LD=$lt_LD_RC # Whether we need hard or soft links. LN_S=$lt_LN_S # A BSD-compatible nm program. NM=$lt_NM # A symbol stripping program STRIP=$lt_STRIP # Used to examine libraries when file_magic_cmd begins "file" MAGIC_CMD=$MAGIC_CMD # Used on cygwin: DLL creation program. DLLTOOL="$DLLTOOL" # Used on cygwin: object dumper. OBJDUMP="$OBJDUMP" # Used on cygwin: assembler. AS="$AS" # The name of the directory that contains temporary libtool files. objdir=$objdir # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl_RC # Object file suffix (normally "o"). objext="$ac_objext" # Old archive suffix (normally "a"). libext="$libext" # Shared library suffix (normally ".so"). shrext_cmds='$shrext_cmds' # Executable file suffix (normally ""). exeext="$exeext" # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic_RC pic_mode=$pic_mode # What is the maximum length of a command? max_cmd_len=$lt_cv_sys_max_cmd_len # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o_RC # Must we lock files when doing compilation? need_locks=$lt_need_locks # Do we need the lib prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static_RC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_RC # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_RC # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec_RC # Compiler flag to generate thread-safe objects. thread_safe_flag_spec=$lt_thread_safe_flag_spec_RC # Library versioning type. version_type=$version_type # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Commands used to build and install an old-style archive. RANLIB=$lt_RANLIB old_archive_cmds=$lt_old_archive_cmds_RC old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_RC # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_RC # Commands used to build and install a shared archive. archive_cmds=$lt_archive_cmds_RC archive_expsym_cmds=$lt_archive_expsym_cmds_RC postinstall_cmds=$lt_postinstall_cmds postuninstall_cmds=$lt_postuninstall_cmds # Commands used to build a loadable module (assumed same as above if empty) module_cmds=$lt_module_cmds_RC module_expsym_cmds=$lt_module_expsym_cmds_RC # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # Dependencies to place before the objects being linked to create a # shared library. predep_objects=\`echo $lt_predep_objects_RC | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place after the objects being linked to create a # shared library. postdep_objects=\`echo $lt_postdep_objects_RC | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Dependencies to place before the objects being linked to create a # shared library. predeps=$lt_predeps_RC # Dependencies to place after the objects being linked to create a # shared library. postdeps=$lt_postdeps_RC # The library search path used internally by the compiler when linking # a shared library. compiler_lib_search_path=\`echo $lt_compiler_lib_search_path_RC | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method == file_magic. file_magic_cmd=$lt_file_magic_cmd # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag_RC # Flag that forces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag_RC # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # Same as above, but a single script fragment to be evaled but not shown. finish_eval=$lt_finish_eval # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # This is the shared library runtime path variable. runpath_var=$runpath_var # This is the shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action_RC # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_RC # If ld is used when linking, flag to hardcode \$libdir into # a binary during linking. This must work even if \$libdir does # not exist. hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_RC # Whether we need a single -rpath flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator_RC # Set to yes if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the # resulting binary. hardcode_direct=$hardcode_direct_RC # Set to yes if using the -LDIR flag during linking hardcodes DIR into the # resulting binary. hardcode_minus_L=$hardcode_minus_L_RC # Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into # the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var_RC # Set to yes if building a shared library automatically hardcodes DIR into the library # and all subsequent libraries and executables linked against it. hardcode_automatic=$hardcode_automatic_RC # Variables whose values should be saved in libtool wrapper scripts and # restored at relink time. variables_saved_for_relink="$variables_saved_for_relink" # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs_RC # Compile-time system search path for libraries sys_lib_search_path_spec=\`echo $lt_sys_lib_search_path_spec | \$SED -e "s@\${gcc_dir}@\\\${gcc_dir}@g;s@\${gcc_ver}@\\\${gcc_ver}@g"\` # Run-time system search path for libraries sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Fix the shell variable \$srcfile for the compiler. fix_srcfile_path="$fix_srcfile_path_RC" # Set to yes if exported symbols are required. always_export_symbols=$always_export_symbols_RC # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds_RC # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms_RC # Symbols that must always be exported. include_expsyms=$lt_include_expsyms_RC # ### END LIBTOOL TAG CONFIG: $tagname __EOF__ else # If there is no Makefile yet, we rely on a make rule to execute # `config.status --recheck' to rerun these tests and create the # libtool script then. ltmain_in=`echo $ltmain | sed -e 's/\.sh$/.in/'` if test -f "$ltmain_in"; then test -f Makefile && make "$ltmain" fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ;; *) as_fn_error $? "Unsupported tag name: $tagname" "$LINENO" 5 ;; esac # Append the new tag name to the list of available tags. if test -n "$tagname" ; then available_tags="$available_tags $tagname" fi fi done IFS="$lt_save_ifs" # Now substitute the updated list of available tags. if eval "sed -e 's/^available_tags=.*\$/available_tags=\"$available_tags\"/' \"$ofile\" > \"${ofile}T\""; then mv "${ofile}T" "$ofile" chmod +x "$ofile" else rm -f "${ofile}T" as_fn_error $? "unable to update list of available tagged configurations." "$LINENO" 5 fi fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ac_aux_dir/ltmain.sh" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' # Prevent multiple expansion INCLUDES='-I$(top_srcdir)/gw -I$(top_builddir)/gw' ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_opendir+:} false; then : break fi done if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __cplusplus /* Ultrix mips cc rejects this sort of thing. */ typedef int charset[2]; const charset cs = { 0, 0 }; /* SunOS 4.1.1 cc rejects this. */ char const *const *pcpcc; char **ppc; /* NEC SVR4.0.2 mips cc rejects this. */ struct point {int x, y;}; static struct point const zero = {0,0}; /* AIX XL C 1.02.0.0 rejects this. It does not let you subtract one const X* pointer from another in an arm of an if-expression whose if-part is not a constant expression */ const char *g = "string"; pcpcc = &g + (g ? g-g : 0); /* HPUX 7.0 cc rejects these. */ ++pcpcc; ppc = (char**) pcpcc; pcpcc = (char const *const *) ppc; { /* SCO 3.2v4 cc rejects this sort of thing. */ char tx; char *t = &tx; char const *s = 0 ? (char *) 0 : (char const *) 0; *t++ = 0; if (s) return 0; } { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ int x[] = {25, 17}; const int *foo = &x[0]; ++foo; } { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ typedef const int *iptr; iptr p = 0; ++p; } { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ struct s { int j; const int *ap[3]; } bx; struct s *b = &bx; b->j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; if (!foo) return 0; } return !cs[0] && !zero.x; #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_const=yes else ac_cv_c_const=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 $as_echo "$ac_cv_c_const" >&6; } if test $ac_cv_c_const = no; then $as_echo "#define const /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if ${ac_cv_struct_tm+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_struct_tm=time.h else ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then $as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5 $as_echo_n "checking for working volatile... " >&6; } if ${ac_cv_c_volatile+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { volatile int x; int * volatile y = (int *) 0; return !x && !y; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_volatile=yes else ac_cv_c_volatile=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5 $as_echo "$ac_cv_c_volatile" >&6; } if test $ac_cv_c_volatile = no; then $as_echo "#define volatile /**/" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether closedir returns void" >&5 $as_echo_n "checking whether closedir returns void... " >&6; } if ${ac_cv_func_closedir_void+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_closedir_void=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include <$ac_header_dirent> #ifndef __cplusplus int closedir (); #endif int main () { return closedir (opendir (".")) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_closedir_void=no else ac_cv_func_closedir_void=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_closedir_void" >&5 $as_echo "$ac_cv_func_closedir_void" >&6; } if test $ac_cv_func_closedir_void = yes; then $as_echo "#define CLOSEDIR_VOID 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5 $as_echo_n "checking for error_at_line... " >&6; } if ${ac_cv_lib_error_at_line+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { error_at_line (0, 0, "", 0, "an error occurred"); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_error_at_line=yes else ac_cv_lib_error_at_line=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_error_at_line" >&5 $as_echo "$ac_cv_lib_error_at_line" >&6; } if test $ac_cv_lib_error_at_line = no; then case " $LIBOBJS " in *" error.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS error.$ac_objext" ;; esac fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if ${ac_cv_func_malloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working memcmp" >&5 $as_echo_n "checking for working memcmp... " >&6; } if ${ac_cv_func_memcmp_working+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_memcmp_working=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Some versions of memcmp are not 8-bit clean. */ char c0 = '\100', c1 = '\200', c2 = '\201'; if (memcmp(&c0, &c2, 1) >= 0 || memcmp(&c1, &c2, 1) >= 0) return 1; /* The Next x86 OpenStep bug shows up only when comparing 16 bytes or more and with at least one buffer not starting on a 4-byte boundary. William Lewis provided this test program. */ { char foo[21]; char bar[21]; int i; for (i = 0; i < 4; i++) { char *a = foo + i; char *b = bar + i; strcpy (a, "--------01111111"); strcpy (b, "--------10000000"); if (memcmp (a, b, 16) >= 0) return 1; } return 0; } ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_memcmp_working=yes else ac_cv_func_memcmp_working=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_memcmp_working" >&5 $as_echo "$ac_cv_func_memcmp_working" >&6; } test $ac_cv_func_memcmp_working = no && case " $LIBOBJS " in *" memcmp.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS memcmp.$ac_objext" ;; esac EXE_EXT="" case "$host" in *-sun-solaris*) CFLAGS="$CFLAGS -DSunOS=1" ;; *-cygwin*) EXE_EXT=".exe" ;; *apple-darwin*) CFLAGS="$CFLAGS -DDARWIN=1" LIBS="$LIBS -L/opt/local/lib" ;; *-linux-*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE" LDFLAGS="$LDFLAGS -rdynamic" ;; *-*-openbsd* | *-*-freebsd*) CFLAGS="$CFLAGS -pthread" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_exit in -lpthread" >&5 $as_echo_n "checking for pthread_exit in -lpthread... " >&6; } if ${ac_cv_lib_pthread_pthread_exit+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_exit (); int main () { return pthread_exit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pthread_pthread_exit=yes else ac_cv_lib_pthread_pthread_exit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_exit" >&5 $as_echo "$ac_cv_lib_pthread_pthread_exit" >&6; } if test "x$ac_cv_lib_pthread_pthread_exit" = xyes; then : LIBS="$LIBS -lpthread"; pthread="yes" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_exit in -lc_r" >&5 $as_echo_n "checking for pthread_exit in -lc_r... " >&6; } if ${ac_cv_lib_c_r_pthread_exit+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pthread_exit (); int main () { return pthread_exit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_c_r_pthread_exit=yes else ac_cv_lib_c_r_pthread_exit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_exit" >&5 $as_echo "$ac_cv_lib_c_r_pthread_exit" >&6; } if test "x$ac_cv_lib_c_r_pthread_exit" = xyes; then : LIBS="$LIBS -lc_r"; pthread="yes" fi fi ;; esac # Check whether --with-cflags was given. if test "${with_cflags+set}" = set; then : withval=$with_cflags; CFLAGS="$CFLAGS $withval" fi # Check whether --with-libs was given. if test "${with_libs+set}" = set; then : withval=$with_libs; LIBS="$LIBS $withval" fi nl=' ' echo "${nl}${T_MD}Configuring PAM support ...${T_ME}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with PAM support" >&5 $as_echo_n "checking whether to compile with PAM support... " >&6; } # Check whether --enable-pam was given. if test "${enable_pam+set}" = set; then : enableval=$enable_pam; if test "$enableval" = "yes" then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_end in -lpam" >&5 $as_echo_n "checking for pam_end in -lpam... " >&6; } if ${ac_cv_lib_pam_pam_end+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpam $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char pam_end (); int main () { return pam_end (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_pam_pam_end=yes else ac_cv_lib_pam_pam_end=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pam_pam_end" >&5 $as_echo "$ac_cv_lib_pam_pam_end" >&6; } if test "x$ac_cv_lib_pam_pam_end" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPAM 1 _ACEOF LIBS="-lpam $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5 $as_echo_n "checking for main in -ldl... " >&6; } if ${ac_cv_lib_dl_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_main=yes else ac_cv_lib_dl_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5 $as_echo "$ac_cv_lib_dl_main" >&6; } if test "x$ac_cv_lib_dl_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF LIBS="-ldl $LIBS" fi ac_fn_c_check_header_mongrel "$LINENO" "security/pam_appl.h" "ac_cv_header_security_pam_appl_h" "$ac_includes_default" if test "x$ac_cv_header_security_pam_appl_h" = xyes; then : $as_echo "#define HAVE_PAM_SECURITY 1" >>confdefs.h $as_echo "#define HAVE_PAM 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabling PAM for authentication" >&5 $as_echo "enabling PAM for authentication" >&6; } else ac_fn_c_check_header_mongrel "$LINENO" "pam/pam_appl.h" "ac_cv_header_pam_pam_appl_h" "$ac_includes_default" if test "x$ac_cv_header_pam_pam_appl_h" = xyes; then : $as_echo "#define HAVE_PAM_PAM 1" >>confdefs.h $as_echo "#define HAVE_PAM 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabling PAM for authentication" >&5 $as_echo "enabling PAM for authentication" >&6; } fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } fi fi # Check whether --with-ssl was given. if test "${with_ssl+set}" = set; then : withval=$with_ssl; if test -d "$withval"; then ssllib="$withval/lib"; sslinc="$withval/include" else as_fn_error $? "Unable to find OpenSSL libs and/or directories at $withval" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SSL support" >&5 $as_echo_n "checking whether to compile with SSL support... " >&6; } # Check whether --enable-ssl was given. if test "${enable_ssl+set}" = set; then : enableval=$enable_ssl; if test "$enableval" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 $as_echo "disabled" >&6; } ssl=no else ssl=yes fi else ssl=yes fi if test "$ssl" = "yes" ; then if test "x$ssllib" = "x" && test "x$sslinc" = "x"; then for loc in /usr/lib /usr/local/ssl/lib /usr/local/openssl/lib; do if test -f "$loc/libssl.a"; then ssllib="$loc" fi done for loc in /usr/include/ssl /usr/include/openssl /usr/local/ssl/include \ /usr/local/openssl/include; do if test -d "$loc"; then sslinc="$loc" fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: trying $ssllib $sslinc" >&5 $as_echo "trying $ssllib $sslinc" >&6; } fi if test "x$ssllib" != "x" && test "x$sslinc" != "x"; then CFLAGS="$CFLAGS -I$sslinc" LIBS="$LIBS -L$ssllib" # Extract the first word of "openssl", so it can be a program name with args. set dummy openssl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_OPENSSL+:} false; then : $as_echo_n "(cached) " >&6 else case $OPENSSL in [\\/]* | ?:[\\/]*) ac_cv_path_OPENSSL="$OPENSSL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_OPENSSL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_OPENSSL" && ac_cv_path_OPENSSL="no" ;; esac fi OPENSSL=$ac_cv_path_OPENSSL if test -n "$OPENSSL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OPENSSL" >&5 $as_echo "$OPENSSL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$OPENSSL" = "yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking openssl version" >&5 $as_echo_n "checking openssl version... " >&6; } openssl_version=`$OPENSSL version | awk '{print $2}'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $openssl_version" >&5 $as_echo "$openssl_version" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CRYPTO_lock in -lcrypto" >&5 $as_echo_n "checking for CRYPTO_lock in -lcrypto... " >&6; } if ${ac_cv_lib_crypto_CRYPTO_lock+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char CRYPTO_lock (); int main () { return CRYPTO_lock (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_crypto_CRYPTO_lock=yes else ac_cv_lib_crypto_CRYPTO_lock=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_CRYPTO_lock" >&5 $as_echo "$ac_cv_lib_crypto_CRYPTO_lock" >&6; } if test "x$ac_cv_lib_crypto_CRYPTO_lock" = xyes; then : LIBS="$LIBS -lcrypto" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5 $as_echo_n "checking for SSL_library_init in -lssl... " >&6; } if ${ac_cv_lib_ssl_SSL_library_init+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SSL_library_init (); int main () { return SSL_library_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ssl_SSL_library_init=yes else ac_cv_lib_ssl_SSL_library_init=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_library_init" >&5 $as_echo "$ac_cv_lib_ssl_SSL_library_init" >&6; } if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_connect in -lssl" >&5 $as_echo_n "checking for SSL_connect in -lssl... " >&6; } if ${ac_cv_lib_ssl_SSL_connect+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SSL_connect (); int main () { return SSL_connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ssl_SSL_connect=yes else ac_cv_lib_ssl_SSL_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_connect" >&5 $as_echo "$ac_cv_lib_ssl_SSL_connect" >&6; } if test "x$ac_cv_lib_ssl_SSL_connect" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSSL 1 _ACEOF LIBS="-lssl $LIBS" fi for ac_header in openssl/x509.h openssl/rsa.h openssl/crypto.h \ openssl/pem.h openssl/ssl.h openssl/err.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the OpenSSL library is multithread-enabled" >&5 $as_echo_n "checking whether the OpenSSL library is multithread-enabled... " >&6; } if test "$cross_compiling" = yes; then : echo "Cross-compiling; make sure your SSL library is multithread-enabled" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define OPENSSL_THREAD_DEFINES #include int main(void) { #if defined(THREADS) exit(0); #elif defined(OPENSSL_THREADS) exit(0); #else exit(1); #endif } _ACEOF if ac_fn_c_try_run "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_LIBSSL 1" >>confdefs.h LIBS="$LIBS -lssl" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to compile with SSL support" >&5 $as_echo_n "checking whether to compile with SSL support... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # Check whether --enable-ssl-thread-test was given. if test "${enable_ssl_thread_test+set}" = set; then : enableval=$enable_ssl_thread_test; if test "$enableval" = no ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, continue forced" >&5 $as_echo "no, continue forced" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Either get a multithread-enabled SSL or configure with --disable-ssl" "$LINENO" 5 fi fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi fi nl=' ' echo "${nl}${T_MD}Configuring DocBook support ...${T_ME}" # Extract the first word of "jade", so it can be a program name with args. set dummy jade; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OLDJADE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OLDJADE"; then ac_cv_prog_OLDJADE="$OLDJADE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OLDJADE="jade" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_OLDJADE" && ac_cv_prog_OLDJADE="no" fi fi OLDJADE=$ac_cv_prog_OLDJADE if test -n "$OLDJADE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OLDJADE" >&5 $as_echo "$OLDJADE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$OLDJADE" = "no" ; then # Extract the first word of "openjade", so it can be a program name with args. set dummy openjade; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JADE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JADE"; then ac_cv_prog_JADE="$JADE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JADE="openjade" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_JADE" && ac_cv_prog_JADE="no" fi fi JADE=$ac_cv_prog_JADE if test -n "$JADE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JADE" >&5 $as_echo "$JADE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else JADE=$OLDJADE fi # Extract the first word of "jadetex", so it can be a program name with args. set dummy jadetex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JADETEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JADETEX"; then ac_cv_prog_JADETEX="$JADETEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JADETEX="jadetex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_JADETEX" && ac_cv_prog_JADETEX="no" fi fi JADETEX=$ac_cv_prog_JADETEX if test -n "$JADETEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JADETEX" >&5 $as_echo "$JADETEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "pdfjadetex", so it can be a program name with args. set dummy pdfjadetex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_PDFJADETEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$PDFJADETEX"; then ac_cv_prog_PDFJADETEX="$PDFJADETEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_PDFJADETEX="pdfjadetex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_PDFJADETEX" && ac_cv_prog_PDFJADETEX="no" fi fi PDFJADETEX=$ac_cv_prog_PDFJADETEX if test -n "$PDFJADETEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFJADETEX" >&5 $as_echo "$PDFJADETEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "dvips", so it can be a program name with args. set dummy dvips; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DVIPS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DVIPS"; then ac_cv_prog_DVIPS="$DVIPS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DVIPS="dvips" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_DVIPS" && ac_cv_prog_DVIPS="no" fi fi DVIPS=$ac_cv_prog_DVIPS if test -n "$DVIPS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DVIPS" >&5 $as_echo "$DVIPS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "fig2dev", so it can be a program name with args. set dummy fig2dev; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_FIG2DEV+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$FIG2DEV"; then ac_cv_prog_FIG2DEV="$FIG2DEV" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_FIG2DEV="fig2dev" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_FIG2DEV" && ac_cv_prog_FIG2DEV="no" fi fi FIG2DEV=$ac_cv_prog_FIG2DEV if test -n "$FIG2DEV"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FIG2DEV" >&5 $as_echo "$FIG2DEV" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "convert", so it can be a program name with args. set dummy convert; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CONVERT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CONVERT"; then ac_cv_prog_CONVERT="$CONVERT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CONVERT="convert" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CONVERT" && ac_cv_prog_CONVERT="no" fi fi CONVERT=$ac_cv_prog_CONVERT if test -n "$CONVERT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CONVERT" >&5 $as_echo "$CONVERT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi found="" for loc in /usr /usr/local /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/html/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/html/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/html/docbook.dsl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : HTML_DSL=$file; found=1 fi fi done fi done found="" for loc in /usr /usr/local /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/print/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/print/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/print/docbook.dsl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : TEX_DSL=$file; found=1 fi fi done fi done found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/dtds/decls/xml.dcl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/dtds/decls/xml.dcl \ ${loc}/share/dsssl/docbook-dsssl/dtds/decls/xml.dcl ; do if test "x$found" = "x" ; then as_ac_File=`$as_echo "ac_cv_file_$file" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $file" >&5 $as_echo_n "checking for $file... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r "$file"; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : XML_DCL=$file; found=1 fi fi done fi done # Check whether --enable-docs was given. if test "${enable_docs+set}" = set; then : enableval=$enable_docs; if test "$enableval" = "yes" then DOCSTARGET="docs" else DOCSTARGET="no-docs" fi fi if test "x$HTML_DSL" = "x" -o "x$TEX_DSL" = "x" \ || test "$JADE" = "no" \ || test "$JADETEX" = "no" \ || test "$PDFJADETEX" = "no" \ || test "$DVIPS" = "no" \ || test "$FIG2DEV" = "no" \ || test "$CONVERT" = "no" \ || test "$DOCSTARGET" = "no-docs" then DOCSTARGET="no-docs" else DOCSTARGET="docs" fi case "$DOCSTARGET" in no-docs) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Not building documentation." >&5 $as_echo "Not building documentation." >&6; } ;; docs) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Documentation will be built as well." >&5 $as_echo "Documentation will be built as well." >&6; } ;; esac DOCDRAFTS="IGNORE" # Check whether --enable-drafts was given. if test "${enable_drafts+set}" = set; then : enableval=$enable_drafts; if test "$enableval" = "yes" then DOCDRAFTS="INCLUDE" else DOCDRAFTS="IGNORE" fi fi if test "x$DOCSTARGET" = "xdocs" then case "$DOCDRAFTS" in INCLUDE) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Documentation will include drafts." >&5 $as_echo "Documentation will include drafts." >&6; } ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Ct-Lib support" >&5 $as_echo_n "checking for Ct-Lib support... " >&6; } # Check whether --with-ctlib was given. if test "${with_ctlib+set}" = set; then : withval=$with_ctlib; if test "$withval" = "yes"; then withval=/opt/sybase fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then CTLIB_INCDIR=$withval/include CTLIB_LIBDIR=$withval/lib else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Invalid Ct-Lib directory - unable to find ctpublic.h" "$LINENO" 5 fi CTLIB_LFLAGS="-L$CTLIB_LIBDIR -lct -lcs -lsybtcl -lcomn -lintl" CTLIB_INCLUDE="-I$CTLIB_INCDIR" $as_echo "#define HAVE_CTLIB 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } have_db=yes ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : CTLIB_LFLAGS="$CTLIB_LFLAGS -ldl" fi fi fi if test "x$DBTYPE" = "x" ; then DBTYPE="ctlib" else DBTYPE="$DBTYPE-ctlib" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FreeTDS Ct-Lib support" >&5 $as_echo_n "checking for FreeTDS Ct-Lib support... " >&6; } # Check whether --with-mssql was given. if test "${with_mssql+set}" = set; then : withval=$with_mssql; if test "$withval" = "yes"; then withval=/usr/local fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then CTLIB_INCDIR=$withval/include CTLIB_LIBDIR=$withval/lib else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Invalid FreeTDS directory - unable to find ctpublic.h" "$LINENO" 5 fi CTLIB_LFLAGS="-L$CTLIB_LIBDIR -lct" CTLIB_INCLUDE="-I$CTLIB_INCDIR" $as_echo "#define HAVE_CTLIB 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } have_db=yes ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : CTLIB_LFLAGS="$CTLIB_LFLAGS -ldl" fi fi fi if test "x$DBTYPE" = "x" ; then DBTYPE="freetds" else DBTYPE="$DBTYPE-freetds" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --with-kannel-dir was given. if test "${with_kannel_dir+set}" = set; then : withval=$with_kannel_dir; gwloc="" if test -d "$withval" ; then gwloc="$withval" fi fi # Extract the first word of "gw-config", so it can be a program name with args. set dummy gw-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_GW_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $GW_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_GW_CONFIG="$GW_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy="$gwloc/bin:$gwloc:../gateway/gw/:$PATH" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_GW_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_GW_CONFIG" && ac_cv_path_GW_CONFIG="no" ;; esac fi GW_CONFIG=$ac_cv_path_GW_CONFIG if test -n "$GW_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GW_CONFIG" >&5 $as_echo "$GW_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$GW_CONFIG" = "no"; then found="" for loc in $pgsqlloc /usr /usr/local ; do if test "x$found" = "x" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Kannel include files in" >&5 $as_echo_n "checking for Kannel include files in... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $loc" >&5 $as_echo "$loc" >&6; } as_ac_File=`$as_echo "ac_cv_file_"$loc/include/kannel/gw-config.h"" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for \"$loc/include/kannel/gw-config.h\"" >&5 $as_echo_n "checking for \"$loc/include/kannel/gw-config.h\"... " >&6; } if eval \${$as_ac_File+:} false; then : $as_echo_n "(cached) " >&6 else test "$cross_compiling" = yes && as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 if test -r ""$loc/include/kannel/gw-config.h""; then eval "$as_ac_File=yes" else eval "$as_ac_File=no" fi fi eval ac_res=\$$as_ac_File { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_File"\" = x"yes"; then : CFLAGS="$CFLAGS -I$loc/include/kannel -I$loc/include/kannel"; LDFLAGS="$LDFLAGS -L$loc/lib/kannel -lwap -lgwlib"; found=1 fi fi done; if test "x$found" != "x1" ; then as_fn_error $? "Unable to find gw-config.h, please provide a --with-kannel-dir= location" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking Kannel version" >&5 $as_echo_n "checking Kannel version... " >&6; } gw_version=`$GW_CONFIG --version` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_version" >&5 $as_echo "$gw_version" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking Kannel libs" >&5 $as_echo_n "checking Kannel libs... " >&6; } if ! $GW_CONFIG --libs &>/dev/null ; then LIBS="$LIBS `$GW_CONFIG --libs`" gw_libdir=`$GW_CONFIG --libs` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_libdir" >&5 $as_echo "$gw_libdir" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking Kannel includes" >&5 $as_echo_n "checking Kannel includes... " >&6; } if ! $GW_CONFIG --cflags &>/dev/null ; then CFLAGS="$CFLAGS `$GW_CONFIG --cflags`" gw_incdir=`$GW_CONFIG --cflags` { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gw_incdir" >&5 $as_echo "$gw_incdir" >&6; } fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cfg_create in -lgwlib" >&5 $as_echo_n "checking for cfg_create in -lgwlib... " >&6; } if ${ac_cv_lib_gwlib_cfg_create+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgwlib $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char cfg_create (); int main () { return cfg_create (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_gwlib_cfg_create=yes else ac_cv_lib_gwlib_cfg_create=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gwlib_cfg_create" >&5 $as_echo "$ac_cv_lib_gwlib_cfg_create" >&6; } if test "x$ac_cv_lib_gwlib_cfg_create" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBGWLIB 1 _ACEOF LIBS="-lgwlib $LIBS" else as_fn_error $? "Kannel gwlib is required!" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Kannel's DB support" >&5 $as_echo_n "checking for Kannel's DB support... " >&6; } if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main( #if defined(HAVE_SQLITE3) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="sqlite3" rpm_requires="sqlite3-devel >= 1.8" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_SQLITE) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="sqlite" rpm_requires="sqlite2-devel >= 2.7" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_PGSQL) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="pgsql" rpm_requires="postgresql-devel >= 7.2" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_ORACLE) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="oracle" rpm_requires="oracle-instantclient-devel >= 8" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_MYSQL) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="mysql" rpm_requires="mysql-devel >= 3.23" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gw-config.h" int main(void){ #if defined(HAVE_SDB) exit(0); #endif exit(1); } _ACEOF if ac_fn_c_try_run "$LINENO"; then : rpm_suffix="sdb" rpm_requires="libsdb-devel >= 0.5" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi ac_config_files="$ac_config_files Makefile gw/Makefile rpm/opensmppbox.spec" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by opensmppbox $as_me svn, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ opensmppbox config.status svn configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "sb-config.h") CONFIG_HEADERS="$CONFIG_HEADERS sb-config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "gw/Makefile") CONFIG_FILES="$CONFIG_FILES gw/Makefile" ;; "rpm/opensmppbox.spec") CONFIG_FILES="$CONFIG_FILES rpm/opensmppbox.spec" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in "$ac_file" | "$ac_file":* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for "$ac_file"" >`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # So let's grep whole file. if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi gateway-1.4.5/addons/opensmppbox/sb-config.h.in0000644000175000017500000000712612061727435020150 0ustar toljtolj/* sb-config.h.in. Generated from configure.in by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ #undef CLOSEDIR_VOID /* GW_NAME */ #undef GW_NAME /* GW_VERSION */ #undef GW_VERSION /* Defined to 1 */ #undef HAVE_CTLIB /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL /* Define to 1 if you have the `gwlib' library (-lgwlib). */ #undef HAVE_LIBGWLIB /* Define to 1 if you have the `pam' library (-lpam). */ #undef HAVE_LIBPAM /* Define to 1 if you have the `ssl' library (-lssl). */ #undef HAVE_LIBSSL /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_CRYPTO_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_ERR_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_PEM_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_RSA_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_SSL_H /* Define to 1 if you have the header file. */ #undef HAVE_OPENSSL_X509_H /* "HAVE_PAM" */ #undef HAVE_PAM /* "HAVE_PAM_PAM" */ #undef HAVE_PAM_PAM /* "HAVE_PAM_SECURITY" */ #undef HAVE_PAM_SECURITY /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* VERSION */ #undef VERSION /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to empty if the keyword `volatile' does not work. Warning: valid code using `volatile' can become incorrect without. Disable with care. */ #undef volatile gateway-1.4.5/addons/opensmppbox/example/0000755000175000017500000000000013312227716017145 5ustar toljtoljgateway-1.4.5/addons/opensmppbox/example/smpplogins.txt.example0000644000175000017500000000011411416011564023522 0ustar toljtoljsystem-id-01 password-01 system-type-01 client-02 password-02 vma 127.0.0.1 gateway-1.4.5/addons/opensmppbox/example/opensmppbox.conf.example0000644000175000017500000000167212061727435024031 0ustar toljtolj# sample opensmppbox.conf group = core dlr-storage = mysql # this group defines your opensmppbox group = opensmppbox # our boxc type opensmppbox-id = abcd # the port to listen on for smpp connections opensmppbox-port = 2346 # we connect to the following host as a box bearerbox-host = localhost bearerbox-port = 14009 log-level = 0 log-file = opensmppbox.log our-system-id = chim1 route-to-smsc = my-default-smsc # see sample smpplogins.txt smpp-logins = "/home/opensmppbox/etc/smpplogins.txt" # the following is just standard dlr configuration group = mysql-connection id = mydlr host = localhost username = kannel password = secret database = kannel # you can increase this upon a higher load max-connections = 1 group = dlr-db id = mydlr table = dlr field-smsc = smsc field-timestamp = ts field-destination = destination field-source = source field-service = service field-url = url field-mask = mask field-status = status field-boxc-id = boxcid gateway-1.4.5/addons/opensmppbox/README0000644000175000017500000000212712061727435016377 0ustar toljtoljOVERVIEW ======== OpenSMPPBox is a special Kannel box that listens for smpp connections and accepts and sends sms messages from and to smpp clients. OpenSMPPBox behaves similar to other Kannel boxes and share a compatible configuration file format and command line options. After starting opensmppbox, a new connection to bearerbox is made for each smpp client that is connecting. This (new) connection with it's own 'smsbox-id' is dedicated to sending and receiving messages for this particular smpp client. INSTALLATION ============ Please read the INSTALL file for further instructions. If in a hurry, the quick explanation is: ./bootstrap ./configure make And finally, as root: make install You need to have a development version of Kannel installed in order to compile opensmppbox. The Userguide has also valuable information about the install and configuration steps. To create the userguide, run ./configure with --enable-docs and then type "make docs". HELP ==== The best to ask for help is on Kannel's mailing lists. Please visit Kannel's site for more information: http://www.kannel.org/ gateway-1.4.5/addons/opensmppbox/NEWS0000644000175000017500000000013211453122245016200 0ustar toljtoljOpenSMPPBox Stand Alone Module Please read the ChangeLog file to see the latest changes. gateway-1.4.5/addons/opensmppbox/doc/0000755000175000017500000000000013312227716016257 5ustar toljtoljgateway-1.4.5/addons/opensmppbox/doc/SMPPBox.png0000644000175000017500000002644111416011564020217 0ustar toljtolj‰PNG  IHDR‚<úäF¾ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFPLTE   ,$0 <48@ 0(((HH ,,0H$ U$ Y$ ,@<44a( <84e($8<4,@DD}m,$m,(@@@8Py0,$L(P},PuLHH4,,P@]$…800U…8]m8]u‘<48]}8]8]Hi(YYY]YU]YY™@8@emLm(De…@e‘Hii¡DÚ°-×_RŒ × ˆ¨U#wÅv§ªÁ(Y$`­É²`†´ƒ|F\ð%ƒ"u¾ ¨Vm~µÑP£O)É3„à ­L€Rª[Ö4@]1– QÅàÒþB M„[\T¥ 6B€Lê`¥AÐRS1ž­&Ð_¡db+ ›E`pa.?©ÿQ4 P0Ò|‰F¨VTAËô0‘Ap¹5L Š5vB[G$¤¥æÏµ—pC f¿Ò0Ah‚ÄŠ¨Œ FE­±XÅ( \Ü˯à„@[ÿ/®¬Åb{bQ­ÚFbêk×L5ÖÔ1øŸ=ì#ß^óŽ“‚Fè ™†0ø ‹T+c’FËÈ,"Æu[ ~yÛGŸö>ÿñ³ªºøÁ„ ÞØ—‡dƟÜEkÍPx¥‘ŒºŒ¨(bµŸ™:øqØGoßtðçÿïu ßx)å¡q ÄTyâ()‚½>©ß«U¥Àª‚Z‹ØÇŒv>TwïM÷œ±ø¬#¯þºw­~ù«d‚mÖe0(X°·ƒÜŠ"ÍN2Oœ€èÖýûx°ŽºÎ¿à}ïWúÄiïû®wÞl|cÕcÛ7þožOÆ÷Žc)ˆeAMh ¡ L*‚ÅŠ¢kÏbƒñÁmªÁOny胟8ë_~Ø{ÿÔÿçÑ7Ö/:vŸÓOùü+8!¼â+«úýóWàtñ 7İ.†V8Útèâ·#|/Þg¶¥¼ã¼î\®-_Za%p¾‘ ÃçE† F$LÛ_R…^KÀæãƒ¿äý‡_vïý_Û´è¤=O>åDÆM}mÿxáùéxÀíì§nˆ» þâæzC oâýóî¸ãD]Ì0ÜóÚyÜÚ³/Ÿ68cù©o­jû@ÞÑ®]`BJ1•#Vr'C6ÎX†ï‡q}êx]cZÛJ–,÷?~öyÑ_îY3Çsf‡_zÆíàï;"xàå§þ8 yzû¢¡® Øs˜wÁÂûócž€ûw0ïW¿Ý4zn˜¹Ü±Ç™ÃCc+ÜÐÀ½ðÈ3¼oþ°º¡aå=Ïð¾ù+Ü9¬psÏZ;ç•ÕºrhZµ  eøb¡—üã €*oî^²>ã©Æ²±æÛ·|oÁÇ>6¿xûxa6¯ÿùCõ£Nûï_tßš‡}â|>»³:ñÀWVÆüÕì°÷Ÿœ³ï&]Ìð+£ç¡›Îîë¬\¹o ¹‡g†X1èÙÕð‡‡X1ß Áb†7±øÅŸ-~rå9Ó# m!€»€†,(º#¬Í¨žMûû€µ‡¡.äŸLóßuÆÀg¬{þçívÄñ'ïsò±Çɹç–O}ùü3ÏœÞGÝ}¶mÞB§>` ÷œåæÝS¡§¼ŸûvÞ¨?áMlâÔï]¼„Mœ:1¾¯ì;%‚Ë Ö|@ATLµ—Ɔ“Ñq#°Ölœ×í?뱟8€±—¾xÒ¼wü.ù÷"**ÜËÏNýÔGÎ9§›Ï:û^ÞÇö³µ9aIÍœPËæˆ}ÿtÅÙ¼vÞÈÎ ã-ŸœâW¼ÿècwæ‚a˜·ß¯8`û)ûýŠæ¬psçÝ·Âýì蟮Üét¾xøœXk4Y×â;@ˆ¿îQ×WXöyôèg@öw¹+œÏ‹§¶›ó.ŒÅQ1rïŠ_œõ™txùÜÁ.bÙ´Ó¿{ßýóÊÁî¥Ûhá’j°¿…€˜Ð7n Þ|Kb?ú·†ÍöÙ a+»ue‚ï·´qîÿÁ#þóÓ?úÑ?Ô6ûÑëßÎ~A¹©Ù9«, Ú`â0žbaæ20rÝüÆ¿þ~Èâ?yêÜOœrèØÝ¦~[ºf—L.È–Fx5îå0ˆÄð #k[·;L/=vÝïzêÜOœrÔÅ$MpÁ¦bÈ‚*ŒˆÚ Q [=PºðÁsß{y {Î0‘@Ó†¸—@`ÞÛº×F1‚l‡éΚÍM1Ÿ„ °åïÛÈ@1MŒ[2™°Ñƒ4yÜ;‚Ï(àš“g-š¨Ö²¯Œ+V5£±È¹Ï‘²ôŒ ܾ[šm¡ Âm.Õ¤r$вˠèügR(ûªÞUDã „$Tíæ@€HÀ6–¸«¤LÔw9~# ­ Ú°€¬›*B=®OêAž5Gè²vÂ~óë°º·A fø"«S$ûsÁ¶F)îL@CŠë«­Ô$.îTSê ­Rš E5 6ˆÄýá§Y$ b‰ëßSƒ¨¾Ñi(ô0‚döý…奈‹{+™X cÉý%¢ÝÞŠ­¡hZ£’ÑJ Úñ¤*¶_fbEC O6èYJlPjÅ£*BwGòA+K1jl&V¬Zk³U)}!pãM ¡4¨žV–ŠH]õ`#V¬±VdUò@?‰hù»½5ѱ¹T»ž ,kUÑ'Þkån7ÐŽÙ¿è¿ÿÃÓxM÷OL®wñ×…â—„¦åb[¤ÕàƒbZXÌÚiMêV޵Ŋ}¹²(<ÓžµÜ5ôÀ)]ÖW€¯U& š æ&…V²HO©«Ø'_X÷›'¥Ò†Ë z¬+Ëñ*q5—„viv¿·=- 3—¯1†JIáRØ[´ûoºmlvÚO2A- P”[±ï¶ùWønJqoÑt‹ „²Únì^oùY4/«­}®Ü‚°Á×Gßôx‹&Hý²‰z¼;Ëc× pÎÆL©v±*à\.·–Eñ܆ Îâ׸h‚”‡&h¤K,ÇçpÍrPuв,ßÚ±}ûÖ-E/q! E¤<4^»u›ˆ–{ðx‡+šY ˜¸h®ˆ_:ßJÀá\2A;×í¸Âæ…uØ0І&;À{Ê"d!0ç“ ÚèÈ®[DË=xœ#Ç•Þûª¥Ÿ{œ+ËÒ9pÎ3 „Bà ÈIݲ‰šûî]@iÈ3ïÔ©S‡ÑÚ[Ô}Ks§,À“{¥ <‰@íÕÅk«-bKD[h5NTÏ‹ ;w<Œá=9äÎyòôäƒ6*ßšÓµ ð¶°RXB=ðÂXXÀUÍ×{¼/®¤Àùe)ÚíõÄôG‰ª5\Ë)Áã)œ+./½ÇåøåccÞ»4BÝY]lçml2[Ž+È#ƒÜáJï¼÷cccyž“çy>6æñ·RPLÐIî‘°Ü»â†eÁ…wÞã½óÞ{¼w¾,¸ò›E—؉Öv_ŽúܸEÕÕ¸iw‰\‰»†Ëð$tÒ#[Ûƒ ªŽ@ð£tçò²,Ë¢(ʲ,sçÀå¥+,õE"ÐYGuß/hayqÎ:…ÒLØÄΖs|’vªýû@PØ\,R(Nµ,«§‚€ƒ.µ„¦QŽ»˜¹œüôŽ‹›{ýZÐ(8(`iŠñz˜ûHD®°7ð9¼8‡£×• pŽÔŽŽè§ÜŠræAŠÖzíÜR¸Ì³ì±ãRˆ§ p# znÝ@žƒ÷WEñí¢( ·Xºl¿I!žJÛÜH.¨ª29ý.Ÿý9?Åx*ùé©ÓÓ~n,ŠŸçy›æÏã)ÂS'¢é©ã—nt„ÉÊ<ŸX~GRˆÛëOš‘é"u~æÕMeé(Š¢˜4°=»½NÝ«z’+í `9¾,›<'6/»½FÜÍ߉GD¹cû.ÇA{ÍOÁä9ãÀÆ…Ï‚N:3»½ê%ê0ì>åôO6ëålÄ£R°Ûk÷eYžxÒÙ¸òðº`¯"mön«ÓâSs—ÿâ`·÷´ƒÔÓ ¡§h·Õ‘Î9ç½sáü´ƒÔ ‚×SÇ ½‰ˆÄîÁA"à×)Úm57WUѰ%rí Œ>‘¢Ý^ëuíÊG4pxd .øm v{=¥\:ôçÆˆªþnäÝ)ØíµF3¸gó cŒ9lRKÁn¯fOàôÓϹÒæ”ìb8Wm»^$ŽNÁn¯Ã«G«/øÆh":0»½ŽinOºmû@]pÐ )ÚmuRË¡Ks‰À¹§S´ÛjA/áœþ{šÆ*ÝC)Úmu²9H_üxuõ;—ÈØ¡Çô$‚ç®ýTe„òÉíöúÁ:÷ë¢ܶìözp |YîuÍ'·¥{O v{­íÁôûG”(_ö·Aùîìöz¬m-XCtá‚“œ/Ër«¿8âÊãS°;ä:ˆÿíË \ ü£Ç¸cR¬Ûë„¶ˆxçœsÞe¸R°; hó½ÏŒ3C_TEDÀ{ïKÑn«ãÛÄSÌÔÅ‹úFcn4m1h¯E“¿u‰Ee†Üg~ÿîÿ¤A¤h·ÕÜÉÓê6œÝ)u`½0çû÷†1Ƙ´Å ƒ^ß0™`ÅÓ‹ˆ'M·mÿ««I[ :÷ÍZöá]Ã]+Þ’«…²Ï+Àœïü+ïLÇ×tÒσ¯_çË¥¢Ž%{»X‹ØlÛ’¶=´.Ññµ·ö·rl v{=ÛŒl–ÔòúkÉ2+²gû‚ÐÅí|B51:ç{ß?»½6Á•%W¢U‡h<¨ Õw¾ ,YÞ;‚£šŽ¹-íuê ÃÁÆãiL¹‰ƒž×Æ¡ÄhxÖÁD] 8Y›E}N v{³ùªxìƒÇ@EÀ¢ ¨ó}5JQM!žJ'Q«Õj5Ù€¨•LÄZµjL–…Â’žÌI]â©{eY­†¨ çrX5™*z¦¯F)¿Û'…¸³®’Œ+8qsŒa¯Ä[1`‹É¾é&·#kÕÒ  ™±ªŠU™˜‰ºA°yßéNº&úu-ßjŽž)jDy)Ãj?.X“"Ý‘õ:òÝóUUׄ³¹3«"µZ&HRg £D¨×Q0qDN­Ð8]¤–‰ÈÁb'Û iT¢“¾…­£ŠóOKëùô™¶^?<ÁÝÜØi×D]ùŸ¸ÅÖ£ªÆD¨†‡ׄºQÅ#X]Ò« Ž{4½U_%“«jWPu»Œ†ƒàþ_4ªA…ZuP%l1É]¥÷×SØ[ôe¾XkTD­†ñ8â õFjPGÕ`­1†`ƒžÜ›âÞÔ—#dÂu`°d*jUDîŠmUƒQAê¨kM¦jÔNju… m®i!`PÂ-þ]Å’‰¨JŒ®ÚhÈÄ¢ó´‚Xnìµp5t…*&tu!äigeŒªTGµj©vâ3/»BðV }#À kˆ§.6B2©+‘€Guze/vO¡ŸlÑpq<šXŒ­ŒÔBØQ±áAì0éQí]Õ‚…)ö­‘º  ΃¶b­m$"¨«b3±"jÕ ¨…KzFð¾ø ËÕ€U&UÁbßÞ ÕY¬Uc¥:™æ’^,JÁoÆÍ„‘ £4ˆðQ±бdRW…°Úе1â–‹{¬G¦Ð·Ü¸"Ú›¢ @X¬bEkÄQQµX5NKP šä/ð·Þüæ1…Lˆ­R4xÀ ÕH]³— Äƒ:°ð™›Ú¸àìA øã,6 4P‡8j Ä]øC€˜‡ÌÈ{EEÁJ€`D =$¢¤¦LKFŠ]s;ȧn±Ð²ì-˜À‚ ][uãÛ¥i¦×4$± PÍX0·#Fo Å¡‘àAôu#U–²$ýWãª4Üô"ˆQ±¼ŽÆr¬XQTï— "¾$%¢™ Xa%À¢–0üPˆH]ÅêSDz l,vê|rAÕxÂý«¬ÄüØXÈ2DÉâhÒ“úX–µ\c‚JúªÅT»YWµöÇj­ŽŽÆg¥dªO›;fœ„ k]Ör½”»Â0 ªjc÷™ªªšeÖ®oôT ºÕçdø5œU ÚÊ¡`ÞØ+V†Ø…ãc?ùÁ AϪž ~¨˜Æf&T©¬¼YEbyÝáb­X^Û+ô͸)!èQ—T…u]³0´ÌÎêÃxòº‚ÁÓæ9!½i“ fF뫞WLBBó°tƒH ÿZXP#k J‰¨?]¶©•@œSâqõ1þ¡ Œ º®ÚofPZfð‚^Tj+ŒjCßÂÈ‚–}dÁ£®G\ \Ï¥ÛνàéeWø÷[®ÿÂ[°èÓ»4ŠH JB!Ä€ÀŒ`¬XQ«F+:7ô‚àÕË€‹Î½à³^{õ¿ó,¼|î!,Øït2E›¨›5¶ˆPq½º èNneý;Ÿ'ËØk—Dà¶L" ¬aM XkTH-üàñ'Fwàf8åæÿ~ç–·ú,ü vµ“ –ðòj5²0€A„ZåmÈP+q“—ÜÐ ‚ë‹nþô¥ÿø1Þù£¥—ÁE»äQ#ãL˜k% ÑuPV‡,„µ™¶,°|o.¸.;ôÂ,¿õ.Zz °Þyý.‡ÀóFHCUktp«¯Ž€dö¢ÙI»¿›#×rëþÞOÿ‘Mß/‘Ù¶q…Àb[TPùuHCMŠÁô!Ÿ÷Ô"J—‡š¢D*g–ÍDÕ @cqoÛý’šI<.‡@ѪÅ qÜvÖ²¬Q-™ÔÕ`3QT}BЧ‚ œe– ,qo%`›‰µaqo `â¢;ò„ o#Hœ3¶„…Ó¦% bu¨l R âºSZ÷¤Y³®´×b¨ÒM&Sù q›ˆÖÚLVÿÌ„ {ì6α4„Ž—¢që¥êöW©«ÁˆŠµX±«(‚~)ì1Ɉ€T„S `žªèX¹{åøŽYª=Œ–Ýó‰&ȃ„)4bËçt#«cGlÄŒ²Ú•ࡸ1!è/¶6M@Óõ°ñ›¸¯L‹=™GAÔú|/œ+ÚC)u_…Zc ¨a‚3v‹;û”X÷J]ä5¼÷p…‡Â¥DÔo&*¬daÏLØó*® ì¶°íiC7ñ9¾$˜ hY=‘ôbƒ%>&#k4ä‰~›yT…’ç Ä1ŠÏ½ÇQ:WL,Æ)õÚ5ðàJ&Ƥu#qž»Э[‹ à½/q8‡/˜ð<¢„ {r(œ+qÚ ¡ Ø¢(ÊrÇö­[Š_:Œy_:J‡óø‰OoO‰¨çjàP§NcA®‡1¢æàƒwàð¥#ÇO(ÆãÜb;ÝrïÔ…]K-™dt)Ï®t8Bþ*ÆãV~íý£µAž…©u cR#6øã*ï‰r”ŽrÆ?†%%¢ž»g…-¬4c¬ñÕ­\Þ®Àã;Æ¡†øÐîµcÉÕæHi\<4¾{Z Ð:a™ôÇ@t<ƒ¸‚«¹É 8ç—µý¬”ˆzLE®°yæCãFÄ!Yã–Î=x|é¨tø¨ä‚^}`°7pÑÕ¶×q˜<%-Ú› ¹ ÷NrH7 4êœb|£sàñTø&Ÿwž¢Ã'¥Þq_*ð®pŽÒ9œËËÒ‡óp÷e™;‡ËKWÀµž¼Óª·ä‚þJBa½ÖÅEoêP$\ aõ²ÎŸ‘ôÉ Ï¼X§P´1X Ž XºóH‰¨/ÝPã=…s…se™ç.*ÏËҹ¹bªÏHú®ù2<®pÎι2*|YÎ/Mª)nFpEáœsE”sîÛE÷˦úˆÔ/˜ ]B³cÜ(ÇKÏ-›úÍ ÁÌ  1ƒK¹ –ròƒÓ{sB0#º8,²­íÏÃÖMゥQ:#rZ`ñ9“ÏÌšR©ψn*EQ@Ø’—Ì‚–û²t®(Šº~kª3¦‰'ÛŸôëT Þn#Løú¸”ˆf[g&³­£‚ÙÖ>!˜}¯quô‹ Á¬èÊ/^p‚YÑ>ßÿP¸ØP¾œÌŠ*‡ÿ€Íå Á¬h÷¢øÊ·ëËçS×l–\ œú¨?ß–¿M.˜^Eñ®9ßäÅâÅä‚YѾ… º÷¿ûøæ²H.˜íU–eYÅ?ìQlH.˜Z x"ËŠÔ(jÆŒ1Šw圄`V´Gí§_´ÖcÔ&³¢9fÝí×[k­5%³£¯ñ­G_·ÖÚý‚ÙÑŽ×à# ]> OpenSMPPBox &version; User's Guide Open Source SMPP proxy Rene Kluwen OpenSMPPBox author Chimit Ltd.
rene.kluwen@chimit.nl
Victor Luchitz TLV and other patches Playfon
vluchits@gmail.com
Nikos Balkanas Documentation and patches InAccess Networks SA
nbalkanas@gmail.com
Abstract This document describes how to install and use OpenSMPPBox, the Open Source SMPP proxy originally developed by Chimit Ltd. and now being developed further by the open source community, namely the Kannel Group. &version; ×tamp;
Introduction This chapter introduces SMPP in general terms, and explains the role of OpenSMPPBox in SMS flow, outlining its duties and features. Overview of SMPP The Short Message Peer to Peer (SMPP) protocol is an open, industry standard protocol designed to provide a flexible data communications interface for transfer of short message data between a Message Center, such as a Short Message Service Centre (SMSC), GSM Unstructured Supplementary Services Data (USSD) Server or other type of Message Center and a SMS application system, such as a WAP Proxy Server, EMail Gateway or other Messaging Gateway. It was maintained by the SMS Forum until it reached maturity and was subsequently disbanded in July 2007. SMPP Release v3.4, its most popular version, launched in 12/9/1999. Now in its latest implementation, v5.0 further development has been discontinued since the disband of the SMS Forum. All protocols and specifications can still be downloaded from http://www.smsforum.net/. SMPP supports Digital Cellular Network technologies including: GSM IS-95 (CDMA) ANSI-136 (TDMA) iDEN Using the SMPP protocol, an SMS application system called the "External Short Message Entity" (ESME) may initiate an application layer connection with an SMSC over a TCP/IP or X.25 network connection and may then send short messages and receive short messages to and from the SMSC respectively. The ESME may also query, cancel or replace short messages using SMPP. SMPP supports a full featured set of two-way messaging functions such as: Transmit messages from an ESME to single or multiple destinations via the SMSC An ESME may receive messages via the SMSC from other SME's (e.g. mobile stations). Query the status of a short message stored on the SMSC Cancel or replace a short message stored on the SMSC Send a registered short message (for which a "delivery receipt" will be returned by the SMSC to the message originator) Schedule the message delivery date and time Select the message mode, i.e. datagram or store and forward Set the delivery priority of the short message Define the data coding type of the short message Set the short message validity period Associate a service type with each message e.g. voice mail notification OpenSMPPBox overview OpenSMPPBox is an opensource SMPP proxy, which forwards GSM SMPP PDUs. It is not a pure proxy in the clear sense of the word, since it is not limited to the SMPP protocol. It features an SMPP server port for incoming ESME connections, but the client side uses the more flexible Kannel (Msg *) protocol for connection to Kannel's Bearerbox. This way it can take advantage of Bearerbox's client SMSc protocols not limited to SMPP, but extending to CIMD2, EMI/UUCP etc. It can be used for both MT & MO SMS traffic.
OpenSMPPBox Layout
The ESME connects over SMPP to OpenSMPPBox, thinking that it is an SMSc. Accounts are configured in OpenSMPPBox to allow connections only from specific clients. The SMS is forwarded to Bearerbox, which routes it to the best available SMSc over a variety of protocols. Meanwhile the SMSc will generate both final and intermediate delivery reports. These are routed back from Bearerbox to OpenSMPPbox, which are then rewritten, as to appear that they originated from OpenSMPPBox. These are finally routed back to the requesting ESME. OpenSMPPBox presents a layer of abstraction to the ESME. The ESME doesn't know the real SMScs used for SMS delivery. As far as it is concerned, it is dealing only with a single SMSc, OpenSMPPBox. OpenSMPPBox works like a black box in between your subscribers and Kannel.
Features OpenSMPPBox provides for compliance to SMPP v3.3, SMPP v3.4 & SMPPv5.0 for MT SMS routing over GSM. Options are limited by the features provided by Bearerbox. SMPP Users are defined in a flat text file, which is parsed at client connection (binding) time. This means that users can be added, changed or removed without restarting opensmppbox. The file can be edited by any plain-text file editor. Also it is possible to compile opensmppbox with Unix PAM support (pluggable authentication modules). See the corresponding options in the configuration file. It is possible to restrict ip addresses from which can be bound (connected) per user. See the section on configuring opensmppbox below. Special efforts have been made to make opensmppbox v3.4 compatible by means of TLV (tagged length value) parameters. These parameters can be addressed via the meta-data construction in Kannel. A special example of this: One can conditionally enable transmission of short messages as a whole with length exceeding 140 octets, based on a meta-tag "use_message_payload" in "smpp" group. In case this tag has been set and its value is not zero, opensmppbox will attempt to use the "message_payload" TLV instead of splitting the message into multiple shorter ones with UDH-concatenation bit set. Note that this mechanism only works for ESME's that declare support for SMPP versions 3.4 or greater. A simple usage example: http://localhost:13013/cgi-bin/sendsms?...&meta-data=%3Fsmpp%3Fuse_message_payload%3D1. Limitations Some SMPP methods, for instance querying or cancelling short messages are not available. Billing and logging features are inherited from Kannel, which lacks a great deal of these things. As such, pre-paid billing accounts are not part of the implementation. For post-paid billing, you will need to parse the log-files or possibly use message logging by means of sqlbox. Requirements Latest Kannel must be installed (>1.4.3 svn version), including development headers and libraries. Kannel's gwlib is needed for compilation. Additionally a working (running) Bearerbox is needed to route SMS to. If it is not available, SMS messages can possibly be lost and no more logins are permitted. A C compiler and libraries for ANSI C are needed, with normal Unix extensions such as BSD sockets and related tools. (GNU's GCC tool-chain is recommended) To build this documentation, the docbook c.s. tools are needed.
Installation This chapter explains how the gateway can be installed, either from a source code package or by using a pre-compiled binary version. The goal of this chapter is to get the gateway compiled and all the files in the correct places; the next chapter will explain how the gateway is configured. If you are upgrading from a previous version, please look at for any important information. See chapter 5. Getting the source code The source code is available from Kannel's site, through svn: svn co https://svn.kannel.org/opensmppbox/trunk Authentication is not needed. Finding the documentation OpenSMPPBox documentation consists of two parts: User's Guide, namely the one you're reading at the moment. The README, ChangeLog and various other text files in the source tree. You can also find general information on Kannel's website and information about existing problems at our bug tracker. Everything you need to install and use OpenSMPPBox is in User's Guide. The guide is still incomplete in this respect. The README is not supposed to be very important, nor contain much information. Instead, it will just point to the other documentation. Compiling the proxy If you are using OpenSMPPBox on a supported platform, or one that is similar enough to one, compiling opensmppbox should be trivial. After you have unpacked the source package of your choice, or after you have checked out the source code from SVN, enter the following commands: ./configure make The configure script investigates various things on your computer compilation needs, and writes out the Makefile used to compile OpenSMPPBox. make then runs the commands to actually compile it. It generates the configure.log, of all actions taken, usually the first step in debugging in case of errors. If either command writes out an error message and stops before it finishes its job, you have a problem, and you either need to fix it yourself, if you can, or report the problem to the Kannel project. See for details. For detailed instructions on using the configuration script, see file INSTALL. That file is a generic documentation for configure. You may need to add compilations flags to configure: CFLAGS='-pthread' ./configure The above, for instance, seems to be required on FreeBSD. If you want to do development, you probably want to add CFLAGS that make your compiler print warning messages. For example, for GCC: CFLAGS='-Wall -g' ./configure (You may, at your preference, use even stricter checking options.) Installing the proxy After you have compiled OpenSMPPBox, you need to install certain programs in a suitable place. This is most easily done by using make again: make bindir=/path/to/directory install Replace /path/to/directory with the pathname of the actual directory where the programs should be installed. Actually only a single program is installed opensmppbox. The user that runs make install needs to have write permissions do the bindir directory. It defaults to /usr/local/sbin. So possibly you need to be root to be able to install. The version number of the proxy is added to the file during installation. This makes it easier to have several versions installed, and makes it easy to go back to an older version if the new version proves problematic. After installation, you should now be able to run the Kannel init.d script that will start the proxy. Run the script as root. For opensmppbox we don't have a seperate init script, but versions of the Kannel init script are available that include starting opensmppbox. /etc/init.d/kannel start To stop the gateway just run the same script with the stop parameter. /etc/init.d/kannel stop If OpenSMPPBox is already running and you just want to quickly stop and start the gateway,e.g.to set a new configuration option, run the script with the restart parameter. /etc/init.d/kannel restart Using OpenSMPPBox This chapter explains how the proxy, OpenSMPPBox, is configured and used. It covers the configuration file and proxy administration during runtime. There is only one configuration file for all parts of OpenSMPPBox. If several proxy instances are distributed among different hosts, each one needs to have its own configuration file, with its own options. In bearerbox's status page you can see all connected opensmppbox clients as different smsboxes. Note that the ip address that is listed on the status page of bearerbox is the one of opensmppbox; not the client ip address of the opensmppbox user. Configuring the proxy Configuration file syntax A configuration file consists of groups of configuration variables. Groups are separated by empty lines, and each variable is defined on its own line. Each group in Kannel configuration is distinguished with a group variable. Comments are lines that begin with a number sign (#) and are ignored (they don't, for example, separate groups of variables). A variable definition line has the name of the variable, and equals sign (=) and the value of the variable. The name of the variable can contain any characters except white space and equals. The value of the variable is a string, with or without quotation marks (") around it. Quotation marks are needed if the variable needs to begin or end with white space or contain special characters. Normal C escape character syntax works inside quotation marks. Perhaps an example will make things easier to comprehend: 1 # Proxy configuration 2 group = opensmppbox 3 bearerbox-host = 127.0.0.1 4 bearerbox-port = 13000 6 opensmppbox-id = smppbox1 7 opensmppbox-port = 13001 8 log-file = /var/log/kannel/opensmppbox.log 9 log-level = 0 10 our-system-id = Inaccess 11 route-to-smsc = fast_smsc 12 # New accounts 13 smpp-logins = /etc/opensmppbox/clients Lines 1 and 12 are comment lines. A blank line is needed to separate groups. The remaining lines define variables. The group type is defined by the group variable value. The variables used in each configuration group are explained below: Some variable values are marked as 'bool'. The value for such a variable is true, false, yes, no, on, off, 0 or 1. Arbitrary values are treated as 'true' while if the variable is missing, it is treated as being 'false'. In order to make some configuration lines more readable you may use the delimiter '\' at the end of a line to wrap and concatenate the next line up to the current line. Here is an example: 1 # A group with a wrapped alias line 2 group = dummy 3 anything = hello 4 aliases = hallo;haalloo;\ 5 heelloo;haelloo;healloo 6 whatever = "Hello world!" The above example shows how a list for various alias keywords is wrapped to two lines using the line wrap delimiter. In order to use the delimiter '\' itself, you need to escape it via a prefixed '\' itself. So this is '\\' to escape the wrapping function and use the character in the string. Inclusion of configuration files A configuration file may contain a special directive called include to include other file or a directory with files to the configuration processing. This allows to segment the specific configuration groups required for several services and boxes to different files and hence to have more control in larger setups. Here is an example that illustrates the include statement : # OpenSMPPBox configuration include = "/etc/opensmppbox/conf/opensmppbox1.conf" Above is the main opensmppbox.conf configuration file that includes the following opensmppbox1.conf file with all required directives for the specific box, and a configurations directory which may include more files to include. # opensmppbox1.conf group = opensmppbox bearerbox-host = 127.0.0.1 bearerbox-port = 13002 opensmppbox-id = Dutch opensmppbox-port = 13003 log-file = "/var/log/kannel/opensmppbox.log" log-level = 1 our-system-id = Inaccess route-to-smsc = cardboard smpp-logins = /etc/opensmppbox/clients The above include statement may be defined at any point in the configuration file and at any inclusion depth. Hence you can cascade numerous inclusions if necessary. It must be, however, between groups and must contain whole group definitions. At process start time inclusion of configuration files breaks if either the included file can not be opened and processed or the included file has been processed already in the stack and a recursive loop has been detected. OpenSMPPBox configuration OpenSMPPBox configuration MUST always include a group for general proxy configuration. This group is named as 'opensmppbox' in configuration file. It doesn't matter if this is the first or a later group in the configuration file. In it's simplest form, 'opensmppbox' group looks like this: group = opensmppbox our-system-id = Inaccess smpp-logins = /etc/opensmppbox/clients Naturally this is not sufficient for any real use. Thus, one or more of the optional configuration variables are used. In following list (as in any other similar lists), all mandatory variables are marked with (m), while conditionally mandatory (variables which must be set in certain cases) are marked with (c). opensmppbox Group Variables Variable Value Description group (m) opensmppbox This is a mandatory variable bearerbox-host (o) hostname Bearerbox server. FQDN or IP address. Defaults to localhost. bearerbox-port (o) port number TCP port that bearerbox is listening for incoming opensmppbox connections. Should be the same as smsbox-port configured in bearerbox. Defaults to 13001. opensmppbox-id (o) string Optional opensmppbox instance identifier. This is used for logging identification. opensmppbox-port (o) port number TCP port that opensmppbox is listening for incoming ESME connections. Defaults to 2345. If you want a different port number for each client, you will need to run a separate opensmppbox instance for each port you are listening on. log-file (o) filename Filename that opensmppbox will log messages. If missing, logging is disabled. log-level (o) integer (0...5) Logging level. From maximum (0) to minimum (4). Defaults to 0. our-system-id (m) string Corresponds to SMSC identification transmitted to connected ESMEs. route-to-smsc (o) string Corresponds to smsc-id defined in bearerbox. If set, it will send SMS through this SMSc, else it will let bearerbox route the SMS. Defaults to bearerbox routing. smpp-logins (m) filename File that contains authentication credentials for clients connecting to opensmppbox. This should be a file with a single line per client, with username, password and system-type, seperated by spaces. System-type is a special value. In practice, you should have a different system-type for each connecting client. See description of smpplogins.txt below. use-systemid-as-smsboxid (o) boolean If set to true, this opensmppbox user is authenticating as smsbox to bearerbox as the system-id value (first parameter in smpplogins.txt). If set to false (which is the default) then the smsbox-id is the same as system-type (third parameter in smpplogins.txt). If you are using PAM authentication, then use-systemid-as-smsboxid must be set to true. enable-pam (o) boolean If set to true, then open smpp will use PAM authentication besides the usual smpplogins.txt file. The smpplogins.txt file takes precedence here. If there the user cannot be found there, opensmppbox will try to use PAM authentication. use-systemid-as-smsboxid must be set to true if enable-pam is also true. For this to work, opensmppbox must be compiled with pam-support (configure --enable-pam). pam-acl (o) pam acl account If enable-pam is true, authentication is done against this pam account. It must be present in /etc/pam.d. If not given, then the value "kannel" is used. source-addr-ton (o) number Manually override source address TON setting for the link. (Defaults to -1, do not override). source-addr-npi (o) number Manually override source address NPI setting for the link. (Defaults to -1, do not override). source-addr-autodetect (o) boolean If defined tries to scan the source address and set TON and NPI settings accordingly. (Defaults to no). dest-addr-ton (o) number Manually override destination address TON setting for the link. (Defaults to -1, do not override). dest-addr-npi (o) number Manually override destination address NPI setting for the link. (Defaults to -1, do not override). timeout (o) number The smpp connection gets dropped if opensmppbox does not receive a valid pdu in this number of seconds. (Defaults to 300).
smpp logins The smpplogins.txt file, as set by the smpp-logins configuration variable defines all users that are able to bind as ESME to opensmppbox. The first three tokens of this file are the username, password and foreign system-type that form the credentials on which the bind- method of the ESME are being matched with. The last token and defines a source ip address to restrict logins to. An example with two example logins: goodclient secret remote *.*.*.* franchise ourpassword localbox 127.0.0.1;213.110.120.33 The first line defines a username ("goodclient"), a password ("secret") and an smsbox-id ("remote"). People can log into this account, originating from any ip address.i The second line defines also a username ("franchise"), password("ourpassword") and an smsbox-id ("localbox"), but besides that there is a restriction on that user. It can only bind from the ip addresses 127.0.0.1 and 213.110.120.33. If ip address(es) is/are given, then only those ip addresses are allowed to connect. It works exactly like connect-allow-ip and connect-deny-ip in Kannel.conf. In that case, connect-deny-ip has a mask of "*.*.*.*". The third token in de smpp-logins file is the foreign system-type and is important in terms of Kannel's sms routing rules. It is used as smsbox-id when connecting to bearerbox. This means that messages sent via that system-type will get corresponding dlr's back. This also counts for MO messages. Also group = smsbox-route in Kannel.conf "listens" to this value. For this reason, it is important to use a different system-type for each different client unless they should receive each others' messages. In case use-systemid-as-smsboxid = true, then in stead of system-type, system-id will be used as this "smsbox-id" value. You are encouraged to use this feature and set it to true. Routing of outbound messages It is possible to route incoming messages to specific ESMEs connected to Opensmppbox by setting the use-systemid-as-smsboxid configuration variable to true and utilzing native bearerbox routing capabilities (see smsbox routing in Kannel Userguide). To assign outbound messages to a specific sms centre in bearerbox, one must use the smsc-route configuration group within Opensmppbox. It works exactly in the same manner as smsbox routing in Kannel but in the opposite direction. A configuration example may look like this: group = smsc-route smsc-id = mysmsc shortcode = "1111;2222;3333" Which means all outbound messages with sender number 1111, 2222 or 3333 will be assigned a smsc id "mysmsc". Another example: group = smsc-route smsc-id = mysmsc smsbox-id = "A;B;C" shortcode = "1111;2222;3333" Which means all outbound messages with sender number 1111, 2222 or 3333 originating from the smsbox A, B or C will be assigned a smsc id "mysmsc". Yet another example: group = smsc-route smsc-id = mysmsc receiver-shortcode = "+18887778888;+18887779999;+18886665555" Which means all outbound messages with receiver number +18887778888, +18887779999, +18886665555 will be assigned a smsc id "mysmsc". If none of the rules have been defined or none match the criteria, the default smsc route defined in route-to-smsc configuration variable will be used. smsc-route Group Variables Variable Value Description group (m) smsc-route This is a mandatory variable smsc-id (m) word Defines smsc identifier, messages matching the criteria below, will be assigned to. smsbox-id (o) word-list If set, specifies from which smsbox-ids all outbound messages should be routed to this smsc. List contains smsbox-ids separated by semicolon (";"). If used in combination with config directive shortcode, then this is another matching criteria for the routing decision. shortcode (o) number-list If set, specifies which sender numbers for outbound messages should be routed to this smsc. List contains numbers separated by semicolon (";"). If used in combination with config directive smsbox-id, then only messages originating from the specified smsboxes are matched against the shortcode list. receiver-shortcode (o) number-list If set, specifies which receiver numbers for outbound messages should be routed to this smsc. List contains numbers separated by semicolon (";"). This option takes higher precedence than smsbox-id and shortcode; it supercedes these options.
Getting help and reporting bugs This chapter explains where to find help with problems related to the gateway, and the preferred procedure for reporting bugs and sending corrections to them. The Kannel development mailing list is users@kannel.org. To subscribe, send mail to users-subscribe@kannel.org. This is currently the best location for asking help and reporting bugs. Please include configuration file and version number. Upgrading notes See the file UPGRADE in the source tree.
gateway-1.4.5/addons/opensmppbox/Makefile.am0000644000175000017500000000555412327711130017550 0ustar toljtoljman1pages = gw/opensmppbox.1 man5pages = gw/opensmppbox.5 docsrcs = $(wildcard grep -l ' $*.tmp ${JADE} -V nochunks -t sgml -d $(HTML_DSL) $(XML_DCL) $*.tmp > $@ rm -f $*.tmp .xml.rtf: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp cd `dirname $<` && $(JADE) -o `basename $*`.rtf -t rtf -d $(TEX_DSL) $(XML_DCL) `basename $*`.tmp rm -f $*.tmp .xml.ps: sed "s/#FIGTYPE#/.ps/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || \ ( echo Check `dirname $<`/`basename $*`.log for errors && false) rm -f $*.log cd `dirname $<` && $(DVIPS) -q -o `basename $*`.ps `basename $*`.dvi rm -f $*.dvi $*.tex $*.aux .xml.pdf: sed "s/#FIGTYPE#/.png/;s/#VERSION#/${VERSION}/;s/#DATE#/`date +%Y.%m.%d`/;s/#DRAFTS#/${DOCDRAFTS}/" $< > $*.tmp $(JADE) -o $*.tex -t tex -d $(TEX_DSL) $(XML_DCL) $*.tmp rm -f $*.tmp cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true cd `dirname $<` && $(JADETEX) `basename $*`.tex >/dev/null || true rm -f $*.log $*.dvi cd `dirname $<` && $(PDFJADETEX) `basename $*`.tex > /dev/null || true test -r $*.pdf || false rm -f $*.log $*.tex $*.aux $*.out .fig.png: $(FIG2DEV) -Lpng $< $@ .fig.ps: $(FIG2DEV) -Lps $< $@ .png.ps: $(CONVERT) $< $@ rpm: clean @echo "Preparing to build the RPM files" mkdir -p "$(rpmtemp)/${RPMPKG}" cp -R * "$(rpmtemp)/${RPMPKG}" tar -C "$(rpmtemp)" -c ${RPMPKG} -zf ${RPMPKG}.tar.gz rm -rf "$(rpmtemp)/${RPMPKG}" if [ -d $(rpmtemp) ]; then rmdir "$(rpmtemp)"; fi @echo "Building the RPM" rpmbuild -ta ${RPMPKG}.tar.gz rm -f ${RPMPKG}.tar.gz @echo "**********************************************************************" @echo "* Success!" @echo "* Your files are located under $(shell rpm --eval '%_rpmdir')" @echo "* The Kannel Group " @echo "**********************************************************************" @echo "Thank you for using Kannel." docs: figs ps $(docs) no-docs: figs: $(figs) ps: $(ps) pp: $(pres) SUBDIRS = gw EXTRA_DIST = KannelLICENSE bootstrap gateway-1.4.5/addons/opensmppbox/UPGRADE0000644000175000017500000000025111453122245016515 0ustar toljtolj2010/08/01 From now on, opensmppbox needs to be compiled with Kannel sources later than 2010/07/28 because the dlr_find function prototype has been changed. gateway-1.4.5/addons/opensmppbox/VERSION0000644000175000017500000000105011416636070016556 0ustar toljtoljsvn This file contains the version number of smppbox. It is stored on the first line. Nothing else should be there. Note that if you get this file from SVN, it will just say "svn-r" instead of a version number. This is intentional, it avoids confusion with real releases. Starting with version 0.8, version numbers that have an even second part are STABLE versions and those with odd ones are DEVELOPMENT versions. Thus, 1.0 is stable, 1.1 is development. Don't use development versions for production unless you really know what you do. gateway-1.4.5/addons/opensmppbox/gw/0000755000175000017500000000000013312227715016126 5ustar toljtoljgateway-1.4.5/addons/opensmppbox/gw/Makefile.in0000644000175000017500000003457512327711130020203 0ustar toljtolj# Makefile.in generated by automake 1.9.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ top_builddir = .. am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd INSTALL = @INSTALL@ install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ LIBOBJDIR = sbin_PROGRAMS = opensmppbox$(EXEEXT) subdir = gw DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.in am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/sb-config.h CONFIG_CLEAN_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(sbin_PROGRAMS) am_opensmppbox_OBJECTS = opensmppbox.$(OBJEXT) opensmppbox_OBJECTS = $(am_opensmppbox_OBJECTS) opensmppbox_LDADD = $(LDADD) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/autotools/depcomp am__depfiles_maybe = depfiles COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(opensmppbox_SOURCES) DIST_SOURCES = $(opensmppbox_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMDEP_FALSE = @AMDEP_FALSE@ AMDEP_TRUE = @AMDEP_TRUE@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CONVERT = @CONVERT@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CTLIB_INCLUDE = @CTLIB_INCLUDE@ CTLIB_LFLAGS = @CTLIB_LFLAGS@ CXX = @CXX@ CXXCPP = @CXXCPP@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOCDRAFTS = @DOCDRAFTS@ DOCSTARGET = @DOCSTARGET@ DVIPS = @DVIPS@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ F77 = @F77@ FFLAGS = @FFLAGS@ FIG2DEV = @FIG2DEV@ GREP = @GREP@ GW_CONFIG = @GW_CONFIG@ GW_VERSION = @GW_VERSION@ HTML_DSL = @HTML_DSL@ INCLUDES = @INCLUDES@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ JADE = @JADE@ JADETEX = @JADETEX@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ MAKEINFO = @MAKEINFO@ OBJEXT = @OBJEXT@ OLDJADE = @OLDJADE@ OPENSSL = @OPENSSL@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PDFJADETEX = @PDFJADETEX@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TEX_DSL = @TEX_DSL@ VERSION = @VERSION@ XML_DCL = @XML_DCL@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_F77 = @ac_ct_F77@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ rpm_requires = @rpm_requires@ rpm_suffix = @rpm_suffix@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ opensmppbox_SOURCES = opensmppbox.c EXTRA_DIST = all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu gw/Makefile'; \ cd $(top_srcdir) && \ $(AUTOMAKE) --gnu gw/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)" @list='$(sbin_PROGRAMS)'; for p in $$list; do \ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ if test -f $$p \ || test -f $$p1 \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \ else :; fi; \ done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; for p in $$list; do \ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \ rm -f "$(DESTDIR)$(sbindir)/$$f"; \ done clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; for p in $$list; do \ f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ echo " rm -f $$p $$f"; \ rm -f $$p $$f ; \ done opensmppbox$(EXEEXT): $(opensmppbox_OBJECTS) $(opensmppbox_DEPENDENCIES) @rm -f opensmppbox$(EXEEXT) $(LINK) $(opensmppbox_LDFLAGS) $(opensmppbox_OBJECTS) $(opensmppbox_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opensmppbox.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ @am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$tags $$unique; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) ' { files[$$0] = 1; } \ END { for (i in files) print i; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && cd $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) $$here distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ list='$(DISTFILES)'; for file in $$list; do \ case $$file in \ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ esac; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ dir="/$$dir"; \ $(mkdir_p) "$(distdir)$$dir"; \ else \ dir=''; \ fi; \ if test -d $$d/$$file; then \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ fi; \ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ else \ test -f $(distdir)/$$file \ || cp -p $$d/$$file $(distdir)/$$file \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(mkdir_p) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool clean-sbinPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am info: info-am info-am: install-data-am: install-exec-am: install-sbinPROGRAMS install-info: install-info-am install-man: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-info-am uninstall-sbinPROGRAMS .PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ clean-libtool clean-sbinPROGRAMS ctags distclean \ distclean-compile distclean-generic distclean-libtool \ distclean-tags distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-exec \ install-exec-am install-info install-info-am install-man \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-info-am \ uninstall-sbinPROGRAMS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gateway-1.4.5/addons/opensmppbox/gw/Makefile.am0000644000175000017500000000011612061727435020164 0ustar toljtoljsbin_PROGRAMS = opensmppbox opensmppbox_SOURCES = opensmppbox.c EXTRA_DIST = gateway-1.4.5/addons/opensmppbox/gw/opensmppbox.c0000644000175000017500000025442413111247770020657 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2010 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Author: 2006 Chimit Software Development. * http://www.chimit.nl/ rene.kluwen@chimit.nl */ /* * opensmppbox.c - main program of the opensmppbox */ #include #include #include #include #include #include "gwlib/gwlib.h" #include "gw/msg.h" #include "gw/shared.h" #include "gw/bb.h" #include "gw/smsc/smpp_pdu.h" #include "gw/sms.h" #include "gw/dlr.h" #include "gw/heartbeat.h" #include "gw/meta_data.h" #include "gw/bb_store.h" #undef GW_NAME #undef GW_VERSION #include "../sb-config.h" #ifdef HAVE_PAM_SECURITY #include #elif defined HAVE_PAM_PAM #include #endif /* our config */ static Cfg *cfg; /* have we received restart cmd from bearerbox? */ static volatile sig_atomic_t restart_smppbox = 0; static volatile sig_atomic_t smppbox_status; #define SMPP_DEAD 0 #define SMPP_SHUTDOWN 1 #define SMPP_RUNNING 2 static long smppbox_port; static int smppbox_port_ssl = 0; static long bearerbox_port; static Octstr *bearerbox_host; static int bearerbox_port_ssl = 0; static Octstr *smpp_logins; static Counter *boxid; static int restart = 0; static List *all_boxes; static Dict *list_dict; static Counter *catenated_sms_counter; static long sms_max_length = MAX_SMS_OCTETS; static long smpp_source_addr_ton = -1; static long smpp_source_addr_npi = -1; static int smpp_autodetect_addr = 0; static long smpp_dest_addr_ton = -1; static long smpp_dest_addr_npi = -1; static Dict *smsc_by_receiver = NULL; static Dict *smsc_by_smsbox_id = NULL; static Dict *smsc_by_sender = NULL; static Dict *smsc_by_sender_smsbox_id = NULL; static Octstr *smppbox_id; static Octstr *our_system_id; static Octstr *route_to_smsc; static time_t smpp_timeout; static Octstr *alt_charset; static int systemidisboxcid; static int enablepam; static Octstr *pamacl; #define TIMEOUT_SECONDS 300 typedef enum { SMPP_LOGIN_NOTLOGGEDIN, SMPP_LOGIN_TRANSMITTER, SMPP_LOGIN_RECEIVER, SMPP_LOGIN_TRANSCEIVER } smpp_login; typedef struct _boxc { Connection *smpp_connection; Connection *bearerbox_connection; smpp_login login_type; int logged_in; int is_wap; long id; int load; int version; Octstr *alt_charset; time_t connect_time; Counter *smpp_pdu_counter; Octstr *client_ip; List *incoming; List *retry; /* If sending fails */ List *outgoing; Dict *sent; Semaphore *pending; volatile sig_atomic_t alive; Octstr *boxc_id; /* identifies the connected opensmppbox instance */ Octstr *sms_service; Octstr *route_to_smsc; Dict *msg_acks; Dict *deliver_acks; time_t last_pdu_received; /* used to mark connection usable or still waiting for ident. msg */ volatile int routable; Octstr *service_type; long source_addr_ton; long source_addr_npi; int autodetect_addr; long dest_addr_ton; long dest_addr_npi; int alt_dcs; int validityperiod; int priority; int mo_recode; } Boxc; void smpp_pdu_destroy_item(void *pdu) { smpp_pdu_destroy(pdu); } static Octstr *boxc_route_msg_to_smsc(Boxc *box, Msg *msg); /* * Use PAM (Pluggable Authentication Module) to check sendsms authentication. */ #ifdef HAVE_PAM typedef const struct pam_message pam_message_type; static const char *PAM_username; static const char *PAM_password; static int PAM_conv (int num_msg, pam_message_type **msg, struct pam_response **resp, void *appdata_ptr) { int count = 0, replies = 0; struct pam_response *repl = NULL; int size = sizeof(struct pam_response); #define GET_MEM \ repl = gw_realloc(repl, size); \ size += sizeof(struct pam_response) #define COPY_STRING(s) (s) ? gw_strdup(s) : NULL for (count = 0; count < num_msg; count++) { switch (msg[count]->msg_style) { case PAM_PROMPT_ECHO_ON: GET_MEM; repl[replies].resp_retcode = PAM_SUCCESS; repl[replies++].resp = COPY_STRING(PAM_username); /* PAM frees resp */ break; case PAM_PROMPT_ECHO_OFF: GET_MEM; repl[replies].resp_retcode = PAM_SUCCESS; repl[replies++].resp = COPY_STRING(PAM_password); /* PAM frees resp */ break; case PAM_TEXT_INFO: warning(0, "unexpected message from PAM: %s", msg[count]->msg); break; case PAM_ERROR_MSG: default: /* Must be an error of some sort... */ error(0, "unexpected error from PAM: %s", msg[count]->msg); gw_free(repl); return PAM_CONV_ERR; } } if (repl) *resp = repl; return PAM_SUCCESS; } static struct pam_conv PAM_conversation = { &PAM_conv, NULL }; static int authenticate(const char *acl, const char *login, const char *passwd) { pam_handle_t *pamh; int pam_error; PAM_username = login; PAM_password = passwd; pam_error = pam_start(acl, login, &PAM_conversation, &pamh); info(0, "Starting PAM for user: %s", login); if (pam_error != PAM_SUCCESS || (pam_error = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { warning(0, "PAM auth failed for user: %s", login); pam_end(pamh, pam_error); return 0; } pam_end(pamh, PAM_SUCCESS); info(0, "opensmppbox login by <%s>", login); return 1; } #endif /* HAVE_PAM */ /* check if login exists in database */ int check_login(Boxc *boxc, Octstr *system_id, Octstr *password, Octstr *system_type, smpp_login login_type) { int box; int success; Boxc *thisbox; FILE *fp; char systemid[255], passw[255], systemtype[255], allowed_ips[1024]; Octstr *allowed_ips_str; fp = fopen(octstr_get_cstr(smpp_logins), "r"); if (fp == NULL) { return 0; } while (!feof(fp)) { fscanf(fp, "%s %s %s %s\n", systemid, passw, systemtype, allowed_ips); if (systemidisboxcid) { success = (strcmp(octstr_get_cstr(system_id), systemid) == 0 && strcmp(octstr_get_cstr(password), passw) == 0); } else { success = (strcmp(octstr_get_cstr(system_id), systemid) == 0 && strcmp(octstr_get_cstr(password), passw) == 0 && strcmp(octstr_get_cstr(system_type), systemtype) == 0); } if (success) { if (strcmp(allowed_ips, "") != 0) { allowed_ips_str = octstr_create(allowed_ips); if (is_allowed_ip(allowed_ips_str, octstr_imm("*.*.*.*"), boxc->client_ip) == 0) { info(0, "Box connection tried from denied host <%s>, disconnected", octstr_get_cstr(boxc->client_ip)); octstr_destroy(allowed_ips_str); continue; } octstr_destroy(allowed_ips_str); } fclose(fp); goto valid_login; } } fclose(fp); #ifdef HAVE_PAM if (enablepam && authenticate(octstr_get_cstr(pamacl), octstr_get_cstr(system_id), octstr_get_cstr(password))) { goto valid_login; } #endif return 0; valid_login: for (box = 0; box < gwlist_len(all_boxes); box++) { thisbox = (Boxc *)gwlist_get(all_boxes, box); if (octstr_compare(system_type, thisbox->boxc_id) == 0 && (thisbox->login_type == SMPP_LOGIN_TRANSCEIVER || (thisbox->login_type == login_type))) { debug("bb.sms.smpp", 0, "opensmppbox[%s]: Multiple login: disconnect.", octstr_get_cstr(thisbox->boxc_id)); thisbox->alive = 0; #ifdef HAVE_SHUTDOWN_CONNECTION shutdown_connection(thisbox->bearerbox_connection); shutdown_connection(thisbox->smpp_connection); #endif } } return 1; } /* * Select these based on whether you want to dump SMPP PDUs as they are * sent and received or not. Not dumping should be the default in at least * stable releases. */ #define DEBUG 1 #ifndef DEBUG #define dump_pdu(msg, id, pdu) do{}while(0) #else /** This version does dump. */ #define dump_pdu(msg, id, pdu) \ do { \ debug("opensmppbox", 0, "SMPP[%s]: %s", \ octstr_get_cstr(id), msg); \ smpp_pdu_dump(id, pdu); \ } while(0) #endif /* * Converting SMPP timestamp to minutes relative * to our localtime. * Return -1 if error detected * Author: amalysh@kannel.org */ static int timestamp_to_minutes(Octstr *timestamp) { struct tm tm, local; time_t valutc, utc; int rc, diff, dummy, localdiff; char relation; if (octstr_len(timestamp) == 0) return 0; if (octstr_len(timestamp) != 16) return -1; /* * Timestamp format: * YYMMDDhhmmsstnn[+-R] * t - tenths of second (not used by us) * nn - Time difference in quarter hours between local and UTC time */ rc = sscanf(octstr_get_cstr(timestamp), "%02d%02d%02d%02d%02d%02d%1d%02d%1c", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &dummy, &diff, &relation); if (rc != 9) return -1; utc = time(NULL); if (utc == ((time_t)-1)) return 0; if (relation == '+' || relation == '-') { tm.tm_year += 100; /* number of years since 1900 */ tm.tm_mon--; /* month 0-11 */ tm.tm_isdst = -1; /* convert to sec. since 1970 */ valutc = gw_mktime(&tm); if (valutc == ((time_t)-1)) return -1; /* work out local time, because gw_mktime assume local time */ local = gw_localtime(utc); tm = gw_gmtime(utc); local.tm_isdst = tm.tm_isdst = -1; localdiff = difftime(gw_mktime(&local), gw_mktime(&tm)); valutc += localdiff; debug("sms.smpp",0, "diff between utc and localtime (%d)", localdiff); diff = diff*15*60; switch(relation) { case '+': valutc -= diff; break; case '-': valutc += diff; break; } } else if (relation == 'R') { /* relative to SMSC localtime */ local = gw_localtime(utc); local.tm_year += tm.tm_year; local.tm_mon += tm.tm_mon; local.tm_mday += tm.tm_mday; local.tm_hour += tm.tm_hour; local.tm_min += tm.tm_min; local.tm_sec += tm.tm_sec; valutc = gw_mktime(&local); if (valutc == ((time_t)-1)) return -1; } else { return -1; } tm = gw_gmtime(valutc); debug("sms.smpp",0,"Requested UTC timestamp: %02d-%02d-%02d %02d:%02d:%02d", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); debug("sms.smpp", 0, "requested timestamp in min. (%ld)", (valutc - utc)/60); return ceil ( difftime (valutc, utc) / 60 ); } /* *------------------------------------------------- * receiver thingies *------------------------------------------------- * */ /* send to bearerbox */ static int send_msg(Connection *conn, Boxc *boxconn, Msg *pmsg) { /* Caution: implicit msg_destroy */ write_to_bearerbox_real(conn, pmsg); return 0; } /* for heartbeat fn */ /* static void write_to_bearerboxes(Msg *msg) { long pos; Boxc *box; for (pos = 0; pos < gwlist_len(all_boxes); pos++) { box = (Boxc *)gwlist_get(all_boxes, pos); send_msg(box->bearerbox_connection, box, msg); } } */ /* for heartbeat fn */ /* static long outstanding_requests(void) { return 10; } */ /* * Identify ourself to bearerbox for opensmppbox-specific routing inside bearerbox. * Do this even while no opensmppbox-id is given to unlock the sender thread in * bearerbox. */ static void identify_to_bearerbox(Boxc *conn) { Msg *msg; msg = msg_create(admin); msg->admin.command = cmd_identify; msg->admin.boxc_id = octstr_duplicate(conn->boxc_id); send_msg(conn->bearerbox_connection, conn, msg); } /* read from bearerbox */ static Msg *read_from_box(Connection *conn, Boxc *boxconn) { Octstr *pack; Msg *msg; pack = NULL; while (boxconn->alive) { switch (read_from_bearerbox_real(conn, &msg, 1.0)) { case -1: /* connection to bearerbox lost */ return NULL; break; case 0: /* all is well */ return msg; break; case 1: /* timeout */ break; } } return msg; } Msg *catenate_msg(List *list, int total) { int current = 1, partno = 1, thismsg, max = 0; Msg *current_msg; Msg *ret = msg_duplicate(gwlist_get(list, 0)); uuid_generate(ret->sms.id); octstr_destroy(ret->sms.udhdata); ret->sms.udhdata = NULL; octstr_delete(ret->sms.msgdata, 0, octstr_len(ret->sms.msgdata)); while (max < total) { current_msg = gwlist_get(list, current - 1); if (current_msg) { thismsg = octstr_get_char(current_msg->sms.udhdata, 5); if (thismsg == partno) { octstr_append(ret->sms.msgdata, current_msg->sms.msgdata); max = 0; if (++partno > total) { return ret; } } } if (current >= total) { current = 0; } current++; max++; } /* fail */ debug("opensmppbox", 0, "re-assembling message failed."); msg_destroy(ret); return NULL; } static long convert_addr_from_pdu(Octstr *id, Octstr *addr, long ton, long npi) { long reason = SMPP_ESME_ROK; if (addr == NULL) return reason; switch(ton) { case GSM_ADDR_TON_INTERNATIONAL: /* * Checks to perform: * 1) assume international number has at least 7 chars * 2) the whole source addr consist of digits, exception '+' in front */ if (octstr_len(addr) < 7) { error(0, "SMPP[%s]: Mallformed addr `%s', expected at least 7 digits. ", octstr_get_cstr(id), octstr_get_cstr(addr)); reason = SMPP_ESME_RINVSRCADR; goto error; } else if (octstr_get_char(addr, 0) == '+' && !octstr_check_range(addr, 1, 256, gw_isdigit)) { error(0, "SMPP[%s]: Mallformed addr `%s', expected all digits. ", octstr_get_cstr(id), octstr_get_cstr(addr)); reason = SMPP_ESME_RINVSRCADR; goto error; } else if (octstr_get_char(addr, 0) != '+' && !octstr_check_range(addr, 0, 256, gw_isdigit)) { error(0, "SMPP[%s]: Mallformed addr `%s', expected all digits. ", octstr_get_cstr(id), octstr_get_cstr(addr)); reason = SMPP_ESME_RINVSRCADR; goto error; } /* check if we received leading '00', then remove it*/ if (octstr_search(addr, octstr_imm("00"), 0) == 0) octstr_delete(addr, 0, 2); /* international, insert '+' if not already here */ if (octstr_get_char(addr, 0) != '+') octstr_insert_char(addr, 0, '+'); break; case GSM_ADDR_TON_ALPHANUMERIC: if (octstr_len(addr) > 11) { /* alphanum sender, max. allowed length is 11 (according to GSM specs) */ error(0, "SMPP[%s]: Mallformed addr `%s', alphanum length greater 11 chars. ", octstr_get_cstr(id), octstr_get_cstr(addr)); reason = SMPP_ESME_RINVSRCADR; goto error; } break; default: /* otherwise don't touch addr, user should handle it */ break; } error: return reason; } static int send_pdu(Connection *conn, Octstr *id, SMPP_PDU *pdu) { Octstr *os; int ret; dump_pdu("Sending PDU:", id, pdu); os = smpp_pdu_pack(id, pdu); if (os) { ret = conn_write(conn, os); /* Caller checks for write errors later */ octstr_destroy(os); } else { ret = -1; } return ret; } /* generate 8 character ID, taken from msgid */ static Octstr *generate_smppid(Msg *msg, int version) { char uuidbuf[100]; Octstr *result; // gw_assert(msg->type == sms); // we segfault on this uuid_unparse(msg->sms.id, uuidbuf); result = octstr_create_from_data(uuidbuf, version > 0x33 ? UUID_STR_LEN : 8); return result; } /* * Try to read an SMPP PDU from a Connection. Return -1 for error (caller * should close the connection), 0 for no PDU to ready yet, or 1 for PDU * read and unpacked. Return a pointer to the PDU in `*pdu'. Use `*len' * to store the length of the PDU to read (it may be possible to read the * length, but not the rest of the PDU - we need to remember the lenght * for the next call). `*len' should be zero at the first call. */ static int read_pdu(Boxc *box, Connection *conn, long *len, SMPP_PDU **pdu) { Octstr *os; if (*len == 0) { *len = smpp_pdu_read_len(conn); if (*len == -1) { error(0, "opensmppbox[%s]: Server sent garbage, ignored.", octstr_get_cstr(box->boxc_id)); return -1; } else if (*len == 0) { if (conn_eof(conn) || conn_error(conn)) return -1; return 0; } } os = smpp_pdu_read_data(conn, *len); if (os == NULL) { if (conn_eof(conn) || conn_error(conn)) return -1; return 0; } *len = 0; *pdu = smpp_pdu_unpack(box->boxc_id, os); if (*pdu == NULL) { error(0, "opensmppbox[%s]: PDU unpacking failed.", octstr_get_cstr(box->boxc_id)); debug("bb.sms.smpp", 0, "opensmppbox[%s]: Failed PDU omitted.", octstr_get_cstr(box->boxc_id)); /* octstr_dump(os, 0); */ octstr_destroy(os); return -1; } octstr_destroy(os); return 1; } static List *msg_to_pdu(Boxc *box, Msg *msg) { SMPP_PDU *pdu, *pdu2; List *pdulist = gwlist_create(), *parts; int dlrtype, catenate; int dlr_state = 7; /* UNKNOWN */ Msg *dlr; char *text, *tmps, err[4] = { '0', '0', '0', '\0' }; char submit_date_c_str[11] = { '\0' }, done_date_c_str[11] = { '\0' }; struct tm tm_tmp; Octstr *msgid, *msgid2, *dlr_status, *dlvrd; /* split variables */ unsigned long msg_sequence, msg_count; unsigned long submit_date; int max_msgs; Octstr *header, *footer, *suffix, *split_chars; Msg *msg2; pdu = smpp_pdu_create(deliver_sm, counter_increase(box->smpp_pdu_counter)); pdu->u.deliver_sm.source_addr = octstr_duplicate(msg->sms.sender); pdu->u.deliver_sm.destination_addr = octstr_duplicate(msg->sms.receiver); /* Set the service type of the outgoing message. We'll use the config * directive as default and 'binfo' as specific parameter. */ pdu->u.deliver_sm.service_type = octstr_len(msg->sms.binfo) ? octstr_duplicate(msg->sms.binfo) : octstr_duplicate(box->service_type); /* Check for manual override of source ton and npi values */ if(box->source_addr_ton > -1 && box->source_addr_npi > -1) { pdu->u.deliver_sm.source_addr_ton = box->source_addr_ton; pdu->u.deliver_sm.source_addr_npi = box->source_addr_npi; debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced source addr ton = %ld, source add npi = %ld", octstr_get_cstr(box->boxc_id), box->source_addr_ton, box->source_addr_npi); } else { /* setup default values */ pdu->u.deliver_sm.source_addr_ton = GSM_ADDR_TON_NATIONAL; /* national */ pdu->u.deliver_sm.source_addr_npi = GSM_ADDR_NPI_E164; /* ISDN number plan */ } if (box->autodetect_addr) { /* lets see if its international or alphanumeric sender */ if (octstr_get_char(pdu->u.deliver_sm.source_addr, 0) == '+') { if (!octstr_check_range(pdu->u.deliver_sm.source_addr, 1, 256, gw_isdigit)) { pdu->u.deliver_sm.source_addr_ton = GSM_ADDR_TON_ALPHANUMERIC; /* alphanum */ pdu->u.deliver_sm.source_addr_npi = GSM_ADDR_NPI_UNKNOWN; /* short code */ } else { /* numeric sender address with + in front -> international (remove the +) */ octstr_delete(pdu->u.deliver_sm.source_addr, 0, 1); pdu->u.deliver_sm.source_addr_ton = GSM_ADDR_TON_INTERNATIONAL; } } else { if (!octstr_check_range(pdu->u.deliver_sm.source_addr,0, 256, gw_isdigit)) { pdu->u.deliver_sm.source_addr_ton = GSM_ADDR_TON_ALPHANUMERIC; pdu->u.deliver_sm.source_addr_npi = GSM_ADDR_NPI_UNKNOWN; } } } /* Check for manual override of destination ton and npi values */ if (box->dest_addr_ton > -1 && box->dest_addr_npi > -1) { pdu->u.deliver_sm.dest_addr_ton = box->dest_addr_ton; pdu->u.deliver_sm.dest_addr_npi = box->dest_addr_npi; debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced dest addr ton = %ld, dest add npi = %ld", octstr_get_cstr(box->boxc_id), box->dest_addr_ton, box->dest_addr_npi); } else { pdu->u.deliver_sm.dest_addr_ton = GSM_ADDR_TON_NATIONAL; /* national */ pdu->u.deliver_sm.dest_addr_npi = GSM_ADDR_NPI_E164; /* ISDN number plan */ } /* * if its a international number starting with +, lets remove the * '+' and set number type to international instead */ if (octstr_get_char(pdu->u.deliver_sm.destination_addr,0) == '+') { octstr_delete(pdu->u.deliver_sm.destination_addr, 0,1); pdu->u.deliver_sm.dest_addr_ton = GSM_ADDR_TON_INTERNATIONAL; } /* check length of src/dst address */ if (octstr_len(pdu->u.deliver_sm.destination_addr) > 20 || octstr_len(pdu->u.deliver_sm.source_addr) > 20) { smpp_pdu_destroy(pdu); gwlist_destroy(pdulist, NULL); return NULL; } /* * set the data coding scheme (DCS) field * check if we have a forced value for this from the smsc-group. * Note: if message class is set, then we _must_ force alt_dcs otherwise * dcs has reserved values (e.g. mclass=2, dcs=0x11). We check MWI flag * first here, because MWI and MCLASS can not be set at the same time and * function fields_to_dcs check MWI first, so we have no need to force alt_dcs * if MWI is set. */ if (msg->sms.mwi == MWI_UNDEF && msg->sms.mclass != MC_UNDEF) pdu->u.deliver_sm.data_coding = fields_to_dcs(msg, 1); /* force alt_dcs */ else pdu->u.deliver_sm.data_coding = fields_to_dcs(msg, (msg->sms.alt_dcs != SMS_PARAM_UNDEFINED ? msg->sms.alt_dcs : box->alt_dcs)); /* set protocol id */ if(msg->sms.pid != SMS_PARAM_UNDEFINED) pdu->u.deliver_sm.protocol_id = msg->sms.pid; /* * set the esm_class field * default is store and forward, plus udh and rpi if requested */ pdu->u.deliver_sm.esm_class = 0; if (octstr_len(msg->sms.udhdata)) pdu->u.deliver_sm.esm_class = pdu->u.deliver_sm.esm_class | ESM_CLASS_SUBMIT_UDH_INDICATOR; if (msg->sms.rpi > 0) pdu->u.deliver_sm.esm_class = pdu->u.deliver_sm.esm_class | ESM_CLASS_SUBMIT_RPI; /* Is this a delivery report? */ if (msg->sms.sms_type == report_mo) { pdu->u.deliver_sm.esm_class |= ESM_CLASS_DELIVER_SMSC_DELIVER_ACK; dlrtype = msg->sms.dlr_mask; parts = octstr_split(msg->sms.dlr_url, octstr_imm(";")); msgid = gwlist_extract_first(parts); dlr = dlr_find(box->boxc_id, msgid, msg->sms.receiver, dlrtype, 0); if (dlr == NULL) { /* we could not find a corresponding dlr; nothing to send */ smpp_pdu_destroy(pdu); gwlist_destroy(pdulist, NULL); octstr_destroy(msgid); gwlist_destroy(parts, octstr_destroy_item); return NULL; } dlvrd = octstr_imm("000"); switch (dlrtype) { case DLR_UNDEFINED: case DLR_NOTHING: dlr_state = 8; dlr_status = octstr_imm("REJECTD"); break; case DLR_SUCCESS: dlr_state = 2; dlr_status = octstr_imm("DELIVRD"); dlvrd = octstr_imm("001"); break; case DLR_BUFFERED: dlr_state = 6; dlr_status = octstr_imm("ACCEPTD"); break; case DLR_SMSC_SUCCESS: /* please note that this state does not quite conform to the SMMP v3.4 spec */ dlr_state = 0; dlr_status = octstr_imm("BUFFRED"); break; case DLR_FAIL: case DLR_SMSC_FAIL: dlr_state = 5; dlr_status = octstr_imm("UNDELIV"); break; } text = octstr_get_cstr(msg->sms.msgdata); tmps = strstr(text, "err:"); if (tmps != NULL) { /* we can't use 0-padding with %s, if this is really required, * then convert the numeric string to a real integer. - st */ snprintf(err, sizeof(err), "%3.3s", tmps + (4 * sizeof(char))); tmps = strstr(tmps, " "); text = tmps ? tmps + (1 * sizeof(char)) : ""; } tmps = strstr(text, "text:"); if (tmps != NULL) { text = tmps + (5 * sizeof(char)); } /* restore original submission date from service */ submit_date = 0; if (octstr_len(dlr->sms.service) > 0) { sscanf(octstr_get_cstr(dlr->sms.service), "%ld", &submit_date); } if (!submit_date || submit_date > dlr->sms.time) { submit_date = msg->sms.time; } tm_tmp = gw_localtime(submit_date); gw_strftime(submit_date_c_str, sizeof(submit_date_c_str), "%y%m%d%H%M", &tm_tmp); tm_tmp = gw_localtime(dlr->sms.time); gw_strftime(done_date_c_str, sizeof(done_date_c_str), "%y%m%d%H%M", &tm_tmp); /* the msgids are in dlr->dlr_url as reported by Victor Luchitz */ gwlist_destroy(parts, octstr_destroy_item); parts = octstr_split(dlr->sms.dlr_url, octstr_imm(";")); octstr_destroy(gwlist_extract_first(parts)); if (gwlist_len(parts) > 0) { while ((msgid2 = gwlist_extract_first(parts)) != NULL) { debug("opensmppbox", 0, "DLR for multipart message: sending %s.", octstr_get_cstr(msgid2)); pdu2 = smpp_pdu_create(deliver_sm, counter_increase(box->smpp_pdu_counter)); pdu2->u.deliver_sm.esm_class = pdu->u.deliver_sm.esm_class; pdu2->u.deliver_sm.source_addr_ton = pdu->u.deliver_sm.source_addr_ton; pdu2->u.deliver_sm.source_addr_npi = pdu->u.deliver_sm.source_addr_npi; pdu2->u.deliver_sm.dest_addr_ton = pdu->u.deliver_sm.dest_addr_ton; pdu2->u.deliver_sm.dest_addr_npi = pdu->u.deliver_sm.dest_addr_npi; pdu2->u.deliver_sm.data_coding = pdu->u.deliver_sm.data_coding; pdu2->u.deliver_sm.protocol_id = pdu->u.deliver_sm.protocol_id; pdu2->u.deliver_sm.source_addr = octstr_duplicate(pdu->u.deliver_sm.source_addr); pdu2->u.deliver_sm.destination_addr = octstr_duplicate(pdu->u.deliver_sm.destination_addr); pdu2->u.deliver_sm.service_type = octstr_duplicate(pdu->u.deliver_sm.service_type); if (box->version > 0x33) { pdu2->u.deliver_sm.receipted_message_id = octstr_duplicate(msgid2); pdu2->u.deliver_sm.message_state = dlr_state; dict_destroy(pdu2->u.deliver_sm.tlv); pdu2->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp"); } pdu2->u.deliver_sm.short_message = octstr_format("id:%S sub:001 dlvrd:%S submit date:%s done date:%s stat:%S err:%s text:%12s", msgid2, dlvrd, submit_date_c_str, done_date_c_str, dlr_status, err, text); octstr_destroy(msgid2); gwlist_append(pdulist, pdu2); } smpp_pdu_destroy(pdu); } else { if (box->version > 0x33) { pdu->u.deliver_sm.receipted_message_id = octstr_duplicate(msgid); pdu->u.deliver_sm.message_state = dlr_state; dict_destroy(pdu->u.deliver_sm.tlv); pdu->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp"); } pdu->u.deliver_sm.short_message = octstr_format("id:%S sub:001 dlvrd:%S submit date:%s done date:%s stat:%S err:%s text:%12s", msgid, dlvrd, submit_date_c_str, done_date_c_str, dlr_status, err, text); gwlist_append(pdulist, pdu); } octstr_destroy(msgid); msg_destroy(dlr); gwlist_destroy(parts, octstr_destroy_item); return pdulist; } else { /* ask for the delivery reports if needed */ if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask)) pdu->u.deliver_sm.registered_delivery = 1; else if (DLR_IS_FAIL(msg->sms.dlr_mask) && !DLR_IS_SUCCESS(msg->sms.dlr_mask)) pdu->u.deliver_sm.registered_delivery = 2; /* * set data segments and length */ pdu->u.deliver_sm.short_message = octstr_duplicate(msg->sms.msgdata); } /* * only re-encoding if using default smsc charset that is defined via * alt-charset in smsc group and if MT is not binary */ if (msg->sms.coding == DC_7BIT || (msg->sms.coding == DC_UNDEF && octstr_len(msg->sms.udhdata))) { /* * consider 3 cases: * a) data_coding 0xFX: encoding should always be GSM 03.38 charset * b) data_coding 0x00: encoding may be converted according to alt-charset * c) data_coding 0x00: assume GSM 03.38 charset if alt-charset is not defined */ if ((pdu->u.deliver_sm.data_coding & 0xF0) || (!box->alt_charset && pdu->u.deliver_sm.data_coding == 0)) { charset_utf8_to_gsm(pdu->u.deliver_sm.short_message); } else if (pdu->u.deliver_sm.data_coding == 0 && box->alt_charset) { /* * convert to the given alternative charset */ if (charset_convert(pdu->u.deliver_sm.short_message, "UTF-8", octstr_get_cstr(box->alt_charset)) != 0) error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.", octstr_get_cstr(box->alt_charset), "UTF-8"); pdu->u.deliver_sm.sm_length = octstr_len(pdu->u.deliver_sm.short_message); } } /* prepend udh if present */ if (octstr_len(msg->sms.udhdata)) { octstr_insert(pdu->u.deliver_sm.short_message, msg->sms.udhdata, 0); } pdu->u.deliver_sm.sm_length = octstr_len(pdu->u.deliver_sm.short_message); /* set priority */ if (msg->sms.priority >= 0 && msg->sms.priority <= 3) pdu->u.deliver_sm.priority_flag = msg->sms.priority; else pdu->u.deliver_sm.priority_flag = box->priority; /* set more messages to send */ /* if (box->version > 0x33 && msg->sms.msg_left > 0) pdu->u.deliver_sm.more_messages_to_send = 1; */ header = NULL; footer = NULL; suffix = NULL; split_chars = NULL; catenate = 1; max_msgs = 255; if (catenate) msg_sequence = counter_increase(catenated_sms_counter) & 0xFF; else msg_sequence = 0; /* split sms */ parts = sms_split(msg, header, footer, suffix, split_chars, catenate, msg_sequence, max_msgs, sms_max_length); msg_count = gwlist_len(parts); if ((msg_count > 1) && (box->version > 0x33)) { Octstr *use_message_payload_meta; long use_message_payload; use_message_payload_meta = meta_data_get_value(msg->sms.meta_data, "smpp", octstr_imm("use_message_payload")); use_message_payload = strtol(octstr_get_cstr(use_message_payload_meta), 0, 0); if (use_message_payload) { /* copy short message data to message_payload TLV */ pdu->u.deliver_sm.message_payload = octstr_duplicate(pdu->u.deliver_sm.short_message); octstr_destroy(pdu->u.deliver_sm.short_message); pdu->u.deliver_sm.short_message = NULL; pdu->u.deliver_sm.sm_length = 0; /* pass the message as a single pdu */ msg_count = 1; } octstr_destroy(use_message_payload_meta); } if (msg_count == 1) { /* don't create split_parts of sms fit into one */ gwlist_destroy(parts, msg_destroy_item); parts = NULL; } debug("SMPP", 0, "message length %ld, sending %ld message%s", octstr_len(msg->sms.msgdata), msg_count, msg_count == 1 ? "" : "s"); if (parts) { while((msg2 = gwlist_extract_first(parts)) != NULL) { pdu2 = smpp_pdu_create(deliver_sm, counter_increase(box->smpp_pdu_counter)); pdu2->u.deliver_sm.source_addr_ton = pdu->u.deliver_sm.source_addr_ton; pdu2->u.deliver_sm.source_addr_npi = pdu->u.deliver_sm.source_addr_npi; pdu2->u.deliver_sm.dest_addr_ton = pdu->u.deliver_sm.dest_addr_ton; pdu2->u.deliver_sm.dest_addr_npi = pdu->u.deliver_sm.dest_addr_npi; pdu2->u.deliver_sm.data_coding = pdu->u.deliver_sm.data_coding; pdu2->u.deliver_sm.protocol_id = pdu->u.deliver_sm.protocol_id; pdu2->u.deliver_sm.source_addr = octstr_duplicate(pdu->u.deliver_sm.source_addr); pdu2->u.deliver_sm.destination_addr = octstr_duplicate(pdu->u.deliver_sm.destination_addr); pdu2->u.deliver_sm.service_type = octstr_duplicate(pdu->u.deliver_sm.service_type); /* the following condition is currently always true */ /* uncomment in case we're doing a SAR-split instead */ if (/*octstr_len(msg2->sms.udhdata) > 0*/1) { pdu2->u.deliver_sm.esm_class = pdu->u.deliver_sm.esm_class | ESM_CLASS_DELIVER_UDH_INDICATOR; pdu2->u.deliver_sm.short_message = octstr_cat(msg2->sms.udhdata, msg2->sms.msgdata); } else { pdu2->u.deliver_sm.short_message = octstr_duplicate(msg2->sms.msgdata); } if (box->version > 0x33) { dict_destroy(pdu2->u.deliver_sm.tlv); pdu2->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp"); } gwlist_append(pdulist, pdu2); msg_destroy(msg2); } smpp_pdu_destroy(pdu); } else { if (box->version > 0x33) { dict_destroy(pdu->u.deliver_sm.tlv); pdu->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp"); } gwlist_append(pdulist, pdu); } return pdulist; } /* * Convert SMPP PDU to internal Msgs structure. * Return the Msg if all was fine and NULL otherwise, while getting * the failing reason delivered back in *reason. * XXX semantical check on the incoming values can be extended here. */ static Msg *pdu_to_msg(Boxc *box, SMPP_PDU *pdu, long *reason) { Msg *msg; int ton, npi; gw_assert(pdu->type == submit_sm); msg = msg_create(sms); gw_assert(msg != NULL); msg->sms.sms_type = mt_push; *reason = SMPP_ESME_ROK; /* * Reset source addr to have a prefixed '+' in case we have an * intl. TON to allow backend boxes (ie. smsbox) to distinguish * between national and international numbers. */ ton = pdu->u.submit_sm.source_addr_ton; npi = pdu->u.submit_sm.source_addr_npi; /* check source addr */ if ((*reason = convert_addr_from_pdu(box->boxc_id, pdu->u.submit_sm.source_addr, ton, npi)) != SMPP_ESME_ROK) goto error; msg->sms.sender = pdu->u.submit_sm.source_addr; pdu->u.submit_sm.source_addr = NULL; msg->sms.service = octstr_duplicate(box->sms_service); /* * Follows SMPP spec. v3.4. issue 1.2 * it's not allowed to have destination_addr NULL */ if (pdu->u.submit_sm.destination_addr == NULL) { error(0, "SMPP[%s]: Mallformed destination_addr `%s', may not be empty. " "Discarding MO message.", octstr_get_cstr(box->boxc_id), octstr_get_cstr(pdu->u.submit_sm.destination_addr)); *reason = SMPP_ESME_RINVDSTADR; goto error; } /* copy priority_flag into msg */ if (pdu->u.submit_sm.priority_flag >= 0 && pdu->u.submit_sm.priority_flag <= 3) { msg->sms.priority = pdu->u.submit_sm.priority_flag; } /* Same reset of destination number as for source */ ton = pdu->u.submit_sm.dest_addr_ton; npi = pdu->u.submit_sm.dest_addr_npi; /* check destination addr */ if ((*reason = convert_addr_from_pdu(box->boxc_id, pdu->u.submit_sm.destination_addr, ton, npi)) != SMPP_ESME_ROK) goto error; msg->sms.receiver = pdu->u.submit_sm.destination_addr; pdu->u.submit_sm.destination_addr = NULL; /* SMSCs use service_type for billing information */ msg->sms.binfo = pdu->u.submit_sm.service_type; pdu->u.submit_sm.service_type = NULL; if (pdu->u.submit_sm.esm_class & ESM_CLASS_SUBMIT_RPI) msg->sms.rpi = 1; /* * Check for message_payload if version > 0x33 and sm_length == 0 * Note: SMPP spec. v3.4. doesn't allow to send both: message_payload & short_message! */ if (box->version > 0x33 && pdu->u.submit_sm.sm_length == 0 && pdu->u.submit_sm.message_payload) { msg->sms.msgdata = pdu->u.submit_sm.message_payload; pdu->u.submit_sm.message_payload = NULL; } else { msg->sms.msgdata = pdu->u.submit_sm.short_message; pdu->u.submit_sm.short_message = NULL; } /* * Encode udh if udhi set * for reference see GSM03.40, section 9.2.3.24 */ if (pdu->u.submit_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) { int udhl; udhl = octstr_get_char(msg->sms.msgdata, 0) + 1; debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d", octstr_get_cstr(box->boxc_id), udhl); if (udhl > octstr_len(msg->sms.msgdata)) { error(0, "SMPP[%s]: Mallformed UDH length indicator 0x%03x while message length " "0x%03lx. Discarding MO message.", octstr_get_cstr(box->boxc_id), udhl, octstr_len(msg->sms.msgdata)); *reason = SMPP_ESME_RINVESMCLASS; goto error; } msg->sms.udhdata = octstr_copy(msg->sms.msgdata, 0, udhl); octstr_delete(msg->sms.msgdata, 0, udhl); } dcs_to_fields(&msg, pdu->u.submit_sm.data_coding); /* handle default data coding */ switch (pdu->u.submit_sm.data_coding) { case 0x00: /* default SMSC alphabet */ /* * try to convert from something interesting if specified so * unless it was specified binary, ie. UDH indicator was detected */ if (box->alt_charset && msg->sms.coding != DC_8BIT) { if (charset_convert(msg->sms.msgdata, octstr_get_cstr(box->alt_charset), "UTF-8") != 0) error(0, "Failed to convert msgdata from charset <%s> to <%s>, will leave as is.", "UTF-8", octstr_get_cstr(box->alt_charset)); msg->sms.coding = DC_7BIT; } else { /* assume GSM 03.38 7-bit alphabet */ charset_gsm_to_utf8(msg->sms.msgdata); msg->sms.coding = DC_7BIT; } break; case 0x01: /* ASCII or IA5 - not sure if I need to do anything */ case 0x03: /* ISO-8859-1 - do nothing */ msg->sms.coding = DC_7BIT; break; case 0x02: /* 8 bit binary - do nothing */ case 0x04: /* 8 bit binary - do nothing */ msg->sms.coding = DC_8BIT; break; case 0x05: /* JIS - what do I do with that ? */ break; case 0x06: /* Cyrllic - iso-8859-5, I'll convert to unicode */ if (charset_convert(msg->sms.msgdata, "ISO-8859-5", "UCS-2BE") != 0) error(0, "Failed to convert msgdata from cyrllic to UCS-2, will leave as is"); msg->sms.coding = DC_UCS2; break; case 0x07: /* Hebrew iso-8859-8, I'll convert to unicode */ if (charset_convert(msg->sms.msgdata, "ISO-8859-8", "UCS-2BE") != 0) error(0, "Failed to convert msgdata from hebrew to UCS-2, will leave as is"); msg->sms.coding = DC_UCS2; break; case 0x08: /* unicode UCS-2, yey */ msg->sms.coding = DC_UCS2; break; /* * don't much care about the others, * you implement them if you feel like it */ default: /* * some of smsc send with dcs from GSM 03.38 , but these are reserved in smpp spec. * So we just look decoded values from dcs_to_fields and if none there make our assumptions. * if we have an UDH indicator, we assume DC_8BIT. */ if (msg->sms.coding == DC_UNDEF && pdu->u.submit_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) msg->sms.coding = DC_8BIT; else if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) { /* assume GSM 7Bit , reencode */ msg->sms.coding = DC_7BIT; charset_gsm_to_utf8(msg->sms.msgdata); } } msg->sms.pid = pdu->u.submit_sm.protocol_id; /* set priority flag */ msg->sms.priority = pdu->u.submit_sm.priority_flag; /* ask for the delivery reports if needed */ switch (pdu->u.submit_sm.registered_delivery & 0x03) { case 1: msg->sms.dlr_mask = (DLR_SUCCESS | DLR_FAIL | DLR_SMSC_FAIL); break; case 2: msg->sms.dlr_mask = (DLR_FAIL | DLR_SMSC_FAIL); break; default: msg->sms.dlr_mask = 0; break; } if (pdu->u.submit_sm.esm_class & (0x04|0x08)) { msg->sms.sms_type = report_mo; } if (box->version > 0x33) { if (msg->sms.meta_data == NULL) msg->sms.meta_data = octstr_create(""); meta_data_set_values(msg->sms.meta_data, pdu->u.submit_sm.tlv, "smpp", 1); } msg->sms.time = time(NULL); /* set validity period if needed */ if (pdu->u.submit_sm.validity_period) { msg->sms.validity = time(NULL) + timestamp_to_minutes(pdu->u.submit_sm.validity_period) * 60; } /* set schedule delivery time if needed */ if (pdu->u.submit_sm.schedule_delivery_time) { msg->sms.deferred = time(NULL) + timestamp_to_minutes(pdu->u.submit_sm.schedule_delivery_time) * 60; } return msg; error: msg_destroy(msg); return NULL; } /* * Convert SMPP PDU to internal Msgs structure. * Return the Msg if all was fine and NULL otherwise, while getting * the failing reason delivered back in *reason. * XXX semantical check on the incoming values can be extended here. */ static Msg *data_sm_to_msg(Boxc *box, SMPP_PDU *pdu, long *reason) { Msg *msg; int ton, npi; gw_assert(pdu->type == data_sm); msg = msg_create(sms); gw_assert(msg != NULL); msg->sms.sms_type = mt_push; *reason = SMPP_ESME_ROK; /* * Reset source addr to have a prefixed '+' in case we have an * intl. TON to allow backend boxes (ie. smsbox) to distinguish * between national and international numbers. */ ton = pdu->u.data_sm.source_addr_ton; npi = pdu->u.data_sm.source_addr_npi; /* check source addr */ if ((*reason = convert_addr_from_pdu(box->boxc_id, pdu->u.data_sm.source_addr, ton, npi)) != SMPP_ESME_ROK) goto error; msg->sms.sender = pdu->u.data_sm.source_addr; pdu->u.data_sm.source_addr = NULL; /* * Follows SMPP spec. v3.4. issue 1.2 * it's not allowed to have destination_addr NULL */ if (pdu->u.data_sm.destination_addr == NULL) { error(0, "SMPP[%s]: Mallformed destination_addr `%s', may not be empty. " "Discarding MO message.", octstr_get_cstr(box->boxc_id), octstr_get_cstr(pdu->u.data_sm.destination_addr)); *reason = SMPP_ESME_RINVDSTADR; goto error; } /* Same reset of destination number as for source */ ton = pdu->u.data_sm.dest_addr_ton; npi = pdu->u.data_sm.dest_addr_npi; /* check destination addr */ if ((*reason = convert_addr_from_pdu(box->boxc_id, pdu->u.data_sm.destination_addr, ton, npi)) != SMPP_ESME_ROK) goto error; msg->sms.receiver = pdu->u.data_sm.destination_addr; pdu->u.data_sm.destination_addr = NULL; /* SMSCs use service_type for billing information */ msg->sms.binfo = pdu->u.data_sm.service_type; pdu->u.data_sm.service_type = NULL; if (pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_RPI) msg->sms.rpi = 1; msg->sms.msgdata = pdu->u.data_sm.message_payload; pdu->u.data_sm.message_payload = NULL; /* * Encode udh if udhi set * for reference see GSM03.40, section 9.2.3.24 */ if (pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) { int udhl; udhl = octstr_get_char(msg->sms.msgdata, 0) + 1; debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d", octstr_get_cstr(box->boxc_id), udhl); if (udhl > octstr_len(msg->sms.msgdata)) { error(0, "SMPP[%s]: Mallformed UDH length indicator 0x%03x while message length " "0x%03lx. Discarding MO message.", octstr_get_cstr(box->boxc_id), udhl, octstr_len(msg->sms.msgdata)); *reason = SMPP_ESME_RINVESMCLASS; goto error; } msg->sms.udhdata = octstr_copy(msg->sms.msgdata, 0, udhl); octstr_delete(msg->sms.msgdata, 0, udhl); } dcs_to_fields(&msg, pdu->u.data_sm.data_coding); /* handle default data coding */ switch (pdu->u.data_sm.data_coding) { case 0x00: /* default SMSC alphabet */ /* * try to convert from something interesting if specified so * unless it was specified binary, ie. UDH indicator was detected */ if (box->alt_charset && msg->sms.coding != DC_8BIT) { if (charset_convert(msg->sms.msgdata, "UTF-8", octstr_get_cstr(box->alt_charset)) != 0) error(0, "Failed to convert msgdata from charset <%s> to <%s>, will leave as is.", "UTF-8", octstr_get_cstr(box->alt_charset)); msg->sms.coding = DC_7BIT; } else { /* assume GSM 03.38 7-bit alphabet */ charset_gsm_to_utf8(msg->sms.msgdata); msg->sms.coding = DC_7BIT; } break; case 0x01: /* ASCII or IA5 - not sure if I need to do anything */ case 0x03: /* ISO-8859-1 - do nothing */ msg->sms.coding = DC_7BIT; break; case 0x02: /* 8 bit binary - do nothing */ case 0x04: /* 8 bit binary - do nothing */ msg->sms.coding = DC_8BIT; break; case 0x05: /* JIS - what do I do with that ? */ break; case 0x06: /* Cyrllic - iso-8859-5, I'll convert to unicode */ if (charset_convert(msg->sms.msgdata, "ISO-8859-5", "UCS-2BE") != 0) error(0, "Failed to convert msgdata from cyrllic to UCS-2, will leave as is"); msg->sms.coding = DC_UCS2; break; case 0x07: /* Hebrew iso-8859-8, I'll convert to unicode */ if (charset_convert(msg->sms.msgdata, "ISO-8859-8", "UCS-2BE") != 0) error(0, "Failed to convert msgdata from hebrew to UCS-2, will leave as is"); msg->sms.coding = DC_UCS2; break; case 0x08: /* unicode UCS-2, yey */ msg->sms.coding = DC_UCS2; break; /* * don't much care about the others, * you implement them if you feel like it */ default: /* * some of smsc send with dcs from GSM 03.38 , but these are reserved in smpp spec. * So we just look decoded values from dcs_to_fields and if none there make our assumptions. * if we have an UDH indicator, we assume DC_8BIT. */ if (msg->sms.coding == DC_UNDEF && pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) msg->sms.coding = DC_8BIT; else if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) { /* assume GSM 7Bit , reencode */ msg->sms.coding = DC_7BIT; charset_gsm_to_utf8(msg->sms.msgdata); } } if (box->version > 0x33) { if (msg->sms.meta_data == NULL) msg->sms.meta_data = octstr_create(""); meta_data_set_values(msg->sms.meta_data, pdu->u.data_sm.tlv, "smpp", 1); } msg->sms.time = time(NULL); return msg; error: msg_destroy(msg); return NULL; } Octstr *concat_msgids(Octstr *msgid, List *list) { Octstr *ret = octstr_duplicate(msgid); int i; Msg *msg; for (i = 0; i < gwlist_len(list); i++) { msg = gwlist_get(list, i); octstr_append(ret, octstr_imm(";")); octstr_append(ret, msg->sms.dlr_url); } return ret; } void check_multipart(Boxc *box, Msg *msg, int *msg_to_send, Msg **msg2, List **parts_list) { int reference, total; Octstr *key; if (msg->sms.udhdata && octstr_len(msg->sms.udhdata) == 6 && octstr_get_char(msg->sms.udhdata, 1) == 0) { /* We collect long messages as one and send them to bearerbox as a whole, so they can be sent from the same smsc. */ (*msg_to_send) = 0; debug("opensmppbox", 0, "assemble multi-part message."); reference = octstr_get_char(msg->sms.udhdata, 3); total = octstr_get_char(msg->sms.udhdata, 4); key = octstr_format("%S-%i", msg->sms.receiver, reference); (*parts_list) = dict_get(list_dict, key); if (NULL == (*parts_list)) { (*parts_list) = gwlist_create(); dict_put(list_dict, key, (*parts_list)); } debug("opensmppbox", 0, "received %ld of %d.", gwlist_len((*parts_list)) + 1, total); if ((gwlist_len((*parts_list)) + 1) == total) { debug("opensmppbox", 0, "received all parts of multi-part message."); gwlist_append((*parts_list), msg); /* assemble message */ (*msg2) = catenate_msg((*parts_list), total); dict_put(list_dict, key, NULL); octstr_destroy(key); if (NULL == (*msg2)) { /* we could not assemble an appropiate message */ debug("opensmppbox", 0, "Invalid multi-part message."); } else { Octstr *smsc_id = boxc_route_msg_to_smsc(box, *msg2); (*msg2)->sms.smsc_id = smsc_id ? octstr_duplicate(smsc_id) : NULL; (*msg2)->sms.boxc_id = octstr_duplicate(box->boxc_id); debug("opensmppbox", 0, "multi-part message, length: %ld.", octstr_len((*msg2)->sms.msgdata)); (*msg_to_send) = 1; } } else { gwlist_append((*parts_list), msg); octstr_destroy(key); } } } static void handle_pdu(Connection *conn, Boxc *box, SMPP_PDU *pdu) { SMPP_PDU *resp = NULL; Msg *msg, *msg2, *mack; long reason; Octstr *msgid = NULL, *hold_service, *system_type; int msg_to_send = 1; List *parts_list = NULL; char id[UUID_STR_LEN + 1]; dump_pdu("Got PDU:", box->boxc_id, pdu); switch (pdu->type) { case bind_transmitter: case bind_receiver: case bind_transceiver: break; default: if (!box->logged_in) { resp = smpp_pdu_create(generic_nack, pdu->u.generic_nack.sequence_number); resp->u.generic_nack.command_status = SMPP_ESME_RINVPASWD; goto error; } break; } switch (pdu->type) { case bind_transmitter: system_type = pdu->u.bind_transmitter.system_type ? pdu->u.bind_transmitter.system_type : octstr_imm(""); if (check_login(box, pdu->u.bind_transmitter.system_id, pdu->u.bind_transmitter.password, system_type, SMPP_LOGIN_TRANSMITTER)) { box->logged_in = 1; box->version = pdu->u.bind_transmitter.interface_version; box->login_type = SMPP_LOGIN_TRANSMITTER; box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type); box->sms_service = octstr_duplicate(pdu->u.bind_transmitter.system_id); identify_to_bearerbox(box); resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter.sequence_number); resp->u.bind_transmitter_resp.system_id = octstr_duplicate(our_system_id); } else { resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter_resp.sequence_number); resp->u.bind_transmitter.command_status = 0x0d; /* invalid login */ } break; case bind_receiver: system_type = pdu->u.bind_receiver.system_type ? pdu->u.bind_receiver.system_type : octstr_imm(""); if (check_login(box, pdu->u.bind_receiver.system_id, pdu->u.bind_receiver.password, system_type, SMPP_LOGIN_RECEIVER)) { box->logged_in = 1; box->version = pdu->u.bind_receiver.interface_version; box->login_type = SMPP_LOGIN_RECEIVER; box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type); box->sms_service = octstr_duplicate(pdu->u.bind_receiver.system_id); identify_to_bearerbox(box); resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number); resp->u.bind_receiver_resp.system_id = octstr_duplicate(our_system_id); } else { resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number); resp->u.bind_receiver_resp.command_status = 0x0d; /* invalid login */ } break; case bind_transceiver: system_type = pdu->u.bind_transceiver.system_type ? pdu->u.bind_transceiver.system_type : octstr_imm(""); if (check_login(box, pdu->u.bind_transceiver.system_id, pdu->u.bind_transceiver.password, system_type, SMPP_LOGIN_TRANSCEIVER)) { box->logged_in = 1; box->version = pdu->u.bind_transceiver.interface_version; box->login_type = SMPP_LOGIN_TRANSCEIVER; box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type); box->sms_service = octstr_duplicate(pdu->u.bind_transceiver.system_id); identify_to_bearerbox(box); resp = smpp_pdu_create(bind_transceiver_resp, pdu->u.bind_transceiver.sequence_number); resp->u.bind_transceiver_resp.system_id = octstr_duplicate(our_system_id); } else { resp = smpp_pdu_create(bind_transceiver_resp, pdu->u.bind_transceiver.sequence_number); resp->u.bind_transceiver_resp.command_status = 0x0d; /* invalid login */ } break; case unbind: resp = smpp_pdu_create(unbind_resp, pdu->u.unbind.sequence_number); box->logged_in = 0; box->alive = 0; break; case enquire_link: resp = smpp_pdu_create(enquire_link_resp, pdu->u.enquire_link.sequence_number); break; case data_sm: msg = data_sm_to_msg(box, pdu, &reason); msg2 = msg; if (msg == NULL) { resp = smpp_pdu_create(generic_nack, pdu->u.data_sm.sequence_number); resp->u.generic_nack.command_status = SMPP_ESME_RUNKNOWNERR; } else { Octstr *smsc_id = boxc_route_msg_to_smsc(box, msg); check_multipart(box, msg, &msg_to_send, &msg2, &parts_list); msg->sms.smsc_id = smsc_id ? octstr_duplicate(smsc_id) : NULL; msg->sms.boxc_id = octstr_duplicate(box->boxc_id); msg_dump(msg, 0); resp = smpp_pdu_create(data_sm_resp, pdu->u.data_sm.sequence_number); msgid = generate_smppid(msg, box->version); msg->sms.dlr_url = octstr_duplicate(msgid); resp->u.data_sm_resp.message_id = msgid; if (msg_to_send) { if (DLR_IS_ENABLED(msg2->sms.dlr_mask)) { hold_service = msg2->sms.service; msg2->sms.service = octstr_format("%ld", msg2->sms.time); msgid = generate_smppid(msg2, box->version); if (parts_list) { msg2->sms.dlr_url = concat_msgids(msgid, parts_list); } dlr_add(box->boxc_id, msgid, msg2, 0); octstr_destroy(msgid); octstr_destroy(msg2->sms.service); msg2->sms.service = hold_service; } uuid_unparse(msg2->sms.id, id); msgid = octstr_create(id); dict_put(box->msg_acks, msgid, resp); resp = NULL; send_msg(box->bearerbox_connection, box, msg2); if (parts_list) { /* destroy values */ gwlist_destroy(parts_list, msg_destroy_item); } else if (msg != msg2) { msg_destroy(msg); } } } break; case submit_sm: msg = pdu_to_msg(box, pdu, &reason); msg2 = msg; if (msg == NULL) { resp = smpp_pdu_create(generic_nack, pdu->u.submit_sm.sequence_number); resp->u.generic_nack.command_status = SMPP_ESME_RUNKNOWNERR; } else { Octstr *smsc_id = boxc_route_msg_to_smsc(box, msg); check_multipart(box, msg, &msg_to_send, &msg2, &parts_list); msg->sms.smsc_id = smsc_id ? octstr_duplicate(smsc_id) : NULL; msg->sms.boxc_id = octstr_duplicate(box->boxc_id); msg_dump(msg, 0); resp = smpp_pdu_create(submit_sm_resp, pdu->u.submit_sm.sequence_number); msgid = generate_smppid(msg, box->version); msg->sms.dlr_url = octstr_duplicate(msgid); resp->u.submit_sm_resp.message_id = msgid; if (msg_to_send) { if (DLR_IS_ENABLED(msg2->sms.dlr_mask)) { hold_service = msg2->sms.service; msg2->sms.service = octstr_format("%ld", msg2->sms.time); msgid = generate_smppid(msg2, box->version); if (parts_list) { msg2->sms.dlr_url = concat_msgids(msgid, parts_list); } dlr_add(box->boxc_id, msgid, msg2, 0); octstr_destroy(msgid); octstr_destroy(msg2->sms.service); msg2->sms.service = hold_service; } uuid_unparse(msg2->sms.id, id); msgid = octstr_create(id); dict_put(box->msg_acks, msgid, resp); octstr_destroy(msgid); resp = NULL; send_msg(box->bearerbox_connection, box, msg2); if (parts_list) { /* destroy values */ gwlist_destroy(parts_list, msg_destroy_item); } else if (msg != msg2) { msg_destroy(msg); } } } break; case deliver_sm_resp: msgid = octstr_format("%ld", pdu->u.deliver_sm_resp.sequence_number); mack = dict_get(box->deliver_acks, msgid); if (mack) { msg = msg_duplicate(mack); /* TODO: ack_failed_tmp */ if (pdu->u.deliver_sm_resp.command_status != 0) { msg->ack.nack = ack_failed; } send_msg(box->bearerbox_connection, box, msg); dict_put(box->deliver_acks, msgid, NULL); } octstr_destroy(msgid); break; case unbind_resp: box->logged_in = 0; box->alive = 0; default: error(0, "SMPP[%s]: Unknown PDU type 0x%08lx, ignored.", octstr_get_cstr(box->boxc_id), pdu->type); /* send gnack , see smpp3.4 spec., section 3.3 because we doesn't know what kind of pdu received, we assume generick_nack_resp (header always the same) */ resp = smpp_pdu_create(generic_nack, pdu->u.generic_nack.sequence_number); resp->u.generic_nack.command_status = SMPP_ESME_RINVCMDID; break; } error: smpp_pdu_destroy(pdu); if (resp != NULL) { send_pdu(conn, box->boxc_id, resp); smpp_pdu_destroy(resp); } } /* *------------------------------------------------- * sender thingies *------------------------------------------------- * */ static Boxc *boxc_create(int fd, Octstr *ip, int ssl) { Boxc *boxc; boxc = gw_malloc(sizeof(Boxc)); boxc->logged_in = 0; boxc->is_wap = 0; boxc->load = 0; boxc->smpp_connection = conn_wrap_fd(fd, ssl); boxc->id = counter_increase(boxid); boxc->client_ip = octstr_duplicate(ip); boxc->alive = 1; boxc->connect_time = time(NULL); boxc->boxc_id = NULL; boxc->routable = 0; boxc->smpp_pdu_counter = counter_create(); boxc->alt_charset = NULL; if (NULL != alt_charset) boxc->alt_charset = octstr_duplicate(alt_charset); /* todo: make this configurable on a per-esme basis */ boxc->version = 0x33; /* default value, set upon receiving a bind */ boxc->route_to_smsc = route_to_smsc ? octstr_duplicate(route_to_smsc) : NULL; boxc->msg_acks = dict_create(256, smpp_pdu_destroy_item); boxc->deliver_acks = dict_create(256, msg_destroy_item); boxc->service_type = NULL; boxc->source_addr_ton = smpp_source_addr_ton; boxc->source_addr_npi = smpp_source_addr_npi; boxc->autodetect_addr = smpp_autodetect_addr; boxc->dest_addr_ton = smpp_dest_addr_ton; boxc->dest_addr_npi = smpp_dest_addr_npi; boxc->alt_dcs = 0; boxc->validityperiod = -1; boxc->priority = 0; boxc->mo_recode = 0; boxc->sms_service = NULL; return boxc; } static void boxc_destroy(Boxc *boxc) { if (boxc == NULL) return; /* do nothing to the lists, as they are only references */ if (boxc->smpp_connection) conn_destroy(boxc->smpp_connection); if (boxc->bearerbox_connection) conn_destroy(boxc->bearerbox_connection); if (boxc->boxc_id) octstr_destroy(boxc->boxc_id); if (boxc->alt_charset) octstr_destroy(boxc->alt_charset); counter_destroy(boxc->smpp_pdu_counter); if (boxc->route_to_smsc) { octstr_destroy(boxc->route_to_smsc); } if (boxc->client_ip) octstr_destroy(boxc->client_ip); if (boxc->alt_charset) { octstr_destroy(boxc->alt_charset); } dict_destroy(boxc->msg_acks); dict_destroy(boxc->deliver_acks); if (boxc->sms_service) octstr_destroy(boxc->sms_service); gw_free(boxc); } static Octstr *boxc_route_msg_to_smsc(Boxc *box, Msg *msg) { Octstr *os = NULL, *smsc_id; if (msg->sms.smsc_id != NULL) return msg->sms.smsc_id; char *receiver = octstr_get_cstr(msg->sms.receiver); if ( (receiver) && (strlen(receiver) > 0) ) { smsc_id = dict_get(smsc_by_receiver, msg->sms.receiver); } else { receiver = ""; } if (!smsc_id) { os = octstr_format("%s:%s", octstr_get_cstr(msg->sms.sender), octstr_get_cstr(box->boxc_id)); smsc_id = dict_get(smsc_by_sender_smsbox_id, os); octstr_destroy(os); }; if (!smsc_id) smsc_id = dict_get(smsc_by_sender, msg->sms.sender); if (!smsc_id) smsc_id = dict_get(smsc_by_smsbox_id, box->boxc_id); if (!smsc_id) smsc_id = box->route_to_smsc; if (smsc_id) debug("opensmppbox", 0, "routed msg '%s' to smsc '%s'", receiver, octstr_get_cstr(smsc_id)); return smsc_id; } /* ------------------------------------------------------------------ * SMPP thingies * ------------------------------------------------------------------ */ /* generally, SMPP connections are always non-encrypted. */ static Boxc *accept_smpp(int fd, int ssl) { Boxc *newconn; Octstr *ip; int newfd; struct sockaddr_in client_addr; socklen_t client_addr_len; client_addr_len = sizeof(client_addr); newfd = accept(fd, (struct sockaddr *)&client_addr, &client_addr_len); if (newfd < 0) return NULL; ip = host_ip(client_addr); newconn = boxc_create(newfd, ip, 0); /* * check if the SSL handshake was successfull, otherwise * this is no valid box connection any more */ #ifdef HAVE_LIBSSL if (ssl && !conn_get_ssl(newconn->smpp_connection)) return NULL; #endif info(0, "Client connected from <%s>", octstr_get_cstr(ip)); octstr_destroy(ip); /* XXX TODO: do the hand-shake, baby, yeah-yeah! */ return newconn; } static void smpp_to_bearerbox(void *arg) { Boxc *box = arg; Connection *conn = box->smpp_connection; SMPP_PDU *pdu; long len; box->last_pdu_received = time(NULL); len = 0; while (smppbox_status == SMPP_RUNNING && box->alive) { switch (read_pdu(box, conn, &len, &pdu)) { case -1: error(0, "Invalid SMPP PDU received."); box->alive = 0; break; case 0: // idling if (time(NULL) - box->last_pdu_received > smpp_timeout) { box->alive = 0; } gwthread_sleep(1); break; case 1: box->last_pdu_received = time(NULL); handle_pdu(conn, box, pdu); break; } } #ifdef HAVE_SHUTDOWN_CONNECTION shutdown_connection(box->bearerbox_connection); #endif } /* if this login was made as a transmitter, then find the corresponding receiver connection */ static Boxc *find_receiver_box(Boxc *box) { Boxc *thisbox; int cnt; if (box->login_type == SMPP_LOGIN_RECEIVER || box->login_type == SMPP_LOGIN_TRANSCEIVER) { return box; } for (cnt = 0; cnt < gwlist_len(all_boxes); cnt++) { thisbox = (Boxc *)gwlist_get(all_boxes, cnt); if ((thisbox->login_type == SMPP_LOGIN_RECEIVER || thisbox->login_type == SMPP_LOGIN_TRANSCEIVER) && (octstr_compare(thisbox->boxc_id, box->boxc_id) == 0) && thisbox->alive) { return thisbox; } } return box; } static void bearerbox_to_smpp(void *arg) { Msg *msg, *mack; Boxc *box = arg; SMPP_PDU *pdu; List *pdulist; int dreport, errcode; Boxc *receiver_box; char id[UUID_STR_LEN + 1]; Octstr *msgid; while (smppbox_status == SMPP_RUNNING && box->alive) { msg = read_from_box(box->bearerbox_connection, box); if (msg == NULL) { if ((!box->alive) || conn_eof(box->bearerbox_connection)) { /* tell opensmppbox to die */ /* the client closes the connection, after that die in receiver */ box->alive = 0; } continue; } if (msg_type(msg) == admin) { if (msg->admin.command == cmd_shutdown) { info(0, "Bearerbox told us to die"); box->alive = 0; } else if (msg->admin.command == cmd_restart) { info(0, "Bearerbox told us to restart"); restart = 1; box->alive = 0; } } if (msg_type(msg) == heartbeat) { // todo debug("opensmppbox", 0, "bearerbox_to_smpp: catch an heartbeat - we are alive"); msg_destroy(msg); continue; } if (msg_type(msg) == ack) { uuid_unparse(msg->ack.id, id); msgid = octstr_create(id); pdu = dict_get(box->msg_acks, msgid); errcode = SMPP_ESME_RMSGQFUL; /* in case we get ack_failed_tmp */ if (pdu) { switch (msg->ack.nack) { case ack_buffered: case ack_success: /* we can send the submit_sm_resp as-is */ break; case ack_failed: errcode = SMPP_ESME_RSUBMITFAIL; /* no break */ case ack_failed_tmp: switch (pdu->type) { case submit_sm_resp: octstr_destroy(pdu->u.submit_sm_resp.message_id); pdu->u.submit_sm_resp.message_id = NULL; pdu->u.submit_sm_resp.command_status = errcode; break; case data_sm_resp: octstr_destroy(pdu->u.data_sm_resp.message_id); pdu->u.data_sm_resp.message_id = NULL; pdu->u.data_sm_resp.command_status = errcode; break; default: debug("opensmppbox", 0, "Getting failure ack on unexpected pdu: %s.", pdu->type_name); break; } break; default: debug("opensmppbox", 0, "Unknown ack.nack type: %ld.", msg->ack.nack); break; } send_pdu(box->smpp_connection, box->boxc_id, pdu); dict_put(box->msg_acks, msgid, NULL); /* also destroys item */ } else { debug("opensmppbox", 0, "Ack to unknown message: %s.", id); } octstr_destroy(msgid); } if (!box->alive) { msg_destroy(msg); break; } if (msg_type(msg) == sms) { info(0, "We received an SMS message."); if (msg->sms.sms_type == report_mo) dreport = 1; else dreport = 0; /* Recode to iso-8859-1 the MO message if possible */ if (box->mo_recode && msg->sms.coding == DC_UCS2) { int converted = 0; Octstr *text; text = octstr_duplicate(msg->sms.msgdata); if(0 == octstr_recode (octstr_imm("UTF-8"), octstr_imm("UTF-16BE"), text)) { if(octstr_search(text, octstr_imm("&#"), 0) == -1) { /* XXX I'm trying to search for &#xxxx; text, which indicates that the * text couldn't be recoded. * We should use other function to do the recode or detect it using * other method */ info(0, "MO message converted from UCS-2 to UTF-8"); octstr_destroy(msg->sms.msgdata); msg->sms.msgdata = octstr_duplicate(text); msg->sms.charset = octstr_create("UTF-8"); msg->sms.coding = DC_7BIT; converted=1; } else { octstr_destroy(text); text = octstr_duplicate(msg->sms.msgdata); } } if(!converted && 0 == octstr_recode (octstr_imm("UTF-8"), octstr_imm("UTF-16BE"), text)) { if(octstr_search(text, octstr_imm("&#"), 0) == -1) { /* XXX I'm trying to search for &#xxxx; text, which indicates that the * text couldn't be recoded. * We should use other function to do the recode or detect it using * other method */ info(0, "MO message converted from UCS-2 to UTF-8"); octstr_destroy(msg->sms.msgdata); msg->sms.msgdata = octstr_duplicate(text); msg->sms.charset = octstr_create("UTF-8"); msg->sms.coding = DC_7BIT; /* redundant, but this code could be used if another convertion is required converted=1; } else { octstr_destroy(text); text = octstr_duplicate(msg->sms.msgdata); */ } } octstr_destroy(text); } if (octstr_len(msg->sms.sender) == 0 || octstr_len(msg->sms.receiver) == 0) { error(0, "smppbox_req_thread: no sender/receiver, dump follows:"); msg_dump(msg, 0); /* * Send NACK to bearerbox, otherwise message remains in store file. */ mack = msg_create(ack); mack->ack.nack = ack_failed; mack->ack.time = msg->sms.time; uuid_copy(mack->ack.id, msg->sms.id); send_msg(box->bearerbox_connection, box, mack); msg_destroy(msg); continue; } /* create ack message to be sent afterwards */ mack = msg_create(ack); mack->ack.nack = ack_success; mack->ack.time = msg->sms.time; uuid_copy(mack->ack.id, msg->sms.id); msgid = NULL; receiver_box = find_receiver_box(box); pdulist = msg_to_pdu(receiver_box, msg); if (pdulist != NULL) { while ((pdu = gwlist_extract_first(pdulist)) != NULL) { if (NULL == msgid) { /* Put ack in dict. We will send it as soon as we received a deliver_sm_resp */ msgid = octstr_format("%ld", pdu->u.deliver_sm.sequence_number); dict_put(receiver_box->deliver_acks, msgid, mack); } send_pdu(receiver_box->smpp_connection, box->boxc_id, pdu); smpp_pdu_destroy(pdu); } if (msgid) octstr_destroy(msgid); gwlist_destroy(pdulist, NULL); } else { /* Send NACK to bearerbox, otherwise message remains in store file. */ warning(0, "msg_to_pdu failed, sending negative ack"); mack->ack.nack = ack_failed; send_msg(box->bearerbox_connection, box, mack); } } msg_destroy(msg); } } static void run_smppbox(void *arg) { int fd; Boxc *newconn; long sender; fd = (int)arg; newconn = accept_smpp(fd, 0); if (newconn == NULL) { panic(0, "Socket accept failed"); return; } newconn->boxc_id = octstr_duplicate(smppbox_id); newconn->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL /* bb_our_host */); /* XXX add our_host if required */ if (newconn->bearerbox_connection == NULL) { error(0, "opensmppbox: Failed to connect to bearerbox." ); boxc_destroy(newconn); return; } gwlist_append(all_boxes, newconn); #ifdef DO_HEARTBEATS /* we dont do heartbeats for now */ if (0 > heartbeat_start(write_to_bearerboxes, DEFAULT_HEARTBEAT, outstanding_requests)) { info(0, "OpenSMPPBox: Could not start heartbeat."); } #endif sender = gwthread_create(smpp_to_bearerbox, newconn); if (sender == -1) { error(0, "Failed to start a new thread, disconnecting client <%s>", octstr_get_cstr(newconn->client_ip)); boxc_destroy(newconn); return; } bearerbox_to_smpp(newconn); gwthread_join(sender); gwlist_delete_equal(all_boxes, newconn); boxc_destroy(newconn); } static void wait_for_connections(int fd, void (*function) (void *arg), List *waited) { int ret = 0; int timeout = 10; /* 10 sec. */ gw_assert(function != NULL); while(smppbox_status == SMPP_RUNNING) { ret = gwthread_pollfd(fd, POLLIN, 1.0); if (smppbox_status == SMPP_SHUTDOWN) { if (ret == -1 || !timeout) break; else timeout--; } if (ret > 0) { gwthread_create(function, (void *)fd); gwthread_sleep(1.0); } else if (ret < 0) { if(errno==EINTR) continue; if(errno==EAGAIN) continue; error(errno, "wait_for_connections failed"); } } } static void smppboxc_run(void *arg) { int fd; int port; port = (int)arg; fd = make_server_socket(port, NULL); /* XXX add interface_name if required */ if (fd < 0) { panic(0, "Could not open opensmppbox port %d", port); } /* * infinitely wait for new connections; * to shut down the system, SIGTERM is send and then * select drops with error, so we can check the status */ info(0, "Waiting for SMPP connections on port %d.", port); wait_for_connections(fd, run_smppbox, NULL); info(0, "No more waiting for SMPP connections."); /* close listen socket */ close(fd); } /*********************************************************************** * Main program. Configuration, signal handling, etc. */ static void signal_handler(int signum) { /* On some implementations (i.e. linuxthreads), signals are delivered * to all threads. We only want to handle each signal once for the * entire box, and we let the gwthread wrapper take care of choosing * one. */ if (!gwthread_shouldhandlesignal(signum)) return; switch (signum) { case SIGINT: if (smppbox_status == SMPP_RUNNING) { error(0, "SIGINT received, aborting program..."); smppbox_status = SMPP_SHUTDOWN; } break; case SIGHUP: warning(0, "SIGHUP received, catching and re-opening logs"); log_reopen(); alog_reopen(); break; /* * It would be more proper to use SIGUSR1 for this, but on some * platforms that's reserved by the pthread support. */ case SIGQUIT: warning(0, "SIGQUIT received, reporting memory usage."); gw_check_leaks(); break; } } static void setup_signal_handlers(void) { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGPIPE, &act, NULL); } static void gw_smpp_enter(Cfg *cfg) { } static void gw_smpp_leave() { } static void init_smsc_routes(Cfg *cfg) { CfgGroup *grp; List *list, *items; Octstr *smsc_id, *boxc_ids, *shortcodes, *receiver_shortcodes; int i, j; smsc_by_receiver = dict_create(1000, (void(*)(void *)) octstr_destroy); smsc_by_smsbox_id = dict_create(30, (void(*)(void *)) octstr_destroy); smsc_by_sender = dict_create(50, (void(*)(void *)) octstr_destroy); smsc_by_sender_smsbox_id = dict_create(50, (void(*)(void *)) octstr_destroy); smsc_id = boxc_ids = shortcodes = receiver_shortcodes = NULL; list = items = NULL; list = cfg_get_multi_group(cfg, octstr_imm("smsc-route")); /* loop multi-group "client-route" */ while (list && (grp = gwlist_extract_first(list)) != NULL) { if ((smsc_id = cfg_get(grp, octstr_imm("smsc-id"))) == NULL) { grp_dump(grp); panic(0,"'smsc-id-route' group without valid 'smsc-id' directive!"); } /* * If smsbox-id is given, then any message coming from the specified * smsbox-id in the list will be routed to this smsc. * If shortcode is given, then any message with sender number * matching those will be routed to this smsc. * If both are given, then only sender within shortcode originating * from sysmtem-id list will be routed to this smsc. So if both are * present then this is a logical AND operation. */ boxc_ids = cfg_get(grp, octstr_imm("smsbox-id")); shortcodes = cfg_get(grp, octstr_imm("shortcode")); receiver_shortcodes = cfg_get(grp, octstr_imm("receiver-shortcode")); /* Consider the receiver options: receiver-shortcode. */ if (receiver_shortcodes) { /* receiver-shortcode applies to all MTs from all smscs */ items = octstr_split(receiver_shortcodes, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); debug("opensmppbox",0,"Adding smsc routing to id <%s> for receiver no <%s>", octstr_get_cstr(smsc_id), octstr_get_cstr(item)); if (!dict_put_once(smsc_by_receiver, item, octstr_duplicate(smsc_id))) panic(0, "Routing for receiver no <%s> already exists!", octstr_get_cstr(item)); } gwlist_destroy(items, octstr_destroy_item); }; /* consider now the 3 possibilities: */ if (boxc_ids && !shortcodes) { /* smsbox-id only, so all MT traffic */ items = octstr_split(boxc_ids, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); debug("opensmppbox",0,"Adding smsc routing to id <%s> for box id <%s>", octstr_get_cstr(smsc_id), octstr_get_cstr(item)); if (!dict_put_once(smsc_by_smsbox_id, item, octstr_duplicate(smsc_id))) panic(0, "Routing for box-id <%s> already exists!", octstr_get_cstr(item)); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(boxc_ids); } else if (!boxc_ids && shortcodes) { /* shortcode only, so these MTs from all smscs */ items = octstr_split(shortcodes, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); debug("opensmppbox",0,"Adding smsc routing to id <%s> for sender no <%s>", octstr_get_cstr(smsc_id), octstr_get_cstr(item)); if (!dict_put_once(smsc_by_sender, item, octstr_duplicate(smsc_id))) panic(0, "Routing for sender no <%s> already exists!", octstr_get_cstr(item)); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(shortcodes); } else if (boxc_ids && shortcodes) { /* both, so only specified MTs from specified smsbox ids */ items = octstr_split(shortcodes, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { List *subitems; Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); subitems = octstr_split(boxc_ids, octstr_imm(";")); for (j = 0; j < gwlist_len(subitems); j++) { Octstr *subitem = gwlist_get(subitems, j); octstr_strip_blanks(subitem); debug("opensmppbox",0,"Adding smsc routing to id <%s> " "for sender no <%s> and smsbox id <%s>", octstr_get_cstr(smsc_id), octstr_get_cstr(item), octstr_get_cstr(subitem)); /* construct the dict key ':' */ octstr_insert(subitem, item, 0); octstr_insert_char(subitem, octstr_len(item), ':'); if (!dict_put_once(smsc_by_sender_smsbox_id, subitem, octstr_duplicate(smsc_id))) panic(0, "Routing for sender:smsbox-id <%s> already exists!", octstr_get_cstr(subitem)); } gwlist_destroy(subitems, octstr_destroy_item); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(shortcodes); } octstr_destroy(smsc_id); octstr_destroy(boxc_ids); octstr_destroy(shortcodes); } gwlist_destroy(list, NULL); } static void destroy_smsc_routes(void) { dict_destroy(smsc_by_receiver); smsc_by_receiver = NULL; dict_destroy(smsc_by_smsbox_id); smsc_by_smsbox_id = NULL; dict_destroy(smsc_by_sender); smsc_by_sender = NULL; dict_destroy(smsc_by_sender_smsbox_id); smsc_by_sender_smsbox_id = NULL; } static void init_smppbox(Cfg *cfg) { CfgGroup *grp; Octstr *logfile; long lvl; Octstr *val, *log; /* temporary store variables */ long store_dump_freq = -1; /* dummy variable */ /* some default values */ smppbox_port = 13005; smppbox_port_ssl = 0; bearerbox_host = NULL; bearerbox_port_ssl = 0; logfile = NULL; lvl = 0; systemidisboxcid = 0; /* default backward compatible */ enablepam = 0; /* also default false */ /* init dlr storage */ dlr_init(cfg); /* init storage store */ grp= cfg_get_single_group(cfg, octstr_imm("core")); if (grp != NULL) { log = cfg_get(grp, octstr_imm("store-file")); if (log != NULL) { warning(0, "'store-file' option deprecated, please use 'store-location' and 'store-type' instead."); val = octstr_create("file"); } else { log = cfg_get(grp, octstr_imm("store-location")); val = cfg_get(grp, octstr_imm("store-type")); } if (val != NULL) { if (store_init(cfg, val, log, store_dump_freq, msg_pack, msg_unpack_wrapper) == -1) { panic(0, "Could not start with store init failed."); } } octstr_destroy(val); octstr_destroy(log); } /* initialize low level PDUs */ if (smpp_pdu_init(cfg) == -1) panic(0, "Connot start with PDU init failed."); /* * first we take the port number in bearerbox and other values from the * opensmppbox group in configuration file */ grp = cfg_get_single_group(cfg, octstr_imm("opensmppbox")); if (grp == NULL) panic(0, "No 'opensmppbox' group in configuration"); bearerbox_host = cfg_get(grp, octstr_imm("bearerbox-host")); if (!bearerbox_host) { bearerbox_host = octstr_create(BB_DEFAULT_HOST); } if (cfg_get_integer(&bearerbox_port, grp, octstr_imm("bearerbox-port")) == -1) bearerbox_port = BB_DEFAULT_SMSBOX_PORT; #ifdef HAVE_LIBSSL #if 0 cfg_get_bool(&bearerbox_port_ssl, grp, octstr_imm("bearerbox-port-ssl")); conn_config_ssl(grp); #endif #endif smppbox_id = cfg_get(grp, octstr_imm("opensmppbox-id")); our_system_id = cfg_get(grp, octstr_imm("our-system-id")); route_to_smsc = cfg_get(grp, octstr_imm("route-to-smsc")); if (our_system_id == NULL) { panic(0, "our-system-id is not set."); } alt_charset = cfg_get(grp, octstr_imm("alt-charset")); /* setup logfile stuff */ logfile = cfg_get(grp, octstr_imm("log-file")); cfg_get_integer(&lvl, grp, octstr_imm("log-level")); if (cfg_get_integer(&smppbox_port, grp, octstr_imm("opensmppbox-port")) == -1) smppbox_port = 2345; smpp_logins = cfg_get(grp, octstr_imm("smpp-logins")); if (smpp_logins == NULL) { panic(0, "No user file specified."); } if (logfile != NULL) { info(0, "Starting to log to file %s level %ld", octstr_get_cstr(logfile), lvl); log_open(octstr_get_cstr(logfile), lvl, GW_NON_EXCL); octstr_destroy(logfile); } if (cfg_get_integer(&smpp_timeout, grp, octstr_imm("timeout")) == -1) smpp_timeout = TIMEOUT_SECONDS; if (cfg_get_integer(&smpp_source_addr_ton, grp, octstr_imm("source-addr-ton")) == -1) smpp_source_addr_ton = -1; if (cfg_get_integer(&smpp_source_addr_npi, grp, octstr_imm("source-addr-npi")) == -1) smpp_source_addr_npi = -1; if (cfg_get_bool(&smpp_autodetect_addr, grp, octstr_imm("source-addr-auto")) == -1) smpp_autodetect_addr = 0; if (cfg_get_integer(&smpp_dest_addr_ton, grp, octstr_imm("dest-addr-ton")) == -1) smpp_dest_addr_ton = -1; if (cfg_get_integer(&smpp_dest_addr_npi, grp, octstr_imm("dest-addr-npi")) == -1) smpp_dest_addr_npi = -1; cfg_get_bool(&systemidisboxcid, grp, octstr_imm("use-systemid-as-smsboxid")); cfg_get_bool(&enablepam, grp, octstr_imm("enable-pam")); pamacl = cfg_get(grp, octstr_imm("pam-acl")); if (NULL == pamacl) { pamacl = octstr_create("kannel"); } if (enablepam && !systemidisboxcid) { panic(0, "enable-pam requires systemid-is-boxcid=true."); } #ifndef HAVE_PAM if (enablepam) { panic(0, "enable-pam is set but we are compiled without pam support."); } #endif if (enablepam) { info(0, "Using PAM authentication."); } init_smsc_routes(cfg); catenated_sms_counter = counter_create(); boxid = counter_create(); gw_smpp_enter(cfg); smppbox_status = SMPP_RUNNING; } static int check_args(int i, int argc, char **argv) { if (strcmp(argv[i], "-H")==0 || strcmp(argv[i], "--tryhttp")==0) { //only_try_http = 1; } else return -1; return 0; } /* * Adding hooks to kannel check config * * Martin Conte. */ static int smppbox_is_allowed_in_group(Octstr *group, Octstr *variable) { Octstr *groupstr; groupstr = octstr_imm("group"); #define OCTSTR(name) \ if (octstr_compare(octstr_imm(#name), variable) == 0) \ return 1; #define SINGLE_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), group) == 0) { \ if (octstr_compare(groupstr, variable) == 0) \ return 1; \ fields \ return 0; \ } #define MULTI_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), group) == 0) { \ if (octstr_compare(groupstr, variable) == 0) \ return 1; \ fields \ return 0; \ } #include "opensmppbox-cfg.def" return 0; } #undef OCTSTR #undef SINGLE_GROUP #undef MULTI_GROUP static int smppbox_is_single_group(Octstr *query) { #define OCTSTR(name) #define SINGLE_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), query) == 0) \ return 1; #define MULTI_GROUP(name, fields) \ if (octstr_compare(octstr_imm(#name), query) == 0) \ return 0; #include "opensmppbox-cfg.def" return 0; } int main(int argc, char **argv) { int cf_index; Octstr *filename, *version; gwlib_init(); all_boxes = gwlist_create(); list_dict = dict_create(1, NULL); cf_index = get_and_set_debugs(argc, argv, check_args); setup_signal_handlers(); if (argv[cf_index] == NULL) filename = octstr_create("opensmppbox.conf"); else filename = octstr_create(argv[cf_index]); cfg = cfg_create(filename); /* Adding cfg-checks to core */ cfg_add_hooks(smppbox_is_allowed_in_group, smppbox_is_single_group); if (cfg_read(cfg) == -1) panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(filename)); octstr_destroy(filename); version = octstr_format("opensmppbox version %s gwlib", GW_VERSION); report_versions(octstr_get_cstr(version)); octstr_destroy(version); init_smppbox(cfg); smppboxc_run((void *)smppbox_port); /* shutdown dlr storage */ heartbeat_stop(ALL_HEARTBEATS); dlr_shutdown(); destroy_smsc_routes(); counter_destroy(catenated_sms_counter); counter_destroy(boxid); if (restart_smppbox) { gwthread_sleep(1.0); } gwlist_destroy(all_boxes, NULL); gw_smpp_leave(); gwlib_shutdown(); if (restart_smppbox) execvp(argv[0], argv); return 0; } gateway-1.4.5/addons/opensmppbox/gw/opensmppbox-cfg.def0000644000175000017500000000660613050531353021720 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2010 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* ================================================================== * opensmppbox-cfg.def - Definition of configuration groups and variables * * Rene Kluwen rene.kluwen@chimit.nl * */ SINGLE_GROUP(opensmppbox, OCTSTR(bearerbox-host) OCTSTR(bearerbox-port) OCTSTR(opensmppbox-id) OCTSTR(opensmppbox-port) OCTSTR(log-file) OCTSTR(log-level) OCTSTR(our-system-id) OCTSTR(route-to-smsc) OCTSTR(smpp-logins) OCTSTR(source-addr-ton) OCTSTR(source-addr-npi) OCTSTR(source-addr-auto) OCTSTR(dest-addr-ton) OCTSTR(dest-addr-npi) OCTSTR(timeout) OCTSTR(use-systemid-as-smsboxid) OCTSTR(enable-pam) OCTSTR(pam-acl) OCTSTR(alt-charset) ) MULTI_GROUP(smsc-route, OCTSTR(smsc-id) OCTSTR(smsbox-id) OCTSTR(shortcode) OCTSTR(receiver-shortcode) ) gateway-1.4.5/addons/opensmppbox/configure.in0000644000175000017500000004526512327711130020030 0ustar toljtoljdnl /* ==================================================================== dnl * The Kannel Software License, Version 1.0 dnl * dnl * Copyright (c) 2001-2009 Kannel Group dnl * Copyright (c) 1998-2001 WapIT Ltd. dnl * All rights reserved. dnl * dnl * Redistribution and use in source and binary forms, with or without dnl * modification, are permitted provided that the following conditions dnl * are met: dnl * dnl * 1. Redistributions of source code must retain the above copyright dnl * notice, this list of conditions and the following disclaimer. dnl * dnl * 2. Redistributions in binary form must reproduce the above copyright dnl * notice, this list of conditions and the following disclaimer in dnl * the documentation and/or other materials provided with the dnl * distribution. dnl * dnl * 3. The end-user documentation included with the redistribution, dnl * if any, must include the following acknowledgment: dnl * "This product includes software developed by the dnl * Kannel Group (http://www.kannel.org/)." dnl * Alternately, this acknowledgment may appear in the software itself, dnl * if and wherever such third-party acknowledgments normally appear. dnl * dnl * 4. The names "Kannel" and "Kannel Group" must not be used to dnl * endorse or promote products derived from this software without dnl * prior written permission. For written permission, please dnl * contact org@kannel.org. dnl * dnl * 5. Products derived from this software may not be called "Kannel", dnl * nor may "Kannel" appear in their name, without prior written dnl * permission of the Kannel Group. dnl * dnl * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED dnl * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES dnl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE dnl * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS dnl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, dnl * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT dnl * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR dnl * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, dnl * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE dnl * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, dnl * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. dnl * ==================================================================== dnl * dnl * This software consists of voluntary contributions made by many dnl * individuals on behalf of the Kannel Group. For more information on dnl * the Kannel Group, please see . dnl * dnl * Portions of this software are based upon software originally written at dnl * WapIT Ltd., Helsinki, Finland for the Kannel project. dnl */ dnl OpenSMPPBox - Open Source Kannel Extension for store messages dnl dnl Rene Kluwen dnl dnl Documentation and additional patches by Alejandro Guerrieri dnl dnl This program is free software, distributed under the terms of dnl the GNU General Public License, with a few exceptions granted (see LICENSE) dnl AC_PREREQ(2.5) dnl Initialization AC_INIT([opensmppbox],[svn],[devel@kannel.org]) AC_CONFIG_SRCDIR([gw/opensmppbox.c]) AC_CONFIG_AUX_DIR(autotools) AC_SUBST(SHELL) AM_INIT_AUTOMAKE([$SB_NAME], [$VERSION]) AC_CONFIG_HEADERS([sb-config.h]) AM_MAINTAINER_MODE AC_CANONICAL_HOST dnl Check version number. VERSION=`head -n 1 VERSION` if test "x$VERSION" = "xsvn"; then AC_MSG_CHECKING([svn checkout revision]) AC_SVN_REVISION(SVN_REVISION) AC_MSG_RESULT([$SVN_REVISION]) VERSION="$VERSION-r$SVN_REVISION" fi AC_DEFINE_UNQUOTED(GW_NAME, "OpenSMPPBox", [ GW_NAME ]) AC_DEFINE_UNQUOTED(GW_VERSION, "$VERSION", [ GW_VERSION ]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [ VERSION ]) AC_SUBST(GW_VERSION) AC_SUBST(VERSION) AC_CONFIG_SECTION([Configuring for opensmppbox version $VERSION]) dnl Checks for programs. dnl AC_PROG_CC AC_PROG_LIBTOOL dnl add mmlib to the include path INCLUDES='-I$(top_srcdir)/gw -I$(top_builddir)/gw' AC_SUBST([INCLUDES]) dnl Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT dnl ommiting what kannel is already checking dnl AC_CHECK_HEADERS(sys/ioctl.h sys/time.h sys/types.h unistd.h sys/poll.h) dnl AC_CHECK_HEADERS(pthread.h getopt.h syslog.h iconv.h zlib.h execinfo.h stdlib.h) dnl AC_CHECK_HEADERS([sys/socket.h sys/sockio.h netinet/in.h]) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_STRUCT_TM AC_C_VOLATILE dnl Checks for library functions. AC_FUNC_CLOSEDIR_VOID AC_FUNC_ERROR_AT_LINE AC_FUNC_MALLOC AC_FUNC_MEMCMP dnl AC_TYPE_SIGNAL dnl AC_FUNC_STAT dnl AC_CHECK_FUNCS(gettimeofday select socket strdup getopt_long localtime_r gmtime_r backtrace srandom) dnl Flags for determined platform EXE_EXT="" case "$host" in *-sun-solaris*) CFLAGS="$CFLAGS -DSunOS=1" ;; *-cygwin*) EXE_EXT=".exe" ;; *apple-darwin*) CFLAGS="$CFLAGS -DDARWIN=1" LIBS="$LIBS -L/opt/local/lib" ;; *-linux-*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE" LDFLAGS="$LDFLAGS -rdynamic" ;; *-*-openbsd* | *-*-freebsd*) CFLAGS="$CFLAGS -pthread" AC_CHECK_LIB(pthread, pthread_exit, [LIBS="$LIBS -lpthread"; pthread="yes"], [AC_CHECK_LIB(c_r, pthread_exit, [LIBS="$LIBS -lc_r"; pthread="yes"])] ) ;; esac AC_ARG_WITH(cflags, [ --with-cflags=FLAGS use FLAGS for CFLAGS], CFLAGS="$CFLAGS $withval") AC_ARG_WITH(libs, [ --with-libs=FLAGS use FLAGS for extra libraries], LIBS="$LIBS $withval") dnl Implement the --enable-pam option. AC_CONFIG_SECTION([Configuring PAM support]) AC_MSG_CHECKING([whether to compile with PAM support]) AC_ARG_ENABLE(pam, [ --enable-pam enable PAM authentication @<:@disabled@:>@], [ if test "$enableval" = "yes" then AC_CHECK_LIB(pam, pam_end) AC_CHECK_LIB(dl,main) AC_CHECK_HEADER([security/pam_appl.h], AC_DEFINE(HAVE_PAM_SECURITY, 1, "HAVE_PAM_SECURITY") AC_DEFINE(HAVE_PAM, 1, "HAVE_PAM") AC_MSG_RESULT([enabling PAM for authentication]), [AC_CHECK_HEADER([pam/pam_appl.h], AC_DEFINE(HAVE_PAM_PAM, 1, "HAVE_PAM_PAM") AC_DEFINE(HAVE_PAM, 1, "HAVE_PAM") AC_MSG_RESULT([enabling PAM for authentication]) )] ) else AC_MSG_RESULT(disabled) fi ]) dnl implement SSL stuff. dnl Implement the --with-ssl option. AC_ARG_WITH(ssl, [ --with-ssl[=DIR] where to look for OpenSSL libs and header files DIR points to the installation [/usr/local/ssl]], [ if test -d "$withval"; then ssllib="$withval/lib"; sslinc="$withval/include" else AC_MSG_ERROR(Unable to find OpenSSL libs and/or directories at $withval) fi ]) dnl Implement --enable-ssl option. AC_MSG_CHECKING([whether to compile with SSL support]) AC_ARG_ENABLE(ssl, [ --enable-ssl enable SSL client and server support [enabled]], [ if test "$enableval" = no ; then AC_MSG_RESULT(disabled) ssl=no else ssl=yes fi ],[ ssl=yes ]) if test "$ssl" = "yes" ; then dnl test only if --with-ssl has not been used if test "x$ssllib" = "x" && test "x$sslinc" = "x"; then for loc in /usr/lib /usr/local/ssl/lib /usr/local/openssl/lib; do if test -f "$loc/libssl.a"; then ssllib="$loc" fi done for loc in /usr/include/ssl /usr/include/openssl /usr/local/ssl/include \ /usr/local/openssl/include; do if test -d "$loc"; then sslinc="$loc" fi done fi AC_MSG_RESULT(trying $ssllib $sslinc) fi dnl Implement the SSL library checking routine. dnl This will define HAVE_LIBSSL in config.h if test "x$ssllib" != "x" && test "x$sslinc" != "x"; then CFLAGS="$CFLAGS -I$sslinc" LIBS="$LIBS -L$ssllib" AC_PATH_PROG(OPENSSL, openssl, no) if test "$OPENSSL" = "yes"; then AC_MSG_CHECKING([openssl version]) openssl_version=`$OPENSSL version | awk '{print $2}'` AC_MSG_RESULT([$openssl_version]) fi AC_CHECK_LIB(crypto, CRYPTO_lock, [ LIBS="$LIBS -lcrypto" AC_CHECK_LIB(ssl, SSL_library_init, [ AC_CHECK_LIB(ssl, SSL_connect) AC_CHECK_HEADERS(openssl/x509.h openssl/rsa.h openssl/crypto.h \ openssl/pem.h openssl/ssl.h openssl/err.h) AC_MSG_CHECKING(whether the OpenSSL library is multithread-enabled) AC_TRY_RUN([ #define OPENSSL_THREAD_DEFINES #include int main(void) { #if defined(THREADS) exit(0); #elif defined(OPENSSL_THREADS) exit(0); #else exit(1); #endif } ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LIBSSL) LIBS="$LIBS -lssl" AC_MSG_CHECKING([whether to compile with SSL support]) AC_MSG_RESULT(yes) ], [ AC_ARG_ENABLE(ssl-thread-test, [ --disable-ssl-thread-test disable the multithread test for the OpenSSL library this will force to continue even if the test fails], [ if test "$enableval" = no ; then AC_MSG_RESULT([no, continue forced]) fi ], [ AC_MSG_RESULT(no) AC_MSG_ERROR(Either get a multithread-enabled SSL or configure with --disable-ssl) ]) ], echo "Cross-compiling; make sure your SSL library is multithread-enabled" ) ]) ]) fi dnl DocBook stuff AC_CONFIG_SECTION([Configuring DocBook support]) AC_CHECK_PROG(OLDJADE, jade, jade, no) if test "$OLDJADE" = "no" ; then AC_CHECK_PROG(JADE, openjade, openjade, no) else JADE=$OLDJADE fi AC_CHECK_PROG(JADETEX, jadetex, jadetex, no) AC_CHECK_PROG(PDFJADETEX, pdfjadetex, pdfjadetex, no) AC_CHECK_PROG(DVIPS, dvips, dvips, no) AC_CHECK_PROG(FIG2DEV, fig2dev, fig2dev, no) AC_CHECK_PROG(CONVERT, convert, convert, no) AC_SUBST(HTML_DSL) found="" for loc in /usr /usr/local /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/html/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/html/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/html/docbook.dsl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,HTML_DSL=$file; found=1) fi done fi done AC_SUBST(TEX_DSL) found="" for loc in /usr /usr/local /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/print/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/print/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/print/docbook.dsl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,TEX_DSL=$file; found=1) fi done fi done AC_SUBST(XML_DCL) found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/dtds/decls/xml.dcl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/dtds/decls/xml.dcl \ ${loc}/share/dsssl/docbook-dsssl/dtds/decls/xml.dcl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,XML_DCL=$file; found=1) fi done fi done dnl Implement --enable-docs option. AC_SUBST(DOCSTARGET) AC_ARG_ENABLE(docs, [ --enable-docs enable building of documentation @<:@enabled@:>@], [ if test "$enableval" = "yes" then DOCSTARGET="docs" else DOCSTARGET="no-docs" fi ]) if test "x$HTML_DSL" = "x" -o "x$TEX_DSL" = "x" \ || test "$JADE" = "no" \ || test "$JADETEX" = "no" \ || test "$PDFJADETEX" = "no" \ || test "$DVIPS" = "no" \ || test "$FIG2DEV" = "no" \ || test "$CONVERT" = "no" \ || test "$DOCSTARGET" = "no-docs" then DOCSTARGET="no-docs" else DOCSTARGET="docs" fi case "$DOCSTARGET" in no-docs) AC_MSG_RESULT(Not building documentation.) ;; docs) AC_MSG_RESULT(Documentation will be built as well.) ;; esac dnl Implement --enable-drafts option. AC_SUBST(DOCDRAFTS) DOCDRAFTS="IGNORE" AC_ARG_ENABLE(drafts, [ --enable-drafts enable building of documentation drafts @<:@disabled@:>@], [ if test "$enableval" = "yes" then DOCDRAFTS="INCLUDE" else DOCDRAFTS="IGNORE" fi ]) if test "x$DOCSTARGET" = "xdocs" then case "$DOCDRAFTS" in INCLUDE) AC_MSG_RESULT(Documentation will include drafts.) ;; esac fi dnl Checking for Ct-lib support AC_MSG_CHECKING(for Ct-Lib support) AC_ARG_WITH(ctlib, [ --with-ctlib[=DIR] Include Ct-Lib support. DIR is the Ct-Lib install directory, defaults to /opt/sybase.], [ if test "$withval" = "yes"; then withval=/opt/sybase fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then CTLIB_INCDIR=$withval/include CTLIB_LIBDIR=$withval/lib else AC_MSG_RESULT(no) AC_MSG_ERROR(Invalid Ct-Lib directory - unable to find ctpublic.h) fi CTLIB_LFLAGS="-L$CTLIB_LIBDIR -lct -lcs -lsybtcl -lcomn -lintl" CTLIB_INCLUDE="-I$CTLIB_INCDIR" AC_DEFINE(HAVE_CTLIB, 1, [Defined to 1]) AC_MSG_RESULT(yes) have_db=yes dnl ctlib requires -ldl sometime AC_CHECK_FUNC(dlopen, , AC_CHECK_LIB(dl, dlopen, CTLIB_LFLAGS="$CTLIB_LFLAGS -ldl")) fi if test "x$DBTYPE" = "x" ; then DBTYPE="ctlib" else DBTYPE="$DBTYPE-ctlib" fi ],[ AC_MSG_RESULT(no) ]) AC_SUBST(CTLIB_LFLAGS) AC_SUBST(CTLIB_INCLUDE) dnl Checking for FreeTDS ct-lib support AC_MSG_CHECKING(for FreeTDS Ct-Lib support) AC_ARG_WITH(mssql, [ --with-mssql[=DIR] Include FreeTDS Ct-Lib support. DIR is the FreeTDS install directory, defaults to /usr/local.], [ if test "$withval" = "yes"; then withval=/usr/local fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then CTLIB_INCDIR=$withval/include CTLIB_LIBDIR=$withval/lib else AC_MSG_RESULT(no) AC_MSG_ERROR(Invalid FreeTDS directory - unable to find ctpublic.h) fi CTLIB_LFLAGS="-L$CTLIB_LIBDIR -lct" CTLIB_INCLUDE="-I$CTLIB_INCDIR" AC_DEFINE(HAVE_CTLIB, 1, [Defined to 1]) AC_MSG_RESULT(yes) have_db=yes AC_CHECK_FUNC(dlopen, , AC_CHECK_LIB(dl, dlopen, CTLIB_LFLAGS="$CTLIB_LFLAGS -ldl")) fi if test "x$DBTYPE" = "x" ; then DBTYPE="freetds" else DBTYPE="$DBTYPE-freetds" fi ],[ AC_MSG_RESULT(no) ]) AC_SUBST(CTLIB_LFLAGS) AC_SUBST(CTLIB_INCLUDE) dnl Need to check for kannel dnl Implement the --with-kannel-dir option AC_ARG_WITH(kannel-dir, [ --with-kannel-dir=DIR where to look for Kannel Gateway libs and header files DIR points to the installation [/usr/local] ] , [ gwloc="" if test -d "$withval" ; then gwloc="$withval" fi ]) AC_PATH_PROG(GW_CONFIG, gw-config, no, [$gwloc/bin:$gwloc:../gateway/gw/:$PATH]) dnl check for Kannel gw-config if test "$GW_CONFIG" = "no"; then found="" for loc in $pgsqlloc /usr /usr/local ; do if test "x$found" = "x" ; then AC_MSG_CHECKING([for Kannel include files in]) AC_MSG_RESULT($loc) AC_CHECK_FILE("$loc/include/kannel/gw-config.h", [CFLAGS="$CFLAGS -I$loc/include/kannel -I$loc/include/kannel"; LDFLAGS="$LDFLAGS -L$loc/lib/kannel -lwap -lgwlib"; found=1 ]) fi done; if test "x$found" != "x1" ; then AC_MSG_ERROR([Unable to find gw-config.h, please provide a --with-kannel-dir= location]) fi else dnl gw_config found AC_MSG_CHECKING([Kannel version]) gw_version=`$GW_CONFIG --version` AC_MSG_RESULT([$gw_version]) AC_MSG_CHECKING([Kannel libs]) if ! $GW_CONFIG --libs &>/dev/null ; then LIBS="$LIBS `$GW_CONFIG --libs`" gw_libdir=`$GW_CONFIG --libs` AC_MSG_RESULT([$gw_libdir]) fi AC_MSG_CHECKING([Kannel includes]) if ! $GW_CONFIG --cflags &>/dev/null ; then CFLAGS="$CFLAGS `$GW_CONFIG --cflags`" gw_incdir=`$GW_CONFIG --cflags` AC_MSG_RESULT([$gw_incdir]) fi fi AC_CHECK_LIB([gwlib], [cfg_create], [], AC_MSG_ERROR([Kannel gwlib is required!])) AC_MSG_CHECKING(for Kannel's DB support) AC_TRY_RUN([#include "gw-config.h" int main( #if defined(HAVE_SQLITE3) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "sqlite3", [RPM Suffix]) AC_SUBST(rpm_requires, "sqlite3-devel >= 1.8", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_SQLITE) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "sqlite", [RPM Suffix]) AC_SUBST(rpm_requires, "sqlite2-devel >= 2.7", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_PGSQL) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "pgsql", [RPM Suffix]) AC_SUBST(rpm_requires, "postgresql-devel >= 7.2", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_ORACLE) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "oracle", [RPM Suffix]) AC_SUBST(rpm_requires, "oracle-instantclient-devel >= 8", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_MYSQL) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "mysql", [RPM Suffix]) AC_SUBST(rpm_requires, "mysql-devel >= 3.23", [RPM Requires]) ]) AC_TRY_RUN([#include "gw-config.h" int main(void){ #if defined(HAVE_SDB) exit(0); #endif exit(1); }],[ AC_SUBST(rpm_suffix, "sdb", [RPM Suffix]) AC_SUBST(rpm_requires, "libsdb-devel >= 0.5", [RPM Requires]) ]) AC_CONFIG_FILES([Makefile gw/Makefile rpm/opensmppbox.spec]) AC_OUTPUT gateway-1.4.5/addons/opensmppbox/acinclude.m40000644000175000017500000000161211416125425017700 0ustar toljtoljAC_DEFUN([AC_CVS_DATE], [ cvs_date=`grep ChangeLog CVS/Entries | cut -f4 -d/` day=`grep ChangeLog CVS/Entries | cut -f4 -d/ | cut -c9-10 | tr " " "0"` month=`echo $cvs_date | cut -f2 -d' '` case $month in "Jan") month="01" ;; "Feb") month="02" ;; "Mar") month="03" ;; "Apr") month="04" ;; "May") month="05" ;; "Jun") month="06" ;; "Jul") month="07" ;; "Aug") month="08" ;; "Sep") month="09" ;; "Oct") month="10" ;; "Nov") month="11" ;; "Dec") month="12" ;; esac year=`echo $cvs_date | cut -f5 -d' '` $1="$year$month$day" ]) AC_DEFUN([AC_CONFIG_SECTION], [ nl=' ' echo "${nl}${T_MD}$1 ...${T_ME}" ]) dnl Check which SVN revision is and apply dnl the value to the given variable AC_DEFUN([AC_SVN_REVISION], [ if test -d ".svn" then revision=`svnversion .` test -z "$revision" && revision="unknown" $1="$revision" fi ]) gateway-1.4.5/addons/opensmppbox/INSTALL0000644000175000017500000002200512061727435016545 0ustar toljtoljBasic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for 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 disabled by default to prevent problems with accidental use of stale 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 diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at 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'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. 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. Running `configure' takes awhile. 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. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 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. 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 *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== 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 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 `..'. 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. Installation Names ================== 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'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you 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. 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 `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 `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually 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. 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 `--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: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: 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 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 platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will 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'. `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. 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 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 them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Here is a another example: /bin/bash ./configure CONFIG_SHELL=/bin/bash Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent configuration-related scripts to be executed by `/bin/bash'. `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. gateway-1.4.5/addons/opensmppbox/ChangeLog0000644000175000017500000001700412525130650017261 0ustar toljtolj2015-05-14 Rene Kluwen Fixed crash when garbage was sent to the opensmppbox port. 2014-04-29 Stipe Tolj * doc/userguide.xml: move from DocBook V3.1 to V4.2 and fix various XML tag errors. No content change. * gw/Makefile.in, Makefile.in: automake generated files. * Makefile.am: add $(XML_DCL) reference to the xml.dcl file. * configure[.in]: we need the xml.dcl to be added to the jade execution to have a clean XML tag declaration, since we are in SGML mode here. 2014-04-18 Rene Kluwen Fixed memory leak, hopefully for good. Added fix for dlr_add to use extra parameter use_dst. 2013-11-12 Rene Kluwen Patch by Juno Lopez that allows for segmented reading of pdus when they are split over different tcp packets under high load. 2013-09-01 Rene Kluwen Fixed a small bug in the routing-upon-receiver number where opensmppbox would crash at boot-time if the particular config section is not defined. 2013-08-08 Rene Kluwen Patch provided by Alexander Kovalenko . The generated smpp message id is now more than 8 characters in case of smpp version > 3.3. 2013-07-10 Rene Kluwen Patch provided by Kelvin Porter Kelvin.Porterat h3net.com. Allows routing to smsc based upon receiver number. 2012-12-18 Rene Kluwen Another patch by Victor Luchitz. Multi-part messages now have an smpp message-id of their own. This is in stead of the message id that first used to be the one of the first message-part. 2012-12-11 Rene Kluwen Reverted back to v63 due to too many bugs and problems in these sources. At the same time, introducing a new ESME-to-MT routing possibility. See documentation about 'smsc-route'. Patch provided by Victor Luchitz. Users that currently rely on the MO-routing patch are encouraged to use bearerbox's 'smsbox-route' in combination with 'use-system-id-as-box-id'. It works exactly the same. The "old" opensmppbox is still availabe as a branch called "single-bearerbox-connection". You can still check that branch out if your software is relying on it. 2011-11-05 Rene Kluwen * gw/opensmppbox.c: Fixed memory leak concerning MO messages. Thanks to Victor Luchitz for reporting. 2011-05-13 Rene Kluwen * configure.in: the new configure file didn't seem to work, after make rpm. Couldn't find the Kannel libraries. This patch fixes that. 2011-05-09 Rene Kluwen * gw/opensmppbox.c: Default GSM character set is converted to UTF-8 (Kannel's internal way of exchanging messages). The facilitates foreign (e.g. greek) characters. Thanks to Nii Ako Ampa-Sowa (ampasowa at gmail.com) for the patch. 2011-04-07 Rene Kluwen * gw/opensmppbox.c: Tested system_type on being provided by the smpp client, because if not, opensmppbox would crash. Thanks to info at xen-housing.sk for reporting. 2010-11-10 Alexander Malysh * gw/opensmppbox.c: applied patch that adds validity and deferred handling. Thanks to "XEN-Housing s.r.o." and me :-) for this patch. 2010-10-06 Stipe Tolj * gw/opensmppbox.c: remove 0-padding for %s type from snprintf(), as it is not defined according to the man page and we get compiler warnings. 2010-10-06 Stipe Tolj * gw/opensmppbox.c: remove various compiler warnings. NLC. 2010-10-06 Stipe Tolj * autotools/*, gw/Makefile.in, aclocal.m4, configure, Makefile.in: new configure file after bootstrapping for distribution. 2010-10-06 Stipe Tolj * */*: changing the add-on module name to OpenSMPPBox, along with all references in the output and the configuration file aspects. 2010/09/15 Sending negative ack upon receiving invalid MO/DLR so messages won't stay in bearerbox store. Patch by Victor Luchitz. 2010/08/23 1. Respects softfail from bearerbox (ack_failed_tmp). 2. Propagates message priority in submit_sm further to bearerbox in Msg struct. Thanks to Victor Luchitz for reporting. 2010/08/22 Fixed bug reported by boooch@gmail.com as where authentication including system_type would always fail. 2010/08/19 1) add support for message_payload TLV for deliver_sm packets. This TLV is used in case a smpp meta-flag "use_message_payload" is set. 2) brings smppbox in conformity with SMPP v3.4 in regarding shedule_delivery_time and validiy_period fields in deliver_sm packets. 3) if connected ESME requests delivery report for a submit_sm packet, smppbox will now also notify the ESME of SMSC failures, generated by the bearerbox. 4) provides documentation updates. 5) some minor improvements, including larger dict-size for acks. 2010/08/16 Fixed ghost connections bug, where disconnected smppusers kept being visible as connected in bearerbox status page. 2010/08/11 Filled in msg->sms.sms_type that was incorrectly left undefined. Thanks to Tomasz Konopka for reporting. 2010/08/02 Added optional support for PAM authentication. See userguide. Added recognition of bearerbox acks for messages. If for some reason the message is acked negatively, open smppbox returns an error to the ESME and vice versa. Also an ESME-timeout can now be configured in smppbox.conf. Changes made by Rene Kluwen rene.kluwen@chimit.nl. 2010/08/01 Added extra actual parameter because the dlr_find prototype in the Kannel sources has been changed. The smpp username (system-id) is relayed to bearerbox as billing information (msg->sms.account). This can be used in order to bill the reflected user. A legacy sqlbox patch is available that uses this information for pre-paid billing purposes. 2010/07/28 Patch by Victor Luchitz to add tlv's to delivery reports. At the same time fixed format of submit data/done date in dlrs. 2010/07/27 1. Fixed esm_class for deliver_sm's. 2. fixed original submit date in dlr's. Patches by y Victor Luchitz 2010/07/25 Changed references to smppbox to open smppbox in userguide. 2010/07/22 Patch by Victor Luchitz for optional SMPP v3.4 tags used to indicate message_id and final message state in delivery reports. 2010/07/10 Added documentation tree and building ("make docs"). Patch by Victor Luchitz to configure ton/npi. 2010/07/08 Patch by Victor Luchitz to support SMPP v3.4 tlv's. 2010/07/08 Patch by Victor Luchitz committed to support "err: " text in reports. 2010/07/08 Added support for per user-level ip-restrictions. 2010/06/16 Added support for long messages being sent via de same SMSC (by re-assembling the message and sending it to bearerbox as a whole. Thanks to Tomasz Konopka for testing patiently. 2010/06/15 Added HAVE_SHUTDOWN_CONNECTION #define, so we can use gwlib.a without patching. 2010/06/07 First repository release of smppbox standalone. Some configuration options have been changed from the downloaded version: - bearerbox-port added which replaces the smsbox-port in group = core - bearerbox-host existed already but was not taken into account. It is now. - global-sender removed (was not used) gateway-1.4.5/addons/opensmppbox/rpm/0000755000175000017500000000000013312227716016310 5ustar toljtoljgateway-1.4.5/addons/opensmppbox/rpm/opensmppbox.spec.in0000644000175000017500000000347311453122245022145 0ustar toljtolj%define version @PACKAGE_VERSION@ %define release @rpm_suffix@_%(echo @VERSION@ | cut -d- -f2) Summary: Kannel Box that acts as SMPP Server Name: @PACKAGE_NAME@ Version: %{version} Release: %{release} License: Kannel Group: System Environment/Daemons URL: http://www.kannel.org/~aguerrieri/ Source0: opensmppbox-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: bison, byacc, flex BuildRequires: kannel-devel, openssl-devel, zlib-devel BuildRequires: @rpm_requires@ %description Sqlbox is a special Kannel box that sits between bearerbox and smsbox and uses a database queue to store and forward messages. Messages are queued on a configurable table (defaults to send_sms) and moved to another table (defaults to sent_sms) afterwards. You can also manually insert messages into the send_sms table and they will be sent and moved to the sent_sms table as well. This allows for fast and easy injection of large amounts of messages into Kannel. %prep rm -rf %{buildroot} %setup -q %build %configure %{__make} %install %{__rm} -rf %{buildroot} %makeinstall %{__mkdir_p} %{buildroot}%{_sbindir} %{__mkdir_p} %{buildroot}%{_var}/log/kannel/ %{__mkdir_p} %{buildroot}%{_var}/spool/kannel/ %{__install} -D -m 0640 example/opensmppbox.conf.example %{buildroot}%{_sysconfdir}/kannel/opensmppbox.conf strip %{buildroot}%{_sbindir}/opensmppbox %clean %{__rm} -rf %{buildroot} #%pre #%post #%preun #%postun %files %defattr(-, root, root, 0755) %doc AUTHORS COPYING ChangeLog NEWS README UPGRADE %attr(0640, kannel, kannel) %config(noreplace) %{_sysconfdir}/kannel/opensmppbox.conf %{_sbindir}/* %attr(0750, kannel, kannel) %dir %{_var}/log/kannel/ %attr(0750, kannel, kannel) %dir %{_sysconfdir}/kannel/ %changelog * Mon Jun 07 2010 Rene Kluwen - First RPM version for OpenSMPPBox gateway-1.4.5/solaris/0000755000175000017500000000000013312227714013342 5ustar toljtoljgateway-1.4.5/solaris/prototype.tmpl0000644000175000017500000000122207251445036016306 0ustar toljtolji pkginfo=./pkginfo f none kannel/bin/wmlsc-VERSION_NUM 0755 bin bin f none kannel/bin/wmlsdasm-VERSION_NUM 0755 bin bin f none kannel/bin/seewbmp-VERSION_NUM 0755 bin bin f none kannel/sbin/bearerbox-VERSION_NUM 0755 bin bin f none kannel/sbin/smsbox-VERSION_NUM 0755 bin bin f none kannel/sbin/wapbox-VERSION_NUM 0755 bin bin f none kannel/sbin/run_kannel_box-VERSION_NUM 0755 bin bin f none kannel/man/man1/seewbmp.1 0755 bin bin f none kannel/man/man1/wmlsc.1 0755 bin bin f none kannel/man/man1/wmlsdasm.1 0755 bin bin f none kannel/man/man8/kannel.8 0755 bin bin f none kannel/man/man8/run_kannel_box.8 0755 bin bin f none etc/kannel.conf 0664 bin bin gateway-1.4.5/solaris/copyright0000644000175000017500000000335307146540550015305 0ustar toljtoljThis is Kannel, packaged for Solaris by Derry Hamilton . Original author is the Kannel project, see http://www.kannel.org, run by WapIT Ltd, see http://www.wapit.com. Copyright (c) 1998 WAPIT OY LTD. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by WAPIT OY LTD. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. gateway-1.4.5/solaris/mk-solaris-package.sh0000755000175000017500000000202607423575706017370 0ustar toljtolj#!/bin/sh VERSION=`head -1 ../VERSION` export VERSION DATE=`date +%Y-%m-%d` echo Making WAkannel-${VERSION}.pkg cd .. make make install cd solaris sed "s/VERSION_NUM/${VERSION}/" < prototype.tmpl > prototype sed "s/VERSION_NUM/${VERSION}/" < pkginfo.tmpl > pkginfo TRG=./kannel mkdir ${TRG} mkdir ${TRG}/bin mkdir ${TRG}/sbin mkdir ${TRG}/man cp ../wmlscript/wmlsc ${TRG}/bin/wmlsc-${VERSION} cp ../wmlscript/wmlsdasm ${TRG}/bin/wmlsdasm-${VERSION} cp ../utils/seewbmp ${TRG}/bin/seewbmp-${VERSION} cp ../gw/bearerbox ${TRG}/sbin/bearerbox-${VERSION} cp ../gw/smsbox ${TRG}/sbin/smsbox-${VERSION} cp ../gw/wapbox ${TRG}/sbin/wapbox-${VERSION} cp ../utils/run_kannel_box ${TRG}/sbin/run_kannel_box-${VERSION} cp ../utils/seewbmp.1 ${TRG}/man/man1/seewbmp.1 cp ../wmlscript/wmlsc.1 ${TRG}/man/man1/wmlsc.1 cp ../wmlscript/wmlsdasm.1 ${TRG}/man/man1/wmlsdasm.1 cp ../gw/kannel.8 ${TRG}/man/man8/kannel.8 cp ../utils/run_kannel_box.8 ${TRG}/man/man8/run_kannel_box.8 pkgmk -r `pwd` -d . -o pkgtrans . WAkannel-${VERSION}.pkg WAkannel-${VERSION} gateway-1.4.5/solaris/etc/0000755000175000017500000000000013312227714014115 5ustar toljtoljgateway-1.4.5/solaris/etc/kannel.conf0000644000175000017500000000072407150441430016233 0ustar toljtolj# # Sample configuration file for Kannel on Solaris. # See the documentation for explanations of fields. # group = core admin-port = 13000 admin-password = bar wapbox-port = 13002 wdp-interface-name = "*" #log-file = "/tmp/kannel.log" #log-level = 0 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" admin-deny-ip = "*.*.*.*" #admin-allow-ip = "127.0.0.1" group = wapbox bearerbox-host = localhost #log-file = "/tmp/wapbox.log" #log-level = 0 syslog-level = none gateway-1.4.5/solaris/pkginfo.tmpl0000644000175000017500000000032307606435022015675 0ustar toljtoljPKG="WAkannel-VERSION_NUMBER" NAME="kannel" ARCH="sparc" VERSION="cvs" CATEGORY="application" VENDOR="Kannel project" EMAIL="andreas@fink.org" PSTAMP="Andreas Fink" BASEDIR="/usr/local" CLASSES="none" gateway-1.4.5/solaris/readme.txt0000644000175000017500000000000007146540550015332 0ustar toljtoljgateway-1.4.5/LICENSE0000644000175000017500000000531713227613126012702 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ gateway-1.4.5/checks/0000755000175000017500000000000013312227711013123 5ustar toljtoljgateway-1.4.5/checks/check_octstr.c0000644000175000017500000001000713227613126015744 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * check_octstr.c - checking of octet string functions */ #include #include "gwlib/gwlib.h" static int signof(int n) { if (n < 0) return -1; if (n == 0) return 0; return 1; } static void check_comparisons(void) { static const char *tab[] = { "", "a", "ab", "abc", "abcåäö", "ABCÅÄÖ", }; static const int n = sizeof(tab) / sizeof(tab[0]); int i, j; int sign_str, sign_oct; Octstr *os1, *os2; for (i = 0; i < n; ++i) { os1 = octstr_create(tab[i]); for (j = 0; j < n; ++j) { os2 = octstr_create(tab[j]); sign_str = signof(strcmp(tab[i], tab[j])); sign_oct = signof(octstr_compare(os1, os2)); if (sign_str != sign_oct) panic(0, "strcmp (%d) and octstr_compare (%d) differ for " "`%s' and `%s'", sign_str, sign_oct, tab[i], tab[j]); sign_str = signof(strcasecmp(tab[i], tab[j])); sign_oct = signof(octstr_case_compare(os1, os2)); if (sign_str != sign_oct) panic(0, "strcasecmp (%d) and octstr_case_compare (%d) " "differ for `%s' and `%s'", sign_str, sign_oct, tab[i], tab[j]); octstr_destroy(os2); } octstr_destroy(os1); } } int main(void) { gwlib_init(); log_set_output_level(GW_INFO); check_comparisons(); gwlib_shutdown(); return 0; } gateway-1.4.5/checks/check_headers.sh0000755000175000017500000000057711144324076016246 0ustar toljtolj#!/bin/sh # # Use `test/test_headers' to test gw/wsp_headers.c set -e #set -x loglevel=1 test/test_headers -v $loglevel test/header_test > check_headers.log 2>&1 ret=$? if [ "$ret" != 0 ] || \ grep ERROR: check_headers.log > /dev/null then echo check_headers failed 1>&2 echo See check_headers.log or run test/test_headers for info 1>&2 exit 1 fi rm -f check_headers.log gateway-1.4.5/checks/check_httpsmsc_kannel.sh0000755000175000017500000000206411144324076020021 0ustar toljtolj#!/bin/sh # # Use `test/fakesmsc' to test the bearerbox and the smsbox. set -e #set -x times=10 interval=0 loglevel=0 host=127.0.0.1 gw/bearerbox -v $loglevel gw/smskannel.conf > check_httpsmsc_kannel_sbb.log 2>&1 & sbbpid=$! sleep 1 gw/bearerbox -v $loglevel gw/other_smskannel.conf > check_httpsmsc_kannel_cbb.log 2>&1 & cbbpid=$! sleep 2 test/fakesmsc -H $host -i $interval -m $times '123 234 text relay nop' \ > check_httpsmsc_kannel_fake.log 2>&1 & sleep 1 gw/smsbox -v $loglevel gw/smskannel.conf > check_httpsmsc_kannel_ssb.log 2>&1 & gw/smsbox -v $loglevel gw/other_smskannel.conf > check_httpsmsc_kannel_csb.log 2>&1 & running="yes" while [ $running = "yes" ] do sleep 1 if grep -v "fakesmsc: terminating" check_httpsmsc_kannel_fake.log >/dev/null then running="no" fi done kill -INT $sbbpid kill -INT $cbbpid wait if grep 'WARNING:|ERROR:|PANIC:' check_httpsmsc_kannel_*.log >/dev/null then echo check_httpsmsc_kannel.sh failed 1>&2 echo See check_httpsmsc_kannel_*.log for info 1>&2 exit 1 fi rm -f check_httpsmsc_kannel_*.log gateway-1.4.5/checks/check_list.c0000644000175000017500000001625513227613126015414 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * check_list.c - check that gwlib/list.c works */ #include #include #include #include "gwlib/gwlib.h" #define NUM_PRODUCERS (4) #define NUM_CONSUMERS (4) #define NUM_ITEMS_PER_PRODUCER (1*1000) struct producer_info { List *list; long start_index; long id; }; static char received[NUM_PRODUCERS * NUM_ITEMS_PER_PRODUCER]; typedef struct { long producer; long num; long index; } Item; static Item *new_item(long producer, long num, long index) { Item *item; item = gw_malloc(sizeof(Item)); item->producer = producer; item->num = num; item->index = index; return item; } static void producer(void *arg) { long i, index; long id; struct producer_info *info; info = arg; id = gwthread_self(); index = info->start_index; for (i = 0; i < NUM_ITEMS_PER_PRODUCER; ++i, ++index) gwlist_produce(info->list, new_item(id, i, index)); gwlist_remove_producer(info->list); } static void consumer(void *arg) { List *list; Item *item; list = arg; for (;;) { item = gwlist_consume(list); if (item == NULL) break; received[item->index] = 1; gw_free(item); } } static void init_received(void) { memset(received, 0, sizeof(received)); } static void main_for_producer_and_consumer(void) { List *list; int i; Item *item; struct producer_info tab[NUM_PRODUCERS]; long p, n, index; int errors; list = gwlist_create(); init_received(); for (i = 0; i < NUM_PRODUCERS; ++i) { tab[i].list = list; tab[i].start_index = i * NUM_ITEMS_PER_PRODUCER; gwlist_add_producer(list); tab[i].id = gwthread_create(producer, tab + i); } for (i = 0; i < NUM_CONSUMERS; ++i) gwthread_create(consumer, list); gwthread_join_every(producer); gwthread_join_every(consumer); while (gwlist_len(list) > 0) { item = gwlist_get(list, 0); gwlist_delete(list, 0, 1); warning(0, "main: %ld %ld %ld", (long) item->producer, item->num, item->index); } errors = 0; for (p = 0; p < NUM_PRODUCERS; ++p) { for (n = 0; n < NUM_ITEMS_PER_PRODUCER; ++n) { index = p * NUM_ITEMS_PER_PRODUCER + n; if (!received[index]) { error(0, "Not received: producer=%ld " "item=%ld index=%ld", tab[p].id, n, index); errors = 1; } } } if (errors) panic(0, "Not all messages were received."); } static int compare_cstr(void *item, void *pat) { /* Remove a macro definition of strcmp to prevent warnings from * a broken version in the glibc libary. */ #undef strcmp return strcmp(item, pat) == 0; } static void main_for_list_add_and_delete(void) { static char *items[] = { "one", "two", "three", }; int num_items = sizeof(items) / sizeof(items[0]); int num_repeats = 3; int i, j; char *p; List *list; list = gwlist_create(); for (j = 0; j < num_repeats; ++j) for (i = 0; i < num_items; ++i) gwlist_append(list, items[i]); gwlist_delete_matching(list, items[0], compare_cstr); for (i = 0; i < gwlist_len(list); ++i) { p = gwlist_get(list, i); if (strcmp(p, items[0]) == 0) panic(0, "list contains `%s' after deleting it!", items[0]); } for (i = 0; i < num_items; ++i) gwlist_delete_equal(list, items[i]); if (gwlist_len(list) != 0) panic(0, "list is not empty after deleting everything"); gwlist_destroy(list, NULL); } static void main_for_extract(void) { static char *items[] = { "one", "two", "three", }; int num_items = sizeof(items) / sizeof(items[0]); int num_repeats = 3; int i, j; char *p; List *list, *extracted; list = gwlist_create(); for (j = 0; j < num_repeats; ++j) for (i = 0; i < num_items; ++i) gwlist_append(list, items[i]); for (j = 0; j < num_items; ++j) { extracted = gwlist_extract_matching(list, items[j], compare_cstr); if (extracted == NULL) panic(0, "no extracted elements, should have!"); for (i = 0; i < gwlist_len(list); ++i) { p = gwlist_get(list, i); if (strcmp(p, items[j]) == 0) panic(0, "list contains `%s' after " "extracting it!", items[j]); } for (i = 0; i < gwlist_len(extracted); ++i) { p = gwlist_get(extracted, i); if (strcmp(p, items[j]) != 0) panic(0, "extraction returned wrong element!"); } gwlist_destroy(extracted, NULL); } if (gwlist_len(list) != 0) panic(0, "list is not empty after extracting everything"); gwlist_destroy(list, NULL); } int main(void) { gwlib_init(); log_set_output_level(GW_INFO); main_for_list_add_and_delete(); main_for_extract(); main_for_producer_and_consumer(); gwlib_shutdown(); return 0; } gateway-1.4.5/checks/check_http.sh0000755000175000017500000000404211144324076015601 0ustar toljtolj#!/bin/sh # # Use `test/test_http{,_server}' to test gwlib/http.c. # Incuding the SSL client and server componentes, if, of course, SSL has been # enabled. set -e #set -x times=2 host=127.0.0.1 port="8040" port_ssl="8041" url="http://$host:$port/foo.txt" url_ssl="https://$host:$port_ssl/foo.txt" quiturl="http://$host:$port/quit" quiturl_ssl="https://$host:$port_ssl/quit" ssl_cert="gw/cert.pem" ssl_key="gw/key.pem" ssl_clientcert="/tmp/clientcert.pem" loglevel=0 ssl_enabled="yes" cat $ssl_cert $ssl_key > $ssl_clientcert test/test_http_server -p $port -v $loglevel > check_http_server.log 2>&1 & serverpid=$! sleep 1 test/test_http_server -p $port_ssl -v $loglevel -s -c $ssl_cert -k $ssl_key > check_https_server.log 2>&1 & serverpid_ssl=$! sleep 1 test/test_http -r $times $url > check_http.log 2>&1 ret=$? test/test_http -r 1 -s -c $ssl_clientcert $url_ssl > check_https.log 2>&1 ret=$? if grep 'SSL not compiled in' check_https.log > /dev/null then echo 'do not check SSL, SSL not compiled in' ssl_enabled="no" fi if test "$ssl_enabled" = "yes" then echo -n ' checking SSL connections, too...' test/test_http -r $times -s -c $ssl_clientcert $url_ssl > check_https.log 2>&1 ret=$? else test/test_http -r 1 -s -c $ssl_clientcert $quiturl_ssl >> check_https.log 2>&1 rm -f check_https.log sleep 1 fi test/test_http -r 1 $quiturl >> check_http.log 2>&1 if test "$ssl_enabled" = "yes" then test/test_http -r 1 -s -c $ssl_clientcert $quiturl_ssl >> check_https.log 2>&1 sleep 1 fi sleep 1 if grep 'ERROR:|PANIC:' check_http.log check_http_server.log > /dev/null then echo check_http failed 1>&2 echo See check_http.log and check_http_server.log for info 1>&2 exit 1 fi if test "$ssl_enabled" = "yes" then if grep 'ERROR:|PANIC' check_https.log check_https_server.log > /dev/null then echo check_https failed 1>&2 echo see check_https_log and check_http_server.log for info 1>&2 exit 1 fi fi rm -f check_http*.log rm -f $ssl_clientcert exit 0 gateway-1.4.5/checks/check_ipcheck.c0000644000175000017500000000763413227613126016050 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * check_ipcheck.c - check the is_allowed_ip function * * Lars Wirzenius */ #include "gwlib/gwlib.h" int main(void) { Octstr *ip; Octstr *allowed; Octstr *denied; int result; int i; static struct { char *allowed; char *denied; char *ip; int should_be_allowed; } tab[] = { { "127.0.0.1", "", "127.0.0.1", 1 }, { "127.0.0.1", "", "127.0.0.2", 1 }, { "127.0.0.1", "*.*.*.*", "127.0.0.1", 1 }, { "127.0.0.1", "*.*.*.*", "1.2.3.4", 0 }, { "127.0.0.1", "127.0.0.*", "1.2.3.4", 1 }, { "127.0.0.1", "127.0.0.*", "127.0.0.2", 0 }, }; gwlib_init(); log_set_output_level(GW_INFO); for (i = 0; (size_t) i < sizeof(tab) / sizeof(tab[0]); ++i) { allowed = octstr_imm(tab[i].allowed); denied = octstr_imm(tab[i].denied); ip = octstr_imm(tab[i].ip); result = is_allowed_ip(allowed, denied, ip); if (!!result != !!tab[i].should_be_allowed) { panic(0, "is_allowed_ip did not work for " "allowed=<%s> denied=<%s> ip=<%s>, " "returned %d should be %d", octstr_get_cstr(allowed), octstr_get_cstr(denied), octstr_get_cstr(ip), result, tab[i].should_be_allowed); } } gwlib_shutdown(); return 0; } gateway-1.4.5/checks/check_compiler.sh0000755000175000017500000000054011144324076016433 0ustar toljtolj#!/bin/sh # # Use `test/test_compiler' to test gw/wml_compiler.c set -e test/wml_tester -b test/testcase.wml | test/decompile | diff test/testcase.wml - > check_compiler.log 2>&1 ret=$? if [ "$ret" != 0 ] then echo check_compiler failed 1>&2 echo See check_compiler.log or run test/test_compiler for info 1>&2 exit 1 fi rm -f check_compiler.log gateway-1.4.5/checks/check_date.c0000644000175000017500000001076213227613126015353 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * check_date.c - checking of date handling functions */ #include #include "gwlib/gwlib.h" /* Format of test_dates file: * Valid date strings, one per line. If a date string is valid * but not in the preferred HTTP format, put the preferred version * after it on the same line. Separate them with a tab. */ static void check_reversible(void) { Octstr *dates; long pos, endpos, tabpos; Octstr *date, *canondate; long timeval; dates = octstr_read_file("checks/test_dates"); if (dates == NULL) return; for (pos = 0; ; pos = endpos + 1) { endpos = octstr_search_char(dates, '\n', pos); if (endpos < 0) break; tabpos = octstr_search_char(dates, '\t', pos); if (tabpos >= 0 && tabpos < endpos) { date = octstr_copy(dates, pos, tabpos - pos); canondate = octstr_copy(dates, tabpos + 1, endpos - tabpos - 1); } else { date = octstr_copy(dates, pos, endpos - pos); canondate = octstr_duplicate(date); } timeval = date_parse_http(date); if (timeval == -1) warning(0, "Could not parse date \"%s\"", octstr_get_cstr(date)); else { Octstr *newdate; newdate = date_format_http((unsigned long) timeval); if (octstr_compare(newdate, canondate) != 0) { warning(0, "Date not reversible: \"%s\" becomes \"%s\"", octstr_get_cstr(date), octstr_get_cstr(newdate)); } octstr_destroy(newdate); } octstr_destroy(date); octstr_destroy(canondate); } octstr_destroy(dates); } int main(void) { gwlib_init(); log_set_output_level(GW_INFO); check_reversible(); gwlib_shutdown(); return 0; } gateway-1.4.5/checks/check_counter.c0000644000175000017500000000717213227613126016116 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * check_counter.c - Check that Counter objects work * * This is a test program for checking Counter objects. It creates some * threads that get many counts and check that they are increasing. */ #include #ifndef THREADS #define THREADS 16 #endif #ifndef PER_THREAD #define PER_THREAD (1000) #endif #include "gwlib/gwlib.h" static void check(void *arg) { Counter *c; long i, this, prev; c = arg; prev = -1; for (i = 0; i < PER_THREAD; ++i) { this = counter_increase(c); if (this < 0) panic(0, "counter returned negative"); if (this < prev) panic(0, "counter returned smaller than previous"); prev = this; } } int main(void) { Counter *c; long threads[THREADS]; long i; gwlib_init(); log_set_output_level(GW_INFO); c = counter_create(); for (i = 0; i < THREADS; ++i) threads[i] = gwthread_create(check, c); for (i = 0; i < THREADS; ++i) gwthread_join(threads[i]); return 0; } gateway-1.4.5/checks/test_dates0000644000175000017500000071033707164634500015226 0ustar toljtoljFri, 01 Jan 1999 13:38:00 GMT Fri, 01 Jan 1999 14:29:28 GMT Fri, 01 Jan 1999 15:08:30 GMT Fri, 01 Jan 1999 19:04:31 GMT Fri, 01 Jan 1999 19:04:35 GMT Fri, 01 Jan 1999 19:04:39 GMT Fri, 01 Jan 1999 19:04:41 GMT Fri, 01 Jan 1999 19:05:01 GMT Fri, 01 Jan 1999 19:05:11 GMT Fri, 01 Jan 1999 19:05:31 GMT Fri, 01 Jan 1999 19:05:34 GMT Fri, 01 May 1998 06:21:08 GMT Fri, 01 May 1998 14:42:00 GMT Fri, 01 Nov 1996 22:00:00 GMT Fri, 01 Oct 1999 08:59:56 GMT Fri, 01 Oct 1999 08:59:58 GMT Fri, 01 Oct 1999 09:00:02 GMT Fri, 01 Sep 1989 01:37:20 GMT Fri, 01 Sep 1989 01:37:24 GMT Fri, 01 Sep 1989 01:37:28 GMT Fri, 01 Sep 1989 01:37:32 GMT Fri, 01 Sep 1989 01:37:37 GMT Fri, 01 Sep 2000 12:38:21 GMT Fri, 01 Sep 2000 13:12:18 GMT Fri, 01 Sep 2000 13:12:20 GMT Fri, 01 Sep 2000 13:12:23 GMT Fri, 01 Sep 2000 13:47:23 GMT Fri, 01 Sep 2000 14:05:00 GMT Fri, 01 Sep 2000 14:05:02 GMT Fri, 01 Sep 2000 14:07:55 GMT Fri, 01 Sep 2000 14:07:57 GMT Fri, 01 Sep 2000 14:08:09 GMT Fri, 01 Sep 2000 14:09:41 GMT Fri, 01 Sep 2000 14:09:43 GMT Fri, 01 Sep 2000 14:09:56 GMT Fri, 01 Sep 2000 14:27:28 GMT Fri, 01 Sep 2000 14:30:34 GMT Fri, 01 Sep 2000 14:40:09 GMT Fri, 01 Sep 2000 14:42:04 GMT Fri, 01 Sep 2000 14:47:01 GMT Fri, 01 Sep 2000 14:53:13 GMT Fri, 01 Sep 2000 14:57:29 GMT Fri, 01 Sep 2000 20:12:17 GMT Fri, 01 Sep 2000 20:34:25 GMT Fri, 01 Sep 2000 20:36:18 GMT Fri, 01 Sep 2000 20:37:56 GMT Fri, 01 Sep 2000 20:40:06 GMT Fri, 01 Sep 2000 20:42:46 GMT Fri, 01 Sep 2000 20:44:06 GMT Fri, 01 Sep 2000 20:49:35 GMT Fri, 01 Sep 2000 20:53:56 GMT Fri, 01 Sep 2000 20:55:18 GMT Fri, 01 Sep 2000 21:08:58 GMT Fri, 01 Sep 2000 21:11:59 GMT Fri, 01 Sep 2000 21:28:43 GMT Fri, 01 Sep 2000 21:31:20 GMT Fri, 01 Sep 2000 21:31:40 GMT Fri, 01 Sep 2000 21:33:38 GMT Fri, 01 Sep 2000 21:33:40 GMT Fri, 01 Sep 2000 21:33:42 GMT Fri, 01 Sep 2000 21:33:45 GMT Fri, 01 Sep 2000 21:33:47 GMT Fri, 01 Sep 2000 21:33:50 GMT Fri, 01 Sep 2000 21:33:52 GMT Fri, 01 Sep 2000 21:33:54 GMT Fri, 01 Sep 2000 21:33:56 GMT Fri, 01 Sep 2000 21:33:58 GMT Fri, 01 Sep 2000 21:34:00 GMT Fri, 01 Sep 2000 21:34:02 GMT Fri, 01 Sep 2000 21:34:04 GMT Fri, 01 Sep 2000 21:34:06 GMT Fri, 01 Sep 2000 21:34:08 GMT Fri, 01 Sep 2000 21:34:10 GMT Fri, 01 Sep 2000 21:34:12 GMT Fri, 01 Sep 2000 21:34:14 GMT Fri, 01 Sep 2000 21:34:16 GMT Fri, 01 Sep 2000 21:34:18 GMT Fri, 01 Sep 2000 21:34:20 GMT Fri, 01 Sep 2000 21:34:22 GMT Fri, 01 Sep 2000 21:34:24 GMT Fri, 01 Sep 2000 21:34:31 GMT Fri, 01 Sep 2000 21:43:55 GMT Fri, 01 Sep 2000 21:44:06 GMT Fri, 01 Sep 2000 21:46:10 GMT Fri, 01 Sep 2000 21:51:44 GMT Fri, 01 Sep 2000 22:09:14 GMT Fri, 01 Sep 2000 23:51:51 GMT Fri, 01 Sep 2000 23:51:56 GMT Fri, 02 Apr 1999 20:06:36 GMT Fri, 02 Apr 1999 20:25:57 GMT Fri, 02 Jun 1995 10:51:16 GMT Fri, 02 Jun 2000 01:40:20 GMT Fri, 02 Jun 2000 09:43:12 GMT Fri, 02 Jun 2000 11:24:52 GMT Fri, 02 Jun 2000 15:08:38 GMT Fri, 02 Jun 2000 16:47:46 GMT Fri, 02 Jun 2000 16:47:48 GMT Fri, 02 Jun 2000 16:53:00 GMT Fri, 02 Jun 2000 16:53:06 GMT Fri, 02 Jun 2000 17:08:38 GMT Fri, 02 Jun 2000 17:08:40 GMT Fri, 02 Jun 2000 17:08:42 GMT Fri, 02 Jun 2000 17:08:44 GMT Fri, 02 Jun 2000 17:08:47 GMT Fri, 02 Jun 2000 17:08:51 GMT Fri, 02 Jun 2000 17:08:59 GMT Fri, 02 Jun 2000 17:09:03 GMT Fri, 02 Jun 2000 17:09:12 GMT Fri, 02 Jun 2000 18:34:30 GMT Fri, 03 Dec 1999 08:09:53 GMT Fri, 03 Dec 1999 09:08:16 GMT Fri, 03 Dec 1999 18:55:09 GMT Fri, 03 Dec 1999 21:13:01 GMT Fri, 03 Dec 1999 21:18:55 GMT Fri, 03 Dec 1999 21:18:57 GMT Fri, 03 Dec 1999 21:19:00 GMT Fri, 03 Jan 1997 09:33:26 GMT Fri, 03 Jul 1992 01:57:52 GMT Fri, 03 Mar 1989 19:52:21 GMT Fri, 03 Mar 2000 12:31:53 GMT Fri, 03 Mar 2000 13:01:04 GMT Fri, 03 Mar 2000 13:06:59 GMT Fri, 03 Mar 2000 14:22:31 GMT Fri, 03 Mar 2000 16:04:08 GMT Fri, 03 Mar 2000 16:05:26 GMT Fri, 03 Mar 2000 16:08:30 GMT Fri, 03 Mar 2000 16:11:23 GMT Fri, 03 Mar 2000 16:18:16 GMT Fri, 03 Mar 2000 16:19:45 GMT Fri, 03 Mar 2000 16:24:18 GMT Fri, 03 Mar 2000 16:25:44 GMT Fri, 03 Mar 2000 16:27:13 GMT Fri, 03 Mar 2000 16:27:15 GMT Fri, 03 Oct 1997 13:37:29 GMT Fri, 03 Sep 1999 11:57:29 GMT Fri, 03 Sep 1999 11:57:31 GMT Fri, 03 Sep 1999 12:54:39 GMT Fri, 03 Sep 1999 14:52:39 GMT Fri, 03 Sep 1999 19:27:58 GMT Fri, 03 Sep 1999 21:17:43 GMT Fri, 04 Aug 2000 05:48:16 GMT Fri, 04 Aug 2000 06:30:17 GMT Fri, 04 Aug 2000 09:28:16 GMT Fri, 04 Aug 2000 09:28:18 GMT Fri, 04 Aug 2000 12:43:22 GMT Fri, 04 Aug 2000 19:31:21 GMT Fri, 04 Aug 2000 22:50:01 GMT Fri, 04 Aug 2000 23:28:52 GMT Fri, 04 Aug 2000 23:31:40 GMT Fri, 04 Aug 2000 23:37:04 GMT Fri, 04 Aug 2000 23:37:50 GMT Fri, 04 Aug 2000 23:39:04 GMT Fri, 04 Aug 2000 23:43:26 GMT Fri, 04 Dec 1998 17:47:38 GMT Fri, 04 Feb 2000 03:32:21 GMT Fri, 04 Feb 2000 07:52:30 GMT Fri, 04 Feb 2000 09:49:30 GMT Fri, 04 Feb 2000 16:38:16 GMT Fri, 04 Feb 2000 23:25:45 GMT Fri, 04 Jun 1999 12:24:58 GMT Fri, 04 Jun 1999 15:52:51 GMT Fri, 04 Jun 1999 18:40:00 GMT Fri, 04 Jun 1999 21:17:36 GMT Fri, 04 Jun 1999 21:17:39 GMT Fri, 04 Jun 1999 21:17:41 GMT Fri, 04 Jun 1999 21:17:43 GMT Fri, 04 Jun 1999 21:17:47 GMT Fri, 05 Apr 1996 11:08:30 GMT Fri, 05 Dec 1997 22:13:12 GMT Fri, 05 Feb 1993 16:45:10 GMT Fri, 05 Jun 1998 05:53:50 GMT Fri, 05 May 2000 00:14:03 GMT Fri, 05 May 2000 11:30:20 GMT Fri, 05 May 2000 11:34:51 GMT Fri, 05 May 2000 12:13:39 GMT Fri, 05 May 2000 22:40:25 GMT Fri, 05 Nov 1999 13:08:00 GMT Fri, 05 Nov 1999 15:41:01 GMT Fri, 05 Nov 1999 16:48:00 GMT Fri, 05 Nov 1999 16:51:00 GMT Fri, 05 Nov 1999 16:53:00 GMT Fri, 05 Nov 1999 16:55:00 GMT Fri, 05 Nov 1999 16:57:00 GMT Fri, 05 Nov 1999 18:01:50 GMT Fri, 05 Nov 1999 23:23:43 GMT Fri, 06 Aug 1999 00:05:40 GMT Fri, 06 Aug 1999 01:48:45 GMT Fri, 06 Aug 1999 03:43:49 GMT Fri, 06 Aug 1999 03:56:26 GMT Fri, 06 Aug 1999 05:02:37 GMT Fri, 06 Aug 1999 17:44:11 GMT Fri, 06 Aug 1999 18:58:00 GMT Fri, 06 Aug 1999 19:23:51 GMT Fri, 06 Aug 1999 20:02:24 GMT Fri, 06 Feb 1998 18:06:55 GMT Fri, 06 Mar 1998 03:38:00 GMT Fri, 07 Apr 2000 10:48:12 GMT Fri, 07 Apr 2000 12:56:58 GMT Fri, 07 Apr 2000 20:17:54 GMT Fri, 07 Aug 1998 20:08:51 GMT Fri, 07 Jan 2000 00:17:19 GMT Fri, 07 Jan 2000 10:03:42 GMT Fri, 07 Jan 2000 15:30:30 GMT Fri, 07 Jan 2000 15:48:08 GMT Fri, 07 Jan 2000 16:04:11 GMT Fri, 07 Jan 2000 16:04:13 GMT Fri, 07 Jan 2000 16:05:01 GMT Fri, 07 Jan 2000 19:51:56 GMT Fri, 07 Jan 2000 20:59:42 GMT Fri, 07 Jul 2000 01:10:31 GMT Fri, 07 Jul 2000 03:25:44 GMT Fri, 07 Jul 2000 03:26:41 GMT Fri, 07 Jul 2000 05:44:53 GMT Fri, 07 Jul 2000 09:09:59 GMT Fri, 07 Jul 2000 09:10:09 GMT Fri, 07 Jul 2000 09:14:00 GMT Fri, 07 Jul 2000 09:42:41 GMT Fri, 07 Jul 2000 09:52:39 GMT Fri, 07 Jul 2000 10:01:22 GMT Fri, 07 Jul 2000 10:01:34 GMT Fri, 07 Jul 2000 10:01:36 GMT Fri, 07 Jul 2000 10:01:40 GMT Fri, 07 Jul 2000 10:02:15 GMT Fri, 07 Jul 2000 10:02:24 GMT Fri, 07 Jul 2000 10:02:26 GMT Fri, 07 Jul 2000 14:44:26 GMT Fri, 07 Jul 2000 16:16:07 GMT Fri, 07 Jul 2000 19:36:32 GMT Fri, 07 Jul 2000 19:36:35 GMT Fri, 07 Jul 2000 21:56:31 GMT Fri, 07 Jul 2000 22:33:44 GMT Fri, 07 May 1999 00:16:10 GMT Fri, 07 May 1999 01:25:29 GMT Fri, 07 May 1999 05:49:46 GMT Fri, 07 Nov 1997 23:00:00 GMT Fri, 08 Jan 1999 17:54:40 GMT Fri, 08 Jan 1999 19:11:45 GMT Fri, 08 May 1998 07:11:29 GMT Fri, 08 May 1998 07:15:22 GMT Fri, 08 May 1998 07:42:39 GMT Fri, 08 Oct 1999 07:46:26 GMT Fri, 08 Oct 1999 20:16:02 GMT Fri, 08 Sep 2000 07:27:45 GMT Fri, 09 Apr 1999 07:23:26 GMT Fri, 09 Apr 1999 12:57:09 GMT Fri, 09 Jul 1999 18:47:46 GMT Fri, 09 Jul 1999 18:47:50 GMT Fri, 09 Jul 1999 22:09:28 GMT Fri, 09 Jun 2000 00:49:37 GMT Fri, 09 Jun 2000 05:37:12 GMT Fri, 09 Jun 2000 11:57:26 GMT Fri, 09 Jun 2000 14:16:18 GMT Fri, 09 Jun 2000 15:08:01 GMT Fri, 09 Jun 2000 15:43:31 GMT Fri, 09 Jun 2000 16:04:47 GMT Fri, 09 Jun 2000 18:55:51 GMT Fri, 09 Jun 2000 19:03:59 GMT Fri, 09 Jun 2000 19:04:27 GMT Fri, 09 Nov 1990 02:49:31 GMT Fri, 09 Nov 1990 04:05:24 GMT Fri, 09 Sep 1988 01:04:17 GMT Fri, 10 Apr 1998 22:57:45 GMT Fri, 10 Dec 1999 05:45:42 GMT Fri, 10 Dec 1999 11:03:20 GMT Fri, 10 Dec 1999 11:03:44 GMT Fri, 10 Dec 1999 11:03:46 GMT Fri, 10 Dec 1999 11:03:49 GMT Fri, 10 Dec 1999 11:03:57 GMT Fri, 10 Dec 1999 12:28:26 GMT Fri, 10 Dec 1999 22:56:08 GMT Fri, 10 Jan 1997 11:37:03 GMT Fri, 10 Jul 1998 20:51:41 GMT Fri, 10 Jul 1998 21:03:36 GMT Fri, 10 Mar 2000 00:06:45 GMT Fri, 10 Mar 2000 08:12:30 GMT Fri, 10 Mar 2000 10:44:07 GMT Fri, 10 Mar 2000 10:57:57 GMT Fri, 10 Mar 2000 12:48:39 GMT Fri, 10 Mar 2000 12:54:06 GMT Fri, 10 Mar 2000 13:12:07 GMT Fri, 10 Mar 2000 13:45:46 GMT Fri, 10 Mar 2000 14:21:29 GMT Fri, 10 Mar 2000 15:10:38 GMT Fri, 10 May 1996 04:54:52 GMT Fri, 10 Oct 1997 06:56:55 GMT Fri, 10 Oct 1997 22:29:47 GMT Fri, 10 Sep 1999 02:35:18 GMT Fri, 10 Sep 1999 17:32:05 GMT Fri, 11 Apr 1997 17:32:59 GMT Fri, 11 Apr 1997 17:35:13 GMT Fri, 11 Aug 1989 18:43:01 GMT Fri, 11 Aug 2000 01:26:58 GMT Fri, 11 Aug 2000 01:27:10 GMT Fri, 11 Aug 2000 01:28:32 GMT Fri, 11 Aug 2000 01:28:35 GMT Fri, 11 Aug 2000 01:28:38 GMT Fri, 11 Aug 2000 01:28:40 GMT Fri, 11 Aug 2000 01:28:42 GMT Fri, 11 Aug 2000 01:28:46 GMT Fri, 11 Aug 2000 22:17:47 GMT Fri, 11 Aug 2000 22:35:08 GMT Fri, 11 Aug 2000 22:35:14 GMT Fri, 11 Dec 1998 13:58:20 GMT Fri, 11 Feb 2000 01:03:43 GMT Fri, 11 Feb 2000 01:07:26 GMT Fri, 11 Feb 2000 03:00:35 GMT Fri, 11 Feb 2000 06:02:32 GMT Fri, 11 Feb 2000 09:04:22 GMT Fri, 11 Feb 2000 13:26:17 GMT Fri, 11 Feb 2000 16:19:45 GMT Fri, 11 Feb 2000 16:25:33 GMT Fri, 11 Feb 2000 16:47:40 GMT Fri, 11 Feb 2000 19:30:10 GMT Fri, 11 Feb 2000 21:20:53 GMT Fri, 11 Sep 1998 09:53:06 GMT Fri, 11 Sep 1998 18:26:56 GMT Fri, 12 Apr 1996 06:49:37 GMT Fri, 12 Apr 1996 06:49:40 GMT Fri, 12 Jun 1998 05:52:33 GMT Fri, 12 Mar 1999 08:38:19 GMT Fri, 12 Mar 1999 21:43:54 GMT Fri, 12 Mar 1999 21:45:40 GMT Fri, 12 Mar 1999 21:46:16 GMT Fri, 12 May 1995 12:59:00 GMT Fri, 12 May 2000 02:13:49 GMT Fri, 12 May 2000 02:37:40 GMT Fri, 12 May 2000 10:30:08 GMT Fri, 12 May 2000 15:39:30 GMT Fri, 12 May 2000 15:40:38 GMT Fri, 12 May 2000 20:12:39 GMT Fri, 12 May 2000 21:18:20 GMT Fri, 12 May 2000 22:30:52 GMT Fri, 12 Nov 1999 00:03:36 GMT Fri, 12 Nov 1999 00:57:30 GMT Fri, 12 Nov 1999 01:00:29 GMT Fri, 12 Nov 1999 06:12:15 GMT Fri, 12 Nov 1999 12:36:13 GMT Fri, 12 Nov 1999 18:12:11 GMT Fri, 13 Aug 1999 19:16:16 GMT Fri, 13 Dec 1996 09:29:44 GMT Fri, 13 Dec 1996 09:29:46 GMT Fri, 13 Dec 1996 09:37:41 GMT Fri, 13 Dec 1996 09:49:50 GMT Fri, 13 Feb 1998 00:20:10 GMT Fri, 13 Feb 1998 00:30:12 GMT Fri, 13 Jan 1995 07:02:32 GMT Fri, 13 Jun 1997 09:27:04 GMT Fri, 13 Jun 1997 11:06:20 GMT Fri, 13 Mar 1998 00:03:37 GMT Fri, 13 Mar 1998 16:32:00 GMT Fri, 13 Nov 1998 15:20:06 GMT Fri, 13 Nov 1998 18:10:12 GMT Fri, 14 Apr 2000 08:00:37 GMT Fri, 14 Apr 2000 13:03:43 GMT Fri, 14 Apr 2000 13:43:32 GMT Fri, 14 Jan 2000 00:17:59 GMT Fri, 14 Jan 2000 00:41:19 GMT Fri, 14 Jan 2000 00:42:03 GMT Fri, 14 Jan 2000 00:49:22 GMT Fri, 14 Jan 2000 02:03:58 GMT Fri, 14 Jan 2000 08:50:53 GMT Fri, 14 Jan 2000 09:03:49 GMT Fri, 14 Jan 2000 10:15:46 GMT Fri, 14 Jan 2000 17:08:16 GMT Fri, 14 Jan 2000 19:21:50 GMT Fri, 14 Jan 2000 19:25:21 GMT Fri, 14 Jan 2000 20:49:48 GMT Fri, 14 Jan 2000 21:48:26 GMT Fri, 14 Jul 2000 12:33:02 GMT Fri, 14 Jul 2000 12:49:46 GMT Fri, 14 Jul 2000 13:31:46 GMT Fri, 14 Jul 2000 21:27:42 GMT Fri, 14 Jul 2000 21:35:55 GMT Fri, 14 Jul 2000 21:55:41 GMT Fri, 14 Jul 2000 21:56:34 GMT Fri, 14 Jul 2000 21:57:15 GMT Fri, 14 Jun 1996 22:18:38 GMT Fri, 14 May 1999 06:18:21 GMT Fri, 14 May 1999 06:50:15 GMT Fri, 14 May 1999 17:38:04 GMT Fri, 14 Nov 1997 17:26:14 GMT Fri, 15 Jan 1999 06:53:02 GMT Fri, 15 Jan 1999 06:58:47 GMT Fri, 15 Jan 1999 22:41:04 GMT Fri, 15 May 1998 02:11:48 GMT Fri, 15 May 1998 08:27:32 GMT Fri, 15 May 1998 08:52:15 GMT Fri, 15 Nov 1996 11:24:46 GMT Fri, 15 Oct 1999 02:45:13 GMT Fri, 15 Oct 1999 15:45:36 GMT Fri, 15 Oct 1999 17:38:47 GMT Fri, 15 Sep 2000 04:56:54 GMT Fri, 15 Sep 2000 04:56:58 GMT Fri, 15 Sep 2000 18:52:00 GMT Fri, 15 Sep 2000 23:13:08 GMT Fri, 16 Apr 1999 00:05:00 GMT Fri, 16 Apr 1999 00:07:00 GMT Fri, 16 Apr 1999 08:39:29 GMT Fri, 16 Apr 1999 18:34:30 GMT Fri, 16 Jul 1993 04:11:00 GMT Fri, 16 Jul 1993 05:16:00 GMT Fri, 16 Jun 1995 08:52:26 GMT Fri, 16 Jun 2000 00:01:43 GMT Fri, 16 Jun 2000 00:06:22 GMT Fri, 16 Jun 2000 00:07:27 GMT Fri, 16 Jun 2000 00:07:29 GMT Fri, 16 Jun 2000 00:07:32 GMT Fri, 16 Jun 2000 00:07:35 GMT Fri, 16 Jun 2000 00:07:38 GMT Fri, 16 Jun 2000 00:07:40 GMT Fri, 16 Jun 2000 00:07:42 GMT Fri, 16 Jun 2000 00:07:44 GMT Fri, 16 Jun 2000 00:07:46 GMT Fri, 16 Jun 2000 00:07:48 GMT Fri, 16 Jun 2000 00:07:50 GMT Fri, 16 Jun 2000 00:07:58 GMT Fri, 16 Jun 2000 08:26:12 GMT Fri, 16 Jun 2000 08:26:18 GMT Fri, 16 Jun 2000 08:26:26 GMT Fri, 16 Jun 2000 08:26:31 GMT Fri, 16 Jun 2000 08:26:36 GMT Fri, 16 Jun 2000 12:56:02 GMT Fri, 16 Jun 2000 13:35:25 GMT Fri, 16 Jun 2000 13:40:26 GMT Fri, 16 Jun 2000 13:40:44 GMT Fri, 16 Jun 2000 13:52:44 GMT Fri, 16 Jun 2000 14:22:08 GMT Fri, 16 Jun 2000 14:51:26 GMT Fri, 16 Jun 2000 14:55:02 GMT Fri, 16 Jun 2000 23:38:24 GMT Fri, 16 Sep 1994 14:59:55 GMT Fri, 17 Apr 1998 17:42:08 GMT Fri, 17 Dec 1999 00:25:37 GMT Fri, 17 Dec 1999 13:52:00 GMT Fri, 17 Jan 1986 08:43:33 GMT Fri, 17 Jan 1992 17:44:47 GMT Fri, 17 Jul 1998 18:04:19 GMT Fri, 17 Mar 2000 02:44:14 GMT Fri, 17 Mar 2000 07:31:28 GMT Fri, 17 Mar 2000 07:55:40 GMT Fri, 17 Mar 2000 08:33:43 GMT Fri, 17 Mar 2000 08:42:18 GMT Fri, 17 Mar 2000 08:51:46 GMT Fri, 17 Mar 2000 08:52:17 GMT Fri, 17 Mar 2000 08:53:51 GMT Fri, 17 Mar 2000 08:56:50 GMT Fri, 17 Mar 2000 09:34:26 GMT Fri, 17 Mar 2000 10:49:30 GMT Fri, 17 Mar 2000 11:10:18 GMT Fri, 17 Mar 2000 11:59:04 GMT Fri, 17 Mar 2000 12:11:13 GMT Fri, 17 Mar 2000 12:11:16 GMT Fri, 17 Mar 2000 12:11:19 GMT Fri, 17 Mar 2000 12:11:22 GMT Fri, 17 Mar 2000 12:11:25 GMT Fri, 17 Mar 2000 12:17:36 GMT Fri, 17 Mar 2000 13:09:25 GMT Fri, 17 Mar 2000 13:13:57 GMT Fri, 17 Mar 2000 14:48:42 GMT Fri, 17 Mar 2000 17:06:38 GMT Fri, 17 Mar 2000 23:04:38 GMT Fri, 17 Sep 1999 07:43:35 GMT Fri, 18 Aug 2000 08:43:51 GMT Fri, 18 Aug 2000 11:45:38 GMT Fri, 18 Aug 2000 11:52:12 GMT Fri, 18 Aug 2000 11:52:17 GMT Fri, 18 Aug 2000 11:52:23 GMT Fri, 18 Aug 2000 12:21:34 GMT Fri, 18 Aug 2000 13:39:21 GMT Fri, 18 Aug 2000 14:23:21 GMT Fri, 18 Aug 2000 14:45:09 GMT Fri, 18 Aug 2000 14:45:28 GMT Fri, 18 Aug 2000 14:45:30 GMT Fri, 18 Aug 2000 14:45:34 GMT Fri, 18 Aug 2000 14:45:47 GMT Fri, 18 Aug 2000 14:45:54 GMT Fri, 18 Aug 2000 14:45:59 GMT Fri, 18 Aug 2000 14:46:07 GMT Fri, 18 Aug 2000 14:46:22 GMT Fri, 18 Aug 2000 14:46:58 GMT Fri, 18 Aug 2000 14:47:03 GMT Fri, 18 Aug 2000 14:47:06 GMT Fri, 18 Aug 2000 14:47:09 GMT Fri, 18 Aug 2000 14:47:11 GMT Fri, 18 Aug 2000 14:47:14 GMT Fri, 18 Aug 2000 14:47:17 GMT Fri, 18 Aug 2000 14:47:19 GMT Fri, 18 Aug 2000 14:47:22 GMT Fri, 18 Aug 2000 14:47:31 GMT Fri, 18 Aug 2000 14:47:33 GMT Fri, 18 Aug 2000 14:47:53 GMT Fri, 18 Aug 2000 14:47:55 GMT Fri, 18 Aug 2000 14:47:57 GMT Fri, 18 Aug 2000 14:48:00 GMT Fri, 18 Aug 2000 14:48:03 GMT Fri, 18 Aug 2000 14:48:05 GMT Fri, 18 Aug 2000 14:48:07 GMT Fri, 18 Aug 2000 14:48:09 GMT Fri, 18 Aug 2000 14:48:14 GMT Fri, 18 Aug 2000 14:48:21 GMT Fri, 18 Aug 2000 14:48:23 GMT Fri, 18 Aug 2000 14:48:29 GMT Fri, 18 Aug 2000 14:48:32 GMT Fri, 18 Aug 2000 14:48:34 GMT Fri, 18 Aug 2000 14:48:37 GMT Fri, 18 Aug 2000 14:48:39 GMT Fri, 18 Aug 2000 14:48:41 GMT Fri, 18 Aug 2000 14:48:43 GMT Fri, 18 Aug 2000 14:48:47 GMT Fri, 18 Aug 2000 14:48:49 GMT Fri, 18 Aug 2000 14:48:51 GMT Fri, 18 Aug 2000 14:48:54 GMT Fri, 18 Aug 2000 14:48:57 GMT Fri, 18 Aug 2000 14:48:59 GMT Fri, 18 Aug 2000 14:49:02 GMT Fri, 18 Aug 2000 14:49:10 GMT Fri, 18 Aug 2000 14:49:19 GMT Fri, 18 Aug 2000 14:49:21 GMT Fri, 18 Aug 2000 14:49:25 GMT Fri, 18 Aug 2000 14:49:34 GMT Fri, 18 Aug 2000 14:49:36 GMT Fri, 18 Aug 2000 14:49:38 GMT Fri, 18 Aug 2000 14:49:40 GMT Fri, 18 Aug 2000 14:49:42 GMT Fri, 18 Aug 2000 14:49:53 GMT Fri, 18 Aug 2000 14:50:09 GMT Fri, 18 Aug 2000 14:50:15 GMT Fri, 18 Aug 2000 14:50:18 GMT Fri, 18 Aug 2000 14:50:20 GMT Fri, 18 Aug 2000 14:50:25 GMT Fri, 18 Aug 2000 15:08:28 GMT Fri, 18 Aug 2000 15:09:33 GMT Fri, 18 Aug 2000 15:09:39 GMT Fri, 18 Aug 2000 15:09:41 GMT Fri, 18 Aug 2000 15:09:46 GMT Fri, 18 Aug 2000 15:09:53 GMT Fri, 18 Aug 2000 15:09:55 GMT Fri, 18 Aug 2000 15:09:58 GMT Fri, 18 Aug 2000 15:10:01 GMT Fri, 18 Aug 2000 15:10:14 GMT Fri, 18 Aug 2000 15:10:22 GMT Fri, 18 Aug 2000 15:11:39 GMT Fri, 18 Aug 2000 15:14:21 GMT Fri, 18 Aug 2000 15:14:28 GMT Fri, 18 Aug 2000 15:14:51 GMT Fri, 18 Aug 2000 15:55:09 GMT Fri, 18 Aug 2000 15:55:29 GMT Fri, 18 Aug 2000 15:56:03 GMT Fri, 18 Aug 2000 16:25:36 GMT Fri, 18 Dec 1992 01:03:26 GMT Fri, 18 Dec 1998 18:12:25 GMT Fri, 18 Dec 1998 21:56:21 GMT Fri, 18 Dec 1998 23:00:00 GMT Fri, 18 Feb 2000 00:13:04 GMT Fri, 18 Feb 2000 01:23:30 GMT Fri, 18 Feb 2000 04:35:20 GMT Fri, 18 Feb 2000 11:48:26 GMT Fri, 18 Feb 2000 13:40:17 GMT Fri, 18 Feb 2000 13:44:30 GMT Fri, 18 Feb 2000 14:25:32 GMT Fri, 18 Feb 2000 18:07:43 GMT Fri, 18 Feb 2000 20:41:47 GMT Fri, 18 Feb 2000 22:50:03 GMT Fri, 18 Feb 2000 22:55:53 GMT Fri, 18 Feb 2000 23:28:29 GMT Fri, 18 Jun 1999 00:00:11 GMT Fri, 18 Jun 1999 08:49:50 GMT Fri, 18 Jun 1999 08:49:55 GMT Fri, 18 Jun 1999 08:50:04 GMT Fri, 18 Jun 1999 08:50:09 GMT Fri, 18 Oct 1991 15:06:43 GMT Fri, 18 Oct 1996 08:53:20 GMT Fri, 19 Mar 1999 14:00:18 GMT Fri, 19 Mar 1999 14:01:00 GMT Fri, 19 Mar 1999 18:50:03 GMT Fri, 19 May 1995 09:36:27 GMT Fri, 19 May 2000 17:19:43 GMT Fri, 19 May 2000 19:58:48 GMT Fri, 19 May 2000 20:24:50 GMT Fri, 19 May 2000 21:21:27 GMT Fri, 19 Nov 1999 02:36:28 GMT Fri, 19 Nov 1999 03:25:28 GMT Fri, 19 Nov 1999 03:37:03 GMT Fri, 19 Nov 1999 05:03:01 GMT Fri, 19 Nov 1999 13:12:58 GMT Fri, 19 Nov 1999 15:56:16 GMT Fri, 19 Nov 1999 15:56:22 GMT Fri, 19 Nov 1999 18:42:03 GMT Fri, 19 Nov 1999 19:33:29 GMT Fri, 19 Nov 1999 23:31:26 GMT Fri, 20 Aug 1999 07:29:13 GMT Fri, 20 Aug 1999 07:59:02 GMT Fri, 20 Aug 1999 08:06:20 GMT Fri, 20 Aug 1999 08:20:28 GMT Fri, 20 Aug 1999 19:55:49 GMT Fri, 20 Aug 1999 19:56:35 GMT Fri, 20 Aug 1999 19:57:16 GMT Fri, 20 Aug 1999 19:59:28 GMT Fri, 20 Aug 1999 19:59:50 GMT Fri, 20 Aug 1999 20:00:44 GMT Fri, 20 Aug 1999 20:28:47 GMT Fri, 20 Feb 1998 19:40:35 GMT Fri, 20 Jun 1997 10:37:46 GMT Fri, 20 Nov 1998 16:58:21 GMT Fri, 20 Nov 1998 19:43:55 GMT Fri, 21 Apr 2000 18:21:23 GMT Fri, 21 Apr 2000 23:57:59 GMT Fri, 21 Feb 1997 11:49:55 GMT Fri, 21 Jan 2000 12:16:36 GMT Fri, 21 Jan 2000 13:02:34 GMT Fri, 21 Jan 2000 16:04:15 GMT Fri, 21 Jan 2000 17:05:32 GMT Fri, 21 Jan 2000 17:48:12 GMT Fri, 21 Jan 2000 20:45:20 GMT Fri, 21 Jul 2000 02:10:05 GMT Fri, 21 Jul 2000 05:21:22 GMT Fri, 21 Jul 2000 06:13:44 GMT Fri, 21 Jul 2000 06:22:12 GMT Fri, 21 Jul 2000 06:23:58 GMT Fri, 21 Jul 2000 06:33:46 GMT Fri, 21 Jul 2000 06:34:16 GMT Fri, 21 Jul 2000 06:36:54 GMT Fri, 21 Jul 2000 06:38:58 GMT Fri, 21 Jul 2000 06:41:46 GMT Fri, 21 Jul 2000 06:43:40 GMT Fri, 21 Jul 2000 10:34:18 GMT Fri, 21 Jul 2000 10:36:11 GMT Fri, 21 Jul 2000 13:44:42 GMT Fri, 21 Jul 2000 20:49:22 GMT Fri, 21 Jul 2000 22:05:55 GMT Fri, 21 Jul 2000 22:15:18 GMT Fri, 21 Jun 1996 22:55:09 GMT Fri, 21 Mar 1997 18:27:22 GMT Fri, 21 May 1999 04:50:47 GMT Fri, 21 May 1999 07:23:00 GMT Fri, 21 May 1999 22:00:00 GMT Fri, 22 Dec 1989 19:17:07 GMT Fri, 22 Jan 1993 07:35:22 GMT Fri, 22 Mar 1991 00:00:00 GMT Fri, 22 May 1998 18:42:20 GMT Fri, 22 Nov 1996 10:03:43 GMT Fri, 22 Oct 1999 07:54:57 GMT Fri, 22 Sep 2000 04:08:01 GMT Fri, 22 Sep 2000 04:35:03 GMT Fri, 22 Sep 2000 10:59:53 GMT Fri, 22 Sep 2000 11:18:27 GMT Fri, 22 Sep 2000 11:19:24 GMT Fri, 22 Sep 2000 12:01:49 GMT Fri, 22 Sep 2000 12:10:52 GMT Fri, 22 Sep 2000 12:12:32 GMT Fri, 22 Sep 2000 12:14:57 GMT Fri, 22 Sep 2000 12:22:52 GMT Fri, 22 Sep 2000 12:24:42 GMT Fri, 22 Sep 2000 12:24:49 GMT Fri, 22 Sep 2000 12:26:11 GMT Fri, 22 Sep 2000 12:32:56 GMT Fri, 22 Sep 2000 12:34:43 GMT Fri, 22 Sep 2000 12:35:10 GMT Fri, 22 Sep 2000 12:37:51 GMT Fri, 22 Sep 2000 13:08:45 GMT Fri, 22 Sep 2000 13:08:47 GMT Fri, 22 Sep 2000 13:08:49 GMT Fri, 22 Sep 2000 13:08:51 GMT Fri, 22 Sep 2000 13:08:53 GMT Fri, 22 Sep 2000 13:08:57 GMT Fri, 22 Sep 2000 13:09:01 GMT Fri, 22 Sep 2000 13:09:09 GMT Fri, 22 Sep 2000 13:09:11 GMT Fri, 22 Sep 2000 13:09:15 GMT Fri, 22 Sep 2000 13:12:24 GMT Fri, 22 Sep 2000 13:41:55 GMT Fri, 22 Sep 2000 13:42:37 GMT Fri, 22 Sep 2000 13:43:17 GMT Fri, 22 Sep 2000 13:43:50 GMT Fri, 22 Sep 2000 13:54:19 GMT Fri, 22 Sep 2000 14:00:55 GMT Fri, 22 Sep 2000 14:01:49 GMT Fri, 22 Sep 2000 14:02:52 GMT Fri, 22 Sep 2000 14:02:54 GMT Fri, 22 Sep 2000 14:04:28 GMT Fri, 22 Sep 2000 14:12:37 GMT Fri, 22 Sep 2000 14:16:00 GMT Fri, 22 Sep 2000 14:18:50 GMT Fri, 22 Sep 2000 14:34:17 GMT Fri, 22 Sep 2000 14:35:18 GMT Fri, 22 Sep 2000 14:40:13 GMT Fri, 22 Sep 2000 14:41:25 GMT Fri, 22 Sep 2000 15:03:29 GMT Fri, 22 Sep 2000 15:04:23 GMT Fri, 22 Sep 2000 15:13:29 GMT Fri, 22 Sep 2000 15:16:19 GMT Fri, 22 Sep 2000 18:53:00 GMT Fri, 22 Sep 2000 23:36:58 GMT Fri, 22 Sep 2000 23:48:57 GMT Fri, 22 Sep 2000 23:49:00 GMT Fri, 22 Sep 2000 23:49:02 GMT Fri, 22 Sep 2000 23:49:09 GMT Fri, 22 Sep 2000 23:49:31 GMT Fri, 23 Apr 1999 02:24:52 GMT Fri, 23 Apr 1999 02:45:19 GMT Fri, 23 Apr 1999 12:45:12 GMT Fri, 23 Feb 1996 16:59:20 GMT Fri, 23 Feb 1996 17:01:11 GMT Fri, 23 Feb 1996 17:17:22 GMT Fri, 23 Feb 1996 18:26:03 GMT Fri, 23 Feb 1996 19:48:05 GMT Fri, 23 Feb 1996 20:42:32 GMT Fri, 23 Jul 1999 17:32:47 GMT Fri, 23 Jul 1999 19:32:16 GMT Fri, 23 Jun 2000 00:00:14 GMT Fri, 23 Jun 2000 03:19:17 GMT Fri, 23 Jun 2000 04:40:32 GMT Fri, 23 Jun 2000 04:49:14 GMT Fri, 23 Jun 2000 04:56:49 GMT Fri, 23 Jun 2000 04:56:53 GMT Fri, 23 Jun 2000 04:57:28 GMT Fri, 23 Jun 2000 05:15:02 GMT Fri, 23 Jun 2000 08:00:07 GMT Fri, 23 Jun 2000 15:03:01 GMT Fri, 23 Jun 2000 15:08:44 GMT Fri, 23 Jun 2000 15:09:04 GMT Fri, 23 Jun 2000 15:09:46 GMT Fri, 23 Jun 2000 15:11:54 GMT Fri, 23 Jun 2000 15:12:11 GMT Fri, 23 Jun 2000 15:12:13 GMT Fri, 23 Jun 2000 15:12:18 GMT Fri, 23 Jun 2000 16:37:49 GMT Fri, 23 Jun 2000 21:13:14 GMT Fri, 23 Jun 2000 21:14:04 GMT Fri, 23 Jun 2000 21:14:17 GMT Fri, 23 Jun 2000 21:44:41 GMT Fri, 23 Jun 2000 21:44:45 GMT Fri, 23 Jun 2000 21:44:47 GMT Fri, 23 Oct 1998 10:08:06 GMT Fri, 24 Apr 1998 18:24:56 GMT Fri, 24 Dec 1999 04:11:43 GMT Fri, 24 Dec 1999 06:09:22 GMT Fri, 24 Dec 1999 23:13:55 GMT Fri, 24 Feb 1995 19:38:27 GMT Fri, 24 Jul 1998 18:10:16 GMT Fri, 24 Mar 2000 00:44:27 GMT Fri, 24 Mar 2000 08:28:44 GMT Fri, 24 Mar 2000 11:07:12 GMT Fri, 24 Mar 2000 11:54:54 GMT Fri, 24 Mar 2000 12:03:30 GMT Fri, 24 Mar 2000 12:08:08 GMT Fri, 24 Mar 2000 12:18:16 GMT Fri, 24 Mar 2000 16:01:13 GMT Fri, 24 Mar 2000 16:01:37 GMT Fri, 24 Mar 2000 16:01:55 GMT Fri, 24 Mar 2000 16:01:57 GMT Fri, 24 Mar 2000 16:05:58 GMT Fri, 24 Mar 2000 17:00:57 GMT Fri, 24 Nov 1995 18:56:51 GMT Fri, 24 Sep 1999 02:23:58 GMT Fri, 24 Sep 1999 23:47:00 GMT Fri, 25 Aug 1989 14:41:08 GMT Fri, 25 Aug 1989 14:41:17 GMT Fri, 25 Aug 1989 14:41:26 GMT Fri, 25 Aug 1989 14:41:47 GMT Fri, 25 Aug 1989 14:41:58 GMT Fri, 25 Aug 1989 14:42:20 GMT Fri, 25 Aug 2000 07:12:20 GMT Fri, 25 Aug 2000 14:30:55 GMT Fri, 25 Aug 2000 14:30:57 GMT Fri, 25 Aug 2000 14:37:42 GMT Fri, 25 Aug 2000 14:37:54 GMT Fri, 25 Aug 2000 14:38:05 GMT Fri, 25 Aug 2000 14:38:07 GMT Fri, 25 Aug 2000 14:39:54 GMT Fri, 25 Aug 2000 14:39:56 GMT Fri, 25 Aug 2000 14:39:59 GMT Fri, 25 Aug 2000 14:40:02 GMT Fri, 25 Aug 2000 14:40:08 GMT Fri, 25 Aug 2000 14:40:26 GMT Fri, 25 Aug 2000 14:40:38 GMT Fri, 25 Aug 2000 14:40:54 GMT Fri, 25 Aug 2000 14:41:12 GMT Fri, 25 Aug 2000 14:41:26 GMT Fri, 25 Aug 2000 14:41:49 GMT Fri, 25 Aug 2000 14:42:04 GMT Fri, 25 Aug 2000 14:42:18 GMT Fri, 25 Aug 2000 14:42:27 GMT Fri, 25 Aug 2000 14:42:42 GMT Fri, 25 Aug 2000 14:42:56 GMT Fri, 25 Aug 2000 14:43:06 GMT Fri, 25 Aug 2000 14:43:27 GMT Fri, 25 Aug 2000 14:43:40 GMT Fri, 25 Aug 2000 14:43:44 GMT Fri, 25 Aug 2000 14:44:03 GMT Fri, 25 Aug 2000 14:44:18 GMT Fri, 25 Aug 2000 14:44:32 GMT Fri, 25 Aug 2000 14:44:43 GMT Fri, 25 Aug 2000 14:44:51 GMT Fri, 25 Aug 2000 14:45:14 GMT Fri, 25 Aug 2000 14:45:18 GMT Fri, 25 Aug 2000 14:45:32 GMT Fri, 25 Aug 2000 14:45:50 GMT Fri, 25 Aug 2000 14:46:03 GMT Fri, 25 Aug 2000 14:46:17 GMT Fri, 25 Aug 2000 14:46:39 GMT Fri, 25 Aug 2000 14:46:45 GMT Fri, 25 Aug 2000 14:46:58 GMT Fri, 25 Aug 2000 14:47:10 GMT Fri, 25 Aug 2000 14:47:23 GMT Fri, 25 Aug 2000 14:47:26 GMT Fri, 25 Aug 2000 14:47:46 GMT Fri, 25 Aug 2000 14:47:55 GMT Fri, 25 Aug 2000 14:48:06 GMT Fri, 25 Aug 2000 14:48:11 GMT Fri, 25 Aug 2000 14:48:38 GMT Fri, 25 Aug 2000 14:48:45 GMT Fri, 25 Aug 2000 14:48:49 GMT Fri, 25 Aug 2000 15:07:05 GMT Fri, 25 Aug 2000 15:07:07 GMT Fri, 25 Aug 2000 15:07:09 GMT Fri, 25 Aug 2000 15:07:16 GMT Fri, 25 Aug 2000 15:07:32 GMT Fri, 25 Aug 2000 15:07:51 GMT Fri, 25 Aug 2000 15:07:59 GMT Fri, 25 Aug 2000 15:08:06 GMT Fri, 25 Aug 2000 15:08:16 GMT Fri, 25 Aug 2000 15:08:43 GMT Fri, 25 Aug 2000 15:08:52 GMT Fri, 25 Aug 2000 15:09:00 GMT Fri, 25 Aug 2000 15:09:03 GMT Fri, 25 Aug 2000 15:09:08 GMT Fri, 25 Aug 2000 15:09:17 GMT Fri, 25 Aug 2000 15:09:31 GMT Fri, 25 Aug 2000 15:09:39 GMT Fri, 25 Aug 2000 15:09:59 GMT Fri, 25 Aug 2000 15:10:09 GMT Fri, 25 Aug 2000 15:10:14 GMT Fri, 25 Aug 2000 15:10:23 GMT Fri, 25 Aug 2000 15:10:30 GMT Fri, 25 Aug 2000 15:10:49 GMT Fri, 25 Aug 2000 15:11:06 GMT Fri, 25 Aug 2000 15:11:10 GMT Fri, 25 Aug 2000 15:11:20 GMT Fri, 25 Aug 2000 15:11:31 GMT Fri, 25 Aug 2000 15:11:48 GMT Fri, 25 Aug 2000 15:11:57 GMT Fri, 25 Aug 2000 15:11:59 GMT Fri, 25 Aug 2000 15:12:08 GMT Fri, 25 Aug 2000 15:12:18 GMT Fri, 25 Aug 2000 15:12:45 GMT Fri, 25 Aug 2000 15:12:57 GMT Fri, 25 Aug 2000 15:12:59 GMT Fri, 25 Aug 2000 15:13:01 GMT Fri, 25 Aug 2000 15:13:09 GMT Fri, 25 Aug 2000 15:13:14 GMT Fri, 25 Aug 2000 15:13:22 GMT Fri, 25 Aug 2000 15:13:24 GMT Fri, 25 Aug 2000 15:13:30 GMT Fri, 25 Aug 2000 15:13:33 GMT Fri, 25 Aug 2000 15:13:35 GMT Fri, 25 Aug 2000 15:13:37 GMT Fri, 25 Aug 2000 18:57:31 GMT Fri, 25 Feb 1994 13:07:10 GMT Fri, 25 Feb 1994 13:12:08 GMT Fri, 25 Feb 1994 13:17:40 GMT Fri, 25 Feb 1994 13:20:21 GMT Fri, 25 Feb 1994 13:22:48 GMT Fri, 25 Feb 1994 13:25:46 GMT Fri, 25 Feb 1994 13:29:08 GMT Fri, 25 Feb 1994 13:32:08 GMT Fri, 25 Feb 1994 13:37:34 GMT Fri, 25 Feb 1994 13:41:47 GMT Fri, 25 Feb 1994 13:44:10 GMT Fri, 25 Feb 1994 13:47:02 GMT Fri, 25 Feb 1994 13:53:15 GMT Fri, 25 Feb 1994 13:59:44 GMT Fri, 25 Feb 1994 14:03:03 GMT Fri, 25 Feb 1994 14:05:22 GMT Fri, 25 Feb 1994 14:23:23 GMT Fri, 25 Feb 1994 14:34:44 GMT Fri, 25 Feb 1994 14:39:57 GMT Fri, 25 Feb 1994 14:44:28 GMT Fri, 25 Feb 1994 14:52:35 GMT Fri, 25 Feb 1994 15:00:28 GMT Fri, 25 Feb 1994 15:20:56 GMT Fri, 25 Feb 1994 15:25:28 GMT Fri, 25 Feb 1994 15:28:12 GMT Fri, 25 Feb 1994 15:29:33 GMT Fri, 25 Feb 1994 15:30:52 GMT Fri, 25 Feb 1994 15:32:15 GMT Fri, 25 Feb 1994 15:33:30 GMT Fri, 25 Feb 1994 15:35:59 GMT Fri, 25 Feb 1994 15:39:51 GMT Fri, 25 Feb 1994 15:42:32 GMT Fri, 25 Feb 1994 15:43:58 GMT Fri, 25 Feb 1994 15:46:41 GMT Fri, 25 Feb 1994 15:51:44 GMT Fri, 25 Feb 1994 15:55:07 GMT Fri, 25 Feb 1994 15:56:18 GMT Fri, 25 Feb 1994 16:03:36 GMT Fri, 25 Feb 1994 16:17:48 GMT Fri, 25 Feb 1994 16:26:51 GMT Fri, 25 Feb 1994 16:31:34 GMT Fri, 25 Feb 1994 16:37:01 GMT Fri, 25 Feb 1994 16:43:32 GMT Fri, 25 Feb 2000 04:01:03 GMT Fri, 25 Feb 2000 06:12:57 GMT Fri, 25 Feb 2000 06:36:05 GMT Fri, 25 Feb 2000 06:43:13 GMT Fri, 25 Feb 2000 06:44:47 GMT Fri, 25 Feb 2000 06:49:19 GMT Fri, 25 Feb 2000 06:51:08 GMT Fri, 25 Feb 2000 06:52:30 GMT Fri, 25 Feb 2000 06:53:35 GMT Fri, 25 Feb 2000 08:45:52 GMT Fri, 25 Feb 2000 08:47:39 GMT Fri, 25 Feb 2000 11:57:32 GMT Fri, 25 Feb 2000 18:28:13 GMT Fri, 25 Feb 2000 18:32:09 GMT Fri, 25 Feb 2000 19:56:44 GMT Fri, 25 Feb 2000 23:16:37 GMT Fri, 25 Oct 1996 17:46:06 GMT Fri, 26 Apr 1996 09:12:35 GMT Fri, 26 Dec 1997 23:00:00 GMT Fri, 26 Feb 1999 06:17:18 GMT Fri, 26 Feb 1999 08:30:59 GMT Fri, 26 Feb 1999 18:21:38 GMT Fri, 26 Jul 1991 12:39:08 GMT Fri, 26 Jul 1996 15:38:49 GMT Fri, 26 Jul 1996 15:39:09 GMT Fri, 26 Jul 1996 15:40:08 GMT Fri, 26 Jul 1996 15:40:24 GMT Fri, 26 Jul 1996 15:40:41 GMT Fri, 26 Jul 1996 15:41:05 GMT Fri, 26 Jul 1996 15:41:16 GMT Fri, 26 Jul 1996 15:41:29 GMT Fri, 26 Jul 1996 15:41:40 GMT Fri, 26 Jul 1996 15:41:50 GMT Fri, 26 Jul 1996 15:42:18 GMT Fri, 26 Jul 1996 15:42:43 GMT Fri, 26 Jul 1996 15:43:12 GMT Fri, 26 Jul 1996 15:43:40 GMT Fri, 26 Jul 1996 15:43:50 GMT Fri, 26 Jul 1996 15:44:01 GMT Fri, 26 Jul 1996 15:44:16 GMT Fri, 26 Jul 1996 15:44:26 GMT Fri, 26 Jul 1996 15:44:35 GMT Fri, 26 Jul 1996 15:44:48 GMT Fri, 26 Jul 1996 15:44:59 GMT Fri, 26 Jul 1996 15:45:09 GMT Fri, 26 Jul 1996 15:45:19 GMT Fri, 26 Jul 1996 15:45:28 GMT Fri, 26 Jul 1996 15:45:40 GMT Fri, 26 Jul 1996 15:45:55 GMT Fri, 26 Jul 1996 15:46:13 GMT Fri, 26 Jul 1996 15:46:26 GMT Fri, 26 Jul 1996 15:46:37 GMT Fri, 26 Jul 1996 15:46:47 GMT Fri, 26 Jul 1996 15:46:56 GMT Fri, 26 Jul 1996 15:47:06 GMT Fri, 26 Jul 1996 15:47:15 GMT Fri, 26 Jul 1996 15:47:28 GMT Fri, 26 Jul 1996 15:47:37 GMT Fri, 26 Jul 1996 15:47:45 GMT Fri, 26 Jul 1996 15:47:53 GMT Fri, 26 Jul 1996 15:48:02 GMT Fri, 26 Jul 1996 15:48:11 GMT Fri, 26 Jul 1996 15:48:20 GMT Fri, 26 Jul 1996 15:48:29 GMT Fri, 26 Jul 1996 15:48:38 GMT Fri, 26 Jul 1996 15:48:51 GMT Fri, 26 Jul 1996 15:49:01 GMT Fri, 26 Jul 1996 15:49:48 GMT Fri, 26 Jul 1996 15:50:27 GMT Fri, 26 Jul 1996 15:50:36 GMT Fri, 26 Jul 1996 15:50:59 GMT Fri, 26 Jul 1996 15:51:10 GMT Fri, 26 Jul 1996 15:51:25 GMT Fri, 26 Jun 1998 20:42:57 GMT Fri, 26 May 2000 01:08:38 GMT Fri, 26 May 2000 01:16:51 GMT Fri, 26 May 2000 01:45:49 GMT Fri, 26 May 2000 02:04:22 GMT Fri, 26 May 2000 02:04:24 GMT Fri, 26 May 2000 02:04:26 GMT Fri, 26 May 2000 02:04:28 GMT Fri, 26 May 2000 02:04:34 GMT Fri, 26 May 2000 05:29:49 GMT Fri, 26 May 2000 06:00:34 GMT Fri, 26 May 2000 06:11:05 GMT Fri, 26 May 2000 06:53:04 GMT Fri, 26 May 2000 12:31:04 GMT Fri, 26 May 2000 12:48:18 GMT Fri, 26 May 2000 14:14:59 GMT Fri, 26 May 2000 16:15:42 GMT Fri, 26 May 2000 16:16:50 GMT Fri, 26 May 2000 17:42:57 GMT Fri, 26 May 2000 18:05:53 GMT Fri, 26 May 2000 23:13:32 GMT Fri, 27 Aug 1999 03:46:38 GMT Fri, 27 Aug 1999 11:08:59 GMT Fri, 27 Aug 1999 13:03:01 GMT Fri, 27 Aug 1999 17:18:17 GMT Fri, 27 Mar 1998 23:34:59 GMT Fri, 27 Sep 1996 16:40:54 GMT Fri, 27 Sep 1996 16:43:39 GMT Fri, 28 Apr 2000 02:02:16 GMT Fri, 28 Apr 2000 02:02:19 GMT Fri, 28 Apr 2000 02:03:07 GMT Fri, 28 Apr 2000 02:03:16 GMT Fri, 28 Apr 2000 02:03:22 GMT Fri, 28 Apr 2000 02:03:24 GMT Fri, 28 Apr 2000 02:03:39 GMT Fri, 28 Apr 2000 02:03:45 GMT Fri, 28 Apr 2000 05:58:49 GMT Fri, 28 Apr 2000 06:36:31 GMT Fri, 28 Apr 2000 08:20:01 GMT Fri, 28 Apr 2000 10:17:02 GMT Fri, 28 Apr 2000 14:03:13 GMT Fri, 28 Apr 2000 17:01:48 GMT Fri, 28 Apr 2000 17:03:24 GMT Fri, 28 Apr 2000 17:03:26 GMT Fri, 28 Apr 2000 17:03:28 GMT Fri, 28 Aug 1998 02:33:08 GMT Fri, 28 Aug 1998 06:55:56 GMT Fri, 28 Aug 1998 06:56:22 GMT Fri, 28 Jan 2000 00:56:07 GMT Fri, 28 Jan 2000 13:56:32 GMT Fri, 28 Jan 2000 15:13:43 GMT Fri, 28 Jan 2000 20:10:02 GMT Fri, 28 Jan 2000 23:11:48 GMT Fri, 28 Jan 2000 23:50:40 GMT Fri, 28 Jul 2000 06:48:38 GMT Fri, 28 Jul 2000 18:50:20 GMT Fri, 28 Jul 2000 20:31:42 GMT Fri, 28 Jul 2000 21:27:34 GMT Fri, 28 Jul 2000 21:27:36 GMT Fri, 28 Jul 2000 21:27:38 GMT Fri, 28 Jul 2000 21:27:40 GMT Fri, 28 Jul 2000 22:03:43 GMT Fri, 28 Jul 2000 22:03:47 GMT Fri, 28 Jul 2000 22:03:56 GMT Fri, 28 Jul 2000 22:04:00 GMT Fri, 28 Jul 2000 22:04:11 GMT Fri, 28 May 1999 09:03:29 GMT Fri, 28 May 1999 09:07:51 GMT Fri, 28 May 1999 09:11:21 GMT Fri, 28 May 1999 15:35:38 GMT Fri, 28 May 1999 15:37:28 GMT Fri, 29 Aug 1997 11:36:09 GMT Fri, 29 Oct 1999 06:08:03 GMT Fri, 29 Oct 1999 18:42:57 GMT Fri, 29 Oct 1999 20:58:59 GMT Fri, 29 Oct 1999 21:29:53 GMT Fri, 30 Jan 1998 01:26:31 GMT Fri, 30 Jun 1995 12:30:56 GMT Fri, 30 Jun 2000 01:56:03 GMT Fri, 30 Jun 2000 06:02:26 GMT Fri, 30 Jun 2000 06:02:29 GMT Fri, 30 Jun 2000 12:25:48 GMT Fri, 30 Jun 2000 12:37:04 GMT Fri, 30 Jun 2000 14:13:36 GMT Fri, 30 Jun 2000 14:53:19 GMT Fri, 30 Jun 2000 16:04:08 GMT Fri, 30 Jun 2000 23:50:33 GMT Fri, 30 Jun 2000 23:50:37 GMT Fri, 30 Jun 2000 23:52:58 GMT Fri, 30 May 1997 04:53:05 GMT Fri, 30 May 1997 04:53:12 GMT Fri, 30 May 1997 13:02:00 GMT Fri, 30 Oct 1998 10:43:16 GMT Fri, 31 Jul 1998 19:53:37 GMT Fri, 31 Mar 2000 00:37:46 GMT Fri, 31 Mar 2000 05:45:28 GMT Fri, 31 Mar 2000 08:56:57 GMT Fri, 31 Oct 1997 07:11:37 GMT Fri, 31 Oct 1997 12:55:04 GMT Mon, 01 Dec 1997 18:34:12 GMT Mon, 01 Dec 1997 18:45:24 GMT Mon, 01 Feb 1999 12:42:56 GMT Mon, 01 Feb 1999 21:48:52 GMT Mon, 01 Jul 1996 18:08:04 GMT Mon, 01 Jul 1996 18:17:13 GMT Mon, 01 Mar 1999 21:03:06 GMT Mon, 01 May 2000 00:30:58 GMT Mon, 01 May 2000 05:31:08 GMT Mon, 01 May 2000 05:38:17 GMT Mon, 01 May 2000 05:51:06 GMT Mon, 01 May 2000 10:54:09 GMT Mon, 01 May 2000 16:30:55 GMT Mon, 01 May 2000 18:24:35 GMT Mon, 01 May 2000 18:24:37 GMT Mon, 01 May 2000 18:24:39 GMT Mon, 01 May 2000 18:24:45 GMT Mon, 01 May 2000 18:24:48 GMT Mon, 01 May 2000 18:24:57 GMT Mon, 01 May 2000 18:24:59 GMT Mon, 01 May 2000 18:25:03 GMT Mon, 01 May 2000 18:25:05 GMT Mon, 01 May 2000 18:25:08 GMT Mon, 01 May 2000 18:25:10 GMT Mon, 01 May 2000 18:25:13 GMT Mon, 01 May 2000 18:25:16 GMT Mon, 01 May 2000 18:25:19 GMT Mon, 01 May 2000 18:25:31 GMT Mon, 01 May 2000 18:25:40 GMT Mon, 01 May 2000 18:25:42 GMT Mon, 01 May 2000 18:25:44 GMT Mon, 01 May 2000 18:25:48 GMT Mon, 01 May 2000 18:25:52 GMT Mon, 01 May 2000 18:26:12 GMT Mon, 01 May 2000 18:26:14 GMT Mon, 01 May 2000 18:26:16 GMT Mon, 01 May 2000 18:26:18 GMT Mon, 01 May 2000 18:26:20 GMT Mon, 01 May 2000 18:26:23 GMT Mon, 01 May 2000 18:26:27 GMT Mon, 01 May 2000 18:26:30 GMT Mon, 01 May 2000 18:26:34 GMT Mon, 01 May 2000 18:26:38 GMT Mon, 01 May 2000 18:26:40 GMT Mon, 01 May 2000 18:26:42 GMT Mon, 01 May 2000 18:26:58 GMT Mon, 01 May 2000 18:27:09 GMT Mon, 01 May 2000 18:27:11 GMT Mon, 01 May 2000 18:27:14 GMT Mon, 01 May 2000 18:28:53 GMT Mon, 01 May 2000 18:28:55 GMT Mon, 01 May 2000 18:28:57 GMT Mon, 01 May 2000 18:28:59 GMT Mon, 01 May 2000 18:29:01 GMT Mon, 01 May 2000 18:29:03 GMT Mon, 01 May 2000 18:29:05 GMT Mon, 01 May 2000 18:29:07 GMT Mon, 01 May 2000 18:29:09 GMT Mon, 01 May 2000 18:29:11 GMT Mon, 01 May 2000 18:30:17 GMT Mon, 01 May 2000 18:30:21 GMT Mon, 01 May 2000 18:30:29 GMT Mon, 01 May 2000 20:10:10 GMT Mon, 01 May 2000 20:37:45 GMT Mon, 01 May 2000 20:37:47 GMT Mon, 01 May 2000 20:37:49 GMT Mon, 01 May 2000 20:37:51 GMT Mon, 01 May 2000 20:37:53 GMT Mon, 01 May 2000 20:37:55 GMT Mon, 01 May 2000 20:37:57 GMT Mon, 01 May 2000 20:37:59 GMT Mon, 01 May 2000 20:38:01 GMT Mon, 01 May 2000 20:38:15 GMT Mon, 01 May 2000 21:58:21 GMT Mon, 01 May 2000 23:36:47 GMT Mon, 01 May 2000 23:36:49 GMT Mon, 01 May 2000 23:36:51 GMT Mon, 01 May 2000 23:36:53 GMT Mon, 01 May 2000 23:36:55 GMT Mon, 01 May 2000 23:36:57 GMT Mon, 01 May 2000 23:38:28 GMT Mon, 01 May 2000 23:38:30 GMT Mon, 01 May 2000 23:38:32 GMT Mon, 01 May 2000 23:38:34 GMT Mon, 01 May 2000 23:38:36 GMT Mon, 01 May 2000 23:40:05 GMT Mon, 01 May 2000 23:41:09 GMT Mon, 01 May 2000 23:41:11 GMT Mon, 01 May 2000 23:45:40 GMT Mon, 01 May 2000 23:45:45 GMT Mon, 01 May 2000 23:45:47 GMT Mon, 01 May 2000 23:45:52 GMT Mon, 01 May 2000 23:45:54 GMT Mon, 01 May 2000 23:45:57 GMT Mon, 01 May 2000 23:46:01 GMT Mon, 01 May 2000 23:46:04 GMT Mon, 01 May 2000 23:47:55 GMT Mon, 01 Nov 1999 09:24:56 GMT Mon, 01 Nov 1999 16:15:00 GMT Mon, 01 Nov 1999 23:07:14 GMT Mon, 01 Nov 1999 23:33:04 GMT Mon, 01 Nov 1999 23:33:09 GMT Mon, 01 Nov 1999 23:33:16 GMT Mon, 01 Nov 1999 23:33:21 GMT Mon, 01 Sep 1997 12:48:40 GMT Mon, 02 Aug 1999 00:42:00 GMT Mon, 02 Aug 1999 10:13:50 GMT Mon, 02 Aug 1999 17:19:52 GMT Mon, 02 Aug 1999 18:09:05 GMT Mon, 02 Feb 1998 16:43:18 GMT Mon, 02 Feb 1998 21:07:47 GMT Mon, 02 Mar 1998 05:27:24 GMT Mon, 02 Mar 1998 07:06:59 GMT Mon, 02 Mar 1998 07:08:07 GMT Mon, 02 Nov 1998 17:35:16 GMT Mon, 02 Nov 1998 21:39:53 GMT Mon, 03 Apr 1995 18:14:18 GMT Mon, 03 Apr 2000 02:31:00 GMT Mon, 03 Apr 2000 06:29:04 GMT Mon, 03 Apr 2000 10:25:07 GMT Mon, 03 Apr 2000 11:57:46 GMT Mon, 03 Apr 2000 13:03:36 GMT Mon, 03 Apr 2000 14:48:45 GMT Mon, 03 Apr 2000 16:04:18 GMT Mon, 03 Apr 2000 19:00:21 GMT Mon, 03 Aug 1998 09:15:33 GMT Mon, 03 Aug 1998 12:29:34 GMT Mon, 03 Aug 1998 12:29:48 GMT Mon, 03 Aug 1998 12:29:53 GMT Mon, 03 Aug 1998 12:29:57 GMT Mon, 03 Aug 1998 12:30:14 GMT Mon, 03 Aug 1998 12:30:23 GMT Mon, 03 Jan 2000 03:57:01 GMT Mon, 03 Jan 2000 19:15:05 GMT Mon, 03 Jul 2000 00:41:29 GMT Mon, 03 Jul 2000 13:50:54 GMT Mon, 03 Jul 2000 15:55:24 GMT Mon, 03 Jul 2000 19:12:50 GMT Mon, 03 Jul 2000 19:16:30 GMT Mon, 03 Jul 2000 19:16:32 GMT Mon, 03 Jul 2000 19:16:34 GMT Mon, 03 Jul 2000 19:16:36 GMT Mon, 03 Jul 2000 19:16:38 GMT Mon, 03 Jul 2000 19:16:40 GMT Mon, 03 Jul 2000 19:16:42 GMT Mon, 03 Jul 2000 19:16:44 GMT Mon, 03 Jul 2000 19:16:46 GMT Mon, 03 Jul 2000 19:16:48 GMT Mon, 03 Jul 2000 19:16:50 GMT Mon, 03 Jul 2000 19:16:52 GMT Mon, 03 Jul 2000 19:16:54 GMT Mon, 03 Jul 2000 19:16:56 GMT Mon, 03 Jul 2000 19:16:58 GMT Mon, 03 Jul 2000 19:17:00 GMT Mon, 03 Jul 2000 19:17:02 GMT Mon, 03 Jul 2000 19:17:04 GMT Mon, 03 Jul 2000 19:17:06 GMT Mon, 03 Jul 2000 19:17:08 GMT Mon, 03 Jul 2000 19:17:10 GMT Mon, 03 Jul 2000 19:19:50 GMT Mon, 03 Jul 2000 19:19:53 GMT Mon, 03 Jul 2000 19:49:56 GMT Mon, 03 Jul 2000 20:00:43 GMT Mon, 03 Jul 2000 20:59:32 GMT Mon, 03 Jun 1991 15:44:40 GMT Mon, 03 Jun 1996 18:00:56 GMT Mon, 03 May 1999 17:37:54 GMT Mon, 03 May 1999 21:56:06 GMT Mon, 03 May 1999 22:26:10 GMT Mon, 03 Nov 1997 18:09:13 GMT Mon, 04 Dec 1995 15:54:56 GMT Mon, 04 Jan 1999 10:58:00 GMT Mon, 04 Jan 1999 19:42:43 GMT Mon, 04 Mar 1996 20:36:02 GMT Mon, 04 May 1998 01:59:39 GMT Mon, 04 May 1998 04:21:09 GMT Mon, 04 Oct 1993 09:13:07 GMT Mon, 04 Oct 1993 09:13:10 GMT Mon, 04 Oct 1999 08:17:00 GMT Mon, 04 Sep 2000 04:35:04 GMT Mon, 04 Sep 2000 04:41:07 GMT Mon, 04 Sep 2000 11:11:23 GMT Mon, 04 Sep 2000 11:11:25 GMT Mon, 04 Sep 2000 11:11:27 GMT Mon, 04 Sep 2000 11:11:32 GMT Mon, 04 Sep 2000 13:08:28 GMT Mon, 04 Sep 2000 13:27:28 GMT Mon, 04 Sep 2000 13:28:04 GMT Mon, 04 Sep 2000 13:45:34 GMT Mon, 04 Sep 2000 13:52:23 GMT Mon, 04 Sep 2000 13:56:00 GMT Mon, 04 Sep 2000 14:07:58 GMT Mon, 04 Sep 2000 14:08:41 GMT Mon, 04 Sep 2000 14:18:26 GMT Mon, 04 Sep 2000 15:09:35 GMT Mon, 04 Sep 2000 16:31:35 GMT Mon, 04 Sep 2000 20:38:09 GMT Mon, 04 Sep 2000 20:38:59 GMT Mon, 04 Sep 2000 20:39:05 GMT Mon, 04 Sep 2000 20:55:24 GMT Mon, 05 Apr 1999 06:21:57 GMT Mon, 05 Apr 1999 06:22:20 GMT Mon, 05 Apr 1999 15:22:40 GMT Mon, 05 Jan 1998 08:06:26 GMT Mon, 05 Jul 1999 11:12:29 GMT Mon, 05 Jul 1999 21:22:47 GMT Mon, 05 Jul 1999 21:22:50 GMT Mon, 05 Jun 2000 03:47:47 GMT Mon, 05 Jun 2000 07:32:02 GMT Mon, 05 Jun 2000 08:01:01 GMT Mon, 05 Jun 2000 08:46:34 GMT Mon, 05 Jun 2000 09:31:00 GMT Mon, 05 Jun 2000 09:52:14 GMT Mon, 05 Jun 2000 13:02:44 GMT Mon, 05 Jun 2000 14:41:00 GMT Mon, 05 Jun 2000 17:42:31 GMT Mon, 05 Jun 2000 19:59:54 GMT Mon, 05 Jun 2000 21:00:23 GMT Mon, 05 Jun 2000 21:01:22 GMT Mon, 05 Jun 2000 21:02:17 GMT Mon, 05 Jun 2000 21:04:00 GMT Mon, 05 Jun 2000 21:05:34 GMT Mon, 05 Jun 2000 21:07:56 GMT Mon, 05 Jun 2000 21:07:58 GMT Mon, 05 Jun 2000 21:08:00 GMT Mon, 05 Jun 2000 21:08:02 GMT Mon, 05 Jun 2000 21:08:04 GMT Mon, 05 Jun 2000 21:08:07 GMT Mon, 05 Jun 2000 21:08:09 GMT Mon, 05 Jun 2000 21:08:11 GMT Mon, 05 Jun 2000 21:08:13 GMT Mon, 05 Jun 2000 21:08:15 GMT Mon, 05 Jun 2000 21:08:18 GMT Mon, 05 Jun 2000 21:08:20 GMT Mon, 05 Jun 2000 21:16:00 GMT Mon, 05 Jun 2000 21:16:02 GMT Mon, 05 Jun 2000 21:16:04 GMT Mon, 05 Jun 2000 21:34:42 GMT Mon, 05 Jun 2000 22:43:51 GMT Mon, 05 Jun 2000 23:33:06 GMT Mon, 05 Jun 2000 23:33:08 GMT Mon, 05 Jun 2000 23:33:14 GMT Mon, 05 Jun 2000 23:33:16 GMT Mon, 05 Jun 2000 23:45:03 GMT Mon, 05 Jun 2000 23:51:30 GMT Mon, 05 Jun 2000 23:58:16 GMT Mon, 05 Nov 1990 21:08:26 GMT Mon, 05 Oct 1998 20:54:39 GMT Mon, 06 Apr 1998 05:21:45 GMT Mon, 06 Apr 1998 05:21:47 GMT Mon, 06 Dec 1993 16:33:58 GMT Mon, 06 Dec 1999 00:47:32 GMT Mon, 06 Dec 1999 15:23:07 GMT Mon, 06 Dec 1999 15:23:22 GMT Mon, 06 Dec 1999 15:23:25 GMT Mon, 06 Dec 1999 15:23:30 GMT Mon, 06 Dec 1999 15:23:34 GMT Mon, 06 Dec 1999 15:23:37 GMT Mon, 06 Dec 1999 15:23:43 GMT Mon, 06 Dec 1999 15:23:47 GMT Mon, 06 Dec 1999 15:23:51 GMT Mon, 06 Dec 1999 15:23:57 GMT Mon, 06 Dec 1999 15:24:04 GMT Mon, 06 Dec 1999 15:24:09 GMT Mon, 06 Dec 1999 15:24:14 GMT Mon, 06 Dec 1999 15:24:28 GMT Mon, 06 Dec 1999 15:24:34 GMT Mon, 06 Dec 1999 18:19:45 GMT Mon, 06 Dec 1999 21:22:37 GMT Mon, 06 Dec 1999 21:32:59 GMT Mon, 06 Dec 1999 21:33:12 GMT Mon, 06 Dec 1999 22:16:58 GMT Mon, 06 Jul 1998 01:37:51 GMT Mon, 06 Jul 1998 13:24:00 GMT Mon, 06 Jul 1998 13:26:00 GMT Mon, 06 Jul 1998 13:28:00 GMT Mon, 06 Jun 1994 10:47:00 GMT Mon, 06 Mar 1995 14:00:38 GMT Mon, 06 Mar 2000 00:05:19 GMT Mon, 06 Mar 2000 00:12:01 GMT Mon, 06 Mar 2000 00:17:46 GMT Mon, 06 Mar 2000 00:23:15 GMT Mon, 06 Mar 2000 00:29:52 GMT Mon, 06 Mar 2000 03:11:34 GMT Mon, 06 Mar 2000 08:48:23 GMT Mon, 06 Mar 2000 08:53:06 GMT Mon, 06 Mar 2000 09:02:19 GMT Mon, 06 Mar 2000 09:04:24 GMT Mon, 06 Mar 2000 09:04:56 GMT Mon, 06 Mar 2000 09:05:02 GMT Mon, 06 Mar 2000 09:05:20 GMT Mon, 06 Mar 2000 09:18:21 GMT Mon, 06 Mar 2000 09:18:24 GMT Mon, 06 Mar 2000 09:19:18 GMT Mon, 06 Mar 2000 09:22:55 GMT Mon, 06 Mar 2000 11:31:36 GMT Mon, 06 Mar 2000 12:54:32 GMT Mon, 06 Mar 2000 13:14:01 GMT Mon, 06 Mar 2000 13:14:07 GMT Mon, 06 Mar 2000 13:14:25 GMT Mon, 06 Mar 2000 13:14:48 GMT Mon, 06 Mar 2000 13:14:57 GMT Mon, 06 Mar 2000 13:15:05 GMT Mon, 06 Mar 2000 13:15:12 GMT Mon, 06 Mar 2000 13:15:25 GMT Mon, 06 Mar 2000 13:15:35 GMT Mon, 06 Mar 2000 13:15:46 GMT Mon, 06 Mar 2000 13:15:48 GMT Mon, 06 Mar 2000 13:15:55 GMT Mon, 06 Mar 2000 13:15:57 GMT Mon, 06 Mar 2000 13:15:59 GMT Mon, 06 Mar 2000 13:16:04 GMT Mon, 06 Mar 2000 13:16:06 GMT Mon, 06 Mar 2000 13:16:10 GMT Mon, 06 Mar 2000 13:16:26 GMT Mon, 06 Mar 2000 13:16:36 GMT Mon, 06 Mar 2000 13:16:39 GMT Mon, 06 Mar 2000 13:16:41 GMT Mon, 06 Mar 2000 13:37:20 GMT Mon, 06 Mar 2000 14:24:46 GMT Mon, 06 Mar 2000 14:24:57 GMT Mon, 06 Mar 2000 14:25:21 GMT Mon, 06 Mar 2000 14:25:23 GMT Mon, 06 Mar 2000 14:25:26 GMT Mon, 06 Mar 2000 14:25:36 GMT Mon, 06 Mar 2000 14:25:53 GMT Mon, 06 Mar 2000 14:26:03 GMT Mon, 06 Mar 2000 14:26:05 GMT Mon, 06 Mar 2000 14:26:09 GMT Mon, 06 Mar 2000 14:26:11 GMT Mon, 06 Mar 2000 14:26:17 GMT Mon, 06 Mar 2000 14:26:34 GMT Mon, 06 Mar 2000 14:26:38 GMT Mon, 06 Mar 2000 14:26:47 GMT Mon, 06 Mar 2000 14:26:50 GMT Mon, 06 Mar 2000 15:07:56 GMT Mon, 06 Mar 2000 15:08:03 GMT Mon, 06 Mar 2000 15:08:17 GMT Mon, 06 Mar 2000 15:08:40 GMT Mon, 06 Mar 2000 15:08:42 GMT Mon, 06 Mar 2000 15:08:52 GMT Mon, 06 Mar 2000 15:08:54 GMT Mon, 06 Mar 2000 15:09:54 GMT Mon, 06 Mar 2000 15:10:43 GMT Mon, 06 Mar 2000 15:10:57 GMT Mon, 06 Mar 2000 15:10:59 GMT Mon, 06 Mar 2000 15:11:01 GMT Mon, 06 Mar 2000 15:12:30 GMT Mon, 06 Mar 2000 15:12:56 GMT Mon, 06 Mar 2000 15:13:15 GMT Mon, 06 Mar 2000 15:13:26 GMT Mon, 06 Mar 2000 15:23:59 GMT Mon, 06 Mar 2000 15:24:21 GMT Mon, 06 Mar 2000 15:44:40 GMT Mon, 06 Mar 2000 15:44:57 GMT Mon, 06 Mar 2000 15:45:05 GMT Mon, 06 Mar 2000 15:45:07 GMT Mon, 06 Mar 2000 15:45:17 GMT Mon, 06 Mar 2000 15:45:19 GMT Mon, 06 Mar 2000 15:45:22 GMT Mon, 06 Mar 2000 15:45:33 GMT Mon, 06 Mar 2000 15:45:38 GMT Mon, 06 Mar 2000 15:45:47 GMT Mon, 06 Mar 2000 15:46:35 GMT Mon, 06 Mar 2000 15:46:38 GMT Mon, 06 Mar 2000 15:47:21 GMT Mon, 06 Mar 2000 15:48:11 GMT Mon, 06 Mar 2000 15:49:48 GMT Mon, 06 Mar 2000 16:01:01 GMT Mon, 06 Mar 2000 16:16:45 GMT Mon, 06 Mar 2000 16:26:34 GMT Mon, 06 Mar 2000 16:28:44 GMT Mon, 06 Mar 2000 16:29:45 GMT Mon, 06 May 1996 09:26:02 GMT Mon, 06 Sep 1999 09:18:01 GMT Mon, 07 Apr 1997 18:35:31 GMT Mon, 07 Apr 1997 18:35:33 GMT Mon, 07 Aug 2000 11:27:39 GMT Mon, 07 Aug 2000 11:45:35 GMT Mon, 07 Aug 2000 11:46:34 GMT Mon, 07 Aug 2000 11:46:43 GMT Mon, 07 Aug 2000 15:40:17 GMT Mon, 07 Feb 2000 01:45:25 GMT Mon, 07 Feb 2000 02:42:40 GMT Mon, 07 Feb 2000 02:50:55 GMT Mon, 07 Feb 2000 08:12:50 GMT Mon, 07 Feb 2000 12:22:50 GMT Mon, 07 Feb 2000 13:12:31 GMT Mon, 07 Feb 2000 17:28:35 GMT Mon, 07 Feb 2000 17:53:20 GMT Mon, 07 Feb 2000 17:56:47 GMT Mon, 07 Feb 2000 18:23:53 GMT Mon, 07 Feb 2000 22:37:13 GMT Mon, 07 Jul 1997 15:18:56 GMT Mon, 07 Jul 1997 15:20:00 GMT Mon, 07 Jul 1997 18:18:37 GMT Mon, 07 Jun 1999 18:37:13 GMT Mon, 07 Oct 1996 05:55:48 GMT Mon, 07 Sep 1998 06:59:35 GMT Mon, 08 Feb 1999 19:09:35 GMT Mon, 08 Jul 1991 12:40:57 GMT Mon, 08 Jul 1996 18:23:23 GMT Mon, 08 Jul 1996 18:24:56 GMT Mon, 08 Jul 1996 18:25:35 GMT Mon, 08 Jul 1996 18:26:12 GMT Mon, 08 Jul 1996 18:26:44 GMT Mon, 08 Jul 1996 18:27:15 GMT Mon, 08 Jul 1996 18:42:20 GMT Mon, 08 Jul 1996 19:28:43 GMT Mon, 08 Jul 1996 19:29:21 GMT Mon, 08 Mar 1999 00:15:39 GMT Mon, 08 Mar 1999 12:49:01 GMT Mon, 08 Mar 1999 18:39:21 GMT Mon, 08 Mar 1999 18:46:07 GMT Mon, 08 Mar 1999 21:05:01 GMT Mon, 08 May 2000 05:40:36 GMT Mon, 08 May 2000 06:53:56 GMT Mon, 08 May 2000 08:42:51 GMT Mon, 08 May 2000 09:09:28 GMT Mon, 08 May 2000 09:09:34 GMT Mon, 08 May 2000 10:11:32 GMT Mon, 08 May 2000 10:37:12 GMT Mon, 08 May 2000 11:33:13 GMT Mon, 08 May 2000 12:01:44 GMT Mon, 08 May 2000 12:26:03 GMT Mon, 08 May 2000 12:54:30 GMT Mon, 08 May 2000 14:55:39 GMT Mon, 08 May 2000 15:52:55 GMT Mon, 08 May 2000 18:45:22 GMT Mon, 08 May 2000 20:56:52 GMT Mon, 08 May 2000 20:58:07 GMT Mon, 08 May 2000 22:50:31 GMT Mon, 08 Nov 1999 00:34:00 GMT Mon, 08 Nov 1999 12:24:28 GMT Mon, 08 Nov 1999 18:19:19 GMT Mon, 08 Nov 1999 19:03:20 GMT Mon, 08 Nov 1999 22:28:34 GMT Mon, 09 Aug 1999 00:07:01 GMT Mon, 09 Aug 1999 06:47:01 GMT Mon, 09 Aug 1999 17:23:09 GMT Mon, 09 Aug 1999 17:25:01 GMT Mon, 09 Aug 1999 18:43:49 GMT Mon, 09 Aug 1999 19:32:28 GMT Mon, 09 Feb 1998 15:35:48 GMT Mon, 09 Oct 1995 11:10:41 GMT Mon, 10 Apr 2000 02:43:51 GMT Mon, 10 Apr 2000 05:41:11 GMT Mon, 10 Apr 2000 05:43:22 GMT Mon, 10 Apr 2000 07:28:17 GMT Mon, 10 Apr 2000 07:57:58 GMT Mon, 10 Apr 2000 11:06:12 GMT Mon, 10 Apr 2000 11:50:07 GMT Mon, 10 Apr 2000 11:52:49 GMT Mon, 10 Apr 2000 13:00:00 GMT Mon, 10 Apr 2000 14:53:33 GMT Mon, 10 Apr 2000 15:07:36 GMT Mon, 10 Aug 1998 06:04:32 GMT Mon, 10 Jan 2000 01:26:48 GMT Mon, 10 Jan 2000 08:33:00 GMT Mon, 10 Jan 2000 13:13:02 GMT Mon, 10 Jan 2000 13:20:22 GMT Mon, 10 Jan 2000 13:20:32 GMT Mon, 10 Jan 2000 13:20:59 GMT Mon, 10 Jan 2000 19:32:48 GMT Mon, 10 Jan 2000 20:13:06 GMT Mon, 10 Jan 2000 20:19:09 GMT Mon, 10 Jan 2000 22:05:33 GMT Mon, 10 Jul 2000 00:29:59 GMT Mon, 10 Jul 2000 06:25:18 GMT Mon, 10 Jul 2000 09:18:01 GMT Mon, 10 Jul 2000 12:17:51 GMT Mon, 10 Jul 2000 13:58:27 GMT Mon, 10 Jul 2000 20:19:48 GMT Mon, 10 Jul 2000 22:07:47 GMT Mon, 10 Jul 2000 22:50:37 GMT Mon, 10 May 1999 01:59:34 GMT Mon, 10 May 1999 04:09:18 GMT Mon, 10 May 1999 20:00:10 GMT Mon, 10 May 1999 21:14:28 GMT Mon, 10 Nov 1997 17:40:47 GMT Mon, 11 Dec 1995 10:01:00 GMT Mon, 11 Jan 1999 10:53:07 GMT Mon, 11 Jan 1999 10:53:13 GMT Mon, 11 Jan 1999 10:53:18 GMT Mon, 11 Jan 1999 18:17:20 GMT Mon, 11 May 1998 08:26:26 GMT Mon, 11 May 1998 18:24:19 GMT Mon, 11 May 1998 19:49:02 GMT Mon, 11 Nov 1996 15:50:24 GMT Mon, 11 Oct 1999 17:04:02 GMT Mon, 11 Oct 1999 17:13:24 GMT Mon, 11 Oct 1999 17:15:40 GMT Mon, 11 Oct 1999 21:06:10 GMT Mon, 11 Oct 1999 21:48:00 GMT Mon, 11 Sep 2000 01:33:10 GMT Mon, 11 Sep 2000 01:33:22 GMT Mon, 11 Sep 2000 01:33:50 GMT Mon, 11 Sep 2000 10:04:37 GMT Mon, 11 Sep 2000 11:32:38 GMT Mon, 11 Sep 2000 11:33:18 GMT Mon, 11 Sep 2000 11:33:33 GMT Mon, 11 Sep 2000 11:33:53 GMT Mon, 11 Sep 2000 14:13:33 GMT Mon, 11 Sep 2000 14:13:39 GMT Mon, 11 Sep 2000 14:24:25 GMT Mon, 11 Sep 2000 14:31:04 GMT Mon, 11 Sep 2000 14:32:20 GMT Mon, 11 Sep 2000 14:33:18 GMT Mon, 11 Sep 2000 14:35:04 GMT Mon, 11 Sep 2000 14:36:04 GMT Mon, 11 Sep 2000 14:37:21 GMT Mon, 11 Sep 2000 14:40:10 GMT Mon, 11 Sep 2000 14:42:59 GMT Mon, 11 Sep 2000 14:43:43 GMT Mon, 11 Sep 2000 14:49:00 GMT Mon, 11 Sep 2000 18:52:00 GMT Mon, 12 Apr 1999 11:06:53 GMT Mon, 12 Apr 1999 23:18:27 GMT Mon, 12 Jan 1998 00:45:53 GMT Mon, 12 Jan 1998 21:37:26 GMT Mon, 12 Jan 1998 22:46:27 GMT Mon, 12 Jan 1998 22:51:14 GMT Mon, 12 Jan 1998 23:15:43 GMT Mon, 12 Jan 1998 23:15:45 GMT Mon, 12 Jan 1998 23:15:58 GMT Mon, 12 Jan 1998 23:18:13 GMT Mon, 12 Jan 1998 23:19:36 GMT Mon, 12 Jul 1999 06:25:04 GMT Mon, 12 Jul 1999 23:21:25 GMT Mon, 12 Jun 2000 12:02:25 GMT Mon, 12 Jun 2000 12:02:27 GMT Mon, 12 Jun 2000 14:28:01 GMT Mon, 12 Jun 2000 15:05:22 GMT Mon, 12 Jun 2000 17:12:37 GMT Mon, 12 Jun 2000 17:13:44 GMT Mon, 12 Jun 2000 17:14:33 GMT Mon, 12 Jun 2000 18:16:32 GMT Mon, 12 Jun 2000 18:17:06 GMT Mon, 12 Jun 2000 18:17:15 GMT Mon, 12 Jun 2000 18:17:19 GMT Mon, 12 Jun 2000 18:17:29 GMT Mon, 12 Jun 2000 18:22:50 GMT Mon, 12 Jun 2000 18:24:20 GMT Mon, 12 Jun 2000 18:44:05 GMT Mon, 12 Jun 2000 23:25:04 GMT Mon, 12 Oct 1998 10:08:04 GMT Mon, 12 Oct 1998 18:40:13 GMT Mon, 13 Dec 1999 06:55:54 GMT Mon, 13 Dec 1999 07:04:20 GMT Mon, 13 Dec 1999 07:30:55 GMT Mon, 13 Dec 1999 11:40:48 GMT Mon, 13 Dec 1999 11:47:06 GMT Mon, 13 Dec 1999 15:59:51 GMT Mon, 13 Dec 1999 17:33:14 GMT Mon, 13 Dec 1999 18:59:40 GMT Mon, 13 Dec 1999 21:13:57 GMT Mon, 13 Dec 1999 22:08:40 GMT Mon, 13 Jul 1998 11:32:35 GMT Mon, 13 Jul 1998 11:32:47 GMT Mon, 13 Jul 1998 11:32:49 GMT Mon, 13 Jul 1998 11:32:52 GMT Mon, 13 Jul 1998 11:32:56 GMT Mon, 13 Jun 1994 17:15:33 GMT Mon, 13 Mar 2000 08:14:07 GMT Mon, 13 Mar 2000 10:58:16 GMT Mon, 13 Mar 2000 13:23:07 GMT Mon, 13 Mar 2000 15:16:22 GMT Mon, 13 Mar 2000 16:26:27 GMT Mon, 13 Mar 2000 17:12:36 GMT Mon, 13 Mar 2000 17:22:48 GMT Mon, 13 Mar 2000 20:47:40 GMT Mon, 13 Nov 1995 08:27:00 GMT Mon, 13 Sep 1999 13:32:41 GMT Mon, 13 Sep 1999 22:00:00 GMT Mon, 14 Apr 1997 23:28:15 GMT Mon, 14 Apr 1997 23:28:19 GMT Mon, 14 Apr 1997 23:28:22 GMT Mon, 14 Aug 1995 18:28:53 GMT Mon, 14 Aug 1995 18:28:58 GMT Mon, 14 Aug 1995 18:29:03 GMT Mon, 14 Aug 1995 18:29:08 GMT Mon, 14 Aug 1995 18:29:12 GMT Mon, 14 Aug 1995 18:29:17 GMT Mon, 14 Aug 1995 18:29:21 GMT Mon, 14 Aug 1995 18:29:27 GMT Mon, 14 Aug 1995 18:29:31 GMT Mon, 14 Aug 1995 18:29:35 GMT Mon, 14 Aug 1995 18:29:39 GMT Mon, 14 Aug 1995 18:29:44 GMT Mon, 14 Aug 1995 18:29:48 GMT Mon, 14 Aug 1995 18:29:55 GMT Mon, 14 Aug 1995 18:29:59 GMT Mon, 14 Aug 1995 18:30:03 GMT Mon, 14 Aug 1995 18:30:08 GMT Mon, 14 Aug 1995 18:30:12 GMT Mon, 14 Aug 1995 18:30:16 GMT Mon, 14 Aug 1995 18:30:21 GMT Mon, 14 Aug 1995 18:30:26 GMT Mon, 14 Aug 1995 18:30:30 GMT Mon, 14 Aug 1995 18:30:35 GMT Mon, 14 Aug 1995 18:30:39 GMT Mon, 14 Aug 1995 18:30:43 GMT Mon, 14 Aug 1995 18:30:48 GMT Mon, 14 Aug 1995 18:30:53 GMT Mon, 14 Aug 1995 18:30:57 GMT Mon, 14 Aug 1995 18:31:02 GMT Mon, 14 Aug 1995 18:31:06 GMT Mon, 14 Aug 1995 18:31:11 GMT Mon, 14 Aug 1995 18:31:15 GMT Mon, 14 Aug 1995 18:31:20 GMT Mon, 14 Aug 1995 18:31:24 GMT Mon, 14 Aug 1995 18:31:29 GMT Mon, 14 Aug 1995 18:31:51 GMT Mon, 14 Aug 1995 18:31:56 GMT Mon, 14 Aug 1995 18:32:00 GMT Mon, 14 Aug 1995 18:32:05 GMT Mon, 14 Aug 1995 18:32:09 GMT Mon, 14 Aug 1995 18:32:14 GMT Mon, 14 Aug 1995 18:32:25 GMT Mon, 14 Aug 1995 18:36:29 GMT Mon, 14 Aug 1995 18:36:34 GMT Mon, 14 Aug 1995 18:36:38 GMT Mon, 14 Aug 1995 18:36:43 GMT Mon, 14 Aug 1995 18:36:48 GMT Mon, 14 Aug 1995 18:37:07 GMT Mon, 14 Aug 1995 18:37:13 GMT Mon, 14 Aug 1995 18:37:19 GMT Mon, 14 Aug 1995 18:37:24 GMT Mon, 14 Aug 1995 18:47:25 GMT Mon, 14 Aug 1995 18:47:30 GMT Mon, 14 Aug 1995 18:47:34 GMT Mon, 14 Aug 1995 18:47:39 GMT Mon, 14 Aug 1995 18:47:43 GMT Mon, 14 Aug 1995 18:47:48 GMT Mon, 14 Aug 1995 18:47:54 GMT Mon, 14 Aug 1995 18:47:58 GMT Mon, 14 Aug 1995 18:48:04 GMT Mon, 14 Aug 1995 18:48:10 GMT Mon, 14 Aug 1995 18:48:14 GMT Mon, 14 Aug 1995 18:48:20 GMT Mon, 14 Aug 1995 18:48:25 GMT Mon, 14 Aug 1995 18:48:30 GMT Mon, 14 Aug 1995 18:48:34 GMT Mon, 14 Aug 1995 18:48:39 GMT Mon, 14 Aug 1995 18:48:43 GMT Mon, 14 Aug 1995 18:48:48 GMT Mon, 14 Aug 1995 18:48:52 GMT Mon, 14 Aug 1995 18:48:57 GMT Mon, 14 Aug 1995 18:49:01 GMT Mon, 14 Aug 1995 18:49:06 GMT Mon, 14 Aug 1995 18:49:10 GMT Mon, 14 Aug 1995 18:49:15 GMT Mon, 14 Aug 1995 18:49:19 GMT Mon, 14 Aug 1995 18:49:24 GMT Mon, 14 Aug 1995 18:49:29 GMT Mon, 14 Aug 1995 18:49:34 GMT Mon, 14 Aug 1995 18:49:42 GMT Mon, 14 Aug 1995 18:49:46 GMT Mon, 14 Aug 1995 18:49:52 GMT Mon, 14 Aug 1995 18:49:57 GMT Mon, 14 Aug 1995 18:50:01 GMT Mon, 14 Aug 1995 18:50:08 GMT Mon, 14 Aug 1995 18:50:12 GMT Mon, 14 Aug 1995 18:50:17 GMT Mon, 14 Aug 1995 18:50:22 GMT Mon, 14 Aug 1995 18:50:26 GMT Mon, 14 Aug 1995 18:50:31 GMT Mon, 14 Aug 1995 18:50:35 GMT Mon, 14 Aug 1995 18:50:39 GMT Mon, 14 Aug 2000 01:36:46 GMT Mon, 14 Aug 2000 02:33:55 GMT Mon, 14 Aug 2000 02:33:58 GMT Mon, 14 Aug 2000 02:34:05 GMT Mon, 14 Aug 2000 18:51:30 GMT Mon, 14 Dec 1998 14:02:22 GMT Mon, 14 Feb 2000 00:32:51 GMT Mon, 14 Feb 2000 08:40:33 GMT Mon, 14 Feb 2000 10:17:35 GMT Mon, 14 Feb 2000 10:19:24 GMT Mon, 14 Feb 2000 12:29:45 GMT Mon, 14 Feb 2000 12:29:47 GMT Mon, 14 Feb 2000 12:30:20 GMT Mon, 14 Feb 2000 14:51:27 GMT Mon, 14 Feb 2000 15:09:27 GMT Mon, 14 Feb 2000 15:19:48 GMT Mon, 14 Feb 2000 15:29:42 GMT Mon, 14 Feb 2000 15:30:04 GMT Mon, 14 Feb 2000 15:30:23 GMT Mon, 14 Feb 2000 18:39:02 GMT Mon, 14 Feb 2000 22:09:07 GMT Mon, 14 Feb 2000 22:09:09 GMT Mon, 14 Feb 2000 22:09:16 GMT Mon, 14 Feb 2000 22:09:30 GMT Mon, 14 Feb 2000 23:26:31 GMT Mon, 14 Feb 2000 23:34:21 GMT Mon, 14 Jul 1997 23:46:00 GMT Mon, 14 Oct 1996 08:51:59 GMT Mon, 14 Sep 1998 21:12:58 GMT Mon, 15 Feb 1999 04:52:05 GMT Mon, 15 Feb 1999 20:51:07 GMT Mon, 15 Feb 1999 20:51:10 GMT Mon, 15 Feb 1999 20:51:13 GMT Mon, 15 Feb 1999 20:51:16 GMT Mon, 15 Feb 1999 20:51:19 GMT Mon, 15 Feb 1999 20:51:22 GMT Mon, 15 Feb 1999 20:51:25 GMT Mon, 15 Feb 1999 20:51:27 GMT Mon, 15 Feb 1999 20:51:30 GMT Mon, 15 Feb 1999 20:51:32 GMT Mon, 15 Feb 1999 20:51:35 GMT Mon, 15 Feb 1999 20:51:37 GMT Mon, 15 Feb 1999 20:51:40 GMT Mon, 15 Feb 1999 20:51:42 GMT Mon, 15 Feb 1999 20:51:44 GMT Mon, 15 Feb 1999 20:51:46 GMT Mon, 15 Feb 1999 20:51:48 GMT Mon, 15 Feb 1999 20:51:51 GMT Mon, 15 Feb 1999 20:51:53 GMT Mon, 15 Feb 1999 20:51:57 GMT Mon, 15 Feb 1999 20:52:00 GMT Mon, 15 Feb 1999 20:52:03 GMT Mon, 15 Feb 1999 20:52:06 GMT Mon, 15 Feb 1999 20:52:10 GMT Mon, 15 Feb 1999 20:52:12 GMT Mon, 15 Feb 1999 20:52:14 GMT Mon, 15 Feb 1999 20:52:16 GMT Mon, 15 Feb 1999 20:52:20 GMT Mon, 15 Feb 1999 20:52:58 GMT Mon, 15 Feb 1999 20:53:00 GMT Mon, 15 Feb 1999 20:53:02 GMT Mon, 15 Feb 1999 20:53:29 GMT Mon, 15 Feb 1999 20:53:31 GMT Mon, 15 Feb 1999 20:53:35 GMT Mon, 15 Feb 1999 20:53:38 GMT Mon, 15 Feb 1999 20:53:40 GMT Mon, 15 Feb 1999 20:53:42 GMT Mon, 15 Feb 1999 20:53:44 GMT Mon, 15 Feb 1999 20:53:46 GMT Mon, 15 Feb 1999 20:53:48 GMT Mon, 15 Feb 1999 20:53:50 GMT Mon, 15 Feb 1999 20:53:52 GMT Mon, 15 Feb 1999 20:54:59 GMT Mon, 15 Feb 1999 20:59:45 GMT Mon, 15 Feb 1999 20:59:57 GMT Mon, 15 Feb 1999 21:00:06 GMT Mon, 15 Feb 1999 21:00:18 GMT Mon, 15 Feb 1999 21:00:48 GMT Mon, 15 Feb 1999 21:00:55 GMT Mon, 15 Feb 1999 21:01:21 GMT Mon, 15 Feb 1999 21:01:49 GMT Mon, 15 Feb 1999 21:01:53 GMT Mon, 15 Feb 1999 21:02:07 GMT Mon, 15 Feb 1999 21:02:26 GMT Mon, 15 Feb 1999 21:02:54 GMT Mon, 15 Feb 1999 21:03:05 GMT Mon, 15 Feb 1999 21:03:18 GMT Mon, 15 Feb 1999 21:03:41 GMT Mon, 15 Feb 1999 21:04:14 GMT Mon, 15 Feb 1999 21:04:37 GMT Mon, 15 Feb 1999 21:05:05 GMT Mon, 15 Feb 1999 21:05:23 GMT Mon, 15 Feb 1999 21:05:56 GMT Mon, 15 Feb 1999 21:06:13 GMT Mon, 15 Feb 1999 21:06:40 GMT Mon, 15 Feb 1999 21:07:10 GMT Mon, 15 Feb 1999 21:07:36 GMT Mon, 15 Feb 1999 21:07:57 GMT Mon, 15 Feb 1999 21:08:02 GMT Mon, 15 Feb 1999 21:08:08 GMT Mon, 15 Feb 1999 21:09:02 GMT Mon, 15 Feb 1999 21:09:26 GMT Mon, 15 Feb 1999 21:09:33 GMT Mon, 15 Feb 1999 21:09:38 GMT Mon, 15 Feb 1999 21:09:48 GMT Mon, 15 Feb 1999 21:09:57 GMT Mon, 15 Feb 1999 21:10:11 GMT Mon, 15 Feb 1999 21:10:34 GMT Mon, 15 Feb 1999 21:10:45 GMT Mon, 15 Feb 1999 21:11:03 GMT Mon, 15 Feb 1999 21:11:19 GMT Mon, 15 Feb 1999 21:12:11 GMT Mon, 15 Feb 1999 21:12:23 GMT Mon, 15 Feb 1999 21:12:35 GMT Mon, 15 Feb 1999 21:12:53 GMT Mon, 15 Feb 1999 21:13:14 GMT Mon, 15 Feb 1999 21:13:27 GMT Mon, 15 Feb 1999 21:13:51 GMT Mon, 15 Feb 1999 21:14:13 GMT Mon, 15 Feb 1999 21:14:43 GMT Mon, 15 Feb 1999 21:14:52 GMT Mon, 15 Feb 1999 21:15:06 GMT Mon, 15 Feb 1999 21:15:29 GMT Mon, 15 Feb 1999 21:16:02 GMT Mon, 15 Feb 1999 21:16:21 GMT Mon, 15 Feb 1999 21:16:30 GMT Mon, 15 Feb 1999 21:17:05 GMT Mon, 15 Feb 1999 21:17:38 GMT Mon, 15 Feb 1999 21:17:47 GMT Mon, 15 Feb 1999 21:18:06 GMT Mon, 15 Feb 1999 21:18:26 GMT Mon, 15 Feb 1999 21:18:45 GMT Mon, 15 Feb 1999 21:19:14 GMT Mon, 15 Feb 1999 21:19:22 GMT Mon, 15 Feb 1999 21:19:47 GMT Mon, 15 Feb 1999 21:19:58 GMT Mon, 15 Feb 1999 21:20:09 GMT Mon, 15 Feb 1999 21:20:27 GMT Mon, 15 Feb 1999 21:20:51 GMT Mon, 15 Feb 1999 21:21:32 GMT Mon, 15 Feb 1999 21:21:41 GMT Mon, 15 Feb 1999 21:21:51 GMT Mon, 15 Feb 1999 21:22:00 GMT Mon, 15 Feb 1999 21:22:23 GMT Mon, 15 Feb 1999 21:22:42 GMT Mon, 15 Feb 1999 21:22:55 GMT Mon, 15 Feb 1999 21:23:05 GMT Mon, 15 Feb 1999 21:23:28 GMT Mon, 15 Feb 1999 21:24:05 GMT Mon, 15 Feb 1999 21:24:48 GMT Mon, 15 Feb 1999 21:25:09 GMT Mon, 15 Feb 1999 21:25:22 GMT Mon, 15 Feb 1999 21:25:50 GMT Mon, 15 Feb 1999 21:26:10 GMT Mon, 15 Feb 1999 21:26:22 GMT Mon, 15 Feb 1999 21:26:42 GMT Mon, 15 Feb 1999 21:26:55 GMT Mon, 15 Feb 1999 21:26:59 GMT Mon, 15 Feb 1999 21:27:03 GMT Mon, 15 Feb 1999 21:27:09 GMT Mon, 15 Feb 1999 21:27:41 GMT Mon, 15 Feb 1999 21:28:27 GMT Mon, 15 Feb 1999 21:28:54 GMT Mon, 15 Feb 1999 21:29:02 GMT Mon, 15 Feb 1999 21:29:15 GMT Mon, 15 Feb 1999 21:29:25 GMT Mon, 15 Feb 1999 21:29:55 GMT Mon, 15 Feb 1999 21:30:21 GMT Mon, 15 Feb 1999 21:30:36 GMT Mon, 15 Feb 1999 21:31:03 GMT Mon, 15 Feb 1999 21:31:18 GMT Mon, 15 Feb 1999 21:31:53 GMT Mon, 15 Feb 1999 21:32:11 GMT Mon, 15 Feb 1999 21:32:47 GMT Mon, 15 Feb 1999 21:33:16 GMT Mon, 15 Feb 1999 21:33:46 GMT Mon, 15 Feb 1999 21:33:54 GMT Mon, 15 Feb 1999 21:34:04 GMT Mon, 15 Feb 1999 21:34:29 GMT Mon, 15 Feb 1999 21:34:58 GMT Mon, 15 Feb 1999 21:35:07 GMT Mon, 15 Feb 1999 21:35:13 GMT Mon, 15 Feb 1999 21:35:27 GMT Mon, 15 Feb 1999 21:35:56 GMT Mon, 15 Feb 1999 21:36:21 GMT Mon, 15 Feb 1999 21:36:44 GMT Mon, 15 Feb 1999 21:37:08 GMT Mon, 15 Feb 1999 21:37:24 GMT Mon, 15 Feb 1999 21:37:53 GMT Mon, 15 Feb 1999 21:38:05 GMT Mon, 15 Feb 1999 21:38:11 GMT Mon, 15 Feb 1999 21:38:15 GMT Mon, 15 Feb 1999 21:38:44 GMT Mon, 15 Feb 1999 21:39:09 GMT Mon, 15 Feb 1999 21:39:44 GMT Mon, 15 Feb 1999 21:40:12 GMT Mon, 15 Feb 1999 21:40:38 GMT Mon, 15 Feb 1999 21:41:04 GMT Mon, 15 Feb 1999 21:41:30 GMT Mon, 15 Feb 1999 21:41:56 GMT Mon, 15 Feb 1999 21:42:31 GMT Mon, 15 Feb 1999 21:43:05 GMT Mon, 15 Feb 1999 21:43:25 GMT Mon, 15 Feb 1999 21:43:50 GMT Mon, 15 Feb 1999 21:44:06 GMT Mon, 15 Feb 1999 21:44:22 GMT Mon, 15 Feb 1999 21:44:44 GMT Mon, 15 Feb 1999 21:44:50 GMT Mon, 15 Feb 1999 21:45:26 GMT Mon, 15 Feb 1999 21:45:45 GMT Mon, 15 Feb 1999 21:45:50 GMT Mon, 15 Feb 1999 21:46:13 GMT Mon, 15 Feb 1999 21:46:32 GMT Mon, 15 Feb 1999 21:46:37 GMT Mon, 15 Feb 1999 21:46:56 GMT Mon, 15 Feb 1999 21:47:18 GMT Mon, 15 Feb 1999 21:47:40 GMT Mon, 15 Feb 1999 21:47:52 GMT Mon, 15 Feb 1999 21:48:20 GMT Mon, 15 Feb 1999 21:48:48 GMT Mon, 15 Feb 1999 21:49:09 GMT Mon, 15 Feb 1999 21:49:43 GMT Mon, 15 Feb 1999 21:49:49 GMT Mon, 15 Feb 1999 21:50:05 GMT Mon, 15 Feb 1999 21:50:52 GMT Mon, 15 Feb 1999 21:51:15 GMT Mon, 15 Feb 1999 21:51:37 GMT Mon, 15 Feb 1999 21:51:57 GMT Mon, 15 Feb 1999 21:52:01 GMT Mon, 15 Feb 1999 21:52:05 GMT Mon, 15 Feb 1999 21:52:17 GMT Mon, 15 Feb 1999 21:52:50 GMT Mon, 15 Feb 1999 21:53:37 GMT Mon, 15 Feb 1999 21:53:46 GMT Mon, 15 Feb 1999 21:53:50 GMT Mon, 15 Feb 1999 21:54:07 GMT Mon, 15 Feb 1999 21:54:24 GMT Mon, 15 Feb 1999 21:54:29 GMT Mon, 15 Feb 1999 21:54:35 GMT Mon, 15 Feb 1999 21:54:38 GMT Mon, 15 Feb 1999 21:54:45 GMT Mon, 15 Feb 1999 21:54:49 GMT Mon, 15 Feb 1999 21:54:57 GMT Mon, 15 Feb 1999 21:54:59 GMT Mon, 15 Feb 1999 21:55:07 GMT Mon, 15 Feb 1999 21:55:15 GMT Mon, 15 Feb 1999 21:55:22 GMT Mon, 15 Feb 1999 21:55:26 GMT Mon, 15 Feb 1999 21:55:30 GMT Mon, 15 Feb 1999 21:55:36 GMT Mon, 15 Feb 1999 21:55:42 GMT Mon, 15 Feb 1999 21:55:46 GMT Mon, 15 Feb 1999 21:55:50 GMT Mon, 15 Feb 1999 21:55:57 GMT Mon, 15 Feb 1999 21:56:02 GMT Mon, 15 Feb 1999 21:56:05 GMT Mon, 15 Feb 1999 21:56:10 GMT Mon, 15 Feb 1999 21:56:14 GMT Mon, 15 Feb 1999 21:56:18 GMT Mon, 15 Feb 1999 21:56:21 GMT Mon, 15 Feb 1999 21:56:26 GMT Mon, 15 Feb 1999 21:56:29 GMT Mon, 15 Feb 1999 21:56:32 GMT Mon, 15 Feb 1999 21:56:36 GMT Mon, 15 Feb 1999 21:56:40 GMT Mon, 15 Feb 1999 21:56:44 GMT Mon, 15 Feb 1999 21:56:54 GMT Mon, 15 Feb 1999 21:56:57 GMT Mon, 15 Feb 1999 21:57:01 GMT Mon, 15 Feb 1999 21:57:05 GMT Mon, 15 Feb 1999 21:57:16 GMT Mon, 15 Feb 1999 21:57:22 GMT Mon, 15 Feb 1999 21:57:34 GMT Mon, 15 Feb 1999 21:57:45 GMT Mon, 15 Feb 1999 21:57:52 GMT Mon, 15 Feb 1999 21:58:00 GMT Mon, 15 Feb 1999 21:58:03 GMT Mon, 15 Feb 1999 21:58:15 GMT Mon, 15 Feb 1999 21:58:20 GMT Mon, 15 Feb 1999 21:58:27 GMT Mon, 15 Feb 1999 21:58:31 GMT Mon, 15 Feb 1999 21:58:41 GMT Mon, 15 Feb 1999 21:58:51 GMT Mon, 15 Feb 1999 21:58:55 GMT Mon, 15 Feb 1999 21:58:59 GMT Mon, 15 Feb 1999 21:59:02 GMT Mon, 15 Feb 1999 21:59:05 GMT Mon, 15 Feb 1999 22:01:22 GMT Mon, 15 Feb 1999 22:01:25 GMT Mon, 15 Feb 1999 22:01:27 GMT Mon, 15 Jan 1996 05:59:13 GMT Mon, 15 Jun 1998 09:03:14 GMT Mon, 15 Mar 1999 18:01:58 GMT Mon, 15 May 2000 03:05:40 GMT Mon, 15 May 2000 03:05:42 GMT Mon, 15 May 2000 03:05:44 GMT Mon, 15 May 2000 03:05:46 GMT Mon, 15 May 2000 03:05:48 GMT Mon, 15 May 2000 03:05:50 GMT Mon, 15 May 2000 03:05:52 GMT Mon, 15 May 2000 03:05:54 GMT Mon, 15 May 2000 03:05:56 GMT Mon, 15 May 2000 07:03:37 GMT Mon, 15 May 2000 07:03:43 GMT Mon, 15 May 2000 11:51:58 GMT Mon, 15 May 2000 11:52:08 GMT Mon, 15 May 2000 11:52:13 GMT Mon, 15 May 2000 20:31:22 GMT Mon, 15 May 2000 20:53:45 GMT Mon, 15 Nov 1993 19:52:59 GMT Mon, 15 Nov 1993 19:53:18 GMT Mon, 15 Nov 1999 02:40:00 GMT Mon, 15 Nov 1999 23:19:25 GMT Mon, 16 Aug 1999 16:39:13 GMT Mon, 16 Aug 1999 17:10:29 GMT Mon, 16 Aug 1999 17:10:33 GMT Mon, 16 Dec 1996 02:58:50 GMT Mon, 16 Jun 1997 23:36:00 GMT Mon, 16 Nov 1998 18:38:09 GMT Mon, 16 Sep 1996 11:29:00 GMT Mon, 17 Apr 2000 09:29:42 GMT Mon, 17 Apr 2000 11:44:14 GMT Mon, 17 Apr 2000 11:46:08 GMT Mon, 17 Apr 2000 13:45:52 GMT Mon, 17 Apr 2000 13:56:02 GMT Mon, 17 Apr 2000 14:34:50 GMT Mon, 17 Apr 2000 15:44:09 GMT Mon, 17 Apr 2000 15:44:15 GMT Mon, 17 Apr 2000 15:44:20 GMT Mon, 17 Apr 2000 15:44:22 GMT Mon, 17 Apr 2000 15:44:24 GMT Mon, 17 Apr 2000 15:44:26 GMT Mon, 17 Apr 2000 15:44:29 GMT Mon, 17 Apr 2000 15:44:31 GMT Mon, 17 Apr 2000 15:44:33 GMT Mon, 17 Apr 2000 15:44:35 GMT Mon, 17 Apr 2000 15:44:37 GMT Mon, 17 Apr 2000 15:44:39 GMT Mon, 17 Apr 2000 15:44:41 GMT Mon, 17 Apr 2000 15:44:44 GMT Mon, 17 Apr 2000 15:44:46 GMT Mon, 17 Apr 2000 15:44:48 GMT Mon, 17 Apr 2000 15:44:50 GMT Mon, 17 Apr 2000 15:44:53 GMT Mon, 17 Apr 2000 15:44:59 GMT Mon, 17 Apr 2000 15:45:14 GMT Mon, 17 Apr 2000 17:50:40 GMT Mon, 17 Apr 2000 19:14:23 GMT Mon, 17 Apr 2000 19:17:09 GMT Mon, 17 Apr 2000 19:17:11 GMT Mon, 17 Apr 2000 19:17:13 GMT Mon, 17 Apr 2000 19:17:15 GMT Mon, 17 Apr 2000 19:17:17 GMT Mon, 17 Apr 2000 19:17:19 GMT Mon, 17 Apr 2000 19:17:21 GMT Mon, 17 Apr 2000 19:17:23 GMT Mon, 17 Apr 2000 19:17:28 GMT Mon, 17 Apr 2000 21:00:00 GMT Mon, 17 Aug 1998 12:32:45 GMT Mon, 17 Jan 2000 01:15:48 GMT Mon, 17 Jan 2000 06:04:49 GMT Mon, 17 Jan 2000 14:12:33 GMT Mon, 17 Jan 2000 16:43:33 GMT Mon, 17 Jan 2000 21:21:00 GMT Mon, 17 Jul 2000 00:15:55 GMT Mon, 17 Jul 2000 00:16:28 GMT Mon, 17 Jul 2000 01:13:10 GMT Mon, 17 Jul 2000 01:13:40 GMT Mon, 17 Jul 2000 01:38:08 GMT Mon, 17 Jul 2000 01:38:11 GMT Mon, 17 Jul 2000 01:38:13 GMT Mon, 17 Jul 2000 01:38:15 GMT Mon, 17 Jul 2000 04:28:48 GMT Mon, 17 Jul 2000 07:33:22 GMT Mon, 17 Jul 2000 07:33:38 GMT Mon, 17 Jul 2000 07:34:30 GMT Mon, 17 Jul 2000 11:36:12 GMT Mon, 17 Jul 2000 21:04:43 GMT Mon, 17 Jul 2000 23:00:28 GMT Mon, 17 Jul 2000 23:02:09 GMT Mon, 17 Mar 1997 21:57:36 GMT Mon, 17 Mar 1997 22:54:22 GMT Mon, 17 Mar 1997 22:54:31 GMT Mon, 17 May 1999 23:03:48 GMT Mon, 18 Jan 1999 02:23:01 GMT Mon, 18 Jan 1999 02:32:26 GMT Mon, 18 Jan 1999 07:32:43 GMT Mon, 18 May 1998 08:13:55 GMT Mon, 18 May 1998 08:53:55 GMT Mon, 18 May 1998 13:31:54 GMT Mon, 18 Oct 1999 18:14:58 GMT Mon, 18 Oct 1999 18:16:12 GMT Mon, 18 Oct 1999 18:26:31 GMT Mon, 18 Sep 2000 07:02:15 GMT Mon, 18 Sep 2000 11:58:13 GMT Mon, 18 Sep 2000 11:58:32 GMT Mon, 18 Sep 2000 11:58:46 GMT Mon, 18 Sep 2000 14:26:23 GMT Mon, 18 Sep 2000 14:30:46 GMT Mon, 18 Sep 2000 15:01:41 GMT Mon, 18 Sep 2000 15:02:16 GMT Mon, 18 Sep 2000 15:02:18 GMT Mon, 18 Sep 2000 15:02:20 GMT Mon, 18 Sep 2000 15:02:25 GMT Mon, 18 Sep 2000 15:02:27 GMT Mon, 18 Sep 2000 15:03:49 GMT Mon, 18 Sep 2000 15:03:51 GMT Mon, 18 Sep 2000 15:04:04 GMT Mon, 18 Sep 2000 15:04:06 GMT Mon, 18 Sep 2000 15:04:08 GMT Mon, 18 Sep 2000 15:04:10 GMT Mon, 18 Sep 2000 15:04:15 GMT Mon, 18 Sep 2000 15:04:17 GMT Mon, 18 Sep 2000 15:04:21 GMT Mon, 18 Sep 2000 15:04:27 GMT Mon, 18 Sep 2000 15:04:29 GMT Mon, 18 Sep 2000 15:04:53 GMT Mon, 18 Sep 2000 15:05:36 GMT Mon, 18 Sep 2000 15:07:11 GMT Mon, 18 Sep 2000 15:08:01 GMT Mon, 18 Sep 2000 15:08:16 GMT Mon, 18 Sep 2000 15:13:06 GMT Mon, 18 Sep 2000 15:26:23 GMT Mon, 18 Sep 2000 15:29:19 GMT Mon, 18 Sep 2000 15:29:21 GMT Mon, 18 Sep 2000 15:29:23 GMT Mon, 18 Sep 2000 15:29:25 GMT Mon, 18 Sep 2000 15:29:29 GMT Mon, 18 Sep 2000 15:29:31 GMT Mon, 18 Sep 2000 15:29:34 GMT Mon, 18 Sep 2000 15:30:02 GMT Mon, 18 Sep 2000 15:30:04 GMT Mon, 18 Sep 2000 15:30:10 GMT Mon, 18 Sep 2000 15:30:25 GMT Mon, 18 Sep 2000 15:30:27 GMT Mon, 18 Sep 2000 15:30:31 GMT Mon, 18 Sep 2000 15:32:07 GMT Mon, 18 Sep 2000 16:34:55 GMT Mon, 18 Sep 2000 17:13:16 GMT Mon, 18 Sep 2000 17:41:17 GMT Mon, 18 Sep 2000 17:41:19 GMT Mon, 18 Sep 2000 17:45:49 GMT Mon, 18 Sep 2000 18:04:37 GMT Mon, 18 Sep 2000 18:05:33 GMT Mon, 18 Sep 2000 18:05:35 GMT Mon, 18 Sep 2000 18:05:37 GMT Mon, 18 Sep 2000 18:05:39 GMT Mon, 18 Sep 2000 18:05:41 GMT Mon, 18 Sep 2000 18:05:48 GMT Mon, 18 Sep 2000 18:05:50 GMT Mon, 18 Sep 2000 18:06:00 GMT Mon, 18 Sep 2000 18:06:09 GMT Mon, 18 Sep 2000 18:06:22 GMT Mon, 18 Sep 2000 18:07:29 GMT Mon, 18 Sep 2000 18:52:00 GMT Mon, 18 Sep 2000 19:56:58 GMT Mon, 18 Sep 2000 19:58:07 GMT Mon, 18 Sep 2000 19:58:14 GMT Mon, 18 Sep 2000 19:58:40 GMT Mon, 18 Sep 2000 19:58:51 GMT Mon, 18 Sep 2000 20:23:36 GMT Mon, 18 Sep 2000 20:23:41 GMT Mon, 18 Sep 2000 20:43:27 GMT Mon, 18 Sep 2000 20:43:54 GMT Mon, 18 Sep 2000 20:45:52 GMT Mon, 18 Sep 2000 20:46:00 GMT Mon, 18 Sep 2000 20:55:12 GMT Mon, 18 Sep 2000 21:57:33 GMT Mon, 18 Sep 2000 21:57:35 GMT Mon, 18 Sep 2000 22:51:03 GMT Mon, 18 Sep 2000 23:45:27 GMT Mon, 19 Apr 1999 21:19:40 GMT Mon, 19 Jan 1998 17:21:46 GMT Mon, 19 Jul 1999 11:35:47 GMT Mon, 19 Jul 1999 11:35:50 GMT Mon, 19 Jul 1999 11:36:33 GMT Mon, 19 Jul 1999 16:52:57 GMT Mon, 19 Jul 1999 19:50:42 GMT Mon, 19 Jul 1999 22:22:48 GMT Mon, 19 Jun 2000 09:34:08 GMT Mon, 19 Jun 2000 13:42:03 GMT Mon, 19 Jun 2000 14:53:18 GMT Mon, 19 Jun 2000 15:09:48 GMT Mon, 19 Jun 2000 15:10:13 GMT Mon, 19 Jun 2000 15:35:04 GMT Mon, 19 Jun 2000 16:18:14 GMT Mon, 19 Jun 2000 20:09:21 GMT Mon, 19 Jun 2000 20:12:08 GMT Mon, 19 Jun 2000 20:12:11 GMT Mon, 19 Jun 2000 20:12:14 GMT Mon, 19 Jun 2000 20:12:21 GMT Mon, 19 Jun 2000 20:12:30 GMT Mon, 19 Jun 2000 20:14:25 GMT Mon, 19 Jun 2000 23:03:33 GMT Mon, 19 Jun 2000 23:03:38 GMT Mon, 19 Jun 2000 23:26:36 GMT Mon, 19 Jun 2000 23:37:20 GMT Mon, 19 Jun 2000 23:55:09 GMT Mon, 19 May 1997 18:00:59 GMT Mon, 20 Apr 1998 03:20:27 GMT Mon, 20 Apr 1998 05:30:30 GMT Mon, 20 Apr 1998 05:30:40 GMT Mon, 20 Apr 1998 05:30:50 GMT Mon, 20 Dec 1999 08:07:23 GMT Mon, 20 Dec 1999 14:27:10 GMT Mon, 20 Dec 1999 18:16:54 GMT Mon, 20 Dec 1999 20:19:04 GMT Mon, 20 Dec 1999 22:41:47 GMT Mon, 20 Dec 1999 22:43:40 GMT Mon, 20 Dec 1999 23:07:08 GMT Mon, 20 Jul 1992 00:00:00 GMT Mon, 20 Jul 1992 10:33:47 GMT Mon, 20 Jul 1992 10:34:11 GMT Mon, 20 Jul 1998 03:44:41 GMT Mon, 20 Jul 1998 17:05:16 GMT Mon, 20 Mar 2000 02:53:54 GMT Mon, 20 Mar 2000 09:20:32 GMT Mon, 20 Mar 2000 09:35:58 GMT Mon, 20 Mar 2000 09:36:24 GMT Mon, 20 Mar 2000 10:10:42 GMT Mon, 20 Mar 2000 10:13:32 GMT Mon, 20 Mar 2000 12:11:38 GMT Mon, 20 Mar 2000 15:14:10 GMT Mon, 20 Mar 2000 16:27:18 GMT Mon, 20 Mar 2000 19:34:19 GMT Mon, 20 May 1996 04:54:28 GMT Mon, 20 May 1996 22:00:00 GMT Mon, 20 Sep 1999 20:47:08 GMT Mon, 20 Sep 1999 22:22:30 GMT Mon, 21 Apr 1997 21:28:41 GMT Mon, 21 Aug 2000 00:30:21 GMT Mon, 21 Aug 2000 01:16:27 GMT Mon, 21 Aug 2000 01:57:38 GMT Mon, 21 Aug 2000 04:41:44 GMT Mon, 21 Aug 2000 12:57:41 GMT Mon, 21 Aug 2000 12:57:50 GMT Mon, 21 Aug 2000 12:57:55 GMT Mon, 21 Aug 2000 12:57:57 GMT Mon, 21 Aug 2000 12:58:03 GMT Mon, 21 Aug 2000 12:58:09 GMT Mon, 21 Aug 2000 12:58:11 GMT Mon, 21 Aug 2000 12:58:13 GMT Mon, 21 Aug 2000 12:58:32 GMT Mon, 21 Aug 2000 12:58:40 GMT Mon, 21 Aug 2000 12:58:42 GMT Mon, 21 Aug 2000 12:58:44 GMT Mon, 21 Aug 2000 12:58:49 GMT Mon, 21 Aug 2000 12:58:58 GMT Mon, 21 Aug 2000 13:15:44 GMT Mon, 21 Aug 2000 14:17:36 GMT Mon, 21 Aug 2000 14:25:35 GMT Mon, 21 Aug 2000 16:53:55 GMT Mon, 21 Dec 1998 11:11:40 GMT Mon, 21 Feb 2000 00:20:47 GMT Mon, 21 Feb 2000 04:16:30 GMT Mon, 21 Feb 2000 04:19:12 GMT Mon, 21 Feb 2000 04:21:25 GMT Mon, 21 Feb 2000 04:23:43 GMT Mon, 21 Feb 2000 04:32:50 GMT Mon, 21 Feb 2000 04:37:48 GMT Mon, 21 Feb 2000 04:48:08 GMT Mon, 21 Feb 2000 07:30:46 GMT Mon, 21 Feb 2000 12:50:29 GMT Mon, 21 Feb 2000 12:54:48 GMT Mon, 21 Feb 2000 18:23:31 GMT Mon, 21 Feb 2000 18:56:40 GMT Mon, 21 Feb 2000 19:04:30 GMT Mon, 21 Feb 2000 19:06:22 GMT Mon, 21 Feb 2000 19:06:31 GMT Mon, 21 Feb 2000 19:19:00 GMT Mon, 21 Feb 2000 19:27:23 GMT Mon, 21 Feb 2000 21:50:09 GMT Mon, 21 Jul 1997 19:41:21 GMT Mon, 21 Jun 1999 12:13:36 GMT Mon, 21 Jun 1999 17:48:04 GMT Mon, 21 Sep 1998 09:55:24 GMT Mon, 21 Sep 1998 17:01:05 GMT Mon, 21 Sep 1998 17:06:11 GMT Mon, 21 Sep 1998 18:09:09 GMT Mon, 22 Apr 1996 09:26:21 GMT Mon, 22 Dec 1997 01:04:48 GMT Mon, 22 Dec 1997 01:41:24 GMT Mon, 22 Dec 1997 17:26:12 GMT Mon, 22 Feb 1999 16:06:57 GMT Mon, 22 Feb 1999 16:40:02 GMT Mon, 22 Feb 1999 17:59:54 GMT Mon, 22 Feb 1999 18:12:48 GMT Mon, 22 Jul 1996 22:43:36 GMT Mon, 22 Jul 1996 22:44:01 GMT Mon, 22 Jul 1996 22:44:21 GMT Mon, 22 Jul 1996 22:56:57 GMT Mon, 22 Jul 1996 22:57:30 GMT Mon, 22 Jul 1996 22:58:05 GMT Mon, 22 Jul 1996 22:58:39 GMT Mon, 22 Jul 1996 22:59:20 GMT Mon, 22 Jul 1996 23:00:07 GMT Mon, 22 Jul 1996 23:00:58 GMT Mon, 22 Jul 1996 23:01:46 GMT Mon, 22 Jul 1996 23:02:39 GMT Mon, 22 Jul 1996 23:03:30 GMT Mon, 22 Jul 1996 23:04:22 GMT Mon, 22 Jul 1996 23:05:14 GMT Mon, 22 Jul 1996 23:05:53 GMT Mon, 22 Jul 1996 23:06:40 GMT Mon, 22 Jul 1996 23:07:19 GMT Mon, 22 Jul 1996 23:08:00 GMT Mon, 22 Jul 1996 23:08:41 GMT Mon, 22 Jul 1996 23:09:23 GMT Mon, 22 Jul 1996 23:10:03 GMT Mon, 22 Jul 1996 23:10:53 GMT Mon, 22 Jul 1996 23:11:48 GMT Mon, 22 Jul 1996 23:12:33 GMT Mon, 22 Jul 1996 23:13:07 GMT Mon, 22 Jul 1996 23:13:31 GMT Mon, 22 Jul 1996 23:13:53 GMT Mon, 22 Jul 1996 23:30:11 GMT Mon, 22 Jul 1996 23:32:01 GMT Mon, 22 Jul 1996 23:40:38 GMT Mon, 22 Jul 1996 23:41:48 GMT Mon, 22 Jul 1996 23:44:03 GMT Mon, 22 Jul 1996 23:45:37 GMT Mon, 22 Mar 1999 02:37:56 GMT Mon, 22 Mar 1999 04:53:46 GMT Mon, 22 Mar 1999 17:16:03 GMT Mon, 22 Mar 1999 17:16:27 GMT Mon, 22 Mar 1999 17:16:47 GMT Mon, 22 Mar 1999 17:17:01 GMT Mon, 22 Mar 1999 17:17:16 GMT Mon, 22 Mar 1999 17:17:48 GMT Mon, 22 Mar 1999 17:18:05 GMT Mon, 22 Mar 1999 19:20:51 GMT Mon, 22 May 2000 04:11:57 GMT Mon, 22 May 2000 07:08:18 GMT Mon, 22 May 2000 10:46:29 GMT Mon, 22 May 2000 11:50:06 GMT Mon, 22 May 2000 11:51:07 GMT Mon, 22 May 2000 11:52:12 GMT Mon, 22 May 2000 13:34:10 GMT Mon, 22 May 2000 14:14:46 GMT Mon, 22 May 2000 15:29:04 GMT Mon, 22 May 2000 16:20:33 GMT Mon, 22 May 2000 17:10:48 GMT Mon, 22 May 2000 17:31:42 GMT Mon, 22 May 2000 23:30:52 GMT Mon, 22 May 2000 23:33:55 GMT Mon, 22 May 2000 23:37:20 GMT Mon, 22 Nov 1999 01:41:43 GMT Mon, 22 Nov 1999 07:30:41 GMT Mon, 22 Nov 1999 14:19:38 GMT Mon, 22 Sep 1997 18:07:43 GMT Mon, 23 Aug 1999 11:18:05 GMT Mon, 23 Aug 1999 16:56:31 GMT Mon, 23 Aug 1999 16:56:58 GMT Mon, 23 Aug 1999 17:07:14 GMT Mon, 23 Aug 1999 17:12:38 GMT Mon, 23 Aug 1999 17:16:34 GMT Mon, 23 Aug 1999 17:41:25 GMT Mon, 23 Aug 1999 18:15:27 GMT Mon, 23 Aug 1999 20:44:03 GMT Mon, 23 Nov 1998 01:15:57 GMT Mon, 23 Sep 1996 05:38:17 GMT Mon, 24 Apr 2000 01:05:46 GMT Mon, 24 Aug 1998 13:59:15 GMT Mon, 24 Jan 2000 02:45:15 GMT Mon, 24 Jan 2000 03:49:56 GMT Mon, 24 Jan 2000 06:39:14 GMT Mon, 24 Jan 2000 14:47:46 GMT Mon, 24 Jan 2000 19:04:37 GMT Mon, 24 Jan 2000 19:54:30 GMT Mon, 24 Jul 2000 03:20:15 GMT Mon, 24 Jul 2000 03:22:35 GMT Mon, 24 Jul 2000 03:22:43 GMT Mon, 24 Jul 2000 03:23:02 GMT Mon, 24 Jul 2000 03:23:34 GMT Mon, 24 Jul 2000 06:56:19 GMT Mon, 24 Jul 2000 12:11:24 GMT Mon, 24 Jul 2000 13:48:36 GMT Mon, 24 Jul 2000 13:55:09 GMT Mon, 24 Jul 2000 19:09:25 GMT Mon, 24 Jul 2000 21:48:05 GMT Mon, 24 Jul 2000 22:20:28 GMT Mon, 24 Jul 2000 22:20:42 GMT Mon, 24 Jul 2000 23:09:30 GMT Mon, 24 Jun 1996 08:59:17 GMT Mon, 24 Jun 1996 08:59:19 GMT Mon, 24 Nov 1997 18:30:40 GMT Mon, 24 Nov 1997 20:56:21 GMT Mon, 24 Nov 1997 22:32:19 GMT Mon, 25 Jan 1999 02:36:10 GMT Mon, 25 Jan 1999 05:55:04 GMT Mon, 25 Jan 1999 20:50:32 GMT Mon, 25 Oct 1999 02:42:48 GMT Mon, 25 Oct 1999 14:00:00 GMT Mon, 25 Oct 1999 15:26:52 GMT Mon, 25 Oct 1999 17:24:20 GMT Mon, 25 Oct 1999 18:25:45 GMT Mon, 25 Oct 1999 20:49:19 GMT Mon, 25 Oct 1999 20:51:49 GMT Mon, 25 Sep 1995 06:19:08 GMT Mon, 25 Sep 2000 04:04:45 GMT Mon, 25 Sep 2000 04:08:01 GMT Mon, 25 Sep 2000 04:29:21 GMT Mon, 25 Sep 2000 04:30:16 GMT Mon, 25 Sep 2000 04:31:13 GMT Mon, 25 Sep 2000 04:31:15 GMT Mon, 25 Sep 2000 04:31:17 GMT Mon, 25 Sep 2000 04:31:19 GMT Mon, 25 Sep 2000 04:31:21 GMT Mon, 25 Sep 2000 04:31:25 GMT Mon, 25 Sep 2000 04:31:27 GMT Mon, 25 Sep 2000 04:35:03 GMT Mon, 25 Sep 2000 04:38:01 GMT Mon, 25 Sep 2000 04:40:36 GMT Mon, 25 Sep 2000 04:40:53 GMT Mon, 25 Sep 2000 10:48:20 GMT Mon, 25 Sep 2000 13:19:50 GMT Mon, 25 Sep 2000 13:19:52 GMT Mon, 25 Sep 2000 13:20:03 GMT Mon, 25 Sep 2000 13:20:05 GMT Mon, 25 Sep 2000 13:20:17 GMT Mon, 25 Sep 2000 14:40:09 GMT Mon, 25 Sep 2000 17:44:34 GMT Mon, 25 Sep 2000 18:30:19 GMT Mon, 25 Sep 2000 18:32:01 GMT Mon, 25 Sep 2000 18:55:00 GMT Mon, 25 Sep 2000 19:06:00 GMT Mon, 25 Sep 2000 19:06:24 GMT Mon, 25 Sep 2000 19:11:48 GMT Mon, 25 Sep 2000 19:14:34 GMT Mon, 25 Sep 2000 19:21:01 GMT Mon, 25 Sep 2000 19:25:07 GMT Mon, 25 Sep 2000 21:23:29 GMT Mon, 25 Sep 2000 21:48:04 GMT Mon, 25 Sep 2000 21:48:06 GMT Mon, 25 Sep 2000 21:48:12 GMT Mon, 25 Sep 2000 21:48:20 GMT Mon, 25 Sep 2000 21:48:22 GMT Mon, 25 Sep 2000 21:49:00 GMT Mon, 25 Sep 2000 21:49:19 GMT Mon, 25 Sep 2000 21:49:22 GMT Mon, 25 Sep 2000 21:49:38 GMT Mon, 25 Sep 2000 21:49:52 GMT Mon, 25 Sep 2000 21:49:54 GMT Mon, 25 Sep 2000 21:50:08 GMT Mon, 25 Sep 2000 21:50:44 GMT Mon, 25 Sep 2000 21:51:14 GMT Mon, 25 Sep 2000 21:51:16 GMT Mon, 25 Sep 2000 21:51:31 GMT Mon, 25 Sep 2000 21:51:52 GMT Mon, 25 Sep 2000 21:52:03 GMT Mon, 25 Sep 2000 21:52:44 GMT Mon, 25 Sep 2000 21:53:51 GMT Mon, 26 Apr 1999 21:17:05 GMT Mon, 26 Aug 1996 17:47:32 GMT Mon, 26 Aug 1996 19:00:56 GMT Mon, 26 Aug 1996 19:01:18 GMT Mon, 26 Aug 1996 19:01:40 GMT Mon, 26 Aug 1996 19:02:00 GMT Mon, 26 Aug 1996 19:02:16 GMT Mon, 26 Aug 1996 19:02:34 GMT Mon, 26 Jan 1998 19:43:18 GMT Mon, 26 Jul 1999 13:42:45 GMT Mon, 26 Jun 2000 05:24:11 GMT Mon, 26 Jun 2000 10:31:35 GMT Mon, 26 Jun 2000 12:32:47 GMT Mon, 26 May 1997 07:54:02 GMT Mon, 26 May 1997 09:18:00 GMT Mon, 26 May 1997 15:41:00 GMT Mon, 26 May 1997 15:44:00 GMT Mon, 26 May 1997 17:08:00 GMT Mon, 26 Oct 1998 20:16:51 GMT Mon, 27 Dec 1999 03:34:04 GMT Mon, 27 Dec 1999 16:41:54 GMT Mon, 27 Dec 1999 18:24:49 GMT Mon, 27 Dec 1999 18:24:51 GMT Mon, 27 Dec 1999 18:24:59 GMT Mon, 27 Jan 1997 08:36:13 GMT Mon, 27 Jul 1998 06:35:58 GMT Mon, 27 Mar 2000 00:56:38 GMT Mon, 27 Mar 2000 08:12:17 GMT Mon, 27 Mar 2000 08:15:28 GMT Mon, 27 Mar 2000 08:20:08 GMT Mon, 27 Mar 2000 10:00:49 GMT Mon, 27 Mar 2000 10:50:37 GMT Mon, 27 Mar 2000 11:16:47 GMT Mon, 27 Mar 2000 11:21:39 GMT Mon, 27 Mar 2000 11:30:40 GMT Mon, 27 Mar 2000 11:32:19 GMT Mon, 27 Mar 2000 11:37:18 GMT Mon, 27 Mar 2000 13:52:35 GMT Mon, 27 Mar 2000 14:00:48 GMT Mon, 27 Mar 2000 14:13:38 GMT Mon, 27 Mar 2000 14:28:27 GMT Mon, 27 Mar 2000 14:38:40 GMT Mon, 27 Mar 2000 18:31:02 GMT Mon, 27 Mar 2000 18:49:36 GMT Mon, 27 Nov 1995 13:53:44 GMT Mon, 27 Sep 1999 14:27:49 GMT Mon, 28 Aug 1995 15:56:23 GMT Mon, 28 Aug 2000 02:50:43 GMT Mon, 28 Aug 2000 02:50:46 GMT Mon, 28 Aug 2000 03:39:42 GMT Mon, 28 Aug 2000 04:38:01 GMT Mon, 28 Aug 2000 04:40:57 GMT Mon, 28 Aug 2000 09:26:58 GMT Mon, 28 Aug 2000 09:48:42 GMT Mon, 28 Aug 2000 09:48:45 GMT Mon, 28 Aug 2000 09:48:48 GMT Mon, 28 Aug 2000 09:48:51 GMT Mon, 28 Aug 2000 09:48:54 GMT Mon, 28 Aug 2000 10:40:34 GMT Mon, 28 Aug 2000 10:44:59 GMT Mon, 28 Aug 2000 10:52:15 GMT Mon, 28 Aug 2000 10:54:08 GMT Mon, 28 Aug 2000 13:18:38 GMT Mon, 28 Aug 2000 13:54:06 GMT Mon, 28 Aug 2000 15:34:52 GMT Mon, 28 Aug 2000 15:36:31 GMT Mon, 28 Feb 2000 02:45:10 GMT Mon, 28 Feb 2000 15:12:29 GMT Mon, 28 Feb 2000 15:16:54 GMT Mon, 28 Feb 2000 15:18:20 GMT Mon, 28 Feb 2000 15:20:23 GMT Mon, 28 Feb 2000 15:41:14 GMT Mon, 28 Feb 2000 15:50:08 GMT Mon, 28 Feb 2000 20:18:08 GMT Mon, 28 Feb 2000 20:21:35 GMT Mon, 28 Feb 2000 22:00:00 GMT Mon, 28 Feb 2000 22:16:37 GMT Mon, 28 Feb 2000 22:21:15 GMT Mon, 28 Feb 2000 22:52:42 GMT Mon, 28 Feb 2000 22:56:10 GMT Mon, 28 Jun 1999 13:34:29 GMT Mon, 28 Jun 1999 17:23:20 GMT Mon, 28 Jun 1999 17:23:45 GMT Mon, 28 Jun 1999 17:24:03 GMT Mon, 28 Jun 1999 17:24:19 GMT Mon, 28 Jun 1999 17:25:33 GMT Mon, 28 Jun 1999 17:27:42 GMT Mon, 28 Jun 1999 17:28:03 GMT Mon, 28 Jun 1999 17:28:33 GMT Mon, 28 Jun 1999 17:28:49 GMT Mon, 28 Jun 1999 17:29:07 GMT Mon, 28 Jun 1999 17:29:42 GMT Mon, 28 Jun 1999 17:29:58 GMT Mon, 28 Jun 1999 17:30:14 GMT Mon, 28 Jun 1999 17:30:29 GMT Mon, 28 Jun 1999 20:40:39 GMT Mon, 28 Sep 1998 00:16:58 GMT Mon, 29 Mar 1999 19:16:51 GMT Mon, 29 Mar 1999 20:11:07 GMT Mon, 29 Mar 1999 20:20:27 GMT Mon, 29 Mar 1999 20:20:48 GMT Mon, 29 May 2000 02:53:58 GMT Mon, 29 May 2000 02:55:52 GMT Mon, 29 May 2000 06:44:37 GMT Mon, 29 May 2000 08:52:46 GMT Mon, 29 May 2000 09:12:39 GMT Mon, 29 May 2000 12:44:53 GMT Mon, 29 May 2000 16:17:43 GMT Mon, 29 May 2000 16:47:01 GMT Mon, 29 May 2000 17:12:13 GMT Mon, 29 May 2000 19:21:35 GMT Mon, 29 May 2000 19:52:59 GMT Mon, 29 May 2000 21:27:49 GMT Mon, 29 May 2000 21:28:12 GMT Mon, 29 May 2000 21:28:14 GMT Mon, 29 May 2000 21:28:16 GMT Mon, 29 May 2000 21:28:18 GMT Mon, 29 May 2000 21:28:24 GMT Mon, 29 May 2000 21:28:32 GMT Mon, 29 May 2000 21:28:39 GMT Mon, 29 May 2000 21:28:51 GMT Mon, 29 May 2000 22:52:38 GMT Mon, 29 Nov 1999 01:55:39 GMT Mon, 29 Nov 1999 02:27:55 GMT Mon, 29 Nov 1999 02:40:30 GMT Mon, 29 Nov 1999 09:16:57 GMT Mon, 29 Nov 1999 13:17:14 GMT Mon, 29 Nov 1999 16:56:44 GMT Mon, 29 Nov 1999 18:59:31 GMT Mon, 29 Nov 1999 22:22:33 GMT Mon, 29 Nov 1999 23:01:08 GMT Mon, 30 Aug 1999 02:58:57 GMT Mon, 30 Aug 1999 12:09:49 GMT Mon, 30 Aug 1999 17:23:14 GMT Mon, 30 Aug 1999 17:26:28 GMT Mon, 30 Aug 1999 17:43:25 GMT Mon, 30 Dec 1996 10:00:02 GMT Mon, 30 Dec 1996 11:01:10 GMT Mon, 30 Mar 1998 13:55:00 GMT Mon, 30 Mar 1998 19:58:02 GMT Mon, 30 Nov 1998 03:59:36 GMT Mon, 30 Nov 1998 06:59:54 GMT Mon, 30 Nov 1998 07:03:38 GMT Mon, 30 Nov 1998 07:11:29 GMT Mon, 30 Sep 1996 14:42:43 GMT Mon, 31 Jan 1994 16:46:03 GMT Mon, 31 Jan 2000 05:44:39 GMT Mon, 31 Jan 2000 05:53:43 GMT Mon, 31 Jan 2000 05:56:04 GMT Mon, 31 Jan 2000 06:01:45 GMT Mon, 31 Jan 2000 06:04:08 GMT Mon, 31 Jan 2000 06:12:00 GMT Mon, 31 Jan 2000 06:12:02 GMT Mon, 31 Jan 2000 06:25:48 GMT Mon, 31 Jan 2000 06:27:27 GMT Mon, 31 Jan 2000 07:50:08 GMT Mon, 31 Jan 2000 14:57:16 GMT Mon, 31 Jan 2000 16:52:58 GMT Mon, 31 Jan 2000 18:13:03 GMT Mon, 31 Jan 2000 18:29:16 GMT Mon, 31 Jan 2000 18:32:53 GMT Mon, 31 Jan 2000 19:23:45 GMT Mon, 31 Jan 2000 20:12:24 GMT Mon, 31 Jan 2000 23:23:27 GMT Mon, 31 Jul 2000 17:06:07 GMT Mon, 31 Jul 2000 17:59:57 GMT Mon, 31 Jul 2000 20:45:40 GMT Mon, 31 Jul 2000 21:44:58 GMT Mon, 31 Jul 2000 22:17:06 GMT Mon, 31 Jul 2000 22:17:19 GMT Mon, 31 Jul 2000 22:17:29 GMT Mon, 31 Jul 2000 22:17:39 GMT Mon, 31 Jul 2000 22:17:52 GMT Mon, 31 Jul 2000 22:18:10 GMT Mon, 31 Jul 2000 22:43:13 GMT Mon, 31 Jul 2000 23:52:25 GMT Mon, 31 Jul 2000 23:52:42 GMT Mon, 31 Mar 1997 10:01:52 GMT Mon, 31 May 1999 05:17:14 GMT Mon, 31 May 1999 10:56:24 GMT Mon, 31 May 1999 10:56:26 GMT Mon, 31 May 1999 19:32:21 GMT Mon, 31 May 1999 19:34:08 GMT Mon, 31 May 1999 19:34:12 GMT Mon, 31 Oct 1994 08:00:00 GMT Sat, 01 Apr 2000 00:27:21 GMT Sat, 01 Jan 2000 00:10:29 GMT Sat, 01 Jul 2000 00:37:35 GMT Sat, 01 Jul 2000 00:37:38 GMT Sat, 01 Jul 2000 00:43:03 GMT Sat, 01 Jul 2000 10:25:24 GMT Sat, 01 Jun 1996 16:29:01 GMT Sat, 01 Oct 1994 16:56:43 GMT Sat, 02 Dec 1995 01:30:00 GMT Sat, 02 May 1998 00:45:10 GMT Sat, 02 Oct 1999 14:35:15 GMT Sat, 02 Oct 1999 14:49:30 GMT Sat, 02 Oct 1999 23:46:41 GMT Sat, 02 Sep 2000 15:46:09 GMT Sat, 02 Sep 2000 15:46:12 GMT Sat, 03 Apr 1999 17:19:49 GMT Sat, 03 Apr 1999 19:54:01 GMT Sat, 03 Apr 1999 21:57:18 GMT Sat, 03 Jan 1998 01:47:13 GMT Sat, 03 Jul 1999 12:06:24 GMT Sat, 03 Jun 2000 11:12:40 GMT Sat, 03 Jun 2000 14:13:01 GMT Sat, 03 Jun 2000 14:46:27 GMT Sat, 03 Jun 2000 14:46:29 GMT Sat, 03 Jun 2000 14:46:32 GMT Sat, 03 Jun 2000 14:46:34 GMT Sat, 03 Jun 2000 14:46:37 GMT Sat, 03 Jun 2000 14:46:39 GMT Sat, 03 Jun 2000 14:46:41 GMT Sat, 03 Jun 2000 14:46:45 GMT Sat, 03 Jun 2000 14:46:47 GMT Sat, 03 Jun 2000 14:46:50 GMT Sat, 03 Jun 2000 14:46:52 GMT Sat, 03 Jun 2000 14:46:54 GMT Sat, 03 Jun 2000 14:55:02 GMT Sat, 03 Jun 2000 15:08:13 GMT Sat, 03 Jun 2000 15:10:43 GMT Sat, 03 Jun 2000 15:23:41 GMT Sat, 03 Jun 2000 15:23:43 GMT Sat, 03 Jun 2000 15:24:47 GMT Sat, 03 Jun 2000 22:03:21 GMT Sat, 03 Nov 1990 00:42:14 GMT Sat, 04 Apr 1998 02:17:18 GMT Sat, 04 Apr 1998 02:17:20 GMT Sat, 04 Apr 1998 02:17:25 GMT Sat, 04 Apr 1998 02:20:44 GMT Sat, 04 Apr 1998 02:20:47 GMT Sat, 04 Apr 1998 02:20:49 GMT Sat, 04 Apr 1998 02:20:51 GMT Sat, 04 Apr 1998 02:20:53 GMT Sat, 04 Apr 1998 02:20:55 GMT Sat, 04 Apr 1998 02:20:57 GMT Sat, 04 Apr 1998 02:20:59 GMT Sat, 04 Apr 1998 02:21:03 GMT Sat, 04 Apr 1998 02:21:08 GMT Sat, 04 Apr 1998 02:21:15 GMT Sat, 04 Apr 1998 02:21:17 GMT Sat, 04 Apr 1998 02:21:22 GMT Sat, 04 Apr 1998 02:21:25 GMT Sat, 04 Apr 1998 02:21:29 GMT Sat, 04 Apr 1998 02:21:35 GMT Sat, 04 Apr 1998 02:21:37 GMT Sat, 04 Apr 1998 02:21:39 GMT Sat, 04 Apr 1998 02:21:41 GMT Sat, 04 Apr 1998 02:21:45 GMT Sat, 04 Apr 1998 02:22:13 GMT Sat, 04 Apr 1998 02:22:15 GMT Sat, 04 Apr 1998 02:22:17 GMT Sat, 04 Apr 1998 02:22:19 GMT Sat, 04 Apr 1998 02:22:27 GMT Sat, 04 Apr 1998 02:22:31 GMT Sat, 04 Apr 1998 02:22:45 GMT Sat, 04 Apr 1998 02:22:47 GMT Sat, 04 Apr 1998 02:22:49 GMT Sat, 04 Apr 1998 02:22:52 GMT Sat, 04 Apr 1998 02:22:54 GMT Sat, 04 Apr 1998 02:22:58 GMT Sat, 04 Apr 1998 02:23:07 GMT Sat, 04 Apr 1998 02:23:17 GMT Sat, 04 Apr 1998 02:23:19 GMT Sat, 04 Apr 1998 02:23:21 GMT Sat, 04 Apr 1998 02:23:23 GMT Sat, 04 Apr 1998 02:23:25 GMT Sat, 04 Apr 1998 02:23:27 GMT Sat, 04 Apr 1998 02:23:35 GMT Sat, 04 Apr 1998 02:23:39 GMT Sat, 04 Apr 1998 02:23:41 GMT Sat, 04 Apr 1998 02:24:00 GMT Sat, 04 Apr 1998 02:24:06 GMT Sat, 04 Apr 1998 02:24:35 GMT Sat, 04 Apr 1998 02:24:41 GMT Sat, 04 Dec 1999 08:30:56 GMT Sat, 04 Dec 1999 13:41:02 GMT Sat, 04 Dec 1999 13:41:15 GMT Sat, 04 Mar 2000 00:34:58 GMT Sat, 04 Mar 2000 00:37:36 GMT Sat, 04 Mar 2000 05:01:35 GMT Sat, 04 Mar 2000 07:55:13 GMT Sat, 04 Mar 2000 11:32:38 GMT Sat, 04 Mar 2000 16:04:53 GMT Sat, 04 Mar 2000 16:05:11 GMT Sat, 04 Mar 2000 18:26:56 GMT Sat, 04 Sep 1999 19:38:05 GMT Sat, 04 Sep 1999 20:06:08 GMT Sat, 04 Sep 1999 20:08:32 GMT Sat, 04 Sep 1999 20:10:30 GMT Sat, 05 Aug 2000 00:21:06 GMT Sat, 05 Aug 2000 00:22:47 GMT Sat, 05 Aug 2000 00:28:39 GMT Sat, 05 Aug 2000 00:34:39 GMT Sat, 05 Aug 2000 01:23:22 GMT Sat, 05 Aug 2000 10:53:32 GMT Sat, 05 Aug 2000 10:53:34 GMT Sat, 05 Aug 2000 12:08:58 GMT Sat, 05 Aug 2000 12:17:53 GMT Sat, 05 Aug 2000 13:38:07 GMT Sat, 05 Aug 2000 14:04:15 GMT Sat, 05 Aug 2000 14:10:46 GMT Sat, 05 Aug 2000 14:18:26 GMT Sat, 05 Aug 2000 20:49:41 GMT Sat, 05 Aug 2000 20:49:43 GMT Sat, 05 Feb 2000 08:09:02 GMT Sat, 05 Feb 2000 12:01:52 GMT Sat, 05 Feb 2000 12:33:16 GMT Sat, 05 Jun 1999 09:44:56 GMT Sat, 05 Jun 1999 13:54:38 GMT Sat, 05 Jun 1999 13:58:54 GMT Sat, 05 Jun 1999 14:30:34 GMT Sat, 05 Jun 1999 15:48:10 GMT Sat, 05 Jun 1999 18:32:00 GMT Sat, 05 Jun 1999 19:10:05 GMT Sat, 06 Feb 1999 11:58:02 GMT Sat, 06 Feb 1999 23:00:00 GMT Sat, 06 Jul 1996 21:06:17 GMT Sat, 06 Mar 1999 12:56:37 GMT Sat, 06 Mar 1999 22:16:55 GMT Sat, 06 May 2000 06:11:51 GMT Sat, 06 May 2000 06:11:53 GMT Sat, 06 May 2000 16:20:43 GMT Sat, 06 May 2000 16:21:55 GMT Sat, 06 May 2000 18:38:40 GMT Sat, 06 Nov 1999 03:31:48 GMT Sat, 06 Nov 1999 03:39:41 GMT Sat, 06 Nov 1999 18:38:40 GMT Sat, 06 Nov 1999 19:17:56 GMT Sat, 06 Nov 1999 19:19:15 GMT Sat, 06 Nov 1999 19:19:22 GMT Sat, 06 Oct 1990 04:23:29 GMT Sat, 07 Aug 1999 23:00:45 GMT Sat, 07 Feb 1998 11:40:22 GMT Sat, 07 Mar 1998 15:15:44 GMT Sat, 08 Apr 2000 11:27:23 GMT Sat, 08 Apr 2000 12:56:47 GMT Sat, 08 Apr 2000 13:51:08 GMT Sat, 08 Apr 2000 16:30:01 GMT Sat, 08 Apr 2000 16:32:55 GMT Sat, 08 Apr 2000 16:48:08 GMT Sat, 08 Aug 1998 05:27:43 GMT Sat, 08 Aug 1998 17:05:04 GMT Sat, 08 Feb 1997 17:22:05 GMT Sat, 08 Jan 2000 02:11:45 GMT Sat, 08 Jan 2000 03:10:13 GMT Sat, 08 Jan 2000 05:56:18 GMT Sat, 08 Jan 2000 20:50:16 GMT Sat, 08 Jan 2000 20:59:39 GMT Sat, 08 Jul 2000 03:21:20 GMT Sat, 08 Jul 2000 03:21:22 GMT Sat, 08 Jul 2000 22:13:12 GMT Sat, 08 Mar 1997 15:14:31 GMT Sat, 08 May 1999 11:01:12 GMT Sat, 08 May 1999 12:05:25 GMT Sat, 08 May 1999 18:06:57 GMT Sat, 09 Jan 1999 21:49:25 GMT Sat, 09 Nov 1996 08:11:36 GMT Sat, 09 Nov 1996 08:12:01 GMT Sat, 09 Nov 1996 08:12:05 GMT Sat, 09 Nov 1996 08:12:08 GMT Sat, 09 Nov 1996 08:12:10 GMT Sat, 09 Nov 1996 08:29:08 GMT Sat, 09 Nov 1996 08:29:16 GMT Sat, 09 Nov 1996 08:29:21 GMT Sat, 09 Nov 1996 08:29:35 GMT Sat, 09 Nov 1996 08:29:41 GMT Sat, 09 Nov 1996 08:29:46 GMT Sat, 09 Nov 1996 08:29:59 GMT Sat, 09 Nov 1996 08:30:07 GMT Sat, 09 Nov 1996 08:30:13 GMT Sat, 09 Nov 1996 08:30:19 GMT Sat, 09 Nov 1996 08:30:27 GMT Sat, 09 Nov 1996 19:40:09 GMT Sat, 09 Oct 1999 19:05:02 GMT Sat, 09 Sep 2000 08:58:25 GMT Sat, 09 Sep 2000 17:01:59 GMT Sat, 09 Sep 2000 17:02:55 GMT Sat, 09 Sep 2000 18:52:00 GMT Sat, 10 Apr 1999 09:26:56 GMT Sat, 10 Apr 1999 21:51:06 GMT Sat, 10 Jul 1999 04:46:40 GMT Sat, 10 Jun 2000 17:21:26 GMT Sat, 10 Jun 2000 17:52:41 GMT Sat, 10 Jun 2000 23:39:45 GMT Sat, 11 Apr 1998 18:13:25 GMT Sat, 11 Jan 1997 16:12:00 GMT Sat, 11 Mar 2000 09:25:34 GMT Sat, 11 Mar 2000 09:25:36 GMT Sat, 11 Mar 2000 09:25:38 GMT Sat, 11 Mar 2000 09:25:40 GMT Sat, 11 Nov 1995 11:04:14 GMT Sat, 11 Sep 1999 07:06:28 GMT Sat, 11 Sep 1999 18:35:03 GMT Sat, 12 Aug 1989 23:00:00 GMT Sat, 12 Aug 2000 04:12:28 GMT Sat, 12 Aug 2000 04:14:55 GMT Sat, 12 Aug 2000 06:51:07 GMT Sat, 12 Aug 2000 06:51:14 GMT Sat, 12 Aug 2000 09:20:00 GMT Sat, 12 Aug 2000 12:21:18 GMT Sat, 12 Aug 2000 12:59:03 GMT Sat, 12 Aug 2000 18:31:02 GMT Sat, 12 Aug 2000 20:20:54 GMT Sat, 12 Aug 2000 20:24:15 GMT Sat, 12 Aug 2000 20:28:34 GMT Sat, 12 Aug 2000 20:30:28 GMT Sat, 12 Aug 2000 21:13:22 GMT Sat, 12 Aug 2000 21:35:19 GMT Sat, 12 Aug 2000 23:33:20 GMT Sat, 12 Feb 2000 00:10:03 GMT Sat, 12 Feb 2000 03:58:01 GMT Sat, 12 Feb 2000 14:03:28 GMT Sat, 12 Feb 2000 14:45:49 GMT Sat, 12 Feb 2000 17:50:29 GMT Sat, 12 Feb 2000 17:52:58 GMT Sat, 12 Feb 2000 21:52:50 GMT Sat, 12 Feb 2000 23:45:05 GMT Sat, 12 Nov 1994 10:45:04 GMT Sat, 13 Feb 1999 02:47:17 GMT Sat, 13 Feb 1999 02:50:55 GMT Sat, 13 Feb 1999 21:16:02 GMT Sat, 13 Feb 1999 21:39:30 GMT Sat, 13 Jun 1998 19:08:19 GMT Sat, 13 Jun 1998 20:11:12 GMT Sat, 13 Jun 1998 20:14:32 GMT Sat, 13 Jun 1998 20:25:12 GMT Sat, 13 Jun 1998 20:32:34 GMT Sat, 13 May 2000 02:23:46 GMT Sat, 13 May 2000 04:10:54 GMT Sat, 13 May 2000 04:12:43 GMT Sat, 13 May 2000 04:12:45 GMT Sat, 13 May 2000 04:12:47 GMT Sat, 13 May 2000 04:19:08 GMT Sat, 13 May 2000 04:19:21 GMT Sat, 13 May 2000 04:19:32 GMT Sat, 13 May 2000 04:19:45 GMT Sat, 13 May 2000 06:24:38 GMT Sat, 13 May 2000 06:25:02 GMT Sat, 13 May 2000 06:25:10 GMT Sat, 13 Nov 1999 11:04:00 GMT Sat, 13 Nov 1999 16:24:46 GMT Sat, 13 Nov 1999 21:18:11 GMT Sat, 13 Sep 1997 18:07:29 GMT Sat, 14 Aug 1999 08:35:47 GMT Sat, 14 Aug 1999 09:38:20 GMT Sat, 14 Nov 1998 12:54:02 GMT Sat, 14 Nov 1998 12:54:08 GMT Sat, 14 Nov 1998 13:00:46 GMT Sat, 14 Nov 1998 13:00:52 GMT Sat, 14 Nov 1998 13:10:00 GMT Sat, 14 Nov 1998 13:14:54 GMT Sat, 14 Nov 1998 13:15:00 GMT Sat, 14 Nov 1998 13:18:22 GMT Sat, 14 Nov 1998 13:24:24 GMT Sat, 14 Nov 1998 13:36:48 GMT Sat, 15 Apr 2000 04:43:06 GMT Sat, 15 Apr 2000 04:44:21 GMT Sat, 15 Apr 2000 04:44:38 GMT Sat, 15 Apr 2000 16:19:38 GMT Sat, 15 Jan 2000 01:56:38 GMT Sat, 15 Jan 2000 10:46:14 GMT Sat, 15 Jan 2000 11:35:54 GMT Sat, 15 Jan 2000 12:09:57 GMT Sat, 15 Jan 2000 12:09:59 GMT Sat, 15 Jan 2000 12:10:10 GMT Sat, 15 Jan 2000 12:10:14 GMT Sat, 15 Jan 2000 12:10:20 GMT Sat, 15 Jan 2000 12:10:23 GMT Sat, 15 Jan 2000 12:10:29 GMT Sat, 15 Jan 2000 12:10:32 GMT Sat, 15 Jan 2000 12:10:37 GMT Sat, 15 Jan 2000 12:10:39 GMT Sat, 15 Jan 2000 12:10:41 GMT Sat, 15 Jan 2000 12:10:49 GMT Sat, 15 Jan 2000 12:10:51 GMT Sat, 15 Jan 2000 12:10:56 GMT Sat, 15 Jan 2000 12:11:00 GMT Sat, 15 Jan 2000 12:11:02 GMT Sat, 15 Jan 2000 12:11:17 GMT Sat, 15 Jan 2000 16:40:42 GMT Sat, 15 Jan 2000 21:32:34 GMT Sat, 15 Jan 2000 23:57:42 GMT Sat, 15 Jul 2000 15:50:54 GMT Sat, 15 Jul 2000 18:04:04 GMT Sat, 15 Jul 2000 18:31:49 GMT Sat, 15 Jul 2000 21:18:21 GMT Sat, 15 Jul 2000 21:18:32 GMT Sat, 15 May 1999 18:12:09 GMT Sat, 15 May 1999 22:05:36 GMT Sat, 15 Oct 1994 08:50:22 GMT Sat, 16 Aug 1997 16:51:09 GMT Sat, 16 Jan 1999 02:25:39 GMT Sat, 16 Jan 1999 22:00:48 GMT Sat, 16 Oct 1999 01:55:26 GMT Sat, 16 Oct 1999 20:56:07 GMT Sat, 16 Sep 2000 12:35:43 GMT Sat, 16 Sep 2000 12:36:40 GMT Sat, 16 Sep 2000 12:36:43 GMT Sat, 16 Sep 2000 12:36:57 GMT Sat, 17 Jan 1998 01:34:06 GMT Sat, 17 Jun 2000 03:06:34 GMT Sat, 17 Jun 2000 03:09:36 GMT Sat, 17 Jun 2000 03:17:12 GMT Sat, 17 Jun 2000 03:22:38 GMT Sat, 17 Jun 2000 03:22:42 GMT Sat, 17 Jun 2000 03:24:49 GMT Sat, 17 Jun 2000 03:25:42 GMT Sat, 17 Jun 2000 03:51:12 GMT Sat, 17 Jun 2000 03:51:14 GMT Sat, 17 Jun 2000 07:46:43 GMT Sat, 17 Jun 2000 14:37:28 GMT Sat, 17 Jun 2000 14:37:30 GMT Sat, 17 Jun 2000 14:41:10 GMT Sat, 17 Jun 2000 15:41:56 GMT Sat, 17 Jun 2000 16:32:28 GMT Sat, 17 Jun 2000 17:02:47 GMT Sat, 17 Jun 2000 17:21:33 GMT Sat, 17 Jun 2000 17:21:53 GMT Sat, 17 Jun 2000 17:29:37 GMT Sat, 17 Jun 2000 17:29:55 GMT Sat, 17 Jun 2000 17:29:57 GMT Sat, 17 Jun 2000 17:30:04 GMT Sat, 17 Jun 2000 17:40:10 GMT Sat, 17 Jun 2000 17:52:12 GMT Sat, 17 Jun 2000 17:52:14 GMT Sat, 17 Jun 2000 17:52:16 GMT Sat, 17 Jun 2000 17:52:19 GMT Sat, 17 Jun 2000 17:52:22 GMT Sat, 17 Jun 2000 17:52:24 GMT Sat, 17 Jun 2000 17:52:27 GMT Sat, 17 Jun 2000 17:52:32 GMT Sat, 17 Jun 2000 17:52:34 GMT Sat, 17 Jun 2000 17:52:36 GMT Sat, 17 Jun 2000 17:52:38 GMT Sat, 17 Jun 2000 17:52:40 GMT Sat, 17 Jun 2000 17:52:42 GMT Sat, 17 Jun 2000 17:52:44 GMT Sat, 17 Jun 2000 17:52:47 GMT Sat, 17 Jun 2000 17:52:50 GMT Sat, 17 Jun 2000 17:52:52 GMT Sat, 17 Jun 2000 17:52:55 GMT Sat, 17 Jun 2000 17:52:57 GMT Sat, 17 Jun 2000 17:53:03 GMT Sat, 17 Jun 2000 17:53:15 GMT Sat, 17 Jun 2000 18:50:44 GMT Sat, 17 Jun 2000 20:37:20 GMT Sat, 17 Jun 2000 21:10:36 GMT Sat, 17 Jun 2000 21:10:39 GMT Sat, 17 Jun 2000 21:11:03 GMT Sat, 17 Jun 2000 21:11:05 GMT Sat, 17 Jun 2000 21:18:12 GMT Sat, 17 Jun 2000 21:18:48 GMT Sat, 17 Jun 2000 21:23:18 GMT Sat, 17 Jun 2000 21:23:20 GMT Sat, 17 Jun 2000 21:30:23 GMT Sat, 17 Jun 2000 21:30:35 GMT Sat, 17 Jun 2000 21:32:01 GMT Sat, 17 Oct 1998 04:42:30 GMT Sat, 18 Apr 1998 23:46:37 GMT Sat, 18 Dec 1993 01:05:30 GMT Sat, 18 Dec 1999 13:14:05 GMT Sat, 18 Dec 1999 23:43:16 GMT Sat, 18 Jul 1998 14:30:06 GMT Sat, 18 Jul 1998 14:33:44 GMT Sat, 18 Jul 1998 14:33:48 GMT Sat, 18 Jul 1998 18:55:22 GMT Sat, 18 Jul 1998 18:55:24 GMT Sat, 18 Jul 1998 21:11:41 GMT Sat, 18 Jul 1998 21:15:20 GMT Sat, 18 Mar 2000 07:57:12 GMT Sat, 18 Mar 2000 17:58:14 GMT Sat, 18 Mar 2000 17:58:44 GMT Sat, 18 Mar 2000 18:14:11 GMT Sat, 18 Nov 1995 19:11:28 GMT Sat, 19 Aug 2000 11:59:10 GMT Sat, 19 Aug 2000 12:07:48 GMT Sat, 19 Aug 2000 12:08:07 GMT Sat, 19 Aug 2000 12:52:37 GMT Sat, 19 Aug 2000 14:50:37 GMT Sat, 19 Aug 2000 14:57:50 GMT Sat, 19 Aug 2000 18:54:00 GMT Sat, 19 Aug 2000 20:35:00 GMT Sat, 19 Aug 2000 20:35:43 GMT Sat, 19 Aug 2000 20:35:45 GMT Sat, 19 Feb 2000 00:37:02 GMT Sat, 19 Feb 2000 22:12:11 GMT Sat, 19 Oct 1991 04:33:44 GMT Sat, 19 Sep 1998 20:29:02 GMT Sat, 19 Sep 1998 20:31:47 GMT Sat, 19 Sep 1998 20:31:49 GMT Sat, 19 Sep 1998 20:31:51 GMT Sat, 19 Sep 1998 20:31:53 GMT Sat, 19 Sep 1998 20:31:55 GMT Sat, 19 Sep 1998 20:31:57 GMT Sat, 19 Sep 1998 20:31:59 GMT Sat, 19 Sep 1998 20:32:02 GMT Sat, 19 Sep 1998 20:32:05 GMT Sat, 19 Sep 1998 20:32:08 GMT Sat, 19 Sep 1998 20:32:10 GMT Sat, 19 Sep 1998 22:32:29 GMT Sat, 20 Aug 1994 16:33:01 GMT Sat, 20 Feb 1999 12:21:50 GMT Sat, 20 Feb 1999 17:53:52 GMT Sat, 20 Mar 1999 07:37:36 GMT Sat, 20 Mar 1999 16:38:24 GMT Sat, 20 Mar 1999 16:55:01 GMT Sat, 20 Mar 1999 16:59:59 GMT Sat, 20 Mar 1999 17:03:43 GMT Sat, 20 May 2000 03:56:02 GMT Sat, 20 May 2000 06:24:10 GMT Sat, 20 May 2000 10:54:48 GMT Sat, 20 May 2000 12:56:48 GMT Sat, 20 May 2000 12:57:46 GMT Sat, 20 May 2000 12:57:48 GMT Sat, 20 May 2000 12:57:50 GMT Sat, 20 May 2000 12:57:52 GMT Sat, 20 May 2000 12:59:12 GMT Sat, 20 May 2000 16:44:00 GMT Sat, 20 May 2000 20:58:10 GMT Sat, 20 Nov 1999 05:16:10 GMT Sat, 20 Nov 1999 05:43:28 GMT Sat, 20 Nov 1999 12:53:36 GMT Sat, 20 Nov 1999 21:29:40 GMT Sat, 21 Dec 1996 15:23:20 GMT Sat, 21 Feb 1998 02:28:22 GMT Sat, 21 Feb 1998 21:19:29 GMT Sat, 21 Mar 1998 18:56:26 GMT Sat, 21 Mar 1998 19:09:47 GMT Sat, 21 Nov 1998 19:17:47 GMT Sat, 22 Apr 2000 02:30:14 GMT Sat, 22 Apr 2000 02:31:56 GMT Sat, 22 Apr 2000 03:55:28 GMT Sat, 22 Apr 2000 03:55:31 GMT Sat, 22 Apr 2000 03:55:34 GMT Sat, 22 Apr 2000 03:55:37 GMT Sat, 22 Apr 2000 03:55:41 GMT Sat, 22 Apr 2000 03:55:43 GMT Sat, 22 Apr 2000 03:55:45 GMT Sat, 22 Apr 2000 03:55:47 GMT Sat, 22 Apr 2000 03:55:49 GMT Sat, 22 Apr 2000 03:55:53 GMT Sat, 22 Apr 2000 03:55:56 GMT Sat, 22 Apr 2000 03:55:58 GMT Sat, 22 Apr 2000 03:56:00 GMT Sat, 22 Apr 2000 03:56:03 GMT Sat, 22 Apr 2000 03:56:05 GMT Sat, 22 Apr 2000 03:56:07 GMT Sat, 22 Apr 2000 03:56:09 GMT Sat, 22 Apr 2000 03:56:11 GMT Sat, 22 Apr 2000 03:56:13 GMT Sat, 22 Apr 2000 03:56:17 GMT Sat, 22 Apr 2000 03:56:19 GMT Sat, 22 Apr 2000 03:56:22 GMT Sat, 22 Apr 2000 03:56:24 GMT Sat, 22 Apr 2000 03:56:28 GMT Sat, 22 Apr 2000 03:56:30 GMT Sat, 22 Apr 2000 03:56:32 GMT Sat, 22 Apr 2000 03:56:35 GMT Sat, 22 Apr 2000 03:56:37 GMT Sat, 22 Apr 2000 03:56:39 GMT Sat, 22 Apr 2000 03:56:41 GMT Sat, 22 Apr 2000 03:56:43 GMT Sat, 22 Apr 2000 03:56:45 GMT Sat, 22 Apr 2000 03:56:47 GMT Sat, 22 Apr 2000 03:56:49 GMT Sat, 22 Apr 2000 03:56:52 GMT Sat, 22 Apr 2000 03:56:54 GMT Sat, 22 Apr 2000 03:56:56 GMT Sat, 22 Apr 2000 03:56:58 GMT Sat, 22 Apr 2000 03:57:00 GMT Sat, 22 Apr 2000 03:57:02 GMT Sat, 22 Apr 2000 03:57:04 GMT Sat, 22 Apr 2000 03:57:06 GMT Sat, 22 Apr 2000 03:57:08 GMT Sat, 22 Apr 2000 03:57:10 GMT Sat, 22 Apr 2000 03:57:12 GMT Sat, 22 Apr 2000 03:57:14 GMT Sat, 22 Apr 2000 03:57:17 GMT Sat, 22 Apr 2000 03:57:19 GMT Sat, 22 Apr 2000 03:57:21 GMT Sat, 22 Apr 2000 03:57:24 GMT Sat, 22 Apr 2000 03:57:26 GMT Sat, 22 Apr 2000 03:57:28 GMT Sat, 22 Apr 2000 03:57:30 GMT Sat, 22 Apr 2000 03:57:32 GMT Sat, 22 Apr 2000 03:57:34 GMT Sat, 22 Apr 2000 03:57:36 GMT Sat, 22 Apr 2000 03:57:38 GMT Sat, 22 Apr 2000 03:57:40 GMT Sat, 22 Apr 2000 03:57:42 GMT Sat, 22 Apr 2000 03:57:44 GMT Sat, 22 Apr 2000 03:57:46 GMT Sat, 22 Apr 2000 03:57:48 GMT Sat, 22 Apr 2000 03:57:50 GMT Sat, 22 Apr 2000 03:57:52 GMT Sat, 22 Apr 2000 03:57:54 GMT Sat, 22 Apr 2000 03:57:56 GMT Sat, 22 Apr 2000 03:58:02 GMT Sat, 22 Apr 2000 03:58:04 GMT Sat, 22 Apr 2000 03:58:06 GMT Sat, 22 Apr 2000 03:58:08 GMT Sat, 22 Apr 2000 03:58:10 GMT Sat, 22 Apr 2000 03:58:12 GMT Sat, 22 Apr 2000 03:58:14 GMT Sat, 22 Apr 2000 03:58:16 GMT Sat, 22 Apr 2000 03:58:18 GMT Sat, 22 Apr 2000 03:58:20 GMT Sat, 22 Apr 2000 03:58:22 GMT Sat, 22 Apr 2000 03:58:24 GMT Sat, 22 Apr 2000 03:58:26 GMT Sat, 22 Apr 2000 03:58:28 GMT Sat, 22 Apr 2000 03:58:35 GMT Sat, 22 Apr 2000 04:28:38 GMT Sat, 22 Apr 2000 04:28:43 GMT Sat, 22 Apr 2000 04:28:56 GMT Sat, 22 Apr 2000 04:29:25 GMT Sat, 22 Apr 2000 07:04:06 GMT Sat, 22 Apr 2000 20:36:03 GMT Sat, 22 Jan 2000 00:02:44 GMT Sat, 22 Jan 2000 01:10:00 GMT Sat, 22 Jan 2000 02:22:54 GMT Sat, 22 Jan 2000 19:11:55 GMT Sat, 22 Jan 2000 19:54:57 GMT Sat, 22 Jan 2000 20:31:10 GMT Sat, 22 Jan 2000 23:19:42 GMT Sat, 22 Jul 2000 00:21:37 GMT Sat, 22 Jul 2000 00:45:32 GMT Sat, 22 Jul 2000 00:48:19 GMT Sat, 22 Jul 2000 00:48:26 GMT Sat, 22 Jul 2000 00:59:00 GMT Sat, 22 Jul 2000 00:59:03 GMT Sat, 22 Jul 2000 00:59:06 GMT Sat, 22 Jul 2000 00:59:18 GMT Sat, 22 Jul 2000 01:38:01 GMT Sat, 22 Jul 2000 01:39:42 GMT Sat, 22 Jul 2000 07:37:16 GMT Sat, 22 Jul 2000 17:54:41 GMT Sat, 22 Jul 2000 18:31:21 GMT Sat, 22 Jul 2000 18:41:29 GMT Sat, 22 Jul 2000 20:58:21 GMT Sat, 22 Jul 2000 21:51:47 GMT Sat, 22 Jul 2000 22:35:26 GMT Sat, 22 May 1999 20:38:37 GMT Sat, 22 Nov 1997 17:41:44 GMT Sat, 22 Nov 1997 18:17:32 GMT Sat, 22 Nov 1997 18:18:20 GMT Sat, 22 Nov 1997 18:19:00 GMT Sat, 23 Sep 2000 04:08:01 GMT Sat, 23 Sep 2000 04:35:43 GMT Sat, 23 Sep 2000 14:48:07 GMT Sat, 23 Sep 2000 15:07:34 GMT Sat, 23 Sep 2000 15:07:38 GMT Sat, 24 Apr 1999 00:35:45 GMT Sat, 24 Apr 1999 14:03:42 GMT Sat, 24 Apr 1999 14:49:10 GMT Sat, 24 Apr 1999 14:49:18 GMT Sat, 24 Apr 1999 14:49:26 GMT Sat, 24 Apr 1999 14:49:35 GMT Sat, 24 Apr 1999 14:49:43 GMT Sat, 24 Apr 1999 14:50:02 GMT Sat, 24 Apr 1999 14:50:11 GMT Sat, 24 Apr 1999 14:50:18 GMT Sat, 24 Apr 1999 14:50:27 GMT Sat, 24 Apr 1999 14:50:35 GMT Sat, 24 Apr 1999 14:50:43 GMT Sat, 24 Apr 1999 14:50:51 GMT Sat, 24 Apr 1999 14:51:00 GMT Sat, 24 Apr 1999 14:51:06 GMT Sat, 24 Apr 1999 14:51:15 GMT Sat, 24 Apr 1999 14:51:23 GMT Sat, 24 Apr 1999 14:51:30 GMT Sat, 24 Apr 1999 14:51:38 GMT Sat, 24 Apr 1999 14:51:45 GMT Sat, 24 Apr 1999 14:51:53 GMT Sat, 24 Apr 1999 14:52:01 GMT Sat, 24 Apr 1999 14:52:09 GMT Sat, 24 Apr 1999 14:52:17 GMT Sat, 24 Apr 1999 14:52:25 GMT Sat, 24 Apr 1999 14:52:34 GMT Sat, 24 Apr 1999 14:52:42 GMT Sat, 24 Apr 1999 14:52:50 GMT Sat, 24 Apr 1999 14:52:57 GMT Sat, 24 Apr 1999 14:53:05 GMT Sat, 24 Apr 1999 14:53:13 GMT Sat, 24 Apr 1999 14:53:22 GMT Sat, 24 Apr 1999 14:53:29 GMT Sat, 24 Apr 1999 14:53:37 GMT Sat, 24 Apr 1999 14:53:44 GMT Sat, 24 Apr 1999 14:53:50 GMT Sat, 24 Apr 1999 14:53:56 GMT Sat, 24 Apr 1999 14:54:03 GMT Sat, 24 Apr 1999 14:54:10 GMT Sat, 24 Apr 1999 14:54:17 GMT Sat, 24 Apr 1999 14:54:25 GMT Sat, 24 Apr 1999 14:54:33 GMT Sat, 24 Apr 1999 14:54:40 GMT Sat, 24 Apr 1999 14:54:48 GMT Sat, 24 Apr 1999 14:54:56 GMT Sat, 24 Apr 1999 18:01:02 GMT Sat, 24 Jan 1998 16:12:08 GMT Sat, 24 Jul 1999 05:04:10 GMT Sat, 24 Jul 1999 09:59:00 GMT Sat, 24 Jun 2000 01:32:12 GMT Sat, 24 Jun 2000 04:34:18 GMT Sat, 24 Jun 2000 04:52:55 GMT Sat, 24 Jun 2000 18:51:11 GMT Sat, 24 Jun 2000 18:51:13 GMT Sat, 24 May 1997 16:10:24 GMT Sat, 25 Dec 1999 14:55:18 GMT Sat, 25 Dec 1999 19:21:15 GMT Sat, 25 Dec 1999 20:53:05 GMT Sat, 25 Dec 1999 23:05:05 GMT Sat, 25 Jul 1998 17:32:00 GMT Sat, 25 Jul 1998 17:32:05 GMT Sat, 25 Jul 1998 17:32:52 GMT Sat, 25 Jul 1998 17:32:57 GMT Sat, 25 Mar 2000 00:09:19 GMT Sat, 25 Mar 2000 22:13:01 GMT Sat, 25 Oct 1997 12:57:20 GMT Sat, 26 Aug 2000 00:56:02 GMT Sat, 26 Aug 2000 01:49:27 GMT Sat, 26 Aug 2000 02:11:07 GMT Sat, 26 Aug 2000 02:14:10 GMT Sat, 26 Aug 2000 02:41:43 GMT Sat, 26 Aug 2000 02:50:30 GMT Sat, 26 Aug 2000 02:50:59 GMT Sat, 26 Aug 2000 09:27:31 GMT Sat, 26 Aug 2000 09:27:33 GMT Sat, 26 Aug 2000 09:27:35 GMT Sat, 26 Aug 2000 09:27:37 GMT Sat, 26 Aug 2000 09:28:12 GMT Sat, 26 Aug 2000 09:28:27 GMT Sat, 26 Aug 2000 10:15:06 GMT Sat, 26 Aug 2000 10:15:08 GMT Sat, 26 Aug 2000 10:15:10 GMT Sat, 26 Aug 2000 10:15:40 GMT Sat, 26 Aug 2000 10:15:56 GMT Sat, 26 Aug 2000 11:58:12 GMT Sat, 26 Aug 2000 14:32:57 GMT Sat, 26 Aug 2000 14:32:59 GMT Sat, 26 Aug 2000 14:33:01 GMT Sat, 26 Aug 2000 14:33:03 GMT Sat, 26 Aug 2000 14:33:05 GMT Sat, 26 Aug 2000 14:33:07 GMT Sat, 26 Aug 2000 14:33:09 GMT Sat, 26 Aug 2000 14:33:24 GMT Sat, 26 Aug 2000 14:33:26 GMT Sat, 26 Aug 2000 14:33:29 GMT Sat, 26 Aug 2000 14:35:53 GMT Sat, 26 Aug 2000 14:37:27 GMT Sat, 26 Aug 2000 19:17:05 GMT Sat, 26 Aug 2000 19:33:15 GMT Sat, 26 Aug 2000 19:36:18 GMT Sat, 26 Aug 2000 20:23:35 GMT Sat, 26 Feb 1994 07:39:20 GMT Sat, 26 Feb 2000 16:02:52 GMT Sat, 26 Feb 2000 16:17:28 GMT Sat, 26 Feb 2000 17:34:56 GMT Sat, 26 Jun 1999 00:37:52 GMT Sat, 26 Jun 1999 00:38:40 GMT Sat, 26 Jun 1999 00:39:34 GMT Sat, 26 Jun 1999 00:40:12 GMT Sat, 26 Jun 1999 03:13:09 GMT Sat, 26 Jun 1999 11:11:32 GMT Sat, 26 Sep 1998 16:27:18 GMT Sat, 27 Apr 1996 10:18:18 GMT Sat, 27 Dec 1997 20:02:00 GMT Sat, 27 Feb 1999 20:40:04 GMT Sat, 27 Mar 1999 16:08:32 GMT Sat, 27 May 2000 10:07:11 GMT Sat, 27 May 2000 10:18:10 GMT Sat, 27 May 2000 13:03:18 GMT Sat, 27 May 2000 13:29:58 GMT Sat, 27 May 2000 15:19:35 GMT Sat, 27 May 2000 15:19:39 GMT Sat, 27 May 2000 18:35:52 GMT Sat, 27 Nov 1999 15:06:21 GMT Sat, 27 Nov 1999 15:38:40 GMT Sat, 27 Nov 1999 15:38:42 GMT Sat, 27 Nov 1999 15:41:39 GMT Sat, 27 Nov 1999 15:42:36 GMT Sat, 27 Nov 1999 15:43:41 GMT Sat, 27 Nov 1999 15:43:43 GMT Sat, 27 Nov 1999 15:43:45 GMT Sat, 27 Nov 1999 15:43:47 GMT Sat, 27 Nov 1999 15:43:49 GMT Sat, 27 Nov 1999 15:43:51 GMT Sat, 27 Nov 1999 23:27:49 GMT Sat, 27 Nov 1999 23:42:33 GMT Sat, 27 Nov 1999 23:46:24 GMT Sat, 28 Aug 1999 01:03:13 GMT Sat, 28 Aug 1999 07:56:00 GMT Sat, 28 Aug 1999 08:02:00 GMT Sat, 28 Aug 1999 10:20:00 GMT Sat, 28 Feb 1998 13:02:11 GMT Sat, 28 Jan 1995 00:16:44 GMT Sat, 28 Jan 1995 10:29:28 GMT Sat, 28 Jun 1997 23:05:54 GMT Sat, 28 Nov 1998 22:59:00 GMT Sat, 29 Apr 2000 12:42:16 GMT Sat, 29 Jan 2000 00:10:11 GMT Sat, 29 Jan 2000 03:36:23 GMT Sat, 29 Jan 2000 13:38:18 GMT Sat, 29 Jan 2000 13:44:12 GMT Sat, 29 Jan 2000 15:58:53 GMT Sat, 29 Jan 2000 20:45:05 GMT Sat, 29 Jan 2000 21:04:28 GMT Sat, 29 Jun 1996 17:36:22 GMT Sat, 29 May 1999 18:09:04 GMT Sat, 29 Nov 1997 18:33:19 GMT Sat, 29 Nov 1997 18:33:21 GMT Sat, 29 Nov 1997 20:56:42 GMT Sat, 30 Jan 1999 10:43:10 GMT Sat, 30 Oct 1999 07:34:53 GMT Sat, 30 Oct 1999 20:56:51 GMT Sat, 31 Jul 1999 10:19:00 GMT Sat, 31 Jul 1999 16:21:00 GMT Sat, 31 Jul 1999 18:28:52 GMT Sat, 31 May 1997 09:30:56 GMT Sat, 31 Oct 1998 11:43:51 GMT Sat, 31 Oct 1998 14:15:48 GMT Sat, 31 Oct 1998 18:50:30 GMT Sat, 31 Oct 1998 19:03:16 GMT Sat, 31 Oct 1998 19:16:30 GMT Sat, 31 Oct 1998 19:27:26 GMT Sun, 01 Aug 1999 16:03:41 GMT Sun, 01 Mar 1998 22:40:39 GMT Sun, 01 Nov 1998 18:08:40 GMT Sun, 01 Nov 1998 22:11:01 GMT Sun, 02 Apr 2000 16:01:32 GMT Sun, 02 Apr 2000 16:03:51 GMT Sun, 02 Apr 2000 18:59:15 GMT Sun, 02 Apr 2000 21:34:13 GMT Sun, 02 Apr 2000 21:37:30 GMT Sun, 02 Apr 2000 21:37:33 GMT Sun, 02 Apr 2000 21:37:40 GMT Sun, 02 Apr 2000 21:37:46 GMT Sun, 02 Apr 2000 21:37:53 GMT Sun, 02 Aug 1998 00:49:06 GMT Sun, 02 Aug 1998 00:58:10 GMT Sun, 02 Aug 1998 01:16:59 GMT Sun, 02 Feb 1997 09:25:00 GMT Sun, 02 Jan 2000 06:19:51 GMT Sun, 02 Jan 2000 06:57:59 GMT Sun, 02 Jan 2000 08:32:42 GMT Sun, 02 Jan 2000 08:32:54 GMT Sun, 02 Jan 2000 08:32:57 GMT Sun, 02 Jan 2000 08:32:59 GMT Sun, 02 Jan 2000 08:33:02 GMT Sun, 02 Jan 2000 08:36:25 GMT Sun, 02 Jan 2000 17:41:59 GMT Sun, 02 Jan 2000 18:10:03 GMT Sun, 02 Jul 2000 14:37:56 GMT Sun, 02 Jul 2000 17:18:39 GMT Sun, 02 May 1999 02:32:01 GMT Sun, 02 Nov 1997 16:05:14 GMT Sun, 02 Nov 1997 20:27:50 GMT Sun, 02 Nov 1997 20:27:52 GMT Sun, 02 Nov 1997 20:27:54 GMT Sun, 02 Nov 1997 20:27:56 GMT Sun, 02 Nov 1997 20:27:58 GMT Sun, 02 Nov 1997 20:28:00 GMT Sun, 02 Nov 1997 20:28:03 GMT Sun, 02 Nov 1997 20:28:05 GMT Sun, 02 Nov 1997 20:28:07 GMT Sun, 02 Nov 1997 20:28:21 GMT Sun, 03 Jan 1993 22:26:53 GMT Sun, 03 May 1998 18:04:26 GMT Sun, 03 Oct 1999 18:17:05 GMT Sun, 04 Apr 1999 08:20:50 GMT Sun, 04 Aug 1991 22:00:00 GMT Sun, 04 Aug 1996 10:39:53 GMT Sun, 04 Jan 1998 11:06:53 GMT Sun, 04 Jan 1998 18:40:17 GMT Sun, 04 Jul 1999 21:52:23 GMT Sun, 04 Jul 1999 22:45:27 GMT Sun, 04 Jun 2000 04:35:04 GMT Sun, 04 Jun 2000 05:41:13 GMT Sun, 04 Jun 2000 05:43:18 GMT Sun, 04 Jun 2000 11:14:13 GMT Sun, 04 Jun 2000 11:33:24 GMT Sun, 04 Jun 2000 14:08:28 GMT Sun, 04 Oct 1998 16:54:28 GMT Sun, 04 Oct 1998 16:54:34 GMT Sun, 04 Oct 1998 16:54:37 GMT Sun, 04 Oct 1998 16:54:41 GMT Sun, 04 Oct 1998 16:54:58 GMT Sun, 04 Oct 1998 17:22:42 GMT Sun, 04 Oct 1998 17:22:44 GMT Sun, 04 Oct 1998 19:07:09 GMT Sun, 04 Oct 1998 19:07:29 GMT Sun, 04 Sep 1994 19:19:19 GMT Sun, 05 Dec 1999 03:12:18 GMT Sun, 05 Dec 1999 17:55:40 GMT Sun, 05 Jul 1998 22:00:00 GMT Sun, 05 Mar 2000 10:56:38 GMT Sun, 05 Mar 2000 12:02:50 GMT Sun, 05 Mar 2000 13:11:48 GMT Sun, 05 Mar 2000 16:03:29 GMT Sun, 05 Mar 2000 16:11:51 GMT Sun, 05 Mar 2000 16:42:14 GMT Sun, 05 Mar 2000 16:44:26 GMT Sun, 05 Mar 2000 17:23:26 GMT Sun, 05 Mar 2000 17:28:11 GMT Sun, 05 Mar 2000 17:38:46 GMT Sun, 05 Oct 1997 15:45:29 GMT Sun, 05 Oct 1997 15:45:31 GMT Sun, 05 Sep 1999 08:42:23 GMT Sun, 06 Aug 2000 12:36:39 GMT Sun, 06 Aug 2000 12:38:04 GMT Sun, 06 Aug 2000 15:01:10 GMT Sun, 06 Aug 2000 15:01:14 GMT Sun, 06 Aug 2000 15:01:45 GMT Sun, 06 Aug 2000 16:47:06 GMT Sun, 06 Feb 2000 03:27:32 GMT Sun, 06 Feb 2000 11:28:45 GMT Sun, 06 Feb 2000 22:03:14 GMT Sun, 06 Jun 1999 03:12:24 GMT Sun, 06 Jun 1999 07:54:25 GMT Sun, 06 Jun 1999 22:00:41 GMT Sun, 06 Jun 1999 22:15:20 GMT Sun, 06 Nov 1994 03:14:07 GMT Sun, 06 Nov 1994 03:14:15 GMT Sun, 06 Nov 1994 03:14:21 GMT Sun, 06 Nov 1994 03:14:27 GMT Sun, 06 Nov 1994 03:14:32 GMT Sun, 06 Nov 1994 03:14:37 GMT Sun, 06 Nov 1994 03:14:42 GMT Sun, 06 Nov 1994 03:14:48 GMT Sun, 06 Nov 1994 03:14:53 GMT Sun, 06 Nov 1994 03:14:58 GMT Sun, 06 Nov 1994 03:15:04 GMT Sun, 06 Nov 1994 03:15:10 GMT Sun, 06 Nov 1994 03:15:15 GMT Sun, 06 Nov 1994 03:15:21 GMT Sun, 06 Nov 1994 03:43:23 GMT Sun, 06 Nov 1994 04:29:56 GMT Sun, 06 Nov 1994 08:16:58 GMT Sun, 06 Sep 1998 13:30:48 GMT Sun, 06 Sep 1998 16:00:17 GMT Sun, 06 Sep 1998 16:35:57 GMT Sun, 06 Sep 1998 16:53:05 GMT Sun, 06 Sep 1998 17:45:30 GMT Sun, 07 Dec 1997 10:33:36 GMT Sun, 07 Jun 1998 01:52:04 GMT Sun, 07 Jun 1998 17:37:41 GMT Sun, 07 Mar 1999 12:42:57 GMT Sun, 07 Mar 1999 16:34:26 GMT Sun, 07 Mar 1999 16:36:00 GMT Sun, 07 Mar 1999 16:36:07 GMT Sun, 07 Mar 1999 23:25:23 GMT Sun, 07 Mar 1999 23:26:44 GMT Sun, 07 May 2000 04:35:02 GMT Sun, 07 May 2000 10:51:32 GMT Sun, 07 Nov 1993 13:46:23 GMT Sun, 07 Nov 1999 15:04:00 GMT Sun, 07 Nov 1999 18:55:00 GMT Sun, 07 Nov 1999 18:57:00 GMT Sun, 08 Aug 1999 17:59:28 GMT Sun, 08 Aug 1999 18:20:10 GMT Sun, 08 Aug 1999 19:05:21 GMT Sun, 08 Aug 1999 19:53:39 GMT Sun, 08 Aug 1999 20:03:18 GMT Sun, 08 Nov 1998 12:44:47 GMT Sun, 08 Nov 1998 21:20:14 GMT Sun, 08 Sep 1996 10:35:12 GMT Sun, 08 Sep 1996 10:35:32 GMT Sun, 08 Sep 1996 10:36:08 GMT Sun, 09 Apr 2000 10:56:54 GMT Sun, 09 Apr 2000 11:20:48 GMT Sun, 09 Apr 2000 17:45:02 GMT Sun, 09 Apr 2000 19:06:07 GMT Sun, 09 Apr 2000 19:26:09 GMT Sun, 09 Aug 1998 18:54:22 GMT Sun, 09 Feb 1997 17:29:52 GMT Sun, 09 Feb 1997 17:29:54 GMT Sun, 09 Feb 1997 17:29:56 GMT Sun, 09 Feb 1997 17:41:00 GMT Sun, 09 Feb 1997 17:43:32 GMT Sun, 09 Jan 2000 05:36:21 GMT Sun, 09 Jan 2000 17:16:23 GMT Sun, 09 Jul 2000 00:31:17 GMT Sun, 09 Jun 1996 05:42:42 GMT Sun, 09 May 1993 09:57:58 GMT Sun, 09 May 1999 12:16:03 GMT Sun, 09 May 1999 19:52:26 GMT Sun, 10 Jan 1999 19:05:10 GMT Sun, 10 May 1998 13:04:33 GMT Sun, 10 May 1998 21:34:33 GMT Sun, 10 Nov 1996 23:16:16 GMT Sun, 10 Oct 1999 04:03:36 GMT Sun, 10 Sep 2000 00:40:08 GMT Sun, 11 Apr 1999 08:58:00 GMT Sun, 11 Apr 1999 15:15:00 GMT Sun, 11 Apr 1999 19:10:19 GMT Sun, 11 Apr 1999 19:58:21 GMT Sun, 11 Apr 1999 19:58:42 GMT Sun, 11 Aug 1996 09:43:06 GMT Sun, 11 Jul 1999 16:11:46 GMT Sun, 11 Jul 1999 22:24:27 GMT Sun, 11 Jun 2000 00:06:05 GMT Sun, 11 Jun 2000 00:06:07 GMT Sun, 11 Jun 2000 00:06:14 GMT Sun, 11 Jun 2000 00:06:19 GMT Sun, 11 Jun 2000 02:27:45 GMT Sun, 11 Jun 2000 02:27:52 GMT Sun, 11 Jun 2000 16:23:13 GMT Sun, 11 Jun 2000 16:23:25 GMT Sun, 11 Jun 2000 17:34:49 GMT Sun, 11 Oct 1998 17:48:11 GMT Sun, 12 Apr 1998 00:18:15 GMT Sun, 12 Apr 1998 18:42:15 GMT Sun, 12 Dec 1999 10:10:29 GMT Sun, 12 Dec 1999 18:46:48 GMT Sun, 12 Dec 1999 19:00:01 GMT Sun, 12 Dec 1999 19:46:51 GMT Sun, 12 Dec 1999 21:20:20 GMT Sun, 12 Jan 1992 23:00:00 GMT Sun, 12 Jul 1998 05:17:16 GMT Sun, 12 Mar 1995 11:03:50 GMT Sun, 12 Mar 2000 18:28:44 GMT Sun, 12 Oct 1997 12:46:09 GMT Sun, 12 Oct 1997 17:17:05 GMT Sun, 12 Sep 1999 19:58:04 GMT Sun, 12 Sep 1999 23:09:02 GMT Sun, 12 Sep 1999 23:09:05 GMT Sun, 12 Sep 1999 23:09:07 GMT Sun, 13 Aug 2000 01:24:24 GMT Sun, 13 Aug 2000 03:59:34 GMT Sun, 13 Aug 2000 10:15:23 GMT Sun, 13 Aug 2000 13:23:08 GMT Sun, 13 Aug 2000 17:18:00 GMT Sun, 13 Aug 2000 18:42:07 GMT Sun, 13 Aug 2000 18:42:19 GMT Sun, 13 Aug 2000 18:42:23 GMT Sun, 13 Aug 2000 19:26:06 GMT Sun, 13 Aug 2000 19:26:08 GMT Sun, 13 Aug 2000 19:26:10 GMT Sun, 13 Aug 2000 19:26:12 GMT Sun, 13 Feb 2000 04:38:30 GMT Sun, 13 Feb 2000 18:16:36 GMT Sun, 13 Feb 2000 18:25:33 GMT Sun, 13 Feb 2000 18:30:44 GMT Sun, 13 Feb 2000 18:31:06 GMT Sun, 13 Feb 2000 18:33:23 GMT Sun, 13 Feb 2000 18:42:03 GMT Sun, 13 Feb 2000 18:47:01 GMT Sun, 13 Feb 2000 19:21:43 GMT Sun, 13 Feb 2000 22:05:49 GMT Sun, 13 Feb 2000 22:06:34 GMT Sun, 13 Feb 2000 22:07:02 GMT Sun, 13 Feb 2000 22:58:08 GMT Sun, 13 Jun 1999 14:37:07 GMT Sun, 13 Sep 1998 19:18:03 GMT Sun, 13 Sep 1998 19:58:06 GMT Sun, 13 Sep 1998 20:13:44 GMT Sun, 13 Sep 1998 20:13:51 GMT Sun, 13 Sep 1998 20:13:57 GMT Sun, 13 Sep 1998 20:14:06 GMT Sun, 13 Sep 1998 20:14:29 GMT Sun, 13 Sep 1998 20:14:44 GMT Sun, 13 Sep 1998 20:14:54 GMT Sun, 14 Feb 1999 22:28:13 GMT Sun, 14 Jul 1996 10:04:53 GMT Sun, 14 May 2000 02:57:41 GMT Sun, 14 May 2000 04:35:01 GMT Sun, 14 May 2000 14:50:28 GMT Sun, 14 May 2000 16:21:26 GMT Sun, 14 May 2000 16:26:10 GMT Sun, 14 May 2000 22:07:04 GMT Sun, 14 May 2000 22:07:09 GMT Sun, 14 May 2000 22:07:32 GMT Sun, 14 Nov 1999 02:30:43 GMT Sun, 14 Nov 1999 02:59:22 GMT Sun, 14 Nov 1999 12:00:00 GMT Sun, 14 Sep 1997 12:09:49 GMT Sun, 15 Aug 1999 18:47:29 GMT Sun, 15 Jan 1989 09:04:25 GMT Sun, 15 Jan 1989 09:05:07 GMT Sun, 15 Jan 1989 09:05:31 GMT Sun, 15 Jan 1989 09:08:11 GMT Sun, 15 Jan 1995 13:33:56 GMT Sun, 15 Jan 1995 14:05:36 GMT Sun, 15 Jan 1995 15:32:00 GMT Sun, 15 Jan 1995 15:54:56 GMT Sun, 15 Jun 1997 19:22:51 GMT Sun, 15 Mar 1998 20:04:08 GMT Sun, 15 Mar 1998 22:21:16 GMT Sun, 16 Apr 2000 02:14:21 GMT Sun, 16 Apr 2000 04:35:02 GMT Sun, 16 Apr 2000 14:04:04 GMT Sun, 16 Apr 2000 14:19:05 GMT Sun, 16 Apr 2000 14:21:32 GMT Sun, 16 Apr 2000 14:31:33 GMT Sun, 16 Apr 2000 14:32:43 GMT Sun, 16 Jan 2000 00:00:19 GMT Sun, 16 Jan 2000 00:00:21 GMT Sun, 16 Jan 2000 00:03:40 GMT Sun, 16 Jan 2000 06:08:28 GMT Sun, 16 Jan 2000 15:20:11 GMT Sun, 16 Jan 2000 15:25:21 GMT Sun, 16 Jan 2000 18:06:30 GMT Sun, 16 Jul 1989 22:11:24 GMT Sun, 16 Jul 1989 22:41:02 GMT Sun, 16 Jul 1989 22:56:09 GMT Sun, 16 Jul 1989 22:59:28 GMT Sun, 16 Jul 1989 23:02:54 GMT Sun, 16 Jul 1989 23:06:34 GMT Sun, 16 Jul 2000 01:15:53 GMT Sun, 16 Jul 2000 01:37:32 GMT Sun, 16 Jul 2000 01:45:21 GMT Sun, 16 Jul 2000 01:49:28 GMT Sun, 16 Jul 2000 01:50:17 GMT Sun, 16 Jul 2000 01:53:14 GMT Sun, 16 Jul 2000 03:59:24 GMT Sun, 16 Jul 2000 15:11:05 GMT Sun, 16 Jul 2000 15:11:14 GMT Sun, 16 Jul 2000 23:35:11 GMT Sun, 16 May 1999 08:49:53 GMT Sun, 16 May 1999 08:54:33 GMT Sun, 16 May 1999 17:33:30 GMT Sun, 16 May 1999 18:14:44 GMT Sun, 16 May 1999 18:24:57 GMT Sun, 16 May 1999 18:37:31 GMT Sun, 16 May 1999 20:17:22 GMT Sun, 16 May 1999 23:04:40 GMT Sun, 17 Jul 1994 12:20:55 GMT Sun, 17 Oct 1999 00:23:59 GMT Sun, 17 Oct 1999 15:19:59 GMT Sun, 17 Oct 1999 19:12:32 GMT Sun, 17 Oct 1999 19:12:38 GMT Sun, 17 Oct 1999 19:12:42 GMT Sun, 17 Oct 1999 19:12:46 GMT Sun, 17 Oct 1999 19:12:50 GMT Sun, 17 Oct 1999 19:13:00 GMT Sun, 17 Oct 1999 19:13:12 GMT Sun, 17 Oct 1999 19:13:24 GMT Sun, 17 Sep 2000 00:49:21 GMT Sun, 17 Sep 2000 01:52:39 GMT Sun, 17 Sep 2000 06:47:25 GMT Sun, 17 Sep 2000 06:47:27 GMT Sun, 17 Sep 2000 06:47:29 GMT Sun, 17 Sep 2000 06:47:31 GMT Sun, 17 Sep 2000 06:47:43 GMT Sun, 17 Sep 2000 11:32:46 GMT Sun, 18 Apr 1999 19:36:15 GMT Sun, 18 Dec 1994 00:47:46 GMT Sun, 18 Jan 1998 17:06:23 GMT Sun, 18 Jun 2000 04:35:01 GMT Sun, 18 Jun 2000 05:52:51 GMT Sun, 18 Jun 2000 18:28:40 GMT Sun, 18 Jun 2000 19:31:22 GMT Sun, 18 Jun 2000 23:31:29 GMT Sun, 18 Jun 2000 23:33:28 GMT Sun, 18 Jun 2000 23:33:30 GMT Sun, 18 Jun 2000 23:33:32 GMT Sun, 18 Jun 2000 23:33:43 GMT Sun, 18 Jun 2000 23:33:49 GMT Sun, 18 Jun 2000 23:34:21 GMT Sun, 18 Jun 2000 23:35:01 GMT Sun, 18 Oct 1998 21:39:52 GMT Sun, 19 Dec 1999 03:55:37 GMT Sun, 19 Dec 1999 17:00:39 GMT Sun, 19 Dec 1999 22:01:02 GMT Sun, 19 Dec 1999 22:02:56 GMT Sun, 19 Dec 1999 22:03:04 GMT Sun, 19 Jan 1997 17:42:46 GMT Sun, 19 Jan 1997 18:05:06 GMT Sun, 19 Jan 1997 18:05:22 GMT Sun, 19 Jan 1997 18:05:40 GMT Sun, 19 Jan 1997 18:05:54 GMT Sun, 19 Jan 1997 18:06:08 GMT Sun, 19 Jan 1997 18:06:26 GMT Sun, 19 Jan 1997 18:06:46 GMT Sun, 19 Jan 1997 18:07:00 GMT Sun, 19 Jan 1997 18:07:12 GMT Sun, 19 Jan 1997 18:07:26 GMT Sun, 19 Jan 1997 18:07:36 GMT Sun, 19 Jan 1997 18:07:48 GMT Sun, 19 Jan 1997 18:08:00 GMT Sun, 19 Jan 1997 18:08:12 GMT Sun, 19 Jan 1997 18:08:22 GMT Sun, 19 Jan 1997 18:09:06 GMT Sun, 19 Jan 1997 18:09:18 GMT Sun, 19 Jan 1997 18:09:36 GMT Sun, 19 Jan 1997 18:09:48 GMT Sun, 19 Jan 1997 18:11:06 GMT Sun, 19 Jan 1997 18:11:28 GMT Sun, 19 Jan 1997 18:11:40 GMT Sun, 19 Jan 1997 18:11:58 GMT Sun, 19 Jan 1997 18:12:36 GMT Sun, 19 Jan 1997 18:12:50 GMT Sun, 19 Jan 1997 18:13:12 GMT Sun, 19 Jan 1997 18:13:24 GMT Sun, 19 Jan 1997 18:13:42 GMT Sun, 19 Jan 1997 18:13:58 GMT Sun, 19 Jan 1997 18:14:12 GMT Sun, 19 Jan 1997 18:15:06 GMT Sun, 19 Jan 1997 18:15:26 GMT Sun, 19 Jan 1997 18:15:40 GMT Sun, 19 Jan 1997 18:15:56 GMT Sun, 19 Jan 1997 18:16:08 GMT Sun, 19 Jan 1997 18:16:18 GMT Sun, 19 Jan 1997 18:16:30 GMT Sun, 19 Jan 1997 18:16:40 GMT Sun, 19 Jan 1997 18:17:04 GMT Sun, 19 Jan 1997 18:17:16 GMT Sun, 19 Jan 1997 18:17:26 GMT Sun, 19 Jan 1997 18:17:38 GMT Sun, 19 Jan 1997 18:17:54 GMT Sun, 19 Jan 1997 18:18:04 GMT Sun, 19 Jan 1997 18:18:16 GMT Sun, 19 Jan 1997 18:18:56 GMT Sun, 19 Jan 1997 18:19:14 GMT Sun, 19 Jan 1997 18:19:32 GMT Sun, 19 Jan 1997 18:19:42 GMT Sun, 19 Jan 1997 18:20:08 GMT Sun, 19 Jan 1997 18:53:10 GMT Sun, 19 Jan 1997 20:07:06 GMT Sun, 19 Jan 1997 20:26:46 GMT Sun, 19 Jul 1998 22:00:00 GMT Sun, 19 Mar 2000 05:59:40 GMT Sun, 19 Mar 2000 06:22:52 GMT Sun, 19 Mar 2000 06:26:23 GMT Sun, 19 Mar 2000 06:26:25 GMT Sun, 19 Mar 2000 12:14:18 GMT Sun, 19 Mar 2000 15:52:10 GMT Sun, 19 Mar 2000 20:12:50 GMT Sun, 19 May 1996 12:29:28 GMT Sun, 19 Sep 1999 16:15:17 GMT Sun, 19 Sep 1999 16:15:19 GMT Sun, 20 Aug 1995 05:52:24 GMT Sun, 20 Aug 2000 14:39:44 GMT Sun, 20 Aug 2000 19:36:37 GMT Sun, 20 Aug 2000 19:39:09 GMT Sun, 20 Feb 2000 01:14:46 GMT Sun, 20 Feb 2000 05:13:25 GMT Sun, 20 Feb 2000 08:34:23 GMT Sun, 20 Feb 2000 08:36:14 GMT Sun, 20 Feb 2000 08:36:20 GMT Sun, 20 Feb 2000 08:36:23 GMT Sun, 20 Feb 2000 16:13:56 GMT Sun, 20 Feb 2000 16:48:46 GMT Sun, 20 Feb 2000 16:49:41 GMT Sun, 20 Feb 2000 18:41:18 GMT Sun, 20 Feb 2000 21:06:56 GMT Sun, 20 Feb 2000 21:11:38 GMT Sun, 20 Jun 1999 16:32:20 GMT Sun, 21 Apr 1996 07:28:44 GMT Sun, 21 Jul 1996 20:12:33 GMT Sun, 21 Jun 1998 19:45:14 GMT Sun, 21 Jun 1998 19:48:10 GMT Sun, 21 Jun 1998 19:48:21 GMT Sun, 21 Mar 1999 15:11:37 GMT Sun, 21 Mar 1999 15:57:50 GMT Sun, 21 Mar 1999 16:10:02 GMT Sun, 21 Mar 1999 16:16:21 GMT Sun, 21 Mar 1999 16:16:58 GMT Sun, 21 May 2000 04:41:21 GMT Sun, 21 May 2000 19:15:14 GMT Sun, 21 May 2000 19:18:55 GMT Sun, 21 Nov 1999 08:09:51 GMT Sun, 21 Nov 1999 19:09:22 GMT Sun, 21 Nov 1999 19:36:16 GMT Sun, 22 Aug 1999 18:37:38 GMT Sun, 22 Aug 1999 18:37:52 GMT Sun, 22 Aug 1999 18:37:58 GMT Sun, 22 Aug 1999 18:38:04 GMT Sun, 22 Aug 1999 18:38:24 GMT Sun, 22 Aug 1999 18:38:43 GMT Sun, 22 Aug 1999 18:38:57 GMT Sun, 22 Aug 1999 20:05:55 GMT Sun, 22 Nov 1998 06:44:55 GMT Sun, 23 Apr 2000 03:57:28 GMT Sun, 23 Apr 2000 03:57:31 GMT Sun, 23 Apr 2000 03:57:34 GMT Sun, 23 Apr 2000 03:57:43 GMT Sun, 23 Apr 2000 04:35:02 GMT Sun, 23 Apr 2000 11:43:19 GMT Sun, 23 Apr 2000 20:43:21 GMT Sun, 23 Apr 2000 23:10:23 GMT Sun, 23 Aug 1998 16:31:19 GMT Sun, 23 Aug 1998 20:32:25 GMT Sun, 23 Jan 2000 11:27:04 GMT Sun, 23 Jan 2000 20:16:16 GMT Sun, 23 Jul 2000 00:27:53 GMT Sun, 23 Jul 2000 01:05:37 GMT Sun, 23 Jul 2000 01:06:14 GMT Sun, 23 Jul 2000 01:06:16 GMT Sun, 23 Jul 2000 03:27:27 GMT Sun, 23 Jul 2000 04:14:50 GMT Sun, 23 Jul 2000 04:15:19 GMT Sun, 23 Jul 2000 04:16:04 GMT Sun, 23 Jul 2000 08:20:47 GMT Sun, 23 Jul 2000 09:55:55 GMT Sun, 23 Jul 2000 13:55:42 GMT Sun, 23 Jul 2000 18:04:01 GMT Sun, 23 May 1993 07:23:20 GMT Sun, 23 May 1993 07:23:40 GMT Sun, 23 May 1993 07:23:50 GMT Sun, 23 May 1999 17:03:41 GMT Sun, 24 Jan 1999 23:41:00 GMT Sun, 24 Jul 1994 14:39:45 GMT Sun, 24 Mar 1996 10:09:37 GMT Sun, 24 Mar 1996 22:17:38 GMT Sun, 24 Nov 1996 09:59:16 GMT Sun, 24 Nov 1996 09:59:19 GMT Sun, 24 Oct 1999 00:31:05 GMT Sun, 24 Oct 1999 15:05:52 GMT Sun, 24 Oct 1999 15:05:54 GMT Sun, 24 Oct 1999 15:05:57 GMT Sun, 24 Oct 1999 17:31:48 GMT Sun, 24 Oct 1999 18:25:44 GMT Sun, 24 Sep 2000 04:22:25 GMT Sun, 24 Sep 2000 04:35:04 GMT Sun, 24 Sep 2000 05:05:55 GMT Sun, 24 Sep 2000 05:06:14 GMT Sun, 24 Sep 2000 22:26:22 GMT Sun, 24 Sep 2000 22:26:24 GMT Sun, 24 Sep 2000 22:26:27 GMT Sun, 24 Sep 2000 22:26:56 GMT Sun, 24 Sep 2000 22:26:59 GMT Sun, 24 Sep 2000 22:27:01 GMT Sun, 24 Sep 2000 22:27:05 GMT Sun, 24 Sep 2000 22:27:08 GMT Sun, 24 Sep 2000 22:27:15 GMT Sun, 24 Sep 2000 22:27:18 GMT Sun, 24 Sep 2000 22:27:22 GMT Sun, 24 Sep 2000 22:27:32 GMT Sun, 24 Sep 2000 22:27:34 GMT Sun, 24 Sep 2000 22:27:38 GMT Sun, 24 Sep 2000 22:29:35 GMT Sun, 24 Sep 2000 22:30:21 GMT Sun, 24 Sep 2000 22:30:25 GMT Sun, 24 Sep 2000 22:30:27 GMT Sun, 24 Sep 2000 22:30:30 GMT Sun, 24 Sep 2000 22:30:34 GMT Sun, 24 Sep 2000 22:30:40 GMT Sun, 24 Sep 2000 22:30:43 GMT Sun, 24 Sep 2000 22:30:45 GMT Sun, 24 Sep 2000 22:32:40 GMT Sun, 24 Sep 2000 22:33:42 GMT Sun, 24 Sep 2000 22:33:48 GMT Sun, 24 Sep 2000 22:33:56 GMT Sun, 24 Sep 2000 22:34:04 GMT Sun, 25 Apr 1999 00:50:05 GMT Sun, 25 Apr 1999 02:00:33 GMT Sun, 25 Dec 1994 13:20:52 GMT Sun, 25 Jan 1998 18:05:46 GMT Sun, 25 Jul 1999 17:26:01 GMT Sun, 25 Jun 2000 06:07:54 GMT Sun, 25 Jun 2000 12:23:51 GMT Sun, 25 Jun 2000 17:33:57 GMT Sun, 25 May 1997 02:12:51 GMT Sun, 26 Dec 1999 02:39:54 GMT Sun, 26 Feb 1995 11:02:20 GMT Sun, 26 Jul 1998 04:28:19 GMT Sun, 26 Jul 1998 10:09:44 GMT Sun, 26 Jul 1998 11:43:06 GMT Sun, 26 Jul 1998 11:43:36 GMT Sun, 26 Jul 1998 21:40:19 GMT Sun, 26 Mar 2000 04:35:03 GMT Sun, 26 Mar 2000 12:39:38 GMT Sun, 26 Mar 2000 12:44:36 GMT Sun, 26 Mar 2000 16:51:42 GMT Sun, 26 Mar 2000 18:27:54 GMT Sun, 26 Mar 2000 20:27:21 GMT Sun, 26 Mar 2000 20:27:24 GMT Sun, 26 Mar 2000 20:27:31 GMT Sun, 26 Mar 2000 20:27:34 GMT Sun, 26 Mar 2000 20:57:00 GMT Sun, 26 Mar 2000 21:16:26 GMT Sun, 26 Mar 2000 22:28:05 GMT Sun, 26 Nov 1995 01:26:39 GMT Sun, 26 Sep 1999 07:29:02 GMT Sun, 26 Sep 1999 08:10:42 GMT Sun, 26 Sep 1999 08:15:12 GMT Sun, 26 Sep 1999 08:33:11 GMT Sun, 26 Sep 1999 15:09:47 GMT Sun, 26 Sep 1999 16:09:30 GMT Sun, 26 Sep 1999 18:07:48 GMT Sun, 26 Sep 1999 22:21:40 GMT Sun, 26 Sep 1999 22:38:39 GMT Sun, 27 Aug 2000 00:03:46 GMT Sun, 27 Aug 2000 00:14:18 GMT Sun, 27 Aug 2000 00:24:46 GMT Sun, 27 Aug 2000 00:37:28 GMT Sun, 27 Aug 2000 02:15:47 GMT Sun, 27 Aug 2000 02:18:12 GMT Sun, 27 Aug 2000 02:18:17 GMT Sun, 27 Aug 2000 03:21:10 GMT Sun, 27 Aug 2000 04:35:02 GMT Sun, 27 Aug 2000 07:53:32 GMT Sun, 27 Aug 2000 22:09:12 GMT Sun, 27 Aug 2000 22:17:22 GMT Sun, 27 Aug 2000 22:17:27 GMT Sun, 27 Aug 2000 22:17:31 GMT Sun, 27 Aug 2000 22:17:53 GMT Sun, 27 Dec 1998 18:36:38 GMT Sun, 27 Feb 1994 12:14:20 GMT Sun, 27 Feb 2000 04:20:13 GMT Sun, 27 Feb 2000 04:22:09 GMT Sun, 27 Feb 2000 04:32:12 GMT Sun, 27 Feb 2000 04:32:14 GMT Sun, 27 Feb 2000 04:33:02 GMT Sun, 27 Feb 2000 04:33:04 GMT Sun, 27 Feb 2000 04:33:06 GMT Sun, 27 Feb 2000 04:33:08 GMT Sun, 27 Feb 2000 04:33:10 GMT Sun, 27 Feb 2000 04:33:43 GMT Sun, 27 Feb 2000 04:45:55 GMT Sun, 27 Feb 2000 04:50:34 GMT Sun, 27 Feb 2000 06:32:57 GMT Sun, 27 Feb 2000 15:34:14 GMT Sun, 27 Feb 2000 16:47:51 GMT Sun, 27 Feb 2000 16:52:18 GMT Sun, 27 Feb 2000 17:00:17 GMT Sun, 27 Feb 2000 21:28:01 GMT Sun, 27 Jun 1993 15:58:16 GMT Sun, 27 Jun 1999 13:43:35 GMT Sun, 27 Jun 1999 13:43:37 GMT Sun, 27 Oct 1991 00:00:00 GMT Sun, 27 Sep 1998 09:08:00 GMT Sun, 27 Sep 1998 09:10:00 GMT Sun, 28 Apr 1996 14:22:27 GMT Sun, 28 Mar 1999 17:02:27 GMT Sun, 28 Mar 1999 20:19:38 GMT Sun, 28 Mar 1999 22:33:36 GMT Sun, 28 May 2000 02:59:52 GMT Sun, 28 May 2000 03:02:04 GMT Sun, 28 May 2000 03:02:14 GMT Sun, 28 May 2000 03:02:18 GMT Sun, 28 May 2000 03:02:24 GMT Sun, 28 May 2000 04:19:06 GMT Sun, 28 May 2000 04:35:05 GMT Sun, 28 May 2000 06:06:17 GMT Sun, 28 May 2000 12:45:46 GMT Sun, 28 May 2000 15:08:42 GMT Sun, 28 May 2000 16:17:48 GMT Sun, 28 Nov 1999 01:45:49 GMT Sun, 28 Nov 1999 02:15:08 GMT Sun, 28 Nov 1999 03:07:53 GMT Sun, 28 Nov 1999 03:38:13 GMT Sun, 28 Nov 1999 03:47:24 GMT Sun, 28 Nov 1999 03:55:45 GMT Sun, 28 Nov 1999 04:11:25 GMT Sun, 28 Nov 1999 11:51:48 GMT Sun, 28 Nov 1999 12:59:51 GMT Sun, 28 Nov 1999 14:01:05 GMT Sun, 28 Nov 1999 15:47:02 GMT Sun, 28 Sep 1997 19:21:47 GMT Sun, 29 Aug 1999 02:47:16 GMT Sun, 29 Aug 1999 19:00:55 GMT Sun, 29 Sep 1996 11:02:00 GMT Sun, 30 Apr 2000 02:47:45 GMT Sun, 30 Apr 2000 07:25:29 GMT Sun, 30 Apr 2000 09:30:32 GMT Sun, 30 Apr 2000 16:10:12 GMT Sun, 30 Apr 2000 16:14:04 GMT Sun, 30 Apr 2000 16:14:06 GMT Sun, 30 Apr 2000 16:14:08 GMT Sun, 30 Apr 2000 16:14:10 GMT Sun, 30 Apr 2000 16:14:12 GMT Sun, 30 Apr 2000 16:14:49 GMT Sun, 30 Apr 2000 16:15:06 GMT Sun, 30 Apr 2000 16:15:08 GMT Sun, 30 Apr 2000 16:23:54 GMT Sun, 30 Apr 2000 16:24:02 GMT Sun, 30 Apr 2000 16:24:12 GMT Sun, 30 Apr 2000 20:51:56 GMT Sun, 30 Jan 2000 01:45:32 GMT Sun, 30 Jan 2000 02:09:01 GMT Sun, 30 Jan 2000 04:41:41 GMT Sun, 30 Jan 2000 12:52:53 GMT Sun, 30 Jan 2000 12:55:53 GMT Sun, 30 Jan 2000 14:09:27 GMT Sun, 30 Jan 2000 14:31:41 GMT Sun, 30 Jan 2000 15:01:07 GMT Sun, 30 Jan 2000 15:06:53 GMT Sun, 30 Jan 2000 16:18:35 GMT Sun, 30 Jan 2000 19:01:22 GMT Sun, 30 Jan 2000 19:18:59 GMT Sun, 30 Jan 2000 19:24:47 GMT Sun, 30 Jan 2000 21:02:41 GMT Sun, 30 Jul 2000 04:34:48 GMT Sun, 30 Jul 2000 11:39:34 GMT Sun, 30 Jul 2000 11:40:20 GMT Sun, 30 Jul 2000 18:13:46 GMT Sun, 30 Jul 2000 23:53:35 GMT Sun, 30 May 1993 22:00:00 GMT Sun, 30 May 1999 11:03:45 GMT Sun, 30 Nov 1997 20:21:45 GMT Sun, 30 Nov 1997 22:00:39 GMT Sun, 30 Oct 1994 01:49:50 GMT Sun, 31 Jan 1999 17:34:10 GMT Sun, 31 Oct 1999 00:05:30 GMT Sun, 31 Oct 1999 14:30:35 GMT Thu Jul 9 16:00:00 1998 Thu, 09 Jul 1998 16:00:00 GMT Thu, 01 Apr 1999 00:00:00 GMT Thu, 01 Dec 1994 20:21:40 GMT Thu, 01 Dec 1994 20:21:56 GMT Thu, 01 Dec 1994 20:22:16 GMT Thu, 01 Dec 1994 20:22:24 GMT Thu, 01 Feb 1996 17:52:03 GMT Thu, 01 Feb 1996 19:30:07 GMT Thu, 01 Feb 1996 19:33:39 GMT Thu, 01 Jan 1970 00:00:00 GMT Thu, 01 Jul 1999 17:40:56 GMT Thu, 01 Jul 1999 17:47:08 GMT Thu, 01 Jul 1999 17:57:36 GMT Thu, 01 Jul 1999 21:22:57 GMT Thu, 01 Jun 1995 21:32:06 GMT Thu, 01 Jun 2000 00:47:05 GMT Thu, 01 Jun 2000 01:07:19 GMT Thu, 01 Jun 2000 03:56:00 GMT Thu, 01 Jun 2000 04:14:34 GMT Thu, 01 Jun 2000 05:31:02 GMT Thu, 01 Jun 2000 06:35:57 GMT Thu, 01 Jun 2000 08:56:43 GMT Thu, 01 Jun 2000 18:07:27 GMT Thu, 01 May 1997 15:31:54 GMT Thu, 01 Oct 1998 05:13:10 GMT Thu, 01 Oct 1998 05:14:48 GMT Thu, 01 Oct 1998 17:02:22 GMT Thu, 02 Apr 1998 00:21:02 GMT Thu, 02 Apr 1998 00:21:04 GMT Thu, 02 Apr 1998 11:07:17 GMT Thu, 02 Apr 1998 23:15:42 GMT Thu, 02 Dec 1999 08:15:57 GMT Thu, 02 Dec 1999 08:16:00 GMT Thu, 02 Dec 1999 10:22:30 GMT Thu, 02 Dec 1999 23:06:20 GMT Thu, 02 Dec 1999 23:28:54 GMT Thu, 02 Jan 1997 13:13:27 GMT Thu, 02 Jul 1998 17:07:00 GMT Thu, 02 Mar 2000 14:55:27 GMT Thu, 02 Mar 2000 15:31:49 GMT Thu, 02 Mar 2000 18:10:24 GMT Thu, 02 Mar 2000 18:13:16 GMT Thu, 02 Mar 2000 18:15:30 GMT Thu, 02 Mar 2000 18:17:41 GMT Thu, 02 Mar 2000 18:18:50 GMT Thu, 02 Mar 2000 18:35:46 GMT Thu, 02 Mar 2000 18:35:49 GMT Thu, 02 Mar 2000 19:32:37 GMT Thu, 02 Mar 2000 19:35:12 GMT Thu, 02 Mar 2000 19:35:23 GMT Thu, 02 Mar 2000 19:41:11 GMT Thu, 02 Mar 2000 19:48:05 GMT Thu, 02 Mar 2000 20:33:15 GMT Thu, 02 Mar 2000 20:56:22 GMT Thu, 02 Mar 2000 21:00:14 GMT Thu, 02 Mar 2000 21:02:48 GMT Thu, 02 Mar 2000 21:03:25 GMT Thu, 02 Mar 2000 21:05:49 GMT Thu, 02 Mar 2000 21:06:43 GMT Thu, 02 Mar 2000 21:07:04 GMT Thu, 02 Mar 2000 21:07:54 GMT Thu, 02 Mar 2000 21:10:12 GMT Thu, 02 Mar 2000 21:10:34 GMT Thu, 02 Mar 2000 21:11:36 GMT Thu, 02 Mar 2000 22:01:19 GMT Thu, 02 Mar 2000 22:01:58 GMT Thu, 02 Mar 2000 22:02:08 GMT Thu, 02 Mar 2000 22:26:38 GMT Thu, 02 Mar 2000 23:07:50 GMT Thu, 02 Oct 1997 21:48:31 GMT Thu, 02 Sep 1999 16:24:11 GMT Thu, 02 Sep 1999 18:22:40 GMT Thu, 03 Aug 2000 00:02:51 GMT Thu, 03 Aug 2000 00:05:06 GMT Thu, 03 Aug 2000 00:34:33 GMT Thu, 03 Aug 2000 00:39:17 GMT Thu, 03 Aug 2000 10:55:58 GMT Thu, 03 Aug 2000 19:25:24 GMT Thu, 03 Aug 2000 19:30:14 GMT Thu, 03 Aug 2000 19:31:44 GMT Thu, 03 Aug 2000 19:39:09 GMT Thu, 03 Aug 2000 19:41:46 GMT Thu, 03 Aug 2000 19:45:15 GMT Thu, 03 Aug 2000 20:00:42 GMT Thu, 03 Aug 2000 20:03:33 GMT Thu, 03 Aug 2000 20:08:04 GMT Thu, 03 Aug 2000 20:12:56 GMT Thu, 03 Aug 2000 20:37:43 GMT Thu, 03 Aug 2000 20:49:25 GMT Thu, 03 Aug 2000 20:50:51 GMT Thu, 03 Aug 2000 20:53:11 GMT Thu, 03 Aug 2000 20:54:30 GMT Thu, 03 Dec 1998 07:59:36 GMT Thu, 03 Dec 1998 15:27:59 GMT Thu, 03 Dec 1998 16:52:46 GMT Thu, 03 Feb 2000 09:01:20 GMT Thu, 03 Feb 2000 16:26:23 GMT Thu, 03 Feb 2000 23:04:43 GMT Thu, 03 Jul 1997 11:54:22 GMT Thu, 03 Jun 1999 06:30:14 GMT Thu, 03 Jun 1999 06:30:34 GMT Thu, 03 Jun 1999 06:32:41 GMT Thu, 03 Jun 1999 06:38:50 GMT Thu, 03 Jun 1999 10:35:27 GMT Thu, 03 Jun 1999 19:18:46 GMT Thu, 03 Jun 1999 23:21:47 GMT Thu, 03 Sep 1998 15:09:35 GMT Thu, 04 Dec 1997 21:12:39 GMT Thu, 04 Feb 1999 20:46:09 GMT Thu, 04 Jan 1996 12:07:58 GMT Thu, 04 Jul 1991 15:03:07 GMT Thu, 04 Mar 1999 21:21:22 GMT Thu, 04 May 2000 08:03:46 GMT Thu, 04 May 2000 14:53:52 GMT Thu, 04 May 2000 14:55:50 GMT Thu, 04 May 2000 14:56:55 GMT Thu, 04 May 2000 15:04:25 GMT Thu, 04 May 2000 15:34:59 GMT Thu, 04 May 2000 15:47:42 GMT Thu, 04 May 2000 15:54:16 GMT Thu, 04 May 2000 16:07:36 GMT Thu, 04 May 2000 16:48:56 GMT Thu, 04 May 2000 16:58:26 GMT Thu, 04 May 2000 17:01:10 GMT Thu, 04 May 2000 17:01:13 GMT Thu, 04 May 2000 17:43:04 GMT Thu, 04 May 2000 17:43:08 GMT Thu, 04 May 2000 17:43:12 GMT Thu, 04 May 2000 17:43:15 GMT Thu, 04 May 2000 17:43:46 GMT Thu, 04 May 2000 17:43:59 GMT Thu, 04 May 2000 17:44:07 GMT Thu, 04 May 2000 22:21:35 GMT Thu, 04 Nov 1999 01:06:59 GMT Thu, 04 Nov 1999 08:28:47 GMT Thu, 04 Nov 1999 08:28:49 GMT Thu, 04 Nov 1999 10:14:50 GMT Thu, 04 Nov 1999 10:15:39 GMT Thu, 04 Nov 1999 10:16:03 GMT Thu, 04 Nov 1999 17:10:22 GMT Thu, 04 Nov 1999 20:25:51 GMT Thu, 05 Aug 1999 21:23:14 GMT Thu, 05 Aug 1999 21:34:02 GMT Thu, 05 Aug 1999 21:43:32 GMT Thu, 05 Aug 1999 22:04:52 GMT Thu, 05 Aug 1999 23:17:54 GMT Thu, 05 Feb 1998 11:26:30 GMT Thu, 05 Feb 1998 12:29:14 GMT Thu, 05 Mar 1998 21:56:24 GMT Thu, 05 Mar 1998 21:58:16 GMT Thu, 05 Mar 1998 21:59:31 GMT Thu, 05 Mar 1998 22:45:34 GMT Thu, 05 Oct 1995 16:45:40 GMT Thu, 06 Apr 2000 16:22:06 GMT Thu, 06 Apr 2000 17:07:51 GMT Thu, 06 Aug 1998 06:06:26 GMT Thu, 06 Feb 1997 05:06:11 GMT Thu, 06 Feb 1997 12:51:09 GMT Thu, 06 Jan 2000 10:34:08 GMT Thu, 06 Jan 2000 17:54:06 GMT Thu, 06 Jan 2000 18:15:52 GMT Thu, 06 Jan 2000 18:30:52 GMT Thu, 06 Jan 2000 21:49:27 GMT Thu, 06 Jan 2000 22:47:29 GMT Thu, 06 Jan 2000 23:10:53 GMT Thu, 06 Jul 2000 01:35:03 GMT Thu, 06 Jul 2000 01:43:15 GMT Thu, 06 Jul 2000 04:05:24 GMT Thu, 06 Jul 2000 08:12:08 GMT Thu, 06 Jul 2000 15:13:45 GMT Thu, 06 Jul 2000 15:19:08 GMT Thu, 06 Jul 2000 21:17:18 GMT Thu, 06 Jul 2000 21:17:23 GMT Thu, 06 Jul 2000 21:17:27 GMT Thu, 06 Jul 2000 22:20:30 GMT Thu, 06 Jul 2000 23:26:49 GMT Thu, 06 Jul 2000 23:29:44 GMT Thu, 06 May 1999 01:19:04 GMT Thu, 06 Sep 1990 05:36:21 GMT Thu, 07 Dec 1995 21:45:08 GMT Thu, 07 Jan 1999 00:02:00 GMT Thu, 07 Jan 1999 13:09:58 GMT Thu, 07 Jan 1999 16:41:55 GMT Thu, 07 Jan 1999 16:46:59 GMT Thu, 07 Jan 1999 17:28:47 GMT Thu, 07 Jan 1999 23:51:33 GMT Thu, 07 May 1998 03:19:13 GMT Thu, 07 May 1998 05:27:02 GMT Thu, 07 Oct 1999 03:54:48 GMT Thu, 07 Oct 1999 03:54:50 GMT Thu, 07 Oct 1999 17:17:09 GMT Thu, 07 Sep 2000 00:54:24 GMT Thu, 07 Sep 2000 01:14:30 GMT Thu, 07 Sep 2000 01:14:37 GMT Thu, 07 Sep 2000 01:14:41 GMT Thu, 07 Sep 2000 01:14:45 GMT Thu, 07 Sep 2000 01:15:01 GMT Thu, 07 Sep 2000 18:52:00 GMT Thu, 08 Apr 1999 21:04:47 GMT Thu, 08 Apr 1999 21:29:41 GMT Thu, 08 Apr 1999 22:00:00 GMT Thu, 08 Aug 1996 00:21:18 GMT Thu, 08 Jul 1999 10:12:03 GMT Thu, 08 Jul 1999 10:35:18 GMT Thu, 08 Jun 2000 00:40:04 GMT Thu, 08 Jun 2000 01:29:54 GMT Thu, 08 Jun 2000 02:14:50 GMT Thu, 08 Jun 2000 02:20:22 GMT Thu, 08 Jun 2000 02:30:06 GMT Thu, 08 Jun 2000 04:18:01 GMT Thu, 08 Jun 2000 04:46:11 GMT Thu, 08 Jun 2000 04:46:43 GMT Thu, 08 Jun 2000 04:47:05 GMT Thu, 08 Jun 2000 04:47:12 GMT Thu, 08 Jun 2000 04:47:22 GMT Thu, 08 Jun 2000 04:48:00 GMT Thu, 08 Jun 2000 04:48:11 GMT Thu, 08 Jun 2000 04:49:22 GMT Thu, 08 Jun 2000 04:55:10 GMT Thu, 08 Jun 2000 09:27:12 GMT Thu, 08 Jun 2000 14:23:44 GMT Thu, 08 Jun 2000 15:26:10 GMT Thu, 08 Jun 2000 15:48:23 GMT Thu, 08 Jun 2000 21:30:21 GMT Thu, 08 Jun 2000 22:20:57 GMT Thu, 08 Jun 2000 23:48:02 GMT Thu, 08 Jun 2000 23:58:43 GMT Thu, 08 Jun 2000 23:58:46 GMT Thu, 08 Jun 2000 23:58:48 GMT Thu, 08 Jun 2000 23:58:50 GMT Thu, 08 Jun 2000 23:58:53 GMT Thu, 08 Jun 2000 23:58:55 GMT Thu, 08 Jun 2000 23:58:57 GMT Thu, 09 Apr 1998 08:20:26 GMT Thu, 09 Dec 1999 12:10:11 GMT Thu, 09 Dec 1999 15:56:34 GMT Thu, 09 Dec 1999 16:55:54 GMT Thu, 09 Dec 1999 17:12:11 GMT Thu, 09 Dec 1999 17:12:14 GMT Thu, 09 Dec 1999 17:19:31 GMT Thu, 09 Dec 1999 17:19:48 GMT Thu, 09 Dec 1999 19:07:33 GMT Thu, 09 Dec 1999 19:21:51 GMT Thu, 09 Dec 1999 21:10:18 GMT Thu, 09 Dec 1999 21:22:21 GMT Thu, 09 Dec 1999 21:23:13 GMT Thu, 09 Dec 1999 21:59:40 GMT Thu, 09 Dec 1999 22:21:01 GMT Thu, 09 Dec 1999 22:21:03 GMT Thu, 09 Dec 1999 22:21:05 GMT Thu, 09 Dec 1999 22:21:07 GMT Thu, 09 Dec 1999 22:21:09 GMT Thu, 09 Dec 1999 22:21:11 GMT Thu, 09 Dec 1999 22:21:13 GMT Thu, 09 Dec 1999 22:21:15 GMT Thu, 09 Dec 1999 22:21:17 GMT Thu, 09 Dec 1999 22:21:19 GMT Thu, 09 Dec 1999 22:21:21 GMT Thu, 09 Dec 1999 22:21:23 GMT Thu, 09 Dec 1999 22:21:25 GMT Thu, 09 Dec 1999 22:21:55 GMT Thu, 09 Dec 1999 22:22:05 GMT Thu, 09 Feb 1995 02:47:24 GMT Thu, 09 Jul 1998 16:02:48 GMT Thu, 09 Jul 1998 16:04:32 GMT Thu, 09 Mar 2000 00:23:21 GMT Thu, 09 Mar 2000 01:58:11 GMT Thu, 09 Mar 2000 04:43:36 GMT Thu, 09 Mar 2000 09:00:28 GMT Thu, 09 Mar 2000 09:52:41 GMT Thu, 09 Mar 2000 11:01:07 GMT Thu, 09 Mar 2000 11:34:26 GMT Thu, 09 Mar 2000 12:21:53 GMT Thu, 09 Mar 2000 17:20:12 GMT Thu, 09 Mar 2000 20:07:57 GMT Thu, 09 Mar 2000 20:08:44 GMT Thu, 09 Mar 2000 20:10:54 GMT Thu, 09 Sep 1999 06:40:19 GMT Thu, 09 Sep 1999 22:29:11 GMT Thu, 10 Aug 2000 00:20:03 GMT Thu, 10 Aug 2000 00:40:24 GMT Thu, 10 Aug 2000 00:40:26 GMT Thu, 10 Aug 2000 00:40:34 GMT Thu, 10 Aug 2000 00:40:40 GMT Thu, 10 Aug 2000 00:40:44 GMT Thu, 10 Aug 2000 00:40:56 GMT Thu, 10 Aug 2000 00:41:02 GMT Thu, 10 Aug 2000 00:41:07 GMT Thu, 10 Aug 2000 00:41:16 GMT Thu, 10 Aug 2000 01:29:22 GMT Thu, 10 Aug 2000 03:07:57 GMT Thu, 10 Aug 2000 03:14:06 GMT Thu, 10 Aug 2000 03:14:08 GMT Thu, 10 Aug 2000 03:14:22 GMT Thu, 10 Aug 2000 15:35:50 GMT Thu, 10 Aug 2000 16:25:05 GMT Thu, 10 Aug 2000 17:49:38 GMT Thu, 10 Aug 2000 18:46:40 GMT Thu, 10 Feb 2000 02:40:23 GMT Thu, 10 Feb 2000 02:48:03 GMT Thu, 10 Feb 2000 02:54:11 GMT Thu, 10 Feb 2000 03:43:47 GMT Thu, 10 Feb 2000 03:43:57 GMT Thu, 10 Feb 2000 03:47:20 GMT Thu, 10 Feb 2000 04:08:09 GMT Thu, 10 Feb 2000 18:24:02 GMT Thu, 10 Feb 2000 20:16:38 GMT Thu, 10 Feb 2000 20:16:59 GMT Thu, 10 Feb 2000 20:22:03 GMT Thu, 10 Feb 2000 20:29:58 GMT Thu, 10 Feb 2000 20:34:24 GMT Thu, 10 Feb 2000 20:37:51 GMT Thu, 10 Feb 2000 20:41:51 GMT Thu, 10 Feb 2000 22:56:48 GMT Thu, 10 Jun 1999 00:20:46 GMT Thu, 10 Jun 1999 00:20:53 GMT Thu, 10 Jun 1999 02:09:21 GMT Thu, 10 Jun 1999 18:25:32 GMT Thu, 10 Sep 1998 23:33:15 GMT Thu, 11 Feb 1999 12:29:29 GMT Thu, 11 Jul 1996 16:37:20 GMT Thu, 11 Jun 1998 10:12:26 GMT Thu, 11 Mar 1999 00:51:35 GMT Thu, 11 Mar 1999 00:53:37 GMT Thu, 11 Mar 1999 05:49:10 GMT Thu, 11 Mar 1999 15:36:02 GMT Thu, 11 Mar 1999 22:31:00 GMT Thu, 11 May 2000 02:07:53 GMT Thu, 11 May 2000 02:46:58 GMT Thu, 11 May 2000 04:52:57 GMT Thu, 11 May 2000 08:31:48 GMT Thu, 11 May 2000 10:30:09 GMT Thu, 11 May 2000 13:27:51 GMT Thu, 11 May 2000 13:30:34 GMT Thu, 11 May 2000 13:54:57 GMT Thu, 11 May 2000 15:32:26 GMT Thu, 11 May 2000 20:48:22 GMT Thu, 11 May 2000 20:49:00 GMT Thu, 11 May 2000 20:49:19 GMT Thu, 11 May 2000 20:49:28 GMT Thu, 11 May 2000 21:09:52 GMT Thu, 11 May 2000 22:18:11 GMT Thu, 11 Nov 1999 00:59:04 GMT Thu, 11 Nov 1999 06:18:38 GMT Thu, 11 Nov 1999 08:55:13 GMT Thu, 11 Nov 1999 18:07:21 GMT Thu, 12 Aug 1999 16:22:34 GMT Thu, 12 Aug 1999 16:42:34 GMT Thu, 12 Aug 1999 17:27:31 GMT Thu, 12 Aug 1999 18:53:22 GMT Thu, 12 Aug 1999 19:26:06 GMT Thu, 12 Aug 1999 23:20:06 GMT Thu, 12 Dec 1996 14:51:09 GMT Thu, 12 Dec 1996 14:54:14 GMT Thu, 12 Dec 1996 14:54:20 GMT Thu, 12 Dec 1996 14:54:22 GMT Thu, 12 Feb 1998 09:16:23 GMT Thu, 12 Jan 1995 15:58:48 GMT Thu, 12 Jun 1997 22:00:00 GMT Thu, 12 Mar 1998 18:32:03 GMT Thu, 12 Mar 1998 19:48:22 GMT Thu, 12 Mar 1998 23:47:23 GMT Thu, 13 Apr 2000 06:53:37 GMT Thu, 13 Apr 2000 08:17:59 GMT Thu, 13 Apr 2000 09:04:12 GMT Thu, 13 Apr 2000 09:28:31 GMT Thu, 13 Apr 2000 09:28:33 GMT Thu, 13 Apr 2000 12:33:17 GMT Thu, 13 Apr 2000 13:51:14 GMT Thu, 13 Apr 2000 16:31:19 GMT Thu, 13 Apr 2000 19:56:48 GMT Thu, 13 Apr 2000 21:06:01 GMT Thu, 13 Apr 2000 21:06:09 GMT Thu, 13 Apr 2000 21:19:31 GMT Thu, 13 Aug 1998 01:55:21 GMT Thu, 13 Aug 1998 01:55:23 GMT Thu, 13 Jan 2000 07:02:50 GMT Thu, 13 Jan 2000 15:24:00 GMT Thu, 13 Jan 2000 17:16:26 GMT Thu, 13 Jan 2000 19:54:37 GMT Thu, 13 Jan 2000 20:03:00 GMT Thu, 13 Jan 2000 21:30:31 GMT Thu, 13 Jul 2000 00:44:26 GMT Thu, 13 Jul 2000 05:18:17 GMT Thu, 13 Jul 2000 16:05:52 GMT Thu, 13 Jul 2000 20:58:42 GMT Thu, 13 Jul 2000 21:36:40 GMT Thu, 13 Jul 2000 21:46:52 GMT Thu, 13 Jul 2000 22:21:41 GMT Thu, 13 Jul 2000 23:11:02 GMT Thu, 13 Jul 2000 23:25:02 GMT Thu, 13 Mar 1997 08:20:02 GMT Thu, 13 May 1999 18:00:09 GMT Thu, 13 Oct 1994 13:51:50 GMT Thu, 13 Oct 1994 20:25:16 GMT Thu, 13 Oct 1994 20:25:23 GMT Thu, 13 Oct 1994 21:27:36 GMT Thu, 13 Oct 1994 21:27:43 GMT Thu, 14 May 1998 07:04:54 GMT Thu, 14 May 1998 17:33:17 GMT Thu, 14 Oct 1999 00:13:18 GMT Thu, 14 Oct 1999 21:10:50 GMT Thu, 14 Oct 1999 21:22:09 GMT Thu, 14 Sep 2000 06:46:43 GMT Thu, 14 Sep 2000 06:46:47 GMT Thu, 14 Sep 2000 12:43:14 GMT Thu, 14 Sep 2000 13:00:34 GMT Thu, 14 Sep 2000 14:35:51 GMT Thu, 14 Sep 2000 14:52:39 GMT Thu, 14 Sep 2000 15:07:49 GMT Thu, 14 Sep 2000 15:22:48 GMT Thu, 14 Sep 2000 18:52:00 GMT Thu, 14 Sep 2000 19:49:47 GMT Thu, 14 Sep 2000 19:50:57 GMT Thu, 14 Sep 2000 19:51:00 GMT Thu, 14 Sep 2000 19:51:02 GMT Thu, 14 Sep 2000 19:51:39 GMT Thu, 15 Apr 1999 02:18:50 GMT Thu, 15 Apr 1999 17:47:01 GMT Thu, 15 Apr 1999 18:15:23 GMT Thu, 15 Apr 1999 18:17:30 GMT Thu, 15 Apr 1999 19:54:25 GMT Thu, 15 Apr 1999 19:58:34 GMT Thu, 15 Apr 1999 20:54:39 GMT Thu, 15 Jun 2000 00:20:25 GMT Thu, 15 Jun 2000 00:45:04 GMT Thu, 15 Jun 2000 04:57:15 GMT Thu, 15 Jun 2000 07:33:35 GMT Thu, 15 Jun 2000 08:53:55 GMT Thu, 15 Jun 2000 08:53:57 GMT Thu, 15 Jun 2000 09:03:58 GMT Thu, 15 Jun 2000 09:04:36 GMT Thu, 15 Jun 2000 09:10:04 GMT Thu, 15 Jun 2000 09:12:42 GMT Thu, 15 Jun 2000 09:14:14 GMT Thu, 15 Jun 2000 09:16:33 GMT Thu, 15 Jun 2000 09:17:15 GMT Thu, 15 Jun 2000 09:18:00 GMT Thu, 15 Jun 2000 09:19:46 GMT Thu, 15 Jun 2000 09:27:03 GMT Thu, 15 Jun 2000 09:28:27 GMT Thu, 15 Jun 2000 09:30:21 GMT Thu, 15 Jun 2000 09:30:48 GMT Thu, 15 Jun 2000 09:32:33 GMT Thu, 15 Jun 2000 09:34:24 GMT Thu, 15 Jun 2000 09:37:30 GMT Thu, 15 Jun 2000 09:39:17 GMT Thu, 15 Jun 2000 09:43:08 GMT Thu, 15 Jun 2000 09:43:51 GMT Thu, 15 Jun 2000 09:44:42 GMT Thu, 15 Jun 2000 09:47:24 GMT Thu, 15 Jun 2000 09:50:45 GMT Thu, 15 Jun 2000 09:51:22 GMT Thu, 15 Jun 2000 09:51:54 GMT Thu, 15 Jun 2000 09:54:03 GMT Thu, 15 Jun 2000 10:02:08 GMT Thu, 15 Jun 2000 11:14:28 GMT Thu, 15 Jun 2000 11:14:33 GMT Thu, 15 Jun 2000 11:25:09 GMT Thu, 15 Jun 2000 11:31:18 GMT Thu, 15 Jun 2000 11:34:09 GMT Thu, 15 Jun 2000 13:56:22 GMT Thu, 15 Jun 2000 13:56:24 GMT Thu, 15 Jun 2000 13:56:26 GMT Thu, 15 Jun 2000 13:58:48 GMT Thu, 15 Jun 2000 13:58:53 GMT Thu, 15 Jun 2000 14:20:34 GMT Thu, 15 Jun 2000 15:32:26 GMT Thu, 15 Jun 2000 15:36:43 GMT Thu, 15 Jun 2000 17:09:18 GMT Thu, 15 Oct 1998 11:33:14 GMT Thu, 16 Apr 1998 03:06:42 GMT Thu, 16 Apr 1998 03:07:42 GMT Thu, 16 Dec 1999 16:10:31 GMT Thu, 16 Dec 1999 21:57:04 GMT Thu, 16 Dec 1999 21:59:38 GMT Thu, 16 Feb 1995 21:39:50 GMT Thu, 16 Jul 1998 12:32:45 GMT Thu, 16 Mar 2000 06:31:14 GMT Thu, 16 Mar 2000 08:56:47 GMT Thu, 16 Mar 2000 11:22:11 GMT Thu, 16 Mar 2000 11:24:33 GMT Thu, 16 Mar 2000 11:26:39 GMT Thu, 16 Mar 2000 11:29:15 GMT Thu, 16 Mar 2000 11:29:36 GMT Thu, 16 Mar 2000 11:34:53 GMT Thu, 16 Mar 2000 13:08:39 GMT Thu, 16 Mar 2000 13:09:08 GMT Thu, 16 Mar 2000 13:10:44 GMT Thu, 16 Mar 2000 13:11:08 GMT Thu, 16 Mar 2000 13:11:48 GMT Thu, 16 Mar 2000 13:13:11 GMT Thu, 16 Mar 2000 17:16:35 GMT Thu, 16 Mar 2000 17:17:52 GMT Thu, 16 Mar 2000 17:18:00 GMT Thu, 16 Mar 2000 17:20:01 GMT Thu, 16 Mar 2000 17:20:03 GMT Thu, 16 Mar 2000 17:20:05 GMT Thu, 16 Mar 2000 17:20:07 GMT Thu, 16 Mar 2000 17:20:09 GMT Thu, 16 Mar 2000 17:26:07 GMT Thu, 16 Mar 2000 17:26:25 GMT Thu, 16 May 1996 06:05:11 GMT Thu, 16 Oct 1997 10:20:00 GMT Thu, 16 Sep 1999 17:44:00 GMT Thu, 17 Aug 2000 04:28:24 GMT Thu, 17 Aug 2000 04:29:31 GMT Thu, 17 Aug 2000 04:29:40 GMT Thu, 17 Aug 2000 04:29:47 GMT Thu, 17 Aug 2000 04:30:21 GMT Thu, 17 Aug 2000 08:17:20 GMT Thu, 17 Aug 2000 08:18:24 GMT Thu, 17 Aug 2000 08:23:54 GMT Thu, 17 Aug 2000 08:24:13 GMT Thu, 17 Aug 2000 16:41:15 GMT Thu, 17 Aug 2000 16:41:22 GMT Thu, 17 Aug 2000 16:41:25 GMT Thu, 17 Dec 1998 04:55:31 GMT Thu, 17 Dec 1998 10:12:26 GMT Thu, 17 Dec 1998 11:12:33 GMT Thu, 17 Dec 1998 17:01:03 GMT Thu, 17 Dec 1998 17:05:43 GMT Thu, 17 Dec 1998 17:06:25 GMT Thu, 17 Dec 1998 17:06:30 GMT Thu, 17 Feb 2000 04:21:45 GMT Thu, 17 Feb 2000 10:05:05 GMT Thu, 17 Feb 2000 10:50:49 GMT Thu, 17 Feb 2000 15:36:49 GMT Thu, 17 Feb 2000 15:59:00 GMT Thu, 17 Feb 2000 16:37:16 GMT Thu, 17 Feb 2000 17:18:46 GMT Thu, 17 Feb 2000 17:20:13 GMT Thu, 17 Feb 2000 17:26:31 GMT Thu, 17 Feb 2000 17:44:49 GMT Thu, 17 Feb 2000 17:44:51 GMT Thu, 17 Feb 2000 19:39:28 GMT Thu, 17 Feb 2000 20:50:35 GMT Thu, 17 Feb 2000 23:04:29 GMT Thu, 17 Feb 2000 23:29:44 GMT Thu, 17 Jul 1997 02:22:50 GMT Thu, 17 Jun 1999 02:26:27 GMT Thu, 17 Jun 1999 08:11:35 GMT Thu, 17 Sep 1998 15:31:59 GMT Thu, 17 Sep 1998 16:35:04 GMT Thu, 18 Feb 1999 03:51:44 GMT Thu, 18 Feb 1999 11:04:46 GMT Thu, 18 Feb 1999 11:19:47 GMT Thu, 18 Feb 1999 23:34:40 GMT Thu, 18 Mar 1999 06:39:45 GMT Thu, 18 Mar 1999 07:11:29 GMT Thu, 18 Mar 1999 10:00:00 GMT Thu, 18 May 2000 01:06:39 GMT Thu, 18 May 2000 03:04:14 GMT Thu, 18 May 2000 03:19:00 GMT Thu, 18 May 2000 13:53:49 GMT Thu, 18 May 2000 14:27:29 GMT Thu, 18 May 2000 14:52:59 GMT Thu, 18 May 2000 22:08:14 GMT Thu, 18 Nov 1999 07:31:22 GMT Thu, 18 Nov 1999 17:29:58 GMT Thu, 19 Aug 1999 04:44:50 GMT Thu, 19 Aug 1999 06:08:12 GMT Thu, 19 Aug 1999 17:54:10 GMT Thu, 19 Aug 1999 23:47:23 GMT Thu, 19 Feb 1998 22:46:15 GMT Thu, 19 Mar 1998 19:50:59 GMT Thu, 19 Nov 1998 21:44:59 GMT Thu, 19 Nov 1998 21:45:01 GMT Thu, 20 Apr 2000 00:04:45 GMT Thu, 20 Apr 2000 13:10:27 GMT Thu, 20 Apr 2000 13:55:45 GMT Thu, 20 Apr 2000 14:06:42 GMT Thu, 20 Apr 2000 14:46:39 GMT Thu, 20 Apr 2000 14:47:35 GMT Thu, 20 Apr 2000 15:30:04 GMT Thu, 20 Apr 2000 18:09:19 GMT Thu, 20 Aug 1998 22:17:06 GMT Thu, 20 Jan 2000 17:48:48 GMT Thu, 20 Jan 2000 18:40:31 GMT Thu, 20 Jan 2000 18:48:35 GMT Thu, 20 Jan 2000 20:35:23 GMT Thu, 20 Jan 2000 23:15:22 GMT Thu, 20 Jul 2000 00:58:59 GMT Thu, 20 Jul 2000 05:39:29 GMT Thu, 20 Jul 2000 09:55:08 GMT Thu, 20 Jul 2000 10:17:45 GMT Thu, 20 Jul 2000 10:34:46 GMT Thu, 20 Jul 2000 10:34:57 GMT Thu, 20 Jul 2000 10:34:59 GMT Thu, 20 Jul 2000 10:35:05 GMT Thu, 20 Jul 2000 11:08:47 GMT Thu, 20 Jul 2000 11:09:21 GMT Thu, 20 Jul 2000 11:21:15 GMT Thu, 20 Jul 2000 13:25:55 GMT Thu, 20 Jul 2000 16:30:02 GMT Thu, 20 Jul 2000 16:32:54 GMT Thu, 20 Jul 2000 16:33:15 GMT Thu, 20 Jul 2000 18:22:14 GMT Thu, 20 Jul 2000 21:09:07 GMT Thu, 20 Jul 2000 22:01:28 GMT Thu, 20 Mar 1997 06:54:37 GMT Thu, 20 May 1999 07:52:00 GMT Thu, 21 Aug 1997 22:58:13 GMT Thu, 21 Aug 1997 22:58:15 GMT Thu, 21 Aug 1997 22:58:21 GMT Thu, 21 Aug 1997 22:58:33 GMT Thu, 21 Dec 1989 23:00:00 GMT Thu, 21 Jan 1999 01:12:34 GMT Thu, 21 Mar 1996 06:18:11 GMT Thu, 21 Mar 1996 06:18:13 GMT Thu, 21 Mar 1996 06:18:37 GMT Thu, 21 Mar 1996 06:18:39 GMT Thu, 21 Mar 1996 06:18:41 GMT Thu, 21 Mar 1996 06:18:43 GMT Thu, 21 May 1998 01:54:35 GMT Thu, 21 May 1998 01:55:04 GMT Thu, 21 May 1998 07:50:03 GMT Thu, 21 May 1998 21:24:09 GMT Thu, 21 Nov 1996 09:23:58 GMT Thu, 21 Oct 1999 05:13:21 GMT Thu, 21 Oct 1999 16:20:51 GMT Thu, 21 Oct 1999 16:20:53 GMT Thu, 21 Oct 1999 19:51:33 GMT Thu, 21 Oct 1999 20:44:07 GMT Thu, 21 Oct 1999 20:44:20 GMT Thu, 21 Oct 1999 20:45:15 GMT Thu, 21 Oct 1999 20:45:38 GMT Thu, 21 Oct 1999 20:46:32 GMT Thu, 21 Oct 1999 21:32:18 GMT Thu, 21 Oct 1999 22:18:07 GMT Thu, 21 Oct 1999 22:18:38 GMT Thu, 21 Sep 2000 02:01:35 GMT Thu, 21 Sep 2000 02:03:53 GMT Thu, 21 Sep 2000 02:04:05 GMT Thu, 21 Sep 2000 04:35:01 GMT Thu, 21 Sep 2000 10:35:35 GMT Thu, 21 Sep 2000 11:25:42 GMT Thu, 21 Sep 2000 11:55:48 GMT Thu, 21 Sep 2000 12:25:52 GMT Thu, 21 Sep 2000 12:50:41 GMT Thu, 21 Sep 2000 13:15:25 GMT Thu, 21 Sep 2000 14:11:08 GMT Thu, 21 Sep 2000 14:14:23 GMT Thu, 21 Sep 2000 14:17:54 GMT Thu, 21 Sep 2000 17:32:13 GMT Thu, 21 Sep 2000 17:50:42 GMT Thu, 21 Sep 2000 17:54:20 GMT Thu, 21 Sep 2000 17:54:22 GMT Thu, 21 Sep 2000 17:54:24 GMT Thu, 21 Sep 2000 17:54:28 GMT Thu, 21 Sep 2000 18:07:20 GMT Thu, 21 Sep 2000 18:07:22 GMT Thu, 21 Sep 2000 18:53:00 GMT Thu, 21 Sep 2000 19:00:54 GMT Thu, 21 Sep 2000 19:01:03 GMT Thu, 21 Sep 2000 19:04:43 GMT Thu, 21 Sep 2000 19:04:52 GMT Thu, 21 Sep 2000 19:08:17 GMT Thu, 21 Sep 2000 19:08:19 GMT Thu, 21 Sep 2000 19:08:21 GMT Thu, 21 Sep 2000 19:08:40 GMT Thu, 21 Sep 2000 20:59:27 GMT Thu, 21 Sep 2000 20:59:38 GMT Thu, 21 Sep 2000 20:59:47 GMT Thu, 21 Sep 2000 20:59:49 GMT Thu, 21 Sep 2000 20:59:51 GMT Thu, 21 Sep 2000 20:59:54 GMT Thu, 21 Sep 2000 20:59:56 GMT Thu, 21 Sep 2000 20:59:58 GMT Thu, 21 Sep 2000 21:00:00 GMT Thu, 21 Sep 2000 21:00:17 GMT Thu, 21 Sep 2000 21:00:19 GMT Thu, 21 Sep 2000 21:00:48 GMT Thu, 22 Feb 1996 11:45:51 GMT Thu, 22 Feb 1996 11:45:53 GMT Thu, 22 Feb 1996 11:45:55 GMT Thu, 22 Feb 1996 11:45:57 GMT Thu, 22 Feb 1996 11:46:01 GMT Thu, 22 Feb 1996 11:46:03 GMT Thu, 22 Feb 1996 11:46:05 GMT Thu, 22 Feb 1996 11:46:07 GMT Thu, 22 Feb 1996 11:46:09 GMT Thu, 22 Feb 1996 11:46:12 GMT Thu, 22 Feb 1996 11:46:14 GMT Thu, 22 Feb 1996 11:46:16 GMT Thu, 22 Feb 1996 11:46:18 GMT Thu, 22 Feb 1996 11:46:20 GMT Thu, 22 Feb 1996 11:46:22 GMT Thu, 22 Feb 1996 11:46:24 GMT Thu, 22 Feb 1996 11:46:26 GMT Thu, 22 Feb 1996 11:46:28 GMT Thu, 22 Feb 1996 11:46:31 GMT Thu, 22 Feb 1996 12:02:18 GMT Thu, 22 Jul 1999 12:24:59 GMT Thu, 22 Jun 1995 18:16:10 GMT Thu, 22 Jun 2000 00:48:04 GMT Thu, 22 Jun 2000 00:48:35 GMT Thu, 22 Jun 2000 00:48:41 GMT Thu, 22 Jun 2000 00:48:44 GMT Thu, 22 Jun 2000 01:13:28 GMT Thu, 22 Jun 2000 01:34:00 GMT Thu, 22 Jun 2000 03:13:05 GMT Thu, 22 Jun 2000 03:13:07 GMT Thu, 22 Jun 2000 06:20:14 GMT Thu, 22 Jun 2000 07:43:40 GMT Thu, 22 Jun 2000 14:15:30 GMT Thu, 22 Jun 2000 18:33:42 GMT Thu, 22 Jun 2000 22:15:38 GMT Thu, 22 Jun 2000 22:42:25 GMT Thu, 22 Jun 2000 22:52:03 GMT Thu, 22 Jun 2000 22:57:08 GMT Thu, 22 Jun 2000 22:59:46 GMT Thu, 22 Jun 2000 23:04:13 GMT Thu, 22 Jun 2000 23:15:07 GMT Thu, 22 Oct 1998 20:56:51 GMT Thu, 23 Dec 1999 00:05:16 GMT Thu, 23 Dec 1999 00:37:06 GMT Thu, 23 Dec 1999 00:43:14 GMT Thu, 23 Dec 1999 01:38:27 GMT Thu, 23 Dec 1999 09:14:48 GMT Thu, 23 Jan 1997 19:01:28 GMT Thu, 23 Jul 1998 18:43:34 GMT Thu, 23 Jun 1994 04:00:22 GMT Thu, 23 Mar 2000 00:06:08 GMT Thu, 23 Mar 2000 00:35:07 GMT Thu, 23 Mar 2000 01:03:28 GMT Thu, 23 Mar 2000 01:33:40 GMT Thu, 23 Mar 2000 04:42:40 GMT Thu, 23 Mar 2000 06:38:41 GMT Thu, 23 Mar 2000 08:37:09 GMT Thu, 23 Mar 2000 11:59:02 GMT Thu, 23 Mar 2000 12:09:48 GMT Thu, 23 Mar 2000 12:34:41 GMT Thu, 23 Mar 2000 12:35:55 GMT Thu, 23 Mar 2000 12:57:14 GMT Thu, 23 Mar 2000 12:58:12 GMT Thu, 23 Mar 2000 13:23:47 GMT Thu, 23 Mar 2000 14:19:31 GMT Thu, 23 Mar 2000 14:42:47 GMT Thu, 23 Mar 2000 14:58:11 GMT Thu, 23 Mar 2000 16:29:43 GMT Thu, 23 Mar 2000 16:31:19 GMT Thu, 23 Mar 2000 16:31:22 GMT Thu, 23 Mar 2000 16:45:04 GMT Thu, 23 Mar 2000 16:59:34 GMT Thu, 23 Mar 2000 17:04:40 GMT Thu, 23 Mar 2000 17:14:10 GMT Thu, 23 Mar 2000 17:14:18 GMT Thu, 23 Mar 2000 17:14:25 GMT Thu, 23 Mar 2000 17:14:32 GMT Thu, 23 Mar 2000 17:14:40 GMT Thu, 23 Mar 2000 17:14:47 GMT Thu, 23 Mar 2000 17:14:59 GMT Thu, 23 Mar 2000 17:15:06 GMT Thu, 23 Mar 2000 17:15:13 GMT Thu, 23 Mar 2000 17:15:20 GMT Thu, 23 Mar 2000 17:15:27 GMT Thu, 23 Mar 2000 17:15:34 GMT Thu, 23 Mar 2000 17:15:42 GMT Thu, 23 Mar 2000 17:15:53 GMT Thu, 23 Mar 2000 17:16:01 GMT Thu, 23 Mar 2000 17:16:19 GMT Thu, 23 Mar 2000 17:20:42 GMT Thu, 23 Mar 2000 17:36:42 GMT Thu, 23 Mar 2000 17:37:42 GMT Thu, 23 Mar 2000 17:42:59 GMT Thu, 23 Mar 2000 17:45:08 GMT Thu, 23 Mar 2000 17:51:09 GMT Thu, 23 Mar 2000 17:52:05 GMT Thu, 23 Mar 2000 19:01:14 GMT Thu, 23 Mar 2000 21:51:23 GMT Thu, 23 Mar 2000 23:11:51 GMT Thu, 23 Mar 2000 23:42:06 GMT Thu, 23 May 1996 11:33:37 GMT Thu, 23 Oct 1997 21:00:15 GMT Thu, 23 Sep 1999 09:42:37 GMT Thu, 24 Apr 1997 02:01:17 GMT Thu, 24 Apr 1997 02:01:27 GMT Thu, 24 Aug 2000 07:01:26 GMT Thu, 24 Aug 2000 07:08:38 GMT Thu, 24 Aug 2000 07:12:45 GMT Thu, 24 Aug 2000 07:12:53 GMT Thu, 24 Aug 2000 07:13:06 GMT Thu, 24 Aug 2000 07:13:14 GMT Thu, 24 Aug 2000 07:14:19 GMT Thu, 24 Aug 2000 07:14:22 GMT Thu, 24 Aug 2000 07:14:40 GMT Thu, 24 Aug 2000 07:14:46 GMT Thu, 24 Aug 2000 07:14:53 GMT Thu, 24 Aug 2000 07:14:55 GMT Thu, 24 Aug 2000 07:15:00 GMT Thu, 24 Aug 2000 07:16:46 GMT Thu, 24 Aug 2000 07:16:56 GMT Thu, 24 Aug 2000 07:17:03 GMT Thu, 24 Aug 2000 07:17:13 GMT Thu, 24 Aug 2000 07:17:20 GMT Thu, 24 Aug 2000 07:17:28 GMT Thu, 24 Aug 2000 07:17:36 GMT Thu, 24 Aug 2000 07:17:43 GMT Thu, 24 Aug 2000 07:20:57 GMT Thu, 24 Aug 2000 07:21:26 GMT Thu, 24 Aug 2000 07:22:02 GMT Thu, 24 Aug 2000 07:50:57 GMT Thu, 24 Aug 2000 08:51:56 GMT Thu, 24 Aug 2000 08:52:22 GMT Thu, 24 Aug 2000 08:52:26 GMT Thu, 24 Aug 2000 08:52:32 GMT Thu, 24 Aug 2000 09:06:46 GMT Thu, 24 Aug 2000 09:06:51 GMT Thu, 24 Aug 2000 09:06:53 GMT Thu, 24 Aug 2000 09:07:55 GMT Thu, 24 Aug 2000 09:08:28 GMT Thu, 24 Aug 2000 10:49:51 GMT Thu, 24 Aug 2000 10:50:00 GMT Thu, 24 Aug 2000 10:50:32 GMT Thu, 24 Aug 2000 11:42:40 GMT Thu, 24 Aug 2000 12:06:31 GMT Thu, 24 Aug 2000 12:06:47 GMT Thu, 24 Aug 2000 12:07:23 GMT Thu, 24 Aug 2000 12:07:25 GMT Thu, 24 Aug 2000 12:07:27 GMT Thu, 24 Aug 2000 12:07:29 GMT Thu, 24 Aug 2000 12:07:31 GMT Thu, 24 Aug 2000 12:07:35 GMT Thu, 24 Aug 2000 12:07:39 GMT Thu, 24 Aug 2000 12:07:41 GMT Thu, 24 Aug 2000 12:07:43 GMT Thu, 24 Aug 2000 12:07:45 GMT Thu, 24 Aug 2000 12:07:47 GMT Thu, 24 Aug 2000 12:07:49 GMT Thu, 24 Aug 2000 12:07:53 GMT Thu, 24 Aug 2000 12:44:50 GMT Thu, 24 Aug 2000 13:56:07 GMT Thu, 24 Aug 2000 14:50:46 GMT Thu, 24 Aug 2000 19:19:33 GMT Thu, 24 Aug 2000 19:22:43 GMT Thu, 24 Aug 2000 19:22:45 GMT Thu, 24 Aug 2000 19:22:57 GMT Thu, 24 Aug 2000 19:44:52 GMT Thu, 24 Aug 2000 20:01:25 GMT Thu, 24 Feb 2000 03:38:04 GMT Thu, 24 Feb 2000 10:25:16 GMT Thu, 24 Feb 2000 10:28:08 GMT Thu, 24 Feb 2000 15:07:15 GMT Thu, 24 Feb 2000 16:02:55 GMT Thu, 24 Feb 2000 16:02:59 GMT Thu, 24 Feb 2000 17:53:48 GMT Thu, 24 Feb 2000 17:57:55 GMT Thu, 24 Feb 2000 18:08:32 GMT Thu, 24 Feb 2000 18:14:29 GMT Thu, 24 Feb 2000 18:15:58 GMT Thu, 24 Feb 2000 18:38:35 GMT Thu, 24 Jun 1993 19:24:24 GMT Thu, 24 Oct 1996 19:06:11 GMT Thu, 24 Sep 1998 00:54:00 GMT Thu, 24 Sep 1998 23:42:52 GMT Thu, 24 Sep 1998 23:47:33 GMT Thu, 24 Sep 1998 23:54:41 GMT Thu, 25 Feb 1993 13:43:10 GMT Thu, 25 Feb 1999 18:02:12 GMT Thu, 25 Jun 1998 19:24:28 GMT Thu, 25 Mar 1999 19:43:08 GMT Thu, 25 Mar 1999 19:43:24 GMT Thu, 25 Mar 1999 19:43:28 GMT Thu, 25 May 2000 02:41:54 GMT Thu, 25 May 2000 02:44:55 GMT Thu, 25 May 2000 02:55:03 GMT Thu, 25 May 2000 03:07:16 GMT Thu, 25 May 2000 03:07:18 GMT Thu, 25 May 2000 03:07:26 GMT Thu, 25 May 2000 03:08:13 GMT Thu, 25 May 2000 03:35:30 GMT Thu, 25 May 2000 03:37:35 GMT Thu, 25 May 2000 05:56:25 GMT Thu, 25 May 2000 06:04:37 GMT Thu, 25 May 2000 08:42:00 GMT Thu, 25 May 2000 09:22:19 GMT Thu, 25 May 2000 12:22:24 GMT Thu, 25 May 2000 15:54:03 GMT Thu, 25 May 2000 16:19:17 GMT Thu, 25 May 2000 17:22:18 GMT Thu, 25 May 2000 22:00:53 GMT Thu, 25 May 2000 22:22:09 GMT Thu, 25 May 2000 22:26:02 GMT Thu, 25 Nov 1999 02:14:54 GMT Thu, 25 Nov 1999 04:48:39 GMT Thu, 25 Sep 1997 21:35:09 GMT Thu, 26 Aug 1999 12:06:20 GMT Thu, 26 Aug 1999 16:41:36 GMT Thu, 26 Aug 1999 19:42:31 GMT Thu, 26 Aug 1999 19:42:33 GMT Thu, 26 Aug 1999 21:18:06 GMT Thu, 26 Aug 1999 21:28:05 GMT Thu, 26 Aug 1999 21:54:23 GMT Thu, 26 Dec 1996 12:01:58 GMT Thu, 26 Dec 1996 12:11:04 GMT Thu, 26 Dec 1996 12:16:56 GMT Thu, 26 Jan 1995 21:03:50 GMT Thu, 26 Jun 1997 15:51:06 GMT Thu, 26 Jun 1997 19:33:37 GMT Thu, 26 Jun 1997 19:33:39 GMT Thu, 26 Jun 1997 19:41:35 GMT Thu, 26 Jun 1997 22:00:00 GMT Thu, 26 Mar 1998 09:00:22 GMT Thu, 26 May 1994 13:46:40 GMT Thu, 26 Nov 1998 01:05:03 GMT Thu, 26 Nov 1998 01:05:31 GMT Thu, 26 Nov 1998 10:12:46 GMT Thu, 27 Apr 2000 00:45:54 GMT Thu, 27 Apr 2000 01:01:45 GMT Thu, 27 Apr 2000 08:53:19 GMT Thu, 27 Apr 2000 10:14:02 GMT Thu, 27 Apr 2000 10:24:59 GMT Thu, 27 Apr 2000 11:20:09 GMT Thu, 27 Apr 2000 11:21:05 GMT Thu, 27 Apr 2000 11:26:15 GMT Thu, 27 Apr 2000 16:23:34 GMT Thu, 27 Apr 2000 19:00:08 GMT Thu, 27 Aug 1998 17:58:23 GMT Thu, 27 Aug 1998 23:41:29 GMT Thu, 27 Jan 2000 00:16:03 GMT Thu, 27 Jan 2000 03:19:16 GMT Thu, 27 Jan 2000 03:19:18 GMT Thu, 27 Jan 2000 03:19:23 GMT Thu, 27 Jan 2000 10:54:00 GMT Thu, 27 Jan 2000 14:32:14 GMT Thu, 27 Jan 2000 15:46:03 GMT Thu, 27 Jan 2000 20:51:15 GMT Thu, 27 Jan 2000 20:53:32 GMT Thu, 27 Jul 2000 08:29:02 GMT Thu, 27 Jul 2000 09:28:07 GMT Thu, 27 Jul 2000 15:42:18 GMT Thu, 27 Jul 2000 15:59:56 GMT Thu, 27 Jul 2000 16:00:18 GMT Thu, 27 Jul 2000 23:11:53 GMT Thu, 27 Mar 1997 22:40:08 GMT Thu, 27 Mar 1997 22:40:11 GMT Thu, 27 May 1999 04:51:17 GMT Thu, 27 May 1999 16:55:22 GMT Thu, 27 Nov 1997 22:29:40 GMT Thu, 28 Feb 1991 00:00:00 GMT Thu, 28 May 1998 11:47:28 GMT Thu, 28 Oct 1999 00:04:51 GMT Thu, 28 Oct 1999 01:27:16 GMT Thu, 28 Oct 1999 01:45:00 GMT Thu, 28 Oct 1999 01:45:26 GMT Thu, 28 Oct 1999 01:45:33 GMT Thu, 28 Oct 1999 01:48:37 GMT Thu, 28 Oct 1999 01:48:41 GMT Thu, 28 Oct 1999 01:48:43 GMT Thu, 28 Oct 1999 01:53:17 GMT Thu, 28 Oct 1999 11:49:02 GMT Thu, 28 Oct 1999 12:44:11 GMT Thu, 28 Oct 1999 14:04:49 GMT Thu, 28 Oct 1999 14:54:18 GMT Thu, 28 Oct 1999 16:17:43 GMT Thu, 28 Oct 1999 17:42:02 GMT Thu, 28 Oct 1999 20:45:37 GMT Thu, 28 Oct 1999 21:34:44 GMT Thu, 28 Oct 1999 21:45:16 GMT Thu, 28 Oct 1999 23:13:00 GMT Thu, 28 Oct 1999 23:13:07 GMT Thu, 29 Apr 1999 18:53:41 GMT Thu, 29 Apr 1999 19:39:07 GMT Thu, 29 Jul 1999 17:53:54 GMT Thu, 29 Jul 1999 22:28:52 GMT Thu, 29 Jun 2000 00:48:04 GMT Thu, 29 Jun 2000 01:20:45 GMT Thu, 29 Jun 2000 06:56:27 GMT Thu, 29 Jun 2000 06:56:32 GMT Thu, 29 Jun 2000 06:56:38 GMT Thu, 29 Jun 2000 06:56:43 GMT Thu, 29 Jun 2000 06:56:57 GMT Thu, 29 Jun 2000 06:57:30 GMT Thu, 29 Jun 2000 06:57:37 GMT Thu, 29 Jun 2000 08:22:15 GMT Thu, 29 Jun 2000 08:23:48 GMT Thu, 29 Jun 2000 14:03:10 GMT Thu, 29 Jun 2000 22:06:47 GMT Thu, 29 Jun 2000 22:41:44 GMT Thu, 29 Oct 1998 06:04:05 GMT Thu, 30 Apr 1998 05:46:59 GMT Thu, 30 Dec 1999 01:13:02 GMT Thu, 30 Dec 1999 01:16:30 GMT Thu, 30 Dec 1999 10:36:11 GMT Thu, 30 Dec 1999 14:58:54 GMT Thu, 30 Dec 1999 19:51:26 GMT Thu, 30 Dec 1999 21:02:56 GMT Thu, 30 Jul 1998 18:08:19 GMT Thu, 30 Jul 1998 18:17:12 GMT Thu, 30 Mar 1995 07:28:43 GMT Thu, 30 Mar 1995 07:28:51 GMT Thu, 30 Mar 2000 01:27:15 GMT Thu, 30 Mar 2000 02:29:35 GMT Thu, 30 Mar 2000 09:15:18 GMT Thu, 30 Mar 2000 09:53:11 GMT Thu, 30 Mar 2000 13:21:05 GMT Thu, 30 Mar 2000 14:56:47 GMT Thu, 30 Mar 2000 15:46:44 GMT Thu, 30 Mar 2000 21:33:51 GMT Thu, 31 Aug 1995 12:41:00 GMT Thu, 31 Aug 2000 08:59:02 GMT Thu, 31 Aug 2000 11:44:47 GMT Thu, 31 Aug 2000 12:18:12 GMT Thu, 31 Aug 2000 16:50:28 GMT Thu, 31 Aug 2000 16:50:30 GMT Thu, 31 Aug 2000 16:50:32 GMT Thu, 31 Aug 2000 16:50:36 GMT Thu, 31 Aug 2000 16:51:03 GMT Thu, 31 Aug 2000 16:51:25 GMT Thu, 31 Aug 2000 16:52:01 GMT Thu, 31 Aug 2000 16:53:28 GMT Thu, 31 Aug 2000 16:53:31 GMT Thu, 31 Aug 2000 16:53:38 GMT Thu, 31 Aug 2000 16:53:40 GMT Thu, 31 Aug 2000 16:53:42 GMT Thu, 31 Aug 2000 16:54:13 GMT Thu, 31 Aug 2000 16:54:40 GMT Thu, 31 Aug 2000 20:05:41 GMT Thu, 31 Aug 2000 20:05:45 GMT Thu, 31 Dec 1998 20:05:12 GMT Tue, 01 Aug 1995 15:08:17 GMT Tue, 01 Aug 2000 01:49:23 GMT Tue, 01 Aug 2000 08:46:53 GMT Tue, 01 Dec 1998 22:41:23 GMT Tue, 01 Dec 1998 22:41:25 GMT Tue, 01 Dec 1998 22:42:09 GMT Tue, 01 Dec 1998 22:42:29 GMT Tue, 01 Dec 1998 22:42:31 GMT Tue, 01 Feb 2000 00:30:19 GMT Tue, 01 Feb 2000 07:37:19 GMT Tue, 01 Feb 2000 07:43:35 GMT Tue, 01 Feb 2000 07:44:11 GMT Tue, 01 Feb 2000 08:07:12 GMT Tue, 01 Feb 2000 09:16:06 GMT Tue, 01 Feb 2000 13:21:52 GMT Tue, 01 Feb 2000 14:11:18 GMT Tue, 01 Jul 1997 08:44:32 GMT Tue, 01 Jul 1997 08:44:38 GMT Tue, 01 Jul 1997 08:44:44 GMT Tue, 01 Jul 1997 08:44:50 GMT Tue, 01 Jul 1997 08:44:56 GMT Tue, 01 Jul 1997 08:45:02 GMT Tue, 01 Jul 1997 08:45:08 GMT Tue, 01 Jul 1997 08:45:16 GMT Tue, 01 Jul 1997 08:45:22 GMT Tue, 01 Jul 1997 08:45:28 GMT Tue, 01 Jul 1997 08:45:34 GMT Tue, 01 Jul 1997 08:45:40 GMT Tue, 01 Jul 1997 08:45:46 GMT Tue, 01 Jul 1997 08:45:54 GMT Tue, 01 Jul 1997 08:46:00 GMT Tue, 01 Jul 1997 08:46:06 GMT Tue, 01 Jul 1997 08:46:12 GMT Tue, 01 Jul 1997 08:46:18 GMT Tue, 01 Jul 1997 08:46:26 GMT Tue, 01 Jul 1997 08:46:32 GMT Tue, 01 Jul 1997 08:46:38 GMT Tue, 01 Jul 1997 08:46:46 GMT Tue, 01 Jul 1997 08:46:52 GMT Tue, 01 Jul 1997 08:46:58 GMT Tue, 01 Jul 1997 08:47:04 GMT Tue, 01 Jul 1997 08:47:10 GMT Tue, 01 Jul 1997 08:47:18 GMT Tue, 01 Jul 1997 08:47:24 GMT Tue, 01 Jul 1997 08:47:32 GMT Tue, 01 Jul 1997 08:47:38 GMT Tue, 01 Jul 1997 08:47:44 GMT Tue, 01 Jul 1997 08:47:48 GMT Tue, 01 Jul 1997 08:47:52 GMT Tue, 01 Jul 1997 08:47:56 GMT Tue, 01 Jul 1997 08:48:02 GMT Tue, 01 Jul 1997 08:48:06 GMT Tue, 01 Jul 1997 08:48:10 GMT Tue, 01 Jul 1997 08:48:16 GMT Tue, 01 Jul 1997 08:48:20 GMT Tue, 01 Jul 1997 08:48:28 GMT Tue, 01 Jul 1997 08:48:34 GMT Tue, 01 Jul 1997 08:48:40 GMT Tue, 01 Jul 1997 08:48:46 GMT Tue, 01 Jul 1997 08:48:52 GMT Tue, 01 Jul 1997 08:48:58 GMT Tue, 01 Jul 1997 08:49:04 GMT Tue, 01 Jul 1997 08:49:10 GMT Tue, 01 Jul 1997 08:49:16 GMT Tue, 01 Jul 1997 08:49:20 GMT Tue, 01 Jul 1997 08:49:26 GMT Tue, 01 Jul 1997 08:49:30 GMT Tue, 01 Jun 1993 07:38:02 GMT Tue, 01 Jun 1993 07:38:12 GMT Tue, 01 Jun 1993 07:39:02 GMT Tue, 01 Jun 1999 01:03:05 GMT Tue, 01 Jun 1999 05:08:10 GMT Tue, 01 Nov 1994 14:42:10 GMT Tue, 01 Nov 1994 22:15:51 GMT Tue, 01 Sep 1998 17:43:13 GMT Tue, 01 Sep 1998 20:20:38 GMT Tue, 01 Sep 1998 21:14:42 GMT Tue, 01 Sep 1998 22:38:30 GMT Tue, 02 Dec 1997 10:24:27 GMT Tue, 02 Dec 1997 19:41:44 GMT Tue, 02 Feb 1999 00:57:54 GMT Tue, 02 Feb 1999 00:59:34 GMT Tue, 02 Feb 1999 02:45:28 GMT Tue, 02 Feb 1999 11:52:44 GMT Tue, 02 Feb 1999 11:54:10 GMT Tue, 02 Feb 1999 11:56:14 GMT Tue, 02 Jul 1996 14:49:38 GMT Tue, 02 Mar 1999 15:01:00 GMT Tue, 02 May 2000 01:04:17 GMT Tue, 02 May 2000 02:01:56 GMT Tue, 02 May 2000 02:01:58 GMT Tue, 02 May 2000 03:24:34 GMT Tue, 02 May 2000 03:24:45 GMT Tue, 02 May 2000 04:17:13 GMT Tue, 02 May 2000 08:10:39 GMT Tue, 02 May 2000 09:36:12 GMT Tue, 02 May 2000 09:36:14 GMT Tue, 02 May 2000 09:36:18 GMT Tue, 02 May 2000 09:36:23 GMT Tue, 02 May 2000 13:37:13 GMT Tue, 02 May 2000 15:39:10 GMT Tue, 02 May 2000 15:41:30 GMT Tue, 02 May 2000 15:41:32 GMT Tue, 02 May 2000 15:41:40 GMT Tue, 02 May 2000 17:23:20 GMT Tue, 02 May 2000 20:00:11 GMT Tue, 02 May 2000 23:46:54 GMT Tue, 02 Nov 1999 01:31:00 GMT Tue, 02 Nov 1999 16:19:44 GMT Tue, 02 Nov 1999 19:29:32 GMT Tue, 02 Nov 1999 20:11:32 GMT Tue, 02 Nov 1999 20:17:47 GMT Tue, 02 Nov 1999 20:17:50 GMT Tue, 02 Nov 1999 20:19:46 GMT Tue, 02 Nov 1999 20:19:49 GMT Tue, 02 Nov 1999 21:09:37 GMT Tue, 02 Nov 1999 21:31:37 GMT Tue, 03 Aug 1993 18:43:40 GMT Tue, 03 Aug 1999 05:07:16 GMT Tue, 03 Aug 1999 14:19:18 GMT Tue, 03 Aug 1999 17:27:39 GMT Tue, 03 Aug 1999 19:10:35 GMT Tue, 03 Dec 1996 16:12:40 GMT Tue, 03 Dec 1996 16:13:14 GMT Tue, 03 Jan 1995 11:57:26 GMT Tue, 03 Jan 1995 22:59:49 GMT Tue, 03 Jun 1997 03:26:32 GMT Tue, 03 Nov 1998 21:38:52 GMT Tue, 04 Apr 2000 01:40:05 GMT Tue, 04 Apr 2000 09:56:21 GMT Tue, 04 Apr 2000 10:17:20 GMT Tue, 04 Apr 2000 10:44:57 GMT Tue, 04 Apr 2000 11:43:28 GMT Tue, 04 Apr 2000 12:51:57 GMT Tue, 04 Apr 2000 13:00:49 GMT Tue, 04 Apr 2000 13:24:43 GMT Tue, 04 Apr 2000 13:27:22 GMT Tue, 04 Apr 2000 13:28:16 GMT Tue, 04 Apr 2000 13:28:27 GMT Tue, 04 Apr 2000 13:28:42 GMT Tue, 04 Apr 2000 13:28:49 GMT Tue, 04 Apr 2000 14:23:08 GMT Tue, 04 Apr 2000 15:04:35 GMT Tue, 04 Apr 2000 15:42:36 GMT Tue, 04 Apr 2000 15:43:01 GMT Tue, 04 Apr 2000 15:43:04 GMT Tue, 04 Apr 2000 23:55:32 GMT Tue, 04 Aug 1998 23:03:35 GMT Tue, 04 Jan 2000 00:02:01 GMT Tue, 04 Jan 2000 00:11:18 GMT Tue, 04 Jan 2000 00:11:22 GMT Tue, 04 Jan 2000 13:11:50 GMT Tue, 04 Jan 2000 19:17:47 GMT Tue, 04 Jan 2000 22:48:26 GMT Tue, 04 Jul 2000 00:44:42 GMT Tue, 04 Jul 2000 01:24:37 GMT Tue, 04 Jul 2000 01:24:39 GMT Tue, 04 Jul 2000 01:24:46 GMT Tue, 04 Jul 2000 01:39:25 GMT Tue, 04 Jul 2000 15:47:56 GMT Tue, 04 Jul 2000 21:52:19 GMT Tue, 04 Jul 2000 23:08:58 GMT Tue, 04 May 1999 11:21:13 GMT Tue, 04 May 1999 20:29:57 GMT Tue, 04 May 1999 20:34:52 GMT Tue, 04 May 1999 20:49:17 GMT Tue, 05 Aug 1997 16:49:51 GMT Tue, 05 Dec 1989 10:14:34 GMT Tue, 05 Dec 1989 11:16:54 GMT Tue, 05 Mar 1996 11:03:27 GMT Tue, 05 Sep 2000 12:13:21 GMT Tue, 05 Sep 2000 13:31:48 GMT Tue, 05 Sep 2000 13:34:58 GMT Tue, 05 Sep 2000 13:35:00 GMT Tue, 05 Sep 2000 13:35:02 GMT Tue, 05 Sep 2000 13:53:50 GMT Tue, 05 Sep 2000 13:55:19 GMT Tue, 05 Sep 2000 18:52:00 GMT Tue, 05 Sep 2000 19:45:06 GMT Tue, 06 Apr 1999 20:36:33 GMT Tue, 06 Apr 1999 21:25:50 GMT Tue, 06 Aug 1996 10:50:46 GMT Tue, 06 Aug 1996 13:58:00 GMT Tue, 06 Aug 1996 13:58:18 GMT Tue, 06 Feb 1996 04:33:15 GMT Tue, 06 Jul 1999 01:38:34 GMT Tue, 06 Jul 1999 02:52:52 GMT Tue, 06 Jul 1999 02:58:25 GMT Tue, 06 Jul 1999 03:04:47 GMT Tue, 06 Jul 1999 03:09:40 GMT Tue, 06 Jul 1999 03:35:18 GMT Tue, 06 Jul 1999 09:12:15 GMT Tue, 06 Jul 1999 09:53:05 GMT Tue, 06 Jul 1999 09:53:08 GMT Tue, 06 Jul 1999 13:19:48 GMT Tue, 06 Jul 1999 13:20:02 GMT Tue, 06 Jun 1995 08:22:11 GMT Tue, 06 Jun 1995 08:22:18 GMT Tue, 06 Jun 2000 00:54:05 GMT Tue, 06 Jun 2000 01:02:40 GMT Tue, 06 Jun 2000 01:02:46 GMT Tue, 06 Jun 2000 01:03:03 GMT Tue, 06 Jun 2000 01:03:07 GMT Tue, 06 Jun 2000 01:03:45 GMT Tue, 06 Jun 2000 01:03:48 GMT Tue, 06 Jun 2000 01:06:00 GMT Tue, 06 Jun 2000 01:15:44 GMT Tue, 06 Jun 2000 02:29:28 GMT Tue, 06 Jun 2000 02:29:38 GMT Tue, 06 Jun 2000 02:40:03 GMT Tue, 06 Jun 2000 07:07:30 GMT Tue, 06 Jun 2000 08:42:13 GMT Tue, 06 Jun 2000 09:29:40 GMT Tue, 06 Jun 2000 14:39:37 GMT Tue, 06 Jun 2000 15:26:24 GMT Tue, 06 Jun 2000 15:26:26 GMT Tue, 06 Jun 2000 15:26:28 GMT Tue, 06 Jun 2000 15:26:30 GMT Tue, 06 Jun 2000 15:26:32 GMT Tue, 06 Jun 2000 15:26:34 GMT Tue, 06 Jun 2000 15:26:36 GMT Tue, 06 Jun 2000 15:26:38 GMT Tue, 06 Jun 2000 15:26:40 GMT Tue, 06 Jun 2000 15:26:43 GMT Tue, 06 Jun 2000 15:26:45 GMT Tue, 06 Jun 2000 15:26:48 GMT Tue, 06 Jun 2000 15:29:19 GMT Tue, 06 Jun 2000 18:52:00 GMT Tue, 06 Jun 2000 21:45:43 GMT Tue, 06 Jun 2000 23:36:58 GMT Tue, 06 Oct 1998 16:39:44 GMT Tue, 07 Apr 1998 16:04:18 GMT Tue, 07 Dec 1999 00:19:13 GMT Tue, 07 Dec 1999 01:09:28 GMT Tue, 07 Dec 1999 02:01:00 GMT Tue, 07 Dec 1999 02:11:20 GMT Tue, 07 Dec 1999 12:19:48 GMT Tue, 07 Dec 1999 15:47:34 GMT Tue, 07 Dec 1999 15:47:38 GMT Tue, 07 Dec 1999 17:36:24 GMT Tue, 07 Dec 1999 18:03:12 GMT Tue, 07 Dec 1999 18:14:17 GMT Tue, 07 Dec 1999 19:17:33 GMT Tue, 07 Dec 1999 20:25:47 GMT Tue, 07 Dec 1999 21:00:33 GMT Tue, 07 Dec 1999 21:59:01 GMT Tue, 07 Dec 1999 22:33:32 GMT Tue, 07 Jan 1997 01:21:20 GMT Tue, 07 Jan 1997 01:21:46 GMT Tue, 07 Jan 1997 16:28:22 GMT Tue, 07 Jan 1997 17:03:48 GMT Tue, 07 Jul 1998 09:41:04 GMT Tue, 07 Jul 1998 09:41:10 GMT Tue, 07 Jul 1998 09:41:14 GMT Tue, 07 Jul 1998 09:41:18 GMT Tue, 07 Jul 1998 09:41:22 GMT Tue, 07 Jul 1998 09:41:26 GMT Tue, 07 Jul 1998 09:41:30 GMT Tue, 07 Jul 1998 09:41:34 GMT Tue, 07 Jul 1998 09:41:38 GMT Tue, 07 Jul 1998 09:41:42 GMT Tue, 07 Jul 1998 11:22:00 GMT Tue, 07 Mar 2000 07:57:10 GMT Tue, 07 Mar 2000 08:29:55 GMT Tue, 07 Mar 2000 08:30:44 GMT Tue, 07 Mar 2000 08:34:35 GMT Tue, 07 Mar 2000 08:35:28 GMT Tue, 07 Mar 2000 08:36:35 GMT Tue, 07 Mar 2000 08:36:37 GMT Tue, 07 Mar 2000 08:36:39 GMT Tue, 07 Mar 2000 08:36:41 GMT Tue, 07 Mar 2000 08:36:43 GMT Tue, 07 Mar 2000 08:36:45 GMT Tue, 07 Mar 2000 08:36:48 GMT Tue, 07 Mar 2000 08:36:50 GMT Tue, 07 Mar 2000 08:36:52 GMT Tue, 07 Mar 2000 08:36:54 GMT Tue, 07 Mar 2000 08:36:58 GMT Tue, 07 Mar 2000 08:37:00 GMT Tue, 07 Mar 2000 08:37:02 GMT Tue, 07 Mar 2000 08:37:04 GMT Tue, 07 Mar 2000 08:37:06 GMT Tue, 07 Mar 2000 08:37:08 GMT Tue, 07 Mar 2000 08:37:10 GMT Tue, 07 Mar 2000 08:37:12 GMT Tue, 07 Mar 2000 08:37:14 GMT Tue, 07 Mar 2000 08:37:16 GMT Tue, 07 Mar 2000 08:37:18 GMT Tue, 07 Mar 2000 08:37:20 GMT Tue, 07 Mar 2000 08:37:22 GMT Tue, 07 Mar 2000 08:37:25 GMT Tue, 07 Mar 2000 08:37:30 GMT Tue, 07 Mar 2000 08:37:36 GMT Tue, 07 Mar 2000 08:37:47 GMT Tue, 07 Mar 2000 08:37:51 GMT Tue, 07 Mar 2000 08:37:56 GMT Tue, 07 Mar 2000 08:38:01 GMT Tue, 07 Mar 2000 08:38:07 GMT Tue, 07 Mar 2000 08:38:34 GMT Tue, 07 Mar 2000 08:38:47 GMT Tue, 07 Mar 2000 08:38:51 GMT Tue, 07 Mar 2000 08:39:10 GMT Tue, 07 Mar 2000 08:39:19 GMT Tue, 07 Mar 2000 08:39:32 GMT Tue, 07 Mar 2000 08:39:55 GMT Tue, 07 Mar 2000 08:40:24 GMT Tue, 07 Mar 2000 08:40:38 GMT Tue, 07 Mar 2000 08:40:41 GMT Tue, 07 Mar 2000 08:40:51 GMT Tue, 07 Mar 2000 08:41:07 GMT Tue, 07 Mar 2000 08:43:12 GMT Tue, 07 Mar 2000 08:44:03 GMT Tue, 07 Mar 2000 08:49:24 GMT Tue, 07 Mar 2000 10:17:10 GMT Tue, 07 Mar 2000 11:00:09 GMT Tue, 07 Mar 2000 11:08:21 GMT Tue, 07 Mar 2000 12:59:39 GMT Tue, 07 Mar 2000 12:59:41 GMT Tue, 07 Mar 2000 14:03:53 GMT Tue, 07 Mar 2000 21:49:47 GMT Tue, 07 Mar 2000 21:50:40 GMT Tue, 07 Mar 2000 23:16:22 GMT Tue, 07 Mar 2000 23:18:38 GMT Tue, 07 Mar 2000 23:18:50 GMT Tue, 07 Mar 2000 23:33:36 GMT Tue, 07 Mar 2000 23:35:27 GMT Tue, 07 Mar 2000 23:35:29 GMT Tue, 07 Mar 2000 23:35:31 GMT Tue, 07 Mar 2000 23:35:33 GMT Tue, 07 Mar 2000 23:35:35 GMT Tue, 07 Mar 2000 23:35:39 GMT Tue, 07 Mar 2000 23:35:57 GMT Tue, 07 Nov 1995 08:41:00 GMT Tue, 07 Sep 1999 00:00:10 GMT Tue, 07 Sep 1999 14:04:18 GMT Tue, 07 Sep 1999 17:14:37 GMT Tue, 08 Aug 2000 05:43:35 GMT Tue, 08 Aug 2000 05:43:40 GMT Tue, 08 Aug 2000 05:45:13 GMT Tue, 08 Aug 2000 05:45:18 GMT Tue, 08 Aug 2000 05:45:57 GMT Tue, 08 Aug 2000 05:46:02 GMT Tue, 08 Aug 2000 05:46:50 GMT Tue, 08 Aug 2000 05:46:55 GMT Tue, 08 Aug 2000 05:55:07 GMT Tue, 08 Aug 2000 05:55:14 GMT Tue, 08 Aug 2000 05:56:52 GMT Tue, 08 Aug 2000 05:56:55 GMT Tue, 08 Aug 2000 05:57:08 GMT Tue, 08 Aug 2000 18:31:50 GMT Tue, 08 Aug 2000 19:08:45 GMT Tue, 08 Aug 2000 19:08:47 GMT Tue, 08 Dec 1998 07:19:44 GMT Tue, 08 Feb 2000 00:34:40 GMT Tue, 08 Feb 2000 03:13:37 GMT Tue, 08 Feb 2000 03:47:33 GMT Tue, 08 Feb 2000 03:59:39 GMT Tue, 08 Feb 2000 04:01:15 GMT Tue, 08 Feb 2000 08:25:22 GMT Tue, 08 Feb 2000 08:25:24 GMT Tue, 08 Feb 2000 08:25:27 GMT Tue, 08 Feb 2000 09:39:44 GMT Tue, 08 Feb 2000 10:58:32 GMT Tue, 08 Feb 2000 19:28:31 GMT Tue, 08 Feb 2000 19:33:36 GMT Tue, 08 Feb 2000 19:39:00 GMT Tue, 08 Feb 2000 22:55:35 GMT Tue, 08 Jun 1999 02:41:09 GMT Tue, 08 Jun 1999 09:46:41 GMT Tue, 08 Jun 1999 19:56:40 GMT Tue, 08 Oct 1996 11:57:00 GMT Tue, 08 Sep 1998 19:50:32 GMT Tue, 09 Apr 1996 00:14:00 GMT Tue, 09 Dec 1997 17:49:59 GMT Tue, 09 Feb 1999 12:29:56 GMT Tue, 09 Mar 1999 02:50:57 GMT Tue, 09 Mar 1999 15:23:42 GMT Tue, 09 Mar 1999 15:49:18 GMT Tue, 09 May 2000 01:00:38 GMT Tue, 09 May 2000 02:09:11 GMT Tue, 09 May 2000 11:33:40 GMT Tue, 09 May 2000 11:56:38 GMT Tue, 09 May 2000 13:05:26 GMT Tue, 09 May 2000 13:34:59 GMT Tue, 09 May 2000 14:07:06 GMT Tue, 09 May 2000 15:57:39 GMT Tue, 09 May 2000 18:41:30 GMT Tue, 09 May 2000 19:03:20 GMT Tue, 09 May 2000 19:03:23 GMT Tue, 09 May 2000 19:14:32 GMT Tue, 09 May 2000 20:03:55 GMT Tue, 09 May 2000 21:08:33 GMT Tue, 09 May 2000 21:16:48 GMT Tue, 09 May 2000 21:21:32 GMT Tue, 09 May 2000 21:36:43 GMT Tue, 09 May 2000 23:57:20 GMT Tue, 10 Aug 1999 13:54:47 GMT Tue, 10 Dec 1996 23:00:00 GMT Tue, 10 Feb 1998 20:56:44 GMT Tue, 10 Jan 1995 07:13:44 GMT Tue, 10 Mar 1998 19:28:32 GMT Tue, 10 Oct 1995 13:03:08 GMT Tue, 11 Apr 2000 10:10:02 GMT Tue, 11 Apr 2000 10:12:47 GMT Tue, 11 Apr 2000 11:04:00 GMT Tue, 11 Apr 2000 16:37:56 GMT Tue, 11 Apr 2000 16:38:15 GMT Tue, 11 Apr 2000 16:38:20 GMT Tue, 11 Apr 2000 16:38:22 GMT Tue, 11 Apr 2000 16:38:24 GMT Tue, 11 Apr 2000 16:38:27 GMT Tue, 11 Apr 2000 16:38:30 GMT Tue, 11 Apr 2000 16:38:32 GMT Tue, 11 Apr 2000 16:38:34 GMT Tue, 11 Apr 2000 16:38:36 GMT Tue, 11 Apr 2000 16:38:38 GMT Tue, 11 Apr 2000 16:38:40 GMT Tue, 11 Apr 2000 16:38:42 GMT Tue, 11 Apr 2000 16:38:44 GMT Tue, 11 Apr 2000 16:38:46 GMT Tue, 11 Apr 2000 16:38:48 GMT Tue, 11 Apr 2000 16:38:50 GMT Tue, 11 Apr 2000 16:38:52 GMT Tue, 11 Apr 2000 17:29:41 GMT Tue, 11 Apr 2000 17:56:11 GMT Tue, 11 Apr 2000 17:56:35 GMT Tue, 11 Apr 2000 17:56:41 GMT Tue, 11 Apr 2000 20:17:03 GMT Tue, 11 Apr 2000 20:23:24 GMT Tue, 11 Apr 2000 20:23:44 GMT Tue, 11 Apr 2000 20:24:00 GMT Tue, 11 Apr 2000 20:24:13 GMT Tue, 11 Aug 1998 20:31:56 GMT Tue, 11 Jan 2000 02:15:58 GMT Tue, 11 Jan 2000 02:25:06 GMT Tue, 11 Jan 2000 02:40:26 GMT Tue, 11 Jan 2000 08:31:00 GMT Tue, 11 Jan 2000 14:13:41 GMT Tue, 11 Jan 2000 14:13:44 GMT Tue, 11 Jan 2000 15:51:32 GMT Tue, 11 Jan 2000 19:32:32 GMT Tue, 11 Jan 2000 19:47:59 GMT Tue, 11 Jan 2000 21:34:42 GMT Tue, 11 Jan 2000 21:41:21 GMT Tue, 11 Jan 2000 21:50:26 GMT Tue, 11 Jan 2000 21:50:35 GMT Tue, 11 Jan 2000 21:50:45 GMT Tue, 11 Jan 2000 21:51:09 GMT Tue, 11 Jan 2000 21:51:21 GMT Tue, 11 Jan 2000 21:51:29 GMT Tue, 11 Jan 2000 21:51:39 GMT Tue, 11 Jan 2000 21:51:49 GMT Tue, 11 Jan 2000 21:51:57 GMT Tue, 11 Jan 2000 21:52:04 GMT Tue, 11 Jan 2000 21:52:07 GMT Tue, 11 Jan 2000 21:52:12 GMT Tue, 11 Jan 2000 22:05:45 GMT Tue, 11 Jan 2000 22:26:21 GMT Tue, 11 Jan 2000 22:30:49 GMT Tue, 11 Jan 2000 22:31:05 GMT Tue, 11 Jan 2000 22:31:46 GMT Tue, 11 Jul 2000 03:14:20 GMT Tue, 11 Jul 2000 03:30:25 GMT Tue, 11 Jul 2000 07:30:10 GMT Tue, 11 Jul 2000 07:46:35 GMT Tue, 11 Jul 2000 07:49:02 GMT Tue, 11 Jul 2000 08:30:18 GMT Tue, 11 Jul 2000 09:11:08 GMT Tue, 11 Jul 2000 13:22:24 GMT Tue, 11 Jul 2000 14:16:07 GMT Tue, 11 Jul 2000 15:50:22 GMT Tue, 11 Jul 2000 23:03:48 GMT Tue, 11 Jul 2000 23:38:23 GMT Tue, 11 Jul 2000 23:41:22 GMT Tue, 11 Jun 1996 06:17:50 GMT Tue, 11 Jun 1996 06:18:12 GMT Tue, 11 Jun 1996 06:18:16 GMT Tue, 11 Jun 1996 06:19:54 GMT Tue, 11 Jun 1996 06:19:58 GMT Tue, 11 Mar 1997 16:47:38 GMT Tue, 11 May 1999 15:24:32 GMT Tue, 11 May 1999 16:55:49 GMT Tue, 11 May 1999 21:37:47 GMT Tue, 11 Nov 1997 19:04:15 GMT Tue, 12 Jan 1999 00:29:05 GMT Tue, 12 Mar 1996 12:30:00 GMT Tue, 12 May 1998 06:23:25 GMT Tue, 12 May 1998 06:34:20 GMT Tue, 12 May 1998 07:32:03 GMT Tue, 12 May 1998 09:47:35 GMT Tue, 12 Oct 1999 03:11:52 GMT Tue, 12 Oct 1999 04:43:35 GMT Tue, 12 Oct 1999 17:00:58 GMT Tue, 12 Sep 2000 05:28:22 GMT Tue, 12 Sep 2000 05:28:24 GMT Tue, 12 Sep 2000 06:00:29 GMT Tue, 12 Sep 2000 06:52:30 GMT Tue, 12 Sep 2000 13:33:14 GMT Tue, 12 Sep 2000 18:53:00 GMT Tue, 12 Sep 2000 21:34:53 GMT Tue, 12 Sep 2000 21:50:18 GMT Tue, 12 Sep 2000 22:52:22 GMT Tue, 13 Apr 1999 08:51:41 GMT Tue, 13 Jul 1999 09:29:35 GMT Tue, 13 Jun 2000 01:58:01 GMT Tue, 13 Jun 2000 03:54:59 GMT Tue, 13 Jun 2000 08:16:31 GMT Tue, 13 Jun 2000 08:22:12 GMT Tue, 13 Jun 2000 08:30:10 GMT Tue, 13 Jun 2000 08:30:15 GMT Tue, 13 Jun 2000 08:30:33 GMT Tue, 13 Jun 2000 13:41:49 GMT Tue, 13 Jun 2000 15:02:24 GMT Tue, 13 Jun 2000 15:02:26 GMT Tue, 13 Jun 2000 15:02:28 GMT Tue, 13 Jun 2000 15:02:30 GMT Tue, 13 Jun 2000 15:02:32 GMT Tue, 13 Jun 2000 15:02:50 GMT Tue, 13 Jun 2000 16:19:34 GMT Tue, 13 Jun 2000 16:22:34 GMT Tue, 13 Jun 2000 16:22:56 GMT Tue, 13 Jun 2000 16:22:58 GMT Tue, 13 Jun 2000 16:23:07 GMT Tue, 13 Jun 2000 16:23:12 GMT Tue, 13 Jun 2000 16:23:15 GMT Tue, 13 Jun 2000 16:23:17 GMT Tue, 13 Jun 2000 16:23:19 GMT Tue, 13 Jun 2000 16:23:22 GMT Tue, 13 Jun 2000 16:23:24 GMT Tue, 13 Jun 2000 16:26:34 GMT Tue, 13 Jun 2000 17:28:20 GMT Tue, 13 Jun 2000 17:28:30 GMT Tue, 13 Jun 2000 19:59:23 GMT Tue, 13 Jun 2000 23:35:32 GMT Tue, 13 Jun 2000 23:37:11 GMT Tue, 13 Oct 1998 04:01:18 GMT Tue, 13 Oct 1998 05:18:54 GMT Tue, 13 Oct 1998 05:23:55 GMT Tue, 13 Oct 1998 05:27:33 GMT Tue, 14 Apr 1998 20:00:20 GMT Tue, 14 Dec 1999 02:10:52 GMT Tue, 14 Dec 1999 08:53:27 GMT Tue, 14 Dec 1999 16:51:10 GMT Tue, 14 Dec 1999 19:16:22 GMT Tue, 14 Jul 1998 21:18:38 GMT Tue, 14 Mar 2000 06:07:23 GMT Tue, 14 Mar 2000 09:08:00 GMT Tue, 14 Mar 2000 11:05:34 GMT Tue, 14 Mar 2000 15:35:58 GMT Tue, 14 Mar 2000 20:10:33 GMT Tue, 14 Sep 1999 22:00:00 GMT Tue, 15 Aug 1989 20:31:23 GMT Tue, 15 Aug 1995 13:25:06 GMT Tue, 15 Aug 2000 05:01:31 GMT Tue, 15 Aug 2000 05:44:28 GMT Tue, 15 Aug 2000 06:00:58 GMT Tue, 15 Aug 2000 06:01:19 GMT Tue, 15 Aug 2000 06:05:21 GMT Tue, 15 Aug 2000 06:05:29 GMT Tue, 15 Aug 2000 06:05:37 GMT Tue, 15 Aug 2000 06:05:49 GMT Tue, 15 Aug 2000 06:05:56 GMT Tue, 15 Aug 2000 06:06:12 GMT Tue, 15 Aug 2000 06:06:31 GMT Tue, 15 Aug 2000 06:06:38 GMT Tue, 15 Aug 2000 06:06:56 GMT Tue, 15 Aug 2000 06:07:11 GMT Tue, 15 Aug 2000 06:07:19 GMT Tue, 15 Aug 2000 06:07:33 GMT Tue, 15 Aug 2000 06:12:05 GMT Tue, 15 Aug 2000 06:15:44 GMT Tue, 15 Aug 2000 06:15:46 GMT Tue, 15 Aug 2000 06:15:48 GMT Tue, 15 Aug 2000 06:15:50 GMT Tue, 15 Aug 2000 06:15:52 GMT Tue, 15 Aug 2000 06:16:03 GMT Tue, 15 Aug 2000 06:18:38 GMT Tue, 15 Aug 2000 06:18:40 GMT Tue, 15 Aug 2000 06:20:23 GMT Tue, 15 Aug 2000 06:20:26 GMT Tue, 15 Aug 2000 06:22:04 GMT Tue, 15 Aug 2000 06:22:08 GMT Tue, 15 Aug 2000 06:22:10 GMT Tue, 15 Aug 2000 06:24:59 GMT Tue, 15 Aug 2000 06:25:01 GMT Tue, 15 Aug 2000 06:25:03 GMT Tue, 15 Aug 2000 06:25:05 GMT Tue, 15 Aug 2000 06:25:07 GMT Tue, 15 Aug 2000 06:28:18 GMT Tue, 15 Aug 2000 06:28:20 GMT Tue, 15 Aug 2000 06:28:22 GMT Tue, 15 Aug 2000 06:28:24 GMT Tue, 15 Aug 2000 06:28:26 GMT Tue, 15 Aug 2000 06:45:46 GMT Tue, 15 Aug 2000 06:45:48 GMT Tue, 15 Aug 2000 06:45:50 GMT Tue, 15 Aug 2000 06:45:52 GMT Tue, 15 Aug 2000 06:46:06 GMT Tue, 15 Aug 2000 06:46:57 GMT Tue, 15 Aug 2000 06:47:06 GMT Tue, 15 Aug 2000 06:47:08 GMT Tue, 15 Aug 2000 06:47:27 GMT Tue, 15 Aug 2000 06:47:29 GMT Tue, 15 Aug 2000 06:47:31 GMT Tue, 15 Aug 2000 18:53:54 GMT Tue, 15 Feb 2000 15:54:02 GMT Tue, 15 Feb 2000 16:50:03 GMT Tue, 15 Feb 2000 17:42:56 GMT Tue, 15 Feb 2000 17:43:42 GMT Tue, 15 Feb 2000 19:37:33 GMT Tue, 15 Feb 2000 19:40:42 GMT Tue, 15 Feb 2000 19:53:24 GMT Tue, 15 Feb 2000 22:14:29 GMT Tue, 15 Jun 1999 07:57:06 GMT Tue, 15 Sep 1998 19:47:45 GMT Tue, 16 Apr 1996 13:52:32 GMT Tue, 16 Apr 1996 13:52:54 GMT Tue, 16 Apr 1996 13:53:22 GMT Tue, 16 Dec 1997 12:09:32 GMT Tue, 16 Dec 1997 20:46:12 GMT Tue, 16 Feb 1999 02:17:23 GMT Tue, 16 Feb 1999 12:31:43 GMT Tue, 16 Feb 1999 15:01:00 GMT Tue, 16 Mar 1999 00:11:30 GMT Tue, 16 May 2000 03:01:10 GMT Tue, 16 May 2000 03:25:51 GMT Tue, 16 May 2000 04:22:28 GMT Tue, 16 May 2000 04:46:31 GMT Tue, 16 May 2000 04:46:33 GMT Tue, 16 May 2000 05:46:41 GMT Tue, 16 May 2000 05:55:54 GMT Tue, 16 May 2000 06:44:04 GMT Tue, 16 May 2000 06:46:46 GMT Tue, 16 May 2000 07:21:15 GMT Tue, 16 May 2000 09:54:39 GMT Tue, 16 May 2000 12:47:51 GMT Tue, 16 May 2000 13:13:18 GMT Tue, 16 May 2000 13:48:54 GMT Tue, 16 May 2000 15:17:05 GMT Tue, 16 May 2000 21:35:46 GMT Tue, 16 May 2000 21:57:29 GMT Tue, 16 May 2000 22:56:53 GMT Tue, 16 May 2000 23:11:33 GMT Tue, 16 May 2000 23:28:43 GMT Tue, 16 Nov 1999 09:36:00 GMT Tue, 16 Nov 1999 12:58:37 GMT Tue, 16 Nov 1999 15:52:24 GMT Tue, 16 Oct 1990 00:12:05 GMT Tue, 16 Sep 1997 00:59:37 GMT Tue, 17 Aug 1999 04:37:41 GMT Tue, 17 Aug 1999 05:01:47 GMT Tue, 17 Aug 1999 05:08:17 GMT Tue, 17 Aug 1999 05:13:28 GMT Tue, 17 Aug 1999 09:17:47 GMT Tue, 17 Aug 1999 17:01:47 GMT Tue, 17 Aug 1999 19:29:58 GMT Tue, 17 Feb 1998 12:01:18 GMT Tue, 17 Feb 1998 12:02:35 GMT Tue, 17 Mar 1998 18:53:21 GMT Tue, 18 Apr 2000 10:31:34 GMT Tue, 18 Apr 2000 10:53:25 GMT Tue, 18 Apr 2000 10:58:33 GMT Tue, 18 Apr 2000 11:06:21 GMT Tue, 18 Apr 2000 11:06:25 GMT Tue, 18 Apr 2000 11:19:49 GMT Tue, 18 Apr 2000 12:36:21 GMT Tue, 18 Apr 2000 13:44:52 GMT Tue, 18 Aug 1992 00:00:00 GMT Tue, 18 Jan 2000 02:00:04 GMT Tue, 18 Jan 2000 03:32:04 GMT Tue, 18 Jan 2000 03:32:07 GMT Tue, 18 Jan 2000 03:32:09 GMT Tue, 18 Jan 2000 03:32:11 GMT Tue, 18 Jan 2000 03:32:13 GMT Tue, 18 Jan 2000 06:19:08 GMT Tue, 18 Jan 2000 12:46:02 GMT Tue, 18 Jan 2000 16:33:04 GMT Tue, 18 Jan 2000 22:20:16 GMT Tue, 18 Jul 2000 01:49:58 GMT Tue, 18 Jul 2000 02:02:17 GMT Tue, 18 Jul 2000 02:54:19 GMT Tue, 18 Jul 2000 06:01:10 GMT Tue, 18 Jul 2000 12:39:11 GMT Tue, 18 Jul 2000 15:27:02 GMT Tue, 18 Jul 2000 16:35:19 GMT Tue, 18 Jul 2000 19:57:58 GMT Tue, 18 Jul 2000 19:58:05 GMT Tue, 18 Jul 2000 19:58:09 GMT Tue, 18 Jul 2000 19:58:18 GMT Tue, 18 Jul 2000 20:26:12 GMT Tue, 18 Jul 2000 20:29:35 GMT Tue, 18 Jul 2000 20:46:12 GMT Tue, 18 Jul 2000 22:17:39 GMT Tue, 18 Jul 2000 22:32:16 GMT Tue, 18 Jul 2000 23:02:05 GMT Tue, 18 Jul 2000 23:04:56 GMT Tue, 18 Jul 2000 23:05:49 GMT Tue, 18 Jul 2000 23:06:03 GMT Tue, 18 Jul 2000 23:06:10 GMT Tue, 18 Jul 2000 23:17:30 GMT Tue, 18 Jul 2000 23:54:39 GMT Tue, 18 Mar 1997 23:00:00 GMT Tue, 19 Aug 1997 23:00:27 GMT Tue, 19 Dec 1995 17:36:54 GMT Tue, 19 Dec 1995 17:37:18 GMT Tue, 19 Jan 1999 00:07:45 GMT Tue, 19 Jan 1999 17:43:48 GMT Tue, 19 Jan 1999 18:58:26 GMT Tue, 19 May 1998 08:01:39 GMT Tue, 19 Oct 1999 17:22:20 GMT Tue, 19 Oct 1999 19:36:05 GMT Tue, 19 Sep 2000 02:35:13 GMT Tue, 19 Sep 2000 04:35:02 GMT Tue, 19 Sep 2000 05:45:04 GMT Tue, 19 Sep 2000 09:06:24 GMT Tue, 19 Sep 2000 12:14:28 GMT Tue, 19 Sep 2000 12:14:42 GMT Tue, 19 Sep 2000 12:14:48 GMT Tue, 19 Sep 2000 13:37:53 GMT Tue, 19 Sep 2000 13:38:17 GMT Tue, 19 Sep 2000 13:38:21 GMT Tue, 19 Sep 2000 13:38:23 GMT Tue, 19 Sep 2000 14:17:59 GMT Tue, 19 Sep 2000 15:56:08 GMT Tue, 19 Sep 2000 16:04:41 GMT Tue, 19 Sep 2000 16:04:59 GMT Tue, 19 Sep 2000 16:05:38 GMT Tue, 19 Sep 2000 16:05:40 GMT Tue, 19 Sep 2000 16:05:42 GMT Tue, 19 Sep 2000 16:05:44 GMT Tue, 19 Sep 2000 16:05:46 GMT Tue, 19 Sep 2000 16:05:48 GMT Tue, 19 Sep 2000 16:05:51 GMT Tue, 19 Sep 2000 16:05:53 GMT Tue, 19 Sep 2000 16:05:55 GMT Tue, 19 Sep 2000 16:05:57 GMT Tue, 19 Sep 2000 16:05:59 GMT Tue, 19 Sep 2000 16:06:01 GMT Tue, 19 Sep 2000 16:06:03 GMT Tue, 19 Sep 2000 16:06:05 GMT Tue, 19 Sep 2000 16:06:07 GMT Tue, 19 Sep 2000 16:06:09 GMT Tue, 19 Sep 2000 16:06:11 GMT Tue, 19 Sep 2000 16:06:13 GMT Tue, 19 Sep 2000 16:06:15 GMT Tue, 19 Sep 2000 16:06:17 GMT Tue, 19 Sep 2000 16:08:07 GMT Tue, 19 Sep 2000 16:08:11 GMT Tue, 19 Sep 2000 16:10:31 GMT Tue, 19 Sep 2000 16:27:03 GMT Tue, 19 Sep 2000 16:37:34 GMT Tue, 19 Sep 2000 16:42:02 GMT Tue, 19 Sep 2000 18:04:31 GMT Tue, 19 Sep 2000 18:52:00 GMT Tue, 19 Sep 2000 18:54:00 GMT Tue, 19 Sep 2000 20:36:34 GMT Tue, 19 Sep 2000 21:07:37 GMT Tue, 19 Sep 2000 21:45:39 GMT Tue, 20 Apr 1999 21:40:58 GMT Tue, 20 Aug 1996 09:17:20 GMT Tue, 20 Jan 1998 12:48:00 GMT Tue, 20 Jul 1993 21:36:16 GMT Tue, 20 Jul 1993 21:41:37 GMT Tue, 20 Jul 1999 20:32:27 GMT Tue, 20 Jul 1999 20:54:21 GMT Tue, 20 Jun 2000 00:46:49 GMT Tue, 20 Jun 2000 01:43:55 GMT Tue, 20 Jun 2000 01:51:54 GMT Tue, 20 Jun 2000 01:57:02 GMT Tue, 20 Jun 2000 01:59:16 GMT Tue, 20 Jun 2000 02:14:21 GMT Tue, 20 Jun 2000 02:28:42 GMT Tue, 20 Jun 2000 02:34:07 GMT Tue, 20 Jun 2000 02:42:20 GMT Tue, 20 Jun 2000 04:21:08 GMT Tue, 20 Jun 2000 08:14:05 GMT Tue, 20 Jun 2000 11:36:39 GMT Tue, 20 Jun 2000 15:14:36 GMT Tue, 20 Jun 2000 15:16:29 GMT Tue, 20 Jun 2000 15:16:31 GMT Tue, 20 Jun 2000 17:17:09 GMT Tue, 20 Jun 2000 23:12:18 GMT Tue, 20 Sep 1994 15:42:46 GMT Tue, 21 Dec 1999 00:06:56 GMT Tue, 21 Dec 1999 06:05:10 GMT Tue, 21 Dec 1999 06:06:42 GMT Tue, 21 Dec 1999 09:12:48 GMT Tue, 21 Dec 1999 13:20:15 GMT Tue, 21 Dec 1999 16:25:53 GMT Tue, 21 Dec 1999 17:06:21 GMT Tue, 21 Dec 1999 17:09:44 GMT Tue, 21 Dec 1999 17:09:46 GMT Tue, 21 Dec 1999 18:13:06 GMT Tue, 21 Dec 1999 18:17:32 GMT Tue, 21 Dec 1999 20:43:52 GMT Tue, 21 Dec 1999 23:49:46 GMT Tue, 21 Jul 1998 00:23:32 GMT Tue, 21 Jul 1998 11:58:12 GMT Tue, 21 Mar 1995 19:57:31 GMT Tue, 21 Mar 2000 11:19:03 GMT Tue, 21 Mar 2000 12:00:10 GMT Tue, 21 Mar 2000 12:55:10 GMT Tue, 21 Oct 1997 12:19:06 GMT Tue, 21 Sep 1999 02:43:13 GMT Tue, 21 Sep 1999 20:11:56 GMT Tue, 22 Aug 1995 22:00:00 GMT Tue, 22 Aug 2000 04:50:36 GMT Tue, 22 Aug 2000 05:24:56 GMT Tue, 22 Aug 2000 05:25:04 GMT Tue, 22 Aug 2000 05:25:25 GMT Tue, 22 Aug 2000 05:25:28 GMT Tue, 22 Aug 2000 09:08:40 GMT Tue, 22 Aug 2000 11:41:17 GMT Tue, 22 Aug 2000 12:14:24 GMT Tue, 22 Aug 2000 12:17:39 GMT Tue, 22 Aug 2000 12:18:07 GMT Tue, 22 Aug 2000 13:05:02 GMT Tue, 22 Aug 2000 13:05:04 GMT Tue, 22 Aug 2000 13:05:06 GMT Tue, 22 Aug 2000 13:05:13 GMT Tue, 22 Aug 2000 13:05:18 GMT Tue, 22 Aug 2000 13:06:00 GMT Tue, 22 Aug 2000 13:07:03 GMT Tue, 22 Aug 2000 14:15:02 GMT Tue, 22 Aug 2000 14:30:59 GMT Tue, 22 Aug 2000 14:34:46 GMT Tue, 22 Aug 2000 14:36:23 GMT Tue, 22 Aug 2000 17:53:29 GMT Tue, 22 Aug 2000 19:28:34 GMT Tue, 22 Aug 2000 19:31:49 GMT Tue, 22 Aug 2000 19:31:56 GMT Tue, 22 Aug 2000 19:32:23 GMT Tue, 22 Aug 2000 20:02:00 GMT Tue, 22 Aug 2000 20:02:48 GMT Tue, 22 Aug 2000 20:02:54 GMT Tue, 22 Aug 2000 20:03:21 GMT Tue, 22 Aug 2000 20:04:44 GMT Tue, 22 Aug 2000 20:05:46 GMT Tue, 22 Aug 2000 20:05:53 GMT Tue, 22 Aug 2000 20:06:18 GMT Tue, 22 Aug 2000 20:06:35 GMT Tue, 22 Aug 2000 20:07:18 GMT Tue, 22 Aug 2000 20:07:52 GMT Tue, 22 Aug 2000 20:08:01 GMT Tue, 22 Aug 2000 20:10:20 GMT Tue, 22 Aug 2000 20:11:48 GMT Tue, 22 Aug 2000 20:13:36 GMT Tue, 22 Aug 2000 20:17:05 GMT Tue, 22 Aug 2000 20:19:58 GMT Tue, 22 Aug 2000 20:29:24 GMT Tue, 22 Aug 2000 20:53:47 GMT Tue, 22 Aug 2000 21:05:45 GMT Tue, 22 Aug 2000 21:11:09 GMT Tue, 22 Aug 2000 21:11:37 GMT Tue, 22 Aug 2000 21:12:02 GMT Tue, 22 Aug 2000 21:17:17 GMT Tue, 22 Aug 2000 21:18:26 GMT Tue, 22 Aug 2000 21:20:18 GMT Tue, 22 Aug 2000 21:20:22 GMT Tue, 22 Aug 2000 21:20:54 GMT Tue, 22 Aug 2000 21:21:12 GMT Tue, 22 Aug 2000 21:21:40 GMT Tue, 22 Aug 2000 21:21:54 GMT Tue, 22 Aug 2000 21:22:16 GMT Tue, 22 Aug 2000 21:22:37 GMT Tue, 22 Aug 2000 21:22:43 GMT Tue, 22 Aug 2000 21:26:06 GMT Tue, 22 Aug 2000 21:26:50 GMT Tue, 22 Aug 2000 21:26:59 GMT Tue, 22 Aug 2000 21:29:20 GMT Tue, 22 Aug 2000 21:30:12 GMT Tue, 22 Aug 2000 21:30:20 GMT Tue, 22 Aug 2000 21:36:20 GMT Tue, 22 Aug 2000 21:38:42 GMT Tue, 22 Aug 2000 21:44:45 GMT Tue, 22 Aug 2000 21:50:01 GMT Tue, 22 Aug 2000 21:52:58 GMT Tue, 22 Aug 2000 21:54:36 GMT Tue, 22 Aug 2000 21:56:09 GMT Tue, 22 Aug 2000 21:59:23 GMT Tue, 22 Aug 2000 21:59:25 GMT Tue, 22 Aug 2000 21:59:29 GMT Tue, 22 Aug 2000 21:59:31 GMT Tue, 22 Aug 2000 21:59:33 GMT Tue, 22 Aug 2000 21:59:35 GMT Tue, 22 Aug 2000 21:59:37 GMT Tue, 22 Aug 2000 21:59:45 GMT Tue, 22 Aug 2000 22:03:13 GMT Tue, 22 Dec 1998 09:34:06 GMT Tue, 22 Dec 1998 16:29:00 GMT Tue, 22 Feb 1994 13:21:48 GMT Tue, 22 Feb 1994 13:22:22 GMT Tue, 22 Feb 1994 13:23:30 GMT Tue, 22 Feb 1994 13:24:08 GMT Tue, 22 Feb 1994 13:24:34 GMT Tue, 22 Feb 1994 13:25:46 GMT Tue, 22 Feb 1994 13:26:26 GMT Tue, 22 Feb 1994 13:26:52 GMT Tue, 22 Feb 1994 13:28:06 GMT Tue, 22 Feb 1994 13:28:38 GMT Tue, 22 Feb 1994 13:28:58 GMT Tue, 22 Feb 1994 13:29:34 GMT Tue, 22 Feb 1994 13:29:56 GMT Tue, 22 Feb 1994 13:30:12 GMT Tue, 22 Feb 1994 13:30:58 GMT Tue, 22 Feb 1994 13:31:14 GMT Tue, 22 Feb 1994 13:31:26 GMT Tue, 22 Feb 1994 13:32:00 GMT Tue, 22 Feb 1994 13:32:16 GMT Tue, 22 Feb 1994 13:32:52 GMT Tue, 22 Feb 1994 13:33:12 GMT Tue, 22 Feb 1994 13:33:56 GMT Tue, 22 Feb 1994 13:34:16 GMT Tue, 22 Feb 1994 13:35:04 GMT Tue, 22 Feb 1994 13:35:22 GMT Tue, 22 Feb 1994 13:36:06 GMT Tue, 22 Feb 1994 13:36:26 GMT Tue, 22 Feb 1994 13:37:08 GMT Tue, 22 Feb 1994 13:37:28 GMT Tue, 22 Feb 1994 13:38:10 GMT Tue, 22 Feb 1994 13:38:28 GMT Tue, 22 Feb 1994 13:38:40 GMT Tue, 22 Feb 1994 13:39:14 GMT Tue, 22 Feb 1994 13:39:32 GMT Tue, 22 Feb 1994 13:39:42 GMT Tue, 22 Feb 1994 13:40:18 GMT Tue, 22 Feb 1994 13:40:40 GMT Tue, 22 Feb 1994 13:40:54 GMT Tue, 22 Feb 1994 13:41:38 GMT Tue, 22 Feb 1994 13:41:54 GMT Tue, 22 Feb 1994 13:42:30 GMT Tue, 22 Feb 1994 13:42:54 GMT Tue, 22 Feb 1994 13:43:10 GMT Tue, 22 Feb 1994 13:44:00 GMT Tue, 22 Feb 1994 13:44:22 GMT Tue, 22 Feb 1994 13:45:08 GMT Tue, 22 Feb 1994 13:45:32 GMT Tue, 22 Feb 1994 13:45:46 GMT Tue, 22 Feb 1994 13:46:34 GMT Tue, 22 Feb 1994 13:46:50 GMT Tue, 22 Feb 1994 13:47:26 GMT Tue, 22 Feb 1994 13:47:46 GMT Tue, 22 Feb 1994 13:48:30 GMT Tue, 22 Feb 1994 13:48:52 GMT Tue, 22 Feb 1994 13:49:08 GMT Tue, 22 Feb 1994 13:49:56 GMT Tue, 22 Feb 1994 13:50:16 GMT Tue, 22 Feb 1994 13:51:00 GMT Tue, 22 Feb 1994 13:51:20 GMT Tue, 22 Feb 1994 13:52:06 GMT Tue, 22 Feb 1994 13:52:26 GMT Tue, 22 Feb 1994 13:53:10 GMT Tue, 22 Feb 1994 13:53:32 GMT Tue, 22 Feb 1994 13:53:46 GMT Tue, 22 Feb 1994 13:54:34 GMT Tue, 22 Feb 1994 13:54:52 GMT Tue, 22 Feb 1994 13:55:36 GMT Tue, 22 Feb 1994 13:55:54 GMT Tue, 22 Feb 1994 13:56:38 GMT Tue, 22 Feb 1994 13:56:56 GMT Tue, 22 Feb 1994 13:57:40 GMT Tue, 22 Feb 1994 13:57:56 GMT Tue, 22 Feb 1994 13:58:08 GMT Tue, 22 Feb 1994 13:58:46 GMT Tue, 22 Feb 1994 13:59:06 GMT Tue, 22 Feb 1994 13:59:50 GMT Tue, 22 Feb 1994 14:00:06 GMT Tue, 22 Feb 1994 14:00:22 GMT Tue, 22 Feb 1994 14:01:22 GMT Tue, 22 Feb 1994 14:01:54 GMT Tue, 22 Feb 1994 14:02:58 GMT Tue, 22 Feb 1994 14:03:30 GMT Tue, 22 Feb 1994 14:03:52 GMT Tue, 22 Feb 1994 14:04:52 GMT Tue, 22 Feb 1994 14:05:20 GMT Tue, 22 Feb 1994 14:06:04 GMT Tue, 22 Feb 1994 14:06:12 GMT Tue, 22 Feb 1994 14:06:30 GMT Tue, 22 Feb 1994 14:07:04 GMT Tue, 22 Feb 1994 14:07:18 GMT Tue, 22 Feb 1994 14:07:28 GMT Tue, 22 Feb 1994 14:08:02 GMT Tue, 22 Feb 1994 14:08:22 GMT Tue, 22 Feb 1994 14:09:04 GMT Tue, 22 Feb 1994 14:09:32 GMT Tue, 22 Feb 1994 14:09:52 GMT Tue, 22 Feb 1994 14:10:48 GMT Tue, 22 Feb 1994 14:11:24 GMT Tue, 22 Feb 1994 14:12:18 GMT Tue, 22 Feb 1994 14:12:44 GMT Tue, 22 Feb 1994 14:13:04 GMT Tue, 22 Feb 1994 14:13:52 GMT Tue, 22 Feb 1994 14:14:06 GMT Tue, 22 Feb 1994 14:14:48 GMT Tue, 22 Feb 1994 14:15:02 GMT Tue, 22 Feb 2000 00:32:27 GMT Tue, 22 Feb 2000 01:35:40 GMT Tue, 22 Feb 2000 04:51:51 GMT Tue, 22 Feb 2000 11:32:58 GMT Tue, 22 Feb 2000 14:19:59 GMT Tue, 22 Feb 2000 14:39:15 GMT Tue, 22 Feb 2000 14:39:46 GMT Tue, 22 Feb 2000 18:20:11 GMT Tue, 22 Feb 2000 22:42:00 GMT Tue, 22 Sep 1998 11:59:56 GMT Tue, 22 Sep 1998 13:35:44 GMT Tue, 23 Apr 1996 09:31:35 GMT Tue, 23 Apr 1996 21:57:10 GMT Tue, 23 Feb 1999 20:33:40 GMT Tue, 23 Jul 1996 22:06:40 GMT Tue, 23 Jul 1996 22:06:42 GMT Tue, 23 Jul 1996 22:06:46 GMT Tue, 23 Jun 1998 21:55:14 GMT Tue, 23 Mar 1999 15:29:26 GMT Tue, 23 Mar 1999 23:00:37 GMT Tue, 23 May 2000 03:46:58 GMT Tue, 23 May 2000 03:47:00 GMT Tue, 23 May 2000 03:53:47 GMT Tue, 23 May 2000 03:53:49 GMT Tue, 23 May 2000 03:53:51 GMT Tue, 23 May 2000 03:53:53 GMT Tue, 23 May 2000 03:53:55 GMT Tue, 23 May 2000 03:53:57 GMT Tue, 23 May 2000 03:54:03 GMT Tue, 23 May 2000 03:56:37 GMT Tue, 23 May 2000 03:56:41 GMT Tue, 23 May 2000 03:56:43 GMT Tue, 23 May 2000 03:56:45 GMT Tue, 23 May 2000 03:56:47 GMT Tue, 23 May 2000 03:56:50 GMT Tue, 23 May 2000 04:03:37 GMT Tue, 23 May 2000 04:03:39 GMT Tue, 23 May 2000 04:03:41 GMT Tue, 23 May 2000 04:03:43 GMT Tue, 23 May 2000 04:03:45 GMT Tue, 23 May 2000 04:03:47 GMT Tue, 23 May 2000 04:03:49 GMT Tue, 23 May 2000 04:03:57 GMT Tue, 23 May 2000 04:11:27 GMT Tue, 23 May 2000 04:11:30 GMT Tue, 23 May 2000 04:11:33 GMT Tue, 23 May 2000 04:11:36 GMT Tue, 23 May 2000 04:11:39 GMT Tue, 23 May 2000 04:11:41 GMT Tue, 23 May 2000 04:11:43 GMT Tue, 23 May 2000 05:26:48 GMT Tue, 23 May 2000 08:15:02 GMT Tue, 23 May 2000 08:16:40 GMT Tue, 23 May 2000 08:22:54 GMT Tue, 23 May 2000 10:11:48 GMT Tue, 23 May 2000 10:38:33 GMT Tue, 23 May 2000 10:48:49 GMT Tue, 23 May 2000 10:49:08 GMT Tue, 23 May 2000 14:47:19 GMT Tue, 23 May 2000 15:00:35 GMT Tue, 23 May 2000 15:37:08 GMT Tue, 23 May 2000 18:48:10 GMT Tue, 23 May 2000 18:48:12 GMT Tue, 23 May 2000 18:48:15 GMT Tue, 23 May 2000 18:48:17 GMT Tue, 23 May 2000 18:48:22 GMT Tue, 23 May 2000 18:48:24 GMT Tue, 23 May 2000 18:48:27 GMT Tue, 23 May 2000 21:44:55 GMT Tue, 23 Nov 1999 02:42:51 GMT Tue, 23 Nov 1999 08:39:26 GMT Tue, 23 Nov 1999 08:48:48 GMT Tue, 23 Nov 1999 08:55:34 GMT Tue, 23 Nov 1999 18:04:00 GMT Tue, 23 Nov 1999 18:15:42 GMT Tue, 23 Nov 1999 18:29:16 GMT Tue, 23 Nov 1999 19:17:38 GMT Tue, 23 Nov 1999 21:04:14 GMT Tue, 23 Nov 1999 21:04:18 GMT Tue, 23 Nov 1999 21:04:22 GMT Tue, 23 Nov 1999 21:09:19 GMT Tue, 23 Nov 1999 21:09:21 GMT Tue, 23 Nov 1999 23:50:33 GMT Tue, 23 Nov 1999 23:52:10 GMT Tue, 23 Sep 1997 16:20:02 GMT Tue, 24 Aug 1999 02:23:54 GMT Tue, 24 Feb 1998 06:01:26 GMT Tue, 24 Feb 1998 14:26:51 GMT Tue, 24 Feb 1998 14:26:55 GMT Tue, 24 Jun 1997 18:57:27 GMT Tue, 24 Mar 1998 22:04:21 GMT Tue, 24 Nov 1998 19:27:54 GMT Tue, 24 Sep 1996 12:20:17 GMT Tue, 24 Sep 1996 12:20:19 GMT Tue, 25 Apr 2000 01:22:14 GMT Tue, 25 Apr 2000 02:15:17 GMT Tue, 25 Apr 2000 02:29:27 GMT Tue, 25 Apr 2000 02:57:35 GMT Tue, 25 Apr 2000 02:58:42 GMT Tue, 25 Apr 2000 03:01:35 GMT Tue, 25 Apr 2000 16:30:14 GMT Tue, 25 Apr 2000 20:29:07 GMT Tue, 25 Aug 1998 22:58:03 GMT Tue, 25 Jan 2000 00:39:08 GMT Tue, 25 Jan 2000 00:59:42 GMT Tue, 25 Jan 2000 02:21:30 GMT Tue, 25 Jan 2000 09:59:58 GMT Tue, 25 Jan 2000 15:43:25 GMT Tue, 25 Jan 2000 18:26:04 GMT Tue, 25 Jan 2000 19:19:04 GMT Tue, 25 Jan 2000 19:41:20 GMT Tue, 25 Jan 2000 21:01:12 GMT Tue, 25 Jan 2000 22:09:29 GMT Tue, 25 Jan 2000 22:13:47 GMT Tue, 25 Jul 2000 00:29:07 GMT Tue, 25 Jul 2000 05:45:51 GMT Tue, 25 Jul 2000 06:33:03 GMT Tue, 25 Jul 2000 06:36:42 GMT Tue, 25 Jul 2000 06:43:05 GMT Tue, 25 Jul 2000 13:06:19 GMT Tue, 25 Jul 2000 13:51:43 GMT Tue, 25 Jul 2000 14:00:33 GMT Tue, 25 Jul 2000 14:04:26 GMT Tue, 25 Jul 2000 15:04:30 GMT Tue, 25 Jul 2000 16:23:39 GMT Tue, 25 Jul 2000 16:42:16 GMT Tue, 25 Jul 2000 16:42:18 GMT Tue, 25 Jul 2000 16:42:33 GMT Tue, 25 Jul 2000 17:15:01 GMT Tue, 25 Jul 2000 17:15:32 GMT Tue, 25 Jul 2000 17:15:34 GMT Tue, 25 Jul 2000 17:15:36 GMT Tue, 25 Jul 2000 17:15:38 GMT Tue, 25 Jul 2000 17:15:42 GMT Tue, 25 Jul 2000 17:15:45 GMT Tue, 25 Jul 2000 17:15:47 GMT Tue, 25 Jul 2000 17:15:49 GMT Tue, 25 Jul 2000 17:15:52 GMT Tue, 25 Jul 2000 17:15:54 GMT Tue, 25 Jul 2000 17:15:56 GMT Tue, 25 Jul 2000 17:15:58 GMT Tue, 25 Jul 2000 17:16:01 GMT Tue, 25 Jul 2000 17:16:03 GMT Tue, 25 Jul 2000 17:16:05 GMT Tue, 25 Jul 2000 17:16:07 GMT Tue, 25 Jul 2000 17:16:09 GMT Tue, 25 Jul 2000 17:16:11 GMT Tue, 25 Jul 2000 17:16:13 GMT Tue, 25 Jul 2000 17:16:15 GMT Tue, 25 Jul 2000 17:16:17 GMT Tue, 25 Jul 2000 17:16:19 GMT Tue, 25 Jul 2000 17:16:21 GMT Tue, 25 Jul 2000 17:16:23 GMT Tue, 25 Jul 2000 17:16:25 GMT Tue, 25 Jul 2000 17:16:27 GMT Tue, 25 Jul 2000 17:16:29 GMT Tue, 25 Jul 2000 17:16:31 GMT Tue, 25 Jul 2000 17:16:33 GMT Tue, 25 Jul 2000 17:16:35 GMT Tue, 25 Jul 2000 17:16:38 GMT Tue, 25 Jul 2000 17:16:40 GMT Tue, 25 Jul 2000 17:16:42 GMT Tue, 25 Jul 2000 17:16:44 GMT Tue, 25 Jul 2000 17:16:46 GMT Tue, 25 Jul 2000 17:16:48 GMT Tue, 25 Jul 2000 17:16:52 GMT Tue, 25 Jul 2000 17:16:54 GMT Tue, 25 Jul 2000 17:16:56 GMT Tue, 25 Jul 2000 17:16:58 GMT Tue, 25 Jul 2000 17:17:25 GMT Tue, 25 Jul 2000 17:17:27 GMT Tue, 25 Jul 2000 17:17:29 GMT Tue, 25 Jul 2000 17:17:32 GMT Tue, 25 Jul 2000 17:17:34 GMT Tue, 25 Jul 2000 17:17:36 GMT Tue, 25 Jul 2000 17:17:39 GMT Tue, 25 Jul 2000 17:17:42 GMT Tue, 25 Jul 2000 17:17:47 GMT Tue, 25 Jul 2000 17:17:50 GMT Tue, 25 Jul 2000 17:17:52 GMT Tue, 25 Jul 2000 17:17:54 GMT Tue, 25 Jul 2000 17:17:56 GMT Tue, 25 Jul 2000 17:17:58 GMT Tue, 25 Jul 2000 17:18:00 GMT Tue, 25 Jul 2000 17:18:06 GMT Tue, 25 Jul 2000 17:18:08 GMT Tue, 25 Jul 2000 17:18:10 GMT Tue, 25 Jul 2000 17:18:14 GMT Tue, 25 Jul 2000 17:18:17 GMT Tue, 25 Jul 2000 17:18:20 GMT Tue, 25 Jul 2000 17:18:25 GMT Tue, 25 Jul 2000 17:18:28 GMT Tue, 25 Jul 2000 17:18:31 GMT Tue, 25 Jul 2000 17:18:34 GMT Tue, 25 Jul 2000 17:18:36 GMT Tue, 25 Jul 2000 17:18:38 GMT Tue, 25 Jul 2000 17:18:40 GMT Tue, 25 Jul 2000 17:18:42 GMT Tue, 25 Jul 2000 17:18:44 GMT Tue, 25 Jul 2000 17:18:46 GMT Tue, 25 Jul 2000 17:18:48 GMT Tue, 25 Jul 2000 17:18:50 GMT Tue, 25 Jul 2000 17:18:52 GMT Tue, 25 Jul 2000 17:18:55 GMT Tue, 25 Jul 2000 17:18:57 GMT Tue, 25 Jul 2000 17:18:59 GMT Tue, 25 Jul 2000 17:19:01 GMT Tue, 25 Jul 2000 17:19:03 GMT Tue, 25 Jul 2000 17:19:06 GMT Tue, 25 Jul 2000 17:19:09 GMT Tue, 25 Jul 2000 17:19:45 GMT Tue, 25 Jul 2000 17:19:47 GMT Tue, 25 Jul 2000 17:19:52 GMT Tue, 25 Jul 2000 17:19:54 GMT Tue, 25 Jul 2000 17:19:57 GMT Tue, 25 Jul 2000 17:19:59 GMT Tue, 25 Jul 2000 17:20:01 GMT Tue, 25 Jul 2000 17:20:04 GMT Tue, 25 Jul 2000 17:20:06 GMT Tue, 25 Jul 2000 17:20:14 GMT Tue, 25 Jul 2000 17:20:17 GMT Tue, 25 Jul 2000 17:20:19 GMT Tue, 25 Jul 2000 17:20:21 GMT Tue, 25 Jul 2000 17:20:23 GMT Tue, 25 Jul 2000 17:20:26 GMT Tue, 25 Jul 2000 17:21:53 GMT Tue, 25 Jul 2000 17:21:58 GMT Tue, 25 Jul 2000 17:40:05 GMT Tue, 25 Jul 2000 23:43:44 GMT Tue, 25 May 1999 06:36:42 GMT Tue, 25 Nov 1997 22:45:26 GMT Tue, 25 Nov 1997 22:45:28 GMT Tue, 26 Jan 1999 15:20:05 GMT Tue, 26 Oct 1999 03:49:42 GMT Tue, 26 Oct 1999 17:58:21 GMT Tue, 26 Oct 1999 19:54:02 GMT Tue, 26 Oct 1999 23:24:00 GMT Tue, 26 Sep 2000 04:08:01 GMT Tue, 26 Sep 2000 04:35:26 GMT Tue, 26 Sep 2000 08:05:36 GMT Tue, 26 Sep 2000 10:50:05 GMT Tue, 26 Sep 2000 10:51:25 GMT Tue, 26 Sep 2000 10:51:29 GMT Tue, 26 Sep 2000 10:51:31 GMT Tue, 26 Sep 2000 10:51:34 GMT Tue, 26 Sep 2000 10:51:36 GMT Tue, 26 Sep 2000 10:51:38 GMT Tue, 26 Sep 2000 10:51:40 GMT Tue, 26 Sep 2000 10:51:42 GMT Tue, 26 Sep 2000 10:51:45 GMT Tue, 26 Sep 2000 10:51:52 GMT Tue, 26 Sep 2000 10:51:54 GMT Tue, 26 Sep 2000 10:51:59 GMT Tue, 26 Sep 2000 10:52:11 GMT Tue, 26 Sep 2000 10:52:15 GMT Tue, 26 Sep 2000 10:52:18 GMT Tue, 26 Sep 2000 10:52:20 GMT Tue, 26 Sep 2000 10:52:22 GMT Tue, 26 Sep 2000 10:52:25 GMT Tue, 26 Sep 2000 10:52:28 GMT Tue, 26 Sep 2000 10:52:30 GMT Tue, 26 Sep 2000 10:59:34 GMT Tue, 26 Sep 2000 11:33:49 GMT Tue, 26 Sep 2000 11:50:37 GMT Tue, 26 Sep 2000 12:05:48 GMT Tue, 26 Sep 2000 12:07:24 GMT Tue, 26 Sep 2000 12:15:40 GMT Tue, 26 Sep 2000 12:18:53 GMT Tue, 26 Sep 2000 12:27:59 GMT Tue, 26 Sep 2000 12:28:34 GMT Tue, 26 Sep 2000 12:28:37 GMT Tue, 26 Sep 2000 12:28:39 GMT Tue, 26 Sep 2000 12:28:42 GMT Tue, 26 Sep 2000 12:28:48 GMT Tue, 26 Sep 2000 12:28:53 GMT Tue, 26 Sep 2000 12:29:03 GMT Tue, 26 Sep 2000 12:29:11 GMT Tue, 26 Sep 2000 12:35:21 GMT Tue, 26 Sep 2000 13:39:30 GMT Tue, 26 Sep 2000 13:50:59 GMT Tue, 26 Sep 2000 13:55:01 GMT Tue, 26 Sep 2000 13:55:12 GMT Tue, 26 Sep 2000 13:55:14 GMT Tue, 26 Sep 2000 13:55:16 GMT Tue, 26 Sep 2000 13:55:18 GMT Tue, 26 Sep 2000 13:55:21 GMT Tue, 26 Sep 2000 13:55:23 GMT Tue, 26 Sep 2000 13:55:25 GMT Tue, 26 Sep 2000 13:55:28 GMT Tue, 26 Sep 2000 13:55:30 GMT Tue, 26 Sep 2000 13:55:32 GMT Tue, 26 Sep 2000 13:55:35 GMT Tue, 26 Sep 2000 13:57:03 GMT Tue, 26 Sep 2000 14:05:22 GMT Tue, 26 Sep 2000 14:11:43 GMT Tue, 26 Sep 2000 14:28:44 GMT Tue, 26 Sep 2000 14:32:12 GMT Tue, 26 Sep 2000 14:33:27 GMT Tue, 26 Sep 2000 14:49:15 GMT Tue, 26 Sep 2000 14:49:25 GMT Tue, 26 Sep 2000 14:49:29 GMT Tue, 26 Sep 2000 14:50:11 GMT Tue, 26 Sep 2000 14:50:13 GMT Tue, 26 Sep 2000 14:56:47 GMT Tue, 26 Sep 2000 15:51:02 GMT Tue, 26 Sep 2000 15:52:44 GMT Tue, 26 Sep 2000 15:52:46 GMT Tue, 26 Sep 2000 15:54:23 GMT Tue, 26 Sep 2000 16:02:22 GMT Tue, 26 Sep 2000 16:02:24 GMT Tue, 26 Sep 2000 16:02:37 GMT Tue, 26 Sep 2000 16:20:28 GMT Tue, 26 Sep 2000 16:27:01 GMT Tue, 26 Sep 2000 16:30:15 GMT Tue, 26 Sep 2000 16:33:21 GMT Tue, 26 Sep 2000 19:05:00 GMT Tue, 26 Sep 2000 19:07:00 GMT Tue, 27 Apr 1999 17:12:59 GMT Tue, 27 Apr 1999 20:36:38 GMT Tue, 27 Dec 1988 10:32:37 GMT Tue, 27 Feb 1996 13:43:48 GMT Tue, 27 Jul 1999 05:41:09 GMT Tue, 27 Jun 2000 05:33:31 GMT Tue, 27 Jun 2000 05:54:46 GMT Tue, 27 Jun 2000 06:19:53 GMT Tue, 27 Jun 2000 22:13:17 GMT Tue, 27 Jun 2000 22:28:59 GMT Tue, 27 May 1997 16:45:34 GMT Tue, 27 Oct 1998 17:52:21 GMT Tue, 28 Apr 1998 18:10:10 GMT Tue, 28 Apr 1998 20:43:45 GMT Tue, 28 Apr 1998 21:22:04 GMT Tue, 28 Dec 1999 00:16:29 GMT Tue, 28 Dec 1999 03:59:03 GMT Tue, 28 Dec 1999 03:59:24 GMT Tue, 28 Dec 1999 03:59:26 GMT Tue, 28 Dec 1999 08:27:25 GMT Tue, 28 Dec 1999 14:10:06 GMT Tue, 28 Dec 1999 17:14:00 GMT Tue, 28 Dec 1999 17:32:00 GMT Tue, 28 Jan 1997 20:29:00 GMT Tue, 28 Mar 1995 22:00:00 GMT Tue, 28 Mar 2000 07:25:52 GMT Tue, 28 Mar 2000 07:58:57 GMT Tue, 28 Mar 2000 09:05:02 GMT Tue, 28 Mar 2000 10:45:49 GMT Tue, 28 Mar 2000 10:57:57 GMT Tue, 28 Mar 2000 12:24:17 GMT Tue, 28 Mar 2000 13:08:46 GMT Tue, 28 Mar 2000 13:34:01 GMT Tue, 28 Mar 2000 13:49:34 GMT Tue, 28 Mar 2000 14:02:52 GMT Tue, 28 Mar 2000 14:03:44 GMT Tue, 28 Mar 2000 15:08:45 GMT Tue, 28 Mar 2000 16:04:31 GMT Tue, 28 Mar 2000 16:13:14 GMT Tue, 28 Mar 2000 16:14:05 GMT Tue, 28 Mar 2000 18:25:49 GMT Tue, 28 Mar 2000 18:29:55 GMT Tue, 28 Mar 2000 18:30:24 GMT Tue, 28 Mar 2000 18:30:51 GMT Tue, 28 Mar 2000 18:59:03 GMT Tue, 28 Mar 2000 18:59:13 GMT Tue, 28 Mar 2000 18:59:54 GMT Tue, 28 Mar 2000 19:02:25 GMT Tue, 28 Mar 2000 19:04:20 GMT Tue, 28 Mar 2000 19:11:00 GMT Tue, 28 Mar 2000 22:11:27 GMT Tue, 28 Mar 2000 23:05:02 GMT Tue, 28 Mar 2000 23:07:16 GMT Tue, 28 Mar 2000 23:08:13 GMT Tue, 28 Mar 2000 23:11:41 GMT Tue, 28 Mar 2000 23:12:59 GMT Tue, 28 Mar 2000 23:57:39 GMT Tue, 28 Mar 2000 23:58:57 GMT Tue, 28 Sep 1999 15:29:17 GMT Tue, 28 Sep 1999 19:39:54 GMT Tue, 28 Sep 1999 21:28:54 GMT Tue, 28 Sep 1999 23:36:48 GMT Tue, 29 Aug 2000 07:41:36 GMT Tue, 29 Aug 2000 07:42:08 GMT Tue, 29 Aug 2000 12:00:32 GMT Tue, 29 Aug 2000 14:00:22 GMT Tue, 29 Aug 2000 14:00:24 GMT Tue, 29 Aug 2000 14:00:26 GMT Tue, 29 Aug 2000 14:00:29 GMT Tue, 29 Aug 2000 17:01:47 GMT Tue, 29 Aug 2000 17:01:53 GMT Tue, 29 Aug 2000 20:24:28 GMT Tue, 29 Aug 2000 20:55:43 GMT Tue, 29 Dec 1998 19:27:38 GMT Tue, 29 Dec 1998 21:56:15 GMT Tue, 29 Feb 2000 00:00:00 GMT Tue, 29 Feb 2000 01:29:27 GMT Tue, 29 Feb 2000 01:59:21 GMT Tue, 29 Feb 2000 02:31:58 GMT Tue, 29 Feb 2000 13:11:01 GMT Tue, 29 Feb 2000 15:48:26 GMT Tue, 29 Feb 2000 17:29:15 GMT Tue, 29 Feb 2000 17:29:18 GMT Tue, 29 Feb 2000 17:29:28 GMT Tue, 29 Feb 2000 19:08:16 GMT Tue, 29 Feb 2000 19:10:09 GMT Tue, 29 Feb 2000 19:46:16 GMT Tue, 29 Feb 2000 19:56:13 GMT Tue, 29 Feb 2000 20:11:35 GMT Tue, 29 Feb 2000 20:23:13 GMT Tue, 29 Feb 2000 22:53:08 GMT Tue, 29 Feb 2000 23:32:00 GMT Tue, 29 Jun 1993 19:07:12 GMT Tue, 29 Jun 1999 13:49:14 GMT Tue, 29 Jun 1999 16:12:32 GMT Tue, 29 Mar 1994 17:38:00 GMT Tue, 29 Oct 1996 15:11:33 GMT Tue, 30 Apr 1996 09:42:36 GMT Tue, 30 Jul 1996 11:54:22 GMT Tue, 30 Jun 1998 18:19:21 GMT Tue, 30 Jun 1998 21:40:54 GMT Tue, 30 Jun 1998 21:57:36 GMT Tue, 30 Jun 1998 21:57:48 GMT Tue, 30 Jun 1998 21:57:55 GMT Tue, 30 Mar 1993 00:00:00 GMT Tue, 30 Mar 1999 08:07:01 GMT Tue, 30 Mar 1999 08:07:58 GMT Tue, 30 Mar 1999 08:08:44 GMT Tue, 30 Mar 1999 08:09:13 GMT Tue, 30 Mar 1999 08:10:24 GMT Tue, 30 Mar 1999 11:57:58 GMT Tue, 30 Mar 1999 20:15:23 GMT Tue, 30 Mar 1999 20:22:27 GMT Tue, 30 Mar 1999 20:25:19 GMT Tue, 30 May 2000 05:31:47 GMT Tue, 30 May 2000 09:33:11 GMT Tue, 30 May 2000 17:28:26 GMT Tue, 30 May 2000 18:40:27 GMT Tue, 30 May 2000 19:31:11 GMT Tue, 30 May 2000 19:39:24 GMT Tue, 30 May 2000 20:55:08 GMT Tue, 30 May 2000 22:51:20 GMT Tue, 30 Nov 1999 06:15:36 GMT Tue, 30 Nov 1999 08:55:47 GMT Tue, 30 Nov 1999 08:59:17 GMT Tue, 30 Nov 1999 18:12:50 GMT Tue, 30 Nov 1999 22:24:44 GMT Tue, 30 Oct 1990 15:17:37 GMT Tue, 30 Sep 1997 15:46:45 GMT Tue, 30 Sep 1997 15:46:47 GMT Tue, 31 Aug 1999 01:05:19 GMT Tue, 31 Aug 1999 01:12:59 GMT Tue, 31 Aug 1999 01:15:15 GMT Tue, 31 Aug 1999 01:15:21 GMT Tue, 31 Aug 1999 16:33:09 GMT Tue, 31 Aug 1999 17:50:45 GMT Tue, 31 Aug 1999 18:23:29 GMT Tue, 31 Aug 1999 18:24:24 GMT Tue, 31 Aug 1999 18:30:47 GMT Tue, 31 Aug 1999 18:36:43 GMT Tue, 31 Mar 1998 00:40:37 GMT Wed, 01 Apr 1998 08:07:18 GMT Wed, 01 Apr 1998 08:22:31 GMT Wed, 01 Apr 1998 08:29:09 GMT Wed, 01 Apr 1998 08:35:02 GMT Wed, 01 Apr 1998 08:41:06 GMT Wed, 01 Apr 1998 08:46:47 GMT Wed, 01 Apr 1998 08:57:53 GMT Wed, 01 Apr 1998 09:04:44 GMT Wed, 01 Apr 1998 09:11:33 GMT Wed, 01 Apr 1998 12:59:55 GMT Wed, 01 Dec 1999 00:09:14 GMT Wed, 01 Dec 1999 11:25:39 GMT Wed, 01 Dec 1999 20:55:42 GMT Wed, 01 Dec 1999 22:08:50 GMT Wed, 01 Dec 1999 22:09:18 GMT Wed, 01 Jul 1998 07:32:00 GMT Wed, 01 Jul 1998 19:57:00 GMT Wed, 01 Jul 1998 21:04:12 GMT Wed, 01 Jul 1998 21:36:20 GMT Wed, 01 Jul 1998 21:36:28 GMT Wed, 01 Jul 1998 21:39:02 GMT Wed, 01 Jul 1998 21:39:09 GMT Wed, 01 Jul 1998 21:39:17 GMT Wed, 01 Mar 2000 00:12:09 GMT Wed, 01 Mar 2000 10:31:35 GMT Wed, 01 Mar 2000 15:04:20 GMT Wed, 01 Mar 2000 15:04:27 GMT Wed, 01 Mar 2000 18:05:36 GMT Wed, 01 Mar 2000 18:28:16 GMT Wed, 01 Mar 2000 23:07:07 GMT Wed, 01 Mar 2000 23:11:29 GMT Wed, 01 Mar 2000 23:12:04 GMT Wed, 01 Mar 2000 23:12:49 GMT Wed, 01 Mar 2000 23:30:07 GMT Wed, 01 Sep 1999 04:29:02 GMT Wed, 01 Sep 1999 04:29:07 GMT Wed, 01 Sep 1999 21:37:25 GMT Wed, 02 Aug 1995 05:04:33 GMT Wed, 02 Aug 2000 10:55:38 GMT Wed, 02 Aug 2000 12:56:36 GMT Wed, 02 Aug 2000 13:05:48 GMT Wed, 02 Aug 2000 13:57:08 GMT Wed, 02 Aug 2000 13:59:30 GMT Wed, 02 Aug 2000 14:00:37 GMT Wed, 02 Aug 2000 14:01:57 GMT Wed, 02 Aug 2000 16:25:51 GMT Wed, 02 Aug 2000 16:31:50 GMT Wed, 02 Aug 2000 17:11:46 GMT Wed, 02 Aug 2000 22:31:02 GMT Wed, 02 Aug 2000 22:34:23 GMT Wed, 02 Aug 2000 22:38:17 GMT Wed, 02 Aug 2000 22:38:23 GMT Wed, 02 Aug 2000 22:58:56 GMT Wed, 02 Dec 1998 01:07:29 GMT Wed, 02 Dec 1998 14:15:12 GMT Wed, 02 Dec 1998 20:12:34 GMT Wed, 02 Feb 2000 06:22:04 GMT Wed, 02 Feb 2000 15:22:30 GMT Wed, 02 Feb 2000 17:49:06 GMT Wed, 02 Feb 2000 19:43:56 GMT Wed, 02 Feb 2000 20:43:49 GMT Wed, 02 Feb 2000 20:44:01 GMT Wed, 02 Feb 2000 20:44:03 GMT Wed, 02 Jun 1999 06:25:47 GMT Wed, 02 Jun 1999 13:06:28 GMT Wed, 02 Jun 1999 21:11:24 GMT Wed, 02 Oct 1996 12:54:50 GMT Wed, 02 Sep 1998 16:39:18 GMT Wed, 02 Sep 1998 17:24:30 GMT Wed, 02 Sep 1998 17:24:32 GMT Wed, 02 Sep 1998 17:24:35 GMT Wed, 02 Sep 1998 17:24:39 GMT Wed, 02 Sep 1998 17:24:42 GMT Wed, 02 Sep 1998 17:24:49 GMT Wed, 02 Sep 1998 17:24:52 GMT Wed, 02 Sep 1998 17:24:54 GMT Wed, 02 Sep 1998 17:24:56 GMT Wed, 02 Sep 1998 17:24:58 GMT Wed, 02 Sep 1998 17:25:01 GMT Wed, 02 Sep 1998 17:25:04 GMT Wed, 02 Sep 1998 17:25:07 GMT Wed, 02 Sep 1998 17:25:09 GMT Wed, 02 Sep 1998 17:25:12 GMT Wed, 02 Sep 1998 17:25:14 GMT Wed, 02 Sep 1998 22:15:32 GMT Wed, 03 Apr 1996 00:00:00 GMT Wed, 03 Dec 1997 12:29:41 GMT Wed, 03 Jul 1996 06:18:15 GMT Wed, 03 Mar 1999 00:32:11 GMT Wed, 03 Mar 1999 12:32:00 GMT Wed, 03 Mar 1999 20:39:33 GMT Wed, 03 May 2000 06:32:12 GMT Wed, 03 May 2000 06:33:56 GMT Wed, 03 May 2000 06:34:09 GMT Wed, 03 May 2000 09:53:11 GMT Wed, 03 May 2000 11:34:22 GMT Wed, 03 May 2000 11:57:06 GMT Wed, 03 May 2000 12:07:07 GMT Wed, 03 May 2000 12:48:11 GMT Wed, 03 May 2000 14:09:18 GMT Wed, 03 May 2000 14:14:54 GMT Wed, 03 May 2000 17:07:29 GMT Wed, 03 May 2000 20:42:47 GMT Wed, 03 Nov 1999 00:44:29 GMT Wed, 03 Nov 1999 01:07:55 GMT Wed, 03 Nov 1999 05:38:44 GMT Wed, 03 Nov 1999 16:48:19 GMT Wed, 03 Nov 1999 19:31:09 GMT Wed, 03 Nov 1999 22:43:54 GMT Wed, 04 Aug 1999 22:39:46 GMT Wed, 04 Aug 1999 23:36:41 GMT Wed, 04 Feb 1998 22:52:16 GMT Wed, 04 Jan 1995 16:36:00 GMT Wed, 04 Jan 1995 16:38:00 GMT Wed, 04 Jan 1995 16:39:01 GMT Wed, 04 Jun 1997 20:41:23 GMT Wed, 04 Jun 1997 20:41:28 GMT Wed, 04 Mar 1998 16:51:18 GMT Wed, 04 Nov 1998 00:56:30 GMT Wed, 04 Nov 1998 18:55:31 GMT Wed, 04 Nov 1998 18:59:26 GMT Wed, 04 Nov 1998 19:14:40 GMT Wed, 05 Apr 2000 00:26:21 GMT Wed, 05 Apr 2000 01:49:57 GMT Wed, 05 Apr 2000 07:46:29 GMT Wed, 05 Apr 2000 09:37:54 GMT Wed, 05 Apr 2000 10:27:55 GMT Wed, 05 Apr 2000 11:43:09 GMT Wed, 05 Apr 2000 11:51:45 GMT Wed, 05 Apr 2000 12:08:24 GMT Wed, 05 Apr 2000 14:02:09 GMT Wed, 05 Apr 2000 14:02:11 GMT Wed, 05 Apr 2000 14:02:13 GMT Wed, 05 Apr 2000 14:02:16 GMT Wed, 05 Apr 2000 14:02:19 GMT Wed, 05 Apr 2000 14:02:21 GMT Wed, 05 Apr 2000 14:02:23 GMT Wed, 05 Apr 2000 14:02:25 GMT Wed, 05 Apr 2000 14:07:52 GMT Wed, 05 Apr 2000 14:07:54 GMT Wed, 05 Apr 2000 14:07:56 GMT Wed, 05 Apr 2000 14:09:35 GMT Wed, 05 Apr 2000 14:14:39 GMT Wed, 05 Apr 2000 14:15:17 GMT Wed, 05 Apr 2000 14:15:22 GMT Wed, 05 Apr 2000 14:15:24 GMT Wed, 05 Apr 2000 14:15:26 GMT Wed, 05 Apr 2000 14:15:28 GMT Wed, 05 Apr 2000 15:00:30 GMT Wed, 05 Apr 2000 15:00:32 GMT Wed, 05 Apr 2000 15:21:40 GMT Wed, 05 Apr 2000 15:39:32 GMT Wed, 05 Apr 2000 15:59:09 GMT Wed, 05 Apr 2000 16:06:50 GMT Wed, 05 Apr 2000 16:06:59 GMT Wed, 05 Apr 2000 16:07:59 GMT Wed, 05 Apr 2000 16:08:36 GMT Wed, 05 Apr 2000 16:10:07 GMT Wed, 05 Apr 2000 16:11:12 GMT Wed, 05 Apr 2000 16:11:17 GMT Wed, 05 Jan 2000 15:09:47 GMT Wed, 05 Jul 2000 01:23:18 GMT Wed, 05 Jul 2000 05:14:49 GMT Wed, 05 Jul 2000 15:33:36 GMT Wed, 05 Jul 2000 17:38:31 GMT Wed, 05 Jul 2000 21:24:30 GMT Wed, 05 Jul 2000 23:19:18 GMT Wed, 05 Jul 2000 23:55:48 GMT Wed, 05 Mar 1997 22:04:40 GMT Wed, 05 Mar 1997 22:04:44 GMT Wed, 05 Mar 1997 22:04:48 GMT Wed, 05 Mar 1997 22:04:52 GMT Wed, 05 Mar 1997 22:04:56 GMT Wed, 05 Mar 1997 22:05:00 GMT Wed, 05 Mar 1997 22:05:04 GMT Wed, 05 Mar 1997 22:05:10 GMT Wed, 05 Mar 1997 22:05:14 GMT Wed, 05 Mar 1997 22:05:18 GMT Wed, 05 Mar 1997 22:05:22 GMT Wed, 05 Mar 1997 22:05:26 GMT Wed, 05 Mar 1997 22:05:30 GMT Wed, 05 Mar 1997 22:05:38 GMT Wed, 05 Mar 1997 22:05:54 GMT Wed, 05 Mar 1997 22:05:58 GMT Wed, 05 Mar 1997 22:06:02 GMT Wed, 05 Mar 1997 22:06:06 GMT Wed, 05 Mar 1997 22:06:10 GMT Wed, 05 Mar 1997 22:06:14 GMT Wed, 05 Mar 1997 22:06:18 GMT Wed, 05 Mar 1997 22:06:22 GMT Wed, 05 Mar 1997 22:06:26 GMT Wed, 05 Mar 1997 22:06:30 GMT Wed, 05 Mar 1997 22:06:34 GMT Wed, 05 Mar 1997 22:06:38 GMT Wed, 05 Mar 1997 22:06:42 GMT Wed, 05 Mar 1997 22:06:46 GMT Wed, 05 Mar 1997 22:06:50 GMT Wed, 05 Mar 1997 22:06:54 GMT Wed, 05 Mar 1997 22:06:58 GMT Wed, 05 Mar 1997 22:07:02 GMT Wed, 05 Mar 1997 22:07:06 GMT Wed, 05 Mar 1997 22:07:10 GMT Wed, 05 Mar 1997 22:07:14 GMT Wed, 05 Mar 1997 22:07:18 GMT Wed, 06 May 1998 11:28:12 GMT Wed, 06 May 1998 17:56:03 GMT Wed, 06 Oct 1999 10:33:40 GMT Wed, 06 Oct 1999 19:16:43 GMT Wed, 06 Oct 1999 19:28:44 GMT Wed, 06 Oct 1999 19:30:23 GMT Wed, 06 Oct 1999 20:10:08 GMT Wed, 06 Oct 1999 20:10:13 GMT Wed, 06 Oct 1999 20:10:26 GMT Wed, 06 Oct 1999 20:10:40 GMT Wed, 06 Oct 1999 20:11:15 GMT Wed, 06 Oct 1999 20:11:17 GMT Wed, 06 Oct 1999 20:11:19 GMT Wed, 06 Oct 1999 21:07:29 GMT Wed, 06 Oct 1999 21:11:09 GMT Wed, 06 Oct 1999 21:13:29 GMT Wed, 06 Oct 1999 21:14:08 GMT Wed, 06 Oct 1999 21:17:05 GMT Wed, 06 Oct 1999 22:24:28 GMT Wed, 06 Sep 1995 20:41:02 GMT Wed, 06 Sep 1995 21:18:34 GMT Wed, 06 Sep 2000 01:42:31 GMT Wed, 06 Sep 2000 02:11:36 GMT Wed, 06 Sep 2000 02:19:35 GMT Wed, 06 Sep 2000 02:21:44 GMT Wed, 06 Sep 2000 02:44:53 GMT Wed, 06 Sep 2000 03:27:55 GMT Wed, 06 Sep 2000 05:23:37 GMT Wed, 06 Sep 2000 20:17:38 GMT Wed, 06 Sep 2000 21:49:55 GMT Wed, 06 Sep 2000 21:49:57 GMT Wed, 06 Sep 2000 21:49:59 GMT Wed, 06 Sep 2000 21:50:01 GMT Wed, 06 Sep 2000 21:50:03 GMT Wed, 06 Sep 2000 21:50:12 GMT Wed, 06 Sep 2000 21:50:16 GMT Wed, 06 Sep 2000 21:50:18 GMT Wed, 06 Sep 2000 21:51:04 GMT Wed, 06 Sep 2000 23:37:35 GMT Wed, 07 Apr 1999 16:00:52 GMT Wed, 07 Aug 1996 17:06:58 GMT Wed, 07 Feb 1996 07:47:28 GMT Wed, 07 Jul 1999 02:05:49 GMT Wed, 07 Jul 1999 04:16:31 GMT Wed, 07 Jul 1999 04:16:33 GMT Wed, 07 Jul 1999 04:16:35 GMT Wed, 07 Jul 1999 06:54:30 GMT Wed, 07 Jul 1999 12:49:05 GMT Wed, 07 Jun 2000 00:39:45 GMT Wed, 07 Jun 2000 00:39:47 GMT Wed, 07 Jun 2000 00:45:33 GMT Wed, 07 Jun 2000 03:58:28 GMT Wed, 07 Jun 2000 05:49:08 GMT Wed, 07 Jun 2000 12:10:55 GMT Wed, 07 Jun 2000 13:51:01 GMT Wed, 07 Jun 2000 14:05:48 GMT Wed, 07 Oct 1998 05:15:54 GMT Wed, 07 Oct 1998 22:52:55 GMT Wed, 08 Dec 1999 01:09:12 GMT Wed, 08 Dec 1999 22:17:34 GMT Wed, 08 Dec 1999 22:31:47 GMT Wed, 08 Dec 1999 23:03:11 GMT Wed, 08 Jul 1998 17:33:42 GMT Wed, 08 Mar 2000 05:55:06 GMT Wed, 08 Mar 2000 09:17:12 GMT Wed, 08 Mar 2000 10:38:49 GMT Wed, 08 Mar 2000 14:55:07 GMT Wed, 08 Mar 2000 15:19:08 GMT Wed, 08 Mar 2000 15:40:21 GMT Wed, 08 Mar 2000 23:53:49 GMT Wed, 08 Sep 1999 18:14:31 GMT Wed, 08 Sep 1999 18:20:42 GMT Wed, 08 Sep 1999 18:54:14 GMT Wed, 08 Sep 1999 18:59:00 GMT Wed, 09 Aug 2000 04:46:22 GMT Wed, 09 Aug 2000 13:05:26 GMT Wed, 09 Aug 2000 13:08:57 GMT Wed, 09 Aug 2000 15:46:19 GMT Wed, 09 Aug 2000 17:38:07 GMT Wed, 09 Aug 2000 17:42:26 GMT Wed, 09 Aug 2000 17:56:43 GMT Wed, 09 Aug 2000 18:02:04 GMT Wed, 09 Aug 2000 18:33:01 GMT Wed, 09 Aug 2000 18:38:03 GMT Wed, 09 Aug 2000 21:36:09 GMT Wed, 09 Aug 2000 22:29:53 GMT Wed, 09 Aug 2000 22:29:59 GMT Wed, 09 Aug 2000 22:30:04 GMT Wed, 09 Aug 2000 22:30:11 GMT Wed, 09 Aug 2000 22:30:17 GMT Wed, 09 Aug 2000 22:30:24 GMT Wed, 09 Aug 2000 22:30:28 GMT Wed, 09 Aug 2000 22:30:36 GMT Wed, 09 Aug 2000 22:30:40 GMT Wed, 09 Aug 2000 22:30:45 GMT Wed, 09 Aug 2000 22:30:52 GMT Wed, 09 Aug 2000 22:30:57 GMT Wed, 09 Aug 2000 22:31:05 GMT Wed, 09 Aug 2000 22:31:12 GMT Wed, 09 Aug 2000 22:31:17 GMT Wed, 09 Aug 2000 22:31:22 GMT Wed, 09 Aug 2000 22:31:27 GMT Wed, 09 Aug 2000 22:31:32 GMT Wed, 09 Aug 2000 22:31:38 GMT Wed, 09 Aug 2000 22:31:47 GMT Wed, 09 Aug 2000 22:31:52 GMT Wed, 09 Aug 2000 22:31:58 GMT Wed, 09 Aug 2000 22:32:04 GMT Wed, 09 Aug 2000 22:32:08 GMT Wed, 09 Aug 2000 22:32:14 GMT Wed, 09 Aug 2000 22:32:19 GMT Wed, 09 Aug 2000 22:32:23 GMT Wed, 09 Aug 2000 22:32:28 GMT Wed, 09 Aug 2000 22:32:34 GMT Wed, 09 Aug 2000 22:32:39 GMT Wed, 09 Aug 2000 22:32:43 GMT Wed, 09 Aug 2000 22:32:48 GMT Wed, 09 Aug 2000 22:32:52 GMT Wed, 09 Aug 2000 22:32:56 GMT Wed, 09 Aug 2000 22:33:06 GMT Wed, 09 Aug 2000 22:33:11 GMT Wed, 09 Aug 2000 22:33:16 GMT Wed, 09 Aug 2000 22:33:21 GMT Wed, 09 Aug 2000 22:33:26 GMT Wed, 09 Aug 2000 22:33:30 GMT Wed, 09 Aug 2000 22:33:35 GMT Wed, 09 Aug 2000 22:33:39 GMT Wed, 09 Aug 2000 22:33:43 GMT Wed, 09 Aug 2000 22:33:48 GMT Wed, 09 Aug 2000 22:33:52 GMT Wed, 09 Aug 2000 22:33:56 GMT Wed, 09 Aug 2000 22:33:59 GMT Wed, 09 Aug 2000 22:34:20 GMT Wed, 09 Aug 2000 22:34:27 GMT Wed, 09 Aug 2000 22:35:26 GMT Wed, 09 Aug 2000 22:35:34 GMT Wed, 09 Aug 2000 22:35:45 GMT Wed, 09 Aug 2000 22:35:48 GMT Wed, 09 Aug 2000 22:35:56 GMT Wed, 09 Aug 2000 22:35:59 GMT Wed, 09 Aug 2000 22:36:20 GMT Wed, 09 Aug 2000 22:36:22 GMT Wed, 09 Aug 2000 22:36:24 GMT Wed, 09 Aug 2000 22:37:03 GMT Wed, 09 Aug 2000 22:37:14 GMT Wed, 09 Aug 2000 22:37:18 GMT Wed, 09 Aug 2000 22:38:19 GMT Wed, 09 Aug 2000 22:39:43 GMT Wed, 09 Aug 2000 23:48:05 GMT Wed, 09 Aug 2000 23:48:07 GMT Wed, 09 Aug 2000 23:48:09 GMT Wed, 09 Aug 2000 23:48:11 GMT Wed, 09 Aug 2000 23:48:13 GMT Wed, 09 Dec 1998 05:38:56 GMT Wed, 09 Feb 2000 02:12:33 GMT Wed, 09 Feb 2000 02:35:27 GMT Wed, 09 Feb 2000 02:49:27 GMT Wed, 09 Feb 2000 02:52:29 GMT Wed, 09 Feb 2000 02:52:31 GMT Wed, 09 Feb 2000 02:58:25 GMT Wed, 09 Feb 2000 19:42:35 GMT Wed, 09 Feb 2000 19:51:13 GMT Wed, 09 Feb 2000 22:07:40 GMT Wed, 09 Feb 2000 23:20:13 GMT Wed, 09 Jun 1999 03:07:12 GMT Wed, 09 Jun 1999 10:50:07 GMT Wed, 09 Jun 1999 13:03:06 GMT Wed, 09 Jun 1999 21:45:36 GMT Wed, 09 Jun 1999 23:59:15 GMT Wed, 09 Oct 1996 20:11:38 GMT Wed, 10 Aug 1994 16:26:17 GMT Wed, 10 Aug 1994 16:26:27 GMT Wed, 10 Dec 1997 01:57:09 GMT Wed, 10 Dec 1997 18:31:09 GMT Wed, 10 Dec 1997 19:38:21 GMT Wed, 10 Jun 1998 11:24:00 GMT Wed, 10 Mar 1999 17:42:39 GMT Wed, 10 Mar 1999 20:31:44 GMT Wed, 10 Mar 1999 20:38:08 GMT Wed, 10 Mar 1999 22:11:34 GMT Wed, 10 May 2000 00:50:12 GMT Wed, 10 May 2000 03:21:58 GMT Wed, 10 May 2000 06:07:42 GMT Wed, 10 May 2000 06:07:44 GMT Wed, 10 May 2000 06:58:34 GMT Wed, 10 May 2000 07:26:20 GMT Wed, 10 May 2000 07:26:24 GMT Wed, 10 May 2000 07:26:29 GMT Wed, 10 May 2000 07:26:40 GMT Wed, 10 May 2000 07:26:49 GMT Wed, 10 May 2000 07:26:55 GMT Wed, 10 May 2000 07:27:01 GMT Wed, 10 May 2000 07:27:06 GMT Wed, 10 May 2000 07:27:14 GMT Wed, 10 May 2000 07:27:16 GMT Wed, 10 May 2000 07:27:21 GMT Wed, 10 May 2000 07:27:23 GMT Wed, 10 May 2000 07:27:27 GMT Wed, 10 May 2000 07:27:30 GMT Wed, 10 May 2000 07:27:47 GMT Wed, 10 May 2000 07:28:10 GMT Wed, 10 May 2000 09:02:28 GMT Wed, 10 May 2000 09:02:31 GMT Wed, 10 May 2000 09:02:38 GMT Wed, 10 May 2000 09:02:40 GMT Wed, 10 May 2000 09:02:51 GMT Wed, 10 May 2000 09:03:12 GMT Wed, 10 May 2000 09:03:14 GMT Wed, 10 May 2000 09:03:16 GMT Wed, 10 May 2000 09:03:18 GMT Wed, 10 May 2000 09:03:20 GMT Wed, 10 May 2000 09:03:22 GMT Wed, 10 May 2000 09:03:24 GMT Wed, 10 May 2000 09:03:26 GMT Wed, 10 May 2000 09:03:28 GMT Wed, 10 May 2000 09:03:30 GMT Wed, 10 May 2000 09:03:32 GMT Wed, 10 May 2000 09:03:35 GMT Wed, 10 May 2000 09:03:37 GMT Wed, 10 May 2000 09:03:39 GMT Wed, 10 May 2000 09:03:41 GMT Wed, 10 May 2000 12:25:19 GMT Wed, 10 May 2000 12:25:21 GMT Wed, 10 May 2000 12:27:00 GMT Wed, 10 May 2000 12:27:03 GMT Wed, 10 May 2000 13:21:49 GMT Wed, 10 May 2000 13:23:16 GMT Wed, 10 May 2000 14:23:20 GMT Wed, 10 May 2000 20:20:21 GMT Wed, 10 Nov 1999 03:39:02 GMT Wed, 10 Nov 1999 13:11:32 GMT Wed, 10 Nov 1999 17:52:18 GMT Wed, 10 Nov 1999 18:00:48 GMT Wed, 10 Nov 1999 21:58:46 GMT Wed, 10 Nov 1999 23:11:35 GMT Wed, 11 Aug 1993 15:47:02 GMT Wed, 11 Aug 1993 15:51:30 GMT Wed, 11 Aug 1999 04:06:20 GMT Wed, 11 Aug 1999 16:15:09 GMT Wed, 11 Feb 1998 03:15:23 GMT Wed, 11 Mar 1998 15:27:54 GMT Wed, 11 Nov 1998 12:30:16 GMT Wed, 11 Nov 1998 13:33:34 GMT Wed, 12 Apr 2000 01:10:26 GMT Wed, 12 Apr 2000 01:32:48 GMT Wed, 12 Apr 2000 06:35:08 GMT Wed, 12 Apr 2000 15:26:26 GMT Wed, 12 Apr 2000 16:48:19 GMT Wed, 12 Apr 2000 16:48:22 GMT Wed, 12 Apr 2000 16:48:24 GMT Wed, 12 Apr 2000 16:48:26 GMT Wed, 12 Apr 2000 16:48:28 GMT Wed, 12 Apr 2000 17:32:22 GMT Wed, 12 Aug 1992 13:01:04 GMT Wed, 12 Aug 1992 13:03:25 GMT Wed, 12 Aug 1992 13:03:37 GMT Wed, 12 Aug 1992 13:03:45 GMT Wed, 12 Aug 1992 13:04:33 GMT Wed, 12 Jan 2000 00:52:09 GMT Wed, 12 Jan 2000 00:56:09 GMT Wed, 12 Jan 2000 11:20:17 GMT Wed, 12 Jan 2000 12:23:41 GMT Wed, 12 Jan 2000 13:18:55 GMT Wed, 12 Jan 2000 15:23:23 GMT Wed, 12 Jan 2000 15:54:56 GMT Wed, 12 Jan 2000 19:15:16 GMT Wed, 12 Jan 2000 19:20:15 GMT Wed, 12 Jan 2000 19:20:18 GMT Wed, 12 Jan 2000 19:51:49 GMT Wed, 12 Jan 2000 20:40:40 GMT Wed, 12 Jan 2000 21:07:18 GMT Wed, 12 Jan 2000 21:59:18 GMT Wed, 12 Jul 2000 03:58:15 GMT Wed, 12 Jul 2000 05:01:34 GMT Wed, 12 Jul 2000 06:44:01 GMT Wed, 12 Jul 2000 07:07:54 GMT Wed, 12 Jul 2000 07:20:06 GMT Wed, 12 Jul 2000 07:55:43 GMT Wed, 12 Jul 2000 07:55:58 GMT Wed, 12 Jul 2000 08:30:53 GMT Wed, 12 Jul 2000 09:38:44 GMT Wed, 12 Jul 2000 09:51:12 GMT Wed, 12 Jul 2000 10:24:49 GMT Wed, 12 Jul 2000 14:41:29 GMT Wed, 12 Jul 2000 14:46:56 GMT Wed, 12 Jul 2000 14:46:59 GMT Wed, 12 Jun 1996 04:20:00 GMT Wed, 12 Jun 1996 10:50:02 GMT Wed, 12 Jun 1996 10:50:06 GMT Wed, 12 Jun 1996 10:50:10 GMT Wed, 12 Jun 1996 10:55:28 GMT Wed, 12 Jun 1996 10:55:32 GMT Wed, 12 Jun 1996 10:55:36 GMT Wed, 12 Jun 1996 10:55:40 GMT Wed, 12 Jun 1996 10:55:44 GMT Wed, 12 Jun 1996 10:55:48 GMT Wed, 12 Jun 1996 18:38:07 GMT Wed, 12 May 1999 03:37:46 GMT Wed, 12 May 1999 10:32:34 GMT Wed, 12 May 1999 10:32:43 GMT Wed, 12 May 1999 10:33:13 GMT Wed, 12 May 1999 10:33:51 GMT Wed, 12 May 1999 10:36:06 GMT Wed, 12 May 1999 15:41:15 GMT Wed, 12 May 1999 20:26:20 GMT Wed, 12 Nov 1997 00:13:37 GMT Wed, 12 Nov 1997 00:22:14 GMT Wed, 13 Dec 1995 10:39:45 GMT Wed, 13 May 1998 09:54:52 GMT Wed, 13 May 1998 10:47:17 GMT Wed, 13 Oct 1993 10:24:21 GMT Wed, 13 Oct 1999 08:53:52 GMT Wed, 13 Sep 2000 06:00:11 GMT Wed, 13 Sep 2000 07:59:10 GMT Wed, 13 Sep 2000 18:53:00 GMT Wed, 13 Sep 2000 19:53:25 GMT Wed, 13 Sep 2000 19:53:43 GMT Wed, 14 Aug 1996 07:21:03 GMT Wed, 14 Jul 1999 16:06:06 GMT Wed, 14 Jul 1999 22:45:58 GMT Wed, 14 Jun 2000 08:47:12 GMT Wed, 14 Jun 2000 10:19:11 GMT Wed, 14 Jun 2000 12:57:37 GMT Wed, 14 Jun 2000 12:57:40 GMT Wed, 14 Jun 2000 12:57:43 GMT Wed, 14 Jun 2000 14:36:41 GMT Wed, 14 Jun 2000 15:01:01 GMT Wed, 14 Jun 2000 15:01:52 GMT Wed, 14 Jun 2000 15:27:13 GMT Wed, 14 Jun 2000 16:27:31 GMT Wed, 14 Jun 2000 16:34:05 GMT Wed, 14 Jun 2000 16:57:39 GMT Wed, 14 Jun 2000 20:04:13 GMT Wed, 14 Jun 2000 21:15:45 GMT Wed, 14 Jun 2000 22:39:35 GMT Wed, 14 Jun 2000 22:39:37 GMT Wed, 14 Jun 2000 22:39:39 GMT Wed, 14 Jun 2000 22:40:59 GMT Wed, 14 Jun 2000 23:24:42 GMT Wed, 14 Jun 2000 23:26:48 GMT Wed, 14 Jun 2000 23:46:47 GMT Wed, 14 Jun 2000 23:48:13 GMT Wed, 14 Jun 2000 23:52:29 GMT Wed, 14 Jun 2000 23:52:46 GMT Wed, 14 Jun 2000 23:52:48 GMT Wed, 14 Jun 2000 23:52:50 GMT Wed, 14 Jun 2000 23:52:53 GMT Wed, 14 May 1997 05:41:15 GMT Wed, 14 May 1997 05:41:18 GMT Wed, 14 Oct 1998 00:03:22 GMT Wed, 14 Oct 1998 00:03:24 GMT Wed, 14 Oct 1998 00:03:26 GMT Wed, 14 Oct 1998 00:03:29 GMT Wed, 14 Oct 1998 21:48:01 GMT Wed, 15 Apr 1998 00:33:59 GMT Wed, 15 Apr 1998 00:44:20 GMT Wed, 15 Apr 1998 00:44:23 GMT Wed, 15 Apr 1998 00:44:25 GMT Wed, 15 Dec 1999 04:33:50 GMT Wed, 15 Dec 1999 07:03:50 GMT Wed, 15 Dec 1999 13:51:54 GMT Wed, 15 Dec 1999 14:35:34 GMT Wed, 15 Dec 1999 17:11:30 GMT Wed, 15 Dec 1999 21:22:00 GMT Wed, 15 Dec 1999 23:00:34 GMT Wed, 15 Jul 1998 03:27:03 GMT Wed, 15 Mar 2000 00:56:37 GMT Wed, 15 Mar 2000 01:48:39 GMT Wed, 15 Mar 2000 07:14:52 GMT Wed, 15 Mar 2000 08:39:45 GMT Wed, 15 Mar 2000 08:39:47 GMT Wed, 15 Mar 2000 12:27:27 GMT Wed, 15 Mar 2000 12:28:04 GMT Wed, 15 Mar 2000 13:14:26 GMT Wed, 15 Mar 2000 13:48:10 GMT Wed, 15 Mar 2000 15:33:50 GMT Wed, 15 Mar 2000 16:39:21 GMT Wed, 15 Mar 2000 17:19:52 GMT Wed, 15 Mar 2000 17:21:23 GMT Wed, 15 Mar 2000 17:37:17 GMT Wed, 15 Mar 2000 17:59:08 GMT Wed, 15 Mar 2000 18:05:56 GMT Wed, 15 Mar 2000 18:16:20 GMT Wed, 15 Mar 2000 18:17:27 GMT Wed, 15 Mar 2000 18:17:35 GMT Wed, 15 Mar 2000 18:17:38 GMT Wed, 15 Mar 2000 18:17:40 GMT Wed, 15 Mar 2000 18:17:43 GMT Wed, 15 Mar 2000 18:17:46 GMT Wed, 15 Mar 2000 18:17:49 GMT Wed, 15 Mar 2000 18:17:52 GMT Wed, 15 Mar 2000 18:17:55 GMT Wed, 15 Mar 2000 18:18:01 GMT Wed, 15 Mar 2000 18:18:04 GMT Wed, 15 Mar 2000 18:18:06 GMT Wed, 15 Mar 2000 21:53:34 GMT Wed, 15 Mar 2000 22:43:57 GMT Wed, 15 Mar 2000 22:44:00 GMT Wed, 15 Mar 2000 23:31:52 GMT Wed, 15 Nov 1995 07:15:02 GMT Wed, 15 Oct 1997 17:07:17 GMT Wed, 15 Sep 1999 15:04:29 GMT Wed, 16 Aug 2000 06:10:18 GMT Wed, 16 Aug 2000 07:17:46 GMT Wed, 16 Aug 2000 07:17:49 GMT Wed, 16 Aug 2000 11:24:07 GMT Wed, 16 Aug 2000 16:29:28 GMT Wed, 16 Aug 2000 18:46:03 GMT Wed, 16 Aug 2000 19:30:09 GMT Wed, 16 Aug 2000 22:37:31 GMT Wed, 16 Aug 2000 23:00:56 GMT Wed, 16 Aug 2000 23:12:42 GMT Wed, 16 Aug 2000 23:12:54 GMT Wed, 16 Aug 2000 23:12:56 GMT Wed, 16 Dec 1998 19:07:52 GMT Wed, 16 Dec 1998 19:07:54 GMT Wed, 16 Dec 1998 20:52:00 GMT Wed, 16 Dec 1998 20:54:02 GMT Wed, 16 Feb 2000 01:17:55 GMT Wed, 16 Feb 2000 04:26:03 GMT Wed, 16 Feb 2000 06:39:01 GMT Wed, 16 Feb 2000 16:55:54 GMT Wed, 16 Feb 2000 18:35:08 GMT Wed, 16 Feb 2000 18:56:45 GMT Wed, 16 Feb 2000 21:50:45 GMT Wed, 16 Feb 2000 22:07:46 GMT Wed, 16 Feb 2000 22:56:36 GMT Wed, 16 Feb 2000 23:42:06 GMT Wed, 16 Jun 1999 22:22:07 GMT Wed, 16 Sep 1998 20:49:23 GMT Wed, 17 Apr 1996 05:12:58 GMT Wed, 17 Feb 1993 23:00:00 GMT Wed, 17 Jan 1996 09:44:48 GMT Wed, 17 Jan 1996 09:44:50 GMT Wed, 17 Jan 1996 09:59:05 GMT Wed, 17 Mar 1999 23:00:00 GMT Wed, 17 May 2000 06:29:20 GMT Wed, 17 May 2000 12:00:07 GMT Wed, 17 May 2000 12:57:01 GMT Wed, 17 May 2000 19:05:09 GMT Wed, 17 May 2000 19:05:11 GMT Wed, 17 Nov 1999 09:36:06 GMT Wed, 17 Nov 1999 10:13:27 GMT Wed, 17 Nov 1999 10:13:31 GMT Wed, 17 Nov 1999 10:14:15 GMT Wed, 18 Aug 1999 01:30:55 GMT Wed, 18 Aug 1999 12:00:56 GMT Wed, 18 Aug 1999 14:46:23 GMT Wed, 18 Aug 1999 16:51:31 GMT Wed, 18 Aug 1999 17:10:06 GMT Wed, 18 Aug 1999 18:36:42 GMT Wed, 18 Aug 1999 18:37:51 GMT Wed, 18 Aug 1999 18:38:46 GMT Wed, 18 Aug 1999 18:38:48 GMT Wed, 18 Aug 1999 18:38:50 GMT Wed, 18 Aug 1999 20:09:49 GMT Wed, 18 Feb 1998 20:13:12 GMT Wed, 18 Jan 1995 03:38:00 GMT Wed, 18 Jun 1997 14:28:14 GMT Wed, 18 Jun 1997 14:30:10 GMT Wed, 18 Jun 1997 18:20:03 GMT Wed, 18 Jun 1997 18:20:05 GMT Wed, 18 Mar 1998 20:37:25 GMT Wed, 18 Mar 1998 21:10:13 GMT Wed, 18 Mar 1998 21:10:16 GMT Wed, 18 Mar 1998 23:15:00 GMT Wed, 19 Apr 2000 00:47:34 GMT Wed, 19 Apr 2000 21:39:47 GMT Wed, 19 Apr 2000 21:40:41 GMT Wed, 19 Apr 2000 21:42:01 GMT Wed, 19 Aug 1998 21:38:12 GMT Wed, 19 Jan 2000 06:29:17 GMT Wed, 19 Jan 2000 10:22:58 GMT Wed, 19 Jan 2000 13:12:55 GMT Wed, 19 Jan 2000 13:27:24 GMT Wed, 19 Jan 2000 13:27:52 GMT Wed, 19 Jan 2000 13:28:55 GMT Wed, 19 Jan 2000 13:30:11 GMT Wed, 19 Jan 2000 13:34:23 GMT Wed, 19 Jan 2000 13:40:50 GMT Wed, 19 Jan 2000 13:46:55 GMT Wed, 19 Jan 2000 13:55:01 GMT Wed, 19 Jan 2000 13:56:15 GMT Wed, 19 Jan 2000 13:58:22 GMT Wed, 19 Jan 2000 14:01:13 GMT Wed, 19 Jan 2000 14:08:55 GMT Wed, 19 Jan 2000 14:12:31 GMT Wed, 19 Jan 2000 14:15:12 GMT Wed, 19 Jan 2000 14:17:16 GMT Wed, 19 Jan 2000 14:29:54 GMT Wed, 19 Jan 2000 14:38:54 GMT Wed, 19 Jan 2000 14:43:26 GMT Wed, 19 Jan 2000 14:46:58 GMT Wed, 19 Jan 2000 14:52:55 GMT Wed, 19 Jan 2000 15:40:30 GMT Wed, 19 Jan 2000 16:39:38 GMT Wed, 19 Jan 2000 16:42:08 GMT Wed, 19 Jan 2000 17:24:41 GMT Wed, 19 Jan 2000 17:34:20 GMT Wed, 19 Jan 2000 17:35:47 GMT Wed, 19 Jan 2000 17:44:20 GMT Wed, 19 Jan 2000 17:57:27 GMT Wed, 19 Jan 2000 18:05:03 GMT Wed, 19 Jan 2000 18:13:35 GMT Wed, 19 Jan 2000 18:24:07 GMT Wed, 19 Jan 2000 18:36:58 GMT Wed, 19 Jan 2000 19:00:44 GMT Wed, 19 Jan 2000 19:02:32 GMT Wed, 19 Jan 2000 19:12:33 GMT Wed, 19 Jan 2000 19:45:46 GMT Wed, 19 Jan 2000 20:50:25 GMT Wed, 19 Jan 2000 21:00:16 GMT Wed, 19 Jul 2000 00:03:19 GMT Wed, 19 Jul 2000 00:24:40 GMT Wed, 19 Jul 2000 02:37:09 GMT Wed, 19 Jul 2000 07:34:30 GMT Wed, 19 Jul 2000 10:08:12 GMT Wed, 19 Jul 2000 10:12:00 GMT Wed, 19 Jul 2000 10:12:02 GMT Wed, 19 Jul 2000 10:12:04 GMT Wed, 19 Jul 2000 10:12:06 GMT Wed, 19 Jul 2000 10:12:14 GMT Wed, 19 Jul 2000 10:12:18 GMT Wed, 19 Jul 2000 13:33:10 GMT Wed, 19 Jul 2000 21:37:05 GMT Wed, 19 Jul 2000 23:26:48 GMT Wed, 19 May 1993 06:11:58 GMT Wed, 20 Apr 1994 08:38:00 GMT Wed, 20 Jan 1999 05:26:27 GMT Wed, 20 Jan 1999 09:39:36 GMT Wed, 20 Jan 1999 18:18:53 GMT Wed, 20 Mar 1996 18:38:14 GMT Wed, 20 Mar 1996 20:10:46 GMT Wed, 20 Mar 1996 20:14:44 GMT Wed, 20 May 1998 10:19:16 GMT Wed, 20 Oct 1999 04:05:09 GMT Wed, 20 Oct 1999 23:29:07 GMT Wed, 20 Sep 2000 04:08:01 GMT Wed, 20 Sep 2000 04:35:04 GMT Wed, 20 Sep 2000 10:48:27 GMT Wed, 20 Sep 2000 10:48:29 GMT Wed, 20 Sep 2000 10:52:33 GMT Wed, 20 Sep 2000 12:00:03 GMT Wed, 20 Sep 2000 12:53:54 GMT Wed, 20 Sep 2000 15:49:37 GMT Wed, 20 Sep 2000 15:49:39 GMT Wed, 20 Sep 2000 15:49:41 GMT Wed, 20 Sep 2000 16:31:02 GMT Wed, 20 Sep 2000 17:12:42 GMT Wed, 20 Sep 2000 18:09:12 GMT Wed, 20 Sep 2000 18:14:45 GMT Wed, 20 Sep 2000 18:46:32 GMT Wed, 20 Sep 2000 18:53:00 GMT Wed, 21 Apr 1993 00:00:00 GMT Wed, 21 Apr 1999 00:13:47 GMT Wed, 21 Apr 1999 03:42:33 GMT Wed, 21 Apr 1999 14:30:27 GMT Wed, 21 Apr 1999 14:30:32 GMT Wed, 21 Apr 1999 18:28:59 GMT Wed, 21 Aug 1996 05:58:54 GMT Wed, 21 Jan 1998 00:39:41 GMT Wed, 21 Jan 1998 00:39:43 GMT Wed, 21 Jul 1999 12:53:52 GMT Wed, 21 Jun 2000 00:47:28 GMT Wed, 21 Jun 2000 06:43:00 GMT Wed, 21 Jun 2000 14:32:46 GMT Wed, 21 Jun 2000 14:32:48 GMT Wed, 21 Jun 2000 14:32:51 GMT Wed, 21 Jun 2000 14:32:53 GMT Wed, 21 Jun 2000 19:25:44 GMT Wed, 21 Jun 2000 19:34:55 GMT Wed, 21 Jun 2000 21:39:42 GMT Wed, 21 Jun 2000 21:41:28 GMT Wed, 21 Oct 1998 15:38:33 GMT Wed, 22 Dec 1999 02:26:59 GMT Wed, 22 Dec 1999 02:27:08 GMT Wed, 22 Dec 1999 05:56:42 GMT Wed, 22 Dec 1999 07:43:01 GMT Wed, 22 Dec 1999 10:37:01 GMT Wed, 22 Dec 1999 14:06:42 GMT Wed, 22 Dec 1999 17:59:44 GMT Wed, 22 Dec 1999 18:41:35 GMT Wed, 22 Dec 1999 18:42:31 GMT Wed, 22 Dec 1999 18:42:42 GMT Wed, 22 Dec 1999 18:46:52 GMT Wed, 22 Dec 1999 19:02:55 GMT Wed, 22 Dec 1999 22:26:42 GMT Wed, 22 Jan 1997 22:11:35 GMT Wed, 22 Jul 1998 13:33:17 GMT Wed, 22 Jul 1998 20:45:58 GMT Wed, 22 Mar 2000 01:38:27 GMT Wed, 22 Mar 2000 05:55:00 GMT Wed, 22 Mar 2000 08:52:53 GMT Wed, 22 Mar 2000 09:29:10 GMT Wed, 22 Mar 2000 10:07:39 GMT Wed, 22 Mar 2000 13:07:19 GMT Wed, 22 Mar 2000 15:05:25 GMT Wed, 22 Mar 2000 17:37:48 GMT Wed, 22 Mar 2000 17:43:29 GMT Wed, 22 Mar 2000 20:18:37 GMT Wed, 22 Mar 2000 20:27:11 GMT Wed, 22 Mar 2000 22:27:32 GMT Wed, 22 Mar 2000 22:41:11 GMT Wed, 22 Mar 2000 23:43:37 GMT Wed, 22 Mar 2000 23:53:51 GMT Wed, 22 Sep 1999 00:04:36 GMT Wed, 22 Sep 1999 03:44:58 GMT Wed, 22 Sep 1999 07:35:33 GMT Wed, 22 Sep 1999 23:32:56 GMT Wed, 23 Aug 1995 09:25:29 GMT Wed, 23 Aug 2000 04:42:37 GMT Wed, 23 Aug 2000 21:11:20 GMT Wed, 23 Dec 1998 07:55:13 GMT Wed, 23 Dec 1998 08:39:01 GMT Wed, 23 Dec 1998 22:10:36 GMT Wed, 23 Feb 2000 06:19:07 GMT Wed, 23 Feb 2000 06:27:43 GMT Wed, 23 Feb 2000 06:29:00 GMT Wed, 23 Feb 2000 06:38:31 GMT Wed, 23 Feb 2000 06:42:16 GMT Wed, 23 Feb 2000 12:44:56 GMT Wed, 23 Feb 2000 15:51:08 GMT Wed, 23 Feb 2000 15:55:19 GMT Wed, 23 Feb 2000 17:13:52 GMT Wed, 23 Feb 2000 19:27:14 GMT Wed, 23 Feb 2000 21:37:35 GMT Wed, 23 Feb 2000 23:01:33 GMT Wed, 23 Feb 2000 23:07:08 GMT Wed, 23 Feb 2000 23:07:11 GMT Wed, 23 Feb 2000 23:07:14 GMT Wed, 23 Feb 2000 23:07:18 GMT Wed, 23 Feb 2000 23:07:20 GMT Wed, 23 Feb 2000 23:10:40 GMT Wed, 23 Feb 2000 23:11:39 GMT Wed, 23 Jul 1997 08:18:21 GMT Wed, 23 Jun 1999 18:09:17 GMT Wed, 24 Apr 1996 04:31:23 GMT Wed, 24 Apr 1996 04:36:50 GMT Wed, 24 Feb 1999 12:40:40 GMT Wed, 24 Feb 1999 12:50:50 GMT Wed, 24 Feb 1999 12:54:38 GMT Wed, 24 Feb 1999 12:55:00 GMT Wed, 24 Jun 1992 22:00:00 GMT Wed, 24 Jun 1998 21:30:07 GMT Wed, 24 Jun 1998 21:30:09 GMT Wed, 24 Jun 1998 21:30:11 GMT Wed, 24 Jun 1998 21:34:44 GMT Wed, 24 Mar 1999 07:27:29 GMT Wed, 24 Mar 1999 08:30:56 GMT Wed, 24 Mar 1999 08:33:44 GMT Wed, 24 Mar 1999 08:34:51 GMT Wed, 24 Mar 1999 08:43:17 GMT Wed, 24 Mar 1999 20:54:16 GMT Wed, 24 May 2000 02:11:59 GMT Wed, 24 May 2000 02:42:34 GMT Wed, 24 May 2000 02:52:06 GMT Wed, 24 May 2000 02:52:08 GMT Wed, 24 May 2000 02:52:11 GMT Wed, 24 May 2000 02:52:13 GMT Wed, 24 May 2000 02:52:15 GMT Wed, 24 May 2000 02:52:17 GMT Wed, 24 May 2000 02:52:19 GMT Wed, 24 May 2000 02:52:21 GMT Wed, 24 May 2000 02:52:24 GMT Wed, 24 May 2000 02:52:26 GMT Wed, 24 May 2000 02:52:28 GMT Wed, 24 May 2000 02:52:33 GMT Wed, 24 May 2000 02:52:45 GMT Wed, 24 May 2000 02:52:47 GMT Wed, 24 May 2000 02:52:49 GMT Wed, 24 May 2000 02:52:52 GMT Wed, 24 May 2000 02:52:55 GMT Wed, 24 May 2000 02:52:57 GMT Wed, 24 May 2000 02:53:00 GMT Wed, 24 May 2000 02:53:02 GMT Wed, 24 May 2000 02:53:05 GMT Wed, 24 May 2000 02:53:08 GMT Wed, 24 May 2000 06:46:55 GMT Wed, 24 May 2000 09:11:54 GMT Wed, 24 May 2000 09:49:52 GMT Wed, 24 May 2000 10:01:15 GMT Wed, 24 May 2000 11:17:53 GMT Wed, 24 May 2000 12:55:26 GMT Wed, 24 May 2000 12:55:28 GMT Wed, 24 May 2000 12:55:30 GMT Wed, 24 May 2000 12:55:32 GMT Wed, 24 May 2000 12:55:35 GMT Wed, 24 May 2000 12:55:38 GMT Wed, 24 May 2000 12:55:40 GMT Wed, 24 May 2000 12:55:42 GMT Wed, 24 May 2000 12:55:44 GMT Wed, 24 May 2000 12:55:46 GMT Wed, 24 May 2000 12:55:48 GMT Wed, 24 May 2000 12:55:50 GMT Wed, 24 May 2000 12:55:52 GMT Wed, 24 May 2000 12:55:54 GMT Wed, 24 May 2000 12:55:56 GMT Wed, 24 May 2000 12:55:58 GMT Wed, 24 May 2000 12:56:00 GMT Wed, 24 May 2000 12:56:02 GMT Wed, 24 May 2000 12:56:11 GMT Wed, 24 May 2000 12:56:14 GMT Wed, 24 May 2000 12:56:16 GMT Wed, 24 May 2000 12:56:18 GMT Wed, 24 May 2000 12:56:26 GMT Wed, 24 May 2000 12:56:40 GMT Wed, 24 May 2000 13:25:48 GMT Wed, 24 May 2000 15:10:13 GMT Wed, 24 May 2000 15:11:28 GMT Wed, 24 May 2000 15:51:45 GMT Wed, 24 Nov 1999 00:17:52 GMT Wed, 24 Nov 1999 04:42:43 GMT Wed, 24 Nov 1999 04:43:00 GMT Wed, 24 Nov 1999 12:38:49 GMT Wed, 25 Aug 1999 06:26:49 GMT Wed, 25 Aug 1999 14:54:00 GMT Wed, 25 Aug 1999 22:18:07 GMT Wed, 25 Dec 1996 14:27:10 GMT Wed, 25 Jun 1997 07:33:27 GMT Wed, 25 Nov 1998 10:04:01 GMT Wed, 25 Nov 1998 19:08:54 GMT Wed, 25 Sep 1996 07:38:33 GMT Wed, 25 Sep 1996 07:47:39 GMT Wed, 25 Sep 1996 07:47:41 GMT Wed, 26 Apr 2000 04:09:07 GMT Wed, 26 Apr 2000 07:57:33 GMT Wed, 26 Apr 2000 10:46:28 GMT Wed, 26 Apr 2000 11:17:22 GMT Wed, 26 Apr 2000 11:54:21 GMT Wed, 26 Apr 2000 16:50:32 GMT Wed, 26 Apr 2000 19:12:33 GMT Wed, 26 Apr 2000 20:08:34 GMT Wed, 26 Apr 2000 21:26:18 GMT Wed, 26 Apr 2000 21:50:48 GMT Wed, 26 Apr 2000 22:49:38 GMT Wed, 26 Aug 1998 06:14:15 GMT Wed, 26 Aug 1998 16:54:41 GMT Wed, 26 Jan 2000 04:36:00 GMT Wed, 26 Jan 2000 08:28:20 GMT Wed, 26 Jan 2000 11:16:34 GMT Wed, 26 Jan 2000 14:29:12 GMT Wed, 26 Jan 2000 19:34:26 GMT Wed, 26 Jan 2000 20:32:01 GMT Wed, 26 Jan 2000 20:35:07 GMT Wed, 26 Jan 2000 20:36:19 GMT Wed, 26 Jan 2000 20:36:21 GMT Wed, 26 Jan 2000 20:36:23 GMT Wed, 26 Jan 2000 20:36:25 GMT Wed, 26 Jan 2000 20:36:27 GMT Wed, 26 Jan 2000 20:42:12 GMT Wed, 26 Jan 2000 20:42:14 GMT Wed, 26 Jan 2000 20:44:20 GMT Wed, 26 Jan 2000 20:45:20 GMT Wed, 26 Jan 2000 21:15:02 GMT Wed, 26 Jan 2000 21:17:52 GMT Wed, 26 Jan 2000 21:29:39 GMT Wed, 26 Jan 2000 23:56:09 GMT Wed, 26 Jan 2000 23:56:17 GMT Wed, 26 Jul 1995 00:51:03 GMT Wed, 26 Jul 1995 06:14:38 GMT Wed, 26 Jul 2000 00:18:04 GMT Wed, 26 Jul 2000 02:53:49 GMT Wed, 26 Jul 2000 06:05:21 GMT Wed, 26 Jul 2000 07:08:57 GMT Wed, 26 Jul 2000 07:08:59 GMT Wed, 26 Jul 2000 07:09:07 GMT Wed, 26 Jul 2000 07:09:09 GMT Wed, 26 Jul 2000 07:09:11 GMT Wed, 26 Jul 2000 07:09:13 GMT Wed, 26 Jul 2000 07:09:15 GMT Wed, 26 Jul 2000 07:09:17 GMT Wed, 26 Jul 2000 07:09:19 GMT Wed, 26 Jul 2000 07:09:21 GMT Wed, 26 Jul 2000 07:09:23 GMT Wed, 26 Jul 2000 07:09:25 GMT Wed, 26 Jul 2000 07:09:27 GMT Wed, 26 Jul 2000 07:09:29 GMT Wed, 26 Jul 2000 07:09:31 GMT Wed, 26 Jul 2000 07:09:33 GMT Wed, 26 Jul 2000 07:09:35 GMT Wed, 26 Jul 2000 08:05:13 GMT Wed, 26 Jul 2000 08:09:04 GMT Wed, 26 Jul 2000 13:25:41 GMT Wed, 26 Jul 2000 15:24:37 GMT Wed, 26 Jul 2000 19:40:55 GMT Wed, 26 Jul 2000 19:40:57 GMT Wed, 26 Mar 1997 06:08:00 GMT Wed, 26 Mar 1997 18:45:16 GMT Wed, 26 May 1999 16:35:00 GMT Wed, 26 May 1999 16:36:36 GMT Wed, 26 May 1999 17:01:43 GMT Wed, 26 May 1999 19:52:47 GMT Wed, 26 Nov 1997 23:52:10 GMT Wed, 27 Dec 1995 20:46:35 GMT Wed, 27 Jan 1999 02:49:50 GMT Wed, 27 Oct 1999 07:38:51 GMT Wed, 27 Oct 1999 15:27:26 GMT Wed, 27 Oct 1999 23:18:42 GMT Wed, 27 Sep 2000 04:35:01 GMT Wed, 27 Sep 2000 04:36:05 GMT Wed, 27 Sep 2000 04:36:17 GMT Wed, 27 Sep 2000 10:11:49 GMT Wed, 27 Sep 2000 10:14:02 GMT Wed, 27 Sep 2000 10:14:19 GMT Wed, 27 Sep 2000 10:30:07 GMT Wed, 27 Sep 2000 10:32:06 GMT Wed, 27 Sep 2000 10:32:23 GMT Wed, 27 Sep 2000 11:00:55 GMT Wed, 27 Sep 2000 11:06:27 GMT Wed, 27 Sep 2000 11:56:55 GMT Wed, 27 Sep 2000 12:41:27 GMT Wed, 27 Sep 2000 12:59:08 GMT Wed, 27 Sep 2000 13:00:49 GMT Wed, 27 Sep 2000 13:10:59 GMT Wed, 27 Sep 2000 13:36:19 GMT Wed, 27 Sep 2000 15:09:04 GMT Wed, 27 Sep 2000 15:13:45 GMT Wed, 27 Sep 2000 15:14:52 GMT Wed, 27 Sep 2000 15:16:49 GMT Wed, 27 Sep 2000 15:18:06 GMT Wed, 27 Sep 2000 15:18:08 GMT Wed, 27 Sep 2000 15:18:10 GMT Wed, 27 Sep 2000 15:18:12 GMT Wed, 27 Sep 2000 15:18:16 GMT Wed, 27 Sep 2000 15:18:22 GMT Wed, 27 Sep 2000 15:18:25 GMT Wed, 27 Sep 2000 15:18:34 GMT Wed, 27 Sep 2000 15:18:42 GMT Wed, 27 Sep 2000 15:18:56 GMT Wed, 27 Sep 2000 15:21:04 GMT Wed, 27 Sep 2000 15:21:10 GMT Wed, 27 Sep 2000 15:21:26 GMT Wed, 27 Sep 2000 15:21:31 GMT Wed, 27 Sep 2000 15:25:46 GMT Wed, 27 Sep 2000 15:34:05 GMT Wed, 27 Sep 2000 15:34:32 GMT Wed, 27 Sep 2000 15:37:53 GMT Wed, 27 Sep 2000 15:51:06 GMT Wed, 27 Sep 2000 16:30:37 GMT Wed, 27 Sep 2000 16:37:39 GMT Wed, 27 Sep 2000 16:37:41 GMT Wed, 27 Sep 2000 16:37:43 GMT Wed, 27 Sep 2000 16:37:46 GMT Wed, 27 Sep 2000 16:37:48 GMT Wed, 27 Sep 2000 16:37:52 GMT Wed, 27 Sep 2000 16:37:54 GMT Wed, 27 Sep 2000 16:37:56 GMT Wed, 27 Sep 2000 16:37:58 GMT Wed, 27 Sep 2000 16:38:00 GMT Wed, 27 Sep 2000 16:38:02 GMT Wed, 27 Sep 2000 16:39:06 GMT Wed, 27 Sep 2000 16:39:08 GMT Wed, 27 Sep 2000 16:39:11 GMT Wed, 27 Sep 2000 16:40:07 GMT Wed, 27 Sep 2000 16:40:09 GMT Wed, 27 Sep 2000 16:40:12 GMT Wed, 27 Sep 2000 17:03:55 GMT Wed, 27 Sep 2000 17:04:06 GMT Wed, 27 Sep 2000 17:23:34 GMT Wed, 27 Sep 2000 17:28:20 GMT Wed, 27 Sep 2000 17:41:30 GMT Wed, 27 Sep 2000 17:41:47 GMT Wed, 27 Sep 2000 17:41:49 GMT Wed, 27 Sep 2000 17:42:54 GMT Wed, 27 Sep 2000 17:44:57 GMT Wed, 27 Sep 2000 17:46:42 GMT Wed, 27 Sep 2000 17:46:55 GMT Wed, 27 Sep 2000 18:03:13 GMT Wed, 27 Sep 2000 18:08:15 GMT Wed, 27 Sep 2000 18:09:15 GMT Wed, 27 Sep 2000 18:10:44 GMT Wed, 27 Sep 2000 18:10:51 GMT Wed, 27 Sep 2000 18:10:53 GMT Wed, 27 Sep 2000 18:10:55 GMT Wed, 28 Apr 1999 15:47:39 GMT Wed, 28 Jul 1999 17:30:10 GMT Wed, 28 Jun 2000 04:49:48 GMT Wed, 28 Jun 2000 10:42:18 GMT Wed, 28 Jun 2000 11:27:56 GMT Wed, 28 Jun 2000 11:27:58 GMT Wed, 28 Jun 2000 11:28:00 GMT Wed, 28 Jun 2000 11:28:12 GMT Wed, 28 Jun 2000 11:28:17 GMT Wed, 28 Jun 2000 11:28:47 GMT Wed, 28 Jun 2000 15:42:43 GMT Wed, 28 Jun 2000 17:47:47 GMT Wed, 28 Jun 2000 18:56:48 GMT Wed, 28 Jun 2000 18:56:53 GMT Wed, 28 Jun 2000 18:56:57 GMT Wed, 28 Jun 2000 18:57:01 GMT Wed, 28 Jun 2000 19:00:55 GMT Wed, 28 Jun 2000 19:04:13 GMT Wed, 28 Jun 2000 19:08:29 GMT Wed, 28 Jun 2000 20:51:40 GMT Wed, 28 Jun 2000 22:04:52 GMT Wed, 28 Jun 2000 22:05:06 GMT Wed, 28 May 1997 16:59:28 GMT Wed, 28 May 1997 21:10:36 GMT Wed, 29 Apr 1998 05:28:10 GMT Wed, 29 Apr 1998 14:55:22 GMT Wed, 29 Dec 1999 14:04:15 GMT Wed, 29 Dec 1999 14:12:00 GMT Wed, 29 Dec 1999 14:33:00 GMT Wed, 29 Dec 1999 15:51:00 GMT Wed, 29 Dec 1999 16:36:00 GMT Wed, 29 Dec 1999 17:49:48 GMT Wed, 29 Dec 1999 17:50:18 GMT Wed, 29 Mar 2000 00:05:12 GMT Wed, 29 Mar 2000 00:06:39 GMT Wed, 29 Mar 2000 11:51:44 GMT Wed, 29 Mar 2000 12:53:28 GMT Wed, 29 Mar 2000 14:09:11 GMT Wed, 29 Mar 2000 14:42:43 GMT Wed, 29 Mar 2000 17:52:28 GMT Wed, 29 Mar 2000 18:12:56 GMT Wed, 29 Mar 2000 18:17:37 GMT Wed, 29 Mar 2000 18:32:40 GMT Wed, 29 Mar 2000 19:36:54 GMT Wed, 29 Mar 2000 21:02:58 GMT Wed, 29 Mar 2000 22:06:00 GMT Wed, 29 Mar 2000 23:54:31 GMT Wed, 29 Sep 1999 18:02:00 GMT Wed, 29 Sep 1999 20:37:32 GMT Wed, 29 Sep 1999 21:02:59 GMT Wed, 29 Sep 1999 22:32:15 GMT Wed, 30 Aug 2000 09:00:07 GMT Wed, 30 Aug 2000 09:00:10 GMT Wed, 30 Aug 2000 11:35:47 GMT Wed, 30 Aug 2000 11:39:50 GMT Wed, 30 Aug 2000 11:42:12 GMT Wed, 30 Aug 2000 11:43:15 GMT Wed, 30 Aug 2000 11:43:17 GMT Wed, 30 Aug 2000 11:43:19 GMT Wed, 30 Aug 2000 11:43:21 GMT Wed, 30 Aug 2000 11:43:23 GMT Wed, 30 Aug 2000 11:43:25 GMT Wed, 30 Aug 2000 11:43:27 GMT Wed, 30 Aug 2000 11:43:29 GMT Wed, 30 Aug 2000 11:43:31 GMT Wed, 30 Aug 2000 11:43:33 GMT Wed, 30 Aug 2000 11:43:35 GMT Wed, 30 Aug 2000 11:43:37 GMT Wed, 30 Aug 2000 11:43:39 GMT Wed, 30 Aug 2000 11:43:41 GMT Wed, 30 Aug 2000 11:43:43 GMT Wed, 30 Aug 2000 11:43:45 GMT Wed, 30 Aug 2000 11:43:47 GMT Wed, 30 Aug 2000 11:43:49 GMT Wed, 30 Aug 2000 11:43:51 GMT Wed, 30 Aug 2000 11:43:53 GMT Wed, 30 Aug 2000 11:43:55 GMT Wed, 30 Aug 2000 11:43:58 GMT Wed, 30 Aug 2000 11:44:00 GMT Wed, 30 Aug 2000 11:44:02 GMT Wed, 30 Aug 2000 11:44:05 GMT Wed, 30 Aug 2000 11:44:07 GMT Wed, 30 Aug 2000 11:44:09 GMT Wed, 30 Aug 2000 11:44:11 GMT Wed, 30 Aug 2000 11:44:13 GMT Wed, 30 Aug 2000 11:44:15 GMT Wed, 30 Aug 2000 11:44:17 GMT Wed, 30 Aug 2000 11:44:19 GMT Wed, 30 Aug 2000 11:44:21 GMT Wed, 30 Aug 2000 11:44:23 GMT Wed, 30 Aug 2000 11:44:25 GMT Wed, 30 Aug 2000 11:44:27 GMT Wed, 30 Aug 2000 11:44:29 GMT Wed, 30 Aug 2000 11:44:34 GMT Wed, 30 Aug 2000 12:58:30 GMT Wed, 30 Aug 2000 12:59:19 GMT Wed, 30 Aug 2000 13:01:12 GMT Wed, 30 Aug 2000 13:09:44 GMT Wed, 30 Aug 2000 13:09:46 GMT Wed, 30 Aug 2000 13:09:48 GMT Wed, 30 Aug 2000 13:09:51 GMT Wed, 30 Aug 2000 13:09:53 GMT Wed, 30 Aug 2000 13:09:56 GMT Wed, 30 Aug 2000 13:09:58 GMT Wed, 30 Aug 2000 13:10:00 GMT Wed, 30 Aug 2000 13:10:02 GMT Wed, 30 Aug 2000 13:10:04 GMT Wed, 30 Aug 2000 13:10:06 GMT Wed, 30 Aug 2000 13:10:08 GMT Wed, 30 Aug 2000 13:12:39 GMT Wed, 30 Aug 2000 13:12:41 GMT Wed, 30 Aug 2000 13:12:43 GMT Wed, 30 Jan 1991 13:10:27 GMT Wed, 30 Jun 1999 09:09:35 GMT Wed, 30 Jun 1999 09:09:41 GMT Wed, 30 Jun 1999 17:22:00 GMT Wed, 30 Jun 1999 17:48:12 GMT Wed, 30 Oct 1996 16:41:44 GMT Wed, 30 Sep 1998 04:04:37 GMT Wed, 30 Sep 1998 17:14:17 GMT Wed, 30 Sep 1998 21:16:33 GMT Wed, 31 Dec 1997 11:00:00 GMT Wed, 31 Dec 1997 19:56:24 GMT Wed, 31 Mar 1999 07:33:33 GMT Wed, 31 Mar 1999 10:46:14 GMT Wed, 31 Mar 1999 10:46:56 GMT Wed, 31 Mar 1999 12:38:33 GMT Wed, 31 Mar 1999 16:49:01 GMT Wed, 31 Mar 1999 18:29:51 GMT Wed, 31 Mar 1999 18:34:42 GMT Wed, 31 Mar 1999 18:37:38 GMT Wed, 31 May 2000 12:18:10 GMT Wed, 31 May 2000 14:23:04 GMT Wed, 31 May 2000 15:38:27 GMT Wed, 31 May 2000 17:14:51 GMT Wed, 31 May 2000 17:42:43 GMT Wed, 31 May 2000 17:44:25 GMT Wed, 31 May 2000 18:20:32 GMT Wed, 31 May 2000 20:39:26 GMT Wed, 31 May 2000 20:50:07 GMT Tue, 19 Jan 2038 03:14:07 GMT Thu, 01 Jan 1970 00:00:00 GMT Tue, 19 Jan 2038 03:14:06 GMT Thu, 01 Jan 1970 01:00:00 GMT gateway-1.4.5/checks/check_fakesmsc.sh0000755000175000017500000000143511144324076016421 0ustar toljtolj#!/bin/sh # # Use `test/fakesmsc' to test the bearerbox and the smsbox. set -e #set -x times=10 interval=0 loglevel=0 host=127.0.0.1 gw/bearerbox -v $loglevel gw/smskannel.conf > check_fakesmsc_bb.log 2>&1 & bbpid=$! sleep 2 test/fakesmsc -H $host -r 20000 -i $interval -m $times '123 234 text nop' \ > check_fakesmsc.log 2>&1 & sleep 1 gw/smsbox -v $loglevel gw/smskannel.conf > check_fakesmsc_sms.log 2>&1 & running="yes" while [ $running = "yes" ] do sleep 2 if grep "Got message $times" check_fakesmsc.log >/dev/null then running="no" fi done kill -INT $bbpid wait if grep 'WARNING:|ERROR:|PANIC:' check_fakesmsc*.log >/dev/null then echo check_fakesmsc.sh failed 1>&2 echo See check_fakesmsc*.log for info 1>&2 exit 1 fi rm -f check_fakesmsc*.log exit 0 gateway-1.4.5/checks/check_ppg.sh0000755000175000017500000003132511144324076015414 0ustar toljtolj#!/bin/sh # # Use 'test/test_ppg' and 'test/test_http_server' to test PPG. It presumes # using of http smsc. # # Note: Running this script can take quite a long time, if your input does have # many files. Two (ok ip and sms control document) should be quite enough for # a general make check. Use more only if you are interested of detailed test- # ing of ppg. set -e #set -x host=127.0.0.1 list_port=18082 server_port=18081 push_port=18080 loglevel=0 username="foo" password="bar" prefix="test" contents="sl" # Kannel configuration file conf_file="gw/pushkannel.conf" # Push content. Use only sl, because compilers should be tested separately content_file="$prefix/sl.txt" # Ok ip control files ip_control_files="$prefix/*iptest*" # Ok sms control files sms_control_files="$prefix/*smstest*" # Erroneous ip control files wrong_ip_files="$prefix/*witest*" # Erroneous sms control files wrong_sms_files="$prefix/*wstest*" # File containing the blacklist blacklist="$prefix/blacklist.txt" # File containing the whitelist whitelist="$prefix/whitelist.txt" sleep 1 test/test_http_server -p $list_port -w $whitelist -b $blacklist > check_http_list.log 2>&1 & listid=$! error=no # ok control files requesting an ip bearer. Names contain string 'ip'. Bearer- # box should not use smsc (do a http fetch) when ip bearer is requested. for control_file in $ip_control_files; do if [ -f $control_file ] then gw/bearerbox -v $loglevel $conf_file > check_bb.tmp 2>&1 & bbpid=$! sleep 2 gw/wapbox -v $loglevel $conf_file > check_wap.tmp 2>&1 & wappid=$! sleep 2 test/test_ppg -c $contents http://$host:$push_port/cgi-bin/wap-push.cgi?username=$username'&'password=$password $content_file $control_file > check_ppg.tmp 2>&1 sleep 1 if ! grep "and type push response" check_ppg.tmp > /dev/null then cat check_ppg.tmp >> check_ppg.log 2>&1 error="yes" echo "ppg failed with control file $control_file" fi if ! grep "Connectionless push accepted" check_wap.tmp > /dev/null then cat check_wap.tmp >> check_wap.log 2>&1 error="yes" echo "wap failed with control file $control_file" fi if ! grep "got wdp from wapbox" check_bb.tmp > /dev/null then cat check_bb.tmp >> check_bb.log 2>&1 error="yes" echo "bb failed with control file $control_file" fi kill -INT $wappid sleep 1 kill -INT $bbpid sleep 2 # We can panic when we are going down, too if test "$error" != "yes" then if grep 'WARNING:|ERROR:|PANIC:' check_bb.tmp > /dev/null then cat check_bb.tmp >> check_bb.log 2>&1 error="yes" echo "got errors in bb when going down when $control_file" fi if grep 'WARNING:|ERROR:|PANIC:' check_wap.tmp > /dev/null then cat check_wap.tmp >> check_wap.log 2>&1 error="yes" echo "got errors in wap when going down when $control_file" fi if grep 'WARNING:|ERROR:|PANIC:' check_ppg.tmp > /dev/null then cat check_ppg.tmp >> check_ppg.log 2>&1 error="yes" echo "got errors in ppg when going down when $control_file" fi fi rm -f check_bb.tmp check_wap.tmp check_ppg.tmp fi; done # Erroneous control files requesting an ip bearer. Ppg should reject these and # report pi. Names contain string 'wi'. for control_file in $wrong_ip_files; do if [ -f $control_file ] then have_iperrors=yes gw/bearerbox -v $loglevel $conf_file > check_bb.tmp 2>&1 & bbpid=$! sleep 2 gw/wapbox -v $loglevel $conf_file > check_wap.tmp 2>&1 & wappid=$! sleep 2 test/test_ppg -c $contents http://$host:$push_port/cgi-bin/wap-push.cgi?username=$username'&'password=$password $content_file $control_file > check_ppg.tmp 2>&1 sleep 1 if ! grep "and type push response" check_ppg.tmp > /dev/null && ! grep "and type bad message response" check_ppg.tmp > /dev/null then cat check_ppg.tmp >> check_ppg.log 2>&1 error="yes" echo "ppg failed when control file $control_file" fi if grep "Connectionless push accepted" check_wap.tmp > /dev/null && grep "WARNING" check_wap.tmp > /dev/null then cat check_wap.tmp >> check_wap.log 2>&1 error="yes" echo "wap failed when control file $control_file" fi if grep "got wdp from wapbox" check_bb.tmp > /dev/null then cat check_bb.tmp >> check_bb.log 2>&1 error="yes" echo "bb failed when control file $control_file" fi kill -INT $wappid sleep 1 kill -INT $bbpid sleep 2 # We can panic when we are going down, too if test "$error" != "yes" then if grep 'ERROR:|PANIC:' check_bb.tmp > /dev/null then cat check_bb.tmp >> check_bb.log 2>&1 error="yes" echo "got errors in bb when going down with $control_file" fi if grep 'ERROR:|PANIC:' check_wap.tmp > /dev/null then cat check_wap.tmp >> check_wap.log 2>&1 error="yes" echo "got errors in wap when going down with $control_file" fi if grep 'ERROR:|PANIC:' check_ppg.tmp > /dev/null then cat check_ppg.tmp >> check_ppg.log 2>&1 error="yes" echo "got errors in ppg when going down with $control_file" fi fi rm -f check_bb.tmp check_wap.tmp check_ppg.tmp fi; done # Ok control files requesting a sms bearer. Names contain string 'sms'. Ppg # should use smsc (do a http fetch). for control_file in $sms_control_files; do if [ -f $control_file ] then test/test_http_server -p $server_port > check_http_sim.tmp 2>&1 & simid=$! sleep 1 gw/bearerbox -v $loglevel $conf_file > check_bb.tmp 2>&1 & bbpid=$! sleep 2 gw/wapbox -v $loglevel $conf_file > check_wap.tmp 2>&1 & wappid=$! sleep 2 test/test_ppg -c $contents http://$host:$push_port/cgi-bin/wap-push.cgi?username=$username'&'password=$password $content_file $control_file > check_ppg.tmp 2>&1 sleep 1 if ! grep "and type push response" check_ppg.tmp > /dev/null then cat check_ppg.tmp >> check_ppg.log 2>&1 error="yes" echo "ppg failed with control file $control_file" fi if ! grep "Connectionless push accepted" check_wap.tmp > /dev/null then cat check_wap.tmp >> check_wap.log 2>&1 error="yes" echo "wap failed with control file $control_file" fi if ! grep "got sms from wapbox" check_bb.tmp > /dev/null then cat check_bb.tmp >> check_bb.log 2>&1 error="yes" echo "bb failed with control file $control_file" fi kill -INT $wappid sleep 1 kill -INT $bbpid sleep 2 test/test_http -qv 4 http://$host:$server_port/quit sleep 2 # We can panic when we are going down, too if test "$error" != "yes" then if grep 'WARNING:|ERROR:|PANIC:' check_bb.tmp > /dev/null then cat check_bb.tmp >> check_bb.log 2>&1 error="yes" echo "got errors in bb when going down with $control_file" fi if grep 'WARNING:|ERROR:|PANIC:' check_wap.tmp > /dev/null then cat check_wap.tmp >> check_wap.log 2>&1 error="yes" echo "got errors in wap when going down with $control_file" fi if grep 'WARNING:|ERROR:|PANIC:' check_ppg.tmp > /dev/null then cat check_ppg.tmp >> check_ppg.log 2>&1 error="yes" echo "got errors in ppg when going down with $control_file" fi if grep 'WARNING:|ERROR:|PANIC:' check_http_sim.tmp > /dev/null then cat check_sim.tmp >> check_sim.log 2>&1 error="yes" echo "errors, http_sim when going down with $control_file" fi fi rm -f check_bb.tmp check_wap.tmp check_ppg.tmp check_http_sim.tmp fi; done # Erroneous control documents requesting a sms bearer. Ppg should reject these # and inform pi. Names contain the string 'ws'. for control_file in $wrong_sms_files; do if [ -f $control_file ] then test/test_http_server -p $server_port > check_http_sim.tmp 2>&1 & simid=$ sleep 1 gw/bearerbox -v $loglevel $conf_file > check_bb.tmp 2>&1 & bbpid=$! sleep 2 gw/wapbox -v $loglevel $conf_file > check_wap.tmp 2>&1 & wappid=$! sleep 2 test/test_ppg -c $contents http://$host:$push_port/cgi-bin/wap-push.cgi?username=$username'&'password=$password $content_file $control_file > check_ppg.tmp 2>&1 sleep 1 if ! grep "and type push response" check_ppg.tmp > /dev/null && ! grep "and type bad message response" check_ppg.tmp > /dev/null then cat check_ppg.tmp >> check_ppg.log 2>&1 error="yes" echo "ppg failed, going down with control file $control_file" fi if grep "Connectionless push accepted" check_wap.tmp > /dev/null && grep "WARNING" check_wap.tmp > /dev/null then cat check_wap.tmp >> check_wap.log 2>&1 error="yes" echo "wap failed, going down with control file $control_file" fi if grep "got sms from wapbox" check_bb.tmp > /dev/null then cat check_bb.tmp >> check_bb.log 2>&1 error="yes" echo "bb failed, going down with control file $control_file" fi kill -INT $wappid sleep 2 kill -INT $bbpid sleep 1 test/test_http -qv 4 http://$host:$server_port/quit sleep 2 # We can panic when we are going down, too if test "$error" != "yes" then if grep 'ERROR:|PANIC:' check_bb.tmp > /dev/null then cat check_bb.tmp >> check_bb.log 2>&1 error="yes" echo "got errors in bb when ending tests" fi if grep 'ERROR:|PANIC:' check_wap.tmp > /dev/null then cat check_wap.tmp >> check_wap.log 2>&1 error="yes" echo "got errors in wap when ending tests" fi if grep 'ERROR:|PANIC:' check_ppg.tmp > /dev/null then cat check_ppg.tmp >> check_ppg.log 2>&1 error="yes" echo "got errors in ppg when ending tests" fi if grep 'ERROR:|PANIC:' check_http_sim.tmp > /dev/null then cat check_http_sim.tmp >> check_http_sim.log 2>&1 error="yes" echo "got errors in http_sim when ending tests" fi fi rm -f check_bb.tmp check_wap.tmp check_ppg.tmp fi; done kill -INT $listid sleep 1 test/test_http -qv 4 http://$host:$list_port/quit wait if test "$error" = "yes" then echo "check_ppg failed" 1>&2 echo "See check_bb.log, check_wap.log, check_ppg.log," 1>&2 echo "check_http_list.log, check_http_sim.log for info" 1>&2 exit 1 fi rm -f check_bb.log check_wap.log check_ppg.log check_http_list.log check_http_sim.log exit 0 gateway-1.4.5/checks/check_fakewap.sh0000755000175000017500000000145311144324076016243 0ustar toljtolj#!/bin/sh # # Use `test/fakewap' to test the bearerbox and the wapbox. set -e #set -x host=127.0.0.1 times=2 port=8040 url="http://$host:$port/hello.wml" loglevel=0 test/test_http_server -f test/hello.wml -p $port > check_http.log 2>&1 & httppid=$! gw/bearerbox -v $loglevel gw/wapkannel.conf > check_bb.log 2>&1 & bbpid=$! sleep 2 gw/wapbox -v $loglevel gw/wapkannel.conf > check_wap.log 2>&1 & wappid=$! sleep 2 test/fakewap -g $host -m $times $url > check_fake.log 2>&1 ret=$? test/test_http -qv 4 http://$host:$port/quit kill -INT $bbpid kill -INT $wappid wait if [ "$ret" != 0 ] then echo check_fakewap failed 1>&2 echo See check_bb.log, check_wap.log, check_fake.log, 1>&2 echo check_http.log for info 1>&2 exit 1 fi rm -f check_bb.log check_wap.log check_fake.log check_http.log exit 0 gateway-1.4.5/checks/check_sendsms.sh0000755000175000017500000000710211144324076016276 0ustar toljtolj#!/bin/sh # # Use `test/fakesmsc' to test sendsms in smsbox. set -e #set -x host=127.0.0.1 times=10 interval=0 loglevel=0 sendsmsport=13013 global_sender=13013 username=tester password=foobar url="http://$host:$sendsmsport/cgi-bin/sendsms?from=123&to=234&\ text=test&username=$username&password=$password" gw/bearerbox -v $loglevel gw/smskannel.conf > check_sendsms_bb.log 2>&1 & bbpid=$! sleep 2 test/fakesmsc -H $host -r 20000 -i $interval -m $times '123 234 text nop' \ > check_sendsms_smsc.log 2>&1 & sleep 1 gw/smsbox -v $loglevel gw/smskannel.conf > check_sendsms_sms.log 2>&1 & sleep 2 # All cgivars are OK url="http://$host:$sendsmsport/cgi-bin/sendsms?from=123&to=234&\ text=test&username=$username&password=$password" i=0 while [ $i -lt $times ] do test/test_http $url >> check_sendsms.log 2>&1 i=`expr $i + 1` done sleep 5 if grep 'WARNING:|ERROR:|PANIC:' check_sendsms*.log >/dev/null || [ $times -ne `grep -c 'Got message .*: <123 234 text test>' \ check_sendsms_smsc.log` ] then echo check_sendsms.sh failed with non-empty fields 1>&2 echo See check_sendsms*.log for info 1>&2 exit 1 fi # Empty fields: message. This is OK, we must get a canned reply url="http://$host:$sendsmsport/cgi-bin/sendsms?from=123&to=234&\ text=&username=$username&password=$password" test/test_http $url >> check_sendsms.log 2>&1 sleep 1 if grep 'WARNING:|ERROR:|PANIC:' check_sendsms*.log >/dev/null then echo check_sendsms.sh failed with empty message 1>&2 echo See check_sendsms*.log for info 1>&2 exit 1 fi # From. This is OK, too: now global-sender replaces from field url="http://$host:$sendsmsport/cgi-bin/sendsms?from=&to=234&\ text=test&username=$username&password=$password" test/test_http $url >> check_sendsms.log 2>&1 sleep 1 if grep 'WARNING:|ERROR:|PANIC:' check_sendsms*.log >/dev/null || [ 1 -ne `grep -c '<'$global_sender' 234 text test>' check_sendsms_smsc.log` ] then echo check_sendsms.sh failed with empty from field 1>&2 echo See check_sendsms*.log for info 1>&2 exit 1 fi # To. Now smsbox must report an error. url="http://$host:$sendsmsport/cgi-bin/sendsms?from=123&to=&\ text=&username=$username&password=$password" test/test_http $url >> check_sendsms.log 2>&1 sleep 1 if grep 'WARNING:|ERROR:|PANIC:' check_sendsms*.log >/dev/null || [ 1 -ne `grep -c 'got empty cgi variable' check_sendsms_sms.log` ] then echo check_sendsms.sh failed with empty to field 1>&2 echo See check_sendsms*.log for info 1>&2 exit 1 fi # Username. This is an authentication error. url="http://$host:$sendsmsport/cgi-bin/sendsms?from=123&to=234&\ text=&username=&password=$password" test/test_http $url >> check_sendsms.log 2>&1 sleep 1 if grep 'WARNING:|ERROR:|PANIC:' check_sendsms*.log >/dev/null || [ 1 -ne `grep -c '' \ check_sendsms_sms.log` ] then echo check_sendsms.sh failed username authorisation test 1>&2 echo See check_sendsms*.log for info 1>&2 exit 1 fi # Password. Ditto. url="http://$host:$sendsmsport/cgi-bin/sendsms?from=123&to=234&\ text=&username=$username&password=" if grep 'WARNING:|ERROR:|PANIC:' check_sendsms*.log >/dev/null || [ 1 -ne `grep -c '' \ check_sendsms_sms.log` ] then echo check_sendsms.sh failed with password authorisation test 1>&2 echo See check_sendsms*.log for info 1>&2 exit 1 fi kill -INT $bbpid wait # Do we panic when going down ? if grep 'WARNING:|ERROR:|PANIC:' check_sendsms*.log >/dev/null then echo check_sendsms.sh failed when going down 1>&2 echo See check_sendsms*.log for info 1>&2 exit 1 fi rm -f check_sendsms*.log exit 0 gateway-1.4.5/checks/check_smpp.sh0000755000175000017500000000120713310754115015577 0ustar toljtolj#!/bin/sh # # Use `test/drive_smpp' to test SMPP driver. set -e #set -x times=10 test/drive_smpp -v 0 -m $times 2> check_smpp_drive.log 1>&2 & sleep 1 gw/bearerbox -v 0 test/drive_smpp.conf 2> check_smpp_bb.log 1>&2 & bbpid=$! running=yes while [ $running = yes ] do sleep 1 if grep "All messages sent to ESME." check_smpp_drive.log > /dev/null then running=no fi done sleep 5 kill -INT $bbpid sleep 15 if grep 'WARNING:|ERROR:|PANIC:' check_smpp*.log >/dev/null then echo check_smpp.sh failed 1>&2 echo See check_smpp*.log for info 1>&2 exit 1 fi rm -f check_smpp*.log exit 0 gateway-1.4.5/gw/0000755000175000017500000000000013312227712012301 5ustar toljtoljgateway-1.4.5/gw/mime_decompiler.h0000644000175000017500000000634113227613126015613 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * mime_decompiler.h - decompiling application/vnd.wap.multipart.* * to multipart/ * * * This is a header for Mime decompiler for decompiling binary mime * format to text mime format, which is used for transmitting POST * data from mobile terminal to decrease the use of the bandwidth. * * See comments below for explanations on individual functions. * * Bruno Rodrigues */ #ifndef MIME_DECOMPILER_H #define MIME_DECOMPILER_H int mime_decompile(Octstr *binary_mime, Octstr **mime); #endif gateway-1.4.5/gw/wap_push_sl_compiler.h0000644000175000017500000000620513227613126016676 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_sl_compiler.h: The interface to sl tokenizer * * By Aarno Syvänen for Wiral Ltd */ #ifndef WAP_PUSH_SL_COMPILER_H #define WAP_PUSH_SL_COMPILER_H #include "gwlib/gwlib.h" /* * Compiles a sl document to sl binary. Input textual form of a sl document * and its charset (from http headers), output the document in a tokenised * form. */ int sl_compile(Octstr *sl_doc, Octstr *charset, Octstr **sl_binary); #endif gateway-1.4.5/gw/sms.c0000644000175000017500000003406113227613126013256 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * sms.c - features specific to SMS but not particular to any SMSC protocol. * * This file current contains very little, but sms features that are * currently implemented separately in each protocol should be extracted * and placed here. */ #include "sms.h" #include "dlr.h" /* * Encode DCS using sms fields * mode = 0= encode using 00xxx, 1= encode using Fx mode * */ int fields_to_dcs(Msg *msg, int mode) { int dcs=0; /* Coding defaults to 7BIT or to 8BIT if udh is set */ if (msg->sms.coding == DC_UNDEF) { if (octstr_len(msg->sms.udhdata)) msg->sms.coding = DC_8BIT; else msg->sms.coding = DC_7BIT; } /* MWI */ if (msg->sms.mwi != MWI_UNDEF) { dcs = msg->sms.mwi; /* sets bits 2, 1 and 0 */ if (dcs & 0x04) dcs = (dcs & 0x03) | 0xC0; /* MWI Inactive */ else { dcs = (dcs & 0x03) | 0x08; /* MWI Active, sets bit 3 */ if (! octstr_len(msg->sms.msgdata)) dcs |= 0xC0; /* Discard */ else if (msg->sms.coding == DC_7BIT) dcs |= 0xD0; /* 7bit */ else dcs |= 0xE0; /* UCS-2 */ /* XXX Shouldn't happen to have mwi and dc=DC_8BIT! */ } } /* Non-MWI */ else { /* mode 0 or mode UNDEF */ if (mode == 0 || mode == SMS_PARAM_UNDEFINED || msg->sms.coding == DC_UCS2 || msg->sms.compress == COMPRESS_ON) { /* bits 7,6 are 0 */ if (msg->sms.compress == COMPRESS_ON) dcs |= 0x20; /* sets bit 5 */ if (msg->sms.mclass != MC_UNDEF) dcs |= (0x10 | msg->sms.mclass); /* sets bit 4,1,0 */ if (msg->sms.coding != DC_UNDEF) dcs |= (msg->sms.coding << 2); /* sets bit 3,2 */ } /* mode 1 */ else { dcs |= 0xF0; /* sets bits 7-3 */ if(msg->sms.coding != DC_UNDEF) dcs |= (msg->sms.coding << 2); /* only DC_7BIT or DC_8BIT, sets bit 2*/ if (msg->sms.mclass == MC_UNDEF) dcs |= 1; /* default meaning: ME specific */ else dcs |= msg->sms.mclass; /* sets bit 1,0 */ } } return dcs; } /* * Decode DCS to sms fields */ int dcs_to_fields(Msg **msg, int dcs) { /* Non-MWI Mode 1 */ if ((dcs & 0xF0) == 0xF0) { dcs &= 0x07; (*msg)->sms.coding = (dcs & 0x04) ? DC_8BIT : DC_7BIT; /* grab bit 2 */ (*msg)->sms.mclass = dcs & 0x03; /* grab bits 1,0 */ (*msg)->sms.alt_dcs = 1; /* set 0xFX data coding */ } /* Non-MWI Mode 0 */ else if ((dcs & 0xC0) == 0x00) { (*msg)->sms.alt_dcs = 0; (*msg)->sms.compress = ((dcs & 0x20) == 0x20) ? 1 : 0; /* grab bit 5 */ (*msg)->sms.mclass = ((dcs & 0x10) == 0x10) ? dcs & 0x03 : MC_UNDEF; /* grab bit 0,1 if bit 4 is on */ (*msg)->sms.coding = (dcs & 0x0C) >> 2; /* grab bit 3,2 */ } /* MWI */ else if ((dcs & 0xC0) == 0xC0) { (*msg)->sms.alt_dcs = 0; (*msg)->sms.coding = ((dcs & 0x30) == 0x30) ? DC_UCS2 : DC_7BIT; if (!(dcs & 0x08)) dcs |= 0x04; /* if bit 3 is active, have mwi += 4 */ dcs &= 0x07; (*msg)->sms.mwi = dcs ; /* grab bits 1,0 */ } else { return 0; } return 1; } /* * Compute length of an Octstr after it will be converted to GSM 03.38 * 7 bit alphabet - escaped characters would be counted as two septets */ int sms_msgdata_len(Msg* msg) { int ret = 0; Octstr* msgdata = NULL; /* got a bad input */ if (!msg || !msg->sms.msgdata) return -1; if (msg->sms.coding == DC_7BIT) { msgdata = octstr_duplicate(msg->sms.msgdata); charset_utf8_to_gsm(msgdata); ret = octstr_len(msgdata); octstr_destroy(msgdata); } else ret = octstr_len(msg->sms.msgdata); return ret; } int sms_swap(Msg *msg) { Octstr *sender = NULL; if (msg->sms.sender != NULL && msg->sms.receiver != NULL) { sender = msg->sms.sender; msg->sms.sender = msg->sms.receiver; msg->sms.receiver = sender; return 1; } return 0; } /***************************************************************************** * * Split an SMS message into smaller ones. */ #define CATENATE_UDH_LEN 5 void prepend_catenation_udh(Msg *sms, int part_no, int num_messages, int msg_sequence) { if (sms->sms.udhdata == NULL) sms->sms.udhdata = octstr_create(""); if (octstr_len(sms->sms.udhdata) == 0) octstr_append_char(sms->sms.udhdata, CATENATE_UDH_LEN); octstr_format_append(sms->sms.udhdata, "%c\3%c%c%c", 0, msg_sequence, num_messages, part_no); /* Set the number of messages left, if any */ if (part_no < num_messages) sms->sms.msg_left = num_messages - part_no; else sms->sms.msg_left = 0; /* * Now that we added the concatenation information the * length is all wrong. we need to recalculate it. */ octstr_set_char(sms->sms.udhdata, 0, octstr_len(sms->sms.udhdata) - 1 ); } static Octstr *extract_msgdata_part(Octstr *msgdata, Octstr *split_chars, int max_part_len) { long i, len; Octstr *part; len = max_part_len; if (max_part_len < octstr_len(msgdata) && split_chars != NULL) for (i = max_part_len; i > 0; i--) if (octstr_search_char(split_chars, octstr_get_char(msgdata, i - 1), 0) != -1) { len = i; break; } part = octstr_copy(msgdata, 0, len); octstr_delete(msgdata, 0, len); return part; } static Octstr *extract_msgdata_part_by_coding(Msg *msg, Octstr *split_chars, int max_part_len) { Octstr *temp = NULL, *temp_utf; if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) { /* nothing to do here, just call the original extract_msgdata_part */ return extract_msgdata_part(msg->sms.msgdata, split_chars, max_part_len); } /* * XXX TODO * Convert to and the from gsm, so we drop all non GSM chars. * This means effectively that we can NOT use any encoding specific * characters in the SMSC module scope that are NOT in the GSM 03.38 * alphabet, i.e. UTF-8 0xC2 0xAE is latin1 0xAE and maps to an unknown * character due to this round-trip transcoding. */ charset_utf8_to_gsm(msg->sms.msgdata); charset_gsm_to_utf8(msg->sms.msgdata); /* * else we need to do something special. I'll just get charset_gsm_truncate to * cut the string to the required length and then count real characters. */ temp = octstr_duplicate(msg->sms.msgdata); charset_utf8_to_gsm(temp); charset_gsm_truncate(temp, max_part_len); /* calculate utf-8 length */ temp_utf = octstr_duplicate(temp); charset_gsm_to_utf8(temp_utf); max_part_len = octstr_len(temp_utf); octstr_destroy(temp); octstr_destroy(temp_utf); /* now just call the original extract_msgdata_part with the new length */ return extract_msgdata_part(msg->sms.msgdata, split_chars, max_part_len); } List *sms_split(Msg *orig, Octstr *header, Octstr *footer, Octstr *nonlast_suffix, Octstr *split_chars, int catenate, unsigned long msg_sequence, int max_messages, int max_octets) { long max_part_len, udh_len, hf_len, nlsuf_len; unsigned long total_messages, msgno; long last; List *list; Msg *part, *temp; hf_len = octstr_len(header) + octstr_len(footer); nlsuf_len = octstr_len(nonlast_suffix); udh_len = octstr_len(orig->sms.udhdata); /* First check whether the message is under one-part maximum */ if (orig->sms.coding == DC_8BIT || orig->sms.coding == DC_UCS2) max_part_len = max_octets - udh_len - hf_len; else max_part_len = (max_octets - udh_len) * 8 / 7 - hf_len; if (sms_msgdata_len(orig) > max_part_len && catenate) { /* Change part length to take concatenation overhead into account */ if (udh_len == 0) udh_len = 1; /* Add the udh total length octet */ udh_len += CATENATE_UDH_LEN; if (orig->sms.coding == DC_8BIT || orig->sms.coding == DC_UCS2) max_part_len = max_octets - udh_len - hf_len; else max_part_len = (max_octets - udh_len) * 8 / 7 - hf_len; } /* ensure max_part_len is never negativ */ max_part_len = max_part_len > 0 ? max_part_len : 0; temp = msg_duplicate(orig); msgno = 0; list = gwlist_create(); last = 0; do { msgno++; part = msg_duplicate(orig); /* * if its a DLR request message getting split, * only ask DLR for the first one */ if ((msgno > 1) && DLR_IS_ENABLED(part->sms.dlr_mask)) { octstr_destroy(part->sms.dlr_url); part->sms.dlr_url = NULL; part->sms.dlr_mask = 0; } octstr_destroy(part->sms.msgdata); if (sms_msgdata_len(temp) <= max_part_len || msgno == max_messages) last = 1; part->sms.msgdata = extract_msgdata_part_by_coding(temp, split_chars, max_part_len - nlsuf_len); /* create new id for every part, except last */ if (!last) uuid_generate(part->sms.id); if (header) octstr_insert(part->sms.msgdata, header, 0); if (footer) octstr_append(part->sms.msgdata, footer); if (!last && nonlast_suffix) octstr_append(part->sms.msgdata, nonlast_suffix); gwlist_append(list, part); } while (!last); total_messages = msgno; msg_destroy(temp); if (catenate && total_messages > 1) { for (msgno = 1; msgno <= total_messages; msgno++) { part = gwlist_get(list, msgno - 1); prepend_catenation_udh(part, msgno, total_messages, msg_sequence); } } return list; } int sms_priority_compare(const void *a, const void *b) { int ret; Msg *msg1 = (Msg*)a, *msg2 = (Msg*)b; gw_assert(msg_type(msg1) == sms); gw_assert(msg_type(msg2) == sms); if (msg1->sms.priority > msg2->sms.priority) ret = 1; else if (msg1->sms.priority < msg2->sms.priority) ret = -1; else { if (msg1->sms.time > msg2->sms.time) ret = 1; else if (msg1->sms.time < msg2->sms.time) ret = -1; else ret = 0; } return ret; } int sms_charset_processing(Octstr *charset, Octstr *body, int coding) { int resultcode = 0; /* debug("gw.sms", 0, "%s: enter, charset=%s, coding=%d, msgdata is:", __func__, octstr_get_cstr(charset), coding); octstr_dump(body, 0); */ if (octstr_len(charset)) { if (coding == DC_7BIT) { /* * For 7 bit, convert to UTF-8 */ if (charset_convert(body, octstr_get_cstr(charset), "UTF-8") < 0) { error(0, "Failed to convert msgdata from charset <%s> to <%s>, will leave as is.", octstr_get_cstr(charset), "UTF-8"); resultcode = -1; } } else if (coding == DC_UCS2) { /* * For UCS-2, convert to UTF-16BE */ if (charset_convert(body, octstr_get_cstr(charset), "UTF-16BE") < 0) { error(0, "Failed to convert msgdata from charset <%s> to <%s>, will leave as is.", octstr_get_cstr(charset), "UTF-16BE"); resultcode = -1; } } } /* debug("gw.sms", 0, "%s: exit, charset=%s, coding=%d, msgdata is:", __func__, octstr_get_cstr(charset), coding); octstr_dump(body, 0); */ return resultcode; } gateway-1.4.5/gw/urltrans.h0000644000175000017500000002550113227613126014332 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * urltrans.h - URL translations * * The SMS gateway receives service requests sent as SMS messages and uses * a web server to actually perform the requests. The first word of the * SMS message usually specifies the service, and for each service there is * a URL that specifies the web page or cgi-bin that performs the service. * Thus, in effect, the gateway `translates' SMS messages to URLs. * * urltrans.h and urltrans.c implement a data structure for holding a list * of translations and formatting a SMS request into a URL. It is used as * follows: * * 1. Create a URLTranslation object with urltrans_create. * 2. Add translations into it with urltrans_add_one or urltrans_add_cfg. * 3. Receive SMS messages, and translate them into URLs with * urltrans_get_url. * 4. When you are done, free the object with urltrans_destroy. * * See below for more detailed instructions for using the functions. * * Lars Wirzenius for WapIT Ltd. */ #ifndef URLTRANS_H #define URLTRANS_H #include "gwlib/gwlib.h" #include "msg.h" #include "numhash.h" #include "gwlib/regex.h" /* * This is the data structure that holds the list of translations. It is * opaque and is defined in and usable only within urltrans.c. */ typedef struct URLTranslationList URLTranslationList; /* * This is the data structure that holds one translation. It is also * opaque, and is accessed via some of the functions below. */ typedef struct URLTranslation URLTranslation; enum { TRANSTYPE_GET_URL = 0, TRANSTYPE_POST_URL, TRANSTYPE_POST_XML, TRANSTYPE_TEXT, TRANSTYPE_FILE, TRANSTYPE_EXECUTE, TRANSTYPE_SENDSMS }; /* * Create a new URLTranslationList object. Return NULL if the creation failed, * or a pointer to the object if it succeded. * * The object is empty: it contains no translations. */ URLTranslationList *urltrans_create(void); /* * Destroy a URLTranslationList object. */ void urltrans_destroy(URLTranslationList *list); /* * Add a translation to the object. The group is parsed internally. * * There can be several patterns for the same keyword, but with different * patterns. urltrans_get_url will pick the pattern that best matches the * actual SMS message. (See urltrans_get_pattern for a description of the * algorithm.) * * There can only be one pattern with keyword "default", however. * * Sendsms-translations do not use keyword. Instead they use username and * password * * Return -1 for error, or 0 for OK. */ int urltrans_add_one(URLTranslationList *trans, CfgGroup *grp); /* * Add translations to a URLTranslation object from a Config object * (see config.h). Translations are added from groups in `cfg' that * contain variables called "keyword" and "url". For each such group, * urltrans_add_one is called. * * Return -1 for error, 0 for OK. If -1 is returned, the URLTranslation * object may have been partially modified. */ int urltrans_add_cfg(URLTranslationList *trans, Cfg *cfg); /* * Find the translation that corresponds to a given text string * * Use the translation with pattern whose keyword is the same as the first * word of the text and that has the number of `%s' fields as the text * has words after the first one. If no such pattern exists, use the * pattern whose keyword is "default". If there is no such pattern, either, * return NULL. * * If 'smsc' is set, only accept translation with no 'accepted-smsc' set or * with matching smsc in that list. * * If 'account' is set, only accept translation with no 'accepted-account' set or * with matching account in that list. */ URLTranslation *urltrans_find(URLTranslationList *trans, Msg *msg); /* * Find the translation that corresponds to a given name * * Use the translation with service whose name is the same as the first * word of the text. If no such pattern exists, return NULL. */ URLTranslation *urltrans_find_service(URLTranslationList *trans, Msg *msg); /* * find matching URLTranslation for the given 'username', or NULL * if not found. Password must be checked afterwards */ URLTranslation *urltrans_find_username(URLTranslationList *trans, Octstr *name); /* * Return the populated URL octstr from the given pattern containing * the escape codes with values from the Msg. * urtrans_get_pattern() uses this internally, but we want to provide * this function also to the external calling space for use of the * defined escape codes for Msg values. */ Octstr *urltrans_fill_escape_codes(Octstr *pattern, Msg *request); /* * Return a pattern given contents of an SMS message. Find the appropriate * translation pattern and fill in the missing parts from the contents of * the SMS message. * * `sms' is the SMS message that is being translated. * * Return NULL if there is a failure. Otherwise, return a pointer to the * pattern, which is stored in dynamically allocated memory that the * caller should free when the pattern is no longer needed. * * The pattern is URL, fixed text or file name according to type of urltrans */ Octstr *urltrans_get_pattern(URLTranslation *t, Msg *sms); /* * Return the type of the translation, see enumeration above */ int urltrans_type(URLTranslation *t); /* * Return prefix and suffix of translations, if they have been set. */ Octstr *urltrans_prefix(URLTranslation *t); Octstr *urltrans_suffix(URLTranslation *t); /* * Return default sender number, or NULL if not set. */ Octstr *urltrans_default_sender(URLTranslation *t); /* * Return (a recommended) faked sender number, or NULL if not set. */ Octstr *urltrans_faked_sender(URLTranslation *t); /* * Return maximum number of SMS messages that should be generated from * the web page directed by the URL translation. */ int urltrans_max_messages(URLTranslation *t); /* * Return the concatenation status for SMS messages that should be generated * from the web page directed by the URL translation. (1=enabled) */ int urltrans_concatenation(URLTranslation *t); /* * Return (recommended) delimiter characters when splitting long * replies into several messages */ Octstr *urltrans_split_chars(URLTranslation *t); /* * return a string that should be added after each sms message if it is * except for the last one. */ Octstr *urltrans_split_suffix(URLTranslation *t); /* * Return if set that should not send 'empty reply' messages */ int urltrans_omit_empty(URLTranslation *t); /* * return a string that should be inserted to each SMS, if any */ Octstr *urltrans_header(URLTranslation *t); /* * return a string that should be appended to each SMS, if any */ Octstr *urltrans_footer(URLTranslation *t); /* * Return the alternative charset to be used for the sms-service. */ Octstr *urltrans_alt_charset(URLTranslation *t); /* * return the name, username or password string, or NULL if not set * (used only with TRANSTYPE_SENDSMS) */ Octstr *urltrans_name(URLTranslation *t); Octstr *urltrans_username(URLTranslation *t); Octstr *urltrans_password(URLTranslation *t); /* Return forced smsc ID for send-sms user, if set */ Octstr *urltrans_forced_smsc(URLTranslation *t); /* Return default smsc ID for send-sms user, if set */ Octstr *urltrans_default_smsc(URLTranslation *t); /* Return allow and deny IP strings, if set. */ Octstr *urltrans_allow_ip(URLTranslation *t); Octstr *urltrans_deny_ip(URLTranslation *t); /* Return allowed and denied prefixes */ Octstr *urltrans_allowed_prefix(URLTranslation *t); Octstr *urltrans_denied_prefix(URLTranslation *t); Octstr *urltrans_allowed_recv_prefix(URLTranslation *t); Octstr *urltrans_denied_recv_prefix(URLTranslation *t); /* Return white and black to number list */ Numhash *urltrans_white_list(URLTranslation *t); Numhash *urltrans_black_list(URLTranslation *t); regex_t *urltrans_white_list_regex(URLTranslation *t); regex_t *urltrans_black_list_regex(URLTranslation *t); /* Return value of true (!0) or false (0) variables */ int urltrans_assume_plain_text(URLTranslation *t); int urltrans_accept_x_kannel_headers(URLTranslation *t); int urltrans_strip_keyword(URLTranslation *t); int urltrans_send_sender(URLTranslation *t); /* Return DLR related values */ Octstr *urltrans_dlr_url(URLTranslation *t); int urltrans_dlr_mask(URLTranslation *t); #endif gateway-1.4.5/gw/alt_charsets.h0000644000175000017500000000657613227613126015147 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef ALT_CHARSETS_H #define ALT_CHARSETS_H /* file of FtS -kludges (Fuck the Standards) * * used to bypass non-standard charset things in SMS Centers * * Kalle Marjola 1999 */ /* this one is for Nokia CIMD 1.3.6 SMS Center - it causes error * if a standard specified dollar sign is sent. */ #define CIMD_PLAIN_DOLLAR_SIGN 1 /* for Sonera EMI, for unknown reason the $ and ¡ characters * are swapped in ISO to MT conversion */ #define EMI_SWAPPED_CHARS 2 /* * for CMG's EMI/UCP, operators may use NCR (national representation * codes), like ISO 21 German for the german "Umlauts". * i.e. Vodafone D2 uses this charset kludges. */ #define EMI_NRC_ISO_21 3 #endif gateway-1.4.5/gw/heartbeat.c0000644000175000017500000001437713227613126014423 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * heartbeat.c - thread for sending heartbeat Msgs to bearerbox */ #include #include "gwlib/gwlib.h" #include "msg.h" #include "heartbeat.h" /* * Each running heartbeat gets one of these. They are collected in * the heartbeats List. */ struct hb_info { hb_send_func_t *send_func; double freq; hb_load_func_t *load_func; long thread; volatile sig_atomic_t running; }; /* List of struct hb_info. */ static List *heartbeats = NULL; /* * Look for a hb_info in a list, by thread number. */ static int find_hb(void *item, void *pattern) { long *threadnrp; struct hb_info *info; info = item; threadnrp = pattern; return info->thread == *threadnrp; } static void heartbeat_thread(void *arg) { struct hb_info *info; time_t last_hb; info = arg; last_hb = 0; while (info->running) { Msg *msg; gwthread_sleep(info->freq); /* * Because the sleep can be interrupted, we might end up sending * heartbeats faster than the configured heartbeat frequency. * This is not bad unless we send them way too fast. Make sure * our frequency is not more than twice the configured one. */ if (difftime(time(NULL), last_hb) < info->freq / 2) continue; msg = msg_create(heartbeat); if (NULL != info->load_func) msg->heartbeat.load = info->load_func(); info->send_func(msg); last_hb = time(NULL); } } long heartbeat_start(hb_send_func_t *send_func, double freq, hb_load_func_t *load_func) { struct hb_info *info; /* can't start with send_funct NULL */ if (send_func == NULL) return -1; info = gw_malloc(sizeof(*info)); info->send_func = send_func; info->freq = (freq <= 0 ? DEFAULT_HEARTBEAT : freq); info->load_func = load_func; info->running = 1; info->thread = gwthread_create(heartbeat_thread, info); if (info->thread >= 0) { if (heartbeats == NULL) heartbeats = gwlist_create(); gwlist_append(heartbeats, info); return info->thread; } else { gw_free(info); return -1; } } /* * function : heartbeat_stop * arguments: long hb_thread, the thread number of the heartbeat * that is wished to be stopped. * if hb_thread == ALL_HEARTBEATS then all heartbeats * are stopped. * returns : - */ void heartbeat_stop(long hb_thread) { List *matching_info; struct hb_info *info; /* * First, check if there are heartbeats to stop. * If not, do not continue, otherwise this function will crash */ if (heartbeats == NULL) return; if (hb_thread == ALL_HEARTBEATS) { while (NULL != (info = gwlist_extract_first(heartbeats))) { gw_assert(info); info->running = 0; gwthread_wakeup(info->thread); gwthread_join(info->thread); gw_free(info); } } else { matching_info = gwlist_extract_matching(heartbeats, &hb_thread, find_hb); if (matching_info == NULL) { warning(0, "Could not stop heartbeat %ld: not found.", hb_thread); return; } gw_assert(gwlist_len(matching_info) == 1); info = gwlist_extract_first(matching_info); gwlist_destroy(matching_info, NULL); info->running = 0; gwthread_wakeup(hb_thread); gwthread_join(hb_thread); gw_free(info); } if (gwlist_len(heartbeats) == 0) { gwlist_destroy(heartbeats, NULL); heartbeats = NULL; } } gateway-1.4.5/gw/bb_store.c0000644000175000017500000001602713227613126014255 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * bb_store.c : wrapper for the different bearerbox box SMS storage/retrieval module * * Author: Alexander Malysh, 2006 */ #include "gw-config.h" #include "gwlib/gwlib.h" #include "msg.h" #include "bearerbox.h" #include "bb_store.h" long (*store_messages)(void); int (*store_save)(Msg *msg); int (*store_save_ack)(Msg *msg, ack_status_t status); int (*store_load)(void(*receive_msg)(Msg*)); int (*store_dump)(void); void (*store_shutdown)(void); Octstr* (*store_msg_pack)(Msg *msg); Msg* (*store_msg_unpack)(Octstr *os); void (*store_for_each_message)(void(*callback_fn)(Msg* msg, void *data), void *data); int store_init(Cfg *cfg, const Octstr *type, const Octstr *fname, long dump_freq, void *pack_func, void *unpack_func) { int ret; store_msg_pack = pack_func; store_msg_unpack = unpack_func; if (type == NULL || octstr_str_compare(type, "file") == 0) { ret = store_file_init(fname, dump_freq); } else if (octstr_str_compare(type, "spool") == 0) { ret = store_spool_init(fname); #ifdef HAVE_REDIS } else if (octstr_str_compare(type, "redis") == 0) { ret = store_redis_init(cfg); #endif } else { error(0, "Unknown 'store-type' defined."); ret = -1; } return ret; } struct status { const char *format; Octstr *status; }; static void status_cb(Msg *msg, void *d) { struct status *data = d; struct tm tm; char id[UUID_STR_LEN + 1]; if (msg == NULL) return; /* transform the time value */ #if LOG_TIMESTAMP_LOCALTIME tm = gw_localtime(msg->sms.time); #else tm = gw_gmtime(msg->sms.time); #endif uuid_unparse(msg->sms.id, id); octstr_format_append(data->status, data->format, id, (msg->sms.sms_type == mo ? "MO" : msg->sms.sms_type == mt_push ? "MT-PUSH" : msg->sms.sms_type == mt_reply ? "MT-REPLY" : msg->sms.sms_type == report_mo ? "DLR-MO" : msg->sms.sms_type == report_mt ? "DLR-MT" : ""), tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, (msg->sms.sender ? octstr_get_cstr(msg->sms.sender) : ""), (msg->sms.receiver ? octstr_get_cstr(msg->sms.receiver) : ""), (msg->sms.smsc_id ? octstr_get_cstr(msg->sms.smsc_id) : ""), (msg->sms.boxc_id ? octstr_get_cstr(msg->sms.boxc_id) : ""), msg->sms.mclass, msg->sms.coding, msg->sms.mwi, msg->sms.compress, msg->sms.dlr_mask, (msg->sms.udhdata ? msg->sms.udhdata : octstr_imm("")), (msg->sms.msgdata ? msg->sms.msgdata : octstr_imm(""))); } Octstr *store_status(int status_type) { Octstr *ret = octstr_create(""); const char *format; struct status data; /* check if we are active */ if (store_for_each_message == NULL) return ret; /* set the type based header */ if (status_type == BBSTATUS_HTML) { octstr_append_cstr(ret, "\n" "" "" "" "\n"); format = "" "" "" "\n"; } else if (status_type == BBSTATUS_XML) { format = "\t\n\t%s\n\t%s\n\t" "\n\t" "%s\n\t" "%s\n\t%s\n\t" "%s\n\t" "%ld:%ld:%ld:%ld:%ld\n\t" "%E\n\t%E\n\t" "\n"; } else { octstr_append_cstr(ret, "[SMS ID] [Type] [Time] [Sender] [Receiver] [SMSC ID] [BOX ID] [Flags] [UDH] [Message]\n"); format = "[%s] [%s] [%04d-%02d-%02d %02d:%02d:%02d] [%s] [%s] [%s] [%s] [%ld:%ld:%ld:%ld:%ld] [%E] [%E]\n"; } data.format = format; data.status = ret; store_for_each_message(status_cb, &data); /* set the type based footer */ if (status_type == BBSTATUS_HTML) { octstr_append_cstr(ret,"
SMS IDTypeTimeSenderReceiverSMSC IDBOX IDFlagsUDHMessage
%s%s%04d-%02d-%02d %02d:%02d:%02d%s%s%s%s%ld:%ld:%ld:%ld:%ld%E%E
"); } return ret; } gateway-1.4.5/gw/bb_smscconn_cb.h0000644000175000017500000001174613227613126015420 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef BB_SMSCCONN_CB #define BB_SMSCCONN_CB #include "msg.h" #include "smscconn.h" /* Callback functions for SMSC Connection implementations. * All functions return immediately. * * NOTE: These callback functions MUST be called by SMSCConn * implementations in given times! See smscconn_p.h for details */ /* called immediately after startup is done. This is called * AUTOMATICALLY by smscconn_create, no need to call it from * various implementations */ void bb_smscconn_ready(SMSCConn *conn); /* called each time when SMS center connected */ void bb_smscconn_connected(SMSCConn *conn); /* called after SMSCConn is shutdown or it kills itself * because of non-recoverable problems. SMSC Connection has already * destroyed all its private data areas and set status as SMSCCONN_DEAD. * Calling this function must be the last thing done by SMSC Connection * before exiting with the last thread */ void bb_smscconn_killed(void); /* * Called after successful sending of Msg 'sms'. Generate dlr message if * DLR_SMSC_SUCCESS mask is set. 'reply' will be passed as msgdata to * generated dlr message. This callback takes * care of 'sms' and 'reply' and it CAN NOT be used by caller again. */ void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply); /* * Called after failed sending of 'sms'. Generate dlr message if * DLR_SMSC_FAIL or DLR_FAIL mask is set. 'reply' will be passed as * msgdata to generated dlr message.Reason is set accordingly. * callback handles 'sms' and 'reply' and MAY NOT be used by caller again */ void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply); enum { SMSCCONN_SUCCESS = 0, SMSCCONN_QUEUED, SMSCCONN_FAILED_SHUTDOWN, SMSCCONN_FAILED_REJECTED, SMSCCONN_FAILED_MALFORMED, SMSCCONN_FAILED_TEMPORARILY, SMSCCONN_FAILED_DISCARDED, SMSCCONN_FAILED_QFULL, SMSCCONN_FAILED_EXPIRED }; /* called when a new message 'sms' received. Callback handles * 'sms' and MAY NOT be used by caller again. Return SMSCCONN_SUCCESS if all went * fine, SMSCCONN_FAILED_QFULL if incoming queue full, SMSCCONN_FAILED_TEMPORARILY * if store enabled and failed, and SMSCCONN_FAILED_REJECTED if bearerbox does * NOT accept the 'sms' (black/whitelisted) */ long bb_smscconn_receive(SMSCConn *conn, Msg *sms); #endif gateway-1.4.5/gw/wap-appl.c0000644000175000017500000016326313227613126014204 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/wap-appl.c - wapbox application layer and push ota indication, response * and confirmation primitive implementation. * * This module implements various indication and confirmation primitives and * protocol mappings as defined in: * * WAP-189-PushOTA-20000217-a (hereafter called ota) * WAP-200-WDP-20001212-a (wdp) * WAP-248-UAProf-20011020-a (UAProf) * * Wapbox application layer itself is not a WAP Forum protocol. * * The application layer is reads events from its event queue, fetches the * corresponding URLs and feeds back events to the WSP layer (pull). * * In addition, the layer forwards WSP events related to push to the module * wap_push_ppg and wsp, implementing indications, responses and confirma- * tions of ota. * * Note that push header encoding and decoding are divided two parts: * first decoding and encoding numeric values and then packing these values * into WSP format and unpacking them from WSP format. This module contains * encoding part. * * Lars Wirzenius */ #include #include "gwlib/gwlib.h" #include "wmlscript/ws.h" #include "xml_shared.h" #include "wml_compiler.h" #include "mime_decompiler.h" #include "wap/wap.h" #include "wap-appl.h" #include "wap_push_ppg.h" #include "wap/wsp_strings.h" #include "wap/wsp_caps.h" #include "wap/wsp.h" #ifdef ENABLE_COOKIES #include "wap/cookies.h" #endif #include "radius/radius_acct.h" #include "wap-error.h" #include "wap-maps.h" #define ENABLE_NOT_ACCEPTED /* * Give the status the module: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum { limbo, running, terminating } run_status = limbo; /* * The queue of incoming events. */ static List *queue = NULL; /* * HTTP caller identifier for application layer. */ static HTTPCaller *caller = NULL; /* * Number of currently running HTTP fetching threads. */ static Counter *fetches = NULL; /* * Charsets supported by WML compiler, queried from wml_compiler. */ static List *charsets = NULL; struct content { Octstr *body; Octstr *type; Octstr *charset; Octstr *url; Octstr *version; }; /* * A mapping from HTTP request identifiers to information about the request. */ struct request_data { long client_SDU_size; WAPEvent *event; long session_id; Octstr *method; Octstr *url; long x_wap_tod; List *request_headers; Octstr *msisdn; }; /* * WSP smart error messaging */ extern int wsp_smart_errors; extern Octstr *device_home; /* * Defines if PPG is running in wapbox instance */ static int have_ppg = 0; /* * Private functions. */ static void main_thread(void *); static void start_fetch(WAPEvent *); static void return_replies_thread(void *); static void dev_null(const char *data, size_t len, void *context); static Octstr *convert_wml_to_wmlc(struct content *content); static Octstr *convert_wmlscript_to_wmlscriptc(struct content *content); /* DAVI: To-Do static Octstr *convert_multipart_mixed(struct content *content); */ static Octstr *deconvert_multipart_formdata(struct content *content); /* DAVI: To-Do static Octstr *deconvert_mms_message(struct content *content); */ static List *negotiate_capabilities(List *req_caps); static struct { char *type; char *result_type; Octstr *(*convert)(struct content *); } converters[] = { { "text/vnd.wap.wml", "application/vnd.wap.wmlc", convert_wml_to_wmlc }, { "text/vnd.wap.wmlscript", "application/vnd.wap.wmlscriptc", convert_wmlscript_to_wmlscriptc }, /* DAVI: To-Do { "multipart/mixed", "application/vnd.wap.multipart.mixed", convert_multipart_mixed }, */ }; #define NUM_CONVERTERS ((long)(sizeof(converters) / sizeof(converters[0]))) static struct { char *type; char *result_type; Octstr *(*deconvert)(struct content *); } deconverters[] = { { "application/vnd.wap.multipart.form-data", "multipart/form-data; boundary=kannel_boundary", deconvert_multipart_formdata }, /* DAVI: To-Do { "application/vnd.wap.mms-message", "multipart/related; type=application/smil; boundary=kannel_boundary; start=", deconvert_mms_message }, */ }; #define NUM_DECONVERTERS ((long)(sizeof(deconverters) / sizeof(deconverters[0]))) /* * Following functions implement indications and conformations part of Push * OTA protocol. */ static void indicate_push_connection(WAPEvent *e); static void indicate_push_disconnect(WAPEvent *e); static void indicate_push_suspend(WAPEvent *e); static void indicate_push_resume(WAPEvent *e); static void confirm_push(WAPEvent *e); static void indicate_push_abort(WAPEvent *e); static void split_header_list(List **headers, List **new_headers, char *name); static void check_application_headers(List **headers, List **app_headers); static void decode_bearer_indication(List **headers, List **bearer_headers); static void response_push_connection(WAPEvent *e); /*********************************************************************** * The public interface to the application layer. */ void wap_appl_init(Cfg *cfg) { gw_assert(run_status == limbo); queue = gwlist_create(); fetches = counter_create(); gwlist_add_producer(queue); run_status = running; charsets = wml_charsets(); caller = http_caller_create(); gwthread_create(main_thread, NULL); gwthread_create(return_replies_thread, NULL); if (cfg != NULL) have_ppg = 1; else have_ppg = 0; } void wap_appl_shutdown(void) { gw_assert(run_status == running); run_status = terminating; gwlist_remove_producer(queue); gwthread_join_every(main_thread); http_caller_signal_shutdown(caller); gwthread_join_every(return_replies_thread); wap_map_destroy(); wap_map_user_destroy(); http_caller_destroy(caller); gwlist_destroy(queue, wap_event_destroy_item); gwlist_destroy(charsets, octstr_destroy_item); counter_destroy(fetches); } void wap_appl_dispatch(WAPEvent *event) { gw_assert(run_status == running); gwlist_produce(queue, event); } long wap_appl_get_load(void) { gw_assert(run_status == running); return counter_value(fetches) + gwlist_len(queue); } /*********************************************************************** * Private functions. */ /* * When we have a push event, create ota indication or confirmation and send * it to ppg module. * Because Accept-Application and Bearer-Indication are optional, we cannot * rely on them. We must ask ppg main module do we have an open push session * for this initiator. Push is identified by push id. * If there is no ppg configured, do not refer to ppg's sessions' list. */ static void main_thread(void *arg) { WAPEvent *ind, *res; long sid; WAPAddrTuple *tuple; while (run_status == running && (ind = gwlist_consume(queue)) != NULL) { switch (ind->type) { case S_MethodInvoke_Ind: res = wap_event_create(S_MethodInvoke_Res); res->u.S_MethodInvoke_Res.server_transaction_id = ind->u.S_MethodInvoke_Ind.server_transaction_id; res->u.S_MethodInvoke_Res.session_id = ind->u.S_MethodInvoke_Ind.session_id; wsp_session_dispatch_event(res); start_fetch(ind); break; case S_Unit_MethodInvoke_Ind: start_fetch(ind); break; case S_Connect_Ind: tuple = ind->u.S_Connect_Ind.addr_tuple; if (have_ppg && wap_push_ppg_have_push_session_for(tuple)) { indicate_push_connection(ind); } else { res = wap_event_create(S_Connect_Res); /* FIXME: Not yet used by WSP layer */ res->u.S_Connect_Res.server_headers = NULL; res->u.S_Connect_Res.negotiated_capabilities = negotiate_capabilities(ind->u.S_Connect_Ind.requested_capabilities); res->u.S_Connect_Res.session_id = ind->u.S_Connect_Ind.session_id; wsp_session_dispatch_event(res); } wap_event_destroy(ind); break; case S_Disconnect_Ind: sid = ind->u.S_Disconnect_Ind.session_handle; if (have_ppg && wap_push_ppg_have_push_session_for_sid(sid)) indicate_push_disconnect(ind); wap_event_destroy(ind); break; case S_Suspend_Ind: sid = ind->u.S_Suspend_Ind.session_id; if (have_ppg && wap_push_ppg_have_push_session_for_sid(sid)) indicate_push_suspend(ind); wap_event_destroy(ind); break; case S_Resume_Ind: sid = ind->u.S_Resume_Ind.session_id; if (have_ppg && wap_push_ppg_have_push_session_for_sid(sid)) { indicate_push_resume(ind); } else { res = wap_event_create(S_Resume_Res); res->u.S_Resume_Res.server_headers = NULL; res->u.S_Resume_Res.session_id = ind->u.S_Resume_Ind.session_id; wsp_session_dispatch_event(res); } wap_event_destroy(ind); break; case S_MethodResult_Cnf: wap_event_destroy(ind); break; case S_ConfirmedPush_Cnf: confirm_push(ind); wap_event_destroy(ind); break; case S_MethodAbort_Ind: /* XXX Interrupt the fetch thread somehow */ wap_event_destroy(ind); break; case S_PushAbort_Ind: indicate_push_abort(ind); wap_event_destroy(ind); break; case Pom_Connect_Res: response_push_connection(ind); wap_event_destroy(ind); break; default: panic(0, "WAP-APPL: Can't handle %s event", wap_event_name(ind->type)); break; } /* switch */ } /* while */ } /* * Tries to convert or compile a specific content-type to * it's complementing one. It does not convert if the client has explicitely * told us via Accept: header that a specific type is supported. * Returns 1 if an convertion has been successfull, * -1 if an convertion failed and 0 if no convertion routine * was maching this content-type */ static int convert_content(struct content *content, List *request_headers, int allow_empty) { Octstr *new_body; int failed = 0; int i; for (i = 0; i < NUM_CONVERTERS; i++) { if (octstr_str_compare(content->type, converters[i].type) == 0 && !http_type_accepted(request_headers, octstr_get_cstr(content->type))) { debug("wap.convert",0,"WSP: Converting from <%s> to <%s>", octstr_get_cstr(content->type), converters[i].result_type); /* * Note: if request is HEAD, body is empty and we still need to adapt * content-type but we don't need to convert a 0 bytes body */ if (allow_empty && octstr_len(content->body) == 0) return 1; new_body = converters[i].convert(content); if (new_body != NULL) { long s = octstr_len(content->body); octstr_destroy(content->body); octstr_destroy(content->type); content->body = new_body; content->type = octstr_create(converters[i].result_type); debug("wap.convert",0,"WSP: Content-type is " "now <%s>, size %ld bytes (before: %ld bytes), content body is:", converters[i].result_type, octstr_len(new_body), s); octstr_dump(new_body, 0); return 1; } debug("wap.convert",0,"WSP: Content convertion failed!"); failed = 1; } } return (failed ? -1 : 0); } /* * Tries to deconvert or decompile a specific content-type to * it's complementing one. * Returns 1 if an deconvertion has been successfull, * -1 if an deconvertion failed and 0 if no deconvertion routine * was maching this content-type */ static int deconvert_content(struct content *content) { Octstr *new_body; int failed = 0; int i; debug("wap.deconvert",0,"WSP deconvert: Trying to deconvert:"); octstr_dump(content->body, 0); for (i = 0; i < NUM_DECONVERTERS; i++) { if (octstr_str_compare(content->type, deconverters[i].type) == 0) { debug("wap.deconvert",0,"WSP: Deconverting from <%s> to <%s>", octstr_get_cstr(content->type), deconverters[i].result_type); new_body = deconverters[i].deconvert(content); if (new_body != NULL) { long s = octstr_len(content->body); octstr_destroy(content->body); octstr_destroy(content->type); content->body = new_body; content->type = octstr_create(deconverters[i].result_type); debug("wap.convert",0,"WSP: Content-type is " "now <%s>, size %ld bytes (before: %ld bytes), content body is:", deconverters[i].result_type, octstr_len(new_body), s); octstr_dump(new_body, 0); return 1; } debug("wap.deconvert",0,"WSP: Content convertion failed!"); failed = 1; } } return (failed ? -1 : 0); } /* Add a header identifying our gateway version */ static void add_kannel_version(List *headers) { http_header_add(headers, "X-WAP-Gateway", GW_NAME "/" GW_VERSION); } /* Add Accept-Charset: headers for stuff the WML compiler can * convert to UTF-8. */ /* XXX This is not really correct, since we will not be able * to handle those charsets for all content types, just WML/XHTML. */ static void add_charset_headers(List *headers) { if (!http_charset_accepted(headers, "utf-8")) http_header_add(headers, "Accept-Charset", "utf-8"); } /* Add Accept: headers for stuff we can convert for the phone */ static void add_accept_headers(List *headers) { int i; for (i = 0; i < NUM_CONVERTERS; i++) { if (http_type_accepted(headers, "*/*") || ( http_type_accepted(headers, converters[i].result_type) && !http_type_accepted(headers, converters[i].type))) { http_header_add(headers, "Accept", converters[i].type); } } } /* Add X-WAP-Network-Client-IP: header to proxy client IP to HTTP server */ static void add_network_info(List *headers, WAPAddrTuple *addr_tuple) { if (octstr_len(addr_tuple->remote->address) > 0) { http_header_add(headers, "X-WAP-Network-Client-IP", octstr_get_cstr(addr_tuple->remote->address)); } } /* Add X-WAP-Session-ID: header to request */ static void add_session_id(List *headers, long session_id) { if (session_id != -1) { char buf[40]; sprintf(buf, "%ld", session_id); http_header_add(headers, "X-WAP-Session-ID", buf); } } /* Add X-WAP-Client-SDU-Size: to provide information on client capabilities */ static void add_client_sdu_size(List *headers, long sdu_size) { if (sdu_size > 0) { Octstr *buf; buf = octstr_format("%ld", sdu_size); http_header_add(headers, "X-WAP-Client-SDU-Size", octstr_get_cstr(buf)); octstr_destroy(buf); } } /* Add proxy Via: header to request with our Kannel version */ static void add_via(List *headers) { Octstr *os; Octstr *version; version = http_header_value(headers, octstr_imm("Encoding-Version")); os = octstr_format("WAP/%s %S (" GW_NAME "/%s)", (version ? octstr_get_cstr(version) : "1.1"), get_official_name(), GW_VERSION); http_header_add(headers, "Via", octstr_get_cstr(os)); octstr_destroy(os); octstr_destroy(version); } /* * Add an X-WAP.TOD header to the response headers. It is defined in * the "WAP Caching Model" specification. * We generate it in textual form and let WSP header packing convert it * to binary form. */ static void add_x_wap_tod(List *headers) { Octstr *gateway_time; gateway_time = date_format_http(time(NULL)); if (gateway_time == NULL) { warning(0, "Could not add X-WAP.TOD response header."); return; } http_header_add(headers, "X-WAP.TOD", octstr_get_cstr(gateway_time)); octstr_destroy(gateway_time); } /* Add MSISDN provisioning information to HTTP header */ static void add_msisdn(List *headers, WAPAddrTuple *addr_tuple, Octstr *send_msisdn_header) { Octstr *msisdn = NULL; Octstr *value = NULL; if (send_msisdn_header == NULL || octstr_len(send_msisdn_header) == 0) return; /* * Security considerations. If there are headers with the header name we * use to pass on the MSISDN number, then remove them. */ if ((value = http_header_value(headers, send_msisdn_header)) != NULL) { warning(0, "MSISDN header <%s> already present on request, " "header value=<%s>", octstr_get_cstr(send_msisdn_header), octstr_get_cstr(value)); http_header_remove_all(headers, octstr_get_cstr(send_msisdn_header)); } /* * XXX Add generic msisdn provisioning cleanly in here! * See revision 1.89 for Bruno's try. */ /* We do not accept NULL values to be added to the HTTP header */ if ((msisdn = radius_acct_get_msisdn(addr_tuple->remote->address)) != NULL) { http_header_add(headers, octstr_get_cstr(send_msisdn_header), octstr_get_cstr(msisdn)); } octstr_destroy(value); octstr_destroy(msisdn); } /* * Map WSP UAProf headers 'Profile', 'Profile-Diff' to W-HTTP headers * 'X-WAP-Profile', 'X-WAP-Profile-Diff' according to WAP-248-UAProf-20011020-a, * section 9.2.3.3. */ /* static void map_uaprof_headers(List *headers) { Octstr *os; Octstr *version; version = http_header_value(headers, octstr_imm("Encoding-Version")); os = octstr_format("WAP/%s %S (" GW_NAME "/%s)", (version ? octstr_get_cstr(version) : "1.1"), get_official_name(), GW_VERSION); http_header_add(headers, "Via", octstr_get_cstr(os)); octstr_destroy(os); octstr_destroy(version); } */ /* XXX DAVI: Disabled in cvs revision 1.81 for Opengroup tests static void add_referer_url(List *headers, Octstr *url) { if (octstr_len(url) > 0) { http_header_add(headers, "Referer", octstr_get_cstr(url)); } } */ static void set_referer_url(Octstr *url, WSPMachine *sm) { gw_assert(url != NULL); gw_assert(sm != NULL); octstr_destroy(sm->referer_url); sm->referer_url = octstr_duplicate(url); } static Octstr *get_referer_url(const WSPMachine *sm) { return sm ? sm->referer_url : NULL; } /* * Return the reply from an HTTP request to the phone via a WSP session. */ static void return_session_reply(long server_transaction_id, long status, List *headers, Octstr *body, long session_id) { WAPEvent *e; e = wap_event_create(S_MethodResult_Req); e->u.S_MethodResult_Req.server_transaction_id = server_transaction_id; e->u.S_MethodResult_Req.status = status; e->u.S_MethodResult_Req.response_headers = headers; e->u.S_MethodResult_Req.response_body = body; e->u.S_MethodResult_Req.session_id = session_id; wsp_session_dispatch_event(e); } /* * Return the reply from an HTTP request to the phone via connectionless * WSP. */ static void return_unit_reply(WAPAddrTuple *tuple, long transaction_id, long status, List *headers, Octstr *body) { WAPEvent *e; e = wap_event_create(S_Unit_MethodResult_Req); e->u.S_Unit_MethodResult_Req.addr_tuple = wap_addr_tuple_duplicate(tuple); e->u.S_Unit_MethodResult_Req.transaction_id = transaction_id; e->u.S_Unit_MethodResult_Req.status = status; e->u.S_Unit_MethodResult_Req.response_headers = headers; e->u.S_Unit_MethodResult_Req.response_body = body; wsp_unit_dispatch_event(e); } static void normalize_charset(struct content * content, List* device_headers) { Octstr* charset; if ((charset = find_charset_encoding(content->body)) == NULL) { if (octstr_len(content->charset) > 0) { charset = octstr_duplicate(content->charset); } else { charset = octstr_imm("UTF-8"); } } debug("wap-appl",0,"Normalizing charset from %s", octstr_get_cstr(charset)); if (octstr_case_compare(charset, octstr_imm("UTF-8")) != 0 && !http_charset_accepted(device_headers, octstr_get_cstr(charset))) { if (!http_charset_accepted(device_headers, "UTF-8")) { warning(0, "WSP: Device doesn't support charset <%s> neither UTF-8", octstr_get_cstr(charset)); } else { debug("wsp",0,"Converting wml/xhtml from charset <%s> to UTF-8", octstr_get_cstr(charset)); if (charset_convert(content->body, octstr_get_cstr(charset), "UTF-8") >= 0) { octstr_destroy(content->charset); content->charset = octstr_create("UTF-8"); } } } octstr_destroy(charset); } /* * Return an HTTP reply back to the phone. */ static void return_reply(int status, Octstr *content_body, List *headers, long sdu_size, WAPEvent *orig_event, long session_id, Octstr *method, Octstr *url, int x_wap_tod, List *request_headers, Octstr *msisdn) { struct content content; int converted; WSPMachine *sm; List *device_headers, *t_headers; WAPAddrTuple *addr_tuple; Octstr *ua, *server; content.url = url; content.body = content_body; content.version = content.type = content.charset = NULL; server = ua = NULL; /* Get session machine for this session. If this was a connection-less * request be obviously will not find any session machine entry. */ sm = find_session_machine_by_id(session_id); device_headers = gwlist_create(); /* ensure we pass only the original headers to the convertion routine */ t_headers = (orig_event->type == S_MethodInvoke_Ind) ? orig_event->u.S_MethodInvoke_Ind.session_headers : NULL; if (t_headers != NULL) http_header_combine(device_headers, t_headers); t_headers = (orig_event->type == S_MethodInvoke_Ind) ? orig_event->u.S_MethodInvoke_Ind.request_headers : orig_event->u.S_Unit_MethodInvoke_Ind.request_headers; if (t_headers != NULL) http_header_combine(device_headers, t_headers); /* * We are acting as a proxy. Hence ensure we log a correct HTTP response * code to our access-log file to allow identification of failed proxying * requests in the main accesss-log. */ /* get client IP and User-Agent identifier */ addr_tuple = (orig_event->type == S_MethodInvoke_Ind) ? orig_event->u.S_MethodInvoke_Ind.addr_tuple : orig_event->u.S_Unit_MethodInvoke_Ind.addr_tuple; ua = http_header_value(request_headers, octstr_imm("User-Agent")); if (headers != NULL) { /* get response content type and Server identifier */ http_header_get_content_type(headers, &content.type, &content.charset); server = http_header_value(headers, octstr_imm("Server")); } /* log the access */ /* XXX make this configurable in the future */ alog("%s %s %s <%s> (%s, charset='%s') %ld %d <%s> <%s>", octstr_get_cstr(addr_tuple->remote->address), msisdn ? octstr_get_cstr(msisdn) : "-", octstr_get_cstr(method), octstr_get_cstr(url), content.type ? octstr_get_cstr(content.type) : "", content.charset ? octstr_get_cstr(content.charset) : "", octstr_len(content.body), status < 0 ? HTTP_BAD_GATEWAY : status, ua ? octstr_get_cstr(ua) : "", server ? octstr_get_cstr(server) : ""); octstr_destroy(ua); octstr_destroy(server); if (status < 0) { error(0, "WSP: HTTP lookup failed, oops."); /* smart WSP error messaging?! */ if (wsp_smart_errors) { Octstr *referer_url; status = HTTP_OK; content.type = octstr_create("text/vnd.wap.wml"); content.charset = octstr_create(""); /* * check if a referer for this URL exists and * get back to the previous page in this case */ if ((referer_url = get_referer_url(find_session_machine_by_id(session_id)))) { content.body = error_requesting_back(url, referer_url); debug("wap.wsp",0,"WSP: returning smart error WML deck for referer URL"); } /* * if there is no referer to retun to, check if we have a * device-home defined and return to that, otherwise simply * drop an error wml deck. */ else if (device_home != NULL) { content.body = error_requesting_back(url, device_home); debug("wap.wsp",0,"WSP: returning smart error WML deck for device-home URL"); } else { content.body = error_requesting(url); debug("wap.wsp",0,"WSP: returning smart error WML deck"); } /* * if we did not connect at all there is no content in * the headers list, so create for the upcoming transformation */ if (headers == NULL) headers = http_create_empty_headers(); converted = convert_content(&content, device_headers, 0); if (converted == 1) http_header_mark_transformation(headers, content.body, content.type); } else { /* no WSP smart error messaging */ status = HTTP_BAD_GATEWAY; content.type = octstr_create("text/plain"); content.charset = octstr_create(""); content.body = octstr_create(""); } } else { /* received response by HTTP server */ #ifdef ENABLE_COOKIES if (session_id != -1) if (get_cookies(headers, find_session_machine_by_id(session_id)) == -1) error(0, "WSP: Failed to extract cookies"); #endif /* * XXX why do we transcode charsets on the content body here?! * Why is this not in the scope of the HTTP server, rather * then doing this inside Kannel?! st. */ /* * Adapts content body's charset to device. * If device doesn't support body's charset but supports UTF-8, this * block tries to convert body to UTF-8. * (This is required for Sharp GX20 for example) */ if (octstr_search(content.type, octstr_imm("text/vnd.wap.wml"), 0) >= 0 || octstr_search(content.type, octstr_imm("application/xhtml+xml"), 0) >= 0 || octstr_search(content.type, octstr_imm("application/vnd.wap.xhtml+xml"), 0) >= 0) { normalize_charset(&content, device_headers); } /* set WBXML Encoding-Version for wml->wmlc conversion */ if (sm != NULL) { content.version = http_header_value(sm->http_headers, octstr_imm("Encoding-Version")); } else { content.version = NULL; } /* convert content-type by our own converter table */ converted = convert_content(&content, device_headers, octstr_compare(method, octstr_imm("HEAD")) == 0); if (converted < 0) { warning(0, "WSP: All converters for `%s' at `%s' failed.", octstr_get_cstr(content.type), octstr_get_cstr(url)); /* * Don't change status; just send the client what we did get. * Or if smart error messages are configured, send a wmlc deck * with accurate information. */ if (wsp_smart_errors) { octstr_destroy(content.body); octstr_destroy(content.charset); content.body = error_converting(url, content.type); content.charset = octstr_create("UTF-8"); debug("wap.wsp",0,"WSP: returning smart error WML deck for failed converters"); converted = convert_content(&content, device_headers, 0); if (converted == 1) http_header_mark_transformation(headers, content.body, content.type); } } else if (converted == 1) { http_header_mark_transformation(headers, content.body, content.type); /* * set referer URL to WSPMachine, but only if this was a converted * content-type, like .wml */ if (session_id != -1) { debug("wap.wsp.http",0,"WSP: Setting Referer URL to <%s>", octstr_get_cstr(url)); if ((sm = find_session_machine_by_id(session_id)) != NULL) { set_referer_url(url, sm); } else { error(0,"WSP: Failed to find session machine for ID %ld", session_id); } } } /* if converted == 0 then we pass the content wihtout modification */ } if (headers == NULL) headers = http_create_empty_headers(); http_remove_hop_headers(headers); http_header_remove_all(headers, "X-WAP.TOD"); if (x_wap_tod) add_x_wap_tod(headers); if (content.body == NULL) content.body = octstr_create(""); /* * Deal with otherwise wap-aware servers that return text/html error * messages if they report an error. * (Normally we leave the content type alone even if the client doesn't * claim to accept it, because the server might know better than the * gateway.) */ if (http_status_class(status) != HTTP_STATUS_SUCCESSFUL && !http_type_accepted(request_headers, octstr_get_cstr(content.type))) { warning(0, "WSP: Content type <%s> not supported by client," " deleting body.", octstr_get_cstr(content.type)); octstr_destroy(content.body); content.body = octstr_create(""); octstr_destroy(content.type); content.type = octstr_create("text/plain"); http_header_mark_transformation(headers, content.body, content.type); } /* remove body if request method was HEAD, we act strictly here */ else if (octstr_compare(method, octstr_imm("HEAD")) == 0) { octstr_destroy(content.body); content.body = octstr_create(""); /* change to text/plain if received content-type is not accepted */ if (!http_type_accepted(request_headers, "*/*") && !http_type_accepted(request_headers, octstr_get_cstr(content.type))) { octstr_destroy(content.type); content.type = octstr_create("text/plain"); } debug("wsp",0,"WSP: HEAD request, removing body, content-type is now <%s>", octstr_get_cstr(content.type)); http_header_mark_transformation(headers, content.body, content.type); } #ifdef ENABLE_NOT_ACCEPTED /* Returns HTTP response 406 if content-type is not supported by device */ else if (request_headers && content.type && !http_type_accepted(request_headers, octstr_get_cstr(content.type)) && !http_type_accepted(request_headers, "*/*")) { warning(0, "WSP: content-type <%s> not supported", octstr_get_cstr(content.type)); status = HTTP_NOT_ACCEPTABLE; octstr_destroy(content.type); content.type = octstr_create("text/plain"); octstr_destroy(content.charset); octstr_destroy(content.body); content.charset = octstr_create(""); content.body = octstr_create(""); http_header_mark_transformation(headers, content.body, content.type); } #endif /* * If the response is too large to be sent to the client, * suppress it and inform the client. */ if (octstr_len(content.body) > sdu_size && sdu_size > 0) { /* * Only change the status if it indicated success. * If it indicated an error, then that information is * more useful to the client than our "Bad Gateway" would be. * The too-large body is probably an error page in html. */ /* XXX add WSP smart messaging here too */ if (http_status_class(status) == HTTP_STATUS_SUCCESSFUL) status = HTTP_BAD_GATEWAY; warning(0, "WSP: Entity at %s too large (size %ld B, limit %lu B)", octstr_get_cstr(url), octstr_len(content.body), sdu_size); octstr_destroy(content.body); content.body = octstr_create(""); http_header_mark_transformation(headers, content.body, content.type); } if (orig_event->type == S_MethodInvoke_Ind) { return_session_reply(orig_event->u.S_MethodInvoke_Ind.server_transaction_id, status, headers, content.body, session_id); } else { return_unit_reply(orig_event->u.S_Unit_MethodInvoke_Ind.addr_tuple, orig_event->u.S_Unit_MethodInvoke_Ind.transaction_id, status, headers, content.body); } octstr_destroy(content.version); /* body was re-used above */ octstr_destroy(content.type); /* body was re-used above */ octstr_destroy(content.charset); octstr_destroy(url); /* same as content.url */ http_destroy_headers(device_headers); counter_decrease(fetches); } /* * This thread receives replies from HTTP layer and sends them back to * the phone. */ static void return_replies_thread(void *arg) { Octstr *body; struct request_data *p; int status; Octstr *final_url; List *headers; while (run_status == running) { p = http_receive_result(caller, &status, &final_url, &headers, &body); if (p == NULL) break; return_reply(status, body, headers, p->client_SDU_size, p->event, p->session_id, p->method, p->url, p->x_wap_tod, p->request_headers, p->msisdn); wap_event_destroy(p->event); http_destroy_headers(p->request_headers); octstr_destroy(p->msisdn); gw_free(p); octstr_destroy(final_url); } } /* * This WML deck is returned when the user asks for the magic * URL "kannel:alive". */ #define HEALTH_DECK \ "" \ "" \ "

Ok

" static void start_fetch(WAPEvent *event) { int ret; long client_SDU_size; /* 0 means no limit */ Octstr *url; List *session_headers; List *request_headers; List *actual_headers; List *resp_headers; WAPAddrTuple *addr_tuple; long session_id; Octstr *content_body; Octstr *method; /* type of request, normally a get or a post */ Octstr *request_body; int x_wap_tod; /* X-WAP.TOD header was present in request */ Octstr *magic_url; struct request_data *p; Octstr *send_msisdn_query, *send_msisdn_header, *send_msisdn_format; int accept_cookies; Octstr *msisdn; counter_increase(fetches); if (event->type == S_MethodInvoke_Ind) { struct S_MethodInvoke_Ind *p; /* WSP, connection orientated */ p = &event->u.S_MethodInvoke_Ind; session_headers = p->session_headers; request_headers = p->request_headers; url = octstr_duplicate(p->request_uri); addr_tuple = p->addr_tuple; session_id = p->session_id; client_SDU_size = p->client_SDU_size; request_body = octstr_duplicate(p->request_body); method = p->method; } else { struct S_Unit_MethodInvoke_Ind *p; /* WDP, non orientated */ p = &event->u.S_Unit_MethodInvoke_Ind; session_headers = NULL; request_headers = p->request_headers; url = octstr_duplicate(p->request_uri); addr_tuple = p->addr_tuple; session_id = -1; client_SDU_size = 0; /* No limit */ request_body = octstr_duplicate(p->request_body); method = p->method; } msisdn = radius_acct_get_msisdn(addr_tuple->remote->address); info(0, "Fetching URL <%s> for MSISDN <%s>, IP <%s:%ld>", octstr_get_cstr(url), msisdn ? octstr_get_cstr(msisdn) : "", addr_tuple->remote->address ? octstr_get_cstr(addr_tuple->remote->address) : "", addr_tuple->remote->port); /* * XXX this URL mapping needs to be rebuild! st. */ /* try to rewrite URL */ wap_map_url(&url, &send_msisdn_query, &send_msisdn_header, &send_msisdn_format, &accept_cookies); /* if no mapping found, then use our RADIUS acct proxy header */ if (send_msisdn_header == NULL) send_msisdn_header = octstr_create("X-WAP-Network-Client-MSISDN"); actual_headers = gwlist_create(); if (session_headers != NULL) http_header_combine(actual_headers, session_headers); if (request_headers != NULL) http_header_combine(actual_headers, request_headers); x_wap_tod = http_header_remove_all(actual_headers, "X-WAP.TOD"); add_accept_headers(actual_headers); add_charset_headers(actual_headers); add_network_info(actual_headers, addr_tuple); add_client_sdu_size(actual_headers, client_SDU_size); add_via(actual_headers); #ifdef ENABLE_COOKIES /* DAVI: to finish - accept_cookies -1, * use global accept-cookies, 0 = no, 1 = yes ? */ if (accept_cookies != 0 && (session_id != -1) && /* DAVI (set_cookies(url, actual_headers, find_session_machine_by_id(session_id)) == -1)) */ (set_cookies(actual_headers, find_session_machine_by_id(session_id)) == -1)) error(0, "WSP: Failed to add cookies"); #endif /* set referer URL to HTTP header from WSPMachine */ /* * XXX This makes Open Group's test suite wml/events/tasks/go/5 failing, * which requires that device is *not* sending referer, but Kannel drops * it in. We have to remove this for now. */ /* if (session_id != -1) { if ((referer_url = get_referer_url(find_session_machine_by_id(session_id))) != NULL) { add_referer_url(actual_headers, referer_url); } } */ add_kannel_version(actual_headers); add_session_id(actual_headers, session_id); add_msisdn(actual_headers, addr_tuple, send_msisdn_header); octstr_destroy(send_msisdn_query); octstr_destroy(send_msisdn_header); octstr_destroy(send_msisdn_format); http_remove_hop_headers(actual_headers); http_header_pack(actual_headers); magic_url = octstr_imm("kannel:alive"); /* check if this request is a call for our magic URL */ if (octstr_str_compare(method, "GET") == 0 && octstr_compare(url, magic_url) == 0) { ret = HTTP_OK; resp_headers = gwlist_create(); http_header_add(resp_headers, "Content-Type", "text/vnd.wap.wml"); content_body = octstr_create(HEALTH_DECK); octstr_destroy(request_body); return_reply(ret, content_body, resp_headers, client_SDU_size, event, session_id, method, url, x_wap_tod, actual_headers, msisdn); wap_event_destroy(event); http_destroy_headers(actual_headers); octstr_destroy(msisdn); } /* otherwise it should be a GET, POST or HEAD request type */ else if (octstr_str_compare(method, "GET") == 0 || octstr_str_compare(method, "POST") == 0 || octstr_str_compare(method, "HEAD") == 0) { /* we don't allow a body within a GET or HEAD request */ if (request_body != NULL && (octstr_str_compare(method, "GET") == 0 || octstr_str_compare(method, "HEAD") == 0)) { octstr_destroy(request_body); request_body = NULL; } /* * Call deconvert_content() here for transformations of binary * encoded POST requests from the client into plain text decoded * POST requests for the HTTP server. * Mainly this is used for multipart/form-data transmissions, * including MMS on-the-fly message decoding. * When we are doing mms, the phone POSTs contents and acknowled- * gements. In this case, we dont do not deconvert anything. */ if (octstr_str_compare(method, "POST") == 0 && request_body && octstr_len(request_body)) { struct content content; int converted; http_header_get_content_type(actual_headers, &content.type, &content.charset); content.body = request_body; converted = deconvert_content(&content); if (converted == 1) http_header_mark_transformation(actual_headers, content.body, content.type); request_body = content.body; octstr_destroy(content.type); octstr_destroy(content.charset); } /* struct that is used for the HTTP response identifier */ p = gw_malloc(sizeof(*p)); p->client_SDU_size = client_SDU_size; p->event = event; p->session_id = session_id; p->method = method; p->url = url; p->x_wap_tod = x_wap_tod; p->request_headers = actual_headers; p->msisdn = msisdn; /* issue the request to the HTTP server */ http_start_request(caller, http_name2method(method), url, actual_headers, request_body, 0, p, NULL); octstr_destroy(request_body); } /* we don't support the WSP/HTTP method the client asked us */ else { error(0, "WSP: Method %s not supported.", octstr_get_cstr(method)); content_body = octstr_create(""); resp_headers = http_create_empty_headers(); ret = HTTP_NOT_IMPLEMENTED; octstr_destroy(request_body); return_reply(ret, content_body, resp_headers, client_SDU_size, event, session_id, method, url, x_wap_tod, actual_headers, msisdn); wap_event_destroy(event); http_destroy_headers(actual_headers); octstr_destroy(msisdn); } } /* Shut up WMLScript compiler status/trace messages. */ static void dev_null(const char *data, size_t len, void *context) { /* nothing */ } static Octstr *convert_wml_to_wmlc(struct content *content) { Octstr *wmlc; int ret; /* content->charset is passed from the HTTP header parsing */ ret = wml_compile(content->body, content->charset, &wmlc, content->version); /* wmlc is created implicitely in wml_compile() */ if (ret == 0) return wmlc; octstr_destroy(wmlc); warning(0, "WSP: WML compilation failed."); return NULL; } static Octstr *convert_wmlscript_to_wmlscriptc(struct content *content) { WsCompilerParams params; WsCompilerPtr compiler; WsResult result; unsigned char *result_data; size_t result_size; Octstr *wmlscriptc; memset(¶ms, 0, sizeof(params)); params.use_latin1_strings = 0; params.print_symbolic_assembler = 0; params.print_assembler = 0; params.meta_name_cb = NULL; params.meta_name_cb_context = NULL; params.meta_http_equiv_cb = NULL; params.meta_http_equiv_cb_context = NULL; params.stdout_cb = dev_null; params.stderr_cb = dev_null; compiler = ws_create(¶ms); if (compiler == NULL) { panic(0, "WSP: could not create WMLScript compiler"); } result = ws_compile_data(compiler, octstr_get_cstr(content->url), (unsigned char *)octstr_get_cstr(content->body), octstr_len(content->body), &result_data, &result_size); if (result != WS_OK) { warning(0, "WSP: WMLScript compilation failed: %s", ws_result_to_string(result)); wmlscriptc = NULL; } else { wmlscriptc = octstr_create_from_data((char *)result_data, result_size); } return wmlscriptc; } /* * XXX There's a big bug in http_get_content_type that * assumes that header parameter is charset without looking at * parameter key. Good!. I'll use its value to catch boundary * value for now * ie. "Content-Type: (foo/bar);something=(value)" it gets value * without caring about what is "something" */ /* DAVI: To-Do static Octstr *convert_multipart_mixed(struct content *content) { Octstr *result = NULL; debug("wap.wsp.multipart.mixed", 0, "WSP.Multipart.Mixed, boundary=[%s]", octstr_get_cstr(content->charset)); result = octstr_duplicate(content->body); return result; } */ static Octstr *deconvert_multipart_formdata(struct content *content) { Octstr *mime; if ((mime_decompile(content->body, &mime)) == 0) return mime; return NULL; } /* DAVI: To-Do static Octstr *deconvert_mms_message(struct content *content) { Octstr *mime; if ((mms_decompile(content->body, &mime)) == 0) return mime; return NULL; } */ /* The interface for capability negotiation is a bit different from * the negotiation at WSP level, to make it easier to program. * The application layer gets a list of requested capabilities, * basically a straight decoding of the WSP level capabilities. * It replies with a list of all capabilities it wants to set or * refuse. (Refuse by setting cap->data to NULL). Any capabilities * it leaves out are considered "unknown; don't care". The WSP layer * will either process those itself, or refuse them. * * At the WSP level, not sending a reply to a capability means accepting * what the client proposed. If the application layer wants this to * happen, it should set cap->data to NULL and cap->accept to 1. * (The WSP layer does not try to guess what kind of reply would be * identical to what the client proposed, because the format of the * reply is often different from the format of the request, and this * is likely to be true for unknown capabilities too.) */ static List *negotiate_capabilities(List *req_caps) { /* Currently we don't know or care about any capabilities, * though it is likely that "Extended Methods" will be * the first. */ return gwlist_create(); } /* * Ota submodule implements indications, responses and confirmations part of * ota. */ /* * If Accept-Application is empty, add header indicating default application * wml ua (see ota 6.4.1). Otherwise decode application id (see http://www. * wapforum.org/wina/push-app-id.htm). FIXME: capability negotiation (no- * thing means default, if so negotiated). * Function does not allocate memory neither for headers nor application_ * headers. * Returns encoded application headers and input header list without them. */ static void check_application_headers(List **headers, List **application_headers) { List *inh = NULL; int i; long len; Octstr *appid_name, *coded_octstr; char *appid_value, *coded_value; split_header_list(headers, &inh, "Accept-Application"); if (*headers == NULL || gwlist_len(inh) == 0) { http_header_add(*application_headers, "Accept-Application", "wml ua"); debug("wap.appl.push", 0, "APPL: No push application, assuming wml" " ua"); if (*headers != NULL) http_destroy_headers(inh); return; } i = 0; len = gwlist_len(inh); coded_value = NULL; appid_value = NULL; while (i < len) { http_header_get(inh, i, &appid_name, &coded_octstr); /* Greatest value reserved by WINA is 0xFF00 0000*/ coded_value = octstr_get_cstr(coded_octstr); if (coded_value != NULL) appid_value = (char *)wsp_application_id_to_cstr((long) coded_value); if (appid_value != NULL && coded_value != NULL) http_header_add(*application_headers, "Accept-Application", appid_value); else { error(0, "OTA: Unknown application is, skipping: "); octstr_dump(coded_octstr, 0, GW_ERROR); } i++; } debug("wap.appl.push", 0, "application headers were"); http_header_dump(*application_headers); http_destroy_headers(inh); octstr_destroy(appid_name); octstr_destroy(coded_octstr); } /* * Bearer-Indication field is defined in ota 6.4.1. * Skip the header, if it is malformed or if there is more than one bearer * indication. * Function does not allocate memory neither for headers nor bearer_headers. * Return encoded bearer indication header and input header list without it. */ static void decode_bearer_indication(List **headers, List **bearer_headers) { List *inb; Octstr *name, *coded_octstr; char *value; unsigned char coded_value; if (*headers == NULL) { debug("wap.appl", 0, "APPL: no client headers, continuing"); return; } split_header_list(headers, &inb, "Bearer-Indication"); if (gwlist_len(inb) == 0) { debug("wap.appl.push", 0, "APPL: No bearer indication headers," " continuing"); http_destroy_headers(inb); return; } if (gwlist_len(inb) > 1) { error(0, "APPL: To many bearer indication header(s), skipping" " them"); http_destroy_headers(inb); return; } http_header_get(inb, 0, &name, &coded_octstr); http_destroy_headers(inb); /* Greatest assigned number for a bearer type is 0xff, see wdp, appendix C */ coded_value = octstr_get_char(coded_octstr, 0); value = (char *)wsp_bearer_indication_to_cstr(coded_value); if (value != NULL && coded_value != 0) { http_header_add(*bearer_headers, "Bearer-Indication", value); debug("wap.appl.push", 0, "bearer indication header was"); http_header_dump(*bearer_headers); return; } else { error(0, "APPL: Illegal bearer indication value, skipping:"); octstr_dump(coded_octstr, 0, GW_ERROR); http_destroy_headers(*bearer_headers); return; } } /* * Separate headers into two lists, one having all headers named "name" and * the other rest of them. */ static void split_header_list(List **headers, List **new_headers, char *name) { if (*headers == NULL) return; *new_headers = http_header_find_all(*headers, name); http_header_remove_all(*headers, name); } /* * Find headers Accept-Application and Bearer-Indication amongst push headers, * decode them and add them to their proper field. */ static void indicate_push_connection(WAPEvent *e) { WAPEvent *ppg_event; List *push_headers, *application_headers, *bearer_headers; push_headers = http_header_duplicate(e->u.S_Connect_Ind.client_headers); application_headers = http_create_empty_headers(); bearer_headers = http_create_empty_headers(); ppg_event = wap_event_create(Pom_Connect_Ind); ppg_event->u.Pom_Connect_Ind.addr_tuple = wap_addr_tuple_duplicate(e->u.S_Connect_Ind.addr_tuple); ppg_event->u.Pom_Connect_Ind.requested_capabilities = wsp_cap_duplicate_list(e->u.S_Connect_Ind.requested_capabilities); check_application_headers(&push_headers, &application_headers); ppg_event->u.Pom_Connect_Ind.accept_application = application_headers; decode_bearer_indication(&push_headers, &bearer_headers); if (gwlist_len(bearer_headers) == 0) { http_destroy_headers(bearer_headers); ppg_event->u.Pom_Connect_Ind.bearer_indication = NULL; } else ppg_event->u.Pom_Connect_Ind.bearer_indication = bearer_headers; ppg_event->u.Pom_Connect_Ind.push_headers = push_headers; ppg_event->u.Pom_Connect_Ind.session_id = e->u.S_Connect_Ind.session_id; debug("wap.appl", 0, "APPL: making OTA connection indication to PPG"); wap_push_ppg_dispatch_event(ppg_event); } static void indicate_push_disconnect(WAPEvent *e) { WAPEvent *ppg_event; ppg_event = wap_event_create(Pom_Disconnect_Ind); ppg_event->u.Pom_Disconnect_Ind.reason_code = e->u.S_Disconnect_Ind.reason_code; ppg_event->u.Pom_Disconnect_Ind.error_headers = octstr_duplicate(e->u.S_Disconnect_Ind.error_headers); ppg_event->u.Pom_Disconnect_Ind.error_body = octstr_duplicate(e->u.S_Disconnect_Ind.error_body); ppg_event->u.Pom_Disconnect_Ind.session_handle = e->u.S_Disconnect_Ind.session_handle; wap_push_ppg_dispatch_event(ppg_event); } /* * We do not implement acknowledgement headers */ static void confirm_push(WAPEvent *e) { WAPEvent *ppg_event; ppg_event = wap_event_create(Po_ConfirmedPush_Cnf); ppg_event->u.Po_ConfirmedPush_Cnf.server_push_id = e->u.S_ConfirmedPush_Cnf.server_push_id; ppg_event->u.Po_ConfirmedPush_Cnf.session_handle = e->u.S_ConfirmedPush_Cnf.session_id; debug("wap.appl", 0, "OTA: confirming push for ppg"); wap_push_ppg_dispatch_event(ppg_event); } static void indicate_push_abort(WAPEvent *e) { WAPEvent *ppg_event; ppg_event = wap_event_create(Po_PushAbort_Ind); ppg_event->u.Po_PushAbort_Ind.push_id = e->u.S_PushAbort_Ind.push_id; ppg_event->u.Po_PushAbort_Ind.reason = e->u.S_PushAbort_Ind.reason; ppg_event->u.Po_PushAbort_Ind.session_handle = e->u.S_PushAbort_Ind.session_id; debug("wap.push.ota", 0, "OTA: making push abort indication for ppg"); wap_push_ppg_dispatch_event(ppg_event); } static void indicate_push_suspend(WAPEvent *e) { WAPEvent *ppg_event; ppg_event = wap_event_create(Pom_Suspend_Ind); ppg_event->u.Pom_Suspend_Ind.reason = e->u.S_Suspend_Ind.reason; ppg_event->u.Pom_Suspend_Ind.session_id = e->u.S_Suspend_Ind.session_id; wap_push_ppg_dispatch_event(ppg_event); } /* * Find Bearer-Indication amongst client headers, decode it and assign it to * a separate field in the event structure. */ static void indicate_push_resume(WAPEvent *e) { WAPEvent *ppg_event; List *push_headers, *bearer_headers; push_headers = http_header_duplicate(e->u.S_Resume_Ind.client_headers); bearer_headers = http_create_empty_headers(); ppg_event = wap_event_create(Pom_Resume_Ind); ppg_event->u.Pom_Resume_Ind.addr_tuple = wap_addr_tuple_duplicate( e->u.S_Resume_Ind.addr_tuple); decode_bearer_indication(&push_headers, &bearer_headers); if (gwlist_len(bearer_headers) == 0) { http_destroy_headers(bearer_headers); ppg_event->u.Pom_Resume_Ind.bearer_indication = NULL; } else ppg_event->u.Pom_Resume_Ind.bearer_indication = bearer_headers; ppg_event->u.Pom_Resume_Ind.client_headers = push_headers; ppg_event->u.Pom_Resume_Ind.session_id = e->u.S_Resume_Ind.session_id; wap_push_ppg_dispatch_event(ppg_event); } /* * Server headers are mentioned in table in ota 6.4.1, but none of the primit- * ives use them. They are optional in S_Connect_Res, so we do not use them. */ static void response_push_connection(WAPEvent *e) { WAPEvent *wsp_event; gw_assert(e->type = Pom_Connect_Res); wsp_event = wap_event_create(S_Connect_Res); wsp_event->u.S_Connect_Res.session_id = e->u.Pom_Connect_Res.session_id; wsp_event->u.S_Connect_Res.negotiated_capabilities = wsp_cap_duplicate_list(e->u.Pom_Connect_Res.negotiated_capabilities); debug("wap.appl", 0, "APPL: making push connect response"); wsp_session_dispatch_event(wsp_event); } gateway-1.4.5/gw/bb_store.h0000644000175000017500000001130213227613126014251 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * bb_store.h : declarations for the bearerbox box SMS storage/retrieval module * * Author: Alexander Malysh, 2005 */ #ifndef BB_STORE_H_ #define BB_STORE_H_ #define BB_STORE_DEFAULT_DUMP_FREQ 10 /* return number of SMS messages in current store (file) */ extern long (*store_messages)(void); /* assign ID and save given message to store. Return -1 if save failed */ extern int (*store_save)(Msg *msg); /* * Store ack/nack to the store file for a given message with a given status. * @return: -1 if save failed ; 0 otherwise. */ extern int (*store_save_ack)(Msg *msg, ack_status_t status); /* load store from file; delete any messages that have been relayed, * and create a new store file from remaining. Calling this function * might take a while, depending on store size * Return -1 if something fails (bb can then PANIC normally) */ extern int (*store_load)(void(*receive_msg)(Msg*)); /* dump currently non-acknowledged messages into file. This is done * automatically now and then, but can be forced. Return -1 if file * problems */ extern int (*store_dump)(void); /* * Function pointers used inside the storage subsystem to pack and * unpack a Msg with variable serialization functions. */ extern Octstr* (*store_msg_pack)(Msg *msg); extern Msg* (*store_msg_unpack)(Octstr *os); /* initialize system. Return -1 if fname is bad (too long). */ int store_init(Cfg *cfg, const Octstr *type, const Octstr *fname, long dump_freq, void *pack_func, void *unpack_func); /* init shutdown (system dies when all acks have been processed) */ extern void (*store_shutdown)(void); /* return all containing messages in the current store */ Octstr* store_status(int status_type); extern void (*store_for_each_message)(void(*callback_fn)(Msg*, void*), void *data); /** * Init functions for different store types. */ int store_spool_init(const Octstr *fname); int store_file_init(const Octstr *fname, long dump_freq); #ifdef HAVE_REDIS int store_redis_init(Cfg *cfg); #endif #endif /*BB_STORE_H_*/ gateway-1.4.5/gw/wap-maps.c0000644000175000017500000002172713227613126014206 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/wap-maps.c - URL mapping * * Bruno Rodrigues */ #include "gwlib/gwlib.h" #include "wap-maps.h" struct url_map_struct { Octstr *name; Octstr *url; Octstr *map_url; Octstr *send_msisdn_query; Octstr *send_msisdn_header; Octstr *send_msisdn_format; int accept_cookies; }; struct user_map_struct { Octstr *name; Octstr *user; Octstr *pass; Octstr *msisdn; }; /* * XXX All mapping functions should be implemented with Dicts instead of * Lists! Linear scans in lists are pretty slow against hash table lookups, * espacially when you have *lot* of entries, which is the case in URL re- * writting in general. * TODO: identify a hash key that can be used and use that as lookup. */ /* mapping storrage */ static List *url_map = NULL; static Dict *user_map = NULL; /******************************************************************** * Creation and destruction of mapping entries */ void wap_map_add_url(Octstr *name, Octstr *url, Octstr *map_url, Octstr *send_msisdn_query, Octstr *send_msisdn_header, Octstr *send_msisdn_format, int accept_cookies) { struct url_map_struct *entry; if (url_map == NULL) url_map = gwlist_create(); entry = gw_malloc(sizeof(*entry)); entry->name = name; entry->url = url; entry->map_url = map_url; entry->send_msisdn_query = send_msisdn_query; entry->send_msisdn_header = send_msisdn_header; entry->send_msisdn_format = send_msisdn_format; entry->accept_cookies = accept_cookies; gwlist_append(url_map, entry); } static void wap_user_map_destroy(void *i) { struct user_map_struct *entry = i; octstr_destroy(entry->name); octstr_destroy(entry->user); octstr_destroy(entry->pass); octstr_destroy(entry->msisdn); gw_free(entry); } void wap_map_add_user(Octstr *name, Octstr *user, Octstr *pass, Octstr *msisdn) { struct user_map_struct *entry; if (user_map == NULL) user_map = dict_create(32, wap_user_map_destroy); entry = gw_malloc(sizeof(*entry)); entry->name = name; entry->user = user; entry->pass = pass; entry->msisdn = msisdn; dict_put(user_map, entry->user, entry); } void wap_map_destroy(void) { long i; struct url_map_struct *entry; if (url_map != NULL) { for (i = 0; i < gwlist_len(url_map); i++) { entry = gwlist_get(url_map, i); octstr_destroy(entry->name); octstr_destroy(entry->url); octstr_destroy(entry->map_url); octstr_destroy(entry->send_msisdn_query); octstr_destroy(entry->send_msisdn_header); octstr_destroy(entry->send_msisdn_format); gw_free(entry); } gwlist_destroy(url_map, NULL); } url_map = NULL; } void wap_map_user_destroy(void) { dict_destroy(user_map); user_map = NULL; } /******************************************************************** * Public functions */ void wap_map_url_config(char *s) { char *in, *out; s = gw_strdup(s); in = strtok(s, " \t"); if (!in) return; out = strtok(NULL, " \t"); if (!out) return; wap_map_add_url(octstr_imm("unknown"), octstr_create(in), octstr_create(out), NULL, NULL, NULL, 0); gw_free(s); } void wap_map_url_config_device_home(char *to) { wap_map_add_url(octstr_imm("Device Home"), octstr_imm("DEVICE:home*"), octstr_create(to), NULL, NULL, NULL, -1); } void wap_map_url(Octstr **osp, Octstr **send_msisdn_query, Octstr **send_msisdn_header, Octstr **send_msisdn_format, int *accept_cookies) { long i; Octstr *newurl, *tmp1, *tmp2; newurl = tmp1 = tmp2 = NULL; *send_msisdn_query = *send_msisdn_header = *send_msisdn_format = NULL; *accept_cookies = -1; debug("wsp",0,"WSP: Mapping url <%s>", octstr_get_cstr(*osp)); for (i = 0; url_map && i < gwlist_len(url_map); i++) { struct url_map_struct *entry; entry = gwlist_get(url_map, i); /* debug("wsp",0,"WSP: matching <%s> with <%s>", octstr_get_cstr(entry->url), octstr_get_cstr(entry->map_url)); */ /* DAVI: I only have '*' terminated entry->url implementation for now */ tmp1 = octstr_duplicate(entry->url); octstr_delete(tmp1, octstr_len(tmp1)-1, 1); /* remove last '*' */ tmp2 = octstr_copy(*osp, 0, octstr_len(tmp1)); debug("wsp",0,"WSP: Matching <%s> with <%s>", octstr_get_cstr(tmp1), octstr_get_cstr(tmp2)); if (octstr_case_compare(tmp2, tmp1) == 0) { /* rewrite url if configured to do so */ if (entry->map_url != NULL) { if (octstr_get_char(entry->map_url, octstr_len(entry->map_url)-1) == '*') { newurl = octstr_duplicate(entry->map_url); octstr_delete(newurl, octstr_len(newurl)-1, 1); octstr_append(newurl, octstr_copy(*osp, octstr_len(entry->url)-1, octstr_len(*osp)-octstr_len(entry->url)+1)); } else { newurl = octstr_duplicate(entry->map_url); } debug("wsp",0,"WSP: URL Rewriten from <%s> to <%s>", octstr_get_cstr(*osp), octstr_get_cstr(newurl)); octstr_destroy(*osp); *osp = newurl; } *accept_cookies = entry->accept_cookies; *send_msisdn_query = octstr_duplicate(entry->send_msisdn_query); *send_msisdn_header = octstr_duplicate(entry->send_msisdn_header); *send_msisdn_format = octstr_duplicate(entry->send_msisdn_format); octstr_destroy(tmp1); octstr_destroy(tmp2); break; } octstr_destroy(tmp1); octstr_destroy(tmp2); } } int wap_map_user(Octstr **msisdn, Octstr *user, Octstr *pass) { struct user_map_struct *entry; entry = dict_get(user_map, user); if (entry != NULL && octstr_compare(pass, entry->pass) == 0) { *msisdn = octstr_duplicate(entry->msisdn); return 1; } return 0; } gateway-1.4.5/gw/bb_smscconn.c0000644000175000017500000023214113310706661014741 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * SMSC Connection interface for Bearerbox. * * Includes callback functions called by SMSCConn implementations * * Handles all startup/shutdown adminstrative work in bearerbox, plus * routing, writing actual access logs, handling failed messages etc. * * Kalle Marjola 2000 for project Kannel * Alexander Malysh 2003, 2004, 2005 */ #include "gw-config.h" #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "msg.h" #include "sms.h" #include "bearerbox.h" #include "numhash.h" #include "smscconn.h" #include "dlr.h" #include "load.h" #include "bb_smscconn_cb.h" /* callback functions for connections */ #include "smscconn_p.h" /* to access counters */ #include "smsc/smpp_pdu.h" /* access smpp_pdu_init/smpp_pdu_shutdown */ /* passed from bearerbox core */ extern volatile sig_atomic_t bb_status; extern List *incoming_sms; extern List *outgoing_sms; extern Counter *incoming_sms_counter; extern Counter *outgoing_sms_counter; extern Counter *incoming_dlr_counter; extern Counter *outgoing_dlr_counter; extern Load *outgoing_sms_load; extern Load *incoming_sms_load; extern Load *incoming_dlr_load; extern Load *outgoing_dlr_load; extern List *flow_threads; extern List *suspended; extern List *isolated; /* outgoing sms queue control */ extern long max_outgoing_sms_qlength; /* incoming sms queue control */ extern long max_incoming_sms_qlength; /* configuration filename */ extern Octstr *cfg_filename; /* our own thingies */ static volatile sig_atomic_t smsc_running; static List *smsc_list; static RWLock smsc_list_lock; static Cfg *cfg_reloaded; static List *smsc_groups; static Octstr *unified_prefix; static RWLock white_black_list_lock; static Octstr *black_list_sender_url; static Octstr *white_list_sender_url; static Octstr *black_list_receiver_url; static Octstr *white_list_receiver_url; static Numhash *black_list_sender; static Numhash *white_list_sender; static Numhash *black_list_receiver; static Numhash *white_list_receiver; static regex_t *white_list_sender_regex; static regex_t *black_list_sender_regex; static regex_t *white_list_receiver_regex; static regex_t *black_list_receiver_regex; static long router_thread = -1; /* message resend */ static long sms_resend_frequency; static long sms_resend_retry; /* * Counter for catenated SMS messages. The counter that can be put into * the catenated SMS message's UDH headers is actually the lowest 8 bits. */ Counter *split_msg_counter; /* Flag for handling concatenated incoming messages. */ static volatile sig_atomic_t handle_concatenated_mo; /* How long to wait for message parts */ static long concatenated_mo_timeout; /* Flag for return value of check_concat */ enum {concat_error = -1, concat_complete = 0, concat_pending = 1, concat_none}; /* * forward declaration */ static long route_incoming_to_smsc(SMSCConn *conn, Msg *msg); static void concat_handling_init(void); static void concat_handling_shutdown(void); static void concat_handling_cleanup(void); static int concat_handling_check_and_handle(Msg **msg, Octstr *smscid); static void concat_handling_clear_old_parts(int force); /*--------------------------------------------------------------------------- * CALLBACK FUNCTIONS * * called by SMSCConn implementations when appropriate */ void bb_smscconn_ready(SMSCConn *conn) { gwlist_add_producer(flow_threads); gwlist_add_producer(incoming_sms); } void bb_smscconn_connected(SMSCConn *conn) { if (router_thread >= 0) gwthread_wakeup(router_thread); } void bb_smscconn_killed(void) { /* NOTE: after status has been set to SMSCCONN_DEAD, bearerbox * is free to release/delete 'conn' */ gwlist_remove_producer(incoming_sms); gwlist_remove_producer(flow_threads); } static void handle_split(SMSCConn *conn, Msg *msg, long reason) { struct split_parts *split = msg->sms.split_parts; /* * if the reason is not a success and status is still success * then set status of a split to the reason. * Note: reason 'malformed','discarded' or 'rejected' has higher priority! */ switch(reason) { case SMSCCONN_FAILED_TEMPORARILY: /* * Check if SMSC link alive and if so increase resend_try and set resend_time. * If SMSC link is not active don't increase resend_try and don't set resend_time * because we don't want to delay messages due to broken connection. */ if (smscconn_status(conn) == SMSCCONN_ACTIVE) { /* * Check if sms_resend_retry set and this msg has exceeded a limit also * honor "single shot" with sms_resend_retry set to zero. */ if (sms_resend_retry >= 0 && msg->sms.resend_try >= sms_resend_retry) { warning(0, "Maximum retries for message exceeded, discarding it!"); bb_smscconn_send_failed(NULL, msg, SMSCCONN_FAILED_DISCARDED, octstr_create("Retries Exceeded")); return; } msg->sms.resend_try = (msg->sms.resend_try > 0 ? msg->sms.resend_try + 1 : 1); time(&msg->sms.resend_time); } gwlist_produce(outgoing_sms, msg); return; case SMSCCONN_FAILED_DISCARDED: case SMSCCONN_FAILED_REJECTED: case SMSCCONN_FAILED_MALFORMED: debug("bb.sms.splits", 0, "Set split msg status to %ld", reason); split->status = reason; break; case SMSCCONN_SUCCESS: break; /* nothing todo */ default: if (split->status == SMSCCONN_SUCCESS) { debug("bb.sms.splits", 0, "Set split msg status to %ld", reason); split->status = reason; } break; } /* * now destroy this message, because we don't need it anymore. * we will split it again in smscconn_send(...). */ msg_destroy(msg); if (counter_decrease(split->parts_left) <= 1) { /* all splited parts were processed */ counter_destroy(split->parts_left); msg = split->orig; msg->sms.split_parts = NULL; if (split->status == SMSCCONN_SUCCESS) bb_smscconn_sent(conn, msg, NULL); else { debug("bb.sms.splits", 0, "Parts of concatenated message failed."); bb_smscconn_send_failed(conn, msg, split->status, NULL); } gw_free(split); } } void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply) { if (sms->sms.split_parts != NULL) { handle_split(conn, sms, SMSCCONN_SUCCESS); octstr_destroy(reply); return; } /* write ACK to store file */ store_save_ack(sms, ack_success); if (sms->sms.sms_type != report_mt) { bb_alog_sms(conn, sms, "Sent SMS"); counter_increase(outgoing_sms_counter); load_increase(outgoing_sms_load); if (conn != NULL) { counter_increase(conn->sent); load_increase(conn->outgoing_sms_load); } } else { bb_alog_sms(conn, sms, "Sent DLR"); counter_increase(outgoing_dlr_counter); load_increase(outgoing_dlr_load); if (conn != NULL) { counter_increase(conn->sent_dlr); load_increase(conn->outgoing_dlr_load); } } /* generate relay confirmancy message */ if (DLR_IS_SMSC_SUCCESS(sms->sms.dlr_mask)) { Msg *dlrmsg; if (reply == NULL) reply = octstr_create(""); octstr_insert_data(reply, 0, "ACK/", 4); dlrmsg = create_dlr_from_msg((conn->id?conn->id:conn->name), sms, reply, DLR_SMSC_SUCCESS); if (dlrmsg != NULL) { bb_smscconn_receive(conn, dlrmsg); } } msg_destroy(sms); octstr_destroy(reply); } void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply) { if (sms->sms.split_parts != NULL) { handle_split(conn, sms, reason); octstr_destroy(reply); return; } switch (reason) { case SMSCCONN_FAILED_TEMPORARILY: /* * Check if SMSC link alive and if so increase resend_try and set resend_time. * If SMSC link is not active don't increase resend_try and don't set resend_time * because we don't want to delay messages due to a broken connection. */ if (conn && smscconn_status(conn) == SMSCCONN_ACTIVE) { /* * Check if sms_resend_retry set and this msg has exceeded a limit also * honor "single shot" with sms_resend_retry set to zero. */ if (sms_resend_retry >= 0 && sms->sms.resend_try >= sms_resend_retry) { warning(0, "Maximum retries for message exceeded, discarding it!"); bb_smscconn_send_failed(NULL, sms, SMSCCONN_FAILED_DISCARDED, octstr_create("Retries Exceeded")); break; } sms->sms.resend_try = (sms->sms.resend_try > 0 ? sms->sms.resend_try + 1 : 1); time(&sms->sms.resend_time); } gwlist_produce(outgoing_sms, sms); break; case SMSCCONN_FAILED_SHUTDOWN: gwlist_produce(outgoing_sms, sms); break; default: /* write NACK to store file */ store_save_ack(sms, ack_failed); if (conn) counter_increase(conn->failed); if (reason == SMSCCONN_FAILED_DISCARDED) { if (sms->sms.sms_type != report_mt) bb_alog_sms(conn, sms, "DISCARDED SMS"); else bb_alog_sms(conn, sms, "DISCARDED DLR"); } else if (reason == SMSCCONN_FAILED_EXPIRED) { if (sms->sms.sms_type != report_mt) bb_alog_sms(conn, sms, "EXPIRED SMS"); else bb_alog_sms(conn, sms, "EXPIRED DLR"); } else if (reason == SMSCCONN_FAILED_REJECTED) { if (sms->sms.sms_type != report_mt) bb_alog_sms(conn, sms, "REJECTED Send SMS"); else bb_alog_sms(conn, sms, "REJECTED Send DLR"); } else { if (sms->sms.sms_type != report_mt) bb_alog_sms(conn, sms, "FAILED Send SMS"); else bb_alog_sms(conn, sms, "FAILED Send DLR"); } /* generate relay confirmancy message */ if (DLR_IS_SMSC_FAIL(sms->sms.dlr_mask) || DLR_IS_FAIL(sms->sms.dlr_mask)) { Msg *dlrmsg; if (reply == NULL) reply = octstr_create(""); octstr_insert_data(reply, 0, "NACK/", 5); dlrmsg = create_dlr_from_msg((conn ? (conn->id?conn->id:conn->name) : NULL), sms, reply, DLR_SMSC_FAIL); if (dlrmsg != NULL) { bb_smscconn_receive(conn, dlrmsg); } } msg_destroy(sms); break; } octstr_destroy(reply); } static long bb_smscconn_receive_internal(SMSCConn *conn, Msg *sms) { int rc; Msg *copy; copy = msg_duplicate(sms); /* * Try to reroute internally to an smsc-id without leaving * actually bearerbox scope. * Scope: internal routing (to smsc-ids) */ if ((rc = route_incoming_to_smsc(conn, copy)) == -1) { /* * Now try to route the message to a specific smsbox * connection based on the existing msg->sms.boxc_id or * the registered receiver numbers for specific smsbox'es. * Scope: external routing (to smsbox connections) */ rc = route_incoming_to_boxc(copy); } if (rc == -1 || (rc != SMSCCONN_SUCCESS && rc != SMSCCONN_QUEUED)) { warning(0, "incoming messages queue too long, dropping a message"); if (sms->sms.sms_type == report_mo) bb_alog_sms(conn, sms, "DROPPED Received DLR"); else bb_alog_sms(conn, sms, "DROPPED Received SMS"); /* put nack into store-file */ store_save_ack(sms, ack_failed); msg_destroy(copy); msg_destroy(sms); gwthread_sleep(0.1); /* letting the queue go down */ return (rc == -1 ? SMSCCONN_FAILED_QFULL : rc); } if (sms->sms.sms_type != report_mo) { bb_alog_sms(conn, sms, "Receive SMS"); counter_increase(incoming_sms_counter); load_increase(incoming_sms_load); if (conn != NULL) { counter_increase(conn->received); load_increase(conn->incoming_sms_load); } } else { bb_alog_sms(conn, sms, "Receive DLR"); counter_increase(incoming_dlr_counter); load_increase(incoming_dlr_load); if (conn != NULL) { counter_increase(conn->received_dlr); load_increase(conn->incoming_dlr_load); } } msg_destroy(sms); return SMSCCONN_SUCCESS; } long bb_smscconn_receive(SMSCConn *conn, Msg *sms) { char *uf; int ret; /* * first check whether msgdata data is NULL and set it to empty * because seems too much kannels parts rely on msgdata not to be NULL. */ if (sms->sms.msgdata == NULL) sms->sms.msgdata = octstr_create(""); /* * First normalize in smsc level and then on global level. * In outbound direction it's vise versa, hence first global then smsc. */ uf = (conn && conn->unified_prefix) ? octstr_get_cstr(conn->unified_prefix) : NULL; normalize_number(uf, &(sms->sms.sender)); uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL; normalize_number(uf, &(sms->sms.sender)); /* * We don't perform white/black-listing for DLRs. * Fix sms type if not set already. */ if (sms->sms.sms_type != report_mo) { sms->sms.sms_type = mo; gw_rwlock_rdlock(&white_black_list_lock); if (white_list_sender && numhash_find_number(white_list_sender, sms->sms.sender) < 1) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is not in white-list-sender, message discarded", octstr_get_cstr(sms->sms.sender)); bb_alog_sms(conn, sms, "REJECTED Receive SMS - not white-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (white_list_sender_regex && gw_regex_match_pre(white_list_sender_regex, sms->sms.sender) == 0) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is not in white-list-sender, message discarded", octstr_get_cstr(sms->sms.sender)); bb_alog_sms(conn, sms, "REJECTED Receive SMS - not white-regex-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (black_list_sender && numhash_find_number(black_list_sender, sms->sms.sender) == 1) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is in black-list-sender, message discarded", octstr_get_cstr(sms->sms.sender)); bb_alog_sms(conn, sms, "REJECTED Receive SMS - black-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (black_list_sender_regex && gw_regex_match_pre(black_list_sender_regex, sms->sms.sender) != 0) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is in black-list-sender, message discarded", octstr_get_cstr(sms->sms.sender)); bb_alog_sms(conn, sms, "REJECTED Receive SMS - black-regex-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (white_list_receiver && numhash_find_number(white_list_receiver, sms->sms.receiver) < 1) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is not in white-list-receiver, message discarded", octstr_get_cstr(sms->sms.receiver)); bb_alog_sms(conn, sms, "REJECTED Receive SMS - not white-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (white_list_receiver_regex && gw_regex_match_pre(white_list_receiver_regex, sms->sms.receiver) == 0) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is not in white-list-receiver, message discarded", octstr_get_cstr(sms->sms.receiver)); bb_alog_sms(conn, sms, "REJECTED Receive SMS - not white-regex-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (black_list_receiver && numhash_find_number(black_list_receiver, sms->sms.receiver) == 1) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is in black-list-receiver, message discarded", octstr_get_cstr(sms->sms.receiver)); bb_alog_sms(conn, sms, "REJECTED Receive SMS - black-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } if (black_list_receiver_regex && gw_regex_match_pre(black_list_receiver_regex, sms->sms.receiver) != 0) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is in black-list-receiver, message discarded", octstr_get_cstr(sms->sms.receiver)); bb_alog_sms(conn, sms, "REJECTED Receive SMS - black-regex-listed SMS"); msg_destroy(sms); return SMSCCONN_FAILED_REJECTED; } gw_rwlock_unlock(&white_black_list_lock); } /* write to store (if enabled) */ if (store_save(sms) == -1) { msg_destroy(sms); return SMSCCONN_FAILED_TEMPORARILY; } /* Before routing to some box or re-routing, do concatenation handling * and replace copy as such. */ if (handle_concatenated_mo && sms->sms.sms_type == mo) { ret = concat_handling_check_and_handle(&sms, (conn ? conn->id : NULL)); switch(ret) { case concat_pending: counter_increase(incoming_sms_counter); /* ?? */ load_increase(incoming_sms_load); if (conn != NULL) { counter_increase(conn->received); load_increase(conn->incoming_sms_load); } return SMSCCONN_SUCCESS; case concat_complete: /* Combined sms received! save new one since it is now combined. */ break; case concat_error: /* failed to save, go away. */ msg_destroy(sms); return SMSCCONN_FAILED_TEMPORARILY; case concat_none: break; default: panic(0, "Internal error: Unhandled concat result."); break; } } return bb_smscconn_receive_internal(conn, sms); } int bb_reload_smsc_groups() { debug("bb.sms", 0, "Reloading smsc groups list from config resource"); cfg_destroy(cfg_reloaded); cfg_reloaded = cfg_create(cfg_filename); if (cfg_read(cfg_reloaded) == -1) { warning(0, "Error opening configuration file %s", octstr_get_cstr(cfg_filename)); return -1; } gwlist_destroy(smsc_groups, NULL); smsc_groups = cfg_get_multi_group(cfg_reloaded, octstr_imm("smsc")); return 0; } /*--------------------------------------------------------------------- * Other functions */ /* function to route outgoing SMS'es from delay-list * use some nice magics to route them to proper SMSC */ static void sms_router(void *arg) { Msg *msg, *startmsg, *newmsg; long ret; time_t concat_mo_check; gwlist_add_producer(flow_threads); gwthread_wakeup(MAIN_THREAD_ID); startmsg = newmsg = NULL; ret = SMSCCONN_SUCCESS; concat_mo_check = time(NULL); while(bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) { if (newmsg == startmsg) { if (ret == SMSCCONN_QUEUED || ret == SMSCCONN_FAILED_QFULL) { /* sleep: sms_resend_frequency / 2 , so we reduce amount of msgs to send */ double sleep_time = (sms_resend_frequency / 2 > 1 ? sms_resend_frequency / 2 : sms_resend_frequency); debug("bb.sms", 0, "sms_router: time to sleep %.2f secs.", sleep_time); gwthread_sleep(sleep_time); debug("bb.sms", 0, "sms_router: gwlist_len = %ld", gwlist_len(outgoing_sms)); } startmsg = msg = gwlist_timed_consume(outgoing_sms, concatenated_mo_timeout); newmsg = NULL; } else { newmsg = msg = gwlist_timed_consume(outgoing_sms, concatenated_mo_timeout); } if (difftime(time(NULL), concat_mo_check) > concatenated_mo_timeout) { concat_mo_check = time(NULL); concat_handling_clear_old_parts(0); } /* shutdown or timeout */ if (msg == NULL) { newmsg = startmsg = NULL; continue; } debug("bb.sms", 0, "sms_router: handling message (%p vs %p)", msg, startmsg); /* handle delayed msgs */ if (msg->sms.resend_try > 0 && difftime(time(NULL), msg->sms.resend_time) < sms_resend_frequency && bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) { debug("bb.sms", 0, "re-queing SMS not-yet-to-be resent"); gwlist_produce(outgoing_sms, msg); ret = SMSCCONN_QUEUED; continue; } ret = smsc2_rout(msg, 1); switch(ret) { case SMSCCONN_SUCCESS: debug("bb.sms", 0, "Message routed successfully."); newmsg = startmsg = NULL; break; case SMSCCONN_QUEUED: debug("bb.sms", 0, "Routing failed, re-queued."); break; case SMSCCONN_FAILED_DISCARDED: msg_destroy(msg); newmsg = startmsg = NULL; break; case SMSCCONN_FAILED_QFULL: debug("bb.sms", 0, "Routing failed, re-queuing."); gwlist_produce(outgoing_sms, msg); break; case SMSCCONN_FAILED_EXPIRED: debug("bb.sms", 0, "Routing failed, expired."); msg_destroy(msg); newmsg = startmsg = NULL; break; default: break; } } gwlist_remove_producer(flow_threads); } #define OCTSTR(os) octstr_imm(#os) static int cmp_conn_grp_checksum(void *a, void *b) { int ret; SMSCConn *conn = a; Octstr *os; os = cfg_get_group_checksum((CfgGroup*)b, NULL ); ret = (octstr_compare(conn->chksum, os) == 0); octstr_destroy(os); return ret; } static int cmp_rout_grp_checksum(void *a, void *b) { int ret; SMSCConn *conn = a; Octstr *os; os = cfg_get_group_checksum((CfgGroup*)b, OCTSTR(denied-smsc-id), OCTSTR(allowed-smsc-id), OCTSTR(preferred-smsc-id), OCTSTR(allowed-prefix), OCTSTR(denied-prefix), OCTSTR(preferred-prefix), OCTSTR(unified-prefix), OCTSTR(reroute), OCTSTR(reroute-smsc-id), OCTSTR(reroute-receiver), OCTSTR(reroute-dlr), OCTSTR(allowed-smsc-id-regex), OCTSTR(denied-smsc-id-regex), OCTSTR(preferred-smsc-id-regex), OCTSTR(allowed-prefix-regex), OCTSTR(denied-prefix-regex), OCTSTR(preferred-prefix-regex), NULL ); ret = (octstr_compare(conn->chksum_conn, os) == 0); octstr_destroy(os); return ret; } #undef OCTSTR static int cmp_conn_grp_id(void *a, void *b) { int ret; SMSCConn *conn = a; Octstr *os = cfg_get((CfgGroup*)b, octstr_imm("smsc-id")); ret = (os && octstr_compare(conn->id, os) == 0); octstr_destroy(os); return ret; } /*------------------------------------------------------------- * public functions * */ int smsc2_start(Cfg *cfg) { CfgGroup *grp; SMSCConn *conn; Octstr *os; int i, j, m; if (smsc_running) return -1; /* at start-up time there is no reloaded config */ cfg_reloaded = NULL; /* create split sms counter */ split_msg_counter = counter_create(); /* create smsc list and rwlock for it */ smsc_list = gwlist_create(); gw_rwlock_init_static(&smsc_list_lock); grp = cfg_get_single_group(cfg, octstr_imm("core")); unified_prefix = cfg_get(grp, octstr_imm("unified-prefix")); gw_rwlock_init_static(&white_black_list_lock); white_list_sender = black_list_sender = NULL; white_list_sender_url = black_list_sender_url = NULL; if ((white_list_sender_url = cfg_get(grp, octstr_imm("white-list"))) != NULL) /* TODO deprecated, remove */ warning(0, "Option 'white-list' is deprecated! Please use 'white-list-sender' instead!"); else white_list_sender_url = cfg_get(grp, octstr_imm("white-list-sender")); if (white_list_sender_url != NULL) { if ((white_list_sender = numhash_create(octstr_get_cstr(white_list_sender_url))) == NULL) panic(0, "Could not get white-list at URL <%s>", octstr_get_cstr(white_list_sender_url)); } if ((os = cfg_get(grp, octstr_imm("white-list-regex"))) != NULL) /* TODO deprecated, remove */ warning(0, "Option 'white-list-regex' is deprecated! Please use 'white-list-sender-regex' instead!"); else os = cfg_get(grp, octstr_imm("white-list-sender-regex")); if (os != NULL) { if ((white_list_sender_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } if ((black_list_sender_url = cfg_get(grp, octstr_imm("black-list"))) != NULL) /* TODO deprecated, remove */ warning(0, "Option 'black-list' is deprecated! Please use 'black-list-sender' instead!"); else black_list_sender_url = cfg_get(grp, octstr_imm("black-list-sender")); if (black_list_sender_url != NULL) { if ((black_list_sender = numhash_create(octstr_get_cstr(black_list_sender_url))) == NULL) panic(0, "Could not get black-list at URL <%s>", octstr_get_cstr(black_list_sender_url)); } if ((os = cfg_get(grp, octstr_imm("black-list-regex"))) != NULL) /* TODO deprecated, remove */ warning(0, "Option 'black-list-regex' is deprecated! Please use 'black-list-sender-regex' instead!"); else os = cfg_get(grp, octstr_imm("black-list-sender-regex")); if (os != NULL) { if ((black_list_sender_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } white_list_receiver = black_list_receiver = NULL; white_list_receiver_url = black_list_receiver_url = NULL; white_list_receiver_url = cfg_get(grp, octstr_imm("white-list-receiver")); if (white_list_receiver_url != NULL) { if ((white_list_receiver = numhash_create(octstr_get_cstr(white_list_receiver_url))) == NULL) panic(0, "Could not get white-list-receiver at URL <%s>", octstr_get_cstr(white_list_receiver_url)); } if ((os = cfg_get(grp, octstr_imm("white-list-receiver-regex"))) != NULL) { if ((white_list_receiver_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } black_list_receiver_url = cfg_get(grp, octstr_imm("black-list-receiver")); if (black_list_receiver_url != NULL) { if ((black_list_receiver = numhash_create(octstr_get_cstr(black_list_receiver_url))) == NULL) panic(0, "Could not get black-list-receiver at URL <%s>", octstr_get_cstr(black_list_receiver_url)); } if ((os = cfg_get(grp, octstr_imm("black-list-receiver-regex"))) != NULL) { if ((black_list_receiver_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } if (cfg_get_integer(&sms_resend_frequency, grp, octstr_imm("sms-resend-freq")) == -1 || sms_resend_frequency <= 0) { sms_resend_frequency = 60; } info(0, "Set SMS resend frequency to %ld seconds.", sms_resend_frequency); if (cfg_get_integer(&sms_resend_retry, grp, octstr_imm("sms-resend-retry")) == -1) { sms_resend_retry = -1; info(0, "SMS resend retry set to unlimited."); } else info(0, "SMS resend retry set to %ld.", sms_resend_retry); if (cfg_get_bool((int*)&handle_concatenated_mo, grp, octstr_imm("sms-combine-concatenated-mo")) == -1) handle_concatenated_mo = 1; /* default is TRUE. */ if (cfg_get_integer(&concatenated_mo_timeout, grp, octstr_imm("sms-combine-concatenated-mo-timeout")) == -1) concatenated_mo_timeout = 1800; if (handle_concatenated_mo) concat_handling_init(); /* initialize low level PDUs */ if (smpp_pdu_init(cfg) == -1) panic(0, "Connot start with PDU init failed."); smsc_groups = cfg_get_multi_group(cfg, octstr_imm("smsc")); gwlist_add_producer(smsc_list); for (i = 0; i < gwlist_len(smsc_groups) && (grp = gwlist_get(smsc_groups, i)) != NULL; i++) { /* multiple instances for the same group? */ m = smscconn_instances(grp); for (j = 0; j < m; j++) { conn = smscconn_create(grp, 1); if (conn == NULL) panic(0, "Cannot start with SMSC connection failing"); gwlist_append(smsc_list, conn); } } gwlist_remove_producer(smsc_list); if ((router_thread = gwthread_create(sms_router, NULL)) == -1) panic(0, "Failed to start a new thread for SMS routing"); gwlist_add_producer(incoming_sms); smsc_running = 1; return 0; } /* * Find a matching smsc-id in the smsc list starting at position start. * NOTE: Caller must ensure that smsc_list is properly locked! */ static long smsc2_find(Octstr *id, long start) { SMSCConn *conn = NULL; long i; if (start > gwlist_len(smsc_list) || start < 0 || id == NULL) return -1; for (i = start; i < gwlist_len(smsc_list); i++) { conn = gwlist_get(smsc_list, i); if (conn != NULL && conn->admin_id != NULL && octstr_compare(conn->admin_id, id) == 0) { break; } } if (i >= gwlist_len(smsc_list)) i = -1; return i; } int smsc2_stop_smsc(Octstr *id) { SMSCConn *conn; long i = -1; int success = 0; if (!smsc_running) return -1; gw_rwlock_rdlock(&smsc_list_lock); /* find the specific smsc via id */ while((i = smsc2_find(id, ++i)) != -1) { conn = gwlist_get(smsc_list, i); if (conn != NULL && smscconn_status(conn) == SMSCCONN_DEAD) { info(0, "HTTP: Could not shutdown already dead smsc-id `%s'", octstr_get_cstr(id)); } else { info(0,"HTTP: Shutting down smsc-id `%s'", octstr_get_cstr(id)); smscconn_shutdown(conn, 1); /* shutdown the smsc */ success = 1; } } gw_rwlock_unlock(&smsc_list_lock); if (success == 0) { error(0, "SMSC %s not found", octstr_get_cstr(id)); return -1; } return 0; } int smsc2_restart_smsc(Octstr *id) { CfgGroup *grp; SMSCConn *conn, *new_conn; Octstr *smscid = NULL; long i = -1; int hit; int num = 0; int success = 0; if (!smsc_running) return -1; gw_rwlock_wrlock(&smsc_list_lock); if (bb_reload_smsc_groups() != 0) { gw_rwlock_unlock(&smsc_list_lock); return -1; } /* find the specific smsc via id */ while((i = smsc2_find(id, ++i)) != -1) { long group_index; /* check if smsc has online status already */ conn = gwlist_get(smsc_list, i); if (conn != NULL && smscconn_status(conn) != SMSCCONN_DEAD) { warning(0, "HTTP: Could not re-start already running smsc-id `%s'", octstr_get_cstr(id)); continue; } /* find the group with equal smsc (admin-)id */ hit = -1; grp = NULL; for (group_index = 0; group_index < gwlist_len(smsc_groups) && (grp = gwlist_get(smsc_groups, group_index)) != NULL; group_index++) { smscid = cfg_get(grp, octstr_imm("smsc-admin-id")); if (smscid == NULL) smscid = cfg_get(grp, octstr_imm("smsc-id")); if (smscid != NULL && octstr_compare(smscid, id) == 0) { if (hit < 0) hit = 0; if (hit == num) break; else hit++; } octstr_destroy(smscid); smscid = NULL; } octstr_destroy(smscid); if (hit != num) { /* config group not found */ error(0, "HTTP: Could not find config for smsc-id `%s'", octstr_get_cstr(id)); break; } info(0,"HTTP: Re-starting smsc-id `%s'", octstr_get_cstr(id)); new_conn = smscconn_create(grp, 1); if (new_conn == NULL) { error(0, "Start of SMSC connection failed, smsc-id `%s'", octstr_get_cstr(id)); continue; /* keep old connection on the list */ } /* drop old connection from the active smsc list */ gwlist_delete(smsc_list, i, 1); /* destroy the connection */ smscconn_destroy(conn); gwlist_insert(smsc_list, i, new_conn); smscconn_start(new_conn); success = 1; num++; } gw_rwlock_unlock(&smsc_list_lock); if (success == 0) { error(0, "SMSC %s not found", octstr_get_cstr(id)); return -1; } /* wake-up the router */ if (router_thread >= 0) gwthread_wakeup(router_thread); return 0; } int smsc2_remove_smsc(Octstr *id) { SMSCConn *conn; long i = -1; int success = 0; if (!smsc_running) return -1; gw_rwlock_wrlock(&smsc_list_lock); gwlist_add_producer(smsc_list); while((i = smsc2_find(id, ++i)) != -1) { conn = gwlist_get(smsc_list, i); gwlist_delete(smsc_list, i, 1); smscconn_shutdown(conn, 0); smscconn_destroy(conn); success = 1; } gwlist_remove_producer(smsc_list); gw_rwlock_unlock(&smsc_list_lock); if (success == 0) { error(0, "SMSC %s not found", octstr_get_cstr(id)); return -1; } return 0; } int smsc2_add_smsc(Octstr *id) { CfgGroup *grp; SMSCConn *conn; Octstr *smscid = NULL; long i; int success = 0; if (!smsc_running) return -1; gw_rwlock_wrlock(&smsc_list_lock); if (bb_reload_smsc_groups() != 0) { gw_rwlock_unlock(&smsc_list_lock); return -1; } if (smsc2_find(id, 0) != -1) { warning(0, "Could not add already existing SMSC %s", octstr_get_cstr(id)); gw_rwlock_unlock(&smsc_list_lock); return -1; } gwlist_add_producer(smsc_list); grp = NULL; for (i = 0; i < gwlist_len(smsc_groups) && (grp = gwlist_get(smsc_groups, i)) != NULL; i++) { smscid = cfg_get(grp, octstr_imm("smsc-admin-id")); if (smscid == NULL) smscid = cfg_get(grp, octstr_imm("smsc-id")); if (smscid != NULL && octstr_compare(smscid, id) == 0) { conn = smscconn_create(grp, 1); if (conn != NULL) { gwlist_append(smsc_list, conn); if (conn->dead_start) { /* Shutdown connection if it's not configured to connect at start-up time */ smscconn_shutdown(conn, 0); } else { smscconn_start(conn); } success = 1; } } } gwlist_remove_producer(smsc_list); gw_rwlock_unlock(&smsc_list_lock); if (success == 0) { error(0, "SMSC %s not found", octstr_get_cstr(id)); return -1; } return 0; } int smsc2_reload_lists(void) { Numhash *tmp; int rc = 1; if (white_list_sender_url != NULL) { tmp = numhash_create(octstr_get_cstr(white_list_sender_url)); if (white_list_sender == NULL) { error(0, "Unable to reload white_list."), rc = -1; } else { gw_rwlock_wrlock(&white_black_list_lock); numhash_destroy(white_list_sender); white_list_sender = tmp; gw_rwlock_unlock(&white_black_list_lock); } } if (black_list_sender_url != NULL) { tmp = numhash_create(octstr_get_cstr(black_list_sender_url)); if (black_list_sender == NULL) { error(0, "Unable to reload black_list"); rc = -1; } else { gw_rwlock_wrlock(&white_black_list_lock); numhash_destroy(black_list_sender); black_list_sender = tmp; gw_rwlock_unlock(&white_black_list_lock); } } if (white_list_receiver_url != NULL) { tmp = numhash_create(octstr_get_cstr(white_list_receiver_url)); if (white_list_receiver == NULL) { error(0, "Unable to reload white_list."), rc = -1; } else { gw_rwlock_wrlock(&white_black_list_lock); numhash_destroy(white_list_receiver); white_list_receiver = tmp; gw_rwlock_unlock(&white_black_list_lock); } } if (black_list_receiver_url != NULL) { tmp = numhash_create(octstr_get_cstr(black_list_receiver_url)); if (black_list_receiver == NULL) { error(0, "Unable to reload black_list"); rc = -1; } else { gw_rwlock_wrlock(&white_black_list_lock); numhash_destroy(black_list_receiver); black_list_receiver = tmp; gw_rwlock_unlock(&white_black_list_lock); } } return rc; } void smsc2_resume(int is_init) { SMSCConn *conn; long i; if (!smsc_running) return; gw_rwlock_rdlock(&smsc_list_lock); for (i = 0; i < gwlist_len(smsc_list); i++) { conn = gwlist_get(smsc_list, i); if (!is_init || !conn->dead_start) { smscconn_start(conn); } else { /* Shutdown the connections that are not configured to start at boot */ smscconn_shutdown(conn, 0); } } gw_rwlock_unlock(&smsc_list_lock); if (router_thread >= 0) gwthread_wakeup(router_thread); } void smsc2_suspend(void) { SMSCConn *conn; long i; if (!smsc_running) return; gw_rwlock_rdlock(&smsc_list_lock); for (i = 0; i < gwlist_len(smsc_list); i++) { conn = gwlist_get(smsc_list, i); smscconn_stop(conn); } gw_rwlock_unlock(&smsc_list_lock); } int smsc2_shutdown(void) { SMSCConn *conn; long i; if (!smsc_running) return -1; /* stop concat handling */ concat_handling_shutdown(); /* Call shutdown for all SMSC Connections; they should * handle that they quit, by emptying queues and then dying off */ gw_rwlock_rdlock(&smsc_list_lock); for(i=0; i < gwlist_len(smsc_list); i++) { conn = gwlist_get(smsc_list, i); smscconn_shutdown(conn, 1); } gw_rwlock_unlock(&smsc_list_lock); if (router_thread >= 0) gwthread_wakeup(router_thread); /* start avalanche by calling shutdown */ /* XXX shouldn'w we be sure that all smsces have closed their * receive thingies? Is this guaranteed by setting bb_status * to shutdown before calling these? */ gwlist_remove_producer(incoming_sms); /* shutdown low levele PDU things */ smpp_pdu_shutdown(); return 0; } void smsc2_cleanup(void) { SMSCConn *conn; long i; if (!smsc_running) return; debug("smscconn", 0, "final clean-up for SMSCConn"); gw_rwlock_wrlock(&smsc_list_lock); for (i = 0; i < gwlist_len(smsc_list); i++) { conn = gwlist_get(smsc_list, i); smscconn_destroy(conn); } gwlist_destroy(smsc_list, NULL); smsc_list = NULL; gw_rwlock_unlock(&smsc_list_lock); gwlist_destroy(smsc_groups, NULL); octstr_destroy(unified_prefix); numhash_destroy(white_list_sender); numhash_destroy(black_list_sender); octstr_destroy(white_list_sender_url); octstr_destroy(black_list_sender_url); if (white_list_sender_regex != NULL) gw_regex_destroy(white_list_sender_regex); if (black_list_sender_regex != NULL) gw_regex_destroy(black_list_sender_regex); numhash_destroy(white_list_receiver); numhash_destroy(black_list_receiver); octstr_destroy(white_list_receiver_url); octstr_destroy(black_list_receiver_url); if (white_list_receiver_regex != NULL) gw_regex_destroy(white_list_receiver_regex); if (black_list_receiver_regex != NULL) gw_regex_destroy(black_list_receiver_regex); /* destroy msg split counter */ counter_destroy(split_msg_counter); gw_rwlock_destroy(&smsc_list_lock); gw_rwlock_destroy(&white_black_list_lock); /* Stop concat handling */ concat_handling_cleanup(); smsc_running = 0; } Octstr *smsc2_status(int status_type) { Octstr *tmp; char tmp3[64]; char *lb; long i; int para = 0; SMSCConn *conn; StatusInfo info; const Octstr *conn_id = NULL; const Octstr *conn_admin_id = NULL; const Octstr *conn_name = NULL; float incoming_sms_load_0, incoming_sms_load_1, incoming_sms_load_2; float outgoing_sms_load_0, outgoing_sms_load_1, outgoing_sms_load_2; float incoming_dlr_load_0, incoming_dlr_load_1, incoming_dlr_load_2; float outgoing_dlr_load_0, outgoing_dlr_load_1, outgoing_dlr_load_2; if ((lb = bb_status_linebreak(status_type)) == NULL) return octstr_create("Un-supported format"); if (status_type == BBSTATUS_HTML || status_type == BBSTATUS_WML) para = 1; if (!smsc_running) { if (status_type == BBSTATUS_XML) return octstr_create ("\n\t0\n"); else return octstr_format("%sNo SMSC connections%s\n\n", para ? "

" : "", para ? "

" : ""); } if (status_type != BBSTATUS_XML) tmp = octstr_format("%sSMSC connections:%s", para ? "

" : "", lb); else tmp = octstr_format("%d\n\t", gwlist_len(smsc_list)); gw_rwlock_rdlock(&smsc_list_lock); for (i = 0; i < gwlist_len(smsc_list); i++) { incoming_sms_load_0 = incoming_sms_load_1 = incoming_sms_load_2 = 0.0; outgoing_sms_load_0 = outgoing_sms_load_1 = outgoing_sms_load_2 = 0.0; incoming_dlr_load_0 = incoming_dlr_load_1 = incoming_dlr_load_2 = 0.0; outgoing_dlr_load_0 = outgoing_dlr_load_1 = outgoing_dlr_load_2 = 0.0; conn = gwlist_get(smsc_list, i); if ((smscconn_info(conn, &info) == -1)) { /* * we do not delete SMSCs from the list * this way we can show in the status which links are dead */ continue; } conn_id = conn ? smscconn_id(conn) : octstr_imm("unknown"); conn_id = conn_id ? conn_id : octstr_imm("unknown"); conn_admin_id = conn ? smscconn_admin_id(conn) : octstr_imm("unknown"); conn_admin_id = conn_admin_id ? conn_admin_id : octstr_imm("unknown"); conn_name = conn ? smscconn_name(conn) : octstr_imm("unknown"); if (status_type == BBSTATUS_HTML) { octstr_append_cstr(tmp, "    "); octstr_append(tmp, conn_id); octstr_append_cstr(tmp, "["); octstr_append(tmp, conn_admin_id); octstr_append_cstr(tmp, "]    "); } else if (status_type == BBSTATUS_TEXT) { octstr_append_cstr(tmp, " "); octstr_append(tmp, conn_id); octstr_append_cstr(tmp, "["); octstr_append(tmp, conn_admin_id); octstr_append_cstr(tmp, "] "); } if (status_type == BBSTATUS_XML) { octstr_append_cstr(tmp, "\n\t\t"); octstr_append(tmp, conn_name); octstr_append_cstr(tmp, "\n\t\t"); octstr_append(tmp, conn_admin_id); octstr_append_cstr(tmp, "\n\t\t"); octstr_append(tmp, conn_id); octstr_append_cstr(tmp, "\n\t\t"); } else octstr_append(tmp, conn_name); switch (info.status) { case SMSCCONN_ACTIVE: case SMSCCONN_ACTIVE_RECV: sprintf(tmp3, "online %lds", info.online); incoming_sms_load_0 = load_get(conn->incoming_sms_load,0); incoming_sms_load_1 = load_get(conn->incoming_sms_load,1); incoming_sms_load_2 = load_get(conn->incoming_sms_load,2); outgoing_sms_load_0 = load_get(conn->outgoing_sms_load,0); outgoing_sms_load_1 = load_get(conn->outgoing_sms_load,1); outgoing_sms_load_2 = load_get(conn->outgoing_sms_load,2); incoming_dlr_load_0 = load_get(conn->incoming_dlr_load,0); incoming_dlr_load_1 = load_get(conn->incoming_dlr_load,1); incoming_dlr_load_2 = load_get(conn->incoming_dlr_load,2); outgoing_dlr_load_0 = load_get(conn->outgoing_dlr_load,0); outgoing_dlr_load_1 = load_get(conn->outgoing_dlr_load,1); outgoing_dlr_load_2 = load_get(conn->outgoing_dlr_load,2); break; case SMSCCONN_DISCONNECTED: sprintf(tmp3, "disconnected"); break; case SMSCCONN_CONNECTING: sprintf(tmp3, "connecting"); break; case SMSCCONN_RECONNECTING: sprintf(tmp3, "re-connecting"); break; case SMSCCONN_DEAD: sprintf(tmp3, "dead"); break; default: sprintf(tmp3, "unknown"); break; } if (status_type == BBSTATUS_XML) octstr_format_append(tmp, "%s\n" "\t\t%ld\n" "\t\t%ld\n" "\t\t\n" "\t\t\t%ld\n" "\t\t\t%ld\n" "\t\t\t%.2f,%.2f,%.2f\n" "\t\t\t%.2f,%.2f,%.2f\n" "\t\t\n\t\t\n" "\t\t\t%ld\n" "\t\t\t%ld\n" "\t\t\t%.2f,%.2f,%.2f\n" "\t\t\t%.2f,%.2f,%.2f\n" "\t\t\n" "\t\n", tmp3, info.failed, info.queued, info.received, info.sent, incoming_sms_load_0, incoming_sms_load_1, incoming_sms_load_2, outgoing_sms_load_0, outgoing_sms_load_1, outgoing_sms_load_2, info.received_dlr, info.sent_dlr, incoming_dlr_load_0, incoming_dlr_load_1, incoming_dlr_load_2, outgoing_dlr_load_0, outgoing_dlr_load_1, outgoing_dlr_load_2); else octstr_format_append(tmp, " (%s, rcvd: sms %ld (%.2f,%.2f,%.2f) / dlr %ld (%.2f,%.2f,%.2f), " "sent: sms %ld (%.2f,%.2f,%.2f) / dlr %ld (%.2f,%.2f,%.2f), failed %ld, " "queued %ld msgs)%s", tmp3, info.received, incoming_sms_load_0, incoming_sms_load_1, incoming_sms_load_2, info.received_dlr, incoming_dlr_load_0, incoming_dlr_load_1, incoming_dlr_load_2, info.sent, outgoing_sms_load_0, outgoing_sms_load_1, outgoing_sms_load_2, info.sent_dlr, outgoing_dlr_load_0, outgoing_dlr_load_1, outgoing_dlr_load_2, info.failed, info.queued, lb); } gw_rwlock_unlock(&smsc_list_lock); if (para) octstr_append_cstr(tmp, "

"); if (status_type == BBSTATUS_XML) octstr_append_cstr(tmp, "\n"); else octstr_append_cstr(tmp, "\n\n"); return tmp; } int smsc2_graceful_restart(void) { CfgGroup *grp; SMSCConn *conn; List *keep, *add, *remove; List *l; int i, m; if (!smsc_running) return -1; gw_rwlock_wrlock(&smsc_list_lock); /* load the smsc groups from the config resource */ if (bb_reload_smsc_groups() != 0) { gw_rwlock_unlock(&smsc_list_lock); return -1; } /* List of SMSCConn that we keep running */ keep = gwlist_create(); /* List of CfgGroup that we will add */ add = gwlist_create(); /* List of SMSCConnn that we will shutdown */ remove = gwlist_create(); /* * Loop through the loaded smsc groups */ for (i = 0; i < gwlist_len(smsc_groups) && (grp = gwlist_get(smsc_groups, i)) != NULL; i++) { /* * 1st check: Search for the same md5 hash of the whole group. * If we find it, then this group is already running, and no * routing information has changed, bail out. */ if ((l = gwlist_search_all(smsc_list, grp, cmp_conn_grp_checksum)) != NULL) { while ((conn = gwlist_extract_first(l)) != NULL) { gwlist_append(keep, conn); } gwlist_destroy(l, NULL); continue; } /* * 2nd check: Search for the same md5 hash minus the routing * information. If we find it, then this group is already running * and the routing information changed, we'll apply only the new * routing information. */ if ((l = gwlist_search_all(smsc_list, grp, cmp_rout_grp_checksum)) != NULL) { while ((conn = gwlist_extract_first(l)) != NULL) { gwlist_append(keep, conn); smscconn_reconfig(conn, grp); info(0, "Re-configured routing for smsc-id `%s'.", octstr_get_cstr(conn->id)); } gwlist_destroy(l, NULL); continue; } /* * 3rd check: if the smsc-id is NOT in the running list, then * this is a new group, add it. If the smsc-id IS found, then * mark it/them to be removed, and add the new group. */ if ((l = gwlist_search_all(smsc_list, grp, cmp_conn_grp_id)) == NULL) { gwlist_append(add, grp); continue; } else { while ((conn = gwlist_extract_first(l)) != NULL) { /* add them to the remove list only * if they are not yet present inside. */ if (gwlist_search_equal(remove, conn) != -1) gwlist_append(remove, conn); } gwlist_destroy(l, NULL); gwlist_append(add, grp); continue; } } /* * TODO Effectively a change in the 'instances' multiplier will result in a * disconnect of all running instances, and re-connecting the number of * configured instances. The reason for this is that the change in the * 'instances' value causes the md5 hash to be different for that connection. * We MAY exclude the 'instances' directive from the while md5 checksum, this * makes the down-grading easier, allowing the rest to keep running. But the * up-grading is more difficult, since we can't use the 'add' list here, it * would create too much instances. */ /* * We may have running smsc-ids now, that haven't been * re-loaded from the new config, hence add them to be removed. */ for (i = 0; i < gwlist_len(smsc_list) && (conn = gwlist_get(smsc_list, i)) != NULL; i++) { /* if this is already in the remove list, bail out. */ if (gwlist_search_equal(remove, conn) != -1) continue; /* if this is in the keep list, bail out. */ if (gwlist_search_equal(keep, conn) != -1) continue; /* mark it to be removed */ gwlist_append(remove, conn); } gwlist_destroy(keep, NULL); /* * Stop any connections from the remove list. * * The smscconn_shutdown() only initiates the shutdown, * it is not guaranteed that the SMSC connection is stopped * and the status is SMSCCONN_DEAD when we return from the * function call. Therefore we pass the connection to a * retry list, in order to cleanly destroy all connection * structures that have been stopped and reached SMSSCONN_DEAD. */ l = gwlist_create(); gwlist_add_producer(smsc_list); while ((conn = gwlist_extract_first(remove)) != NULL) { if ((i = gwlist_search_equal(smsc_list, conn)) != -1) { gwlist_delete(smsc_list, i, 1); smscconn_shutdown(conn, 0); /* if smsc is still in shutdown, then add to retry list */ if (smscconn_destroy(conn) == -1) gwlist_append(l, conn); } } gwlist_remove_producer(smsc_list); gwlist_destroy(remove, NULL); /* * Start any connections from the add list. */ gwlist_add_producer(smsc_list); while ((grp = gwlist_extract_first(add)) != NULL) { /* multiple instances for the same group? */ m = smscconn_instances(grp); for (i = 0; i < m; i++) { conn = smscconn_create(grp, 1); if (conn != NULL) { gwlist_append(smsc_list, conn); if (conn->dead_start) { /* Shutdown connection if it's not configured to connect at start-up time */ smscconn_shutdown(conn, 0); } else { smscconn_start(conn); } } } } gwlist_remove_producer(smsc_list); gwlist_destroy(add, NULL); gw_rwlock_unlock(&smsc_list_lock); /* wake-up the router */ if (router_thread >= 0) gwthread_wakeup(router_thread); /* * We may still have pending connections in the retry list * that haven't been destroyed yet. */ while ((conn = gwlist_extract_first(l)) != NULL) { if (smscconn_destroy(conn) == -1) { gwlist_append(l, conn); gwthread_sleep(2); } } gwlist_destroy(l, NULL); return 0; } /* function to route outgoing SMS'es * * If finds a good one, puts into it and returns SMSCCONN_SUCCESS * If finds only bad ones, but acceptable, queues and * returns SMSCCONN_QUEUED (like all acceptable currently disconnected) * if message acceptable but queues full returns SMSCCONN_FAILED_QFULL and * message is not destroyed. * If cannot find nothing at all, returns SMSCCONN_FAILED_DISCARDED and * message is NOT destroyed (otherwise it is) */ long smsc2_rout(Msg *msg, int resend) { StatusInfo stat; SMSCConn *conn, *best_preferred, *best_ok; long bp_load, bo_load; int i, s, ret, bad_found, full_found; long max_queue, queue_length; char *uf; /* XXX handle ack here? */ if (msg_type(msg) != sms) { error(0, "Attempt to route non SMS message through smsc2_rout!"); return SMSCCONN_FAILED_DISCARDED; } /* check if validity period has expired */ if (msg->sms.validity != SMS_PARAM_UNDEFINED && time(NULL) > msg->sms.validity) { bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_EXPIRED, octstr_create("validity expired")); return SMSCCONN_FAILED_EXPIRED; } /* unify prefix of receiver, in case of it has not been * already done */ uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL; normalize_number(uf, &(msg->sms.receiver)); /* check for white/back-listed sender/receiver */ gw_rwlock_rdlock(&white_black_list_lock); if (white_list_sender && numhash_find_number(white_list_sender, msg->sms.sender) < 1) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is not in white-list-sender, message rejected", octstr_get_cstr(msg->sms.sender)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("sender not in white-list")); return SMSCCONN_FAILED_REJECTED; } if (white_list_sender_regex && gw_regex_match_pre(white_list_sender_regex, msg->sms.sender) == 0) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is not in white-list-sender, message rejected", octstr_get_cstr(msg->sms.sender)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("sender not in white-list")); return SMSCCONN_FAILED_REJECTED; } if (black_list_sender && numhash_find_number(black_list_sender, msg->sms.sender) == 1) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is in black-list-sender, message rejected", octstr_get_cstr(msg->sms.sender)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("sender in black-list")); return SMSCCONN_FAILED_REJECTED; } if (black_list_sender_regex && gw_regex_match_pre(black_list_sender_regex, msg->sms.sender) != 0) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is in black-list-sender, message rejected", octstr_get_cstr(msg->sms.sender)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("sender in black-list")); return SMSCCONN_FAILED_REJECTED; } if (white_list_receiver && numhash_find_number(white_list_receiver, msg->sms.receiver) < 1) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is not in white-list-receiver, message rejected", octstr_get_cstr(msg->sms.receiver)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("receiver not in white-list")); return SMSCCONN_FAILED_REJECTED; } if (white_list_receiver_regex && gw_regex_match_pre(white_list_receiver_regex, msg->sms.receiver) == 0) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is not in white-list-receiver, message rejected", octstr_get_cstr(msg->sms.receiver)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("receiver not in white-list")); return SMSCCONN_FAILED_REJECTED; } if (black_list_receiver && numhash_find_number(black_list_receiver, msg->sms.receiver) == 1) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is in black-list-receiver, message rejected", octstr_get_cstr(msg->sms.receiver)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("receiver in black-list")); return SMSCCONN_FAILED_REJECTED; } if (black_list_receiver_regex && gw_regex_match_pre(black_list_receiver_regex, msg->sms.receiver) != 0) { gw_rwlock_unlock(&white_black_list_lock); info(0, "Number <%s> is in black-list-receiver, message rejected", octstr_get_cstr(msg->sms.receiver)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_REJECTED, octstr_create("receiver in black-list")); return SMSCCONN_FAILED_REJECTED; } gw_rwlock_unlock(&white_black_list_lock); /* select in which list to add this * start - from random SMSCConn, as they are all 'equal' */ gw_rwlock_rdlock(&smsc_list_lock); if (gwlist_len(smsc_list) == 0) { warning(0, "No SMSCes to receive message"); gw_rwlock_unlock(&smsc_list_lock); return SMSCCONN_FAILED_DISCARDED; } best_preferred = best_ok = NULL; bad_found = full_found = 0; bp_load = bo_load = queue_length = 0; if (msg->sms.split_parts == NULL) { /* * if global queue not empty then 20% reserved for old msgs * and 80% for new msgs. So we can guarantee that old msgs find * place in the SMSC's queue. */ if (gwlist_len(outgoing_sms) > 0) { max_queue = (resend ? max_outgoing_sms_qlength : max_outgoing_sms_qlength * 0.8); } else max_queue = max_outgoing_sms_qlength; s = gw_rand() % gwlist_len(smsc_list); conn = NULL; for (i = 0; i < gwlist_len(smsc_list); i++) { conn = gwlist_get(smsc_list, (i+s) % gwlist_len(smsc_list)); smscconn_info(conn, &stat); queue_length += (stat.queued > 0 ? stat.queued : 0); ret = smscconn_usable(conn,msg); if (ret == -1) continue; /* if we already have a preferred one, skip non-preferred */ if (ret != 1 && best_preferred) continue; /* If connection is not currently answering ... */ if (stat.status != SMSCCONN_ACTIVE) { bad_found = 1; continue; } /* check queue length */ if (stat.queued > max_queue) { full_found = 1; continue; } if (ret == 1) { /* preferred */ if (best_preferred == NULL || stat.load < bp_load) { best_preferred = conn; bp_load = stat.load; continue; } } if (best_ok == NULL || stat.load < bo_load) { best_ok = conn; bo_load = stat.load; } } queue_length += gwlist_len(outgoing_sms); if (max_outgoing_sms_qlength > 0 && !resend && queue_length > gwlist_len(smsc_list) * max_outgoing_sms_qlength) { gw_rwlock_unlock(&smsc_list_lock); debug("bb.sms", 0, "sum(#queues) limit"); return SMSCCONN_FAILED_QFULL; } } else { struct split_parts *parts = msg->sms.split_parts; /* check whether this SMSCConn still on the list */ if (gwlist_search_equal(smsc_list, parts->smsc_conn) != -1) best_preferred = parts->smsc_conn; } if (best_preferred) ret = smscconn_send(best_preferred, msg); else if (best_ok) ret = smscconn_send(best_ok, msg); else if (bad_found) { gw_rwlock_unlock(&smsc_list_lock); if (max_outgoing_sms_qlength < 0 || gwlist_len(outgoing_sms) < max_outgoing_sms_qlength) { gwlist_produce(outgoing_sms, msg); return SMSCCONN_QUEUED; } debug("bb.sms", 0, "bad_found queue full"); return SMSCCONN_FAILED_QFULL; /* queue full */ } else if (full_found) { gw_rwlock_unlock(&smsc_list_lock); debug("bb.sms", 0, "full_found queue full"); return SMSCCONN_FAILED_QFULL; } else { gw_rwlock_unlock(&smsc_list_lock); if (bb_status == BB_SHUTDOWN) { msg_destroy(msg); return SMSCCONN_QUEUED; } warning(0, "Cannot find SMSCConn for message to <%s>, rejected.", octstr_get_cstr(msg->sms.receiver)); bb_smscconn_send_failed(NULL, msg_duplicate(msg), SMSCCONN_FAILED_DISCARDED, octstr_create("no SMSC")); return SMSCCONN_FAILED_DISCARDED; } gw_rwlock_unlock(&smsc_list_lock); /* check the status of sending operation */ if (ret == -1) return smsc2_rout(msg, resend); /* re-try */ msg_destroy(msg); return SMSCCONN_SUCCESS; } /* * Try to reroute to another smsc. * @return -1 if no rerouting info available; otherwise return code from smsc2_route. */ static long route_incoming_to_smsc(SMSCConn *conn, Msg *msg) { Octstr *smsc; /* sanity check */ if (!conn || !msg) return -1; /* check for dlr rerouting */ if (!conn->reroute_dlr && (msg->sms.sms_type == report_mo || msg->sms.sms_type == report_mt)) return -1; /* * Check if we have any "reroute" rules to obey. Which means msg gets * transported internally from MO to MT msg. */ if (conn->reroute) { /* change message direction */ store_save_ack(msg, ack_success); msg->sms.sms_type = mt_push; store_save(msg); /* drop into outbound queue again for routing */ return smsc2_rout(msg, 0); } if (conn->reroute_to_smsc) { /* change message direction */ store_save_ack(msg, ack_success); msg->sms.sms_type = mt_push; store_save(msg); /* apply directly to the given smsc-id for MT traffic */ octstr_destroy(msg->sms.smsc_id); msg->sms.smsc_id = octstr_duplicate(conn->reroute_to_smsc); return smsc2_rout(msg, 0); } if (conn->reroute_by_receiver && msg->sms.receiver && (smsc = dict_get(conn->reroute_by_receiver, msg->sms.receiver))) { /* change message direction */ store_save_ack(msg, ack_success); msg->sms.sms_type = mt_push; store_save(msg); /* route by receiver number */ /* XXX implement wildcard matching too! */ octstr_destroy(msg->sms.smsc_id); msg->sms.smsc_id = octstr_duplicate(smsc); return smsc2_rout(msg, 0); } return -1; } /*-------------------------------- * incoming concatenated messages handling */ typedef struct ConcatMsg { int refnum; int total_parts; int num_parts; Octstr *udh; /* normalized UDH */ time_t trecv; Octstr *key; /* in dict. */ int ack; /* set to the type of ack to send when deleting. */ /* array of parts */ Msg **parts; Octstr *smsc_id; /* name of smsc conn where we received this msgs */ } ConcatMsg; static Dict *incoming_concat_msgs; static Mutex *concat_lock; static void destroy_concatMsg(void *x) { int i; ConcatMsg *msg = x; gw_assert(msg); for (i = 0; i < msg->total_parts; i++) { if (msg->parts[i]) { store_save_ack(msg->parts[i], msg->ack); msg_destroy(msg->parts[i]); } } gw_free(msg->parts); octstr_destroy(msg->key); octstr_destroy(msg->udh); octstr_destroy(msg->smsc_id); gw_free(msg); } static void concat_handling_init(void) { if (incoming_concat_msgs != NULL) /* already initialised? */ return; incoming_concat_msgs = dict_create(max_incoming_sms_qlength > 0 ? max_incoming_sms_qlength : 1024, destroy_concatMsg); concat_lock = mutex_create(); debug("bb.sms",0,"MO concatenated message handling enabled"); } static void concat_handling_shutdown(void) { /* check if we were enabled at all? */ if (!handle_concatenated_mo) return; /* deactivate */ handle_concatenated_mo = 0; /* go through the queue and send messages as is */ concat_handling_clear_old_parts(1); } static void concat_handling_cleanup(void) { if (incoming_concat_msgs == NULL) return; dict_destroy(incoming_concat_msgs); mutex_destroy(concat_lock); incoming_concat_msgs = NULL; concat_lock = NULL; debug("bb.sms",0,"MO concatenated message handling cleaned up"); } static void concat_handling_clear_old_parts(int force) { List *keys; Octstr *key; /* not initialized, go away */ if (incoming_concat_msgs == NULL) return; debug("bb.sms.splits", 0, "clear_old_concat_parts called"); /* Remove any pending messages that are too old. */ keys = dict_keys(incoming_concat_msgs); while((key = gwlist_extract_first(keys)) != NULL) { ConcatMsg *x; Msg *msg; SMSCConn *conn; int i, destroy = 1, smsc_index; mutex_lock(concat_lock); x = dict_get(incoming_concat_msgs, key); octstr_destroy(key); if (x == NULL || (!force && difftime(time(NULL), x->trecv) < concatenated_mo_timeout)) { mutex_unlock(concat_lock); continue; } dict_remove(incoming_concat_msgs, x->key); mutex_unlock(concat_lock); /* try to find SMSCConn */ gw_rwlock_rdlock(&smsc_list_lock); /** * TODO handle cases where we goes down and have to clean concat parts for rerouting */ smsc_index = smsc2_find(x->smsc_id, 0); if (smsc_index != -1) { conn = gwlist_get(smsc_list, smsc_index); warning(0, "Time-out waiting for concatenated message '%s'. Send message parts as is.", octstr_get_cstr(x->key)); for (i = 0; i < x->total_parts && destroy == 1; i++) { if (x->parts[i] == NULL) continue; msg = msg_duplicate(x->parts[i]); switch(bb_smscconn_receive_internal(conn, msg)) { case SMSCCONN_FAILED_REJECTED: case SMSCCONN_QUEUED: case SMSCCONN_SUCCESS: msg_destroy(x->parts[i]); x->parts[i] = NULL; x->num_parts--; break; case SMSCCONN_FAILED_TEMPORARILY: case SMSCCONN_FAILED_QFULL: default: /* oops put it back into dict and retry on next run */ store_save(x->parts[i]); destroy = 0; break; } } } gw_rwlock_unlock(&smsc_list_lock); if (destroy) { destroy_concatMsg(x); } else { ConcatMsg *x1; mutex_lock(concat_lock); x1 = dict_get(incoming_concat_msgs, x->key); if (x1 != NULL) { /* oops we have new part */ int i; if (x->total_parts != x1->total_parts) { /* broken handset, don't know what todo here?? * for now just put old concatMsg into dict with * another key and it will be cleaned up on next run. */ octstr_format_append(x->key, " %d", x->total_parts); dict_put(incoming_concat_msgs, x->key, x); } else { for (i = 0; i < x->total_parts; i++) { if (x->parts[i] == NULL) continue; if (x1->parts[i] == NULL) { x1->parts[i] = x->parts[i]; x->parts[i] = NULL; } } destroy_concatMsg(x); } } else { dict_put(incoming_concat_msgs, x->key, x); } mutex_unlock(concat_lock); } } gwlist_destroy(keys, octstr_destroy_item); } /* Checks if message is concatenated. Returns: * - returns concat_complete if no concat parts, or message complete * - returns concat_pending (and sets *pmsg to NULL) if parts pending * - returns concat_error if store_save fails */ static int concat_handling_check_and_handle(Msg **pmsg, Octstr *smscid) { Msg *msg = *pmsg; int l, iel = 0, refnum, pos, c, part, totalparts, i, sixteenbit; Octstr *udh = msg->sms.udhdata, *key; ConcatMsg *cmsg; int ret = concat_complete; if (!handle_concatenated_mo) return concat_none; /* ... module not initialised or there is no UDH or smscid is NULL. */ if (incoming_concat_msgs == NULL || (l = octstr_len(udh)) == 0 || smscid == NULL) return concat_none; for (pos = 1, c = -1; pos < l - 1; pos += iel + 2) { iel = octstr_get_char(udh, pos + 1); if ((c = octstr_get_char(udh, pos)) == 0 || c == 8) break; } if (pos >= l) /* no concat UDH found. */ return concat_none; /* c = 0 means 8 bit, c = 8 means 16 bit concat info */ sixteenbit = (c == 8); refnum = (!sixteenbit) ? octstr_get_char(udh, pos + 2) : (octstr_get_char(udh, pos + 2) << 8) | octstr_get_char(udh, pos + 3); totalparts = octstr_get_char(udh, pos + 3 + sixteenbit); part = octstr_get_char(udh, pos + 4 + sixteenbit); if (part < 1 || part > totalparts) { warning(0, "Invalid concatenation UDH [ref = %d] in message from %s!", refnum, octstr_get_cstr(msg->sms.sender)); return concat_none; } /* extract UDH */ udh = octstr_duplicate(msg->sms.udhdata); octstr_delete(udh, pos, iel + 2); if (octstr_len(udh) <= 1) /* no other UDH elements. */ octstr_delete(udh, 0, octstr_len(udh)); else octstr_set_char(udh, 0, octstr_len(udh) - 1); debug("bb.sms.splits", 0, "Got part %d [ref %d, total parts %d] of message from %s. Dump follows:", part, refnum, totalparts, octstr_get_cstr(msg->sms.sender)); msg_dump(msg, 0); key = octstr_format("'%S' '%S' '%S' '%d' '%d' '%H'", msg->sms.sender, msg->sms.receiver, smscid, refnum, totalparts, udh); mutex_lock(concat_lock); if ((cmsg = dict_get(incoming_concat_msgs, key)) == NULL) { cmsg = gw_malloc(sizeof(*cmsg)); cmsg->refnum = refnum; cmsg->total_parts = totalparts; cmsg->udh = udh; udh = NULL; cmsg->num_parts = 0; cmsg->key = octstr_duplicate(key); cmsg->ack = ack_success; cmsg->smsc_id = octstr_duplicate(smscid); cmsg->parts = gw_malloc(totalparts * sizeof(*cmsg->parts)); memset(cmsg->parts, 0, cmsg->total_parts * sizeof(*cmsg->parts)); /* clear it. */ dict_put(incoming_concat_msgs, key, cmsg); } octstr_destroy(key); octstr_destroy(udh); /* check if we have seen message part before... */ if (cmsg->parts[part - 1] != NULL) { error(0, "Duplicate message part %d, ref %d, from %s, to %s. Discarded!", part, refnum, octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver)); store_save_ack(msg, ack_success); msg_destroy(msg); *pmsg = msg = NULL; mutex_unlock(concat_lock); return concat_pending; } else { cmsg->parts[part -1] = msg; cmsg->num_parts++; /* always update receive time so we have it from last part and don't timeout */ cmsg->trecv = time(NULL); } if (cmsg->num_parts < cmsg->total_parts) { /* wait for more parts. */ *pmsg = msg = NULL; mutex_unlock(concat_lock); return concat_pending; } /* we have all the parts: Put them together, modify UDH, return message. */ msg = msg_duplicate(cmsg->parts[0]); uuid_generate(msg->sms.id); /* give it a new ID. */ debug("bb.sms.splits",0,"Received all concatenated message parts from %s, to %s, refnum %d", octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver), refnum); for (i = 1; i < cmsg->total_parts; i++) octstr_append(msg->sms.msgdata, cmsg->parts[i]->sms.msgdata); /* Attempt to save the new one, if that fails, then reply with fail. */ if (store_save(msg) == -1) { mutex_unlock(concat_lock); msg_destroy(msg); *pmsg = msg = NULL; return concat_error; } else *pmsg = msg; /* return the message part. */ /* fix up UDH */ octstr_destroy(msg->sms.udhdata); msg->sms.udhdata = cmsg->udh; cmsg->udh = NULL; /* Delete it from the queue and from the Dict. */ /* Note: dict_put with NULL value delete and destroy value */ dict_put(incoming_concat_msgs, cmsg->key, NULL); mutex_unlock(concat_lock); debug("bb.sms.splits", 0, "Got full message [ref %d] of message from %s to %s. Dumping: ", refnum, octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver)); msg_dump(msg,0); return ret; } gateway-1.4.5/gw/smsbox.c0000644000175000017500000036610113227613126013772 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsbox.c - main program of the smsbox */ #include #include #include #include #include /* libxml & xpath things */ #include #include #include #include #include "gwlib/gwlib.h" #include "gwlib/regex.h" #include "gwlib/gw-timer.h" #include "msg.h" #include "sms.h" #include "dlr.h" #include "bb.h" #include "shared.h" #include "heartbeat.h" #include "html.h" #include "urltrans.h" #include "ota_prov_attr.h" #include "ota_prov.h" #include "ota_compiler.h" #include "xml_shared.h" #ifdef HAVE_SECURITY_PAM_APPL_H #include #endif #define SENDSMS_DEFAULT_CHARS "0123456789 +-" #define O_DESTROY(a) { if(a) octstr_destroy(a); a = NULL; } #define ACCOUNT_MAX_LEN 64 /* Defaults for the HTTP request queueing inside http_queue_thread */ #define HTTP_MAX_RETRIES 0 #define HTTP_RETRY_DELAY 10 /* in sec. */ #define HTTP_MAX_PENDING 512 /* max requests handled in parallel */ /* Timer item structure for HTTP retrying */ typedef struct TimerItem { Timer *timer; void *id; } TimerItem; /* have we received restart cmd from bearerbox? */ volatile sig_atomic_t restart = 0; static Cfg *cfg; static long bb_port; static int bb_ssl = 0; static long sendsms_port = 0; static Octstr *sendsms_interface = NULL; static Octstr *smsbox_id = NULL; static Octstr *sendsms_url = NULL; static Octstr *sendota_url = NULL; static Octstr *xmlrpc_url = NULL; static Octstr *bb_host; static Octstr *accepted_chars = NULL; static int only_try_http = 0; static URLTranslationList *translations = NULL; static long sms_max_length = MAX_SMS_OCTETS; static char *sendsms_number_chars; static Octstr *global_sender = NULL; static Octstr *reply_couldnotfetch = NULL; static Octstr *reply_couldnotrepresent = NULL; static Octstr *reply_requestfailed = NULL; static Octstr *reply_emptymessage = NULL; static int mo_recode = 0; static Numhash *white_list; static Numhash *black_list; static regex_t *white_list_regex = NULL; static regex_t *black_list_regex = NULL; static long max_http_retries = HTTP_MAX_RETRIES; static long http_queue_delay = HTTP_RETRY_DELAY; static Octstr *ppg_service_name = NULL; static List *smsbox_requests = NULL; /* the inbound request queue */ static List *smsbox_http_requests = NULL; /* the outbound HTTP request queue */ /* Timerset for the HTTP retry mechanism. */ static Timerset *timerset = NULL; /* Maximum requests that we handle in parallel */ static Semaphore *max_pending_requests; /* for delayed HTTP answers. * Dict key is uuid, value is HTTPClient pointer * of open transaction */ static int immediate_sendsms_reply = 0; static Dict *client_dict = NULL; static List *sendsms_reply_hdrs = NULL; /*********************************************************************** * Communication with the bearerbox. */ /* * Identify ourself to bearerbox for smsbox-specific routing inside bearerbox. * Do this even while no smsbox-id is given to unlock the sender thread in * bearerbox. */ static void identify_to_bearerbox(void) { Msg *msg; msg = msg_create(admin); msg->admin.command = cmd_identify; msg->admin.boxc_id = octstr_duplicate(smsbox_id); write_to_bearerbox(msg); } /* * Handle delayed reply to HTTP sendsms client, if any */ static void delayed_http_reply(Msg *msg) { HTTPClient *client; Octstr *os, *answer; char id[UUID_STR_LEN + 1]; int status; uuid_unparse(msg->ack.id, id); os = octstr_create(id); debug("sms.http", 0, "Got ACK (%ld) of %s", msg->ack.nack, octstr_get_cstr(os)); client = dict_remove(client_dict, os); if (client == NULL) { debug("sms.http", 0, "No client - multi-send or ACK to pull-reply"); octstr_destroy(os); return; } /* XXX this should be fixed so that we really wait for DLR * SMSC accept/deny before doing this - but that is far * more slower, a bit more complex, and is done later on */ switch (msg->ack.nack) { case ack_success: status = HTTP_ACCEPTED; answer = octstr_create("0: Accepted for delivery"); break; case ack_buffered: status = HTTP_ACCEPTED; answer = octstr_create("3: Queued for later delivery"); break; case ack_failed: status = HTTP_FORBIDDEN; answer = octstr_create("Not routable. Do not try again."); break; case ack_failed_tmp: status = HTTP_SERVICE_UNAVAILABLE; answer = octstr_create("Temporal failure, try again later."); break; default: error(0, "Strange reply from bearerbox!"); status = HTTP_SERVICE_UNAVAILABLE; answer = octstr_create("Temporal failure, try again later."); break; } http_send_reply(client, status, sendsms_reply_hdrs, answer); octstr_destroy(answer); octstr_destroy(os); } /* * Read an Msg from the bearerbox and send it to the proper receiver * via a List. At the moment all messages are sent to the smsbox_requests * List. */ static void read_messages_from_bearerbox(void) { time_t start, t; int secs; int total = 0; int ret; Msg *msg; start = t = time(NULL); while (program_status != shutting_down) { /* block infinite for reading messages */ ret = read_from_bearerbox(&msg, INFINITE_TIME); if (ret == -1) { if (program_status != shutting_down) { error(0, "Bearerbox is gone, restarting"); program_status = shutting_down; restart = 1; } break; } else if (ret == 1) /* timeout */ continue; else if (msg == NULL) /* just to be sure, may not happens */ break; if (msg_type(msg) == admin) { if (msg->admin.command == cmd_shutdown) { info(0, "Bearerbox told us to die"); program_status = shutting_down; } else if (msg->admin.command == cmd_restart) { info(0, "Bearerbox told us to restart"); restart = 1; program_status = shutting_down; } /* * XXXX here should be suspend/resume, add RSN */ msg_destroy(msg); } else if (msg_type(msg) == sms) { if (total == 0) start = time(NULL); total++; gwlist_produce(smsbox_requests, msg); } else if (msg_type(msg) == ack) { if (!immediate_sendsms_reply) delayed_http_reply(msg); msg_destroy(msg); } else { warning(0, "Received other message than sms/admin, ignoring!"); msg_destroy(msg); } } secs = difftime(time(NULL), start); info(0, "Received (and handled?) %d requests in %d seconds " "(%.2f per second)", total, secs, (float)total / secs); } /*********************************************************************** * Send Msg to bearerbox for delivery to phone, possibly split it first. */ /* * Counter for catenated SMS messages. The counter that can be put into * the catenated SMS message's UDH headers is actually the lowest 8 bits. */ static Counter *catenated_sms_counter; /* * Send a message to the bearerbox for delivery to a phone. Use * configuration from `trans' to format the message before sending. * Return >= 0 for success & count of splitted sms messages, * -1 for failure. Does not destroy the msg. */ static int send_message(URLTranslation *trans, Msg *msg) { int max_msgs; Octstr *header, *footer, *suffix, *split_chars; int catenate; unsigned long msg_sequence, msg_count; List *list; Msg *part; gw_assert(msg != NULL); gw_assert(msg_type(msg) == sms); if (trans != NULL) max_msgs = urltrans_max_messages(trans); else max_msgs = 1; if (max_msgs == 0) { info(0, "No reply sent, denied."); return 0; } /* * Encode our smsbox-id to the msg structure. * This will allow bearerbox to return specific answers to the * same smsbox, mainly for DLRs and SMS proxy modes. */ if (smsbox_id != NULL) { msg->sms.boxc_id = octstr_duplicate(smsbox_id); } /* * Empty message? Two alternatives have to be handled: * a) it's a HTTP sms-service reply: either ignore it or * substitute the "empty" warning defined * b) it's a sendsms HTTP interface call: leave the message empty */ if (octstr_len(msg->sms.msgdata) == 0 && msg->sms.sms_type == mt_reply) { if (trans != NULL && urltrans_omit_empty(trans)) return 0; else msg->sms.msgdata = octstr_duplicate(reply_emptymessage); } if (trans == NULL) { header = NULL; footer = NULL; suffix = NULL; split_chars = NULL; catenate = 0; } else { header = urltrans_header(trans); footer = urltrans_footer(trans); suffix = urltrans_split_suffix(trans); split_chars = urltrans_split_chars(trans); catenate = urltrans_concatenation(trans); /* * If there hasn't been yet any DLR-URL set in the message * and we have configured values from the URLTranslation, * hence the 'group = sms-service' context group, then use * them in the message. */ if (msg->sms.dlr_url == NULL && (msg->sms.dlr_url = octstr_duplicate(urltrans_dlr_url(trans))) != NULL) msg->sms.dlr_mask = urltrans_dlr_mask(trans); } if (catenate) msg_sequence = counter_increase(catenated_sms_counter) & 0xFF; else msg_sequence = 0; list = sms_split(msg, header, footer, suffix, split_chars, catenate, msg_sequence, max_msgs, sms_max_length); msg_count = gwlist_len(list); debug("sms", 0, "message length %ld, sending %ld messages", octstr_len(msg->sms.msgdata), msg_count); /* * In order to get catenated msgs work properly, we * have moved catenation to bearerbox. * So here we just need to put splitted msgs into one again and send * to bearerbox that will care about catenation. */ if (catenate) { Msg *new_msg = msg_duplicate(msg); octstr_delete(new_msg->sms.msgdata, 0, octstr_len(new_msg->sms.msgdata)); while((part = gwlist_extract_first(list)) != NULL) { octstr_append(new_msg->sms.msgdata, part->sms.msgdata); msg_destroy(part); } write_to_bearerbox(new_msg); } else { /* msgs are the independent parts so sent those as is */ while ((part = gwlist_extract_first(list)) != NULL) write_to_bearerbox(part); } gwlist_destroy(list, NULL); return msg_count; } /*********************************************************************** * Stuff to remember which receiver belongs to which HTTP query. * This also includes HTTP request data to queue a failed HTTP request * into the smsbox_http_request queue which is then handled by the * http_queue_thread thread on a re-scheduled time basis. */ static HTTPCaller *caller; static Counter *num_outstanding_requests; struct receiver { Msg *msg; URLTranslation *trans; int method; /* the HTTP method to use */ Octstr *url; /* the after pattern URL */ List *http_headers; Octstr *body; /* body content of the request */ unsigned long retries; /* number of performed retries */ }; /* * Again no urltranslation when we got an answer to wap push - it can only be dlr. */ static void *remember_receiver(Msg *msg, URLTranslation *trans, int method, Octstr *url, List *headers, Octstr *body, unsigned int retries) { struct receiver *receiver; counter_increase(num_outstanding_requests); receiver = gw_malloc(sizeof(*receiver)); receiver->msg = msg_create(sms); receiver->msg->sms.sender = octstr_duplicate(msg->sms.sender); receiver->msg->sms.receiver = octstr_duplicate(msg->sms.receiver); /* ppg_service_name should always be not NULL here */ if (trans != NULL && (msg->sms.service == NULL || ppg_service_name == NULL || octstr_compare(msg->sms.service, ppg_service_name) != 0)) { receiver->msg->sms.service = octstr_duplicate(urltrans_name(trans)); } else { receiver->msg->sms.service = octstr_duplicate(msg->sms.service); } receiver->msg->sms.smsc_id = octstr_duplicate(msg->sms.smsc_id); /* to remember if it's a DLR http get */ receiver->msg->sms.sms_type = msg->sms.sms_type; receiver->trans = trans; /* remember the HTTP request if we need to queue this */ receiver->method = method; receiver->url = octstr_duplicate(url); receiver->http_headers = http_header_duplicate(headers); receiver->body = octstr_duplicate(body); receiver->retries = retries; return receiver; } static void get_receiver(void *id, Msg **msg, URLTranslation **trans, int *method, Octstr **url, List **headers, Octstr **body, unsigned long *retries) { struct receiver *receiver; receiver = id; *msg = receiver->msg; *trans = receiver->trans; *method = receiver->method; *url = receiver->url; *headers = receiver->http_headers; *body = receiver->body; *retries = receiver->retries; gw_free(receiver); counter_decrease(num_outstanding_requests); } static long outstanding_requests(void) { return counter_value(num_outstanding_requests); } /*********************************************************************** * Thread for receiving reply from HTTP query and sending it to phone. */ static void strip_prefix_and_suffix(Octstr *html, Octstr *prefix, Octstr *suffix) { long prefix_end, suffix_start; if (prefix == NULL || suffix == NULL) return; prefix_end = octstr_case_search(html, prefix, 0); if (prefix_end == -1) return; prefix_end += octstr_len(prefix); suffix_start = octstr_case_search(html, suffix, prefix_end); if (suffix_start == -1) return; octstr_delete(html, 0, prefix_end); octstr_truncate(html, suffix_start - prefix_end); } static void get_x_kannel_from_headers(List *headers, Octstr **from, Octstr **to, Octstr **udh, Octstr **user, Octstr **pass, Octstr **smsc, int *mclass, int *mwi, int *coding, int *compress, int *validity, int *deferred, int *dlr_mask, Octstr **dlr_url, Octstr **account, int *pid, int *alt_dcs, int *rpi, Octstr **binfo, int *priority, Octstr **meta_data) { Octstr *name, *val; long l; for(l=0; l value and * type to text/plain */ static void get_x_kannel_from_xml(int requesttype , Octstr **type, Octstr **body, List *headers, Octstr **from, Octstr **to, Octstr **udh, Octstr **user, Octstr **pass, Octstr **smsc, int *mclass, int *mwi, int *coding, int *compress, int *validity, int *deferred, int *dlr_mask, Octstr **dlr_url, Octstr **account, int *pid, int *alt_dcs, int *rpi, List **tolist, Octstr **charset, Octstr **binfo, int *priority, Octstr **meta_data) { xmlDocPtr doc = NULL; xmlXPathContextPtr xpathCtx = NULL; xmlXPathObjectPtr xpathObj = NULL; xmlChar *xml_string; Octstr *text = NULL, *tmp = NULL; if (*body == NULL) return; debug("sms", 0, "XMLParsing: XML: <%s>", octstr_get_cstr(*body)); /* ok, start parsing */ doc = xmlParseMemory(octstr_get_cstr(*body), octstr_len(*body)); if (doc == NULL) { error(0, "XMLParsing: Could not parse xmldoc: <%s>", octstr_get_cstr(*body)); return; } xpathCtx = xmlXPathNewContext(doc); if (xpathCtx == NULL) { error(0, "XMLParsing: Could not create xpath context."); xmlFreeDoc(doc); return; } #define XPATH_SEARCH_OCTSTR(path, var, nostrip) \ do { \ xpathObj = xmlXPathEvalExpression(BAD_CAST path, xpathCtx); \ if (xpathObj != NULL && !xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) { \ xml_string = xmlXPathCastToString(xpathObj); \ O_DESTROY(var); \ var = octstr_create((const char*) xml_string); \ if(nostrip == 0) \ octstr_strip_blanks(var); \ xmlFree(xml_string); \ } \ if (xpathObj != NULL) xmlXPathFreeObject(xpathObj); \ } while(0) #define XPATH_SEARCH_NUMBER(path, var) \ do { \ xpathObj = xmlXPathEvalExpression(BAD_CAST path, xpathCtx); \ if (xpathObj != NULL && !xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) { \ var = xmlXPathCastToNumber(xpathObj); \ } \ if (xpathObj != NULL) xmlXPathFreeObject(xpathObj); \ } while(0) /* auth */ xpathObj = xmlXPathEvalExpression(BAD_CAST "/message/submit/from", xpathCtx); if (xpathObj != NULL && !xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) { xmlXPathFreeObject(xpathObj); if(requesttype == mt_push) { /* user */ XPATH_SEARCH_OCTSTR("/message/submit/from/user", *user, 0); XPATH_SEARCH_OCTSTR("/message/submit/from/username", *user, 0); /* pass */ XPATH_SEARCH_OCTSTR("/message/submit/from/pass", *pass, 0); XPATH_SEARCH_OCTSTR("/message/submit/from/password", *pass, 0); } /* account */ XPATH_SEARCH_OCTSTR("/message/submit/from/account", *account, 0); /* binfo */ XPATH_SEARCH_OCTSTR("/message/submit/from/binfo", *binfo, 0); } XPATH_SEARCH_OCTSTR("/message/submit/oa/number", *from, 0); /* to (da/number) Multiple tags */ xpathObj = xmlXPathEvalExpression(BAD_CAST "/message/submit/da/number/text()", xpathCtx); if (xpathObj != NULL && !xmlXPathNodeSetIsEmpty(xpathObj->nodesetval)) { int i; *tolist = gwlist_create(); for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) { if (xpathObj->nodesetval->nodeTab[i]->type != XML_TEXT_NODE) continue; xml_string = xmlXPathCastNodeToString(xpathObj->nodesetval->nodeTab[i]); tmp = octstr_create((const char*) xpathObj->nodesetval->nodeTab[i]->content); xmlFree(xml_string); octstr_strip_blanks(tmp); gwlist_append(*tolist, tmp); } } if (xpathObj != NULL) xmlXPathFreeObject(xpathObj); /* udh */ XPATH_SEARCH_OCTSTR("/message/submit/udh", *udh, 0); if(*udh != NULL && octstr_hex_to_binary(*udh) == -1) octstr_url_decode(*udh); /* smsc */ XPATH_SEARCH_OCTSTR("/message/submit/smsc", *smsc, 0); if (*smsc == NULL) XPATH_SEARCH_OCTSTR("/message/submit/to", *smsc, 0); /* pid */ XPATH_SEARCH_NUMBER("/message/submit/pid", *pid); /* rpi */ XPATH_SEARCH_NUMBER("/message/submit/rpi", *rpi); /* dcs* (dcs/ *) */ /* mclass (dcs/mclass) */ XPATH_SEARCH_NUMBER("/message/submit/dcs/mclass", *mclass); /* mwi (dcs/mwi) */ XPATH_SEARCH_NUMBER("/message/submit/dcs/mwi", *mwi); /* coding (dcs/coding) */ XPATH_SEARCH_NUMBER("/message/submit/dcs/coding", *coding); /* compress (dcs/compress) */ XPATH_SEARCH_NUMBER("/message/submit/dcs/compress", *compress); /* alt-dcs (dcs/alt-dcs) */ XPATH_SEARCH_NUMBER("/message/submit/dcs/alt-dcs", *alt_dcs); /* statusrequest* (statusrequest/ *) */ /* dlr-mask (statusrequest/dlr-mask) */ XPATH_SEARCH_NUMBER("/message/submit/statusrequest/dlr-mask", *dlr_mask); /* dlr-url */ XPATH_SEARCH_OCTSTR("/message/submit/statusrequest/dlr-url", *dlr_url, 0); /* validity (vp/delay) */ XPATH_SEARCH_NUMBER("/message/submit/vp/delay", *validity); /* deferred (timing/delay) */ XPATH_SEARCH_NUMBER("/message/submit/timing/delay", *deferred); /* priority */ XPATH_SEARCH_NUMBER("/message/submit/priority", *priority); /* meta_data */ XPATH_SEARCH_OCTSTR("/message/submit/meta-data", *meta_data, 0); /* charset from */ O_DESTROY(*charset); if (doc->encoding != NULL) *charset = octstr_create((const char*) doc->encoding); else *charset = octstr_create("UTF-8"); /* text */ /* first try to receive type, default text */ tmp = NULL; XPATH_SEARCH_OCTSTR("/message/submit/ud/@type", tmp, 0); /* now receive message body */ XPATH_SEARCH_OCTSTR("/message/submit/ud", text, 0); if (text != NULL) { if (tmp != NULL && octstr_str_case_compare(tmp, "binary") == 0) octstr_hex_to_binary(text); else octstr_url_decode(text); } octstr_destroy(tmp); octstr_truncate(*body, 0); if(text != NULL) { octstr_append(*body, text); octstr_destroy(text); } O_DESTROY(*type); *type = octstr_create("text/plain"); if (xpathCtx != NULL) xmlXPathFreeContext(xpathCtx); if (doc != NULL) xmlFreeDoc(doc); } static void fill_message(Msg *msg, URLTranslation *trans, Octstr *replytext, Octstr *from, Octstr *to, Octstr *udh, int mclass, int mwi, int coding, int compress, int validity, int deferred, Octstr *dlr_url, int dlr_mask, int pid, int alt_dcs, int rpi, Octstr *smsc, Octstr *account, Octstr *charset, Octstr *binfo, int priority, Octstr *meta_data) { msg->sms.msgdata = replytext; msg->sms.time = time(NULL); if (charset) msg->sms.charset = charset; if (dlr_url != NULL) { if (urltrans_accept_x_kannel_headers(trans)) { octstr_destroy(msg->sms.dlr_url); msg->sms.dlr_url = dlr_url; } else { warning(0, "Tried to change dlr_url to '%s', denied.", octstr_get_cstr(dlr_url)); octstr_destroy(dlr_url); } } if (smsc != NULL) { if (urltrans_accept_x_kannel_headers(trans)) { octstr_destroy(msg->sms.smsc_id); msg->sms.smsc_id = smsc; } else { warning(0, "Tried to change SMSC to '%s', denied.", octstr_get_cstr(smsc)); octstr_destroy(smsc); } } if (from != NULL) { if (urltrans_accept_x_kannel_headers(trans)) { octstr_destroy(msg->sms.sender); msg->sms.sender = from; } else { warning(0, "Tried to change sender to '%s', denied.", octstr_get_cstr(from)); octstr_destroy(from); } } if (to != NULL) { if (urltrans_accept_x_kannel_headers(trans)) { octstr_destroy(msg->sms.receiver); msg->sms.receiver = to; } else { warning(0, "Tried to change receiver to '%s', denied.", octstr_get_cstr(to)); octstr_destroy(to); } } if (udh != NULL) { if (urltrans_accept_x_kannel_headers(trans)) { octstr_destroy(msg->sms.udhdata); msg->sms.udhdata = udh; } else { warning(0, "Tried to set UDH field, denied."); O_DESTROY(udh); } } if (mclass != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.mclass = mclass; else warning(0, "Tried to set MClass field, denied."); } if (pid != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.pid = pid; else warning(0, "Tried to set PID field, denied."); } if (rpi != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.rpi = rpi; else warning(0, "Tried to set RPI field, denied."); } if (alt_dcs != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.alt_dcs = alt_dcs; else warning(0, "Tried to set Alt-DCS field, denied."); } if (mwi != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.mwi = mwi; else warning(0, "Tried to set MWI field, denied."); } if (coding != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.coding = coding; else warning(0, "Tried to set Coding field, denied."); } if (compress != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.compress = compress; else warning(0, "Tried to set Compress field, denied."); } /* Compatibility Mode */ if (msg->sms.coding == DC_UNDEF) { if(octstr_len(udh)) msg->sms.coding = DC_8BIT; else msg->sms.coding = DC_7BIT; } if (validity != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.validity = validity * 60 + time(NULL); else warning(0, "Tried to change validity to '%d', denied.", validity); } if (deferred != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.deferred = deferred * 60 + time(NULL); else warning(0, "Tried to change deferred to '%d', denied.", deferred); } if (dlr_mask != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) { msg->sms.dlr_mask = dlr_mask; } else warning(0, "Tried to change dlr_mask to '%d', denied.", dlr_mask); } if (account) { if (urltrans_accept_x_kannel_headers(trans)) { msg->sms.account = account; } else { warning(0, "Tried to change account to '%s', denied.", octstr_get_cstr(account)); octstr_destroy(account); } } if (binfo) { if (urltrans_accept_x_kannel_headers(trans)) { msg->sms.binfo = binfo; } else { warning(0, "Tried to change billing info to '%s', denied.", octstr_get_cstr(binfo)); octstr_destroy(binfo); } } if (priority != SMS_PARAM_UNDEFINED) { if (urltrans_accept_x_kannel_headers(trans)) msg->sms.priority = priority; else warning(0, "Tried to change priority to '%d', denied.", priority); } if (meta_data != NULL) { if (urltrans_accept_x_kannel_headers(trans)) { octstr_destroy(msg->sms.meta_data); msg->sms.meta_data = meta_data; } else { warning(0, "Tried to set Meta-Data field, denied."); octstr_destroy(meta_data); } } } /*********************************************************************** * Thread to handle failed HTTP requests and retries to deliver the * information to the HTTP server. The thread uses the smsbox_http_requests * queue that is spooled by url_result_thread in case the HTTP requests * fails. */ static void http_queue_thread(void *arg) { void *id; Msg *msg; URLTranslation *trans; Octstr *req_url; List *req_headers; Octstr *req_body; unsigned long retries; int method; TimerItem *i; while ((i = gwlist_consume(smsbox_http_requests)) != NULL) { /* * The timer thread has injected the item to retry the * HTTP call again now. */ debug("sms.http",0,"HTTP: Queue contains %ld outstanding requests", gwlist_len(smsbox_http_requests)); /* * Get all required HTTP request data from the queue and reconstruct * the id pointer for later lookup in url_result_thread. */ get_receiver(i->id, &msg, &trans, &method, &req_url, &req_headers, &req_body, &retries); gw_timer_elapsed_destroy(i->timer); gw_free(i); if (retries < max_http_retries) { id = remember_receiver(msg, trans, method, req_url, req_headers, req_body, ++retries); debug("sms.http",0,"HTTP: Retrying request <%s> (%ld/%ld)", octstr_get_cstr(req_url), retries, max_http_retries); /* re-queue this request to the HTTPCaller list */ http_start_request(caller, method, req_url, req_headers, req_body, 1, id, NULL); } msg_destroy(msg); octstr_destroy(req_url); http_destroy_headers(req_headers); octstr_destroy(req_body); } } static void url_result_thread(void *arg) { Octstr *final_url, *req_body, *type, *replytext; List *reply_headers; int status, method; void *id; Msg *msg; URLTranslation *trans; Octstr *req_url; List *req_headers; Octstr *text_html, *text_plain, *text_wml, *text_xml; Octstr *octet_stream; unsigned long retries; unsigned int queued; /* indicate if processes reply is re-queued */ TimerItem *item; Octstr *reply_body, *charset, *alt_charset; Octstr *udh, *from, *to, *dlr_url, *account, *smsc, *binfo, *meta_data; int dlr_mask, mclass, mwi, coding, compress, pid, alt_dcs, rpi; int validity, deferred, priority; text_html = octstr_imm("text/html"); text_wml = octstr_imm("text/vnd.wap.wml"); text_plain = octstr_imm("text/plain"); text_xml = octstr_imm("text/xml"); octet_stream = octstr_imm("application/octet-stream"); for (;;) { queued = 0; id = http_receive_result(caller, &status, &final_url, &reply_headers, &reply_body); semaphore_up(max_pending_requests); if (id == NULL) break; from = to = udh = smsc = dlr_url = account = binfo = charset = alt_charset = meta_data = NULL; mclass = mwi = compress = pid = alt_dcs = rpi = dlr_mask = validity = deferred = priority = SMS_PARAM_UNDEFINED; coding = DC_7BIT; get_receiver(id, &msg, &trans, &method, &req_url, &req_headers, &req_body, &retries); if (status == HTTP_OK || status == HTTP_ACCEPTED) { if (msg->sms.sms_type == report_mo) { /* we are done */ goto requeued; } http_header_get_content_type(reply_headers, &type, &charset); if (octstr_case_compare(type, text_html) == 0 || octstr_case_compare(type, text_wml) == 0) { if (trans != NULL) strip_prefix_and_suffix(reply_body, urltrans_prefix(trans), urltrans_suffix(trans)); replytext = html_to_sms(reply_body); octstr_strip_blanks(replytext); get_x_kannel_from_headers(reply_headers, &from, &to, &udh, NULL, NULL, &smsc, &mclass, &mwi, &coding, &compress, &validity, &deferred, &dlr_mask, &dlr_url, &account, &pid, &alt_dcs, &rpi, &binfo, &priority, &meta_data); } else if (octstr_case_compare(type, text_plain) == 0) { replytext = octstr_duplicate(reply_body); octstr_destroy(reply_body); reply_body = NULL; get_x_kannel_from_headers(reply_headers, &from, &to, &udh, NULL, NULL, &smsc, &mclass, &mwi, &coding, &compress, &validity, &deferred, &dlr_mask, &dlr_url, &account, &pid, &alt_dcs, &rpi, &binfo, &priority, &meta_data); } else if (octstr_case_compare(type, text_xml) == 0) { replytext = octstr_duplicate(reply_body); octstr_destroy(reply_body); reply_body = NULL; get_x_kannel_from_xml(mt_reply, &type, &replytext, reply_headers, &from, &to, &udh, NULL, NULL, &smsc, &mclass, &mwi, &coding, &compress, &validity, &deferred, &dlr_mask, &dlr_url, &account, &pid, &alt_dcs, &rpi, NULL, &charset, &binfo, &priority, &meta_data); } else if (octstr_case_compare(type, octet_stream) == 0) { replytext = octstr_duplicate(reply_body); octstr_destroy(reply_body); coding = DC_8BIT; reply_body = NULL; get_x_kannel_from_headers(reply_headers, &from, &to, &udh, NULL, NULL, &smsc, &mclass, &mwi, &coding, &compress, &validity, &deferred, &dlr_mask, &dlr_url, &account, &pid, &alt_dcs, &rpi, &binfo, &priority, &meta_data); } else { replytext = octstr_duplicate(reply_couldnotrepresent); } /* * If there was a charset specified in the HTTP response, * we're not going to touch the encoding. Otherwise check if * we have a defined alt-charset for this sms-service. */ if (octstr_len(charset) == 0 && (alt_charset = urltrans_alt_charset(trans)) != NULL) { octstr_destroy(charset); charset = octstr_duplicate(alt_charset); } /* * Ensure now that we transcode to our internal encoding. */ if (sms_charset_processing(charset, replytext, coding) == -1) { replytext = octstr_duplicate(reply_couldnotrepresent); } octstr_destroy(type); } else if (max_http_retries > retries) { item = gw_malloc(sizeof(TimerItem)); item->timer = gw_timer_create(timerset, smsbox_http_requests, NULL); item->id = remember_receiver(msg, trans, method, req_url, req_headers, req_body, retries); gw_timer_elapsed_start(item->timer, http_queue_delay, item); queued++; goto requeued; } else replytext = octstr_duplicate(reply_couldnotfetch); if (final_url == NULL) final_url = octstr_imm(""); if (reply_body == NULL) reply_body = octstr_imm(""); if (msg->sms.sms_type != report_mo) { fill_message(msg, trans, replytext, from, to, udh, mclass, mwi, coding, compress, validity, deferred, dlr_url, dlr_mask, pid, alt_dcs, rpi, smsc, account, charset, binfo, priority, meta_data); alog("SMS HTTP-request sender:%s request: '%s' url: '%s' reply: %d '%s'", octstr_get_cstr(msg->sms.receiver), (msg->sms.msgdata != NULL) ? octstr_get_cstr(msg->sms.msgdata) : "", octstr_get_cstr(final_url), status, (status == HTTP_OK) ? "<< successful >>" : octstr_get_cstr(reply_body)); } else { octstr_destroy(replytext); } requeued: octstr_destroy(final_url); http_destroy_headers(reply_headers); octstr_destroy(reply_body); octstr_destroy(req_url); http_destroy_headers(req_headers); octstr_destroy(req_body); if (msg->sms.sms_type != report_mo && !queued) { if (send_message(trans, msg) < 0) error(0, "failed to send message to phone"); } msg_destroy(msg); } } /*********************************************************************** * Thread to receive SMS messages from bearerbox and obeying the requests * in them. HTTP requests are started in the background (another thread * will deal with the replies) and other requests are fulfilled directly. */ /* * Perform the service requested by the user: translate the request into * a pattern, if it is an URL, start its fetch and return 0, otherwise * return the string in `*result' and return 1. Return -1 for errors. * If we are translating url for ppg dlr, we do not use trans data * structure defined for sms services. This is indicated by trans = NULL. */ static int obey_request(Octstr **result, URLTranslation *trans, Msg *msg) { Octstr *pattern, *xml, *tmp; List *request_headers; void *id; struct tm tm; char p[22]; int type; FILE *f; gw_assert(msg != NULL); gw_assert(msg_type(msg) == sms); if (msg->sms.sms_type == report_mo) type = TRANSTYPE_GET_URL; else type = urltrans_type(trans); pattern = urltrans_get_pattern(trans, msg); gw_assert(pattern != NULL); switch (type) { case TRANSTYPE_TEXT: debug("sms", 0, "formatted text answer: <%s>", octstr_get_cstr(pattern)); *result = pattern; alog("SMS request sender:%s request: '%s' fixed answer: '%s'", octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.msgdata), octstr_get_cstr(pattern)); break; case TRANSTYPE_FILE: *result = octstr_read_file(octstr_get_cstr(pattern)); octstr_destroy(pattern); alog("SMS request sender:%s request: '%s' file answer: '%s'", octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.msgdata), octstr_get_cstr(*result)); break; case TRANSTYPE_EXECUTE: semaphore_down(max_pending_requests); debug("sms.exec", 0, "executing sms-service '%s'", octstr_get_cstr(pattern)); if ((f = popen(octstr_get_cstr(pattern), "r")) != NULL) { octstr_destroy(pattern); *result = octstr_read_pipe(f); pclose(f); semaphore_up(max_pending_requests); alog("SMS request sender:%s request: '%s' file answer: '%s'", octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.msgdata), octstr_get_cstr(*result)); } else { error(0, "popen failed for '%s': %d: %s", octstr_get_cstr(pattern), errno, strerror(errno)); *result = NULL; octstr_destroy(pattern); return -1; } break; /* * No Kannel headers when we are sending dlrs to wap push */ case TRANSTYPE_GET_URL: request_headers = http_create_empty_headers(); http_header_add(request_headers, "User-Agent", GW_NAME "/" GW_VERSION); if (trans != NULL) { if (urltrans_send_sender(trans)) { http_header_add(request_headers, "X-Kannel-From", octstr_get_cstr(msg->sms.receiver)); } } id = remember_receiver(msg, trans, HTTP_METHOD_GET, pattern, request_headers, NULL, 0); semaphore_down(max_pending_requests); http_start_request(caller, HTTP_METHOD_GET, pattern, request_headers, NULL, 1, id, NULL); octstr_destroy(pattern); http_destroy_headers(request_headers); *result = NULL; return 0; break; case TRANSTYPE_POST_URL: request_headers = http_create_empty_headers(); http_header_add(request_headers, "User-Agent", GW_NAME "/" GW_VERSION); if (msg->sms.coding == DC_8BIT) http_header_add(request_headers, "Content-Type", "application/octet-stream"); else if(msg->sms.coding == DC_UCS2) http_header_add(request_headers, "Content-Type", "text/plain; charset=\"UTF-16BE\""); else { Octstr *header; header = octstr_create("text/plain"); if (msg->sms.charset) { octstr_append(header, octstr_imm("; charset=\"")); octstr_append(header, msg->sms.charset); octstr_append(header, octstr_imm("\"")); } else { octstr_append(header, octstr_imm("; charset=\"UTF-8\"")); } http_header_add(request_headers, "Content-Type", octstr_get_cstr(header)); O_DESTROY(header); } if (urltrans_send_sender(trans)) http_header_add(request_headers, "X-Kannel-From", octstr_get_cstr(msg->sms.receiver)); http_header_add(request_headers, "X-Kannel-To", octstr_get_cstr(msg->sms.sender)); tm = gw_gmtime(msg->sms.time); sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); http_header_add(request_headers, "X-Kannel-Time", p); tm = gw_gmtime(time(NULL)); sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); http_header_add(request_headers, "Date", p); /* HTTP RFC 14.18 */ if (octstr_len(msg->sms.udhdata)) { Octstr *os; os = octstr_duplicate(msg->sms.udhdata); octstr_url_encode(os); http_header_add(request_headers, "X-Kannel-UDH", octstr_get_cstr(os)); octstr_destroy(os); } if (octstr_len(msg->sms.smsc_id)) { Octstr *os; os = octstr_duplicate(msg->sms.smsc_id); http_header_add(request_headers, "X-Kannel-SMSC", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.mclass != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d",msg->sms.mclass); http_header_add(request_headers, "X-Kannel-MClass", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.pid != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d",msg->sms.pid); http_header_add(request_headers, "X-Kannel-PID", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.rpi != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d",msg->sms.rpi); http_header_add(request_headers, "X-Kannel-RPI", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.alt_dcs != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d",msg->sms.alt_dcs); http_header_add(request_headers, "X-Kannel-Alt-DCS", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.mwi != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d",msg->sms.mwi); http_header_add(request_headers, "X-Kannel-MWI", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.coding != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d",msg->sms.coding); http_header_add(request_headers, "X-Kannel-Coding", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.compress != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d",msg->sms.compress); http_header_add(request_headers, "X-Kannel-Compress", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.validity != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d", (msg->sms.validity - time(NULL)) / 60); http_header_add(request_headers, "X-Kannel-Validity", octstr_get_cstr(os)); octstr_destroy(os); } if (msg->sms.deferred != SMS_PARAM_UNDEFINED) { Octstr *os; os = octstr_format("%d", (msg->sms.deferred - time(NULL)) / 60); http_header_add(request_headers, "X-Kannel-Deferred", octstr_get_cstr(os)); octstr_destroy(os); } if (octstr_len(msg->sms.service)) { http_header_add(request_headers, "X-Kannel-Service", octstr_get_cstr(msg->sms.service)); } if (octstr_len(msg->sms.binfo)) { http_header_add(request_headers, "X-Kannel-BInfo", octstr_get_cstr(msg->sms.binfo)); } if (octstr_len(msg->sms.meta_data)) { http_header_add(request_headers, "X-Kannel-Meta-Data", octstr_get_cstr(msg->sms.meta_data)); } id = remember_receiver(msg, trans, HTTP_METHOD_POST, pattern, request_headers, msg->sms.msgdata, 0); semaphore_down(max_pending_requests); http_start_request(caller, HTTP_METHOD_POST, pattern, request_headers, msg->sms.msgdata, 1, id, NULL); octstr_destroy(pattern); http_destroy_headers(request_headers); *result = NULL; return 0; break; case TRANSTYPE_POST_XML: /* XXX The first two chars are beeing eaten somewhere and * only sometimes - something must be ungry */ #define OCTSTR_APPEND_XML(xml, tag, text) \ octstr_format_append(xml, " \t\t<" tag ">%s\n", (text?octstr_get_cstr(text):"")) #define OCTSTR_APPEND_XML_OCTSTR(xml, tag, text) \ do { \ xmlDocPtr tmp_doc = xmlNewDoc(BAD_CAST "1.0"); \ xmlChar *xml_escaped = NULL; \ if (text != NULL) xml_escaped = xmlEncodeEntitiesReentrant(tmp_doc, BAD_CAST octstr_get_cstr(text)); \ octstr_format_append(xml, " \t\t<" tag ">%s\n", (xml_escaped != NULL ? (char*)xml_escaped : "")); \ if (xml_escaped != NULL) xmlFree(xml_escaped); \ xmlFreeDoc(tmp_doc); \ } while(0) #define OCTSTR_APPEND_XML_NUMBER(xml, tag, value) \ octstr_format_append(xml, " \t\t<" tag ">%ld\n", (long) value) request_headers = http_create_empty_headers(); http_header_add(request_headers, "User-Agent", GW_NAME "/" GW_VERSION); if (msg->sms.coding == DC_UCS2) { http_header_add(request_headers, "Content-Type", "text/xml; charset=\"ISO-8859-1\""); /* for account and other strings */ } else { Octstr *header; header = octstr_create("text/xml"); if(msg->sms.charset) { octstr_append(header, octstr_imm("; charset=\"")); octstr_append(header, msg->sms.charset); octstr_append(header, octstr_imm("\"")); } http_header_add(request_headers, "Content-Type", octstr_get_cstr(header)); O_DESTROY(header); } tm = gw_gmtime(time(NULL)); sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); http_header_add(request_headers, "Date", p); /* HTTP RFC 14.18 */ xml = octstr_create(""); octstr_append(xml, octstr_imm("sms.coding == DC_UCS2 || msg->sms.charset == NULL) octstr_append(xml, octstr_imm("ISO-8859-1")); else octstr_append(xml, msg->sms.charset); octstr_append(xml, octstr_imm("\"?>\n")); /* * XXX damn windows that breaks with this : * octstr_append(xml, octstr_imm("\n")); */ octstr_append(xml, octstr_imm("\n")); octstr_append(xml, octstr_imm("\t\n")); /* oa */ if (urltrans_send_sender(trans)) { tmp = octstr_create(""); OCTSTR_APPEND_XML_OCTSTR(tmp, "number", msg->sms.receiver); OCTSTR_APPEND_XML(xml, "oa", tmp); octstr_destroy(tmp); } /* da */ tmp = octstr_create(""); OCTSTR_APPEND_XML_OCTSTR(tmp, "number", msg->sms.sender); OCTSTR_APPEND_XML(xml, "da", tmp); octstr_destroy(tmp); /* udh */ if (octstr_len(msg->sms.udhdata)) { Octstr *t; t = octstr_duplicate(msg->sms.udhdata); octstr_url_encode(t); OCTSTR_APPEND_XML_OCTSTR(xml, "udh", t); octstr_destroy(t); } /* ud */ if (octstr_len(msg->sms.msgdata)) { octstr_url_encode(msg->sms.msgdata); OCTSTR_APPEND_XML_OCTSTR(xml, "ud", msg->sms.msgdata); } /* pid */ if (msg->sms.pid != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(xml, "pid", msg->sms.pid); /* rpi */ if (msg->sms.rpi != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(xml, "rpi", msg->sms.rpi); /* dcs */ tmp = octstr_create(""); if (msg->sms.coding != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(tmp, "coding", msg->sms.coding); if (msg->sms.mclass != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(tmp, "mclass", msg->sms.mclass); if (msg->sms.alt_dcs != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(tmp, "alt-dcs", msg->sms.alt_dcs); if (msg->sms.mwi != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(tmp, "mwi", msg->sms.mwi); if (msg->sms.compress != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(tmp, "compress", msg->sms.compress); if (octstr_len(tmp)) OCTSTR_APPEND_XML(xml, "dcs", tmp); octstr_destroy(tmp); /* deferred (timing/delay) */ tmp = octstr_create(""); if(msg->sms.deferred != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(tmp, "delay", (msg->sms.deferred - time(NULL)) / 60); if(octstr_len(tmp)) OCTSTR_APPEND_XML(xml, "timing", tmp); octstr_destroy(tmp); /* validity (vp/delay) */ tmp = octstr_create(""); if(msg->sms.validity != SMS_PARAM_UNDEFINED) OCTSTR_APPEND_XML_NUMBER(tmp, "delay", (msg->sms.validity - time(NULL)) / 60); if(octstr_len(tmp)) OCTSTR_APPEND_XML(xml, "vp", tmp); octstr_destroy(tmp); /* time (at) */ tm = gw_gmtime(msg->sms.time); tmp = octstr_format("%04d%02d" "%02d%02d%02d" "%02d0", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); OCTSTR_APPEND_XML(xml, "at", tmp); octstr_destroy(tmp); /* smsc */ if (octstr_len(msg->sms.smsc_id)) { tmp = octstr_create(""); if (octstr_len(msg->sms.smsc_id)) OCTSTR_APPEND_XML_OCTSTR(tmp, "account", msg->sms.smsc_id); if (octstr_len(tmp)) OCTSTR_APPEND_XML(xml, "from", tmp); O_DESTROY(tmp); } /* service = to/service */ if (octstr_len(msg->sms.service)) { tmp = octstr_create(""); OCTSTR_APPEND_XML_OCTSTR(tmp, "service", msg->sms.service); if (octstr_len(tmp)) OCTSTR_APPEND_XML(xml, "to", tmp); O_DESTROY(tmp); } /* meta_data */ if (octstr_len(msg->sms.meta_data)) { OCTSTR_APPEND_XML_OCTSTR(xml, "meta-data", msg->sms.meta_data); } /* End XML */ octstr_append(xml, octstr_imm("\t\n")); octstr_append(xml, octstr_imm("\n")); if (msg->sms.msgdata != NULL) octstr_destroy(msg->sms.msgdata); msg->sms.msgdata = xml; debug("sms", 0, "XMLBuild: XML: <%s>", octstr_get_cstr(msg->sms.msgdata)); id = remember_receiver(msg, trans, HTTP_METHOD_POST, pattern, request_headers, msg->sms.msgdata, 0); semaphore_down(max_pending_requests); http_start_request(caller, HTTP_METHOD_POST, pattern, request_headers, msg->sms.msgdata, 1, id, NULL); octstr_destroy(pattern); http_destroy_headers(request_headers); *result = NULL; return 0; break; case TRANSTYPE_SENDSMS: error(0, "Got URL translation type SENDSMS for incoming message."); alog("SMS request sender:%s request: '%s' FAILED bad translation", octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.msgdata)); octstr_destroy(pattern); return -1; break; default: error(0, "Unknown URL translation type %d", urltrans_type(trans)); alog("SMS request sender:%s request: '%s' FAILED unknown translation", octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.msgdata)); octstr_destroy(pattern); return -1; break; } return 1; } static void obey_request_thread(void *arg) { Msg *msg, *mack, *reply_msg; Octstr *tmp, *reply; URLTranslation *trans; Octstr *p; int ret, dreport=0; while ((msg = gwlist_consume(smsbox_requests)) != NULL) { if (msg->sms.sms_type == report_mo) dreport = 1; else dreport = 0; /* Recode to UTF-8 the MO message if possible */ if (mo_recode && msg->sms.coding == DC_UCS2) { Octstr *text; text = octstr_duplicate(msg->sms.msgdata); if (octstr_recode(octstr_imm("UTF-8"), octstr_imm("UTF-16BE"), text) == 0) { info(0, "MO message converted from UCS-2 to UTF-8"); octstr_destroy(msg->sms.msgdata); msg->sms.msgdata = octstr_duplicate(text); msg->sms.charset = octstr_create("UTF-8"); msg->sms.coding = DC_7BIT; } octstr_destroy(text); } if (octstr_len(msg->sms.sender) == 0 || octstr_len(msg->sms.receiver) == 0) { error(0, "smsbox_req_thread: no sender/receiver, dump follows:"); msg_dump(msg, 0); /* * Send NACK to bearerbox, otherwise message remains in store file. */ mack = msg_create(ack); mack->ack.nack = ack_failed; mack->ack.time = msg->sms.time; uuid_copy(mack->ack.id, msg->sms.id); write_to_bearerbox(mack); msg_destroy(msg); continue; } /* create ack message to be sent afterwards */ mack = msg_create(ack); mack->ack.nack = ack_success; mack->ack.time = msg->sms.time; uuid_copy(mack->ack.id, msg->sms.id); /* * no smsbox services when we are doing ppg dlr - so trans would be * NULL in this case. */ if (dreport) { if (msg->sms.service == NULL || (msg->sms.service != NULL && ppg_service_name != NULL && octstr_compare(msg->sms.service, ppg_service_name) == 0)) { trans = NULL; } else { trans = urltrans_find_service(translations, msg); } info(0, "Starting delivery report <%s> from <%s>", octstr_get_cstr(msg->sms.service), octstr_get_cstr(msg->sms.sender)); } else { trans = urltrans_find(translations, msg); if (trans == NULL) { warning(0, "No translation found for <%s> from <%s> to <%s>", octstr_get_cstr(msg->sms.msgdata), octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver)); sms_swap(msg); goto error; } info(0, "Starting to service <%s> from <%s> to <%s>", octstr_get_cstr(msg->sms.msgdata), octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver)); /* * Transcode to an alt-charset encoding if requested for sms-service. * This ensures that legacy systems using Kannel 1.4.1 which used * latin1 as internal encoding can issue the same content to the * application servers. */ tmp = urltrans_alt_charset(trans); if (tmp != NULL && msg->sms.coding == DC_7BIT) { if (charset_convert(msg->sms.msgdata, "UTF-8", octstr_get_cstr(tmp)) != 0) { error(0, "Failed to convert msgdata from charset <%s> to <%s>, will leave as is.", "UTF-8", octstr_get_cstr(tmp)); } } /* * now, we change the sender (receiver now 'cause we swap them later) * if faked-sender or similar set. Note that we ignore if the * replacement fails. */ tmp = octstr_duplicate(msg->sms.sender); p = urltrans_faked_sender(trans); if (p != NULL) { octstr_destroy(msg->sms.sender); msg->sms.sender = octstr_duplicate(p); } else if (global_sender != NULL) { octstr_destroy(msg->sms.sender); msg->sms.sender = octstr_duplicate(global_sender); } else { octstr_destroy(msg->sms.sender); msg->sms.sender = octstr_duplicate(msg->sms.receiver); } octstr_destroy(msg->sms.receiver); msg->sms.receiver = tmp; msg->sms.sms_type = mt_reply; } /* TODO: check if the sender is approved to use this service */ if (msg->sms.service == NULL && trans != NULL) msg->sms.service = octstr_duplicate(urltrans_name(trans)); ret = obey_request(&reply, trans, msg); if (ret != 0) { if (ret == -1) { error: error(0, "request failed"); /* XXX this can be something different, according to urltranslation */ reply = octstr_duplicate(reply_requestfailed); trans = NULL; /* do not use any special translation */ } if (!dreport) { /* create reply message */ reply_msg = msg_create(sms); reply_msg->sms.sms_type = mt_reply; reply_msg->sms.sender = msg->sms.sender; msg->sms.sender = NULL; reply_msg->sms.receiver = msg->sms.receiver; msg->sms.receiver = NULL; reply_msg->sms.smsc_id = msg->sms.smsc_id; msg->sms.smsc_id = NULL; reply_msg->sms.msgdata = reply; reply_msg->sms.time = time(NULL); /* set current time */ /* send message */ if (send_message(trans, reply_msg) < 0) error(0, "request_thread: failed"); /* cleanup */ msg_destroy(reply_msg); } } write_to_bearerbox(mack); /* implicit msg_destroy */ msg_destroy(msg); } } /*********************************************************************** * HTTP sendsms interface. */ #ifdef HAVE_SECURITY_PAM_APPL_H /*Module for pam authentication */ /* * Use PAM (Pluggable Authentication Module) to check sendsms authentication. */ typedef const struct pam_message pam_message_type; static const char *PAM_username; static const char *PAM_password; static int PAM_conv (int num_msg, pam_message_type **msg, struct pam_response **resp, void *appdata_ptr) { int count = 0, replies = 0; struct pam_response *repl = NULL; int size = sizeof(struct pam_response); #define GET_MEM \ repl = gw_realloc(repl, size); \ size += sizeof(struct pam_response) #define COPY_STRING(s) (s) ? gw_strdup(s) : NULL for (count = 0; count < num_msg; count++) { switch (msg[count]->msg_style) { case PAM_PROMPT_ECHO_ON: GET_MEM; repl[replies].resp_retcode = PAM_SUCCESS; repl[replies++].resp = COPY_STRING(PAM_username); /* PAM frees resp */ break; case PAM_PROMPT_ECHO_OFF: GET_MEM; repl[replies].resp_retcode = PAM_SUCCESS; repl[replies++].resp = COPY_STRING(PAM_password); /* PAM frees resp */ break; case PAM_TEXT_INFO: warning(0, "unexpected message from PAM: %s", msg[count]->msg); break; case PAM_ERROR_MSG: default: /* Must be an error of some sort... */ error(0, "unexpected error from PAM: %s", msg[count]->msg); gw_free(repl); return PAM_CONV_ERR; } } if (repl) *resp = repl; return PAM_SUCCESS; } static struct pam_conv PAM_conversation = { &PAM_conv, NULL }; static int authenticate(const char *login, const char *passwd) { pam_handle_t *pamh; int pam_error; PAM_username = login; PAM_password = passwd; pam_error = pam_start("kannel", login, &PAM_conversation, &pamh); if (pam_error != PAM_SUCCESS || (pam_error = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { pam_end(pamh, pam_error); return 0; } pam_end(pamh, PAM_SUCCESS); info(0, "sendsms used by <%s>", login); return 1; } /* * Check for matching username and password for requests. * Return an URLTranslation if successful NULL otherwise. */ static int pam_authorise_user(List *list) { Octstr *val, *user = NULL; char *pwd, *login; int result; if ((user = http_cgi_variable(list, "user")) == NULL && (user = http_cgi_variable(list, "username"))==NULL) return 0; login = octstr_get_cstr(user); if ((val = http_cgi_variable(list, "password")) == NULL && (val = http_cgi_variable(list, "pass")) == NULL) return 0; pwd = octstr_get_cstr(val); result = authenticate(login, pwd); return result; } #endif /* HAVE_SECURITY_PAM_APPL_H */ static Octstr* store_uuid(Msg *msg) { char id[UUID_STR_LEN + 1]; Octstr *stored_uuid; gw_assert(msg != NULL); gw_assert(!immediate_sendsms_reply); uuid_unparse(msg->sms.id, id); stored_uuid = octstr_create(id); debug("sms.http", 0, "Stored UUID %s", octstr_get_cstr(stored_uuid)); /* this octstr is then used to store the HTTP client into * client_dict, if need to, in sendsms_thread */ return stored_uuid; } static Octstr *smsbox_req_handle(URLTranslation *t, Octstr *client_ip, HTTPClient *client, Octstr *from, Octstr *to, Octstr *text, Octstr *charset, Octstr *udh, Octstr *smsc, int mclass, int mwi, int coding, int compress, int validity, int deferred, int *status, int dlr_mask, Octstr *dlr_url, Octstr *account, int pid, int alt_dcs, int rpi, List *receiver, Octstr *binfo, int priority, Octstr *meta_data) { Msg *msg = NULL; Octstr *newfrom = NULL; Octstr *returnerror = NULL; Octstr *receiv; Octstr *stored_uuid = NULL; List *failed_id = NULL; List *allowed = NULL; List *denied = NULL; int no_recv, ret = 0, i; /* * Multi-cast messages with several receivers in 'to' are handled * in a loop. We only change sms.time and sms.receiver within the * loop below, because everything else is identical for all receivers. * If receiver is not null, to list is already present on it */ if(receiver == NULL) { receiver = octstr_split_words(to); } no_recv = gwlist_len(receiver); /* * check if UDH length is legal, or otherwise discard the * message, to prevent intentional buffer overflow schemes */ if (udh != NULL && (octstr_len(udh) != octstr_get_char(udh, 0) + 1)) { returnerror = octstr_create("UDH field misformed, rejected"); goto field_error; } if (udh != NULL && octstr_len(udh) > MAX_SMS_OCTETS) { returnerror = octstr_create("UDH field is too long, rejected"); goto field_error; } /* * Check for white and black lists, first for the URLTranlation * lists and then for the global lists. * * Set the 'allowed' and 'denied' lists accordingly to process at * least all allowed receiver messages. This is a constrain * walk through all disallowing rules within the lists. */ allowed = gwlist_create(); denied = gwlist_create(); for (i = 0; i < no_recv; i++) { receiv = gwlist_get(receiver, i); /* * Check if there are any illegal characters in the 'to' scheme */ if (strspn(octstr_get_cstr(receiv), sendsms_number_chars) < octstr_len(receiv)) { info(0,"Illegal characters in 'to' string ('%s') vs '%s'", octstr_get_cstr(receiv), sendsms_number_chars); gwlist_append_unique(denied, receiv, octstr_item_match); } /* * First of all fill the two lists systematicaly by the rules, * then we will revice the lists. */ if (urltrans_white_list(t) && numhash_find_number(urltrans_white_list(t), receiv) < 1) { info(0, "Number <%s> is not in white-list, message discarded", octstr_get_cstr(receiv)); gwlist_append_unique(denied, receiv, octstr_item_match); } else { gwlist_append_unique(allowed, receiv, octstr_item_match); } if (urltrans_white_list_regex(t) && gw_regex_match_pre(urltrans_white_list_regex(t), receiv) == 0) { info(0, "Number <%s> is not in white-list-regex, message discarded", octstr_get_cstr(receiv)); gwlist_append_unique(denied, receiv, octstr_item_match); } else { gwlist_append_unique(allowed, receiv, octstr_item_match); } if (urltrans_black_list(t) && numhash_find_number(urltrans_black_list(t), receiv) == 1) { info(0, "Number <%s> is in black-list, message discarded", octstr_get_cstr(receiv)); gwlist_append_unique(denied, receiv, octstr_item_match); } else { gwlist_append_unique(allowed, receiv, octstr_item_match); } if (urltrans_black_list_regex(t) && gw_regex_match_pre(urltrans_black_list_regex(t), receiv) == 1) { info(0, "Number <%s> is in black-list-regex, message discarded", octstr_get_cstr(receiv)); gwlist_append_unique(denied, receiv, octstr_item_match); } else { gwlist_append_unique(allowed, receiv, octstr_item_match); } if (white_list && numhash_find_number(white_list, receiv) < 1) { info(0, "Number <%s> is not in global white-list, message discarded", octstr_get_cstr(receiv)); gwlist_append_unique(denied, receiv, octstr_item_match); } else { gwlist_append_unique(allowed, receiv, octstr_item_match); } if (white_list_regex && gw_regex_match_pre(white_list_regex, receiv) == 0) { info(0, "Number <%s> is not in global white-list-regex, message discarded", octstr_get_cstr(receiv)); gwlist_append_unique(denied, receiv, octstr_item_match); } else { gwlist_append_unique(allowed, receiv, octstr_item_match); } if (black_list && numhash_find_number(black_list, receiv) == 1) { info(0, "Number <%s> is in global black-list, message discarded", octstr_get_cstr(receiv)); gwlist_append_unique(denied, receiv, octstr_item_match); } else { gwlist_append_unique(allowed, receiv, octstr_item_match); } if (black_list_regex && gw_regex_match_pre(black_list_regex, receiv) == 1) { info(0, "Number <%s> is in global black-list-regex, message discarded", octstr_get_cstr(receiv)); gwlist_append_unique(denied, receiv, octstr_item_match); } else { gwlist_append_unique(allowed, receiv, octstr_item_match); } } /* * Now we have to revise the 'allowed' and 'denied' lists by walking * the 'denied' list and check if items are also present in 'allowed', * then we will discard them from 'allowed'. */ for (i = 0; i < gwlist_len(denied); i++) { receiv = gwlist_get(denied, i); gwlist_delete_matching(allowed, receiv, octstr_item_match); } /* have all receivers been denied by list rules?! */ if (gwlist_len(allowed) == 0) { returnerror = octstr_create("Number(s) has/have been denied by white- and/or black-lists."); goto field_error; } if (urltrans_faked_sender(t) != NULL) { /* discard previous from */ newfrom = octstr_duplicate(urltrans_faked_sender(t)); } else if (octstr_len(from) > 0) { newfrom = octstr_duplicate(from); } else if (urltrans_default_sender(t) != NULL) { newfrom = octstr_duplicate(urltrans_default_sender(t)); } else if (global_sender != NULL) { newfrom = octstr_duplicate(global_sender); } else { returnerror = octstr_create("Sender missing and no global set, rejected"); goto field_error; } info(0, "sendsms sender:<%s:%s> (%s) to:<%s> msg:<%s>", octstr_get_cstr(urltrans_username(t)), octstr_get_cstr(newfrom), octstr_get_cstr(client_ip), ( to == NULL ? "multi-cast" : octstr_get_cstr(to) ), ( text == NULL ? "" : octstr_get_cstr(text) )); /* * Create the msg structure and fill the types. Note that sms.receiver * and sms.time are set in the multi-cast support loop below. */ msg = msg_create(sms); msg->sms.service = octstr_duplicate(urltrans_name(t)); msg->sms.sms_type = mt_push; msg->sms.sender = octstr_duplicate(newfrom); if(octstr_len(account)) { if(octstr_len(account) <= ACCOUNT_MAX_LEN && octstr_search_chars(account, octstr_imm("[]\n\r"), 0) == -1) { msg->sms.account = account ? octstr_duplicate(account) : NULL; } else { returnerror = octstr_create("Account field misformed or too long, rejected"); goto field_error; } } msg->sms.msgdata = text ? octstr_duplicate(text) : octstr_create(""); msg->sms.udhdata = udh ? octstr_duplicate(udh) : octstr_create(""); if (octstr_len(binfo)) msg->sms.binfo = octstr_duplicate(binfo); if(octstr_len(dlr_url)) { if(octstr_len(dlr_url) < 8) { /* http(s):// */ returnerror = octstr_create("DLR-URL field misformed, rejected"); goto field_error; } else { Octstr *tmp; tmp = octstr_copy(dlr_url, 0, 7); if(octstr_case_compare(tmp, octstr_imm("http://")) == 0) { msg->sms.dlr_url = octstr_duplicate(dlr_url); } else { O_DESTROY(tmp); tmp = octstr_copy(dlr_url, 0, 8); if(octstr_case_compare(tmp, octstr_imm("https://")) != 0) { returnerror = octstr_create("DLR-URL field misformed, rejected"); O_DESTROY(tmp); goto field_error; } #ifdef HAVE_LIBSSL msg->sms.dlr_url = octstr_duplicate(dlr_url); #else /* HAVE_LIBSSL */ else { warning(0, "DLR-URL with https but SSL not supported, url is <%s>", octstr_get_cstr(dlr_url)); } #endif /* HAVE_LIBSSL */ } O_DESTROY(tmp); } } else { msg->sms.dlr_url = octstr_create(""); } if ( dlr_mask < -1 || dlr_mask > 66 ) { /* 01000010 */ returnerror = octstr_create("DLR-Mask field misformed, rejected"); goto field_error; } msg->sms.dlr_mask = dlr_mask; if ( mclass < -1 || mclass > 3 ) { returnerror = octstr_create("MClass field misformed, rejected"); goto field_error; } msg->sms.mclass = mclass; if ( pid < -1 || pid > 255 ) { returnerror = octstr_create("PID field misformed, rejected"); goto field_error; } msg->sms.pid = pid; if ( rpi < -1 || rpi > 2) { returnerror = octstr_create("RPI field misformed, rejected"); goto field_error; } msg->sms.rpi = rpi; if ( alt_dcs < -1 || alt_dcs > 1 ) { returnerror = octstr_create("Alt-DCS field misformed, rejected"); goto field_error; } msg->sms.alt_dcs = alt_dcs; if ( mwi < -1 || mwi > 7 ) { returnerror = octstr_create("MWI field misformed, rejected"); goto field_error; } msg->sms.mwi = mwi; if ( coding < -1 || coding > 2 ) { returnerror = octstr_create("Coding field misformed, rejected"); goto field_error; } msg->sms.coding = coding; if ( compress < -1 || compress > 1 ) { returnerror = octstr_create("Compress field misformed, rejected"); goto field_error; } msg->sms.compress = compress; /* Compatibility Mode */ if ( msg->sms.coding == DC_UNDEF) { if(octstr_len(udh)) msg->sms.coding = DC_8BIT; else msg->sms.coding = DC_7BIT; } if (validity < -1) { returnerror = octstr_create("Validity field misformed, rejected"); goto field_error; } else if (validity != SMS_PARAM_UNDEFINED) msg->sms.validity = validity * 60 + time(NULL); if (deferred < -1) { returnerror = octstr_create("Deferred field misformed, rejected"); goto field_error; } else if (deferred != SMS_PARAM_UNDEFINED) msg->sms.deferred = deferred * 60 + time(NULL); if (priority != SMS_PARAM_UNDEFINED && (priority < 0 || priority > 3)) { returnerror = octstr_create("Priority field misformed, rejected"); goto field_error; } msg->sms.priority = priority; /* new smsc-id argument - we should check this one, if able, but that's advanced logics -- Kalle */ if (urltrans_forced_smsc(t)) { msg->sms.smsc_id = octstr_duplicate(urltrans_forced_smsc(t)); if (smsc) info(0, "send-sms request smsc id ignored, " "as smsc id forced to %s", octstr_get_cstr(urltrans_forced_smsc(t))); } else if (smsc) { msg->sms.smsc_id = octstr_duplicate(smsc); } else if (urltrans_default_smsc(t)) { msg->sms.smsc_id = octstr_duplicate(urltrans_default_smsc(t)); } else msg->sms.smsc_id = NULL; if (sms_charset_processing(charset, msg->sms.msgdata, msg->sms.coding) == -1) { returnerror = octstr_create("Charset or body misformed, rejected"); goto field_error; } msg->sms.meta_data = octstr_duplicate(meta_data); msg->sms.receiver = NULL; /* * All checks are done, now add multi-cast request support by * looping through 'allowed'. This should work for any * number of receivers within 'to'. If the message fails append * it to 'failed_id'. */ failed_id = gwlist_create(); if (!immediate_sendsms_reply) { stored_uuid = store_uuid(msg); dict_put(client_dict, stored_uuid, client); } while ((receiv = gwlist_extract_first(allowed)) != NULL) { O_DESTROY(msg->sms.receiver); msg->sms.receiver = octstr_duplicate(receiv); msg->sms.time = time(NULL); /* send the message and return number of splits */ ret = send_message(t, msg); if (ret == -1) { /* add the receiver to the failed list */ gwlist_append(failed_id, receiv); } else { /* log the sending as successful for this particular message */ alog("send-SMS request added - sender:%s:%s %s target:%s request: '%s'", octstr_get_cstr(urltrans_username(t)), octstr_get_cstr(newfrom), octstr_get_cstr(client_ip), octstr_get_cstr(receiv), udh == NULL ? ( text == NULL ? "" : octstr_get_cstr(text) ) : "<< UDH >>"); } } if (gwlist_len(failed_id) > 0) goto transmit_error; *status = HTTP_ACCEPTED; returnerror = octstr_create("Sent."); /* * Append all denied receivers to the returned body in case this is * a multi-cast send request */ if (gwlist_len(denied) > 0) { octstr_format_append(returnerror, " Denied receivers are:"); while ((receiv = gwlist_extract_first(denied)) != NULL) { octstr_format_append(returnerror, " %s", octstr_get_cstr(receiv)); } } /* * Append number of splits to returned body. * This may be used by the calling client. */ if (ret > 1) octstr_format_append(returnerror, " Message splits: %d", ret); cleanup: octstr_destroy(stored_uuid); gwlist_destroy(failed_id, NULL); gwlist_destroy(allowed, NULL); gwlist_destroy(denied, NULL); gwlist_destroy(receiver, octstr_destroy_item); octstr_destroy(newfrom); msg_destroy(msg); return returnerror; field_error: alog("send-SMS request failed - %s", octstr_get_cstr(returnerror)); *status = HTTP_BAD_REQUEST; goto cleanup; transmit_error: error(0, "sendsms_request: failed"); *status = HTTP_INTERNAL_SERVER_ERROR; returnerror = octstr_create("Sending failed."); if (!immediate_sendsms_reply) dict_remove(client_dict, stored_uuid); /* * Append all receivers to the returned body in case this is * a multi-cast send request */ if (no_recv > 1) { octstr_format_append(returnerror, " Failed receivers are:"); while ((receiv = gwlist_extract_first(failed_id)) != NULL) { octstr_format_append(returnerror, " %s", octstr_get_cstr(receiv)); } } goto cleanup; } /* * new authorisation, usable by POST and GET */ static URLTranslation *authorise_username(Octstr *username, Octstr *password, Octstr *client_ip) { URLTranslation *t = NULL; if (username == NULL || password == NULL) return NULL; if ((t = urltrans_find_username(translations, username))==NULL) return NULL; if (octstr_compare(password, urltrans_password(t))!=0) return NULL; else { Octstr *allow_ip = urltrans_allow_ip(t); Octstr *deny_ip = urltrans_deny_ip(t); if (is_allowed_ip(allow_ip, deny_ip, client_ip) == 0) { warning(0, "Non-allowed connect tried by <%s> from <%s>, ignored", octstr_get_cstr(username), octstr_get_cstr(client_ip)); return NULL; } } info(0, "sendsms used by <%s>", octstr_get_cstr(username)); return t; } /* * Authentication whith the database of Kannel. * Check for matching username and password for requests. * Return an URLTranslation if successful NULL otherwise. */ static URLTranslation *default_authorise_user(List *list, Octstr *client_ip) { Octstr *pass, *user = NULL; if ((user = http_cgi_variable(list, "username")) == NULL) user = http_cgi_variable(list, "user"); if ((pass = http_cgi_variable(list, "password")) == NULL) pass = http_cgi_variable(list, "pass"); return authorise_username(user, pass, client_ip); } static URLTranslation *authorise_user(List *list, Octstr *client_ip) { #ifdef HAVE_SECURITY_PAM_APPL_H URLTranslation *t; t = urltrans_find_username(translations, octstr_imm("pam")); if (t != NULL) { if (pam_authorise_user(list)) return t; else return NULL; } else return default_authorise_user(list, client_ip); #else return default_authorise_user(list, client_ip); #endif } /* * Create and send an SMS message from an HTTP request. * Args: args contains the CGI parameters */ static Octstr *smsbox_req_sendsms(List *args, Octstr *client_ip, int *status, HTTPClient *client) { URLTranslation *t = NULL; Octstr *tmp_string; Octstr *from, *to, *charset, *text, *udh, *smsc, *dlr_url, *account; Octstr *binfo, *meta_data; int dlr_mask, mclass, mwi, coding, compress, validity, deferred, pid; int alt_dcs, rpi, priority; from = to = udh = text = smsc = account = dlr_url = charset = binfo = meta_data = NULL; mclass = mwi = coding = compress = validity = deferred = dlr_mask = pid = alt_dcs = rpi = priority = SMS_PARAM_UNDEFINED; /* check the username and password */ t = authorise_user(args, client_ip); if (t == NULL) { *status = HTTP_FORBIDDEN; return octstr_create("Authorization failed for sendsms"); } udh = http_cgi_variable(args, "udh"); text = http_cgi_variable(args, "text"); charset = http_cgi_variable(args, "charset"); smsc = http_cgi_variable(args, "smsc"); from = http_cgi_variable(args, "from"); to = http_cgi_variable(args, "to"); account = http_cgi_variable(args, "account"); binfo = http_cgi_variable(args, "binfo"); dlr_url = http_cgi_variable(args, "dlr-url"); if(dlr_url == NULL) { /* deprecated dlrurl without "-" */ dlr_url = http_cgi_variable(args, "dlrurl"); if(dlr_url != NULL) warning(0, " field used and deprecated. Please use dlr-url instead."); } tmp_string = http_cgi_variable(args, "dlr-mask"); if(tmp_string == NULL) { /* deprecated dlrmask without "-" */ tmp_string = http_cgi_variable(args, "dlrmask"); if(tmp_string != NULL) warning(0, " field used and deprecated. Please use dlr-mask instead."); } if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &dlr_mask); tmp_string = http_cgi_variable(args, "mclass"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &mclass); tmp_string = http_cgi_variable(args, "pid"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &pid); tmp_string = http_cgi_variable(args, "rpi"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &rpi); tmp_string = http_cgi_variable(args, "alt-dcs"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &alt_dcs); tmp_string = http_cgi_variable(args, "mwi"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &mwi); tmp_string = http_cgi_variable(args, "coding"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &coding); tmp_string = http_cgi_variable(args, "compress"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &compress); tmp_string = http_cgi_variable(args, "validity"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &validity); tmp_string = http_cgi_variable(args, "deferred"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &deferred); tmp_string = http_cgi_variable(args, "priority"); if(tmp_string != NULL) sscanf(octstr_get_cstr(tmp_string),"%d", &priority); meta_data = http_cgi_variable(args, "meta-data"); /* * we required "to" to be defined */ if (to == NULL) { error(0, "%s got insufficient headers ( is NULL)", octstr_get_cstr(sendsms_url)); *status = HTTP_BAD_REQUEST; return octstr_create("Missing receiver number, rejected"); } else if (octstr_len(to) == 0) { error(0, "%s got empty cgi variable", octstr_get_cstr(sendsms_url)); *status = HTTP_BAD_REQUEST; return octstr_create("Empty receiver number not allowed, rejected"); } return smsbox_req_handle(t, client_ip, client, from, to, text, charset, udh, smsc, mclass, mwi, coding, compress, validity, deferred, status, dlr_mask, dlr_url, account, pid, alt_dcs, rpi, NULL, binfo, priority, meta_data); } /* * Create and send an SMS message from an HTTP request. * Args: args contains the CGI parameters */ static Octstr *smsbox_sendsms_post(List *headers, Octstr *body, Octstr *client_ip, int *status, HTTPClient *client) { URLTranslation *t = NULL; Octstr *user, *pass, *ret, *type; List *tolist; Octstr *text_html, *text_plain, *text_wml, *text_xml, *octet_stream; Octstr *text; Octstr *from, *to, *udh, *smsc, *charset, *dlr_url, *account, *binfo, *meta_data; int dlr_mask, mclass, mwi, coding, compress, validity, deferred; int pid, alt_dcs, rpi, priority; text_html = octstr_imm("text/html"); text_wml = octstr_imm("text/vnd.wap.wml"); text_plain = octstr_imm("text/plain"); text_xml = octstr_imm("text/xml"); octet_stream = octstr_imm("application/octet-stream"); user = pass = ret = type = NULL; tolist = NULL; from = to = udh = smsc = account = dlr_url = charset = binfo = meta_data = NULL; mclass = mwi = coding = compress = validity = deferred = dlr_mask = pid = alt_dcs = rpi = priority = SMS_PARAM_UNDEFINED; http_header_get_content_type(headers, &type, &charset); if (octstr_case_compare(type, text_html) == 0 || octstr_case_compare(type, text_wml) == 0) { text = html_to_sms(body); octstr_strip_blanks(text); body = text; get_x_kannel_from_headers(headers, &from, &to, &udh, &user, &pass, &smsc, &mclass, &mwi, &coding, &compress, &validity, &deferred, &dlr_mask, &dlr_url, &account, &pid, &alt_dcs, &rpi, &binfo, &priority, &meta_data); } else if (octstr_case_compare(type, text_plain) == 0 || octstr_case_compare(type, octet_stream) == 0) { get_x_kannel_from_headers(headers, &from, &to, &udh, &user, &pass, &smsc, &mclass, &mwi, &coding, &compress, &validity, &deferred, &dlr_mask, &dlr_url, &account, &pid, &alt_dcs, &rpi, &binfo, &priority, &meta_data); } else if (octstr_case_compare(type, text_xml) == 0) { get_x_kannel_from_xml(mt_push, &type, &body, headers, &from, &to, &udh, &user, &pass, &smsc, &mclass, &mwi, &coding, &compress, &validity, &deferred, &dlr_mask, &dlr_url, &account, &pid, &alt_dcs, &rpi, &tolist, &charset, &binfo, &priority, &meta_data); } else { *status = HTTP_BAD_REQUEST; ret = octstr_create("Invalid content-type"); goto error; } /* check the username and password */ t = authorise_username(user, pass, client_ip); if (t == NULL) { *status = HTTP_FORBIDDEN; ret = octstr_create("Authorization failed for sendsms"); } else if (to == NULL && tolist == NULL) { error(0, "%s got insufficient headers ( and are NULL)", octstr_get_cstr(sendsms_url)); *status = HTTP_BAD_REQUEST; ret = octstr_create("Missing receiver(s) number(s), rejected"); } else if (to != NULL && octstr_len(to) == 0) { error(0, "%s got empty cgi variable", octstr_get_cstr(sendsms_url)); *status = HTTP_BAD_REQUEST; ret = octstr_create("Empty receiver number not allowed, rejected"); } else { if (octstr_case_compare(type, octstr_imm("application/octet-stream")) == 0) { if (coding == DC_UNDEF) coding = DC_8BIT; /* XXX Force UCS-2 with DC Field */ } else if (octstr_case_compare(type, octstr_imm("text/plain")) == 0) { if (coding == DC_UNDEF) coding = DC_7BIT; } else { error(0, "%s got weird content type %s", octstr_get_cstr(sendsms_url), octstr_get_cstr(type)); *status = HTTP_UNSUPPORTED_MEDIA_TYPE; ret = octstr_create("Unsupported content-type, rejected"); } if (ret == NULL) ret = smsbox_req_handle(t, client_ip, client, from, to, body, charset, udh, smsc, mclass, mwi, coding, compress, validity, deferred, status, dlr_mask, dlr_url, account, pid, alt_dcs, rpi, tolist, binfo, priority, meta_data); } octstr_destroy(user); octstr_destroy(pass); octstr_destroy(from); octstr_destroy(to); octstr_destroy(udh); octstr_destroy(smsc); octstr_destroy(dlr_url); octstr_destroy(account); octstr_destroy(binfo); octstr_destroy(meta_data); error: octstr_destroy(type); octstr_destroy(charset); return ret; } /* * Create and send an SMS message from a XML-RPC request. * Answer with a valid XML-RPC response for a successful request. * * function signature: boolean sms.send(struct) * * The MUST contain at least 's with name 'username', * 'password', 'to' and MAY contain additional 's with name * 'from', 'account', 'smsc', 'udh', 'dlrmask', 'dlrurl'. All values * are of type string. */ static Octstr *smsbox_xmlrpc_post(List *headers, Octstr *body, Octstr *client_ip, int *status) { Octstr *ret, *type; Octstr *charset; Octstr *output; Octstr *method_name; XMLRPCDocument *msg; charset = NULL; ret = NULL; /* * check if the content type is valid for this request */ http_header_get_content_type(headers, &type, &charset); if (octstr_case_compare(type, octstr_imm("text/xml")) != 0) { error(0, "Unsupported content-type '%s'", octstr_get_cstr(type)); *status = HTTP_BAD_REQUEST; ret = octstr_format("Unsupported content-type '%s'", octstr_get_cstr(type)); } else { /* * parse the body of the request and check if it is a valid XML-RPC * structure */ msg = xmlrpc_parse_call(body); if ((xmlrpc_parse_status(msg) != XMLRPC_COMPILE_OK) && ((output = xmlrpc_parse_error(msg)) != NULL)) { /* parse failure */ error(0, "%s", octstr_get_cstr(output)); *status = HTTP_BAD_REQUEST; ret = octstr_format("%s", octstr_get_cstr(output)); octstr_destroy(output); } else { /* * at least the structure has been valid, now check for the * required methodName and the required variables */ if (octstr_case_compare((method_name = xmlrpc_get_call_name(msg)), octstr_imm("sms.send")) != 0) { error(0, "Unknown method name '%s'", octstr_get_cstr(method_name)); *status = HTTP_BAD_REQUEST; ret = octstr_format("Unkown method name '%s'", octstr_get_cstr(method_name)); } else { /* * TODO: check for the required struct members */ } } xmlrpc_destroy_call(msg); } return ret; } /* * Create and send an SMS OTA (auto configuration) message from an HTTP * request. If cgivar "text" is present, use it as a xml configuration source, * otherwise read the configuration from the configuration file. * Args: list contains the CGI parameters */ static Octstr *smsbox_req_sendota(List *list, Octstr *client_ip, int *status, HTTPClient *client) { Octstr *id, *from, *phonenumber, *smsc, *ota_doc, *doc_type, *account; CfgGroup *grp; Octstr *returnerror; Octstr *stored_uuid = NULL; List *grplist; Octstr *p; URLTranslation *t; Msg *msg; int ret, ota_type; id = phonenumber = smsc = account = NULL; /* check the username and password */ t = authorise_user(list, client_ip); if (t == NULL) { *status = HTTP_FORBIDDEN; return octstr_create("Authorization failed for sendota"); } if ((phonenumber = http_cgi_variable(list, "to")) == NULL) { if ((phonenumber = http_cgi_variable(list, "phonenumber")) == NULL) { error(0, "%s needs a valid phone number.", octstr_get_cstr(sendota_url)); *status = HTTP_BAD_REQUEST; return octstr_create("Wrong sendota args."); } } if (urltrans_faked_sender(t) != NULL) { from = octstr_duplicate(urltrans_faked_sender(t)); } else if ((from = http_cgi_variable(list, "from")) != NULL && octstr_len(from) > 0) { from = octstr_duplicate(from); } else if (urltrans_default_sender(t) != NULL) { from = octstr_duplicate(urltrans_default_sender(t)); } else if (global_sender != NULL) { from = octstr_duplicate(global_sender); } else { *status = HTTP_BAD_REQUEST; return octstr_create("Sender missing and no global set, rejected"); } /* check does we have an external XML source for configuration */ if ((ota_doc = http_cgi_variable(list, "text")) != NULL) { Octstr *sec, *pin; /* * We are doing the XML OTA compiler mode for this request */ debug("sms", 0, "OTA service with XML document"); ota_doc = octstr_duplicate(ota_doc); if ((doc_type = http_cgi_variable(list, "type")) == NULL) doc_type = octstr_format("%s", "settings"); else doc_type = octstr_duplicate(doc_type); if ((sec = http_cgi_variable(list, "sec")) == NULL) sec = octstr_create("USERPIN"); else sec = octstr_duplicate(sec); if ((pin = http_cgi_variable(list, "pin")) == NULL) pin = octstr_create("12345"); else pin = octstr_duplicate(pin); if ((ret = ota_pack_message(&msg, ota_doc, doc_type, from, phonenumber, sec, pin)) < 0) { *status = HTTP_BAD_REQUEST; msg_destroy(msg); if (ret == -2) return octstr_create("Erroneous document type, cannot" " compile\n"); else if (ret == -1) return octstr_create("Erroneous ota source, cannot compile\n"); } goto send; } else { /* * We are doing the ota-settings or ota-bookmark group mode * for this request. * * Check if a ota-setting ID has been given and decide which OTA * properties to be send to the client otherwise try to find a * ota-bookmark ID. If none is found then send the default * ota-setting group, which is the first within the config file. */ id = http_cgi_variable(list, "otaid"); grplist = cfg_get_multi_group(cfg, octstr_imm("ota-setting")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("ota-id")); if (id == NULL || (p != NULL && octstr_compare(p, id) == 0)) { ota_type = 1; goto found; } octstr_destroy(p); } gwlist_destroy(grplist, NULL); grplist = cfg_get_multi_group(cfg, octstr_imm("ota-bookmark")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("ota-id")); if (id == NULL || (p != NULL && octstr_compare(p, id) == 0)) { ota_type = 0; goto found; } octstr_destroy(p); } gwlist_destroy(grplist, NULL); if (id != NULL) error(0, "%s can't find any ota-setting or ota-bookmark group with ota-id '%s'.", octstr_get_cstr(sendota_url), octstr_get_cstr(id)); else error(0, "%s can't find any ota-setting group.", octstr_get_cstr(sendota_url)); octstr_destroy(from); *status = HTTP_BAD_REQUEST; return octstr_create("Missing ota-setting or ota-bookmark group."); } found: octstr_destroy(p); gwlist_destroy(grplist, NULL); /* tokenize the OTA settings or bookmarks group and return the message */ if (ota_type) msg = ota_tokenize_settings(grp, from, phonenumber); else msg = ota_tokenize_bookmarks(grp, from, phonenumber); send: /* we still need to check if smsc is forced for this */ smsc = http_cgi_variable(list, "smsc"); if (urltrans_forced_smsc(t)) { msg->sms.smsc_id = octstr_duplicate(urltrans_forced_smsc(t)); if (smsc) info(0, "send-sms request smsc id ignored, as smsc id forced to %s", octstr_get_cstr(urltrans_forced_smsc(t))); } else if (smsc) { msg->sms.smsc_id = octstr_duplicate(smsc); } else if (urltrans_default_smsc(t)) { msg->sms.smsc_id = octstr_duplicate(urltrans_default_smsc(t)); } else msg->sms.smsc_id = NULL; account = http_cgi_variable(list, "account"); if (octstr_len(account) > 0) msg->sms.account = octstr_duplicate(account); octstr_dump(msg->sms.msgdata, 0); info(0, "%s <%s> <%s>", octstr_get_cstr(sendota_url), id ? octstr_get_cstr(id) : "", octstr_get_cstr(phonenumber)); if (!immediate_sendsms_reply) { stored_uuid = store_uuid(msg); dict_put(client_dict, stored_uuid, client); } ret = send_message(t, msg); if (ret == -1) { error(0, "sendota_request: failed"); *status = HTTP_INTERNAL_SERVER_ERROR; returnerror = octstr_create("Sending failed."); dict_remove(client_dict, stored_uuid); } else { *status = HTTP_ACCEPTED; returnerror = octstr_create("Sent."); } msg_destroy(msg); octstr_destroy(stored_uuid); return returnerror; } /* * Create and send an SMS OTA (auto configuration) message from an HTTP POST * request. Take the X-Kannel-foobar HTTP headers as parameter information. * Args: list contains the CGI parameters * * We still care about passed GET variable, in case the X-Kannel-foobar * parameters are not used but the POST contains the XML body itself. */ static Octstr *smsbox_sendota_post(List *headers, Octstr *body, Octstr *client_ip, int *status, HTTPClient *client) { Octstr *name, *val, *ret; Octstr *from, *to, *id, *user, *pass, *smsc; Octstr *type, *charset, *doc_type, *ota_doc, *sec, *pin; Octstr *stored_uuid = NULL; URLTranslation *t; Msg *msg; long l; int r; id = from = to = user = pass = smsc = NULL; doc_type = ota_doc = sec = pin = NULL; /* * process all special HTTP headers * * XXX can't we do this better? * Obviously http_header_find_first() does this */ for (l = 0; l < gwlist_len(headers); l++) { http_header_get(headers, l, &name, &val); if (octstr_case_compare(name, octstr_imm("X-Kannel-OTA-ID")) == 0) { id = octstr_duplicate(val); octstr_strip_blanks(id); } else if (octstr_case_compare(name, octstr_imm("X-Kannel-From")) == 0) { from = octstr_duplicate(val); octstr_strip_blanks(from); } else if (octstr_case_compare(name, octstr_imm("X-Kannel-To")) == 0) { to = octstr_duplicate(val); octstr_strip_blanks(to); } else if (octstr_case_compare(name, octstr_imm("X-Kannel-Username")) == 0) { user = octstr_duplicate(val); octstr_strip_blanks(user); } else if (octstr_case_compare(name, octstr_imm("X-Kannel-Password")) == 0) { pass = octstr_duplicate(val); octstr_strip_blanks(pass); } else if (octstr_case_compare(name, octstr_imm("X-Kannel-SMSC")) == 0) { smsc = octstr_duplicate(val); octstr_strip_blanks(smsc); } else if (octstr_case_compare(name, octstr_imm("X-Kannel-SEC")) == 0) { sec = octstr_duplicate(val); octstr_strip_blanks(sec); } else if (octstr_case_compare(name, octstr_imm("X-Kannel-PIN")) == 0) { pin = octstr_duplicate(val); octstr_strip_blanks(pin); } } /* apply defaults */ if (!sec) sec = octstr_imm("USERPIN"); if (!pin) pin = octstr_imm("1234"); /* check the username and password */ t = authorise_username(user, pass, client_ip); if (t == NULL) { *status = HTTP_FORBIDDEN; ret = octstr_create("Authorization failed for sendota"); } /* let's see if we have at least a target msisdn */ else if (to == NULL) { error(0, "%s needs a valid phone number.", octstr_get_cstr(sendota_url)); *status = HTTP_BAD_REQUEST; ret = octstr_create("Wrong sendota args."); } else { if (urltrans_faked_sender(t) != NULL) { from = octstr_duplicate(urltrans_faked_sender(t)); } else if (from != NULL && octstr_len(from) > 0) { } else if (urltrans_default_sender(t) != NULL) { from = octstr_duplicate(urltrans_default_sender(t)); } else if (global_sender != NULL) { from = octstr_duplicate(global_sender); } else { *status = HTTP_BAD_REQUEST; ret = octstr_create("Sender missing and no global set, rejected"); goto error; } /* * get the content-type of the body document */ http_header_get_content_type(headers, &type, &charset); if (octstr_case_compare(type, octstr_imm("application/x-wap-prov.browser-settings")) == 0) { doc_type = octstr_format("%s", "settings"); } else if (octstr_case_compare(type, octstr_imm("application/x-wap-prov.browser-bookmarks")) == 0) { doc_type = octstr_format("%s", "bookmarks"); } else if (octstr_case_compare(type, octstr_imm("text/vnd.wap.connectivity-xml")) == 0) { doc_type = octstr_format("%s", "oma-settings"); } if (doc_type == NULL) { error(0, "%s got weird content type %s", octstr_get_cstr(sendota_url), octstr_get_cstr(type)); *status = HTTP_UNSUPPORTED_MEDIA_TYPE; ret = octstr_create("Unsupported content-type, rejected"); } else { /* * ok, this is want we expect * now lets compile the whole thing */ ota_doc = octstr_duplicate(body); if ((r = ota_pack_message(&msg, ota_doc, doc_type, from, to, sec, pin)) < 0) { *status = HTTP_BAD_REQUEST; msg_destroy(msg); if (r == -2) { ret = octstr_create("Erroneous document type, cannot" " compile\n"); goto error; } else if (r == -1) { ret = octstr_create("Erroneous ota source, cannot compile\n"); goto error; } } /* we still need to check if smsc is forced for this */ if (urltrans_forced_smsc(t)) { msg->sms.smsc_id = octstr_duplicate(urltrans_forced_smsc(t)); if (smsc) info(0, "send-sms request smsc id ignored, as smsc id forced to %s", octstr_get_cstr(urltrans_forced_smsc(t))); } else if (smsc) { msg->sms.smsc_id = octstr_duplicate(smsc); } else if (urltrans_default_smsc(t)) { msg->sms.smsc_id = octstr_duplicate(urltrans_default_smsc(t)); } else msg->sms.smsc_id = NULL; info(0, "%s <%s> <%s>", octstr_get_cstr(sendota_url), id ? octstr_get_cstr(id) : "XML", octstr_get_cstr(to)); if (!immediate_sendsms_reply) { stored_uuid = store_uuid(msg); dict_put(client_dict, stored_uuid, client); } r = send_message(t, msg); if (r == -1) { error(0, "sendota_request: failed"); *status = HTTP_INTERNAL_SERVER_ERROR; ret = octstr_create("Sending failed."); if (!immediate_sendsms_reply) dict_remove(client_dict, stored_uuid); } else { *status = HTTP_ACCEPTED; ret = octstr_create("Sent."); } msg_destroy(msg); octstr_destroy(stored_uuid); } } error: octstr_destroy(user); octstr_destroy(pass); octstr_destroy(smsc); return ret; } static void sendsms_thread(void *arg) { HTTPClient *client; Octstr *ip, *url, *body, *answer; List *hdrs, *args; int status; for (;;) { /* reset request wars */ ip = url = body = answer = NULL; hdrs = args = NULL; client = http_accept_request(sendsms_port, &ip, &url, &hdrs, &body, &args); if (client == NULL) break; info(0, "smsbox: Got HTTP request <%s> from <%s>", octstr_get_cstr(url), octstr_get_cstr(ip)); /* * determine which kind of HTTP request this is any * call the necessary routine for it */ /* sendsms */ if (octstr_compare(url, sendsms_url) == 0) { /* * decide if this is a GET or POST request and let the * related routine handle the checking */ if (body == NULL) answer = smsbox_req_sendsms(args, ip, &status, client); else answer = smsbox_sendsms_post(hdrs, body, ip, &status, client); } /* XML-RPC */ else if (octstr_compare(url, xmlrpc_url) == 0) { /* * XML-RPC request needs to have a POST body */ if (body == NULL) { answer = octstr_create("Incomplete request."); status = HTTP_BAD_REQUEST; } else answer = smsbox_xmlrpc_post(hdrs, body, ip, &status); } /* sendota */ else if (octstr_compare(url, sendota_url) == 0) { if (body == NULL) answer = smsbox_req_sendota(args, ip, &status, client); else answer = smsbox_sendota_post(hdrs, body, ip, &status, client); } /* add aditional URI compares here */ else { answer = octstr_create("Unknown request."); status = HTTP_NOT_FOUND; } debug("sms.http", 0, "Status: %d Answer: <%s>", status, octstr_get_cstr(answer)); octstr_destroy(ip); octstr_destroy(url); http_destroy_headers(hdrs); octstr_destroy(body); http_destroy_cgiargs(args); if (immediate_sendsms_reply || status != HTTP_ACCEPTED) http_send_reply(client, status, sendsms_reply_hdrs, answer); else { debug("sms.http", 0, "Delayed reply - wait for bearerbox"); } octstr_destroy(answer); } } /*********************************************************************** * Main program. Configuration, signal handling, etc. */ static void signal_handler(int signum) { /* On some implementations (i.e. linuxthreads), signals are delivered * to all threads. We only want to handle each signal once for the * entire box, and we let the gwthread wrapper take care of choosing * one. */ if (!gwthread_shouldhandlesignal(signum)) return; switch (signum) { case SIGINT: case SIGTERM: if (program_status != shutting_down) { error(0, "SIGINT received, aborting program..."); program_status = shutting_down; } break; case SIGHUP: warning(0, "SIGHUP received, catching and re-opening logs"); log_reopen(); alog_reopen(); break; /* * It would be more proper to use SIGUSR1 for this, but on some * platforms that's reserved by the pthread support. */ case SIGQUIT: warning(0, "SIGQUIT received, reporting memory usage."); gw_check_leaks(); break; } } static void setup_signal_handlers(void) { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGPIPE, &act, NULL); } static Cfg *init_smsbox(Cfg *cfg) { CfgGroup *grp; Octstr *logfile; Octstr *p; long lvl, value; Octstr *http_proxy_host = NULL; long http_proxy_port = -1; int http_proxy_ssl = 0; List *http_proxy_exceptions = NULL; Octstr *http_proxy_username = NULL; Octstr *http_proxy_password = NULL; Octstr *http_proxy_exceptions_regex = NULL; int ssl = 0; int lf, m; long max_req; bb_port = BB_DEFAULT_SMSBOX_PORT; bb_ssl = 0; bb_host = octstr_create(BB_DEFAULT_HOST); logfile = NULL; lvl = 0; lf = m = 1; /* * first we take the port number in bearerbox and other values from the * core group in configuration file */ grp = cfg_get_single_group(cfg, octstr_imm("core")); cfg_get_integer(&bb_port, grp, octstr_imm("smsbox-port")); #ifdef HAVE_LIBSSL cfg_get_bool(&bb_ssl, grp, octstr_imm("smsbox-port-ssl")); #endif /* HAVE_LIBSSL */ cfg_get_integer(&http_proxy_port, grp, octstr_imm("http-proxy-port")); #ifdef HAVE_LIBSSL cfg_get_bool(&http_proxy_ssl, grp, octstr_imm("http-proxy-ssl")); #endif /* HAVE_LIBSSL */ http_proxy_host = cfg_get(grp, octstr_imm("http-proxy-host")); http_proxy_username = cfg_get(grp, octstr_imm("http-proxy-username")); http_proxy_password = cfg_get(grp, octstr_imm("http-proxy-password")); http_proxy_exceptions = cfg_get_list(grp, octstr_imm("http-proxy-exceptions")); http_proxy_exceptions_regex = cfg_get(grp, octstr_imm("http-proxy-exceptions-regex")); #ifdef HAVE_LIBSSL conn_config_ssl(grp); #endif /* * get the remaining values from the smsbox group */ grp = cfg_get_single_group(cfg, octstr_imm("smsbox")); if (grp == NULL) panic(0, "No 'smsbox' group in configuration"); smsbox_id = cfg_get(grp, octstr_imm("smsbox-id")); p = cfg_get(grp, octstr_imm("bearerbox-host")); if (p != NULL) { octstr_destroy(bb_host); bb_host = p; } cfg_get_integer(&bb_port, grp, octstr_imm("bearerbox-port")); #ifdef HAVE_LIBSSL if (cfg_get_bool(&ssl, grp, octstr_imm("bearerbox-port-ssl")) != -1) bb_ssl = ssl; #endif /* HAVE_LIBSSL */ cfg_get_bool(&mo_recode, grp, octstr_imm("mo-recode")); if(mo_recode < 0) mo_recode = 0; reply_couldnotfetch= cfg_get(grp, octstr_imm("reply-couldnotfetch")); if (reply_couldnotfetch == NULL) reply_couldnotfetch = octstr_create("Could not fetch content, sorry."); reply_couldnotrepresent= cfg_get(grp, octstr_imm("reply-couldnotfetch")); if (reply_couldnotrepresent == NULL) reply_couldnotrepresent = octstr_create("Result could not be represented " "as an SMS message."); reply_requestfailed= cfg_get(grp, octstr_imm("reply-requestfailed")); if (reply_requestfailed == NULL) reply_requestfailed = octstr_create("Request Failed"); reply_emptymessage= cfg_get(grp, octstr_imm("reply-emptymessage")); if (reply_emptymessage == NULL) reply_emptymessage = octstr_create(""); { Octstr *os; os = cfg_get(grp, octstr_imm("white-list")); if (os != NULL) { white_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } os = cfg_get(grp, octstr_imm("white-list-regex")); if (os != NULL) { if ((white_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } os = cfg_get(grp, octstr_imm("black-list")); if (os != NULL) { black_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } os = cfg_get(grp, octstr_imm("black-list-regex")); if (os != NULL) { if ((black_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); } } cfg_get_integer(&sendsms_port, grp, octstr_imm("sendsms-port")); /* check if want to bind to a specific interface */ sendsms_interface = cfg_get(grp, octstr_imm("sendsms-interface")); cfg_get_integer(&sms_max_length, grp, octstr_imm("sms-length")); #ifdef HAVE_LIBSSL cfg_get_bool(&ssl, grp, octstr_imm("sendsms-port-ssl")); #endif /* HAVE_LIBSSL */ /* * load the configuration settings for the sendsms and sendota URIs * else assume the default URIs, st. */ if ((sendsms_url = cfg_get(grp, octstr_imm("sendsms-url"))) == NULL) sendsms_url = octstr_imm("/cgi-bin/sendsms"); if ((xmlrpc_url = cfg_get(grp, octstr_imm("xmlrpc-url"))) == NULL) xmlrpc_url = octstr_imm("/cgi-bin/xmlrpc"); if ((sendota_url = cfg_get(grp, octstr_imm("sendota-url"))) == NULL) sendota_url = octstr_imm("/cgi-bin/sendota"); global_sender = cfg_get(grp, octstr_imm("global-sender")); accepted_chars = cfg_get(grp, octstr_imm("sendsms-chars")); sendsms_number_chars = accepted_chars ? octstr_get_cstr(accepted_chars) : SENDSMS_DEFAULT_CHARS; logfile = cfg_get(grp, octstr_imm("log-file")); cfg_get_integer(&lvl, grp, octstr_imm("log-level")); if (logfile != NULL) { info(0, "Starting to log to file %s level %ld", octstr_get_cstr(logfile), lvl); log_open(octstr_get_cstr(logfile), lvl, GW_NON_EXCL); octstr_destroy(logfile); } if ((p = cfg_get(grp, octstr_imm("syslog-level"))) != NULL) { long level; Octstr *facility; if ((facility = cfg_get(grp, octstr_imm("syslog-facility"))) != NULL) { log_set_syslog_facility(octstr_get_cstr(facility)); octstr_destroy(facility); } if (octstr_compare(p, octstr_imm("none")) == 0) { log_set_syslog(NULL, 0); } else if (octstr_parse_long(&level, p, 0, 10) > 0) { log_set_syslog("smsbox", level); } octstr_destroy(p); } else { log_set_syslog(NULL, 0); } if (global_sender != NULL) { info(0, "Service global sender set as '%s'", octstr_get_cstr(global_sender)); } /* should smsbox reply to sendsms immediate or wait for bearerbox ack */ cfg_get_bool(&immediate_sendsms_reply, grp, octstr_imm("immediate-sendsms-reply")); /* determine which timezone we use for access logging */ if ((p = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) { lf = (octstr_case_compare(p, octstr_imm("gmt")) == 0) ? 0 : 1; octstr_destroy(p); } /* should predefined markers be used, ie. prefixing timestamp */ cfg_get_bool(&m, grp, octstr_imm("access-log-clean")); /* open access-log file */ if ((p = cfg_get(grp, octstr_imm("access-log"))) != NULL) { info(0, "Logging accesses to '%s'.", octstr_get_cstr(p)); alog_open(octstr_get_cstr(p), lf, m ? 0 : 1); octstr_destroy(p); } /* HTTP queueing values */ cfg_get_integer(&max_http_retries, grp, octstr_imm("http-request-retry")); cfg_get_integer(&http_queue_delay, grp, octstr_imm("http-queue-delay")); if (sendsms_port > 0) { if (http_open_port_if(sendsms_port, ssl, sendsms_interface) == -1) { if (only_try_http) error(0, "Failed to open HTTP socket, ignoring it"); else panic(0, "Failed to open HTTP socket"); } else { info(0, "Set up send sms service at port %ld", sendsms_port); gwthread_create(sendsms_thread, NULL); } } /* set maximum allowed MO/DLR requests in parallel */ if (cfg_get_integer(&max_req, grp, octstr_imm("max-pending-requests")) == -1) max_req = HTTP_MAX_PENDING; max_pending_requests = semaphore_create(max_req); if (cfg_get_integer(&value, grp, octstr_imm("http-timeout")) == 0) http_set_client_timeout(value); /* * Reading the name we are using for ppg services from ppg core group */ if ((grp = cfg_get_single_group(cfg, octstr_imm("ppg"))) != NULL) { if ((ppg_service_name = cfg_get(grp, octstr_imm("service-name"))) == NULL) ppg_service_name = octstr_create("ppg"); } if (http_proxy_host != NULL && http_proxy_port > 0) { http_use_proxy(http_proxy_host, http_proxy_port, http_proxy_ssl, http_proxy_exceptions, http_proxy_username, http_proxy_password, http_proxy_exceptions_regex); } octstr_destroy(http_proxy_host); octstr_destroy(http_proxy_username); octstr_destroy(http_proxy_password); octstr_destroy(http_proxy_exceptions_regex); gwlist_destroy(http_proxy_exceptions, octstr_destroy_item); return cfg; } static int check_args(int i, int argc, char **argv) { if (strcmp(argv[i], "-H")==0 || strcmp(argv[i], "--tryhttp")==0) { only_try_http = 1; } else return -1; return 0; } int main(int argc, char **argv) { int cf_index; Octstr *filename; double heartbeat_freq = DEFAULT_HEARTBEAT; gwlib_init(); cf_index = get_and_set_debugs(argc, argv, check_args); setup_signal_handlers(); if (argv[cf_index] == NULL) filename = octstr_create("kannel.conf"); else filename = octstr_create(argv[cf_index]); cfg = cfg_create(filename); if (cfg_read(cfg) == -1) panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(filename)); octstr_destroy(filename); report_versions("smsbox"); init_smsbox(cfg); if (max_http_retries > 0) { info(0, "Using HTTP request queueing with %ld retries, %lds delay.", max_http_retries, http_queue_delay); } debug("sms", 0, "----------------------------------------------"); debug("sms", 0, GW_NAME " smsbox version %s starting", GW_VERSION); translations = urltrans_create(); if (translations == NULL) panic(0, "urltrans_create failed"); if (urltrans_add_cfg(translations, cfg) == -1) panic(0, "urltrans_add_cfg failed"); client_dict = dict_create(32, NULL); sendsms_reply_hdrs = http_create_empty_headers(); http_header_add(sendsms_reply_hdrs, "Content-type", "text/html"); http_header_add(sendsms_reply_hdrs, "Pragma", "no-cache"); http_header_add(sendsms_reply_hdrs, "Cache-Control", "no-cache"); caller = http_caller_create(); smsbox_requests = gwlist_create(); smsbox_http_requests = gwlist_create(); timerset = gw_timerset_create(); gwlist_add_producer(smsbox_requests); gwlist_add_producer(smsbox_http_requests); num_outstanding_requests = counter_create(); catenated_sms_counter = counter_create(); gwthread_create(obey_request_thread, NULL); gwthread_create(url_result_thread, NULL); gwthread_create(http_queue_thread, NULL); connect_to_bearerbox(bb_host, bb_port, bb_ssl, NULL /* bb_our_host */); /* XXX add our_host if required */ if (0 > heartbeat_start(write_to_bearerbox, heartbeat_freq, outstanding_requests)) { info(0, GW_NAME "Could not start heartbeat."); } identify_to_bearerbox(); read_messages_from_bearerbox(); info(0, GW_NAME " smsbox terminating."); heartbeat_stop(ALL_HEARTBEATS); http_close_all_ports(); gwthread_join_every(sendsms_thread); gwlist_remove_producer(smsbox_requests); gwlist_remove_producer(smsbox_http_requests); gwthread_join_every(obey_request_thread); http_caller_signal_shutdown(caller); gwthread_join_every(url_result_thread); gwthread_join_every(http_queue_thread); close_connection_to_bearerbox(); alog_close(); urltrans_destroy(translations); gw_assert(gwlist_len(smsbox_requests) == 0); gw_assert(gwlist_len(smsbox_http_requests) == 0); gwlist_destroy(smsbox_requests, NULL); gwlist_destroy(smsbox_http_requests, NULL); http_caller_destroy(caller); gw_timerset_destroy(timerset); counter_destroy(num_outstanding_requests); counter_destroy(catenated_sms_counter); octstr_destroy(bb_host); octstr_destroy(global_sender); octstr_destroy(accepted_chars); octstr_destroy(smsbox_id); octstr_destroy(sendsms_url); octstr_destroy(sendota_url); octstr_destroy(xmlrpc_url); octstr_destroy(reply_emptymessage); octstr_destroy(reply_requestfailed); octstr_destroy(reply_couldnotfetch); octstr_destroy(reply_couldnotrepresent); octstr_destroy(sendsms_interface); octstr_destroy(ppg_service_name); numhash_destroy(black_list); numhash_destroy(white_list); if (white_list_regex != NULL) gw_regex_destroy(white_list_regex); if (black_list_regex != NULL) gw_regex_destroy(black_list_regex); semaphore_destroy(max_pending_requests); cfg_destroy(cfg); dict_destroy(client_dict); http_destroy_headers(sendsms_reply_hdrs); /* * Just sleep for a while to get bearerbox chance to restart. * Otherwise we will fail while trying to connect to bearerbox! */ if (restart) { gwthread_sleep(10.0); /* now really restart */ restart_box(argv); } log_close_all(); gwlib_shutdown(); return 0; } gateway-1.4.5/gw/bb_http.c0000644000175000017500000004662413227613126014106 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * bb_http.c : bearerbox http adminstration commands * * NOTE: this is a special bearerbox module - it does call * functions from core module! (other modules are fully * encapsulated, and only called outside) * * Kalle Marjola 2000 for project Kannel */ #include #include #include #include "gwlib/gwlib.h" #include "bearerbox.h" /* passed from bearerbox core */ extern volatile sig_atomic_t bb_status; /* our own thingies */ static volatile sig_atomic_t httpadmin_running; static long ha_port; static Octstr *ha_interface; static Octstr *ha_password; static Octstr *ha_status_pw; static Octstr *ha_allow_ip; static Octstr *ha_deny_ip; /*--------------------------------------------------------- * static functions */ /* * check if the password matches. Return NULL if * it does (or is not required) */ static Octstr *httpd_check_authorization(List *cgivars, int status) { Octstr *password; static double sleep = 0.01; password = http_cgi_variable(cgivars, "password"); if (status) { if (ha_status_pw == NULL) return NULL; if (password == NULL) goto denied; if (octstr_compare(password, ha_password)!=0 && octstr_compare(password, ha_status_pw)!=0) goto denied; } else { if (password == NULL || octstr_compare(password, ha_password)!=0) goto denied; } sleep = 0.0; return NULL; /* allowed */ denied: gwthread_sleep(sleep); sleep += 1.0; /* little protection against brute force * password cracking */ return octstr_create("Denied"); } /* * check if we still have time to do things */ static Octstr *httpd_check_status(void) { if (bb_status == BB_SHUTDOWN || bb_status == BB_DEAD) return octstr_create("Avalanche has already started, too late to " "save the sheeps"); return NULL; } static Octstr *httpd_status(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 1))!= NULL) return reply; return bb_print_status(status_type); } static Octstr *httpd_store_status(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 1))!= NULL) return reply; return store_status(status_type); } static Octstr *httpd_loglevel(List *cgivars, int status_type) { Octstr *reply; Octstr *level; int new_loglevel; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; /* check if new loglevel is given */ level = http_cgi_variable(cgivars, "level"); if (level) { new_loglevel = atoi(octstr_get_cstr(level)); log_set_log_level(new_loglevel); return octstr_format("log-level set to %d", new_loglevel); } else { return octstr_create("New level not given"); } } static Octstr *httpd_shutdown(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if (bb_status == BB_SHUTDOWN) bb_status = BB_DEAD; else { bb_shutdown(); gwthread_wakeup(MAIN_THREAD_ID); } return octstr_create("Bringing system down"); } static Octstr *httpd_isolate(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; if (bb_isolate() == -1) return octstr_create("Already isolated"); else return octstr_create(GW_NAME " isolated from message providers"); } static Octstr *httpd_suspend(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; if (bb_suspend() == -1) return octstr_create("Already suspended"); else return octstr_create(GW_NAME " suspended"); } static Octstr *httpd_resume(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; if (bb_resume() == -1) return octstr_create("Already running"); else return octstr_create("Running resumed"); } static Octstr *httpd_restart(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; if (bb_status == BB_SHUTDOWN) { bb_status = BB_DEAD; gwthread_wakeup_all(); return octstr_create("Trying harder to restart"); } bb_restart(); return octstr_create("Restarting....."); } static Octstr *httpd_graceful_restart(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; if (bb_status == BB_SHUTDOWN) { bb_status = BB_DEAD; bb_restart(); return octstr_create("Already in shutdown phase, restarting hard..."); } bb_graceful_restart(); return octstr_create("Restarting gracefully....."); } static Octstr *httpd_flush_dlr(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; if (bb_flush_dlr() == -1) return octstr_create("Suspend " GW_NAME " before trying to flush DLR queue"); else return octstr_create("DLR queue flushed"); } static Octstr *httpd_stop_smsc(List *cgivars, int status_type) { Octstr *reply; Octstr *smsc; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; /* check if the smsc id is given */ smsc = http_cgi_variable(cgivars, "smsc"); if (smsc) { if (bb_stop_smsc(smsc) == -1) return octstr_format("Could not shut down smsc-id `%s'", octstr_get_cstr(smsc)); else return octstr_format("SMSC `%s' shut down", octstr_get_cstr(smsc)); } else return octstr_create("SMSC id not given"); } static Octstr *httpd_remove_smsc(List *cgivars, int status_type) { Octstr *reply; Octstr *smsc; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; /* check if the smsc id is given */ smsc = http_cgi_variable(cgivars, "smsc"); if (smsc) { if (bb_remove_smsc(smsc) == -1) return octstr_format("Could not remove smsc-id `%s'", octstr_get_cstr(smsc)); else return octstr_format("SMSC `%s' removed", octstr_get_cstr(smsc)); } else return octstr_create("SMSC id not given"); } static Octstr *httpd_add_smsc(List *cgivars, int status_type) { Octstr *reply; Octstr *smsc; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; /* check if the smsc id is given */ smsc = http_cgi_variable(cgivars, "smsc"); if (smsc) { if (bb_add_smsc(smsc) == -1) return octstr_format("Could not add smsc-id `%s'", octstr_get_cstr(smsc)); else return octstr_format("SMSC `%s' added", octstr_get_cstr(smsc)); } else return octstr_create("SMSC id not given"); } static Octstr *httpd_restart_smsc(List *cgivars, int status_type) { Octstr *reply; Octstr *smsc; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; /* check if the smsc id is given */ smsc = http_cgi_variable(cgivars, "smsc"); if (smsc) { if (bb_restart_smsc(smsc) == -1) return octstr_format("Could not re-start smsc-id `%s'", octstr_get_cstr(smsc)); else return octstr_format("SMSC `%s' re-started", octstr_get_cstr(smsc)); } else return octstr_create("SMSC id not given"); } static Octstr *httpd_reload_lists(List *cgivars, int status_type) { Octstr *reply; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; if (bb_reload_lists() == -1) return octstr_create("Could not re-load lists"); else return octstr_create("Black/white lists re-loaded"); } static Octstr *httpd_remove_message(List *cgivars, int status_type) { Octstr *reply; Octstr *message_id; if ((reply = httpd_check_authorization(cgivars, 0))!= NULL) return reply; if ((reply = httpd_check_status())!= NULL) return reply; /* check if the smsc id is given */ message_id = http_cgi_variable(cgivars, "id"); if (message_id) { if (octstr_len(message_id) != UUID_STR_LEN) return octstr_format("Message id should be %d characters long", UUID_STR_LEN); if (bb_remove_message(message_id) == -1) return octstr_format("Could not remove message id `%s'", octstr_get_cstr(message_id)); else return octstr_format("Message id `%s' removed", octstr_get_cstr(message_id)); } else return octstr_create("Message id not given"); } /* Known httpd commands and their functions */ static struct httpd_command { const char *command; Octstr * (*function)(List *cgivars, int status_type); } httpd_commands[] = { { "status", httpd_status }, { "store-status", httpd_store_status }, { "log-level", httpd_loglevel }, { "shutdown", httpd_shutdown }, { "suspend", httpd_suspend }, { "isolate", httpd_isolate }, { "resume", httpd_resume }, { "restart", httpd_restart }, { "graceful-restart", httpd_graceful_restart }, { "flush-dlr", httpd_flush_dlr }, { "stop-smsc", httpd_stop_smsc }, { "start-smsc", httpd_restart_smsc }, { "add-smsc", httpd_add_smsc }, { "remove-smsc", httpd_remove_smsc }, { "reload-lists", httpd_reload_lists }, { "remove-message", httpd_remove_message }, { NULL , NULL } /* terminate list */ }; static void httpd_serve(HTTPClient *client, Octstr *ourl, List *headers, Octstr *body, List *cgivars) { Octstr *reply, *final_reply, *url; char *content_type; char *header, *footer; int status_type; int i; long pos; reply = final_reply = NULL; /* for compiler please */ url = octstr_duplicate(ourl); /* Set default reply format according to client * Accept: header */ if (http_type_accepted(headers, "text/vnd.wap.wml")) { status_type = BBSTATUS_WML; content_type = "text/vnd.wap.wml"; } else if (http_type_accepted(headers, "text/html")) { status_type = BBSTATUS_HTML; content_type = "text/html"; } else if (http_type_accepted(headers, "text/xml")) { status_type = BBSTATUS_XML; content_type = "text/xml"; } else { status_type = BBSTATUS_TEXT; content_type = "text/plain"; } /* kill '/cgi-bin' prefix */ pos = octstr_search(url, octstr_imm("/cgi-bin/"), 0); if (pos != -1) octstr_delete(url, pos, 9); else if (octstr_get_char(url, 0) == '/') octstr_delete(url, 0, 1); /* look for type and kill it */ pos = octstr_search_char(url, '.', 0); if (pos != -1) { Octstr *tmp = octstr_copy(url, pos+1, octstr_len(url) - pos - 1); octstr_delete(url, pos, octstr_len(url) - pos); if (octstr_str_compare(tmp, "txt") == 0) status_type = BBSTATUS_TEXT; else if (octstr_str_compare(tmp, "html") == 0) status_type = BBSTATUS_HTML; else if (octstr_str_compare(tmp, "xml") == 0) status_type = BBSTATUS_XML; else if (octstr_str_compare(tmp, "wml") == 0) status_type = BBSTATUS_WML; octstr_destroy(tmp); } for (i=0; httpd_commands[i].command != NULL; i++) { if (octstr_str_compare(url, httpd_commands[i].command) == 0) { reply = httpd_commands[i].function(cgivars, status_type); break; } } /* check if command found */ if (httpd_commands[i].command == NULL) { char *lb = bb_status_linebreak(status_type); reply = octstr_format("Unknown command `%S'.%sPossible commands are:%s", ourl, lb, lb); for (i=0; httpd_commands[i].command != NULL; i++) octstr_format_append(reply, "%s%s", httpd_commands[i].command, lb); } gw_assert(reply != NULL); if (status_type == BBSTATUS_HTML) { header = "\n" "\n" GW_NAME "\n\n

"; footer = "

\n\n"; content_type = "text/html"; } else if (status_type == BBSTATUS_WML) { header = "\n" "\n" "\n\n \n

"; footer = "

\n
\n
\n"; content_type = "text/vnd.wap.wml"; } else if (status_type == BBSTATUS_XML) { header = "\n" "\n"; footer = "\n"; } else { header = ""; footer = ""; content_type = "text/plain"; } final_reply = octstr_create(header); octstr_append(final_reply, reply); octstr_append_cstr(final_reply, footer); /* debug("bb.http", 0, "Result: '%s'", octstr_get_cstr(final_reply)); */ http_destroy_headers(headers); headers = gwlist_create(); http_header_add(headers, "Content-Type", content_type); http_send_reply(client, HTTP_OK, headers, final_reply); octstr_destroy(url); octstr_destroy(ourl); octstr_destroy(body); octstr_destroy(reply); octstr_destroy(final_reply); http_destroy_headers(headers); http_destroy_cgiargs(cgivars); } static void httpadmin_run(void *arg) { HTTPClient *client; Octstr *ip, *url, *body; List *headers, *cgivars; while(bb_status != BB_DEAD) { if (bb_status == BB_SHUTDOWN) bb_shutdown(); client = http_accept_request(ha_port, &ip, &url, &headers, &body, &cgivars); if (client == NULL) break; if (is_allowed_ip(ha_allow_ip, ha_deny_ip, ip) == 0) { info(0, "HTTP admin tried from denied host <%s>, disconnected", octstr_get_cstr(ip)); http_close_client(client); continue; } httpd_serve(client, url, headers, body, cgivars); octstr_destroy(ip); } httpadmin_running = 0; } /*------------------------------------------------------------- * public functions * */ int httpadmin_start(Cfg *cfg) { CfgGroup *grp; int ssl = 0; #ifdef HAVE_LIBSSL Octstr *ssl_server_cert_file; Octstr *ssl_server_key_file; #endif /* HAVE_LIBSSL */ if (httpadmin_running) return -1; grp = cfg_get_single_group(cfg, octstr_imm("core")); if (cfg_get_integer(&ha_port, grp, octstr_imm("admin-port")) == -1) panic(0, "Missing admin-port variable, cannot start HTTP admin"); ha_interface = cfg_get(grp, octstr_imm("admin-interface")); ha_password = cfg_get(grp, octstr_imm("admin-password")); if (ha_password == NULL) panic(0, "You MUST set HTTP admin-password"); ha_status_pw = cfg_get(grp, octstr_imm("status-password")); ha_allow_ip = cfg_get(grp, octstr_imm("admin-allow-ip")); ha_deny_ip = cfg_get(grp, octstr_imm("admin-deny-ip")); #ifdef HAVE_LIBSSL cfg_get_bool(&ssl, grp, octstr_imm("admin-port-ssl")); /* * check if SSL is desired for HTTP servers and then * load SSL client and SSL server public certificates * and private keys */ ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file")); ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file")); if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) { /* we are fine here, the following call is now in conn_config_ssl(), * so there is no reason to do this twice. use_global_server_certkey_file(ssl_server_cert_file, ssl_server_key_file); */ } else if (ssl) { panic(0, "You MUST specify cert and key files within core group for SSL-enabled HTTP servers!"); } octstr_destroy(ssl_server_cert_file); octstr_destroy(ssl_server_key_file); #endif /* HAVE_LIBSSL */ http_open_port_if(ha_port, ssl, ha_interface); if (gwthread_create(httpadmin_run, NULL) == -1) panic(0, "Failed to start a new thread for HTTP admin"); httpadmin_running = 1; return 0; } void httpadmin_stop(void) { http_close_all_ports(); gwthread_join_every(httpadmin_run); octstr_destroy(ha_interface); octstr_destroy(ha_password); octstr_destroy(ha_status_pw); octstr_destroy(ha_allow_ip); octstr_destroy(ha_deny_ip); ha_password = NULL; ha_status_pw = NULL; ha_allow_ip = NULL; ha_deny_ip = NULL; } gateway-1.4.5/gw/ota_prov_attr.h0000644000175000017500000004553613227613126015355 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * ota_prov_attr.h: binary encoded XML tag constants for the OTA provisioning * * In order to make handsets accept browser settings sent over the air, the * settings must be provided in a binary encoded XML document with a specific * MIME-type depending on the setting type. The settings must be pushed over * SMS to a predefined WDP (Wireless Datagram Protocol) port (49999) as a WSP * (Wirless Session Protocol) connection less unsecure push. Handsets able to * receive settings over the air must always listen on this port. * * Two setting MIME-types are defined: * * - application/x-wap-prov.browser-settings * - application/x-wap-prov.browser-bookmarks * * Description of the XML DTD (Document Type Definition): * * * * * * * * Simple example of a XML document: * * * * * * * * * * * * * * * * * * * * * * * * (based upon the Nokia Over The Air Settings Specification) * * initial re-engineered code by Yann Muller - 3G Lab, 2000. * fixed to support official specs by Stipe Tolj - Wapme Systems AG, 2001. * extensive inline documentation by Stipe Tolj - Wapme Systems AG, 2001. */ /* * The XML document which is build in smsbox.c:smsbox_req_sendota() is * binary encoded according to WBXML with the following global tokens */ #define WBXML_TOK_END_STR_I 0x00 #define WBXML_TOK_END 0x01 #define WBXML_TOK_STR_I 0x03 /******************************************************************** * Description of the single XML tag tokens */ #define WBXML_TOK_CHARACTERISTIC_LIST 0x05 /* * This element groups the browser settings into logical different types: * ADDRESS, BOOKMARK, URL, MMSURL, NAME and ID. */ #define WBXML_TOK_CHARACTERISTIC 0x06 /* * The PARM element is used to provide the actual value for the individual * settings parameters within each CHARACTERISTIC element. */ #define WBXML_TOK_PARM 0x07 /* * Tokens representing the NAME or VALUE tags */ #define WBXML_TOK_NAME 0x10 #define WBXML_TOK_VALUE 0x11 /******************************************************************** * CHARACTERISTIC elements with TYPE=ADDRESS * * Characteristics elements with the TYPE=ADDRESS attribute embrace settings * concerning a particular bearer, e.g. GSM/SMS or GSM/CSD. Several address * settings can be provided in one document. However, for each bearer, only * the address settings listed first will be used. The type of the bearer is * specified by a PARM attribute and depending on the bearer additional PARM * elements are required or optional. * * Example: * * * * * * * * * */ #define WBXML_TOK_TYPE_ADDRESS 0x06 /* * The PARM element with NAME=BEARER attribute is used to identify the bearer * to be used for a specific setting set. VALUE can be assigned following: * * VALUE -> [*GSM_CSD*|GSM_SMS|GSM_USSD|IS136_CSD|GPRS] */ #define WBXML_TOK_NAME_BEARER 0x12 #define WBXML_TOK_VALUE_GSM_CSD 0x45 #define WBXML_TOK_VALUE_GSM_SMS 0x46 #define WBXML_TOK_VALUE_GSM_USSD 0x47 #define WBXML_TOK_VALUE_IS136_CSD 0x48 #define WBXML_TOK_VALUE_GPRS 0x49 /* * The PARM element with NAME=PROXY attribute is used to identify the IP * address of the WAP proxy in case of CSD and the service number in case of * SMS. In case of USSD the PROXY can be either an IP address or an MSISDN * number. This is indicated in the PROXY_TYPE PARM element. VALUE can be * assigned following: * * VALUE -> proxy(using inline string) */ #define WBXML_TOK_NAME_PROXY 0x13 /* * The PARM element with NAME=PORT attribute specifies whether connection less * or connection oriented connections should be used. VALUE can be assigned * following: * * VALUE -> [*9200*|9201|9202|9203] * * Use 9200 (or 9202) for connection less connections and 9201 (or 9203) for * connection oriented connections. Port numbers 9202 and 9203 enable secure * connections (by means of WTLS), whereas port numbers 9200 and 9201 disable * secure connections. */ #define WBXML_TOK_NAME_PORT 0x14 #define WBXML_TOK_VALUE_PORT_9200 0x60 #define WBXML_TOK_VALUE_PORT_9201 0x61 #define WBXML_TOK_VALUE_PORT_9202 0x62 #define WBXML_TOK_VALUE_PORT_9203 0x63 /* * The PARM element with the NAME=PROXY_TYPE attribute is used to identify * the format of the PROXY PARM element. VALUE can be assigned following: * * VALUE -> [*MSISDN_NO*|IPV4] */ #define WBXML_TOK_NAME_PROXY_TYPE 0x16 #define WBXML_TOK_VALUE_MSISDN_NO 0x76 #define WBXML_TOK_VALUE_IPV4 0x77 /* * The PARM elements with the NAME=PROXY_AUTHNAME and NAME=PROXY_AUTHSECRET * attributes indicates the login name and password to be used for gateway * required authentication. Support of this PARM elements is manufacturer * specific. VALUEs can be assigned following: * * VALUE -> login name(using inline string) * VALUE -> password(using inline string) */ #define WBXML_TOK_NAME_PROXY_AUTHNAME 0x18 #define WBXML_TOK_NAME_PROXY_AUTHSECRET 0x19 /* * The PARM element with the NAME=PROXY_LOGINTYPE attribute specifies whether * an automatic or manual login should be performed at the proxy. VALUE can * be assigned following: * * VALUE -> [AUTOMATIC|MANUAL] * * Using the MANUAL logintype the user will be prompted for username and * password when a browse session is started. Using the AUTOMATIC logintype * the user will be NOT prompted for username and password when a browse * session is started, but a static name and password from the WAP settingset * will be used. */ #define WBXML_TOK_NAME_PROXY_LOGINTYPE 0x1E #define WBXML_TOK_VALUE_AUTOMATIC 0x64 #define WBXML_TOK_VALUE_MANUAL 0x65 /* * The PARM element with the NAME=PPP_AUTHTYPE attribute indicates which * protocol to use for user authentication. VALUE can be assigned following: * * VALUE -> [*PAP*|CHAP|MS_CHAP] * * PAP is short for Password Authentication Protocol, a type of authentication * which uses clear-text passwords and is the least sophisticated * authentication protocol, and CHAP stands for Challenge Handshake * Authentication Protocol, a protocol used to negotiate the most secure form * of encrypted authentication supported by both server and client. MS_CHAP * (Microsoft(tm)-CHAP) is similar to the CHAP protocol, but is using an * encryption scheme that is alternative to the one used for CHAP. */ #define WBXML_TOK_NAME_PPP_AUTHTYPE 0x22 #define WBXML_TOK_VALUE_AUTH_PAP 0x70 #define WBXML_TOK_VALUE_AUTH_CHAP 0x71 #define WBXML_TOK_VALUE_AUTH_MS_CHAP 0x78 /* * The PARM elements with the NAME=PPP_AUTHNAME and NAME=PPP_AUTHSECRET * attributes indicate the login name and password to be used. VALUEs can be * assigned following: * * VALUE -> login name(using inline string) * VALUE -> password(using inline string) * * Maximum length of login name is 32 bytes. * Maximum length of password is 20 bytes. */ #define WBXML_TOK_NAME_PPP_AUTHNAME 0x23 #define WBXML_TOK_NAME_PPP_AUTHSECRET 0x24 /* * The PARM element with the NAME=PPP_LOGINTYPE attribute specifies whether an * automatic or manual login should be performed in the PPP negotiation at the * access point of the service provider. VALUE can be assigned following * * VALUE -> [AUTOMATIC|MANUAL] * * (same impacts as for PROXY_LOGINTYPE) */ #define WBXML_TOK_NAME_PPP_LOGINTYPE 0x1D /* * The PARM element with the NAME=CSD_DIALSTRING attribute specifies the * MSISDN number of the modem pool. VALUE can be assigned following: * * VALUE -> msisdn number(using inline string) * * Maximum length of msisdn number is 21 bytes. */ #define WBXML_TOK_NAME_CSD_DIALSTRING 0x21 /* * The PARM element with the NAME=CSD_CALLTYPE attribute indicates the type * of circuit switched call to be used for connection. VALUE can be assigned * following: * * VALUE -> [*ANALOGUE*|ISDN] * * (In general the call type should be set to ANALOGUE since ISDN is not * generaly available on all networks.) */ #define WBXML_TOK_NAME_CSD_CALLTYPE 0x28 #define WBXML_TOK_VALUE_CONN_ANALOGUE 0x72 #define WBXML_TOK_VALUE_CONN_ISDN 0x73 /* * The PARM element with the NAME=CSD_CALLSPEED attribute indicates the * desired call speed to be used for the connection. VALUE can be assgined * following: * * VALUE -> [*AUTO*|*9600*|14400|19200|28800|38400|43200|57600] * * Default value is AUTO when CSD_CALLTYPE is ANALOGUE and 9600 when * CSD_CALLTYPE is ISDN. */ #define WBXML_TOK_NAME_CSD_CALLSPEED 0x29 #define WBXML_TOK_VALUE_SPEED_AUTO 0x6A #define WBXML_TOK_VALUE_SPEED_9600 0x6B #define WBXML_TOK_VALUE_SPEED_14400 0x6C #define WBXML_TOK_VALUE_SPEED_19200 0x6D #define WBXML_TOK_VALUE_SPEED_28800 0x6E #define WBXML_TOK_VALUE_SPEED_38400 0x6F #define WBXML_TOK_VALUE_SPEED_43200 0x74 #define WBXML_TOK_VALUE_SPEED_57600 0x75 /* * The PARM element with the NAME=ISP_NAME attribute indicates the name of the * Internet Service Provider. Support of this PARM element is manufacturer * specific. VALUE can be assigned following: * * VALUE -> isp name(using inline string) * * Maximum length of isp name is 20 bytes. */ #define WBXML_TOK_NAME_ISP_NAME 0x7E /* * The PARM element with the NAME=SMS_SMSC_ADDRESS attribute indicates the * MSISDN number of the SMS Service Center (SMSC). VALUE can be assigned * following: * * VALUE -> sms smsc address(using inline string) * * Maximum length of sms smsc address is 21 bytes. */ #define WBXML_TOK_NAME_SMS_SMSC_ADDRESS 0x1A /* * The PARM element with the name NAME=USSD_SERVICE_CODE attribute indicates * the USSD service code. VALUE can be assigned following: * * VALUE -> ussd service code(using inline string) * * Maximum length of ussd service code is 10 bytes. */ #define WBXML_TOK_NAME_USSD_SERVICE_CODE 0x1B /* * The PARM element with the NAME=GPRS_ACCESSPOINTNAME attribute indicates * the access point name on Gateway GRPS Support Nodes (GGSN). Allowed * characters are: ['a'-'z','A'-'Z','0'-'9','.','-','*'] * * VALUE -> acess point name(using inline string) * * Maximum length of access point name is 100 bytes. */ #define WBXML_TOK_NAME_GPRS_ACCESSPOINTNAME 0x1C /******************************************************************** * CHARACTERISTIC elements with TYPE=URL * * The CHARACTERISTIC element with the TYPE=URL attribute has only one * attribute which indicates the URL of the home page. VALUES can be assigned * following: * * VALUE -> url(using inline string) * * Maximum length of URL is 100 bytes. * * Example: * * */ #define WBXML_TOK_TYPE_URL 0x07 /******************************************************************** * CHARACTERISTIC elements with TYPE=MMSURL * * The CHARACTERISTIC element with the TYPE=MMSURL attribute has only one * attribute which indicates the URL of the MMSC. VALUES can be assigned * following: * * VALUE -> url(using inline string) * * Maximum length of URL is 100 bytes. * * Example: * * */ #define WBXML_TOK_TYPE_MMSURL 0x7C /******************************************************************** * CHARACTERISTIC elements with TYPE=NAME * * This element type must contain exactly one PARM element with NAME=NAME, * which states the user-recognisable name to apply for the settings. The * VALUE of the PARM element can be assigned following: * * VALUE -> name(using inline string) * * Maximum length of name is 20 bytes. * * Example: * * * * */ #define WBXML_TOK_TYPE_NAME 0x08 /******************************************************************** * CHARACTERISTIC elements with TYPE=BOOKMARK * * This element must contain exactly two PARM elements, which define the * name and URL for a homepage or for bookmarks. * * When this element is used with the MIME-type *.browser-settings the first * element indicates the homepage to be used together with the corresponding * settings. Note that the URL included in this element and the CHARACTERISTIC * element TYPE=URL are both required to define a homepage and their content * must be equal. A homepage and several bookmarks can be provided in one * document of the MIME-type referred to above. However, the maximum number of * bookmarks accepted is manufacturer specific. * * When this element is used with the MIME-type *.browser-bookmarks the * element indicates bookmarks only * * Example: * * * * * */ #define WBXML_TOK_TYPE_BOOKMARK 0x7F /* * The PARM element with the NAME=NAME attribute indicates the name of the * bookmark or homepage. VALUE can be assigned following: * * VALUE -> bookmark name(using inline string) * * Maximum length of bookmark name is 50 bytes. */ #define WBXML_TOK_NAME_NAME 0x15 /* * The PARM element with the NAME=URL attribute indicates the URL of the * bookmark or homepage. VALUE can be assigned following: * * VALUE -> bookmark url(using inline string) * * Maximum length of bookmark url is 255 bytes. */ #define WBXML_TOK_NAME_URL 0x17 /******************************************************************** * CHARACTERISTIC elements with TYPE=ID * * This element type must contain exactly one PARM element, which defines an * ID to be used to provide some security to the provisioning application. * The ID should be known by the subscriber through the subscription or * through other communication with the operator. When provisioning data * containing the ID is received the user is able to verify the received ID * with the ID previously received by other means from the operator. Support * of this CHARACTERISTIC element is manufacturer specific. * * Example: * * * * */ #define WBXML_TOK_TYPE_ID 0x7D /* * The PARM elment with the NAME=NAME attribute indicates the ID. VALUE can be * assigned following: * * VALUE -> id(using inline string) * * Maximum length of id is 8 bytes. */ /* end of ota_prov_attr.h */ gateway-1.4.5/gw/other_smskannel.conf0000644000175000017500000000352110477115750016354 0ustar toljtolj# # THIS IS A SAMPLE CONFIGURATION FOR SMS KANNEL # # This second/other SMS Kannel configuration is meant to be used # together with original gw/smskannel.conf, to test out Kannel as # HTTP SMSC. # # The entire system is run like this # # 1% gw/bearerbox gw/smskannel.conf # 2% gw/smsbox gw/smskannel.conf # 1% gw/bearerbox gw/other_smskannel.conf # 2% gw/smsbox gw/other_smskannel.conf # 3% test/fakesmsc -r 10000 -H localhost -i 1 -m 100 "100 300 text relay nop" # # ..all 3 commands in separate shells (or screen sessions) # # For any modifications to this file, see Kannel User Guide # If that does not help, send email to users@kannel.org # # Kalle Marjola Mar 2001 # group = core admin-port = 15000 smsbox-port = 15001 admin-password = bar #status-password = foo #admin-deny-ip = "" #admin-allow-ip = "" #log-file = "/tmp/bearerbox2.log" #log-level = 0 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" #unified-prefix = "+358,00358,0;+,00" #access-log = "/tmp/access2.log" #store-file = "/tmp/kannel2.store" #ssl-server-cert-file = "cert.pem" #ssl-server-key-file = "key.pem" #ssl-certkey-file = "mycertandprivkeyfile.pem" # SMSC CONNECTIONS group = smsc smsc = http system-type = kannel port = 15130 #connect-allow-ip = "127.0.0.1" smsc-username = tester smsc-password = foobar send-url = "http://localhost:13013/cgi-bin/sendsms" # SMSBOX SETUP group = smsbox bearerbox-host = 127.0.0.1 sendsms-port = 15015 global-sender = 15015 #sendsms-chars = "0123456789 +-" #log-file = "/tmp/smsbox2.log" #log-level = 0 #access-log = "/tmp/access2.log" # SEND-SMS USERS group = sendsms-user username = tester password = foobar #user-deny-ip = "" #user-allow-ip = "" # SERVICES group = sms-service keyword = nop text = "You asked nothing and I did it!" # there should be default always group = sms-service keyword = default text = "No service specified" gateway-1.4.5/gw/bb_alog.c0000644000175000017500000003440313227613126014041 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/bb_alog.c -- encapsulate custom access log logic and escape code parsing * * Stipe Tolj * Alexander Malysh */ #include "gwlib/gwlib.h" #include "msg.h" #include "sms.h" #include "bearerbox.h" #include "smscconn.h" static Octstr *custom_log_format = NULL; /******************************************************************** * Routine to escape the values into the custom log format. * * The following escape code values are acceptable within the * 'access-log-format' config directive of bearerbox: * * %l - log message * %i - smsc-id * %n - service-name (for MO) or sendsms-user (for MT) * %A - account * %B - billing identifier/information * %p - sender (from) * %P - receiver (to) * %m - message class (mclass) * %c - coding * %M - message waiting indicator (mwi) * %C - compress indicator * %d - dlr_mask * %R - dlr_url * %D - meta-data * %a - the original SMS message, spaces squeezed * %u - UDH data (in escaped form) * %U - length of UDH data * %k - the keyword in the SMS request (the first word in the SMS message) * %s - next word from the SMS message, starting with the second one * %S - same as %s, but '*' is converted to '~' * %r - words not yet used by %s * %b - the original SMS message * %N - the DLR notification message * %L - length of SMS message * %t - the time of the message, formatted as "YYYY-MM-DD HH:MM:SS" * %T - the time of the message, in UNIX epoch timestamp format * %I - the internal message ID * %F - the foreign (smsc-provided) message ID * %x - smsbox-id, identifying the smsbox connection * * Most escape codes should be compatible with escape codes used in * sms-service groups. * * The default access-log-format would look like this (if access-log-clean is true): * "%t %l [SMSC:%i] [SVC:%n] [ACT:%A] [BINF:%B] [FID:%F] [META:%D] [from:%p] [to:%P] \ * [flags:%m:%c:%M:%C:%d] [msg:%L:%b] [udh:%U:%u]" */ static Octstr *get_pattern(SMSCConn *conn, Msg *msg, const char *message) { int nextarg, j; struct tm tm; int num_words; List *word_list; Octstr *result; const char *pattern; Octstr *temp, *text, *udh; size_t n; long i; text = msg->sms.msgdata ? octstr_duplicate(msg->sms.msgdata) : octstr_create(""); udh = msg->sms.udhdata ? octstr_duplicate(msg->sms.udhdata) : octstr_create(""); if ((msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2)) octstr_binary_to_hex(text, 1); else octstr_convert_printable(text); octstr_binary_to_hex(udh, 1); if (octstr_len(text)) { word_list = octstr_split_words(text); num_words = gwlist_len(word_list); } else { word_list = gwlist_create(); num_words = 0; } result = octstr_create(""); pattern = octstr_get_cstr(custom_log_format); nextarg = 1; while (*pattern != '\0') { n = strcspn(pattern, "%"); octstr_append_data(result, pattern, n); pattern += n; gw_assert(*pattern == '%' || *pattern == '\0'); if (*pattern == '\0') break; pattern++; switch (*pattern) { case 'k': if (num_words <= 0) break; octstr_append(result, gwlist_get(word_list, 0)); break; case 's': if (nextarg >= num_words) break; octstr_append(result, gwlist_get(word_list, nextarg)); ++nextarg; break; case 'S': if (nextarg >= num_words) break; temp = gwlist_get(word_list, nextarg); for (i = 0; i < octstr_len(temp); ++i) { if (octstr_get_char(temp, i) == '*') octstr_append_char(result, '~'); else octstr_append_char(result, octstr_get_char(temp, i)); } ++nextarg; break; case 'r': for (j = nextarg; j < num_words; ++j) { if (j != nextarg) octstr_append_char(result, '+'); octstr_append(result, gwlist_get(word_list, j)); } break; case 'l': if (message) octstr_append_cstr(result, message); break; case 'P': if (msg->sms.receiver) octstr_append(result, msg->sms.receiver); break; case 'p': if (msg->sms.sender) octstr_append(result, msg->sms.sender); break; case 'a': for (j = 0; j < num_words; ++j) { if (j > 0) octstr_append_char(result, ' '); octstr_append(result, gwlist_get(word_list, j)); } break; case 'b': if (text) octstr_append(result, text); break; case 'L': octstr_append_decimal(result, octstr_len(msg->sms.msgdata)); break; case 't': tm = gw_gmtime(msg->sms.time); octstr_format_append(result, "%04d-%02d-%02d %02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case 'T': if (msg->sms.time != MSG_PARAM_UNDEFINED) octstr_format_append(result, "%ld", msg->sms.time); break; case 'i': if (conn && smscconn_id(conn)) octstr_append(result, smscconn_id(conn)); else if (conn && smscconn_name(conn)) octstr_append(result, smscconn_name(conn)); else if (msg->sms.smsc_id) octstr_append(result, msg->sms.smsc_id); break; case 'I': if (!uuid_is_null(msg->sms.id)) { char id[UUID_STR_LEN + 1]; uuid_unparse(msg->sms.id, id); octstr_append_cstr(result, id); } break; case 'n': if (msg->sms.service != NULL) octstr_append(result, msg->sms.service); break; case 'd': octstr_append_decimal(result, msg->sms.dlr_mask); break; case 'R': if (msg->sms.dlr_url != NULL) octstr_append(result, msg->sms.dlr_url); break; case 'N': if (msg->sms.sms_type == report_mo && text != NULL) octstr_append(result, text); break; case 'D': /* meta_data */ if (msg->sms.meta_data != NULL) octstr_append(result, msg->sms.meta_data); break; case 'c': octstr_append_decimal(result, msg->sms.coding); break; case 'm': octstr_append_decimal(result, msg->sms.mclass); break; case 'C': octstr_append_decimal(result, msg->sms.compress); break; case 'M': octstr_append_decimal(result, msg->sms.mwi); break; case 'u': if (octstr_len(udh)) { octstr_append(result, udh); } break; case 'U': octstr_append_decimal(result, octstr_len(msg->sms.udhdata)); break; case 'B': /* billing identifier/information */ if (octstr_len(msg->sms.binfo)) { octstr_append(result, msg->sms.binfo); } break; case 'A': /* account */ if (octstr_len(msg->sms.account)) { octstr_append(result, msg->sms.account); } break; case 'F': /* the foreign (smsc-provided) message ID */ if (msg->sms.foreign_id != NULL) octstr_append(result, msg->sms.foreign_id); break; case 'x': /* the boxc_id, hence the smsbox-id of the message */ if (msg->sms.boxc_id != NULL) octstr_append(result, msg->sms.boxc_id); break; /* XXX add more here if needed */ case '%': octstr_format_append(result, "%%"); break; default: warning(0, "Unknown escape code (%%%c) within custom-log-format, skipping!", *pattern); octstr_format_append(result, "%%%c", *pattern); break; } /* switch(...) */ pattern++; } /* for ... */ gwlist_destroy(word_list, octstr_destroy_item); octstr_destroy(text); octstr_destroy(udh); return result; } /******************************************************************** * */ void bb_alog_init(const Octstr *format) { gw_assert(format != NULL); custom_log_format = octstr_duplicate(format); } void bb_alog_shutdown(void) { octstr_destroy(custom_log_format); custom_log_format = NULL; } void bb_alog_sms(SMSCConn *conn, Msg *msg, const char *message) { Octstr *text = NULL; gw_assert(msg_type(msg) == sms); /* if we don't have any custom log, then use our "default" one */ if (custom_log_format == NULL) { Octstr *udh; const Octstr *cid; text = msg->sms.msgdata ? octstr_duplicate(msg->sms.msgdata) : octstr_create(""); udh = msg->sms.udhdata ? octstr_duplicate(msg->sms.udhdata) : octstr_create(""); if (conn && smscconn_id(conn)) cid = smscconn_id(conn); else if (conn && smscconn_name(conn)) cid = smscconn_name(conn); else if (msg->sms.smsc_id) cid = msg->sms.smsc_id; else cid = octstr_imm(""); if ((msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2)) octstr_binary_to_hex(text, 1); else octstr_convert_printable(text); octstr_binary_to_hex(udh, 1); alog("%s [SMSC:%s] [SVC:%s] [ACT:%s] [BINF:%s] [FID:%s] [META:%s] [from:%s] [to:%s] [flags:%ld:%ld:%ld:%ld:%ld] " "[msg:%ld:%s] [udh:%ld:%s]", message, octstr_get_cstr(cid), msg->sms.service ? octstr_get_cstr(msg->sms.service) : "", msg->sms.account ? octstr_get_cstr(msg->sms.account) : "", msg->sms.binfo ? octstr_get_cstr(msg->sms.binfo) : "", msg->sms.foreign_id ? octstr_get_cstr(msg->sms.foreign_id) : "", msg->sms.meta_data ? octstr_get_cstr(msg->sms.meta_data) : "", msg->sms.sender ? octstr_get_cstr(msg->sms.sender) : "", msg->sms.receiver ? octstr_get_cstr(msg->sms.receiver) : "", msg->sms.mclass, msg->sms.coding, msg->sms.mwi, msg->sms.compress, msg->sms.dlr_mask, octstr_len(msg->sms.msgdata), octstr_get_cstr(text), octstr_len(msg->sms.udhdata), octstr_get_cstr(udh) ); octstr_destroy(udh); } else { text = get_pattern(conn, msg, message); alog("%s", octstr_get_cstr(text)); } octstr_destroy(text); } gateway-1.4.5/gw/dlr.c0000644000175000017500000004532513227613126013242 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/dlr.c * * Implementation of handling delivery reports (DLRs) * * Andreas Fink , 18.08.2001 * Stipe Tolj , 22.03.2002 * Alexander Malysh 2003 * * Changes: * 2001-12-17: andreas@fink.org: * implemented use of mutex to avoid two mysql calls to run at the same time * 2002-03-22: stolj@wapme.de: * added more abstraction to fit for several other storage types * 2002-08-04: stolj@wapme.de: * added simple database library (sdb) support * 2002-11-14: stolj@wapme.de: * added re-routing info for DLRs to route via bearerbox to the same smsbox * instance. This is required if you use state conditioned smsboxes or smppboxes * via one bearerbox. Previously bearerbox was simple ignoring to which smsbox * connection a msg is passed. Now we can route the messages inside bearerbox. * 2009-04-29: aguerrieri at kannel dot org: * added support for ms-sql and sybase via freetds. */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "sms.h" #include "dlr.h" #include "dlr_p.h" #include "meta_data.h" /* Our callback functions */ static struct dlr_storage *handles = NULL; /* * Function to allocate a new struct dlr_entry entry * and initialize it to zero */ struct dlr_entry *dlr_entry_create(void) { struct dlr_entry *dlr; dlr = gw_malloc(sizeof(*dlr)); gw_assert(dlr != NULL); /* set all values to NULL */ memset(dlr, 0, sizeof(*dlr)); return dlr; } /* * Duplicate dlr entry */ struct dlr_entry *dlr_entry_duplicate(const struct dlr_entry *dlr) { struct dlr_entry *ret; if (dlr == NULL) return NULL; ret = dlr_entry_create(); ret->smsc = octstr_duplicate(dlr->smsc); ret->timestamp = octstr_duplicate(dlr->timestamp); ret->source = octstr_duplicate(dlr->source); ret->destination = octstr_duplicate(dlr->destination); ret->service = octstr_duplicate(dlr->service); ret->url = octstr_duplicate(dlr->url); ret->boxc_id = octstr_duplicate(dlr->boxc_id); ret->mask = dlr->mask; return ret; } /* * Function to destroy the struct dlr_entry entry */ void dlr_entry_destroy(struct dlr_entry *dlr) { /* sanity check */ if (dlr == NULL) return; #define O_DELETE(a) { if (a) octstr_destroy(a); a = NULL; } O_DELETE(dlr->smsc); O_DELETE(dlr->timestamp); O_DELETE(dlr->source); O_DELETE(dlr->destination); O_DELETE(dlr->service); O_DELETE(dlr->url); O_DELETE(dlr->boxc_id); #undef O_DELETE dlr->mask = 0; gw_free(dlr); } /* * Load all configuration directives that are common for all database * types that use the 'dlr-db' group to define which attributes are * used in the table */ struct dlr_db_fields *dlr_db_fields_create(CfgGroup *grp) { struct dlr_db_fields *ret = NULL; ret = gw_malloc(sizeof(*ret)); gw_assert(ret != NULL); memset(ret, 0, sizeof(*ret)); if (!(ret->table = cfg_get(grp, octstr_imm("table")))) panic(0, "DLR: DB: directive 'table' is not specified!"); ret->ttl = 0; if (cfg_get_integer(&ret->ttl, grp, octstr_imm("ttl")) == -1 || ret->ttl < 0) ret->ttl = 0; if (!(ret->field_smsc = cfg_get(grp, octstr_imm("field-smsc")))) panic(0, "DLR: DB: directive 'field-smsc' is not specified!"); if (!(ret->field_ts = cfg_get(grp, octstr_imm("field-timestamp")))) panic(0, "DLR: DB: directive 'field-timestamp' is not specified!"); if (!(ret->field_src = cfg_get(grp, octstr_imm("field-source")))) panic(0, "DLR: DB: directive 'field-source' is not specified!"); if (!(ret->field_dst = cfg_get(grp, octstr_imm("field-destination")))) panic(0, "DLR: DB: directive 'field-destination' is not specified!"); if (!(ret->field_serv = cfg_get(grp, octstr_imm("field-service")))) panic(0, "DLR: DB: directive 'field-service' is not specified!"); if (!(ret->field_url = cfg_get(grp, octstr_imm("field-url")))) panic(0, "DLR: DB: directive 'field-url' is not specified!"); if (!(ret->field_mask = cfg_get(grp, octstr_imm("field-mask")))) panic(0, "DLR: DB: directive 'field-mask' is not specified!"); if (!(ret->field_status = cfg_get(grp, octstr_imm("field-status")))) panic(0, "DLR: DB: directive 'field-status' is not specified!"); if (!(ret->field_boxc = cfg_get(grp, octstr_imm("field-boxc-id")))) panic(0, "DLR: DB: directive 'field-boxc-id' is not specified!"); return ret; } void dlr_db_fields_destroy(struct dlr_db_fields *fields) { /* sanity check */ if (fields == NULL) return; #define O_DELETE(a) { if (a) octstr_destroy(a); a = NULL; } O_DELETE(fields->table); O_DELETE(fields->field_smsc); O_DELETE(fields->field_ts); O_DELETE(fields->field_src); O_DELETE(fields->field_dst); O_DELETE(fields->field_serv); O_DELETE(fields->field_url); O_DELETE(fields->field_mask); O_DELETE(fields->field_status); O_DELETE(fields->field_boxc); #undef O_DELETE gw_free(fields); } /* * Initialize specifically dlr storage. If defined storage is unknown * then panic. */ void dlr_init(Cfg* cfg) { CfgGroup *grp; Octstr *dlr_type; /* check which DLR storage type we are using */ grp = cfg_get_single_group(cfg, octstr_imm("core")); if(grp == NULL) panic(0, "DLR: can't find group core"); dlr_type = cfg_get(grp, octstr_imm("dlr-storage")); /* * assume we are using internal memory in case no directive * has been specified, warn the user anyway */ if (dlr_type == NULL) { dlr_type = octstr_imm("internal"); warning(0, "DLR: using default 'internal' for storage type."); } /* call the sub-init routine */ if (octstr_compare(dlr_type, octstr_imm("spool")) == 0) { handles = dlr_init_spool(cfg); } else if (octstr_compare(dlr_type, octstr_imm("mysql")) == 0) { handles = dlr_init_mysql(cfg); } else if (octstr_compare(dlr_type, octstr_imm("sdb")) == 0) { handles = dlr_init_sdb(cfg); } else if (octstr_compare(dlr_type, octstr_imm("oracle")) == 0) { handles = dlr_init_oracle(cfg); } else if (octstr_compare(dlr_type, octstr_imm("internal")) == 0) { handles = dlr_init_mem(cfg); } else if (octstr_compare(dlr_type, octstr_imm("pgsql")) == 0) { handles = dlr_init_pgsql(cfg); } else if (octstr_compare(dlr_type, octstr_imm("mssql")) == 0) { handles = dlr_init_mssql(cfg); } else if (octstr_compare(dlr_type, octstr_imm("sqlite3")) == 0) { handles = dlr_init_sqlite3(cfg); } else if (octstr_compare(dlr_type, octstr_imm("redis")) == 0) { handles = dlr_init_redis(cfg); } else if (octstr_compare(dlr_type, octstr_imm("cassandra")) == 0) { handles = dlr_init_cass(cfg); } /* * add aditional types here */ if (handles == NULL) { panic(0, "DLR: storage type '%s' is not supported!", octstr_get_cstr(dlr_type)); } /* check needed function pointers */ if (handles->dlr_add == NULL || handles->dlr_get == NULL || handles->dlr_remove == NULL) panic(0, "DLR: storage type '%s' don't implement needed functions", octstr_get_cstr(dlr_type)); /* get info from storage */ info(0, "DLR using storage type: %s", handles->type); /* cleanup */ octstr_destroy(dlr_type); } /* * Shutdown dlr storage */ void dlr_shutdown() { if (handles != NULL && handles->dlr_shutdown != NULL) handles->dlr_shutdown(); } /* * Return count waiting delivery entries or -1 if error occurs */ long dlr_messages(void) { if (handles != NULL && handles->dlr_messages != NULL) return handles->dlr_messages(); return -1; } /* * Return type of used dlr storage */ const char* dlr_type(void) { if (handles != NULL && handles->type != NULL) return handles->type; return "unknown"; } /* * Add new dlr entry into dlr storage. */ void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg, int use_dst) { struct dlr_entry *dlr = NULL; /* Add the foreign_id so all SMSC modules can use it. * Obey also the original message in the split_parts list. */ if (msg->sms.foreign_id != NULL) octstr_destroy(msg->sms.foreign_id); msg->sms.foreign_id = octstr_duplicate(ts); if (msg->sms.split_parts != NULL) { struct split_parts *split = msg->sms.split_parts; if (split->orig->sms.foreign_id != NULL) octstr_destroy(split->orig->sms.foreign_id); split->orig->sms.foreign_id = octstr_duplicate(ts); } if (octstr_len(smsc) == 0) { warning(0, "DLR[%s]: Can't add a dlr without smsc-id", dlr_type()); return; } /* sanity check */ if (handles == NULL || handles->dlr_add == NULL || msg == NULL) return; /* check if delivery receipt requested */ if (!DLR_IS_ENABLED(msg->sms.dlr_mask)) return; /* allocate new struct dlr_entry struct */ dlr = dlr_entry_create(); gw_assert(dlr != NULL); /* now copy all values, we are interested in */ dlr->smsc = (smsc ? octstr_duplicate(smsc) : octstr_create("")); dlr->timestamp = (ts ? octstr_duplicate(ts) : octstr_create("")); dlr->source = (msg->sms.sender ? octstr_duplicate(msg->sms.sender) : octstr_create("")); dlr->destination = (msg->sms.receiver ? octstr_duplicate(msg->sms.receiver) : octstr_create("")); dlr->service = (msg->sms.service ? octstr_duplicate(msg->sms.service) : octstr_create("")); dlr->url = (msg->sms.dlr_url ? octstr_duplicate(msg->sms.dlr_url) : octstr_create("")); dlr->boxc_id = (msg->sms.boxc_id ? octstr_duplicate(msg->sms.boxc_id) : octstr_create("")); dlr->mask = msg->sms.dlr_mask; dlr->use_dst = use_dst; debug("dlr.dlr", 0, "DLR[%s]: Adding DLR smsc=%s, ts=%s, src=%s, dst=%s, mask=%d, boxc=%s", dlr_type(), octstr_get_cstr(dlr->smsc), octstr_get_cstr(dlr->timestamp), octstr_get_cstr(dlr->source), octstr_get_cstr(dlr->destination), dlr->mask, octstr_get_cstr(dlr->boxc_id)); /* call registered function */ handles->dlr_add(dlr); } /* * Return Msg* if dlr entry found in DB, otherwise NULL. * NOTE: If typ is end status (e.g. DELIVERED) then dlr entry * will be removed from DB. */ Msg *dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int typ, int use_dst) { Msg *msg = NULL; struct dlr_entry *dlr = NULL; Octstr *dst_min = NULL; Octstr *dlr_mask; if(octstr_len(smsc) == 0) { warning(0, "DLR[%s]: Can't find a dlr without smsc-id", dlr_type()); return NULL; } /* check if we have handler registered */ if (handles == NULL || handles->dlr_get == NULL) return NULL; if (use_dst && dst) { dst_min = octstr_duplicate(dst); int len = octstr_len(dst); if (len > MIN_DST_LEN) octstr_delete(dst_min, 0, len - MIN_DST_LEN); } debug("dlr.dlr", 0, "DLR[%s]: Looking for DLR smsc=%s, ts=%s, dst=%s, type=%d", dlr_type(), octstr_get_cstr(smsc), octstr_get_cstr(ts), octstr_get_cstr(dst), typ); dlr = handles->dlr_get(smsc, ts, dst_min); if (dlr == NULL) { warning(0, "DLR[%s]: DLR from SMSC<%s> for DST<%s> not found.", dlr_type(), octstr_get_cstr(smsc), octstr_get_cstr(dst)); return NULL; } #define O_SET(x, val) if (octstr_len(val) > 0) { x = val; val = NULL; } if ((typ & dlr->mask) > 0) { /* its an entry we are interested in */ msg = msg_create(sms); msg->sms.sms_type = report_mo; msg->sms.dlr_mask = typ; O_SET(msg->sms.service, dlr->service); O_SET(msg->sms.smsc_id, dlr->smsc); O_SET(msg->sms.receiver, dlr->destination); O_SET(msg->sms.sender, dlr->source); /* if dlr_url was present, recode it here again */ O_SET(msg->sms.dlr_url, dlr->url); /* add the foreign_id */ msg->sms.foreign_id = octstr_duplicate(ts); /* * insert original message to the data segment * later in the smsc module */ msg->sms.msgdata = NULL; /* * If a boxc_id is available, then instruct bearerbox to * route this msg back to originating smsbox */ O_SET(msg->sms.boxc_id, dlr->boxc_id); /* * We will provide the DLR request bitmask in the DLR going back * to the smsbox connection for processing. This allows smsbox * connection type applications to avoid temporary storing and * resolving data to pull up this information. */ dlr_mask = octstr_format("%ld", dlr->mask); msg->sms.meta_data = octstr_create(""); meta_data_set_value(msg->sms.meta_data, METADATA_ORIG_MSG_GROUP, octstr_imm(METADATA_ORIG_MSG_GROUP_DLR_MASK), dlr_mask, 1); octstr_destroy(dlr_mask); time(&msg->sms.time); debug("dlr.dlr", 0, "DLR[%s]: created DLR message for URL <%s>", dlr_type(), (msg->sms.dlr_url?octstr_get_cstr(msg->sms.dlr_url):"")); } else { debug("dlr.dlr", 0, "DLR[%s]: Ignoring DLR message because of mask type=%d dlr->mask=%d", dlr_type(), typ, dlr->mask); /* ok that was a status report but we where not interested in having it */ msg = NULL; } #undef O_SET /* check for end status and if so remove from storage */ if (DLR_IS_NOT_FINAL(typ) && DLR_IS_SUCCESS_OR_FAIL(dlr->mask)) { debug("dlr.dlr", 0, "DLR[%s]: DLR not destroyed, still waiting for other delivery report", dlr_type()); /* update dlr entry status if function defined */ if (handles != NULL && handles->dlr_update != NULL){ handles->dlr_update(smsc, ts, dst_min, typ); } } else { if (handles != NULL && handles->dlr_remove != NULL){ /* it's not good for internal storage, but better for all others */ handles->dlr_remove(smsc, ts, dst_min); } else { warning(0, "DLR[%s]: Storage don't have remove operation defined", dlr_type()); } } /* destroy struct dlr_entry */ dlr_entry_destroy(dlr); octstr_destroy(dst_min); return msg; } void dlr_flush(void) { info(0, "Flushing all %ld queued DLR messages in %s storage", dlr_messages(), dlr_type()); if (handles != NULL && handles->dlr_flush != NULL) handles->dlr_flush(); } Msg* create_dlr_from_msg(const Octstr *smsc, const Msg *msg, const Octstr *reply, long stat) { Msg *dlrmsg; if (msg == NULL) return NULL; /* generate DLR */ debug("dlr.dlr", 0,"SMSC[%s]: creating DLR message", (smsc ? octstr_get_cstr(smsc) : "UNKNOWN")); dlrmsg = msg_create(sms); gw_assert(dlrmsg != NULL); dlrmsg->sms.service = octstr_duplicate(msg->sms.service); dlrmsg->sms.dlr_mask = stat; dlrmsg->sms.sms_type = report_mo; dlrmsg->sms.smsc_id = octstr_duplicate(smsc ? smsc : msg->sms.smsc_id); dlrmsg->sms.sender = octstr_duplicate(msg->sms.sender); dlrmsg->sms.receiver = octstr_duplicate(msg->sms.receiver); dlrmsg->sms.dlr_url = octstr_duplicate(msg->sms.dlr_url); dlrmsg->sms.msgdata = octstr_duplicate(reply); dlrmsg->sms.boxc_id = octstr_duplicate(msg->sms.boxc_id); dlrmsg->sms.foreign_id = octstr_duplicate(msg->sms.foreign_id); time(&dlrmsg->sms.time); dlrmsg->sms.meta_data = octstr_duplicate(msg->sms.meta_data); /* add original DLR bit-mask, as we do in dlr_find() */ if (DLR_IS_ENABLED(msg->sms.dlr_mask)) { Octstr *dlr_mask = octstr_format("%ld", msg->sms.dlr_mask); if (dlrmsg->sms.meta_data == NULL) dlrmsg->sms.meta_data = octstr_create(""); meta_data_set_value(dlrmsg->sms.meta_data, METADATA_ORIG_MSG_GROUP, octstr_imm(METADATA_ORIG_MSG_GROUP_DLR_MASK), dlr_mask, 1); octstr_destroy(dlr_mask); } debug("dlr.dlr", 0,"SMSC[%s]: DLR = %s", (smsc ? octstr_get_cstr(smsc) : "UNKNOWN"), (dlrmsg->sms.dlr_url ? octstr_get_cstr(dlrmsg->sms.dlr_url) : "")); return dlrmsg; } gateway-1.4.5/gw/wap_push_ppg.h0000644000175000017500000001532513227613126015157 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Push PPG main module header * * This module implements following Wapforum specifications: * WAP-151-PPGService-19990816-a (called afterwards ppg), * WAP-164-PAP-19991108-a (pap), * WAP-164_100-PAP-20000218-a (pap implementation note). * * We refer following Wapforum specifications: * WAP-145-PushMessage-19990816-a (push message) * WAP-200-WDP-20001212-a (wdp) * WAP-203-WSP-20000504-a (wsp) * WAP-189-PushOTA-20000217-a (ota). * * In addition, rfcs 1521, 2045 and 2617 are referred. * * By Aarno Syvänen for Wapit Ltd and for Wiral Ltd. */ #ifndef WAP_PUSH_PPG_H #define WAP_PUSH_PPG_H #include "wap/wap_events.h" #include "wap/wap.h" #include "wap/wap_addr.h" #include "gwlib/gwlib.h" typedef struct PPGSessionMachine PPGSessionMachine; typedef struct PPGPushMachine PPGPushMachine; /* * Enumerations used by PPG main module for PAP attribute, see PPG Services, * Chapter 6. * * Message state */ enum { PAP_UNDELIVERABLE, /* general message status */ PAP_UNDELIVERABLE1, /* transformation failure */ PAP_UNDELIVERABLE2, /* no bearer support */ PAP_PENDING, PAP_EXPIRED, PAP_DELIVERED, /* general message status */ PAP_DELIVERED1, /* for unconfirmed push, PPG internal */ PAP_DELIVERED2, /* for confirmed push, PPG internal */ PAP_ABORTED, PAP_TIMEOUT, PAP_CANCELLED }; /* * PAP protocol status codes used by PPG main module. See Push Access Protocol, * 9.13 and 9.14. */ enum { PAP_OK = 1000, PAP_ACCEPTED_FOR_PROCESSING = 1001, PAP_BAD_REQUEST = 2000, PAP_FORBIDDEN = 2001, PAP_ADDRESS_ERROR = 2002, PAP_CAPABILITIES_MISMATCH = 2005, PAP_DUPLICATE_PUSH_ID = 2007, PAP_INTERNAL_SERVER_ERROR = 3000, PAP_TRANSFORMATION_FAILURE = 3006, PAP_REQUIRED_BEARER_NOT_AVAILABLE = 3010, PAP_SERVICE_FAILURE = 4000, PAP_CLIENT_ABORTED = 5000, PAP_ABORT_USERPND = 5028 }; /* * Values for last attribute (it is, is this message last using this bearer). */ enum { NOT_LAST, LAST }; /* * Enumerations used by PAP message fields, see Push Access Protocol, Chapter * 9. Default values are the first ones (ones having value 0) * * Simple answer to question is something required or not */ enum { PAP_FALSE, PAP_TRUE }; /* * Priority */ enum { PAP_MEDIUM, PAP_HIGH, PAP_LOW }; /* * Delivery method */ enum { PAP_NOT_SPECIFIED = 0, PAP_PREFERCONFIRMED = 1, PAP_UNCONFIRMED = 2, PAP_CONFIRMED = 3 }; /* * Port number definitions */ enum { CONNECTIONLESS_PUSH_CLIPORT = 2948, CONNECTIONLESS_SERVPORT = 9200, CONNECTED_CLIPORT = 9209, CONNECTED_SERVPORT = 9201 }; struct PPGSessionMachine { #define OCTSTR(name) Octstr *name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define INTEGER(name) long name; #define PUSHMACHINES(name) List *name; #define CAPABILITIES(name) List *name; #define MACHINE(fields) fields #include "wap_ppg_session_machine.def" }; struct PPGPushMachine { #define OCTSTR(name) Octstr *name; #define OPTIONAL_OCTSTR(name) Octstr *name; #define INTEGER(name) long name; #define ADDRTUPLE(name) WAPAddrTuple *name; #define HTTPHEADER(name) List *name; #define CAPABILITIES(name) List *name; #define MACHINE(fields) fields #include "wap_ppg_push_machine.def" }; void wap_push_ppg_init(wap_dispatch_func_t *ota_dispatch, wap_dispatch_func_t *appl_dispatch, Cfg *cfg); void wap_push_ppg_shutdown(void); void wap_push_ppg_dispatch_event(WAPEvent *e); /* * Check do we have established a session with an initiator for this push. * Initiators are identified by their address tuple (ppg main module does not * know wsp sessions until told. */ PPGSessionMachine *wap_push_ppg_have_push_session_for(WAPAddrTuple *tuple); /* * Now iniator are identified by their session id. This function is used after * the session is established. */ PPGSessionMachine *wap_push_ppg_have_push_session_for_sid(long sid); #endif gateway-1.4.5/gw/urltrans.c0000644000175000017500000013362413227613126014333 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * urltrans.c - URL translations * * Lars Wirzenius */ #include #include #include #include #include #include #include "urltrans.h" #include "gwlib/gwlib.h" #include "gw/sms.h" #include "gw/dlr.h" #include "gw/meta_data.h" /*********************************************************************** * Definitions of data structures. These are not visible to the external * world -- they may be accessed only via the functions declared in * urltrans.h. */ /* * Hold one keyword/options entity */ struct URLTranslation { int type; /* see enumeration in header file */ Octstr *pattern; /* url, text or file-name pattern */ Octstr *prefix; /* for prefix-cut */ Octstr *suffix; /* for suffix-cut */ Octstr *faked_sender;/* works only with certain services */ Octstr *default_sender;/* Default sender to sendsms-user */ long max_messages; /* absolute limit of reply messages */ int concatenation; /* send long messages as concatenated SMS's if true */ Octstr *split_chars;/* allowed chars to be used to split message */ Octstr *split_suffix;/* chars added to end after each split (not last) */ int omit_empty; /* if the reply is empty, is notification send */ Octstr *header; /* string to be inserted to each SMS */ Octstr *footer; /* string to be appended to each SMS */ Octstr *alt_charset; /* alternative charset to use towards service */ List *accepted_smsc; /* smsc id's allowed to use this service. If not set, all messages can use this service */ List *accepted_account; /* account id's allowed to use this service. If not set, all messages can use this service */ Octstr *name; /* Translation name */ Octstr *username; /* send sms username */ Octstr *password; /* password associated */ Octstr *forced_smsc;/* if smsc id is forcet to certain for this user */ Octstr *default_smsc; /* smsc id if none given in http send-sms request */ Octstr *allow_ip; /* allowed IPs to request send-sms with this account */ Octstr *deny_ip; /* denied IPs to request send-sms with this account */ Octstr *allowed_prefix; /* Prefixes (of sender) allowed in this translation, or... */ Octstr *denied_prefix; /* ...denied prefixes */ Octstr *allowed_recv_prefix; /* Prefixes (of receiver) allowed in this translation, or... */ Octstr *denied_recv_prefix; /* ...denied prefixes */ Numhash *white_list; /* To numbers allowed, or ... */ Numhash *black_list; /* ...denied numbers */ int assume_plain_text; /* for type: octet-stream */ int accept_x_kannel_headers; /* do we accept special headers in reply */ int strip_keyword; /* POST body */ int send_sender; /* POST headers */ int args; int has_catchall_arg; int catch_all; Octstr *dlr_url; /* URL to call for delivery reports */ long dlr_mask; /* DLR event mask */ regex_t *keyword_regex; /* the compiled regular expression for the keyword*/ regex_t *accepted_smsc_regex; regex_t *accepted_account_regex; regex_t *allowed_prefix_regex; regex_t *denied_prefix_regex; regex_t *allowed_receiver_prefix_regex; regex_t *denied_receiver_prefix_regex; regex_t *white_list_regex; regex_t *black_list_regex; }; /* * Hold the list of all translations. */ struct URLTranslationList { List *list; List *defaults; /* List of default sms-services */ Dict *names; /* Dict of lowercase Octstr names */ }; /*********************************************************************** * Declarations of internal functions. These are defined at the end of * the file. */ static long count_occurences(Octstr *str, Octstr *pat); static URLTranslation *create_onetrans(CfgGroup *grp); static void destroy_onetrans(void *ot); static URLTranslation *find_translation(URLTranslationList *trans, Msg *msg); static URLTranslation *find_default_translation(URLTranslationList *trans, Octstr *smsc, Octstr *sender, Octstr *receiver, Octstr *account); /*********************************************************************** * Implementations of the functions declared in urltrans.h. See the * header for explanations of what they should do. */ static void destroy_keyword_list(void *list) { gwlist_destroy(list, NULL); } URLTranslationList *urltrans_create(void) { URLTranslationList *trans; trans = gw_malloc(sizeof(URLTranslationList)); trans->list = gwlist_create(); trans->defaults = gwlist_create(); trans->names = dict_create(1024, destroy_keyword_list); return trans; } void urltrans_destroy(URLTranslationList *trans) { gwlist_destroy(trans->list, destroy_onetrans); gwlist_destroy(trans->defaults, destroy_onetrans); dict_destroy(trans->names); gw_free(trans); } int urltrans_add_one(URLTranslationList *trans, CfgGroup *grp) { URLTranslation *ot; List *list2; ot = create_onetrans(grp); if (ot == NULL) return -1; if (ot->type != TRANSTYPE_SENDSMS && ot->keyword_regex == NULL) gwlist_append(trans->defaults, ot); else gwlist_append(trans->list, ot); list2 = dict_get(trans->names, ot->name); if (list2 == NULL) { list2 = gwlist_create(); dict_put(trans->names, ot->name, list2); } gwlist_append(list2, ot); return 0; } int urltrans_add_cfg(URLTranslationList *trans, Cfg *cfg) { CfgGroup *grp; List *list; list = cfg_get_multi_group(cfg, octstr_imm("sms-service")); while (list && (grp = gwlist_extract_first(list)) != NULL) { if (urltrans_add_one(trans, grp) == -1) { gwlist_destroy(list, NULL); return -1; } } gwlist_destroy(list, NULL); list = cfg_get_multi_group(cfg, octstr_imm("sendsms-user")); while (list && (grp = gwlist_extract_first(list)) != NULL) { if (urltrans_add_one(trans, grp) == -1) { gwlist_destroy(list, NULL); return -1; } } gwlist_destroy(list, NULL); return 0; } URLTranslation *urltrans_find(URLTranslationList *trans, Msg *msg) { URLTranslation *t = NULL; t = find_translation(trans, msg); if (t == NULL) { t = find_default_translation(trans, msg->sms.smsc_id, msg->sms.sender, msg->sms.receiver, msg->sms.account); } return t; } URLTranslation *urltrans_find_service(URLTranslationList *trans, Msg *msg) { URLTranslation *t; List *list; list = dict_get(trans->names, msg->sms.service); if (list != NULL) { t = gwlist_get(list, 0); } else { t = NULL; } return t; } URLTranslation *urltrans_find_username(URLTranslationList *trans, Octstr *name) { URLTranslation *t; int i; gw_assert(name != NULL); for (i = 0; i < gwlist_len(trans->list); ++i) { t = gwlist_get(trans->list, i); if (t->type == TRANSTYPE_SENDSMS) { if (octstr_compare(name, t->username) == 0) return t; } } return NULL; } /* * Remove the first word and the whitespace that follows it from * the start of the message data. */ static void strip_keyword(Msg *request) { int ch; long pos; pos = 0; for (; (ch = octstr_get_char(request->sms.msgdata, pos)) >= 0; pos++) if (isspace(ch)) break; for (; (ch = octstr_get_char(request->sms.msgdata, pos)) >= 0; pos++) if (!isspace(ch)) break; octstr_delete(request->sms.msgdata, 0, pos); } Octstr *urltrans_fill_escape_codes(Octstr *pattern, Msg *request) { Octstr *enc; Octstr *meta_group, *meta_param; int nextarg, j; struct tm tm; int num_words; List *word_list; Octstr *result; long pattern_len; long pos; int c; long i, k; Octstr *temp; result = octstr_create(""); if (request->sms.msgdata) { word_list = octstr_split_words(request->sms.msgdata); num_words = gwlist_len(word_list); } else { word_list = gwlist_create(); num_words = 0; } pattern_len = octstr_len(pattern); nextarg = 1; pos = 0; for (;;) { while (pos < pattern_len) { c = octstr_get_char(pattern, pos); if (c == '%' && pos + 1 < pattern_len) break; octstr_append_char(result, c); ++pos; } if (pos == pattern_len) break; switch (octstr_get_char(pattern, pos + 1)) { case 'a': for (j = 0; j < num_words; ++j) { enc = octstr_duplicate(gwlist_get(word_list, j)); octstr_url_encode(enc); if (j > 0) octstr_append_char(result, '+'); octstr_append(result, enc); octstr_destroy(enc); } break; case 'A': if (request->sms.msgdata) { enc = octstr_duplicate(request->sms.msgdata); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'b': /* message payload, URL-encoded */ enc = octstr_duplicate(request->sms.msgdata); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'B': /* billing identifier/information */ if (octstr_len(request->sms.binfo)) { enc = octstr_duplicate(request->sms.binfo); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'c': octstr_append_decimal(result, request->sms.coding); break; case 'C': if (octstr_len(request->sms.charset)) { octstr_append(result, request->sms.charset); } else { switch (request->sms.coding) { case DC_UNDEF: case DC_7BIT: octstr_append(result, octstr_imm("UTF-8")); break; case DC_8BIT: octstr_append(result, octstr_imm("8-BIT")); break; case DC_UCS2: octstr_append(result, octstr_imm("UTF-16BE")); break; } } break; case 'd': enc = octstr_create(""); octstr_append_decimal(enc, request->sms.dlr_mask); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'D': /* meta_data */ if (octstr_len(request->sms.meta_data)) { enc = octstr_duplicate(request->sms.meta_data); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'e': /* message payload, printable hexadecimal byte codes */ if (octstr_len(request->sms.msgdata)) { enc = octstr_duplicate(request->sms.msgdata); octstr_binary_to_hex(enc, 1); octstr_append(result, enc); octstr_destroy(enc); } break; case 'f': /* smsc number*/ if (octstr_len(request->sms.smsc_number)) { enc = octstr_duplicate(request->sms.smsc_number); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'F': if (request->sms.foreign_id == NULL) break; enc = octstr_duplicate(request->sms.foreign_id); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'i': if (request->sms.smsc_id == NULL) break; enc = octstr_duplicate(request->sms.smsc_id); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'I': if (!uuid_is_null(request->sms.id)) { char id[UUID_STR_LEN + 1]; uuid_unparse(request->sms.id, id); octstr_append_cstr(result, id); } break; case 'k': if (num_words <= 0) break; enc = octstr_duplicate(gwlist_get(word_list, 0)); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'm': /* mclass - message class */ enc = octstr_create(""); octstr_append_decimal(enc, request->sms.mclass); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'M': /* mwi - message waiting indicator */ enc = octstr_create(""); octstr_append_decimal(enc, request->sms.mwi); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'n': if (request->sms.service == NULL) break; enc = octstr_duplicate(request->sms.service); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'o': /* account information (may be operator id for aggregators */ if (octstr_len(request->sms.account)) { enc = octstr_duplicate(request->sms.account); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'O': /* DCS */ { int dcs; dcs = fields_to_dcs(request, request->sms.alt_dcs); octstr_format_append(result, "%02d", dcs); break; } /* NOTE: the sender and receiver is already switched in * message, so that's why we must use 'sender' when * we want original receiver and vice versa */ case 'P': enc = octstr_duplicate(request->sms.sender); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'p': enc = octstr_duplicate(request->sms.receiver); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'q': if (strncmp(octstr_get_cstr(request->sms.receiver),"00",2)==0) { enc = octstr_copy(request->sms.receiver, 2, octstr_len(request->sms.receiver)); octstr_url_encode(enc); octstr_format_append(result, "%%2B%S", enc); octstr_destroy(enc); } else { enc = octstr_duplicate(request->sms.receiver); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'Q': if (strncmp(octstr_get_cstr(request->sms.sender), "00", 2) == 0) { enc = octstr_copy(request->sms.sender, 2, octstr_len(request->sms.sender)); octstr_url_encode(enc); octstr_format_append(result, "%%2B%S", enc); octstr_destroy(enc); } else { enc = octstr_duplicate(request->sms.sender); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'r': for (j = nextarg; j < num_words; ++j) { enc = octstr_duplicate(gwlist_get(word_list, j)); octstr_url_encode(enc); if (j != nextarg) octstr_append_char(result, '+'); octstr_append(result, enc); octstr_destroy(enc); } break; case 'R': /* dlr_url */ if (octstr_len(request->sms.dlr_url)) { enc = octstr_duplicate(request->sms.dlr_url); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 's': if (nextarg >= num_words) break; enc = octstr_duplicate(gwlist_get(word_list, nextarg)); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); ++nextarg; break; case 'S': if (nextarg >= num_words) break; temp = gwlist_get(word_list, nextarg); for (i = 0; i < octstr_len(temp); ++i) { if (octstr_get_char(temp, i) == '*') octstr_append_char(result, '~'); else octstr_append_char(result, octstr_get_char(temp, i)); } ++nextarg; break; case 't': tm = gw_gmtime(request->sms.time); octstr_format_append(result, "%04d-%02d-%02d+%02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case 'T': if (request->sms.time == MSG_PARAM_UNDEFINED) break; octstr_format_append(result, "%ld", request->sms.time); break; case 'u': if(octstr_len(request->sms.udhdata)) { enc = octstr_duplicate(request->sms.udhdata); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'v': if (request->sms.validity != MSG_PARAM_UNDEFINED) { octstr_format_append(result, "%ld", (request->sms.validity - time(NULL)) / 60); } break; case 'V': if (request->sms.deferred != MSG_PARAM_UNDEFINED) { octstr_format_append(result, "%ld", (request->sms.deferred - time(NULL)) / 60); } break; /* * This allows to pass meta-data individual parameters into urls. * The syntax is as follows: %#group#parameter# * For example: %#smpp#my_param# would be replaced with the value * 'my_param' from the group 'smpp' coming inside the meta_data field. */ case '#': /* ASCII 0x23 == '#' */ k = octstr_search_char(pattern, 0x23, pos + 2); if (k >= 0) { pos += 2; meta_group = octstr_copy(pattern, pos, (k-pos)); pos = k + 1; k = octstr_search_char(pattern, 0x23, pos); if (k >= 0) { meta_param = octstr_copy(pattern, pos, (k-pos)); pos = k - 1; if (request->sms.meta_data != NULL) { enc = meta_data_get_value(request->sms.meta_data, octstr_get_cstr(meta_group), meta_param); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } octstr_destroy(meta_param); } else { pos++; } octstr_destroy(meta_group); } break; /* XXX sms.parameters not present in here: * * pid - will we receive this ? * * alt-dcs - shouldn't be required unless we want to inform * which alt-dcs external server should use back * * compress - if we use compression, probably kannel would * decompress and reset this to 0. not required * * rpi - we don't receive these from smsc * * username, password, dlr-url, account - nonsense to send */ case '%': octstr_format_append(result, "%%"); break; default: octstr_format_append(result, "%%%c", octstr_get_char(pattern, pos + 1)); break; } pos += 2; } gwlist_destroy(word_list, octstr_destroy_item); return result; } /* * Trans being NULL means that we are servicing ppg (doing dlr, but this does not * concern us here). */ Octstr *urltrans_get_pattern(URLTranslation *t, Msg *request) { Octstr *result, *pattern; if (request->sms.sms_type != report_mo && t->type == TRANSTYPE_SENDSMS) return octstr_create(""); /* check if this is a delivery report message or not */ if (request->sms.sms_type != report_mo) { pattern = t->pattern; } else { /* this is a DLR message */ pattern = request->sms.dlr_url; if (octstr_len(pattern) == 0) { if (t && octstr_len(t->dlr_url)) { pattern = t->dlr_url; } else { return octstr_create(""); } } } /* We have pulled this out into an own exported function. This * gives other modules the chance to use the same escape code * semantics for Msgs. */ result = urltrans_fill_escape_codes(pattern, request); /* * this SHOULD be done in smsbox, not here, but well, * much easier to do here */ if (t && (t->type == TRANSTYPE_POST_URL || t->type == TRANSTYPE_POST_XML) && t->strip_keyword) strip_keyword(request); return result; } int urltrans_type(URLTranslation *t) { return t->type; } Octstr *urltrans_prefix(URLTranslation *t) { return t->prefix; } Octstr *urltrans_suffix(URLTranslation *t) { return t->suffix; } Octstr *urltrans_default_sender(URLTranslation *t) { return t->default_sender; } Octstr *urltrans_faked_sender(URLTranslation *t) { return t->faked_sender; } int urltrans_max_messages(URLTranslation *t) { return t->max_messages; } int urltrans_concatenation(URLTranslation *t) { return t->concatenation; } Octstr *urltrans_split_chars(URLTranslation *t) { return t->split_chars; } Octstr *urltrans_split_suffix(URLTranslation *t) { return t->split_suffix; } int urltrans_omit_empty(URLTranslation *t) { return t->omit_empty; } Octstr *urltrans_header(URLTranslation *t) { return t->header; } Octstr *urltrans_footer(URLTranslation *t) { return t->footer; } Octstr *urltrans_alt_charset(URLTranslation *t) { return t->alt_charset; } Octstr *urltrans_name(URLTranslation *t) { return t->name; } Octstr *urltrans_username(URLTranslation *t) { return t->username; } Octstr *urltrans_password(URLTranslation *t) { return t->password; } Octstr *urltrans_forced_smsc(URLTranslation *t) { return t->forced_smsc; } Octstr *urltrans_default_smsc(URLTranslation *t) { return t->default_smsc; } Octstr *urltrans_allow_ip(URLTranslation *t) { return t->allow_ip; } Octstr *urltrans_deny_ip(URLTranslation *t) { return t->deny_ip; } Octstr *urltrans_allowed_prefix(URLTranslation *t) { return t->allowed_prefix; } Octstr *urltrans_denied_prefix(URLTranslation *t) { return t->denied_prefix; } Octstr *urltrans_allowed_recv_prefix(URLTranslation *t) { return t->allowed_recv_prefix; } Octstr *urltrans_denied_recv_prefix(URLTranslation *t) { return t->denied_recv_prefix; } Numhash *urltrans_white_list(URLTranslation *t) { return t->white_list; } regex_t *urltrans_white_list_regex(URLTranslation *t) { return t->white_list_regex; } Numhash *urltrans_black_list(URLTranslation *t) { return t->black_list; } regex_t *urltrans_black_list_regex(URLTranslation *t) { return t->black_list_regex; } int urltrans_assume_plain_text(URLTranslation *t) { return t->assume_plain_text; } int urltrans_accept_x_kannel_headers(URLTranslation *t) { return t->accept_x_kannel_headers; } int urltrans_strip_keyword(URLTranslation *t) { return t->strip_keyword; } int urltrans_send_sender(URLTranslation *t) { return t->send_sender; } Octstr *urltrans_dlr_url(URLTranslation *t) { return t->dlr_url; } int urltrans_dlr_mask(URLTranslation *t) { return t->dlr_mask; } /*********************************************************************** * Internal functions. */ /* * Create one URLTranslation. Return NULL for failure, pointer to it for OK. */ static URLTranslation *create_onetrans(CfgGroup *grp) { URLTranslation *ot; Octstr *url, *post_url, *post_xml, *text, *file, *exec; Octstr *accepted_smsc, *accepted_account, *forced_smsc, *default_smsc; Octstr *grpname; int is_sms_service, regex_flag = REG_EXTENDED; Octstr *accepted_smsc_regex; Octstr *accepted_account_regex; Octstr *allowed_prefix_regex; Octstr *denied_prefix_regex; Octstr *allowed_receiver_prefix_regex; Octstr *denied_receiver_prefix_regex; Octstr *white_list_regex; Octstr *black_list_regex; Octstr *keyword_regex; Octstr *os, *tmp; grpname = cfg_get_group_name(grp); if (grpname == NULL) return NULL; if (octstr_str_compare(grpname, "sms-service") == 0) is_sms_service = 1; else if (octstr_str_compare(grpname, "sendsms-user") == 0) is_sms_service = 0; else { octstr_destroy(grpname); return NULL; } octstr_destroy(grpname); ot = gw_malloc(sizeof(URLTranslation)); memset(ot, 0, sizeof(*ot)); if (is_sms_service) { cfg_get_bool(&ot->catch_all, grp, octstr_imm("catch-all")); ot->dlr_url = cfg_get(grp, octstr_imm("dlr-url")); if (cfg_get_integer(&ot->dlr_mask, grp, octstr_imm("dlr-mask")) == -1) ot->dlr_mask = DLR_UNDEFINED; ot->alt_charset = cfg_get(grp, octstr_imm("alt-charset")); url = cfg_get(grp, octstr_imm("get-url")); if (url == NULL) url = cfg_get(grp, octstr_imm("url")); post_url = cfg_get(grp, octstr_imm("post-url")); post_xml = cfg_get(grp, octstr_imm("post-xml")); file = cfg_get(grp, octstr_imm("file")); text = cfg_get(grp, octstr_imm("text")); exec = cfg_get(grp, octstr_imm("exec")); if (url != NULL) { ot->type = TRANSTYPE_GET_URL; ot->pattern = octstr_duplicate(url); } else if (post_url != NULL) { ot->type = TRANSTYPE_POST_URL; ot->pattern = octstr_duplicate(post_url); ot->catch_all = 1; } else if (post_xml != NULL) { ot->type = TRANSTYPE_POST_XML; ot->pattern = octstr_duplicate(post_xml); ot->catch_all = 1; } else if (file != NULL) { ot->type = TRANSTYPE_FILE; ot->pattern = octstr_duplicate(file); } else if (text != NULL) { ot->type = TRANSTYPE_TEXT; ot->pattern = octstr_duplicate(text); } else if (exec != NULL) { ot->type = TRANSTYPE_EXECUTE; ot->pattern = octstr_duplicate(exec); } else { octstr_destroy(url); octstr_destroy(post_url); octstr_destroy(post_xml); octstr_destroy(file); octstr_destroy(text); octstr_destroy(exec); error(0, "Configuration group `sms-service' " "did not specify get-url, post-url, post-xml, file or text."); goto error; } octstr_destroy(url); octstr_destroy(post_url); octstr_destroy(post_xml); octstr_destroy(file); octstr_destroy(text); octstr_destroy(exec); tmp = cfg_get(grp, octstr_imm("keyword")); keyword_regex = cfg_get(grp, octstr_imm("keyword-regex")); if (tmp == NULL && keyword_regex == NULL) { error(0, "Group 'sms-service' must include either 'keyword' or 'keyword-regex'."); goto error; } if (tmp != NULL && keyword_regex != NULL) { error(0, "Group 'sms-service' may inlcude either 'keyword' or 'keyword-regex'."); octstr_destroy(tmp); octstr_destroy(keyword_regex); goto error; } if (tmp != NULL && octstr_str_compare(tmp, "default") == 0) { /* default sms-service */ ot->keyword_regex = NULL; octstr_destroy(tmp); } else if (tmp != NULL) { Octstr *aliases; /* convert to regex */ regex_flag |= REG_ICASE; keyword_regex = octstr_format("^[ ]*(%S", tmp); octstr_destroy(tmp); aliases = cfg_get(grp, octstr_imm("aliases")); if (aliases != NULL) { long i; List *l; l = octstr_split(aliases, octstr_imm(";")); octstr_destroy(aliases); for (i = 0; i < gwlist_len(l); ++i) { os = gwlist_get(l, i); octstr_format_append(keyword_regex, "|%S", os); } gwlist_destroy(l, octstr_destroy_item); } octstr_append_cstr(keyword_regex, ")[ ]*"); } if (keyword_regex != NULL && (ot->keyword_regex = gw_regex_comp(keyword_regex, regex_flag)) == NULL) { error(0, "Could not compile pattern '%s'", octstr_get_cstr(keyword_regex)); octstr_destroy(keyword_regex); goto error; } ot->name = cfg_get(grp, octstr_imm("name")); if (ot->name == NULL) ot->name = keyword_regex ? octstr_duplicate(keyword_regex) : octstr_create("default"); octstr_destroy(keyword_regex); accepted_smsc = cfg_get(grp, octstr_imm("accepted-smsc")); if (accepted_smsc != NULL) { ot->accepted_smsc = octstr_split(accepted_smsc, octstr_imm(";")); octstr_destroy(accepted_smsc); } accepted_account = cfg_get(grp, octstr_imm("accepted-account")); if (accepted_account != NULL) { ot->accepted_account = octstr_split(accepted_account, octstr_imm(";")); octstr_destroy(accepted_account); } accepted_smsc_regex = cfg_get(grp, octstr_imm("accepted-smsc-regex")); if (accepted_smsc_regex != NULL) { if ( (ot->accepted_smsc_regex = gw_regex_comp(accepted_smsc_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(accepted_smsc_regex)); octstr_destroy(accepted_smsc_regex); } accepted_account_regex = cfg_get(grp, octstr_imm("accepted-account-regex")); if (accepted_account_regex != NULL) { if ( (ot->accepted_account_regex = gw_regex_comp(accepted_account_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(accepted_account_regex)); octstr_destroy(accepted_account_regex); } cfg_get_bool(&ot->assume_plain_text, grp, octstr_imm("assume-plain-text")); cfg_get_bool(&ot->accept_x_kannel_headers, grp, octstr_imm("accept-x-kannel-headers")); cfg_get_bool(&ot->strip_keyword, grp, octstr_imm("strip-keyword")); cfg_get_bool(&ot->send_sender, grp, octstr_imm("send-sender")); ot->prefix = cfg_get(grp, octstr_imm("prefix")); ot->suffix = cfg_get(grp, octstr_imm("suffix")); ot->allowed_recv_prefix = cfg_get(grp, octstr_imm("allowed-receiver-prefix")); allowed_receiver_prefix_regex = cfg_get(grp, octstr_imm("allowed-receiver-prefix-regex")); if (allowed_receiver_prefix_regex != NULL) { if ((ot->allowed_receiver_prefix_regex = gw_regex_comp(allowed_receiver_prefix_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(allowed_receiver_prefix_regex)); octstr_destroy(allowed_receiver_prefix_regex); } ot->allowed_recv_prefix = cfg_get(grp, octstr_imm("allowed-receiver-prefix")); ot->denied_recv_prefix = cfg_get(grp, octstr_imm("denied-receiver-prefix")); denied_receiver_prefix_regex = cfg_get(grp, octstr_imm("denied-receiver-prefix-regex")); if (denied_receiver_prefix_regex != NULL) { if ((ot->denied_receiver_prefix_regex = gw_regex_comp(denied_receiver_prefix_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'",octstr_get_cstr(denied_receiver_prefix_regex)); octstr_destroy(denied_receiver_prefix_regex); } ot->args = count_occurences(ot->pattern, octstr_imm("%s")); ot->args += count_occurences(ot->pattern, octstr_imm("%S")); ot->has_catchall_arg = (count_occurences(ot->pattern, octstr_imm("%r")) > 0) || (count_occurences(ot->pattern, octstr_imm("%a")) > 0); } else { ot->type = TRANSTYPE_SENDSMS; ot->pattern = octstr_create(""); ot->args = 0; ot->has_catchall_arg = 0; ot->catch_all = 1; ot->username = cfg_get(grp, octstr_imm("username")); ot->password = cfg_get(grp, octstr_imm("password")); ot->dlr_url = cfg_get(grp, octstr_imm("dlr-url")); grp_dump(grp); if (ot->password == NULL) { error(0, "Password required for send-sms user"); goto error; } ot->name = cfg_get(grp, octstr_imm("name")); if (ot->name == NULL) ot->name = octstr_duplicate(ot->username); forced_smsc = cfg_get(grp, octstr_imm("forced-smsc")); default_smsc = cfg_get(grp, octstr_imm("default-smsc")); if (forced_smsc != NULL) { if (default_smsc != NULL) { info(0, "Redundant default-smsc for send-sms user %s", octstr_get_cstr(ot->username)); } ot->forced_smsc = forced_smsc; octstr_destroy(default_smsc); } else if (default_smsc != NULL) ot->default_smsc = default_smsc; ot->deny_ip = cfg_get(grp, octstr_imm("user-deny-ip")); ot->allow_ip = cfg_get(grp, octstr_imm("user-allow-ip")); ot->default_sender = cfg_get(grp, octstr_imm("default-sender")); } ot->allowed_prefix = cfg_get(grp, octstr_imm("allowed-prefix")); allowed_prefix_regex = cfg_get(grp, octstr_imm("allowed-prefix-regex")); if (allowed_prefix_regex != NULL) { if ((ot->allowed_prefix_regex = gw_regex_comp(allowed_prefix_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(allowed_prefix_regex)); octstr_destroy(allowed_prefix_regex); } ot->denied_prefix = cfg_get(grp, octstr_imm("denied-prefix")); denied_prefix_regex = cfg_get(grp, octstr_imm("denied-prefix-regex")); if (denied_prefix_regex != NULL) { if ((ot->denied_prefix_regex = gw_regex_comp(denied_prefix_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(denied_prefix_regex)); octstr_destroy(denied_prefix_regex); } os = cfg_get(grp, octstr_imm("white-list")); if (os != NULL) { ot->white_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } white_list_regex = cfg_get(grp, octstr_imm("white-list-regex")); if (white_list_regex != NULL) { if ((ot->white_list_regex = gw_regex_comp(white_list_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(white_list_regex)); octstr_destroy(white_list_regex); } os = cfg_get(grp, octstr_imm("black-list")); if (os != NULL) { ot->black_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } black_list_regex = cfg_get(grp, octstr_imm("black-list-regex")); if (black_list_regex != NULL) { if ((ot->black_list_regex = gw_regex_comp(black_list_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(black_list_regex)); octstr_destroy(black_list_regex); } if (cfg_get_integer(&ot->max_messages, grp, octstr_imm("max-messages")) == -1) ot->max_messages = 1; cfg_get_bool(&ot->concatenation, grp, octstr_imm("concatenation")); cfg_get_bool(&ot->omit_empty, grp, octstr_imm("omit-empty")); ot->header = cfg_get(grp, octstr_imm("header")); ot->footer = cfg_get(grp, octstr_imm("footer")); ot->faked_sender = cfg_get(grp, octstr_imm("faked-sender")); ot->split_chars = cfg_get(grp, octstr_imm("split-chars")); ot->split_suffix = cfg_get(grp, octstr_imm("split-suffix")); if ( (ot->prefix == NULL && ot->suffix != NULL) || (ot->prefix != NULL && ot->suffix == NULL) ) { warning(0, "Service : suffix and prefix are only used" " if both are set."); } if ((ot->prefix != NULL || ot->suffix != NULL) && ot->type != TRANSTYPE_GET_URL) { warning(0, "Service : suffix and prefix are only used" " if type is 'get-url'."); } return ot; error: error(0, "Couldn't create a URLTranslation."); destroy_onetrans(ot); return NULL; } /* * Free one URLTranslation. */ static void destroy_onetrans(void *p) { URLTranslation *ot; ot = p; if (ot != NULL) { octstr_destroy(ot->dlr_url); octstr_destroy(ot->pattern); octstr_destroy(ot->prefix); octstr_destroy(ot->suffix); octstr_destroy(ot->default_sender); octstr_destroy(ot->faked_sender); octstr_destroy(ot->split_chars); octstr_destroy(ot->split_suffix); octstr_destroy(ot->header); octstr_destroy(ot->footer); octstr_destroy(ot->alt_charset); gwlist_destroy(ot->accepted_smsc, octstr_destroy_item); gwlist_destroy(ot->accepted_account, octstr_destroy_item); octstr_destroy(ot->name); octstr_destroy(ot->username); octstr_destroy(ot->password); octstr_destroy(ot->forced_smsc); octstr_destroy(ot->default_smsc); octstr_destroy(ot->allow_ip); octstr_destroy(ot->deny_ip); octstr_destroy(ot->allowed_prefix); octstr_destroy(ot->denied_prefix); octstr_destroy(ot->allowed_recv_prefix); octstr_destroy(ot->denied_recv_prefix); numhash_destroy(ot->white_list); numhash_destroy(ot->black_list); if (ot->keyword_regex != NULL) gw_regex_destroy(ot->keyword_regex); if (ot->accepted_smsc_regex != NULL) gw_regex_destroy(ot->accepted_smsc_regex); if (ot->accepted_account_regex != NULL) gw_regex_destroy(ot->accepted_account_regex); if (ot->allowed_prefix_regex != NULL) gw_regex_destroy(ot->allowed_prefix_regex); if (ot->denied_prefix_regex != NULL) gw_regex_destroy(ot->denied_prefix_regex); if (ot->allowed_receiver_prefix_regex != NULL) gw_regex_destroy(ot->allowed_receiver_prefix_regex); if (ot->denied_receiver_prefix_regex != NULL) gw_regex_destroy(ot->denied_receiver_prefix_regex); if (ot->white_list_regex != NULL) gw_regex_destroy(ot->white_list_regex); if (ot->black_list_regex != NULL) gw_regex_destroy(ot->black_list_regex); gw_free(ot); } } /* * checks if the number of passed words matches the service-pattern defined in the * translation. returns 0 if arguments are okay, -1 otherwise. */ static int check_num_args(URLTranslation *t, List *words) { const int IS_OKAY = 0; const int NOT_OKAY = -1; int n; n = gwlist_len(words); /* check number of arguments */ if (t->catch_all) return IS_OKAY; if (n - 1 == t->args) return IS_OKAY; if (t->has_catchall_arg && n - 1 >= t->args) return IS_OKAY; return NOT_OKAY; } /* * checks if a request matches the parameters of a URL-Translation, e.g. whether or not * a user is allowed to use certain services. returns 0 if allowed, -1 if not. */ static int check_allowed_translation(URLTranslation *t, Octstr *smsc, Octstr *sender, Octstr *receiver, Octstr *account) { const int IS_ALLOWED = 0; const int NOT_ALLOWED = -1; /* if smsc_id set and accepted_smsc exist, accept * translation only if smsc id is in accept string */ if (smsc && t->accepted_smsc && !gwlist_search(t->accepted_smsc, smsc, octstr_item_match)) return NOT_ALLOWED; if (smsc && t->accepted_smsc_regex && gw_regex_match_pre( t->accepted_smsc_regex, smsc) == 0) return NOT_ALLOWED; /* if account_id set and accepted_account exist, accept * translation only if smsc id is in accept string */ if (account && t->accepted_account && !gwlist_search(t->accepted_account, account, octstr_item_match)) return NOT_ALLOWED; if (account && t->accepted_account_regex && gw_regex_match_pre( t->accepted_account_regex, account) == 0) return NOT_ALLOWED; /* Have allowed for sender */ if (t->allowed_prefix && !t->denied_prefix && does_prefix_match(t->allowed_prefix, sender) != 1) return NOT_ALLOWED; if (t->allowed_prefix_regex && !t->denied_prefix_regex && gw_regex_match_pre(t->allowed_prefix_regex, sender) == 0) return NOT_ALLOWED; /* Have denied for sender */ if (t->denied_prefix && !t->allowed_prefix && does_prefix_match(t->denied_prefix, sender) == 1) return NOT_ALLOWED; if (t->denied_prefix_regex && !t->allowed_prefix_regex && gw_regex_match_pre(t->denied_prefix_regex, sender) == 1) return NOT_ALLOWED; /* Have allowed for receiver */ if (t->allowed_recv_prefix && !t->denied_recv_prefix && does_prefix_match(t->allowed_recv_prefix, receiver) != 1) return NOT_ALLOWED; if (t->allowed_receiver_prefix_regex && !t->denied_receiver_prefix_regex && gw_regex_match_pre(t->allowed_receiver_prefix_regex, receiver) == 0) return NOT_ALLOWED; /* Have denied for receiver */ if (t->denied_recv_prefix && !t->allowed_recv_prefix && does_prefix_match(t->denied_recv_prefix, receiver) == 1) return NOT_ALLOWED; if (t->denied_receiver_prefix_regex && !t->allowed_receiver_prefix_regex && gw_regex_match_pre(t->denied_receiver_prefix_regex, receiver) == 0) return NOT_ALLOWED; if (t->white_list && numhash_find_number(t->white_list, sender) < 1) { return NOT_ALLOWED; } if (t->white_list_regex && gw_regex_match_pre(t->white_list_regex, sender) == 0) { return NOT_ALLOWED; } if (t->black_list && numhash_find_number(t->black_list, sender) == 1) { return NOT_ALLOWED; } if (t->black_list_regex && gw_regex_match_pre(t->black_list_regex, sender) == 1) { return NOT_ALLOWED; } /* Have allowed and denied */ if (t->denied_prefix && t->allowed_prefix && does_prefix_match(t->allowed_prefix, sender) != 1 && does_prefix_match(t->denied_prefix, sender) == 1) return NOT_ALLOWED; if (t->denied_prefix_regex && t->allowed_prefix_regex && gw_regex_match_pre(t->allowed_prefix_regex, sender) == 0 && gw_regex_match_pre(t->denied_prefix_regex, sender) == 1) return NOT_ALLOWED; return IS_ALLOWED; }; /* get_matching_translations - iterate over all translations in trans. * for each translation check whether * the translation's keyword has already been interpreted as a regexp. * if not, compile it now, * otherwise retrieve compilation result from dictionary. * * the translations where the word matches the translation's pattern * are returned in a list * */ static List *get_matching_translations(URLTranslationList *trans, Octstr *msg) { List *list; long i; URLTranslation *t; gw_assert(trans != NULL && msg != NULL); list = gwlist_create(); for (i = 0; i < gwlist_len(trans->list); ++i) { t = gwlist_get(trans->list, i); if (t->keyword_regex == NULL) continue; if (gw_regex_match_pre(t->keyword_regex, msg) == 1) { debug("", 0, "match found: %s", octstr_get_cstr(t->name)); gwlist_append(list, t); } else { debug("", 0, "no match found: %s", octstr_get_cstr(t->name)); } } return list; } /* * Find the appropriate translation */ static URLTranslation *find_translation(URLTranslationList *trans, Msg *msg) { Octstr *data; int i; URLTranslation *t = NULL; List *list, *words; /* convert tolower and try to match */ data = octstr_duplicate(msg->sms.msgdata); i = 0; while((i = octstr_search_char(data, 0, i)) != -1 && i < octstr_len(data) - 1) { octstr_delete(data, i, 1); } list = get_matching_translations(trans, data); words = octstr_split_words(data); /** * List now contains all translations where the keyword of the sms * matches the pattern defined by the tranlsation's keyword. */ for (i = 0; i < gwlist_len(list); ++i) { t = gwlist_get(list, i); /* TODO check_num_args, do we really need this??? */ if (check_allowed_translation(t, msg->sms.smsc_id, msg->sms.sender, msg->sms.receiver, msg->sms.account) == 0 && check_num_args(t, words) == 0) break; t = NULL; } octstr_destroy(data); gwlist_destroy(words, octstr_destroy_item); gwlist_destroy(list, NULL); return t; } static URLTranslation *find_default_translation(URLTranslationList *trans, Octstr *smsc, Octstr *sender, Octstr *receiver, Octstr *account) { URLTranslation *t; int i; List *list; list = trans->defaults; t = NULL; for (i = 0; i < gwlist_len(list); ++i) { t = gwlist_get(list, i); if (check_allowed_translation(t, smsc, sender, receiver, account) == 0) break; t = NULL; } return t; } /* * Count the number of times `pat' occurs in `str'. */ static long count_occurences(Octstr *str, Octstr *pat) { long count; long pos; long len; count = 0; pos = 0; len = octstr_len(pat); while ((pos = octstr_search(str, pat, pos)) != -1) { ++count; pos += len; } return count; } gateway-1.4.5/gw/wml_compiler.c0000644000175000017500000015512113227613126015146 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wml_compiler.c - compiling WML to WML binary * * This is an implemention for WML compiler for compiling the WML text * format to WML binary format, which is used for transmitting the * decks to the mobile terminal to decrease the use of the bandwidth. * * * Tuomas Luttinen for Wapit Ltd. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "wml_compiler.h" #include "xml_definitions.h" /*********************************************************************** * Declarations of data types. * * Binary code values are defined by OMNA, see * http://www.openmobilealliance.org/tech/omna/omna-wbxml-public-docid.htm */ struct wml_externalid_t { char *string; unsigned long value; }; typedef struct wml_externalid_t wml_externalid_t; #define NUMBERED(name, strings) \ static const wml_externalid_t name##_strings[] = { strings }; #define ASSIGN(string, number) { string, number }, #include "wbxml_tokens.def" #define NUMBER_OF_WML_EXTERNALID ((long) sizeof(public_ids_strings)/sizeof(public_ids_strings[0])) struct wbxml_version_t { char *string; char value; }; typedef struct wbxml_version_t wbxml_version_t; static wbxml_version_t wbxml_version[] = { { "1.1", 0x01 }, { "1.2", 0x02 }, { "1.3", 0x03 }, { "1.4", 0x04 }, { "1.5", 0x05 } }; #define NUMBER_OF_WBXML_VERSION sizeof(wbxml_version)/sizeof(wbxml_version[0]) typedef enum { NOESC, ESC, UNESC, FAILED } var_esc_t; /* * The wml token table node with two fields. */ typedef struct { char *text; unsigned char token; } wml_table_t; /* * The wml token table node with three fields. */ typedef struct { char *text1; char *text2; unsigned char token; } wml_table3_t; /* * The binary WML structure, that has been passed around between the * internal functions. It contains the header fields for wbxml version, * the WML public ID and the character set, the length of the string table, * the list structure implementing the string table and the octet string * containing the encoded WML binary. */ typedef struct { unsigned char wbxml_version; unsigned long wml_public_id; unsigned long character_set; unsigned long string_table_length; List *string_table; Octstr *wbxml_string; } wml_binary_t; /* * The string table list node. */ typedef struct { unsigned long offset; Octstr *string; } string_table_t; /* * The string table proposal list node. */ typedef struct { int count; Octstr *string; } string_table_proposal_t; /* * The wml hash table node. */ typedef struct { Octstr *item; unsigned char binary; } wml_hash_t; /* * The hash table node for attribute and values. */ typedef struct { Octstr *attribute; unsigned char binary; List *value_list; } wml_attribute_t; #include "xml_shared.h" #include "wml_definitions.h" /*********************************************************************** * Declarations of global variables. */ Dict *wml_elements_dict; Dict *wml_attributes_dict; List *wml_attr_values_list; List *wml_URL_values_list; int wml_xml_parser_opt; /*********************************************************************** * Declarations of internal functions. These are defined at the end of * the file. */ /* * Parsing functions. These funtions operate on a single node or a * smaller datatype. Look for more details on the functions at the * definitions. */ static int parse_document(xmlDocPtr document, Octstr *charset, wml_binary_t **wbxml, Octstr *version); static int parse_node(xmlNodePtr node, wml_binary_t **wbxml); static int parse_element(xmlNodePtr node, wml_binary_t **wbxml); static int parse_attribute(xmlAttrPtr attr, wml_binary_t **wbxml); static int parse_attr_value(Octstr *attr_value, List *tokens, wml_binary_t **wbxml, int charset, var_esc_t default_esc); static int parse_text(xmlNodePtr node, wml_binary_t **wbxml); static int parse_cdata(xmlNodePtr node, wml_binary_t **wbxml); static int parse_st_octet_string(Octstr *ostr, int cdata, var_esc_t default_esc, wml_binary_t **wbxml); static void parse_st_end(wml_binary_t **wbxml); static void parse_entities(Octstr *wml_source); /* * Variable functions. These functions are used to find and parse variables. */ static int parse_variable(Octstr *text, int start, var_esc_t default_esc, Octstr **output, wml_binary_t **wbxml); static Octstr *get_variable(Octstr *text, int start); static var_esc_t check_variable_syntax(Octstr *variable, var_esc_t default_esc); /* * wml_binary-functions. These are used to create, destroy and modify * wml_binary_t. */ static wml_binary_t *wml_binary_create(void); static void wml_binary_destroy(wml_binary_t *wbxml); static void wml_binary_output(Octstr *ostr, wml_binary_t *wbxml); /* Output into the wml_binary. */ static void output_st_char(int byte, wml_binary_t **wbxml); static void output_st_octet_string(Octstr *ostr, wml_binary_t **wbxml); static void output_variable(Octstr *variable, Octstr **output, var_esc_t escaped, wml_binary_t **wbxml); /* * Memory allocation and deallocations. */ static wml_hash_t *hash_create(char *text, unsigned char token); static wml_attribute_t *attribute_create(void); static void attr_dict_construct(wml_table3_t *attributes, Dict *attr_dict); static void hash_destroy(void *p); static void attribute_destroy(void *p); /* * Comparison functions for the hash tables. */ static int hash_cmp(void *hash1, void *hash2); /* * Miscellaneous help functions. */ static int check_do_elements(xmlNodePtr node); static var_esc_t check_variable_name(xmlNodePtr node); static Octstr *get_do_element_name(xmlNodePtr node); static int check_if_url(int hex); static int check_if_emphasis(xmlNodePtr node); static int wml_table_len(wml_table_t *table); static int wml_table3_len(wml_table3_t *table); /* * String table functions, used to add and remove strings into and from the * string table. */ static string_table_t *string_table_create(int offset, Octstr *ostr); static void string_table_destroy(string_table_t *node); static string_table_proposal_t *string_table_proposal_create(Octstr *ostr); static void string_table_proposal_destroy(string_table_proposal_t *node); static void string_table_build(xmlNodePtr node, wml_binary_t **wbxml); static void string_table_collect_strings(xmlNodePtr node, List *strings); static List *string_table_collect_words(List *strings); static List *string_table_sort_list(List *start); static List *string_table_add_many(List *sorted, wml_binary_t **wbxml); static unsigned long string_table_add(Octstr *ostr, wml_binary_t **wbxml); static void string_table_apply(Octstr *ostr, wml_binary_t **wbxml); static void string_table_output(Octstr *ostr, wml_binary_t **wbxml); /*********************************************************************** * Generic error message formater for libxml2 related errors */ static void xml_error(void) { xmlErrorPtr err; Octstr *msg; /* we should have an error, but be more sensitive */ if ((err = xmlGetLastError()) == NULL) return; /* replace annoying line feeds */ msg = octstr_format("%s", err->message); octstr_replace(msg, octstr_imm("\n"), octstr_imm(" ")); error(0,"XML error: code: %d, level: %d, line: %d, %s", err->code, err->level, err->line, octstr_get_cstr(msg)); octstr_destroy(msg); } /*********************************************************************** * Implementations of the functions declared in wml_compiler.h. */ /* * The actual compiler function. This operates as interface to the compiler. * For more information, look wml_compiler.h. */ int wml_compile(Octstr *wml_text, Octstr *charset, Octstr **wml_binary, Octstr *version) { int ret = 0; size_t size; xmlDocPtr pDoc = NULL; char *wml_c_text; wml_binary_t *wbxml = NULL; *wml_binary = octstr_create(""); wbxml = wml_binary_create(); /* Remove the extra space from start and the end of the WML Document. */ octstr_strip_blanks(wml_text); /* Check the WML-code for \0-characters and for WML entities. Fast patch. -- tuo */ parse_entities(wml_text); size = octstr_len(wml_text); wml_c_text = octstr_get_cstr(wml_text); debug("wml_compile",0, "WML: Given charset: %s", octstr_get_cstr(charset)); if (octstr_search_char(wml_text, '\0', 0) != -1) { error(0, "WML compiler: Compiling error: " "\\0 character found in the middle of the WML source."); ret = -1; } else { /* * An empty octet string for the binary output is created, the wml * source is parsed into a parsing tree and the tree is then compiled * into binary. */ pDoc = xmlReadMemory(wml_c_text, size, NULL, octstr_get_cstr(charset), wml_xml_parser_opt); if (pDoc != NULL) { /* * If we have a set internal encoding, then apply this information * to the XML parsing tree document for later transcoding ability. */ if (charset) pDoc->charset = xmlParseCharEncoding(octstr_get_cstr(charset)); ret = parse_document(pDoc, charset, &wbxml, version); wml_binary_output(*wml_binary, wbxml); } else { error(0, "WML compiler: Compiling error: " "libxml2 returned a NULL pointer"); xml_error(); ret = -1; } } wml_binary_destroy(wbxml); if (pDoc) xmlFreeDoc(pDoc); return ret; } /* * Initialization: makes up the hash tables for the compiler. */ void wml_init(int wml_xml_strict) { int i = 0, len = 0; wml_hash_t *temp = NULL; /* The wml elements into a hash table. */ len = wml_table_len(wml_elements); wml_elements_dict = dict_create(len, hash_destroy); for (i = 0; i < len; i++) { temp = hash_create(wml_elements[i].text, wml_elements[i].token); dict_put(wml_elements_dict, temp->item, temp); } /* Attributes. */ len = wml_table3_len(wml_attributes); wml_attributes_dict = dict_create(len, attribute_destroy); attr_dict_construct(wml_attributes, wml_attributes_dict); /* Attribute values. */ len = wml_table_len(wml_attribute_values); wml_attr_values_list = gwlist_create(); for (i = 0; i < len; i++) { temp = hash_create(wml_attribute_values[i].text, wml_attribute_values[i].token); gwlist_append(wml_attr_values_list, temp); } /* URL values. */ len = wml_table_len(wml_URL_values); wml_URL_values_list = gwlist_create(); for (i = 0; i < len; i++) { temp = hash_create(wml_URL_values[i].text, wml_URL_values[i].token); gwlist_append(wml_URL_values_list, temp); } /* Strict XML parsing. */ wml_xml_parser_opt = wml_xml_strict ? (XML_PARSE_NOERROR | XML_PARSE_NONET) : (XML_PARSE_RECOVER | XML_PARSE_NOERROR | XML_PARSE_NONET); } /* * Shutdown: Frees the memory allocated by initialization. */ void wml_shutdown() { dict_destroy(wml_elements_dict); dict_destroy(wml_attributes_dict); gwlist_destroy(wml_attr_values_list, hash_destroy); gwlist_destroy(wml_URL_values_list, hash_destroy); } /*********************************************************************** * Internal functions. */ /* * parse_node - the recursive parsing function for the parsing tree. * Function checks the type of the node, calls for the right parse * function for the type, then calls itself for the first child of * the current node if there's one and after that calls itself for the * next child on the list. */ static int parse_node(xmlNodePtr node, wml_binary_t **wbxml) { int status = 0; /* Call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_element(node, wbxml); break; case XML_TEXT_NODE: status = parse_text(node, wbxml); break; case XML_CDATA_SECTION_NODE: status = parse_cdata(node, wbxml); break; case XML_COMMENT_NODE: case XML_PI_NODE: /* Comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * WML. Therefore they are assumed to be an error. */ default: error(0, "WML compiler: Unknown XML node in the WML source."); return -1; break; } /* * If node is an element with content, it will need an end tag after it's * children. The status for it is returned by parse_element. */ switch (status) { case 0: if (node->children != NULL) if (parse_node(node->children, wbxml) == -1) return -1; break; case 1: if (node->children != NULL) if (parse_node(node->children, wbxml) == -1) return -1; parse_st_end(wbxml); break; case -1: /* Something went wrong in the parsing. */ return -1; default: error(0, "WML compiler: undefined return value in a parse function."); return -1; break; } if (node->next != NULL) if (parse_node(node->next, wbxml) == -1) return -1; return 0; } /* * parse_document - the parsing function for the document node. * The function outputs the WBXML version, WML public id and the * character set values into start of the wbxml. */ static int parse_document(xmlDocPtr document, Octstr *charset, wml_binary_t **wbxml, Octstr *version) { xmlNodePtr node; Octstr *externalID = NULL; long i; if (document == NULL) { error(0, "WML compiler: XML parsing failed, no parsed document."); error(0, "Most probably an error in the WML source."); return -1; } /* Return WBXML version dependent on device given Encoding-Version */ if (version == NULL) { (*wbxml)->wbxml_version = 0x01; /* WBXML Version number 1.1 */ info(0, "WBXML: No wbxml version given, assuming 1.1"); } else { for (i = 0; i < NUMBER_OF_WBXML_VERSION; i++) { if (octstr_compare(version, octstr_imm(wbxml_version[i].string)) == 0) { (*wbxml)->wbxml_version = wbxml_version[i].value; debug("parse_document",0,"WBXML: Encoding with wbxml version <%s>", octstr_get_cstr(version)); break; } } if (i == NUMBER_OF_WBXML_VERSION) { (*wbxml)->wbxml_version = 0x01; /* WBXML Version number 1.1 */ warning(0, "WBXML: Unknown wbxml version, assuming 1.1 (<%s> is unknown)", octstr_get_cstr(version)); } } /* Return WML Version dependent on xml ExternalID string */ if ((document->intSubset != NULL) && (document->intSubset->ExternalID != NULL)) externalID = octstr_create((char *)document->intSubset->ExternalID); if (externalID == NULL) { (*wbxml)->wml_public_id = 0x04; /* WML 1.1 Public ID */ warning(0, "WBXML: WML without ExternalID, assuming 1.1"); } else { for (i = 0; i < NUMBER_OF_WML_EXTERNALID; i++) { if (octstr_compare(externalID, octstr_imm(public_ids_strings[i].string)) == 0) { (*wbxml)->wml_public_id = public_ids_strings[i].value; debug("parse_document",0,"WBXML: WML with ExternalID <%s>", octstr_get_cstr(externalID)); break; } } if (i == NUMBER_OF_WML_EXTERNALID) { (*wbxml)->wml_public_id = 0x04; /* WML 1.1 Public ID */ warning(0, "WBXML: WML with unknown ExternalID, assuming 1.1 " "(<%s> is unknown)", octstr_get_cstr(externalID)); } } octstr_destroy(externalID); (*wbxml)->string_table_length = 0x00; /* String table length=0 */ /* * Make sure we set the charset encoding right. If none is given * then set UTF-8 as default. */ (*wbxml)->character_set = charset ? parse_charset(charset) : parse_charset(octstr_imm("UTF-8")); node = xmlDocGetRootElement(document); if (node == NULL) { error(0, "WML compiler: XML parsing failed, no document root element."); error(0, "Most probably an error in the WML source."); xml_error(); return -1; } string_table_build(node, wbxml); return parse_node(node, wbxml); } /* * parse_element - the parsing function for an element node. * The element tag is encoded into one octet hexadecimal value, * if possible. Otherwise it is encoded as text. If the element * needs an end tag, the function returns 1, for no end tag 0 * and -1 for an error. */ static int parse_element(xmlNodePtr node, wml_binary_t **wbxml) { int add_end_tag = 0; unsigned char wbxml_hex = 0, status_bits; xmlAttrPtr attribute; Octstr *name; wml_hash_t *element; name = octstr_create((char *)node->name); /* Check, if the tag can be found from the code page. */ if ((element = dict_get(wml_elements_dict, name)) != NULL) { wbxml_hex = element->binary; /* A conformance patch: no do-elements of same name in a card or template. An extremely ugly patch. --tuo */ if (wbxml_hex == 0x27 || /* Card */ wbxml_hex == 0x3B) /* Template */ if (check_do_elements(node) == -1) { add_end_tag = -1; error(0, "WML compiler: Two or more do elements with same" " name in a card or template element."); } /* A conformance patch: if variable in setvar has a bad name, it's ignored. */ if (wbxml_hex == 0x3E) /* Setvar */ if (check_variable_name(node) == FAILED) { octstr_destroy(name); return add_end_tag; } if ((status_bits = element_check_content(node)) > 0) { wbxml_hex = wbxml_hex | status_bits; /* If this node has children, the end tag must be added after them. */ if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) add_end_tag = 1; } output_st_char(wbxml_hex, wbxml); } else { /* The tag was not on the code page, it has to be encoded as a string. */ wbxml_hex = WBXML_LITERAL; if ((status_bits = element_check_content(node)) > 0) { wbxml_hex = wbxml_hex | status_bits; /* If this node has children, the end tag must be added after them. */ if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) add_end_tag = 1; } output_st_char(wbxml_hex, wbxml); octstr_append_uintvar((*wbxml)->wbxml_string,string_table_add(octstr_duplicate(name), wbxml)); warning(0, "WML compiler: Unknown tag in WML source: <%s>", octstr_get_cstr(name)); } /* Encode the attribute list for this node and add end tag after the list. */ if(node->properties != NULL) { attribute = node->properties; while (attribute != NULL) { parse_attribute(attribute, wbxml); attribute = attribute->next; } parse_st_end(wbxml); } octstr_destroy(name); return add_end_tag; } /* * parse_attribute - the parsing function for attributes. The function * encodes the attribute (and probably start of the value) as a one * hexadecimal octet. The value (or the rest of it) is coded as a string * maybe using predefined attribute value tokens to reduce the length * of the output. Returns 0 for success, -1 for error. */ static int parse_attribute(xmlAttrPtr attr, wml_binary_t **wbxml) { int status = 0; int coded_length = 0; unsigned char wbxml_hex = 0x00; wml_hash_t *hit = NULL; wml_attribute_t *attribute = NULL; Octstr *name = NULL, *pattern = NULL, *p = NULL; name = octstr_create((char *)attr->name); if (attr->children != NULL) pattern = create_octstr_from_node((char *)attr->children); else pattern = NULL; /* Check if the attribute is found on the code page. */ if ((attribute = dict_get(wml_attributes_dict, name)) != NULL) { if (attr->children == NULL || (hit = gwlist_search(attribute->value_list, (void *)pattern, hash_cmp)) == NULL) { if(attribute->binary == 0x00) { warning(0, "WML compiler: can't compile attribute %s%s%s%s", octstr_get_cstr(attribute->attribute), (attr->children != NULL ? "=\"": ""), (attr->children != NULL ? octstr_get_cstr(pattern) : ""), (attr->children != NULL ? "\"": "")); wbxml_hex = WBXML_LITERAL; output_st_char(wbxml_hex, wbxml); output_st_char(string_table_add(octstr_duplicate(name), wbxml), wbxml); } else { wbxml_hex = attribute->binary; output_st_char(wbxml_hex, wbxml); } } else if (hit->binary) { wbxml_hex = hit->binary; coded_length = octstr_len(hit->item); output_st_char(wbxml_hex, wbxml); } else status = -1; } else { /* The attribute was not on the code page, it has to be encoded as a string. */ wbxml_hex = WBXML_LITERAL; output_st_char(wbxml_hex, wbxml); octstr_append_uintvar((*wbxml)->wbxml_string,string_table_add(octstr_duplicate(name), wbxml)); warning(0, "WML compiler: Unknown attribute in WML source: <%s>", octstr_get_cstr(name)); } if (status >= 0) { var_esc_t default_esc; default_esc = (octstr_str_compare (name, "href") == 0) ? ESC : NOESC; /* The rest of the attribute is coded as a inline string. */ if (pattern != NULL && coded_length < (int) octstr_len(pattern)) { if (coded_length == 0) p = create_octstr_from_node((char *)attr->children); else p = octstr_copy(pattern, coded_length, octstr_len(pattern) - coded_length); if (check_if_url(wbxml_hex)) status = parse_attr_value(p, wml_URL_values_list, wbxml, attr->doc->charset, default_esc); else status = parse_attr_value(p, wml_attr_values_list, wbxml, attr->doc->charset, default_esc); if (status != 0) error(0, "WML compiler: could not output attribute " "value as a string."); octstr_destroy(p); } } /* Memory cleanup. */ octstr_destroy(name); if (pattern != NULL) octstr_destroy(pattern); return status; } /* * parse_attr_value - parses an attributes value using WML value codes. */ static int parse_attr_value(Octstr *attr_value, List *tokens, wml_binary_t **wbxml, int charset, var_esc_t default_esc) { int i, pos, wbxml_hex; wml_hash_t *temp = NULL; Octstr *cut_text = NULL; char *tmp; /* * Beware that libxml2 does internal encoding in UTF-8 while parsing. * So if our original WML source had a different encoding set, we have * to transcode at least here. Only transcode if target encoding differs * from libxml2's internal encoding (UTF-8). */ tmp = (char*) xmlGetCharEncodingName(charset); if (charset != XML_CHAR_ENCODING_UTF8 && charset_convert(attr_value, "UTF-8", tmp) != 0) { error(0, "Failed to convert XML attribute value from charset " "<%s> to <%s>, will leave as is.", "UTF-8", tmp ? tmp : "(undef)"); } /* * The attribute value is search for text strings that can be replaced * with one byte codes. Note that the algorith is not foolproof; seaching * is done in an order and the text before first hit is not checked for * those tokens that are after the hit in the order. Most likely it would * be waste of time anyway. String table is not used here, since at least * Nokia 7110 doesn't seem to understand string table references here. */ /* A fast patch to allow reserved names to be variable names. May produce a little longer binary at some points. --tuo */ if (octstr_search_char(attr_value, '$', 0) >= 0) { if (parse_st_octet_string(attr_value, 0, default_esc, wbxml) != 0) return -1; } else { for (i = 0; i < gwlist_len(tokens); i++) { temp = gwlist_get(tokens, i); pos = octstr_search(attr_value, temp->item, 0); switch (pos) { case -1: break; case 0: wbxml_hex = temp->binary; output_st_char(wbxml_hex, wbxml); octstr_delete(attr_value, 0, octstr_len(temp->item)); break; default: /* * There is some text before the first hit, that has to * be handled too. */ gw_assert(pos <= octstr_len(attr_value)); cut_text = octstr_copy(attr_value, 0, pos); if (parse_st_octet_string(cut_text, 0, default_esc, wbxml) != 0) return -1; octstr_destroy(cut_text); wbxml_hex = temp->binary; output_st_char(wbxml_hex, wbxml); octstr_delete(attr_value, 0, pos + octstr_len(temp->item)); break; } } /* * If no hits, then the attr_value is handled as a normal text, * otherwise the remaining part is searched for other hits too. */ if ((int) octstr_len(attr_value) > 0) { if (i < gwlist_len(tokens)) parse_attr_value(attr_value, tokens, wbxml, charset, default_esc); else if (parse_st_octet_string(attr_value, 0, default_esc, wbxml) != 0) return -1; } } return 0; } /* * parse_st_end - adds end tag to an element. */ static void parse_st_end(wml_binary_t **wbxml) { output_st_char(WBXML_END, wbxml); } /* * parse_text - a text string parsing function. * This function parses a text node. */ static int parse_text(xmlNodePtr node, wml_binary_t **wbxml) { int ret; Octstr *temp; char* tmp; temp = create_octstr_from_node((char *)node); /* returns string in UTF-8 */ /* * Beware that libxml2 does internal encoding in UTF-8 while parsing. * So if our original WML source had a different encoding set, we have * to transcode at least here. Only transcode if target encoding differs * from libxml2's internal encoding (UTF-8). */ tmp = (char*) xmlGetCharEncodingName(node->doc->charset); if (node->doc->charset != XML_CHAR_ENCODING_UTF8 && charset_convert(temp, "UTF-8", tmp) != 0) { error(0, "Failed to convert XML text entity from charset " "<%s> to <%s>, will leave as is.", "UTF-8", tmp ? tmp : "(undef)"); } octstr_shrink_blanks(temp); if (!check_if_emphasis(node->prev) && !check_if_emphasis(node->next)) octstr_strip_blanks(temp); if (octstr_len(temp) == 0) ret = 0; else ret = parse_st_octet_string(temp, 0, NOESC, wbxml); /* Memory cleanup. */ octstr_destroy(temp); return ret; } /* * parse_cdata - a cdata section parsing function. * This function parses a cdata section that is outputted into the binary * "as is". */ static int parse_cdata(xmlNodePtr node, wml_binary_t **wbxml) { int ret = 0; Octstr *temp; temp = create_octstr_from_node((char *)node); parse_st_octet_string(temp, 1, NOESC, wbxml); /* Memory cleanup. */ octstr_destroy(temp); return ret; } /* * parse_variable - a variable parsing function. * Arguments: * - text: the octet string containing a variable * - start: the starting position of the variable not including * trailing & * Returns: lenth of the variable for success, -1 for failure, 0 for * variable syntax error, when it will be ignored. * Parsed variable is returned as an octet string in Octstr **output. */ static int parse_variable(Octstr *text, int start, var_esc_t default_esc, Octstr **output, wml_binary_t **wbxml) { var_esc_t esc; int ret; Octstr *variable; variable = get_variable(text, start + 1); octstr_truncate(*output, 0); if (variable == NULL) return 0; if (octstr_get_char(variable, 0) == '$') { octstr_append_char(*output, '$'); octstr_destroy(variable); ret = 2; } else { if (octstr_get_char(text, start + 1) == '(') ret = octstr_len(variable) + 3; else ret = octstr_len(variable) + 1; if ((esc = check_variable_syntax(variable, default_esc)) != FAILED) output_variable(variable, output, esc, wbxml); else octstr_destroy(variable); } return ret; } /* * get_variable - get the variable name from text. * Octstr *text contains the text with a variable name starting at point * int start. */ static Octstr *get_variable(Octstr *text, int start) { Octstr *var = NULL; long end; int ch; gw_assert(text != NULL); gw_assert(start >= 0 && start <= (int) octstr_len(text)); ch = octstr_get_char(text, start); if (ch == '$') { var = octstr_create("$"); } else if (ch == '(') { start ++; end = octstr_search_char(text, ')', start); if (end == -1) error(0, "WML compiler: braces opened, but not closed for a " "variable."); else if (end - start == 0) error(0, "WML compiler: empty braces without variable."); else var = octstr_copy(text, start, end - start); } else { end = start + 1; while (isalnum(ch = octstr_get_char(text, end)) || (ch == '_')) end ++; var = octstr_copy(text, start, end - start); } return var; } /* * check_variable_syntax - checks the variable syntax and the possible * escape mode it has. Octstr *variable contains the variable string. */ static var_esc_t check_variable_syntax(Octstr *variable, var_esc_t default_esc) { Octstr *escape; char ch; int pos, len, i; var_esc_t ret; if ((pos = octstr_search_char(variable, ':', 0)) > 0) { len = octstr_len(variable) - pos; escape = octstr_copy(variable, pos + 1, len - 1); octstr_truncate(variable, pos); octstr_truncate(escape, len); octstr_convert_range(escape, 0, octstr_len(escape), tolower); if (octstr_str_compare(escape, "noesc") == 0 || octstr_str_compare(escape, "n") == 0 ) ret = NOESC; else if (octstr_str_compare(escape, "unesc") == 0 || octstr_str_compare(escape, "u") == 0 ) ret = UNESC; else if (octstr_str_compare(escape, "escape") == 0 || octstr_str_compare(escape, "e") == 0 ) ret = ESC; else { error(0, "WML compiler: syntax error in variable escaping."); octstr_destroy(escape); return FAILED; } octstr_destroy(escape); } else ret = default_esc; ch = octstr_get_char(variable, 0); if (!(isalpha((int)ch)) && ch != '_') { error(0, "WML compiler: syntax error in variable; name starting " "with %c.", ch); return FAILED; } else for (i = 1; i < (int) octstr_len(variable); i++) if (!isalnum((int)(ch = octstr_get_char(variable, 0))) && ch != '_') { warning(0, "WML compiler: syntax error in variable."); return FAILED; } return ret; } /* * parse_st_octet_string - parse an octet string into wbxml_string, the string * is checked for variables. If string is string table applicable, it will * be checked for string insrtances that are in the string table, otherwise * not. Returns 0 for success, -1 for error. */ static int parse_st_octet_string(Octstr *ostr, int cdata, var_esc_t default_esc, wml_binary_t **wbxml) { Octstr *output, *var, *temp = NULL; int var_len; int start = 0, pos = 0, len; /* No variables? Ok, let's take the easy way... (CDATA never contains variables.) */ if ((pos = octstr_search_char(ostr, '$', 0)) < 0 || cdata == 1) { string_table_apply(ostr, wbxml); return 0; } len = octstr_len(ostr); output = octstr_create(""); var = octstr_create(""); while (pos < len) { if (octstr_get_char(ostr, pos) == '$') { if (pos > start) { temp = octstr_copy(ostr, start, pos - start); octstr_insert(output, temp, octstr_len(output)); octstr_destroy(temp); } if ((var_len = parse_variable(ostr, pos, default_esc, &var, wbxml)) > 0) { if (octstr_len(var) > 0) { if (octstr_get_char(var, 0) == '$') /* * No, it's not actually variable, but $-character * escaped as "$$". So everything should be packed * into one string. */ octstr_insert(output, var, octstr_len(output)); else { /* * The string is output as a inline string and the * variable as a string table variable reference. */ if (octstr_len(output) > 0) string_table_apply(output, wbxml); octstr_truncate(output, 0); output_st_octet_string(var, wbxml); } /* Variable had a syntax error, so it's skipped. */ } pos = pos + var_len; start = pos; } else return -1; } else pos ++; } /* Was there still something after the last variable? */ if (start < pos) { if (octstr_len(output) == 0) { octstr_destroy(output); output = octstr_copy(ostr, start, pos - start); } else { temp = octstr_copy(ostr, start, pos - start); octstr_insert(output, temp, octstr_len(output)); octstr_destroy(temp); } } if (octstr_len(output) > 0) string_table_apply(output, wbxml); octstr_destroy(output); octstr_destroy(var); return 0; } /* * parse_entities - replaces WML entites in the WML source with equivalent * numerical entities. A fast patch for WAP 1.1 compliance. */ static void parse_entities(Octstr *wml_source) { static char entity_nbsp[] = " "; static char entity_shy[] = "­"; static char nbsp[] = " "; static char shy[] = "­"; int pos = 0; Octstr *temp; if ((pos = octstr_search(wml_source, octstr_imm(entity_nbsp), pos)) >= 0) { temp = octstr_create(nbsp); while (pos >= 0) { octstr_delete(wml_source, pos, strlen(entity_nbsp)); octstr_insert(wml_source, temp, pos); pos = octstr_search(wml_source, octstr_imm(entity_nbsp), pos); } octstr_destroy(temp); } pos = 0; if ((pos = octstr_search(wml_source, octstr_imm(entity_shy), pos)) >= 0) { temp = octstr_create(shy); while (pos >= 0) { octstr_delete(wml_source, pos, strlen(entity_shy)); octstr_insert(wml_source, temp, pos); pos = octstr_search(wml_source, octstr_imm(entity_shy), pos); } octstr_destroy(temp); } } /* * wml_binary_create - reserves memory for the wml_binary_t and sets the * fields to zeros and NULLs. */ static wml_binary_t *wml_binary_create(void) { wml_binary_t *wbxml; wbxml = gw_malloc(sizeof(wml_binary_t)); wbxml->wbxml_version = 0x00; wbxml->wml_public_id = 0x00; wbxml->character_set = 0x00; wbxml->string_table_length = 0x00; wbxml->string_table = gwlist_create(); wbxml->wbxml_string = octstr_create(""); return wbxml; } /* * wml_binary_destroy - frees the memory allocated for the wml_binary_t. */ static void wml_binary_destroy(wml_binary_t *wbxml) { if (wbxml != NULL) { gwlist_destroy(wbxml->string_table, NULL); octstr_destroy(wbxml->wbxml_string); gw_free(wbxml); } } /* * wml_binary_output - outputs all the fiels of wml_binary_t into ostr. */ static void wml_binary_output(Octstr *ostr, wml_binary_t *wbxml) { octstr_append_char(ostr, wbxml->wbxml_version); octstr_append_uintvar(ostr, wbxml->wml_public_id); octstr_append_uintvar(ostr, wbxml->character_set); octstr_append_uintvar(ostr, wbxml->string_table_length); if (wbxml->string_table_length > 0) string_table_output(ostr, &wbxml); octstr_insert(ostr, wbxml->wbxml_string, octstr_len(ostr)); } /* * output_st_char - output a character into wbxml_string. * Returns 0 for success, -1 for error. */ static void output_st_char(int byte, wml_binary_t **wbxml) { octstr_append_char((*wbxml)->wbxml_string, byte); } /* * output_st_octet_string - output an octet string into wbxml. * Returns 0 for success, -1 for an error. No conversions. */ static void output_st_octet_string(Octstr *ostr, wml_binary_t **wbxml) { octstr_insert((*wbxml)->wbxml_string, ostr, octstr_len((*wbxml)->wbxml_string)); } /* * output_variable - output a variable reference into the string table. */ static void output_variable(Octstr *variable, Octstr **output, var_esc_t escaped, wml_binary_t **wbxml) { switch (escaped) { case ESC: octstr_append_char(*output, WBXML_EXT_T_0); break; case UNESC: octstr_append_char(*output, WBXML_EXT_T_1); break; default: octstr_append_char(*output, WBXML_EXT_T_2); break; } octstr_append_uintvar(*output, string_table_add(variable, wbxml)); } /* * hash_create - allocates memory for a 2 field hash table node. */ static wml_hash_t *hash_create(char *text, unsigned char token) { wml_hash_t *table_node; table_node = gw_malloc(sizeof(wml_hash_t)); table_node->item = octstr_create(text); table_node->binary = token; return table_node; } /* * attribute_create - allocates memory for the attributes hash table node * that contains the attribute, the binary for it and a list of binary values * tied with the attribute. */ static wml_attribute_t *attribute_create(void) { wml_attribute_t *attr; attr = gw_malloc(sizeof(wml_attribute_t)); attr->attribute = NULL; attr->binary = 0; attr->value_list = gwlist_create(); return attr; } /* * attr_dict_construct - takes a table of attributes and their values and * inputs these into a dictionary. */ static void attr_dict_construct(wml_table3_t *attributes, Dict *attr_dict) { int i = 0; wml_attribute_t *node = NULL; wml_hash_t *temp = NULL; node = attribute_create(); do { if (node->attribute == NULL) node->attribute = octstr_create(attributes[i].text1); else if (strcmp(attributes[i].text1, attributes[i-1].text1) != 0) { dict_put(attr_dict, node->attribute, node); node = attribute_create(); node->attribute = octstr_create(attributes[i].text1); } if (attributes[i].text2 == NULL) node->binary = attributes[i].token; else { temp = hash_create(attributes[i].text2, attributes[i].token); gwlist_append(node->value_list, (void *)temp); } i++; } while (attributes[i].text1 != NULL); dict_put(attr_dict, node->attribute, node); } /* * hash_destroy - deallocates memory of a 2 field hash table node. */ static void hash_destroy(void *p) { wml_hash_t *node; if (p == NULL) return; node = p; octstr_destroy(node->item); gw_free(node); } /* * attribute_destroy - deallocates memory of a attribute hash table node. */ static void attribute_destroy(void *p) { wml_attribute_t *node; if (p == NULL) return; node = p; octstr_destroy(node->attribute); gwlist_destroy(node->value_list, hash_destroy); gw_free(node); } /* * hash_cmp - compares pattern against item and if the pattern matches the * item returns 1, else 0. */ static int hash_cmp(void *item, void *pattern) { int ret = 0; gw_assert(item != NULL && pattern != NULL); gw_assert(((wml_hash_t *)item)->item != NULL); if (octstr_search(pattern, ((wml_hash_t *)item)->item, 0) == 0) ret = 1; return ret; } /* * check_do_elements - a helper function for parse_element for checking if a * card or template element has two or more do elements of the same name. * Returns 0 for OK and -1 for an error (== do elements with same name found). */ static int check_do_elements(xmlNodePtr node) { xmlNodePtr child; int i, status = 0; Octstr *name = NULL; List *name_list = NULL; name_list = gwlist_create(); if ((child = node->children) != NULL) { while (child != NULL) { if (child->name && strcmp((char *)child->name, "do") == 0) { name = get_do_element_name(child); if (name == NULL) { error(0, "WML compiler: no name or type in a do element"); return -1; } for (i = 0; i < gwlist_len(name_list); i ++) if (octstr_compare(gwlist_get(name_list, i), name) == 0) { octstr_destroy(name); status = -1; break; } if (status != -1) gwlist_append(name_list, name); else break; } child = child->next; } } gwlist_destroy(name_list, octstr_destroy_item); return status; } /* * check_variable_name - checks the name for variable in a setvar element. * If the name has syntax error, -1 is returned, else 0. */ static var_esc_t check_variable_name(xmlNodePtr node) { Octstr *name = NULL; xmlAttrPtr attr; var_esc_t ret = FAILED; if ((attr = node->properties) != NULL) { while (attr != NULL) { if (attr->name && strcmp((char *)attr->name, "name") == 0) { name = create_octstr_from_node((char *)attr->children); break; } attr = attr->next; } } if (attr == NULL) { error(0, "WML compiler: no name in a setvar element"); return FAILED; } ret = check_variable_syntax(name, NOESC); octstr_destroy(name); return ret; } /* * get_do_element_name - returns the name for a do element. Name is either * name when the element has the attribute or defaults to the type attribute * if there is no name. */ static Octstr *get_do_element_name(xmlNodePtr node) { Octstr *name = NULL; xmlAttrPtr attr; if ((attr = node->properties) != NULL) { while (attr != NULL) { if (attr->name && strcmp((char *)attr->name, "name") == 0) { name = create_octstr_from_node((char *)attr->children); break; } attr = attr->next; } if (attr == NULL) { attr = node->properties; while (attr != NULL) { if (attr->name && strcmp((char *)attr->name, "type") == 0) { name = create_octstr_from_node((char *)attr->children); break; } attr = attr->next; } } } return name; } /* * check_if_url - checks whether the attribute value is an URL or some other * kind of value. Returns 1 for an URL and 0 otherwise. */ static int check_if_url(int hex) { switch ((unsigned char) hex) { case 0x4A: case 0x4B: case 0x4C: /* href, href http://, href https:// */ case 0x32: case 0x58: case 0x59: /* src, src http://, src https:// */ return 1; break; } return 0; } /* * check_if_emphasis - checks if the node is an emphasis element. * Returns 1 for an emphasis and 0 otherwise. */ static int check_if_emphasis(xmlNodePtr node) { if (node == NULL || node->name == NULL) return 0; if (strcmp((char *)node->name, "b") == 0) return 1; if (strcmp((char *)node->name, "big") == 0) return 1; if (strcmp((char *)node->name, "em") == 0) return 1; if (strcmp((char *)node->name, "i") == 0) return 1; if (strcmp((char *)node->name, "small") == 0) return 1; if (strcmp((char *)node->name, "strong") == 0) return 1; if (strcmp((char *)node->name, "u") == 0) return 1; return 0; } /* * wml_table_len - returns the length of a wml_table_t array. */ static int wml_table_len(wml_table_t *table) { int i = 0; while (table[i].text != NULL) i++; return i; } /* * wml_table3_len - returns the length of a wml_table3_t array. */ static int wml_table3_len(wml_table3_t *table) { int i = 0; while (table[i].text1 != NULL) i++; return i; } /* * string_table_create - reserves memory for the string_table_t and sets the * fields. */ static string_table_t *string_table_create(int offset, Octstr *ostr) { string_table_t *node; node = gw_malloc(sizeof(string_table_t)); node->offset = offset; node->string = ostr; return node; } /* * string_table_destroy - frees the memory allocated for the string_table_t. */ static void string_table_destroy(string_table_t *node) { if (node != NULL) { octstr_destroy(node->string); gw_free(node); } } /* * string_table_proposal_create - reserves memory for the * string_table_proposal_t and sets the fields. */ static string_table_proposal_t *string_table_proposal_create(Octstr *ostr) { string_table_proposal_t *node; node = gw_malloc(sizeof(string_table_proposal_t)); node->count = 1; node->string = ostr; return node; } /* * string_table_proposal_destroy - frees the memory allocated for the * string_table_proposal_t. */ static void string_table_proposal_destroy(string_table_proposal_t *node) { if (node != NULL) { octstr_destroy(node->string); gw_free(node); } } /* * string_table_build - collects the strings from the WML source into a list, * adds those strings that appear more than once into string table. The rest * of the strings are sliced into words and the same procedure is executed to * the list of these words. */ static void string_table_build(xmlNodePtr node, wml_binary_t **wbxml) { string_table_proposal_t *item = NULL; List *list = NULL; list = gwlist_create(); string_table_collect_strings(node, list); list = string_table_add_many(string_table_sort_list(list), wbxml); list = string_table_collect_words(list); /* Don't add strings if there aren't any. (no NULLs please) */ if (list) { list = string_table_add_many(string_table_sort_list(list), wbxml); } /* Memory cleanup. */ while (gwlist_len(list)) { item = gwlist_extract_first(list); string_table_proposal_destroy(item); } gwlist_destroy(list, NULL); } /* * string_table_collect_strings - collects the strings from the WML * ocument into a list that is then further processed to build the * string table for the document. */ static void string_table_collect_strings(xmlNodePtr node, List *strings) { Octstr *string; xmlAttrPtr attribute; switch (node->type) { case XML_TEXT_NODE: string = create_octstr_from_node((char *)node); octstr_shrink_blanks(string); octstr_strip_blanks(string); if (octstr_len(string) > WBXML_STRING_TABLE_MIN) octstr_strip_nonalphanums(string); if (octstr_len(string) > WBXML_STRING_TABLE_MIN) gwlist_append(strings, string); else octstr_destroy(string); break; case XML_ELEMENT_NODE: if(node->properties != NULL) { attribute = node->properties; while (attribute != NULL) { if (attribute->children != NULL) string_table_collect_strings(attribute->children, strings); attribute = attribute->next; } } break; default: break; } if (node->children != NULL) string_table_collect_strings(node->children, strings); if (node->next != NULL) string_table_collect_strings(node->next, strings); } /* * string_table_sort_list - takes a list of octet strings and returns a list * of string_table_proposal_t:s that contains the same strings with number of * instants of every string in the input list. */ static List *string_table_sort_list(List *start) { int i; Octstr *string = NULL; string_table_proposal_t *item = NULL; List *sorted = NULL; sorted = gwlist_create(); while (gwlist_len(start)) { string = gwlist_extract_first(start); /* Check whether the string is unique. */ for (i = 0; i < gwlist_len(sorted); i++) { item = gwlist_get(sorted, i); if (octstr_compare(item->string, string) == 0) { octstr_destroy(string); string = NULL; item->count ++; break; } } if (string != NULL) { item = string_table_proposal_create(string); gwlist_append(sorted, item); } } gwlist_destroy(start, NULL); return sorted; } /* * string_table_add_many - takes a list of string with number of instants and * adds those whose number is greater than 1 into the string table. Returns * the list ofrejected strings for memory cleanup. */ static List *string_table_add_many(List *sorted, wml_binary_t **wbxml) { string_table_proposal_t *item = NULL; List *list = NULL; list = gwlist_create(); while (gwlist_len(sorted)) { item = gwlist_extract_first(sorted); if (item->count > 1 && octstr_len(item->string) > WBXML_STRING_TABLE_MIN) { string_table_add(octstr_duplicate(item->string), wbxml); string_table_proposal_destroy(item); } else gwlist_append(list, item); } gwlist_destroy(sorted, NULL); return list; } /* * string_table_collect_words - takes a list of strings and returns a list * of words contained by those strings. */ static List *string_table_collect_words(List *strings) { Octstr *word = NULL; string_table_proposal_t *item = NULL; List *list = NULL, *temp_list = NULL; while (gwlist_len(strings)) { item = gwlist_extract_first(strings); if (list == NULL) { list = octstr_split_words(item->string); string_table_proposal_destroy(item); } else { temp_list = octstr_split_words(item->string); while ((word = gwlist_extract_first(temp_list)) != NULL) gwlist_append(list, word); gwlist_destroy(temp_list, NULL); string_table_proposal_destroy(item); } } gwlist_destroy(strings, NULL); return list; } /* * string_table_add - adds a string to the string table. Duplicates are * discarded. The function returns the offset of the string in the * string table; if the string is already in the table then the offset * of the first copy. */ static unsigned long string_table_add(Octstr *ostr, wml_binary_t **wbxml) { string_table_t *item = NULL; unsigned long i, offset = 0; /* Check whether the string is unique. */ for (i = 0; i < (unsigned long)gwlist_len((*wbxml)->string_table); i++) { item = gwlist_get((*wbxml)->string_table, i); if (octstr_compare(item->string, ostr) == 0) { octstr_destroy(ostr); return item->offset; } } /* Create a new list item for the string table. */ offset = (*wbxml)->string_table_length; item = string_table_create(offset, ostr); (*wbxml)->string_table_length = (*wbxml)->string_table_length + octstr_len(ostr) + 1; gwlist_append((*wbxml)->string_table, item); return offset; } /* * string_table_apply - takes a octet string of WML bnary and goes it * through searching for substrings that are in the string table and * replaces them with string table references. */ static void string_table_apply(Octstr *ostr, wml_binary_t **wbxml) { Octstr *input = NULL; string_table_t *item = NULL; long i = 0, word_s = 0, str_e = 0; input = octstr_create(""); for (i = 0; i < gwlist_len((*wbxml)->string_table); i++) { item = gwlist_get((*wbxml)->string_table, i); if (octstr_len(item->string) > WBXML_STRING_TABLE_MIN) /* No use to replace 1 to 3 character substring, the reference will eat the saving up. A variable will be in the string table even though it's only 1 character long. */ if ((word_s = octstr_search(ostr, item->string, 0)) >= 0) { /* Check whether the octet string are equal if they are equal in length. */ if (octstr_len(ostr) == octstr_len(item->string)) { if ((word_s = octstr_compare(ostr, item->string)) == 0) { octstr_truncate(ostr, 0); octstr_append_char(ostr, WBXML_STR_T); octstr_append_uintvar(ostr, item->offset); str_e = 1; } } /* Check the possible substrings. */ else if (octstr_len(ostr) > octstr_len(item->string)) { if (word_s + octstr_len(item->string) == octstr_len(ostr)) str_e = 1; octstr_delete(ostr, word_s, octstr_len(item->string)); octstr_truncate(input, 0); /* Substring in the start? No STR_END then. */ if (word_s > 0) octstr_append_char(input, WBXML_STR_END); octstr_append_char(input, WBXML_STR_T); octstr_append_uintvar(input, item->offset); /* Subtring the end? No need to start a new one. */ if ( word_s < octstr_len(ostr)) octstr_append_char(input, WBXML_STR_I); octstr_insert(ostr, input, word_s); } /* If te string table entry is longer than the string, it can be skipped. */ } } octstr_destroy(input); if (octstr_get_char(ostr, 0) != WBXML_STR_T) output_st_char(WBXML_STR_I, wbxml); if (!str_e) octstr_append_char(ostr, WBXML_STR_END); output_st_octet_string(ostr, wbxml); } /* * string_table_output - writes the contents of the string table * into an octet string that is sent to the phone. */ static void string_table_output(Octstr *ostr, wml_binary_t **wbxml) { string_table_t *item; while ((item = gwlist_extract_first((*wbxml)->string_table)) != NULL) { octstr_insert(ostr, item->string, octstr_len(ostr)); octstr_append_char(ostr, WBXML_STR_END); string_table_destroy(item); } } gateway-1.4.5/gw/ota_compiler.h0000644000175000017500000000626313227613126015141 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * ota_compiler.h: The interface to ota settings and bookmarks tokenizer * * By Aarno Syvänen for Wiral Ltd */ #ifndef OTA_COMPILER_H #define OTA_COMPILER_H #include "gwlib/gwlib.h" /* * Compiles an ota document to ota binary. Input textual form of a ota document * and its charset (from http headers), output the document in a tokenised * form. * Returns -1 when error, 0 otherwise. */ int ota_compile(Octstr *ota_doc, Octstr *charset, Octstr **ota_binary); #endif gateway-1.4.5/gw/smscconn.c0000644000175000017500000006460713227613126014310 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * SMSC Connection * * Interface for main bearerbox to SMS center connection modules * * Kalle Marjola 2000 for project Kannel */ #include #include #include "gwlib/gwlib.h" #include "gwlib/regex.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "sms.h" extern Counter *split_msg_counter; /* * Some defaults */ #define SMSCCONN_RECONNECT_DELAY 10.0 /* * Add reroute information to the connection data. Where the priority * is in the order: reroute, reroute-smsc-id, reroute-receiver. */ static void init_reroute(SMSCConn *conn, CfgGroup *grp) { Octstr *rule; long i; if (cfg_get_bool(&conn->reroute_dlr, grp, octstr_imm("reroute-dlr")) == -1) conn->reroute_dlr = 0; info(0, "DLR rerouting for smsc id <%s> %s.", octstr_get_cstr(conn->id), (conn->reroute_dlr?"enabled":"disabled")); if (cfg_get_bool(&conn->reroute, grp, octstr_imm("reroute")) != -1) { debug("smscconn",0,"Adding general internal routing for smsc id <%s>", octstr_get_cstr(conn->id)); return; } if ((conn->reroute_to_smsc = cfg_get(grp, octstr_imm("reroute-smsc-id"))) != NULL) { /* reroute all messages to a specific smsc-id */ debug("smscconn",0,"Adding internal routing: smsc id <%s> to smsc id <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(conn->reroute_to_smsc)); return; } if ((rule = cfg_get(grp, octstr_imm("reroute-receiver"))) != NULL) { List *routes; /* create hash dictionary for this smsc-id */ conn->reroute_by_receiver = dict_create(100, (void(*)(void *)) octstr_destroy); routes = octstr_split(rule, octstr_imm(";")); for (i = 0; i < gwlist_len(routes); i++) { Octstr *item = gwlist_get(routes, i); Octstr *smsc, *receiver; List *receivers; /* first word is the smsc-id, all other are the receivers */ receivers = octstr_split(item, octstr_imm(",")); smsc = gwlist_extract_first(receivers); if (smsc) octstr_strip_blanks(smsc); while((receiver = gwlist_extract_first(receivers))) { octstr_strip_blanks(receiver); debug("smscconn",0,"Adding internal routing for smsc id <%s>: " "receiver <%s> to smsc id <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(receiver), octstr_get_cstr(smsc)); if (!dict_put_once(conn->reroute_by_receiver, receiver, octstr_duplicate(smsc))) panic(0, "Could not set internal routing for smsc id <%s>: " "receiver <%s> to smsc id <%s>, because receiver has already routing entry!", octstr_get_cstr(conn->id), octstr_get_cstr(receiver), octstr_get_cstr(smsc)); octstr_destroy(receiver); } octstr_destroy(smsc); gwlist_destroy(receivers, octstr_destroy_item); } octstr_destroy(rule); gwlist_destroy(routes, octstr_destroy_item); } } unsigned int smscconn_instances(CfgGroup *grp) { long i; if (cfg_get_integer(&i, grp, octstr_imm("instances")) == -1) i = 1; else if (i < 0) i = 0; return i; } SMSCConn *smscconn_create(CfgGroup *grp, int start_as_stopped) { SMSCConn *conn; Octstr *smsc_type; int ret; Octstr *allowed_smsc_id_regex; Octstr *denied_smsc_id_regex; Octstr *allowed_prefix_regex; Octstr *denied_prefix_regex; Octstr *preferred_prefix_regex; Octstr *tmp; if (grp == NULL) return NULL; conn = gw_malloc(sizeof(*conn)); memset(conn, 0, sizeof(*conn)); conn->why_killed = SMSCCONN_ALIVE; conn->status = SMSCCONN_CONNECTING; conn->connect_time = -1; conn->is_stopped = start_as_stopped; #define OCTSTR(os) octstr_imm(#os) /* checksum of the whole config, without instance multiplier */ conn->chksum = cfg_get_group_checksum(grp, NULL ); /* checksum of the connection related part, without routing * and without instance multiplier */ conn->chksum_conn = cfg_get_group_checksum(grp, OCTSTR(denied-smsc-id), OCTSTR(allowed-smsc-id), OCTSTR(preferred-smsc-id), OCTSTR(allowed-prefix), OCTSTR(denied-prefix), OCTSTR(preferred-prefix), OCTSTR(unified-prefix), OCTSTR(reroute), OCTSTR(reroute-smsc-id), OCTSTR(reroute-receiver), OCTSTR(reroute-dlr), OCTSTR(allowed-smsc-id-regex), OCTSTR(denied-smsc-id-regex), OCTSTR(preferred-smsc-id-regex), OCTSTR(allowed-prefix-regex), OCTSTR(denied-prefix-regex), OCTSTR(preferred-prefix-regex), NULL ); conn->received = counter_create(); conn->received_dlr = counter_create(); conn->sent = counter_create(); conn->sent_dlr = counter_create(); conn->failed = counter_create(); conn->flow_mutex = mutex_create(); conn->outgoing_sms_load = load_create(); /* add 60,300,-1 entries */ load_add_interval(conn->outgoing_sms_load, 60); load_add_interval(conn->outgoing_sms_load, 300); load_add_interval(conn->outgoing_sms_load, -1); conn->incoming_sms_load = load_create(); /* add 60,300,-1 entries */ load_add_interval(conn->incoming_sms_load, 60); load_add_interval(conn->incoming_sms_load, 300); load_add_interval(conn->incoming_sms_load, -1); conn->incoming_dlr_load = load_create(); /* add 60,300,-1 entries to dlr */ load_add_interval(conn->incoming_dlr_load, 60); load_add_interval(conn->incoming_dlr_load, 300); load_add_interval(conn->incoming_dlr_load, -1); conn->outgoing_dlr_load = load_create(); /* add 60,300,-1 entries to dlr */ load_add_interval(conn->outgoing_dlr_load, 60); load_add_interval(conn->outgoing_dlr_load, 300); load_add_interval(conn->outgoing_dlr_load, -1); #define GET_OPTIONAL_VAL(x, n) x = cfg_get(grp, octstr_imm(n)) #define SPLIT_OPTIONAL_VAL(x, n) \ do { \ Octstr *tmp = cfg_get(grp, octstr_imm(n)); \ if (tmp) x = octstr_split(tmp, octstr_imm(";")); \ else x = NULL; \ octstr_destroy(tmp); \ }while(0) GET_OPTIONAL_VAL(conn->id, "smsc-id"); SPLIT_OPTIONAL_VAL(conn->allowed_smsc_id, "allowed-smsc-id"); SPLIT_OPTIONAL_VAL(conn->denied_smsc_id, "denied-smsc-id"); SPLIT_OPTIONAL_VAL(conn->preferred_smsc_id, "preferred-smsc-id"); GET_OPTIONAL_VAL(conn->allowed_prefix, "allowed-prefix"); GET_OPTIONAL_VAL(conn->denied_prefix, "denied-prefix"); GET_OPTIONAL_VAL(conn->preferred_prefix, "preferred-prefix"); GET_OPTIONAL_VAL(conn->unified_prefix, "unified-prefix"); GET_OPTIONAL_VAL(conn->our_host, "our-host"); GET_OPTIONAL_VAL(conn->log_file, "log-file"); cfg_get_bool(&conn->alt_dcs, grp, octstr_imm("alt-dcs")); GET_OPTIONAL_VAL(allowed_smsc_id_regex, "allowed-smsc-id-regex"); if (allowed_smsc_id_regex != NULL) if ((conn->allowed_smsc_id_regex = gw_regex_comp(allowed_smsc_id_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(allowed_smsc_id_regex)); GET_OPTIONAL_VAL(denied_smsc_id_regex, "denied-smsc-id-regex"); if (denied_smsc_id_regex != NULL) if ((conn->denied_smsc_id_regex = gw_regex_comp(denied_smsc_id_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(denied_smsc_id_regex)); GET_OPTIONAL_VAL(allowed_prefix_regex, "allowed-prefix-regex"); if (allowed_prefix_regex != NULL) if ((conn->allowed_prefix_regex = gw_regex_comp(allowed_prefix_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(allowed_prefix_regex)); GET_OPTIONAL_VAL(denied_prefix_regex, "denied-prefix-regex"); if (denied_prefix_regex != NULL) if ((conn->denied_prefix_regex = gw_regex_comp(denied_prefix_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(denied_prefix_regex)); GET_OPTIONAL_VAL(preferred_prefix_regex, "preferred-prefix-regex"); if (preferred_prefix_regex != NULL) if ((conn->preferred_prefix_regex = gw_regex_comp(preferred_prefix_regex, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(preferred_prefix_regex)); if ((tmp = cfg_get(grp, octstr_imm("throughput"))) != NULL) { if (octstr_parse_double(&conn->throughput, tmp, 0) == -1) conn->throughput = 0; octstr_destroy(tmp); info(0, "Set throughput to %.3f for smsc id <%s>", conn->throughput, octstr_get_cstr(conn->id)); } /* Sets the admin_id. Equals to connection id if empty */ GET_OPTIONAL_VAL(conn->admin_id, "smsc-admin-id"); if (conn->admin_id == NULL) conn->admin_id = octstr_duplicate(conn->id); /* configure the internal rerouting rules for this smsc id */ init_reroute(conn, grp); if (cfg_get_integer(&conn->log_level, grp, octstr_imm("log-level")) == -1) conn->log_level = 0; if (cfg_get_integer(&conn->max_sms_octets, grp, octstr_imm("max-sms-octets")) == -1) conn->max_sms_octets = MAX_SMS_OCTETS; if (cfg_get_bool(&conn->dead_start, grp, octstr_imm("dead-start")) == -1) conn->dead_start = 0; /* default to connect at start-up time */ /* open a smsc-id specific log-file in exlusive mode */ if (conn->log_file) conn->log_idx = log_open(octstr_get_cstr(conn->log_file), conn->log_level, GW_EXCL); #undef GET_OPTIONAL_VAL #undef SPLIT_OPTIONAL_VAL if (conn->allowed_smsc_id && conn->denied_smsc_id) warning(0, "Both 'allowed-smsc-id' and 'denied-smsc-id' set, deny-list " "automatically ignored"); if (conn->allowed_smsc_id_regex && conn->denied_smsc_id_regex) warning(0, "Both 'allowed-smsc-id_regex' and 'denied-smsc-id_regex' set, deny-regex " "automatically ignored"); if (cfg_get_integer(&conn->reconnect_delay, grp, octstr_imm("reconnect-delay")) == -1) conn->reconnect_delay = SMSCCONN_RECONNECT_DELAY; smsc_type = cfg_get(grp, octstr_imm("smsc")); if (smsc_type == NULL) { error(0, "Required field 'smsc' missing for smsc group."); smscconn_destroy(conn); octstr_destroy(smsc_type); return NULL; } if (octstr_compare(smsc_type, octstr_imm("fake")) == 0) ret = smsc_fake_create(conn, grp); else if (octstr_compare(smsc_type, octstr_imm("cimd2")) == 0) ret = smsc_cimd2_create(conn, grp); else if (octstr_compare(smsc_type, octstr_imm("emi")) == 0) ret = smsc_emi2_create(conn, grp); else if (octstr_compare(smsc_type, octstr_imm("http")) == 0) ret = smsc_http_create(conn, grp); else if (octstr_compare(smsc_type, octstr_imm("smpp")) == 0) ret = smsc_smpp_create(conn, grp); else if (octstr_compare(smsc_type, octstr_imm("at")) == 0) ret = smsc_at2_create(conn,grp); else if (octstr_compare(smsc_type, octstr_imm("cgw")) == 0) ret = smsc_cgw_create(conn,grp); else if (octstr_compare(smsc_type, octstr_imm("smasi")) == 0) ret = smsc_smasi_create(conn, grp); else if (octstr_compare(smsc_type, octstr_imm("oisd")) == 0) ret = smsc_oisd_create(conn, grp); else if (octstr_compare(smsc_type, octstr_imm("loopback")) == 0) ret = smsc_loopback_create(conn, grp); #ifdef HAVE_GSOAP else if (octstr_compare(smsc_type, octstr_imm("parlayx")) == 0) ret = smsc_soap_parlayx_create(conn, grp); #endif else ret = smsc_wrapper_create(conn, grp); octstr_destroy(smsc_type); if (ret == -1) { smscconn_destroy(conn); return NULL; } gw_assert(conn->send_msg != NULL); bb_smscconn_ready(conn); return conn; } void smscconn_shutdown(SMSCConn *conn, int finish_sending) { gw_assert(conn != NULL); mutex_lock(conn->flow_mutex); if (conn->status == SMSCCONN_DEAD) { mutex_unlock(conn->flow_mutex); return; } /* Call SMSC specific destroyer */ if (conn->shutdown) { /* * we must unlock here, because module manipulate their state * and will try to lock this mutex.Otherwise we have deadlock! */ mutex_unlock(conn->flow_mutex); conn->shutdown(conn, finish_sending); } else { conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; mutex_unlock(conn->flow_mutex); } return; } int smscconn_destroy(SMSCConn *conn) { if (conn == NULL) return 0; if (conn->status != SMSCCONN_DEAD) return -1; mutex_lock(conn->flow_mutex); counter_destroy(conn->received); counter_destroy(conn->received_dlr); counter_destroy(conn->sent); counter_destroy(conn->sent_dlr); counter_destroy(conn->failed); load_destroy(conn->incoming_sms_load); load_destroy(conn->incoming_dlr_load); load_destroy(conn->outgoing_sms_load); load_destroy(conn->outgoing_dlr_load); octstr_destroy(conn->name); octstr_destroy(conn->id); octstr_destroy(conn->admin_id); gwlist_destroy(conn->allowed_smsc_id, octstr_destroy_item); gwlist_destroy(conn->denied_smsc_id, octstr_destroy_item); gwlist_destroy(conn->preferred_smsc_id, octstr_destroy_item); octstr_destroy(conn->denied_prefix); octstr_destroy(conn->allowed_prefix); octstr_destroy(conn->preferred_prefix); octstr_destroy(conn->unified_prefix); octstr_destroy(conn->our_host); octstr_destroy(conn->log_file); octstr_destroy(conn->chksum); octstr_destroy(conn->chksum_conn); if (conn->denied_smsc_id_regex != NULL) gw_regex_destroy(conn->denied_smsc_id_regex); if (conn->allowed_smsc_id_regex != NULL) gw_regex_destroy(conn->allowed_smsc_id_regex); if (conn->preferred_prefix_regex != NULL) gw_regex_destroy(conn->preferred_prefix_regex); if (conn->denied_prefix_regex != NULL) gw_regex_destroy(conn->denied_prefix_regex); if (conn->allowed_prefix_regex != NULL) gw_regex_destroy(conn->allowed_prefix_regex); octstr_destroy(conn->reroute_to_smsc); dict_destroy(conn->reroute_by_receiver); mutex_unlock(conn->flow_mutex); mutex_destroy(conn->flow_mutex); gw_free(conn); return 0; } int smscconn_stop(SMSCConn *conn) { gw_assert(conn != NULL); mutex_lock(conn->flow_mutex); if (conn->status == SMSCCONN_DEAD || conn->is_stopped != 0 || conn->why_killed != SMSCCONN_ALIVE) { mutex_unlock(conn->flow_mutex); return -1; } conn->is_stopped = 1; mutex_unlock(conn->flow_mutex); if (conn->stop_conn) conn->stop_conn(conn); return 0; } void smscconn_start(SMSCConn *conn) { gw_assert(conn != NULL); mutex_lock(conn->flow_mutex); if (conn->status == SMSCCONN_DEAD || conn->is_stopped == 0) { mutex_unlock(conn->flow_mutex); return; } conn->is_stopped = 0; mutex_unlock(conn->flow_mutex); if (conn->start_conn) conn->start_conn(conn); } const Octstr *smscconn_name(SMSCConn *conn) { gw_assert(conn != NULL); return conn->name; } const Octstr *smscconn_id(SMSCConn *conn) { gw_assert(conn != NULL); return conn->id; } const Octstr *smscconn_admin_id(SMSCConn *conn) { gw_assert(conn != NULL); return conn->admin_id; } int smscconn_usable(SMSCConn *conn, Msg *msg) { gw_assert(conn != NULL); gw_assert(msg != NULL && msg_type(msg) == sms); /* dead transmitter or active receiver connections are not feasible */ if (conn->status == SMSCCONN_DEAD || conn->status == SMSCCONN_ACTIVE_RECV || conn->why_killed != SMSCCONN_ALIVE) return -1; /* if allowed-smsc-id set, then only allow this SMSC if message * smsc-id matches any of its allowed SMSCes */ if (conn->allowed_smsc_id && (msg->sms.smsc_id == NULL || gwlist_search(conn->allowed_smsc_id, msg->sms.smsc_id, octstr_item_match) == NULL)) { return -1; } /* ..if no allowed-smsc-id set but denied-smsc-id and message smsc-id * is set, deny message if smsc-ids match */ else if (conn->denied_smsc_id && msg->sms.smsc_id != NULL && gwlist_search(conn->denied_smsc_id, msg->sms.smsc_id, octstr_item_match) != NULL) { return -1; } if (conn->allowed_smsc_id_regex) { if (msg->sms.smsc_id == NULL) return -1; if (gw_regex_match_pre(conn->allowed_smsc_id_regex, msg->sms.smsc_id) == 0) return -1; } else if (conn->denied_smsc_id_regex && msg->sms.smsc_id != NULL) { if (gw_regex_match_pre(conn->denied_smsc_id_regex, msg->sms.smsc_id) == 1) return -1; } /* Have allowed */ if (conn->allowed_prefix && !conn->denied_prefix && (does_prefix_match(conn->allowed_prefix, msg->sms.receiver) != 1)) return -1; if (conn->allowed_prefix_regex && !conn->denied_prefix_regex && gw_regex_match_pre(conn->allowed_prefix_regex, msg->sms.receiver) == 0) return -1; /* Have denied */ if (conn->denied_prefix && !conn->allowed_prefix && (does_prefix_match(conn->denied_prefix, msg->sms.receiver) == 1)) return -1; if (conn->denied_prefix_regex && !conn->allowed_prefix_regex && gw_regex_match_pre(conn->denied_prefix_regex, msg->sms.receiver) == 1) return -1; /* Have allowed and denied */ if (conn->denied_prefix && conn->allowed_prefix && (does_prefix_match(conn->allowed_prefix, msg->sms.receiver) != 1) && (does_prefix_match(conn->denied_prefix, msg->sms.receiver) == 1)) return -1; if (conn->allowed_prefix_regex && conn->denied_prefix_regex && gw_regex_match_pre(conn->allowed_prefix_regex, msg->sms.receiver) == 0 && gw_regex_match_pre(conn->denied_prefix_regex, msg->sms.receiver) == 1) return -1; /* then see if it is preferred one */ if (conn->preferred_smsc_id && msg->sms.smsc_id != NULL && gwlist_search(conn->preferred_smsc_id, msg->sms.smsc_id, octstr_item_match) != NULL) return 1; if (conn->preferred_prefix && does_prefix_match(conn->preferred_prefix, msg->sms.receiver) == 1) return 1; if (conn->preferred_prefix_regex && gw_regex_match_pre(conn->preferred_prefix_regex, msg->sms.receiver) == 1) return 1; return 0; } int smscconn_send(SMSCConn *conn, Msg *msg) { int ret = -1; List *parts = NULL; gw_assert(conn != NULL); mutex_lock(conn->flow_mutex); if (conn->status == SMSCCONN_DEAD || conn->why_killed != SMSCCONN_ALIVE) { mutex_unlock(conn->flow_mutex); return -1; } /* if this a retry of splitted message, don't unify prefix and don't try to split */ if (msg->sms.split_parts == NULL) { /* normalize the destination number for this smsc */ char *uf = conn->unified_prefix ? octstr_get_cstr(conn->unified_prefix) : NULL; normalize_number(uf, &(msg->sms.receiver)); /* split msg */ parts = sms_split(msg, NULL, NULL, NULL, NULL, 1, counter_increase(split_msg_counter) & 0xff, 0xff, conn->max_sms_octets); if (gwlist_len(parts) == 1) { /* don't create split_parts of sms fit into one */ gwlist_destroy(parts, msg_destroy_item); parts = NULL; } } if (parts == NULL) ret = conn->send_msg(conn, msg); else { long i, parts_len = gwlist_len(parts); struct split_parts *split = gw_malloc(sizeof(*split)); /* must duplicate, because smsc2_route will destroy this msg */ split->orig = msg_duplicate(msg); split->parts_left = counter_create(); split->status = SMSCCONN_SUCCESS; counter_set(split->parts_left, parts_len); split->smsc_conn = conn; debug("bb.sms.splits", 0, "new split_parts created %p", split); for (i = 0; i < parts_len; i++) { msg = gwlist_get(parts, i); msg->sms.split_parts = split; ret = conn->send_msg(conn, msg); if (ret < 0) { if (i == 0) { counter_destroy(split->parts_left); gwlist_destroy(parts, msg_destroy_item); gw_free(split); mutex_unlock(conn->flow_mutex); return ret; } /* * Some parts were sent. So handle this within * bb_smscconn_XXX(). */ split->status = SMSCCONN_FAILED_REJECTED; counter_increase_with(split->parts_left, -(parts_len - i)); warning(0, "Could not send all parts of a split message"); break; } } gwlist_destroy(parts, msg_destroy_item); } mutex_unlock(conn->flow_mutex); return ret; } int smscconn_status(SMSCConn *conn) { gw_assert(conn != NULL); return conn->status; } int smscconn_info(SMSCConn *conn, StatusInfo *infotable) { if (conn == NULL || infotable == NULL) return -1; mutex_lock(conn->flow_mutex); infotable->status = conn->status; infotable->killed = conn->why_killed; infotable->is_stopped = conn->is_stopped; infotable->online = time(NULL) - conn->connect_time; infotable->sent = counter_value(conn->sent); infotable->received = counter_value(conn->received); infotable->sent_dlr = counter_value(conn->sent_dlr); infotable->received_dlr = counter_value(conn->received_dlr); infotable->failed = counter_value(conn->failed); if (conn->queued) infotable->queued = conn->queued(conn); else infotable->queued = -1; infotable->load = conn->load; mutex_unlock(conn->flow_mutex); return 0; } void smscconn_reconfig(SMSCConn *conn, CfgGroup *grp) { Octstr *tmp; gw_assert(conn != NULL); if (grp == NULL) return; #define GET_OPTIONAL_VAL(x, n) \ octstr_destroy(x); \ x = cfg_get(grp, octstr_imm(n)) #define SPLIT_OPTIONAL_VAL(x, n) \ gwlist_destroy(x, octstr_destroy_item); \ if ((tmp = cfg_get(grp, octstr_imm(n))) != NULL) \ x = octstr_split(tmp, octstr_imm(";")); \ else \ x = NULL; \ octstr_destroy(tmp); #define GET_OPTIONAL_REGEX(x, n) \ gw_regex_destroy(x); \ if ((tmp = cfg_get(grp, octstr_imm(n))) != NULL) { \ if ((x = gw_regex_comp(tmp, REG_EXTENDED)) == NULL) \ error(0, "Could not compile pattern '%s'", octstr_get_cstr(tmp)); \ octstr_destroy(tmp); \ } SPLIT_OPTIONAL_VAL(conn->allowed_smsc_id, "allowed-smsc-id"); SPLIT_OPTIONAL_VAL(conn->denied_smsc_id, "denied-smsc-id"); SPLIT_OPTIONAL_VAL(conn->preferred_smsc_id, "preferred-smsc-id"); GET_OPTIONAL_VAL(conn->allowed_prefix, "allowed-prefix"); GET_OPTIONAL_VAL(conn->denied_prefix, "denied-prefix"); GET_OPTIONAL_VAL(conn->preferred_prefix, "preferred-prefix"); GET_OPTIONAL_VAL(conn->unified_prefix, "unified-prefix"); GET_OPTIONAL_REGEX(conn->allowed_smsc_id_regex, "allowed-smsc-id-regex"); GET_OPTIONAL_REGEX(conn->denied_smsc_id_regex, "denied-smsc-id-regex"); GET_OPTIONAL_REGEX(conn->preferred_smsc_id_regex, "preferred-smsc-id-regex"); GET_OPTIONAL_REGEX(conn->allowed_prefix_regex, "allowed-prefix-regex"); GET_OPTIONAL_REGEX(conn->denied_prefix_regex, "denied-prefix-regex"); GET_OPTIONAL_REGEX(conn->preferred_prefix_regex, "preferred-prefix-regex"); octstr_destroy(conn->reroute_to_smsc); dict_destroy(conn->reroute_by_receiver); init_reroute(conn, grp); /* * Since we applied changes, we need to re-compute * at least the overall checksum. The other one * is not changed as the routing values are excluded. * also the checksum hash values. */ octstr_destroy(conn->chksum); conn->chksum = cfg_get_group_checksum(grp, NULL); } gateway-1.4.5/gw/smskannel-ssl.conf0000644000175000017500000000335407623311401015744 0ustar toljtolj# # THIS IS A SAMPLE CONFIGURATION FOR SMS KANNEL # (using SSL enabled HTTP servers) # # It is run like this: # # 1% gw/bearerbox gw/smskannel.conf # 2% gw/smsbox gw/smskannel.conf # 3% test/fakesmsc -p 10000 -H localhost -i 1 -m 100 "123 345 text nop" # # ..all 3 commands in separate shells (or screen sessions) # # For any modifications to this file, see Kannel User Guide # If that does not help, send email to users@kannel.org # # Kalle Marjola May 2000 # Changed for new fakesmsc version by Uoti Urpala Jan 2001 # Added service and sendsms for HTTP SMSC by Kalle Marjola Mar 2001 # Adopted for SSL enabled traffic by Stipe Tolj 2002 # group = core admin-port = 13000 admin-port-ssl = yes smsbox-port = 13001 admin-password = bar #status-password = foo #admin-deny-ip = "" #admin-allow-ip = "" #log-file = "/tmp/kannel.log" #log-level = 0 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" #unified-prefix = "+358,00358,0;+,00" #access-log = "/tmp/access.log" #store-file = "/tmp/kannel.store" #ssl-server-cert-file = "cert.pem" #ssl-server-key-file = "key.pem" #ssl-certkey-file = "mycertandprivkeyfile.pem" # SMSC CONNECTIONS group = smsc smsc = fake smsc-id = FAKE port = 10000 connect-allow-ip = 127.0.0.1 # SMSBOX SETUP group = smsbox bearerbox-host = localhost sendsms-port = 13013 sendsms-port-ssl = yes global-sender = 13013 #sendsms-chars = "0123456789 +-" #log-file = "/tmp/smsbox.log" #log-level = 0 #access-log = "/tmp/access.log" # SEND-SMS USERS group = sendsms-user username = tester password = foobar #user-deny-ip = "" #user-allow-ip = "" # SERVICES group = sms-service keyword = nop text = "You asked nothing and I did it!" # there should be default always group = sms-service keyword = default text = "No service specified" gateway-1.4.5/gw/control.html0000644000175000017500000001076207345707421014666 0ustar toljtolj Gateway control form

Gateway control form

Note: This form is a simple example of how to control a Kannel gateway

Hostname
Port
Password
Action
Status Format
Go

Note: This form is a simple example of how to send SMS

Hostname
Port
Method
User:
Pass:
From:
To:
Text:
Charset:
UDH:
Class (Message Class):
Coding (Data Coding):
MWI (Message Waiting Indicator):
Validity (mins):
Deferred (mins):
Go!
gateway-1.4.5/gw/html.c0000644000175000017500000002205513227613126013420 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * html.c - routines for manipulating HTML. * * Lars Wirzenius */ #include #include #include #include "html.h" #include "gwlib/gwlib.h" #define SMS_MAX 161 /* Is there a comment beginning at offset `pos'? */ static int html_comment_begins(Octstr *html, long pos) { char buf[10]; octstr_get_many_chars(buf, html, pos, 4); buf[5] = '\0'; return strcmp(buf, ""), *pos); if (i == -1) *pos = octstr_len(html); else *pos = i; } /* Skip a beginning or ending tag in HTML, including any attributes. */ static void skip_html_tag(Octstr *html, long *pos) { long i, len; int c; /* Skip leading '<'. */ ++(*pos); /* Skip name of tag and attributes with values. */ len = octstr_len(html); while (*pos < len && (c = octstr_get_char(html, *pos)) != '>') { if (c == '"' || c == '\'') { i = octstr_search_char(html, c, *pos + 1); if (i == -1) *pos = len; else *pos = i + 1; } else ++(*pos); } /* Skip trailing '>' if it is there. */ if (octstr_get_char(html, *pos) == '>') ++(*pos); } /* Convert an HTML entity into a single character and advance `*html' past the entity. */ static void convert_html_entity(Octstr *sms, Octstr *html, long *pos) { static struct { char *entity; int latin1; } tab[] = { { "&", '&' }, { "<", '<' }, { ">", '>' }, /* The following is copied from http://www.hut.fi/~jkorpela/HTML3.2/latin1.html by Jukka Korpela. Hand and script edited to form this table. */ { " ", ' ' }, { "¡", 161 }, { "¢", 162 }, { "£", 163 }, { "¤", 164 }, { "¥", 165 }, { "¦", 166 }, { "§", 167 }, { "¨", 168 }, { "©", 169 }, { "ª", 170 }, { "«", 171 }, { "¬", 172 }, { "­", 173 }, { "®", 174 }, { "¯", 175 }, { "°", 176 }, { "±", 177 }, { "²", 178 }, { "³", 179 }, { "´", 180 }, { "µ", 181 }, { "¶", 182 }, { "·", 183 }, { "¸", 184 }, { "¹", 185 }, { "º", 186 }, { "»", 187 }, { "¼", 188 }, { "½", 189 }, { "¾", 190 }, { "¿", 191 }, { "À", 192 }, { "Á", 193 }, { "Â", 194 }, { "Ã", 195 }, { "Ä", 196 }, { "Å", 197 }, { "Æ", 198 }, { "Ç", 199 }, { "È", 200 }, { "É", 201 }, { "Ê", 202 }, { "Ë", 203 }, { "Ì", 204 }, { "Í", 205 }, { "Î", 206 }, { "Ï", 207 }, { "Ð", 208 }, { "Ñ", 209 }, { "Ò", 210 }, { "Ó", 211 }, { "Ô", 212 }, { "Õ", 213 }, { "Ö", 214 }, { "×", 215 }, { "Ø", 216 }, { "Ù", 217 }, { "Ú", 218 }, { "Û", 219 }, { "Ü", 220 }, { "Ý", 221 }, { "Þ", 222 }, { "ß", 223 }, { "à", 224 }, { "á", 225 }, { "â", 226 }, { "ã", 227 }, { "ä", 228 }, { "å", 229 }, { "æ", 230 }, { "ç", 231 }, { "è", 232 }, { "é", 233 }, { "ê", 234 }, { "ë", 235 }, { "ì", 236 }, { "í", 237 }, { "î", 238 }, { "ï", 239 }, { "ð", 240 }, { "ñ", 241 }, { "ò", 242 }, { "ó", 243 }, { "ô", 244 }, { "õ", 245 }, { "ö", 246 }, { "÷", 247 }, { "ø", 248 }, { "ù", 249 }, { "ú", 250 }, { "û", 251 }, { "ü", 252 }, { "ý", 253 }, { "þ", 254 }, { "ÿ", 255 }, }; int num_tab = sizeof(tab) / sizeof(tab[0]); long i, code; size_t len; char buf[1024]; if (octstr_get_char(html, *pos + 1) == '#') { if (octstr_get_char(html, *pos + 2) == 'x' || octstr_get_char(html, *pos + 2) == 'X') i = octstr_parse_long(&code, html, *pos + 3, 16); /* hex */ else i = octstr_parse_long(&code, html, *pos + 2, 10); /* decimal */ if (i > 0) { if (code < 256) octstr_append_char(sms, code); *pos = i + 1; if (octstr_get_char(html, *pos) == ';') ++(*pos); } else { ++(*pos); octstr_append_char(sms, '&'); } } else { for (i = 0; i < num_tab; ++i) { len = strlen(tab[i].entity); octstr_get_many_chars(buf, html, *pos, len); buf[len] = '\0'; if (strcmp(buf, tab[i].entity) == 0) { *pos += len; octstr_append_char(sms, tab[i].latin1); break; } } if (i == num_tab) { ++(*pos); octstr_append_char(sms, '&'); } } } Octstr *html_to_sms(Octstr *html) { long i, len; int c; Octstr *sms; sms = octstr_create(""); len = octstr_len(html); i = 0; while (i < len) { c = octstr_get_char(html, i); switch (c) { case '<': if (html_comment_begins(html, i)) skip_html_comment(html, &i); else skip_html_tag(html, &i); break; case '&': convert_html_entity(sms, html, &i); break; default: octstr_append_char(sms, c); ++i; break; } } octstr_shrink_blanks(sms); octstr_strip_blanks(sms); return sms; } gateway-1.4.5/gw/html.h0000644000175000017500000000614413227613126013426 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * html.h - declarations for functions that manipulate HTML * * Lars Wirzenius for WapIT Ltd. */ #ifndef HTML_H #define HTML_H #include #include "gwlib/gwlib.h" /* * Remove HTML tags and decode HTML entities in `html'. Return the new * string. * * Do something intelligent even with broken HTML so that the * function never fails. */ Octstr *html_to_sms(Octstr *html); #endif gateway-1.4.5/gw/shared.c0000644000175000017500000002025113227613126013716 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * shared.c - some utility routines shared by all Kannel boxes * * Lars Wirzenius */ #include #include #include #include "gwlib/gwlib.h" #include "shared.h" volatile enum program_status program_status = starting_up; /*********************************************************************** * Communication with the bearerbox. */ /* this is a static connection if only *one* boxc connection is * established from a foobarbox to bearerbox. */ static Connection *bb_conn; Connection *connect_to_bearerbox_real(Octstr *host, int port, int ssl, Octstr *our_host) { Connection *conn; #ifdef HAVE_LIBSSL if (ssl) conn = conn_open_ssl(host, port, NULL, our_host); /* XXX add certkeyfile to be given to conn_open_ssl */ else #endif /* HAVE_LIBSSL */ conn = conn_open_tcp(host, port, our_host); if (conn == NULL) return NULL; if (ssl) info(0, "Connected to bearerbox at %s port %d using SSL.", octstr_get_cstr(host), port); else info(0, "Connected to bearerbox at %s port %d.", octstr_get_cstr(host), port); return conn; } void connect_to_bearerbox(Octstr *host, int port, int ssl, Octstr *our_host) { bb_conn = connect_to_bearerbox_real(host, port, ssl, our_host); if (bb_conn == NULL) panic(0, "Couldn't connect to the bearerbox."); } void close_connection_to_bearerbox_real(Connection *conn) { conn_destroy(conn); } void close_connection_to_bearerbox(void) { close_connection_to_bearerbox_real(bb_conn); bb_conn = NULL; } void write_to_bearerbox_real(Connection *conn, Msg *pmsg) { Octstr *pack; pack = msg_pack(pmsg); if (conn_write_withlen(conn, pack) == -1) error(0, "Couldn't write Msg to bearerbox."); msg_destroy(pmsg); octstr_destroy(pack); } void write_to_bearerbox(Msg *pmsg) { write_to_bearerbox_real(bb_conn, pmsg); } int deliver_to_bearerbox_real(Connection *conn, Msg *msg) { Octstr *pack; pack = msg_pack(msg); if (conn_write_withlen(conn, pack) == -1) { error(0, "Couldn't deliver Msg to bearerbox."); octstr_destroy(pack); return -1; } octstr_destroy(pack); msg_destroy(msg); return 0; } int deliver_to_bearerbox(Msg *msg) { return deliver_to_bearerbox_real(bb_conn, msg); } int read_from_bearerbox_real(Connection *conn, Msg **msg, double seconds) { int ret; Octstr *pack; pack = NULL; *msg = NULL; while (program_status != shutting_down) { pack = conn_read_withlen(conn); gw_claim_area(pack); if (pack != NULL) break; if (conn_error(conn)) { error(0, "Error reading from bearerbox, disconnecting."); return -1; } if (conn_eof(conn)) { error(0, "Connection closed by the bearerbox."); return -1; } ret = conn_wait(conn, seconds); if (ret < 0) { error(0, "Connection to bearerbox broke."); return -1; } else if (ret == 1) { /* debug("gwlib.gwlib", 0, "Connection to bearerbox timed out after %.2f seconds.", seconds); */ return 1; } } if (pack == NULL) return -1; *msg = msg_unpack(pack); octstr_destroy(pack); if (*msg == NULL) { error(0, "Failed to unpack data!"); return -1; } return 0; } int read_from_bearerbox(Msg **msg, double seconds) { return read_from_bearerbox_real(bb_conn, msg, seconds); } /***************************************************************************** * * Function validates an OSI date. Return unmodified octet string date when it * is valid, NULL otherwise. */ Octstr *parse_date(Octstr *date) { long date_value; if (octstr_get_char(date, 4) != '-') goto error; if (octstr_get_char(date, 7) != '-') goto error; if (octstr_get_char(date, 10) != 'T') goto error; if (octstr_get_char(date, 13) != ':') goto error; if (octstr_get_char(date, 16) != ':') goto error; if (octstr_get_char(date, 19) != 'Z') goto error; if (octstr_parse_long(&date_value, date, 0, 10) < 0) goto error; if (octstr_parse_long(&date_value, date, 5, 10) < 0) goto error; if (date_value < 1 || date_value > 12) goto error; if (octstr_parse_long(&date_value, date, 8, 10) < 0) goto error; if (date_value < 1 || date_value > 31) goto error; if (octstr_parse_long(&date_value, date, 11, 10) < 0) goto error; if (date_value < 0 || date_value > 23) goto error; if (octstr_parse_long(&date_value, date, 14, 10) < 0) goto error; if (date_value < 0 || date_value > 59) goto error; if (date_value < 0 || date_value > 59) goto error; if (octstr_parse_long(&date_value, date, 17, 10) < 0) goto error; return date; error: warning(0, "parse_date: not an ISO date"); return NULL; } int restart_box(char **argv) { int rc; if (!(rc = fork())) { /* * Sleep a while in order to get father * process time to cleanup things */ gwthread_sleep(1.0); if (execvp(argv[0],argv) == -1) error(errno, "Unable to start new process."); } else if (rc == -1) error(errno, "Could not restart, exiting..."); return rc == -1 ? -1 : 0; } gateway-1.4.5/gw/dlr_oracle.c0000644000175000017500000003420513227613126014562 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dlr_oracle.c - Oracle dlr storage implementation. * * Author: Alexander Malysh , (C) 2003 * Robert Ga³ach * 2004 Rewrited sql queries to use binding variables. * * Copyright: See COPYING file that comes with this distribution */ #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #include "dlr_p.h" #ifdef HAVE_ORACLE /* * Our connection pool to oracle. */ static DBPool *pool = NULL; /* * Database fields, which we are use. */ static struct dlr_db_fields *fields = NULL; static long dlr_messages_oracle() { List *result, *row; Octstr *sql; DBPoolConn *conn; long msgs = -1; conn = dbpool_conn_consume(pool); if (conn == NULL) return -1; sql = octstr_format("SELECT count(*) FROM %S", fields->table); #if defined(DLR_TRACE) debug("dlr.oracle", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(conn, sql, NULL, &result) != 0) { octstr_destroy(sql); dbpool_conn_produce(conn); return -1; } dbpool_conn_produce(conn); octstr_destroy(sql); if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); msgs = strtol(octstr_get_cstr(gwlist_get(row,0)), NULL, 10); gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(result, NULL); return msgs; } static void dlr_shutdown_oracle() { dbpool_destroy(pool); dlr_db_fields_destroy(fields); } static void dlr_add_oracle(struct dlr_entry *entry) { Octstr *sql, *os_mask; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.oracle", 0, "adding DLR entry into database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { dlr_entry_destroy(entry); return; } sql = octstr_format("INSERT INTO %S (%S, %S, %S, %S, %S, %S, %S, %S, %S) VALUES " "(:1, :2, :3, :4, :5, :6, :7, :8, 0)", fields->table, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status); os_mask = octstr_format("%d", entry->mask); gwlist_append(binds, entry->smsc); /* :1 */ gwlist_append(binds, entry->timestamp); /* :2 */ gwlist_append(binds, entry->source); /* :3 */ gwlist_append(binds, entry->destination); /* :4 */ gwlist_append(binds, entry->service); /* :5 */ gwlist_append(binds, entry->url); /* :6 */ gwlist_append(binds, os_mask); /* :7 */ gwlist_append(binds, entry->boxc_id); /* :8 */ #if defined(DLR_TRACE) debug("dlr.oracle", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: ORACLE: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination)); else if (!res) warning(0, "DLR: ORACLE: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination)); dbpool_conn_produce(pconn); octstr_destroy(sql); gwlist_destroy(binds, NULL); octstr_destroy(os_mask); dlr_entry_destroy(entry); } static void dlr_remove_oracle(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.oracle", 0, "removing DLR from database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; if (dst) like = octstr_format("AND %S LIKE CONCAT('%%', :3)", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("DELETE FROM %S WHERE %S=:1 AND %S=:2 %S AND ROWNUM < 2", fields->table, fields->field_smsc, fields->field_ts, like); gwlist_append(binds, (Octstr *)smsc); /* :1 */ gwlist_append(binds, (Octstr *)ts); /* :2 */ if (dst) /* :3 */ gwlist_append(binds, (Octstr *)dst); #if defined(DLR_TRACE) debug("dlr.oracle", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: ORACLE: Error while removing dlr entry for DST<%s>", octstr_get_cstr(dst)); else if (!res) warning(0, "DLR: ORACLE: No dlr deleted for DST<%s>", octstr_get_cstr(dst)); dbpool_conn_produce(pconn); gwlist_destroy(binds, NULL); octstr_destroy(sql); octstr_destroy(like); } static struct dlr_entry* dlr_get_oracle(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; DBPoolConn *pconn; List *result = NULL, *row; struct dlr_entry *res = NULL; List *binds = gwlist_create(); pconn = dbpool_conn_consume(pool); if (pconn == NULL) /* should not happens, but sure is sure */ return NULL; if (dst) like = octstr_format("AND %S LIKE CONCAT('%%', :3)", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("SELECT %S, %S, %S, %S, %S, %S FROM %S WHERE %S=:1 AND %S=:2 %S AND ROWNUM < 2", fields->field_mask, fields->field_serv, fields->field_url, fields->field_src, fields->field_dst, fields->field_boxc, fields->table, fields->field_smsc, fields->field_ts, like); gwlist_append(binds, (Octstr *)smsc); /* :1 */ gwlist_append(binds, (Octstr *)ts); /* :2 */ if (dst) /* :3 */ gwlist_append(binds, (Octstr *)dst); #if defined(DLR_TRACE) debug("dlr.oracle", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(pconn, sql, binds, &result) != 0) { octstr_destroy(sql); octstr_destroy(like); dbpool_conn_produce(pconn); return NULL; } octstr_destroy(sql); octstr_destroy(like); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); #define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i)) if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); res = dlr_entry_create(); gw_assert(res != NULL); res->mask = atoi(LO2CSTR(row,0)); res->service = octstr_create(LO2CSTR(row, 1)); res->url = octstr_create(LO2CSTR(row,2)); res->source = octstr_create(LO2CSTR(row, 3)); res->destination = octstr_create(LO2CSTR(row, 4)); res->boxc_id = octstr_create(LO2CSTR(row, 5)); gwlist_destroy(row, octstr_destroy_item); res->smsc = octstr_duplicate(smsc); } gwlist_destroy(result, NULL); #undef LO2CSTR return res; } static void dlr_update_oracle(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status) { Octstr *sql, *os_status, *like; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.oracle", 0, "updating DLR status in database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; if (dst) like = octstr_format("AND %S LIKE CONCAT('%%', :4)", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("UPDATE %S SET %S=:1 WHERE %S=:2 AND %S=:3 %S AND ROWNUM < 2", fields->table, fields->field_status, fields->field_smsc, fields->field_ts, like); os_status = octstr_format("%d", status); gwlist_append(binds, (Octstr *)os_status); /* :1 */ gwlist_append(binds, (Octstr *)smsc); /* :2 */ gwlist_append(binds, (Octstr *)ts); /* :3 */ if (dst) /* :4 */ gwlist_append(binds, (Octstr *)dst); #if defined(DLR_TRACE) debug("dlr.oracle", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: ORACLE: Error while updating dlr entry for DST<%s>", octstr_get_cstr(dst)); else if (!res) warning(0, "DLR: ORACLE: No dlr found to update for DST<%s> (status: %d)", octstr_get_cstr(dst), status); dbpool_conn_produce(pconn); gwlist_destroy(binds, NULL); octstr_destroy(os_status); octstr_destroy(sql); octstr_destroy(like); } static void dlr_flush_oracle (void) { Octstr *sql; DBPoolConn *pconn; int rows; pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; sql = octstr_format("DELETE FROM %S", fields->table); #if defined(DLR_TRACE) debug("dlr.oracle", 0, "sql: %s", octstr_get_cstr(sql)); #endif rows = dbpool_conn_update(pconn, sql, NULL); if (rows == -1) error(0, "DLR: ORACLE: Error while flushing dlr entries from database"); else debug("dlr.oracle", 0, "Flushing %d DLR entries from database", rows); dbpool_conn_produce(pconn); octstr_destroy(sql); } static struct dlr_storage handles = { .type = "oracle", .dlr_messages = dlr_messages_oracle, .dlr_shutdown = dlr_shutdown_oracle, .dlr_add = dlr_add_oracle, .dlr_get = dlr_get_oracle, .dlr_remove = dlr_remove_oracle, .dlr_update = dlr_update_oracle, .dlr_flush = dlr_flush_oracle }; struct dlr_storage *dlr_init_oracle(Cfg *cfg) { CfgGroup *grp; List *grplist; long pool_size; DBConf *db_conf = NULL; Octstr *id, *username, *password, *tnsname; int found; if ((grp = cfg_get_single_group(cfg, octstr_imm("dlr-db"))) == NULL) panic(0, "DLR: ORACLE: group 'dlr-db' is not specified!"); if (!(id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: ORACLE: directive 'id' is not specified!"); /* initialize database fields */ fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); grplist = cfg_get_multi_group(cfg, octstr_imm("oracle-connection")); found = 0; while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { Octstr *p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, id) == 0) { found = 1; } if (p != NULL) octstr_destroy(p); if (found == 1) break; } gwlist_destroy(grplist, NULL); if (found == 0) panic(0, "DLR: ORACLE: connection settings for id '%s' are not specified!", octstr_get_cstr(id)); username = cfg_get(grp, octstr_imm("username")); password = cfg_get(grp, octstr_imm("password")); tnsname = cfg_get(grp, octstr_imm("tnsname")); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1) pool_size = 1; if (username == NULL || password == NULL || tnsname == NULL) panic(0, "DLR: ORACLE: connection settings missing for id '%s', please" " check you configuration.",octstr_get_cstr(id)); /* ok we are ready to create dbpool */ db_conf = gw_malloc(sizeof(*db_conf)); db_conf->oracle = gw_malloc(sizeof(OracleConf)); db_conf->oracle->username = username; db_conf->oracle->password = password; db_conf->oracle->tnsname = tnsname; pool = dbpool_create(DBPOOL_ORACLE, db_conf, pool_size); gw_assert(pool != NULL); if (dbpool_conn_count(pool) == 0) panic(0, "DLR: ORACLE: Couldnot establish oracle connection(s)."); octstr_destroy(id); return &handles; } #else /* no oracle support build in */ struct dlr_storage *dlr_init_oracle(Cfg *cfg) { return NULL; } #endif /* HAVE_ORACLE */ gateway-1.4.5/gw/wap_push_pap_mime.h0000644000175000017500000001017213227613126016153 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_pap_mime.h: Header for a (gateway oriented) mime parser for pap * module. This parser conforms proxy rules set in Push Message, chapter 7. * (Headers are passed as they are) * * By Aarno Syvänen for Wapit Ltd */ #ifndef WAP_PUSH_PAP_MIME_H #define WAP_PUSH_PAP_MIME_H #include "gwlib/gwlib.h" /* * Implementation of the external function, PAP uses MIME type multipart/ * related to communicate a push message and related control information from * pi to ppg. Mime_parse separates parts of message and in addition returns * MIME-part-headers of the content entity. Preamble and epilogue of are dis- * carded from control messages, but not from a multipart content entity. * Multipart/related content type is defined in rfc 2046, chapters 5.1, 5.1.1, * and 5.1.7. Grammar is capitulated in rfc 2046 appendix A and in rfc 822, * appendix D. Functions called by mime_parse remove parsed parts from the mime * content. * Input: pointer to mime boundary and mime content * Output: in all cases, pointer to pap control document and push data. If * there is a capabilities document, pointer to this is returned, too. If there * is none, pointer to NULL instead. * In addition, return 1 if parsing was succesfull, 0 otherwise. */ int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, Octstr **push_data, List **content_headers, Octstr **rdf_content); #endif gateway-1.4.5/gw/msg-decl.h0000644000175000017500000001033113227613126014146 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * msg-decl.h - message declarations * * This file contains declarations of the message types. See the * architecture document to see how these should be interpreted and * modified. * * This file is included by a number of other files. * * Lars Wirzenius */ MSG(heartbeat, { INTEGER(load) }) MSG(admin, { INTEGER(command) OCTSTR(boxc_id) }) MSG(sms, { OCTSTR(sender) OCTSTR(receiver) OCTSTR(udhdata) OCTSTR(msgdata) INTEGER(time) OCTSTR(smsc_id) OCTSTR(smsc_number) OCTSTR(foreign_id) OCTSTR(service) OCTSTR(account) UUID(id) INTEGER(sms_type) INTEGER(mclass) INTEGER(mwi) INTEGER(coding) INTEGER(compress) INTEGER(validity) INTEGER(deferred) INTEGER(dlr_mask) OCTSTR(dlr_url) INTEGER(pid) INTEGER(alt_dcs) INTEGER(rpi) OCTSTR(charset) OCTSTR(boxc_id) OCTSTR(binfo) INTEGER(msg_left) VOID(split_parts) INTEGER(priority) INTEGER(resend_try) INTEGER(resend_time) OCTSTR(meta_data) }) MSG(ack, { INTEGER(nack) INTEGER(time) UUID(id) }) MSG(wdp_datagram, { OCTSTR(source_address) INTEGER(source_port) OCTSTR(destination_address) INTEGER(destination_port) OCTSTR(user_data) }) #undef MSG #undef INTEGER #undef OCTSTR #undef UUID #undef VOID gateway-1.4.5/gw/dlr_mssql.c0000644000175000017500000003124013227613126014450 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dlr_mssql.c - MSSQL dlr storage implementation. * * Author: Alejandro Guerrieri * * Based on dlr_oracle.c * Alexander Malysh * Robert Ga³ach * * Copyright: See COPYING file that comes with this distribution */ #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #include "dlr_p.h" #ifdef HAVE_MSSQL /* * Our connection pool to mssql. */ static DBPool *pool = NULL; /* * Database fields, which we are use. */ static struct dlr_db_fields *fields = NULL; static long dlr_messages_mssql() { List *result, *row; Octstr *sql; DBPoolConn *conn; long msgs = -1; conn = dbpool_conn_consume(pool); if (conn == NULL) return -1; sql = octstr_format("SELECT COUNT(*) FROM %S", fields->table); #if defined(DLR_TRACE) debug("dlr.mssql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(conn, sql, NULL, &result) != 0) { octstr_destroy(sql); dbpool_conn_produce(conn); return -1; } dbpool_conn_produce(conn); octstr_destroy(sql); if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); msgs = strtol(octstr_get_cstr(gwlist_get(row,0)), NULL, 10); gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(result, NULL); return msgs; } static void dlr_shutdown_mssql() { dbpool_destroy(pool); dlr_db_fields_destroy(fields); } static void dlr_add_mssql(struct dlr_entry *entry) { Octstr *sql; DBPoolConn *pconn; debug("dlr.mssql", 0, "adding DLR entry into database"); int res; pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { dlr_entry_destroy(entry); return; } sql = octstr_format("INSERT INTO %S (%S, %S, %S, %S, %S, %S, %S, %S, %S) VALUES " "('%S', '%S', '%S', '%S', '%S', '%S', '%d', '%S', '%d')", fields->table, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status, entry->smsc, entry->timestamp, entry->source, entry->destination, entry->service, entry->url, entry->mask, entry->boxc_id, 0); #if defined(DLR_TRACE) debug("dlr.mssql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, NULL)) == -1) error(0, "DLR: MSSQL: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination)); else if (!res) warning(0, "DLR: MSSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination)); dbpool_conn_produce(pconn); octstr_destroy(sql); dlr_entry_destroy(entry); } static void dlr_remove_mssql(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; DBPoolConn *pconn; int res; debug("dlr.mssql", 0, "removing DLR from database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; if (dst) like = octstr_format("AND %S LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("SET ROWCOUNT 1\nDELETE FROM %S WHERE %S='%S' AND " "%S='%S' %S \nSET ROWCOUNT 0", fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like); #if defined(DLR_TRACE) debug("dlr.mssql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, NULL)) == -1) error(0, "DLR: MSSQL: Error while removing dlr entry for DST<%s>", octstr_get_cstr(dst)); else if (!res) warning(0, "DLR: MSSQL: No dlr deleted for DST<%s>", octstr_get_cstr(dst)); dbpool_conn_produce(pconn); octstr_destroy(sql); octstr_destroy(like); } static struct dlr_entry* dlr_get_mssql(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; DBPoolConn *pconn; List *result = NULL, *row; struct dlr_entry *res = NULL; pconn = dbpool_conn_consume(pool); if (pconn == NULL) /* should not happens, but sure is sure */ return NULL; if (dst) like = octstr_format("AND %S LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("SELECT %S, %S, %S, %S, %S, %S FROM %S WHERE %S='%S'" " AND %S='%S' %S", fields->field_mask, fields->field_serv, fields->field_url, fields->field_src, fields->field_dst, fields->field_boxc, fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like); #if defined(DLR_TRACE) debug("dlr.mssql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(pconn, sql, NULL, &result) != 0) { octstr_destroy(sql); dbpool_conn_produce(pconn); return NULL; } octstr_destroy(sql); octstr_destroy(like); dbpool_conn_produce(pconn); #define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i)) if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); res = dlr_entry_create(); gw_assert(res != NULL); res->mask = atoi(LO2CSTR(row,0)); res->service = octstr_create(LO2CSTR(row, 1)); res->url = octstr_create(LO2CSTR(row,2)); res->source = octstr_create(LO2CSTR(row, 3)); res->destination = octstr_create(LO2CSTR(row, 4)); res->boxc_id = octstr_create(LO2CSTR(row, 5)); gwlist_destroy(row, octstr_destroy_item); res->smsc = octstr_duplicate(smsc); } gwlist_destroy(result, NULL); #undef LO2CSTR return res; } static void dlr_update_mssql(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status) { Octstr *sql, *like; DBPoolConn *pconn; int res; debug("dlr.mssql", 0, "updating DLR status in database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; if (dst) like = octstr_format("AND %S LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("SET ROWCOUNT 1\nUPDATE %S SET %S=%d WHERE %S='%S' " "AND %S='%S' %S\nSET ROWCOUNT 0", fields->table, fields->field_status, status, fields->field_smsc, smsc, fields->field_ts, ts, like); #if defined(DLR_TRACE) debug("dlr.mssql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, NULL)) == -1) error(0, "DLR: MSSQL: Error while updating dlr entry for DST<%s>", octstr_get_cstr(dst)); else if (!res) warning(0, "DLR: MSSQL: No dlr found to update for DST<%s> (status: %d)", octstr_get_cstr(dst), status); dbpool_conn_produce(pconn); octstr_destroy(sql); octstr_destroy(like); } static void dlr_flush_mssql (void) { Octstr *sql; DBPoolConn *pconn; int rows; pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; sql = octstr_format("DELETE FROM %S", fields->table); #if defined(DLR_TRACE) debug("dlr.mssql", 0, "sql: %s", octstr_get_cstr(sql)); #endif rows = dbpool_conn_update(pconn, sql, NULL); if (rows == -1) error(0, "DLR: MSSQL: Error while flushing dlr entries from database"); else debug("dlr.mssql", 0, "Flushing %d DLR entries from database", rows); dbpool_conn_produce(pconn); octstr_destroy(sql); } static struct dlr_storage handles = { .type = "mssql", .dlr_messages = dlr_messages_mssql, .dlr_shutdown = dlr_shutdown_mssql, .dlr_add = dlr_add_mssql, .dlr_get = dlr_get_mssql, .dlr_remove = dlr_remove_mssql, .dlr_update = dlr_update_mssql, .dlr_flush = dlr_flush_mssql }; struct dlr_storage *dlr_init_mssql(Cfg *cfg) { CfgGroup *grp; List *grplist; long pool_size; DBConf *db_conf = NULL; Octstr *id, *username, *password, *server, *database; int found; if ((grp = cfg_get_single_group(cfg, octstr_imm("dlr-db"))) == NULL) panic(0, "DLR: MSSQL: group 'dlr-db' is not specified!"); if (!(id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: MSSQL: directive 'id' is not specified!"); /* initialize database fields */ fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); grplist = cfg_get_multi_group(cfg, octstr_imm("mssql-connection")); found = 0; while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { Octstr *p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, id) == 0) { found = 1; } if (p != NULL) octstr_destroy(p); if (found == 1) break; } gwlist_destroy(grplist, NULL); if (found == 0) panic(0, "DLR: MSSQL: connection settings for id '%s' are not specified!", octstr_get_cstr(id)); username = cfg_get(grp, octstr_imm("username")); password = cfg_get(grp, octstr_imm("password")); server = cfg_get(grp, octstr_imm("server")); database = cfg_get(grp, octstr_imm("database")); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1) pool_size = 1; if (username == NULL || password == NULL || server == NULL || database == NULL) { panic(0, "DLR: MSSQL: connection settings missing for id '%s'. " "Please check you configuration.", octstr_get_cstr(id)); } /* ok we are ready to create dbpool */ db_conf = gw_malloc(sizeof(*db_conf)); db_conf->mssql = gw_malloc(sizeof(MSSQLConf)); db_conf->mssql->username = username; db_conf->mssql->password = password; db_conf->mssql->server = server; db_conf->mssql->database = database; pool = dbpool_create(DBPOOL_MSSQL, db_conf, pool_size); gw_assert(pool != NULL); if (dbpool_conn_count(pool) == 0) panic(0, "DLR: MSSQL: Could not establish mssql connection(s)."); octstr_destroy(id); return &handles; } #else /* no mssql support build in */ struct dlr_storage *dlr_init_mssql(Cfg *cfg) { return NULL; } #endif /* HAVE_MSSQL */ gateway-1.4.5/gw/bb_udp.c0000644000175000017500000003075113227613126013711 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * bb_udpc.c : bearerbox UDP sender/receiver module * * handles start/restart/shutdown/suspend/die operations of the UDP * WDP interface * * Kalle Marjola 2000 for project Kannel */ #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "msg.h" #include "bearerbox.h" /* passed from bearerbox core */ extern volatile sig_atomic_t bb_status; extern List *incoming_wdp; extern Counter *incoming_wdp_counter; extern Counter *outgoing_wdp_counter; extern List *flow_threads; extern List *suspended; extern List *isolated; /* our own thingies */ static volatile sig_atomic_t udp_running; static List *udpc_list; typedef struct _udpc { int fd; Octstr *addr; List *outgoing_list; long receiver; } Udpc; /* * IP numbers which are allowed or denied us of the bearerbox via UDP. */ static Octstr *allow_ip; static Octstr *deny_ip; /* forward declarations */ static void udpc_destroy(Udpc *udpc); /*------------------------------------------------- * receiver thingies */ static void udp_receiver(void *arg) { Octstr *datagram, *cliaddr; int ret; Msg *msg; Udpc *conn = arg; Octstr *ip; gwlist_add_producer(incoming_wdp); gwlist_add_producer(flow_threads); gwthread_wakeup(MAIN_THREAD_ID); /* remove messages from socket until it is closed */ while (bb_status != BB_DEAD && bb_status != BB_SHUTDOWN) { gwlist_consume(isolated); /* block here if suspended/isolated */ if (read_available(conn->fd, 100000) < 1) continue; ret = udp_recvfrom(conn->fd, &datagram, &cliaddr); if (ret == -1) { if (errno == EAGAIN) /* No datagram available, don't block. */ continue; error(errno, "Failed to receive an UDP"); /* * just continue, or is there ANY error that would result * in situation where it would be better to break; or even * die off? - Kalle 28.2 */ continue; } /* discard the message if the client is not allowed */ ip = udp_get_ip(cliaddr); if (!is_allowed_ip(allow_ip, deny_ip, ip)) { warning(0, "UDP: Discarding packet from %s, IP is denied.", octstr_get_cstr(ip)); octstr_destroy(datagram); } else { debug("bb.udp", 0, "datagram received"); msg = msg_create(wdp_datagram); msg->wdp_datagram.source_address = udp_get_ip(cliaddr); msg->wdp_datagram.source_port = udp_get_port(cliaddr); msg->wdp_datagram.destination_address = udp_get_ip(conn->addr); msg->wdp_datagram.destination_port = udp_get_port(conn->addr); msg->wdp_datagram.user_data = datagram; gwlist_produce(incoming_wdp, msg); counter_increase(incoming_wdp_counter); } octstr_destroy(cliaddr); octstr_destroy(ip); } gwlist_remove_producer(incoming_wdp); gwlist_remove_producer(flow_threads); } /*--------------------------------------------- * sender thingies */ static int send_udp(int fd, Msg *msg) { Octstr *cliaddr; int ret; cliaddr = udp_create_address(msg->wdp_datagram.destination_address, msg->wdp_datagram.destination_port); ret = udp_sendto(fd, msg->wdp_datagram.user_data, cliaddr); if (ret == -1) error(0, "WDP/UDP: could not send UDP datagram"); octstr_destroy(cliaddr); return ret; } static void udp_sender(void *arg) { Msg *msg; Udpc *conn = arg; gwlist_add_producer(flow_threads); while(bb_status != BB_DEAD) { gwlist_consume(suspended); /* block here if suspended */ if ((msg = gwlist_consume(conn->outgoing_list)) == NULL) break; debug("bb.udp", 0, "udp: sending message"); if (send_udp(conn->fd, msg) == -1) /* ok, we failed... tough * XXX log the message or something like that... but this * is not as fatal as it is with SMS-messages... */ { msg_destroy(msg); continue; } counter_increase(outgoing_wdp_counter); msg_destroy(msg); } gwthread_join(conn->receiver); udpc_destroy(conn); gwlist_remove_producer(flow_threads); } /*--------------------------------------------------------------- * accept/create thingies */ static Udpc *udpc_create(int port, char *interface_name) { Udpc *udpc; Octstr *os; int fl; udpc = gw_malloc(sizeof(Udpc)); udpc->fd = udp_bind(port, interface_name); os = octstr_create(interface_name); udpc->addr = udp_create_address(os, port); octstr_destroy(os); if (udpc->addr == NULL) { error(0, "updc_create: could not resolve interface <%s>", interface_name); close(udpc->fd); gw_free(udpc); return NULL; } fl = fcntl(udpc->fd, F_GETFL); fcntl(udpc->fd, F_SETFL, fl | O_NONBLOCK); os = udp_get_ip(udpc->addr); debug("bb.udp", 0, "udpc_create: Bound to UDP <%s:%d>", octstr_get_cstr(os), udp_get_port(udpc->addr)); octstr_destroy(os); udpc->outgoing_list = gwlist_create(); return udpc; } static void udpc_destroy(Udpc *udpc) { if (udpc == NULL) return; if (udpc->fd >= 0) close(udpc->fd); octstr_destroy(udpc->addr); gw_assert(gwlist_len(udpc->outgoing_list) == 0); gwlist_destroy(udpc->outgoing_list, NULL); gw_free(udpc); } static int add_service(int port, char *interface_name) { Udpc *udpc; if ((udpc = udpc_create(port, interface_name)) == NULL) goto error; gwlist_add_producer(udpc->outgoing_list); udpc->receiver = gwthread_create(udp_receiver, udpc); if (udpc->receiver == -1) goto error; if (gwthread_create(udp_sender, udpc) == -1) goto error; gwlist_append(udpc_list, udpc); return 0; error: error(0, "Failed to start UDP receiver/sender thread"); udpc_destroy(udpc); return -1; } /*------------------------------------------------------------- * public functions * */ int udp_start(Cfg *cfg) { CfgGroup *grp; Octstr *iface; List *ifs; int allow_wtls; if (udp_running) return -1; debug("bb.udp", 0, "starting UDP sender/receiver module"); grp = cfg_get_single_group(cfg, octstr_imm("core")); iface = cfg_get(grp, octstr_imm("wdp-interface-name")); if (iface == NULL) { error(0, "Missing wdp-interface-name variable, cannot start UDP"); return -1; } allow_ip = cfg_get(grp, octstr_imm("udp-allow-ip")); deny_ip = cfg_get(grp, octstr_imm("udp-deny-ip")); /* we'll activate WTLS as soon as we have a 'wtls' config group */ grp = cfg_get_single_group(cfg, octstr_imm("wtls")); allow_wtls = grp != NULL ? 1 : 0; udpc_list = gwlist_create(); /* have a list of running systems */ ifs = octstr_split(iface, octstr_imm(";")); octstr_destroy(iface); while (gwlist_len(ifs) > 0) { iface = gwlist_extract_first(ifs); info(0, "Adding interface %s", octstr_get_cstr(iface)); add_service(9200, octstr_get_cstr(iface)); /* wsp */ add_service(9201, octstr_get_cstr(iface)); /* wsp/wtp */ #ifdef HAVE_WTLS_OPENSSL if (allow_wtls) { add_service(9202, octstr_get_cstr(iface)); /* wsp/wtls */ add_service(9203, octstr_get_cstr(iface)); /* wsp/wtp/wtls */ } #else if (allow_wtls) error(0, "These is a 'wtls' group in configuration, but no WTLS support compiled in!"); #endif /* add_service(9204, octstr_get_cstr(interface_name)); * vcard */ /* add_service(9205, octstr_get_cstr(interface_name)); * vcal */ /* add_service(9206, octstr_get_cstr(interface_name)); * vcard/wtls */ /* add_service(9207, octstr_get_cstr(interface_name)); * vcal/wtls */ octstr_destroy(iface); } gwlist_destroy(ifs, NULL); gwlist_add_producer(incoming_wdp); udp_running = 1; return 0; } /* * this function receives an WDP message and adds it to * corresponding outgoing_list. */ int udp_addwdp(Msg *msg) { int i; Udpc *udpc, *def_udpc; Octstr *ip; def_udpc = NULL; if (!udp_running) return -1; assert(msg != NULL); assert(msg_type(msg) == wdp_datagram); gwlist_lock(udpc_list); /* select in which list to add this */ for (i=0; i < gwlist_len(udpc_list); i++) { udpc = gwlist_get(udpc_list, i); if (msg->wdp_datagram.source_port == udp_get_port(udpc->addr)) { def_udpc = udpc; ip = udp_get_ip(udpc->addr); if (octstr_compare(msg->wdp_datagram.source_address, ip) == 0) { octstr_destroy(ip); gwlist_produce(udpc->outgoing_list, msg); gwlist_unlock(udpc_list); return 0; } octstr_destroy(ip); } } if (NULL != def_udpc) { gwlist_produce(def_udpc->outgoing_list, msg); gwlist_unlock(udpc_list); return 0; } gwlist_unlock(udpc_list); return -1; } int udp_shutdown(void) { if (!udp_running) return -1; debug("bb.thread", 0, "udp_shutdown: Starting avalanche"); gwlist_remove_producer(incoming_wdp); return 0; } int udp_die(void) { Udpc *udpc; if (!udp_running) return -1; /* * remove producers from all outgoing lists. */ debug("bb.udp", 0, "udp_die: removing producers from udp-lists"); while((udpc = gwlist_consume(udpc_list)) != NULL) { gwlist_remove_producer(udpc->outgoing_list); } gwlist_destroy(udpc_list, NULL); udp_running = 0; octstr_destroy(allow_ip); octstr_destroy(deny_ip); allow_ip = NULL; deny_ip = NULL; return 0; } int udp_outgoing_queue(void) { int i, q = 0; Udpc *udpc; if (!udp_running || udpc_list == NULL) return 0; gwlist_lock(udpc_list); for (i=0; i < gwlist_len(udpc_list); i++) { udpc = gwlist_get(udpc_list, i); q += gwlist_len(udpc->outgoing_list); } gwlist_unlock(udpc_list); return q; } gateway-1.4.5/gw/wap-error.h0000644000175000017500000000575213227613126014404 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap-error.h - interface to error handling layer */ #ifndef WAP_ERROR_H #define WAP_ERROR_H #include "wap/wap.h" Octstr* error_requesting_back(Octstr *url, Octstr *referer); Octstr* error_requesting(Octstr *url); Octstr* error_converting(Octstr *url, Octstr *type); #endif gateway-1.4.5/gw/ota_prov.c0000644000175000017500000005536513227613126014317 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * ota_prov.c: OTA settings and bookmarks provisioning routines * * This module contains routines for the SMS OTA (auto configuration) message * creation and manipulation for the sendota HTTP interface. * * Official Nokia and Ericsson WAP OTA configuration settings coded * by Stipe Tolj , Wapme Systems AG. * * Officual OMA ProvCont OTA provisioning coded * by Paul Bagyenda, digital solutions Ltd. * * XML compiler by Aarno Syvänen , Wiral Ltd. */ #include #include "gwlib/gwlib.h" #ifdef HAVE_LIBSSL #include #endif #include "msg.h" #include "sms.h" #include "ota_prov.h" #include "ota_prov_attr.h" #include "ota_compiler.h" #include "wap/wsp_headers.h" /*************************************************************************** * * Implementation of the internal function */ /* * Append the User Data Header (UDH) including the length (UDHL). Only ports * UDH here - SAR UDH is added when (or if) we split the message. This is our * *specific* WDP layer. */ static void ota_pack_udh(Msg **msg, Octstr *doc_type) { (*msg)->sms.udhdata = octstr_create(""); if (octstr_case_compare(doc_type, octstr_imm("oma-settings")) == 0) octstr_append_from_hex((*msg)->sms.udhdata, "0605040B840B84"); else if (octstr_case_compare(doc_type, octstr_imm("syncsettings")) == 0) { octstr_append_from_hex((*msg)->sms.udhdata, "060504C34CC002"); } else octstr_append_from_hex((*msg)->sms.udhdata, "060504C34FC002"); } /* * Our WSP headers: Push Id, PDU type, headers, charset. */ static int ota_pack_push_headers(Msg **msg, Octstr *mime_type, Octstr *sec, Octstr *pin, Octstr *ota_binary) { (*msg)->sms.msgdata = octstr_create(""); if (octstr_case_compare(mime_type, octstr_imm("settings")) == 0) { /* PUSH ID, PDU type, header length, value length */ octstr_append_from_hex((*msg)->sms.msgdata, "01062C1F2A"); /* MIME type for settings */ octstr_format_append((*msg)->sms.msgdata, "%s", "application/x-wap-prov.browser-settings"); octstr_append_from_hex((*msg)->sms.msgdata, "00"); /* charset UTF-8 */ octstr_append_from_hex((*msg)->sms.msgdata, "81EA"); } else if (octstr_case_compare(mime_type, octstr_imm("bookmarks")) == 0) { /* PUSH ID, PDU type, header length, value length */ octstr_append_from_hex((*msg)->sms.msgdata, "01062D1F2B"); /* MIME type for bookmarks */ octstr_format_append((*msg)->sms.msgdata, "%s", "application/x-wap-prov.browser-bookmarks"); octstr_append_from_hex((*msg)->sms.msgdata, "00"); /* charset UTF-8 */ octstr_append_from_hex((*msg)->sms.msgdata, "81EA"); } else if (octstr_case_compare(mime_type, octstr_imm("syncsettings")) == 0) { octstr_append_from_hex((*msg)->sms.msgdata, "3406060502020b81EA"); } else if (octstr_case_compare(mime_type, octstr_imm("oma-settings")) == 0) { Octstr *hdr = octstr_create(""), *mac; unsigned char *p; unsigned int mac_len; #ifdef HAVE_LIBSSL unsigned char macbuf[EVP_MAX_MD_SIZE]; #endif /* PUSH ID, PDU type, header length, value length */ octstr_append_from_hex((*msg)->sms.msgdata, "0106"); octstr_append_from_hex(hdr, "1f2db6"); /* Content type + other type + sec param */ wsp_pack_short_integer(hdr, 0x11); if (octstr_case_compare(sec, octstr_imm("netwpin")) == 0) wsp_pack_short_integer(hdr, 0x0); else if (octstr_case_compare(sec, octstr_imm("userpin")) == 0) wsp_pack_short_integer(hdr, 0x01); else if (octstr_case_compare(sec, octstr_imm("usernetwpin")) == 0) wsp_pack_short_integer(hdr, 0x02); else if (octstr_case_compare(sec, octstr_imm("userpinmac")) == 0) wsp_pack_short_integer(hdr, 0x03); /* XXXX Although not quite supported now.*/ else { warning(0, "OMA ProvCont: Unknown SEC pin type '%s'.", octstr_get_cstr(sec)); wsp_pack_short_integer(hdr, 0x01); } wsp_pack_short_integer(hdr, 0x12); /* MAC */ #ifdef HAVE_LIBSSL p = HMAC(EVP_sha1(), octstr_get_cstr(pin), octstr_len(pin), (unsigned char *)octstr_get_cstr(ota_binary), octstr_len(ota_binary), macbuf, &mac_len); #else mac_len = 0; p = ""; warning(0, "OMA ProvCont: No SSL Support, '%s' not supported!", octstr_get_cstr(mime_type)); #endif mac = octstr_create_from_data((char *)p, mac_len); octstr_binary_to_hex(mac, 1); octstr_append(hdr, mac); octstr_append_from_hex(hdr, "00"); octstr_append_uintvar((*msg)->sms.msgdata, octstr_len(hdr)); octstr_append((*msg)->sms.msgdata, hdr); octstr_destroy(hdr); octstr_destroy(mac); } else { warning(0, "Unknown MIME type in OTA request, type '%s' is unsupported.", octstr_get_cstr(mime_type)); return 0; } return 1; } /*************************************************************************** * * Implementation of the external function */ int ota_pack_message(Msg **msg, Octstr *ota_doc, Octstr *doc_type, Octstr *from, Octstr *phone_number, Octstr *sec, Octstr *pin) { Octstr *ota_binary; *msg = msg_create(sms); (*msg)->sms.sms_type = mt_push; ota_pack_udh(msg, doc_type); if (ota_compile(ota_doc, octstr_imm("UTF-8"), &ota_binary) == -1) goto cerror; if (!ota_pack_push_headers(msg, doc_type, sec, pin, ota_binary)) goto herror; octstr_format_append((*msg)->sms.msgdata, "%S", ota_binary); (*msg)->sms.sender = octstr_duplicate(from); (*msg)->sms.receiver = octstr_duplicate(phone_number); (*msg)->sms.coding = DC_8BIT; (*msg)->sms.time = time(NULL); octstr_dump((*msg)->sms.msgdata, 0); info(0, "/cgi-bin/sendota: XML request for target <%s>", octstr_get_cstr(phone_number)); octstr_destroy(ota_binary); octstr_destroy(ota_doc); octstr_destroy(doc_type); octstr_destroy(from); octstr_destroy(sec); octstr_destroy(pin); return 0; herror: octstr_destroy(ota_binary); octstr_destroy(ota_doc); octstr_destroy(doc_type); octstr_destroy(from); octstr_destroy(sec); octstr_destroy(pin); return -2; cerror: octstr_destroy(ota_doc); octstr_destroy(doc_type); octstr_destroy(from); octstr_destroy(sec); octstr_destroy(pin); return -1; } Msg *ota_tokenize_settings(CfgGroup *grp, Octstr *from, Octstr *receiver) { Octstr *url, *desc, *ipaddr, *phonenum, *username, *passwd; int speed, bearer, calltype, connection, security, authent; Msg *msg; Octstr *p; url = NULL; desc = NULL; ipaddr = NULL; phonenum = NULL; username = NULL; passwd = NULL; bearer = -1; calltype = WBXML_TOK_VALUE_CONN_ISDN; connection = WBXML_TOK_VALUE_PORT_9201; security = 0; authent = WBXML_TOK_VALUE_AUTH_PAP; url = cfg_get(grp, octstr_imm("location")); desc = cfg_get(grp, octstr_imm("service")); ipaddr = cfg_get(grp, octstr_imm("ipaddress")); phonenum = cfg_get(grp, octstr_imm("phonenumber")); p = cfg_get(grp, octstr_imm("bearer")); if (p != NULL) { if (strcasecmp(octstr_get_cstr(p), "data") == 0) bearer = WBXML_TOK_VALUE_GSM_CSD; else bearer = -1; octstr_destroy(p); } p = cfg_get(grp, octstr_imm("calltype")); if (p != NULL) { if (strcasecmp(octstr_get_cstr(p), "analog") == 0) calltype = WBXML_TOK_VALUE_CONN_ANALOGUE; else calltype = WBXML_TOK_VALUE_CONN_ISDN; octstr_destroy(p); } speed = WBXML_TOK_VALUE_SPEED_9600; p = cfg_get(grp, octstr_imm("speed")); if (p != NULL) { if (octstr_compare(p, octstr_imm("14400")) == 0) speed = WBXML_TOK_VALUE_SPEED_14400; octstr_destroy(p); } /* connection mode: UDP (port 9200) or TCP (port 9201)*/ p = cfg_get(grp, octstr_imm("connection")); if (p != NULL) { if (strcasecmp(octstr_get_cstr(p), "temp") == 0) connection = WBXML_TOK_VALUE_PORT_9200; else connection = WBXML_TOK_VALUE_PORT_9201; octstr_destroy(p); } /* dial in security: CHAP or PAP */ p = cfg_get(grp, octstr_imm("pppsecurity")); if (p != NULL) { if (strcasecmp(octstr_get_cstr(p), "on") == 0) authent = WBXML_TOK_VALUE_AUTH_CHAP; else authent = WBXML_TOK_VALUE_AUTH_PAP; octstr_destroy(p); } /* WTLS: for UDP (port 9202) or TCP (port 9203) */ p = cfg_get(grp, octstr_imm("authentication")); if (p != NULL) { if (strcasecmp(octstr_get_cstr(p), "secure") == 0) security = 1; else security = WBXML_TOK_VALUE_PORT_9201; octstr_destroy(p); } if (security == 1) connection = (connection == WBXML_TOK_VALUE_PORT_9201)? WBXML_TOK_VALUE_PORT_9203 : WBXML_TOK_VALUE_PORT_9202; username = cfg_get(grp, octstr_imm("login")); passwd = cfg_get(grp, octstr_imm("secret")); msg = msg_create(sms); /* * Append the User Data Header (UDH) including the length (UDHL) * WDP layer (start WDP headers) */ msg->sms.sms_type = mt_push; msg->sms.udhdata = octstr_create(""); /* * Within OTA spec this is "0B0504C34FC0020003040201", but it works * with the following too?! */ octstr_append_from_hex(msg->sms.udhdata, "060504C34FC002"); /* WDP layer (end WDP headers) */ /* * WSP layer (start WSP headers) */ msg->sms.msgdata = octstr_create(""); /* PUSH ID, PDU type, header length, value length */ octstr_append_from_hex(msg->sms.msgdata, "01062C1F2A"); /* MIME-type: application/x-wap-prov.browser-settings */ octstr_format_append(msg->sms.msgdata, "%s", "application/x-wap-prov.browser-settings"); octstr_append_from_hex(msg->sms.msgdata, "00"); /* charset UTF-8 */ octstr_append_from_hex(msg->sms.msgdata, "81EA"); /* WSP layer (end WSP headers) */ /* * WSP layer (start WSP data field) */ /* WBXML version 1.1 */ octstr_append_from_hex(msg->sms.msgdata, "0101"); /* charset UTF-8 */ octstr_append_from_hex(msg->sms.msgdata, "6A00"); /* CHARACTERISTIC_LIST */ octstr_append_from_hex(msg->sms.msgdata, "45"); /* CHARACTERISTIC with content and attributes */ octstr_append_from_hex(msg->sms.msgdata, "C6"); /* TYPE=ADDRESS */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_TYPE_ADDRESS); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* bearer type */ if (bearer != -1) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=BEARER, VALUE=GSM_CSD */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_BEARER); octstr_append_char(msg->sms.msgdata, bearer); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* IP address */ if (ipaddr != NULL) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=PROXY, VALUE, inline string */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_PROXY); octstr_append_char(msg->sms.msgdata, WBXML_TOK_VALUE); octstr_append_char(msg->sms.msgdata, WBXML_TOK_STR_I); octstr_append(msg->sms.msgdata, octstr_duplicate(ipaddr)); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END_STR_I); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* connection type */ if (connection != -1) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=PORT, VALUE */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_PORT); octstr_append_char(msg->sms.msgdata, connection); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* phone number */ if (phonenum != NULL) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=CSD_DIALSTRING, VALUE, inline string */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_CSD_DIALSTRING); octstr_append_char(msg->sms.msgdata, WBXML_TOK_VALUE); octstr_append_char(msg->sms.msgdata, WBXML_TOK_STR_I); octstr_append(msg->sms.msgdata, octstr_duplicate(phonenum)); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END_STR_I); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* authentication */ /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=PPP_AUTHTYPE, VALUE */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_PPP_AUTHTYPE); octstr_append_char(msg->sms.msgdata, authent); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* user name */ if (username != NULL) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=PPP_AUTHNAME, VALUE, inline string */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_PPP_AUTHNAME); octstr_append_char(msg->sms.msgdata, WBXML_TOK_VALUE); octstr_append_char(msg->sms.msgdata, WBXML_TOK_STR_I); octstr_append(msg->sms.msgdata, octstr_duplicate(username)); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END_STR_I); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* password */ if (passwd != NULL) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=PPP_AUTHSECRET, VALUE, inline string */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_PPP_AUTHSECRET); octstr_append_char(msg->sms.msgdata, WBXML_TOK_VALUE); octstr_append_char(msg->sms.msgdata, WBXML_TOK_STR_I); octstr_append(msg->sms.msgdata, octstr_duplicate(passwd)); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END_STR_I); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* data call type */ if (calltype != -1) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=CSD_CALLTYPE, VALUE */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_CSD_CALLTYPE); octstr_append_char(msg->sms.msgdata, calltype); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* speed */ /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=CSD_CALLSPEED, VALUE */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_CSD_CALLSPEED); octstr_append_char(msg->sms.msgdata, speed); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* end CHARACTERISTIC TYPE=ADDRESS */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* homepage */ if (url != NULL) { /* CHARACTERISTIC with attributes */ octstr_append_from_hex(msg->sms.msgdata, "86"); /* TYPE=URL */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_TYPE_URL); octstr_append_char(msg->sms.msgdata, WBXML_TOK_VALUE); octstr_append_char(msg->sms.msgdata, WBXML_TOK_STR_I); octstr_append(msg->sms.msgdata, url); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END_STR_I); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* CHARACTERISTIC with content and attributes */ octstr_append_from_hex(msg->sms.msgdata, "C6"); /* TYPE=NAME */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_TYPE_NAME); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* service description */ if (desc != NULL) { /* PARAM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=NAME, VALUE, inline */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_NAME); octstr_append_char(msg->sms.msgdata, WBXML_TOK_VALUE); octstr_append_char(msg->sms.msgdata, WBXML_TOK_STR_I); octstr_append(msg->sms.msgdata, desc); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END_STR_I); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* end of CHARACTERISTIC */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* end of CHARACTERISTIC-LIST */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* WSP layer (end WSP data field) */ msg->sms.sender = from; msg->sms.receiver = octstr_duplicate(receiver); msg->sms.coding = DC_8BIT; msg->sms.time = time(NULL); octstr_destroy(url); octstr_destroy(desc); octstr_destroy(ipaddr); octstr_destroy(phonenum); octstr_destroy(username); octstr_destroy(passwd); return msg; } Msg *ota_tokenize_bookmarks(CfgGroup *grp, Octstr *from, Octstr *receiver) { Octstr *url, *name; Msg *msg; url = NULL; name = NULL; url = cfg_get(grp, octstr_imm("url")); name = cfg_get(grp, octstr_imm("name")); msg = msg_create(sms); /* * Append the User Data Header (UDH) including the length (UDHL) * WDP layer (start WDP headers) */ msg->sms.sms_type = mt_push; msg->sms.udhdata = octstr_create(""); octstr_append_from_hex(msg->sms.udhdata, "060504C34FC002"); /* WDP layer (end WDP headers) */ /* * WSP layer (start WSP headers) */ msg->sms.msgdata = octstr_create(""); /* PUSH ID, PDU type, header length, value length */ octstr_append_from_hex(msg->sms.msgdata, "01062D1F2B"); /* MIME-type: application/x-wap-prov.browser-bookmarks */ octstr_format_append(msg->sms.msgdata, "%s", "application/x-wap-prov.browser-bookmarks"); octstr_append_from_hex(msg->sms.msgdata, "00"); /* charset UTF-8 */ octstr_append_from_hex(msg->sms.msgdata, "81EA"); /* WSP layer (end WSP headers) */ /* * WSP layer (start WSP data field) */ /* WBXML version 1.1 */ octstr_append_from_hex(msg->sms.msgdata, "0101"); /* charset UTF-8 */ octstr_append_from_hex(msg->sms.msgdata, "6A00"); /* CHARACTERISTIC_LIST */ octstr_append_from_hex(msg->sms.msgdata, "45"); /* CHARACTERISTIC with content and attributes */ octstr_append_from_hex(msg->sms.msgdata, "C6"); /* TYPE=BOOKMARK */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_TYPE_BOOKMARK); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* name */ if (name != NULL) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=PROXY, VALUE, inline string */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_NAME); octstr_append_char(msg->sms.msgdata, WBXML_TOK_VALUE); octstr_append_char(msg->sms.msgdata, WBXML_TOK_STR_I); octstr_append(msg->sms.msgdata, octstr_duplicate(name)); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END_STR_I); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* URL */ if (url != NULL) { /* PARM with attributes */ octstr_append_from_hex(msg->sms.msgdata, "87"); /* NAME=PROXY, VALUE, inline string */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_NAME_URL); octstr_append_char(msg->sms.msgdata, WBXML_TOK_VALUE); octstr_append_char(msg->sms.msgdata, WBXML_TOK_STR_I); octstr_append(msg->sms.msgdata, octstr_duplicate(url)); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END_STR_I); octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); } /* end of CHARACTERISTIC */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* end of CHARACTERISTIC-LIST */ octstr_append_char(msg->sms.msgdata, WBXML_TOK_END); /* WSP layer (end WSP data field) */ msg->sms.sender = from; msg->sms.receiver = octstr_duplicate(receiver); msg->sms.coding = DC_8BIT; msg->sms.time = time(NULL); octstr_destroy(name); octstr_destroy(url); return msg; } gateway-1.4.5/gw/meta_data.h0000644000175000017500000000747413227613126014410 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * meta_data.h * * Meta Data manupilation. * * Alexander Malysh , 2007-2009 */ #ifndef META_DATA_H #define META_DATA_H #define METADATA_DLR_GROUP "dlr" #define METADATA_DLR_GROUP_DONETIME "donetime" #define METADATA_DLR_GROUP_SUBMITTIME "submittime" #define METADATA_DLR_GROUP_ERRORCODE "errorcode" #define METADATA_ORIG_MSG_GROUP "orig_msg" #define METADATA_ORIG_MSG_GROUP_DLR_MASK "dlr_mask" #define METADATA_SMPP_GROUP "smpp" /** * Get Dictionary with all values for this group. */ Dict *meta_data_get_values(const Octstr *data, const char *group); /** * Replace Dictionary for the given group. */ int meta_data_set_values(Octstr *data, const Dict *dict, const char *group, int replace); /** * Set or replace value for a given group and key. */ int meta_data_set_value(Octstr *data, const char *group, const Octstr *key, const Octstr *value, int replace); /** * Get value for a given group and key. */ Octstr *meta_data_get_value(Octstr *data, const char *group, const Octstr *key); /** * Merge two meta data strings into one */ Octstr *meta_data_merge(const Octstr *data, const Octstr *new_data, int replace); #endif gateway-1.4.5/gw/dlr_mem.c0000644000175000017500000001470613227613126014077 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/dlr_mem.c * * Implementation of handling delivery reports (DLRs) * in memory * * Andreas Fink , 18.08.2001 * Stipe Tolj , 22.03.2002 * Alexander Malysh 2003 */ #include "gwlib/gwlib.h" #include "dlr_p.h" /* * This is the global list where all messages being sent out are being kept track * of his list is looked up once a delivery report comes in */ static List *dlr_waiting_list; static RWLock rwlock; /* * Destroy dlr_waiting_list. */ static void dlr_mem_shutdown() { gw_rwlock_wrlock(&rwlock); gwlist_destroy(dlr_waiting_list, (gwlist_item_destructor_t *)dlr_entry_destroy); gw_rwlock_unlock(&rwlock); gw_rwlock_destroy(&rwlock); } /* * Get count of dlr messages waiting. */ static long dlr_mem_messages(void) { return gwlist_len(dlr_waiting_list); } static void dlr_mem_flush(void) { long i; long len; gw_rwlock_wrlock(&rwlock); len = gwlist_len(dlr_waiting_list); for (i = 0; i < len; i++) { struct dlr_entry *dlr = gwlist_get(dlr_waiting_list, 0); gwlist_delete(dlr_waiting_list, 0, 1); dlr_entry_destroy(dlr); } gw_rwlock_unlock(&rwlock); } /* * add struct dlr_entry to list */ static void dlr_mem_add(struct dlr_entry *dlr) { gw_rwlock_wrlock(&rwlock); gwlist_append(dlr_waiting_list,dlr); gw_rwlock_unlock(&rwlock); } /* * Private compare function * Return 0 if entry match and 1 if not. */ static int dlr_mem_entry_match(struct dlr_entry *dlr, const Octstr *smsc, const Octstr *ts, const Octstr *dst) { /* XXX: check destination addr too, because e.g. for UCP is not enough to check only * smsc and timestamp (timestamp is even without milliseconds) */ if (dst){ long pos = octstr_len(dlr->destination) - octstr_len(dst); if (pos < 0) return 1; if (octstr_compare(dlr->smsc, smsc) == 0 && octstr_compare(dlr->timestamp, ts) == 0 && octstr_search(dlr->destination, dst, pos) != -1) return 0; } else if (octstr_compare(dlr->smsc, smsc) == 0 && octstr_compare(dlr->timestamp, ts) == 0) return 0; return 1; } /* * Find matching entry and return copy of it, otherwise NULL */ static struct dlr_entry *dlr_mem_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { long i; long len; struct dlr_entry *dlr = NULL, *ret = NULL; gw_rwlock_rdlock(&rwlock); len = gwlist_len(dlr_waiting_list); for (i=0; i < len; i++) { dlr = gwlist_get(dlr_waiting_list, i); if (dlr_mem_entry_match(dlr, smsc, ts, dst) == 0) { ret = dlr_entry_duplicate(dlr); break; } } gw_rwlock_unlock(&rwlock); /* we couldnt find a matching entry */ return ret; } /* * Remove matching entry */ static void dlr_mem_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { long i; long len; struct dlr_entry *dlr = NULL; gw_rwlock_wrlock(&rwlock); len = gwlist_len(dlr_waiting_list); for (i=0; i < len; i++) { dlr = gwlist_get(dlr_waiting_list, i); if (dlr_mem_entry_match(dlr, smsc, ts, dst) == 0) { gwlist_delete(dlr_waiting_list, i, 1); dlr_entry_destroy(dlr); break; } } gw_rwlock_unlock(&rwlock); } static struct dlr_storage handles = { .type = "internal", .dlr_add = dlr_mem_add, .dlr_get = dlr_mem_get, .dlr_remove = dlr_mem_remove, .dlr_shutdown = dlr_mem_shutdown, .dlr_messages = dlr_mem_messages, .dlr_flush = dlr_mem_flush }; /* * Initialize dlr_waiting_list and return out storage handles. */ struct dlr_storage *dlr_init_mem(Cfg *cfg) { dlr_waiting_list = gwlist_create(); gw_rwlock_init_static(&rwlock); return &handles; } gateway-1.4.5/gw/bb_boxc.c0000644000175000017500000014645313227613126014063 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * bb_boxc.c : bearerbox box connection module * * handles start/restart/stop/suspend/die operations of the sms and * wapbox connections * * Kalle Marjola 2000 for project Kannel * Alexander Malysh (various fixes) */ #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "msg.h" #include "bearerbox.h" #include "bb_smscconn_cb.h" #define SMSBOX_MAX_PENDING 100 /* passed from bearerbox core */ extern volatile sig_atomic_t bb_status; extern volatile sig_atomic_t restart; extern List *incoming_sms; extern List *outgoing_sms; extern List *incoming_wdp; extern List *outgoing_wdp; extern List *flow_threads; extern List *suspended; /* incoming/outgoing sms queue control */ extern long max_incoming_sms_qlength; /* our own thingies */ static volatile sig_atomic_t smsbox_running; static volatile sig_atomic_t wapbox_running; static List *wapbox_list; static List *smsbox_list; static RWLock *smsbox_list_rwlock; /* dictionaries for holding the smsbox routing information */ static Dict *smsbox_by_id; static Dict *smsbox_by_smsc; static Dict *smsbox_by_receiver; static Dict *smsbox_by_smsc_receiver; static long smsbox_port; static int smsbox_port_ssl; static Octstr *smsbox_interface; static long wapbox_port; static int wapbox_port_ssl; /* max pending messages on the line to smsbox */ static long smsbox_max_pending; static Octstr *box_allow_ip; static Octstr *box_deny_ip; static Counter *boxid; /* sms_to_smsboxes thread-id */ static long sms_dequeue_thread; typedef struct _boxc { Connection *conn; int is_wap; long id; int load; time_t connect_time; Octstr *client_ip; List *incoming; List *retry; /* If sending fails */ List *outgoing; Dict *sent; Semaphore *pending; volatile sig_atomic_t alive; Octstr *boxc_id; /* identifies the connected smsbox instance */ /* used to mark connection usable or still waiting for ident. msg */ volatile int routable; } Boxc; /* forward declaration */ static void sms_to_smsboxes(void *arg); static int send_msg(Boxc *boxconn, Msg *pmsg); static void boxc_sent_push(Boxc*, Msg*); static void boxc_sent_pop(Boxc*, Msg*, Msg**); static void boxc_gwlist_destroy(List *list); /*------------------------------------------------- * receiver thingies */ static Msg *read_from_box(Boxc *boxconn) { int ret; Octstr *pack; Msg *msg; pack = NULL; while (bb_status != BB_DEAD && boxconn->alive) { /* XXX: if box doesn't send (just keep conn open) we block here while shutdown */ pack = conn_read_withlen(boxconn->conn); gw_claim_area(pack); if (pack != NULL) break; if (conn_error(boxconn->conn)) { info(0, "Read error when reading from box <%s>, disconnecting", octstr_get_cstr(boxconn->client_ip)); return NULL; } if (conn_eof(boxconn->conn)) { info(0, "Connection closed by the box <%s>", octstr_get_cstr(boxconn->client_ip)); return NULL; } ret = conn_wait(boxconn->conn, -1.0); if (ret < 0) { error(0, "Connection to box <%s> broke.", octstr_get_cstr(boxconn->client_ip)); return NULL; } } if (pack == NULL) return NULL; msg = msg_unpack(pack); octstr_destroy(pack); if (msg == NULL) error(0, "Failed to unpack data!"); return msg; } /* * Try to deliver message to internal or smscconn queue * and generate ack/nack for smsbox connections. */ static void deliver_sms_to_queue(Msg *msg, Boxc *conn) { Msg *mack; int rc; /* * save modifies ID and time, so if the smsbox uses it, save * it FIRST for the reply message!!! */ mack = msg_create(ack); gw_assert(mack != NULL); uuid_copy(mack->ack.id, msg->sms.id); mack->ack.time = msg->sms.time; store_save(msg); rc = smsc2_rout(msg, 0); switch (rc) { case SMSCCONN_SUCCESS: mack->ack.nack = ack_success; break; case SMSCCONN_QUEUED: mack->ack.nack = ack_buffered; break; case SMSCCONN_FAILED_DISCARDED: /* no router at all */ warning(0, "Message rejected by bearerbox, no router!"); /* * we don't store_save_ack() here, since the call to * bb_smscconn_send_failed() within smsc2_route() did * it already. */ mack->ack.nack = ack_failed; /* destroy original message */ msg_destroy(msg); break; case SMSCCONN_FAILED_QFULL: /* queue full */ warning(0, "Message rejected by bearerbox, %s!", (rc == SMSCCONN_FAILED_DISCARDED) ? "no router" : "queue full"); /* * first create nack for store-file, in order to delete * message from store-file. */ mack->ack.nack = ack_failed_tmp; store_save_ack(msg, ack_failed_tmp); /* destroy original message */ msg_destroy(msg); break; case SMSCCONN_FAILED_EXPIRED: /* validity expired */ warning(0, "Message rejected by bearerbox, validity expired!"); /* * we don't store_save_ack() here, since the call to * bb_smscconn_send_failed() within smsc2_route() did * it already. */ mack->ack.nack = ack_failed; /* destroy original message */ msg_destroy(msg); break; case SMSCCONN_FAILED_REJECTED: /* white/black-list rejection */ warning(0, "Message rejected by bearerbox, white/black listed!"); mack->ack.nack = ack_failed; /* destroy original message */ msg_destroy(msg); break; default: break; } /* put ack into incoming queue of conn */ send_msg(conn, mack); msg_destroy(mack); } static void boxc_receiver(void *arg) { Boxc *conn = arg; Msg *msg, *mack; /* remove messages from socket until it is closed */ while (bb_status != BB_DEAD && conn->alive) { gwlist_consume(suspended); /* block here if suspended */ msg = read_from_box(conn); if (msg == NULL) { /* garbage/connection lost */ conn->alive = 0; break; } /* we don't accept new messages in shutdown phase */ if ((bb_status == BB_SHUTDOWN || bb_status == BB_DEAD) && msg_type(msg) == sms) { mack = msg_create(ack); uuid_copy(mack->ack.id, msg->sms.id); mack->ack.time = msg->sms.time; mack->ack.nack = ack_failed_tmp; msg_destroy(msg); send_msg(conn, mack); msg_destroy(mack); continue; } if (msg_type(msg) == sms && conn->is_wap == 0) { debug("bb.boxc", 0, "boxc_receiver: sms received"); /* deliver message to queue */ deliver_sms_to_queue(msg, conn); if (conn->routable == 0) { conn->routable = 1; /* wakeup the dequeue thread */ gwthread_wakeup(sms_dequeue_thread); } } else if (msg_type(msg) == wdp_datagram && conn->is_wap) { debug("bb.boxc", 0, "boxc_receiver: got wdp from wapbox"); /* XXX we should block these in SHUTDOWN phase too, but we need ack/nack msgs implemented first. */ gwlist_produce(conn->outgoing, msg); } else if (msg_type(msg) == sms && conn->is_wap) { debug("bb.boxc", 0, "boxc_receiver: got sms from wapbox"); /* should be a WAP push message, so tried it the same way */ deliver_sms_to_queue(msg, conn); if (conn->routable == 0) { conn->routable = 1; /* wakeup the dequeue thread */ gwthread_wakeup(sms_dequeue_thread); } } else { if (msg_type(msg) == heartbeat) { if (msg->heartbeat.load != conn->load) debug("bb.boxc", 0, "boxc_receiver: heartbeat with " "load value %ld received", msg->heartbeat.load); conn->load = msg->heartbeat.load; } else if (msg_type(msg) == ack) { if (msg->ack.nack == ack_failed_tmp) { Msg *orig; boxc_sent_pop(conn, msg, &orig); if (orig != NULL) /* retry this message */ gwlist_append(conn->retry, orig); } else { boxc_sent_pop(conn, msg, NULL); store_save(msg); } debug("bb.boxc", 0, "boxc_receiver: got ack"); } /* if this is an identification message from an smsbox instance */ else if (msg_type(msg) == admin && msg->admin.command == cmd_identify) { /* * any smsbox sends this command even if boxc_id is NULL, * but we will only consider real identified boxes */ if (msg->admin.boxc_id != NULL) { /* Only interested if the connection is not named, or its a different name */ if (conn->boxc_id == NULL || octstr_compare(conn->boxc_id, msg->admin.boxc_id)) { List *boxc_id_list = NULL; /* * Different name, need to remove it from the old list. * * I Don't think this case should ever arise, but might as well * be safe. */ if (conn->boxc_id != NULL) { /* Get the list for this box id */ boxc_id_list = dict_get(smsbox_by_id, conn->boxc_id); /* Delete the connection from the list */ if (boxc_id_list != NULL) { gwlist_delete_equal(boxc_id_list, conn); } octstr_destroy(conn->boxc_id); } /* Get the list for this box id */ boxc_id_list = dict_get(smsbox_by_id, msg->admin.boxc_id); /* No list yet, so create it */ if (boxc_id_list == NULL) { boxc_id_list = gwlist_create(); if (!dict_put_once(smsbox_by_id, msg->admin.boxc_id, boxc_id_list)) /* list already added */ boxc_id_list = dict_get(smsbox_by_id, msg->admin.boxc_id); } /* Add the connection into the list */ gwlist_append(boxc_id_list, conn); conn->boxc_id = msg->admin.boxc_id; } else { octstr_destroy(msg->admin.boxc_id); } msg->admin.boxc_id = NULL; debug("bb.boxc", 0, "boxc_receiver: got boxc_id <%s> from <%s>", octstr_get_cstr(conn->boxc_id), octstr_get_cstr(conn->client_ip)); } conn->routable = 1; /* wakeup the dequeue thread */ gwthread_wakeup(sms_dequeue_thread); } else warning(0, "boxc_receiver: unknown msg received from <%s>, " "ignored", octstr_get_cstr(conn->client_ip)); msg_destroy(msg); } } } /*--------------------------------------------- * sender thingies */ static int send_msg(Boxc *boxconn, Msg *pmsg) { Octstr *pack; pack = msg_pack(pmsg); if (pack == NULL) return -1; if (boxconn->boxc_id != NULL) debug("bb.boxc", 0, "send_msg: sending msg to boxc: <%s>", octstr_get_cstr(boxconn->boxc_id)); else debug("bb.boxc", 0, "send_msg: sending msg to box: <%s>", octstr_get_cstr(boxconn->client_ip)); if (conn_write_withlen(boxconn->conn, pack) == -1) { error(0, "Couldn't write Msg to box <%s>, disconnecting", octstr_get_cstr(boxconn->client_ip)); octstr_destroy(pack); return -1; } octstr_destroy(pack); return 0; } static void boxc_sent_push(Boxc *conn, Msg *m) { Octstr *os; char id[UUID_STR_LEN + 1]; if (conn->is_wap || !conn->sent || !m || msg_type(m) != sms) return; uuid_unparse(m->sms.id, id); os = octstr_create(id); dict_put(conn->sent, os, msg_duplicate(m)); semaphore_down(conn->pending); octstr_destroy(os); } /* * Remove msg from sent queue. * Return 0 if message should be deleted from store and 1 if not (e.g. tmp nack) */ static void boxc_sent_pop(Boxc *conn, Msg *m, Msg **orig) { Octstr *os; char id[UUID_STR_LEN + 1]; Msg *msg; if (conn->is_wap || !conn->sent || !m || (msg_type(m) != ack && msg_type(m) != sms)) return; if (orig != NULL) *orig = NULL; uuid_unparse((msg_type(m) == sms ? m->sms.id : m->ack.id), id); os = octstr_create(id); msg = dict_remove(conn->sent, os); octstr_destroy(os); if (!msg) { error(0, "BOXC: Got ack for nonexistend message!"); msg_dump(m, 0); return; } semaphore_up(conn->pending); if (orig == NULL) msg_destroy(msg); else *orig = msg; } static void boxc_sender(void *arg) { Msg *msg; Boxc *conn = arg; gwlist_add_producer(flow_threads); while (bb_status != BB_DEAD && conn->alive) { /* * Make sure there's no data left in the outgoing connection before * doing the potentially blocking gwlist_consume()s */ conn_flush(conn->conn); gwlist_consume(suspended); /* block here if suspended */ if ((msg = gwlist_consume(conn->incoming)) == NULL) { /* tell sms/wapbox to die */ msg = msg_create(admin); msg->admin.command = restart ? cmd_restart : cmd_shutdown; send_msg(conn, msg); msg_destroy(msg); break; } if (msg_type(msg) == heartbeat) { debug("bb.boxc", 0, "boxc_sender: catch an heartbeat - we are alive"); msg_destroy(msg); continue; } boxc_sent_push(conn, msg); if (!conn->alive || send_msg(conn, msg) == -1) { /* we got message here */ boxc_sent_pop(conn, msg, NULL); gwlist_produce(conn->retry, msg); break; } msg_destroy(msg); debug("bb.boxc", 0, "boxc_sender: sent message to <%s>", octstr_get_cstr(conn->client_ip)); } /* the client closes the connection, after that die in receiver */ /* conn->alive = 0; */ /* set conn to unroutable */ conn->routable = 0; gwlist_remove_producer(flow_threads); } /*--------------------------------------------------------------- * accept/create/kill thingies */ static Boxc *boxc_create(int fd, Octstr *ip, int ssl) { Boxc *boxc; boxc = gw_malloc(sizeof(Boxc)); boxc->is_wap = 0; boxc->load = 0; boxc->conn = conn_wrap_fd(fd, ssl); boxc->id = counter_increase(boxid); boxc->client_ip = ip; boxc->alive = 1; boxc->connect_time = time(NULL); boxc->boxc_id = NULL; boxc->routable = 0; return boxc; } static void boxc_destroy(Boxc *boxc) { if (boxc == NULL) return; /* do nothing to the lists, as they are only references */ if (boxc->conn) conn_destroy(boxc->conn); octstr_destroy(boxc->client_ip); octstr_destroy(boxc->boxc_id); gw_free(boxc); } static Boxc *accept_boxc(int fd, int ssl) { Boxc *newconn; Octstr *ip; int newfd; struct sockaddr_in client_addr; socklen_t client_addr_len; client_addr_len = sizeof(client_addr); newfd = accept(fd, (struct sockaddr *)&client_addr, &client_addr_len); if (newfd < 0) return NULL; ip = host_ip(client_addr); if (is_allowed_ip(box_allow_ip, box_deny_ip, ip) == 0) { info(0, "Box connection tried from denied host <%s>, disconnected", octstr_get_cstr(ip)); octstr_destroy(ip); close(newfd); return NULL; } newconn = boxc_create(newfd, ip, ssl); /* * check if the SSL handshake was successfull, otherwise * this is no valid box connection any more */ #ifdef HAVE_LIBSSL if (ssl && !conn_get_ssl(newconn->conn)) return NULL; #endif info(0, "Client connected from <%s> %s", octstr_get_cstr(ip), ssl?"using SSL":""); /* XXX TODO: do the hand-shake, baby, yeah-yeah! */ return newconn; } static void run_smsbox(void *arg) { Boxc *newconn; long sender; Msg *msg; List *keys; Octstr *key; gwlist_add_producer(flow_threads); newconn = arg; newconn->incoming = gwlist_create(); gwlist_add_producer(newconn->incoming); newconn->retry = incoming_sms; newconn->outgoing = outgoing_sms; newconn->sent = dict_create(smsbox_max_pending, NULL); newconn->pending = semaphore_create(smsbox_max_pending); sender = gwthread_create(boxc_sender, newconn); if (sender == -1) { error(0, "Failed to start a new thread, disconnecting client <%s>", octstr_get_cstr(newconn->client_ip)); goto cleanup; } /* * We register newconn in the smsbox_list here but mark newconn as routable * after identification or first message received from smsbox. So we can avoid * a race condition for routable smsboxes (otherwise between startup and * registration we will forward some messages to smsbox). */ gw_rwlock_wrlock(smsbox_list_rwlock); gwlist_append(smsbox_list, newconn); gw_rwlock_unlock(smsbox_list_rwlock); gwlist_add_producer(newconn->outgoing); boxc_receiver(newconn); gwlist_remove_producer(newconn->outgoing); /* remove us from smsbox routing list */ gw_rwlock_wrlock(smsbox_list_rwlock); gwlist_delete_equal(smsbox_list, newconn); if (newconn->boxc_id) { /* Get the list, and remove the connection from it */ List *boxc_id_list = dict_get(smsbox_by_id, newconn->boxc_id); if(boxc_id_list != NULL) { gwlist_delete_equal(boxc_id_list, newconn); } } gw_rwlock_unlock(smsbox_list_rwlock); /* * check if we in the shutdown phase and sms dequeueing thread * has removed the producer already */ if (gwlist_producer_count(newconn->incoming) > 0) gwlist_remove_producer(newconn->incoming); /* check if we are still waiting for ack's and semaphore locked */ if (dict_key_count(newconn->sent) >= smsbox_max_pending) semaphore_up(newconn->pending); /* allow sender to go down */ gwthread_join(sender); /* put not acked msgs into incoming queue */ keys = dict_keys(newconn->sent); while((key = gwlist_extract_first(keys)) != NULL) { msg = dict_remove(newconn->sent, key); gwlist_produce(incoming_sms, msg); octstr_destroy(key); } gw_assert(gwlist_len(keys) == 0); gwlist_destroy(keys, octstr_destroy_item); /* clear our send queue */ while((msg = gwlist_extract_first(newconn->incoming)) != NULL) { gwlist_produce(incoming_sms, msg); } cleanup: gw_assert(gwlist_len(newconn->incoming) == 0); gwlist_destroy(newconn->incoming, NULL); gw_assert(dict_key_count(newconn->sent) == 0); dict_destroy(newconn->sent); semaphore_destroy(newconn->pending); boxc_destroy(newconn); /* wakeup the dequeueing thread */ gwthread_wakeup(sms_dequeue_thread); gwlist_remove_producer(flow_threads); } static void run_wapbox(void *arg) { Boxc *newconn; List *newlist; long sender; gwlist_add_producer(flow_threads); newconn = arg; newconn->is_wap = 1; /* * create a new incoming list for just that box, * and add it to list of list pointers, so we can start * to route messages to it. */ debug("bb", 0, "setting up systems for new wapbox"); newlist = gwlist_create(); /* this is released by the sender/receiver if it exits */ gwlist_add_producer(newlist); newconn->incoming = newlist; newconn->retry = incoming_wdp; newconn->outgoing = outgoing_wdp; sender = gwthread_create(boxc_sender, newconn); if (sender == -1) { error(0, "Failed to start a new thread, disconnecting client <%s>", octstr_get_cstr(newconn->client_ip)); goto cleanup; } gwlist_append(wapbox_list, newconn); gwlist_add_producer(newconn->outgoing); boxc_receiver(newconn); /* cleanup after receiver has exited */ gwlist_remove_producer(newconn->outgoing); gwlist_lock(wapbox_list); gwlist_delete_equal(wapbox_list, newconn); gwlist_unlock(wapbox_list); while (gwlist_producer_count(newlist) > 0) gwlist_remove_producer(newlist); newconn->alive = 0; gwthread_join(sender); cleanup: gw_assert(gwlist_len(newlist) == 0); gwlist_destroy(newlist, NULL); boxc_destroy(newconn); gwlist_remove_producer(flow_threads); } /*------------------------------------------------ * main single thread functions */ typedef struct _addrpar { Octstr *address; int port; int wapboxid; } AddrPar; static void ap_destroy(AddrPar *addr) { octstr_destroy(addr->address); gw_free(addr); } static int cmp_route(void *ap, void *ms) { AddrPar *addr = ap; Msg *msg = ms; if (msg->wdp_datagram.source_port == addr->port && octstr_compare(msg->wdp_datagram.source_address, addr->address)==0) return 1; return 0; } static int cmp_boxc(void *bc, void *ap) { Boxc *boxc = bc; AddrPar *addr = ap; if (boxc->id == addr->wapboxid) return 1; return 0; } static Boxc *route_msg(List *route_info, Msg *msg) { AddrPar *ap; Boxc *conn, *best; int i, b, len; ap = gwlist_search(route_info, msg, cmp_route); if (ap == NULL) { debug("bb.boxc", 0, "Did not find previous routing info for WDP, " "generating new"); route: if (gwlist_len(wapbox_list) == 0) return NULL; gwlist_lock(wapbox_list); /* take random wapbox from list, and then check all wapboxes * and select the one with lowest load level - if tied, the first * one */ len = gwlist_len(wapbox_list); b = gw_rand() % len; best = gwlist_get(wapbox_list, b); for(i = 0; i < gwlist_len(wapbox_list); i++) { conn = gwlist_get(wapbox_list, (i+b) % len); if (conn != NULL && best != NULL) if (conn->load < best->load) best = conn; } if (best == NULL) { warning(0, "wapbox_list empty!"); gwlist_unlock(wapbox_list); return NULL; } conn = best; conn->load++; /* simulate new client until we get new values */ ap = gw_malloc(sizeof(AddrPar)); ap->address = octstr_duplicate(msg->wdp_datagram.source_address); ap->port = msg->wdp_datagram.source_port; ap->wapboxid = conn->id; gwlist_produce(route_info, ap); gwlist_unlock(wapbox_list); } else conn = gwlist_search(wapbox_list, ap, cmp_boxc); if (conn == NULL) { /* routing failed; wapbox has disappeared! * ..remove routing info and re-route */ debug("bb.boxc", 0, "Old wapbox has disappeared, re-routing"); gwlist_delete_equal(route_info, ap); ap_destroy(ap); goto route; } return conn; } /* * this thread listens to incoming_wdp list * and then routs messages to proper wapbox */ static void wdp_to_wapboxes(void *arg) { List *route_info; AddrPar *ap; Boxc *conn; Msg *msg; int i; gwlist_add_producer(flow_threads); gwlist_add_producer(wapbox_list); route_info = gwlist_create(); while(bb_status != BB_DEAD) { gwlist_consume(suspended); /* block here if suspended */ if ((msg = gwlist_consume(incoming_wdp)) == NULL) break; gw_assert(msg_type(msg) == wdp_datagram); conn = route_msg(route_info, msg); if (conn == NULL) { warning(0, "Cannot route message, discard it"); msg_destroy(msg); continue; } gwlist_produce(conn->incoming, msg); } debug("bb", 0, "wdp_to_wapboxes: destroying lists"); while((ap = gwlist_extract_first(route_info)) != NULL) ap_destroy(ap); gw_assert(gwlist_len(route_info) == 0); gwlist_destroy(route_info, NULL); gwlist_lock(wapbox_list); for(i=0; i < gwlist_len(wapbox_list); i++) { conn = gwlist_get(wapbox_list, i); gwlist_remove_producer(conn->incoming); conn->alive = 0; } gwlist_unlock(wapbox_list); gwlist_remove_producer(wapbox_list); gwlist_remove_producer(flow_threads); } static void wait_for_connections(int fd, void (*function) (void *arg), List *waited, int ssl) { int ret; int timeout = 10; /* 10 sec. */ gw_assert(function != NULL); while(bb_status != BB_DEAD) { /* if we are being shutdowned, as long as there is * messages in incoming list allow new connections, but when * list is empty, exit. * Note: We have timeout (defined above) for which we allow new connections. * Otherwise we wait here for ever! */ if (bb_status == BB_SHUTDOWN) { ret = gwlist_wait_until_nonempty(waited); if (ret == -1 || !timeout) break; else timeout--; } /* block here if suspended */ gwlist_consume(suspended); ret = gwthread_pollfd(fd, POLLIN, 1.0); if (ret > 0) { Boxc *newconn = accept_boxc(fd, ssl); if (newconn != NULL) { gwthread_create(function, newconn); gwthread_sleep(1.0); } else { error(0, "Failed to create new boxc connection."); } } else if (ret < 0 && errno != EINTR && errno != EAGAIN) error(errno, "bb_boxc::wait_for_connections failed"); } } static void smsboxc_run(void *arg) { int fd; gwlist_add_producer(flow_threads); gwthread_wakeup(MAIN_THREAD_ID); fd = make_server_socket(smsbox_port, smsbox_interface ? octstr_get_cstr(smsbox_interface) : NULL); /* XXX add interface_name if required */ if (fd < 0) { panic(0, "Could not open smsbox port %ld", smsbox_port); } /* * infinitely wait for new connections; * to shut down the system, SIGTERM is send and then * select drops with error, so we can check the status */ wait_for_connections(fd, run_smsbox, incoming_sms, smsbox_port_ssl); gwlist_remove_producer(smsbox_list); /* continue avalanche */ gwlist_remove_producer(outgoing_sms); /* all connections do the same, so that all must remove() before it * is completely over */ while(gwlist_wait_until_nonempty(smsbox_list) == 1) gwthread_sleep(1.0); /* close listen socket */ close(fd); gwthread_wakeup(sms_dequeue_thread); gwthread_join(sms_dequeue_thread); gwlist_destroy(smsbox_list, NULL); smsbox_list = NULL; gw_rwlock_destroy(smsbox_list_rwlock); smsbox_list_rwlock = NULL; /* destroy things related to smsbox routing */ dict_destroy(smsbox_by_id); smsbox_by_id = NULL; dict_destroy(smsbox_by_smsc); smsbox_by_smsc = NULL; dict_destroy(smsbox_by_receiver); smsbox_by_receiver = NULL; dict_destroy(smsbox_by_smsc_receiver); smsbox_by_smsc_receiver = NULL; gwlist_remove_producer(flow_threads); } static void wapboxc_run(void *arg) { int fd, port; gwlist_add_producer(flow_threads); gwthread_wakeup(MAIN_THREAD_ID); port = (int) *((long*)arg); fd = make_server_socket(port, NULL); /* XXX add interface_name if required */ if (fd < 0) { panic(0, "Could not open wapbox port %d", port); } wait_for_connections(fd, run_wapbox, incoming_wdp, wapbox_port_ssl); /* continue avalanche */ gwlist_remove_producer(outgoing_wdp); /* wait for all connections to die and then remove list */ while(gwlist_wait_until_nonempty(wapbox_list) == 1) gwthread_sleep(1.0); /* wait for wdp_to_wapboxes to exit */ while(gwlist_consume(wapbox_list)!=NULL) ; /* close listen socket */ close(fd); gwlist_destroy(wapbox_list, NULL); wapbox_list = NULL; gwlist_remove_producer(flow_threads); } /* * Populates the corresponding smsbox_by_foobar dictionary hash tables */ static void init_smsbox_routes(Cfg *cfg) { CfgGroup *grp; List *list, *items; Octstr *boxc_id, *smsc_ids, *shortcuts; int i, j; boxc_id = smsc_ids = shortcuts = NULL; list = cfg_get_multi_group(cfg, octstr_imm("smsbox-route")); /* loop multi-group "smsbox-route" */ while (list && (grp = gwlist_extract_first(list)) != NULL) { if ((boxc_id = cfg_get(grp, octstr_imm("smsbox-id"))) == NULL) { grp_dump(grp); panic(0,"'smsbox-route' group without valid 'smsbox-id' directive!"); } /* * If smsc-id is given, then any message comming from the specified * smsc-id in the list will be routed to this smsbox instance. * If shortcode is given, then any message with receiver number * matching those will be routed to this smsbox instance. * If both are given, then only receiver within shortcode originating * from smsc-id list will be routed to this smsbox instance. So if both * are present then this is a logical AND operation. */ smsc_ids = cfg_get(grp, octstr_imm("smsc-id")); shortcuts = cfg_get(grp, octstr_imm("shortcode")); /* consider now the 3 possibilities: */ if (smsc_ids && !shortcuts) { /* smsc-id only, so all MO traffic */ items = octstr_split(smsc_ids, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); debug("bb.boxc",0,"Adding smsbox routing to id <%s> for smsc id <%s>", octstr_get_cstr(boxc_id), octstr_get_cstr(item)); if (!dict_put_once(smsbox_by_smsc, item, octstr_duplicate(boxc_id))) panic(0, "Routing for smsc-id <%s> already exists!", octstr_get_cstr(item)); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(smsc_ids); } else if (!smsc_ids && shortcuts) { /* shortcode only, so these MOs from all smscs */ items = octstr_split(shortcuts, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); debug("bb.boxc",0,"Adding smsbox routing to id <%s> for receiver no <%s>", octstr_get_cstr(boxc_id), octstr_get_cstr(item)); if (!dict_put_once(smsbox_by_receiver, item, octstr_duplicate(boxc_id))) panic(0, "Routing for receiver no <%s> already exists!", octstr_get_cstr(item)); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(shortcuts); } else if (smsc_ids && shortcuts) { /* both, so only specified MOs from specified smscs */ items = octstr_split(shortcuts, octstr_imm(";")); for (i = 0; i < gwlist_len(items); i++) { List *subitems; Octstr *item = gwlist_get(items, i); octstr_strip_blanks(item); subitems = octstr_split(smsc_ids, octstr_imm(";")); for (j = 0; j < gwlist_len(subitems); j++) { Octstr *subitem = gwlist_get(subitems, j); octstr_strip_blanks(subitem); debug("bb.boxc",0,"Adding smsbox routing to id <%s> " "for receiver no <%s> and smsc id <%s>", octstr_get_cstr(boxc_id), octstr_get_cstr(item), octstr_get_cstr(subitem)); /* construct the dict key ':' */ octstr_insert(subitem, item, 0); octstr_insert_char(subitem, octstr_len(item), ':'); if (!dict_put_once(smsbox_by_smsc_receiver, subitem, octstr_duplicate(boxc_id))) panic(0, "Routing for receiver:smsc <%s> already exists!", octstr_get_cstr(subitem)); } gwlist_destroy(subitems, octstr_destroy_item); } gwlist_destroy(items, octstr_destroy_item); octstr_destroy(shortcuts); } octstr_destroy(boxc_id); } gwlist_destroy(list, NULL); } /*------------------------------------------------------------- * public functions * * SMSBOX */ int smsbox_start(Cfg *cfg) { CfgGroup *grp; if (smsbox_running) return -1; debug("bb", 0, "starting smsbox connection module"); grp = cfg_get_single_group(cfg, octstr_imm("core")); if (cfg_get_integer(&smsbox_port, grp, octstr_imm("smsbox-port")) == -1) { error(0, "Missing smsbox-port variable, cannot start smsboxes"); return -1; } #ifdef HAVE_LIBSSL cfg_get_bool(&smsbox_port_ssl, grp, octstr_imm("smsbox-port-ssl")); #endif /* HAVE_LIBSSL */ if (smsbox_port_ssl) debug("bb", 0, "smsbox connection module is SSL-enabled"); smsbox_interface = cfg_get(grp, octstr_imm("smsbox-interface")); if (cfg_get_integer(&smsbox_max_pending, grp, octstr_imm("smsbox-max-pending")) == -1) { smsbox_max_pending = SMSBOX_MAX_PENDING; info(0, "BOXC: 'smsbox-max-pending' not set, using default (%ld).", smsbox_max_pending); } box_allow_ip = cfg_get(grp, octstr_imm("box-allow-ip")); if (box_allow_ip == NULL) box_allow_ip = octstr_create(""); box_deny_ip = cfg_get(grp, octstr_imm("box-deny-ip")); if (box_deny_ip == NULL) box_deny_ip = octstr_create(""); if (box_allow_ip != NULL && box_deny_ip == NULL) info(0, "Box connection allowed IPs defined without any denied..."); smsbox_list = gwlist_create(); /* have a list of connections */ smsbox_list_rwlock = gw_rwlock_create(); if (!boxid) boxid = counter_create(); /* the smsbox routing specific inits */ smsbox_by_id = dict_create(10, (void(*)(void *)) boxc_gwlist_destroy); smsbox_by_smsc = dict_create(30, (void(*)(void *)) octstr_destroy); smsbox_by_receiver = dict_create(50, (void(*)(void *)) octstr_destroy); smsbox_by_smsc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy); /* load the defined smsbox routing rules */ init_smsbox_routes(cfg); gwlist_add_producer(outgoing_sms); gwlist_add_producer(smsbox_list); smsbox_running = 1; if ((sms_dequeue_thread = gwthread_create(sms_to_smsboxes, NULL)) == -1) panic(0, "Failed to start a new thread for smsbox routing"); if (gwthread_create(smsboxc_run, NULL) == -1) panic(0, "Failed to start a new thread for smsbox connections"); return 0; } int smsbox_restart(Cfg *cfg) { if (!smsbox_running) return -1; /* send new config to clients */ return 0; } /* WAPBOX */ int wapbox_start(Cfg *cfg) { CfgGroup *grp; if (wapbox_running) return -1; debug("bb", 0, "starting wapbox connection module"); grp = cfg_get_single_group(cfg, octstr_imm("core")); if (cfg_get_integer(&wapbox_port, grp, octstr_imm("wapbox-port")) == -1) { error(0, "Missing wapbox-port variable, cannot start WAP"); return -1; } #ifdef HAVE_LIBSSL cfg_get_bool(&wapbox_port_ssl, grp, octstr_imm("wapbox-port-ssl")); #endif /* HAVE_LIBSSL */ box_allow_ip = cfg_get(grp, octstr_imm("box-allow-ip")); if (box_allow_ip == NULL) box_allow_ip = octstr_create(""); box_deny_ip = cfg_get(grp, octstr_imm("box-deny-ip")); if (box_deny_ip == NULL) box_deny_ip = octstr_create(""); if (box_allow_ip != NULL && box_deny_ip == NULL) info(0, "Box connection allowed IPs defined without any denied..."); wapbox_list = gwlist_create(); /* have a list of connections */ gwlist_add_producer(outgoing_wdp); if (!boxid) boxid = counter_create(); if (gwthread_create(wdp_to_wapboxes, NULL) == -1) panic(0, "Failed to start a new thread for wapbox routing"); if (gwthread_create(wapboxc_run, &wapbox_port) == -1) panic(0, "Failed to start a new thread for wapbox connections"); wapbox_running = 1; return 0; } Octstr *boxc_status(int status_type) { Octstr *tmp; char *lb, *ws; int i, boxes, para = 0; time_t orig, t; Boxc *bi; orig = time(NULL); /* * XXX: this will cause segmentation fault if this is called * between 'destroy_list and setting list to NULL calls. * Ok, this has to be fixed, but now I am too tired. */ if ((lb = bb_status_linebreak(status_type))==NULL) return octstr_create("Un-supported format"); if (status_type == BBSTATUS_HTML) ws = "    "; else if (status_type == BBSTATUS_TEXT) ws = " "; else ws = ""; if (status_type == BBSTATUS_HTML || status_type == BBSTATUS_WML) para = 1; if (status_type == BBSTATUS_XML) { tmp = octstr_create (""); octstr_append_cstr(tmp, "\n\t"); } else tmp = octstr_format("%sBox connections:%s", para ? "

" : "", lb); boxes = 0; if (wapbox_list) { gwlist_lock(wapbox_list); for(i=0; i < gwlist_len(wapbox_list); i++) { bi = gwlist_get(wapbox_list, i); if (bi->alive == 0) continue; t = orig - bi->connect_time; if (status_type == BBSTATUS_XML) octstr_format_append(tmp, "\n\t\twapbox\n\t\t%s\n" "\t\ton-line %ldd %ldh %ldm %lds\n" "\t\t%s\n\t\n", octstr_get_cstr(bi->client_ip), t/3600/24, t/3600%24, t/60%60, t%60, #ifdef HAVE_LIBSSL conn_get_ssl(bi->conn) != NULL ? "yes" : "no" #else "not installed" #endif ); else octstr_format_append(tmp, "%swapbox, IP %s (on-line %ldd %ldh %ldm %lds) %s %s", ws, octstr_get_cstr(bi->client_ip), t/3600/24, t/3600%24, t/60%60, t%60, #ifdef HAVE_LIBSSL conn_get_ssl(bi->conn) != NULL ? "using SSL" : "", #else "", #endif lb); boxes++; } gwlist_unlock(wapbox_list); } if (smsbox_list) { gw_rwlock_rdlock(smsbox_list_rwlock); for(i=0; i < gwlist_len(smsbox_list); i++) { bi = gwlist_get(smsbox_list, i); if (bi->alive == 0) continue; t = orig - bi->connect_time; if (status_type == BBSTATUS_XML) octstr_format_append(tmp, "\n\t\tsmsbox\n" "\t\t%s\n\t\t%s\n" "\t\t%ld\n" "\t\ton-line %ldd %ldh %ldm %lds\n" "\t\t%s\n\t", (bi->boxc_id ? octstr_get_cstr(bi->boxc_id) : ""), octstr_get_cstr(bi->client_ip), gwlist_len(bi->incoming) + dict_key_count(bi->sent), t/3600/24, t/3600%24, t/60%60, t%60, #ifdef HAVE_LIBSSL conn_get_ssl(bi->conn) != NULL ? "yes" : "no" #else "not installed" #endif ); else octstr_format_append(tmp, "%ssmsbox:%s, IP %s (%ld queued), (on-line %ldd %ldh %ldm %lds) %s %s", ws, (bi->boxc_id ? octstr_get_cstr(bi->boxc_id) : "(none)"), octstr_get_cstr(bi->client_ip), gwlist_len(bi->incoming) + dict_key_count(bi->sent), t/3600/24, t/3600%24, t/60%60, t%60, #ifdef HAVE_LIBSSL conn_get_ssl(bi->conn) != NULL ? "using SSL" : "", #else "", #endif lb); boxes++; } gw_rwlock_unlock(smsbox_list_rwlock); } if (boxes == 0 && status_type != BBSTATUS_XML) { octstr_destroy(tmp); tmp = octstr_format("%sNo boxes connected", para ? "

" : ""); } if (para) octstr_append_cstr(tmp, "

"); if (status_type == BBSTATUS_XML) octstr_append_cstr(tmp, "
\n"); else octstr_append_cstr(tmp, "\n\n"); return tmp; } int boxc_incoming_wdp_queue(void) { int i, q = 0; Boxc *boxc; if (wapbox_list) { gwlist_lock(wapbox_list); for(i=0; i < gwlist_len(wapbox_list); i++) { boxc = gwlist_get(wapbox_list, i); q += gwlist_len(boxc->incoming); } gwlist_unlock(wapbox_list); } return q; } void boxc_cleanup(void) { octstr_destroy(box_allow_ip); octstr_destroy(box_deny_ip); box_allow_ip = NULL; box_deny_ip = NULL; counter_destroy(boxid); boxid = NULL; octstr_destroy(smsbox_interface); smsbox_interface = NULL; } /* * Route the incoming message to one of the following input queues: * a specific smsbox conn * a random smsbox conn if no shortcut routing and msg->sms.boxc_id match * * BEWARE: All logic inside here should be fast, hence speed processing * optimized, because every single MO message passes this function and we * have to ensure that no unncessary overhead is done. */ int route_incoming_to_boxc(Msg *msg) { Boxc *bc = NULL; Octstr *s, *r, *rs, *boxc_id = NULL; long len, b, i; int full_found = 0; gw_assert(msg_type(msg) == sms); /* msg_dump(msg, 0); */ /* Check we have at least one smsbox connected! */ gw_rwlock_rdlock(smsbox_list_rwlock); if (gwlist_len(smsbox_list) == 0) { gw_rwlock_unlock(smsbox_list_rwlock); warning(0, "smsbox_list empty!"); if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) { gwlist_produce(incoming_sms, msg); return 0; } else { return -1; } } /* * Do we have a specific smsbox-id route to pass this msg to? */ if (octstr_len(msg->sms.boxc_id) > 0) { boxc_id = msg->sms.boxc_id; } else { /* * Check if we have a "smsbox-route" for this msg. * Where the shortcode route has a higher priority then the smsc-id rule. * Highest priority has the combined : route. */ Octstr *os = octstr_format("%s:%s", octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.smsc_id)); s = (msg->sms.smsc_id ? dict_get(smsbox_by_smsc, msg->sms.smsc_id) : NULL); r = (msg->sms.receiver ? dict_get(smsbox_by_receiver, msg->sms.receiver) : NULL); rs = (os ? dict_get(smsbox_by_smsc_receiver, os) : NULL); octstr_destroy(os); if (rs) boxc_id = rs; else if (r) boxc_id = r; else if (s) boxc_id = s; } /* We have a specific smsbox-id to use */ if (boxc_id != NULL) { List *boxc_id_list = dict_get(smsbox_by_id, boxc_id); if (gwlist_len(boxc_id_list) == 0) { /* * something is wrong, this was the smsbox connection we used * for sending, so it seems this smsbox is gone */ warning(0, "Could not route message to smsbox id <%s>, smsbox is gone!", octstr_get_cstr(boxc_id)); gw_rwlock_unlock(smsbox_list_rwlock); if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) { gwlist_produce(incoming_sms, msg); return 0; } else { return -1; } } /* * Take random smsbox from list, as long as it has space we will use it, * otherwise check the next one. */ len = gwlist_len(boxc_id_list); b = gw_rand() % len; for (i = 0; i < len; i++) { bc = gwlist_get(boxc_id_list, (i+b) % len); if (bc != NULL && max_incoming_sms_qlength > 0 && gwlist_len(bc->incoming) > max_incoming_sms_qlength) { bc = NULL; } if (bc != NULL) { break; } } if (bc != NULL) { bc->load++; gwlist_produce(bc->incoming, msg); gw_rwlock_unlock(smsbox_list_rwlock); return 1; /* we are done */ } else { /* * we have routing defined, but no smsbox connected at the moment. * put msg into global incoming queue and wait until smsbox with * such boxc_id connected. */ gw_rwlock_unlock(smsbox_list_rwlock); if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) { gwlist_produce(incoming_sms, msg); return 0; } else { return -1; } } } /* * Ok, none of the specific routing things applied previously, * so route it to a random smsbox. * Take random smsbox from list, as long as it has space we will * use it, therwise check the next one. */ len = gwlist_len(smsbox_list); b = gw_rand() % len; for (i = 0; i < len; i++) { bc = gwlist_get(smsbox_list, (i+b) % len); if (bc->boxc_id != NULL || bc->routable == 0) bc = NULL; if (bc != NULL && max_incoming_sms_qlength > 0 && gwlist_len(bc->incoming) > max_incoming_sms_qlength) { full_found = 1; bc = NULL; } if (bc != NULL) { break; } } if (bc != NULL) { bc->load++; gwlist_produce(bc->incoming, msg); } gw_rwlock_unlock(smsbox_list_rwlock); if (bc == NULL && full_found == 0) { warning(0, "smsbox_list empty!"); if (max_incoming_sms_qlength < 0 || max_incoming_sms_qlength > gwlist_len(incoming_sms)) { gwlist_produce(incoming_sms, msg); return 0; } else { return -1; } } else if (bc == NULL && full_found == 1) { return -1; } return 1; } static void sms_to_smsboxes(void *arg) { Msg *newmsg, *startmsg, *msg; long i, len; int ret = -1; Boxc *boxc; gwlist_add_producer(flow_threads); newmsg = startmsg = msg = NULL; while (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) { if (newmsg == startmsg) { /* check if we are in shutdown phase */ if (gwlist_producer_count(smsbox_list) == 0) break; if (ret == 0 || ret == -1) { /* debug("", 0, "time to sleep"); */ gwthread_sleep(60.0); /* debug("", 0, "wake up list len %ld", gwlist_len(incoming_sms)); */ /* shutdown ? */ if (gwlist_producer_count(smsbox_list) == 0 && gwlist_len(smsbox_list) == 0) break; } startmsg = msg = gwlist_consume(incoming_sms); /* debug("", 0, "gwlist_consume done 1"); */ newmsg = NULL; } else { newmsg = msg = gwlist_consume(incoming_sms); /* Back at the first message? */ if (newmsg == startmsg) { gwlist_insert(incoming_sms, 0, msg); continue; } } if (msg == NULL) break; gw_assert(msg_type(msg) == sms); /* debug("bb.sms", 0, "sms_boxc_router: handling message (%p vs %p)", msg, startmsg); */ ret = route_incoming_to_boxc(msg); if (ret == 1) startmsg = newmsg = NULL; else if (ret == -1) { gwlist_produce(incoming_sms, msg); } } gw_rwlock_rdlock(smsbox_list_rwlock); len = gwlist_len(smsbox_list); for (i=0; i < len; i++) { boxc = gwlist_get(smsbox_list, i); gwlist_remove_producer(boxc->incoming); } gw_rwlock_unlock(smsbox_list_rwlock); gwlist_remove_producer(flow_threads); } /* * Simple wrapper to allow the named smsbox Lists to be * destroyed when the smsbox_by_id Dict is destroyed * */ static void boxc_gwlist_destroy(List *list) { gwlist_destroy(list, NULL); } gateway-1.4.5/gw/bearerbox.c0000644000175000017500000010051213227613126014420 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * bearerbox.c * * this is the core module of the bearerbox. It starts everything and * listens to HTTP requests and traps signals. * All started modules are responsible for the rest. * * Kalle Marjola 2000 for project Kannel */ #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "msg.h" #include "bearerbox.h" #include "shared.h" #include "dlr.h" #include "load.h" /* global variables; included to other modules as needed */ List *incoming_sms; List *outgoing_sms; List *incoming_wdp; List *outgoing_wdp; Counter *incoming_sms_counter; Counter *outgoing_sms_counter; Counter *incoming_dlr_counter; Counter *outgoing_dlr_counter; Counter *incoming_wdp_counter; Counter *outgoing_wdp_counter; /* incoming/outgoing sms queue control */ long max_incoming_sms_qlength; long max_outgoing_sms_qlength; Load *outgoing_sms_load; Load *incoming_sms_load; Load *incoming_dlr_load; Load *outgoing_dlr_load; /* this is not a list of items; instead it is used as * indicator to note how many threads we have. * ALL flow threads must exit before we may safely change * bb_status from BB_SHUTDOWN to BB_DEAD * * XXX: prehaps we could also have items in this list, as * descriptors of each thread? */ List *flow_threads; /* and still more abuse; we use this list to put us into * 'suspend' state - if there are any producers (only core adds/removes them) * receiver/sender systems just sit, blocked in gwlist_consume */ List *suspended; /* this one is like 'suspended', but only for receiving UDP/SMSC * (suspended state puts producers for both lists) */ List *isolated; /* configuration filename */ Octstr *cfg_filename; volatile sig_atomic_t bb_status; /* * Flags for main thread to check what is to do. */ enum { BB_GRACEFUL_RESTART = 1, BB_CHECKLEAKS = 2, BB_LOGREOPEN = 3 }; /* Here we will set above flags */ static volatile sig_atomic_t bb_todo = 0; /* own global variables */ static Mutex *status_mutex; static time_t start_time; volatile sig_atomic_t restart = 0; /* to avoid copied code */ static void set_shutdown_status(void) { sig_atomic_t old = bb_status; bb_status = BB_SHUTDOWN; if (old == BB_SUSPENDED) gwlist_remove_producer(suspended); if (old == BB_SUSPENDED || old == BB_ISOLATED) gwlist_remove_producer(isolated); } /*------------------------------------------------------- * signals */ static void signal_handler(int signum) { /* On some implementations (i.e. linuxthreads), signals are delivered * to all threads. We only want to handle each signal once for the * entire box, and we let the gwthread wrapper take care of choosing * one. */ if (!gwthread_shouldhandlesignal(signum)) return; switch (signum) { case SIGINT: case SIGTERM: if (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) { bb_status = BB_SHUTDOWN; } else if (bb_status == BB_SHUTDOWN) { bb_status = BB_DEAD; } else if (bb_status == BB_DEAD) { panic(0, "Cannot die by its own will"); } break; case SIGHUP: bb_todo |= BB_GRACEFUL_RESTART; break; case SIGUSR2: bb_todo |= BB_LOGREOPEN; break; /* * It would be more proper to use SIGUSR1 for this, but on some * platforms that's reserved by the pthread support. */ case SIGQUIT: bb_todo |= BB_CHECKLEAKS; break; } } static void setup_signal_handlers(void) { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGPIPE, &act, NULL); sigaction(SIGUSR2, &act, NULL); } /*-------------------------------------------------------- * functions to start/init sub-parts of the bearerbox * * these functions are NOT thread safe but they have no need to be, * as there is only one core bearerbox thread */ static int start_smsc(Cfg *cfg) { static int started = 0; if (started) return 0; if (smsbox_start(cfg) == -1) { error(0, "Unable to start smsbox module."); return -1; } if (smsc2_start(cfg) == -1) { error(0, "Unable to start smsc module."); return -1; } started = 1; return 0; } static void wdp_router(void *arg) { Msg *msg; gwlist_add_producer(flow_threads); while (bb_status != BB_DEAD) { if ((msg = gwlist_consume(outgoing_wdp)) == NULL) break; gw_assert(msg_type(msg) == wdp_datagram); /* if (msg->list == sms) smsc_addwdp(msg); else */ udp_addwdp(msg); } udp_die(); /* smsc_endwdp(); */ gwlist_remove_producer(flow_threads); } static int start_wap(Cfg *cfg) { static int started = 0; if (started) return 0; wapbox_start(cfg); debug("bb", 0, "starting WDP router"); if (gwthread_create(wdp_router, NULL) == -1) panic(0, "Failed to start a new thread for WDP routing"); started = 1; return 0; } static int start_udp(Cfg *cfg) { static int started = 0; if (started) return 0; udp_start(cfg); start_wap(cfg); started = 1; return 0; } /* * check that there is basic thingies in configuration */ static int check_config(Cfg *cfg) { CfgGroup *grp; long smsp, wapp; grp = cfg_get_single_group(cfg, octstr_imm("core")); if (grp == NULL) return -1; if (cfg_get_integer(&smsp, grp, octstr_imm("smsbox-port")) == -1) smsp = -1; if (cfg_get_integer(&wapp, grp, octstr_imm("wapbox-port")) == -1) wapp = -1; #ifndef NO_SMS grp = cfg_get_single_group(cfg, octstr_imm("smsbox")); if (smsp != -1 && grp == NULL) { error(0, "No 'smsbox' group in configuration, but smsbox-port set"); return -1; } #else warning(0, "Kannel was compiled without SMS support"); #endif #ifndef NO_WAP grp = cfg_get_single_group(cfg, octstr_imm("wapbox")); if (wapp != -1 && grp == NULL) { error(0, "No 'wapbox' group in configuration, but wapbox-port set"); return -1; } #else warning(0, "Kannel was compiled without WAP support"); #endif return 0; } /* * check our own variables */ static int check_args(int i, int argc, char **argv) { if (strcmp(argv[i], "-S")==0 || strcmp(argv[i], "--suspended")==0) bb_status = BB_SUSPENDED; else if (strcmp(argv[i], "-I")==0 || strcmp(argv[i], "--isolated")==0) bb_status = BB_ISOLATED; else return -1; return 0; } static Cfg *init_bearerbox(Cfg *cfg) { CfgGroup *grp; Octstr *log, *val; long loglevel, store_dump_freq, value; int lf, m; #ifdef HAVE_LIBSSL Octstr *ssl_server_cert_file; Octstr *ssl_server_key_file; int ssl_enabled = 0; #endif /* HAVE_LIBSSL */ Octstr *http_proxy_host = NULL; long http_proxy_port = -1; int http_proxy_ssl = 0; List *http_proxy_exceptions = NULL; Octstr *http_proxy_username = NULL; Octstr *http_proxy_password = NULL; Octstr *http_proxy_exceptions_regex = NULL; /* defaults: use localtime and markers for access-log */ lf = m = 1; grp = cfg_get_single_group(cfg, octstr_imm("core")); log = cfg_get(grp, octstr_imm("log-file")); if (log != NULL) { if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1) loglevel = 0; log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL); octstr_destroy(log); } if ((val = cfg_get(grp, octstr_imm("syslog-level"))) != NULL) { long level; Octstr *facility; if ((facility = cfg_get(grp, octstr_imm("syslog-facility"))) != NULL) { log_set_syslog_facility(octstr_get_cstr(facility)); octstr_destroy(facility); } if (octstr_compare(val, octstr_imm("none")) == 0) { log_set_syslog(NULL, 0); } else if (octstr_parse_long(&level, val, 0, 10) > 0) { log_set_syslog("bearerbox", level); } octstr_destroy(val); } else { log_set_syslog(NULL, 0); } if (check_config(cfg) == -1) panic(0, "Cannot start with corrupted configuration"); /* determine which timezone we use for access logging */ if ((log = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) { lf = (octstr_case_compare(log, octstr_imm("gmt")) == 0) ? 0 : 1; octstr_destroy(log); } /* should predefined markers be used, ie. prefixing timestamp */ cfg_get_bool(&m, grp, octstr_imm("access-log-clean")); /* custom access-log format */ if ((log = cfg_get(grp, octstr_imm("access-log-format"))) != NULL) { bb_alog_init(log); octstr_destroy(log); } /* open access-log file */ if ((log = cfg_get(grp, octstr_imm("access-log"))) != NULL) { alog_open(octstr_get_cstr(log), lf, m ? 0 : 1); octstr_destroy(log); } if (cfg_get_integer(&store_dump_freq, grp, octstr_imm("store-dump-freq")) == -1) store_dump_freq = -1; log = cfg_get(grp, octstr_imm("store-file")); /* initialize the store file */ if (log != NULL) { warning(0, "'store-file' option deprecated, please use 'store-location' and 'store-type' instead."); val = octstr_create("file"); } else { log = cfg_get(grp, octstr_imm("store-location")); val = cfg_get(grp, octstr_imm("store-type")); } if (store_init(cfg, val, log, store_dump_freq, msg_pack, msg_unpack_wrapper) == -1) panic(0, "Could not start with store init failed."); octstr_destroy(val); octstr_destroy(log); cfg_get_integer(&http_proxy_port, grp, octstr_imm("http-proxy-port")); #ifdef HAVE_LIBSSL cfg_get_bool(&http_proxy_ssl, grp, octstr_imm("http-proxy-ssl")); #endif /* HAVE_LIBSSL */ http_proxy_host = cfg_get(grp, octstr_imm("http-proxy-host")); http_proxy_username = cfg_get(grp, octstr_imm("http-proxy-username")); http_proxy_password = cfg_get(grp, octstr_imm("http-proxy-password")); http_proxy_exceptions = cfg_get_list(grp, octstr_imm("http-proxy-exceptions")); http_proxy_exceptions_regex = cfg_get(grp, octstr_imm("http-proxy-exceptions-regex")); conn_config_ssl (grp); /* * Make sure we have "ssl-server-cert-file" and "ssl-server-key-file" specified * in the core group since we need it to run SSL-enabled internal box * connections configured via "smsbox-port-ssl = yes" and "wapbox-port-ssl = yes". * Check only these, because for "admin-port-ssl" and "sendsms-port-ssl" for the * SSL-enabled HTTP servers are probed within gw/bb_http.c:httpadmin_start() */ #ifdef HAVE_LIBSSL ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file")); ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file")); if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) { /* we are fine, at least files are specified in the configuration */ } else { cfg_get_bool(&ssl_enabled, grp, octstr_imm("smsbox-port-ssl")); cfg_get_bool(&ssl_enabled, grp, octstr_imm("wapbox-port-ssl")); if (ssl_enabled) { panic(0, "You MUST specify cert and key files within core group for SSL-enabled inter-box connections!"); } } octstr_destroy(ssl_server_cert_file); octstr_destroy(ssl_server_key_file); #endif /* HAVE_LIBSSL */ /* if all seems to be OK by the first glimpse, real start-up */ outgoing_sms = gwlist_create(); incoming_sms = gwlist_create(); outgoing_wdp = gwlist_create(); incoming_wdp = gwlist_create(); outgoing_sms_counter = counter_create(); incoming_sms_counter = counter_create(); incoming_dlr_counter = counter_create(); outgoing_dlr_counter = counter_create(); outgoing_wdp_counter = counter_create(); incoming_wdp_counter = counter_create(); status_mutex = mutex_create(); outgoing_sms_load = load_create(); /* add 60,300,-1 entries */ load_add_interval(outgoing_sms_load, 60); load_add_interval(outgoing_sms_load, 300); load_add_interval(outgoing_sms_load, -1); incoming_sms_load = load_create(); /* add 60,300,-1 entries */ load_add_interval(incoming_sms_load, 60); load_add_interval(incoming_sms_load, 300); load_add_interval(incoming_sms_load, -1); incoming_dlr_load = load_create(); /* add 60,300,-1 entries to dlr */ load_add_interval(incoming_dlr_load, 60); load_add_interval(incoming_dlr_load, 300); load_add_interval(incoming_dlr_load, -1); outgoing_dlr_load = load_create(); /* add 60,300,-1 entries to dlr */ load_add_interval(outgoing_dlr_load, 60); load_add_interval(outgoing_dlr_load, 300); load_add_interval(outgoing_dlr_load, -1); setup_signal_handlers(); /* http-admin is REQUIRED */ httpadmin_start(cfg); if (cfg_get_integer(&max_incoming_sms_qlength, grp, octstr_imm("maximum-queue-length")) == -1) max_incoming_sms_qlength = -1; else { warning(0, "Option 'maximum-queue-length' is deprecated! Please use" " 'sms-incoming-queue-limit' instead!"); } if (max_incoming_sms_qlength == -1 && cfg_get_integer(&max_incoming_sms_qlength, grp, octstr_imm("sms-incoming-queue-limit")) == -1) max_incoming_sms_qlength = -1; if (cfg_get_integer(&max_outgoing_sms_qlength, grp, octstr_imm("sms-outgoing-queue-limit")) == -1) max_outgoing_sms_qlength = -1; if (max_outgoing_sms_qlength < 0) max_outgoing_sms_qlength = DEFAULT_OUTGOING_SMS_QLENGTH; if (cfg_get_integer(&value, grp, octstr_imm("http-timeout")) == 0) http_set_client_timeout(value); #ifndef NO_SMS { List *list; list = cfg_get_multi_group(cfg, octstr_imm("smsc")); if (list != NULL) { gwlist_destroy(list, NULL); if (start_smsc(cfg) == -1) { panic(0, "Unable to start SMSCs."); return NULL; } } } #endif #ifndef NO_WAP grp = cfg_get_single_group(cfg, octstr_imm("core")); val = cfg_get(grp, octstr_imm("wdp-interface-name")); if (val != NULL && octstr_len(val) > 0) start_udp(cfg); octstr_destroy(val); if (cfg_get_single_group(cfg, octstr_imm("wapbox")) != NULL) start_wap(cfg); #endif if (http_proxy_host != NULL && http_proxy_port > 0) { http_use_proxy(http_proxy_host, http_proxy_port, http_proxy_ssl, http_proxy_exceptions, http_proxy_username, http_proxy_password, http_proxy_exceptions_regex); } octstr_destroy(http_proxy_host); octstr_destroy(http_proxy_username); octstr_destroy(http_proxy_password); octstr_destroy(http_proxy_exceptions_regex); gwlist_destroy(http_proxy_exceptions, octstr_destroy_item); return cfg; } static void empty_msg_lists(void) { Msg *msg; #ifndef NO_WAP if (gwlist_len(incoming_wdp) > 0 || gwlist_len(outgoing_wdp) > 0) warning(0, "Remaining WDP: %ld incoming, %ld outgoing", gwlist_len(incoming_wdp), gwlist_len(outgoing_wdp)); info(0, "Total WDP messages: received %ld, sent %ld", counter_value(incoming_wdp_counter), counter_value(outgoing_wdp_counter)); #endif while ((msg = gwlist_extract_first(incoming_wdp)) != NULL) msg_destroy(msg); while ((msg = gwlist_extract_first(outgoing_wdp)) != NULL) msg_destroy(msg); gwlist_destroy(incoming_wdp, NULL); gwlist_destroy(outgoing_wdp, NULL); counter_destroy(incoming_wdp_counter); counter_destroy(outgoing_wdp_counter); #ifndef NO_SMS /* XXX we should record these so that they are not forever lost... */ if (gwlist_len(incoming_sms) > 0 || gwlist_len(outgoing_sms) > 0) debug("bb", 0, "Remaining SMS: %ld incoming, %ld outgoing", gwlist_len(incoming_sms), gwlist_len(outgoing_sms)); info(0, "Total SMS messages: received %ld, dlr %ld, sent %ld, dlr %ld", counter_value(incoming_sms_counter), counter_value(incoming_dlr_counter), counter_value(outgoing_sms_counter), counter_value(outgoing_dlr_counter)); #endif gwlist_destroy(incoming_sms, msg_destroy_item); gwlist_destroy(outgoing_sms, msg_destroy_item); counter_destroy(incoming_sms_counter); counter_destroy(incoming_dlr_counter); counter_destroy(outgoing_sms_counter); counter_destroy(outgoing_dlr_counter); load_destroy(incoming_sms_load); load_destroy(incoming_dlr_load); load_destroy(outgoing_sms_load); load_destroy(outgoing_dlr_load); } static void dispatch_into_queue(Msg *msg) { char id[UUID_STR_LEN + 1]; gw_assert(msg != NULL), gw_assert(msg_type(msg) == sms); switch (msg->sms.sms_type) { case mt_push: case mt_reply: case report_mt: gwlist_append(outgoing_sms, msg); break; case mo: case report_mo: gwlist_append(incoming_sms, msg); break; default: uuid_unparse(msg->sms.id, id); error(0, "Not handled sms_type %ld within store for message ID %s", msg->sms.sms_type, id); msg_destroy(msg); break; } } int main(int argc, char **argv) { int cf_index; Cfg *cfg; bb_status = BB_RUNNING; gwlib_init(); start_time = time(NULL); suspended = gwlist_create(); isolated = gwlist_create(); gwlist_add_producer(suspended); gwlist_add_producer(isolated); cf_index = get_and_set_debugs(argc, argv, check_args); if (argv[cf_index] == NULL) cfg_filename = octstr_create("kannel.conf"); else cfg_filename = octstr_create(argv[cf_index]); cfg = cfg_create(cfg_filename); if (cfg_read(cfg) == -1) panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(cfg_filename)); dlr_init(cfg); report_versions("bearerbox"); flow_threads = gwlist_create(); if (init_bearerbox(cfg) == NULL) panic(0, "Initialization failed."); info(0, "----------------------------------------"); info(0, GW_NAME " bearerbox II version %s starting", GW_VERSION); gwthread_sleep(5.0); /* give time to threads to register themselves */ if (store_load(dispatch_into_queue) == -1) panic(0, "Cannot start with store-file failing"); info(0, "MAIN: Start-up done, entering mainloop"); if (bb_status == BB_SUSPENDED) { info(0, "Gateway is now SUSPENDED by startup arguments"); } else if (bb_status == BB_ISOLATED) { info(0, "Gateway is now ISOLATED by startup arguments"); gwlist_remove_producer(suspended); } else { smsc2_resume(1); gwlist_remove_producer(suspended); gwlist_remove_producer(isolated); } while (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD && gwlist_producer_count(flow_threads) > 0) { /* debug("bb", 0, "Main Thread: going to sleep."); */ /* * Not infinite sleep here, because we should notice * when all "flow threads" are dead and shutting bearerbox * down. * XXX if all "flow threads" call gwthread_wakeup(MAIN_THREAD_ID), * we can enter infinite sleep then. */ gwthread_sleep(10.0); /* debug("bb", 0, "Main Thread: woken up."); */ if (bb_todo == 0) { continue; } if (bb_todo & BB_GRACEFUL_RESTART) { warning(0, "SIGHUP received, re-opening logs and gracefully restarting."); log_reopen(); alog_reopen(); bb_graceful_restart(); bb_todo = bb_todo & ~BB_GRACEFUL_RESTART; } if (bb_todo & BB_LOGREOPEN) { warning(0, "SIGUSR2 received, re-opening logs."); log_reopen(); alog_reopen(); bb_todo = bb_todo & ~BB_LOGREOPEN; } if (bb_todo & BB_CHECKLEAKS) { warning(0, "SIGQUIT received, reporting memory usage."); gw_check_leaks(); bb_todo = bb_todo & ~BB_CHECKLEAKS; } } if (bb_status == BB_SHUTDOWN || bb_status == BB_DEAD) warning(0, "Killing signal or HTTP admin command received, shutting down..."); /* call shutdown */ bb_shutdown(); /* wake up any sleeping threads */ gwthread_wakeup_all(); /* wait until flow threads exit */ while (gwlist_consume(flow_threads) != NULL) ; info(0, "All flow threads have died, killing core"); bb_status = BB_DEAD; httpadmin_stop(); boxc_cleanup(); smsc2_cleanup(); store_shutdown(); empty_msg_lists(); gwlist_destroy(flow_threads, NULL); gwlist_destroy(suspended, NULL); gwlist_destroy(isolated, NULL); mutex_destroy(status_mutex); alog_close(); /* if we have any */ bb_alog_shutdown(); cfg_destroy(cfg); octstr_destroy(cfg_filename); dlr_shutdown(); /* now really restart */ if (restart) restart_box(argv); gwlib_shutdown(); return 0; } /*---------------------------------------------------------------- * public functions used via HTTP adminstration interface/module */ int bb_shutdown(void) { static int called = 0; mutex_lock(status_mutex); if (called) { mutex_unlock(status_mutex); return -1; } debug("bb", 0, "Shutting down " GW_NAME "..."); called = 1; set_shutdown_status(); mutex_unlock(status_mutex); #ifndef NO_SMS debug("bb", 0, "shutting down smsc"); smsc2_shutdown(); #endif #ifndef NO_WAP debug("bb", 0, "shutting down udp"); udp_shutdown(); #endif return 0; } int bb_isolate(void) { mutex_lock(status_mutex); if (bb_status != BB_RUNNING && bb_status != BB_SUSPENDED) { mutex_unlock(status_mutex); return -1; } if (bb_status == BB_RUNNING) { smsc2_suspend(); gwlist_add_producer(isolated); } else gwlist_remove_producer(suspended); bb_status = BB_ISOLATED; mutex_unlock(status_mutex); return 0; } int bb_suspend(void) { mutex_lock(status_mutex); if (bb_status != BB_RUNNING && bb_status != BB_ISOLATED) { mutex_unlock(status_mutex); return -1; } if (bb_status != BB_ISOLATED) { smsc2_suspend(); gwlist_add_producer(isolated); } bb_status = BB_SUSPENDED; gwlist_add_producer(suspended); mutex_unlock(status_mutex); return 0; } int bb_resume(void) { mutex_lock(status_mutex); if (bb_status != BB_SUSPENDED && bb_status != BB_ISOLATED) { mutex_unlock(status_mutex); return -1; } if (bb_status == BB_SUSPENDED) gwlist_remove_producer(suspended); smsc2_resume(0); bb_status = BB_RUNNING; gwlist_remove_producer(isolated); mutex_unlock(status_mutex); return 0; } int bb_flush_dlr(void) { /* beware that mutex locking is done in dlr_foobar() routines */ if (bb_status != BB_SUSPENDED) { return -1; } dlr_flush(); return 0; } int bb_stop_smsc(Octstr *id) { return smsc2_stop_smsc(id); } int bb_restart_smsc(Octstr *id) { return smsc2_restart_smsc(id); } int bb_add_smsc(Octstr *id) { return smsc2_add_smsc(id); } int bb_remove_smsc(Octstr *id) { return smsc2_remove_smsc(id); } int bb_restart(void) { restart = 1; return bb_shutdown(); } int bb_graceful_restart(void) { return smsc2_graceful_restart(); } int bb_reload_lists(void) { return smsc2_reload_lists(); } int bb_remove_message(Octstr *message_id) { Msg *msg; int ret; msg = msg_create(ack); msg->ack.nack = ack_failed; msg->ack.time = time(NULL); uuid_parse(octstr_get_cstr(message_id), msg->ack.id); ret = store_save(msg); msg_destroy(msg); if (ret != 0) { error(0, "Could not delete message %s", octstr_get_cstr(message_id)); return -1; } return 0; } #define append_status(r, s, f, x) { s = f(x); octstr_append(r, s); \ octstr_destroy(s); } Octstr *bb_print_status(int status_type) { char *s, *lb; char *frmt, *footer; Octstr *ret, *str, *version; time_t t; if ((lb = bb_status_linebreak(status_type)) == NULL) return octstr_create("Un-supported format"); t = time(NULL) - start_time; if (bb_status == BB_RUNNING) s = "running"; else if (bb_status == BB_ISOLATED) s = "isolated"; else if (bb_status == BB_SUSPENDED) s = "suspended"; else if (bb_status == BB_FULL) s = "filled"; else s = "going down"; version = version_report_string("bearerbox"); if (status_type == BBSTATUS_HTML) { frmt = "%s

\n\n" "

Status: %s, uptime %ldd %ldh %ldm %lds

\n\n" "

WDP: received %ld (%ld queued), sent %ld " "(%ld queued)

\n\n" "

SMS: received %ld (%ld queued), sent %ld " "(%ld queued), store size %ld
\n" " SMS: inbound (%.2f,%.2f,%.2f) msg/sec, " "outbound (%.2f,%.2f,%.2f) msg/sec

\n\n" "

DLR: received %ld, sent %ld
\n" " DLR: inbound (%.2f,%.2f,%.2f) msg/sec, outbound (%.2f,%.2f,%.2f) msg/sec
\n" " DLR: %ld queued, using %s storage

\n\n"; footer = "

"; } else if (status_type == BBSTATUS_WML) { frmt = "%s

\n\n" "

Status: %s, uptime %ldd %ldh %ldm %lds

\n\n" "

WDP: received %ld (%ld queued)
\n" " WDP: sent %ld (%ld queued)

\n\n" "

SMS: received %ld (%ld queued)
\n" " SMS: sent %ld (%ld queued)
\n" " SMS: store size %ld
\n" " SMS: inbound (%.2f,%.2f,%.2f) msg/sec
\n" " SMS: outbound (%.2f,%.2f,%.2f) msg/sec

\n" "

DLR: received %ld
\n" " DLR: sent %ld
\n" " DLR: inbound (%.2f,%.2f,%.2f) msg/sec
\n" " DLR: outbound (%.2f,%.2f,%.2f) msg/sec
\n" " DLR: %ld queued
\n" " DLR: using %s storage

\n\n"; footer = "

"; } else if (status_type == BBSTATUS_XML) { frmt = "%s\n" "%s, uptime %ldd %ldh %ldm %lds\n" "\t\n\t\t%ld%ld" "\n\t\t%ld%ld" "\n\t\n" "\t\n\t\t%ld%ld" "\n\t\t%ld%ld" "\n\t\t%ld\n\t\t" "%.2f,%.2f,%.2f\n\t\t" "%.2f,%.2f,%.2f\n\t\t" "\n" "\t\n\t\t%ld\n\t\t" "%ld\n\t\t" "%.2f,%.2f,%.2f\n\t\t" "%.2f,%.2f,%.2f\n\t\t" "%ld\n\t\t%s\n\t\n"; footer = ""; } else { frmt = "%s\n\nStatus: %s, uptime %ldd %ldh %ldm %lds\n\n" "WDP: received %ld (%ld queued), sent %ld (%ld queued)\n\n" "SMS: received %ld (%ld queued), sent %ld (%ld queued), store size %ld\n" "SMS: inbound (%.2f,%.2f,%.2f) msg/sec, " "outbound (%.2f,%.2f,%.2f) msg/sec\n\n" "DLR: received %ld, sent %ld\n" "DLR: inbound (%.2f,%.2f,%.2f) msg/sec, outbound (%.2f,%.2f,%.2f) msg/sec\n" "DLR: %ld queued, using %s storage\n\n"; footer = ""; } ret = octstr_format(frmt, octstr_get_cstr(version), s, t/3600/24, t/3600%24, t/60%60, t%60, counter_value(incoming_wdp_counter), gwlist_len(incoming_wdp) + boxc_incoming_wdp_queue(), counter_value(outgoing_wdp_counter), gwlist_len(outgoing_wdp) + udp_outgoing_queue(), counter_value(incoming_sms_counter), gwlist_len(incoming_sms), counter_value(outgoing_sms_counter), gwlist_len(outgoing_sms), store_messages(), load_get(incoming_sms_load,0), load_get(incoming_sms_load,1), load_get(incoming_sms_load,2), load_get(outgoing_sms_load,0), load_get(outgoing_sms_load,1), load_get(outgoing_sms_load,2), counter_value(incoming_dlr_counter), counter_value(outgoing_dlr_counter), load_get(incoming_dlr_load,0), load_get(incoming_dlr_load,1), load_get(incoming_dlr_load,2), load_get(outgoing_dlr_load,0), load_get(outgoing_dlr_load,1), load_get(outgoing_dlr_load,2), dlr_messages(), dlr_type()); octstr_destroy(version); append_status(ret, str, boxc_status, status_type); append_status(ret, str, smsc2_status, status_type); octstr_append_cstr(ret, footer); return ret; } char *bb_status_linebreak(int status_type) { switch (status_type) { case BBSTATUS_HTML: return "
\n"; case BBSTATUS_WML: return "
\n"; case BBSTATUS_TEXT: return "\n"; case BBSTATUS_XML: return "\n"; default: return NULL; } } gateway-1.4.5/gw/bb.h0000644000175000017500000000610213227613126013037 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * default defines for bearer box behaviour * * These all can be overriden in appropriate configuration files * */ #ifndef BB_H #define BB_H #define BB_DEFAULT_THREAD_MAX 20 #define BB_DEFAULT_HOST "localhost" #define BB_DEFAULT_SMSBOX_PORT 13001 #define BB_DEFAULT_WAPBOX_PORT 13002 #define BB_DEFAULT_HTTP_PORT 13000 #define BB_DEFAULT_MAX_QUEUE 1000 #endif gateway-1.4.5/gw/sms.h0000644000175000017500000001675113227613126013271 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * sms.h - definitions specific to SMS but not particular to any SMSC protocol. * * Sms features that are currently implemented separately in each protocol * should be extracted and placed here. */ /* * DCS Encoding, acording to ETSI 03.38 v7.2.0 * * 00abcdef * bit 5 (a) indicates compressed text * bit 4 (b) indicates Message Class value presence * bits 3,2 (c,d) indicates Data Coding (00=7bit, 01=8bit, 10=UCS-2) * bits 1,0 (e,f) indicates Message Class, if bit 4(b) is active * * 11110abc * bit 2 (a) indicates 0=7bit, 1=8bit * bits 1,0 (b,c) indicates Message Class * * 11abc0de * bits 5,4 (a,b) indicates 00=discard message, 01=store message * 10=store message and text is UCS-2 * bit 3 (c) indicates indication active * bits 1,0 (d,e) indicates indicator (00=voice mail, 01=fax, * 10=email, 11=other) */ #ifndef SMS_H #define SMS_H #include "msg.h" #define SMS_PARAM_UNDEFINED MSG_PARAM_UNDEFINED #define MC_UNDEF SMS_PARAM_UNDEFINED #define MC_CLASS0 0 #define MC_CLASS1 1 #define MC_CLASS2 2 #define MC_CLASS3 3 #define MWI_UNDEF SMS_PARAM_UNDEFINED #define MWI_VOICE_ON 0 #define MWI_FAX_ON 1 #define MWI_EMAIL_ON 2 #define MWI_OTHER_ON 3 #define MWI_VOICE_OFF 4 #define MWI_FAX_OFF 5 #define MWI_EMAIL_OFF 6 #define MWI_OTHER_OFF 7 #define DC_UNDEF SMS_PARAM_UNDEFINED #define DC_7BIT 0 #define DC_8BIT 1 #define DC_UCS2 2 #define COMPRESS_UNDEF SMS_PARAM_UNDEFINED #define COMPRESS_OFF 0 #define COMPRESS_ON 1 #define RPI_UNDEF SMS_PARAM_UNDEFINED #define RPI_OFF 0 #define RPI_ON 1 #define SMS_7BIT_MAX_LEN 160 #define SMS_8BIT_MAX_LEN 140 #define SMS_UCS2_MAX_LEN 70 /* * Maximum number of octets in an SMS message. Note that this is 8 bit * characters, not 7 bit characters. */ #define MAX_SMS_OCTETS 140 /* Encode DCS using sms fields * mode = 0= encode using 00xxxxxx, 1= encode using 1111xxxx mode */ int fields_to_dcs(Msg *msg, int mode); /* * Decode DCS to sms fields * returns 0 if dcs is invalid */ int dcs_to_fields(Msg **msg, int mode); /* * Compute length of the message data in Msg after it will be converted * to the proper coding. * If coding is 7 bit, then sms_msgdata_len will return the number of * septets this message will convert to, taking into account GSM 03.38 * escape sequences of special chars, which would count as two septets. */ int sms_msgdata_len(Msg *msg); /* * Swap an MO message to an MT message (hence swap receiver/sender addresses) * and vice versa for internal bearerbox rerouting (if needed). * Returns 1 if successfull, 0 otherwise. */ int sms_swap(Msg *msg); /* * * Split an SMS message into smaller ones. * * The original SMS message is represented as an Msg object, and the * resulting list of smaller ones is represented as a List of Msg objects. * A plain text header and/or footer can be added to each part, and an * additional suffix can be added to each part except the last one. * Optionally, a UDH prefix can be added to each part so that phones * that understand this prefix can join the messages into one large one * again. At most `max_messages' parts will be generated; surplus text * from the original message will be silently ignored. * * If the original message has UDH, they will be duplicated in each part. * It is an error to use catenation and UDH together, or catenation and 7 * bit mode toghether; in these cases, catenation is silently ignored. * * If `catenate' is true, `msg_sequence' is used as the sequence number for * the logical message. The catenation UDH contain three numbers: the * concatenated message reference, which is constant for all parts of * the logical message, the total number of parts in the logical message, * and the sequence number of the current part. * * Note that `msg_sequence' must have a value in the range 0..255. * * `max_octets' gives the maximum number of octets in on message, including * UDH, and after 7 bit characters have been packed into octets. */ List *sms_split(Msg *orig, Octstr *header, Octstr *footer, Octstr *nonlast_suffix, Octstr *split_chars, int catenate, unsigned long msg_sequence, int max_messages, int max_octets); /** * Create multipart UDH */ void prepend_catenation_udh(Msg *sms, int part_no, int num_messages, int msg_sequence); /** * Compare priority and time of two sms's. * @return -1 of a < b; 0 a = b; 1 a > b */ int sms_priority_compare(const void *a, const void *b); /* * Re-encode an SMSmessage , based on the 'charset' that defines the content * encoding and the 'coding' that defines the desired target encoding. * Return 0 on success, -1 otherwise. */ int sms_charset_processing(Octstr *charset, Octstr *body, int coding); #endif gateway-1.4.5/gw/wap-error.c0000644000175000017500000001164513227613126014375 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/wap-error.c - smart wap error handling * * Stipe Tolj */ #include "gwlib/gwlib.h" #include "wap/wsp.h" #include "wap-error.h" Octstr* error_requesting_back(Octstr *url, Octstr *referer) { Octstr *wml; gw_assert(url != NULL); gw_assert(referer != NULL); wml = octstr_format( "" \ "" \ "" \ "

Error: could not request URL `%s'.

" \ "

Either the HTTP server is down or the request timed out. " \ "Returning to previous page

"\ "

--
" GW_NAME "/%s

", octstr_get_cstr(referer), octstr_get_cstr(url), GW_VERSION ); return wml; } Octstr* error_requesting(Octstr *url) { Octstr *wml; gw_assert(url != NULL); wml = octstr_format( "" \ "" \ "" \ "

Error: could not request URL `%s'.

" \ "

Either the HTTP server is down or the request timed out.

" \ "

--
" GW_NAME "/%s

", octstr_get_cstr(url), GW_VERSION ); return wml; } Octstr* error_converting(Octstr *url, Octstr *type) { Octstr *wml; gw_assert(url != NULL && type != NULL); wml = octstr_format( "" \ "" \ "" \ "

Error: could not convert or compile content-type `%s' " \ "at URL `%s'.

" \ "

Either there was no supported converting routine " \ "or converter failed while processing.

" \ "

--
" GW_NAME "/%s

", octstr_get_cstr(type), octstr_get_cstr(url), GW_VERSION ); return wml; } gateway-1.4.5/gw/dlr_p.h0000644000175000017500000001331213227613126013555 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/dlr_p.h * * Implementation of handling delivery reports (DLRs) * These are private header. * * Andreas Fink , 18.08.2001 * Stipe Tolj , 22.03.2002 * Alexander Malysh */ #ifndef DLR_P_H #define DLR_P_H 1 #define DLR_TRACE 1 /* Used in destination based queries for EMI/UUCP DLRs */ #define MIN_DST_LEN 7 /* * The structure of a delivery report entry. */ struct dlr_entry { Octstr *smsc; Octstr *timestamp; Octstr *source; Octstr *destination; Octstr *service; Octstr *url; Octstr *boxc_id; int mask; int use_dst; }; /* * Create struct dlr_entry and initialize it to zero */ struct dlr_entry *dlr_entry_create(void); /* * Destroy struct dlr_entry */ void dlr_entry_destroy(struct dlr_entry *dlr); /* * Duplicate dlr entry */ struct dlr_entry *dlr_entry_duplicate(const struct dlr_entry *dlr); /* * Callback functions to handle specific dlr storage type */ struct dlr_storage { /* * Type of storage. Used for status reguest. */ const char* type; /* * Add dlr entry into storage. * NOTE: this function is responsible to destroy struct dlr_entry */ void (*dlr_add) (struct dlr_entry *entry); /* * Find and return struct dlr_entry. If entry not found return NULL. * NOTE: Caller will destroy struct dlr_entry */ struct dlr_entry* (*dlr_get) (const Octstr *smsc, const Octstr *ts, const Octstr *dst); /* * Remove matching dlr entry from storage */ void (*dlr_remove) (const Octstr *smsc, const Octstr *ts, const Octstr *dst); /* * Update dlr entry status field if any. */ void (*dlr_update) (const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status); /* * Return count dlr entries in storage. */ long (*dlr_messages) (void); /* * Flush storage */ void (*dlr_flush) (void); /* * Shutdown storage */ void (*dlr_shutdown) (void); }; /* * Will be used by DB based storage types. * We have helper init function also. */ struct dlr_db_fields { Octstr *table; long ttl; Octstr *field_smsc; Octstr *field_ts; Octstr *field_src; Octstr *field_dst; Octstr *field_serv; Octstr *field_url; Octstr *field_mask; Octstr *field_status; Octstr *field_boxc; }; struct dlr_db_fields *dlr_db_fields_create(CfgGroup *grp); void dlr_db_fields_destroy(struct dlr_db_fields *fields); /* * Storages we have already. This will gone in future * if we have module API implemented. */ struct dlr_storage *dlr_init_mem(Cfg *cfg); struct dlr_storage *dlr_init_spool(Cfg *cfg); struct dlr_storage *dlr_init_mysql(Cfg *cfg); struct dlr_storage *dlr_init_sdb(Cfg *cfg); struct dlr_storage *dlr_init_oracle(Cfg *cfg); struct dlr_storage *dlr_init_pgsql(Cfg *cfg); struct dlr_storage *dlr_init_mssql(Cfg *cfg); struct dlr_storage *dlr_init_sqlite3(Cfg *cfg); struct dlr_storage *dlr_init_redis(Cfg *cfg); struct dlr_storage *dlr_init_cass(Cfg *cfg); #endif /* DLR_P_H */ gateway-1.4.5/gw/msg.h0000644000175000017500000001241513227613126013246 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * msg.h - declarations for message manipulation * * This file declares the Msg data type and the functions to manipulate it. * * Lars Wirzenius */ #ifndef MSG_H #define MSG_H #include "gwlib/gwlib.h" #define MSG_PARAM_UNDEFINED -1 enum msg_type { #define MSG(type, stmt) type, #include "msg-decl.h" msg_type_count }; typedef struct { enum msg_type type; #define INTEGER(name) long name; #define OCTSTR(name) Octstr *name; #define UUID(name) uuid_t name; #define VOID(name) void *name; #define MSG(type, stmt) struct type stmt type; #include "msg-decl.h" } Msg; struct split_parts { /* original large message */ Msg *orig; /* how many parts still not sent */ Counter *parts_left; /* status of splitted message parts */ long status; /* pointer to SMSCConn */ void *smsc_conn; }; /* enums for Msg fields */ /* sms message type */ enum { mo = 0, mt_reply = 1, mt_push = 2, report_mo = 3, report_mt = 4 }; /* admin commands */ enum { cmd_shutdown = 0, cmd_suspend = 1, cmd_resume = 2, cmd_identify = 3, cmd_restart = 4, cmd_feature = 5, }; /* ack message status */ typedef enum { ack_success = 0, ack_failed = 1, /* do not try again (e.g. no route) */ ack_failed_tmp = 2, /* temporary failed, try again (e.g. queue full) */ ack_buffered = 3 } ack_status_t; /* * Create a new, empty Msg object. Panics if fails. */ Msg *msg_create_real(enum msg_type type, const char *file, long line, const char *func); #define msg_create(type) \ gw_claim_area(msg_create_real((type), __FILE__, __LINE__, __func__)) /* * Create a new Msg object that is a copy of an existing one. * Panics if fails. */ Msg *msg_duplicate(Msg *msg); /* * Return type of the message */ enum msg_type msg_type(Msg *msg); /* * Destroy an Msg object. All fields are also destroyed. */ void msg_destroy(Msg *msg); /* * Destroy an Msg object. Wrapper around msg_destroy to make it suitable for * gwlist_destroy. */ void msg_destroy_item(void *msg); /* * For debugging: Output with `debug' (in gwlib/log.h) the contents of * an Msg object. */ void msg_dump(Msg *msg, int level); /* * Pack an Msg into an Octstr. Panics if fails. */ Octstr *msg_pack(Msg *msg); /* * Unpack an Msg from an Octstr. Return NULL for failure, otherwise a pointer * to the Msg. */ Msg *msg_unpack_real(Octstr *os, const char *file, long line, const char *func); #define msg_unpack(os) \ gw_claim_area(msg_unpack_real((os), __FILE__, __LINE__, __func__)) Msg *msg_unpack_wrapper(Octstr *os); #endif gateway-1.4.5/gw/ota_compiler.c0000644000175000017500000006623413227613126015140 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * ota_compiler.c: Tokenizes OTA provisioning documents * * This compiler handles the following OTA config formats: * * - Nokia/Ericsson OTA settings specificaion. DTD is defined in * Over The Air Settings Specification (hereafter called OTA), chapter 6. * (See http://www.americas.nokia.com/messaging/default.asp) * * - OMA OTA client provisionig content specification, as defined in * document OMA-WAP-ProvCont-V1.1-20050428-C.pdf. (hereafter called OMA) * (See http://www.openmobilealliance.com/release_program/cp_v1_1.htm) * * Histrorically the Nokia/Ericsson OTA config format was the first scratch * in allowing remote WAP profile configuration via SMS bearer. While the WAP * Forum transfered into the Open Mobile Alliance (OMA), the technical working * groups addopted the provisioning concept to a more generic OTA provisioning * concept. The OMA client provisioning specs v1.1 are part of the WAP 2.0 * protocol stack. * * Aarno Syvänen for Wiral Ltd * Stipe Tolj for Wapme Systems AG * Paul Bagyenda for digital solutions Ltd. */ #include #include #include #include #include #include #include "shared.h" #include "xml_shared.h" #include "ota_compiler.h" /**************************************************************************** * * Global variables * * Two token table types, one and two token fields */ struct ota_2table_t { char *name; unsigned char token; }; typedef struct ota_2table_t ota_2table_t; /* * Ota tokenizes whole of attribute value, or uses an inline string. See ota, * chapter 8.2. */ struct ota_3table_t { char *name; char *value; unsigned char token; unsigned char code_page; }; typedef struct ota_3table_t ota_3table_t; /* * Elements from tag code page zero. These are defined in OTA, chapter 8.1 * and OMA, chapter 7.1. */ static ota_2table_t ota_elements[] = { { "SYNCSETTINGS", 0x15 }, { "WAP-PROVISIONINGDOC", 0x05 }, { "CHARACTERISTIC-LIST", 0x05 }, { "CHARACTERISTIC", 0x06 }, { "PARM", 0x07 } }; #define NUMBER_OF_ELEMENTS sizeof(ota_elements)/sizeof(ota_elements[0]) /* * SYNCSETTINGS tags are defined in OTA specs 7.0, chapter 11.1 */ static ota_2table_t ota_syncsettings_elements[] = { { "Addr", 0x45 }, { "AddrType", 0x46 }, { "Auth", 0x47 }, { "AuthLevel", 0x48 }, { "AuthScheme", 0x49 }, { "Bearer", 0x4A }, { "ConRef", 0x4B }, { "ConType", 0x4C }, { "Cred", 0x4D }, { "CTType", 0x4E }, { "CTVer", 0x4F }, { "HostAddr", 0x50 }, { "Name", 0x51 }, { "Port", 0x52 }, { "RefID", 0x53 }, { "RemoteDB", 0x54 }, { "URI", 0x56 }, { "Username", 0x57 }, { "Version", 0x58 } }; #define NUMBER_OF_SYNCSETTINGS_ELEMENTS sizeof(ota_syncsettings_elements)/sizeof(ota_syncsettings_elements[0]) /* * Attribute names and values from code page zero. These are defined in ota, * chapter 8.2. Some values are presented as inline strings; in this case * value "INLINE" is used. (Note a quirk: there is an attribute with name * "VALUE".) * * For a documentation of the single attributes see gw/ota_prov_attr.h. */ static ota_3table_t ota_attributes[] = { { "TYPE", "ADDRESS", 0x06 }, { "TYPE", "URL", 0x07 }, { "TYPE", "MMSURL", 0x7c }, { "TYPE", "NAME", 0x08 }, { "TYPE", "ID", 0x7d }, { "TYPE", "BOOKMARK", 0x7f }, { "NAME", "BEARER", 0x12 }, { "NAME", "PROXY", 0x13 }, { "NAME", "PORT", 0x14 }, { "NAME", "NAME", 0x15 }, { "NAME", "PROXY_TYPE", 0x16 }, { "NAME", "URL", 0x17 }, { "NAME", "PROXY_AUTHNAME", 0x18 }, { "NAME", "PROXY_AUTHSECRET", 0x19 }, { "NAME", "SMS_SMSC_ADDRESS", 0x1a }, { "NAME", "USSD_SERVICE_CODE", 0x1b }, { "NAME", "GPRS_ACCESSPOINTNAME", 0x1c }, { "NAME", "PPP_LOGINTYPE", 0x1d }, { "NAME", "PROXY_LOGINTYPE", 0x1e }, { "NAME", "CSD_DIALSTRING", 0x21 }, { "NAME", "CSD_CALLTYPE", 0x28 }, { "NAME", "CSD_CALLSPEED", 0x29 }, { "NAME", "PPP_AUTHTYPE", 0x22 }, { "NAME", "PPP_AUTHNAME", 0x23 }, { "NAME", "PPP_AUTHSECRET", 0x24 }, { "NAME", "ISP_NAME", 0x7e }, { "NAME", "INLINE", 0x10 }, { "VALUE", "GSM/CSD", 0x45 }, { "VALUE", "GSM/SMS", 0x46 }, { "VALUE", "GSM/USSD", 0x47 }, { "VALUE", "IS-136/CSD", 0x48 }, { "VALUE", "GPRS", 0x49 }, { "VALUE", "9200", 0x60 }, { "VALUE", "9201", 0x61 }, { "VALUE", "9202", 0x62 }, { "VALUE", "9203", 0x63 }, { "VALUE", "AUTOMATIC", 0x64 }, { "VALUE", "MANUAL", 0x65 }, { "VALUE", "AUTO", 0x6a }, { "VALUE", "9600", 0x6b }, { "VALUE", "14400", 0x6c }, { "VALUE", "19200", 0x6d }, { "VALUE", "28800", 0x6e }, { "VALUE", "38400", 0x6f }, { "VALUE", "PAP", 0x70 }, { "VALUE", "CHAP", 0x71 }, { "VALUE", "ANALOGUE", 0x72 }, { "VALUE", "ISDN", 0x73 }, { "VALUE", "43200", 0x74 }, { "VALUE", "57600", 0x75 }, { "VALUE", "MSISDN_NO", 0x76 }, { "VALUE", "IPV4", 0x77 }, { "VALUE", "MS_CHAP", 0x78 }, { "VALUE", "INLINE", 0x11 } }; #define NUMBER_OF_ATTRIBUTES sizeof(ota_attributes)/sizeof(ota_attributes[0]) /* * Defines OMA ProvCont WBXML tokens, see chapter 7. * Value 'INLINE' has to be always last in attribute group, since this * is a break condition within a while loop. */ static ota_3table_t oma_ota_attributes[] = { { "VERSION", "1.0", 0x46 }, { "VERSION", "INLINE", 0x45 }, { "TYPE", "PXLOGICAL", 0x51 }, { "TYPE", "PXPHYSICAL", 0x52 }, { "TYPE", "PORT", 0x53 }, { "TYPE", "VALIDITY", 0x54 }, { "TYPE", "NAPDEF", 0x55 }, { "TYPE", "BOOTSTRAP", 0x56 }, { "TYPE", "VENDORCONFIG", 0x57 }, { "TYPE", "PXAUTHINFO", 0x59 }, { "TYPE", "NAPAUTHINFO", 0x5A }, { "TYPE", "ACCESS", 0x5B }, { "TYPE", "BEARERINFO", 0x5C }, { "TYPE", "DNS-ADDRINFO", 0x5D }, { "TYPE", "CLIENTIDENTITY", 0x58 }, { "TYPE", "APPLICATION", 0x55, 1 }, { "TYPE", "APPADDR", 0x56, 1 }, { "TYPE", "APPAUTH", 0x57, 1 }, { "TYPE", "RESOURCE", 0x59, 1 }, { "TYPE", "WLAN", 0x5A, 1 }, { "TYPE", "SEC-SSID", 0x5B, 1 }, { "TYPE", "EAP", 0x5C, 1 }, { "TYPE", "CERT", 0x5D, 1 }, { "TYPE", "WEPKEY", 0x5E, 1 }, { "TYPE", "INLINE", 0x50 }, { "NAME", "NAME", 0x7 }, { "NAME", "NAP-ADDRESS", 0x8 }, { "NAME", "NAP-ADDRTYPE", 0x9 }, { "NAME", "CALLTYPE", 0xA }, { "NAME", "VALIDUNTIL", 0xB }, { "NAME", "AUTHTYPE", 0xC }, { "NAME", "AUTHNAME", 0xD }, { "NAME", "AUTHSECRET", 0xE }, { "NAME", "LINGER", 0xF }, { "NAME", "BEARER", 0x10 }, { "NAME", "NAPID", 0x11 }, { "NAME", "COUNTRY", 0x12 }, { "NAME", "NETWORK", 0x13 }, { "NAME", "INTERNET", 0x14 }, { "NAME", "PROXY-ID", 0x15 }, { "NAME", "PROXY-PROVIDER-ID", 0x16 }, { "NAME", "DOMAIN", 0x17 }, { "NAME", "PROVURL", 0x18 }, { "NAME", "PXAUTH-TYPE", 0x19 }, { "NAME", "PXAUTH-ID", 0x1A }, { "NAME", "PXAUTH-PW", 0x1B }, { "NAME", "STARTPAGE", 0x1C }, { "NAME", "BASAUTH-ID", 0x1D }, { "NAME", "BASAUTH-PW", 0x1E }, { "NAME", "PUSHENABLED", 0x1F }, { "NAME", "PXADDR", 0x20 }, { "NAME", "PXADDRTYPE", 0x21 }, { "NAME", "TO-NAPID", 0x22 }, { "NAME", "PORTNBR", 0x23 }, { "NAME", "SERVICE", 0x24 }, { "NAME", "LINKSPEED", 0x25 }, { "NAME", "DNLINKSPEED", 0x26 }, { "NAME", "LOCAL-ADDR", 0x27 }, { "NAME", "LOCAL-ADDRTYPE", 0x28 }, { "NAME", "CONTEXT-ALLOW", 0x29 }, { "NAME", "TRUST", 0x2A }, { "NAME", "MASTER", 0x2B }, { "NAME", "SID", 0x2C }, { "NAME", "SOC", 0x2D }, { "NAME", "WSP-VERSION", 0x2E }, { "NAME", "PHYSICAL-PROXY-ID", 0x2F }, { "NAME", "CLIENT-ID", 0x30 }, { "NAME", "DELIVERY-ERR-SDU", 0x31 }, { "NAME", "DELIVERY-ORDER", 0x32 }, { "NAME", "TRAFFIC-CLASS", 0x33 }, { "NAME", "MAX-SDU-SIZE", 0x34 }, { "NAME", "MAX-BITRATE-UPLINK", 0x35 }, { "NAME", "MAX-BITRATE-DNLINK", 0x36 }, { "NAME", "RESIDUAL-BER", 0x37 }, { "NAME", "SDU-ERROR-RATIO", 0x38 }, { "NAME", "TRAFFIC-HANDL-PRIO", 0x39 }, { "NAME", "TRANSFER-DELAY", 0x3A }, { "NAME", "GUARANTEED-BITRATE-UPLINK", 0x3B }, { "NAME", "GUARANTEED-BITRATE-DNLINK", 0x3C }, { "NAME", "PXADDR-FQDN", 0x3D }, { "NAME", "PROXY-PW", 0x3E }, { "NAME", "PPGAUTH-TYPE", 0x3F }, { "NAME", "PULLENABLED", 0x47 }, { "NAME", "DNS-ADDR", 0x48 }, { "NAME", "MAX-NUM-RETRY", 0x49 }, { "NAME", "FIRST-RETRY-TIMEOUT", 0x4A }, { "NAME", "REREG-THRESHOLD", 0x4B }, { "NAME", "T-BIT", 0x4C }, { "NAME", "AUTH-ENTITY", 0x4E }, { "NAME", "SPI", 0x4F }, { "NAME", "AACCEPT", 0x2E, 1 }, { "NAME", "AAUTHDATA", 0x2F, 1 }, { "NAME", "AAUTHLEVEL", 0x30, 1 }, { "NAME", "AAUTHNAME", 0x31, 1 }, { "NAME", "AAUTHSECRET", 0x32, 1 }, { "NAME", "AAUTHTYPE", 0x33, 1 }, { "NAME", "ADDR", 0x34, 1 }, { "NAME", "ADDRTYPE", 0x35, 1 }, { "NAME", "APPID", 0x36, 1 }, { "NAME", "APROTOCOL", 0x37, 1 }, { "NAME", "PROVIDER-ID", 0x38, 1 }, { "NAME", "TO-PROXY", 0x39, 1 }, { "NAME", "URI", 0x3A, 1 }, { "NAME", "RULE", 0x3B, 1 }, { "NAME", "APPREF", 0x3C, 1 }, { "NAME", "TO-APPREF", 0x3D, 1 }, { "NAME", "PRI-SSID", 0x3E, 1 }, { "NAME", "PRI-U-SSID", 0x3F, 1 }, { "NAME", "PRI-H-SSID", 0x40, 1 }, { "NAME", "S-SSID", 0x41, 1 }, { "NAME", "S-U-SSID", 0x42, 1 }, { "NAME", "NETMODE", 0x43, 1 }, { "NAME", "SECMODE", 0x44, 1 }, { "NAME", "EAPTYPE", 0x45, 1 }, { "NAME", "USERNAME", 0x46, 1 }, { "NAME", "PASSWORD", 0x47, 1 }, { "NAME", "REALM", 0x48, 1 }, { "NAME", "USE-PSEUD", 0x49, 1 }, { "NAME", "ENCAPS", 0x5B, 1 }, { "NAME", "VER-SER-REALM", 0x4C, 1 }, { "NAME", "CLIENT-AUTH", 0x4D, 1 }, { "NAME", "SES-VAL-TIME", 0x4E, 1 }, { "NAME", "CIP-SUIT", 0x4F, 1 }, { "NAME", "PEAP-V0", 0x60, 1 }, { "NAME", "PEAP-V1", 0x61, 1 }, { "NAME", "PEAP-V2", 0x62, 1 }, { "NAME", "ISS-NAME", 0x63, 1 }, { "NAME", "SUB-NAME", 0x64, 1 }, { "NAME", "CERT-TYPE", 0x65, 1 }, { "NAME", "SER-NUM", 0x66, 1 }, { "NAME", "SUB-KEY-ID", 0x67, 1 }, { "NAME", "THUMBPRINT", 0x68, 1 }, { "NAME", "WPA-PRES-KEY-ASC", 0x69, 1 }, { "NAME", "WPA-PRES-KEY-HEX", 0x6A, 1 }, { "NAME", "WEPKEYIND", 0x6B, 1 }, { "NAME", "WEPAUTHMODE", 0x6C, 1 }, { "NAME", "LENGTH", 0x6D, 1 }, { "NAME", "INDEX", 0x6E, 1 }, { "NAME", "DATA", 0x6F, 1 }, { "NAME", "WLANHAND", 0x70, 1 }, { "NAME", "EDIT-SET", 0x71, 1 }, { "NAME", "VIEW-SET", 0x72, 1 }, { "NAME", "FORW-SET", 0x73, 1 }, { "NAME", "INLINE", 0x5 }, { "VALUE", "IPV4", 0x85 }, { "VALUE", "IPV6", 0x86 }, { "VALUE", "E164", 0x87 }, { "VALUE", "ALPHA", 0x88 }, { "VALUE", "APN", 0x89 }, { "VALUE", "SCODE", 0x8A }, { "VALUE", "TETRA-ITSI", 0x8B }, { "VALUE", "MAN", 0x8C }, { "VALUE", "APPSRV", 0x8D, 1 }, { "VALUE", "OBEX", 0x8E, 1 }, { "VALUE", "ANALOG-MODEM", 0x90 }, { "VALUE", "V.120", 0x91 }, { "VALUE", "V.110", 0x92 }, { "VALUE", "X.31", 0x93 }, { "VALUE", "BIT-TRANSPARENT", 0x94 }, { "VALUE", "DIRECT-ASYNCHRONOUS-DATA-SERVICE", 0x95 }, { "VALUE", "PAP", 0x9A }, { "VALUE", "CHAP", 0x9B }, { "VALUE", "HTTP-BASIC", 0x9C }, { "VALUE", "HTTP-DIGEST", 0x9D }, { "VALUE", "WTLS-SS", 0x9E }, { "VALUE", "MD5", 0x9F }, { "VALUE", "GSM-USSD", 0xA2 }, { "VALUE", "GSM-SMS", 0xA3 }, { "VALUE", "ANSI-136-GUTS", 0xA4 }, { "VALUE", "IS-95-CDMA-SMS", 0xA5 }, { "VALUE", "IS-95-CDMA-CSD", 0xA6 }, { "VALUE", "IS-95-CDMA-PACKET", 0xA7 }, { "VALUE", "ANSI-136-CSD", 0xA8 }, { "VALUE", "ANSI-136-GPRS", 0xA9 }, { "VALUE", "GSM-CSD", 0xAA }, { "VALUE", "GSM-GPRS", 0xAB }, { "VALUE", "AMPS-CDPD", 0xAC }, { "VALUE", "PDC-CSD", 0xAD }, { "VALUE", "PDC-PACKET", 0xAE }, { "VALUE", "IDEN-SMS", 0xAF }, { "VALUE", "IDEN-CSD", 0xB0 }, { "VALUE", "IDEN-PACKET", 0xB1 }, { "VALUE", "FLEX/REFLEX", 0xB2 }, { "VALUE", "PHS-SMS", 0xB3 }, { "VALUE", "PHS-CSD", 0xB4 }, { "VALUE", "TETRA-SDS", 0xB5 }, { "VALUE", "TETRA-PACKET", 0xB6 }, { "VALUE", "ANSI-136-GHOST", 0xB7 }, { "VALUE", "MOBITEX-MPAK", 0xB8 }, { "VALUE", "CDMA2000-1X-SIMPLE-IP", 0xB9 }, { "VALUE", "CDMA2000-1X-MOBILE-IP", 0xBA }, { "VALUE", "3G-GSM", 0xBB }, { "VALUE", "WLAN", 0xBC }, { "VALUE", "AUTOBAUDING", 0xC5 }, { "VALUE", "CL-WSP", 0xCA }, { "VALUE", "CO-WSP", 0xCB }, { "VALUE", "CL-SEC-WSP", 0xCC }, { "VALUE", "CO-SEC-WSP", 0xCD }, { "VALUE", "CL-SEC-WTA", 0xCE }, { "VALUE", "CO-SEC-WTA", 0xCF }, { "VALUE", "OTA-HTTP-TO", 0xD0 }, { "VALUE", "OTA-HTTP-TLS-TO", 0xD1 }, { "VALUE", "OTA-HTTP-PO", 0xD2 }, { "VALUE", "OTA-HTTP-TLS-PO", 0xD3 }, { "VALUE", ",", 0x90, 1 }, { "VALUE", "HTTP-", 0x91, 1 }, { "VALUE", "BASIC", 0x92, 1 }, { "VALUE", "DIGEST", 0x93, 1 }, { "VALUE", "AAA", 0xE0 }, { "VALUE", "HA", 0xE1 }, { "VALUE", "INLINE", 0x6 }, }; #define OMA_VALUE_TAG 0x06 #define NUMBER_OF_OMA_ATTRIBUTES sizeof(oma_ota_attributes)/sizeof(oma_ota_attributes[0]) #include "xml_definitions.h" /**************************************************************************** * * Prototypes of internal functions. Note that 'Ptr' means here '*'. */ static int parse_document(xmlDocPtr document, Octstr *charset, simple_binary_t **ota_binary); static int parse_node(xmlNodePtr node, simple_binary_t **otabxml); static int parse_element(xmlNodePtr node, simple_binary_t **otabxml); static int parse_attribute(xmlAttrPtr attr, simple_binary_t **otabxml); /*************************************************************************** * * Implementation of the external function */ int ota_compile(Octstr *ota_doc, Octstr *charset, Octstr **ota_binary) { simple_binary_t *otabxml; int ret; xmlDocPtr pDoc; size_t size; char *ota_c_text; *ota_binary = octstr_create(""); otabxml = simple_binary_create(); octstr_strip_blanks(ota_doc); octstr_shrink_blanks(ota_doc); set_charset(ota_doc, charset); size = octstr_len(ota_doc); ota_c_text = octstr_get_cstr(ota_doc); pDoc = xmlParseMemory(ota_c_text, size); ret = 0; if (pDoc) { ret = parse_document(pDoc, charset, &otabxml); simple_binary_output(*ota_binary, otabxml); xmlFreeDoc(pDoc); } else { xmlFreeDoc(pDoc); octstr_destroy(*ota_binary); simple_binary_destroy(otabxml); error(0, "OTA: No document to parse. Probably an error in OTA source"); return -1; } simple_binary_destroy(otabxml); return ret; } /***************************************************************************** * * Implementation of internal functions * * Parse document node. Store wbmxl version number and character set into the * start of the document. There are no wapforum public identifier for ota. * FIXME: Add parse_prologue! */ static int parse_document(xmlDocPtr document, Octstr *charset, simple_binary_t **otabxml) { xmlNodePtr node; if (document->intSubset && document->intSubset->ExternalID && strcmp((char *)document->intSubset->ExternalID, "-//WAPFORUM//DTD PROV 1.0//EN") == 0) { /* OMA ProvCont */ (*otabxml)->wbxml_version = 0x03; /* WBXML Version number 1.3 */ (*otabxml)->public_id = 0x0B; /* Public id for this kind of doc */ } else { /* OTA */ (*otabxml)->wbxml_version = 0x01; /* WBXML Version number 1.1 */ (*otabxml)->public_id = 0x01; /* Public id for an unknown document type */ } (*otabxml)->code_page = 0; charset = octstr_create("UTF-8"); (*otabxml)->charset = parse_charset(charset); octstr_destroy(charset); node = xmlDocGetRootElement(document); return parse_node(node, otabxml); } /* * The recursive parsing function for the parsing tree. Function checks the * type of the node, calls for the right parse function for the type, then * calls itself for the first child of the current node if there's one and * after that calls itself for the next child on the list. */ static int parse_node(xmlNodePtr node, simple_binary_t **otabxml) { int status = 0; /* Call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_element(node, otabxml); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * OTA. Therefore they are assumed to be an error. */ default: error(0, "OTA compiler: Unknown XML node in the OTA source."); return -1; break; } /* * If node is an element with content, it will need an end tag after it's * children. The status for it is returned by parse_element. */ switch (status) { case 0: if (node->children != NULL && parse_node(node->children, otabxml) == -1) return -1; break; case 1: if (node->children != NULL && parse_node(node->children, otabxml) == -1) return -1; parse_end(otabxml); break; case -1: /* Something went wrong in the parsing. */ return -1; break; default: warning(0,"OTA compiler: Undefined return value in a parse function."); return -1; break; } if (node->next != NULL && parse_node(node->next, otabxml) == -1) return -1; return 0; } /* * Parse only valid syncsettings tags. Output element tags as binary * tokens. If the element has CDATA content, output it. * Returns: 1, add an end tag (element node has no children) * 0, do not add an end tag (it has children) * -1, an error occurred */ static int parse_ota_syncsettings(xmlNodePtr node, simple_binary_t **otabxml) { Octstr *name, *content; unsigned char status_bits, ota_hex; int add_end_tag; size_t i; name = NULL; content = NULL; name = octstr_create((char *)node->name); if (octstr_len(name) == 0) { goto error; } i = 0; while (i < NUMBER_OF_SYNCSETTINGS_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(ota_syncsettings_elements[i].name)) == 0) break; ++i; } if (i == NUMBER_OF_SYNCSETTINGS_ELEMENTS) { goto error; } ota_hex = ota_syncsettings_elements[i].token; output_char(ota_syncsettings_elements[i].token, otabxml); /* if the node has CDATA content output it. * Else expect child tags */ if (!only_blanks((char *)node->children->content)) { content = octstr_create((char *)node->children->content); parse_inline_string(content, otabxml); } add_end_tag = 0; if ((status_bits = element_check_content(node)) > 0) { ota_hex = ota_hex | status_bits; /* If this node has children, the end tag must be added after them. */ if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) { add_end_tag = 1; } } octstr_destroy(content); octstr_destroy(name); return add_end_tag; error: warning(0, "OTA compiler: Unknown tag '%s' in OTA SyncSettings source", octstr_get_cstr(name)); octstr_destroy(content); octstr_destroy(name); return -1; } /* * Parse an element node. Check if there is a token for an element tag; if not * output the element as a string, else output the token. After that, call * attribute parsing functions * Returns: 1, add an end tag (element node has no children) * 0, do not add an end tag (it has children) * -1, an error occurred */ static int parse_element(xmlNodePtr node, simple_binary_t **otabxml) { Octstr *name; size_t i; unsigned char status_bits, ota_hex; int add_end_tag, syncstat; xmlAttrPtr attribute; /* if compiling a syncsettings document there's no need to continue with the parsing of ota or oma tags. */ syncstat = -1; if (octstr_search_char((**otabxml).binary, 0x55, 0) == 0) { syncstat = parse_ota_syncsettings(node, otabxml); if (syncstat >= 0) { return syncstat; } } name = octstr_create((char *)node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_ELEMENTS) { if (octstr_case_compare(name, octstr_imm(ota_elements[i].name)) == 0) break; ++i; } status_bits = 0x00; ota_hex = 0x00; add_end_tag = 0; if (i != NUMBER_OF_ELEMENTS) { ota_hex = ota_elements[i].token; if ((status_bits = element_check_content(node)) > 0) { ota_hex = ota_hex | status_bits; if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) add_end_tag = 1; } output_char(ota_hex, otabxml); } else { warning(0, "OTA compiler: Unknown tag '%s' in OTA source", octstr_get_cstr(name)); ota_hex = WBXML_LITERAL; if ((status_bits = element_check_content(node)) > 0) { ota_hex = ota_hex | status_bits; /* If this node has children, the end tag must be added after them. */ if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) add_end_tag = 1; } output_char(ota_hex, otabxml); output_octet_string(octstr_duplicate(name), otabxml); } if (node->properties != NULL) { attribute = node->properties; while (attribute != NULL) { parse_attribute(attribute, otabxml); attribute = attribute->next; } parse_end(otabxml); } octstr_destroy(name); return add_end_tag; } /* * Tokenises an attribute, and in most cases, its value. (Some values are re- * presented as an inline string). Tokenisation is based on tables in ota, * chapters 8.1 and 8.2. * Returns 0 when success, -1 when error. */ static int parse_attribute(xmlAttrPtr attr, simple_binary_t **otabxml) { Octstr *name, *value, *valueos, *nameos; unsigned char ota_hex; size_t i, limit; ota_3table_t *alist; name = octstr_create((char *)attr->name); if (attr->children != NULL) value = create_octstr_from_node((char *)attr->children); else value = NULL; if (value == NULL) goto error; /* OMA has it's own dedicated public ID, so use this */ if ((*otabxml)->public_id == 0x0B) { alist = oma_ota_attributes; limit = NUMBER_OF_OMA_ATTRIBUTES; } else { alist = ota_attributes; limit = NUMBER_OF_ATTRIBUTES; } i = 0; valueos = NULL; nameos = NULL; while (i < limit) { nameos = octstr_imm(alist[i].name); if (octstr_case_compare(name, nameos) == 0) { if (alist[i].value != NULL) { valueos = octstr_imm(alist[i].value); } if (octstr_case_compare(value, valueos) == 0) { break; } if (octstr_compare(valueos, octstr_imm("INLINE")) == 0) { break; } } ++i; } if (i == limit) { warning(0, "OTA compiler: Unknown attribute '%s' in OTA source, " "with value '%s'.", octstr_get_cstr(name), octstr_get_cstr(value)); goto error; } ota_hex = alist[i].token; /* if not inline used */ if (octstr_compare(valueos, octstr_imm("INLINE")) != 0) { /* Switch code page. */ if (alist[i].code_page != (*otabxml)->code_page) { output_char(0, otabxml); output_char(alist[i].code_page, otabxml); (*otabxml)->code_page = alist[i].code_page; } /* if OMA add value tag */ if ((*otabxml)->public_id == 0x0B && name && octstr_case_compare(name, octstr_imm("value")) == 0) output_char(OMA_VALUE_TAG, otabxml); output_char(ota_hex, otabxml); } else { /* Switch code page. */ if (alist[i].code_page != (*otabxml)->code_page) { output_char(0, otabxml); output_char(alist[i].code_page, otabxml); (*otabxml)->code_page = alist[i].code_page; } output_char(ota_hex, otabxml); parse_inline_string(value, otabxml); } octstr_destroy(name); octstr_destroy(value); return 0; error: octstr_destroy(name); octstr_destroy(value); return -1; } gateway-1.4.5/gw/wap_push_ota.h0000644000175000017500000000643513227613126015156 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Push OTA header * * By Aarno Syvänen for Wapit Ltd. */ #ifndef WAP_PUSH_OTA_H #define WAP_PUSH_OTA_H #include "wap/wap_events.h" #include "wap/wap.h" #define CURRENT_VERSION 0; #define CONNECTED_PORT 9201; /* * Type of bearers (see WDP, Appendix C. pp. 78-79). Only one supported */ enum { GSM_CSD_IPV4 = 0x0A }; void wap_push_ota_init(wap_dispatch_func_t *wsp_dispatch, wap_dispatch_func_t *wsp_unit_dispatch); void wap_push_ota_shutdown(void); void wap_push_ota_dispatch_event(WAPEvent *e); void wap_push_ota_bb_address_set(Octstr *ba); #endif gateway-1.4.5/gw/wap_ppg_push_machine.def0000644000175000017500000001426413227613126017153 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_ppg_session_machine.def: macro call to generate the machine to store * data for WAP connected pushes. * See architecture document for guidance how to use this. * * Fields of the machine have following meaning: * a) Identification: pi_push_id, push_id, sender_address * * b) Implementing PAP attribute (see PPG Services, Chapter 6): * message_state, code, desc, event_time, delivery_method * * c) Session this push uses: session_id, addr_tuple * * d) fields to implement time dependent push: timestamp and field to * store the message * * e) field to implement priority: a priority field. Priority scheme * stores the message, too. * * f) fields to store push message data until the session is establish- * ed: push headers, push data, push capabilities. * * g) field to define network and bearer PI is asking: address_type * * h) fields to specify reporting to PI: progress_notes_requested, ppg_ * notify_requested_to * * i) PI authentication fields: authentication fields for this push: * authenticated, trusted. * * j) Smsc used for pushing * * k) fields used for delivery reports: dlr_url, dlr_mask, smsbox_id, * service_name * * By Aarno Syvänen for Wapit Ltd, for Wiral Ltd and for Global Networks Inc */ #if !defined(MACHINE) #error "Macro MACHINE is missing" #elif !defined(INTEGER) #error "Macro INTEGER is missing" #elif !defined(OCTSTR) #error "Macro OCTSTR is missing" #elif !defined(OPTIONAL_OCTSTR) #error "Macro OPTIONAL_OCTSTR is missing" #elif !defined(ADDRTUPLE) #error "Macro ADDRTUPLE is missing" #elif !defined(CAPABILITIES) #error "Macro CAPABILITIES is missing" #elif !defined(HTTPHEADER) #error "Macro HTTPHEADER is missing" #endif MACHINE(OCTSTR(pi_push_id) /* this id is selected by PI and SHOULD include data separating different PIs */ INTEGER(push_id) /* this id is generated by Kannel */ OPTIONAL_OCTSTR(sender_address) /* PPG address known by PI */ INTEGER(message_state) /* Implementing PAP attribute */ INTEGER(code) OPTIONAL_OCTSTR(desc) OCTSTR(event_time) INTEGER(delivery_method) INTEGER(session_id) /* link to the push session */ ADDRTUPLE(addr_tuple) OPTIONAL_OCTSTR(deliver_after_timestamp) /* for time dependent push, in PAP format */ INTEGER(priority) /* for QoS attribute priority */ HTTPHEADER(push_headers) OPTIONAL_OCTSTR(push_data) INTEGER(address_type) /* defining the network */ INTEGER(progress_notes_requested)/* do we send progress notes about this push */ OPTIONAL_OCTSTR(ppg_notify_requested_to) /* do we notify PI the results */ INTEGER(authenticated) /* transferring trust from the client to PPG */ INTEGER(trusted) OPTIONAL_OCTSTR(smsc_id) /* smsc used for pushes */ OPTIONAL_OCTSTR(dlr_url) /* for delivery reports */ INTEGER(dlr_mask) OPTIONAL_OCTSTR(smsbox_id) OPTIONAL_OCTSTR(service_name) ) #undef MACHINE #undef INTEGER #undef OCTSTR #undef OPTIONAL_OCTSTR #undef ADDRTUPLE #undef CAPABILITIES #undef HTTPHEADER gateway-1.4.5/gw/wbxml_tokens.def0000644000175000017500000001334613227613126015507 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /**** Preprocessor magic ****/ /* Entry in a LINEAR table. Default is to do nothing for it. */ #if !defined(STRING) #define STRING #endif /* String table where entries have assigned numbers. Multiple * entries can have the same number (the first listed entry is used * when looking up by number). */ #if !defined(NUMBERED) #define NUMBERED LINEAR #endif /* Entry in a NUMBERED table */ #if !defined(ASSIGN) #define ASSIGN(string, number) STRING(string) #endif /**** End of preprocessor magic. Tables start here. ****/ /* Registered WSP Content Type Codes Assignments. * Now they are maintained by OMNA, see URL * * http://www.openmobilealliance.org/tech/omna/index.htm (depricated) * http://www.openmobilealliance.org/Technical/omna/omna-wbxml-public-docid.aspx */ NUMBERED(public_ids, /* Well-Known Values */ ASSIGN("-//WAPFORUM//DTD WML 1.0//EN", 0x02) ASSIGN("-//WAPFORUM//DTD WTA 1.0//EN", 0x03) ASSIGN("-//WAPFORUM//DTD WML 1.1//EN", 0x04) ASSIGN("-//WAPFORUM//DTD SI 1.0//EN", 0x05) ASSIGN("-//WAPFORUM//DTD SL 1.0//EN", 0x06) ASSIGN("-//WAPFORUM//DTD CO 1.0//EN", 0x07) ASSIGN("-//WAPFORUM//DTD CHANNEL 1.1//EN", 0x08) ASSIGN("-//WAPFORUM//DTD WML 1.2//EN", 0x09) ASSIGN("-//WAPFORUM//DTD WML 1.3//EN", 0x0A) ASSIGN("-//WAPFORUM//DTD PROV 1.0//EN", 0x0B) ASSIGN("-//WAPFORUM//DTD WTA-WML 1.2//EN", 0x0C) ASSIGN("-//WAPFORUM//DTD EMN 1.0//EN", 0x0D) ASSIGN("-//OMA//DTD DRMREL 1.0//EN", 0x0E) ASSIGN("-//WIRELESSVILLAGE//DTD CSP 1.0//EN", 0x0F) ASSIGN("-//WIRELESSVILLAGE//DTD CSP 1.1//EN", 0x10) ASSIGN("-//OMA//DTD WV-CSP 1.2//EN", 0x11) ASSIGN("-//OMA//DTD IMPS-CSP 1.3//EN", 0x12) ASSIGN("-//OMA//DRM 2.1//EN", 0x13) ASSIGN("-//OMA//SRM 1.0//EN", 0x14) /* Registered Values */ ASSIGN("-//PHONE.COM//DTD ALERT 1.0//EN", 0x1100) ASSIGN("-//PHONE.COM//DTD CACHE-OPERATION 1.0//EN", 0x1101) ASSIGN("-//PHONE.COM//DTD SIGNAL 1.0//EN", 0x1102) ASSIGN("-//PHONE.COM//DTD LIST 1.0//EN", 0x1103) ASSIGN("-//PHONE.COM//DTD LISTCMD 1.0//EN", 0x1104) ASSIGN("-//PHONE.COM//DTD CHANNEL 1.0//EN", 0x1105) ASSIGN("-//PHONE.COM//DTD MMC 1.0//EN", 0x1106) ASSIGN("-//PHONE.COM//DTD BEARER-CHOICE 1.0//EN", 0x1107) ASSIGN("-//PHONE.COM//DTD WML 1.1//EN", 0x1108) ASSIGN("-//PHONE.COM//DTD CHANNEL 1.1//EN", 0x1109) ASSIGN("-//PHONE.COM//DTD LIST 1.1//EN", 0x110A) ASSIGN("-//PHONE.COM//DTD LISTCMD 1.1//EN", 0x110B) ASSIGN("-//PHONE.COM//DTD MMC 1.1//EN", 0x110C) ASSIGN("-//PHONE.COM//DTD WML 1.3//EN", 0x110D) ASSIGN("-//PHONE.COM//DTD MMC 2.0//EN", 0x110E) ASSIGN("-//3GPP2.COM//DTD IOTA 1.0//EN", 0x1200) ASSIGN("-//SYNCML//DTD SyncML 1.2//EN", 0x1201) ASSIGN("-//SYNCML//DTD MetaInf 1.2//EN", 0x1202) ASSIGN("-//SYNCML//DTD DevInf 1.2//EN", 0x1203) ASSIGN("-//NOKIA//DTD LANDMARKS 1.0//EN", 0x1204) ) /**** More preprocessor magic ****/ #undef STRING #undef NUMBERED #undef ASSIGN gateway-1.4.5/gw/smsc/0000755000175000017500000000000013312227712013246 5ustar toljtoljgateway-1.4.5/gw/smsc/smsc.h0000644000175000017500000001032713227613126014372 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc.h - interface to SMS center subsystem * * Lars Wirzenius for WapIT Ltd. * * New API by Kalle Marjola 1999 */ #ifndef SMSC_H #define SMSC_H #include #include #include #include "gwlib/gwlib.h" #include "msg.h" /* * A data structure representing an SMS center. This data structure * is opaque: users MUST NOT use the fields directly, only the * smsc_* functions may do so. */ typedef struct SMSCenter SMSCenter; /* Open the connection to an SMS center. 'grp' is a configgroup which determines the sms center. See details from sample configuration file 'kannel.conf' The operation returns NULL for error and the pointer to the new SMSCenter structure for OK. */ SMSCenter *smsc_open(CfgGroup *grp); /* * reopen once opened SMS Center connection. Close old connection if * exists * * return 0 on success * return -1 if failed * return -2 if failed and no use to repeat the progress (i.e. currently * reopen not implemented) */ int smsc_reopen(SMSCenter *smsc); /* Return the `name' of an SMC center. Name is defined here as a string that a human understands that uniquely identifies the SMSC. This operation cannot fail. */ char *smsc_name(SMSCenter *smsc); /* Close the connection to an SMS center. Return -1 for error (the connection will be closed anyway, but there was some error while doing so, so it wasn't closed cleanly), or 0 for OK. Return 0 if the smsc is NULL or smsc is already closed. */ int smsc_close(SMSCenter *smsc); #endif gateway-1.4.5/gw/smsc/smsc_fake.c0000644000175000017500000004677213227613126015370 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_fake.c - interface to fakesmsc.c * * Uoti Urpala 2001 */ /* Doesn't support multi-send * Doesn't warn about unrecognized configuration variables */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "msg.h" #include "sms.h" #include "dlr.h" typedef struct privdata { List *outgoing_queue; long connection_thread; int shutdown; /* Signal to the connection thread to shut down */ int listening_socket; /* File descriptor */ int port; /* Port number to listen */ Octstr *allow_ip, *deny_ip; } PrivData; static int fake_open_connection(SMSCConn *conn, PrivData *privdata) { int s; if ((s = make_server_socket(privdata->port, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL))) == -1) { error(0, "smsc_fake: could not create listening socket in port %d", privdata->port); return -1; } if (socket_set_blocking(s, 0) == -1) { error(0, "smsc_fake: couldn't make listening socket port %d non-blocking", privdata->port); return -1; } privdata->listening_socket = s; return 0; } static int sms_to_client(Connection *client, Msg *msg) { Octstr *line; Octstr *msgdata = NULL; /* NULL to allow octstr_destroy */ debug("bb.sms", 0, "smsc_fake: sending message to client"); /* msg_dump(msg, 0); */ line = octstr_duplicate(msg->sms.sender); octstr_append_char(line, ' '); octstr_append(line, msg->sms.receiver); if (octstr_len(msg->sms.udhdata)) { octstr_append(line, octstr_imm(" udh ")); msgdata = octstr_duplicate(msg->sms.udhdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); octstr_destroy(msgdata); octstr_append(line, octstr_imm(" data ")); msgdata = octstr_duplicate(msg->sms.msgdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); } else { if (msg->sms.coding == DC_8BIT) { octstr_append(line, octstr_imm(" data ")); msgdata = octstr_duplicate(msg->sms.msgdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); } else if (msg->sms.coding == DC_UCS2) { octstr_append(line, octstr_imm(" ucs-2 ")); msgdata = octstr_duplicate(msg->sms.msgdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); } else { octstr_append(line, octstr_imm(" text ")); octstr_append(line, msg->sms.msgdata); } } octstr_append_char(line, 10); if (conn_write(client, line) == -1) { octstr_destroy(msgdata); octstr_destroy(line); return -1; } octstr_destroy(msgdata); octstr_destroy(line); return 1; } static void msg_to_bb(SMSCConn *conn, Octstr *line) { long p, p2; Msg *msg; Octstr *type = NULL; /* might be destroyed after error before created */ msg = msg_create(sms); p = octstr_search_char(line, ' ', 0); if (p == -1) goto error; msg->sms.sender = octstr_copy(line, 0, p); p2 = octstr_search_char(line, ' ', p + 1); if (p2 == -1) goto error; msg->sms.receiver = octstr_copy(line, p + 1, p2 - p - 1); p = octstr_search_char(line, ' ', p2 + 1); if (p == -1) goto error; type = octstr_copy(line, p2 + 1, p - p2 - 1); if (!octstr_compare(type, octstr_imm("text"))) { msg->sms.msgdata = octstr_copy(line, p + 1, LONG_MAX); msg->sms.coding = DC_7BIT; } else if (!octstr_compare(type, octstr_imm("data"))) { msg->sms.msgdata = octstr_copy(line, p + 1, LONG_MAX); msg->sms.coding = DC_8BIT; if (octstr_url_decode(msg->sms.msgdata) == -1) warning(0, "smsc_fake: url-encoded data from client looks malformed"); } else if (!octstr_compare(type, octstr_imm("ucs2"))) { msg->sms.msgdata = octstr_copy(line, p + 1, LONG_MAX); msg->sms.coding = DC_UCS2; if (octstr_url_decode(msg->sms.msgdata) == -1) warning(0, "smsc_fake: url-encoded data from client looks malformed"); } else if (!octstr_compare(type, octstr_imm("route"))) { p2 = octstr_search_char(line, ' ', p + 1); if (p2 == -1) goto error; msg->sms.boxc_id = octstr_copy(line, p + 1, p2 - p - 1); msg->sms.msgdata = octstr_copy(line, p2 + 1, LONG_MAX); } else if (!octstr_compare(type, octstr_imm("udh-data")) || !octstr_compare(type, octstr_imm("udh"))) { p2 = octstr_search_char(line, ' ', p + 1); if (p2 == -1) goto error; msg->sms.udhdata = octstr_copy(line, p + 1, p2 - p - 1); msg->sms.msgdata = octstr_copy(line, p2 + 1, LONG_MAX); if (msg->sms.coding == DC_UNDEF) msg->sms.coding = DC_8BIT; if (octstr_url_decode(msg->sms.msgdata) == -1 || octstr_url_decode(msg->sms.udhdata) == -1) warning(0, "smsc_fake: url-encoded data from client looks malformed"); } else if (!octstr_compare(type, octstr_imm("udh-text"))) { p2 = octstr_search_char(line, ' ', p + 1); if (p2 == -1) goto error; msg->sms.udhdata = octstr_copy(line, p + 1, p2 - p - 1); msg->sms.msgdata = octstr_copy(line, p2 + 1, LONG_MAX); if (msg->sms.coding == DC_UNDEF) msg->sms.coding = DC_7BIT; if (octstr_url_decode(msg->sms.udhdata) == -1) warning(0, "smsc_fake: url-encoded udh data from client looks malformed"); } else if (!octstr_compare(type, octstr_imm("dlr-mask"))) { Octstr *tmp; p2 = octstr_search_char(line, ' ', p + 1); if (p2 == -1) goto error; tmp = octstr_copy(line, p + 1, p2 - p - 1); msg->sms.dlr_mask = atoi(octstr_get_cstr(tmp)); octstr_destroy(tmp); msg->sms.msgdata = octstr_copy(line, p2 + 1, LONG_MAX); } else goto error; octstr_destroy(line); octstr_destroy(type); time(&msg->sms.time); msg->sms.smsc_id = octstr_duplicate(conn->id); debug("bb.sms", 0, "smsc_fake: new message received"); /* msg_dump(msg, 0); */ bb_smscconn_receive(conn, msg); return; error: warning(0, "smsc_fake: invalid message syntax from client, ignored"); msg_destroy(msg); octstr_destroy(line); octstr_destroy(type); return; } static void main_connection_loop(SMSCConn *conn, Connection *client) { PrivData *privdata = conn->data; Octstr *line; Msg *msg; double delay = 0; if (conn->throughput > 0) { delay = 1.0 / conn->throughput; } while (1) { while (!conn->is_stopped && !privdata->shutdown && (line = conn_read_line(client))) msg_to_bb(conn, line); if (conn_error(client)) goto error; if (conn_eof(client)) goto eof; /* * We won't get DLRs from fakesmsc itself, due that we don't have * corresponding message IDs etc. We threat the DLR receiving here. So * DLR "originate" from the protocol layer towards abstraction layer. * This is all for pure debugging and testing. */ while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) { /* pass msg to fakesmsc daemon */ if (sms_to_client(client, msg) == 1) { Msg *copy = msg_duplicate(msg); /* * Actually no guarantee of it having been really sent, * but I suppose that doesn't matter since this interface * is just for debugging anyway. The upper layer will send * a SMSC success DLR if mask is set. Be aware that msg is * destroyed in abstraction layer, that's why we use a copy * afterwards to handle the final DLR. */ bb_smscconn_sent(conn, msg, NULL); /* and now the final DLR */ if (DLR_IS_SUCCESS_OR_FAIL(copy->sms.dlr_mask)) { Msg *dlrmsg; Octstr *tmp; int dlrstat = DLR_SUCCESS; char id[UUID_STR_LEN + 1]; uuid_unparse(copy->sms.id, id); tmp = octstr_create(id); dlrmsg = dlr_find(conn->id, tmp, /* smsc message id */ copy->sms.receiver, /* destination */ dlrstat, 0); if (dlrmsg != NULL) { /* XXX TODO: Provide a SMPP DLR text in msgdata */ bb_smscconn_receive(conn, dlrmsg); } else { error(0,"smsc_fale: got DLR but could not find message or " "was not interested in it"); } octstr_destroy(tmp); } msg_destroy(copy); } else { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED")); goto error; } /* obey throughput speed limit, if any */ if (conn->throughput > 0) { gwthread_sleep(delay); } } if (privdata->shutdown) { debug("bb.sms", 0, "smsc_fake shutting down, closing client socket"); conn_destroy(client); return; } conn_wait(client, -1); if (conn_error(client)) goto error; if (conn_eof(client)) goto eof; } error: info(0, "IO error to fakesmsc client. Closing connection."); conn_destroy(client); return; eof: info(0, "EOF from fakesmsc client. Closing connection."); conn_destroy(client); return; } static void fake_listener(void *arg) { SMSCConn *conn = arg; PrivData *privdata = conn->data; struct sockaddr_in client_addr; socklen_t client_addr_len; Octstr *ip; Connection *client; int s, ret; Msg *msg; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (1) { client_addr_len = sizeof(client_addr); ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1); if (ret == -1) { if (errno == EINTR) continue; error(0, "Poll for fakesmsc connections failed, shutting down"); break; } if (privdata->shutdown) break; if (ret == 0) /* * This thread was woke up from elsewhere, but * if we're not shutting down nothing to do here. */ continue; s = accept(privdata->listening_socket, (struct sockaddr *)&client_addr, &client_addr_len); if (s == -1) { warning(errno, "fake_listener: accept() failed, retrying..."); continue; } ip = host_ip(client_addr); if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) { info(0, "Fakesmsc connection tried from denied host <%s>, " "disconnected", octstr_get_cstr(ip)); octstr_destroy(ip); close(s); continue; } client = conn_wrap_fd(s, 0); if (client == NULL) { error(0, "fake_listener: conn_wrap_fd failed on accept()ed fd"); octstr_destroy(ip); close(s); continue; } conn_claim(client); info(0, "Fakesmsc client connected from %s", octstr_get_cstr(ip)); octstr_destroy(ip); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); main_connection_loop(conn, client); if (privdata->shutdown) break; mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); } } if (close(privdata->listening_socket) == -1) warning(errno, "smsc_fake: couldn't close listening socket at shutdown"); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } gwlist_destroy(privdata->outgoing_queue, NULL); octstr_destroy(privdata->allow_ip); octstr_destroy(privdata->deny_ip); gw_free(privdata); conn->data = NULL; mutex_unlock(conn->flow_mutex); debug("bb.sms", 0, "smsc_fake connection has completed shutdown."); bb_smscconn_killed(); } static int add_msg_cb(SMSCConn *conn, Msg *sms) { PrivData *privdata = conn->data; Msg *copy; copy = msg_duplicate(sms); /* * Send DLR if desired, which means first add the DLR entry * and then later find it and remove it. We need to ensure * that we put the DLR in first before producing the copy * to the list. */ if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask)) { Octstr *tmp; char id[UUID_STR_LEN + 1]; uuid_unparse(sms->sms.id, id); tmp = octstr_format("%s", id); dlr_add(conn->id, tmp, sms, 0); octstr_destroy(tmp); } gwlist_produce(privdata->outgoing_queue, copy); gwthread_wakeup(privdata->connection_thread); return 0; } static int shutdown_cb(SMSCConn *conn, int finish_sending) { PrivData *privdata = conn->data; debug("bb.sms", 0, "Shutting down SMSCConn FAKE, %s", finish_sending ? "slow" : "instant"); /* * Documentation claims this would have been done by smscconn.c, * but isn't when this code is being written. */ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; privdata->shutdown = 1; /* * Separate from why_killed to avoid locking, as * why_killed may be changed from outside? */ if (finish_sending == 0) { Msg *msg; while((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } } gwthread_wakeup(privdata->connection_thread); return 0; } static void start_cb(SMSCConn *conn) { PrivData *privdata = conn->data; /* in case there are messages in the buffer already */ gwthread_wakeup(privdata->connection_thread); debug("bb.sms", 0, "smsc_fake: start called"); } static long queued_cb(SMSCConn *conn) { PrivData *privdata = conn->data; long ret; ret = (privdata ? gwlist_len(privdata->outgoing_queue) : 0); /* use internal queue as load, maybe something else later */ conn->load = ret; return ret; } int smsc_fake_create(SMSCConn *conn, CfgGroup *cfg) { PrivData *privdata = NULL; Octstr *allow_ip, *deny_ip; long portno; /* has to be long because of cfg_get_integer */ if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) portno = 0; allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip")); if (allow_ip) deny_ip = octstr_create("*.*.*.*"); else deny_ip = NULL; if (portno == 0) { error(0, "'port' invalid in 'fake' record."); goto error; } privdata = gw_malloc(sizeof(PrivData)); privdata->listening_socket = -1; privdata->port = portno; privdata->allow_ip = allow_ip; privdata->deny_ip = deny_ip; if (fake_open_connection(conn, privdata) < 0) { gw_free(privdata); privdata = NULL; goto error; } conn->data = privdata; conn->name = octstr_format("FAKE:%d", privdata->port); privdata->outgoing_queue = gwlist_create(); privdata->shutdown = 0; conn->status = SMSCCONN_CONNECTING; conn->connect_time = time(NULL); if ((privdata->connection_thread = gwthread_create(fake_listener, conn)) == -1) goto error; conn->shutdown = shutdown_cb; conn->queued = queued_cb; conn->start_conn = start_cb; conn->send_msg = add_msg_cb; return 0; error: error(0, "Failed to create fake smsc connection"); if (privdata != NULL) { gwlist_destroy(privdata->outgoing_queue, NULL); if (close(privdata->listening_socket == -1)) { error(errno, "smsc_fake: closing listening socket port %d failed", privdata->listening_socket); } } gw_free(privdata); octstr_destroy(allow_ip); octstr_destroy(deny_ip); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; return -1; } gateway-1.4.5/gw/smsc/smsc_wrapper.c0000644000175000017500000003205013227613126016122 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * SMSC Connection wrapper * * Interface to old SMS center implementations * * Kalle Marjola 2000 */ #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "smsc.h" #include "smsc_p.h" typedef struct smsc_wrapper { SMSCenter *smsc; List *outgoing_queue; List *stopped; /* list-trick for suspend/isolate */ long receiver_thread; long sender_thread; Mutex *reconnect_mutex; } SmscWrapper; static void smscwrapper_destroy(SmscWrapper *wrap) { if (wrap == NULL) return; gwlist_destroy(wrap->outgoing_queue, NULL); gwlist_destroy(wrap->stopped, NULL); mutex_destroy(wrap->reconnect_mutex); if (wrap->smsc != NULL) smsc_close(wrap->smsc); gw_free(wrap); } static int reconnect(SMSCConn *conn) { SmscWrapper *wrap = conn->data; Msg *msg; int ret; int wait = 1; /* disable double-reconnect * NOTE: it is still possible that we do double-connect if * first thread gets through this if-statement and then * execution switches to another thread.. this can be avoided * via double-mutex system, but I do not feel it is worth it, * maybe later --rpr */ if (conn->status == SMSCCONN_RECONNECTING) { mutex_lock(wrap->reconnect_mutex); /* wait here */ mutex_unlock(wrap->reconnect_mutex); return 0; } mutex_lock(wrap->reconnect_mutex); debug("bb.sms", 0, "smsc_wrapper <%s>: reconnect started", octstr_get_cstr(conn->name)); while((msg = gwlist_extract_first(wrap->outgoing_queue))!=NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); } conn->status = SMSCCONN_RECONNECTING; while(conn->why_killed == SMSCCONN_ALIVE) { ret = smsc_reopen(wrap->smsc); if (ret == 0) { info(0, "Re-open of %s succeeded.", octstr_get_cstr(conn->name)); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); break; } else if (ret == -2) { error(0, "Re-open of %s failed permanently", octstr_get_cstr(conn->name)); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(wrap->reconnect_mutex); mutex_unlock(conn->flow_mutex); return -1; /* permanent failure */ } else { error(0, "Re-open to <%s> failed, retrying after %d minutes...", octstr_get_cstr(conn->name), wait); gwthread_sleep(wait*60.0); wait = wait > 10 ? 10 : wait * 2 + 1; } } mutex_unlock(wrap->reconnect_mutex); return 0; } static Msg *sms_receive(SMSCConn *conn) { SmscWrapper *wrap = conn->data; int ret; Msg *newmsg = NULL; if (smscenter_pending_smsmessage(wrap->smsc) == 1) { ret = smscenter_receive_msg(wrap->smsc, &newmsg); if (ret == 1) { /* if any smsc_id available, use it */ newmsg->sms.smsc_id = octstr_duplicate(conn->id); return newmsg; } else if (ret == 0) { /* "NEVER" happens */ warning(0, "SMSC %s: Pending message returned '1', " "but nothing to receive!", octstr_get_cstr(conn->name)); msg_destroy(newmsg); return NULL; } else { msg_destroy(newmsg); if (reconnect(conn) == -1) smscconn_shutdown(conn, 0); return NULL; } } return NULL; } static void wrapper_receiver(void *arg) { Msg *msg; SMSCConn *conn = arg; SmscWrapper *wrap = conn->data; /* SmscWrapper *wrap = conn->data; ** non-used */ double sleep = 0.0001; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* remove messages from SMSC until we are killed */ while(conn->why_killed == SMSCCONN_ALIVE) { gwlist_consume(wrap->stopped); /* block here if suspended/isolated */ msg = sms_receive(conn); if (msg) { debug("bb.sms", 0, "smscconn (%s): new message received", octstr_get_cstr(conn->name)); sleep = 0.0001; bb_smscconn_receive(conn, msg); } else { /* note that this implementations means that we sleep even * when we fail connection.. but time is very short, anyway */ gwthread_sleep(sleep); /* gradually sleep longer and longer times until something starts to * happen - this of course reduces response time, but that's better than * extensive CPU usage when it is not used */ sleep *= 2; if (sleep >= 2.0) sleep = 1.999999; } } conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; /* this thread is joined at sender */ } static int sms_send(SMSCConn *conn, Msg *msg) { SmscWrapper *wrap = conn->data; int ret; debug("bb.sms", 0, "smscconn_sender (%s): sending message", octstr_get_cstr(conn->name)); ret = smscenter_submit_msg(wrap->smsc, msg); if (ret == -1) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED")); if (reconnect(conn) == -1) smscconn_shutdown(conn, 0); return -1; } else { bb_smscconn_sent(conn, msg, NULL); return 0; } } static void wrapper_sender(void *arg) { Msg *msg; SMSCConn *conn = arg; SmscWrapper *wrap = conn->data; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* send messages to SMSC until our outgoing_list is empty and * no producer anymore (we are set to shutdown) */ while(conn->status != SMSCCONN_DEAD) { if ((msg = gwlist_consume(wrap->outgoing_queue)) == NULL) break; if (octstr_search_char(msg->sms.receiver, ' ', 0) != -1) { /* * multi-send: this should be implemented in corresponding * SMSC protocol, but while we are waiting for that... */ int i; Msg *newmsg; /* split from spaces: in future, split with something more sensible, * this is dangerous... (as space is url-encoded as '+') */ List *nlist = octstr_split_words(msg->sms.receiver); debug("bb.sms", 0, "Handling multi-receiver message"); for(i=0; i < gwlist_len(nlist); i++) { newmsg = msg_duplicate(msg); octstr_destroy(newmsg->sms.receiver); newmsg->sms.receiver = gwlist_get(nlist, i); sms_send(conn, newmsg); } gwlist_destroy(nlist, NULL); msg_destroy(msg); } else sms_send(conn,msg); } /* cleanup, we are now dying */ debug("bb.sms", 0, "SMSCConn %s sender died, waiting for receiver", octstr_get_cstr(conn->name)); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; if (conn->is_stopped) { gwlist_remove_producer(wrap->stopped); conn->is_stopped = 0; } gwthread_wakeup(wrap->receiver_thread); gwthread_join(wrap->receiver_thread); /* call 'failed' to all messages still in queue */ mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; while((msg = gwlist_extract_first(wrap->outgoing_queue))!=NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } smscwrapper_destroy(wrap); conn->data = NULL; mutex_unlock(conn->flow_mutex); bb_smscconn_killed(); } static int wrapper_add_msg(SMSCConn *conn, Msg *sms) { SmscWrapper *wrap = conn->data; Msg *copy; copy = msg_duplicate(sms); gwlist_produce(wrap->outgoing_queue, copy); return 0; } static int wrapper_shutdown(SMSCConn *conn, int finish_sending) { SmscWrapper *wrap = conn->data; debug("bb.sms", 0, "Shutting down SMSCConn %s, %s", octstr_get_cstr(conn->name), finish_sending ? "slow" : "instant"); if (finish_sending == 0) { Msg *msg; while((msg = gwlist_extract_first(wrap->outgoing_queue))!=NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } } gwlist_remove_producer(wrap->outgoing_queue); gwthread_wakeup(wrap->sender_thread); gwthread_wakeup(wrap->receiver_thread); return 0; } static void wrapper_stop(SMSCConn *conn) { SmscWrapper *wrap = conn->data; debug("smscconn", 0, "Stopping wrapper"); gwlist_add_producer(wrap->stopped); } static void wrapper_start(SMSCConn *conn) { SmscWrapper *wrap = conn->data; debug("smscconn", 0, "Starting wrapper"); gwlist_remove_producer(wrap->stopped); } static long wrapper_queued(SMSCConn *conn) { SmscWrapper *wrap = conn->data; long ret = gwlist_len(wrap->outgoing_queue); /* use internal queue as load, maybe something else later */ conn->load = ret; return ret; } int smsc_wrapper_create(SMSCConn *conn, CfgGroup *cfg) { /* 1. Call smsc_open() * 2. create sender/receiver threads * 3. fill up the conn * * XXX open() SHOULD be done in distinct thread, not here! */ SmscWrapper *wrap; wrap = gw_malloc(sizeof(SmscWrapper)); wrap->smsc = NULL; conn->data = wrap; conn->send_msg = wrapper_add_msg; wrap->outgoing_queue = gwlist_create(); wrap->stopped = gwlist_create(); wrap->reconnect_mutex = mutex_create(); gwlist_add_producer(wrap->outgoing_queue); if ((wrap->smsc = smsc_open(cfg)) == NULL) goto error; conn->name = octstr_create(smsc_name(wrap->smsc)); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); if (conn->is_stopped) gwlist_add_producer(wrap->stopped); /* XXX here we could fail things... specially if the second one * fails.. so fix this ASAP * * moreover, open should be in sender/receiver, so that we can continue * while trying to open... maybe move this, or just wait for new * implementations of various SMSC protocols */ if ((wrap->receiver_thread = gwthread_create(wrapper_receiver, conn))==-1) goto error; if ((wrap->sender_thread = gwthread_create(wrapper_sender, conn))==-1) goto error; conn->shutdown = wrapper_shutdown; conn->queued = wrapper_queued; conn->stop_conn = wrapper_stop; conn->start_conn = wrapper_start; return 0; error: error(0, "Failed to create Smsc wrapper"); conn->data = NULL; smscwrapper_destroy(wrap); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; return -1; } gateway-1.4.5/gw/smsc/http/0000755000175000017500000000000013312227711014224 5ustar toljtoljgateway-1.4.5/gw/smsc/http/brunet.c0000644000175000017500000002670613227613126015706 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /*---------------------------------------------------------------- * Brunet - A german aggregator (mainly doing T-Mobil D1 connections) * * o bruHTT v1.3L (for MO traffic) * o bruHTP v2.1 (date 22.04.2003) (for MT traffic) * * Stipe Tolj * Tobias Weber */ #include "gwlib/gwlib.h" /* MT related function */ static int brunet_send_sms(SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; Octstr *url, *tid, *xser; List *headers; char id[UUID_STR_LEN + 1]; int dcs; /* * Construct TransactionId. * Beware that brunet needs an "clean" octstr representation, * without the dashes in the string. So remove them. */ uuid_unparse(sms->sms.id, id); tid = octstr_create(id); octstr_replace(tid, octstr_imm("-"), octstr_imm("")); /* form the basic URL */ url = octstr_format("%S?MsIsdn=%E&Originator=%E", conndata->send_url, sms->sms.receiver, sms->sms.sender); /* * We use &binfo= from sendsms interface to encode * additional paramters. If a mandatory value is not set, * a default value is applied */ if (octstr_len(sms->sms.binfo)) { octstr_url_decode(sms->sms.binfo); octstr_format_append(url, "&%S", sms->sms.binfo); } /* CustomerId */ if (octstr_search(url, octstr_create("CustomerId="), 0) == -1) { octstr_format_append(url, "&CustomerId=%S", conndata->username); } /* TransactionId */ if (octstr_search(url, octstr_create("TransactionId="), 0) == -1) { octstr_format_append(url, "&TransactionId=%S", tid); } /* SMSCount */ if (octstr_search(url, octstr_create("SMSCount="), 0) == -1) { octstr_format_append(url, "&%s", "SMSCount=1"); } /* ActionType */ if (octstr_search(url, octstr_create("ActionType="), 0) == -1) { octstr_format_append(url, "&%s", "ActionType=A"); } /* ServiceDeliveryType */ if (octstr_search(url, octstr_create("ServiceDeliveryType="), 0) == -1) { octstr_format_append(url, "&%s", "ServiceDeliveryType=P"); } /* if coding is not set and UDH exists, assume DC_8BIT * else default to DC_7BIT */ if (sms->sms.coding == DC_UNDEF) sms->sms.coding = octstr_len(sms->sms.udhdata) > 0 ? DC_8BIT : DC_7BIT; if (sms->sms.coding == DC_8BIT) octstr_format_append(url, "&MessageType=B&Text=%H", sms->sms.msgdata); else octstr_format_append(url, "&MessageType=S&Text=%E", sms->sms.msgdata); dcs = fields_to_dcs(sms, (sms->sms.alt_dcs != SMS_PARAM_UNDEFINED ? sms->sms.alt_dcs : 0)); /* XSer processing */ xser = octstr_create(""); /* XSer DCS values */ if (dcs != 0 && dcs != 4) octstr_format_append(xser, "0201%02x", dcs & 0xff); /* add UDH header */ if (octstr_len(sms->sms.udhdata)) { octstr_format_append(xser, "01%02x%H", octstr_len(sms->sms.udhdata), sms->sms.udhdata); } if (octstr_len(xser) > 0) octstr_format_append(url, "&XSer=%S", xser); octstr_destroy(xser); headers = http_create_empty_headers(); debug("smsc.http.brunet", 0, "HTTP[%s]: Sending request <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(url)); /* * Brunet requires an SSL-enabled HTTP client call, this is handled * transparently by the Kannel HTTP layer module. */ http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, NULL, 0, sms, NULL); octstr_destroy(url); octstr_destroy(tid); http_destroy_headers(headers); return 0; } /* * Parse a line in the format: * and return a Dict with the name as key and the value as value, * otherwise return NULL if a parsing error occures. */ static Dict *brunet_parse_body(Octstr *body) { Dict *param = NULL; List *words = NULL; long len; Octstr *word; words = octstr_split_words(body); if ((len = gwlist_len(words)) > 0) { param = dict_create(4, (void(*)(void *)) octstr_destroy); while ((word = gwlist_extract_first(words)) != NULL) { List *l = octstr_split(word, octstr_imm("=")); Octstr *key = gwlist_extract_first(l); Octstr *value = gwlist_extract_first(l); if (octstr_len(key)) dict_put(param, key, value); octstr_destroy(key); octstr_destroy(word); gwlist_destroy(l, (void(*)(void *)) octstr_destroy); } } gwlist_destroy(words, (void(*)(void *)) octstr_destroy); return param; } static void brunet_parse_reply(SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body) { if (status == HTTP_OK || status == HTTP_ACCEPTED) { Dict *param; Octstr *status; if ((param = brunet_parse_body(body)) != NULL && (status = dict_get(param, octstr_imm("Status"))) != NULL && octstr_case_compare(status, octstr_imm("0")) == 0) { Octstr *msg_id; /* pass the MessageId for this MT to the logging facility */ if ((msg_id = dict_get(param, octstr_imm("MessageId"))) != NULL) msg->sms.binfo = octstr_duplicate(msg_id); bb_smscconn_sent(conn, msg, NULL); } else { error(0, "HTTP[%s]: Message was malformed. SMSC response `%s'.", octstr_get_cstr(conn->id), octstr_get_cstr(body)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body)); } dict_destroy(param); } else { error(0, "HTTP[%s]: Message was rejected. SMSC response `%s'.", octstr_get_cstr(conn->id), octstr_get_cstr(body)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED, octstr_duplicate(body)); } } /* MO related function */ static void brunet_receive_sms(SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars) { ConnData *conndata = conn->data; Octstr *user, *from, *to, *text, *udh; Octstr *retmsg; int mclass, mwi, coding, validity, deferred; List *reply_headers; int ret; mclass = mwi = coding = validity = deferred = 0; user = http_cgi_variable(cgivars, "CustomerId"); from = http_cgi_variable(cgivars, "MsIsdn"); to = http_cgi_variable(cgivars, "Recipient"); text = http_cgi_variable(cgivars, "SMMO"); udh = http_cgi_variable(cgivars, "XSer"); debug("smsc.http.brunet", 0, "HTTP[%s]: Received a request", octstr_get_cstr(conn->id)); if (user == NULL || octstr_compare(user, conndata->username) != 0) { error(0, "HTTP[%s]: Authorization failure. CustomerId was <%s>.", octstr_get_cstr(conn->id), octstr_get_cstr(user)); retmsg = octstr_create("Authorization failed for MO submission."); } else if (from == NULL || to == NULL || text == NULL) { error(0, "HTTP[%s]: Insufficient args.", octstr_get_cstr(conn->id)); retmsg = octstr_create("Insufficient arguments, rejected."); } else { Msg *msg; msg = msg_create(sms); debug("smsc.http.brunet", 0, "HTTP[%s]: Received new MO SMS.", octstr_get_cstr(conn->id)); msg->sms.sender = octstr_duplicate(from); msg->sms.receiver = octstr_duplicate(to); msg->sms.msgdata = octstr_duplicate(text); msg->sms.udhdata = octstr_duplicate(udh); msg->sms.smsc_id = octstr_duplicate(conn->id); msg->sms.time = time(NULL); /* XXX maybe extract from DateReceived */ msg->sms.mclass = mclass; msg->sms.mwi = mwi; msg->sms.coding = coding; msg->sms.validity = time(NULL) + validity * 60; msg->sms.deferred = time(NULL) + deferred * 60; ret = bb_smscconn_receive(conn, msg); if (ret == -1) retmsg = octstr_create("Status=1"); else retmsg = octstr_create("Status=0"); } reply_headers = gwlist_create(); http_header_add(reply_headers, "Content-Type", "text/plain"); debug("smsc.http.brunet", 0, "HTTP[%s]: Sending reply `%s'.", octstr_get_cstr(conn->id), octstr_get_cstr(retmsg)); http_send_reply(client, HTTP_OK, reply_headers, retmsg); octstr_destroy(retmsg); http_destroy_headers(reply_headers); } static int brunet_init(SMSCConn *conn, CfgGroup *cfg) { ConnData *conndata = conn->data; if (conndata->username == NULL) { error(0, "HTTP[%s]: 'username' (=CustomerId) required for Brunet http smsc", octstr_get_cstr(conn->id)); return -1; } return 0; } struct smsc_http_fn_callbacks smsc_http_brunet_callback = { .init = brunet_init, .send_sms = brunet_send_sms, .parse_reply = brunet_parse_reply, .receive_sms = brunet_receive_sms, }; gateway-1.4.5/gw/smsc/http/xidris.c0000644000175000017500000002766213227613126015713 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /*---------------------------------------------------------------- * 3united.com (formerly Xidris) - An austrian (AT) SMS aggregator * Implementing version 1.3, 2003-05-06 * Updating to version 1.9.1, 2004-09-28 * * Stipe Tolj */ #include "gwlib/gwlib.h" /* * Parse for an parameter of an given XML tag and return it as Octstr */ static Octstr *parse_xml_tag(Octstr *body, Octstr *tag) { Octstr *stag, *etag, *ret; int spos, epos; stag = octstr_format("<%s>", octstr_get_cstr(tag)); if ((spos = octstr_search(body, stag, 0)) == -1) { octstr_destroy(stag); return NULL; } etag = octstr_format("", octstr_get_cstr(tag)); if ((epos = octstr_search(body, etag, spos+octstr_len(stag))) == -1) { octstr_destroy(stag); octstr_destroy(etag); return NULL; } ret = octstr_copy(body, spos+octstr_len(stag), epos+1 - (spos+octstr_len(etag))); octstr_strip_blanks(ret); octstr_strip_crlfs(ret); octstr_destroy(stag); octstr_destroy(etag); return ret; } /* MT related function */ static int xidris_send_sms(SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; Octstr *url, *new_msg; List *headers; int dcs, esm_class; url = new_msg = NULL; dcs = esm_class = 0; /* format the URL for call */ url = octstr_format("%S?" "app_id=%E&key=%E&dest_addr=%E&source_addr=%E", conndata->send_url, conndata->username, conndata->password, sms->sms.receiver, sms->sms.sender); if (octstr_len(sms->sms.udhdata)) { /* RAW additions for binary (8bit) msgs */ /* set the data coding scheme (DCS) and ESM class fields */ dcs = fields_to_dcs(sms, sms->sms.alt_dcs); /* ESM_CLASS_SUBMIT_STORE_AND_FORWARD_MODE | ESM_CLASS_SUBMIT_UDH_INDICATOR */ esm_class = 0x03 | 0x40; /* prepend UDH header to message block */ new_msg = octstr_duplicate(sms->sms.udhdata); octstr_append(new_msg, sms->sms.msgdata); octstr_format_append(url, "&type=200&dcs=%d&esm=%d&message=%H", dcs, esm_class, new_msg); } else { /* additions for text (7bit) msgs */ octstr_format_append(url, "&type=%E&message=%E", (sms->sms.mclass ? octstr_imm("1") : octstr_imm("0")), sms->sms.msgdata); } /* * We use &account= from sendsms interface to encode any additionaly * proxied parameters, ie. billing information. */ if (octstr_len(sms->sms.account)) { octstr_url_decode(sms->sms.account); octstr_format_append(url, "&%s", octstr_get_cstr(sms->sms.account)); } headers = gwlist_create(); debug("smsc.http.xidris", 0, "HTTP[%s]: Sending request <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(url)); http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, NULL, 0, sms, NULL); octstr_destroy(url); octstr_destroy(new_msg); http_destroy_headers(headers); return 0; } static void xidris_parse_reply(SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body) { Octstr *code, *desc, *mid; if (status == HTTP_OK || status == HTTP_ACCEPTED) { /* now parse the XML document for error code */ code = parse_xml_tag(body, octstr_imm("status")); desc = parse_xml_tag(body, octstr_imm("description")); /* The following parsing assumes we get only *one* message id in the * response XML. Which is ok, since we garantee via previous concat * splitting, that we only pass PDUs of 1 SMS size to SMSC. */ mid = parse_xml_tag(body, octstr_imm("message_id")); if (octstr_case_compare(code, octstr_imm("0")) == 0 && mid != NULL) { /* ensure the message id gets logged */ msg->sms.binfo = octstr_duplicate(mid); /* SMSC ACK.. now we have the message id. */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) dlr_add(conn->id, mid, msg, 0); octstr_destroy(mid); bb_smscconn_sent(conn, msg, NULL); } else { error(0, "HTTP[%s]: Message not accepted. Status code <%s> " "description `%s'.", octstr_get_cstr(conn->id), octstr_get_cstr(code), octstr_get_cstr(desc)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_duplicate(desc)); } } else { error(0, "HTTP[%s]: Message was rejected. SMSC response was:", octstr_get_cstr(conn->id)); octstr_dump(body, 0); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED")); } } /* MO related function */ static void xidris_receive_sms(SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars) { ConnData *conndata = conn->data; Octstr *user, *pass, *from, *to, *text, *account, *binfo; Octstr *state, *mid, *dest; Octstr *retmsg; int mclass, mwi, coding, validity, deferred; List *reply_headers; int ret, status; mclass = mwi = coding = validity = deferred = 0; retmsg = NULL; /* generic values */ user = http_cgi_variable(cgivars, "app_id"); pass = http_cgi_variable(cgivars, "key"); /* MO specific values */ from = http_cgi_variable(cgivars, "source_addr"); to = http_cgi_variable(cgivars, "dest_addr"); text = http_cgi_variable(cgivars, "message"); account = http_cgi_variable(cgivars, "operator"); binfo = http_cgi_variable(cgivars, "tariff"); /* DLR (callback) specific values */ state = http_cgi_variable(cgivars, "state"); mid = http_cgi_variable(cgivars, "message_id"); dest = http_cgi_variable(cgivars, "dest_addr"); debug("smsc.http.xidris", 0, "HTTP[%s]: Received a request", octstr_get_cstr(conn->id)); if (user == NULL || pass == NULL || octstr_compare(user, conndata->username) != 0 || octstr_compare(pass, conndata->password) != 0) { error(0, "HTTP[%s]: Authorization failure. username was <%s>.", octstr_get_cstr(conn->id), octstr_get_cstr(user)); retmsg = octstr_create("Authorization failed for MO submission."); status = HTTP_UNAUTHORIZED; } else if (state != NULL && mid != NULL && dest != NULL) { /* a DLR message */ Msg *dlrmsg; int dlrstat = -1; if (octstr_compare(state, octstr_imm("DELIVRD")) == 0) dlrstat = DLR_SUCCESS; else if (octstr_compare(state, octstr_imm("ACCEPTD")) == 0) dlrstat = DLR_BUFFERED; else dlrstat = DLR_FAIL; dlrmsg = dlr_find(conn->id, mid, /* smsc message id */ dest, /* destination */ dlrstat, 0); if (dlrmsg != NULL) { dlrmsg->sms.msgdata = octstr_duplicate(mid); dlrmsg->sms.sms_type = report_mo; ret = bb_smscconn_receive(conn, dlrmsg); status = (ret == 0 ? HTTP_OK : HTTP_FORBIDDEN); } else { error(0,"HTTP[%s]: got DLR but could not find message or was not interested " "in it id<%s> dst<%s>, type<%d>", octstr_get_cstr(conn->id), octstr_get_cstr(mid), octstr_get_cstr(dest), dlrstat); status = HTTP_OK; } } else if (from == NULL || to == NULL || text == NULL) { error(0, "HTTP[%s]: Insufficient args.", octstr_get_cstr(conn->id)); retmsg = octstr_create("Insufficient arguments, rejected."); status = HTTP_BAD_REQUEST; } else { Msg *msg; msg = msg_create(sms); debug("smsc.http.xidris", 0, "HTTP[%s]: Received new MO SMS.", octstr_get_cstr(conn->id)); msg->sms.sender = octstr_duplicate(from); msg->sms.receiver = octstr_duplicate(to); msg->sms.msgdata = octstr_duplicate(text); msg->sms.account = octstr_duplicate(account); msg->sms.binfo = octstr_duplicate(binfo); msg->sms.smsc_id = octstr_duplicate(conn->id); msg->sms.time = time(NULL); msg->sms.mclass = mclass; msg->sms.mwi = mwi; msg->sms.coding = coding; msg->sms.validity = time(NULL) + validity * 60; msg->sms.deferred = time(NULL) + deferred * 60; ret = bb_smscconn_receive(conn, msg); status = (ret == 0 ? HTTP_OK : HTTP_FORBIDDEN); } reply_headers = gwlist_create(); debug("smsc.http.xidris", 0, "HTTP[%s]: Sending reply with HTTP status <%d>.", octstr_get_cstr(conn->id), status); http_send_reply(client, status, reply_headers, retmsg); octstr_destroy(retmsg); http_destroy_headers(reply_headers); } static int xidris_init(SMSCConn *conn, CfgGroup *cfg) { ConnData *conndata = conn->data; if (conndata->username == NULL || conndata->password == NULL) { error(0, "HTTP[%s]: 'username' and 'password' required for Xidris http smsc", octstr_get_cstr(conn->id)); return -1; } return 0; } struct smsc_http_fn_callbacks smsc_http_xidris_callback = { .init = xidris_init, .send_sms = xidris_send_sms, .parse_reply = xidris_parse_reply, .receive_sms = xidris_receive_sms, }; gateway-1.4.5/gw/smsc/http/generic.c0000644000175000017500000006043613227613126016021 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /*---------------------------------------------------------------- * Generic HTTP interface * * This 'generic' type will handle the 'send-url' directive in the * group the same way the 'sms-service' for smsbox does, via * URLTranslation. Response interpretation is based on the three * regex value that match against the response body. The HTTP response * code is not obeyed. * * Example config group: * * group = smsc * smsc = http * system-type = generic * send-url = "http:///?from=%P&to=%p&text=%b" * status-success-regex = "ok" * status-permfail-regex = "failure" * status-tempfail-regex = "retry later" * generic-foreign-id-regex = "(.+)" * generic-param-from = "phoneNumber" * generic-param-to = "shortCode" * generic-param-text = "message" * generic-message-sent = "OK" * generic-status-sent = 200 * generic-status-error = 400 * * Note that neither 'smsc-username' nor 'smsc-password' is required, * since they are coded into the the 'send-url' value directly. * * Stipe Tolj * * MO processing by Alejandro Guerrieri */ #include "gwlib/gwlib.h" /* * This maps fields to values for MO parameters */ struct fieldmap { Octstr *username; Octstr *password; Octstr *from; Octstr *to; Octstr *text; Octstr *udh; Octstr *service; Octstr *account; Octstr *binfo; Octstr *meta_data; Octstr *dlr_mask; Octstr *dlr_err; Octstr *dlr_url; Octstr *dlr_mid; Octstr *flash; Octstr *mclass; Octstr *mwi; Octstr *coding; Octstr *validity; Octstr *deferred; Octstr *foreign_id; Octstr *message_sent; long status_sent; long status_error; }; struct generic_values { struct fieldmap *map; /* The following are compiled regex for the 'generic' type for handling * success, permanent failure and temporary failure. For types that use * simple HTTP body parsing, these may be used also for other types, * ie. for our own Kannel reply parsing. */ regex_t *success_regex; regex_t *permfail_regex; regex_t *tempfail_regex; /* Compiled regex for the 'generic' type to get the foreign message id * from the HTTP response body */ regex_t *generic_foreign_id_regex; }; /* * Destroys the FieldMap structure */ static void fieldmap_destroy(struct fieldmap *fieldmap) { if (fieldmap == NULL) return; octstr_destroy(fieldmap->username); octstr_destroy(fieldmap->password); octstr_destroy(fieldmap->from); octstr_destroy(fieldmap->to); octstr_destroy(fieldmap->text); octstr_destroy(fieldmap->udh); octstr_destroy(fieldmap->service); octstr_destroy(fieldmap->account); octstr_destroy(fieldmap->binfo); octstr_destroy(fieldmap->meta_data); octstr_destroy(fieldmap->dlr_mask); octstr_destroy(fieldmap->dlr_err); octstr_destroy(fieldmap->dlr_url); octstr_destroy(fieldmap->dlr_mid); octstr_destroy(fieldmap->flash); octstr_destroy(fieldmap->mclass); octstr_destroy(fieldmap->mwi); octstr_destroy(fieldmap->coding); octstr_destroy(fieldmap->validity); octstr_destroy(fieldmap->deferred); octstr_destroy(fieldmap->foreign_id); octstr_destroy(fieldmap->message_sent); gw_free(fieldmap); } /* * Get the FieldMap struct to map MO parameters */ static struct fieldmap *generic_get_field_map(CfgGroup *grp) { struct fieldmap *fm = NULL; fm = gw_malloc(sizeof(*fm)); gw_assert(fm != NULL); fm->username = cfg_get(grp, octstr_imm("generic-param-username")); if (fm->username == NULL) fm->username = octstr_create("username"); fm->password = cfg_get(grp, octstr_imm("generic-param-password")); if (fm->password == NULL) fm->password = octstr_create("password"); fm->from = cfg_get(grp, octstr_imm("generic-param-from")); if (fm->from == NULL) fm->from = octstr_create("from"); fm->to = cfg_get(grp, octstr_imm("generic-param-to")); if (fm->to == NULL) fm->to = octstr_create("to"); fm->text = cfg_get(grp, octstr_imm("generic-param-text")); if (fm->text == NULL) fm->text = octstr_create("text"); fm->udh = cfg_get(grp, octstr_imm("generic-param-udh")); if (fm->udh == NULL) fm->udh = octstr_create("udh"); /* "service" preloads the "username" parameter to mimic former behaviour */ fm->service = cfg_get(grp, octstr_imm("generic-param-service")); if (fm->service == NULL) fm->service = octstr_create("username"); fm->account = cfg_get(grp, octstr_imm("generic-param-account")); if (fm->account == NULL) fm->account = octstr_create("account"); fm->binfo = cfg_get(grp, octstr_imm("generic-param-binfo")); if (fm->binfo == NULL) fm->binfo = octstr_create("binfo"); fm->dlr_mask = cfg_get(grp, octstr_imm("generic-param-dlr-mask")); if (fm->dlr_mask == NULL) fm->dlr_mask = octstr_create("dlr-mask"); fm->dlr_err = cfg_get(grp, octstr_imm("generic-param-dlr-err")); if (fm->dlr_err == NULL) fm->dlr_err = octstr_create("dlr-err"); fm->dlr_url = cfg_get(grp, octstr_imm("generic-param-dlr-url")); if (fm->dlr_url == NULL) fm->dlr_url = octstr_create("dlr-url"); fm->dlr_mid = cfg_get(grp, octstr_imm("generic-param-dlr-mid")); if (fm->dlr_mid == NULL) fm->dlr_mid = octstr_create("dlr-mid"); fm->flash = cfg_get(grp, octstr_imm("generic-param-flash")); if (fm->flash == NULL) fm->flash = octstr_create("flash"); fm->mclass = cfg_get(grp, octstr_imm("generic-param-mclass")); if (fm->mclass == NULL) fm->mclass = octstr_create("mclass"); fm->mwi = cfg_get(grp, octstr_imm("generic-param-mwi")); if (fm->mwi == NULL) fm->mwi = octstr_create("mwi"); fm->coding = cfg_get(grp, octstr_imm("generic-param-coding")); if (fm->coding == NULL) fm->coding = octstr_create("coding"); fm->validity = cfg_get(grp, octstr_imm("generic-param-validity")); if (fm->validity == NULL) fm->validity = octstr_create("validity"); fm->deferred = cfg_get(grp, octstr_imm("generic-param-deferred")); if (fm->deferred == NULL) fm->deferred = octstr_create("deferred"); fm->foreign_id = cfg_get(grp, octstr_imm("generic-param-foreign-id")); if (fm->foreign_id == NULL) fm->foreign_id = octstr_create("foreign-id"); fm->meta_data = cfg_get(grp, octstr_imm("generic-param-meta-data")); if (fm->meta_data == NULL) fm->meta_data = octstr_create("meta-data"); fm->message_sent = cfg_get(grp, octstr_imm("generic-message-sent")); if (fm->message_sent == NULL) fm->message_sent = octstr_create("Sent"); /* both success and error uses HTTP_ACCEPTED to mimic former behaviour */ if (cfg_get_integer(&fm->status_sent, grp, octstr_imm("generic-status-sent")) == -1) { fm->status_sent = HTTP_ACCEPTED; } if (cfg_get_integer(&fm->status_error, grp, octstr_imm("generic-status-error")) == -1) { fm->status_error = HTTP_ACCEPTED; } return fm; } static void generic_receive_sms(SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars) { ConnData *conndata = conn->data; struct generic_values *values = conndata->data; struct fieldmap *fm = values->map; Octstr *user, *pass, *from, *to, *text, *udh, *account, *binfo, *meta_data; Octstr *dlrmid, *dlrerr; Octstr *tmp_string, *retmsg; int dlrmask; List *reply_headers; int ret, retstatus; dlrmask = SMS_PARAM_UNDEFINED; /* Parse enough parameters to validate the request */ user = http_cgi_variable(cgivars, octstr_get_cstr(fm->username)); pass = http_cgi_variable(cgivars, octstr_get_cstr(fm->password)); from = http_cgi_variable(cgivars, octstr_get_cstr(fm->from)); to = http_cgi_variable(cgivars, octstr_get_cstr(fm->to)); text = http_cgi_variable(cgivars, octstr_get_cstr(fm->text)); udh = http_cgi_variable(cgivars, octstr_get_cstr(fm->udh)); dlrmid = http_cgi_variable(cgivars, octstr_get_cstr(fm->dlr_mid)); tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->dlr_mask)); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%d", &dlrmask); } dlrerr = http_cgi_variable(cgivars, octstr_get_cstr(fm->dlr_err)); debug("smsc.http.generic", 0, "HTTP[%s]: Received an HTTP request", octstr_get_cstr(conn->id)); if ((conndata->username != NULL && conndata->password != NULL) && (user == NULL || pass == NULL || octstr_compare(user, conndata->username) != 0 || octstr_compare(pass, conndata->password) != 0)) { error(0, "HTTP[%s]: Authorization failure", octstr_get_cstr(conn->id)); retmsg = octstr_create("Authorization failed for sendsms"); retstatus = fm->status_error; } else if (dlrmask != DLR_UNDEFINED && dlrmid != NULL) { /* we got a DLR, and we don't require additional values */ Msg *dlrmsg; dlrmsg = dlr_find(conn->id, dlrmid, /* message id */ to, /* destination */ dlrmask, 0); if (dlrmsg != NULL) { dlrmsg->sms.sms_type = report_mo; dlrmsg->sms.msgdata = octstr_duplicate(text); dlrmsg->sms.account = octstr_duplicate(conndata->username); debug("smsc.http.generic", 0, "HTTP[%s]: Received DLR for DLR-URL <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(dlrmsg->sms.dlr_url)); if (dlrerr != NULL) { /* pass errorcode as is */ if (dlrmsg->sms.meta_data == NULL) dlrmsg->sms.meta_data = octstr_create(""); meta_data_set_value(dlrmsg->sms.meta_data, METADATA_DLR_GROUP, octstr_imm(METADATA_DLR_GROUP_ERRORCODE), dlrerr, 1); } Msg *resp = msg_duplicate(dlrmsg); ret = bb_smscconn_receive(conn, dlrmsg); if (ret == -1) { retmsg = octstr_create("Not accepted"); retstatus = fm->status_error; } else { retmsg = urltrans_fill_escape_codes(fm->message_sent, resp); retstatus = fm->status_sent; } msg_destroy(resp); } else { error(0,"HTTP[%s]: Got DLR but could not find message or was not interested " "in it id<%s> dst<%s>, type<%d>", octstr_get_cstr(conn->id), octstr_get_cstr(dlrmid), octstr_get_cstr(to), dlrmask); retmsg = octstr_create("Unknown DLR, not accepted"); retstatus = fm->status_error; } } else if (from == NULL || to == NULL || text == NULL) { error(0, "HTTP[%s]: Insufficient args", octstr_get_cstr(conn->id)); retmsg = octstr_create("Insufficient args, rejected"); retstatus = fm->status_error; } else if (udh != NULL && (octstr_len(udh) != octstr_get_char(udh, 0) + 1)) { error(0, "HTTP[%s]: UDH field misformed, rejected", octstr_get_cstr(conn->id)); retmsg = octstr_create("UDH field misformed, rejected"); retstatus = fm->status_error; } else if (udh != NULL && octstr_len(udh) > MAX_SMS_OCTETS) { error(0, "HTTP[%s]: UDH field is too long, rejected", octstr_get_cstr(conn->id)); retmsg = octstr_create("UDH field is too long, rejected"); retstatus = fm->status_error; } else { /* we got a normal MO SMS */ Msg *msg; msg = msg_create(sms); /* Parse the rest of the parameters */ tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->flash)); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%ld", &msg->sms.mclass); } tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->mclass)); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%ld", &msg->sms.mclass); } tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->mwi)); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%ld", &msg->sms.mwi); } tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->coding)); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%ld", &msg->sms.coding); } tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->validity)); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%ld", &msg->sms.validity); msg->sms.validity = time(NULL) + msg->sms.validity * 60; } tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->deferred)); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%ld", &msg->sms.deferred); msg->sms.deferred = time(NULL) + msg->sms.deferred * 60; } account = http_cgi_variable(cgivars, octstr_get_cstr(fm->account)); binfo = http_cgi_variable(cgivars, octstr_get_cstr(fm->binfo)); meta_data = http_cgi_variable(cgivars, octstr_get_cstr(fm->meta_data)); debug("smsc.http.generic", 0, "HTTP[%s]: Constructing new SMS", octstr_get_cstr(conn->id)); msg->sms.msgdata = octstr_duplicate(text); /* re-encode content if necessary */ if (conndata->alt_charset && sms_charset_processing(conndata->alt_charset, msg->sms.msgdata, msg->sms.coding) == -1) { error(0, "HTTP[%s]: Charset or body misformed, will leave it as it is.", octstr_get_cstr(conn->id)); } msg->sms.service = octstr_duplicate(user); msg->sms.sender = octstr_duplicate(from); msg->sms.receiver = octstr_duplicate(to); msg->sms.udhdata = octstr_duplicate(udh); msg->sms.smsc_id = octstr_duplicate(conn->id); msg->sms.time = time(NULL); msg->sms.account = octstr_duplicate(account); msg->sms.binfo = octstr_duplicate(binfo); msg->sms.meta_data = octstr_duplicate(meta_data); Msg *resp = msg_duplicate(msg); ret = bb_smscconn_receive(conn, msg); if (ret == -1) { retmsg = octstr_create("Not accepted"); retstatus = fm->status_error; } else { retmsg = urltrans_fill_escape_codes(fm->message_sent, resp); retstatus = fm->status_sent; } msg_destroy(resp); } reply_headers = gwlist_create(); http_header_add(reply_headers, "Content-Type", "text/plain"); debug("smsc.http.generic", 0, "HTTP[%s]: Sending reply", octstr_get_cstr(conn->id)); http_send_reply(client, retstatus, reply_headers, retmsg); octstr_destroy(retmsg); http_destroy_headers(reply_headers); } static int generic_send_sms(SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; Octstr *url = NULL; List *headers; /* We use the escape code population function from our * URLTranslation module to fill in the appropriate values * into the URL scheme. */ url = urltrans_fill_escape_codes(conndata->send_url, sms); headers = gwlist_create(); debug("smsc.http.generic", 0, "HTTP[%s]: Sending request <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(url)); http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, NULL, 0, sms, NULL); octstr_destroy(url); http_destroy_headers(headers); return 0; } static void generic_parse_reply(SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body) { ConnData *conndata = conn->data; struct generic_values *values = conndata->data; regmatch_t pmatch[2]; Octstr *msgid = NULL; /* * Our generic type checks only content on the HTTP response body. * We use the pre-compiled regex to match against the states. * This is the most generic criteria (at the moment). */ if ((values->success_regex != NULL) && (gw_regex_exec(values->success_regex, body, 0, NULL, 0) == 0)) { /* SMSC ACK... the message id should be in the body */ /* add to our own DLR storage */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) { /* directive 'generic-foreign-id-regex' is present, fetch the foreign ID */ if ((values->generic_foreign_id_regex != NULL)) { if (gw_regex_exec(values->generic_foreign_id_regex, body, sizeof(pmatch) / sizeof(regmatch_t), pmatch, 0) == 0) { if (pmatch[1].rm_so != -1 && pmatch[1].rm_eo != -1) { msgid = octstr_copy(body, pmatch[1].rm_so, pmatch[1].rm_eo - pmatch[1].rm_so); debug("smsc.http.generic", 0, "HTTP[%s]: Found foreign message id <%s> in body.", octstr_get_cstr(conn->id), octstr_get_cstr(msgid)); dlr_add(conn->id, msgid, msg, 0); octstr_destroy(msgid); } } if (msgid == NULL) warning(0, "HTTP[%s]: Can't get the foreign message id from the HTTP body.", octstr_get_cstr(conn->id)); } else { char id[UUID_STR_LEN + 1]; /* use own own UUID as msg ID in the DLR storage */ uuid_unparse(msg->sms.id, id); msgid = octstr_create(id); dlr_add(conn->id, msgid, msg, 0); octstr_destroy(msgid); } } bb_smscconn_sent(conn, msg, NULL); } else if ((values->permfail_regex != NULL) && (gw_regex_exec(values->permfail_regex, body, 0, NULL, 0) == 0)) { error(0, "HTTP[%s]: Message not accepted.", octstr_get_cstr(conn->id)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body)); } else if ((values->tempfail_regex != NULL) && (gw_regex_exec(values->tempfail_regex, body, 0, NULL, 0) == 0)) { warning(0, "HTTP[%s]: Message temporary not accepted, will retry.", octstr_get_cstr(conn->id)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, octstr_duplicate(body)); } else { error(0, "HTTP[%s]: Message was rejected. SMSC response was:", octstr_get_cstr(conn->id)); octstr_dump(body, 0); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED")); } } static int generic_init(SMSCConn *conn, CfgGroup *cfg) { Octstr *os; ConnData *conndata = conn->data; struct generic_values *values; conndata->data = values = gw_malloc(sizeof(*values)); /* reset */ memset(conndata->data, 0, sizeof(*values)); values->success_regex = values->permfail_regex = values->tempfail_regex = NULL; values->generic_foreign_id_regex = NULL; values->map = generic_get_field_map(cfg); /* pre-compile regex expressions */ if ((os = cfg_get(cfg, octstr_imm("status-success-regex"))) != NULL) { if ((values->success_regex = gw_regex_comp(os, REG_EXTENDED|REG_NOSUB)) == NULL) error(0, "HTTP[%s]: Could not compile pattern '%s' defined for variable 'status-success-regex'", octstr_get_cstr(conn->id), octstr_get_cstr(os)); octstr_destroy(os); } else { /* we need at least the criteria for a successful sent */ error(0, "HTTP[%s]: 'status-success-regex' required for generic http smsc", octstr_get_cstr(conn->id)); return -1; } if ((os = cfg_get(cfg, octstr_imm("status-permfail-regex"))) != NULL) { if ((values->permfail_regex = gw_regex_comp(os, REG_EXTENDED|REG_NOSUB)) == NULL) panic(0, "Could not compile pattern '%s' defined for variable 'status-permfail-regex'", octstr_get_cstr(os)); octstr_destroy(os); } if ((os = cfg_get(cfg, octstr_imm("status-tempfail-regex"))) != NULL) { if ((values->tempfail_regex = gw_regex_comp(os, REG_EXTENDED|REG_NOSUB)) == NULL) panic(0, "Could not compile pattern '%s' defined for variable 'status-tempfail-regex'", octstr_get_cstr(os)); octstr_destroy(os); } if ((os = cfg_get(cfg, octstr_imm("generic-foreign-id-regex"))) != NULL) { if ((values->generic_foreign_id_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s' defined for variable 'generic-foreign-id-regex'", octstr_get_cstr(os)); else { /* check quickly that at least 1 group seems to be defined in the regex */ if (octstr_search_char(os, '(', 0) == -1 || octstr_search_char(os, ')', 0) == -1) warning(0, "HTTP[%s]: No group defined in pattern '%s' for variable 'generic-foreign-id-regex'", octstr_get_cstr(conn->id), octstr_get_cstr(os)); } octstr_destroy(os); } debug("", 0, "generic init completed"); return 0; } static void generic_destroy(SMSCConn *conn) { ConnData *conndata; struct generic_values *values; if (conn == NULL || conn->data == NULL) return; conndata = conn->data; values = conndata->data; fieldmap_destroy(values->map); if (values->success_regex) gw_regex_destroy(values->success_regex); if (values->permfail_regex) gw_regex_destroy(values->permfail_regex); if (values->tempfail_regex) gw_regex_destroy(values->tempfail_regex); if (values->generic_foreign_id_regex) gw_regex_destroy(values->generic_foreign_id_regex); gw_free(values); conndata->data = NULL; debug("", 0, "generic destroy completed"); } struct smsc_http_fn_callbacks smsc_http_generic_callback = { .init = generic_init, .destroy = generic_destroy, .send_sms = generic_send_sms, .parse_reply = generic_parse_reply, .receive_sms = generic_receive_sms, }; gateway-1.4.5/gw/smsc/http/clickatell.c0000644000175000017500000002750313227613126016512 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /*---------------------------------------------------------------- * Clickatell - http://api.clickatell.com/ * * Rene Kluwen * Stipe Tolj , */ #include "gwlib/gwlib.h" /* MT related function */ static int clickatell_send_sms(SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; Octstr *url, *os; char id[UUID_STR_LEN + 1]; List *headers; /* form the basic URL */ url = octstr_format("%S/sendmsg?to=%E&from=%E&api_id=%E&user=%E&password=%E", conndata->send_url, sms->sms.receiver, sms->sms.sender, conndata->system_id, conndata->username, conndata->password); /* append MD5 digest as msg ID from our UUID */ uuid_unparse(sms->sms.id, id); os = octstr_create(id); octstr_replace(os, octstr_imm("-"), octstr_imm("")); octstr_format_append(url, "&cliMsgId=%E", os); octstr_destroy(os); /* add UDH header */ if(octstr_len(sms->sms.udhdata)) { octstr_format_append(url, "&udh=%H", sms->sms.udhdata); } if(sms->sms.coding == DC_8BIT) { octstr_format_append(url, "&data=%H&mclass=%d", sms->sms.msgdata, sms->sms.mclass); } else if(sms->sms.coding == DC_UCS2) { octstr_format_append(url, "&unicode=1&text=%H", sms->sms.msgdata); } else { octstr_format_append(url, "&text=%E", sms->sms.msgdata); if (conndata->alt_charset) { octstr_format_append(url, "&charset=%E", conndata->alt_charset); } else { octstr_append_cstr(url, "&charset=UTF-8"); } } if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask)) octstr_format_append(url, "&callback=3&deliv_ack=1"); headers = http_create_empty_headers(); debug("smsc.http.clickatell", 0, "HTTP[%s]: Sending request <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(url)); /* * Clickatell requires optionally an SSL-enabled HTTP client call, this is handled * transparently by the Kannel HTTP layer module. */ http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, NULL, 0, sms, NULL); octstr_destroy(url); http_destroy_headers(headers); return 0; } /* * Parse a line in the format: ID: XXXXXXXXXXXXXXXXXX * and return a Dict with the 'ID' as key and the value as value, * otherwise return NULL if a parsing error occures. */ static Dict *clickatell_parse_body(Octstr *body) { Dict *param = NULL; List *words = NULL; long len; Octstr *word, *value; words = octstr_split_words(body); if ((len = gwlist_len(words)) > 1) { word = gwlist_extract_first(words); if (octstr_compare(word, octstr_imm("ID:")) == 0) { value = gwlist_extract_first(words); param = dict_create(4, (void(*)(void *)) octstr_destroy); dict_put(param, octstr_imm("ID"), value); } else if (octstr_compare(word, octstr_imm("ERR:")) == 0) { value = gwlist_extract_first(words); param = dict_create(4, (void(*)(void *)) octstr_destroy); dict_put(param, octstr_imm("ERR"), value); } octstr_destroy(word); } gwlist_destroy(words, (void(*)(void *)) octstr_destroy); return param; } static void clickatell_parse_reply(SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body) { if (status == HTTP_OK || status == HTTP_ACCEPTED) { Dict *param; Octstr *msgid; if ((param = clickatell_parse_body(body)) != NULL && (msgid = dict_get(param, octstr_imm("ID"))) != NULL && msgid != NULL) { /* SMSC ACK.. now we have the message id. */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) dlr_add(conn->id, msgid, msg, 0); bb_smscconn_sent(conn, msg, NULL); } else { error(0, "HTTP[%s]: Message was malformed or error was returned. SMSC response `%s'.", octstr_get_cstr(conn->id), octstr_get_cstr(body)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body)); } dict_destroy(param); } else { error(0, "HTTP[%s]: Message was rejected. SMSC response `%s'.", octstr_get_cstr(conn->id), octstr_get_cstr(body)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED, octstr_duplicate(body)); } } /* MO related function */ static void clickatell_receive_sms(SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars) { List *reply_headers; int ret; Octstr *apimsgid, *status, *timestamp, *retmsg, *dest, *charge; Octstr *api_id, *from, *to, *text, *charset, *udh; int httpstatus = HTTP_UNAUTHORIZED, dlrstat; Msg *dlrmsg, *momsg; struct tm tm; /* dlr parameters */ apimsgid = http_cgi_variable(cgivars, "apiMsgId"); status = http_cgi_variable(cgivars, "status"); /* timestamp is for both DLR & MO */ timestamp = http_cgi_variable(cgivars, "timestamp"); dest = http_cgi_variable(cgivars, "to"); charge = http_cgi_variable(cgivars, "charge"); /* MO parameters */ api_id = http_cgi_variable(cgivars, "api_id"); from = http_cgi_variable(cgivars, "from"); to = http_cgi_variable(cgivars, "to"); text = http_cgi_variable(cgivars, "text"); charset = http_cgi_variable(cgivars, "charset"); udh = http_cgi_variable(cgivars, "udh"); debug("smsc.http.clickatell", 0, "HTTP[%s]: Received a request", octstr_get_cstr(conn->id)); if (api_id != NULL && from != NULL && to != NULL && timestamp != NULL && text != NULL && charset != NULL && udh != NULL) { /* we received an MO message */ debug("smsc.http.clickatell", 0, "HTTP[%s]: Received MO message from %s: <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(from), octstr_get_cstr(text)); momsg = msg_create(sms); momsg->sms.sms_type = mo; momsg->sms.sender = octstr_duplicate(from); momsg->sms.receiver = octstr_duplicate(to); momsg->sms.msgdata = octstr_duplicate(text); momsg->sms.charset = octstr_duplicate(charset); momsg->sms.service = octstr_duplicate(api_id); momsg->sms.binfo = octstr_duplicate(api_id); momsg->sms.smsc_id = octstr_duplicate(conn->id); if (octstr_len(udh) > 0) { momsg->sms.udhdata = octstr_duplicate(udh); } strptime(octstr_get_cstr(timestamp), "%Y-%m-%d %H:%M:%S", &tm); momsg->sms.time = gw_mktime(&tm); /* note: implicit msg_destroy */ ret = bb_smscconn_receive(conn, momsg); httpstatus = HTTP_OK; retmsg = octstr_create("Thanks"); } else if (apimsgid == NULL || status == NULL || timestamp == NULL || dest == NULL) { error(0, "HTTP[%s]: Insufficient args.", octstr_get_cstr(conn->id)); httpstatus = HTTP_OK; retmsg = octstr_create("Insufficient arguments, rejected."); } else { switch (atoi(octstr_get_cstr(status))) { case 1: /* message unknown */ case 5: /* error with message */ case 6: /* user cancelled message */ case 7: /* error delivering message */ case 9: /* routing error */ case 10: /* message expired */ dlrstat = 2; /* delivery failure */ break; case 2: /* message queued */ case 3: /* delivered */ case 11: /* message queued for later delivery */ dlrstat = 4; /* message buffered */ break; case 4: /* received by recipient */ case 8: /* OK */ dlrstat = 1; /* message received */ break; default: /* unknown status code */ dlrstat = 16; /* smsc reject */ break; } dlrmsg = dlr_find(conn->id, apimsgid, /* smsc message id */ dest, /* destination */ dlrstat, 0); if (dlrmsg != NULL) { /* dlrmsg->sms.msgdata = octstr_duplicate(apimsgid); */ dlrmsg->sms.sms_type = report_mo; dlrmsg->sms.time = atoi(octstr_get_cstr(timestamp)); if (charge) { /* unsure if smsbox relays the binfo field to dlrs. But it is here in case they will start to do it. */ dlrmsg->sms.binfo = octstr_duplicate(charge); } ret = bb_smscconn_receive(conn, dlrmsg); httpstatus = (ret == 0 ? HTTP_OK : HTTP_FORBIDDEN); retmsg = octstr_create("Sent"); } else { error(0,"HTTP[%s]: got DLR but could not find message or was not interested " "in it id<%s> dst<%s>, type<%d>", octstr_get_cstr(conn->id), octstr_get_cstr(apimsgid), octstr_get_cstr(dest), dlrstat); httpstatus = HTTP_OK; retmsg = octstr_create("Thanks"); } } reply_headers = gwlist_create(); http_header_add(reply_headers, "Content-Type", "text/plain"); debug("smsc.http.clickatell", 0, "HTTP[%s]: Sending reply `%s'.", octstr_get_cstr(conn->id), octstr_get_cstr(retmsg)); http_send_reply(client, httpstatus, reply_headers, retmsg); octstr_destroy(retmsg); http_destroy_headers(reply_headers); } struct smsc_http_fn_callbacks smsc_http_clickatell_callback = { .send_sms = clickatell_send_sms, .parse_reply = clickatell_parse_reply, .receive_sms = clickatell_receive_sms, }; gateway-1.4.5/gw/smsc/smsc_ois.c0000644000175000017500000013037513227613126015245 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /***************************************************************************** * smsc_ois.c - Sema Group SMS2000 (G6.0) Center (OIS 5.0). * Jouko Koski (EDS) for WapIT Ltd. * * The SMS2000 has a general X.25 access gateway for accessing the SMSC, * as described in the Open Interface Specification 5.0 document. * A protocol translator - like the Cisco 2501 router - hides all the * X.25 trickery from us. We just connect to a preconfigured router * address/port, and the translator forwards the connection to the SMS2000. * Correspondingly, if the SMSC has something to say, it looks like * the router were contacting our port. The router should be configured so, * that it has a pre-defined address and tcp port in X.25 automode establishing * a X.25 link and a similar configuration in X.25 side connecting to a pre- * defined address and port, it shall not encapsulate everything in Telnet * (set the stream mode), and it should suppress banner messages like "Trying * 9876...Open" (set the quiet mode). * * Whenever possible, I've tried to steal ideas and code from other smsc_* * files, particularly from Hao Shi's (EDS) original implementation for a * serial-line-connected PAD. However, the code is highly evolutionary, * because during the implementation new technical details kept popping * up all the time (initially, PAD commands were supposed to be used, * but the router was configured to "automode", so they weren't necessary; * instead the router gave banner messages and wanted some telnet negotiations; * the router insisted echoing everything and delayed s after s; * telnet transmit-binary mode solved that; then the stream mode (no telnet * encapsulation) was discovered; suddenly the banners were turned off also; * but still the smsc didn't deliver mo messages, because it wanted to * connect instead of using our existing connection; then we began to use * short connection sessions for transmitting instead of a single ever- * lasting connection, and also started to specifically listen for smsc * initiated connections, which yielded two separate input buffers; then * suddenly the banners were there again, so some intelligence had to be * added to adapt their (non-)existence; then revealed the spec version 4.5 * had been obsolete all the time and we got 5.0; the router apparently * caused some extra packets on the x.25 side and everybody was blaming the * application; then the connection maintenance and buffering was again * revisited to achieve better performance and reliability... Really an * interesting story but think if it were about you instead of me :-) * * Really funny thing is that according to the spec the SMS2000 does have * a direct TCP/IP access interface. However, here we have the general X.25 * access interface, since we started with the old spec and probably the * simpler TCP/IP access is not available in our particular customer's * installation, not at least when this was written. In the direct access * only single ever-lasting connection is necessary, and the messages are * the same but their format is different. Encoding tricks are the same. * So, if you are implementing that access mode some day, there are probably * differences between this access mode and yours on so many levels, that * simple if () selections won't work; write your own code from (nearly) * scratch and take appropriate encoding conversion functions here. Or do * just whatever you want, what should I care :-). */ #include #include #include #include #include #include #include #include #include #include #include "smsc.h" #include "smsc_p.h" #include "gwlib/gwlib.h" #include "sms.h" /* XXX Delete me and replace dcs with dcs_to_fields */ enum dcs_body_type { DCS_GSM_TEXT = 0, DCS_OCTET_DATA = 4 /* flag_8bit */ }; /* 'private:' */ int ois_debug_level = 0; /* some extra verbosity in debug logging */ /* 0=just normal debugging, 1=input/output messages, 2=function entries, */ /* 3=message assembly/disassembly, 4=disconnection tracing, */ /* 5=message conversions, and 8=message polling (=too much) */ #define SAY(d,s) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s); } #define SAY2(d,s,t) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t); } #define SAY3(d,s,t,u) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t,u); } #define IOTRACE(x,s,l) SAY3(1,"%s [%s]",x,ois_debug_str(s,l)) #define BUFLEN (511) /* sure enough for ois messages */ #define OIS_OPEN_WAITTIME (15) /* seconds, waiting for banners */ #define OIS_MESSAGE_WAITTIME (30) /* seconds, until closing idle connection */ #define OIS_WAITTIME (999999) /* microseconds, waiting for banners at a time */ #define OIS_NOWAIT (0) /* microseconds, not waiting */ #define MAXCOUNTER (10000) /* ois message id */ #define EOL ('\r') /* ois definition for the eol */ typedef struct ois_listentry { struct ois_listentry *next; Msg *msg; } ois_listentry; #define OIS_FLAG_DEBUG (0x000f) #define OIS_FLAG_ERROR (0x0100) #define OIS_FLAG_NOBANNER (0x0200) #define OIS_FLAG_MULTIPLE_CALL (0x0400) #define OIS_FLAG_CLOSED (0x0800) static int ois_counter = 0; /* [0..MAXCOUNTER), ois "unique" message id */ static int ois_open_listener(SMSCenter *smsc); static int ois_open_sender(SMSCenter *smsc); static int ois_open_receiver(SMSCenter *smsc); static void ois_disconnect_all(SMSCenter *smsc); static void ois_disconnect(SMSCenter *smsc); static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec); static int ois_check_input(SMSCenter *smsc, long wait_usec); static int ois_check_incoming(SMSCenter *smsc, long wait_usec); static void ois_append_to_list(ois_listentry **head, Msg *msg); static int ois_int_to_i4(char *raw, int nbr); static int ois_increment_counter(void); static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg); static int ois_encode_submit_sm_invoke(char *str, const Msg *msg); static int ois_append_msisdn(char *raw, const Msg *msg); static int ois_append_sme_reference_number(char *raw); static int ois_append_priority(char *raw); static int ois_append_originating_address(char *raw); static int ois_append_validity_period(char *raw); static int ois_append_data_coding_scheme(char *raw, const Msg *msg); static int ois_append_status_report_request(char *raw); static int ois_append_protocol_id(char *raw); static int ois_append_submission_options(char *raw, const Msg *msg); static int ois_append_sm_text(char *raw, const Msg *msg); static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer); static int ois_decode_submit_sm_result(int *code, const char *str); static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer); static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str); static int ois_check_deliver_sm_invoke(const char *str); static int ois_adjust_destination_address(Msg *msg, const char *raw); static int ois_ignore_smsc_reference_number(const char *raw); static int ois_adjust_originating_address(Msg *msg, const char *raw); static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw); static int ois_ignore_protocol_id(const char *raw); static int ois_adjust_additional_information(Msg *msg, const char *raw); static int ois_adjust_sm_text(Msg *msg, const char *raw); static int ois_ignore_time(const char *raw); static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str); static int ois_encode_deliver_sm_result(char *str, int result); static int ois_expand_gsm7(char *raw8, const char *raw7, int len); static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len); static char ois_expand_gsm7_from_bits(const char *bits, int pos); static int ois_convert_to_ia5(char *str, const char *raw, int len); static int ois_convert_from_ia5(char *raw, const char *str); static int ois_convert_to_iso88591(char *raw, int len); static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc); static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc); static void ois_swap_buffering(SMSCenter *smsc); static const char *ois_debug_str(const char *raw, int len); /* 'public:' */ /* * Establish a connection to the SMSC. */ SMSCenter *ois_open(int receiveport, const char *hostname, int port, int debug_level) { SMSCenter *smsc; int ret; ois_debug_level = debug_level & OIS_FLAG_DEBUG; SAY(2, "ois_open"); /* create a SMSCenter structure */ smsc = smscenter_construct(); if (smsc == NULL) { goto error; } smsc->type = SMSC_TYPE_OIS; smsc->receive_port = receiveport; smsc->hostname = gw_strdup(hostname); smsc->port = port; smsc->ois_flags = ois_debug_level; ret = ois_open_listener(smsc); if (ret < 0) { goto error; } sprintf(smsc->name, "OIS:TCP/X.25-Translator:localhost:%d:TCP:%.512s:%d", smsc->receive_port, smsc->hostname, smsc->port); return smsc; error: error(0, "ois_open: could not open"); smscenter_destruct(smsc); return NULL; } /* * Terminate the SMSC connection. */ int ois_close(SMSCenter *smsc) { ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_close"); if (smsc->type != SMSC_TYPE_OIS) { warning(0, "ois_close: closing a not-ois connection..."); } ois_swap_buffering(smsc); smscenter_remove_from_buffer(smsc, smsc->buflen); ois_swap_buffering(smsc); smscenter_remove_from_buffer(smsc, smsc->buflen); SAY(4, "ois_close: ois_disconnect_all"); ois_disconnect_all(smsc); return 0; } /* * Re-establish a SMSC connection. */ int ois_reopen(SMSCenter *smsc) { int ret; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_reopen"); ois_close(smsc); if (smsc->type == SMSC_TYPE_OIS) { ret = ois_open_listener(smsc); if (ret < 0) { goto error; } } else { error(0, "ois_reopen: wrong smsc type"); goto error; } return 0; error: error(0, "ois_reopen: could not open"); return -1; } /* * Check for MO messages. * Put all incoming MO messages into an internal queue. */ int ois_pending_smsmessage(SMSCenter *smsc) { int ret; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(8, "ois_pending_smsmessage"); ret = ois_check_incoming(smsc, OIS_NOWAIT); if (ret == 0 && smsc->socket != -1) { ret = ois_check_input(smsc, OIS_NOWAIT); } if (ret == 0 && smsc->ois_socket != -1) { ois_swap_buffering(smsc); ret = ois_check_input(smsc, OIS_NOWAIT); ois_swap_buffering(smsc); if (smsc->ois_socket == -1 && smsc->ois_ack_debt != 0) { warning(0, "ois_pending_smsmessage: missing %d ack(s)...", smsc->ois_ack_debt); } } return ret; } /* * Send a MT message. */ int ois_submit_msg(SMSCenter *smsc, const Msg *msg) { int ret; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_submit_msg"); ois_swap_buffering(smsc); if (msg_type((Msg *)msg) != sms) { error(0, "ois_submit_msg: can not handle message types other than smart_msg"); goto error; } if (smsc->socket == -1) { ret = ois_open_sender(smsc); if (ret < 0) { goto error; } } ret = ois_submit_sm_invoke(smsc, msg); if (ret < 0) { goto error_close; } ++smsc->ois_ack_debt; time(&smsc->ois_alive); ret = 0; goto out; error_close: if (smsc->ois_ack_debt != 0) { warning(0, "ois_submit_msg: missing %d ack(s)...", smsc->ois_ack_debt); } SAY(4, "ois_submit_msg: ois_disconnect in error_close"); ois_disconnect(smsc); error: SAY(2, "ois_submit_msg error"); ret = -1; out: ois_swap_buffering(smsc); return ret; } /* * Receive a MO message (from the internal queue). */ int ois_receive_msg(SMSCenter *smsc, Msg **msg) { ois_listentry *item; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_receive_msg"); item = smsc->ois_received_mo; if (item == NULL) { /* no mo messages */ if ((smsc->ois_flags & OIS_FLAG_ERROR) == 0) { return 0; /* should actually not happen */ } else { return -1; /* error pending, reopen? */ } } else { /* we have a message waiting */ smsc->ois_received_mo = item->next; *msg = item->msg; gw_free(item); return 1; /* got the message */ } } /* * Destruct the internal queue. */ void ois_delete_queue(SMSCenter *smsc) { Msg *msg; ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG; SAY(2, "ois_delete_queue"); while (ois_receive_msg(smsc, &msg) > 0) { gw_free(msg); } return; } /* * Implementation of 'private:' */ static int ois_open_listener(SMSCenter *smsc) { SAY(2, "ois_open_listener"); smsc->ois_listening_socket = make_server_socket(smsc->receive_port, NULL); /* XXX add interface_name if required */ if (smsc->ois_listening_socket < 0) { goto error; } if (socket_set_blocking(smsc->ois_listening_socket, 0) < 0) { ois_close(smsc); goto error; } smsc->ois_flags &= ~OIS_FLAG_ERROR; smsc->ois_flags &= ~OIS_FLAG_NOBANNER; smsc->ois_alive2 = time(&smsc->ois_alive); SAY2(2, "ois_open_listener fd=%d", smsc->ois_listening_socket); return 0; error: error(0, "ois_open_listener: failed to open listening socket"); return -1; } static int ois_open_sender(SMSCenter *smsc) { int ret; char buffer[BUFLEN+1]; time_t now; time_t beginning; SAY(2, "ois_open_sender"); debug("bb.sms.ois", 0, "connecting to host %s port %d", smsc->hostname, smsc->port); time(&beginning); smsc->socket = tcpip_connect_to_server(smsc->hostname, smsc->port, NULL); /* XXX add interface_name if required */ if (smsc->socket < 0) { return -1; } else { smsc->buflen = 0; time(&smsc->ois_alive); smsc->ois_ack_debt = 0; } SAY2(2, "ois_open_sender fd=%d", smsc->socket); if (smsc->ois_flags & OIS_FLAG_NOBANNER) { return 0; } buffer[0] = '\0'; for (time(&now); (now - beginning) < OIS_OPEN_WAITTIME; time(&now)) { ret = ois_read_into_buffer(smsc, OIS_WAITTIME); if (ret < 0) { goto error; } if (smsc->buflen == 0) { /* assume that the router is in the quiet mode */ /* there will be no banners */ smsc->ois_flags |= OIS_FLAG_NOBANNER; debug("bb.sms.ois", 0, "assuming that %s:%d is in the quiet mode", smsc->hostname, smsc->port); return 0; } ret = ois_extract_line_from_buffer(buffer, smsc); if (ret > 0) { if (strncmp(buffer, "Trying", 6) == 0 && strstr(buffer, "...Open\r\n") != NULL) { time(&smsc->ois_alive); return 0; } else { break; } } } error: SAY(4, "ois_open_sender: ois_disconnect in error"); ois_disconnect(smsc); error(0, "ois_open_sender: failed to connect [%s%s]", buffer, ois_debug_str(smsc->buffer, smsc->buflen)); return -1; } static int ois_open_receiver(SMSCenter *smsc) { struct sockaddr_in addr; int addrlen; Octstr *os; SAY(2, "ois_open_receiver"); /* the listening socket should be non-blocking... */ addrlen = sizeof(addr); smsc->socket = accept(smsc->ois_listening_socket, (struct sockaddr *)&addr, (socklen_t *)&addrlen); if (smsc->socket == -1) { if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) /* || errno == ECONNABORTED || errno == EPROTO) -Kalle 6.7 */ { return 0; } else { error(errno, "ois_open_receiver: accept failed"); smsc->ois_flags |= OIS_FLAG_ERROR; return -1; } } SAY2(2, "ois_open_receiver fd=%d", smsc->socket); os = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr); debug("bb.sms.ois", 0, "connection from host %s port %hu", octstr_get_cstr(os), ntohs(addr.sin_port)); octstr_destroy(os); time(&smsc->ois_alive); return 0; } static void ois_disconnect_all(SMSCenter *smsc) { SAY2(2, "ois_disconnect_all fd=%d", smsc->ois_listening_socket); ois_swap_buffering(smsc); SAY(4, "ois_disconnect_all: ois_disconnect"); ois_disconnect(smsc); /* smsc->socket */ ois_swap_buffering(smsc); SAY(4, "ois_disconnect_all: ois_disconnect"); ois_disconnect(smsc); /* smsc->socket */ if (smsc->ois_listening_socket != -1) { if (close(smsc->ois_listening_socket) == -1) { warning(errno, "ois_disconnect_all: close failed..."); } smsc->ois_listening_socket = -1; } return; } static void ois_disconnect(SMSCenter *smsc) { SAY2(2, "ois_disconnect fd=%d", smsc->socket); if (smsc->socket != -1) { if (close(smsc->socket) == -1) { warning(errno, "ois_disconnect: close failed..."); } smsc->socket = -1; } return; } static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec) { int ret; SAY(8, "ois_read_into_buffer"); if (smsc->socket == -1) { if ((smsc->ois_flags & OIS_FLAG_CLOSED) == 0) { debug("bb.sms.ois", 0, "attempting to read from a closed socket"); smsc->ois_flags |= OIS_FLAG_CLOSED; } return 0; } else { smsc->ois_flags &= ~OIS_FLAG_CLOSED; } ret = read_available(smsc->socket, wait_usec); if (ret > 0) { time(&smsc->ois_alive); ret = smscenter_read_into_buffer(smsc); if (ret > 0 || (ret == 0 && smsc->buflen > 0)) { SAY(2, "ois_read_into_buffer got something"); } else if (ret == 0) { if (smsc->buflen > 0) { SAY(2, "ois_read_into_buffer has something"); ret = 1; } SAY(4, "ois_read_into_buffer: ois_disconnect"); ois_disconnect(smsc); } } return ret; } static int ois_check_input(SMSCenter *smsc, long wait_usec) { char buffer[BUFLEN+1]; time_t now; int ret; SAY(8, "ois_check_input"); ret = ois_read_into_buffer(smsc, wait_usec); if (ret < 0) { goto error; } ret = ois_extract_msg_from_buffer(buffer, smsc); if (ret > 0) { IOTRACE("received", buffer, ret); switch (buffer[0]) { case 's': ret = ois_submit_sm_result(smsc, buffer); if (ret > 0) { warning(0, "ois_check_input: submit sm result signals (%d)...", ret); } else if (ret < 0) { error(0, "ois_check_input: invalid submit sm result"); goto error; } --smsc->ois_ack_debt; time(&smsc->ois_alive); break; case 'M': ret = ois_deliver_sm_invoke(smsc, buffer); if (ret >= 0) { ret = ois_deliver_sm_result(smsc, ret, buffer); if (ret < 0) { goto error; } } else { error(0, "ois_check_input: invalid deliver sm invoke"); goto error; } time(&smsc->ois_alive); break; default: warning(0, "ois_check_input: unexpected message [%s]...", ois_debug_str(buffer, ret)); break; } } else { if (smsc->socket != -1) { time(&now); if ((now - smsc->ois_alive) > OIS_MESSAGE_WAITTIME) { debug("bb.sms.ois", 0, "closing an idle connection"); SAY(4, "ois_check_input: ois_disconnect"); ois_disconnect(smsc); } } } if (ret < 0) { error(0, "ois_check_input: malformatted message [%s]", ois_debug_str(buffer, -ret)); goto error; } if (smsc->ois_received_mo != NULL || (smsc->ois_flags & OIS_FLAG_ERROR) != 0) { SAY(2, "ois_check_input has something"); return 1; /* at least one message in the queue or an error pending */ } else { return 0; /* no messages this time */ } error: smsc->ois_flags |= OIS_FLAG_ERROR; return 1; } static int ois_check_incoming(SMSCenter *smsc, long wait_usec) { fd_set read_fd; struct timeval tv; int ret; SAY(8, "ois_check_incoming"); tv.tv_sec = 0; tv.tv_usec = wait_usec; FD_ZERO(&read_fd); FD_SET(smsc->ois_listening_socket, &read_fd); ret = select(smsc->ois_listening_socket + 1, &read_fd, NULL, NULL, &tv); if (ret == -1) { if (errno == EINTR || errno == EAGAIN) { return 0; } else { error(errno, "ois_check_incoming: select failed"); smsc->ois_flags |= OIS_FLAG_ERROR; return -1; } } else if (ret == 0) { return 0; } /* if we end up here, someone is trying to connect */ if (smsc->socket != -1) { if ((smsc->ois_flags & OIS_FLAG_MULTIPLE_CALL) == 0) { /* if you see lots of these, maybe we should accept */ /* multiple incoming connections at a time... */ debug("bb.sms.ois", 0, "letting an incoming call to wait until the old one disconnects"); smsc->ois_flags |= OIS_FLAG_MULTIPLE_CALL; } return 0; } smsc->ois_flags &= ~OIS_FLAG_MULTIPLE_CALL; return ois_open_receiver(smsc); } static void ois_append_to_list(ois_listentry **head, Msg *msg) { ois_listentry *item; ois_listentry *tail; SAY(2, "ois_append_to_list"); item = gw_malloc(sizeof(ois_listentry)); item->next = NULL; item->msg = msg; if (*head == NULL) { *head = item; } else { /* not so bright algorithm, but ok with relatively short lists */ for (tail = *head; tail->next != NULL; tail = tail->next) ; tail->next = item; } return; } static int ois_int_to_i4(char *raw, int nbr) { int pos; SAY(3, "ois_int_to_i4"); for (pos = 0; pos < 4; ++pos) { raw[pos] = (char)(nbr % 0x100); nbr /= 0x100; } return 4; } static int ois_increment_counter(void) { SAY(3, "ois_increment_counter"); ois_counter = (ois_counter+1) % MAXCOUNTER; return ois_counter; } static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg) { char body[BUFLEN+1]; char buffer[BUFLEN+1]; int len; int count; int i; int ret; SAY(2, "ois_submit_sm_invoke"); /* construct a message */ ois_increment_counter(); /* once per invoke */ len = ois_encode_submit_sm_invoke(body, msg); /* the x.25 gear should be capable to fragment large messages, but... */ /* let's just use an explicit 128 byte blocks */ count = (len-1) / 121; /* 121 = 128 - 6 - 1 */ /* first part */ sprintf(buffer, "%c%c%04d%.121s%c", 'S', /* submit sm invoke */ (char)(0x50|count), /* ia5 encoding, first part */ ois_counter, &body[0], EOL); IOTRACE("sending", buffer, strlen(buffer)); ret = write_to_socket(smsc->socket, buffer); if (ret < 0) { goto error; } /* additional parts */ for (i = 1; i <= count; ++i) { sprintf(buffer, "%c%c%04d%.121s%c", 'S', /* submit sm invoke */ (char)(0x60|(count-i)), /* ia5, additional part */ ois_counter, &body[i*121], EOL); IOTRACE("sending", buffer, strlen(buffer)); ret = write_to_socket(smsc->socket, buffer); if (ret < 0) { goto error; } } SAY(2, "ois_submit_sm_invoke ok"); return 0; error: SAY(2, "ois_submit_sm_invoke error"); return -1; } static int ois_encode_submit_sm_invoke(char *str, const Msg *msg) { char raw[BUFLEN]; int pos; int ret; SAY(3, "ois_encode_submit_sm_invoke"); /* construct the submit sm invoke body content */ pos = 0; pos += ois_append_msisdn(&raw[pos], msg); pos += ois_append_sme_reference_number(&raw[pos]); pos += ois_append_priority(&raw[pos]); pos += ois_append_originating_address(&raw[pos]); pos += ois_append_validity_period(&raw[pos]); pos += ois_append_data_coding_scheme(&raw[pos], msg); pos += ois_append_status_report_request(&raw[pos]); pos += ois_append_protocol_id(&raw[pos]); pos += ois_append_submission_options(&raw[pos], msg); pos += ois_append_sm_text(&raw[pos], msg); ret = ois_convert_to_ia5(str, raw, pos); return ret; } static int ois_append_msisdn(char *raw, const Msg *msg) { int len; SAY(3, "ois_append_msisdn"); len = octstr_len(msg->sms.receiver); raw[0] = (char) len; memcpy(&raw[1], octstr_get_cstr(msg->sms.receiver), len); return 1 + len; } static int ois_append_sme_reference_number(char *raw) { SAY(3, "ois_append_sme_reference_number"); /* 1=key, 2=not key (OIS 4.5) */ /* or 1=reject duplicates, 2=allow duplicates (OIS 5.0) */ raw[0] = (char) 2; return 1 + ois_int_to_i4(&raw[1], ois_counter); } static int ois_append_priority(char *raw) { SAY(3, "ois_append_priority"); raw[0] = (char) 1; /* 0=high, 1=normal */ return 1; } static int ois_append_originating_address(char *raw) { SAY(3, "ois_append_originating_address"); raw[0] = (char) 2; /* length */ raw[1] = 'A'; /* A3=address type, actual address is unnecessary */ raw[2] = '3'; return 3; } static int ois_append_validity_period(char *raw) { SAY(3, "ois_append_validity_period"); raw[0] = (char) 2; /* 0=none, 1=absolute, 2=relative */ raw[1] = (char) 1; /* relative, (v+1)*5 minutes, v<144 */ return 2; } static int ois_append_data_coding_scheme(char *raw, const Msg *msg) { SAY(3, "ois_append_data_coding_scheme"); /* 0x0f is a special code for ASCII text, the SMSC will convert * this to GSM and set the DCS to 0. * FIXME: Convert to GSM ourselves and use DCS_GSM_TEXT. * FIXME: use fields_to_dcs and try to support DC_UCS2 too ;) */ raw[0] = (char) (msg->sms.coding == DC_8BIT ? DCS_OCTET_DATA : 0x0f); return 1; } static int ois_append_status_report_request(char *raw) { SAY(3, "ois_append_status_report_request"); raw[0] = (char) 0x00; /* bit field, bit 0=abandoned, bit 2=delivered */ return 1; } static int ois_append_protocol_id(char *raw) { SAY(3, "ois_append_protocol_id"); raw[0] = (char) 0; /* 0=default */ return 1; } static int ois_append_submission_options(char *raw, const Msg *msg) { SAY(3, "ois_append_submission_options"); /* bit field, bit 0=reply path, bit 1=udh, bits 3-4=dcs interpretation */ raw[0] = (char) 0x00; if (octstr_len(msg->sms.udhdata)) { raw[0] |= (char) 0x02; } if (msg->sms.coding == DC_8BIT) { /* XXX and UCS-2? */ raw[0] |= (char) 0x10; } return 1; } static int ois_append_sm_text(char *raw, const Msg *msg) { int udhlen7, udhlen8; int msglen7, msglen8; int len; SAY(3, "ois_append_sm_text"); if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) { charset_utf8_to_gsm(msg->sms.udhdata); charset_utf8_to_gsm(msg->sms.msgdata); } /* calculate lengths */ udhlen8 = octstr_len(msg->sms.udhdata); msglen8 = octstr_len(msg->sms.msgdata); udhlen7 = udhlen8; msglen7 = msglen8; len = udhlen8 + msglen8; /* copy text */ raw[0] = (char) (len); raw[1] = (char) (udhlen7 + msglen7); memcpy(&raw[2], octstr_get_cstr(msg->sms.udhdata), udhlen8); memcpy(&raw[2+udhlen8], octstr_get_cstr(msg->sms.msgdata), msglen8); IOTRACE("encoding", &raw[2], len); return 2 + len; } static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer) { int status; int ret; SAY(2, "ois_submit_sm_result"); ret = ois_decode_submit_sm_result(&status, buffer); if (ret < 0) { goto error; } return status; error: return -1; } static int ois_decode_submit_sm_result(int *code, const char *str) { int buflen; char raw[BUFLEN]; int len; SAY(3, "ois_decode_submit_sm_result"); buflen = strlen(str) - 1; if (buflen < 7 || str[0] != 's' || str[1] != 0x50 || str[buflen] != EOL) { goto error; } len = ois_convert_from_ia5(raw, &str[6]); if (len <= 0) { goto error; } *code = raw[0]; *code &= 0xff; /* there is smsc reference number and accept time, but we ignore them */ return 0; error: return -1; } static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer) { Msg *msg; int ret; ois_listentry **mo; SAY(2, "ois_deliver_sm_invoke"); msg = msg_create(sms); ret = ois_decode_deliver_sm_invoke(msg, buffer); if (ret < 0) { goto error; } mo = (ois_listentry **)&smsc->ois_received_mo; ois_append_to_list(mo, msg); return 0; error: msg_destroy(msg); return -1; } static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str) { char body[BUFLEN+1]; char raw[BUFLEN]; int len; int i; int pos; int ret; SAY(3, "ois_decode_deliver_sm_invoke"); ret = ois_check_deliver_sm_invoke(str); if (ret < 0) { goto error; } /* extract body */ len = strlen(str); for (pos = 0, i = 6; i < len; ++i) { if (str[i] != EOL) { body[pos++] = str[i]; } else { i += 6; } } body[pos] = '\0'; memset(raw, '\0', sizeof(raw)); len = ois_convert_from_ia5(raw, body); /* adjust msg values */ pos = 0; pos += ois_adjust_destination_address(msg, &raw[pos]); pos += ois_ignore_smsc_reference_number(&raw[pos]); pos += ois_adjust_originating_address(msg, &raw[pos]); pos += ois_adjust_data_coding_scheme(msg, &raw[pos]); pos += ois_ignore_protocol_id(&raw[pos]); pos += ois_adjust_additional_information(msg, &raw[pos]); pos += ois_adjust_sm_text(msg, &raw[pos]); pos += ois_ignore_time(&raw[pos]); /* accept time */ pos += ois_ignore_time(&raw[pos]); /* invoke time */ if (pos != len) { error(0, "ois_decode_deliver_sm_invoke: message parsing error (%d!=%d)", pos, len); goto error; } return 0; error: return -1; } static int ois_check_deliver_sm_invoke(const char *str) { int buflen; char buffer[BUFLEN+1]; int count; SAY(3, "ois_check_deliver_sm_invoke"); /* check the (initial) header and trailer */ buflen = strlen(str) - 1; if (buflen < 7 || str[0] != 'M' || (str[1] & 0x50) != 0x50 || str[buflen] != EOL) { goto error; } count = str[1] & 0x0f; while (--count >= 0) { /* check the additional header */ sprintf(buffer, "%c%c%c%.4s", EOL, 'M', /* deliver sm invoke */ (char)(0x60|count), /* ia5 encoding, additional part */ &str[2]); if (strstr(str, buffer) == NULL) { goto error; } } return 0; error: return -1; } static int ois_adjust_destination_address(Msg *msg, const char *raw) { int len; SAY(3, "ois_adjust_destination_address"); len = raw[0] & 0xff; msg->sms.receiver = octstr_create_from_data(&raw[1+2], len-2); return 1 + len; } static int ois_ignore_smsc_reference_number(const char *raw) { int value; SAY(3, "ois_ignore_smsc_reference_number"); value = raw[3] & 0xff; value <<= 8; value |= raw[2] & 0xff; value <<= 8; value |= raw[1] & 0xff; value <<= 8; value |= raw[0] & 0xff; return 4; } static int ois_adjust_originating_address(Msg *msg, const char *raw) { int len; SAY(3, "ois_adjust_originating_address"); len = raw[0] & 0xff; msg->sms.sender = octstr_create_from_data(&raw[1+2], len-2); return 1 + len; } static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw) { SAY(3, "ois_adjust_data_coding_scheme"); /* we're using this variable temporarily: * ois_adjust_sm_text will set the correct value */ msg->sms.coding = (raw[0] & 0xff) + 1; return 1; } static int ois_ignore_protocol_id(const char *raw) { SAY(3, "ois_ignore_protocol_id"); return 1; } static int ois_adjust_additional_information(Msg *msg, const char *raw) { SAY(3, "ois_adjust_additional_information"); /* we're using this variable temporarily: * ois_adjust_sm_text will set the correct value */ msg->sms.mclass = raw[0] & 0xff; return 1; } static int ois_adjust_sm_text(Msg *msg, const char *raw) { int msglen7, msglen8; char buffer[BUFLEN+1]; SAY(3, "ois_adjust_sm_text"); /* calculate lengths */ msglen7 = raw[0] & 0xff; msglen8 = raw[1] & 0xff; /* copy text, note: flag contains temporarily the raw type description */ switch ((msg->sms.coding - 1) & 0xff) { case 0x00: /* gsm7 */ ois_expand_gsm7(buffer, &raw[2], msglen7); ois_convert_to_iso88591(buffer, msglen7); if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */ msg->sms.msgdata = octstr_create(""); msg->sms.udhdata = octstr_create_from_data(buffer, msglen7); } else { msg->sms.msgdata = octstr_create_from_data(buffer, msglen7); msg->sms.udhdata = octstr_create(""); } msg->sms.coding = DC_7BIT; break; case 0x0f: /* ia5 */ memcpy(buffer, &raw[2], msglen8); ois_convert_to_iso88591(buffer, msglen8); if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */ msg->sms.msgdata = octstr_create(""); msg->sms.udhdata = octstr_create_from_data(buffer, msglen8); } else { msg->sms.msgdata = octstr_create_from_data(buffer, msglen8); msg->sms.udhdata = octstr_create(""); } msg->sms.coding = DC_7BIT; break; default: /* 0xf4, 0xf5, 0xf6, 0xf7; 8bit to disp, mem, sim or term */ if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */ msg->sms.msgdata = octstr_create(""); msg->sms.udhdata = octstr_create_from_data(&raw[2], msglen8); } else { msg->sms.msgdata = octstr_create_from_data(&raw[2], msglen8); msg->sms.udhdata = octstr_create(""); } msg->sms.coding = DC_8BIT; break; } msg->sms.mclass = MC_UNDEF; if (octstr_len(msg->sms.udhdata)) { IOTRACE("decoded udh", octstr_get_cstr(msg->sms.udhdata), octstr_len(msg->sms.udhdata)); } else { IOTRACE("decoded", octstr_get_cstr(msg->sms.msgdata), octstr_len(msg->sms.msgdata)); } return 2 + msglen8; } static int ois_ignore_time(const char *raw) { char str[15]; SAY(3, "ois_ignore_time"); strncpy(str, raw, 14); str[14] = '\0'; return 14; } static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str) { char body[BUFLEN+1]; char buffer[BUFLEN+1]; int ret; SAY(2, "ois_deliver_sm_result"); /* construct a message */ ois_encode_deliver_sm_result(body, result); /* first and only part */ sprintf(buffer, "%c%c%.4s%.121s%c", 'm', /* deliver sm result */ (char)(0x50), /* ia5 encoding, the only part */ &str[2], &body[0], EOL); IOTRACE("sending", buffer, strlen(buffer)); ret = write_to_socket(smsc->socket, buffer); if (ret < 0) { goto error; } return 0; error: return -1; } static int ois_encode_deliver_sm_result(char *str, int result) { char raw[4]; SAY(3, "ois_encode_deliver_sm_result"); /* construct the deliver sm result body content */ raw[0] = (char) result; return ois_convert_to_ia5(str, raw, 1); } static int ois_expand_gsm7(char *raw8, const char *raw7, int len) { int i; char bits[8*(BUFLEN+1)]; SAY2(3, "ois_expand_gsm7 len=%d", len); /* yeah, there are also better algorithms, but... */ /* well, at least this is fairly portable and ok for small messages... */ ois_expand_gsm7_to_bits(bits, raw7, len); for (i = 0; i < len; ++i) { raw8[i] = ois_expand_gsm7_from_bits(bits, i); } SAY2(5, "ois_expand_gsm7 gave [%s]", ois_debug_str(raw8, i)); return i; } static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len) { int i, j, k; char ch; SAY(3, "ois_expand_gsm7_to_bits"); len *= 7; /* number of bits in the gms 7-bit msg */ for (j = i = 0; j < len; ++i) { ch = raw7[i]; for (k = 0; k < 8; ++k) { bits[j++] = (char) (ch & 0x01); ch >>= 1; } } return j; } static char ois_expand_gsm7_from_bits(const char *bits, int pos) { int i; char ch; SAY2(8, "ois_expand_gsm7_from_bits pos=%d", pos); pos *= 7; /* septet position in bits */ ch = '\0'; for (i = 6; i >= 0; --i) { ch <<= 1; ch |= bits[pos+i]; } return ch; } static int ois_convert_to_ia5(char *str, const char *raw, int len) { int j; int i; int ch; SAY2(3, "ois_convert_to_ia5 len=%d", len); for (j = i = 0; i < len; ++i) { ch = raw[i] & 0xff; if (ch == 0x5c || ch == 0x5e || ch == 0x60 || ch == 0x7e) { str[j++] = (char) 0x5c; str[j++] = (char) ch; } else if (0x20 <= ch && ch < 0x7f) { str[j++] = (char) ch; } else if (0x00 <= ch && ch < 0x20) { str[j++] = (char) 0x5e; str[j++] = (char) ch + 0x40; } else if (0xa0 <= ch && ch < 0xff) { str[j++] = (char) 0x60; str[j++] = (char) ch - 0x80; } else if (0x80 <= ch && ch < 0xa0) { str[j++] = (char) 0x7e; str[j++] = (char) ch - 0x40; } else if (ch == 0x7f) { str[j++] = (char) 0x5e; str[j++] = (char) 0x7e; } else { /* ch == 0xff */ str[j++] = (char) 0x7e; str[j++] = (char) 0x7e; } } str[j] = '\0'; SAY2(5, "ois_convert_to_ia5 gave [%s]", ois_debug_str(str, j)); return j; } static int ois_convert_from_ia5(char *raw, const char *str) { int j; int i; int ch; SAY(3, "ois_convert_from_ia5"); for (j = i = 0; ; ++i) { ch = str[i] & 0xff; if (ch < 0x20 || 0x7f <= ch) { break; } else if (ch == 0x5c) { ch = str[++i] & 0xff; if (ch == 0x5c || ch == 0x5e || ch == 0x60 || ch == 0x7e) { raw[j++] = (char) ch; } else { break; } } else if (ch == 0x5e) { ch = str[++i] & 0xff; if (0x40 <= ch && ch < 0x60) { raw[j++] = (char) ch - 0x40; } else if (ch == 0x7e) { raw[j++] = (char) 0x7f; } else { break; } } else if (ch == 0x60) { ch = str[++i] & 0xff; if (0x20 <= ch && ch < 0x7f) { raw[j++] = (char) ch + 0x80; } else { break; } } else if (ch == 0x7e) { ch = str[++i] & 0xff; if (0x40 <= ch && ch < 0x60) { raw[j++] = (char) ch + 0x40; } else if (ch == 0x7e) { raw[j++] = (char) 0xff; } else { break; } } else { /* 0x20 <= ch && ch < 0x7f */ raw[j++] = (char) ch; } } SAY2(5, "ois_convert_from_ia5 gave [%s]", ois_debug_str(raw, j)); return j; } static int ois_convert_to_iso88591(char *raw, int len) { /* a best effort 1-to-1 conversion according to ois appendix a */ static const char gsm_to_iso88591[] = { '@', 0xa3,'$', 0xa5,0xe8,0xe9,0xf9,0xec, /* 0x00 - 0x07 */ 0xf2,0xc7,'\n',0xd8,0xf8,'\r',0xc5,0xe5, /* 0x08 - 0x0f */ 'D', ' ', 'F', 'G', 'L', 'W', 'P', 'Y', /* 0x10 - 0x17, poor! */ 'Y', 'S', 'X', ' ', 0xc6,0xe6,'b', 0xc9, /* 0x18 - 0x1f, poor! */ ' ', '!', '"', '#', 0xa4, '%', '&', '\'',/* 0x20 - 0x27 */ '(', ')', '*', '+', ',', '-', '.', '/', /* 0x28 - 0x2f */ '0', '1', '2', '3', '4', '5', '6', '7', /* 0x30 - 0x37 */ '8', '9', ':', ';', '<', '=', '>', '?', /* 0x38 - 0x3f */ 0xa1,'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40 - 0x47 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 0x48 - 0x4f */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50 - 0x57 */ 'X', 'Y', 'Z', 0xc4,0xd6,0xd1,0xdc,0xa7, /* 0x58 - 0x5f */ 0xbf,'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60 - 0x67 */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 0x68 - 0x6f */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70 - 0x77 */ 'x', 'y', 'z', 0xe4,0xf6,0xf1,0xfc,0xe0 /* 0x78 - 0x7f */ }; int i; SAY2(3, "ois_convert_to_iso88591 len=%d", len); for (i = 0; i < len; ++i) { raw[i] = gsm_to_iso88591[raw[i] & 0x7f]; } SAY2(5, "ois_convert_to_iso88591 gave [%s]", ois_debug_str(raw, i)); return i; } /* * Extract a message from the internal buffer. */ static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc) { int len; int count; SAY2(8, "ois_extract_msg_from_buffer buflen=%ld", (long)smsc->buflen); str[0] = '\0'; if (smsc->buflen < 7) { /* 7 = 6 + 1 */ return 0; /* we don't have a message yet */ } if (strchr("SRDATECQLMPOVsrdatecqlmpov", smsc->buffer[0]) == NULL || (smsc->buffer[1] & 0xf0) != 0x50) { goto error; } /* a valid message type, find the end of the message */ count = smsc->buffer[1] & 0x0f; for (len = 0; (size_t) len < smsc->buflen; ++len) { if (smsc->buffer[len] == EOL) { if (--count < 0) { ++len; break; } } } if (count >= 0) { /* we don't have all the pieces */ if (len < BUFLEN) { return 0; /* ...but maybe later */ } goto error; } /* the buffer contains a promising message candidate */ memcpy(str, smsc->buffer, len); str[len] = '\0'; smscenter_remove_from_buffer(smsc, len); /* just the message */ return len; error: for (len = 0; (size_t) len < smsc->buflen && smsc->buffer[len] != EOL; ++len) ; if (len > BUFLEN) len = BUFLEN; memcpy(str, smsc->buffer, len); str[len] = '\0'; smscenter_remove_from_buffer(smsc, smsc->buflen); /* everything */ return -len; } /* * Extract a line from the internal buffer. */ static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc) { int len; SAY2(3, "ois_extract_line_from_buffer buflen=%ld", (long)smsc->buflen); str[0] = '\0'; for (len = 0; (size_t) len < smsc->buflen && smsc->buffer[len] != '\n'; ++len) ; if ((size_t) len >= smsc->buflen) { return 0; } else { ++len; } /* the buffer contains a line */ memcpy(str, smsc->buffer, len); str[len] = '\0'; smscenter_remove_from_buffer(smsc, len); /* just the line */ return len; } static void ois_swap_buffering(SMSCenter *smsc) { time_t alive; int socket; char *buffer; size_t bufsize; size_t buflen; SAY(8, "ois_swap_buffering"); if (smsc->ois_bufsize == 0) { smsc->ois_buflen = 0; smsc->ois_bufsize = smsc->bufsize; smsc->ois_buffer = gw_malloc(smsc->ois_bufsize); memset(smsc->ois_buffer, 0, smsc->ois_bufsize); } alive = smsc->ois_alive; smsc->ois_alive = smsc->ois_alive2; smsc->ois_alive2 = alive; socket = smsc->socket; smsc->socket = smsc->ois_socket; smsc->ois_socket = socket; buffer = smsc->buffer; smsc->buffer = smsc->ois_buffer; smsc->ois_buffer = buffer; buflen = smsc->buflen; smsc->buflen = smsc->ois_buflen; smsc->ois_buflen = buflen; bufsize = smsc->bufsize; smsc->bufsize = smsc->ois_bufsize; smsc->ois_bufsize = bufsize; return; } static const char *ois_debug_str(const char *raw, int len) { static const char hex[] = "0123456789abcdef"; static char str[4*(BUFLEN+1)+1]; int pos; int ch; int i; pos = 0; for (i = 0; i < len; ++i) { ch = raw[i] & 0xff; if (0x20 <= ch && ch < 0x7f && ch != 0x5c) { str[pos++] = (char) ch; } else { str[pos++] = '\\'; str[pos++] = 'x'; str[pos++] = hex[ch/16]; str[pos++] = hex[ch%16]; } } str[pos] = '\0'; return str; } gateway-1.4.5/gw/smsc/smsc_cimd2.c0000644000175000017500000023211113227613126015440 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* Driver for CIMD 2 SMS centres. * Copyright 2000 WapIT Oy Ltd. * Author: Richard Braakman * * Upgrade to SMSCConn API: 2002 Kalle Marjola / 2003 Angel Fradejas */ /* TODO: Check checksums on incoming packets */ /* TODO: Leading or trailing spaces are not allowed on parameters * "user identity" and "password". Check this. */ /* TODO: Try to use the "More messages to send" flag */ /* This code is based on the CIMD 2 spec, version 2-0 en. * All USSD-specific parts have been left out, since we only want to * communicate with SMSC's. * * I found one contradiction in the spec: * * - The definition of Integer parameters specifies decimal digits only, * but at least one Integer parameter (Validity Period Relative) can * be negative. I assume that this means a leading - is valid. */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "shared.h" #include "sms.h" #include "dlr.h" typedef struct privdata { Octstr *username; Octstr *password; Octstr *host; long port; long our_port; long keepalive; Octstr *my_number; int no_dlr; int socket; int send_seq; int receive_seq; Octstr *inbuffer; List *received; time_t next_ping; List *outgoing_queue; SMSCConn *conn; int io_thread; int quitting; List *stopped; /* list-trick for suspend/isolate */ } PrivData; /* Microseconds before giving up on a request */ #define RESPONSE_TIMEOUT (60 * 1000000) /* Textual names for the operation codes defined by the CIMD 2 spec. */ /* If you make changes here, also change the operation table. */ enum { /* Requests from client */ LOGIN = 1, LOGOUT = 2, SUBMIT_MESSAGE = 3, ENQUIRE_MESSAGE_STATUS = 4, DELIVERY_REQUEST = 5, CANCEL_MESSAGE = 6, SET_REQ = 8, GET_REQ = 9, /* Requests from server */ DELIVER_MESSAGE = 20, DELIVER_STATUS_REPORT = 23, /* Requests from either */ ALIVE = 40, /* Not a request; add to any request to make it a response */ RESPONSE = 50, /* Responses not related to requests */ GENERAL_ERROR_RESPONSE = 98, NACK = 99 }; /* Textual names for the parameters defined by the CIMD 2 spec. */ /* If you make changes here, also change the parameter table. */ enum { P_USER_IDENTITY = 10, P_PASSWORD = 11, P_DESTINATION_ADDRESS = 21, P_ORIGINATING_ADDRESS = 23, P_ORIGINATING_IMSI = 26, P_ALPHANUMERIC_ORIGINATING_ADDRESS = 27, P_ORIGINATED_VISITED_MSC = 28, P_DATA_CODING_SCHEME = 30, P_USER_DATA_HEADER = 32, P_USER_DATA = 33, P_USER_DATA_BINARY = 34, P_MORE_MESSAGES_TO_SEND = 44, P_VALIDITY_PERIOD_RELATIVE = 50, P_VALIDITY_PERIOD_ABSOLUTE = 51, P_PROTOCOL_IDENTIFIER = 52, P_FIRST_DELIVERY_TIME_RELATIVE = 53, P_FIRST_DELIVERY_TIME_ABSOLUTE = 54, P_REPLY_PATH = 55, P_STATUS_REPORT_REQUEST = 56, P_CANCEL_ENABLED = 58, P_CANCEL_MODE = 59, P_MC_TIMESTAMP = 60, P_STATUS_CODE = 61, P_STATUS_ERROR_CODE = 62, P_DISCHARGE_TIME = 63, P_TARIFF_CLASS = 64, P_SERVICE_DESCRIPTION = 65, P_MESSAGE_COUNT = 66, P_PRIORITY = 67, P_DELIVERY_REQUEST_MODE = 68, P_SERVICE_CENTER_ADDRESS = 69, P_GET_PARAMETER = 500, P_MC_TIME = 501, P_ERROR_CODE = 900, P_ERROR_TEXT = 901 }; /***************************************************************************/ /* Table of properties of the parameters defined by CIMD 2, and some */ /* functions to look up fields. */ /***************************************************************************/ /* Parameter types, internal. CIMD 2 spec considers P_TIME to be "Integer" * and P_SMS to be "User Data". */ enum { P_INT, P_STRING, P_ADDRESS, P_TIME, P_HEX, P_SMS }; /* Information about the parameters defined by the CIMD 2 spec. * Used for warning about invalid incoming messages, and for validating * outgoing messages. */ static const struct { char *name; int number; int maxlen; int type; /* P_ values */ int minval, maxval; /* For P_INT */ } parameters[] = { { "user identity", P_USER_IDENTITY, 32, P_STRING }, { "password", P_PASSWORD, 32, P_STRING }, { "destination address", P_DESTINATION_ADDRESS, 20, P_ADDRESS }, { "originating address", P_ORIGINATING_ADDRESS, 20, P_ADDRESS }, /* IMSI is International Mobile Subscriber Identity number */ { "originating IMSI", P_ORIGINATING_IMSI, 20, P_ADDRESS }, { "alphanumeric originating address", P_ALPHANUMERIC_ORIGINATING_ADDRESS, 11, P_STRING }, { "originated visited MSC", P_ORIGINATED_VISITED_MSC, 20, P_ADDRESS }, { "data coding scheme", P_DATA_CODING_SCHEME, 3, P_INT, 0, 255 }, { "user data header", P_USER_DATA_HEADER, 280, P_HEX }, { "user data", P_USER_DATA, 480, P_SMS }, { "user data binary", P_USER_DATA_BINARY, 280, P_HEX }, { "more messages to send", P_MORE_MESSAGES_TO_SEND, 1, P_INT, 0, 1 }, { "validity period relative", P_VALIDITY_PERIOD_RELATIVE, 3, P_INT, -1, 255 }, { "validity period absolute", P_VALIDITY_PERIOD_ABSOLUTE, 12, P_TIME }, { "protocol identifier", P_PROTOCOL_IDENTIFIER, 3, P_INT, 0, 255 }, { "first delivery time relative", P_FIRST_DELIVERY_TIME_RELATIVE, 3, P_INT, -1, 255 }, { "first delivery time absolute", P_FIRST_DELIVERY_TIME_ABSOLUTE, 12, P_TIME }, { "reply path", P_REPLY_PATH, 1, P_INT, 0, 1 }, { "status report request", P_STATUS_REPORT_REQUEST, 2, P_INT, 0, 63 }, { "cancel enabled", P_CANCEL_ENABLED, 1, P_INT, 0, 1 }, { "cancel mode", P_CANCEL_MODE, 1, P_INT, 0, 2 }, { "service centre timestamp", P_MC_TIMESTAMP, 12, P_TIME }, { "status code", P_STATUS_CODE, 2, P_INT, 0, 9 }, { "status error code", P_STATUS_ERROR_CODE, 3, P_INT, 0, 999 }, { "discharge time", P_DISCHARGE_TIME, 12, P_TIME }, { "tariff class", P_TARIFF_CLASS, 2, P_INT, 0, 99 }, { "service description", P_SERVICE_DESCRIPTION, 2, P_INT, 0, 9 }, { "message count", P_MESSAGE_COUNT, 3, P_INT, 0, 999 }, { "priority", P_PRIORITY, 1, P_INT, 1, 9 }, { "delivery request mode", P_DELIVERY_REQUEST_MODE, 1, P_INT, 0, 2 }, { "service center address", P_SERVICE_CENTER_ADDRESS, 20, P_ADDRESS }, { "get parameter", P_GET_PARAMETER, 3, P_INT, 501, 999 }, { "MC time", P_MC_TIME, 12, P_TIME }, { "error code", P_ERROR_CODE, 3, P_INT, 0, 999 }, { "error text", P_ERROR_TEXT, 64, P_STRING }, { NULL } }; /* Return the index in the parameters array for this parameter id. * Return -1 if it is not found. */ static int parm_index(int parmno) { int i; for (i = 0; parameters[i].name != NULL; i++) { if (parameters[i].number == parmno) return i; } return -1; } #ifndef NO_GWASSERT /* Return the type of this parameter id. Return -1 if the id is unknown. */ static int parm_type(int parmno) { int i = parm_index(parmno); if (i < 0) return -1; return parameters[i].type; } #endif /* Return the max length for this parameter id. * Return -1 if the id is unknown. */ static int parm_maxlen(int parmno) { int i = parm_index(parmno); if (i < 0) return -1; return parameters[i].maxlen; } static const char *parm_name(int parmno) { int i = parm_index(parmno); if (i < 0) return NULL; return parameters[i].name; } #ifndef NO_GWASSERT /* Return 1 if the value for this (Integer) parameter is in range. * Return 0 otherwise. Return -1 if the parameter was not found. */ static int parm_in_range(int parmno, long value) { int i; i = parm_index(parmno); if (i < 0) return -1; return (value >= parameters[i].minval && value <= parameters[i].maxval); } #endif /* Helper function to check P_ADDRESS type */ static int isphonedigit(int c) { return isdigit(c) || c == '+' || c == '-'; } static int parm_valid_address(Octstr *value) { return octstr_check_range(value, 0, octstr_len(value), isphonedigit); } /***************************************************************************/ /* Some functions to look up information about operation codes */ /***************************************************************************/ static int operation_find(int operation); static Octstr *operation_name(int operation); static int operation_can_send(int operation); static int operation_can_receive(int operation); static const struct { char *name; int code; int can_send; int can_receive; } operations[] = { { "Login", LOGIN, 1, 0 }, { "Logout", LOGOUT, 1, 0 }, { "Submit message", SUBMIT_MESSAGE, 1, 0 }, { "Enquire message status", ENQUIRE_MESSAGE_STATUS, 1, 0 }, { "Delivery request", DELIVERY_REQUEST, 1, 0 }, { "Cancel message", CANCEL_MESSAGE, 1, 0 }, { "Set parameter", SET_REQ, 1, 0 }, { "Get parameter", GET_REQ, 1, 0 }, { "Deliver message", DELIVER_MESSAGE, 0, 1 }, { "Deliver status report", DELIVER_STATUS_REPORT, 0, 1 }, { "Alive", ALIVE, 1, 1 }, { "NACK", NACK, 1, 1 }, { "General error response", GENERAL_ERROR_RESPONSE, 0, 1 }, { NULL, 0, 0, 0 } }; static int operation_find(int operation) { int i; for (i = 0; operations[i].name != NULL; i++) { if (operations[i].code == operation) return i; } return -1; } /* Return a human-readable representation of this operation code */ static Octstr *operation_name(int operation) { int i; i = operation_find(operation); if (i >= 0) return octstr_create(operations[i].name); if (operation >= RESPONSE) { i = operation_find(operation - RESPONSE); if (i >= 0) { Octstr *name = octstr_create(operations[i].name); octstr_append_cstr(name, " response"); return name; } } /* Put the operation number here when we have octstr_format */ return octstr_create("(unknown)"); } /* Return true if a CIMD2 client may send this operation */ static int operation_can_send(int operation) { int i = operation_find(operation); if (i >= 0) return operations[i].can_send; /* If we can receive the request, then we can send the response. */ if (operation >= RESPONSE) return operation_can_receive(operation - RESPONSE); return 0; } /* Return true if a CIMD2 server may send this operation */ static int operation_can_receive(int operation) { int i = operation_find(operation); if (i >= 0) return operations[i].can_receive; /* If we can send the request, then we can receive the response. */ if (operation >= RESPONSE) return operation_can_send(operation - RESPONSE); return 0; } /***************************************************************************/ /* Packet encoding/decoding functions. They handle packets at the octet */ /* level, and know nothing of the network. */ /***************************************************************************/ struct packet { /* operation and seq are -1 if their value could not be parsed */ int operation; int seq; /* Sequence number */ Octstr *data; /* Encoded packet */ /* CIMD 2 packet structure is so simple that packet information is * stored as a valid encoded packet, and decoded as necessary. * Exceptions: operation code and sequence number are also stored * as ints for speed, and the checksum is not added until the packet * is about to be sent. Since checksums are optional, the packet * is still valid without a checksum. * * The sequence number is kept at 0 until it's time to actually * send the packet, so that the send functions have control over * the sequence numbers. */ }; /* These are the separators defined by the CIMD 2 spec */ #define STX 2 /* Start of packet */ #define ETX 3 /* End of packet */ #define TAB 9 /* End of parameter */ /* The same separators, in string form */ #define STX_str "\02" #define ETX_str "\03" #define TAB_str "\011" /* A reminder that packets are created without a valid sequence number */ #define BOGUS_SEQUENCE 0 static Msg *cimd2_accept_delivery_report_message(struct packet *request, SMSCConn *conn); /* Look for the STX OO:SSS TAB header defined by CIMD 2, where OO is the * operation code in two decimals and SSS is the sequence number in three * decimals. Leave the results in the proper fields of the packet. * Try to make sense of headers that don't fit this pattern; validating * the packet format is not our job. */ static void packet_parse_header(struct packet *packet) { int pos; long number; /* Set default values, in case we can't parse the fields */ packet->operation = -1; packet->seq = -1; pos = octstr_parse_long(&number, packet->data, 1, 10); if (pos < 0) return; packet->operation = number; if (octstr_get_char(packet->data, pos++) != ':') return; pos = octstr_parse_long(&number, packet->data, pos, 10); if (pos < 0) return; packet->seq = number; } /* Accept an Octstr containing one packet, build a struct packet around * it, and return that struct. The Octstr is stored in the struct. * No error checking is done here yet. */ static struct packet *packet_parse(Octstr *packet_data) { struct packet *packet; packet = gw_malloc(sizeof(*packet)); packet->data = packet_data; /* Fill in packet->operation and packet->seq */ packet_parse_header(packet); return packet; } /* Deallocate this packet */ static void packet_destroy(struct packet *packet) { if (packet != NULL) { octstr_destroy(packet->data); gw_free(packet); } } /* Find the first packet in "in", delete it from "in", and return it as * a struct. Return NULL if "in" contains no packet. Always delete * leading non-packet data from "in". (The CIMD 2 spec says we should * ignore any data between the packet markers). */ static struct packet *packet_extract(Octstr *in, SMSCConn *conn) { int stx, etx; Octstr *packet; /* Find STX, and delete everything up to it */ stx = octstr_search_char(in, STX, 0); if (stx < 0) { octstr_delete(in, 0, octstr_len(in)); return NULL; } else { octstr_delete(in, 0, stx); } /* STX is now in position 0. Find ETX. */ etx = octstr_search_char(in, ETX, 1); if (etx < 0) return NULL; /* What shall we do with STX data... STX data... ETX? * Either skip to the second STX, or assume an ETX marker before * the STX. Doing the latter has a chance of succeeding, and * will at least allow good logging of the error. */ stx = octstr_search_char(in, STX, 1); if (stx >= 0 && stx < etx) { warning(0, "CIMD2[%s]: packet without end marker", octstr_get_cstr(conn->id)); packet = octstr_copy(in, 0, stx); octstr_delete(in, 0, stx); octstr_append_cstr(packet, ETX_str); } else { /* Normal case. Copy packet, and cut it from the source. */ packet = octstr_copy(in, 0, etx + 1); octstr_delete(in, 0, etx + 1); } return packet_parse(packet); } /* The get_parm functions always return the first parameter with the * correct id. There is only one case where the spec allows multiple * parameters with the same id, and that is when an SMS has multiple * destination addresses. We only support one destination address anyway. */ /* Look for the first parameter with id 'parmno' and return its value. * Return NULL if the parameter was not found. */ static Octstr *packet_get_parm(struct packet *packet, int parmno) { long pos, next; long valuepos; long number; gw_assert(packet != NULL); pos = octstr_search_char(packet->data, TAB, 0); if (pos < 0) return NULL; /* Bad packet, nothing we can do */ /* Parameters have a tab on each end. If we don't find the * closing tab, we're at the checksum, so we stop. */ for ( ; (next = octstr_search_char(packet->data, TAB, pos + 1)) >= 0; pos = next) { if (octstr_parse_long(&number, packet->data, pos + 1, 10) < 0) continue; if (number != parmno) continue; valuepos = octstr_search_char(packet->data, ':', pos + 1); if (valuepos < 0) continue; /* badly formatted parm */ valuepos++; /* skip the ':' */ /* Found the right parameter */ return octstr_copy(packet->data, valuepos, next - valuepos); } return NULL; } /* Look for an Integer parameter with id 'parmno' in the packet and * return its value. Return INT_MIN if the parameter was not found. * (Unfortunately, -1 is a valid parameter value for at least one * parameter.) */ static long packet_get_int_parm(struct packet *packet, int parmno) { Octstr *valuestr = NULL; long value; /* Our code should never even try a bad parameter access. */ gw_assert(parm_type(parmno) == P_INT); valuestr = packet_get_parm(packet, parmno); if (!valuestr) goto error; if (octstr_parse_long(&value, valuestr, 0, 10) < 0) goto error; octstr_destroy(valuestr); return value; error: octstr_destroy(valuestr); return INT_MIN; } /* Look for a String parameter with id 'parmno' in the packet and * return its value. Return NULL if the parameter was not found. * No translations are done on the value. */ static Octstr *packet_get_string_parm(struct packet *packet, int parmno) { /* Our code should never even try a bad parameter access. */ gw_assert(parm_type(parmno) == P_STRING); return packet_get_parm(packet, parmno); } /* Look for an Address parameter with id 'parmno' in the packet and * return its value. Return NULL if the parameter was not found. * No translations are done on the value. */ static Octstr *packet_get_address_parm(struct packet *packet, int parmno) { /* Our code should never even try a bad parameter access. */ gw_assert(parm_type(parmno) == P_ADDRESS); return packet_get_parm(packet, parmno); } /* Look for an SMS parameter with id 'parmno' in the packet and return its * value. Return NULL if the parameter was not found. No translations * are done on the value, so it will be in the ISO-Latin-1 character set * with CIMD2-specific escapes. */ static Octstr *packet_get_sms_parm(struct packet *packet, int parmno) { /* Our code should never even try a bad parameter access. */ gw_assert(parm_type(parmno) == P_SMS); return packet_get_parm(packet, parmno); } /* There is no packet_get_time_parm because the CIMD 2 timestamp * format is useless. It's in the local time of the MC, with * a 2-digit year and no DST information. We can do without. */ /* Look for a Hex parameter with id 'parmno' in the packet and return * its value. Return NULL if the parameter was not found. The value * is de-hexed. */ static Octstr *packet_get_hex_parm(struct packet *packet, int parmno) { Octstr *value = NULL; /* Our code should never even try a bad parameter access. */ gw_assert(parm_type(parmno) == P_HEX); value = packet_get_parm(packet, parmno); if (!value) goto error; if (octstr_hex_to_binary(value) < 0) goto error; return value; error: octstr_destroy(value); return NULL; } /* Check if the header is according to CIMD 2 spec, generating log * entries as necessary. Return -1 if anything was wrong, otherwise 0. */ static int packet_check_header(struct packet *packet, SMSCConn *conn) { Octstr *data; gw_assert(packet != NULL); data = packet->data; /* The header must have a two-digit operation code, a colon, * and a three-digit sequence number, followed by a tab. * (CIMD2, 3.1) */ if (octstr_len(data) < 8 || !octstr_check_range(data, 1, 2, gw_isdigit) || octstr_get_char(data, 3) != ':' || !octstr_check_range(data, 4, 3, gw_isdigit) || octstr_get_char(data, 7) != TAB) { warning(0, "CIMD2[%s]: packet header in wrong format", octstr_get_cstr(conn->id)); return -1; } return 0; } static int packet_check_parameter(struct packet *packet, long pos, long len, SMSCConn *conn) { Octstr *data; long parm; long dpos, dlen; int negative; long value; int i; int errors = 0; gw_assert(packet != NULL); data = packet->data; /* The parameter header should be TAB, followed by a three-digit * parameter number, a colon, and the data. We already know about * the tab. */ if (len < 5 || !octstr_check_range(data, pos + 1, 3, gw_isdigit) || octstr_get_char(data, pos + 4) != ':') { warning(0, "CIMD2[%s]: parameter at offset %ld in wrong format", octstr_get_cstr(conn->id), pos); errors++; } /* If we can't parse a parameter number, there's nothing more * that we can check. */ dpos = octstr_parse_long(&parm, data, pos + 1, 10); if (dpos < 0) return -1; if (octstr_get_char(data, dpos) == ':') dpos++; dlen = len - (dpos - pos); /* dlen can not go negative because octstr_parse_long must have * been stopped by the TAB at the end of the parameter data. */ gw_assert(dlen >= 0); i = parm_index(parm); if (i < 0) { warning(0, "CIMD2[%s]: packet contains unknown parameter %ld", octstr_get_cstr(conn->id), parm); return -1; } if (dlen > parameters[i].maxlen) { warning(0, "CIMD2[%s]: packet has '%s' parameter with length %ld, spec says max %d", octstr_get_cstr(conn->id), parameters[i].name, len, parameters[i].maxlen); errors++; } switch (parameters[i].type) { case P_INT: /* Allow a leading - */ negative = (octstr_get_char(data, dpos) == '-'); if (!octstr_check_range(data, dpos + negative, dlen - negative, gw_isdigit)) { warning(0, "CIMD2[%s]: packet has '%s' parameter with non-integer contents", octstr_get_cstr(conn->id), parameters[i].name); errors++; } if (octstr_parse_long(&value, data, dpos, 10) >= 0 && (value < parameters[i].minval || value > parameters[i].maxval)) { warning(0, "CIMD2[%s]: packet has '%s' parameter out of range (value %ld, min %d, max %d)", octstr_get_cstr(conn->id), parameters[i].name, value, parameters[i].minval, parameters[i].maxval); errors++; } break; case P_TIME: if (!octstr_check_range(data, dpos, dlen, gw_isdigit)) { warning(0, "CIMD2[%s]: packet has '%s' parameter with non-digit contents", octstr_get_cstr(conn->id), parameters[i].name); errors++; } break; case P_ADDRESS: if (!octstr_check_range(data, dpos, dlen, isphonedigit)) { warning(0, "CIMD2[%s]: packet has '%s' parameter with non phone number contents", octstr_get_cstr(conn->id), parameters[i].name); errors++; } break; case P_HEX: if (!octstr_check_range(data, dpos, dlen, gw_isxdigit)) { warning(0, "CIMD2[%s]: packet has '%s' parameter with non-hex contents", octstr_get_cstr(conn->id), parameters[i].name); errors++; } if (dlen % 2 != 0) { warning(0, "CIMD2[%s]: packet has odd-length '%s' parameter", octstr_get_cstr(conn->id), parameters[i].name); errors++; } break; case P_SMS: case P_STRING: /* nothing to check */ break; } if (errors > 0) return -1; return 0; } /* Check the packet against the CIMD 2 spec, generating log entries as * necessary. Return -1 if anything was wrong, otherwise 0. */ /* TODO: Check if parameters found actually belong in the packet type */ static int packet_check(struct packet *packet, SMSCConn *conn) { int errors = 0; long pos, next; Octstr *data; gw_assert(packet != NULL); data = packet->data; if (octstr_search_char(data, 0, 0) >= 0) { /* CIMD2 spec does not allow NUL bytes in a packet */ warning(0, "CIMD2[%s]: packet contains NULs", octstr_get_cstr(conn->id)); errors++; } /* Assume the packet starts with STX and ends with ETX, * because we parsed it that way in the first place. */ errors += (packet_check_header(packet,conn) < 0); /* Parameters are separated by tabs. After the last parameter * there is a tab, an optional two-digit checksum, and the ETX. * Check each parameter in turn, by skipping from tab to tab. */ /* Start at the first tab, wherever it is, so that we can still * check parameters if the header was weird. */ pos = octstr_search_char(data, TAB, 0); for ( ; pos >= 0; pos = next) { next = octstr_search_char(data, TAB, pos + 1); if (next >= 0) { errors += (packet_check_parameter(packet, pos, next - pos, conn) < 0); } else { /* Check if the checksum has the right format. Don't * check the sum itself here, that will be done in a * separate call later. */ /* There are two valid formats: TAB ETX (no checksum) * and TAB digit digit ETX. We already know the TAB * and the ETX are there. */ if (!(octstr_len(data) - pos == 2 || (octstr_len(data) - pos == 4 && octstr_check_range(data, pos + 1, 2, gw_isxdigit)))) { warning(0, "CIMD2[%s]: packet checksum in wrong format", octstr_get_cstr(conn->id)); errors++; } } } if (errors > 0) { octstr_dump(packet->data, 0); return -1; } return 0; } static void packet_check_can_receive(struct packet *packet, SMSCConn *conn) { gw_assert(packet != NULL); if (!operation_can_receive(packet->operation)) { Octstr *name = operation_name(packet->operation); warning(0, "CIMD2[%s]: SMSC sent us %s request", octstr_get_cstr(conn->id), octstr_get_cstr(name)); octstr_destroy(name); } } /* Table of known error codes */ static struct { int code; char *text; } cimd2_errors[] = { { 0, "No error" }, { 1, "Unexpected operation" }, { 2, "Syntax error" }, { 3, "Unsupported parameter error" }, { 4, "Connection to message center lost" }, { 5, "No response from message center" }, { 6, "General system error" }, { 7, "Cannot find information" }, { 8, "Parameter formatting error" }, { 9, "Requested operation failed" }, /* LOGIN error codes */ { 100, "Invalid login" }, { 101, "Incorrect access type" }, { 102, "Too many users with this login id" }, { 103, "Login refused by message center" }, /* SUBMIT MESSAGE error codes */ { 300, "Incorrect destination address" }, { 301, "Incorrect number of destination addresses" }, { 302, "Syntax error in user data parameter" }, { 303, "Incorrect bin/head/normal user data parameter combination" }, { 304, "Incorrect data coding scheme parameter usage" }, { 305, "Incorrect validity period parameters usage" }, { 306, "Incorrect originator address usage" }, { 307, "Incorrect pid paramterer usage" }, { 308, "Incorrect first delivery parameter usage" }, { 309, "Incorrect reply path usage" }, { 310, "Incorrect status report request parameter usage" }, { 311, "Incorrect cancel enabled parameter usage" }, { 312, "Incorrect priority parameter usage" }, { 313, "Incorrect tariff class parameter usage" }, { 314, "Incorrect service description parameter usage" }, { 315, "Incorrect transport type parameter usage" }, { 316, "Incorrect message type parameter usage" }, { 318, "Incorrect mms parameter usage" }, { 319, "Incorrect operation timer parameter usage" }, /* ENQUIRE MESSAGE STATUS error codes */ { 400, "Incorrect address parameter usage" }, { 401, "Incorrect scts parameter usage" }, /* DELIVERY REQUEST error codes */ { 500, "Incorrect scts parameter usage" }, { 501, "Incorrect mode parameter usage" }, { 502, "Incorrect parameter combination" }, /* CANCEL MESSAGE error codes */ { 600, "Incorrect scts parameter usage" }, { 601, "Incorrect address parameter usage" }, { 602, "Incorrect mode parameter usage" }, { 603, "Incorrect parameter combination" }, /* SET error codes */ { 800, "Changing password failed" }, { 801, "Changing password not allowed" }, /* GET error codes */ { 900, "Unsupported item requested" }, { -1, NULL } }; static int packet_display_error(struct packet *packet, SMSCConn *conn) { int code; Octstr *text = NULL; Octstr *opname = NULL; code = packet_get_int_parm(packet, P_ERROR_CODE); text = packet_get_string_parm(packet, P_ERROR_TEXT); if (code <= 0) { octstr_destroy(text); return 0; } if (text == NULL) { /* No error text. Try to find it in the table. */ int i; for (i = 0; cimd2_errors[i].text != NULL; i++) { if (cimd2_errors[i].code == code) { text = octstr_create(cimd2_errors[i].text); break; } } } if (text == NULL) { /* Still no error text. Make one up. */ text = octstr_create("Unknown error"); } opname = operation_name(packet->operation); error(0, "CIMD2[%s]: %s contained error message:", octstr_get_cstr(conn->id), octstr_get_cstr(opname)); error(0, "code %03d: %s", code, octstr_get_cstr(text)); octstr_destroy(opname); octstr_destroy(text); return code; } /* Table of special combinations, for convert_gsm_to_latin1. */ /* Each cimd1, cimd2 pair is mapped to a character in the GSM default * character set. */ static const struct { unsigned char cimd1, cimd2; unsigned char gsm; } cimd_combinations[] = { { 'O', 'a', 0 }, /* @ */ { 'L', '-', 1 }, /* Pounds sterling */ { 'Y', '-', 3 }, /* Yen */ { 'e', '`', 4 }, /* egrave */ { 'e', '\'', 5 }, /* eacute */ { 'u', '`', 6 }, /* ugrave */ { 'i', '`', 7 }, /* igrave */ { 'o', '`', 8 }, /* ograve */ { 'C', ',', 9 }, /* C cedilla */ { 'O', '/', 11 }, /* Oslash */ { 'o', '/', 12 }, /* oslash */ { 'A', '*', 14 }, /* Aring */ { 'a', '*', 15 }, /* aring */ { 'g', 'd', 16 }, /* greek delta */ { '-', '-', 17 }, /* underscore */ { 'g', 'f', 18 }, /* greek phi */ { 'g', 'g', 19 }, /* greek gamma */ { 'g', 'l', 20 }, /* greek lambda */ { 'g', 'o', 21 }, /* greek omega */ { 'g', 'p', 22 }, /* greek pi */ { 'g', 'i', 23 }, /* greek psi */ { 'g', 's', 24 }, /* greek sigma */ { 'g', 't', 25 }, /* greek theta */ { 'g', 'x', 26 }, /* greek xi */ { 'X', 'X', 27 }, /* escape */ { 'A', 'E', 28 }, /* AE ligature */ { 'a', 'e', 29 }, /* ae ligature */ { 's', 's', 30 }, /* german double s */ { 'E', '\'', 31 }, /* Eacute */ { 'q', 'q', '"' }, { 'o', 'x', 36 }, /* international currency symbol */ { '!', '!', 64 }, /* inverted ! */ { 'A', '"', 91 }, /* Adieresis */ { 'O', '"', 92 }, /* Odieresis */ { 'N', '~', 93 }, /* N tilde */ { 'U', '"', 94 }, /* Udieresis */ { 's', 'o', 95 }, /* section mark */ { '?', '?', 96 }, /* inverted ? */ { 'a', '"', 123 }, /* adieresis */ { 'o', '"', 124 }, /* odieresis */ { 'n', '~', 125 }, /* n tilde */ { 'u', '"', 126 }, /* udieresis */ { 'a', '`', 127 }, /* agrave */ { 0, 0, 0 } }; /* Convert text in the CIMD2 User Data format to the GSM default * character set. * CIMD2 allows 8-bit characters in this format; they map directly * to the corresponding ISO-8859-1 characters. Since we are heading * toward that character set in the end, we don't bother converting * those to GSM. */ static void convert_cimd2_to_gsm(Octstr *text, SMSCConn *conn) { long pos, len; int cimd1, cimd2; int c; int i; /* CIMD2 uses four single-character mappings that do not map * to themselves: * '@' from 64 to 0, '$' from 36 to 2, ']' from 93 to 14 (A-ring), * and '}' from 125 to 15 (a-ring). * Other than those, we only have to worry about the escape * sequences introduced by _ (underscore). */ len = octstr_len(text); for (pos = 0; pos < len; pos++) { c = octstr_get_char(text, pos); if (c == '@') octstr_set_char(text, pos, 0); else if (c == '$') octstr_set_char(text, pos, 2); else if (c == ']') octstr_set_char(text, pos, 14); else if (c == '}') octstr_set_char(text, pos, 15); else if (c == '_' && pos + 2 < len) { cimd1 = octstr_get_char(text, pos + 1); cimd2 = octstr_get_char(text, pos + 2); for (i = 0; cimd_combinations[i].cimd1 != 0; i++) { if (cimd_combinations[i].cimd1 == cimd1 && cimd_combinations[i].cimd2 == cimd2) break; } if (cimd_combinations[i].cimd1 == 0) warning(0, "CIMD2[%s]: Encountered unknown " "escape code _%c%c, ignoring.", octstr_get_cstr(conn->id), cimd1, cimd2); else { octstr_delete(text, pos, 2); octstr_set_char(text, pos, cimd_combinations[i].gsm); len = octstr_len(text); } } } } /* Convert text in the GSM default character set to the CIMD2 User Data * format, which is a representation of the GSM default character set * in the lower 7 bits of ISO-8859-1. (8-bit characters are also * allowed, but it's just as easy not to use them.) */ static void convert_gsm_to_cimd2(Octstr *text) { long pos, len; len = octstr_len(text); for (pos = 0; pos < len; pos++) { int c, i; c = octstr_get_char(text, pos); /* If c is not in the GSM alphabet at this point, * the caller did something badly wrong. */ gw_assert(c >= 0); gw_assert(c < 128); for (i = 0; cimd_combinations[i].cimd1 != 0; i++) { if (cimd_combinations[i].gsm == c) break; } if (cimd_combinations[i].gsm == c) { /* Escape sequence */ octstr_insert_data(text, pos, "_ ", 2); pos += 2; len += 2; octstr_set_char(text, pos - 1, cimd_combinations[i].cimd1); octstr_set_char(text, pos, cimd_combinations[i].cimd2); } else if (c == 2) { /* The dollar sign is the only GSM character that * does not have a CIMD escape sequence and does not * map to itself. */ octstr_set_char(text, pos, '$'); } } } /***************************************************************************/ /* Packet encoding functions. They do not allow the creation of invalid */ /* CIMD 2 packets. */ /***************************************************************************/ /* Build a new packet struct with this operation code and sequence number. */ static struct packet *packet_create(int operation, int seq) { struct packet *packet; char minpacket[sizeof("sOO:SSSte")]; packet = gw_malloc(sizeof(*packet)); packet->operation = operation; packet->seq = seq; sprintf(minpacket, STX_str "%02d:%03d" TAB_str ETX_str, operation, seq); packet->data = octstr_create(minpacket); return packet; } /* Add a parameter to the end of packet */ static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn) { char parmh[sizeof("tPPP:")]; long position; long len; int copied = 0; len = octstr_len(value); gw_assert(packet != NULL); gw_assert(parm_type(parmno) == parmtype); if (len > parm_maxlen(parmno)) { warning(0, "CIMD2[%s]: %s parameter too long, truncating from " "%ld to %ld characters", octstr_get_cstr(conn->id), parm_name(parmno), len, (long) parm_maxlen(parmno)); value = octstr_copy(value, 0, parm_maxlen(parmno)); copied = 1; } /* There's a TAB and ETX at the end; insert it before those. * The new parameter will come with a new starting TAB. */ position = octstr_len(packet->data) - 2; sprintf(parmh, TAB_str "%03d:", parmno); octstr_insert_data(packet->data, position, parmh, strlen(parmh)); octstr_insert(packet->data, value, position + strlen(parmh)); if (copied) octstr_destroy(value); } /* Add a String parameter to the packet */ static void packet_add_string_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn) { packet_add_parm(packet, P_STRING, parmno, value, conn); } /* Add an Address parameter to the packet */ static void packet_add_address_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn) { gw_assert(octstr_check_range(value, 0, octstr_len(value), isphonedigit)); packet_add_parm(packet, P_ADDRESS, parmno, value, conn); } /* Add an SMS parameter to the packet. The caller is expected to have done * the translation to the GSM character set already. */ static void packet_add_sms_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn) { packet_add_parm(packet, P_SMS, parmno, value, conn); } /* There is no function for adding a Time parameter to the packet, because * the format makes Time parameters useless for us. If you find that you * need to use them, then also add code for querying the SMS center timestamp * and using that for synchronization. And beware of DST changes. */ /* Add a Hexadecimal parameter to the packet */ static void packet_add_hex_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn) { value = octstr_duplicate(value); octstr_binary_to_hex(value, 1); /* 1 for uppercase hex, i.e. A .. F */ packet_add_parm(packet, P_HEX, parmno, value, conn); octstr_destroy(value); } /* Add an Integer parameter to the packet */ static void packet_add_int_parm(struct packet *packet, int parmno, long value, SMSCConn *conn) { char buf[128]; Octstr *valuestr; gw_assert(parm_in_range(parmno, value)); sprintf(buf, "%ld", value); valuestr = octstr_create(buf); packet_add_parm(packet, P_INT, parmno, valuestr, conn); octstr_destroy(valuestr); } static void packet_set_checksum(struct packet *packet) { Octstr *data; int checksum; long pos, len; char buf[16]; gw_assert(packet != NULL); data = packet->data; if (octstr_get_char(data, octstr_len(data) - 2) != TAB) { /* Packet already has checksum; kill it. */ octstr_delete(data, octstr_len(data) - 3, 2); } gw_assert(octstr_get_char(data, octstr_len(data) - 2) == TAB); /* Sum all the way up to the last TAB */ checksum = 0; for (pos = 0, len = octstr_len(data); pos < len - 1; pos++) { checksum += octstr_get_char(data, pos); checksum &= 0xff; } sprintf(buf, "%02X", checksum); octstr_insert_data(data, len - 1, buf, 2); } static void packet_set_sequence(struct packet *packet, int seq) { char buf[16]; gw_assert(packet != NULL); gw_assert(seq >= 0); gw_assert(seq < 256); sprintf(buf, "%03d", seq); /* Start at 4 to skip the ZZ: part of the header. */ octstr_set_char(packet->data, 4, buf[0]); octstr_set_char(packet->data, 5, buf[1]); octstr_set_char(packet->data, 6, buf[2]); packet->seq = seq; } static struct packet *packet_encode_message(Msg *msg, Octstr *sender_prefix, SMSCConn *conn) { struct packet *packet; PrivData *pdata = conn->data; Octstr *text; int spaceleft; long truncated; int dcs = 0; int setvalidity = 0; gw_assert(msg != NULL); gw_assert(msg->type == sms); gw_assert(msg->sms.receiver != NULL); dcs = fields_to_dcs(msg, (msg->sms.alt_dcs != -1 ? msg->sms.alt_dcs : conn->alt_dcs)); if (msg->sms.sender == NULL) msg->sms.sender = octstr_create(""); if (!parm_valid_address(msg->sms.receiver)) { warning(0, "CIMD2[%s]: non-digits in destination phone number '%s', discarded", octstr_get_cstr(conn->id), octstr_get_cstr(msg->sms.receiver)); return NULL; } packet = packet_create(SUBMIT_MESSAGE, BOGUS_SEQUENCE); packet_add_address_parm(packet, P_DESTINATION_ADDRESS, msg->sms.receiver, conn); /* CIMD2 interprets the originating address as a sub-address to * our connection number (so if the connection is "400" and we * fill in "600" as the sender number, the user sees "400600"). * Since we have no way to ask what this number is, it has to * be configured. */ /* Quick and dirty check to see if we are using alphanumeric sender */ if (parm_valid_address(msg->sms.sender)) { /* We are not, so send in the usual way */ /* Speed up the default case */ if (octstr_len(sender_prefix) == 0) { packet_add_address_parm(packet, P_ORIGINATING_ADDRESS,msg->sms.sender, conn); } else if (octstr_compare(sender_prefix, octstr_imm("never")) != 0) { if (octstr_ncompare(sender_prefix, msg->sms.sender, octstr_len(sender_prefix)) == 0) { Octstr *sender; sender = octstr_copy(msg->sms.sender, octstr_len(sender_prefix), octstr_len(msg->sms.sender)); packet_add_address_parm(packet, P_ORIGINATING_ADDRESS, sender, conn); octstr_destroy(sender); } else { warning(0, "CIMD2[%s]: Sending message with originating address <%s>, " "which does not start with the sender-prefix.", octstr_get_cstr(conn->id), octstr_get_cstr(msg->sms.sender)); } } } else { /* The test above to check if sender was all digits failed, so assume we want alphanumeric sender */ packet_add_string_parm(packet, P_ALPHANUMERIC_ORIGINATING_ADDRESS,msg->sms.sender, conn); } /* Add the validity period if necessary. This sets the relative validity * period as this is the description of the "validity" parameter of the * sendsms interface. * * Convert from minutes to GSM 03.40 specification (section 9.2.3.12). * 0-143 = 0 to 12 hours in 5 minute increments. * 144-167 = 12hrs30min to 24hrs in 30 minute increments. * 168-196 = 2days to 30days in 1 day increments. * 197-255 = 5weeks to 63weeks in 1 week increments. * * This code was copied from smsc_at2.c. */ if (msg->sms.validity != MSG_PARAM_UNDEFINED) { long val = (msg->sms.validity - time(NULL)) / 60; if (val > 635040) setvalidity = 255; if (val >= 50400 && val <= 635040) setvalidity = (val - 1) / 7 / 24 / 60 + 192 + 1; if (val > 43200 && val < 50400) setvalidity = 197; if (val >= 2880 && val <= 43200) setvalidity = (val - 1) / 24 / 60 + 166 + 1; if (val > 1440 && val < 2880) setvalidity = 168; if (val >= 750 && val <= 1440) setvalidity = (val - 720 - 1) / 30 + 143 + 1; if (val > 720 && val < 750) setvalidity = 144; if (val >= 5 && val <= 720) setvalidity = (val - 1) / 5 - 1 + 1; if (val < 5) setvalidity = 0; packet_add_int_parm(packet, P_VALIDITY_PERIOD_RELATIVE, setvalidity, conn); } /* Explicitly ask not to get status reports. * If we do not do this, the server's default might be to * send status reports in some cases, and we don't do anything * with those reports anyway. */ /* ask for the delivery reports if needed*/ if (!pdata->no_dlr) if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask)) packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 14, conn); else packet_add_int_parm(packet, P_STATUS_REPORT_REQUEST, 0, conn); else if( pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask)) warning(0, "CIMD2[%s]: dlr request make no sense while no-dlr set to true", octstr_get_cstr(conn->id)); /* Turn off reply path as default. * This avoids phones automatically asking for a reply */ if (msg->sms.rpi > 0) packet_add_int_parm(packet, P_REPLY_PATH, 1, conn); else packet_add_int_parm(packet, P_REPLY_PATH, 0, conn); /* Use binfo to set the tariff class */ if (octstr_len(msg->sms.binfo)) packet_add_parm(packet, P_INT, P_TARIFF_CLASS, msg->sms.binfo, conn); /* Set the protocol identifier if requested */ if (msg->sms.pid > 0) packet_add_int_parm(packet, P_PROTOCOL_IDENTIFIER, msg->sms.pid, conn); /* If there are more messages to the same destination, then set the * More Messages to Send flag. This allow faster delivery of many messages * to the same destination */ if (msg->sms.msg_left > 0) packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 1, conn); else packet_add_int_parm(packet, P_MORE_MESSAGES_TO_SEND, 0, conn); truncated = 0; spaceleft = 140; if (octstr_len(msg->sms.udhdata)) { /* udhdata will be truncated and warned about if * it does not fit. */ packet_add_hex_parm(packet, P_USER_DATA_HEADER, msg->sms.udhdata, conn); } if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) spaceleft = spaceleft * 8 / 7; if (spaceleft < 0) spaceleft = 0; text = octstr_duplicate(msg->sms.msgdata); if (octstr_len(text) > 0 && spaceleft == 0) { warning(0, "CIMD2[%s]: message filled up with UDH, no room for message text", octstr_get_cstr(conn->id)); } else if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) { if (octstr_len(text) > spaceleft) { truncated = octstr_len(text) - spaceleft; octstr_truncate(text, spaceleft); } packet_add_hex_parm(packet, P_USER_DATA_BINARY, text, conn); } else { /* Going from latin1 to GSM to CIMD2 may seem like a * detour, but it's the only way to get all the escape * codes right. */ charset_utf8_to_gsm(text); truncated = charset_gsm_truncate(text, spaceleft); convert_gsm_to_cimd2(text); packet_add_sms_parm(packet, P_USER_DATA, text, conn); } if (dcs != 0) packet_add_int_parm(packet, P_DATA_CODING_SCHEME, dcs, conn); if (truncated > 0) { warning(0, "CIMD2[%s]: truncating message text to fit in %d characters.", octstr_get_cstr(conn->id), spaceleft); } octstr_destroy(text); return packet; } /***************************************************************************/ /* Protocol functions. These implement various transactions. */ /***************************************************************************/ /* Give this packet a proper sequence number for sending. */ static void packet_set_send_sequence(struct packet *packet, PrivData *pdata) { gw_assert(pdata != NULL); /* LOGIN packets always have sequence number 001 */ if (packet->operation == LOGIN) pdata->send_seq = 1; /* Send sequence numbers are always odd, receiving are always even */ gw_assert(pdata->send_seq % 2 == 1); packet_set_sequence(packet, pdata->send_seq); pdata->send_seq += 2; if (pdata->send_seq > 256) pdata->send_seq = 1; } static struct packet *cimd2_get_packet(PrivData *pdata, Octstr **ts) { struct packet *packet = NULL; gw_assert(pdata != NULL); /* If packet is already available, don't try to read anything */ packet = packet_extract(pdata->inbuffer, pdata->conn); while (packet == NULL) { if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) { warning(0, "CIMD2[%s]: SMSC is not responding", octstr_get_cstr(pdata->conn->id)); return NULL; } if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) { error(0, "CIMD2[%s]: cimd2_get_packet: read failed", octstr_get_cstr(pdata->conn->id)); return NULL; } packet = packet_extract(pdata->inbuffer, pdata->conn); } packet_check(packet,pdata->conn); packet_check_can_receive(packet,pdata->conn); debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>", octstr_get_cstr(pdata->conn->id), octstr_get_cstr(packet->data)); if (ts) *ts = packet_get_parm(packet,P_MC_TIMESTAMP); if (pdata->keepalive > 0) pdata->next_ping = time(NULL) + pdata->keepalive; return packet; } /* Acknowledge a request. The CIMD 2 spec only defines positive responses * to the server, because the server is perfect. */ static void cimd2_send_response(struct packet *request, PrivData *pdata) { struct packet *response; gw_assert(request != NULL); gw_assert(request->operation < RESPONSE); response = packet_create(request->operation + RESPONSE, request->seq); packet_set_checksum(response); debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>", octstr_get_cstr(pdata->conn->id), octstr_get_cstr(response->data)); /* Don't check errors here because if there is something * wrong with the socket, the main loop will detect it. */ octstr_write_to_socket(pdata->socket, response->data); packet_destroy(response); } static Msg *cimd2_accept_message(struct packet *request, SMSCConn *conn) { Msg *message = NULL; Octstr *destination = NULL; Octstr *origin = NULL; Octstr *UDH = NULL; Octstr *text = NULL; int DCS; /* See GSM 03.38. The bit patterns we can handle are: * 000xyyxx Uncompressed text, yy indicates alphabet. * yy = 00, default alphabet * yy = 01, 8-bit data * yy = 10, UCS-2 * yy = 11, reserved * 1111xyxx Data, y indicates alphabet. * y = 0, default alphabet * y = 1, 8-bit data */ DCS = packet_get_int_parm(request, P_DATA_CODING_SCHEME); destination = packet_get_address_parm(request, P_DESTINATION_ADDRESS); origin = packet_get_address_parm(request, P_ORIGINATING_ADDRESS); UDH = packet_get_hex_parm(request, P_USER_DATA_HEADER); /* Text is either in User Data or User Data Binary field. */ text = packet_get_sms_parm(request, P_USER_DATA); if (text != NULL) { convert_cimd2_to_gsm(text,conn); charset_gsm_to_utf8(text); } else { /* * FIXME: If DCS indicates GSM charset, and we get it in binary, * then it's probably bit-packed. We'll have to undo it because * our "charset_gsm" means one gsm character per octet. This is * not currently supported. -- RB */ text = packet_get_hex_parm(request, P_USER_DATA_BINARY); } /* Code elsewhere in the gateway always expects the sender and * receiver fields to be filled, so we discard messages that * lack them. If they should not be discarded, then the code * handling sms messages should be reviewed. -- RB */ if (!destination || octstr_len(destination) == 0) { info(0, "CIMD2[%s]: Got SMS without receiver, discarding.", octstr_get_cstr(conn->id)); goto error; } if (!origin || octstr_len(origin) == 0) { info(0, "CIMD2[%s]: Got SMS without sender, discarding.", octstr_get_cstr(conn->id)); goto error; } if (!text && (!UDH || octstr_len(UDH) == 0)) { info(0, "CIMD2[%s]: Got empty SMS, ignoring.", octstr_get_cstr(conn->id)); goto error; } message = msg_create(sms); if (! dcs_to_fields(&message, DCS)) { /* XXX Should reject this message ? */ debug("bb.sms.cimd2", 0, "CIMD2[%s]: Invalid DCS", octstr_get_cstr(conn->id)); dcs_to_fields(&message, 0); } time(&message->sms.time); message->sms.sender = origin; message->sms.receiver = destination; if (UDH) { message->sms.udhdata = UDH; } message->sms.msgdata = text; return message; error: msg_destroy(message); octstr_destroy(destination); octstr_destroy(origin); octstr_destroy(UDH); octstr_destroy(text); return NULL; } /* Deal with a request from the CIMD2 server, and acknowledge it. */ static void cimd2_handle_request(struct packet *request, SMSCConn *conn) { PrivData *pdata = conn->data; Msg *message = NULL; if ((request->seq == 254 && pdata->receive_seq == 0) || request->seq == pdata->receive_seq - 2) { warning(0, "CIMD2[%s]: request had same sequence number as previous.", octstr_get_cstr(conn->id)); } else { pdata->receive_seq = request->seq + 2; if (pdata->receive_seq > 254) pdata->receive_seq = 0; if (request->operation == DELIVER_STATUS_REPORT) { message = cimd2_accept_delivery_report_message(request, conn); if (message) gwlist_append(pdata->received, message); } else if (request->operation == DELIVER_MESSAGE) { message = cimd2_accept_message(request,conn); if (message) gwlist_append(pdata->received, message); } } cimd2_send_response(request, pdata); } /* Send a request and wait for the ack. If the other side responds with * an error code, attempt to correct and retry. * If other packets arrive while we wait for the ack, handle them. * * Return -1 if the SMSC refused the request. Return -2 for other * errors, such as being unable to send the request at all. If the * function returns -2, the caller would do well to try to reopen the * connection. * * The SMSCenter must be already open. * * TODO: This function has grown large and complex. Break it up * into smaller pieces. */ static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts) { PrivData *pdata = conn->data; int ret; struct packet *reply = NULL; int errorcode; int tries = 0; gw_assert(pdata != NULL); gw_assert(request != NULL); gw_assert(operation_can_send(request->operation)); if (pdata->socket < 0) { warning(0, "CIMD2[%s]: cimd2_request: socket not open.", octstr_get_cstr(conn->id)); return -2; } retransmit: packet_set_send_sequence(request, pdata); packet_set_checksum(request); debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(request->data)); ret = octstr_write_to_socket(pdata->socket, request->data); if (ret < 0) goto io_error; next_reply: packet_destroy(reply); /* destroy old, if any */ reply = cimd2_get_packet(pdata, ts); if (!reply) goto io_error; errorcode = packet_display_error(reply,conn); if (reply->operation == NACK) { warning(0, "CIMD2[%s]: received NACK", octstr_get_cstr(conn->id)); octstr_dump(reply->data, 0); /* Correct sequence number if server says it was wrong, * but only if server's number is sane. */ if (reply->seq != request->seq && (reply->seq % 2) == 1) { warning(0, "CIMD2[%s]: correcting sequence number from %ld to %ld.", octstr_get_cstr(conn->id), (long) pdata->send_seq, (long) reply->seq); pdata->send_seq = reply->seq; } goto retry; } if (reply->operation == GENERAL_ERROR_RESPONSE) { error(0, "CIMD2[%s]: received general error response", octstr_get_cstr(conn->id)); goto io_error; } /* The server sent us a request. Handle it, then wait for * a new reply. */ if (reply->operation < RESPONSE) { cimd2_handle_request(reply, conn); goto next_reply; } if (reply->seq != request->seq) { /* We got a response to a different request number than * what we send. Strange. */ warning(0, "CIMD2[%s]: response had unexpected sequence number; ignoring.", octstr_get_cstr(conn->id)); goto next_reply; } if (reply->operation != request->operation + RESPONSE) { /* We got a response that didn't match our request */ Octstr *request_name = operation_name(request->operation); Octstr *reply_name = operation_name(reply->operation); warning(0, "CIMD2[%s]: %s request got a %s", octstr_get_cstr(conn->id), octstr_get_cstr(request_name), octstr_get_cstr(reply_name)); octstr_destroy(request_name); octstr_destroy(reply_name); octstr_dump(reply->data, 0); goto retry; } if (errorcode > 0) goto error; /* The reply passed all the checks... looks like the SMSC accepted * our request! */ packet_destroy(reply); return 0; io_error: packet_destroy(reply); return -2; error: packet_destroy(reply); return -1; retry: if (++tries < 3) { warning(0, "CIMD2[%s]: Retransmitting (take %d)", octstr_get_cstr(conn->id), tries); goto retransmit; } warning(0, "CIMD2[%s]: Giving up.", octstr_get_cstr(conn->id)); goto io_error; } /* Close the SMSC socket without fanfare. */ static void cimd2_close_socket(PrivData *pdata) { gw_assert(pdata != NULL); if (pdata->socket < 0) return; if (close(pdata->socket) < 0) warning(errno, "CIMD2[%s]: error closing socket", octstr_get_cstr(pdata->conn->id)); pdata->socket = -1; } /* Open a socket to the SMSC, send a login packet, and wait for ack. * This may block. Return 0 for success, or -1 for failure. */ /* Make sure the socket is closed before calling this function, otherwise * we will leak fd's. */ static int cimd2_login(SMSCConn *conn) { PrivData *pdata = conn->data; int ret; struct packet *packet = NULL; gw_assert(pdata != NULL); if (pdata->socket >= 0) { warning(0, "CIMD2[%s]: login: socket was already open; closing", octstr_get_cstr(conn->id)); cimd2_close_socket(pdata); } pdata->socket = tcpip_connect_to_server_with_port( octstr_get_cstr(pdata->host), pdata->port, pdata->our_port, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL)); if (pdata->socket != -1) { packet = packet_create(LOGIN, BOGUS_SEQUENCE); packet_add_string_parm(packet, P_USER_IDENTITY, pdata->username, conn); packet_add_string_parm(packet, P_PASSWORD, pdata->password, conn); ret = cimd2_request(packet, conn, NULL); if (ret >= 0) { packet_destroy(packet); info(0, "CIMD2[%s] logged in.", octstr_get_cstr(conn->id)); return 0; } } error(0, "CIMD2[%s] login failed.", octstr_get_cstr(conn->id)); cimd2_close_socket(pdata); packet_destroy(packet); return -1; } static void cimd2_logout(SMSCConn *conn) { struct packet *packet = NULL; int ret; packet = packet_create(LOGOUT, BOGUS_SEQUENCE); /* TODO: Don't wait very long for a response in this case. */ ret = cimd2_request(packet, conn, NULL); if (ret == 0) { info(0, "CIMD2[%s] logged out.", octstr_get_cstr(conn->id)); } packet_destroy(packet); } static int cimd2_send_alive(SMSCConn *conn) { struct packet *packet = NULL; int ret; packet = packet_create(ALIVE, BOGUS_SEQUENCE); ret = cimd2_request(packet, conn, NULL); packet_destroy(packet); if (ret < 0) warning(0, "CIMD2[%s]: SMSC not alive.", octstr_get_cstr(conn->id)); return ret; } static void cimd2_destroy(PrivData *pdata) { int discarded; if (pdata == NULL) return; octstr_destroy(pdata->host); octstr_destroy(pdata->username); octstr_destroy(pdata->password); octstr_destroy(pdata->inbuffer); octstr_destroy(pdata->my_number); discarded = gwlist_len(pdata->received); if (discarded > 0) warning(0, "CIMD2[%s]: discarded %d received messages", octstr_get_cstr(pdata->conn->id), discarded); gwlist_destroy(pdata->received, msg_destroy_item); gwlist_destroy(pdata->outgoing_queue, NULL); gwlist_destroy(pdata->stopped, NULL); gw_free(pdata); } static int cimd2_submit_msg(SMSCConn *conn, Msg *msg) { PrivData *pdata = conn->data; struct packet *packet; Octstr *ts = NULL; int ret; gw_assert(pdata != NULL); debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending message", octstr_get_cstr(conn->id)); packet = packet_encode_message(msg, pdata->my_number,conn); if (!packet) { /* This is a protocol error. Does this help? I doubt.. * But nevermind that. */ bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED")); return -1; } ret = cimd2_request(packet, conn, &ts); if ((ret == 0) && (ts) && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask) && !pdata->no_dlr) { dlr_add(conn->name, ts, msg, 1); } octstr_destroy(ts); packet_destroy(packet); if (ret == -1) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED")); } else if (ret == -2) { cimd2_close_socket(pdata); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(conn->flow_mutex); } else { bb_smscconn_sent(conn,msg, NULL); } return ret; } static int cimd2_receive_msg(SMSCConn *conn, Msg **msg) { PrivData *pdata = conn->data; long ret; struct packet *packet; gw_assert(pdata != NULL); if (gwlist_len(pdata->received) > 0) { *msg = gwlist_consume(pdata->received); return 1; } if (pdata->socket < 0) { /* XXX We have to assume that smsc_send_message is * currently trying to reopen, so we have to make * this thread wait. It should be done in a nicer * way. */ return 0; } ret = read_available(pdata->socket, 0); if (ret == 0) { if (pdata->keepalive > 0 && pdata->next_ping < time(NULL)) { if (cimd2_send_alive(conn) < 0) return -1; } return 0; } if (ret < 0) { warning(errno, "CIMD2[%s]: cimd2_receive_msg: read_available failed", octstr_get_cstr(conn->id)); return -1; } /* We have some data waiting... see if it is an sms delivery. */ ret = octstr_append_from_socket(pdata->inbuffer, pdata->socket); if (ret == 0) { warning(0, "CIMD2[%s]: cimd2_receive_msg: service center closed connection.", octstr_get_cstr(conn->id)); return -1; } if (ret < 0) { warning(0, "CIMD2[%s]: cimd2_receive_msg: read failed", octstr_get_cstr(conn->id)); return -1; } for (;;) { packet = packet_extract(pdata->inbuffer,conn); if (!packet) break; packet_check(packet,conn); packet_check_can_receive(packet,conn); debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>", octstr_get_cstr(pdata->conn->id), octstr_get_cstr(packet->data)); if (packet->operation < RESPONSE) cimd2_handle_request(packet, conn); else { error(0, "CIMD2[%s]: cimd2_receive_msg: unexpected response packet", octstr_get_cstr(conn->id)); octstr_dump(packet->data, 0); } packet_destroy(packet); } if (gwlist_len(pdata->received) > 0) { *msg = gwlist_consume(pdata->received); return 1; } return 0; } static Msg *cimd2_accept_delivery_report_message(struct packet *request, SMSCConn *conn) { Msg *msg = NULL; Octstr *destination = NULL; Octstr *timestamp = NULL; Octstr *statuscode = NULL; int st_code; int code; destination = packet_get_parm(request, P_DESTINATION_ADDRESS); timestamp = packet_get_parm(request, P_MC_TIMESTAMP); statuscode = packet_get_parm(request, P_STATUS_CODE); st_code = atoi(octstr_get_cstr(statuscode)); switch(st_code) { case 2: /* validity period expired */ code = DLR_EXPIRED; break; case 3: /* delivery failed */ case 6: /* last no response */ case 7: /* message cancelled */ case 8: /* message deleted */ case 9: /* message deleted by cancel */ code = DLR_FAIL; break; case 4: /* delivery successful */ code = DLR_SUCCESS; break; default: code = 0; } if(code) msg = dlr_find(conn->name, timestamp, destination, code, 1); else msg = NULL; /* recode the body into msgdata */ if (msg) { msg->sms.msgdata = packet_get_parm(request, P_USER_DATA); if (!msg->sms.msgdata) { msg->sms.msgdata = statuscode; statuscode = NULL; } } octstr_destroy(statuscode); octstr_destroy(destination); octstr_destroy(timestamp); return msg; } static Msg *sms_receive(SMSCConn *conn) { PrivData *pdata = conn->data; int ret; Msg *newmsg = NULL; ret = cimd2_receive_msg(conn, &newmsg); if (ret == 1) { /* if any smsc_id available, use it */ newmsg->sms.smsc_id = octstr_duplicate(conn->id); return newmsg; } else if (ret == 0) { /* no message, just retry... */ return NULL; } /* error. reconnect. */ msg_destroy(newmsg); mutex_lock(conn->flow_mutex); cimd2_close_socket(pdata); conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(conn->flow_mutex); return NULL; } static void io_thread (void *arg) { Msg *msg; SMSCConn *conn = arg; PrivData *pdata = conn->data; double sleep = 0.0001; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* remove messages from SMSC until we are killed */ while (!pdata->quitting) { gwlist_consume(pdata->stopped); /* block here if suspended/isolated */ /* check that connection is active */ if (conn->status != SMSCCONN_ACTIVE) { if (cimd2_login(conn) != 0) { error(0, "CIMD2[%s]: Couldn't connect to SMSC (retrying in %ld seconds).", octstr_get_cstr(conn->id), conn->reconnect_delay); gwthread_sleep(conn->reconnect_delay); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); continue; } mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); bb_smscconn_connected(conn); mutex_unlock(conn->flow_mutex); } /* receive messages */ do { msg = sms_receive(conn); if (msg) { sleep = 0; debug("bb.sms.cimd2", 0, "CIMD2[%s]: new message received", octstr_get_cstr(conn->id)); bb_smscconn_receive(conn, msg); } } while (msg); /* send messages */ do { msg = gwlist_extract_first(pdata->outgoing_queue); if (msg) { sleep = 0; if (cimd2_submit_msg(conn,msg) != 0) break; } } while (msg); if (sleep > 0) { /* note that this implementations means that we sleep even * when we fail connection.. but time is very short, anyway */ gwthread_sleep(sleep); /* gradually sleep longer and longer times until something starts to * happen - this of course reduces response time, but that's better than * extensive CPU usage when it is not used */ sleep *= 2; if (sleep >= 2.0) sleep = 1.999999; } else { sleep = 0.0001; } } } static int cimd2_add_msg_cb (SMSCConn *conn, Msg *sms) { PrivData *pdata = conn->data; Msg *copy; copy = msg_duplicate(sms); gwlist_produce(pdata->outgoing_queue, copy); gwthread_wakeup(pdata->io_thread); return 0; } static int cimd2_shutdown_cb (SMSCConn *conn, int finish_sending) { PrivData *pdata = conn->data; debug("bb.sms", 0, "Shutting down SMSCConn CIMD2 %s (%s)", octstr_get_cstr(conn->id), finish_sending ? "slow" : "instant"); /* Documentation claims this would have been done by smscconn.c, but isn't when this code is being written. */ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; pdata->quitting = 1; /* Separate from why_killed to avoid locking, as * why_killed may be changed from outside? */ if (finish_sending == 0) { Msg *msg; while ((msg = gwlist_extract_first(pdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } } cimd2_logout(conn); if (conn->is_stopped) { gwlist_remove_producer(pdata->stopped); conn->is_stopped = 0; } if (pdata->io_thread != -1) { gwthread_wakeup(pdata->io_thread); gwthread_join(pdata->io_thread); } cimd2_close_socket(pdata); cimd2_destroy(pdata); debug("bb.sms", 0, "SMSCConn CIMD2 %s shut down.", octstr_get_cstr(conn->id)); conn->status = SMSCCONN_DEAD; bb_smscconn_killed(); return 0; } static void cimd2_start_cb (SMSCConn *conn) { PrivData *pdata = conn->data; gwlist_remove_producer(pdata->stopped); /* in case there are messages in the buffer already */ gwthread_wakeup(pdata->io_thread); debug("bb.sms", 0, "SMSCConn CIMD2 %s, start called", octstr_get_cstr(conn->id)); } static void cimd2_stop_cb (SMSCConn *conn) { PrivData *pdata = conn->data; gwlist_add_producer(pdata->stopped); debug("bb.sms", 0, "SMSCConn CIMD2 %s, stop called", octstr_get_cstr(conn->id)); } static long cimd2_queued_cb (SMSCConn *conn) { PrivData *pdata = conn->data; conn->load = (pdata ? (conn->status != SMSCCONN_DEAD ? gwlist_len(pdata->outgoing_queue) : 0) : 0); return conn->load; } int smsc_cimd2_create(SMSCConn *conn, CfgGroup *grp) { PrivData *pdata; int ok; int maxlen; pdata = gw_malloc(sizeof(PrivData)); conn->data = pdata; pdata->conn = conn; pdata->no_dlr = 0; pdata->quitting = 0; pdata->socket = -1; pdata->received = gwlist_create(); pdata->inbuffer = octstr_create(""); pdata->send_seq = 1; pdata->receive_seq = 0; pdata->outgoing_queue = gwlist_create(); pdata->stopped = gwlist_create(); gwlist_add_producer(pdata->outgoing_queue); if (conn->is_stopped) gwlist_add_producer(pdata->stopped); pdata->host = cfg_get(grp, octstr_imm("host")); if (cfg_get_integer(&(pdata->port), grp, octstr_imm("port")) == -1) pdata->port = 0; if (cfg_get_integer(&(pdata->our_port), grp, octstr_imm("our-port")) == -1) pdata->our_port = 0; pdata->username = cfg_get(grp, octstr_imm("smsc-username")); pdata->password = cfg_get(grp, octstr_imm("smsc-password")); pdata->my_number = cfg_get(grp, octstr_imm("my-number")); if (cfg_get_integer(&(pdata->keepalive), grp,octstr_imm("keepalive")) == -1) pdata->keepalive = 0; cfg_get_bool(&pdata->no_dlr, grp, octstr_imm("no-dlr")); /* Check that config is OK */ ok = 1; if (pdata->host == NULL) { error(0,"CIMD2[%s]: Configuration file doesn't specify host", octstr_get_cstr(conn->id)); ok = 0; } if (pdata->port == 0) { error(0,"CIMD2[%s]: Configuration file doesn't specify port", octstr_get_cstr(conn->id)); ok = 0; } if (pdata->username == NULL) { error(0, "CIMD2[%s]: Configuration file doesn't specify username.", octstr_get_cstr(conn->id)); ok = 0; } if (pdata->password == NULL) { error(0, "CIMD2[%s]: Configuration file doesn't specify password.", octstr_get_cstr(conn->id)); ok = 0; } if (!ok) { cimd2_destroy(pdata); return -1; } conn->name = octstr_format("CIMD2:%s:%d:%s", octstr_get_cstr(pdata->host), pdata->port, octstr_get_cstr(pdata->username)); if (pdata->keepalive > 0) { debug("bb.sms.cimd2", 0, "CIMD2[%s]: Keepalive set to %ld seconds", octstr_get_cstr(conn->id), pdata->keepalive); pdata->next_ping = time(NULL) + pdata->keepalive; } maxlen = parm_maxlen(P_USER_IDENTITY); if (octstr_len(pdata->username) > maxlen) { octstr_truncate(pdata->username, maxlen); warning(0, "CIMD2[%s]: Truncating username to %d chars", octstr_get_cstr(conn->id), maxlen); } maxlen = parm_maxlen(P_PASSWORD); if (octstr_len(pdata->password) > maxlen) { octstr_truncate(pdata->password, maxlen); warning(0, "CIMD2[%s]: Truncating password to %d chars", octstr_get_cstr(conn->id), maxlen); } pdata->io_thread = gwthread_create(io_thread, conn); if (pdata->io_thread == -1) { error(0,"CIMD2[%s]: Couldn't start I/O thread.", octstr_get_cstr(conn->id)); pdata->quitting = 1; gwthread_wakeup(pdata->io_thread); gwthread_join(pdata->io_thread); cimd2_destroy(pdata); return -1; } conn->send_msg = cimd2_add_msg_cb; conn->shutdown = cimd2_shutdown_cb; conn->queued = cimd2_queued_cb; conn->start_conn = cimd2_start_cb; conn->stop_conn = cimd2_stop_cb; return 0; } gateway-1.4.5/gw/smsc/smsc_emi_x25.c0000644000175000017500000013200113227613126015707 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /***************************************************************************** * smsc_emi.c - implement interface to the CMG SMS Center (UCP/EMI). * Mikael Gueck for WapIT Ltd. */ /* This file implements two smsc interfaces: EMI_X25 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smsc.h" #include "smsc_p.h" #include "alt_charsets.h" #include "sms.h" #ifndef CRTSCTS #define CRTSCTS 0 #endif /****************************************************************************** * Static functions */ static int get_data(SMSCenter *smsc, char *buff, int length); static int put_data(SMSCenter *smsc, char *buff, int length, int is_backup); static int memorybuffer_append_data(SMSCenter *smsc, char *buff, int length); static int memorybuffer_insert_data(SMSCenter *smsc, char *buff, int length); static int memorybuffer_has_rawmessage(SMSCenter *smsc, int type, char auth); static int memorybuffer_cut_rawmessage(SMSCenter *smsc, char *buff, int length); static int parse_rawmessage_to_msg(SMSCenter *smsc, Msg **msg, char *rawmessage, int length); static int parse_msg_to_rawmessage(SMSCenter *smsc, Msg *msg, char *rawmessage, int length); static int acknowledge_from_rawmessage(SMSCenter *smsc, char *rawmessage, int length); static int parse_emi_to_iso88591(char *from, char *to, int length, int alt_charset); static int parse_iso88591_to_emi(char *from, char *to, int length, int alt_charset); static int parse_binary_to_emi(char *from, char *to, int length); static int at_dial(char *device, char *phonenum, char *at_prefix, time_t how_long); static int guarantee_link(SMSCenter *smsc); static void generate_checksum(const unsigned char *buffer, unsigned char *checksum_out); static int wait_for_ack(SMSCenter *smsc, int op_type); static char char_iso_to_sms(unsigned char from, int alt_charset); static char char_sms_to_iso(unsigned char from, int alt_charset); /****************************************************************************** * Open the connection and log in - handshake baby */ static int emi_open_connection(SMSCenter *smsc) { char tmpbuff[1024]; sprintf(tmpbuff, "/dev/%s", smsc->emi_serialdevice); smsc->emi_fd = at_dial(tmpbuff, smsc->emi_phonenum, "ATD", 30); if (smsc->emi_fd <= 0) return -1; return 0; } /* open EMI smscenter */ SMSCenter *emi_open(char *phonenum, char *serialdevice, char *username, char *password) { SMSCenter *smsc; smsc = smscenter_construct(); if (smsc == NULL) goto error; smsc->type = SMSC_TYPE_EMI_X25; smsc->emi_phonenum = gw_strdup(phonenum); smsc->emi_serialdevice = gw_strdup(serialdevice); smsc->emi_username = gw_strdup(username); smsc->emi_password = gw_strdup(password); smsc->emi_current_msg_number = 0; if (emi_open_connection(smsc) < 0) goto error; sprintf(smsc->name, "EMI:%s:%s", smsc->emi_phonenum, smsc->emi_username); return smsc; error: error(0, "emi_open failed"); smscenter_destruct(smsc); return NULL; } int emi_reopen(SMSCenter *smsc) { emi_close(smsc); if (emi_open_connection(smsc) < 0) { error(0, "emi_reopen failed"); return -1; } return 0; } int emi_close(SMSCenter *smsc) { return emi_close_ip(smsc); } static int emi_fill_ucp60_login(char *buf, char *OAdC, char *passwd) { int max_ia5passwd_len; char *ia5passwd; max_ia5passwd_len = strlen(passwd) * 2 + 1; ia5passwd = gw_malloc(max_ia5passwd_len); if (parse_binary_to_emi(passwd, ia5passwd, strlen(passwd)) < 0) { error(0, "parse_binary_to_emi failed"); gw_free(ia5passwd); return -1; } sprintf(buf, "%s/%c/%c/%c/%s//%s/////", OAdC, /* OAdC: Address code originator */ '6', /* OTON: 6 = Abbreviated number (short number alias) */ '5', /* ONPI: 5 = Private (TCP/IP address/abbreviated number address) */ '1', /* STYP: 1 = open session */ ia5passwd, /* PWD: Current password encoded into IA5 characters */ "0100" /* VERS: Version number 0100 */ ); gw_free(ia5passwd); return 0; } static int emi_open_session(SMSCenter *smsc) { char message_whole [1024]; char message_body [1024]; char message_header [50]; char message_footer [10]; char my_buffer [1024]; int length; memset(message_whole, 0, sizeof(message_whole)); memset(message_body, 0, sizeof(message_body)); memset(message_header, 0, sizeof(message_header)); memset(message_footer, 0, sizeof(message_footer)); if (emi_fill_ucp60_login(message_body, smsc->emi_username, smsc->emi_password) < 0) { error(0, "emi_fill_ucp60_login failed"); return -1; } length = strlen(message_body); length += 13; /* header (fixed) */ length += 2; /* footer (fixed) */ length += 2; /* slashes between header, body, footer */ sprintf(message_header, "%02i/%05i/O/60", (smsc->emi_current_msg_number++ % 100), length); /* FOOTER */ sprintf(my_buffer, "%s/%s/", message_header, message_body); generate_checksum((unsigned char *)my_buffer, (unsigned char *)message_footer); sprintf(message_whole, "\x02%s/%s/%s\x03", message_header, message_body, message_footer); debug("bb.sms.emi", 0, "final UCP60 msg: <%s>", message_whole); put_data(smsc, message_whole, strlen(message_whole), 0); if (!wait_for_ack(smsc, 60)) { info(0, "emi_open_session: wait for ack failed!"); return -1; } return 0; } /******************************************************* * the actual protocol open... quite simple here */ static int emi_open_connection_ip(SMSCenter *smsc) { smsc->emi_fd = tcpip_connect_to_server_with_port(smsc->emi_hostname, smsc->emi_port, smsc->emi_our_port, NULL); /* XXX add interface_name if required */ if (smsc->emi_fd < 0) return -1; if (smsc->emi_username && smsc->emi_password) { return emi_open_session(smsc); } return 0; } int emi_reopen_ip(SMSCenter *smsc) { emi_close_ip(smsc); return emi_open_connection_ip(smsc); } int emi_close_ip(SMSCenter *smsc) { if (smsc->emi_fd == -1) { info(0, "Trying to close already closed EMI, ignoring"); return 0; } close(smsc->emi_fd); smsc->emi_fd = -1; return 0; } /****************************************************************************** * Check if the buffers contain any messages */ int emi_pending_smsmessage(SMSCenter *smsc) { char *tmpbuff; int n = 0; /* time_t timenow; */ /* Block until we have a connection */ guarantee_link(smsc); /* If we have MO-message, then act (return 1) */ if (memorybuffer_has_rawmessage(smsc, 52, 'O') > 0 || memorybuffer_has_rawmessage(smsc, 1, 'O') > 0 ) return 1; tmpbuff = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); /* check for data */ n = get_data(smsc, tmpbuff, 10 * 1024); if (n > 0) memorybuffer_insert_data(smsc, tmpbuff, n); /* delete all ACKs/NACKs/whatever */ while (memorybuffer_has_rawmessage(smsc, 51, 'R') > 0 || memorybuffer_has_rawmessage(smsc, 1, 'R') > 0) memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024); gw_free(tmpbuff); /* If we have MO-message, then act (return 1) */ if (memorybuffer_has_rawmessage(smsc, 52, 'O') > 0 || memorybuffer_has_rawmessage(smsc, 1, 'O') > 0) return 1; /* time(&timenow); if( (smsc->emi_last_spoke + 60*20) < timenow) { time(&smsc->emi_last_spoke); } */ return 0; } /****************************************************************************** * Submit (send) a Mobile Terminated message to the EMI server */ int emi_submit_msg(SMSCenter *smsc, Msg *omsg) { char *tmpbuff = NULL; if (smsc == NULL) goto error; if (omsg == NULL) goto error; tmpbuff = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); if (parse_msg_to_rawmessage(smsc, omsg, tmpbuff, 10*1024) < 1) goto error; if (put_data(smsc, tmpbuff, strlen(tmpbuff), 0) < 0) { info(0, "put_data failed!"); goto error; } wait_for_ack(smsc, 51); /* smsc->emi_current_msg_number += 1; */ debug("bb.sms.emi", 0, "Submit Ok..."); gw_free(tmpbuff); return 0; error: debug("bb.sms.emi", 0, "Submit Error..."); gw_free(tmpbuff); return -1; } /****************************************************************************** * Receive a Mobile Terminated message to the EMI server */ int emi_receive_msg(SMSCenter *smsc, Msg **tmsg) { char *tmpbuff; Msg *msg = NULL; *tmsg = NULL; tmpbuff = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); /* get and delete message from buffer */ memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024); parse_rawmessage_to_msg(smsc, &msg, tmpbuff, strlen(tmpbuff)); /* yeah yeah, I got the message... */ acknowledge_from_rawmessage(smsc, tmpbuff, strlen(tmpbuff)); /* return with the joyful news */ gw_free(tmpbuff); if (msg == NULL) goto error; *tmsg = msg; return 1; error: gw_free(tmpbuff); msg_destroy(msg); return -1; } /****************************************************************************** * Internal functions */ /****************************************************************************** * Guarantee that we have a link */ static int guarantee_link(SMSCenter *smsc) { int need_to_connect = 0; /* If something is obviously wrong. */ if (strstr(smsc->buffer, "OK")) need_to_connect = 1; if (strstr(smsc->buffer, "NO CARRIER")) need_to_connect = 1; if (strstr(smsc->buffer, "NO DIALTONE")) need_to_connect = 1; /* Clear the buffer */ while (need_to_connect) { /* Connect */ need_to_connect = emi_open_connection(smsc) < 0; /* Clear the buffer so that the next call to guarantee doesn't find the "NO CARRIER" string again. */ smsc->buflen = 0; memset(smsc->buffer, 0, smsc->bufsize); } return 0; } static int at_dial(char *device, char *phonenum, char *at_prefix, time_t how_long) { char tmpbuff[1024]; int howmanyread = 0; int thistime = 0; int redial; int fd = -1; int ret; time_t timestart; struct termios tios; /* The time at the start of the function is used when determining whether we have used up our allotted dial time and have to abort. */ time(×tart); /* Open the device properly. Remember to set the access codes correctly. */ fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY); if (fd == -1) { error(errno, "at_dial: error opening character device <%s>", device); goto error; } tcflush(fd, TCIOFLUSH); /* The speed initialisation is pretty important. */ tcgetattr(fd, &tios); #if defined(B115200) cfsetospeed(&tios, B115200); cfsetispeed(&tios, B115200); #elif defined(B76800) cfsetospeed(&tios, B76800); cfsetispeed(&tios, B76800); #elif defined(B57600) cfsetospeed(&tios, B57600); cfsetispeed(&tios, B57600); #elif defined(B38400) cfsetospeed(&tios, B38400); cfsetispeed(&tios, B38400); #elif defined(B19200) cfsetospeed(&tios, B19200); cfsetispeed(&tios, B19200); #elif defined(B9600) cfsetospeed(&tios, B9600); cfsetispeed(&tios, B9600); #endif kannel_cfmakeraw(&tios); tios.c_cflag |= (HUPCL | CREAD | CRTSCTS); ret = tcsetattr(fd, TCSANOW, &tios); if (ret == -1) { error(errno, "EMI[X25]: at_dial: fail to set termios attribute"); } /* Dial using an AT command string. */ for (redial = 1; redial; ) { info(0, "at_dial: dialing <%s> on <%s> for <%i> seconds", phonenum, device, (int)(how_long - (time(NULL) - timestart))); /* Send AT dial request. */ howmanyread = 0; sprintf(tmpbuff, "%s%s\r\n", at_prefix, phonenum); ret = write(fd, tmpbuff, strlen(tmpbuff)); /* errors... -mg */ memset(&tmpbuff, 0, sizeof(tmpbuff)); /* Read the answer to the AT command and react accordingly. */ for (; ; ) { /* We don't want to dial forever */ if (how_long != 0 && time(NULL) > timestart + how_long) goto timeout; /* We don't need more space for dialout */ if (howmanyread >= (int) sizeof(tmpbuff)) goto error; /* We read 1 char a time so that we don't accidentally read past the modem chat and into the SMSC datastream -mg */ thistime = read(fd, &tmpbuff[howmanyread], 1); if (thistime == -1) { if (errno == EAGAIN) continue; if (errno == EINTR) continue; goto error; } else { howmanyread += thistime; } /* Search for the newline on the AT status line. */ if (tmpbuff[howmanyread - 1] == '\r' || tmpbuff[howmanyread - 1] == '\n') { /* XXX ADD ALL POSSIBLE CHAT STRINGS XXX */ if (strstr(tmpbuff, "CONNECT") != NULL) { debug("bb.sms.emi", 0, "at_dial: CONNECT"); redial = 0; break; } else if (strstr(tmpbuff, "NO CARRIER") != NULL) { debug("bb.sms.emi", 0, "at_dial: NO CARRIER"); redial = 1; break; } else if (strstr(tmpbuff, "BUSY") != NULL) { debug("bb.sms.emi", 0, "at_dial: BUSY"); redial = 1; break; } else if (strstr(tmpbuff, "NO DIALTONE") != NULL) { debug("bb.sms.emi", 0, "at_dial: NO DIALTONE"); redial = 1; break; } } /* End of if lastchr=='\r'||'\n'. */ /* Thou shall not consume all system resources by repeatedly looping a strstr search when the string update latency is very high as it is in serial communication. -mg */ usleep(1000); } /* End of read loop. */ /* Thou shall not flood the modem with dial requests. -mg */ sleep(1); } /* End of dial loop. */ debug("bb.sms.emi", 0, "at_dial: done with dialing"); return fd; timeout: error(0, "at_dial timed out"); close(fd); return -1; error: error(0, "at_dial failed"); close(fd); return -1; } /****************************************************************************** * Wait for an ACK or NACK from the remote * * REQUIRED by the protocol that it must be waited... */ static int wait_for_ack(SMSCenter *smsc, int op_type) { char *tmpbuff; int found = 0; int n; time_t start; tmpbuff = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); start = time(NULL); do { /* check for data */ n = get_data(smsc, tmpbuff, 1024 * 10); /* At least the X.31 interface wants to append the data. Kalle, what about the TCP/IP interface? Am I correct that you are assuming that the message arrives in a single read(2)? -mg */ if (n > 0) memorybuffer_append_data(smsc, tmpbuff, n); /* act on data */ if (memorybuffer_has_rawmessage(smsc, op_type, 'R') > 0) { memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024); debug("bb.sms.emi", 0, "Found ACK/NACK: <%s>", tmpbuff); found = 1; } } while (!found && ((time(NULL) - start) < 5)); gw_free(tmpbuff); return found; } /****************************************************************************** * Get the modem buffer data to buff, return the amount read * * Reads from main fd, but also from backup-fd - does accept if needed */ static int get_data(SMSCenter *smsc, char *buff, int length) { int n = 0; struct sockaddr_in client_addr; socklen_t client_addr_len; fd_set rf; struct timeval to; int ret; memset(buff, 0, length); if (smsc->type == SMSC_TYPE_EMI_X25) { tcdrain(smsc->emi_fd); n = read(smsc->emi_fd, buff, length); return n; } FD_ZERO(&rf); if (smsc->emi_fd >= 0) FD_SET(smsc->emi_fd, &rf); if (smsc->emi_secondary_fd >= 0) FD_SET(smsc->emi_secondary_fd, &rf); if (smsc->emi_backup_fd > 0) FD_SET(smsc->emi_backup_fd, &rf); FD_SET(0, &rf); to.tv_sec = 0; to.tv_usec = 100; ret = select(FD_SETSIZE, &rf, NULL, NULL, &to); if (ret > 0) { if (smsc->emi_secondary_fd >= 0 && FD_ISSET(smsc->emi_secondary_fd, &rf)) { n = read(smsc->emi_secondary_fd, buff, length - 1); if (n == -1) { error(errno, "Error - Secondary socket closed"); close(smsc->emi_secondary_fd); smsc->emi_secondary_fd = -1; } else if (n == 0) { info(0, "Secondary socket closed by SMSC"); close(smsc->emi_secondary_fd); smsc->emi_secondary_fd = -1; } else { /* UGLY! We put 'X' after message */ buff[n] = 'X'; /* if it is from secondary fd!!! */ n++; } } else if (smsc->emi_fd >= 0 && FD_ISSET(smsc->emi_fd, &rf)) { n = read(smsc->emi_fd, buff, length); if (n == 0) { close(smsc->emi_fd); info(0, "Main EMI socket closed by SMSC"); smsc->emi_fd = -1; /* ready to be re-opened */ } } if ((smsc->emi_backup_fd > 0) && FD_ISSET(smsc->emi_backup_fd, &rf)) { if (smsc->emi_secondary_fd == -1) { Octstr *ip, *allow; smsc->emi_secondary_fd = accept(smsc->emi_backup_fd, (struct sockaddr *)&client_addr, &client_addr_len); ip = host_ip(client_addr); if (smsc->emi_backup_allow_ip == NULL) allow = NULL; else allow = octstr_create(smsc->emi_backup_allow_ip); if (is_allowed_ip(allow, octstr_imm("*.*.*.*"), ip) == 0) { info(0, "SMSC secondary connection tried from <%s>, " "disconnected", octstr_get_cstr(ip)); octstr_destroy(ip); octstr_destroy(allow); close(smsc->emi_secondary_fd); smsc->emi_secondary_fd = -1; return 0; } info(0, "Secondary socket opened by SMSC from <%s>", octstr_get_cstr(ip)); octstr_destroy(ip); octstr_destroy(allow); } else info(0, "New connection request while old secondary is open!"); } } if (n > 0) { debug("bb.sms.emi", 0, "get_data:Read %d bytes: <%.*s>", n, n, buff); debug("bb.sms.emi", 0, "get_data:smsc->buffer == <%s>", smsc->buffer); } return n; } /****************************************************************************** * Put the buff data to the modem buffer, return the amount of data put */ static int put_data(SMSCenter *smsc, char *buff, int length, int is_backup) { size_t len = length; int ret; int fd = -1; fd = smsc->emi_fd; tcdrain(smsc->emi_fd); /* Write until all data has been successfully written to the fd. */ while (len > 0) { ret = write(fd, buff, len); if (ret == -1) { if (errno == EINTR) continue; if (errno == EAGAIN) continue; error(errno, "Writing to fd failed"); return -1; } /* ret may be less than len, if the writing was interrupted by a signal. */ len -= ret; buff += ret; } if (smsc->type == SMSC_TYPE_EMI_X25) { /* Make sure the data gets written immediately. Wait a while just to add some latency so that the modem (or the UART) doesn't choke on the data. */ tcdrain(smsc->emi_fd); usleep(1000); } return 0; } /****************************************************************************** * Append the buff data to smsc->buffer */ static int memorybuffer_append_data(SMSCenter *smsc, char *buff, int length) { while (smsc->bufsize < (smsc->buflen + length)) { /* buffer too small */ char *p = gw_realloc(smsc->buffer, smsc->bufsize * 2); smsc->buffer = p; smsc->bufsize *= 2; } memcpy(smsc->buffer + smsc->buflen, buff, length); smsc->buflen += length; return 0; } /****************************************************************************** * Insert (put to head) the buff data to smsc->buffer */ static int memorybuffer_insert_data(SMSCenter *smsc, char *buff, int length) { while (smsc->bufsize < (smsc->buflen + length)) { /* buffer too small */ char *p = gw_realloc(smsc->buffer, smsc->bufsize * 2); smsc->buffer = p; smsc->bufsize *= 2; } memmove(smsc->buffer + length, smsc->buffer, smsc->buflen); memcpy(smsc->buffer, buff, length); smsc->buflen += length; return 0; } /****************************************************************************** * Check the smsc->buffer for a raw STX...ETX message */ static int memorybuffer_has_rawmessage(SMSCenter *smsc, int type, char auth) { char tmpbuff[1024], tmpbuff2[1024]; char *stx, *etx; stx = memchr(smsc->buffer, '\2', smsc->buflen); etx = memchr(smsc->buffer, '\3', smsc->buflen); if (stx && etx && stx < etx) { strncpy(tmpbuff, stx, etx - stx + 1); tmpbuff[etx - stx + 1] = '\0'; if (auth) sprintf(tmpbuff2, "/%c/%02i/", auth, type); else sprintf(tmpbuff2, "/%02i/", type); if (strstr(tmpbuff, tmpbuff2) != NULL) { debug("bb.sms.emi", 0, "found message <%c/%02i>...msg <%s>", auth, type, tmpbuff); return 1; } } return 0; } /****************************************************************************** * Cut the first raw message from the smsc->buffer * and put it in buff, return success 0, failure -1 */ static int memorybuffer_cut_rawmessage(SMSCenter *smsc, char *buff, int length) { char *stx, *etx; int size_of_cut_piece; /* We don't check for NULLs since we're sure that nobody has fooled around with smsc->buffer since has_rawmessage was last called... */ stx = memchr(smsc->buffer, '\2', smsc->buflen); etx = memchr(smsc->buffer, '\3', smsc->buflen); if (*(etx + 1) == 'X') /* secondary! UGLY KLUDGE */ etx++; size_of_cut_piece = (etx - stx) + 1; if (length < size_of_cut_piece) { error(0, "the buffer you provided for cutting was too small"); return -1; } /* move the part before our magic rawmessage to the safe house */ memcpy(buff, stx, size_of_cut_piece); buff[size_of_cut_piece] = '\0'; /* NULL-terminate */ /* move the stuff in membuffer one step down */ memmove(stx, etx + 1, (smsc->buffer + smsc->bufsize) - stx ); smsc->buflen -= size_of_cut_piece; return 0; } /****************************************************************************** * Parse the raw message to the Msg structure */ static int parse_rawmessage_to_msg(SMSCenter *smsc, Msg **msg, char *rawmessage, int length) { char emivars[128][1024]; char *leftslash, *rightslash; char isotext[2048]; int msgnbr; int tmpint; msgnbr = -1; memset(isotext, 0, sizeof(isotext)); strncpy(isotext, rawmessage, length); leftslash = isotext; for (tmpint = 0; leftslash != NULL; tmpint++) { rightslash = strchr(leftslash + 1, '/'); if (rightslash == NULL) rightslash = strchr(leftslash + 1, '\3'); if (rightslash == NULL) break; *rightslash = '\0'; strcpy(emivars[tmpint], leftslash + 1); leftslash = rightslash; } if (strcmp(emivars[3], "01") == 0) { if (strcmp(emivars[7], "2") == 0) { strcpy(isotext, emivars[8]); } else if (strcmp(emivars[7], "3") == 0) { parse_emi_to_iso88591(emivars[8], isotext, sizeof(isotext), smsc->alt_charset); } else { error(0, "Unknown 01-type EMI SMS (%s)", emivars[7]); strcpy(isotext, ""); } } else if (strcmp(emivars[3], "51") == 0) { parse_emi_to_iso88591(emivars[24], isotext, sizeof(isotext), smsc->alt_charset); } else if (strcmp(emivars[3], "52") == 0) { parse_emi_to_iso88591(emivars[24], isotext, sizeof(isotext), smsc->alt_charset); } else { error(0, "HEY WE SHOULD NOT BE HERE!! Type = %s", emivars[3]); strcpy(isotext, ""); } *msg = msg_create(sms); if (*msg == NULL) goto error; (*msg)->sms.sender = octstr_create(emivars[5]); (*msg)->sms.receiver = octstr_create(emivars[4]); (*msg)->sms.msgdata = octstr_create(isotext); (*msg)->sms.udhdata = NULL; return msgnbr; error: return -1; } /* * notify the SMSC that we got the message */ static int acknowledge_from_rawmessage(SMSCenter *smsc, char *rawmessage, int length) { char emivars[128][1024]; char timestamp[2048], sender[2048], receiver[2048]; char emitext[2048], isotext[2048]; char *leftslash, *rightslash; int msgnbr; int tmpint; int is_backup = 0; msgnbr = -1; memset(&sender, 0, sizeof(sender)); memset(&receiver, 0, sizeof(receiver)); memset(&emitext, 0, sizeof(emitext)); memset(&isotext, 0, sizeof(isotext)); memset(×tamp, 0, sizeof(timestamp)); strncpy(isotext, rawmessage, length); leftslash = isotext; if (isotext[length - 1] == 'X') is_backup = 1; for (tmpint = 0; leftslash != NULL; tmpint++) { rightslash = strchr(leftslash + 1, '/'); if (rightslash == NULL) rightslash = strchr(leftslash + 1, '\3'); if (rightslash == NULL) break; *rightslash = '\0'; strcpy(emivars[tmpint], leftslash + 1); leftslash = rightslash; } /* BODY */ sprintf(isotext, "A//%s:%s", emivars[4], emivars[18]); sprintf(isotext, "A//%s:", emivars[5]); is_backup = 0; /* HEADER */ debug("bb.sms.emi", 0, "acknowledge: type = '%s'", emivars[3]); sprintf(emitext, "%s/%05i/%s/%s", emivars[0], (int) strlen(isotext) + 17, "R", emivars[3]); smsc->emi_current_msg_number = atoi(emivars[0]) + 1; /* FOOTER */ sprintf(timestamp, "%s/%s/", emitext, isotext); generate_checksum((unsigned char *)timestamp, (unsigned char *)receiver); sprintf(sender, "%c%s/%s/%s%c", 0x02, emitext, isotext, receiver, 0x03); put_data(smsc, sender, strlen(sender), is_backup); return msgnbr; } /****************************************************************************** * Parse the Msg structure to the raw message format */ static int parse_msg_to_rawmessage(SMSCenter *smsc, Msg *msg, char *rawmessage, int rawmessage_length) { char message_whole[10*1024]; char message_body[10*1024]; char message_header[1024]; char message_footer[1024]; char my_buffer[10*1024]; char my_buffer2[10*1024]; char msgtext[1024]; int length; char mt; char mcl[20]; char snumbits[20]; char xser[1024]; int udh_len; memset(&message_whole, 0, sizeof(message_whole)); memset(&message_body, 0, sizeof(message_body)); memset(&message_header, 0, sizeof(message_header)); memset(&message_footer, 0, sizeof(message_footer)); memset(&my_buffer, 0, sizeof(my_buffer)); memset(&my_buffer2, 0, sizeof(my_buffer2)); mt = '3'; memset(&snumbits, 0, sizeof(snumbits)); memset(&xser, 0, sizeof(xser)); /* XXX parse_iso88591_to_emi shouldn't use NUL terminated * strings, but Octstr directly, or a char* and a length. */ if (octstr_len(msg->sms.udhdata)) { char xserbuf[258]; /* we need a properly formated UDH here, there first byte contains his length * this will be formatted in the xser field of the EMI Protocol */ udh_len = octstr_get_char(msg->sms.udhdata, 0) + 1; xserbuf[0] = 1; xserbuf[1] = udh_len; octstr_get_many_chars(&xserbuf[2], msg->sms.udhdata, 0, udh_len); parse_binary_to_emi(xserbuf, xser, udh_len + 2); } else { udh_len = 0; } if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) { octstr_get_many_chars(msgtext, msg->sms.msgdata, 0, octstr_len(msg->sms.msgdata)); msgtext[octstr_len(msg->sms.msgdata)] = '\0'; parse_iso88591_to_emi(msgtext, my_buffer2, octstr_len(msg->sms.msgdata), smsc->alt_charset); strcpy(snumbits, ""); mt = '3'; strcpy(mcl, ""); } else { octstr_get_many_chars(msgtext, msg->sms.msgdata, 0, octstr_len(msg->sms.msgdata)); parse_binary_to_emi(msgtext, my_buffer2, octstr_len(msg->sms.msgdata)); sprintf(snumbits, "%04ld", octstr_len(msg->sms.msgdata)*8); mt = '4'; strcpy(mcl, "1"); } /* XXX Where is DCS ? Is it in XSER like in emi2 ? * Please someone encode it with fields_to_dcs */ sprintf(message_body, "%s/%s/%s/%s/%s//%s////////////%c/%s/%s////%s//////%s//", octstr_get_cstr(msg->sms.receiver), msg->sms.sender ? octstr_get_cstr(msg->sms.sender) : "", "", "", "", "0100", mt, snumbits, my_buffer2, mcl, xser); /* HEADER */ length = strlen(message_body); length += 13; /* header (fixed) */ length += 2; /* footer (fixed) */ length += 2; /* slashes between header, body, footer */ sprintf(message_header, "%02i/%05i/%s/%s", (smsc->emi_current_msg_number++ % 100), length, "O", "51"); /* FOOTER */ sprintf(my_buffer, "%s/%s/", message_header, message_body); generate_checksum((unsigned char *)my_buffer, (unsigned char *)message_footer); sprintf(message_whole, "%c%s/%s/%s%c", 0x02, message_header, message_body, message_footer, 0x03); strncpy(rawmessage, message_whole, rawmessage_length); if (smsc->type == SMSC_TYPE_EMI_X25) { /* IC3S braindead EMI stack chokes on this... must fix it at the next time... */ strcat(rawmessage, "\r"); } debug("bb.sms.emi", 0, "emi %d message %s", smsc->emi_current_msg_number, rawmessage); return strlen(rawmessage); } /****************************************************************************** * Parse the data from the two byte EMI code to normal ISO-8869-1 */ static int parse_emi_to_iso88591(char *from, char *to, int length, int alt_charset) { int hmtg = 0; unsigned int mychar; char tmpbuff[128]; for (hmtg = 0; hmtg <= (int)strlen(from); hmtg += 2) { strncpy(tmpbuff, from + hmtg, 2); sscanf(tmpbuff, "%x", &mychar); to[hmtg / 2] = char_sms_to_iso(mychar, alt_charset); } to[(hmtg / 2)-1] = '\0'; return 0; } /****************************************************************************** * Parse the data from normal ISO-8869-1 to the two byte EMI code */ static int parse_iso88591_to_emi(char *from, char *to, int length, int alt_charset) { char buf[10]; unsigned char tmpchar; char *ptr; if (!from || !to || length <= 0) return -1; *to = '\0'; debug("bb.sms.emi", 0, "emi parsing <%s> to emi, length %d", from, length); for (ptr = from; length > 0; ptr++, length--) { tmpchar = char_iso_to_sms(*ptr, alt_charset); sprintf(buf, "%02X", tmpchar); strncat(to, buf, 2); } return 0; } /****************************************************************************** * Parse the data from binary to the two byte EMI code */ static int parse_binary_to_emi(char *from, char *to, int length) { char buf[10]; char *ptr; if (!from || !to || length <= 0) return -1; *to = '\0'; for (ptr = from; length > 0; ptr++, length--) { sprintf(buf, "%02X", (unsigned char)*ptr); strncat(to, buf, 2); } return 0; } /****************************************************************************** * Generate the EMI message checksum */ static void generate_checksum(const unsigned char *buf, unsigned char *out) { const unsigned char *p; int j; j = 0; for (p = buf; *p != '\0'; p++) { j += *p; if (j >= 256) j -= 256; } sprintf((char *)out, "%02X", j); } /****************************************************************************** * Translate character from iso to emi_mt * PGrönholm */ static char char_iso_to_sms(unsigned char from, int alt_charset) { switch ((char)from) { case 'A': return 0x41; case 'B': return 0x42; case 'C': return 0x43; case 'D': return 0x44; case 'E': return 0x45; case 'F': return 0x46; case 'G': return 0x47; case 'H': return 0x48; case 'I': return 0x49; case 'J': return 0x4A; case 'K': return 0x4B; case 'L': return 0x4C; case 'M': return 0x4D; case 'N': return 0x4E; case 'O': return 0x4F; case 'P': return 0x50; case 'Q': return 0x51; case 'R': return 0x52; case 'S': return 0x53; case 'T': return 0x54; case 'U': return 0x55; case 'V': return 0x56; case 'W': return 0x57; case 'X': return 0x58; case 'Y': return 0x59; case 'Z': return 0x5A; case 'a': return 0x61; case 'b': return 0x62; case 'c': return 0x63; case 'd': return 0x64; case 'e': return 0x65; case 'f': return 0x66; case 'g': return 0x67; case 'h': return 0x68; case 'i': return 0x69; case 'j': return 0x6A; case 'k': return 0x6B; case 'l': return 0x6C; case 'm': return 0x6D; case 'n': return 0x6E; case 'o': return 0x6F; case 'p': return 0x70; case 'q': return 0x71; case 'r': return 0x72; case 's': return 0x73; case 't': return 0x74; case 'u': return 0x75; case 'v': return 0x76; case 'w': return 0x77; case 'x': return 0x78; case 'y': return 0x79; case 'z': return 0x7A; case '0': return 0x30; case '1': return 0x31; case '2': return 0x32; case '3': return 0x33; case '4': return 0x34; case '5': return 0x35; case '6': return 0x36; case '7': return 0x37; case '8': return 0x38; case '9': return 0x39; case ':': return 0x3A; case ';': return 0x3B; case '<': return 0x3C; case '=': return 0x3D; case '>': return 0x3E; case '?': return 0x3F; case 'Ä': return '['; case 'Ö': return '\\'; case 'Å': return 0x0E; case 'Ü': return ']'; case 'ä': return '{'; case 'ö': return '|'; case 'å': return 0x0F; case 'ü': return '}'; case 'ß': return '~'; case '§': return '^'; case 'Ñ': return 0x5F; case 'ø': return 0x0C; /* case 'Delta': return 0x10; */ /* case 'Fii': return 0x12; */ /* case 'Lambda': return 0x13; */ /* case 'Alpha': return 0x14; */ /* case 'Omega': return 0x15; */ /* case 'Pii': return 0x16; */ /* case 'Pii': return 0x17; */ /* case 'Delta': return 0x18; */ /* case 'Delta': return 0x19; */ /* case 'Delta': return 0x1A; */ case ' ': return 0x20; case '@': if (alt_charset == EMI_SWAPPED_CHARS) return 0x00; else return 0x40; case '£': return 0x01; case '$': return 0x24; case '¥': return 0x03; case 'è': return 0x04; case 'é': return 0x05; case 'ù': return 0x06; case 'ì': return 0x07; case 'ò': return 0x08; case 'Ç': return 0x09; case '\r': return 0x0A; case 'Ø': return 0x0B; case '\n': return 0x0D; case 'Æ': return 0x1C; case 'æ': return 0x1D; case 'É': return 0x1F; case '!': return 0x21; case '"': return 0x22; case '#': return 0x23; case '¤': return 0x02; case '%': return 0x25; case '&': return 0x26; case '\'': return 0x27; case '(': return 0x28; case ')': return 0x29; case '*': return 0x2A; case '+': return 0x2B; case ',': return 0x2C; case '-': return 0x2D; case '.': return 0x2E; case '/': return 0x2F; case '¿': return 0x60; case 'ñ': return 0x1E; case 'à': return 0x7F; case '¡': if (alt_charset == EMI_SWAPPED_CHARS) return 0x40; else return 0x00; case '_': return 0x11; default: return 0x20; /* space */ } /* switch */ } /****************************************************************************** * Translate character from emi_mo to iso * PGrönholm */ static char char_sms_to_iso(unsigned char from, int alt_charset) { switch ((int)from) { case 0x41: return 'A'; case 0x42: return 'B'; case 0x43: return 'C'; case 0x44: return 'D'; case 0x45: return 'E'; case 0x46: return 'F'; case 0x47: return 'G'; case 0x48: return 'H'; case 0x49: return 'I'; case 0x4A: return 'J'; case 0x4B: return 'K'; case 0x4C: return 'L'; case 0x4D: return 'M'; case 0x4E: return 'N'; case 0x4F: return 'O'; case 0x50: return 'P'; case 0x51: return 'Q'; case 0x52: return 'R'; case 0x53: return 'S'; case 0x54: return 'T'; case 0x55: return 'U'; case 0x56: return 'V'; case 0x57: return 'W'; case 0x58: return 'X'; case 0x59: return 'Y'; case 0x5A: return 'Z'; case 0x61: return 'a'; case 0x62: return 'b'; case 0x63: return 'c'; case 0x64: return 'd'; case 0x65: return 'e'; case 0x66: return 'f'; case 0x67: return 'g'; case 0x68: return 'h'; case 0x69: return 'i'; case 0x6A: return 'j'; case 0x6B: return 'k'; case 0x6C: return 'l'; case 0x6D: return 'm'; case 0x6E: return 'n'; case 0x6F: return 'o'; case 0x70: return 'p'; case 0x71: return 'q'; case 0x72: return 'r'; case 0x73: return 's'; case 0x74: return 't'; case 0x75: return 'u'; case 0x76: return 'v'; case 0x77: return 'w'; case 0x78: return 'x'; case 0x79: return 'y'; case 0x7A: return 'z'; case 0x30: return '0'; case 0x31: return '1'; case 0x32: return '2'; case 0x33: return '3'; case 0x34: return '4'; case 0x35: return '5'; case 0x36: return '6'; case 0x37: return '7'; case 0x38: return '8'; case 0x39: return '9'; case 0x3A: return ':'; case 0x3B: return ';'; case 0x3C: return '<'; case 0x3D: return '='; case 0x3E: return '>'; case 0x3F: return '?'; case '[': return 'Ä'; case '\\': return 'Ö'; case '\xC5': return 'Å'; case ']': return 'Ü'; case '{': return 'ä'; case '|': return 'ö'; case 0xE5: return 'å'; case '}': return 'ü'; case '~': return 'ß'; case 0xA7: return '§'; case 0xD1: return 'Ñ'; case 0xF8: return 'ø'; /* case 'Delta': return 0x10; */ /* case 'Fii': return 0x12; */ /* case 'Lambda': return 0x13; */ /* case 'Alpha': return 0x14; */ /* case 'Omega': return 0x15; */ /* case 'Pii': return 0x16; */ /* case 'Pii': return 0x17; */ /* case 'Delta': return 0x18; */ /* case 'Delta': return 0x19; */ /* case 'Delta': return 0x1A; */ case 0x20: return ' '; case 0x40: return '@'; case 0xA3: return '£'; case 0x24: return '$'; case 0xA5: return '¥'; case 0xE8: return 'è'; case 0xE9: return 'é'; case 0xF9: return 'ù'; case 0xEC: return 'ì'; case 0xF2: return 'ò'; case 0xC7: return 'Ç'; case 0x0A: return '\r'; case 0xD8: return 'Ø'; case 0x0D: return '\n'; case 0xC6: return 'Æ'; case 0xE6: return 'æ'; case 0x1F: return 'É'; case 0x21: return '!'; case 0x22: return '"'; case 0x23: return '#'; case 0xA4: return '¤'; case 0x25: return '%'; case 0x26: return '&'; case 0x27: return '\''; case 0x28: return '('; case 0x29: return ')'; case 0x2A: return '*'; case 0x2B: return '+'; case 0x2C: return ','; case 0x2D: return '-'; case 0x2E: return '.'; case 0x2F: return '/'; case 0xBF: return '¿'; case 0xF1: return 'ñ'; case 0xE0: return 'à'; case 0xA1: return '¡'; case 0x5F: return '_'; default: return ' '; } /* switch */ } gateway-1.4.5/gw/smsc/smpp_pdu.def0000644000175000017500000005125113227613126015564 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smpp_pdu.def - definitions of SMPP PDU structure * * Lars Wirzenius * Daniel Lukic : * Initial optional parameters implementation. * Alexander Malysh : * Extended optional parameters implementation. * Stipe Tolj : * Adding SMPP v5.0 PDUs */ #include "smpp_pdu_opt.def" #ifndef PDU #error Macro PDU not defined. #endif #ifndef INTEGER #error Macro INTEGER not defined. #endif #ifndef NULTERMINATED #error Macro NULTERMINATED not defined. #endif #ifndef OCTETS #error Macro OCTETS not defined. #endif #ifndef OPTIONAL_BEGIN #error Macro OPTIONAL_BEGIN not defined. #endif #ifndef TLV_INTEGER #error Macro TLV_INTEGER not defined. #endif #ifndef TLV_NULTERMINATED #error Macro TLV_NULTERMINATED not defined. #endif #ifndef TLV_OCTETS #error Macro TLV_OCTETS not defined. #endif #ifndef OPTIONAL_END #error Macro OPTIONAL_END not defined. #endif /* * All SMPP PDUs have a common header consisting of four integers. * The first integer, command_length, is dealt with implicitly by * the I/O stuff, so we don't store it in the PDU data structure. * The other three are defined in the HEADER macro. */ #ifdef HEADER #error Macro HEADER was already defined. #endif #define HEADER \ INTEGER(command_id, 4) \ INTEGER(command_status, 4) \ INTEGER(sequence_number, 4) /* * PDUs defined in SMPP v3.4 */ PDU(bind_transmitter, 0x00000002, HEADER NULTERMINATED(system_id, 16) NULTERMINATED(password, 9) NULTERMINATED(system_type, 13) INTEGER(interface_version, 1) INTEGER(addr_ton, 1) INTEGER(addr_npi, 1) NULTERMINATED(address_range, 41) ) PDU(bind_transmitter_resp, 0x80000002, HEADER NULTERMINATED(system_id, 16) OPTIONAL_BEGIN TLV_INTEGER(sc_interface_version, 1) OPTIONAL_END ) PDU(bind_receiver, 0x00000001, HEADER NULTERMINATED(system_id, 16) NULTERMINATED(password, 9) NULTERMINATED(system_type, 13) INTEGER(interface_version, 1) INTEGER(addr_ton, 1) INTEGER(addr_npi, 1) NULTERMINATED(address_range, 41) ) PDU(bind_receiver_resp, 0x80000001, HEADER NULTERMINATED(system_id, 16) OPTIONAL_BEGIN TLV_INTEGER(sc_interface_version, 1) OPTIONAL_END ) PDU(bind_transceiver, 0x00000009, HEADER NULTERMINATED(system_id, 16) NULTERMINATED(password, 9) NULTERMINATED(system_type, 13) INTEGER(interface_version, 1) INTEGER(addr_ton, 1) INTEGER(addr_npi, 1) NULTERMINATED(address_range, 41) ) PDU(bind_transceiver_resp, 0x80000009, HEADER NULTERMINATED(system_id, 16) OPTIONAL_BEGIN TLV_INTEGER(sc_interface_version, 1) OPTIONAL_END ) PDU(outbind, 0x0000000B, HEADER NULTERMINATED(system_id, 16) NULTERMINATED(password, 9) ) PDU(unbind, 0x00000006, HEADER ) PDU(unbind_resp, 0x80000006, HEADER ) PDU(generic_nack, 0x80000000, HEADER ) PDU(submit_sm, 0x00000004, HEADER NULTERMINATED(service_type, 6) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) INTEGER(dest_addr_ton, 1) INTEGER(dest_addr_npi, 1) NULTERMINATED(destination_addr, 21) INTEGER(esm_class, 1) INTEGER(protocol_id, 1) INTEGER(priority_flag, 1) NULTERMINATED(schedule_delivery_time, 17) NULTERMINATED(validity_period, 17) INTEGER(registered_delivery, 1) INTEGER(replace_if_present_flag, 1) INTEGER(data_coding, 1) INTEGER(sm_default_msg_id, 1) INTEGER(sm_length, 1) OCTETS(short_message, sm_length) OPTIONAL_BEGIN /* defined in SMPP v3.4 */ TLV_INTEGER(user_message_reference, 2) TLV_INTEGER(source_port, 2) TLV_INTEGER(source_addr_subunit, 1) TLV_INTEGER(destination_port, 2) /* renamed to 'dest_port' in SMPP v5.0 ?? */ TLV_INTEGER(dest_addr_subunit, 1) TLV_INTEGER(sar_msg_ref_num, 2) TLV_INTEGER(sar_total_segments, 1) TLV_INTEGER(sar_segment_seqnum, 1) TLV_INTEGER(more_messages_to_send, 1) TLV_INTEGER(payload_type, 1) TLV_OCTETS(message_payload, 0, 65536) TLV_INTEGER(privacy_indicator, 1) TLV_OCTETS(callback_num, 4, 19) TLV_INTEGER(callback_num_pres_ind, 1) TLV_OCTETS(callback_num_atag, 0, 65) TLV_OCTETS(source_subaddress, 2, 23) TLV_OCTETS(dest_subaddress, 2, 23) TLV_INTEGER(user_response_code, 1) TLV_INTEGER(display_time, 1) TLV_INTEGER(sms_signal, 2) TLV_INTEGER(ms_validity, 1) TLV_INTEGER(ms_msg_wait_facilities, 1) TLV_INTEGER(number_of_messages, 1) TLV_INTEGER(alert_on_message_delivery, 0) TLV_INTEGER(language_indicator, 1) TLV_INTEGER(its_reply_type, 1) TLV_OCTETS(its_session_info, 2, 2) TLV_OCTETS(ussd_service_op, 1, 1) /* added in SMPP v5.0 */ TLV_OCTETS(billing_identification, 1, 1024) TLV_INTEGER(dest_addr_np_country, 5) TLV_OCTETS(dest_addr_np_information, 10, 10) TLV_INTEGER(dest_addr_np_resolution, 1) TLV_INTEGER(dest_bearer_type, 1) TLV_NULTERMINATED(dest_network_id, 65) TLV_INTEGER(dest_network_type, 1) TLV_OCTETS(dest_node_id, 6, 6) TLV_INTEGER(dest_telematics_id, 2) TLV_INTEGER(qos_time_to_live, 4) TLV_INTEGER(set_dpf, 1) TLV_INTEGER(source_bearer_type, 1) TLV_NULTERMINATED(source_network_id, 65) TLV_INTEGER(source_network_type, 1) TLV_OCTETS(source_node_id, 6, 6) TLV_INTEGER(source_telematics_id, 1) OPTIONAL_END ) PDU(submit_sm_resp, 0x80000004, HEADER NULTERMINATED(message_id, 65) OPTIONAL_BEGIN /* added in SMPP v5.0 */ TLV_NULTERMINATED(additional_status_info_text, 256) TLV_INTEGER(delivery_failure_reason, 1) TLV_INTEGER(dpf_result, 1) TLV_OCTETS(network_error_code, 3, 3) OPTIONAL_END ) PDU(submit_multi, 0x00000021, HEADER NULTERMINATED(service_type, 6) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) INTEGER(number_of_dests, 1) NULTERMINATED(dest_address_es, 254 * 24) INTEGER(esm_class, 1) INTEGER(protocol_id, 1) INTEGER(priority_flag, 1) NULTERMINATED(schedule_delivery_time, 17) NULTERMINATED(validity_period, 17) INTEGER(registered_delivery, 1) INTEGER(replace_if_present_flag, 1) INTEGER(data_coding, 1) INTEGER(sm_default_msg_id, 1) INTEGER(sm_length, 1) OCTETS(short_message, sm_length) OPTIONAL_BEGIN /* defined in SMPP v3.4 */ TLV_INTEGER(user_message_reference, 2) TLV_INTEGER(source_port, 2) TLV_INTEGER(source_addr_subunit, 1) TLV_INTEGER(destination_port, 2) TLV_INTEGER(dest_addr_subunit, 1) TLV_INTEGER(sar_msg_ref_num, 2) TLV_INTEGER(sar_total_segments, 1) TLV_INTEGER(sar_segment_seqnum, 1) TLV_INTEGER(payload_type, 1) TLV_OCTETS(message_payload, 0, 65536) TLV_INTEGER(privacy_indicator, 1) TLV_OCTETS(callback_num, 4, 19) TLV_INTEGER(callback_num_pres_ind, 1) TLV_OCTETS(callback_num_atag, 0, 65) TLV_OCTETS(source_subaddress, 2, 23) TLV_OCTETS(dest_subaddress, 2, 23) TLV_INTEGER(display_time, 1) TLV_INTEGER(sms_signal, 2) TLV_INTEGER(ms_validity, 1) TLV_INTEGER(ms_msg_wait_facilities, 1) TLV_INTEGER(alert_on_message_delivery, 0) TLV_INTEGER(language_indicator, 1) /* added in SMPP v5.0 */ TLV_OCTETS(billing_identification, 1, 1024) TLV_INTEGER(dest_addr_np_country, 5) TLV_OCTETS(dest_addr_np_information, 10, 10) TLV_INTEGER(dest_addr_np_resolution, 1) TLV_INTEGER(dest_bearer_type, 1) TLV_NULTERMINATED(dest_network_id, 65) TLV_INTEGER(dest_network_type, 1) TLV_OCTETS(dest_node_id, 6, 6) TLV_INTEGER(dest_telematics_id, 2) TLV_INTEGER(its_reply_type, 1) TLV_OCTETS(its_session_info, 2, 2) TLV_INTEGER(more_messages_to_send, 1) TLV_INTEGER(number_of_messages, 1) TLV_INTEGER(qos_time_to_live, 4) TLV_INTEGER(set_dpf, 1) TLV_INTEGER(source_bearer_type, 1) TLV_NULTERMINATED(source_network_id, 65) TLV_INTEGER(source_network_type, 1) TLV_OCTETS(source_node_id, 6, 6) TLV_INTEGER(source_telematics_id, 1) TLV_INTEGER(user_response_code, 1) OPTIONAL_END ) PDU(submit_multi_resp, 0x80000021, HEADER NULTERMINATED(message_id, 65) INTEGER(no_unsuccess, 1) //VAR_OCTETS(unsuccess_sme, 6, 27) //OCTETS(unsuccess_sme, 27) OPTIONAL_BEGIN /* added in SMPP v5.0 */ TLV_NULTERMINATED(additional_status_info_text, 256) TLV_INTEGER(delivery_failure_reason, 1) TLV_INTEGER(dpf_result, 1) TLV_OCTETS(network_error_code, 3, 3) OPTIONAL_END ) PDU(deliver_sm, 0x00000005, HEADER NULTERMINATED(service_type, 6) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) INTEGER(dest_addr_ton, 1) INTEGER(dest_addr_npi, 1) NULTERMINATED(destination_addr, 21) INTEGER(esm_class, 1) INTEGER(protocol_id, 1) INTEGER(priority_flag, 1) NULTERMINATED(schedule_delivery_time, 17) NULTERMINATED(validity_period, 17) INTEGER(registered_delivery, 1) INTEGER(replace_if_present_flag, 1) INTEGER(data_coding, 1) INTEGER(sm_default_msg_id, 1) INTEGER(sm_length, 1) OCTETS(short_message, sm_length) OPTIONAL_BEGIN /* defined in SMPP v3.4 */ TLV_INTEGER(user_message_reference, 2) TLV_INTEGER(source_port, 2) TLV_INTEGER(destination_port, 2) /* renamed to 'dest_port' in SMPP v5.0 ?? */ TLV_INTEGER(sar_msg_ref_num, 2) TLV_INTEGER(sar_total_segments, 1) TLV_INTEGER(sar_segment_seqnum, 1) TLV_INTEGER(user_response_code, 1) TLV_INTEGER(privacy_indicator, 1) TLV_INTEGER(payload_type, 1) TLV_OCTETS(message_payload, 0, 65536) TLV_OCTETS(callback_num, 4, 19) TLV_OCTETS(source_subaddress, 2, 23) TLV_OCTETS(dest_subaddress, 2, 23) TLV_INTEGER(language_indicator, 1) TLV_OCTETS(its_session_info, 2, 2) TLV_OCTETS(network_error_code, 3, 3) TLV_INTEGER(message_state, 1) TLV_NULTERMINATED(receipted_message_id, 65) /* added in SMPP v5.0 */ TLV_OCTETS(callback_num_atag, 0, 65) TLV_INTEGER(callback_num_pres_ind, 1) TLV_INTEGER(dest_addr_np_country, 5) TLV_OCTETS(dest_addr_np_information, 10, 10) TLV_INTEGER(dest_addr_np_resolution, 1) TLV_INTEGER(dest_addr_subunit, 1) TLV_NULTERMINATED(dest_network_id, 65) TLV_INTEGER(dpf_result, 1) TLV_INTEGER(its_reply_type, 1) TLV_INTEGER(source_addr_subunit, 1) TLV_NULTERMINATED(source_network_id, 65) TLV_OCTETS(source_node_id, 6, 6) TLV_OCTETS(ussd_service_op, 1, 1) OPTIONAL_END ) PDU(deliver_sm_resp, 0x80000005, HEADER NULTERMINATED(message_id, 1) OPTIONAL_BEGIN /* added in SMPP v5.0 */ TLV_NULTERMINATED(additional_status_info_text, 256) TLV_INTEGER(delivery_failure_reason, 1) TLV_OCTETS(network_error_code, 3, 3) OPTIONAL_END ) PDU(data_sm, 0x00000103, HEADER NULTERMINATED(service_type, 6) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 65) INTEGER(dest_addr_ton, 1) INTEGER(dest_addr_npi, 1) NULTERMINATED(destination_addr, 65) INTEGER(esm_class, 1) INTEGER(registered_delivery, 1) INTEGER(data_coding, 1) OPTIONAL_BEGIN /* defined in SMPP v3.4 */ TLV_INTEGER(source_port, 2) TLV_INTEGER(source_addr_subunit, 1) TLV_INTEGER(source_network_type, 1) TLV_INTEGER(source_bearer_type, 1) TLV_INTEGER(source_telematics_id, 1) TLV_INTEGER(destination_port, 2) TLV_INTEGER(dest_addr_subunit, 1) TLV_INTEGER(dest_network_type, 1) TLV_INTEGER(dest_bearer_type, 1) TLV_INTEGER(dest_telematics_id, 2) TLV_INTEGER(sar_msg_ref_num, 2) TLV_INTEGER(sar_total_segments, 1) TLV_INTEGER(sar_segment_seqnum, 1) TLV_INTEGER(more_messages_to_send, 1) TLV_INTEGER(qos_time_to_live, 4) TLV_INTEGER(payload_type, 1) TLV_OCTETS(message_payload, 0, 65536) TLV_INTEGER(set_dpf, 1) TLV_NULTERMINATED(receipted_message_id, 65) TLV_INTEGER(message_state, 1) TLV_OCTETS(network_error_code, 3, 3) TLV_INTEGER(user_message_reference, 2) TLV_INTEGER(privacy_indicator, 1) TLV_OCTETS(callback_num, 4, 19) TLV_INTEGER(callback_num_pres_ind, 1) TLV_OCTETS(callback_num_atag, 0, 65) TLV_OCTETS(source_subaddress, 2, 23) TLV_OCTETS(dest_subaddress, 2, 23) TLV_INTEGER(user_response_code, 1) TLV_INTEGER(display_time, 1) TLV_INTEGER(sms_signal, 2) TLV_INTEGER(ms_validity, 1) TLV_INTEGER(ms_msg_wait_facilities, 1) TLV_INTEGER(number_of_messages, 1) TLV_INTEGER(alert_on_message_delivery, 0) TLV_INTEGER(language_indicator, 1) TLV_INTEGER(its_reply_type, 1) TLV_OCTETS(its_session_info, 2, 2) /* added in SMPP v5.0 */ TLV_OCTETS(billing_identification, 1, 1024) TLV_INTEGER(dest_addr_np_country, 5) TLV_OCTETS(dest_addr_np_information, 10, 10) TLV_INTEGER(dest_addr_np_resolution, 1) TLV_NULTERMINATED(dest_network_id, 65) TLV_OCTETS(dest_node_id, 6, 6) TLV_NULTERMINATED(source_network_id, 65) TLV_OCTETS(source_node_id, 6, 6) TLV_OCTETS(ussd_service_op, 1, 1) OPTIONAL_END ) PDU(data_sm_resp, 0x80000103, HEADER NULTERMINATED(message_id, 65) OPTIONAL_BEGIN /* defined in SMPP v3.4 */ TLV_NULTERMINATED(additional_status_info_text, 256) TLV_INTEGER(delivery_failure_reason, 1) TLV_INTEGER(dpf_result, 1) TLV_OCTETS(network_error_code, 3, 3) OPTIONAL_END ) PDU(query_sm, 0x00000003, HEADER NULTERMINATED(message_id, 65) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) ) PDU(query_sm_resp, 0x80000003, HEADER NULTERMINATED(message_id, 65) NULTERMINATED(final_date, 17) INTEGER(message_state, 1) INTEGER(error_code, 1) ) PDU(cancel_sm, 0x00000008, HEADER NULTERMINATED(service_type, 6) NULTERMINATED(message_id, 65) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) INTEGER(dest_addr_ton, 1) INTEGER(dest_addr_npi, 1) NULTERMINATED(destination_addr, 65) ) PDU(cancel_sm_resp, 0x80000008, HEADER ) PDU(replace_sm, 0x00000007, HEADER NULTERMINATED(service_type, 6) NULTERMINATED(message_id, 65) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) NULTERMINATED(schedule_delivery_time, 17) NULTERMINATED(validity_period, 17) INTEGER(registered_delivery, 1) INTEGER(sm_default_msg_id, 1) INTEGER(sm_length, 1) OCTETS(short_message, sm_length) OPTIONAL_BEGIN /* added in SMPP v5.0 */ TLV_OCTETS(message_payload, 0, 65536) OPTIONAL_END ) PDU(replace_sm_resp, 0x80000007, HEADER ) PDU(enquire_link, 0x00000015, HEADER ) PDU(enquire_link_resp, 0x80000015, HEADER ) PDU(alert_notification, 0x00000102, HEADER INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) INTEGER(esme_addr_ton, 1) INTEGER(esme_addr_npi, 1) NULTERMINATED(esme_addr, 65) OPTIONAL_BEGIN /* defined in SMPP v3.4 */ TLV_INTEGER(ms_availability_status, 1) OPTIONAL_END ) /* * PDUs defined in SMPP v5.0 */ PDU(broadcast_sm, 0x00000111, HEADER NULTERMINATED(service_type, 6) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) NULTERMINATED(message_id, 65) INTEGER(priority_flag, 1) NULTERMINATED(schedule_delivery_time, 17) NULTERMINATED(validity_period, 17) INTEGER(registered_delivery, 1) INTEGER(replace_if_present_flag, 1) INTEGER(data_coding, 1) INTEGER(sm_default_msg_id, 1) OPTIONAL_BEGIN TLV_OCTETS(broadcast_area_identifier, 1, 101) TLV_OCTETS(broadcast_content_type, 3, 3) TLV_OCTETS(broadcast_rep_num, 3, 3) TLV_OCTETS(broadcast_frequency_interval, 3, 3) //OPTIONAL_BEGIN TLV_INTEGER(alert_on_message_delivery, 0) TLV_INTEGER(broadcast_channel_indicator, 1) TLV_OCTETS(broadcast_content_type_info, 1, 254) TLV_INTEGER(broadcast_message_class, 1) TLV_OCTETS(broadcast_service_group, 1, 254) TLV_OCTETS(callback_num, 4, 19) TLV_OCTETS(callback_num_atag, 0, 65) TLV_INTEGER(callback_num_pres_ind, 1) TLV_INTEGER(dest_addr_subunit, 1) TLV_OCTETS(dest_subaddress, 2, 23) TLV_INTEGER(destination_port, 2) /* called 'dest_port' in SMPP v5.0 spec?? */ TLV_INTEGER(display_time, 1) TLV_INTEGER(language_indicator, 1) TLV_OCTETS(message_payload, 0, 65536) TLV_INTEGER(ms_validity, 1) TLV_INTEGER(payload_type, 1) TLV_INTEGER(privacy_indicator, 1) TLV_INTEGER(sms_signal, 2) TLV_INTEGER(source_addr_subunit, 1) TLV_INTEGER(source_port, 2) TLV_OCTETS(source_subaddress, 2, 23) TLV_INTEGER(user_message_reference, 2) OPTIONAL_END ) PDU(broadcast_sm_resp, 0x80000111, HEADER NULTERMINATED(message_id, 65) OPTIONAL_BEGIN TLV_INTEGER(broadcast_error_status, 4) TLV_OCTETS(failed_broadcast_area_identifier, 1, 101) OPTIONAL_END ) PDU(query_broadcast_sm, 0x00000112, HEADER NULTERMINATED(message_id, 65) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) OPTIONAL_BEGIN TLV_INTEGER(user_message_reference, 2) OPTIONAL_END ) PDU(query_broadcast_sm_resp, 0x80000112, HEADER NULTERMINATED(message_id, 65) OPTIONAL_BEGIN TLV_INTEGER(message_state, 1) TLV_OCTETS(broadcast_area_identifier, 1, 101) TLV_INTEGER(broadcast_area_success, 1) //OPTIONAL_BEGIN TLV_NULTERMINATED(broadcast_end_time, 16) TLV_INTEGER(user_message_reference, 2) OPTIONAL_END ) PDU(cancel_broadcast_sm, 0x00000113, HEADER NULTERMINATED(service_type, 6) NULTERMINATED(message_id, 65) INTEGER(source_addr_ton, 1) INTEGER(source_addr_npi, 1) NULTERMINATED(source_addr, 21) OPTIONAL_BEGIN TLV_OCTETS(broadcast_content_type, 3, 3) TLV_INTEGER(user_message_reference, 2) OPTIONAL_END ) PDU(cancel_broadcast_sm_resp, 0x80000113, HEADER ) #undef PDU #undef INTEGER #undef NULTERMINATED #undef OCTETS #undef HEADER #undef OPTIONAL_BEGIN #undef TLV_INTEGER #undef TLV_NULTERMINATED #undef TLV_OCTETS #undef OPTIONAL_END gateway-1.4.5/gw/smsc/smsc_oisd.c0000644000175000017500000013500313227613126015402 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc.oisd.c - Driver for Sema Group SMS Center G8.1 (OIS 5.8) * using direct TCP/IP access interface * * Dariusz Markowicz 2002-2004 * * This code is based on the CIMD2 module design. * * References: * * [1] Sema SMSC Version G8.1 Open Interface Specification * document version 5.8, 18 January 2001, Sema Telecoms. */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "shared.h" #include "sms.h" #include "dlr.h" typedef struct privdata { Octstr *host; long port; long keepalive; Octstr *my_number; long validityperiod; int no_dlr; int socket; unsigned long send_seq; Octstr *inbuffer; List *received; time_t next_ping; List *outgoing_queue; SMSCConn *conn; int io_thread; int quitting; List *stopped; /* list-trick for suspend/isolate */ } PrivData; /* Microseconds before giving up on a request */ #define RESPONSE_TIMEOUT (10 * 1000000) #define RESULT_SUCCESS 0 enum { INVOKE = 0, RESULT = 1 }; /* Textual names for the operation codes defined by the OISD spec. */ /* If you make changes here, also change the operation table. */ enum { SUBMIT_SM = 0, STATUS_REPORT = 4, DELIVER_SM = 9, RETRIEVE_REQUEST = 11, /* Not a request; add to any request to make it a response */ RESPONSE = 50 }; static int isphonedigit(int c) { return isdigit(c) || c == '+' || c == '-'; } static int parm_valid_address(Octstr *value) { return octstr_check_range(value, 0, octstr_len(value), isphonedigit); } /***************************************************************************/ /* Some functions to look up information about operation codes */ /***************************************************************************/ static int operation_find(int operation); static Octstr *operation_name(int operation); static int operation_can_send(int operation); static int operation_can_receive(int operation); static const struct { char *name; int code; int can_send; int can_receive; } operations[] = { { "Submit SM", SUBMIT_SM, 1, 0 }, { "Status Report", STATUS_REPORT, 0, 1 }, { "Deliver SM", DELIVER_SM, 0, 1 }, { "Retrieve Request", RETRIEVE_REQUEST, 1, 0 }, { NULL, 0, 0, 0 } }; static int operation_find(int operation) { int i; for (i = 0; operations[i].name != NULL; i++) { if (operations[i].code == operation) return i; } return -1; } /* Return a human-readable representation of this operation code */ static Octstr *operation_name(int operation) { int i; i = operation_find(operation); if (i >= 0) return octstr_create(operations[i].name); if (operation >= RESPONSE) { i = operation_find(operation - RESPONSE); if (i >= 0) { Octstr *name = octstr_create(operations[i].name); octstr_append_cstr(name, " response"); return name; } } /* Put the operation number here when we have octstr_format */ return octstr_create("(unknown)"); } /* Return true if a OISD client may send this operation */ static int operation_can_send(int operation) { int i = operation_find(operation); if (i >= 0) return operations[i].can_send; /* If we can receive the request, then we can send the response. */ if (operation >= RESPONSE) return operation_can_receive(operation - RESPONSE); return 0; } /* Return true if a OISD server may send this operation */ static int operation_can_receive(int operation) { int i = operation_find(operation); if (i >= 0) return operations[i].can_receive; /* If we can send the request, then we can receive the response. */ if (operation >= RESPONSE) return operation_can_send(operation - RESPONSE); return 0; } /*************************************************************************** * Packet encoding/decoding functions. They handle packets at the octet * * level, and know nothing of the network. * ***************************************************************************/ struct packet { unsigned long opref; /* operation reference */ int operation; Octstr *data; /* Encoded packet */ }; /* A reminder that packets are created without a valid sequence number */ #define BOGUS_SEQUENCE 0 static Msg *oisd_accept_delivery_report_message(struct packet *request, SMSCConn *conn); static void packet_parse_header(struct packet *packet) { packet->opref = (octstr_get_char(packet->data, 3) << 24) | (octstr_get_char(packet->data, 2) << 16) | (octstr_get_char(packet->data, 1) << 8) | (octstr_get_char(packet->data, 0)); packet->operation = octstr_get_char(packet->data, 5); if (octstr_get_char(packet->data, 4) == 1) packet->operation += RESPONSE; } /* * Accept an Octstr containing one packet, build a struct packet around * it, and return that struct. The Octstr is stored in the struct. * No error checking is done here yet. */ static struct packet *packet_parse(Octstr *packet_data) { struct packet *packet; packet = gw_malloc(sizeof(*packet)); packet->data = packet_data; /* Fill in packet->operation and packet->opref */ packet_parse_header(packet); return packet; } /* Deallocate this packet */ static void packet_destroy(struct packet *packet) { if (packet != NULL) { octstr_destroy(packet->data); gw_free(packet); } } /* * Find the first packet in "in", delete it from "in", and return it as * a struct. Return NULL if "in" contains no packet. Always delete * leading non-packet data from "in". */ static struct packet *packet_extract(Octstr *in, SMSCConn *conn) { Octstr *packet; int size, i; static char s[4][4] = { { 0x01, 0x0b, 0x00, 0x00 }, { 0x01, 0x00, 0x00, 0x00 }, { 0x00, 0x04, 0x00, 0x00 }, { 0x00, 0x09, 0x00, 0x00 } }; /* msgtype, oper, 0, 0 */ char known_bytes[4]; if (octstr_len(in) < 10) return NULL; octstr_get_many_chars(known_bytes, in, 4, 4); /* Find s, and delete everything up to it. */ /* If packet starts with one of s, it should be good packet */ for (i = 0; i < 4; i++) { if (memcmp(s[i], known_bytes, 4) == 0) break; } if (i >= 4) { error(0, "OISD[%s]: wrong packet", octstr_get_cstr(conn->id)); octstr_dump(in, 0); return NULL; } /* Find end of packet */ size = (octstr_get_char(in, 9) << 8) | octstr_get_char(in, 8); if (size + 10 > octstr_len(in)) return NULL; packet = octstr_copy(in, 0, size + 10); octstr_delete(in, 0, size + 10); return packet_parse(packet); } static void packet_check_can_receive(struct packet *packet, SMSCConn *conn) { gw_assert(packet != NULL); if (!operation_can_receive(packet->operation)) { Octstr *name = operation_name(packet->operation); warning(0, "OISD[%s]: SMSC sent us %s request", octstr_get_cstr(conn->id), octstr_get_cstr(name)); octstr_destroy(name); } } static int oisd_expand_gsm7_to_bits(char *bits, Octstr *raw7) { int i, j, k; int len; char ch; len = octstr_len(raw7) * 7; /* number of bits in the gsm 7-bit msg */ for (j = i = 0; j < len; ++i) { ch = octstr_get_char(raw7, i); for (k = 0; k < 8; ++k) { bits[j++] = (char) (ch & 0x01); ch >>= 1; } } return j; } static char oisd_expand_gsm7_from_bits(const char *bits, int pos) { int i; char ch; pos *= 7; /* septet position in bits */ ch = '\0'; for (i = 6; i >= 0; --i) { ch <<= 1; ch |= bits[pos + i]; } return ch; } static Octstr *oisd_expand_gsm7(Octstr *raw7) { Octstr *raw8; int i, len; char *bits; raw8 = octstr_create(""); bits = gw_malloc(8 * octstr_len(raw7) + 1); oisd_expand_gsm7_to_bits(bits, raw7); len = octstr_len(raw7); for (i = 0; i < len; ++i) { octstr_append_char(raw8, oisd_expand_gsm7_from_bits(bits, i)); } gw_free(bits); return raw8; } static void oisd_shrink_gsm7(Octstr *str) { Octstr *result; int len, i; int numbits, value; result = octstr_create(""); len = octstr_len(str); value = 0; numbits = 0; for (i = 0; i < len; i++) { value += octstr_get_char(str, i) << numbits; numbits += 7; if (numbits >= 8) { octstr_append_char(result, value & 0xff); value >>= 8; numbits -= 8; } } if (numbits > 0) octstr_append_char(result, value); octstr_delete(str, 0, LONG_MAX); octstr_append(str, result); octstr_destroy(result); } /**************************************************************************** * Packet encoding functions. They do not allow the creation of invalid * OISD packets. ***************************************************************************/ /* Build a new packet struct with this operation code and sequence number. */ static struct packet *packet_create(int operation, unsigned long opref) { struct packet *packet; unsigned char header[10]; packet = gw_malloc(sizeof(*packet)); packet->operation = operation; packet->opref = opref; /* Opref */ header[0] = opref & 0xff; header[1] = (opref >> 8) & 0xff; header[2] = (opref >> 16) & 0xff; header[3] = (opref >> 24) & 0xff; /* Message Type & Operation */ if (operation > RESPONSE) { header[4] = RESULT; header[5] = operation - RESPONSE; } else { header[4] = INVOKE; header[5] = operation; } /* Unused */ header[6] = 0; header[7] = 0; /* Data Size */ header[8] = 0; header[9] = 0; packet->data = octstr_create_from_data((char *)header, 10); return packet; } static void packet_set_data_size(struct packet *packet) { int len; gw_assert(packet != NULL); len = octstr_len(packet->data) - 10; octstr_set_char(packet->data, 8, len & 0xff); /* Data Size */ octstr_set_char(packet->data, 9, (len >> 8) & 0xff); } static void packet_set_sequence(struct packet *packet, unsigned long opref) { gw_assert(packet != NULL); octstr_set_char(packet->data, 0, opref & 0xff); octstr_set_char(packet->data, 1, (opref >> 8) & 0xff); octstr_set_char(packet->data, 2, (opref >> 16) & 0xff); octstr_set_char(packet->data, 3, (opref >> 24) & 0xff); packet->opref = opref; } static struct packet *packet_encode_message(Msg *msg, SMSCConn *conn) { struct packet *packet; PrivData *pdata = conn->data; int DCS; int setvalidity = SMS_PARAM_UNDEFINED; int so = 0; int udhlen7, udhlen8; int msglen7, msglen8; Octstr *udhdata = NULL; Octstr *msgdata = NULL; gw_assert(msg != NULL); gw_assert(msg->type == sms); gw_assert(msg->sms.receiver != NULL); DCS = fields_to_dcs(msg, 0); if (msg->sms.sender == NULL) msg->sms.sender = octstr_create(""); if (!parm_valid_address(msg->sms.receiver)) { warning(0, "OISD[%s]: non-digits in destination phone number '%s', discarded", octstr_get_cstr(conn->id), octstr_get_cstr(msg->sms.receiver)); return NULL; } if (!parm_valid_address(msg->sms.sender)) { warning(0, "OISD[%s]: non-digits in originating phone number '%s', discarded", octstr_get_cstr(conn->id), octstr_get_cstr(msg->sms.sender)); return NULL; } packet = packet_create(SUBMIT_SM, BOGUS_SEQUENCE); gw_assert(octstr_check_range(msg->sms.receiver, 0, octstr_len(msg->sms.receiver), isphonedigit)); /* MSISDN length */ octstr_append_char(packet->data, (unsigned char) octstr_len(msg->sms.receiver)); /* MSISDN */ octstr_append(packet->data, msg->sms.receiver); /* Duplicate msg. behaviour */ /* 1=reject duplicates, 2=allow duplicates */ octstr_append_char(packet->data, 2); /* SME ref. no. unused in this protocol implementation, but set */ octstr_append_char(packet->data, 0); octstr_append_char(packet->data, 0); octstr_append_char(packet->data, 0); octstr_append_char(packet->data, 0); /* Priority 0=high, 1=normal */ octstr_append_char(packet->data, 1); gw_assert(octstr_check_range(msg->sms.sender, 0, octstr_len(msg->sms.sender), isphonedigit)); /* Originating address length */ octstr_append_char(packet->data, (unsigned char) (octstr_len(msg->sms.sender) + 2)); /* XXX: GSM operator dependent ? */ /* TON */ octstr_append_char(packet->data, 0x42); /* NPI */ octstr_append_char(packet->data, 0x44); /* Originating address */ octstr_append(packet->data, msg->sms.sender); /* Validity period type 0=none, 1=absolute, 2=relative */ /* * Validity-Period (TP-VP) * see GSM 03.40 section 9.2.3.12 */ if (msg->sms.validity != SMS_PARAM_UNDEFINED) setvalidity = (msg->sms.validity - time(NULL)) / 60; else if (setvalidity != SMS_PARAM_UNDEFINED) setvalidity = pdata->validityperiod; if (setvalidity != SMS_PARAM_UNDEFINED) { /* Validity period type 0=none, 1=absolute, 2=relative */ octstr_append_char(packet->data, 2); if (setvalidity > 635040) setvalidity = 255; else if (setvalidity >= 50400 && setvalidity <= 635040) setvalidity = (setvalidity - 1) / 7 / 24 / 60 + 192 + 1; else if (setvalidity > 43200 && setvalidity < 50400) setvalidity = 197; else if (setvalidity >= 2880 && setvalidity <= 43200) setvalidity = (setvalidity - 1) / 24 / 60 + 166 + 1; else if (setvalidity > 1440 && setvalidity < 2880) setvalidity = 168; else if (setvalidity >= 750 && setvalidity <= 1440) setvalidity = (setvalidity - 720 - 1) / 30 + 143 + 1; else if (setvalidity > 720 && setvalidity < 750) setvalidity = 144; else if (setvalidity >= 5 && setvalidity <= 720) setvalidity = (setvalidity - 1) / 5 - 1 + 1; else if (setvalidity < 5) setvalidity = 0; octstr_append_char(packet->data, setvalidity); } else { /* Validity period type 0=none, 1=absolute, 2=relative */ octstr_append_char(packet->data, 0); setvalidity = 0; /* reset */ } if (setvalidity >= 0 && setvalidity <= 143) debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d minutes", octstr_get_cstr(conn->id), (setvalidity + 1)*5); else if (setvalidity >= 144 && setvalidity <= 167) debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %3.1f hours", octstr_get_cstr(conn->id), ((float)(setvalidity - 143) / 2) + 12); else if (setvalidity >= 168 && setvalidity <= 196) debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d days", octstr_get_cstr(conn->id), (setvalidity - 166)); else debug("bb.smsc.oisd", 0, "OISD[%s]: Validity-Period: %d weeks", octstr_get_cstr(conn->id), (setvalidity - 192)); /* Data coding scheme */ octstr_append_char(packet->data, DCS); /* Explicitly ask not to get status reports. * If we do not do this, the server's default might be to * send status reports in some cases, and we don't do anything * with those reports anyway. */ /* ask for the delivery reports if needed*/ if (!pdata->no_dlr) if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask)) octstr_append_char(packet->data, 7); else octstr_append_char(packet->data, 0); else if (pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask)) warning(0, "OISD[%s]: dlr request make no sense while no-dlr set to true", octstr_get_cstr(conn->id)); /* Protocol id 0=default */ octstr_append_char(packet->data, 0); if (octstr_len(msg->sms.udhdata)) so |= 0x02; if (msg->sms.coding == DC_8BIT) so |= 0x10; /* Submission options */ octstr_append_char(packet->data, so); udhlen8 = octstr_len(msg->sms.udhdata); msglen8 = octstr_len(msg->sms.msgdata); udhdata = octstr_duplicate(msg->sms.udhdata); msgdata = octstr_duplicate(msg->sms.msgdata); if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) { debug("bb.sms.oisd", 0, "OISD[%s]: sending UTF-8=%s", octstr_get_cstr(conn->id), octstr_get_cstr(msg->sms.msgdata)); charset_utf8_to_gsm(msgdata); oisd_shrink_gsm7(msgdata); } /* calculate lengths */ udhlen7 = octstr_len(udhdata); msglen7 = octstr_len(msgdata); octstr_append_char(packet->data, (unsigned char) (udhlen8 + msglen8)); octstr_append_char(packet->data, (unsigned char) (udhlen7 + msglen7)); /* * debug("bb.sms.oisd", 0, "OISD[%s]: packet_encode_message udhlen8=%d, msglen8=%d", * octstr_get_cstr(conn->id), udhlen8, msglen8); * debug("bb.sms.oisd", 0, "OISD[%s]: packet_encode_message udhlen7=%d, msglen7=%d", * octstr_get_cstr(conn->id), udhlen7, msglen7); */ /* copy text */ octstr_append(packet->data, udhdata); octstr_append(packet->data, msgdata); /* Sub-logical SME number */ octstr_append_char(packet->data, 0); octstr_append_char(packet->data, 0); octstr_destroy(udhdata); octstr_destroy(msgdata); return packet; } /*************************************************************************** * Protocol functions. These implement various transactions. * ***************************************************************************/ /* Give this packet a proper sequence number for sending. */ static void packet_set_send_sequence(struct packet *packet, PrivData *pdata) { gw_assert(pdata != NULL); packet_set_sequence(packet, pdata->send_seq); pdata->send_seq++; } static struct packet *oisd_get_packet(PrivData *pdata, Octstr **ts) { struct packet *packet = NULL; gw_assert(pdata != NULL); /* If packet is already available, don't try to read anything */ packet = packet_extract(pdata->inbuffer, pdata->conn); while (packet == NULL) { if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) { warning(0, "OISD[%s]: SMSC is not responding", octstr_get_cstr(pdata->conn->id)); return NULL; } if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) { error(0, "OISD[%s]: oisd_get_packet: read failed", octstr_get_cstr(pdata->conn->id)); return NULL; } packet = packet_extract(pdata->inbuffer, pdata->conn); } packet_check_can_receive(packet, pdata->conn); debug("bb.sms.oisd", 0, "OISD[%s]: received", octstr_get_cstr(pdata->conn->id)); if (packet->operation != RETRIEVE_REQUEST + RESPONSE) octstr_dump(packet->data, 0); if (ts) *ts = octstr_copy(packet->data, 15, 14); if (pdata->keepalive > 0) pdata->next_ping = time(NULL) + pdata->keepalive; return packet; } /* * Acknowledge a request. */ static void oisd_send_response(struct packet *request, PrivData *pdata) { struct packet *response; gw_assert(request != NULL); gw_assert(request->operation < RESPONSE); response = packet_create(request->operation + RESPONSE, request->opref); octstr_append_char(response->data, (char) RESULT_SUCCESS); packet_set_data_size(response); debug("bb.sms.oisd", 0, "OISD[%s]: sending response", octstr_get_cstr(pdata->conn->id)); octstr_dump(response->data, 0); /* Don't check errors here because if there is something * wrong with the socket, the main loop will detect it. */ octstr_write_to_socket(pdata->socket, response->data); packet_destroy(response); } static Msg *oisd_accept_message(struct packet *request, SMSCConn *conn) { Msg *msg = NULL; int DCS; int dest_len; int origin_len; int add_info; int msglen7, msglen8; int udh_len; msg = msg_create(sms); /* See GSM 03.38. The bit patterns we can handle are: * 000xyyxx Uncompressed text, yy indicates alphabet. * yy = 00, default alphabet * yy = 01, 8-bit data * yy = 10, UCS-2 * yy = 11, reserved * 1111xyxx Data, y indicates alphabet. * y = 0, default alphabet * y = 1, 8-bit data */ /* Additional information * xxxxxxyz This field conveys additional information to assist * the recipient in interpreting the SM. * z = reply path * y = user data header indicator * x = reserved */ /* * Destination addr. and Originating addr. w/o TOA */ /* Destination addr. length */ dest_len = octstr_get_char(request->data, 10); /* Destination addr. */ msg->sms.receiver = octstr_copy(request->data, 11+2, dest_len-2); /* Originating addr. length */ origin_len = octstr_get_char(request->data, 11+dest_len+4); /* Originating addr. */ msg->sms.sender = octstr_copy(request->data, 11+dest_len+5+2, origin_len-2); DCS = octstr_get_char(request->data, 11+dest_len+5+origin_len); if (!dcs_to_fields(&msg, DCS)) { /* XXX: Should reject this message ? */ debug("bb.sms.oisd", 0, "OISD[%s]: Invalid DCS", octstr_get_cstr(conn->id)); dcs_to_fields(&msg, 0); } add_info = octstr_get_char(request->data,11+dest_len+5+origin_len+2); msglen7 = octstr_get_char(request->data, 11+dest_len+5+origin_len+3); msglen8 = octstr_get_char(request->data, 11+dest_len+5+origin_len+4); msg->sms.rpi = add_info & 0x01; debug("bb.sms.oisd", 0, "OISD[%s]: received DCS=%02X, add_info=%d, msglen7=%d, msglen8=%d, rpi=%ld", octstr_get_cstr(conn->id), DCS, add_info, msglen7, msglen8, msg->sms.rpi); if (msg->sms.coding == DC_7BIT) { msg->sms.msgdata = oisd_expand_gsm7(octstr_copy(request->data, 11+dest_len+5+origin_len+5, msglen7)); debug("bb.sms.oisd", 0, "OISD[%s]: received raw8=%s ", octstr_get_cstr(conn->id), octstr_get_cstr(msg->sms.msgdata)); if (add_info & 0x02) { warning(0, "OISD[%s]: 7-bit UDH ?", octstr_get_cstr(conn->id)); } else { charset_gsm_to_utf8(msg->sms.msgdata); debug("bb.sms.oisd", 0, "OISD[%s]: received UTF-8=%s", octstr_get_cstr(conn->id), octstr_get_cstr(msg->sms.msgdata)); } } else { /* 0xf4, 0xf5, 0xf6, 0xf7; 8bit to disp, mem, sim or term */ if (add_info & 0x02) { udh_len = octstr_get_char(request->data, 11+dest_len+5+origin_len+5)+1; msg->sms.msgdata = octstr_copy(request->data, 11+dest_len+5+origin_len+5+udh_len, msglen8); msg->sms.udhdata = octstr_copy(request->data, 11+dest_len+5+origin_len+5, udh_len); } else { msg->sms.msgdata = octstr_copy(request->data, 11+dest_len+5+origin_len+5, msglen8); } } /* Code elsewhere in the gateway always expects the sender and * receiver fields to be filled, so we discard messages that * lack them. If they should not be discarded, then the code * handling sms messages should be reviewed. -- RB */ if (!(msg->sms.receiver) || octstr_len(msg->sms.receiver) == 0) { info(0, "OISD[%s]: Got SMS without receiver, discarding.", octstr_get_cstr(conn->id)); goto error; } if (!(msg->sms.sender) || octstr_len(msg->sms.sender) == 0) { info(0, "OISD[%s]: Got SMS without sender, discarding.", octstr_get_cstr(conn->id)); goto error; } if ((!(msg->sms.msgdata) || octstr_len(msg->sms.msgdata) == 0) && (!(msg->sms.udhdata) || octstr_len(msg->sms.udhdata) == 0)) { msg->sms.msgdata = octstr_create(""); } return msg; error: msg_destroy(msg); return NULL; } /* Deal with a request from the OISD server, and acknowledge it. */ static void oisd_handle_request(struct packet *request, SMSCConn *conn) { PrivData *pdata = conn->data; Msg *msg = NULL; if (request->operation == STATUS_REPORT) { msg = oisd_accept_delivery_report_message(request, conn); if (msg) gwlist_append(pdata->received, msg); } else if (request->operation == DELIVER_SM) { msg = oisd_accept_message(request, conn); if (msg) gwlist_append(pdata->received, msg); } oisd_send_response(request, pdata); } /* Send a request and wait for the ack. If the other side responds with * an error code, attempt to correct and retry. * If other packets arrive while we wait for the ack, handle them. * * Return -1 if the SMSC refused the request. Return -2 for other * errors, such as being unable to send the request at all. If the * function returns -2, the caller would do well to try to reopen the * connection. * * The SMSCenter must be already open. */ static int oisd_request(struct packet *request, SMSCConn *conn, Octstr **ts) { PrivData *pdata = conn->data; int ret; struct packet *reply = NULL; int errorcode; int tries = 0; Octstr *request_name; gw_assert(pdata != NULL); gw_assert(request != NULL); gw_assert(operation_can_send(request->operation)); if (pdata->socket < 0) { warning(0, "OISD[%s]: oisd_request: socket not open.", octstr_get_cstr(conn->id)); return -2; } packet_set_data_size(request); retransmit: packet_set_send_sequence(request, pdata); request_name = operation_name(request->operation); debug("bb.sms.oisd", 0, "OISD[%s]: sending %s request", octstr_get_cstr(conn->id), octstr_get_cstr(request_name)); octstr_destroy(request_name); if (request->operation != RETRIEVE_REQUEST) octstr_dump(request->data, 0); ret = octstr_write_to_socket(pdata->socket, request->data); if (ret < 0) goto io_error; next_reply: packet_destroy(reply); /* destroy old, if any */ reply = oisd_get_packet(pdata, ts); if (!reply) goto io_error; /* The server sent us a request. Handle it, then wait for * a new reply. */ if (reply->operation < RESPONSE) { oisd_handle_request(reply, conn); goto next_reply; } if (reply->opref != request->opref) { /* We got a response to a different request number than * what we send. Strange. */ warning(0, "OISD[%s]: response had unexpected sequence number; ignoring.", octstr_get_cstr(conn->id)); goto next_reply; } if (reply->operation != request->operation + RESPONSE) { /* We got a response that didn't match our request */ Octstr *request_name = operation_name(request->operation); Octstr *reply_name = operation_name(reply->operation); warning(0, "OISD[%s]: %s request got a %s", octstr_get_cstr(conn->id), octstr_get_cstr(request_name), octstr_get_cstr(reply_name)); octstr_destroy(request_name); octstr_destroy(reply_name); octstr_dump(reply->data, 0); goto retry; } errorcode = octstr_get_char(reply->data, 10); /* Result */ if (errorcode > 0) goto error; /* The reply passed all the checks... looks like the SMSC accepted * our request! */ packet_destroy(reply); return 0; io_error: packet_destroy(reply); return -2; error: packet_destroy(reply); return -1; retry: if (++tries < 3) { warning(0, "OISD[%s]: Retransmitting (take %d)", octstr_get_cstr(conn->id), tries); goto retransmit; } warning(0, "OISD[%s]: Giving up.", octstr_get_cstr(conn->id)); goto io_error; } /* Close the SMSC socket without fanfare. */ static void oisd_close_socket(PrivData *pdata) { gw_assert(pdata != NULL); if (pdata->socket < 0) return; if (close(pdata->socket) < 0) warning(errno, "OISD[%s]: error closing socket", octstr_get_cstr(pdata->conn->id)); pdata->socket = -1; } /* * Open a socket to the SMSC, send a login packet, and wait for ack. * This may block. Return 0 for success, or -1 for failure. * Make sure the socket is closed before calling this function, otherwise * we will leak fd's. */ static int oisd_login(SMSCConn *conn) { PrivData *pdata = conn->data; struct packet *packet = NULL; gw_assert(pdata != NULL); if (pdata->socket >= 0) { warning(0, "OISD[%s]: login: socket was already open; closing", octstr_get_cstr(conn->id)); oisd_close_socket(pdata); } pdata->socket = tcpip_connect_to_server( octstr_get_cstr(pdata->host), pdata->port, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL)); if (pdata->socket != -1) { info(0, "OISD[%s] logged in.", octstr_get_cstr(conn->id)); return 0; } error(0, "OISD[%s] login failed.", octstr_get_cstr(conn->id)); oisd_close_socket(pdata); packet_destroy(packet); return -1; } static int oisd_send_delivery_request(SMSCConn *conn) { PrivData *pdata = conn->data; struct packet *packet = NULL; int ret; gw_assert(conn != NULL); packet = packet_create(RETRIEVE_REQUEST, BOGUS_SEQUENCE); gw_assert(octstr_check_range(pdata->my_number, 0, octstr_len(pdata->my_number), isphonedigit)); /* Originating address length */ octstr_append_char(packet->data, (char) (octstr_len(pdata->my_number) + 2)); /* TON */ octstr_append_char(packet->data, 0x42); /* NPI */ octstr_append_char(packet->data, 0x44); /* Originating address */ octstr_append(packet->data, pdata->my_number); /* Receive ready flag */ octstr_append_char(packet->data, 1); /* Retrieve order */ octstr_append_char(packet->data, 0); ret = oisd_request(packet, conn, NULL); packet_destroy(packet); if (ret < 0) warning(0, "OISD[%s]: Sending delivery request failed.\n", octstr_get_cstr(conn->id)); return ret; } static void oisd_destroy(PrivData *pdata) { int discarded; if (pdata == NULL) return; octstr_destroy(pdata->host); octstr_destroy(pdata->inbuffer); octstr_destroy(pdata->my_number); discarded = gwlist_len(pdata->received); if (discarded > 0) warning(0, "OISD[%s]: discarded %d received messages", octstr_get_cstr(pdata->conn->id), discarded); gwlist_destroy(pdata->received, msg_destroy_item); gwlist_destroy(pdata->outgoing_queue, NULL); gwlist_destroy(pdata->stopped, NULL); gw_free(pdata); } static int oisd_submit_msg(SMSCConn *conn, Msg *msg) { PrivData *pdata = conn->data; struct packet *packet; Octstr *ts = NULL; int ret; gw_assert(pdata != NULL); debug("bb.sms.oisd", 0, "OISD[%s]: sending message", octstr_get_cstr(conn->id)); packet = packet_encode_message(msg, conn); if (!packet) { /* This is a protocol error. Does this help? I doubt.. * But nevermind that. */ bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED")); return -1; } ret = oisd_request(packet, conn, &ts); if((ret == 0) && (ts) && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask) && !pdata->no_dlr) { dlr_add(conn->name, ts, msg, 0); } octstr_destroy(ts); packet_destroy(packet); if (ret == -1) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED")); } else if (ret == -2) { oisd_close_socket(pdata); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(conn->flow_mutex); } else { bb_smscconn_sent(conn, msg, NULL); } return ret; } static int oisd_receive_msg(SMSCConn *conn, Msg **msg) { PrivData *pdata = conn->data; long ret; struct packet *packet; gw_assert(pdata != NULL); if (gwlist_len(pdata->received) > 0) { *msg = gwlist_consume(pdata->received); return 1; } if (pdata->socket < 0) { /* XXX We have to assume that smsc_send_message is * currently trying to reopen, so we have to make * this thread wait. It should be done in a nicer * way. */ return 0; } ret = read_available(pdata->socket, 0); if (ret == 0) { if (pdata->keepalive > 0 && pdata->next_ping < time(NULL)) { if (oisd_send_delivery_request(conn) < 0) return -1; } return 0; } if (ret < 0) { warning(errno, "OISD[%s]: oisd_receive_msg: read_available failed", octstr_get_cstr(conn->id)); return -1; } /* We have some data waiting... see if it is an sms delivery. */ ret = octstr_append_from_socket(pdata->inbuffer, pdata->socket); if (ret == 0) { warning(0, "OISD[%s]: oisd_receive_msg: service center closed connection.", octstr_get_cstr(conn->id)); return -1; } if (ret < 0) { warning(0, "OISD[%s]: oisd_receive_msg: read failed", octstr_get_cstr(conn->id)); return -1; } for (;;) { packet = packet_extract(pdata->inbuffer, conn); if (!packet) break; packet_check_can_receive(packet, conn); debug("bb.sms.oisd", 0, "OISD[%s]: received", octstr_get_cstr(pdata->conn->id)); octstr_dump(packet->data, 0); if (packet->operation < RESPONSE) oisd_handle_request(packet, conn); else { error(0, "OISD[%s]: oisd_receive_msg: unexpected response packet", octstr_get_cstr(conn->id)); octstr_dump(packet->data, 0); } packet_destroy(packet); } if (gwlist_len(pdata->received) > 0) { *msg = gwlist_consume(pdata->received); return 1; } return 0; } static Msg *oisd_accept_delivery_report_message(struct packet *request, SMSCConn *conn) { Msg *msg = NULL; Octstr *destination = NULL; Octstr *timestamp = NULL; int st_code; int code; int dest_len; /* MSISDN length */ dest_len = octstr_get_char(request->data, 10); /* MSISDN */ destination = octstr_copy(request->data, 10+1, dest_len); /* Accept time */ timestamp = octstr_copy(request->data, 10+1+dest_len+1+4+4, 14); /* SM status */ st_code = octstr_get_char(request->data, 10+1+dest_len+1+4+4+14); switch (st_code) { case 1: case 2: code = DLR_FAIL; break; case 3: /* success */ code = DLR_SUCCESS; break; case 4: case 5: case 6: default: code = 0; } if (code) msg = dlr_find(conn->name, timestamp, destination, code, 0); octstr_destroy(destination); octstr_destroy(timestamp); return msg; } static Msg *sms_receive(SMSCConn *conn) { PrivData *pdata = conn->data; int ret; Msg *newmsg = NULL; ret = oisd_receive_msg(conn, &newmsg); if (ret == 1) { /* if any smsc_id available, use it */ newmsg->sms.smsc_id = octstr_duplicate(conn->id); return newmsg; } else if (ret == 0) { /* no message, just retry... */ return NULL; } /* error. reconnect. */ msg_destroy(newmsg); mutex_lock(conn->flow_mutex); oisd_close_socket(pdata); conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(conn->flow_mutex); return NULL; } static void io_thread (void *arg) { Msg *msg; SMSCConn *conn = arg; PrivData *pdata = conn->data; double sleep = 0.0001; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* remove messages from SMSC until we are killed */ while (!pdata->quitting) { gwlist_consume(pdata->stopped); /* block here if suspended/isolated */ /* check that connection is active */ if (conn->status != SMSCCONN_ACTIVE) { if (oisd_login(conn) != 0) { error(0, "OISD[%s]: Couldn't connect to SMSC (retrying in %ld seconds).", octstr_get_cstr(conn->id), conn->reconnect_delay); gwthread_sleep(conn->reconnect_delay); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); continue; } mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); bb_smscconn_connected(conn); mutex_unlock(conn->flow_mutex); } /* receive messages */ do { msg = sms_receive(conn); if (msg) { sleep = 0; debug("bb.sms.oisd", 0, "OISD[%s]: new message received", octstr_get_cstr(conn->id)); bb_smscconn_receive(conn, msg); } } while (msg); /* send messages */ do { msg = gwlist_extract_first(pdata->outgoing_queue); if (msg) { sleep = 0; if (oisd_submit_msg(conn, msg) != 0) break; } } while (msg); if (sleep > 0) { /* note that this implementations means that we sleep even * when we fail connection.. but time is very short, anyway */ gwthread_sleep(sleep); /* gradually sleep longer and longer times until something starts to * happen - this of course reduces response time, but that's better than * extensive CPU usage when it is not used */ sleep *= 2; if (sleep >= 2.0) sleep = 1.999999; } else { sleep = 0.0001; } } } static int oisd_add_msg_cb (SMSCConn *conn, Msg *sms) { PrivData *pdata = conn->data; Msg *copy; copy = msg_duplicate(sms); gwlist_produce(pdata->outgoing_queue, copy); gwthread_wakeup(pdata->io_thread); return 0; } static int oisd_shutdown_cb (SMSCConn *conn, int finish_sending) { PrivData *pdata = conn->data; debug("bb.sms", 0, "Shutting down SMSCConn OISD %s (%s)", octstr_get_cstr(conn->id), finish_sending ? "slow" : "instant"); /* Documentation claims this would have been done by smscconn.c, but isn't when this code is being written. */ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; pdata->quitting = 1; /* Separate from why_killed to avoid locking, as * why_killed may be changed from outside? */ if (finish_sending == 0) { Msg *msg; while ((msg = gwlist_extract_first(pdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } } if (conn->is_stopped) { gwlist_remove_producer(pdata->stopped); conn->is_stopped = 0; } if (pdata->io_thread != -1) { gwthread_wakeup(pdata->io_thread); gwthread_join(pdata->io_thread); } oisd_close_socket(pdata); oisd_destroy(pdata); debug("bb.sms", 0, "SMSCConn OISD %s shut down.", octstr_get_cstr(conn->id)); conn->status = SMSCCONN_DEAD; bb_smscconn_killed(); return 0; } static void oisd_start_cb (SMSCConn *conn) { PrivData *pdata = conn->data; gwlist_remove_producer(pdata->stopped); /* in case there are messages in the buffer already */ gwthread_wakeup(pdata->io_thread); debug("bb.sms", 0, "SMSCConn OISD %s, start called", octstr_get_cstr(conn->id)); } static void oisd_stop_cb (SMSCConn *conn) { PrivData *pdata = conn->data; gwlist_add_producer(pdata->stopped); debug("bb.sms", 0, "SMSCConn OISD %s, stop called", octstr_get_cstr(conn->id)); } static long oisd_queued_cb (SMSCConn *conn) { PrivData *pdata = conn->data; conn->load = (pdata ? (conn->status != SMSCCONN_DEAD ? gwlist_len(pdata->outgoing_queue) : 0) : 0); return conn->load; } int smsc_oisd_create(SMSCConn *conn, CfgGroup *grp) { PrivData *pdata; int ok; pdata = gw_malloc(sizeof(PrivData)); conn->data = pdata; pdata->conn = conn; pdata->no_dlr = 0; pdata->quitting = 0; pdata->socket = -1; pdata->received = gwlist_create(); pdata->inbuffer = octstr_create(""); pdata->send_seq = 1; pdata->outgoing_queue = gwlist_create(); pdata->stopped = gwlist_create(); gwlist_add_producer(pdata->outgoing_queue); if (conn->is_stopped) gwlist_add_producer(pdata->stopped); pdata->host = cfg_get(grp, octstr_imm("host")); if (cfg_get_integer(&(pdata->port), grp, octstr_imm("port")) == -1) pdata->port = 0; pdata->my_number = cfg_get(grp, octstr_imm("my-number")); if (cfg_get_integer(&(pdata->keepalive), grp, octstr_imm("keepalive")) == -1) pdata->keepalive = 0; if (cfg_get_integer(&(pdata->validityperiod), grp, octstr_imm("validityperiod")) == -1) pdata->validityperiod = SMS_PARAM_UNDEFINED; cfg_get_bool(&pdata->no_dlr, grp, octstr_imm("no-dlr")); /* Check that config is OK */ ok = 1; if (pdata->host == NULL) { error(0, "OISD[%s]: Configuration file doesn't specify host", octstr_get_cstr(conn->id)); ok = 0; } if (pdata->port == 0) { error(0, "OISD[%s]: Configuration file doesn't specify port", octstr_get_cstr(conn->id)); ok = 0; } if (pdata->my_number == NULL && pdata->keepalive > 0) { error(0, "OISD[%s]: Configuration file doesn't specify my-number.", octstr_get_cstr(conn->id)); ok = 0; } if (!ok) { oisd_destroy(pdata); return -1; } conn->name = octstr_format("OISD:%s:%d", octstr_get_cstr(pdata->host), pdata->port); if (pdata->keepalive > 0) { debug("bb.sms.oisd", 0, "OISD[%s]: Keepalive set to %ld seconds", octstr_get_cstr(conn->id), pdata->keepalive); pdata->next_ping = time(NULL) + pdata->keepalive; } if (pdata->validityperiod > 0) { debug("bb.sms.oisd", 0, "OISD[%s]: Validity-Period set to %ld", octstr_get_cstr(conn->id), pdata->validityperiod); } pdata->io_thread = gwthread_create(io_thread, conn); if (pdata->io_thread == -1) { error(0, "OISD[%s]: Couldn't start I/O thread.", octstr_get_cstr(conn->id)); pdata->quitting = 1; gwthread_wakeup(pdata->io_thread); gwthread_join(pdata->io_thread); oisd_destroy(pdata); return -1; } conn->send_msg = oisd_add_msg_cb; conn->shutdown = oisd_shutdown_cb; conn->queued = oisd_queued_cb; conn->start_conn = oisd_start_cb; conn->stop_conn = oisd_stop_cb; return 0; } gateway-1.4.5/gw/smsc/smpp_pdu.c0000644000175000017500000011372013227613126015250 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smpp_pdu.c - parse and generate SMPP PDUs * * Lars Wirzenius * Alexander Malysh : * Extended optional parameters implementation. */ #include #include "smpp_pdu.h" #define MIN_SMPP_PDU_LEN (4*4) /* old value was (1024). We need more because message_payload can be up to 64K octets*/ #define MAX_SMPP_PDU_LEN (7424) /* we use ; in the middle because ; is split char in smsc-id and can't be in the smsc-id */ #define DEFAULT_SMSC_ID "def;ault" struct smpp_tlv { Octstr *name; long tag; long length; Octstr *constant; enum { SMPP_TLV_OCTETS = 0, SMPP_TLV_NULTERMINATED = 1, SMPP_TLV_INTEGER = 2 } type; }; /* Dict(smsc_id, Dict(tag, tlv)) */ static Dict *tlvs_by_tag; /* Dict(smsc_id, Dict(tag_name, tlv)) */ static Dict *tlvs_by_name; static Dict *tlvs_by_const; static List *tlvs; static int initialized; static void smpp_tlv_destroy(struct smpp_tlv *tlv) { if (tlv == NULL) return; octstr_destroy(tlv->name); octstr_destroy(tlv->constant); gw_free(tlv); } void smpp_tlv_add_constant(Octstr *smsc_id, Dict **tlvs) { Dict *constant; List *keys; Octstr *key; struct smpp_tlv *tlv; constant = dict_get(tlvs_by_const, smsc_id); if (constant == NULL) return; keys = dict_keys(constant); while ((key = gwlist_extract_first(keys)) != NULL) { /* only add if not available already */ tlv = dict_get(constant, key); if (tlv && tlv->constant) { if (*tlvs) { if (dict_get(*tlvs, key) == NULL) dict_put(*tlvs, key, octstr_duplicate(tlv->constant)); } else { *tlvs = dict_create(1024, octstr_destroy_item); dict_put(*tlvs, key, octstr_duplicate(tlv->constant)); } } octstr_destroy(key); } gwlist_destroy(keys, NULL); } static struct smpp_tlv *smpp_tlv_get_by_name(Octstr *smsc_id, Octstr *name) { struct smpp_tlv *res = NULL; Dict *tmp_dict; if (tlvs_by_name == NULL || name == NULL) return NULL; if (smsc_id != NULL) { tmp_dict = dict_get(tlvs_by_name, smsc_id); if (tmp_dict != NULL) res = dict_get(tmp_dict, name); } if (res == NULL) { /* try default smsc_id */ smsc_id = octstr_imm(DEFAULT_SMSC_ID); tmp_dict = dict_get(tlvs_by_name, smsc_id); if (tmp_dict != NULL) res = dict_get(tmp_dict, name); } return res; } static struct smpp_tlv *smpp_tlv_get_by_tag(Octstr *smsc_id, long tag) { struct smpp_tlv *res = NULL; Dict *tmp_dict; Octstr *tmp; if (tlvs_by_tag == NULL) return NULL; tmp = octstr_format("%ld", tag); if (smsc_id != NULL) { tmp_dict = dict_get(tlvs_by_tag, smsc_id); if (tmp_dict != NULL) res = dict_get(tmp_dict, tmp); } if (res == NULL) { /* try default smsc_id */ smsc_id = octstr_imm(DEFAULT_SMSC_ID); tmp_dict = dict_get(tlvs_by_tag, smsc_id); if (tmp_dict != NULL) res = dict_get(tmp_dict, tmp); } octstr_destroy(tmp); return res; } int smpp_pdu_init(Cfg *cfg) { CfgGroup *grp; List *l; if (initialized) return 0; l = cfg_get_multi_group(cfg, octstr_imm("smpp-tlv")); tlvs = gwlist_create(); tlvs_by_tag = dict_create(1024, (void(*)(void*))dict_destroy); tlvs_by_name = dict_create(1024, (void(*)(void*))dict_destroy); tlvs_by_const = dict_create(1024, (void(*)(void*))dict_destroy); while (l != NULL && (grp = gwlist_extract_first(l)) != NULL) { struct smpp_tlv *tlv; Octstr *tmp, *smsc_id; List *l2; tlv = gw_malloc(sizeof(*tlv)); if ((tlv->name = cfg_get(grp, octstr_imm("name"))) == NULL) { error(0, "SMPP: Unable to get name for smpp-tlv."); smpp_tlv_destroy(tlv); goto failed; } tlv->constant = cfg_get(grp, octstr_imm("const")); if (cfg_get_integer(&tlv->tag, grp, octstr_imm("tag")) == -1) { error(0, "SMPP: Unable to get tag for smpp-tlv."); smpp_tlv_destroy(tlv); goto failed; } if (cfg_get_integer(&tlv->length, grp, octstr_imm("length")) == -1) { error(0, "SMPP: Unable to get length for smpp-tlv."); smpp_tlv_destroy(tlv); goto failed; } if ((tmp = cfg_get(grp, octstr_imm("type"))) == NULL) { error(0, "SMPP: Unable to get type for smpp-tlv."); smpp_tlv_destroy(tlv); goto failed; } if (octstr_str_case_compare(tmp, "octetstring") == 0) tlv->type = SMPP_TLV_OCTETS; else if (octstr_str_case_compare(tmp, "nulterminated") == 0) tlv->type = SMPP_TLV_NULTERMINATED; else if (octstr_str_case_compare(tmp, "integer") == 0) tlv->type = SMPP_TLV_INTEGER; else { error(0, "SMPP: Unknown type for smpp-tlv: `%s'", octstr_get_cstr(tmp)); octstr_destroy(tmp); smpp_tlv_destroy(tlv); goto failed; } octstr_destroy(tmp); /* put to all TLVs */ gwlist_produce(tlvs, tlv); smsc_id = cfg_get(grp, octstr_imm("smsc-id")); if (smsc_id != NULL) { l2 = octstr_split(smsc_id, octstr_imm(";")); octstr_destroy(smsc_id); } else { l2 = gwlist_create(); gwlist_produce(l2, octstr_create(DEFAULT_SMSC_ID)); } while(l2 != NULL && (smsc_id = gwlist_extract_first(l2)) != NULL) { Dict *tmp_dict; debug("sms.smpp", 0, "adding smpp-tlv for smsc-id=%s", octstr_get_cstr(smsc_id)); /* name */ tmp_dict = dict_get(tlvs_by_name, smsc_id); if (tmp_dict == NULL) { tmp_dict = dict_create(1024, NULL); dict_put(tlvs_by_name, smsc_id, tmp_dict); } /* put into dict */ if (!dict_put_once(tmp_dict, tlv->name, tlv)) { error(0, "SMPP: Double TLV name %s found.", octstr_get_cstr(tlv->name)); octstr_destroy(smsc_id); goto failed; } /* tag */ tmp_dict = dict_get(tlvs_by_tag, smsc_id); if (tmp_dict == NULL) { tmp_dict = dict_create(1024, NULL); dict_put(tlvs_by_tag, smsc_id, tmp_dict); } tmp = octstr_format("%ld", tlv->tag); if (!dict_put_once(tmp_dict, tmp, tlv)) { error(0, "SMPP: Double TLV tag %s found.", octstr_get_cstr(tmp)); gwlist_destroy(l2, octstr_destroy_item); octstr_destroy(tmp); octstr_destroy(smsc_id); goto failed; } /* const */ if (tlv->constant != NULL) { tmp_dict = dict_get(tlvs_by_const, smsc_id); if (tmp_dict == NULL) { tmp_dict = dict_create(1024, NULL); dict_put(tlvs_by_const, smsc_id, tmp_dict); } if (!dict_put_once(tmp_dict, tlv->name, tlv)) { error(0, "SMPP: Double TLV name %s found.", octstr_get_cstr(tlv->name)); octstr_destroy(smsc_id); goto failed; } } octstr_destroy(tmp); octstr_destroy(smsc_id); } gwlist_destroy(l2, octstr_destroy_item); } gwlist_destroy(l, NULL); initialized = 1; return 0; failed: gwlist_destroy(tlvs, (void(*)(void*))smpp_tlv_destroy); dict_destroy(tlvs_by_tag); dict_destroy(tlvs_by_name); return -1; } int smpp_pdu_shutdown(void) { if (initialized == 0) return 0; initialized = 0; gwlist_destroy(tlvs, (void(*)(void*))smpp_tlv_destroy); tlvs = NULL; dict_destroy(tlvs_by_tag); dict_destroy(tlvs_by_name); tlvs_by_tag = tlvs_by_name = NULL; return 0; } static long decode_integer(Octstr *os, long pos, int octets) { unsigned long u; int i; if (octstr_len(os) < pos + octets) return -1; u = 0; for (i = 0; i < octets; ++i) u = (u << 8) | octstr_get_char(os, pos + i); return u; } static void append_encoded_integer(Octstr *os, unsigned long u, long octets) { long i; for (i = 0; i < octets; ++i) octstr_append_char(os, (u >> ((octets - i - 1) * 8)) & 0xFF); } static int copy_until_nul(const char *field_name, Octstr *os, long *pos, long max_octets, Octstr **data) { long nul; *data = NULL; nul = octstr_search_char(os, '\0', *pos); if (nul == -1) { warning(0, "SMPP: PDU NULL terminated string (%s) has no NULL.", field_name); return -1; } if (*pos + max_octets < nul) { error(0, "SMPP: PDU NULL terminated string (%s) longer than allowed.", field_name); return -1; } *data = (nul - *pos > 0) ? octstr_copy(os, *pos, nul - *pos) : NULL; *pos = nul + 1; return 0; } static int is_defined_field(long type, const char *field_name) { switch (type) { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) OCTETS(name, octets) #define TLV_NULTERMINATED(name, max_len) OCTETS(name, max_len) #define TLV_OCTETS(name, min_len, max_len) OCTETS(name, min_len) #define OPTIONAL_END #define INTEGER(name, octets) OCTETS(name, octets) #define NULTERMINATED(name, max_octets) OCTETS(name, max_octets) #define OCTETS(name, field_giving_octetst) \ if (strncmp(#name, field_name, sizeof(#name) - 1) == 0) \ return 1; #define PDU(name, id, fields) \ case id: { \ fields \ } break; #include "smpp_pdu.def" default: break; } return 0; } SMPP_PDU *smpp_pdu_create(unsigned long type, unsigned long seq_no) { SMPP_PDU *pdu; pdu = gw_malloc(sizeof(*pdu)); pdu->type = type; switch (type) { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) p->name = -1; #define TLV_NULTERMINATED(name, max_len) p->name = NULL; #define TLV_OCTETS(name, min_len, max_len) p->name = NULL; #define OPTIONAL_END p->tlv = dict_create(1024, octstr_destroy_item); #define INTEGER(name, octets) p->name = 0; #define NULTERMINATED(name, max_octets) p->name = NULL; #define OCTETS(name, field_giving_octetst) p->name = NULL; #define PDU(name, id, fields) \ case id: { \ struct name *p = &pdu->u.name; \ pdu->type_name = #name; \ fields \ p->command_id = type; \ p->sequence_number = seq_no; \ } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error."); gw_free(pdu); return NULL; } return pdu; } void smpp_pdu_destroy(SMPP_PDU *pdu) { if (pdu == NULL) return; switch (pdu->type) { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) p->name = -1; #define TLV_NULTERMINATED(name, max_octets) octstr_destroy(p->name); #define TLV_OCTETS(name, min_len, max_len) octstr_destroy(p->name); #define OPTIONAL_END dict_destroy(p->tlv); #define INTEGER(name, octets) p->name = 0; /* Make sure "p" is used */ #define NULTERMINATED(name, max_octets) octstr_destroy(p->name); #define OCTETS(name, field_giving_octets) octstr_destroy(p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error while destroying."); } gw_free(pdu); } Octstr *smpp_pdu_pack(Octstr *smsc_id, SMPP_PDU *pdu) { Octstr *os; Octstr *temp; os = octstr_create(""); gw_assert(pdu != NULL); /* * Fix lengths of octet string fields. */ switch (pdu->type) { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) #define TLV_NULTERMINATED(name, max_len) #define TLV_OCTETS(name, min_len, max_len) #define OPTIONAL_END #define INTEGER(name, octets) p = *(&p); #define NULTERMINATED(name, max_octets) p = *(&p); #define OCTETS(name, field_giving_octets) \ p->field_giving_octets = octstr_len(p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error while packing."); } switch (pdu->type) { #define TL(name, octets) \ append_encoded_integer(os, SMPP_##name, 2); \ append_encoded_integer(os, octets, 2); #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) \ if (p->name >= 0) { \ TL(name, octets); \ INTEGER(name, octets) \ } #define TLV_NULTERMINATED(name, max_len) \ if (p->name != NULL) { \ TL(name, (octstr_len(p->name) > max_len ? max_len : octstr_len(p->name) + 1)); \ NULTERMINATED(name, max_len) \ } #define TLV_OCTETS(name, min_len, max_len) \ if (p->name != NULL) { \ unsigned long len = octstr_len(p->name); \ if (len > max_len || len < min_len) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \ #name, len, min_len, max_len);\ } else { \ TL(name, len); \ octstr_append(os, p->name); \ } \ } #define OPTIONAL_END \ if (p->tlv != NULL) { \ Octstr *key; \ List *keys; \ struct smpp_tlv *tlv; \ keys = dict_keys(p->tlv); \ while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \ tlv = smpp_tlv_get_by_name(smsc_id, key); \ if (tlv == NULL) { \ if (!is_defined_field(pdu->type, octstr_get_cstr(key))) \ error(0, "SMPP: Unknown TLV `%s', don't send.", octstr_get_cstr(key)); \ octstr_destroy(key); \ continue; \ } \ switch(tlv->type) { \ case SMPP_TLV_INTEGER: { \ long val = atol(octstr_get_cstr(dict_get(p->tlv, key))); \ append_encoded_integer(os, tlv->tag, 2); \ append_encoded_integer(os, tlv->length, 2); \ append_encoded_integer(os, val, tlv->length); \ break; \ } \ case SMPP_TLV_OCTETS: \ case SMPP_TLV_NULTERMINATED: { \ Octstr *val = dict_get(p->tlv, key); \ unsigned long len = octstr_len(val); \ if (len > tlv->length) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %ld) dropped.", \ octstr_get_cstr(key), len, tlv->length);\ octstr_destroy(key); \ continue; \ } \ append_encoded_integer(os, tlv->tag, 2); \ if (tlv->type == SMPP_TLV_NULTERMINATED) \ append_encoded_integer(os, len + 1, 2); \ else \ append_encoded_integer(os, len, 2); \ octstr_append(os, val); \ if (tlv->type == SMPP_TLV_NULTERMINATED) \ octstr_append_char(os, '\0'); \ break; \ } \ default: \ panic(0, "SMPP: Internal error, unknown configured TLV type %d.", tlv->type); \ break; \ } \ octstr_destroy(key); \ } \ gwlist_destroy(keys, octstr_destroy_item); \ } #define INTEGER(name, octets) \ append_encoded_integer(os, p->name, octets); #define NULTERMINATED(name, max_octets) \ if (p->name != NULL) { \ if (octstr_len(p->name) >= max_octets) { \ warning(0, "SMPP: PDU element <%s> too long " \ "(length is %ld, should be %d)", \ #name, octstr_len(p->name), max_octets-1); \ temp = octstr_copy(p->name, 0, max_octets-1); \ } else \ temp = octstr_duplicate(p->name); \ octstr_append(os, temp); \ octstr_destroy(temp); \ } \ octstr_append_char(os, '\0'); #define OCTETS(name, field_giving_octets) \ if (p->name) octstr_append(os, p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type 0x%08lx, internal error while packing.", pdu->type); break; } temp = octstr_create(""); append_encoded_integer(temp, octstr_len(os) + 4, 4); octstr_insert(os, temp, 0); octstr_destroy(temp); return os; } SMPP_PDU *smpp_pdu_unpack(Octstr *smsc_id, Octstr *data_without_len) { SMPP_PDU *pdu; unsigned long type; long len, pos; len = octstr_len(data_without_len); if (len < 4) { error(0, "SMPP: PDU was too short (%ld bytes).", octstr_len(data_without_len)); return NULL; } /* get the PDU type */ if ((type = decode_integer(data_without_len, 0, 4)) == -1) return NULL; /* create a coresponding representation structure */ pdu = smpp_pdu_create(type, 0); if (pdu == NULL) return NULL; pos = 0; switch (type) { #define OPTIONAL_BEGIN \ { /* Read optional parameters */ \ while (pos + 4 <= len) { \ struct smpp_tlv *tlv; \ unsigned long opt_tag, opt_len; \ opt_tag = decode_integer(data_without_len, pos, 2); pos += 2; \ debug("sms.smpp", 0, "Optional parameter tag (0x%04lx)", opt_tag); \ opt_len = decode_integer(data_without_len, pos, 2); pos += 2; \ debug("sms.smpp", 0, "Optional parameter length read as %ld", opt_len); \ /* check configured TLVs */ \ tlv = smpp_tlv_get_by_tag(smsc_id, opt_tag); \ if (tlv != NULL) debug("sms.smpp", 0, "Found configured optional parameter `%s'", octstr_get_cstr(tlv->name)); #define TLV_INTEGER(mname, octets) \ if (SMPP_##mname == opt_tag) { \ /* check length */ \ if (opt_len > octets) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #mname, opt_len); \ pos += opt_len; \ continue; \ } \ INTEGER(mname, opt_len); \ if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_format("%ld", p->mname)); \ } else #define TLV_NULTERMINATED(mname, max_len) \ if (SMPP_##mname == opt_tag) { \ /* check length */ \ if (opt_len > max_len || pos+opt_len > len) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) dropped.", #mname, opt_len); \ pos += opt_len; \ continue; \ } \ if(p->mname != NULL) { \ warning(0, "SMPP: Optional field (%s) was sent more than once, overwriting", #mname); \ octstr_destroy(p->mname); \ p->mname = NULL; \ } \ copy_until_nul(#mname, data_without_len, &pos, opt_len, &p->mname); \ if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_duplicate(p->mname)); \ } else #define TLV_OCTETS(mname, min_len, max_len) \ if (SMPP_##mname == opt_tag) { \ /* check length */ \ if (opt_len < min_len || opt_len > max_len || pos + opt_len > len) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %d - %d) dropped.", \ #mname, opt_len, min_len, max_len); \ pos += opt_len; \ continue; \ } \ if(p->mname != NULL) { \ warning(0, "SMPP: Optional field (%s) was sent more than once, overwriting", #mname); \ octstr_destroy(p->mname); \ p->mname = NULL; \ } \ p->mname = octstr_copy(data_without_len, pos, opt_len); \ pos += opt_len; \ if (tlv != NULL) dict_put(p->tlv, tlv->name, octstr_duplicate(p->mname)); \ } else #define OPTIONAL_END \ { \ Octstr *val = NULL; \ if (tlv != NULL) { \ /* found configured tlv */ \ /* check length */ \ if (opt_len > tlv->length) { \ error(0, "SMPP: Optional field (%s) with invalid length (%ld) (should be %ld) dropped.", \ octstr_get_cstr(tlv->name), opt_len, tlv->length); \ pos += opt_len; \ continue; \ } \ switch (tlv->type) { \ case SMPP_TLV_INTEGER: { \ long val_i; \ if ((val_i = decode_integer(data_without_len, pos, opt_len)) == -1) \ goto err; \ val = octstr_format("%ld", val_i); \ dict_put(p->tlv, tlv->name, val); \ pos += opt_len; \ break; \ } \ case SMPP_TLV_OCTETS: { \ val = octstr_copy(data_without_len, pos, opt_len); \ dict_put(p->tlv, tlv->name, val); \ pos += opt_len; \ break; \ } \ case SMPP_TLV_NULTERMINATED: { \ if (copy_until_nul(octstr_get_cstr(tlv->name), data_without_len, &pos, opt_len, &val) == 0) \ dict_put(p->tlv, tlv->name, val); \ break; \ } \ default: \ panic(0, "SMPP: Internal error, unknown configured TLV type %d.", tlv->type); \ break; \ } \ } else { \ val = octstr_copy(data_without_len, pos, opt_len); \ if (val) \ octstr_binary_to_hex(val, 0); \ else \ val = octstr_create(""); \ warning(0, "SMPP: Unknown TLV(0x%04lx,0x%04lx,%s) for PDU type (%s) received!", \ opt_tag, opt_len, octstr_get_cstr(val), pdu->type_name); \ octstr_destroy(val); \ pos += opt_len; \ } \ } \ } \ } #define INTEGER(name, octets) \ if ((p->name = decode_integer(data_without_len, pos, octets)) == -1) \ goto err; \ pos += octets; #define NULTERMINATED(name, max_octets) \ /* just warn about errors but not fail */ \ copy_until_nul(#name, data_without_len, &pos, max_octets, &p->name); #define OCTETS(name, field_giving_octets) \ p->name = octstr_copy(data_without_len, pos, \ p->field_giving_octets); \ if (p->field_giving_octets != (unsigned long) octstr_len(p->name)) { \ error(0, "smpp_pdu: error while unpacking '" #name "', " \ "len is %ld but should have been %ld, dropping.", \ octstr_len(p->name), p->field_giving_octets); \ goto err; \ } else { \ pos += p->field_giving_octets; \ } #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type 0x%08lx, internal error while unpacking.", type); break; } return pdu; err: smpp_pdu_destroy(pdu); octstr_dump(data_without_len, 0); return NULL; } void smpp_pdu_dump(Octstr *smsc_id, SMPP_PDU *pdu) { debug("sms.smpp", 0, "SMPP PDU %p dump:", (void *) pdu); debug("sms.smpp", 0, " type_name: %s", pdu->type_name); switch (pdu->type) { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, max_len) \ if (p->name != -1) { \ INTEGER(name, max_len) \ } #define TLV_NULTERMINATED(name, max_len) \ if (p->name != NULL) { \ NULTERMINATED(name, max_len) \ } #define TLV_OCTETS(name, min_len, max_len) \ if (p->name != NULL) { \ OCTETS(name, max_len) \ } #define OPTIONAL_END \ if (p->tlv != NULL) { \ List *keys; \ Octstr *key; \ struct smpp_tlv *tlv; \ keys = dict_keys(p->tlv); \ while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \ tlv = smpp_tlv_get_by_name(smsc_id, key); \ if (tlv != NULL) { \ octstr_dump_short(dict_get(p->tlv, key), 2, octstr_get_cstr(key)); \ } \ octstr_destroy(key); \ } \ gwlist_destroy(keys, octstr_destroy_item); \ } #define INTEGER(name, octets) \ debug("sms.smpp", 0, " %s: %lu = 0x%08lx", #name, p->name, p->name); #define NULTERMINATED(name, max_octets) \ octstr_dump_short(p->name, 2, #name); #define OCTETS(name, field_giving_octets) \ octstr_dump_short(p->name, 2, #name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error."); break; } debug("sms.smpp", 0, "SMPP PDU dump ends."); } void smpp_pdu_dump_line(Octstr *smsc_id, SMPP_PDU *pdu) { Octstr *str = octstr_create(""); octstr_format_append(str, "SMPP PDU %p dump: [type_name:%d:%s]", (void *) pdu, strlen(pdu->type_name), pdu->type_name); switch (pdu->type) { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, max_len) \ if (p->name != -1) { \ INTEGER(name, max_len) \ } #define TLV_NULTERMINATED(name, max_len) \ if (p->name != NULL) { \ NULTERMINATED(name, max_len) \ } #define TLV_OCTETS(name, min_len, max_len) \ if (p->name != NULL) { \ OCTETS(name, max_len) \ } #define OPTIONAL_END \ if (p->tlv != NULL) { \ List *keys; \ Octstr *key; \ struct smpp_tlv *tlv; \ keys = dict_keys(p->tlv); \ while(keys != NULL && (key = gwlist_extract_first(keys)) != NULL) { \ tlv = smpp_tlv_get_by_name(smsc_id, key); \ if (tlv != NULL) { \ Octstr *val = dict_get(p->tlv, key); \ octstr_format_append(str, " [%E:%d:%E]", key, octstr_len(val), val); \ } \ octstr_destroy(key); \ } \ gwlist_destroy(keys, octstr_destroy_item); \ } #define INTEGER(name, octets) \ octstr_format_append(str, " [%s:0:0x%08lx]", #name, p->name); #define NULTERMINATED(name, max_octets) \ octstr_format_append(str, " [%s:%d:%E]", #name, octstr_len(p->name), (p->name != NULL ? p->name : octstr_imm("NULL"))); #define OCTETS(name, field_giving_octets) \ octstr_format_append(str, " [%s:%d:%E]", #name, octstr_len(p->name), (p->name != NULL ? p->name : octstr_imm("NULL"))); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smpp_pdu.def" default: error(0, "Unknown SMPP_PDU type, internal error."); break; } debug("sms.smpp", 0, "%s", octstr_get_cstr(str)); octstr_destroy(str); } long smpp_pdu_read_len(Connection *conn) { Octstr *os; unsigned char buf[4]; /* The length is 4 octets. */ long len; os = conn_read_fixed(conn, sizeof(buf)); if (os == NULL) return 0; octstr_get_many_chars((char*) buf, os, 0, sizeof(buf)); octstr_destroy(os); len = decode_network_long(buf); if (len < MIN_SMPP_PDU_LEN) { error(0, "SMPP: PDU length was too small (%ld, minimum is %ld).", len, (long) MIN_SMPP_PDU_LEN); return -1; } if (len > MAX_SMPP_PDU_LEN) { error(0, "SMPP: PDU length was too large (%ld, maximum is %ld).", len, (long) MAX_SMPP_PDU_LEN); return -1; } return len; } Octstr *smpp_pdu_read_data(Connection *conn, long len) { Octstr *os; os = conn_read_fixed(conn, len - 4); /* `len' includes itself. */ return os; } /* * Return error string for given error code * NOTE: If you add new error strings here please use * error strings from SMPP spec. and please keep * error codes in switch statement sorted by error * code ID. */ const char *smpp_error_to_string(enum SMPP_ERROR_MESSAGES error) { switch (error) { case SMPP_ESME_ROK: return "OK"; case SMPP_ESME_RINVMSGLEN: return "Message Length is invalid"; case SMPP_ESME_RINVCMDLEN: return "Command Length is invalid"; case SMPP_ESME_RINVCMDID: return "Invalid Command ID"; case SMPP_ESME_RINVBNDSTS: return "Incorrect BIND Status for given command"; case SMPP_ESME_RALYBND: return "ESME Already in Bound State"; case SMPP_ESME_RINVPRTFLG: return "Invalid Priority Flag"; case SMPP_ESME_RINVREGDLVFLG: return "Invalid Registered Delivery Flag"; case SMPP_ESME_RSYSERR: return "System Error"; case SMPP_ESME_RINVSRCADR: return "Invalid Source Address"; case SMPP_ESME_RINVDSTADR: return "Invalid Destination Address"; case SMPP_ESME_RBINDFAIL: return "Bind Failed"; case SMPP_ESME_RINVPASWD: return "Invalid Password"; case SMPP_ESME_RINVSYSID: return "Invalid System ID"; case SMPP_ESME_RCANCELFAIL: return "Cancel SM Failed"; case SMPP_ESME_RREPLACEFAIL: return "Replace SM Failed"; case SMPP_ESME_RMSGQFUL: return "Message Queue Full"; case SMPP_ESME_RINVSERTYP: return "Invalid Service Type"; case SMPP_ESME_RINVNUMDESTS: return "Invalid number of destinations"; case SMPP_ESME_RINVDLNAME: return "Invalid Distribution List Name"; case SMPP_ESME_RINVDESTFLAG: return "Destination flag is invalid"; case SMPP_ESME_RINVSUBREP: return "Submit w/replace not supported/allowed"; case SMPP_ESME_RINVESMCLASS: return "Invalid esm_class field data"; case SMPP_ESME_RCNTSUBDL: return "Cannot Submit to Distribution List"; case SMPP_ESME_RSUBMITFAIL: return "Submit failed"; case SMPP_ESME_RINVSRCTON: return "Invalid Source address TON"; case SMPP_ESME_RINVSRCNPI: return "Invalid Source address NPI"; case SMPP_ESME_RINVDSTTON: return "Invalid Destination address TON"; case SMPP_ESME_RINVDSTNPI: return "Invalid Destination address NPI"; case SMPP_ESME_RINVSYSTYP: return "Invalid system_type field"; case SMPP_ESME_RINVREPFLAG: return "Invalid replace_if_present flag"; case SMPP_ESME_RINVNUMMSGS: return "Invalid number of messages"; case SMPP_ESME_RTHROTTLED: return "Throttling error"; case SMPP_ESME_RINVSCHED: return "Invalid Scheduled Delivery Time"; case SMPP_ESME_RINVEXPIRY: return "Invalid message validity period"; case SMPP_ESME_RINVDFTMSGID: return "Predefined Message ID is Invalid or specific predefined message was not found"; case SMPP_ESME_RX_T_APPN: return "ESME Receiver Temporary App Error Code"; case SMPP_ESME_RX_P_APPN: return "ESME Receiver Permanent App Error Code"; case SMPP_ESME_RX_R_APPN: return "ESME Receiver Reject Message Error Code"; case SMPP_ESME_RQUERYFAIL: return "query_sm request failed"; case SMPP_ESME_RINVTLVSTREAM: return "Error in optional part of the PDU Body"; case SMPP_ESME_RTLVNOTALLWD: return "TLV not allowed"; case SMPP_ESME_RINVTLVLEN: return "Invalid Parameter Length"; case SMPP_ESME_RMISSINGTLV: return "Expected TLV missing"; case SMPP_ESME_RINVTLVVAL: return "Invalid TLV value"; case SMPP_ESME_RDELIVERYFAILURE: return "Transaction Delivery Failure"; case SMPP_ESME_RUNKNOWNERR: return "Unknown Error"; case SMPP_ESME_RSERTYPUNAUTH: return "ESME Not authorized to use specified service_type"; case SMPP_ESME_RPROHIBITED: return "ESME Prohibited from using specified operation"; case SMPP_ESME_RSERTYPUNAVAIL: return "Specified service_type is unavailable"; case SMPP_ESME_RSERTYPDENIED: return "Specified service_type is denied"; case SMPP_ESME_RINVDCS: return "Invalid Data Coding Scheme"; case SMPP_ESME_RINVSRCADDRSUBUNIT: return "Source Address Sub unit is invalid"; case SMPP_ESME_RINVDSTADDRSUBUNIT: return "Destination Address Sub unit is invalid"; case SMPP_ESME_RINVBCASTFREQINT: return "Broadcast Frequency Interval is invalid"; case SMPP_ESME_RINVBCASTALIAS_NAME: return "Broadcast Alias Name is invalid"; case SMPP_ESME_RINVBCASTAREAFMT: return "Broadcast Area Format is invalid"; case SMPP_ESME_RINVNUMBCAST_AREAS: return "Number of Broadcast Areas is invalid"; case SMPP_ESME_RINVBCASTCNTTYPE: return "Broadcast Content Type is invalid"; case SMPP_ESME_RINVBCASTMSGCLASS: return "Broadcast Message Class is invalid"; case SMPP_ESME_RBCASTFAIL: return "broadcast_sm operation failed"; case SMPP_ESME_RBCASTQUERYFAIL: return "broadcast_query_sm operation failed"; case SMPP_ESME_RBCASTCANCELFAIL: return "broadcast_cancel_sm operation failed"; case SMPP_ESME_RINVBCAST_REP: return "Number of Repeated Broadcasts is invalid"; case SMPP_ESME_RINVBCASTSRVGRP: return "Broadcast Service Group is invalid"; case SMPP_ESME_RINVBCASTCHANIND: return "Broadcast Channel Indicator is invalid"; default: /* tell the user that we have a vendor-specific beast here */ if (error >= 0x0400 && error <= 0x04FF) return "Vendor-specific error, please refer to your SMPP provider"; else return "Unknown/Reserved"; } } gateway-1.4.5/gw/smsc/smsc_smpp.c0000644000175000017500000033645413250216757015445 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_smpp.c - SMPP v3.3, v3.4 and v5.0 implementation * * Lars Wirzenius * Stipe Tolj * Alexander Malysh */ /* XXX check SMSCConn conformance */ /* XXX UDH reception */ /* XXX check UDH sending fields esm_class and data_coding from GSM specs */ /* XXX charset conversions on incoming messages (didn't work earlier, either) */ /* XXX numbering plans and type of number: check spec */ #include "gwlib/gwlib.h" #include "msg.h" #include "smsc_p.h" #include "smpp_pdu.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "sms.h" #include "dlr.h" #include "bearerbox.h" #include "meta_data.h" #include "load.h" #define SMPP_DEFAULT_CHARSET "UTF-8" #define SMPP_DEFAULT_UCS2_CHARSET "UTF-16BE" enum smpp_pdu_dump_format { SMPP_PDU_DUMP_MULTILINE = 1, SMPP_PDU_DUMP_LINE = 2 }; /* * Select these based on whether you want to dump SMPP PDUs as they are * sent and received or not. Not dumping should be the default in at least * stable releases. */ #define DEBUG 1 #ifndef DEBUG #define dump_pdu(msg, id, pdu, format) do{}while(0) #else /** This version does dump. */ #define dump_pdu(msg, id, pdu, format) \ do { \ debug("bb.sms.smpp", 0, "SMPP[%s]: %s", \ octstr_get_cstr(id), msg); \ if (format == SMPP_PDU_DUMP_MULTILINE) \ smpp_pdu_dump(id, pdu); \ else \ smpp_pdu_dump_line(id, pdu); \ } while(0) #endif /* * Some defaults. */ #define SMPP_ENQUIRE_LINK_INTERVAL 30.0 #define SMPP_MAX_PENDING_SUBMITS 10 #define SMPP_DEFAULT_VERSION 0x34 #define SMPP_DEFAULT_PRIORITY 0 #define SMPP_THROTTLING_SLEEP_TIME 1 #define SMPP_DEFAULT_CONNECTION_TIMEOUT 10 * SMPP_ENQUIRE_LINK_INTERVAL #define SMPP_DEFAULT_WAITACK 60 #define SMPP_DEFAULT_SHUTDOWN_TIMEOUT 30 #define SMPP_DEFAULT_PORT 2775 /* * Some defines */ #define SMPP_WAITACK_RECONNECT 0x00 #define SMPP_WAITACK_REQUEUE 0x01 #define SMPP_WAITACK_NEVER_EXPIRE 0x02 /*********************************************************************** * Implementation of the actual SMPP protocol: reading and writing * PDUs in the correct order. */ typedef struct { long transmitter; long receiver; gw_prioqueue_t *msgs_to_send; Dict *sent_msgs; List *received_msgs; Counter *message_id_counter; Octstr *host; Octstr *system_type; Octstr *username; Octstr *password; Octstr *address_range; Octstr *my_number; Octstr *service_type; int source_addr_ton; int source_addr_npi; int dest_addr_ton; int dest_addr_npi; int our_port; int our_receiver_port; long bind_addr_ton; long bind_addr_npi; int transmit_port; int receive_port; int use_ssl; Octstr *ssl_client_certkey_file; volatile int quitting; long enquire_link_interval; long max_pending_submits; int version; int priority; /* set default priority for messages */ int validityperiod; time_t throttling_err_time; int smpp_msg_id_type; /* msg id in C string, hex or decimal */ int autodetect_addr; Octstr *alt_charset; Octstr *alt_addr_charset; long connection_timeout; long wait_ack; int wait_ack_action; int esm_class; long log_format; Load *load; SMSCConn *conn; } SMPP; struct smpp_msg { time_t sent_time; Msg *msg; }; /* * create smpp_msg struct */ static inline struct smpp_msg* smpp_msg_create(Msg *msg) { struct smpp_msg *result = gw_malloc(sizeof(struct smpp_msg)); gw_assert(result != NULL); result->sent_time = time(NULL); result->msg = msg; return result; } /* * destroy smpp_msg struct. If destroy_msg flag is set, then message will be freed as well */ static inline void smpp_msg_destroy(struct smpp_msg *msg, int destroy_msg) { /* sanity check */ if (msg == NULL) return; if (destroy_msg && msg->msg != NULL) msg_destroy(msg->msg); gw_free(msg); } static SMPP *smpp_create(SMSCConn *conn, Octstr *host, int transmit_port, int receive_port, int our_port, int our_receiver_port, Octstr *system_type, Octstr *username, Octstr *password, Octstr *address_range, int source_addr_ton, int source_addr_npi, int dest_addr_ton, int dest_addr_npi, int enquire_link_interval, int max_pending_submits, int version, int priority, int validity, Octstr *my_number, int smpp_msg_id_type, int autodetect_addr, Octstr *alt_charset, Octstr *alt_addr_charset, Octstr *service_type, long connection_timeout, long wait_ack, int wait_ack_action, int esm_class) { SMPP *smpp; smpp = gw_malloc(sizeof(*smpp)); smpp->transmitter = -1; smpp->receiver = -1; smpp->msgs_to_send = gw_prioqueue_create(sms_priority_compare); smpp->sent_msgs = dict_create(max_pending_submits, NULL); gw_prioqueue_add_producer(smpp->msgs_to_send); smpp->received_msgs = gwlist_create(); smpp->message_id_counter = counter_create(); counter_increase(smpp->message_id_counter); smpp->host = octstr_duplicate(host); smpp->system_type = octstr_duplicate(system_type); smpp->our_port = our_port; smpp->our_receiver_port = our_receiver_port; smpp->username = octstr_duplicate(username); smpp->password = octstr_duplicate(password); smpp->address_range = octstr_duplicate(address_range); smpp->source_addr_ton = source_addr_ton; smpp->source_addr_npi = source_addr_npi; smpp->dest_addr_ton = dest_addr_ton; smpp->dest_addr_npi = dest_addr_npi; smpp->my_number = octstr_duplicate(my_number); smpp->service_type = octstr_duplicate(service_type); smpp->transmit_port = transmit_port; smpp->receive_port = receive_port; smpp->enquire_link_interval = enquire_link_interval; smpp->max_pending_submits = max_pending_submits; smpp->quitting = 0; smpp->version = version; smpp->priority = priority; smpp->validityperiod = validity; smpp->conn = conn; smpp->throttling_err_time = 0; smpp->smpp_msg_id_type = smpp_msg_id_type; smpp->autodetect_addr = autodetect_addr; smpp->alt_charset = octstr_duplicate(alt_charset); smpp->alt_addr_charset = octstr_duplicate(alt_addr_charset); smpp->connection_timeout = connection_timeout; smpp->wait_ack = wait_ack; smpp->wait_ack_action = wait_ack_action; smpp->bind_addr_ton = 0; smpp->bind_addr_npi = 0; smpp->use_ssl = 0; smpp->ssl_client_certkey_file = NULL; smpp->load = load_create_real(0); load_add_interval(smpp->load, 1); smpp->esm_class = esm_class; return smpp; } static void smpp_destroy(SMPP *smpp) { if (smpp != NULL) { gw_prioqueue_destroy(smpp->msgs_to_send, msg_destroy_item); dict_destroy(smpp->sent_msgs); gwlist_destroy(smpp->received_msgs, msg_destroy_item); counter_destroy(smpp->message_id_counter); octstr_destroy(smpp->host); octstr_destroy(smpp->username); octstr_destroy(smpp->password); octstr_destroy(smpp->system_type); octstr_destroy(smpp->service_type); octstr_destroy(smpp->address_range); octstr_destroy(smpp->my_number); octstr_destroy(smpp->alt_charset); octstr_destroy(smpp->alt_addr_charset); octstr_destroy(smpp->ssl_client_certkey_file); load_destroy(smpp->load); gw_free(smpp); } } /* * Try to read an SMPP PDU from a Connection. Return -1 for error (caller * should close the connection), -2 for malformed PDU , 0 for no PDU to * ready yet, or 1 for PDU * read and unpacked. Return a pointer to the PDU in `*pdu'. Use `*len' * to store the length of the PDU to read (it may be possible to read the * length, but not the rest of the PDU - we need to remember the lenght * for the next call). `*len' should be zero at the first call. */ static int read_pdu(SMPP *smpp, Connection *conn, long *len, SMPP_PDU **pdu) { Octstr *os; if (*len == 0) { *len = smpp_pdu_read_len(conn); if (*len == -1) { error(0, "SMPP[%s]: Server sent garbage, ignored.", octstr_get_cstr(smpp->conn->id)); return -2; } else if (*len == 0) { if (conn_eof(conn) || conn_error(conn)) return -1; return 0; } } os = smpp_pdu_read_data(conn, *len); if (os == NULL) { if (conn_eof(conn) || conn_error(conn)) return -1; return 0; } *len = 0; *pdu = smpp_pdu_unpack(smpp->conn->id, os); if (*pdu == NULL) { error(0, "SMPP[%s]: PDU unpacking failed.", octstr_get_cstr(smpp->conn->id)); debug("bb.sms.smpp", 0, "SMPP[%s]: Failed PDU follows.", octstr_get_cstr(smpp->conn->id)); octstr_dump(os, 0); octstr_destroy(os); return -2; } octstr_destroy(os); return 1; } static long convert_addr_from_pdu(Octstr *id, Octstr *addr, long ton, long npi, Octstr *alt_addr_charset) { long reason = SMPP_ESME_ROK; if (addr == NULL) return reason; switch(ton) { case GSM_ADDR_TON_INTERNATIONAL: /* * Checks to perform: * 1) assume international number has at least 7 chars * 2) the whole source addr consist of digits, exception '+' in front */ if (octstr_len(addr) < 7) { /* We consider this as a "non-hard" condition, since there "may" * be international numbers routable that are < 7 digits. Think * of 2 digit country code + 3 digit emergency code. */ warning(0, "SMPP[%s]: Malformed addr `%s', generally expected at least 7 digits. ", octstr_get_cstr(id), octstr_get_cstr(addr)); } else if (octstr_get_char(addr, 0) == '+' && !octstr_check_range(addr, 1, 256, gw_isdigit)) { error(0, "SMPP[%s]: Malformed addr `%s', expected all digits. ", octstr_get_cstr(id), octstr_get_cstr(addr)); reason = SMPP_ESME_RINVSRCADR; goto error; } else if (octstr_get_char(addr, 0) != '+' && !octstr_check_range(addr, 0, 256, gw_isdigit)) { error(0, "SMPP[%s]: Malformed addr `%s', expected all digits. ", octstr_get_cstr(id), octstr_get_cstr(addr)); reason = SMPP_ESME_RINVSRCADR; goto error; } /* check if we received leading '00', then remove it*/ if (octstr_search(addr, octstr_imm("00"), 0) == 0) octstr_delete(addr, 0, 2); /* international, insert '+' if not already here */ if (octstr_get_char(addr, 0) != '+') octstr_insert_char(addr, 0, '+'); break; case GSM_ADDR_TON_ALPHANUMERIC: if (octstr_len(addr) > 11) { /* alphanum sender, max. allowed length is 11 (according to GSM specs) */ error(0, "SMPP[%s]: Malformed addr `%s', alphanumeric length greater 11 chars. ", octstr_get_cstr(id), octstr_get_cstr(addr)); reason = SMPP_ESME_RINVSRCADR; goto error; } if (alt_addr_charset) { if (octstr_str_case_compare(alt_addr_charset, "gsm") == 0) charset_gsm_to_utf8(addr); else if (charset_convert(addr, octstr_get_cstr(alt_addr_charset), SMPP_DEFAULT_CHARSET) != 0) error(0, "Failed to convert address from charset <%s> to <%s>, leave as is.", octstr_get_cstr(alt_addr_charset), SMPP_DEFAULT_CHARSET); } break; default: /* otherwise don't touch addr, user should handle it */ break; } error: return reason; } static void handle_mt_dcs(Octstr *short_message, char *internal, int data_coding) { /* * Keep in mind that we do transcode the encoding here, * but effectively we're limited to the GSM 03.38 alphabet character * range, since we do a round-trip conversion from/to UTF-8/GSM in * function gw/sms.c:extract_msgdata_part_by_coding(). * * If your underlying radio network is NOT GSM, and you want to support * the extended range of characters of the tables, then remove the * round-trip conversion from the above mentioned function. */ switch (data_coding) { case 0x01: /* ASCII or IA5 */ if (charset_convert(short_message, internal, "ASCII") != 0) { error(0, "Failed to convert msgdata from %s to ASCII, will leave as is", internal); } break; case 0x03: /* ISO-8859-1 (aka latin1) */ if (charset_convert(short_message, internal, "LATIN1") != 0) { error(0, "Failed to convert msgdata from %s to LATIN1, will leave as is", internal); } break; case 0x02: /* 8 bit binary - do nothing */ case 0x04: /* 8 bit binary - do nothing */ break; case 0x05: /* Japanese, JIS(X 0208-1990) */ if (charset_convert(short_message, internal, "JIS_X0208-1990") != 0) error(0, "Failed to convert msgdata from %s to Japanese (JIS-X0208-1990), " "will leave as is", internal); break; case 0x06: /* Cyrllic - iso-8859-5 */ if (charset_convert(short_message, internal, "ISO-8859-5") != 0) error(0, "Failed to convert msgdata from %s to Cyrllic (ISO-8859-5), " "will leave as is", internal); break; case 0x07: /* Hebrew iso-8859-8 */ if (charset_convert(short_message, internal, "ISO-8859-8") != 0) error(0, "Failed to convert msgdata from %s to Hebrew (ISO-8859-8), " "will leave as is", internal); break; case 0x08: /* unicode UCS-2 */ if (charset_convert(short_message, internal, SMPP_DEFAULT_UCS2_CHARSET) != 0) error(0, "Failed to convert msgdata from %s to Unicode (UTF-16BE), " "will leave as is", internal); break; case 0x0D: /* Japanese, Extended Kanji JIS(X 0212-1990) */ if (charset_convert(short_message, internal, "JIS_X0212-1990") != 0) error(0, "Failed to convert msgdata from %s to Japanese (JIS-X0212-1990), " "will leave as is", internal); break; case 0x0E: /* Korean, KS C 5601 - now called KS X 1001, convert to Unicode */ if (charset_convert(short_message, internal, "KSC_5601") != 0 && charset_convert(short_message, internal, "KSC5636") != 0) error(0, "Failed to convert msgdata from %s to Korean (KSC_5601/KSC5636), " "will leave as is", internal); break; case 0x00: /* GSM 03.38 */ default: charset_utf8_to_gsm(short_message); break; /* * don't much care about the others, * you implement them if you feel like it */ } } static void handle_mo_dcs(Msg *msg, Octstr *alt_charset, int data_coding, int esm_class) { switch (data_coding) { case 0x00: /* default SMSC alphabet */ /* * try to convert from something interesting if specified so * unless it was specified binary, i.e. UDH indicator was detected */ if (alt_charset && msg->sms.coding != DC_8BIT) { if (charset_convert(msg->sms.msgdata, octstr_get_cstr(alt_charset), SMPP_DEFAULT_CHARSET) != 0) error(0, "Failed to convert msgdata from charset <%s> to <%s>, will leave as is.", octstr_get_cstr(alt_charset), SMPP_DEFAULT_CHARSET); msg->sms.coding = DC_7BIT; } else { /* assume GSM 03.38 7-bit alphabet */ charset_gsm_to_utf8(msg->sms.msgdata); msg->sms.coding = DC_7BIT; } break; case 0x01: /* ASCII/IA5 - we don't need to perform any conversion * due that UTF-8's first range is exactly the ASCII table */ msg->sms.coding = DC_7BIT; break; case 0x03: /* ISO-8859-1 - I'll convert to internal encoding */ if (charset_convert(msg->sms.msgdata, "ISO-8859-1", SMPP_DEFAULT_CHARSET) != 0) error(0, "Failed to convert msgdata from ISO-8859-1 to " SMPP_DEFAULT_CHARSET ", will leave as is"); msg->sms.coding = DC_7BIT; break; case 0x02: /* 8 bit binary - do nothing */ case 0x04: /* 8 bit binary - do nothing */ msg->sms.coding = DC_8BIT; break; case 0x05: /* Japanese, JIS(X 0208-1990) */ if (charset_convert(msg->sms.msgdata, "JIS_X0208-1990", SMPP_DEFAULT_CHARSET) != 0) error(0, "Failed to convert msgdata from Japanese (JIS_X0208-1990) to " SMPP_DEFAULT_CHARSET ", will leave as is"); msg->sms.coding = DC_7BIT; break; case 0x06: /* Cyrllic - iso-8859-5, I'll convert to internal encoding */ if (charset_convert(msg->sms.msgdata, "ISO-8859-5", SMPP_DEFAULT_CHARSET) != 0) error(0, "Failed to convert msgdata from Cyrllic (ISO-8859-5) to " SMPP_DEFAULT_CHARSET ", will leave as is"); msg->sms.coding = DC_7BIT; break; case 0x07: /* Hebrew iso-8859-8, I'll convert to internal encoding */ if (charset_convert(msg->sms.msgdata, "ISO-8859-8", SMPP_DEFAULT_CHARSET) != 0) error(0, "Failed to convert msgdata from Hebrew (ISO-8859-8) to " SMPP_DEFAULT_CHARSET ", will leave as is"); msg->sms.coding = DC_7BIT; break; case 0x08: /* unicode UCS-2, yey */ msg->sms.coding = DC_UCS2; break; case 0x0D: /* Japanese, Extended Kanji JIS(X 0212-1990) */ if (charset_convert(msg->sms.msgdata, "JIS_X0212-1990", SMPP_DEFAULT_CHARSET) != 0) error(0, "Failed to convert msgdata from Japanese (JIS-X0212-1990) to " SMPP_DEFAULT_CHARSET ", will leave as is"); msg->sms.coding = DC_7BIT; break; case 0x0E: /* Korean, KS C 5601 - now called KS X 1001, convert to Unicode */ if (charset_convert(msg->sms.msgdata, "KSC_5601", SMPP_DEFAULT_CHARSET) != 0 && charset_convert(msg->sms.msgdata, "KSC5636", SMPP_DEFAULT_CHARSET) != 0) error(0, "Failed to convert msgdata from Korean (KSC_5601/KSC5636) to " SMPP_DEFAULT_CHARSET ", will leave as is"); msg->sms.coding = DC_7BIT; break; /* * don't much care about the others, * you implement them if you feel like it */ default: /* * some of smsc send with dcs from GSM 03.38 , but these are reserved in smpp spec. * So we just look decoded values from dcs_to_fields and if none there make our assumptions. * if we have an UDH indicator, we assume DC_8BIT. */ if (msg->sms.coding == DC_UNDEF && (esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR)) msg->sms.coding = DC_8BIT; else if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) { /* assume GSM 7Bit , re-encode */ msg->sms.coding = DC_7BIT; charset_gsm_to_utf8(msg->sms.msgdata); } break; } } /* * Convert SMPP PDU to internal Msgs structure. * Return the Msg if all was fine and NULL otherwise, while getting * the failing reason delivered back in *reason. * XXX semantical check on the incoming values can be extended here. */ static Msg *pdu_to_msg(SMPP *smpp, SMPP_PDU *pdu, long *reason) { Msg *msg; int ton, npi; gw_assert(pdu->type == deliver_sm); msg = msg_create(sms); gw_assert(msg != NULL); *reason = SMPP_ESME_ROK; /* * Reset source addr to have a prefixed '+' in case we have an * intl. TON to allow backend boxes (ie. smsbox) to distinguish * between national and international numbers. */ ton = pdu->u.deliver_sm.source_addr_ton; npi = pdu->u.deliver_sm.source_addr_npi; /* check source addr */ if ((*reason = convert_addr_from_pdu(smpp->conn->id, pdu->u.deliver_sm.source_addr, ton, npi, smpp->alt_addr_charset)) != SMPP_ESME_ROK) goto error; msg->sms.sender = pdu->u.deliver_sm.source_addr; pdu->u.deliver_sm.source_addr = NULL; /* * Follows SMPP spec. v3.4. issue 1.2 * it's not allowed to have destination_addr NULL */ if (pdu->u.deliver_sm.destination_addr == NULL) { error(0, "SMPP[%s]: Malformed destination_addr `%s', may not be empty. " "Discarding MO message.", octstr_get_cstr(smpp->conn->id), octstr_get_cstr(pdu->u.deliver_sm.destination_addr)); *reason = SMPP_ESME_RINVDSTADR; goto error; } /* Same reset of destination number as for source */ ton = pdu->u.deliver_sm.dest_addr_ton; npi = pdu->u.deliver_sm.dest_addr_npi; /* check destination addr */ if ((*reason = convert_addr_from_pdu(smpp->conn->id, pdu->u.deliver_sm.destination_addr, ton, npi, smpp->alt_addr_charset)) != SMPP_ESME_ROK) goto error; msg->sms.receiver = pdu->u.deliver_sm.destination_addr; pdu->u.deliver_sm.destination_addr = NULL; /* SMSCs use service_type for billing information * According to SMPP v5.0 there is no 'billing_identification' * TLV in the deliver_sm PDU optional TLVs. */ msg->sms.binfo = pdu->u.deliver_sm.service_type; pdu->u.deliver_sm.service_type = NULL; /* Foreign ID on MO */ msg->sms.foreign_id = pdu->u.deliver_sm.receipted_message_id; pdu->u.deliver_sm.receipted_message_id = NULL; if (pdu->u.deliver_sm.esm_class & ESM_CLASS_SUBMIT_RPI) msg->sms.rpi = 1; /* * Check for message_payload if version > 0x33 and sm_length == 0 * Note: SMPP spec. v3.4. doesn't allow to send both: message_payload & short_message! */ if (smpp->version > 0x33 && pdu->u.deliver_sm.sm_length == 0 && pdu->u.deliver_sm.message_payload) { msg->sms.msgdata = pdu->u.deliver_sm.message_payload; pdu->u.deliver_sm.message_payload = NULL; } else { msg->sms.msgdata = pdu->u.deliver_sm.short_message; pdu->u.deliver_sm.short_message = NULL; } /* check sar_msg_ref_num, sar_segment_seqnum, sar_total_segments */ if (smpp->version > 0x33 && pdu->u.deliver_sm.sar_msg_ref_num >= 0 && pdu->u.deliver_sm.sar_segment_seqnum > 0 && pdu->u.deliver_sm.sar_total_segments > 0) { /* For GSM networks, the concatenation related TLVs (sar_msg_ref_num, sar_total_segments, sar_segment_seqnum) or port addressing related TLVs (source_port, dest_port) cannot be used in conjunction with encoded User Data Header in the short_message (user data) field. This means that the above listed TLVs cannot be used if the User Data Header Indicator flag is set. */ if (pdu->u.deliver_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) { error(0, "SMPP[%s]: sar_msg_ref_num, sar_segment_seqnum, sar_total_segments in conjuction with UDHI used, rejected.", octstr_get_cstr(smpp->conn->id)); *reason = SMPP_ESME_RINVTLVVAL; goto error; } /* create multipart UDH */ prepend_catenation_udh(msg, pdu->u.deliver_sm.sar_segment_seqnum, pdu->u.deliver_sm.sar_total_segments, pdu->u.deliver_sm.sar_msg_ref_num); } /* * Encode udh if udhi set * for reference see GSM03.40, section 9.2.3.24 */ if (pdu->u.deliver_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) { int udhl; udhl = octstr_get_char(msg->sms.msgdata, 0) + 1; debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d", octstr_get_cstr(smpp->conn->id), udhl); if (udhl > octstr_len(msg->sms.msgdata)) { error(0, "SMPP[%s]: Malformed UDH length indicator 0x%03x while message length " "0x%03lx. Discarding MO message.", octstr_get_cstr(smpp->conn->id), udhl, octstr_len(msg->sms.msgdata)); *reason = SMPP_ESME_RINVESMCLASS; goto error; } msg->sms.udhdata = octstr_copy(msg->sms.msgdata, 0, udhl); octstr_delete(msg->sms.msgdata, 0, udhl); } dcs_to_fields(&msg, pdu->u.deliver_sm.data_coding); /* handle default data coding */ handle_mo_dcs(msg, smpp->alt_charset, pdu->u.deliver_sm.data_coding, pdu->u.deliver_sm.esm_class); msg->sms.pid = pdu->u.deliver_sm.protocol_id; /* set priority flag */ msg->sms.priority = pdu->u.deliver_sm.priority_flag; if (msg->sms.meta_data == NULL) msg->sms.meta_data = octstr_create(""); meta_data_set_values(msg->sms.meta_data, pdu->u.deliver_sm.tlv, "smpp", 1); return msg; error: msg_destroy(msg); return NULL; } /* * Convert SMPP PDU to internal Msgs structure. * Return the Msg if all was fine and NULL otherwise, while getting * the failing reason delivered back in *reason. * XXX semantical check on the incoming values can be extended here. */ static Msg *data_sm_to_msg(SMPP *smpp, SMPP_PDU *pdu, long *reason) { Msg *msg; int ton, npi; gw_assert(pdu->type == data_sm); msg = msg_create(sms); gw_assert(msg != NULL); *reason = SMPP_ESME_ROK; /* * Reset source addr to have a prefixed '+' in case we have an * intl. TON to allow backend boxes (ie. smsbox) to distinguish * between national and international numbers. */ ton = pdu->u.data_sm.source_addr_ton; npi = pdu->u.data_sm.source_addr_npi; /* check source addr */ if ((*reason = convert_addr_from_pdu(smpp->conn->id, pdu->u.data_sm.source_addr, ton, npi, smpp->alt_addr_charset)) != SMPP_ESME_ROK) goto error; msg->sms.sender = pdu->u.data_sm.source_addr; pdu->u.data_sm.source_addr = NULL; /* * Follows SMPP spec. v3.4. issue 1.2 * it's not allowed to have destination_addr NULL */ if (pdu->u.data_sm.destination_addr == NULL) { error(0, "SMPP[%s]: Malformed destination_addr `%s', may not be empty. " "Discarding MO message.", octstr_get_cstr(smpp->conn->id), octstr_get_cstr(pdu->u.data_sm.destination_addr)); *reason = SMPP_ESME_RINVDSTADR; goto error; } /* Same reset of destination number as for source */ ton = pdu->u.data_sm.dest_addr_ton; npi = pdu->u.data_sm.dest_addr_npi; /* check destination addr */ if ((*reason = convert_addr_from_pdu(smpp->conn->id, pdu->u.data_sm.destination_addr, ton, npi, smpp->alt_addr_charset)) != SMPP_ESME_ROK) goto error; msg->sms.receiver = pdu->u.data_sm.destination_addr; pdu->u.data_sm.destination_addr = NULL; /* SMSCs use service_type for billing information */ if (smpp->version == 0x50 && pdu->u.data_sm.billing_identification) { msg->sms.binfo = pdu->u.data_sm.billing_identification; pdu->u.data_sm.billing_identification = NULL; } else { msg->sms.binfo = pdu->u.data_sm.service_type; pdu->u.data_sm.service_type = NULL; } /* Foreign ID on MO */ msg->sms.foreign_id = pdu->u.data_sm.receipted_message_id; pdu->u.data_sm.receipted_message_id = NULL; if (pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_RPI) msg->sms.rpi = 1; msg->sms.msgdata = pdu->u.data_sm.message_payload; pdu->u.data_sm.message_payload = NULL; /* check sar_msg_ref_num, sar_segment_seqnum, sar_total_segments */ if (pdu->u.data_sm.sar_msg_ref_num >= 0 && pdu->u.data_sm.sar_segment_seqnum > 0 && pdu->u.data_sm.sar_total_segments > 0) { /* For GSM networks, the concatenation related TLVs (sar_msg_ref_num, sar_total_segments, sar_segment_seqnum) or port addressing related TLVs (source_port, dest_port) cannot be used in conjunction with encoded User Data Header in the short_message (user data) field. This means that the above listed TLVs cannot be used if the User Data Header Indicator flag is set. */ if (pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) { error(0, "SMPP[%s]: sar_msg_ref_num, sar_segment_seqnum, sar_total_segments in conjuction with UDHI used, rejected.", octstr_get_cstr(smpp->conn->id)); *reason = SMPP_ESME_RINVTLVVAL; goto error; } /* create multipart UDH */ prepend_catenation_udh(msg, pdu->u.data_sm.sar_segment_seqnum, pdu->u.data_sm.sar_total_segments, pdu->u.data_sm.sar_msg_ref_num); } /* * Encode udh if udhi set * for reference see GSM03.40, section 9.2.3.24 */ if (pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) { int udhl; udhl = octstr_get_char(msg->sms.msgdata, 0) + 1; debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d", octstr_get_cstr(smpp->conn->id), udhl); if (udhl > octstr_len(msg->sms.msgdata)) { error(0, "SMPP[%s]: Malformed UDH length indicator 0x%03x while message length " "0x%03lx. Discarding MO message.", octstr_get_cstr(smpp->conn->id), udhl, octstr_len(msg->sms.msgdata)); *reason = SMPP_ESME_RINVESMCLASS; goto error; } msg->sms.udhdata = octstr_copy(msg->sms.msgdata, 0, udhl); octstr_delete(msg->sms.msgdata, 0, udhl); } dcs_to_fields(&msg, pdu->u.data_sm.data_coding); /* handle default data coding */ handle_mo_dcs(msg, smpp->alt_charset, pdu->u.data_sm.data_coding, pdu->u.data_sm.esm_class); if (msg->sms.meta_data == NULL) msg->sms.meta_data = octstr_create(""); meta_data_set_values(msg->sms.meta_data, pdu->u.data_sm.tlv, "smpp", 1); return msg; error: msg_destroy(msg); return NULL; } static long smpp_status_to_smscconn_failure_reason(long status) { switch(status) { case SMPP_ESME_RMSGQFUL: case SMPP_ESME_RTHROTTLED: case SMPP_ESME_RX_T_APPN: case SMPP_ESME_RSYSERR: return SMSCCONN_FAILED_TEMPORARILY; break; default: return SMSCCONN_FAILED_REJECTED; } } static SMPP_PDU *msg_to_pdu(SMPP *smpp, Msg *msg) { SMPP_PDU *pdu; int validity; Octstr *tmp; int ton_npi_forced; int data_coding = -1; pdu = smpp_pdu_create(submit_sm, counter_increase(smpp->message_id_counter)); pdu->u.submit_sm.source_addr = octstr_duplicate(msg->sms.sender); pdu->u.submit_sm.destination_addr = octstr_duplicate(msg->sms.receiver); /* Set the service type of the outgoing message. We'll use the config * directive as default and 'binfo' as specific parameter. */ if (octstr_len(msg->sms.binfo)) { /* SMPP v5.0 has an own TLV for billing information */ if (smpp->version == 0x50) { pdu->u.submit_sm.billing_identification = octstr_duplicate(msg->sms.binfo); } else { pdu->u.submit_sm.service_type = octstr_duplicate(msg->sms.binfo); } } else { pdu->u.submit_sm.service_type = octstr_duplicate(smpp->service_type); } /* Check for manual override of source ton and npi values */ if (smpp->source_addr_ton > -1 && smpp->source_addr_npi > -1) { pdu->u.submit_sm.source_addr_ton = smpp->source_addr_ton; pdu->u.submit_sm.source_addr_npi = smpp->source_addr_npi; debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced source addr ton = %d, source add npi = %d", octstr_get_cstr(smpp->conn->id), smpp->source_addr_ton, smpp->source_addr_npi); } else { /* setup default values */ pdu->u.submit_sm.source_addr_ton = GSM_ADDR_TON_NATIONAL; /* national */ pdu->u.submit_sm.source_addr_npi = GSM_ADDR_NPI_E164; /* ISDN number plan */ } /* Check for forced source ton and npi values via meta-data */ ton_npi_forced = 0; tmp = meta_data_get_value(msg->sms.meta_data, METADATA_SMPP_GROUP, octstr_imm("source_addr_ton")); if (tmp != NULL) { ton_npi_forced = 1; pdu->u.submit_sm.source_addr_ton = atoi(octstr_get_cstr(tmp)); octstr_destroy(tmp); } tmp = meta_data_get_value(msg->sms.meta_data, METADATA_SMPP_GROUP, octstr_imm("source_addr_npi")); if (tmp != NULL) { ton_npi_forced = 1; pdu->u.submit_sm.source_addr_npi = atoi(octstr_get_cstr(tmp)); octstr_destroy(tmp); } /* don't touch source_addr ton/npi if overwritten in meta_data */ if (pdu->u.submit_sm.source_addr && !ton_npi_forced && smpp->autodetect_addr) { /* lets see if its international or alphanumeric sender */ if (octstr_get_char(pdu->u.submit_sm.source_addr, 0) == '+') { if (!octstr_check_range(pdu->u.submit_sm.source_addr, 1, 256, gw_isdigit)) { pdu->u.submit_sm.source_addr_ton = GSM_ADDR_TON_ALPHANUMERIC; /* alphanum */ pdu->u.submit_sm.source_addr_npi = GSM_ADDR_NPI_UNKNOWN; /* short code */ if (smpp->alt_addr_charset) { if (octstr_str_case_compare(smpp->alt_addr_charset, "gsm") == 0) { /* @ would break PDU if converted into GSM*/ octstr_replace(pdu->u.submit_sm.source_addr, octstr_imm("@"), octstr_imm("?")); charset_utf8_to_gsm(pdu->u.submit_sm.source_addr); } else if (charset_convert(pdu->u.submit_sm.source_addr, SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset)) != 0) error(0, "Failed to convert source_addr from charset <%s> to <%s>, will send as is.", SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset)); } } else { /* numeric sender address with + in front -> international (remove the +) */ octstr_delete(pdu->u.submit_sm.source_addr, 0, 1); pdu->u.submit_sm.source_addr_ton = GSM_ADDR_TON_INTERNATIONAL; } } else { if (!octstr_check_range(pdu->u.submit_sm.source_addr,0, 256, gw_isdigit)) { pdu->u.submit_sm.source_addr_ton = GSM_ADDR_TON_ALPHANUMERIC; pdu->u.submit_sm.source_addr_npi = GSM_ADDR_NPI_UNKNOWN; if (smpp->alt_addr_charset) { if (octstr_str_case_compare(smpp->alt_addr_charset, "gsm") == 0) { /* @ would break PDU if converted into GSM */ octstr_replace(pdu->u.submit_sm.source_addr, octstr_imm("@"), octstr_imm("?")); charset_utf8_to_gsm(pdu->u.submit_sm.source_addr); } else if (charset_convert(pdu->u.submit_sm.source_addr, SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset)) != 0) error(0, "Failed to convert source_addr from charset <%s> to <%s>, will send as is.", SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_addr_charset)); } } } } /* Check for manual override of destination ton and npi values */ if (smpp->dest_addr_ton > -1 && smpp->dest_addr_npi > -1) { pdu->u.submit_sm.dest_addr_ton = smpp->dest_addr_ton; pdu->u.submit_sm.dest_addr_npi = smpp->dest_addr_npi; debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced dest addr ton = %d, dest add npi = %d", octstr_get_cstr(smpp->conn->id), smpp->dest_addr_ton, smpp->dest_addr_npi); } else { pdu->u.submit_sm.dest_addr_ton = GSM_ADDR_TON_NATIONAL; /* national */ pdu->u.submit_sm.dest_addr_npi = GSM_ADDR_NPI_E164; /* ISDN number plan */ } /* Check for forced destination ton and npi values via meta-data */ ton_npi_forced = 0; tmp = meta_data_get_value(msg->sms.meta_data, METADATA_SMPP_GROUP, octstr_imm("dest_addr_ton")); if (tmp != NULL) { ton_npi_forced = 1; pdu->u.submit_sm.dest_addr_ton = atoi(octstr_get_cstr(tmp)); octstr_destroy(tmp); } tmp = meta_data_get_value(msg->sms.meta_data, METADATA_SMPP_GROUP, octstr_imm("dest_addr_npi")); if (tmp != NULL) { ton_npi_forced = 1; pdu->u.submit_sm.dest_addr_npi = atoi(octstr_get_cstr(tmp)); octstr_destroy(tmp); } /* don't touch source_addr ton/npi if overwritten in meta_data */ if (!ton_npi_forced) { /* * if its a international number starting with +, lets remove the * '+' and set number type to international instead */ if (octstr_get_char(pdu->u.submit_sm.destination_addr,0) == '+') { octstr_delete(pdu->u.submit_sm.destination_addr, 0,1); pdu->u.submit_sm.dest_addr_ton = GSM_ADDR_TON_INTERNATIONAL; } } /* check length of src/dst address */ if (octstr_len(pdu->u.submit_sm.destination_addr) > 20 || octstr_len(pdu->u.submit_sm.source_addr) > 20) { smpp_pdu_destroy(pdu); return NULL; } /* * set the data coding scheme (DCS) field * check if we have a forced value for this from the smsc-group. * Note: if message class is set, then we _must_ force alt_dcs otherwise * dcs has reserved values (e.g. mclass=2, dcs=0x11). We check MWI flag * first here, because MWI and MCLASS can not be set at the same time and * function fields_to_dcs check MWI first, so we have no need to force alt_dcs * if MWI is set. */ if (msg->sms.mwi == MWI_UNDEF && msg->sms.mclass != MC_UNDEF) pdu->u.submit_sm.data_coding = fields_to_dcs(msg, 1); /* force alt_dcs */ else pdu->u.submit_sm.data_coding = fields_to_dcs(msg, (msg->sms.alt_dcs != SMS_PARAM_UNDEFINED ? msg->sms.alt_dcs : smpp->conn->alt_dcs)); /* set protocol id */ if (msg->sms.pid != SMS_PARAM_UNDEFINED) pdu->u.submit_sm.protocol_id = msg->sms.pid; /* * set the esm_class field * default is store and forward, plus udh and rpi if requested */ pdu->u.submit_sm.esm_class = smpp->esm_class; if (octstr_len(msg->sms.udhdata)) pdu->u.submit_sm.esm_class = pdu->u.submit_sm.esm_class | ESM_CLASS_SUBMIT_UDH_INDICATOR; if (msg->sms.rpi > 0) pdu->u.submit_sm.esm_class = pdu->u.submit_sm.esm_class | ESM_CLASS_SUBMIT_RPI; /* * set data segments and length */ pdu->u.submit_sm.short_message = octstr_duplicate(msg->sms.msgdata); /* Check for forced data_coding value via meta-data */ tmp = meta_data_get_value(msg->sms.meta_data, METADATA_SMPP_GROUP, octstr_imm("data_coding")); if (tmp != NULL) { data_coding = atoi(octstr_get_cstr(tmp)); octstr_destroy(tmp); } /* * only re-encoding if using default smsc charset that is defined via * alt-charset in smsc group and if MT is not binary */ if (msg->sms.coding == DC_7BIT || (msg->sms.coding == DC_UNDEF && octstr_len(msg->sms.udhdata) == 0)) { /* * consider 4 cases: * a) data_coding 0xFX: encoding should always be GSM 03.38 charset * b) data_coding 0xXX: encoding based on forced meta-data value * c) data_coding 0x00: encoding may be converted according to alt-charset * d) data_coding 0x00: assume GSM 03.38 charset if alt-charset is not defined */ if (pdu->u.submit_sm.data_coding & 0xF0) { charset_utf8_to_gsm(pdu->u.submit_sm.short_message); } else if (pdu->u.submit_sm.data_coding == 0 && !smpp->alt_charset) { /* * convert to a forced data_coding value, or GSM 03.38 if not */ handle_mt_dcs(pdu->u.submit_sm.short_message, SMPP_DEFAULT_CHARSET, data_coding); if (data_coding != -1) pdu->u.submit_sm.data_coding = data_coding; } else if (pdu->u.submit_sm.data_coding == 0 && smpp->alt_charset) { /* * convert to the given alternative charset */ if (charset_convert(pdu->u.submit_sm.short_message, SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_charset)) != 0) error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.", SMPP_DEFAULT_CHARSET, octstr_get_cstr(smpp->alt_charset)); } } else if (msg->sms.coding == DC_UCS2 && data_coding > 0x04 && data_coding != 0x08) { /* * convert to a forced data_coding value, which is given in UCS-2, * avoid the transcoding if we want UCS2 (data_coding 0x08) anyway. */ handle_mt_dcs(pdu->u.submit_sm.short_message, SMPP_DEFAULT_UCS2_CHARSET, data_coding); pdu->u.submit_sm.data_coding = data_coding; } /* prepend udh if present */ if (octstr_len(msg->sms.udhdata)) { octstr_insert(pdu->u.submit_sm.short_message, msg->sms.udhdata, 0); } pdu->u.submit_sm.sm_length = octstr_len(pdu->u.submit_sm.short_message); /* check long messages, because: * The sm_length parameter specifies the length of the short_message parameter in octets. * The sm_length should be set to 0 in the submit_sm, submit_multi, and deliver_sm PDUs if * the message_payload parameter is being used to send user data larger than 254 octets. */ if (pdu->u.submit_sm.sm_length > 254) { if (smpp->version > 0x33) { /* put msgdata into message_payload */ pdu->u.submit_sm.message_payload = pdu->u.submit_sm.short_message; pdu->u.submit_sm.short_message = NULL; pdu->u.submit_sm.sm_length = 0; } else { error(0, "SMPP[%s]: Unable to send long message (%ld) Octets in smpp version < 3.4", octstr_get_cstr(smpp->conn->id), pdu->u.submit_sm.sm_length); smpp_pdu_destroy(pdu); return NULL; } } /* * check for validity and deferred settings * were message value has higher priority then smsc config group value * Note: we always send in UTC and just define "Time Difference" as 00 and * direction '+'. */ validity = SMS_PARAM_UNDEFINED; if (msg->sms.validity != SMS_PARAM_UNDEFINED) validity = msg->sms.validity; else if (smpp->validityperiod != SMS_PARAM_UNDEFINED) validity = time(NULL) + smpp->validityperiod * 60; if (validity != SMS_PARAM_UNDEFINED) { struct tm tm = gw_gmtime(validity); pdu->u.submit_sm.validity_period = octstr_format("%02d%02d%02d%02d%02d%02d000+", tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } if (msg->sms.deferred != SMS_PARAM_UNDEFINED) { struct tm tm = gw_gmtime(msg->sms.deferred); pdu->u.submit_sm.schedule_delivery_time = octstr_format("%02d%02d%02d%02d%02d%02d000+", tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } /* ask for the delivery reports if needed */ if (DLR_IS_FAIL(msg->sms.dlr_mask) && !DLR_IS_SUCCESS(msg->sms.dlr_mask)) pdu->u.submit_sm.registered_delivery = 2; else if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask)) pdu->u.submit_sm.registered_delivery = 1; if (DLR_IS_BUFFERED(msg->sms.dlr_mask)) pdu->u.submit_sm.registered_delivery += 16; /* set priority */ if (msg->sms.priority >= 0 && msg->sms.priority <= 3) pdu->u.submit_sm.priority_flag = msg->sms.priority; else pdu->u.submit_sm.priority_flag = smpp->priority; /* set more messages to send */ if (smpp->version > 0x33 && msg->sms.msg_left > 0) pdu->u.submit_sm.more_messages_to_send = 1; dict_destroy(pdu->u.submit_sm.tlv); pdu->u.submit_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp"); /* add any configured constant TLVs */ smpp_tlv_add_constant(smpp->conn->id, &(pdu->u.submit_sm.tlv)); return pdu; } static int send_enquire_link(SMPP *smpp, Connection *conn, long *last_sent) { SMPP_PDU *pdu; Octstr *os; int ret; if (difftime(date_universal_now(),*last_sent) < smpp->enquire_link_interval) return 0; *last_sent = date_universal_now(); pdu = smpp_pdu_create(enquire_link, counter_increase(smpp->message_id_counter)); dump_pdu("Sending enquire link:", smpp->conn->id, pdu, smpp->log_format); os = smpp_pdu_pack(smpp->conn->id, pdu); if (os != NULL) ret = conn_write(conn, os); /* Write errors checked by caller. */ else ret = -1; octstr_destroy(os); smpp_pdu_destroy(pdu); return ret; } static int send_gnack(SMPP *smpp, Connection *conn, long reason, unsigned long seq_num) { SMPP_PDU *pdu; Octstr *os; int ret; pdu = smpp_pdu_create(generic_nack, seq_num); pdu->u.generic_nack.command_status = reason; dump_pdu("Sending generic_nack:", smpp->conn->id, pdu, smpp->log_format); os = smpp_pdu_pack(smpp->conn->id, pdu); if (os != NULL) ret = conn_write(conn, os); else ret = -1; octstr_destroy(os); smpp_pdu_destroy(pdu); return ret; } static int send_unbind(SMPP *smpp, Connection *conn) { SMPP_PDU *pdu; Octstr *os; int ret; pdu = smpp_pdu_create(unbind, counter_increase(smpp->message_id_counter)); dump_pdu("Sending unbind:", smpp->conn->id, pdu, smpp->log_format); os = smpp_pdu_pack(smpp->conn->id, pdu); if (os != NULL) ret = conn_write(conn, os); else ret = -1; octstr_destroy(os); smpp_pdu_destroy(pdu); return ret; } static int send_pdu(Connection *conn, SMPP *smpp, SMPP_PDU *pdu) { Octstr *os; int ret; dump_pdu("Sending PDU:", smpp->conn->id, pdu, smpp->log_format); os = smpp_pdu_pack(smpp->conn->id, pdu); if (os) { /* Caller checks for write errors later */ ret = conn_write(conn, os); /* it's not a error if we still have data buffered */ ret = (ret == 1) ? 0 : ret; } else ret = -1; octstr_destroy(os); return ret; } static int send_messages(SMPP *smpp, Connection *conn, long *pending_submits) { Msg *msg; SMPP_PDU *pdu; Octstr *os; if (*pending_submits == -1) return 0; while (*pending_submits < smpp->max_pending_submits) { /* check our throughput */ if (smpp->conn->throughput > 0 && load_get(smpp->load, 0) >= smpp->conn->throughput) { debug("bb.sms.smpp", 0, "SMPP[%s]: throughput limit exceeded (%.02f,%.02f)", octstr_get_cstr(smpp->conn->id), load_get(smpp->load, 0), smpp->conn->throughput); break; } debug("bb.sms.smpp", 0, "SMPP[%s]: throughput (%.02f,%.02f)", octstr_get_cstr(smpp->conn->id), load_get(smpp->load, 0), smpp->conn->throughput); /* Get next message, quit if none to be sent */ msg = gw_prioqueue_remove(smpp->msgs_to_send); if (msg == NULL) break; /* Send PDU, record it as waiting for ack from SMS center */ pdu = msg_to_pdu(smpp, msg); if (pdu == NULL) { bb_smscconn_send_failed(smpp->conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED SMS")); continue; } /* check for write errors */ if (send_pdu(conn, smpp, pdu) == 0) { struct smpp_msg *smpp_msg = smpp_msg_create(msg); os = octstr_format("%ld", pdu->u.submit_sm.sequence_number); dict_put(smpp->sent_msgs, os, smpp_msg); smpp_pdu_destroy(pdu); octstr_destroy(os); ++(*pending_submits); load_increase(smpp->load); } else { /* write error occurs */ smpp_pdu_destroy(pdu); bb_smscconn_send_failed(smpp->conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); return -1; } } return 0; } /* * Open transmission connection to SMS center. Return NULL for error, * open Connection for OK. Caller must set smpp->conn->status correctly * before calling this. */ static Connection *open_transmitter(SMPP *smpp) { SMPP_PDU *bind; Connection *conn; #ifdef HAVE_LIBSSL if (smpp->use_ssl) conn = conn_open_ssl(smpp->host, smpp->transmit_port, smpp->ssl_client_certkey_file, smpp->conn->our_host); else #endif if (smpp->our_port > 0) conn = conn_open_tcp_with_port(smpp->host, smpp->transmit_port, smpp->our_port, smpp->conn->our_host ); else conn = conn_open_tcp(smpp->host, smpp->transmit_port, smpp->conn->our_host); if (conn == NULL) { error(0, "SMPP[%s]: Couldn't connect to server.", octstr_get_cstr(smpp->conn->id)); return NULL; } bind = smpp_pdu_create(bind_transmitter, counter_increase(smpp->message_id_counter)); bind->u.bind_transmitter.system_id = octstr_duplicate(smpp->username); bind->u.bind_transmitter.password = octstr_duplicate(smpp->password); if (smpp->system_type == NULL) bind->u.bind_transmitter.system_type = octstr_create("VMA"); else bind->u.bind_transmitter.system_type = octstr_duplicate(smpp->system_type); bind->u.bind_transmitter.interface_version = smpp->version; bind->u.bind_transmitter.address_range = octstr_duplicate(smpp->address_range); bind->u.bind_transmitter.addr_ton = smpp->bind_addr_ton; bind->u.bind_transmitter.addr_npi = smpp->bind_addr_npi; if (send_pdu(conn, smpp, bind) == -1) { error(0, "SMPP[%s]: Couldn't send bind_transmitter to server.", octstr_get_cstr(smpp->conn->id)); conn_destroy(conn); conn = NULL; } smpp_pdu_destroy(bind); return conn; } /* * Open transceiver connection to SMS center. Return NULL for error, * open Connection for OK. Caller must set smpp->conn->status correctly * before calling this. */ static Connection *open_transceiver(SMPP *smpp) { SMPP_PDU *bind; Connection *conn; #ifdef HAVE_LIBSSL if (smpp->use_ssl) conn = conn_open_ssl(smpp->host, smpp->transmit_port, smpp->ssl_client_certkey_file, smpp->conn->our_host); else #endif if (smpp->our_port > 0) conn = conn_open_tcp_with_port(smpp->host, smpp->transmit_port, smpp->our_port, smpp->conn->our_host ); else conn = conn_open_tcp(smpp->host, smpp->transmit_port, smpp->conn->our_host); if (conn == NULL) { error(0, "SMPP[%s]: Couldn't connect to server.", octstr_get_cstr(smpp->conn->id)); return NULL; } bind = smpp_pdu_create(bind_transceiver, counter_increase(smpp->message_id_counter)); bind->u.bind_transceiver.system_id = octstr_duplicate(smpp->username); bind->u.bind_transceiver.password = octstr_duplicate(smpp->password); if (smpp->system_type == NULL) bind->u.bind_transceiver.system_type = octstr_create("VMA"); else bind->u.bind_transceiver.system_type = octstr_duplicate(smpp->system_type); bind->u.bind_transceiver.interface_version = smpp->version; bind->u.bind_transceiver.address_range = octstr_duplicate(smpp->address_range); bind->u.bind_transceiver.addr_ton = smpp->bind_addr_ton; bind->u.bind_transceiver.addr_npi = smpp->bind_addr_npi; if (send_pdu(conn, smpp, bind) == -1) { error(0, "SMPP[%s]: Couldn't send bind_transceiver to server.", octstr_get_cstr(smpp->conn->id)); conn_destroy(conn); conn = NULL; } smpp_pdu_destroy(bind); return conn; } /* * Open reception connection to SMS center. Return NULL for error, * open Connection for OK. Caller must set smpp->conn->status correctly * before calling this. */ static Connection *open_receiver(SMPP *smpp) { SMPP_PDU *bind; Connection *conn; #ifdef HAVE_LIBSSL if (smpp->use_ssl) conn = conn_open_ssl(smpp->host, smpp->receive_port, smpp->ssl_client_certkey_file, smpp->conn->our_host); else #endif if (smpp->our_receiver_port > 0) conn = conn_open_tcp_with_port(smpp->host, smpp->receive_port, smpp->our_receiver_port, smpp->conn->our_host); else conn = conn_open_tcp(smpp->host, smpp->receive_port, smpp->conn->our_host); if (conn == NULL) { error(0, "SMPP[%s]: Couldn't connect to server.", octstr_get_cstr(smpp->conn->id)); return NULL; } bind = smpp_pdu_create(bind_receiver, counter_increase(smpp->message_id_counter)); bind->u.bind_receiver.system_id = octstr_duplicate(smpp->username); bind->u.bind_receiver.password = octstr_duplicate(smpp->password); if (smpp->system_type == NULL) bind->u.bind_receiver.system_type = octstr_create("VMA"); else bind->u.bind_receiver.system_type = octstr_duplicate(smpp->system_type); bind->u.bind_receiver.interface_version = smpp->version; bind->u.bind_receiver.address_range = octstr_duplicate(smpp->address_range); bind->u.bind_receiver.addr_ton = smpp->bind_addr_ton; bind->u.bind_receiver.addr_npi = smpp->bind_addr_npi; if (send_pdu(conn, smpp, bind) == -1) { error(0, "SMPP[%s]: Couldn't send bind_receiver to server.", octstr_get_cstr(smpp->conn->id)); conn_destroy(conn); conn = NULL; } smpp_pdu_destroy(bind); return conn; } /* * See SMPP v5.0 spec [http://www.smsforum.net/smppv50.pdf.zip], * section 4.8.4.42 network_error_code for correct encoding. */ static int error_from_network_error_code(Octstr *network_error_code) { unsigned char *nec; int type; int err; if (network_error_code == NULL || octstr_len(network_error_code) != 3) return 0; nec = (unsigned char*) octstr_get_cstr(network_error_code); type = nec[0]; err = (nec[1] << 8) | nec[2]; if ((type >= '0') && (type <= '9')) { /* this is a bogous SMSC sending back network_error_code as * 3 digit string instead as in the delivery report. */ sscanf((char*) nec, "%03d", &err); return err; } return err; } static Msg *handle_dlr(SMPP *smpp, Octstr *destination_addr, Octstr *short_message, Octstr *message_payload, Octstr *receipted_message_id, long message_state, Octstr *network_error_code) { Msg *dlrmsg = NULL; Octstr *respstr = NULL, *msgid = NULL, *network_err = NULL, *dlr_err = NULL, *tmp; int dlrstat = -1; int err_int = 0; /* first check for SMPP v3.4 and above */ if (smpp->version > 0x33 && receipted_message_id) { msgid = octstr_duplicate(receipted_message_id); switch(message_state) { case 0: /* SCHEDULED, defined in SMPP v5.0, sec. 4.7.15, page 127 */ if (smpp->version == 0x50) /* being very pedantic here */ dlrstat = DLR_BUFFERED; break; case 1: /* ENROUTE */ case 6: /* ACCEPTED */ dlrstat = DLR_BUFFERED; break; case 2: /* DELIVERED */ dlrstat = DLR_SUCCESS; break; case 3: /* EXPIRED */ dlrstat = DLR_EXPIRED; break; case 4: /* DELETED */ case 5: /* UNDELIVERABLE */ case 7: /* UNKNOWN */ case 8: /* REJECTED */ dlrstat = DLR_FAIL; break; case 9: /* SKIPPED, defined in SMPP v5.0, sec. 4.7.15, page 127 */ if (smpp->version == 0x50) dlrstat = DLR_FAIL; break; case -1: /* message state is not present, partial SMPP v3.4 */ debug("bb.sms.smpp", 0, "SMPP[%s]: Partial SMPP v3.4, receipted_message_id present but not message_state.", octstr_get_cstr(smpp->conn->id)); dlrstat = -1; break; default: warning(0, "SMPP[%s]: Got DLR with unknown 'message_state' (%ld).", octstr_get_cstr(smpp->conn->id), message_state); dlrstat = DLR_FAIL; break; } } if (network_error_code != NULL) { err_int = error_from_network_error_code(network_error_code); network_err = octstr_duplicate(network_error_code); } /* check for SMPP v.3.4. and message_payload */ if (smpp->version > 0x33 && octstr_len(short_message) == 0) respstr = message_payload; else respstr = short_message; if (msgid == NULL || network_err == NULL || dlrstat == -1) { /* parse the respstr if it exists */ if (respstr) { long curr = 0, vpos = 0; Octstr *stat = NULL; char id_cstr[65], stat_cstr[16], sub_d_cstr[15], done_d_cstr[15]; char err_cstr[4]; int sub, dlrvrd, ret; /* get server message id */ /* first try sscanf way if thus failed then old way */ ret = sscanf(octstr_get_cstr(respstr), "id:%64[^ ] sub:%d dlvrd:%d submit date:%14[0-9] done " "date:%14[0-9] stat:%15[^ ] err:%3[^ ]", id_cstr, &sub, &dlrvrd, sub_d_cstr, done_d_cstr, stat_cstr, err_cstr); if (ret == 7) { /* only if not already here */ if (msgid == NULL) { msgid = octstr_create(id_cstr); octstr_strip_blanks(msgid); } stat = octstr_create(stat_cstr); octstr_strip_blanks(stat); sscanf(err_cstr, "%d", &err_int); dlr_err = octstr_create(err_cstr); octstr_strip_blanks(dlr_err); } else { debug("bb.sms.smpp", 0, "SMPP[%s]: Could not parse DLR string sscanf way, " "fallback to old way. Please report!", octstr_get_cstr(smpp->conn->id)); /* only if not already here */ if (msgid == NULL) { if ((curr = octstr_search(respstr, octstr_imm("id:"), 0)) != -1) { if ((vpos = octstr_search_char(respstr, ' ', curr)) == -1) vpos = octstr_len(respstr); if (vpos-curr > 0) msgid = octstr_copy(respstr, curr+3, vpos-curr-3); } } /* get err & status code */ if ((curr = octstr_search(respstr, octstr_imm("stat:"), 0)) != -1) { if ((vpos = octstr_search_char(respstr, ' ', curr)) == -1) vpos = octstr_len(respstr); if (vpos-curr > 0) stat = octstr_copy(respstr, curr+5, vpos-curr-5); } else { stat = NULL; } if ((curr = octstr_search(respstr, octstr_imm("err:"), 0)) != -1) { if ((vpos = octstr_search_char(respstr, ' ', curr)) == -1) vpos = octstr_len(respstr); if (vpos-curr > 0) dlr_err = octstr_copy(respstr, curr+4, vpos-curr-4); } else { dlr_err = NULL; } } /* * we get the following status: * DELIVRD, ACCEPTD, EXPIRED, DELETED, UNDELIV, UNKNOWN, REJECTD * * Note: some buggy SMSC's send us immediately delivery notifications although * we doesn't requested these. */ if (dlrstat == -1) { if (stat != NULL && octstr_compare(stat, octstr_imm("DELIVRD")) == 0) dlrstat = DLR_SUCCESS; else if (stat != NULL && (octstr_compare(stat, octstr_imm("ACCEPTD")) == 0 || octstr_compare(stat, octstr_imm("ACKED")) == 0 || octstr_compare(stat, octstr_imm("BUFFRED")) == 0 || octstr_compare(stat, octstr_imm("BUFFERD")) == 0 || octstr_compare(stat, octstr_imm("ENROUTE")) == 0)) dlrstat = DLR_BUFFERED; else dlrstat = DLR_FAIL; } octstr_destroy(stat); } } if (msgid != NULL && dlrstat != -1) { /* * Obey which SMPP msg_id type this SMSC is using, where we * have the following semantics for the variable smpp_msg_id: * * bit 1: type for submit_sm_resp, bit 2: type for deliver_sm * * if bit is set value is hex otherwise dec * * 0x00 deliver_sm dec, submit_sm_resp dec * 0x01 deliver_sm dec, submit_sm_resp hex * 0x02 deliver_sm hex, submit_sm_resp dec * 0x03 deliver_sm hex, submit_sm_resp hex * * Default behaviour is SMPP spec compliant, which means * msg_ids should be C strings and hence non modified. */ if (smpp->smpp_msg_id_type == -1) { /* the default, C string */ tmp = octstr_duplicate(msgid); } else { if ((smpp->smpp_msg_id_type & 0x02) || (!octstr_check_range(msgid, 0, octstr_len(msgid), gw_isdigit))) { tmp = octstr_format("%llu", strtoll(octstr_get_cstr(msgid), NULL, 16)); } else { tmp = octstr_format("%llu", strtoll(octstr_get_cstr(msgid), NULL, 10)); } } dlrmsg = dlr_find(smpp->conn->id, tmp, /* smsc message id */ destination_addr, /* destination */ dlrstat, 0); octstr_destroy(msgid); } else tmp = octstr_create(""); if (network_err == NULL && dlr_err != NULL) { unsigned char ctmp[3]; ctmp[0] = 3; /* we assume here its a GSM error due to lack of other information */ ctmp[1] = (err_int >> 8) & 0xFF; ctmp[2] = (err_int & 0xFF); network_err = octstr_create_from_data((char*)ctmp, 3); } if (dlrmsg != NULL) { /* * we found the delivery report in our storage, so recode the * message structure. * The DLR trigger URL is indicated by msg->sms.dlr_url. * Add the DLR error code to meta-data. */ dlrmsg->sms.msgdata = octstr_duplicate(respstr); dlrmsg->sms.sms_type = report_mo; dlrmsg->sms.account = octstr_duplicate(smpp->username); if (network_err != NULL) { if (dlrmsg->sms.meta_data == NULL) { dlrmsg->sms.meta_data = octstr_create(""); } meta_data_set_value(dlrmsg->sms.meta_data, "smpp", octstr_imm("dlr_err"), network_err, 1); } } else { error(0,"SMPP[%s]: got DLR but could not find message or was not interested " "in it id<%s> dst<%s>, type<%d>", octstr_get_cstr(smpp->conn->id), octstr_get_cstr(tmp), octstr_get_cstr(destination_addr), dlrstat); } octstr_destroy(tmp); octstr_destroy(network_err); octstr_destroy(dlr_err); return dlrmsg; } static long smscconn_failure_reason_to_smpp_status(long reason) { switch (reason) { case SMSCCONN_FAILED_REJECTED: return SMPP_ESME_RX_R_APPN; case SMSCCONN_SUCCESS: return SMPP_ESME_ROK; case SMSCCONN_FAILED_QFULL: case SMSCCONN_FAILED_TEMPORARILY: return SMPP_ESME_RX_T_APPN; } return SMPP_ESME_RX_T_APPN; } static int handle_pdu(SMPP *smpp, Connection *conn, SMPP_PDU *pdu, long *pending_submits) { SMPP_PDU *resp = NULL; Octstr *os; Msg *msg = NULL, *dlrmsg=NULL; struct smpp_msg *smpp_msg = NULL; long reason, cmd_stat; int ret = 0; /* * In order to keep the protocol implementation logically clean, * we will obey the required SMPP session state while processing * the PDUs, see Table 2-1, SMPP v3.4 spec, section 2.3, page 17. * Therefore we will interpret our abstracted smpp->conn->status * value as SMPP session state here. */ switch (pdu->type) { case data_sm: /* * Session state check */ if (!(smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV)) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session not bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } resp = smpp_pdu_create(data_sm_resp, pdu->u.data_sm.sequence_number); /* * If SMSCConn stopped then send temp. error code */ mutex_lock(smpp->conn->flow_mutex); if (smpp->conn->is_stopped) { mutex_unlock(smpp->conn->flow_mutex); resp->u.data_sm_resp.command_status = SMPP_ESME_RX_T_APPN; break; } mutex_unlock(smpp->conn->flow_mutex); /* got a deliver ack (DLR)? * NOTE: following SMPP v3.4. spec. we are interested * only on bits 2-5 (some SMSC's send 0x44, and it's * spec. conforme) */ if (pdu->u.data_sm.esm_class & (0x04|0x08|0x20)) { debug("bb.sms.smpp",0,"SMPP[%s] handle_pdu, got DLR", octstr_get_cstr(smpp->conn->id)); dlrmsg = handle_dlr(smpp, pdu->u.data_sm.source_addr, NULL, pdu->u.data_sm.message_payload, pdu->u.data_sm.receipted_message_id, pdu->u.data_sm.message_state, pdu->u.data_sm.network_error_code); if (dlrmsg != NULL) { if (dlrmsg->sms.meta_data == NULL) dlrmsg->sms.meta_data = octstr_create(""); meta_data_set_values(dlrmsg->sms.meta_data, pdu->u.data_sm.tlv, "smpp", 0); /* passing DLR to upper layer */ reason = bb_smscconn_receive(smpp->conn, dlrmsg); } else { /* no DLR will be passed, but we write an access-log entry */ msg = data_sm_to_msg(smpp, pdu, &reason); if (msg == NULL || reason != SMPP_ESME_ROK) { resp->u.data_sm_resp.command_status = reason; break; } reason = SMSCCONN_SUCCESS; bb_alog_sms(smpp->conn, msg, "FAILED Receive DLR"); msg_destroy(msg); } resp->u.data_sm_resp.command_status = smscconn_failure_reason_to_smpp_status(reason); } else { /* MO message */ msg = data_sm_to_msg(smpp, pdu, &reason); if (msg == NULL || reason != SMPP_ESME_ROK) { resp->u.data_sm_resp.command_status = reason; break; } /* Replace MO destination number with my-number */ if (octstr_len(smpp->my_number)) { octstr_destroy(msg->sms.receiver); msg->sms.receiver = octstr_duplicate(smpp->my_number); } time(&msg->sms.time); msg->sms.smsc_id = octstr_duplicate(smpp->conn->id); reason = bb_smscconn_receive(smpp->conn, msg); resp->u.data_sm_resp.command_status = smscconn_failure_reason_to_smpp_status(reason); } break; case deliver_sm: /* * Session state check */ if (!(smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV)) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session not bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } /* * If SMSCConn stopped then send temp. error code */ mutex_lock(smpp->conn->flow_mutex); if (smpp->conn->is_stopped) { mutex_unlock(smpp->conn->flow_mutex); resp = smpp_pdu_create(deliver_sm_resp, pdu->u.deliver_sm.sequence_number); resp->u.deliver_sm_resp.command_status = SMPP_ESME_RX_T_APPN; break; } mutex_unlock(smpp->conn->flow_mutex); /* * Got a deliver ack (DLR)? * NOTE: following SMPP v3.4. spec. we are interested * only on bits 2-5 (some SMSC's send 0x44, and it's * spec. conforme) */ if (pdu->u.deliver_sm.esm_class & (0x04|0x08|0x20)) { debug("bb.sms.smpp",0,"SMPP[%s] handle_pdu, got DLR", octstr_get_cstr(smpp->conn->id)); dlrmsg = handle_dlr(smpp, pdu->u.deliver_sm.source_addr, pdu->u.deliver_sm.short_message, pdu->u.deliver_sm.message_payload, pdu->u.deliver_sm.receipted_message_id, pdu->u.deliver_sm.message_state, pdu->u.deliver_sm.network_error_code); resp = smpp_pdu_create(deliver_sm_resp, pdu->u.deliver_sm.sequence_number); if (dlrmsg != NULL) { if (dlrmsg->sms.meta_data == NULL) dlrmsg->sms.meta_data = octstr_create(""); meta_data_set_values(dlrmsg->sms.meta_data, pdu->u.deliver_sm.tlv, "smpp", 0); /* passing DLR to upper layer */ reason = bb_smscconn_receive(smpp->conn, dlrmsg); } else { /* no DLR will be passed, but we write an access-log entry */ msg = pdu_to_msg(smpp, pdu, &reason); if (msg == NULL) { resp->u.deliver_sm_resp.command_status = reason; break; } reason = SMSCCONN_SUCCESS; bb_alog_sms(smpp->conn, msg, "FAILED Receive DLR"); msg_destroy(msg); } resp->u.deliver_sm_resp.command_status = smscconn_failure_reason_to_smpp_status(reason); } else {/* MO-SMS */ resp = smpp_pdu_create(deliver_sm_resp, pdu->u.deliver_sm.sequence_number); /* ensure the smsc-id is set */ msg = pdu_to_msg(smpp, pdu, &reason); if (msg == NULL) { resp->u.deliver_sm_resp.command_status = reason; break; } /* Replace MO destination number with my-number */ if (octstr_len(smpp->my_number)) { octstr_destroy(msg->sms.receiver); msg->sms.receiver = octstr_duplicate(smpp->my_number); } time(&msg->sms.time); msg->sms.smsc_id = octstr_duplicate(smpp->conn->id); msg->sms.account = octstr_duplicate(smpp->username); reason = bb_smscconn_receive(smpp->conn, msg); resp->u.deliver_sm_resp.command_status = smscconn_failure_reason_to_smpp_status(reason); } break; case enquire_link: /* * Session state check */ if (!(smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV)) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session not bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } resp = smpp_pdu_create(enquire_link_resp, pdu->u.enquire_link.sequence_number); break; case enquire_link_resp: /* * Session state check */ if (!(smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV)) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session not bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } if (pdu->u.enquire_link_resp.command_status != 0) { error(0, "SMPP[%s]: SMSC got error to enquire_link PDU, code 0x%08lx (%s).", octstr_get_cstr(smpp->conn->id), pdu->u.enquire_link_resp.command_status, smpp_error_to_string(pdu->u.enquire_link_resp.command_status)); } break; case submit_sm_resp: /* * Session state check */ if (!(smpp->conn->status == SMSCCONN_ACTIVE)) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session not bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } os = octstr_format("%ld", pdu->u.submit_sm_resp.sequence_number); smpp_msg = dict_remove(smpp->sent_msgs, os); octstr_destroy(os); if (smpp_msg == NULL) { warning(0, "SMPP[%s]: SMSC sent submit_sm_resp PDU " "with wrong sequence number 0x%08lx", octstr_get_cstr(smpp->conn->id), pdu->u.submit_sm_resp.sequence_number); break; } msg = smpp_msg->msg; smpp_msg_destroy(smpp_msg, 0); /* pack submit_sm_resp TLVs into metadata */ if (msg->sms.meta_data == NULL) msg->sms.meta_data = octstr_create(""); meta_data_set_values(msg->sms.meta_data, pdu->u.submit_sm_resp.tlv, "smpp_resp", 1); if (pdu->u.submit_sm_resp.command_status != 0) { error(0, "SMPP[%s]: SMSC returned error code 0x%08lx (%s) " "in response to submit_sm PDU.", octstr_get_cstr(smpp->conn->id), pdu->u.submit_sm_resp.command_status, smpp_error_to_string(pdu->u.submit_sm_resp.command_status)); reason = smpp_status_to_smscconn_failure_reason( pdu->u.submit_sm_resp.command_status); /* * check to see if we got a "throttling error", in which case we'll just * sleep for a while */ if (pdu->u.submit_sm_resp.command_status == SMPP_ESME_RTHROTTLED) time(&(smpp->throttling_err_time)); else smpp->throttling_err_time = 0; bb_smscconn_send_failed(smpp->conn, msg, reason, octstr_format("0x%08lx/%s", pdu->u.submit_sm_resp.command_status, smpp_error_to_string(pdu->u.submit_sm_resp.command_status))); --(*pending_submits); } else if (pdu->u.submit_sm_resp.message_id != NULL) { Octstr *tmp; /* check if msg_id is C string, decimal or hex for this SMSC */ if (smpp->smpp_msg_id_type == -1) { /* the default, C string */ tmp = octstr_duplicate(pdu->u.submit_sm_resp.message_id); } else { if ((smpp->smpp_msg_id_type & 0x01) || (!octstr_check_range(pdu->u.submit_sm_resp.message_id, 0, octstr_len(pdu->u.submit_sm_resp.message_id), gw_isdigit))) { tmp = octstr_format("%llu", strtoll( /* hex */ octstr_get_cstr(pdu->u.submit_sm_resp.message_id), NULL, 16)); } else { tmp = octstr_format("%llu", strtoll( /* decimal */ octstr_get_cstr(pdu->u.submit_sm_resp.message_id), NULL, 10)); } } /* * SMSC ACK.. now we have the message ID. * The message ID is inserted into the msg struct in dlr_add(), * and we add it manually here if no DLR was requested, in * order to get it logged to access-log. */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) { dlr_add(smpp->conn->id, tmp, msg, 0); octstr_destroy(tmp); } else { octstr_destroy(msg->sms.foreign_id); msg->sms.foreign_id = tmp; } bb_smscconn_sent(smpp->conn, msg, NULL); --(*pending_submits); } /* end if for SMSC ACK */ else { error(0, "SMPP[%s]: SMSC returned error code 0x%08lx (%s) " "in response to submit_sm PDU, but no `message_id' value!", octstr_get_cstr(smpp->conn->id), pdu->u.submit_sm_resp.command_status, smpp_error_to_string(pdu->u.submit_sm_resp.command_status)); bb_smscconn_sent(smpp->conn, msg, NULL); --(*pending_submits); } break; case bind_transmitter_resp: /* * Session state check */ if (smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } if (pdu->u.bind_transmitter_resp.command_status != 0 && pdu->u.bind_transmitter_resp.command_status != SMPP_ESME_RALYBND) { error(0, "SMPP[%s]: SMSC rejected login to transmit, code 0x%08lx (%s).", octstr_get_cstr(smpp->conn->id), pdu->u.bind_transmitter_resp.command_status, smpp_error_to_string(pdu->u.bind_transmitter_resp.command_status)); mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(smpp->conn->flow_mutex); if (pdu->u.bind_transmitter_resp.command_status == SMPP_ESME_RINVSYSID || pdu->u.bind_transmitter_resp.command_status == SMPP_ESME_RINVPASWD || pdu->u.bind_transmitter_resp.command_status == SMPP_ESME_RINVSYSTYP) { smpp->quitting = 1; } } else { *pending_submits = 0; mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_ACTIVE; time(&smpp->conn->connect_time); mutex_unlock(smpp->conn->flow_mutex); bb_smscconn_connected(smpp->conn); } break; case bind_transceiver_resp: /* * Session state check */ if (smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } if (pdu->u.bind_transceiver_resp.command_status != 0 && pdu->u.bind_transceiver_resp.command_status != SMPP_ESME_RALYBND) { error(0, "SMPP[%s]: SMSC rejected login to transmit, code 0x%08lx (%s).", octstr_get_cstr(smpp->conn->id), pdu->u.bind_transceiver_resp.command_status, smpp_error_to_string(pdu->u.bind_transceiver_resp.command_status)); mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(smpp->conn->flow_mutex); if (pdu->u.bind_transceiver_resp.command_status == SMPP_ESME_RINVSYSID || pdu->u.bind_transceiver_resp.command_status == SMPP_ESME_RINVPASWD || pdu->u.bind_transceiver_resp.command_status == SMPP_ESME_RINVSYSTYP) { smpp->quitting = 1; } } else { *pending_submits = 0; mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_ACTIVE; time(&smpp->conn->connect_time); mutex_unlock(smpp->conn->flow_mutex); bb_smscconn_connected(smpp->conn); } break; case bind_receiver_resp: /* * Session state check */ if (smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } if (pdu->u.bind_receiver_resp.command_status != 0 && pdu->u.bind_receiver_resp.command_status != SMPP_ESME_RALYBND) { error(0, "SMPP[%s]: SMSC rejected login to receive, code 0x%08lx (%s).", octstr_get_cstr(smpp->conn->id), pdu->u.bind_receiver_resp.command_status, smpp_error_to_string(pdu->u.bind_receiver_resp.command_status)); mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(smpp->conn->flow_mutex); if (pdu->u.bind_receiver_resp.command_status == SMPP_ESME_RINVSYSID || pdu->u.bind_receiver_resp.command_status == SMPP_ESME_RINVPASWD || pdu->u.bind_receiver_resp.command_status == SMPP_ESME_RINVSYSTYP) { smpp->quitting = 1; } } else { /* set only receive status if no transmit is bind */ mutex_lock(smpp->conn->flow_mutex); if (smpp->conn->status != SMSCCONN_ACTIVE) { smpp->conn->status = SMSCCONN_ACTIVE_RECV; time(&smpp->conn->connect_time); } mutex_unlock(smpp->conn->flow_mutex); } break; case unbind: /* * Session state check */ if (!(smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV)) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session not bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } resp = smpp_pdu_create(unbind_resp, pdu->u.unbind.sequence_number); mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(smpp->conn->flow_mutex); *pending_submits = -1; break; case unbind_resp: /* * Session state check */ if (!(smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV)) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session not bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(smpp->conn->flow_mutex); break; case generic_nack: /* * Session state check */ if (!(smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV)) { warning(0, "SMPP[%s]: SMSC sent %s PDU while session not bound, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name); return 0; } cmd_stat = pdu->u.generic_nack.command_status; os = octstr_format("%ld", pdu->u.generic_nack.sequence_number); smpp_msg = dict_remove(smpp->sent_msgs, os); octstr_destroy(os); if (smpp_msg == NULL) { error(0, "SMPP[%s]: SMSC rejected last command, code 0x%08lx (%s).", octstr_get_cstr(smpp->conn->id), cmd_stat, smpp_error_to_string(cmd_stat)); } else { msg = smpp_msg->msg; smpp_msg_destroy(smpp_msg, 0); error(0, "SMPP[%s]: SMSC returned error code 0x%08lx (%s) in response to submit_sm PDU.", octstr_get_cstr(smpp->conn->id), cmd_stat, smpp_error_to_string(cmd_stat)); /* * check to see if we got a "throttling error", in which case we'll just * sleep for a while */ if (cmd_stat == SMPP_ESME_RTHROTTLED) time(&(smpp->throttling_err_time)); else smpp->throttling_err_time = 0; reason = smpp_status_to_smscconn_failure_reason(cmd_stat); bb_smscconn_send_failed(smpp->conn, msg, reason, octstr_format("0x%08lx/%s", cmd_stat, smpp_error_to_string(cmd_stat))); --(*pending_submits); } break; default: error(0, "SMPP[%s]: Unhandled %s PDU type 0x%08lx, ignored.", octstr_get_cstr(smpp->conn->id), pdu->type_name, pdu->type); /* * We received an unknown PDU type, therefore we will respond * with a generic_nack PDU, see SMPP v3.4 spec, section 3.3. */ ret = send_gnack(smpp, conn, SMPP_ESME_RINVCMDID, pdu->u.generic_nack.sequence_number); break; } if (resp != NULL) { ret = send_pdu(conn, smpp, resp) != -1 ? 0 : -1; smpp_pdu_destroy(resp); } return ret; } struct io_arg { SMPP *smpp; int transmitter; }; static struct io_arg *io_arg_create(SMPP *smpp, int transmitter) { struct io_arg *io_arg; io_arg = gw_malloc(sizeof(*io_arg)); io_arg->smpp = smpp; io_arg->transmitter = transmitter; return io_arg; } /* * sent queue cleanup. * @return 1 if io_thread should reconnect; 0 if not */ static int do_queue_cleanup(SMPP *smpp, long *pending_submits) { List *keys; Octstr *key; struct smpp_msg *smpp_msg; time_t now = time(NULL); if (*pending_submits <= 0) return 0; /* check if action set to wait ack for ever */ if (smpp->wait_ack_action == SMPP_WAITACK_NEVER_EXPIRE) return 0; keys = dict_keys(smpp->sent_msgs); if (keys == NULL) return 0; while ((key = gwlist_extract_first(keys)) != NULL) { smpp_msg = dict_get(smpp->sent_msgs, key); if (smpp_msg != NULL && difftime(now, smpp_msg->sent_time) > smpp->wait_ack) { switch(smpp->wait_ack_action) { case SMPP_WAITACK_RECONNECT: /* reconnect */ /* found at least one not acked msg */ warning(0, "SMPP[%s]: Not ACKED message found, reconnecting.", octstr_get_cstr(smpp->conn->id)); octstr_destroy(key); gwlist_destroy(keys, octstr_destroy_item); return 1; /* io_thread will reconnect */ case SMPP_WAITACK_REQUEUE: /* requeue */ smpp_msg = dict_remove(smpp->sent_msgs, key); if (smpp_msg != NULL) { warning(0, "SMPP[%s]: Not ACKED message found, will retransmit." " SENT<%ld>sec. ago, SEQ<%s>, DST<%s>", octstr_get_cstr(smpp->conn->id), (long)difftime(now, smpp_msg->sent_time) , octstr_get_cstr(key), octstr_get_cstr(smpp_msg->msg->sms.receiver)); bb_smscconn_send_failed(smpp->conn, smpp_msg->msg, SMSCCONN_FAILED_TEMPORARILY,NULL); smpp_msg_destroy(smpp_msg, 0); (*pending_submits)--; } break; default: error(0, "SMPP[%s] Unknown clenup action defined 0x%02x.", octstr_get_cstr(smpp->conn->id), smpp->wait_ack_action); octstr_destroy(key); gwlist_destroy(keys, octstr_destroy_item); return 0; } } octstr_destroy(key); } gwlist_destroy(keys, octstr_destroy_item); return 0; } /* * This is the main function for the background thread for doing I/O on * one SMPP connection (the one for transmitting or receiving messages). * It makes the initial connection to the SMPP server and re-connects * if there are I/O errors or other errors that require it. */ static void io_thread(void *arg) { SMPP *smpp; struct io_arg *io_arg; int transmitter; Connection *conn; int ret; long pending_submits; long len; SMPP_PDU *pdu; double timeout; time_t last_cleanup, last_enquire_sent, last_response, now; io_arg = arg; smpp = io_arg->smpp; transmitter = io_arg->transmitter; gw_free(io_arg); /* Make sure we log into our own log-file if defined */ log_thread_to(smpp->conn->log_idx); #define IS_ACTIVE (smpp->conn->status == SMSCCONN_ACTIVE || smpp->conn->status == SMSCCONN_ACTIVE_RECV) conn = NULL; while (!smpp->quitting) { if (transmitter == 1) conn = open_transmitter(smpp); else if (transmitter == 2) conn = open_transceiver(smpp); else conn = open_receiver(smpp); pending_submits = -1; len = 0; last_response = last_cleanup = last_enquire_sent = time(NULL); while(conn != NULL) { ret = read_pdu(smpp, conn, &len, &pdu); if (ret == -1) { /* connection broken */ error(0, "SMPP[%s]: I/O error or other error. Re-connecting.", octstr_get_cstr(smpp->conn->id)); break; } else if (ret == -2) { /* wrong pdu length , send gnack */ len = 0; if (send_gnack(smpp, conn, SMPP_ESME_RINVCMDLEN, 0) == -1) { error(0, "SMPP[%s]: I/O error or other error. Re-connecting.", octstr_get_cstr(smpp->conn->id)); break; } } else if (ret == 1) { /* data available */ /* Deal with the PDU we just got */ dump_pdu("Got PDU:", smpp->conn->id, pdu, smpp->log_format); ret = handle_pdu(smpp, conn, pdu, &pending_submits); smpp_pdu_destroy(pdu); if (ret == -1) { error(0, "SMPP[%s]: I/O error or other error. Re-connecting.", octstr_get_cstr(smpp->conn->id)); break; } /* * check if we are still connected * Note: Function handle_pdu will set status to SMSCCONN_DISCONNECTED * when unbind was received. */ if (smpp->conn->status == SMSCCONN_DISCONNECTED) break; /* * If we are not bounded then no PDU may coming from SMSC. * It's just a workaround for buggy SMSC's who send enquire_link's * although link is not bounded. Means: we doesn't notice these and if link * keep to be not bounden we are reconnect after defined timeout elapsed. */ if (IS_ACTIVE) { /* * Store last response time. */ time(&last_response); } } else { /* no data available */ /* check last enquire_resp, if difftime > as idle_timeout * mark connection as broken. * We have some SMSC connections where connection seems to be OK, but * in reality is broken, because no responses received. */ if (smpp->connection_timeout > 0 && difftime(time(NULL), last_response) > smpp->connection_timeout) { /* connection seems to be broken */ warning(0, "Got no responses within %ld sec., reconnecting...", (long) difftime(time(NULL), last_response)); break; } time(&now); timeout = last_enquire_sent + smpp->enquire_link_interval - now; if (!IS_ACTIVE && timeout <= 0) timeout = smpp->enquire_link_interval; if (transmitter && gw_prioqueue_len(smpp->msgs_to_send) > 0 && smpp->throttling_err_time > 0 && pending_submits < smpp->max_pending_submits) { time_t tr_timeout = smpp->throttling_err_time + SMPP_THROTTLING_SLEEP_TIME - now; timeout = timeout > tr_timeout ? tr_timeout : timeout; } else if (transmitter && gw_prioqueue_len(smpp->msgs_to_send) > 0 && smpp->conn->throughput > 0 && smpp->max_pending_submits > pending_submits) { double t = 1.0 / smpp->conn->throughput; timeout = t < timeout ? t : timeout; } /* sleep a while */ if (timeout > 0 && conn_wait(conn, timeout) == -1) break; } /* send enquire link, only if connection is active */ if (IS_ACTIVE && send_enquire_link(smpp, conn, &last_enquire_sent) == -1) break; /* cleanup sent queue */ if (transmitter && difftime(time(NULL), last_cleanup) > smpp->wait_ack) { if (do_queue_cleanup(smpp, &pending_submits)) break; /* reconnect */ time(&last_cleanup); } /* make sure we send */ if (transmitter && difftime(time(NULL), smpp->throttling_err_time) > SMPP_THROTTLING_SLEEP_TIME) { smpp->throttling_err_time = 0; if (send_messages(smpp, conn, &pending_submits) == -1) break; } /* unbind * Read so long as unbind_resp received or timeout passed. Otherwise we have * double delivered messages. */ if (smpp->quitting) { if (!IS_ACTIVE || send_unbind(smpp, conn) == -1) break; time(&last_response); while(conn_wait(conn, 1.00) != -1 && IS_ACTIVE && difftime(time(NULL), last_response) < SMPP_DEFAULT_SHUTDOWN_TIMEOUT) { if (read_pdu(smpp, conn, &len, &pdu) == 1) { dump_pdu("Got PDU:", smpp->conn->id, pdu, smpp->log_format); handle_pdu(smpp, conn, pdu, &pending_submits); smpp_pdu_destroy(pdu); } } debug("bb.sms.smpp", 0, "SMPP[%s]: %s: break and shutting down", octstr_get_cstr(smpp->conn->id), __PRETTY_FUNCTION__); break; } } if (conn != NULL) { conn_destroy(conn); conn = NULL; } /* set reconnecting status first so that core don't put msgs into our queue */ if (!smpp->quitting) { error(0, "SMPP[%s]: Couldn't connect to SMS center (retrying in %ld seconds).", octstr_get_cstr(smpp->conn->id), smpp->conn->reconnect_delay); mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_RECONNECTING; mutex_unlock(smpp->conn->flow_mutex); gwthread_sleep(smpp->conn->reconnect_delay); } /* * put all queued messages back into global queue,so if * we have another link running than messages will be delivered * quickly */ if (transmitter) { Msg *msg; struct smpp_msg *smpp_msg; List *noresp; Octstr *key; long reason = (smpp->quitting?SMSCCONN_FAILED_SHUTDOWN:SMSCCONN_FAILED_TEMPORARILY); while((msg = gw_prioqueue_remove(smpp->msgs_to_send)) != NULL) bb_smscconn_send_failed(smpp->conn, msg, reason, NULL); noresp = dict_keys(smpp->sent_msgs); while((key = gwlist_extract_first(noresp)) != NULL) { smpp_msg = dict_remove(smpp->sent_msgs, key); if (smpp_msg != NULL) { bb_smscconn_send_failed(smpp->conn, smpp_msg->msg, reason, NULL); smpp_msg_destroy(smpp_msg, 0); } octstr_destroy(key); } gwlist_destroy(noresp, NULL); } } #undef IS_ACTIVE /* * Shutdown sequence as follow: * 1) if this is TX session so join receiver and free SMPP * 2) if RX session available but no TX session so nothing to join then free SMPP */ if (transmitter && smpp->receiver != -1) { gwthread_wakeup(smpp->receiver); gwthread_join(smpp->receiver); } if (transmitter || smpp->transmitter == -1) { debug("bb.smpp", 0, "SMSCConn %s shut down.", octstr_get_cstr(smpp->conn->name)); mutex_lock(smpp->conn->flow_mutex); smpp->conn->status = SMSCCONN_DEAD; smpp->conn->data = NULL; mutex_unlock(smpp->conn->flow_mutex); smpp_destroy(smpp); bb_smscconn_killed(); } } /*********************************************************************** * Functions called by smscconn.c via the SMSCConn function pointers. */ static long queued_cb(SMSCConn *conn) { SMPP *smpp; smpp = conn->data; conn->load = (smpp ? (conn->status != SMSCCONN_DEAD ? gw_prioqueue_len(smpp->msgs_to_send) : 0) : 0); return conn->load; } static int send_msg_cb(SMSCConn *conn, Msg *msg) { SMPP *smpp; smpp = conn->data; gw_prioqueue_produce(smpp->msgs_to_send, msg_duplicate(msg)); gwthread_wakeup(smpp->transmitter); return 0; } static int shutdown_cb(SMSCConn *conn, int finish_sending) { SMPP *smpp; if (conn == NULL) return -1; debug("bb.smpp", 0, "Shutting down SMSCConn %s (%s)", octstr_get_cstr(conn->name), finish_sending ? "slow" : "instant"); mutex_lock(conn->flow_mutex); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; smpp = conn->data; if (smpp == NULL) { mutex_unlock(conn->flow_mutex); return 0; } smpp->quitting = 1; if (smpp->transmitter != -1) gwthread_wakeup(smpp->transmitter); if (smpp->receiver != -1) gwthread_wakeup(smpp->receiver); mutex_unlock(conn->flow_mutex); return 0; } /*********************************************************************** * Public interface. This version is suitable for the Kannel bearerbox * SMSCConn interface. */ int smsc_smpp_create(SMSCConn *conn, CfgGroup *grp) { Octstr *host; long port; long receive_port; Octstr *username; Octstr *password; Octstr *system_id; Octstr *system_type; Octstr *address_range; long source_addr_ton; long source_addr_npi; long dest_addr_ton; long dest_addr_npi; long our_port; long our_receiver_port; Octstr *my_number; Octstr *service_type; SMPP *smpp; int ok; int transceiver_mode; Octstr *smsc_id; long enquire_link_interval; long max_pending_submits; long version; long priority; long validity; long smpp_msg_id_type; int autodetect_addr; Octstr *alt_charset; Octstr *alt_addr_charset; long connection_timeout, wait_ack, wait_ack_action; long esm_class; my_number = alt_addr_charset = alt_charset = NULL; transceiver_mode = 0; autodetect_addr = 1; host = cfg_get(grp, octstr_imm("host")); if (cfg_get_integer(&port, grp, octstr_imm("port")) == -1) port = 0; if (cfg_get_integer(&receive_port, grp, octstr_imm("receive-port")) == -1) receive_port = 0; if (cfg_get_integer(&our_port, grp, octstr_imm("our-port")) == -1) our_port = 0; if (cfg_get_integer(&our_receiver_port, grp, octstr_imm("our-receiver-port")) == -1) our_receiver_port = 0; cfg_get_bool(&transceiver_mode, grp, octstr_imm("transceiver-mode")); username = cfg_get(grp, octstr_imm("smsc-username")); password = cfg_get(grp, octstr_imm("smsc-password")); system_type = cfg_get(grp, octstr_imm("system-type")); address_range = cfg_get(grp, octstr_imm("address-range")); my_number = cfg_get(grp, octstr_imm("my-number")); service_type = cfg_get(grp, octstr_imm("service-type")); system_id = cfg_get(grp, octstr_imm("system-id")); if (system_id != NULL) { warning(0, "SMPP: obsolete system-id variable is set, " "use smsc-username instead."); if (username == NULL) { warning(0, "SMPP: smsc-username not set, using system-id instead"); username = system_id; } else octstr_destroy(system_id); } /* * check if timing values have been configured, otherwise * use the predefined default values. */ if (cfg_get_integer(&enquire_link_interval, grp, octstr_imm("enquire-link-interval")) == -1) enquire_link_interval = SMPP_ENQUIRE_LINK_INTERVAL; if (cfg_get_integer(&max_pending_submits, grp, octstr_imm("max-pending-submits")) == -1) max_pending_submits = SMPP_MAX_PENDING_SUBMITS; /* Check that config is OK */ ok = 1; if (host == NULL) { error(0, "SMPP: Configuration file doesn't specify host"); ok = 0; } if (port == 0 && receive_port == 0) { port = SMPP_DEFAULT_PORT; warning(0, "SMPP: Configuration file doesn't specify port or receive-port. " "Using 'port = %ld' as default.", port); } if (port != 0 && receive_port != 0) { error(0, "SMPP: Configuration file can only have port or receive-port. " "Usage of both in one group is deprecated!"); ok = 0; } if (username == NULL) { error(0, "SMPP: Configuration file doesn't specify username."); ok = 0; } if (password == NULL) { error(0, "SMPP: Configuration file doesn't specify password."); ok = 0; } if (system_type == NULL) { error(0, "SMPP: Configuration file doesn't specify system-type."); ok = 0; } if (octstr_len(service_type) > 6) { error(0, "SMPP: Service type must be 6 characters or less."); ok = 0; } if (transceiver_mode && receive_port != 0) { warning(0, "SMPP: receive-port for transceiver mode defined, ignoring."); receive_port = 0; } if (!ok) return -1; /* if the ton and npi values are forced, set them, else set them to -1 */ if (cfg_get_integer(&source_addr_ton, grp, octstr_imm("source-addr-ton")) == -1) source_addr_ton = -1; if (cfg_get_integer(&source_addr_npi, grp, octstr_imm("source-addr-npi")) == -1) source_addr_npi = -1; if (cfg_get_integer(&dest_addr_ton, grp, octstr_imm("dest-addr-ton")) == -1) dest_addr_ton = -1; if (cfg_get_integer(&dest_addr_npi, grp, octstr_imm("dest-addr-npi")) == -1) dest_addr_npi = -1; /* if source addr autodetection should be used set this to 1 */ if (cfg_get_bool(&autodetect_addr, grp, octstr_imm("source-addr-autodetect")) == -1) autodetect_addr = 1; /* default is autodetect if no option defined */ /* check for any specified interface version */ if (cfg_get_integer(&version, grp, octstr_imm("interface-version")) == -1) version = SMPP_DEFAULT_VERSION; else /* convert decimal to BCD */ version = ((version / 10) << 4) + (version % 10); /* check for any specified priority value in range [0-5] */ if (cfg_get_integer(&priority, grp, octstr_imm("priority")) == -1) priority = SMPP_DEFAULT_PRIORITY; else if (priority < 0 || priority > 3) panic(0, "SMPP: Invalid value for priority directive in configuraton (allowed range 0-3)."); /* check for message validity period */ if (cfg_get_integer(&validity, grp, octstr_imm("validityperiod")) == -1) validity = SMS_PARAM_UNDEFINED; else if (validity < 0) panic(0, "SMPP: Invalid value for validity period (allowed value >= 0)."); /* set the msg_id type variable for this SMSC */ if (cfg_get_integer(&smpp_msg_id_type, grp, octstr_imm("msg-id-type")) == -1) { /* * defaults to C string "as-is" style */ smpp_msg_id_type = -1; } else { if (smpp_msg_id_type < 0 || smpp_msg_id_type > 3) panic(0,"SMPP: Invalid value for msg-id-type directive in configuraton"); } /* check for an alternative charset */ alt_charset = cfg_get(grp, octstr_imm("alt-charset")); alt_addr_charset = cfg_get(grp, octstr_imm("alt-addr-charset")); /* check for connection timeout */ if (cfg_get_integer(&connection_timeout, grp, octstr_imm("connection-timeout")) == -1) connection_timeout = SMPP_DEFAULT_CONNECTION_TIMEOUT; /* check if wait-ack timeout set */ if (cfg_get_integer(&wait_ack, grp, octstr_imm("wait-ack")) == -1) wait_ack = SMPP_DEFAULT_WAITACK; if (cfg_get_integer(&wait_ack_action, grp, octstr_imm("wait-ack-expire")) == -1) wait_ack_action = SMPP_WAITACK_REQUEUE; else if (wait_ack_action > 0x03 || wait_ack_action < 0) panic(0, "SMPP: Invalid wait-ack-expire directive in configuration."); if (cfg_get_integer(&esm_class, grp, octstr_imm("esm-class")) == -1) { esm_class = ESM_CLASS_SUBMIT_STORE_AND_FORWARD_MODE; } smpp = smpp_create(conn, host, port, receive_port, our_port, our_receiver_port, system_type, username, password, address_range, source_addr_ton, source_addr_npi, dest_addr_ton, dest_addr_npi, enquire_link_interval, max_pending_submits, version, priority, validity, my_number, smpp_msg_id_type, autodetect_addr, alt_charset, alt_addr_charset, service_type, connection_timeout, wait_ack, wait_ack_action, esm_class); cfg_get_integer(&smpp->bind_addr_ton, grp, octstr_imm("bind-addr-ton")); cfg_get_integer(&smpp->bind_addr_npi, grp, octstr_imm("bind-addr-npi")); cfg_get_bool(&smpp->use_ssl, grp, octstr_imm("use-ssl")); if (smpp->use_ssl) #ifndef HAVE_LIBSSL panic(0, "SMPP: Can not use 'use-ssl' without SSL support compiled in."); #else smpp->ssl_client_certkey_file = cfg_get(grp, octstr_imm("ssl-client-certkey-file")); #endif conn->data = smpp; conn->name = octstr_format("%sSMPP:%S:%d/%d:%S:%S", (smpp->use_ssl ? "S" : ""), host, port, (!receive_port && transceiver_mode ? port : receive_port), username, system_type); smsc_id = cfg_get(grp, octstr_imm("smsc-id")); if (smsc_id == NULL) { conn->id = octstr_duplicate(conn->name); } if (cfg_get_integer(&smpp->log_format, grp, octstr_imm("log-format")) == -1) smpp->log_format = SMPP_PDU_DUMP_MULTILINE; octstr_destroy(host); octstr_destroy(username); octstr_destroy(password); octstr_destroy(system_type); octstr_destroy(address_range); octstr_destroy(my_number); octstr_destroy(smsc_id); octstr_destroy(alt_charset); octstr_destroy(alt_addr_charset); octstr_destroy(service_type); conn->status = SMSCCONN_CONNECTING; /* * I/O threads are only started if the corresponding ports * have been configured with positive numbers. Use 0 to * disable the creation of the corresponding thread. */ if (port != 0) smpp->transmitter = gwthread_create(io_thread, io_arg_create(smpp, (transceiver_mode ? 2 : 1))); if (receive_port != 0) smpp->receiver = gwthread_create(io_thread, io_arg_create(smpp, 0)); if ((port != 0 && smpp->transmitter == -1) || (receive_port != 0 && smpp->receiver == -1)) { error(0, "SMPP[%s]: Couldn't start I/O threads.", octstr_get_cstr(smpp->conn->id)); smpp->quitting = 1; if (smpp->transmitter != -1) { gwthread_wakeup(smpp->transmitter); gwthread_join(smpp->transmitter); } if (smpp->receiver != -1) { gwthread_wakeup(smpp->receiver); gwthread_join(smpp->receiver); } smpp_destroy(conn->data); conn->data = NULL; return -1; } conn->shutdown = shutdown_cb; conn->queued = queued_cb; conn->send_msg = send_msg_cb; return 0; } gateway-1.4.5/gw/smsc/smsc_loopback.c0000644000175000017500000001317213227613126016240 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_loopback.c - loopback SMSC interface * * This SMSC type is the MT wise counterpart of the 'reroute' functionality * of the smsc group when MOs are re-routed as MT. This SMSC type re-routes * therefore MTs as MOs back again. * * Stipe Tolj */ #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "dlr.h" #define O_DESTROY(a) { octstr_destroy(a); a = NULL; } static int msg_cb(SMSCConn *conn, Msg *msg) { Msg *sms; /* create duplicates first */ sms = msg_duplicate(msg); /* store temporary DLR data for SMSC ACK */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask) && !uuid_is_null(sms->sms.id)) { Octstr *mid; char id[UUID_STR_LEN + 1]; uuid_unparse(sms->sms.id, id); mid = octstr_create(id); dlr_add(conn->id, mid, sms, 0); octstr_destroy(mid); } /* * Inform abstraction layer of sent event, * it will also take care of DLR SMSC events. */ bb_smscconn_sent(conn, sms, NULL); /* now change msg type to reflect flow type */ sms = msg_duplicate(msg); sms->sms.sms_type = mo; /* Since this is a new MO now, make sure that the * values we have still from the MT are cleaned. */ uuid_clear(sms->sms.id); uuid_generate(sms->sms.id); O_DESTROY(sms->sms.boxc_id); sms->sms.dlr_mask = MSG_PARAM_UNDEFINED; O_DESTROY(sms->sms.dlr_url); /* * If there is a reroute-smsc-id in the config group, * then let's use that value, otherwise assign the * smsc-id canonical name for the MO. * This re-assignment of the smsc-id provides some * MO routing capabilities, i.e. via smsbox-route group. */ octstr_destroy(sms->sms.smsc_id); if (conn->reroute_to_smsc) { sms->sms.smsc_id = octstr_duplicate(conn->reroute_to_smsc); } else { sms->sms.smsc_id = octstr_duplicate(conn->id); } /* now pass back again as MO to the abstraction layer */ bb_smscconn_receive(conn, sms); return 0; } static int shutdown_cb(SMSCConn *conn, int finish_sending) { debug("smsc.loopback", 0, "Shutting down SMSCConn %s", octstr_get_cstr(conn->name)); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; conn->status = SMSCCONN_DEAD; bb_smscconn_killed(); return 0; } static void start_cb(SMSCConn *conn) { conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); } static long queued_cb(SMSCConn *conn) { long ret = 0; conn->load = ret; return ret; } int smsc_loopback_create(SMSCConn *conn, CfgGroup *cfg) { conn->data = NULL; conn->name = octstr_format("LOOPBACK:%S", conn->id); conn->status = SMSCCONN_CONNECTING; conn->connect_time = time(NULL); conn->shutdown = shutdown_cb; conn->queued = queued_cb; conn->start_conn = start_cb; conn->send_msg = msg_cb; return 0; } gateway-1.4.5/gw/smsc/emimsg.h0000644000175000017500000001057113227613126014707 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * emimsg.h * * Declarations needed with EMI messages * Uoti Urpala 2001 */ #ifndef EMIMSG_H #define EMIMSG_H #include "gwlib/gwlib.h" struct emimsg { int trn; char or; int ot; int num_fields; Octstr **fields; }; /* Symbolic constants for the number of a field in a message */ enum { E01_ADC, E01_OADC, E01_AC, E01_MT, E01_AMSG, SZ01 }; /* All the 50-series messages have the same number of fields */ enum { E50_ADC, E50_OADC, E50_AC, E50_NRQ, E50_NADC, E50_NT, E50_NPID, E50_LRQ, E50_LRAD, E50_LPID, E50_DD, E50_DDT, E50_VP, E50_RPID, E50_SCTS, E50_DST, E50_RSN, E50_DSCTS, E50_MT, E50_NB, E50_NMSG=20, E50_AMSG=20, E50_TMSG=20, E50_MMS, E50_PR, E50_DCS, E50_MCLS, E50_RPI, E50_CPG, E50_RPLY, E50_OTOA, E50_HPLMN, E50_XSER, E50_RES4, E50_RES5, SZ50 }; enum { E60_OADC, E60_OTON, E60_ONPI, E60_STYP, E60_PWD, E60_NPWD, E60_VERS, E60_LADC, E60_LTON, E60_LNPI, E60_OPID, E60_RES1, SZ60 }; /* Create an EMI msg struct with operation type OT and TRN */ struct emimsg *emimsg_create_op(int ot, int trn, Octstr *whoami); /* Create an empty EMI msg struct as reply */ struct emimsg *emimsg_create_reply(int ot, int trn, int positive, Octstr *whoami); /* Destroy an EMI msg struct */ void emimsg_destroy(struct emimsg *emimsg); /* Duplicate an EMI msg struct */ struct emimsg *emimsg_duplicate(struct emimsg *emimsg); /* Create an emimsg struct from the string. */ /* Doesn't check that the string is strictly according to format */ struct emimsg *get_fields(Octstr *message, Octstr *whoami); /* Send emimsg over conn using the EMI protocol. */ int emimsg_send(Connection *conn, struct emimsg *emimsg, Octstr *whoami); #endif gateway-1.4.5/gw/smsc/smsc_emi.c0000644000175000017500000016343313227613126015226 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_emi.c - interface to EMI/UCP SMS centers * * Uoti Urpala 2001 * Alexander Malysh and Stipe Tolj 2002-2003 * Vincent Chavanis 2005-2006 * * References: * * [1] Short Message Service Centre 4.6 EMI - UCP Interface Specification * document version 4.6, April 2003, CMG Wireless Data Solutions. */ /* Doesn't warn about unrecognized configuration variables */ /* The EMI specification doesn't document how connections should be * opened/used. The way they currently work might need to be changed. */ #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "msg.h" #include "sms.h" #include "emimsg.h" #include "dlr.h" #include "alt_charsets.h" #define EMI2_MAX_TRN 100 typedef struct privdata { Octstr *name; gw_prioqueue_t *outgoing_queue; long receiver_thread; long sender_thread; int shutdown; /* Internal signal to shut down */ int listening_socket; /* File descriptor */ int send_socket; int port, alt_port; /* SMSC port */ int our_port; /* Optional local port number in which to * bind our end of send connection */ int rport; /* Receive-port to listen */ Octstr *allow_ip, *deny_ip; Octstr *host, *alt_host, *username, *password; Octstr *my_number; /* My number if we want to force one */ int unacked; /* Sent messages not acked */ struct { time_t sendtime; /* When we sent out a message with a given * TRN. Is 0 if the TRN slot is currently free. */ int sendtype; /* OT of message, undefined if time == 0 */ Msg *sendmsg; /* Corresponding message for OT == 51 */ } slots[EMI2_MAX_TRN]; int keepalive; /* Seconds to send a Keepalive Command (OT=31) */ int flowcontrol; /* 0=Windowing, 1=Stop-and-Wait */ int waitack; /* Seconds to wait to ack */ int waitack_expire; /* What to do on waitack expire */ int window; /* In windowed flow-control, the window size */ int can_write; /* write = 1, read = 0, for stop-and-wait flow control */ int priv_nexttrn; /* next TRN, this should never be accessed directly. * use int emi2_next_trn (SMSCConn *conn) instead. */ time_t last_activity_time; /* the last time something was sent over the main * SMSC connection */ time_t check_time; int idle_timeout; /* Seconds a Main connection to the SMSC is allowed to be idle. If 0, no idle timeout is in effect */ Octstr *npid; /* Notification PID value */ Octstr *nadc; /* Notification Address */ int alt_charset; /* Alternative GSM charset, defined via values in gwlib/alt_charsets.h */ } PrivData; typedef enum { EMI2_SENDREQ, /* somebody asked this driver to send a SMS message */ EMI2_SMSCREQ, /* the SMSC wants something from us */ EMI2_CONNERR, /* an error condition in the SMSC main connection */ EMI2_TIMEOUT, /* timeout on the SMSC main connection */ } EMI2Event; #define PRIVDATA(conn) ((PrivData *)((conn)->data)) #define SLOTBUSY(conn,i) (PRIVDATA(conn)->slots[(i)].sendtime != 0) #define CONNECTIONIDLE(conn) \ ((PRIVDATA(conn)->unacked == 0) && \ (PRIVDATA(conn)->idle_timeout ? \ (PRIVDATA(conn)->last_activity_time + PRIVDATA(conn)->idle_timeout) <= time(0):0)) #define emi2_can_send(conn) \ ((PRIVDATA(conn)->can_write || !PRIVDATA(conn)->flowcontrol) && \ (PRIVDATA(conn)->unacked < PRIVDATA(conn)->window) && \ (!PRIVDATA(conn)->shutdown)) #define emi2_needs_keepalive(conn) \ (emi2_can_send(conn) && \ (PRIVDATA(conn)->keepalive > 0) && \ (time(NULL) > (PRIVDATA(conn)->last_activity_time + PRIVDATA(conn)->keepalive))) /* * Send an EMI message and update the last_activity_time field. */ static int emi2_emimsg_send(SMSCConn *conn, Connection *server, struct emimsg *emimsg) { int result = emimsg_send(server, emimsg, PRIVDATA(conn)->name); if (result >= 0 && emimsg->or == 'O' && ( emimsg->ot == 31 || emimsg->ot == 51)) { PRIVDATA(conn)->last_activity_time = time (NULL); } return result; } /* Wait for a message of type 'ot', sent with TRN 0, to be acked. * Timeout after 't' seconds. Any other packets received are ignored. * This function is meant for initial login packet(s) and testing. * Return 1 for positive ACK, 0 for timeout, -1 for broken/closed connection, * -2 for negative NACK. */ static int wait_for_ack(PrivData *privdata, Connection *server, int ot, int t) { time_t timeout_time; int time_left; Octstr *str; struct emimsg *emimsg; timeout_time = time(NULL) + t; while (1) { str = conn_read_packet(server, 2, 3); if (conn_eof(server)) { error(0, "EMI2[%s]: connection closed in wait_for_ack", octstr_get_cstr(privdata->name)); return -1; } if (conn_error(server)) { error(0, "EMI2[%s]: connection error in wait_for_ack", octstr_get_cstr(privdata->name)); return -1; } if (str) { emimsg = get_fields(str, privdata->name); if (emimsg == NULL) { octstr_destroy(str); continue; } if (emimsg->ot == ot && emimsg->trn == 0 && emimsg->or == 'R') { octstr_destroy(str); break; } warning(0, "EMI2[%s]: ignoring message %s while waiting for ack to" "ot:%d trn:%d", octstr_get_cstr(privdata->name), octstr_get_cstr(str), ot, 0); emimsg_destroy(emimsg); octstr_destroy(str); } time_left = timeout_time - time(NULL); if (time_left < 0 || privdata->shutdown) return 0; conn_wait(server, time_left); } if (octstr_get_char(emimsg->fields[0], 0) == 'N') { emimsg_destroy(emimsg); return -2; } emimsg_destroy(emimsg); return 1; } static struct emimsg *make_emi31(PrivData *privdata, int trn) { struct emimsg *emimsg; if(octstr_len(privdata->username) || octstr_len(privdata->my_number)) { emimsg = emimsg_create_op(31, trn, privdata->name); if(octstr_len(privdata->username)) { emimsg->fields[0] = octstr_duplicate(privdata->username); } else { emimsg->fields[0] = octstr_duplicate(privdata->my_number); } emimsg->fields[1] = octstr_create("0539"); return emimsg; } else { return NULL; } } static struct emimsg *make_emi60(PrivData *privdata) { struct emimsg *emimsg; emimsg = emimsg_create_op(60, 0, privdata->name); emimsg->fields[E60_OADC] = octstr_duplicate(privdata->username); emimsg->fields[E60_OTON] = octstr_create("6"); emimsg->fields[E60_ONPI] = octstr_create("5"); emimsg->fields[E60_STYP] = octstr_create("1"); emimsg->fields[E60_PWD] = octstr_duplicate(privdata->password); octstr_binary_to_hex(emimsg->fields[E60_PWD], 1); emimsg->fields[E60_VERS] = octstr_create("0100"); return emimsg; } static Connection *open_send_connection(SMSCConn *conn) { PrivData *privdata = conn->data; int result, alt_host, do_alt_host; struct emimsg *emimsg; Connection *server; Msg *msg; int connect_error = 0; int wait_ack = 0; do_alt_host = octstr_len(privdata->alt_host) != 0 || privdata->alt_port != 0; alt_host = 0; mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); while (!privdata->shutdown) { while ((msg = gw_prioqueue_remove(privdata->outgoing_queue))) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); } /* if there is no alternative host, sleep and try to re-connect */ if (alt_host == 0 && connect_error) { error(0, "EMI2[%s]: Couldn't connect to SMS center (retrying in %ld seconds).", octstr_get_cstr(privdata->name), conn->reconnect_delay); gwthread_sleep(conn->reconnect_delay); } if (alt_host != 1) { info(0, "EMI2[%s]: connecting to Primary SMSC", octstr_get_cstr(privdata->name)); mutex_lock(conn->flow_mutex); octstr_destroy(conn->name); conn->name = octstr_format("EMI2:%S:%d:%S", privdata->host, privdata->port, privdata->username ? privdata->username : octstr_imm("null")); mutex_unlock(conn->flow_mutex); server = conn_open_tcp_with_port(privdata->host, privdata->port, privdata->our_port, conn->our_host); if(do_alt_host) alt_host=1; else alt_host=0; } else { info(0, "EMI2[%s]: connecting to Alternate SMSC", octstr_get_cstr(privdata->name)); /* use alt_host or/and alt_port if defined */ mutex_lock(conn->flow_mutex); octstr_destroy(conn->name); conn->name = octstr_format("EMI2:%S:%d:%S", octstr_len(privdata->alt_host) ? privdata->alt_host : privdata->host, privdata->alt_port ? privdata->alt_port : privdata->port, privdata->username ? privdata->username : octstr_imm("null")); mutex_unlock(conn->flow_mutex); server = conn_open_tcp_with_port( (octstr_len(privdata->alt_host) ? privdata->alt_host : privdata->host), (privdata->alt_port ? privdata->alt_port : privdata->port), privdata->our_port, conn->our_host); alt_host=0; } if (privdata->shutdown) { conn_destroy(server); return NULL; } if (server == NULL) { error(0, "EMI2[%s]: opening TCP connection to %s failed", octstr_get_cstr(privdata->name), octstr_get_cstr(privdata->host)); connect_error = 1; continue; } if (privdata->username && privdata->password) { emimsg = make_emi60(privdata); emi2_emimsg_send(conn, server, emimsg); emimsg_destroy(emimsg); wait_ack = privdata->waitack > 30 ? privdata->waitack : 30; result = wait_for_ack(privdata, server, 60, wait_ack); if (result == -2) { /* * Are SMSCs going to return any temporary errors? If so, * testing for those error codes should be added here. */ error(0, "EMI2[%s]: Server rejected our login", octstr_get_cstr(privdata->name)); conn_destroy(server); connect_error = 1; continue; } else if (result == 0) { error(0, "EMI2[%s]: Got no reply to login attempt " "within %d seconds", octstr_get_cstr(privdata->name), wait_ack); conn_destroy(server); connect_error = 1; continue; } else if (result == -1) { /* Broken connection, already logged */ conn_destroy(server); connect_error = 1; continue; } privdata->last_activity_time = 0; /* to force keepalive after login */ privdata->can_write = 1; } mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); return server; } return NULL; } static void pack_7bit(Octstr *str) { Octstr *result; int len, i; int numbits, value; result = octstr_create("0"); len = octstr_len(str); value = 0; numbits = 0; for (i = 0; i < len; i++) { value += octstr_get_char(str, i) << numbits; numbits += 7; if (numbits >= 8) { octstr_append_char(result, value & 0xff); value >>= 8; numbits -= 8; } } if (numbits > 0) octstr_append_char(result, value); octstr_set_char(result, 0, (len * 7 + 3) / 4); octstr_delete(str, 0, LONG_MAX); octstr_append(str, result); octstr_binary_to_hex(str, 1); octstr_destroy(result); } static struct emimsg *msg_to_emimsg(Msg *msg, int trn, PrivData *privdata) { Octstr *str; struct emimsg *emimsg; int dcs; struct tm tm; char p[20]; emimsg = emimsg_create_op(51, trn, privdata->name); str = octstr_duplicate(msg->sms.sender); if(octstr_get_char(str,0) == '+') { /* either alphanum or international */ if (!octstr_check_range(str, 1, 256, gw_isdigit)) { /* alphanumeric sender address with + in front*/ charset_utf8_to_gsm(str); octstr_truncate(str, 11); /* max length of alphanumeric OaDC */ emimsg->fields[E50_OTOA] = octstr_create("5039"); pack_7bit(str); } else { /* international number. Set format and remove + */ emimsg->fields[E50_OTOA] = octstr_create("1139"); octstr_delete(str, 0, 1); octstr_truncate(str, 22); /* max length of numeric OaDC */ } } else { if (!octstr_check_range(str, 0, 256, gw_isdigit)) { /* alphanumeric sender address */ charset_utf8_to_gsm(str); octstr_truncate(str, 11); /* max length of alphanumeric OaDC */ emimsg->fields[E50_OTOA] = octstr_create("5039"); pack_7bit(str); } } emimsg->fields[E50_OADC] = str; /* set protocol id */ if (msg->sms.pid >= 0) { emimsg->fields[E50_RPID] = octstr_format("%04d", msg->sms.pid); } /* set reply path indicator */ if (msg->sms.rpi == 2) emimsg->fields[E50_RPI] = octstr_create("2"); else if (msg->sms.rpi > 0) emimsg->fields[E50_RPI] = octstr_create("1"); str = octstr_duplicate(msg->sms.receiver); if(octstr_get_char(str,0) == '+') { /* international number format */ /* EMI doesnt understand + so we have to replace it with something useful */ /* we try 00 here. Should really be done in the config instead so this */ /* is only a workaround to make wrong configs work */ octstr_delete(str, 0, 1); octstr_insert_data(str, 0, "00",2); } octstr_truncate(str, 16); /* max length of ADC */ emimsg->fields[E50_ADC] = str; emimsg->fields[E50_XSER] = octstr_create(""); /* XSer 01: UDH */ if (octstr_len(msg->sms.udhdata)) { str = octstr_create(""); octstr_append_char(str, 0x01); octstr_append_char(str, octstr_len(msg->sms.udhdata)); octstr_append(str, msg->sms.udhdata); octstr_binary_to_hex(str, 1); octstr_append(emimsg->fields[E50_XSER], str); octstr_destroy(str); } /* XSer 02: DCS */ dcs = fields_to_dcs(msg, msg->sms.alt_dcs); if (dcs != 0 && dcs != 4) { str = octstr_create(""); octstr_append_char(str, 0x02); octstr_append_char(str, 1); /* len 01 */ octstr_append_char(str, dcs); octstr_binary_to_hex(str, 1); octstr_append(emimsg->fields[E50_XSER], str); octstr_destroy(str); } /* XSer 0c: billing identifier */ if (octstr_len(msg->sms.binfo)) { str = octstr_create(""); octstr_append_char(str, 0x0c); octstr_append_char(str, octstr_len(msg->sms.binfo)); octstr_append(str, msg->sms.binfo); octstr_binary_to_hex(str, 1); octstr_append(emimsg->fields[E50_XSER], str); octstr_destroy(str); } if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) { emimsg->fields[E50_MT] = octstr_create("4"); emimsg->fields[E50_MCLS] = octstr_create("1"); str = octstr_duplicate(msg->sms.msgdata); emimsg->fields[E50_NB] = octstr_format("%04d", 8 * octstr_len(str)); octstr_binary_to_hex(str, 1); emimsg->fields[E50_TMSG] = str; } else { emimsg->fields[E50_MT] = octstr_create("3"); str = octstr_duplicate(msg->sms.msgdata); charset_utf8_to_gsm(str); /* * Check if we have to apply some after GSM transcoding kludges */ if (privdata->alt_charset == EMI_NRC_ISO_21) charset_gsm_to_nrc_iso_21_german(str); /* Could still be too long after truncation if there's an UDH part, * but this is only to notice errors elsewhere (should never happen).*/ if (charset_gsm_truncate(str, 160)) error(0, "EMI2[%s]: Message to send is longer " "than 160 gsm characters", octstr_get_cstr(privdata->name)); octstr_binary_to_hex(str, 1); emimsg->fields[E50_AMSG] = str; } if (msg->sms.validity != SMS_PARAM_UNDEFINED) { tm = gw_localtime(msg->sms.validity); sprintf(p, "%02d%02d%02d%02d%02d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100, tm.tm_hour, tm.tm_min); str = octstr_create(p); emimsg->fields[E50_VP] = str; } if (msg->sms.deferred != SMS_PARAM_UNDEFINED) { str = octstr_create("1"); emimsg->fields[E50_DD] = str; tm = gw_localtime(msg->sms.deferred); sprintf(p, "%02d%02d%02d%02d%02d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100, tm.tm_hour, tm.tm_min); str = octstr_create(p); emimsg->fields[E50_DDT] = str; } /* if delivery reports are asked, lets ask for them too */ /* even the sender might not be interested in delivery or non delivery */ /* we still need them back to clear out the memory after the message */ /* has been delivered or non delivery has been confirmed */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) { emimsg->fields[E50_NRQ] = octstr_create("1"); emimsg->fields[E50_NT] = octstr_create(""); octstr_append_decimal(emimsg->fields[E50_NT], 3 + (DLR_IS_BUFFERED(msg->sms.dlr_mask) ? 4 : 0)); if (privdata->npid) emimsg->fields[E50_NPID] = octstr_duplicate(privdata->npid); if (privdata->nadc) emimsg->fields[E50_NADC] = octstr_duplicate(privdata->nadc); } return emimsg; } /* Return -1 if the connection broke, 0 if the request couldn't be handled * (unknown type), or 1 if everything was successful */ static int handle_operation(SMSCConn *conn, Connection *server, struct emimsg *emimsg) { struct emimsg *reply; Octstr *tempstr, *xser; int type, len; Msg *msg = NULL; struct universaltime unitime; int st_code; PrivData *privdata = conn->data; switch(emimsg->ot) { /* * Handle OP/01 call input operation. This operation delivery MO messages * from SMSC to SMT according to [1], section 4.2, p. 9. */ case 01: msg = msg_create(sms); if (emimsg->fields[E01_AMSG] == NULL) emimsg->fields[E01_AMSG] = octstr_create(""); else if (octstr_hex_to_binary(emimsg->fields[E01_AMSG]) == -1) warning(0, "EMI2[%s]: Couldn't decode message text", octstr_get_cstr(privdata->name)); if (emimsg->fields[E01_MT] == NULL) { warning(0, "EMI2[%s]: required field MT missing", octstr_get_cstr(privdata->name)); /* This guess could be incorrect, maybe the message should just be dropped */ emimsg->fields[E01_MT] = octstr_create("3"); } if (octstr_get_char(emimsg->fields[E01_MT], 0) == '3') { msg->sms.msgdata = emimsg->fields[E01_AMSG]; emimsg->fields[E01_AMSG] = NULL; /* So it's not freed */ /* obey the NRC (national replacement codes) */ if (privdata->alt_charset == EMI_NRC_ISO_21) charset_nrc_iso_21_german_to_gsm(msg->sms.msgdata); charset_gsm_to_utf8(msg->sms.msgdata); } else { error(0, "EMI2[%s]: MT == %s isn't supported for operation type 01", octstr_get_cstr(privdata->name), octstr_get_cstr(emimsg->fields[E01_MT])); msg->sms.msgdata = octstr_create(""); } msg->sms.sender = octstr_duplicate(emimsg->fields[E01_OADC]); if (msg->sms.sender == NULL) { warning(0, "EMI2[%s]: Empty sender field in received message", octstr_get_cstr(privdata->name)); msg->sms.sender = octstr_create(""); } if(octstr_len(PRIVDATA(conn)->my_number)) { msg->sms.receiver = octstr_duplicate(PRIVDATA(conn)->my_number); } else { msg->sms.receiver = octstr_duplicate(emimsg->fields[E01_ADC]); } if (msg->sms.receiver == NULL) { warning(0, "EMI2[%s]: Empty receiver field in received message", octstr_get_cstr(privdata->name)); msg->sms.receiver = octstr_create(""); } /* Operation type 01 doesn't have a time stamp field */ time(&msg->sms.time); msg->sms.smsc_id = octstr_duplicate(conn->id); bb_smscconn_receive(conn, msg); reply = emimsg_create_reply(01, emimsg->trn, 1, privdata->name); if (emi2_emimsg_send(conn, server, reply) < 0) { emimsg_destroy(reply); return -1; } emimsg_destroy(reply); return 1; /* * Handle OP/52 delivery short message. This is the MO side of the protocol * implementation. See [1], section 5.4, p. 40. */ case 52: msg = msg_create(sms); /* AMSG is the same field as TMSG */ if (emimsg->fields[E50_AMSG] == NULL) emimsg->fields[E50_AMSG] = octstr_create(""); else if (octstr_hex_to_binary(emimsg->fields[E50_AMSG]) == -1) warning(0, "EMI2[%s]: Couldn't decode message text", octstr_get_cstr(privdata->name)); /* Process XSer fields */ xser = emimsg->fields[E50_XSER]; while (octstr_len(xser) > 0) { int tempint; tempstr = octstr_copy(xser, 0, 4); if (octstr_hex_to_binary(tempstr) == -1) error(0, "EMI2[%s]: Invalid XSer", octstr_get_cstr(privdata->name)); type = octstr_get_char(tempstr, 0); len = octstr_get_char(tempstr, 1); octstr_destroy(tempstr); if (len < 0) { error(0, "EMI2[%s]: Malformed emi XSer field", octstr_get_cstr(privdata->name)); break; } /* Handle supported XSer fields */ switch (type) { case 0x01: /* XSer 01, GSM UDH information */ tempstr = octstr_copy(xser, 4, len * 2); if (octstr_hex_to_binary(tempstr) == -1) error(0, "EMI2[%s]: Invalid UDH contents", octstr_get_cstr(privdata->name)); msg->sms.udhdata = tempstr; break; case 0x02: /* XSer 02, GSM DCS information */ tempstr = octstr_copy(xser, 4, 2); octstr_hex_to_binary(tempstr); tempint = octstr_get_char(tempstr, 0); octstr_destroy(tempstr); if (!dcs_to_fields(&msg, tempint)) { error(0, "EMI2[%s]: Invalid DCS received", octstr_get_cstr(privdata->name)); /* XXX Should we discard message ? */ dcs_to_fields(&msg, 0); } break; /* * XSer 03-0b are for CDMA/TDMA information exchange and are currently * not implemented in this EMI interface. See CMG EMI/UCP spec 4.6, * section 5.1.2.4 for more information. */ case 0x0c: /* XSer 0c, billing identifier */ tempstr = octstr_copy(xser, 4, len * 2); if (octstr_hex_to_binary(tempstr) == -1) { error(0, "EMI2[%s] Invalid XSer 0c billing identifier <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(tempstr)); } else { msg->sms.binfo = tempstr; } break; case 0x0d: /* XSer 0d, single shot indicator */ tempstr = octstr_copy(xser, 4, 2); octstr_hex_to_binary(tempstr); tempint = octstr_get_char(tempstr, 0); octstr_destroy(tempstr); if (tempint) info(0, "EMI2[%s]: Single shot indicator set.", octstr_get_cstr(privdata->name)); break; /* XSer fields 0e-ff are reserved for future use and should not be used. */ default: warning(0, "EMI2[%s]: Unsupported EMI XSer field %d", octstr_get_cstr(privdata->name), type); break; } octstr_delete(xser, 0, 2 * len + 4); } if (emimsg->fields[E50_MT] == NULL) { warning(0, "EMI2[%s]: required field MT missing", octstr_get_cstr(privdata->name)); /* This guess could be incorrect, maybe the message should just be dropped */ emimsg->fields[E50_MT] = octstr_create("3"); } if (octstr_get_char(emimsg->fields[E50_MT], 0) == '3') { msg->sms.msgdata = emimsg->fields[E50_AMSG]; emimsg->fields[E50_AMSG] = NULL; /* So it's not freed */ /* obey the NRC (national replacement codes) */ if (privdata->alt_charset == EMI_NRC_ISO_21) charset_nrc_iso_21_german_to_gsm(msg->sms.msgdata); charset_gsm_to_utf8(msg->sms.msgdata); } else if (octstr_get_char(emimsg->fields[E50_MT], 0) == '4') { msg->sms.msgdata = emimsg->fields[E50_TMSG]; emimsg->fields[E50_TMSG] = NULL; } else { error(0, "EMI2[%s]: MT == %s isn't supported yet", octstr_get_cstr(privdata->name), octstr_get_cstr(emimsg->fields[E50_MT])); msg->sms.msgdata = octstr_create(""); } msg->sms.sender = octstr_duplicate(emimsg->fields[E50_OADC]); if (msg->sms.sender == NULL) { warning(0, "EMI2[%s]: Empty sender field in received message", octstr_get_cstr(privdata->name)); msg->sms.sender = octstr_create(""); } if(octstr_len(PRIVDATA(conn)->my_number)) { msg->sms.receiver = octstr_duplicate(PRIVDATA(conn)->my_number); } else { msg->sms.receiver = octstr_duplicate(emimsg->fields[E50_ADC]); } if (msg->sms.receiver == NULL) { warning(0, "EMI2[%s]: Empty receiver field in received message", octstr_get_cstr(privdata->name)); msg->sms.receiver = octstr_create(""); } tempstr = emimsg->fields[E50_SCTS]; /* Just a shorter name */ if (tempstr == NULL) { warning(0, "EMI2[%s]: Received EMI message doesn't have required timestamp", octstr_get_cstr(privdata->name)); goto notime; } if (octstr_len(tempstr) != 12) { warning(0, "EMI2[%s]: EMI SCTS field must have length 12, now %ld", octstr_get_cstr(privdata->name), octstr_len(tempstr)); goto notime; } if (octstr_parse_long(&unitime.second, tempstr, 10, 10) != 12 || (octstr_delete(tempstr, 10, 2), octstr_parse_long(&unitime.minute, tempstr, 8, 10) != 10) || (octstr_delete(tempstr, 8, 2), octstr_parse_long(&unitime.hour, tempstr, 6, 10) != 8) || (octstr_delete(tempstr, 6, 2), octstr_parse_long(&unitime.year, tempstr, 4, 10) != 6) || (octstr_delete(tempstr, 4, 2), octstr_parse_long(&unitime.month, tempstr, 2, 10) != 4) || (octstr_delete(tempstr, 2, 2), octstr_parse_long(&unitime.day, tempstr, 0, 10) != 2)) { error(0, "EMI2[%s]: EMI delivery time stamp looks malformed", octstr_get_cstr(privdata->name)); notime: time(&msg->sms.time); } else { unitime.year += 2000; /* Conversion function expects full year */ unitime.month -= 1; /* conversion function expects 0-based months */ msg->sms.time = date_convert_universal(&unitime); } msg->sms.smsc_id = octstr_duplicate(conn->id); bb_smscconn_receive(conn, msg); reply = emimsg_create_reply(52, emimsg->trn, 1, privdata->name); if (emi2_emimsg_send(conn, server, reply) < 0) { emimsg_destroy(reply); return -1; } emimsg_destroy(reply); return 1; /* * Handle OP/53 delivery notification. See [1], section 5.5, p. 43. */ case 53: st_code = atoi(octstr_get_cstr(emimsg->fields[E50_DST])); switch(st_code) { case 0: /* delivered */ msg = dlr_find((conn->id ? conn->id : privdata->name), emimsg->fields[E50_SCTS], /* timestamp */ emimsg->fields[E50_OADC], /* destination */ DLR_SUCCESS, 1); break; case 1: /* buffered */ msg = dlr_find((conn->id ? conn->id : privdata->name), emimsg->fields[E50_SCTS], /* timestamp */ emimsg->fields[E50_OADC], /* destination */ DLR_BUFFERED, 1); break; case 2: /* not delivered */ msg = dlr_find((conn->id ? conn->id : privdata->name), emimsg->fields[E50_SCTS], /* timestamp */ emimsg->fields[E50_OADC], /* destination */ DLR_FAIL, 1); break; } if (msg != NULL) { /* * Recode the msg structure with the given msgdata. * Note: the DLR URL is delivered in msg->sms.dlr_url already. */ if ((emimsg->fields[E50_AMSG]) == NULL) msg->sms.msgdata = octstr_create("Delivery Report without text"); else msg->sms.msgdata = octstr_duplicate(emimsg->fields[E50_AMSG]); octstr_hex_to_binary(msg->sms.msgdata); if (octstr_get_char(emimsg->fields[E50_MT], 0) == '3') { /* obey the NRC (national replacement codes) */ if (privdata->alt_charset == EMI_NRC_ISO_21) charset_nrc_iso_21_german_to_gsm(msg->sms.msgdata); charset_gsm_to_utf8(msg->sms.msgdata); } bb_smscconn_receive(conn, msg); } reply = emimsg_create_reply(53, emimsg->trn, 1, privdata->name); if (emi2_emimsg_send(conn, server, reply) < 0) { emimsg_destroy(reply); return -1; } emimsg_destroy(reply); return 1; /* * Handle OP/31 from SMSC side. This is not "purely" spec conform since, * the protocol says "This operation can be used by a SMT to alert the SC.", * which implies semantically only the opposite way. For the sake of EMI/UCP * server implementations that send alert messages to SMTs we handle this * without breaking any core protocol concept. * * See [1], section 4.6, p. 19. */ case 31: reply = emimsg_create_reply(31, emimsg->trn, 1, privdata->name); st_code = emi2_emimsg_send(conn, server, reply); emimsg_destroy(reply); return (st_code < 0 ? -1 : 1); default: error(0, "EMI2[%s]: I don't know how to handle operation type %d", octstr_get_cstr(privdata->name), emimsg->ot); return 0; } } /* * get all unacknowledged messages from the ringbuffer and queue them * for retransmission. */ static void clear_sent(PrivData *privdata) { int i; debug("smsc.emi2", 0, "EMI2[%s]: clear_sent called", octstr_get_cstr(privdata->name)); for (i = 0; i < EMI2_MAX_TRN; i++) { if (privdata->slots[i].sendtime && privdata->slots[i].sendtype == 51) gw_prioqueue_produce(privdata->outgoing_queue, privdata->slots[i].sendmsg); privdata->slots[i].sendtime = 0; } privdata->unacked = 0; } /* * wait seconds seconds for something to happen (a send SMS request, activity * on the SMSC main connection, an error or timeout) and tell the caller * what happened. */ static EMI2Event emi2_wait (SMSCConn *conn, Connection *server, double seconds) { if (emi2_can_send(conn) && gw_prioqueue_len(PRIVDATA(conn)->outgoing_queue)) { return EMI2_SENDREQ; } if (server != NULL) { switch (conn_wait(server, seconds)) { case 1: return gw_prioqueue_len(PRIVDATA(conn)->outgoing_queue) ? EMI2_SENDREQ : EMI2_TIMEOUT; case 0: return EMI2_SMSCREQ; default: return EMI2_CONNERR; } } else { gwthread_sleep(seconds); return gw_prioqueue_len(PRIVDATA(conn)->outgoing_queue) ? EMI2_SENDREQ : EMI2_TIMEOUT; } } /* * obtain the next free TRN. */ static int emi2_next_trn (SMSCConn *conn) { #define INC_TRN(x) ((x)=((x) + 1) % EMI2_MAX_TRN) int result; while (SLOTBUSY(conn,PRIVDATA(conn)->priv_nexttrn)) INC_TRN(PRIVDATA(conn)->priv_nexttrn); /* pick unused TRN */ result = PRIVDATA(conn)->priv_nexttrn; INC_TRN(PRIVDATA(conn)->priv_nexttrn); return result; #undef INC_TRN } /* * send an EMI type 31 message when required. */ static int emi2_keepalive_handling (SMSCConn *conn, Connection *server) { struct emimsg *emimsg; int nexttrn = emi2_next_trn (conn); emimsg = make_emi31(PRIVDATA(conn), nexttrn); if(emimsg) { PRIVDATA(conn)->slots[nexttrn].sendtype= 31; PRIVDATA(conn)->slots[nexttrn].sendtime = time(NULL); PRIVDATA(conn)->unacked++; if (emi2_emimsg_send(conn, server, emimsg) == -1) { emimsg_destroy(emimsg); return -1; } emimsg_destroy(emimsg); } PRIVDATA(conn)->can_write = 0; return 0; } /* * the actual send logic: Send all queued messages in a burst. */ static int emi2_do_send(SMSCConn *conn, Connection *server) { struct emimsg *emimsg; Msg *msg; double delay = 0; if (conn->throughput > 0) { delay = 1.0 / conn->throughput; } /* Send messages if there's room in the sending window */ while (emi2_can_send(conn) && (msg = gw_prioqueue_remove(PRIVDATA(conn)->outgoing_queue)) != NULL) { int nexttrn = emi2_next_trn(conn); if (conn->throughput > 0) gwthread_sleep(delay); /* convert the generic Kannel message into an EMI type message */ emimsg = msg_to_emimsg(msg, nexttrn, PRIVDATA(conn)); /* remember the message for retransmission or DLR */ PRIVDATA(conn)->slots[nexttrn].sendmsg = msg; PRIVDATA(conn)->slots[nexttrn].sendtype = 51; PRIVDATA(conn)->slots[nexttrn].sendtime = time(NULL); /* send the message */ if (emi2_emimsg_send(conn, server, emimsg) == -1) { emimsg_destroy(emimsg); return -1; } /* we just sent a message */ PRIVDATA(conn)->unacked++; emimsg_destroy(emimsg); /* * remember that there is an open request for stop-wait flow control * FIXME: couldn't this be done with the unacked field as well? After * all stop-wait is just a window of size 1. */ PRIVDATA(conn)->can_write = 0; } return 0; } static int emi2_handle_smscreq(SMSCConn *conn, Connection *server) { Octstr *str; struct emimsg *emimsg; PrivData *privdata = conn->data; /* Read acks/nacks/ops from the server */ while ((str = conn_read_packet(server, 2, 3))) { debug("smsc.emi2", 0, "EMI2[%s]: Got packet from the main socket", octstr_get_cstr(privdata->name)); /* parse the msg */ emimsg = get_fields(str, privdata->name); octstr_destroy(str); if (emimsg == NULL) { continue; /* The parse functions logged errors */ } if (emimsg->or == 'O') { /* If the SMSC wants to send operations through this * socket, we'll have to read them because there * might be ACKs too. We just drop them while stopped, * hopefully the SMSC will resend them later. */ if (!conn->is_stopped) { if (handle_operation(conn, server, emimsg) < 0) return -1; /* Connection broke */ } else { info(0, "EMI2[%s]: Ignoring operation from main socket " "because the connection is stopped.", octstr_get_cstr(privdata->name)); } } else { /* Already checked to be 'O' or 'R' */ if (!SLOTBUSY(conn,emimsg->trn) || emimsg->ot != PRIVDATA(conn)->slots[emimsg->trn].sendtype) { error(0, "EMI2[%s]: Got ack for TRN %d, don't remember sending O?", octstr_get_cstr(privdata->name), emimsg->trn); } else { PRIVDATA(conn)->can_write = 1; PRIVDATA(conn)->slots[emimsg->trn].sendtime = 0; PRIVDATA(conn)->unacked--; if (emimsg->ot == 51) { if (octstr_get_char(emimsg->fields[0], 0) == 'A') { /* we got an ack back. We might have to store the */ /* timestamp for delivery notifications now */ Octstr *ts, *adc; int i; Msg *m; ts = octstr_duplicate(emimsg->fields[2]); if (octstr_len(ts)) { i = octstr_search_char(ts,':',0); if (i>0) { octstr_delete(ts,0,i+1); adc = octstr_duplicate(emimsg->fields[2]); octstr_truncate(adc,i); m = PRIVDATA(conn)->slots[emimsg->trn].sendmsg; if(m == NULL) { info(0,"EMI2[%s]: uhhh m is NULL, very bad", octstr_get_cstr(privdata->name)); } else if (DLR_IS_ENABLED_DEVICE(m->sms.dlr_mask)) { dlr_add((conn->id ? conn->id : privdata->name), ts, m, 1); } octstr_destroy(ts); octstr_destroy(adc); } else { octstr_destroy(ts); } } /* * report the successful transmission to the generic bb code. */ bb_smscconn_sent(conn, PRIVDATA(conn)->slots[emimsg->trn].sendmsg, NULL); } else { Octstr *reply; /* create reply message */ reply = octstr_create(""); octstr_append(reply, emimsg->fields[1]); octstr_append_char(reply, '-'); /* system message is optional */ if (emimsg->fields[2] != NULL) octstr_append(reply, emimsg->fields[2]); /* XXX Process error code here long errorcode; octstr_parse_long(&errorcode, emimsg->fields[1], 0, 10); ... switch(errorcode) ... } else { */ bb_smscconn_send_failed(conn, PRIVDATA(conn)->slots[emimsg->trn].sendmsg, SMSCCONN_FAILED_REJECTED, reply); /* } */ } } else if (emimsg->ot == 31) { /* XXX Process error codes here if (octstr_get_char(emimsg->fields[0], 0) == 'N') { long errorcode; octstr_parse_long(&errorcode, emimsg->fields[1], 0, 10); ... switch errorcode ... } else { */ ; /* } */ } else { panic(0, "EMI2[%s]: Bug, ACK handler missing for sent packet", octstr_get_cstr(privdata->name)); } } } emimsg_destroy(emimsg); } if (conn_error(server)) { error(0, "EMI2[%s]: Error trying to read ACKs from SMSC", octstr_get_cstr(privdata->name)); return -1; } if (conn_eof(server)) { info(0, "EMI2[%s]: Main connection closed by SMSC", octstr_get_cstr(privdata->name)); return -1; } return 0; } static void emi2_idleprocessing(SMSCConn *conn, Connection **server) { time_t current_time; int i; PrivData *privdata = conn->data; /* * Check whether there are messages the server hasn't acked in a * reasonable time */ current_time = time(NULL); if (PRIVDATA(conn)->unacked && (current_time > (PRIVDATA(conn)->check_time + 30))) { PRIVDATA(conn)->check_time = current_time; for (i = 0; i < PRIVDATA(conn)->window; i++) { if (SLOTBUSY(conn,i) && PRIVDATA(conn)->slots[i].sendtime < (current_time - PRIVDATA(conn)->waitack)) { if (PRIVDATA(conn)->slots[i].sendtype == 51) { if (PRIVDATA(conn)->waitack_expire == 0x00) { /* 0x00 - disconnect/reconnect */ warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d " "in %d seconds, disconnecting and reconnection", octstr_get_cstr(privdata->name), i, PRIVDATA(conn)->waitack); PRIVDATA(conn)->slots[i].sendtime = 0; PRIVDATA(conn)->unacked--; info(0, "EMI2[%s]: closing connection.", octstr_get_cstr(privdata->name)); conn_destroy(*server); *server = NULL; break; } else if (PRIVDATA(conn)->waitack_expire == 0x01) { /* 0x01 - resend */ warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d " "in %d seconds, resending message", octstr_get_cstr(privdata->name), i, PRIVDATA(conn)->waitack); gw_prioqueue_produce(PRIVDATA(conn)->outgoing_queue, PRIVDATA(conn)->slots[i].sendmsg); PRIVDATA(conn)->slots[i].sendtime = 0; PRIVDATA(conn)->unacked--; if (PRIVDATA(conn)->flowcontrol) PRIVDATA(conn)->can_write=1; /* Wake up this same thread to send again * (simpler than avoiding sleep) */ gwthread_wakeup(PRIVDATA(conn)->sender_thread); } else if (PRIVDATA(conn)->waitack_expire == 0x02) { /* 0x02 - carry on waiting */ warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d " "in %d seconds, carrying on waiting", octstr_get_cstr(privdata->name), i, PRIVDATA(conn)->waitack); } } else if (PRIVDATA(conn)->slots[i].sendtype == 31) { warning(0, "EMI2[%s]: Alert (operation 31) was not " "ACKed within %d seconds", octstr_get_cstr(privdata->name), PRIVDATA(conn)->waitack); if (PRIVDATA(conn)->flowcontrol) PRIVDATA(conn)->can_write=1; } else { panic(0, "EMI2[%s]: Bug, no timeout handler for sent packet", octstr_get_cstr(privdata->name)); } } } } } static void emi2_idletimeout_handling (SMSCConn *conn, Connection **server) { PrivData *privdata = conn->data; /* * close the connection if there was no activity. */ if ((*server != NULL) && CONNECTIONIDLE(conn)) { info(0, "EMI2[%s]: closing idle connection.", octstr_get_cstr(privdata->name)); conn_destroy(*server); *server = NULL; } } /* * this function calculates the new timeouttime. */ static double emi2_get_timeouttime (SMSCConn *conn, Connection *server) { double ka_timeouttime = PRIVDATA(conn)->keepalive ? PRIVDATA(conn)->keepalive + 1 : DBL_MAX; double idle_timeouttime = (PRIVDATA(conn)->idle_timeout && server) ? PRIVDATA(conn)->idle_timeout : DBL_MAX; double result = ka_timeouttime < idle_timeouttime ? ka_timeouttime : idle_timeouttime; if (result == DBL_MAX) result = 30; return result; } /* * the main event processing loop. */ static void emi2_send_loop(SMSCConn *conn, Connection **server) { PrivData *privdata = conn->data; for (;;) { double timeouttime; EMI2Event event; if (emi2_needs_keepalive (conn)) { if (*server == NULL) { return; /* reopen the connection */ } emi2_keepalive_handling (conn, *server); } timeouttime = emi2_get_timeouttime (conn, *server); event = emi2_wait (conn, *server, timeouttime); switch (event) { case EMI2_CONNERR: return; case EMI2_SENDREQ: if (*server == NULL) { return; /* reopen the connection */ } if (emi2_do_send (conn, *server) < 0) { return; /* reopen the connection */ } break; case EMI2_SMSCREQ: if (emi2_handle_smscreq (conn, *server) < 0) { return; /* reopen the connection */ } break; case EMI2_TIMEOUT: break; } if ((*server !=NULL) && (emi2_handle_smscreq (conn, *server) < 0)) { return; /* reopen the connection */ } emi2_idleprocessing (conn, server); emi2_idletimeout_handling (conn, server); if (PRIVDATA(conn)->shutdown && (PRIVDATA(conn)->unacked == 0)) { /* shutdown and no open messages */ break; } if (*server != NULL) { if (conn_error(*server)) { warning(0, "EMI2[%s]: Error reading from the main connection", octstr_get_cstr(privdata->name)); break; } if (conn_eof(*server)) { info(0, "EMI2[%s]: Main connection closed by SMSC", octstr_get_cstr(privdata->name)); break; } } } } static void emi2_sender(void *arg) { SMSCConn *conn = arg; PrivData *privdata = conn->data; Msg *msg; Connection *server; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (!privdata->shutdown) { if ((server = open_send_connection(conn)) == NULL) { privdata->shutdown = 1; if (privdata->rport > 0) gwthread_wakeup(privdata->receiver_thread); break; } emi2_send_loop(conn, &server); clear_sent(privdata); if (server != NULL) { conn_destroy(server); } } while((msg = gw_prioqueue_remove(privdata->outgoing_queue)) != NULL) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); if (privdata->rport > 0) gwthread_join(privdata->receiver_thread); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; debug("bb.sms", 0, "EMI2[%s]: connection has completed shutdown.", octstr_get_cstr(privdata->name)); gw_prioqueue_destroy(privdata->outgoing_queue, NULL); octstr_destroy(privdata->name); octstr_destroy(privdata->allow_ip); octstr_destroy(privdata->deny_ip); octstr_destroy(privdata->host); octstr_destroy(privdata->alt_host); octstr_destroy(privdata->my_number); octstr_destroy(privdata->username); octstr_destroy(privdata->password); octstr_destroy(privdata->npid); octstr_destroy(privdata->nadc); gw_free(privdata); conn->data = NULL; mutex_unlock(conn->flow_mutex); bb_smscconn_killed(); } static void emi2_receiver(SMSCConn *conn, Connection *server) { PrivData *privdata = conn->data; Octstr *str; struct emimsg *emimsg; while (1) { if (conn_eof(server)) { info(0, "EMI2[%s]: receive connection closed by SMSC", octstr_get_cstr(privdata->name)); return; } if (conn_error(server)) { error(0, "EMI2[%s]: receive connection broken", octstr_get_cstr(privdata->name)); return; } if (conn->is_stopped) str = NULL; else str = conn_read_packet(server, 2, 3); if (str) { debug("smsc.emi2", 0, "EMI2[%s]: Got packet from the receive connection.", octstr_get_cstr(privdata->name)); if ( (emimsg = get_fields(str, privdata->name)) ) { if (emimsg->or == 'O') { if (handle_operation(conn, server, emimsg) < 0) { emimsg_destroy(emimsg); return; } } else error(0, "EMI2[%s]: No ACKs expected on receive connection!", octstr_get_cstr(privdata->name)); emimsg_destroy(emimsg); } octstr_destroy(str); } else conn_wait(server, -1); if (privdata->shutdown) break; } return; } static int emi2_open_listening_socket(SMSCConn *conn, PrivData *privdata) { int s; if ( (s = make_server_socket(privdata->rport, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL))) == -1) { error(0, "EMI2[%s]: could not create listening socket in port %d", octstr_get_cstr(privdata->name), privdata->rport); return -1; } if (socket_set_blocking(s, 0) == -1) { error(0, "EMI2[%s]: couldn't make listening socket port %d " "non-blocking", octstr_get_cstr(privdata->name), privdata->rport); close(s); return -1; } privdata->listening_socket = s; return 0; } static void emi2_listener(void *arg) { SMSCConn *conn = arg; PrivData *privdata = conn->data; struct sockaddr_in server_addr; socklen_t server_addr_len; Octstr *ip; Connection *server; int s, ret; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (!privdata->shutdown) { server_addr_len = sizeof(server_addr); ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1); if (ret == -1) { if (errno == EINTR) continue; error(0, "EMI2[%s]: Poll for emi2 smsc connections failed, shutting down", octstr_get_cstr(privdata->name)); break; } if (privdata->shutdown) break; if (ret == 0) /* This thread was woken up from elsewhere, but if we're not shutting down nothing to do here. */ continue; s = accept(privdata->listening_socket, (struct sockaddr *)&server_addr, &server_addr_len); if (s == -1) { warning(errno, "EMI2[%s]: emi2_listener: accept() failed, retrying...", octstr_get_cstr(privdata->name)); continue; } ip = host_ip(server_addr); if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) { info(0, "EMI2[%s]: smsc connection tried from denied host <%s>," " disconnected", octstr_get_cstr(privdata->name), octstr_get_cstr(ip)); octstr_destroy(ip); close(s); continue; } server = conn_wrap_fd(s, 0); if (server == NULL) { error(0, "EMI2[%s]: emi2_listener: conn_wrap_fd failed on accept()ed fd", octstr_get_cstr(privdata->name)); octstr_destroy(ip); close(s); continue; } conn_claim(server); info(0, "EMI2[%s]: smsc connected from %s", octstr_get_cstr(privdata->name), octstr_get_cstr(ip)); octstr_destroy(ip); emi2_receiver(conn, server); conn_destroy(server); } if (close(privdata->listening_socket) == -1) warning(errno, "EMI2[%s]: couldn't close listening socket " "at shutdown", octstr_get_cstr(privdata->name)); gwthread_wakeup(privdata->sender_thread); } static int add_msg_cb(SMSCConn *conn, Msg *sms) { PrivData *privdata = conn->data; Msg *copy; copy = msg_duplicate(sms); gw_prioqueue_produce(privdata->outgoing_queue, copy); gwthread_wakeup(privdata->sender_thread); return 0; } static int shutdown_cb(SMSCConn *conn, int finish_sending) { PrivData *privdata = conn->data; debug("bb.sms", 0, "EMI2[%s]: Shutting down SMSCConn EMI2, %s", octstr_get_cstr(privdata->name), finish_sending ? "slow" : "instant"); /* Documentation claims this would have been done by smscconn.c, but isn't when this code is being written. */ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; privdata->shutdown = 1; /* Separate from why_killed to avoid locking, as why_killed may be changed from outside? */ if (finish_sending == 0) { Msg *msg; while((msg = gw_prioqueue_remove(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } } if (privdata->rport > 0) gwthread_wakeup(privdata->receiver_thread); return 0; } static void start_cb(SMSCConn *conn) { PrivData *privdata = conn->data; /* in case there are messages in the buffer already */ if (privdata->rport > 0) gwthread_wakeup(privdata->receiver_thread); debug("smsc.emi2", 0, "EMI2[%s]: start called", octstr_get_cstr(privdata->name)); } static long queued_cb(SMSCConn *conn) { PrivData *privdata = conn->data; long ret; ret = (privdata ? gw_prioqueue_len(privdata->outgoing_queue) : 0); /* use internal queue as load, maybe something else later */ conn->load = ret; return ret; } int smsc_emi2_create(SMSCConn *conn, CfgGroup *cfg) { PrivData *privdata; Octstr *allow_ip, *deny_ip, *host, *alt_host; long portno, our_port, keepalive, flowcontrol, waitack, idle_timeout, alt_portno, alt_charset, waitack_expire; long window; /* has to be long because of cfg_get_integer */ int i; allow_ip = deny_ip = host = alt_host = NULL; privdata = gw_malloc(sizeof(PrivData)); privdata->outgoing_queue = gw_prioqueue_create(sms_priority_compare); privdata->listening_socket = -1; privdata->can_write = 1; privdata->priv_nexttrn = 0; privdata->last_activity_time = 0; privdata->check_time = 0; host = cfg_get(cfg, octstr_imm("host")); if (host == NULL) { error(0, "EMI2[-]: 'host' missing in emi2 configuration."); goto error; } privdata->host = host; if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) portno = 0; privdata->port = portno; if (privdata->port <= 0 || privdata->port > 65535) { error(0, "EMI2[%s]: 'port' missing/invalid in emi2 configuration.", octstr_get_cstr(host)); goto error; } if (cfg_get_integer(&our_port, cfg, octstr_imm("our-port")) == -1) privdata->our_port = 0; /* 0 means use any port */ else privdata->our_port = our_port; privdata->name = cfg_get(cfg, octstr_imm("smsc-id")); if(privdata->name == NULL) { privdata->name = octstr_create(""); /* Add our_host */ if(octstr_len(conn->our_host)) { octstr_append(privdata->name, conn->our_host); } /* Add our_port */ if(privdata->our_port != 0) { /* if we have our_port but not our_host, add kannel:our_port */ if(octstr_len(privdata->name) == 0) { octstr_append(privdata->name, octstr_imm("kannel")); } octstr_append_char(privdata->name, ':'); octstr_append_decimal(privdata->name, privdata->our_port); } else { if(octstr_len(privdata->name) != 0) { octstr_append(privdata->name, octstr_imm(":*")); } } /* if we have our_host neither our_port */ if(octstr_len(privdata->name) != 0) octstr_append(privdata->name, octstr_imm("->")); octstr_append(privdata->name, privdata->host); octstr_append_char(privdata->name, ':'); octstr_append_decimal(privdata->name, privdata->port); } if (cfg_get_integer(&idle_timeout, cfg, octstr_imm("idle-timeout")) == -1) idle_timeout = 0; privdata->idle_timeout = idle_timeout; alt_host = cfg_get(cfg, octstr_imm("alt-host")); privdata->alt_host = alt_host; if (cfg_get_integer(&portno, cfg, octstr_imm("receive-port")) < 0) portno = 0; privdata->rport = portno; if (cfg_get_integer(&alt_portno, cfg, octstr_imm("alt-port")) < 0) alt_portno = 0; privdata->alt_port = alt_portno; allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip")); if (allow_ip) deny_ip = octstr_create("*.*.*.*"); else deny_ip = NULL; privdata->username = cfg_get(cfg, octstr_imm("smsc-username")); privdata->password = cfg_get(cfg, octstr_imm("smsc-password")); privdata->my_number = cfg_get(cfg, octstr_imm("my-number")); privdata->npid = cfg_get(cfg, octstr_imm("notification-pid")); privdata->nadc = cfg_get(cfg, octstr_imm("notification-addr")); if ( (privdata->username == NULL && privdata->my_number == NULL) || cfg_get_integer(&keepalive, cfg, octstr_imm("keepalive")) < 0) privdata->keepalive = 0; else privdata->keepalive = keepalive; if (cfg_get_integer(&flowcontrol, cfg, octstr_imm("flow-control")) < 0) privdata->flowcontrol = 0; else privdata->flowcontrol = flowcontrol; if (privdata->flowcontrol < 0 || privdata->flowcontrol > 1) { error(0, "EMI2[%s]: 'flow-control' invalid in emi2 configuration.", octstr_get_cstr(privdata->name)); goto error; } if (cfg_get_integer(&window, cfg, octstr_imm("window")) < 0) privdata->window = EMI2_MAX_TRN; else privdata->window = window; if (privdata->window > EMI2_MAX_TRN) { warning(0, "EMI2[%s]: Value of 'window' should be lesser or equal to %d..", octstr_get_cstr(privdata->name), EMI2_MAX_TRN); privdata->window = EMI2_MAX_TRN; } if (cfg_get_integer(&waitack, cfg, octstr_imm("wait-ack")) < 0) privdata->waitack = 60; else privdata->waitack = waitack; if (privdata->waitack < 30 ) { error(0, "EMI2[%s]: 'wait-ack' invalid in emi2 configuration.", octstr_get_cstr(privdata->name)); goto error; } if (cfg_get_integer(&waitack_expire, cfg, octstr_imm("wait-ack-expire")) < 0) privdata->waitack_expire = 0; else privdata->waitack_expire = waitack_expire; if (privdata->waitack_expire >3 ) { error(0, "EMI2[%s]: 'wait-ack-expire' invalid in emi2 configuration.", octstr_get_cstr(privdata->name)); goto error; } if (privdata->rport < 0 || privdata->rport > 65535) { error(0, "EMI2[%s]: 'receive-port' missing/invalid in emi2 configuration.", octstr_get_cstr(privdata->name)); goto error; } if (cfg_get_integer(&alt_charset, cfg, octstr_imm("alt-charset")) < 0) privdata->alt_charset = 0; else privdata->alt_charset = alt_charset; privdata->allow_ip = allow_ip; privdata->deny_ip = deny_ip; if (privdata->rport > 0 && emi2_open_listening_socket(conn,privdata) < 0) { gw_free(privdata); privdata = NULL; goto error; } conn->data = privdata; conn->name = octstr_format("EMI2:%S:%d:%S", privdata->host, privdata->port, privdata->username ? privdata->username : octstr_imm("null")); privdata->shutdown = 0; for (i = 0; i < EMI2_MAX_TRN; i++) privdata->slots[i].sendtime = 0; privdata->unacked = 0; conn->status = SMSCCONN_CONNECTING; conn->connect_time = time(NULL); if ( privdata->rport > 0 && (privdata->receiver_thread = gwthread_create(emi2_listener, conn)) == -1) goto error; if ((privdata->sender_thread = gwthread_create(emi2_sender, conn)) == -1) { privdata->shutdown = 1; if (privdata->rport > 0) { gwthread_wakeup(privdata->receiver_thread); gwthread_join(privdata->receiver_thread); } goto error; } conn->shutdown = shutdown_cb; conn->queued = queued_cb; conn->start_conn = start_cb; conn->send_msg = add_msg_cb; return 0; error: error(0, "EMI2[%s]: Failed to create emi2 smsc connection", (privdata ? octstr_get_cstr(privdata->name) : "-")); if (privdata != NULL) { gw_prioqueue_destroy(privdata->outgoing_queue, NULL); } gw_free(privdata); octstr_destroy(allow_ip); octstr_destroy(deny_ip); octstr_destroy(host); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; info(0, "EMI2[%s]: exiting", (privdata ? octstr_get_cstr(privdata->name) : "-")); return -1; } gateway-1.4.5/gw/smsc/smasi_pdu.def0000644000175000017500000001274513227613126015726 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smasi_pdu.def - definitions of SMASI PDU structure * * Stipe Tolj */ #ifndef PDU #error Macro PDU not defined. #endif #ifndef COMATERMINATED #error Macro COMATERMINATED not defined. #endif #ifndef NONTERMINATED #error Macro NONTERMINATED not defined. #endif #ifdef HEADER #error Macro HEADER was already defined. #endif #define HEADER \ NONTERMINATED(command) PDU(LogonReq, 0x00000001, HEADER COMATERMINATED(Name) COMATERMINATED(Password) ) PDU(LogonConf, 0x00000002, HEADER ) PDU(LogonRej, 0x00000003, HEADER COMATERMINATED(Reason) ) PDU(LogoffReq, 0x00000004, HEADER COMATERMINATED(Reason) ) PDU(LogoffConf, 0x00000005, HEADER ) PDU(SubmitReq, 0x00000010, HEADER COMATERMINATED(Originator) COMATERMINATED(OriginatorType) COMATERMINATED(OriginatorPlan) COMATERMINATED(Destination) COMATERMINATED(DestinationType) COMATERMINATED(DestinationPlan) COMATERMINATED(Sequence) COMATERMINATED(MqPriority) COMATERMINATED(Body) COMATERMINATED(UserDataHeader) COMATERMINATED(BodyEncoding) COMATERMINATED(MsEncoding) COMATERMINATED(Class) COMATERMINATED(ProtocolID) ) PDU(SubmitConf, 0x00000011, HEADER COMATERMINATED(MsgReference) COMATERMINATED(JobId) COMATERMINATED(Point) COMATERMINATED(Sequence) ) PDU(SubmitRej, 0x00000012, HEADER COMATERMINATED(RejectCode) COMATERMINATED(MsgReference) COMATERMINATED(Reason) COMATERMINATED(JobId) COMATERMINATED(At) COMATERMINATED(Point) COMATERMINATED(Sequence) ) PDU(DeliverReq, 0x00000013, HEADER COMATERMINATED(Originator) COMATERMINATED(Destination) COMATERMINATED(Body) COMATERMINATED(UserDataHeader) COMATERMINATED(MsgReference) COMATERMINATED(Sequence) COMATERMINATED(mqTo) COMATERMINATED(mqFrom) COMATERMINATED(JobId) COMATERMINATED(At) COMATERMINATED(Point) COMATERMINATED(SmscSequence) COMATERMINATED(SmscReference) COMATERMINATED(Scts) COMATERMINATED(DestinationPlan) COMATERMINATED(DestinationType) COMATERMINATED(OriginatorPlan) COMATERMINATED(OriginatorType) COMATERMINATED(ProtocolId) COMATERMINATED(PacketId) COMATERMINATED(Position) COMATERMINATED(Class) COMATERMINATED(MsEncoding) ) PDU(DeliverConf, 0x00000014, HEADER COMATERMINATED(MsgReference) COMATERMINATED(Sequence) ) PDU(DeliverRej, 0x00000015, HEADER COMATERMINATED(RejectCode) COMATERMINATED(MsgReference) COMATERMINATED(Sequence) ) PDU(Error, 0x80000016, HEADER COMATERMINATED(Reason) ) PDU(EnquireLinkReq, 0x80000017, HEADER ) PDU(EnquireLinkConf, 0x80000018, HEADER ) #undef PDU #undef COMATERMINATED #undef NONTERMINATED #undef HEADER gateway-1.4.5/gw/smsc/smsc_at.c0000644000175000017500000034374413227613126015065 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_at.c * * New driver for serial connected AT based * devices. * 4.9.2001 * Andreas Fink * 23.6.2008, Andreas Fink, * added support for telnet connections * (for example Multi-Tech MTCBA-G-EN-F4) * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "gwlib/charset.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "msg.h" #include "sms.h" #include "dlr.h" #include "smsc_at.h" #include "load.h" static Octstr *gsm2number(Octstr *pdu); static unsigned char nibble2hex(unsigned char b); static void at2_scan_for_telnet_escapes(PrivAT2data *privdata) { int len; int pos; int start; int a; int b; Octstr *hex; char answer[5]; if(!privdata->ilb) return; start = 0; len = octstr_len(privdata->ilb); hex = octstr_duplicate(privdata->ilb); octstr_binary_to_hex(hex,1); octstr_destroy(hex); while(start < len) { pos = octstr_search_char(privdata->ilb, 0xFF, start); if(pos < 0) return; if((len - pos )<3) return; a = octstr_get_char(privdata->ilb,pos+1); b = octstr_get_char(privdata->ilb,pos+2); switch(a) { case 0xFD: /* do! */ answer[0] = 0xFF; /* escape */ answer[1] = 0xFC; /* wont do any option*/ answer[2] = b; write(privdata->fd,&answer,3); octstr_delete(privdata->ilb,pos,3); len -=3; break; break; case 0xFA: /* do you support option b ? */ octstr_delete(privdata->ilb,pos,3); len -=3; break; break; case 0xFB: /* will */ octstr_delete(privdata->ilb,pos,3); len -=3; break; case 0xFC: /* wont */ octstr_delete(privdata->ilb,pos,3); len -=3; break; } start = pos; } } static int at2_open_device1(PrivAT2data *privdata) { info(0, "AT2[%s]: opening device", octstr_get_cstr(privdata->name)); if (privdata->fd > 0) { warning(0, "AT2[%s]: trying to open device with not closed device!!! Please report!!!", octstr_get_cstr(privdata->name)); at2_close_device(privdata); } if (privdata->is_serial) { privdata->fd = open(octstr_get_cstr(privdata->device), O_RDWR | O_NONBLOCK | O_NOCTTY); privdata->use_telnet = 0; } else { if (octstr_str_compare(privdata->device, "rawtcp") == 0) { privdata->use_telnet = 0; privdata->fd = tcpip_connect_to_server(octstr_get_cstr(privdata->rawtcp_host), privdata->rawtcp_port, NULL); } else if (octstr_str_compare(privdata->device, "telnet") == 0) { privdata->use_telnet = 1; privdata->fd = tcpip_connect_to_server(octstr_get_cstr(privdata->rawtcp_host), privdata->rawtcp_port, NULL); } else { gw_assert(0); } } if (privdata->fd == -1) { error(errno, "AT2[%s]: open failed! ERRNO=%d", octstr_get_cstr(privdata->name), errno); privdata->fd = -1; return -1; } debug("bb.smsc.at2", 0, "AT2[%s]: device opened. Telnet mode = %d", octstr_get_cstr(privdata->name),privdata->use_telnet); return 0; } static int at2_login_device(PrivAT2data *privdata) { info(0, "AT2[%s]: Logging in", octstr_get_cstr(privdata->name)); at2_read_buffer(privdata, 0); gwthread_sleep(0.5); at2_read_buffer(privdata, 0); if((octstr_len(privdata->username) == 0 ) && (octstr_len(privdata->password)> 0)) { at2_wait_modem_command(privdata, 10, 3, NULL); /* wait for Password: prompt */ at2_send_modem_command(privdata, octstr_get_cstr(privdata->password), 2,0); /* wait for OK: */ at2_send_modem_command(privdata, "AT", 2,0); /* wait for OK: */ } else if((octstr_len(privdata->username) > 0 ) && (octstr_len(privdata->password)> 0)) { at2_wait_modem_command(privdata, 10, 2, NULL); /* wait for Login: prompt */ at2_send_modem_command(privdata, octstr_get_cstr(privdata->username), 10,3); /* wait fo Password: */ at2_send_modem_command(privdata, octstr_get_cstr(privdata->password), 2,0); /* wait for OK: */ at2_send_modem_command(privdata, "AT", 2,0); /* wait for OK: */ } return 0; } static int at2_open_device(PrivAT2data *privdata) { struct termios tios; int ret; if ((ret = at2_open_device1(privdata)) != 0) return ret; if (!privdata->is_serial) return 0; tcgetattr(privdata->fd, &tios); kannel_cfmakeraw(&tios); tios.c_iflag |= IGNBRK; /* ignore break & parity errors */ tios.c_iflag &= ~INPCK; /* INPCK: disable parity check */ tios.c_cflag |= HUPCL; /* hangup on close */ tios.c_cflag |= CREAD; /* enable receiver */ tios.c_cflag |= CLOCAL; /* Ignore modem control lines */ tios.c_cflag &= ~CSIZE; /* set to 8 bit */ tios.c_cflag |= CS8; tios.c_oflag &= ~ONLCR; /* no NL to CR-NL mapping outgoing */ tios.c_iflag |= IGNPAR; /* ignore parity */ tios.c_iflag &= ~INPCK; #if defined(CRTSCTS) if(privdata->modem) { if(privdata->modem->hardware_flow_control) { tios.c_cflag |= CRTSCTS; /* enable hardware flow control */ } else { tios.c_cflag &= ~CRTSCTS; /* disable hardware flow control */ } } else { tios.c_cflag &= ~CRTSCTS; /* disable hardware flow control */ } #endif tios.c_cc[VSUSP] = 0; /* otherwhise we can not send CTRL Z */ /* if ( ModemTypes[privdata->modemid].enable_parity ) tios.c_cflag ^= PARODD; */ ret = tcsetattr(privdata->fd, TCSANOW, &tios); /* apply changes now */ if (ret == -1) { error(errno, "AT2[%s]: at_data_link: fail to set termios attribute", octstr_get_cstr(privdata->name)); } tcflush(privdata->fd, TCIOFLUSH); /* * Nokia 7110 and 6210 need some time between opening * the connection and sending the first AT commands */ if (privdata->modem == NULL || privdata->modem->need_sleep) sleep(1); debug("bb.smsc.at2", 0, "AT2[%s]: device opened", octstr_get_cstr(privdata->name)); return 0; } static void at2_close_device(PrivAT2data *privdata) { info(0, "AT2[%s]: Closing device", octstr_get_cstr(privdata->name)); if (privdata->fd != -1) close(privdata->fd); privdata->fd = -1; privdata->pin_ready = 0; privdata->phase2plus = 0; if (privdata->ilb != NULL) octstr_destroy(privdata->ilb); privdata->ilb = octstr_create(""); } static void at2_read_buffer(PrivAT2data *privdata, double timeout) { char buf[MAX_READ + 1]; int ret; size_t count; signed int s; fd_set read_fd; struct timeval tv; if (privdata->fd == -1) { error(errno, "AT2[%s]: at2_read_buffer: fd = -1. Can not read", octstr_get_cstr(privdata->name)); return; } count = MAX_READ; #ifdef SSIZE_MAX if (count > SSIZE_MAX) count = SSIZE_MAX; #endif if (timeout <= 0) { tv.tv_sec = 0; tv.tv_usec = 1000; } else { int usecs = timeout * 1000000; tv.tv_sec = usecs / 1000000; tv.tv_usec = usecs % 1000000; } FD_ZERO(&read_fd); FD_SET(privdata->fd, &read_fd); ret = select(privdata->fd + 1, &read_fd, NULL, NULL, &tv); if (ret == -1) { if (!(errno == EINTR || errno == EAGAIN)) error(errno, "AT2[%s]: error on select", octstr_get_cstr(privdata->name)); return; } if (ret == 0) return; s = read(privdata->fd, buf, count); if (s < 0) { error(errno, "AT2[%s]: at2_read_buffer: Error during read", octstr_get_cstr(privdata->name)); at2_close_device(privdata); } else { octstr_append_data(privdata->ilb, buf, s); if(privdata->use_telnet) at2_scan_for_telnet_escapes(privdata); } } static Octstr *at2_wait_line(PrivAT2data *privdata, time_t timeout, int gt_flag) { Octstr *line; time_t end_time; time_t cur_time; if (timeout == 0) timeout = 3; end_time = time(NULL) + timeout; if (privdata->lines != NULL) octstr_destroy(privdata->lines); privdata->lines = octstr_create(""); while (time(&cur_time) <= end_time) { line = at2_read_line(privdata, gt_flag, timeout); if (line) return line; } return NULL; } static Octstr *at2_extract_line(PrivAT2data *privdata, int gt_flag) { int eol; int gtloc; int len; Octstr *line; Octstr *buf2; int i; len = octstr_len(privdata->ilb); if (len == 0) return NULL; if (gt_flag==1) { /* looking for > if needed */ gtloc = octstr_search_char(privdata->ilb, '>', 0); } else if((gt_flag == 2) && (privdata->username)) { /* looking for "Login" */ gtloc = -1; if(privdata->login_prompt) { gtloc = octstr_search(privdata->ilb,privdata->login_prompt,0); } if(gtloc == -1) { gtloc = octstr_search(privdata->ilb,octstr_imm("Login:"),0); } if(gtloc == -1) { gtloc = octstr_search(privdata->ilb,octstr_imm("Username:"),0); } } else if ((gt_flag == 3) && (privdata->password)) {/* looking for Password */ gtloc = -1; if(privdata->password_prompt) { gtloc = octstr_search(privdata->ilb,privdata->password_prompt,0); } if(gtloc == -1) { gtloc = octstr_search(privdata->ilb,octstr_imm("Password:"),0); } } else gtloc = -1; /* if (gt_flag && (gtloc != -1)) debug("bb.smsc.at2", 0, "in at2_read_line with gt_flag=1, gtloc=%d, ilb=%s", gtloc, octstr_get_cstr(privdata->ilb)); */ eol = octstr_search_char(privdata->ilb, '\r', 0); /* looking for CR */ if ((gtloc != -1) && ((eol == -1) || (eol > gtloc))) eol = gtloc; if (eol == -1) return NULL; line = octstr_copy(privdata->ilb, 0, eol); buf2 = octstr_copy(privdata->ilb, eol + 1, len); octstr_destroy(privdata->ilb); privdata->ilb = buf2; /* remove any non printable chars (including linefeed for example) */ for (i = 0; i < octstr_len(line); i++) { if (octstr_get_char(line, i) < 32) octstr_set_char(line, i, ' '); } octstr_strip_blanks(line); /* empty line, skipping */ if (octstr_len(line) == 0 && (gt_flag == 0)) { return line; } if ((gt_flag) && (gtloc != -1)) { /* got to re-add it again as the parser needs to see it */ octstr_append_cstr(line, ">"); } debug("bb.smsc.at2", 0, "AT2[%s]: <-- %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); return line; } static Octstr *at2_read_line(PrivAT2data *privdata, int gt_flag, double timeout) { Octstr *line; line = at2_extract_line(privdata, gt_flag); if (!line) { at2_read_buffer(privdata, timeout); line = at2_extract_line(privdata, gt_flag); } return line; } static int at2_write_line(PrivAT2data *privdata, char *line) { int count; int s = 0; int write_count = 0, data_written = 0; Octstr *linestr = NULL; linestr = octstr_format("%s\r", line); debug("bb.smsc.at2", 0, "AT2[%s]: --> %s^M", octstr_get_cstr(privdata->name), line); count = octstr_len(linestr); while (count > data_written) { errno = 0; s = write(privdata->fd, octstr_get_cstr(linestr) + data_written, count - data_written); if (s < 0 && errno == EAGAIN && write_count < RETRY_WRITE) { gwthread_sleep(1); ++write_count; } else if (s > 0) { data_written += s; write_count = 0; } else break; } O_DESTROY(linestr); if (s < 0) { error(errno, "AT2[%s]: Couldnot write to device.", octstr_get_cstr(privdata->name)); tcflush(privdata->fd, TCOFLUSH); return s; } tcdrain(privdata->fd); gwthread_sleep((double) (privdata->modem == NULL ? 100 : privdata->modem->sendline_sleep) / 1000); return s; } static int at2_write_ctrlz(PrivAT2data *privdata) { int s; char *ctrlz = "\032" ; int write_count = 0; debug("bb.smsc.at2", 0, "AT2[%s]: --> ^Z", octstr_get_cstr(privdata->name)); while (1) { errno = 0; s = write(privdata->fd, ctrlz, 1); if (s < 0 && errno == EAGAIN && write_count < RETRY_WRITE) { gwthread_sleep(1); ++write_count; } else break; } if (s < 0) { error(errno, "AT2[%s]: Couldnot write to device.", octstr_get_cstr(privdata->name)); tcflush(privdata->fd, TCOFLUSH); return s; } tcdrain(privdata->fd); gwthread_sleep((double) (privdata->modem == NULL ? 100 : privdata->modem->sendline_sleep) / 1000); return s; } static int at2_write(PrivAT2data *privdata, char *line) { int count, data_written = 0, write_count = 0; int s = 0; debug("bb.smsc.at2", 0, "AT2[%s]: --> %s", octstr_get_cstr(privdata->name), line); count = strlen(line); while(count > data_written) { s = write(privdata->fd, line + data_written, count - data_written); if (s < 0 && errno == EAGAIN && write_count < RETRY_WRITE) { gwthread_sleep(1); ++write_count; } else if (s > 0) { data_written += s; write_count = 0; } else break; } if (s < 0) { error(errno, "AT2[%s]: Couldnot write to device.", octstr_get_cstr(privdata->name)); tcflush(privdata->fd, TCOFLUSH); return s; } tcdrain(privdata->fd); gwthread_sleep((double) (privdata->modem == NULL ? 100 : privdata->modem->sendline_sleep) / 1000); return s; } static void at2_flush_buffer(PrivAT2data *privdata) { at2_read_buffer(privdata, 0); octstr_destroy(privdata->ilb); privdata->ilb = octstr_create(""); } static int at2_init_device(PrivAT2data *privdata) { int ret; Octstr *setpin; info(0, "AT2[%s]: init device", octstr_get_cstr(privdata->name)); at2_set_speed(privdata, privdata->speed); /* sleep 10 ms in order to get device some time to accept speed */ gwthread_sleep(0.1); /* reset the modem */ if (at2_send_modem_command(privdata, "ATZ", 0, 0) == -1) { error(0, "AT2[%s]: Wrong or no answer to ATZ, ignoring", octstr_get_cstr(privdata->name)); return -1; } /* check if the modem responded */ if (at2_send_modem_command(privdata, "AT", 0, 0) == -1) { error(0, "AT2[%s]: Wrong or no answer to AT. Trying again", octstr_get_cstr(privdata->name)); if (at2_send_modem_command(privdata, "AT", 0, 0) == -1) { error(0, "AT2[%s]: Second attempt to send AT failed", octstr_get_cstr(privdata->name)); return -1; } } at2_flush_buffer(privdata); if (at2_send_modem_command(privdata, "AT&F", 7, 0) == -1) { error(0, "AT2[%s]: No answer to AT&F. Trying again", octstr_get_cstr(privdata->name)); if (at2_send_modem_command(privdata, "AT&F", 7, 0) == -1) { return -1; } } at2_flush_buffer(privdata); /* check if the modem responded */ if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1) { error(0, "AT2[%s]: Wrong or no answer to ATE0. Trying again", octstr_get_cstr(privdata->name)); if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1) { error(0, "AT2[%s]: Second attempt to send ATE0 failed", octstr_get_cstr(privdata->name)); return -1; } } at2_flush_buffer(privdata); /* enable hardware handshake */ if (octstr_len(privdata->modem->enable_hwhs)) { if (at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->enable_hwhs), 0, 0) == -1) info(0, "AT2[%s]: cannot enable hardware handshake", octstr_get_cstr(privdata->name)); } /* * Check does the modem require a PIN and, if so, send it. * This is not supported by the Nokia Premicell */ if (!privdata->modem->no_pin) { ret = at2_send_modem_command(privdata, "AT+CPIN?", 10, 0); if (!privdata->pin_ready) { if (ret == 2) { if (privdata->pin == NULL) return -1; setpin = octstr_format("AT+CPIN=\"%s\"", octstr_get_cstr(privdata->pin)); ret = at2_send_modem_command(privdata, octstr_get_cstr(setpin), 0, 0); octstr_destroy(setpin); if (ret != 0 ) return -1; } else if (ret == -1) return -1; } /* * we have to wait until +CPIN: READY appears before issuing * the next command. 10 sec should be suficient */ if (!privdata->pin_ready) { at2_wait_modem_command(privdata, 10, 0, NULL); if (!privdata->pin_ready) { at2_send_modem_command(privdata, "AT+CPIN?", 10, 0); if (!privdata->pin_ready) { return -1; /* give up */ } } } } /* * Set the GSM SMS message center address if supplied */ if (octstr_len(privdata->sms_center)) { Octstr *temp; temp = octstr_create("AT+CSCA="); octstr_append_char(temp, 34); octstr_append(temp, privdata->sms_center); octstr_append_char(temp, 34); /* * XXX If some modem don't process the +, remove it and add ",145" * and ",129" to national numbers */ ret = at2_send_modem_command(privdata, octstr_get_cstr(temp), 0, 0); octstr_destroy(temp); if (ret == -1) return -1; if (ret > 0) { info(0, "AT2[%s]: Cannot set SMS message center, continuing", octstr_get_cstr(privdata->name)); } } /* Set the modem to PDU mode and autodisplay of new messages */ ret = at2_send_modem_command(privdata, "AT+CMGF=0", 0, 0); if (ret != 0 ) return -1; /* lets see if it supports GSM SMS 2+ mode */ ret = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0); if (ret != 0) { /* if it doesnt even understand the command, I'm sure it wont support it */ privdata->phase2plus = 0; } else { /* we have to take a part a string like +CSMS: (0,1,128) */ Octstr *ts; int i; List *vals; ts = privdata->lines; privdata->lines = NULL; i = octstr_search_char(ts, '(', 0); if (i > 0) { octstr_delete(ts, 0, i + 1); } i = octstr_search_char(ts, ')', 0); if (i > 0) { octstr_truncate(ts, i); } vals = octstr_split(ts, octstr_imm(",")); octstr_destroy(ts); ts = gwlist_search(vals, octstr_imm("1"), (void*) octstr_item_match); if (ts) privdata->phase2plus = 1; gwlist_destroy(vals, octstr_destroy_item); } if (privdata->phase2plus) { info(0, "AT2[%s]: Phase 2+ is supported", octstr_get_cstr(privdata->name)); ret = at2_send_modem_command(privdata, "AT+CSMS=1", 0, 0); if (ret != 0) return -1; } /* send init string */ ret = at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->init_string), 0, 0); if (ret != 0) return -1; if (privdata->sms_memory_poll_interval && privdata->modem->message_storage) { /* set message storage location for "SIM buffering" using the CPMS command */ if (at2_set_message_storage(privdata, privdata->modem->message_storage) != 0) return -1; } info(0, "AT2[%s]: AT SMSC successfully opened.", octstr_get_cstr(privdata->name)); return 0; } static int at2_send_modem_command(PrivAT2data *privdata, char *cmd, time_t timeout, int gt_flag) { if (at2_write_line(privdata, cmd) == -1) return -1; return at2_wait_modem_command(privdata, timeout, gt_flag, NULL); } static int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int gt_flag, int *output) { Octstr *line = NULL; Octstr *line2 = NULL; Octstr *pdu = NULL; Octstr *smsc_number = NULL; int ret; time_t end_time; time_t cur_time; Msg *msg; int cmgr_flag = 0; if (!timeout) timeout = 3; end_time = time(NULL) + timeout; if (privdata->lines != NULL) octstr_destroy(privdata->lines); privdata->lines = octstr_create(""); smsc_number = octstr_create(""); while (privdata->fd != -1 && time(&cur_time) <= end_time) { O_DESTROY(line); if ((line = at2_read_line(privdata, gt_flag, timeout))) { octstr_append(privdata->lines, line); octstr_append_cstr(privdata->lines, "\n"); if (octstr_search(line, octstr_imm("SIM PIN"), 0) != -1) { ret = 2; goto end; } if (octstr_search(line, octstr_imm("OK"), 0) != -1) { ret = 0; goto end; } if ((gt_flag ) && (octstr_search(line, octstr_imm(">"), 0) != -1)) { ret = 1; goto end; } if (octstr_search(line, octstr_imm("RING"), 0) != -1) { at2_write_line(privdata, "ATH0"); continue; } if (octstr_search(line, octstr_imm("+CPIN: READY"), 0) != -1) { privdata->pin_ready = 1; ret = 3; goto end; } if (octstr_search(line, octstr_imm("+CMS ERROR"), 0) != -1) { int errcode; error(0, "AT2[%s]: +CMS ERROR: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); if (sscanf(octstr_get_cstr(line), "+CMS ERROR: %d", &errcode) == 1) error(0, "AT2[%s]: +CMS ERROR: %s (%d)", octstr_get_cstr(privdata->name), at2_error_string(errcode), errcode); ret = 1; goto end; } else if (octstr_search(line, octstr_imm("+CME ERROR"), 0) != -1) { int errcode; error(0, "AT2[%s]: +CME ERROR: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); if (sscanf(octstr_get_cstr(line), "+CME ERROR: %d", &errcode) == 1) error(0, "AT2[%s]: +CME ERROR: %s (%d)", octstr_get_cstr(privdata->name), at2_error_string(errcode), errcode); ret = 1; goto end; } if (octstr_search(line, octstr_imm("+CMTI:"), 0) != -1 || octstr_search(line, octstr_imm("+CDSI:"), 0) != -1) { /* * we received an incoming message indication * put it in the pending_incoming_messages queue for later retrieval */ debug("bb.smsc.at2", 0, "AT2[%s]: +CMTI incoming SMS indication: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); gwlist_append(privdata->pending_incoming_messages, line); line = NULL; continue; } if (octstr_search(line, octstr_imm("+CMT:"), 0) != -1 || octstr_search(line, octstr_imm("+CDS:"), 0) != -1 || ((octstr_search(line, octstr_imm("+CMGR:"), 0) != -1) && (cmgr_flag = 1)) ) { line2 = at2_wait_line(privdata, 1, 0); if (line2 == NULL) { error(0, "AT2[%s]: got +CMT but waiting for next line timed out", octstr_get_cstr(privdata->name)); } else { octstr_append_cstr(line, "\n"); octstr_append(line, line2); O_DESTROY(line2); at2_pdu_extract(privdata, &pdu, line, smsc_number); if (pdu == NULL) { error(0, "AT2[%s]: got +CMT but pdu_extract failed", octstr_get_cstr(privdata->name)); } else { /* count message even if I can't decode it */ if (output) ++(*output); msg = at2_pdu_decode(pdu, privdata); if (msg != NULL) { octstr_destroy(msg->sms.smsc_id); octstr_destroy(msg->sms.smsc_number); msg->sms.smsc_id = octstr_duplicate(privdata->conn->id); msg->sms.smsc_number = octstr_duplicate(smsc_number); bb_smscconn_receive(privdata->conn, msg); } else { error(0, "AT2[%s]: could not decode PDU to a message.", octstr_get_cstr(privdata->name)); } if (!cmgr_flag) { if (privdata->phase2plus) { at2_send_modem_command(privdata, "AT+CNMA", 3, 0); } } O_DESTROY(pdu); } } continue; } if ((octstr_search(line, octstr_imm("+CMGS:"),0) != -1) && (output)) { /* * found response to a +CMGS command, read the message id * and return it in output */ long temp; if (octstr_parse_long(&temp, line, octstr_search(line, octstr_imm("+CMGS:"), 0) + 6, 10) == -1) error(0, "AT2[%s]: Got +CMGS but failed to read message id", octstr_get_cstr(privdata->name)); else *output = temp; } /* finally check if we received a generic error */ if (octstr_search(line, octstr_imm("ERROR"), 0) != -1) { int errcode; error(0, "AT2[%s]: Generic error: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line)); if (sscanf(octstr_get_cstr(line), "ERROR: %d", &errcode) == 1) error(0, "AT2[%s]: Generic error: %s (%d)", octstr_get_cstr(privdata->name), at2_error_string(errcode), errcode); ret = -1; goto end; } } } /* error(0,"AT2[%s]: timeout. received <%s> until now, buffer size is %d, buf=%s", octstr_get_cstr(privdata->name), privdata->lines ? octstr_get_cstr(privdata->lines) : "", len, privdata->ilb ? octstr_get_cstr(privdata->ilb) : ""); */ O_DESTROY(line); O_DESTROY(line2); O_DESTROY(pdu); O_DESTROY(smsc_number); return -1; /* timeout */ end: O_DESTROY(smsc_number); octstr_append(privdata->lines, line); octstr_append_cstr(privdata->lines, "\n"); O_DESTROY(line); O_DESTROY(line2); O_DESTROY(pdu); return ret; } static int at2_read_delete_message(PrivAT2data* privdata, int message_number) { char cmd[20]; int message_count = 0; sprintf(cmd, "AT+CMGR=%d", message_number); /* read one message from memory */ at2_write_line(privdata, cmd); if (at2_wait_modem_command(privdata, 0, 0, &message_count) != 0) { debug("bb.smsc.at2", 0, "AT2[%s]: failed to get message %d.", octstr_get_cstr(privdata->name), message_number); return 0; /* failed to read the message - skip to next message */ } /* no need to delete if no message collected */ if (!message_count) { debug("bb.smsc.at2", 0, "AT2[%s]: not deleted.", octstr_get_cstr(privdata->name)); return 0; } sprintf(cmd, "AT+CMGD=%d", message_number); /* delete the message we just read */ /* * 3 seconds (default timeout of send_modem_command()) is not enough with some * modems if the message is large, so we'll give it 7 seconds */ if (at2_send_modem_command(privdata, cmd, 7, 0) != 0) { /* * failed to delete the message, we'll just ignore it for now, * this is bad, since if the message really didn't get deleted * we'll see it next time around. */ error(2, "AT2[%s]: failed to delete message %d.", octstr_get_cstr(privdata->name), message_number); } return 1; } /* * This function loops through the pending_incoming_messages queue for CMTI * notifications. * Every notification is parsed and the messages are read (and deleted) * accordingly. */ static void at2_read_pending_incoming_messages(PrivAT2data *privdata) { Octstr *current_storage = NULL; if (privdata->modem->message_storage) { current_storage = octstr_duplicate(privdata->modem->message_storage); } while (gwlist_len(privdata->pending_incoming_messages) > 0) { int pos; long location; Octstr *cmti_storage = NULL, *line = NULL; line = gwlist_extract_first(privdata->pending_incoming_messages); /* message memory starts after the first quote in the string */ if ((pos = octstr_search_char(line, '"', 0)) != -1) { /* grab memory storage name */ int next_quote = octstr_search_char(line, '"', ++pos); if (next_quote == -1) { /* no second qoute - this line must be broken somehow */ O_DESTROY(line); continue; } /* store notification storage location for reference */ cmti_storage = octstr_copy(line, pos, next_quote - pos); } else /* reset pos for the next lookup which would start from the beginning if no memory * location was found */ pos = 0; /* if no message storage is set in configuration - set now */ if (!privdata->modem->message_storage && cmti_storage) { info(2, "AT2[%s]: CMTI received, but no message-storage is set in confiuration." "setting now to <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(cmti_storage)); privdata->modem->message_storage = octstr_duplicate(cmti_storage); current_storage = octstr_duplicate(cmti_storage); at2_set_message_storage(privdata, cmti_storage); } /* find the message id from the line, which should appear after the first comma */ if ((pos = octstr_search_char(line, ',', pos)) == -1) { /* this CMTI notification is probably broken */ error(2, "AT2[%s]: failed to find memory location in CMTI notification", octstr_get_cstr(privdata->name)); O_DESTROY(line); octstr_destroy(cmti_storage); continue; } if ((pos = octstr_parse_long(&location, line, ++pos, 10)) == -1) { /* there was an error parsing the message id. next! */ error(2, "AT2[%s]: error parsing memory location in CMTI notification", octstr_get_cstr(privdata->name)); O_DESTROY(line); octstr_destroy(cmti_storage); continue; } /* check if we need to change storage location before issuing the read command */ if (!current_storage || (octstr_compare(current_storage, cmti_storage) != 0)) { octstr_destroy(current_storage); current_storage = octstr_duplicate(cmti_storage); at2_set_message_storage(privdata, cmti_storage); } if (!at2_read_delete_message(privdata, location)) { error(1, "AT2[%s]: CMTI notification received, but no message found in memory!", octstr_get_cstr(privdata->name)); } octstr_destroy(line); octstr_destroy(cmti_storage); } /* set prefered message storage back to what configured */ if (current_storage && privdata->modem->message_storage && (octstr_compare(privdata->modem->message_storage, current_storage) != 0)) at2_set_message_storage(privdata, privdata->modem->message_storage); octstr_destroy(current_storage); } static int at2_read_sms_memory(PrivAT2data* privdata) { /* get memory status */ if (at2_check_sms_memory(privdata) == -1) { debug("bb.smsc.at2", 0, "AT2[%s]: memory check error", octstr_get_cstr(privdata->name)); return -1; } if (privdata->sms_memory_usage) { /* * that is - greater then 0, meaning there are some messages to fetch * now - I used to just loop over the first input_mem_sms_used locations, * but it doesn't hold, since under load, messages may be received while * we're in the loop, and get stored in locations towards the end of the list, * thus creating 'holes' in the memory. * * There are two ways we can fix this : * (a) Just read the last message location, delete it and return. * It's not a complete solution since holes can still be created if messages * are received between the memory check and the delete command, * and anyway - it will slow us down and won't hold well under pressure * (b) Just scan the entire memory each call, bottom to top. * This will be slow too, but it'll be reliable. * * We can massivly improve performance by stopping after input_mem_sms_used messages * have been read, but send_modem_command returns 0 for no message as well as for a * message read, and the only other way to implement it is by doing memory_check * after each read and stoping when input_mem_sms_used get to 0. This is slow * (modem commands take time) so we improve speed only if there are less then 10 * messages in memory. * * I implemented the alternative - changed at2_wait_modem_command to return the * number of messages it collected. */ int i; int message_count = 0; /* cound number of messages collected */ ModemDef *modem = privdata->modem; debug("bb.smsc.at2", 0, "AT2[%s]: %d messages waiting in memory", octstr_get_cstr(privdata->name), privdata->sms_memory_usage); /* * loop till end of memory or collected enouch messages */ for (i = modem->message_start; i < (privdata->sms_memory_capacity + modem->message_start) && message_count < privdata->sms_memory_usage; ++i) { /* if (meanwhile) there are pending CMTI notifications, process these first * to not let CMTI and sim buffering sit in each others way */ while (gwlist_len(privdata->pending_incoming_messages) > 0) { at2_read_pending_incoming_messages(privdata); } /* read the message and delete it */ message_count += at2_read_delete_message(privdata, i); } } /* at2_send_modem_command(privdata, ModemTypes[privdata->modemid].init1, 0, 0); */ return 0; } static int at2_check_sms_memory(PrivAT2data *privdata) { long values[4]; /* array to put response data in */ int pos; /* position of parser in data stream */ int ret; Octstr *search_cpms = NULL; /* select memory type and get report */ if ((ret = at2_send_modem_command(privdata, "AT+CPMS?", 0, 0)) != 0) { debug("bb.smsc.at2.memory_check", 0, "failed to send mem select command to modem %d", ret); return -1; } search_cpms = octstr_create("+CPMS:"); if ((pos = octstr_search(privdata->lines, search_cpms, 0)) != -1) { /* got back a +CPMS response */ int index = 0; /* index in values array */ pos += 6; /* position of parser in the stream - start after header */ /* skip memory indication */ pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; /* find all the values */ while (index < 4 && pos < octstr_len(privdata->lines) && (pos = octstr_parse_long(&values[index], privdata->lines, pos, 10)) != -1) { ++pos; /* skip number seperator */ ++index; /* increment array index */ if (index == 2) /* skip second memory indication */ pos = octstr_search(privdata->lines, octstr_imm(","), pos) + 1; } if (index < 4) { /* didn't get all memory data - I don't why, so I'll bail */ debug("bb.smsc.at2", 0, "AT2[%s]: couldn't parse all memory locations : %d:'%s'.", octstr_get_cstr(privdata->name), index, &(octstr_get_cstr(privdata->lines)[pos])); O_DESTROY(search_cpms); return -1; } privdata->sms_memory_usage = values[0]; privdata->sms_memory_capacity = values[1]; /* privdata->output_mem_sms_used = values[2]; privdata->output_mem_sms_capacity = values[3]; */ /* everything's cool */ ret = 0; /* clear the buffer */ O_DESTROY(privdata->lines); } else { debug("bb.smsc.at2", 0, "AT2[%s]: no correct header for CPMS response.", octstr_get_cstr(privdata->name)); /* didn't get a +CPMS response - this is clearly an error */ ret = -1; } O_DESTROY(search_cpms); return ret; } static void at2_set_speed(PrivAT2data *privdata, int bps) { struct termios tios; int ret; int speed; if (!privdata->is_serial) return; tcgetattr(privdata->fd, &tios); switch (bps) { case 300: speed = B300; break; case 1200: speed = B1200; break; case 2400: speed = B2400; break; case 4800: speed = B4800; break; case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break; #ifdef B57600 case 57600: speed = B57600; break; #endif #ifdef B115200 case 115200: speed = B115200; break; #endif #ifdef B230400 case 230400: speed = B230400; break; #endif #ifdef B460800 case 460800: speed = B460800; break; #endif #ifdef B500000 case 500000: speed = B500000; break; #endif #ifdef B576000 case 576000: speed = B576000; break; #endif #ifdef B921600 case 921600: speed = B921600; break; #endif default: #if B9600 == 9600 speed = bps; #else speed = B9600; #endif } cfsetospeed(&tios, speed); cfsetispeed(&tios, speed); ret = tcsetattr(privdata->fd, TCSANOW, &tios); /* apply changes now */ if (ret == -1) { error(errno, "AT2[%s]: at_data_link: fail to set termios attribute", octstr_get_cstr(privdata->name)); } tcflush(privdata->fd, TCIOFLUSH); info(0, "AT2[%s]: speed set to %d", octstr_get_cstr(privdata->name), bps); } static void at2_device_thread(void *arg) { SMSCConn *conn = arg; PrivAT2data *privdata = conn->data; int reconnecting = 0, error_count = 0; long idle_timeout, memory_poll_timeout = 0; conn->status = SMSCCONN_CONNECTING; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); reconnect: do { if (reconnecting) { if (conn->status == SMSCCONN_ACTIVE) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); } error(0, "AT2[%s]: Couldn't connect (retrying in %ld seconds).", octstr_get_cstr(privdata->name), conn->reconnect_delay); gwthread_sleep(conn->reconnect_delay); reconnecting = 0; } /* If modems->speed is defined, try to use it, else autodetect */ if (privdata->speed == 0 && privdata->modem != NULL && privdata->modem->speed != 0) { info(0, "AT2[%s]: trying to use speed <%ld> from modem definition", octstr_get_cstr(privdata->name), privdata->modem->speed); if (at2_test_speed(privdata, privdata->modem->speed) == 0) { privdata->speed = privdata->modem->speed; info(0, "AT2[%s]: speed is %ld", octstr_get_cstr(privdata->name), privdata->speed); } else { info(0, "AT2[%s]: speed in modem definition don't work, will autodetect", octstr_get_cstr(privdata->name)); } } if (privdata->speed == 0 && at2_detect_speed(privdata) == -1) { reconnecting = 1; continue; } if (privdata->modem == NULL && at2_detect_modem_type(privdata) == -1) { reconnecting = 1; continue; } if (at2_open_device(privdata)) { error(errno, "AT2[%s]: at2_device_thread: open_at2_device failed.", octstr_get_cstr(privdata->name)); reconnecting = 1; continue; } if (at2_login_device(privdata)) { error(errno, "AT2[%s]: at2_device_thread: at2_login_device failed.", octstr_get_cstr(privdata->name)); reconnecting = 1; continue; } if (privdata->max_error_count > 0 && error_count > privdata->max_error_count && privdata->modem != NULL && privdata->modem->reset_string != NULL) { error_count = 0; if (at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->reset_string), 0, 0) != 0) { error(0, "AT2[%s]: Reset of modem failed.", octstr_get_cstr(privdata->name)); at2_close_device(privdata); reconnecting = 1; continue; } else { info(0, "AT2[%s]: Modem reseted.", octstr_get_cstr(privdata->name)); } } if (at2_init_device(privdata) != 0) { error(0, "AT2[%s]: Initialization of device failed. Attempt #%d on %ld max.", octstr_get_cstr(privdata->name), error_count, privdata->max_error_count); at2_close_device(privdata); error_count++; reconnecting = 1; continue; } else error_count = 0; /* If we got here, then the device is opened */ break; } while (!privdata->shutdown); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); idle_timeout = 0; while (!privdata->shutdown) { at2_wait_modem_command(privdata, 1, 0, NULL); /* read error, so re-connect */ if (privdata->fd == -1) { at2_close_device(privdata); reconnecting = 1; goto reconnect; } while (gwlist_len(privdata->pending_incoming_messages) > 0) { at2_read_pending_incoming_messages(privdata); } if (privdata->keepalive && idle_timeout + privdata->keepalive < time(NULL)) { if (at2_send_modem_command(privdata, octstr_get_cstr(privdata->modem->keepalive_cmd), 5, 0) < 0) { at2_close_device(privdata); reconnecting = 1; goto reconnect; } idle_timeout = time(NULL); } if (privdata->sms_memory_poll_interval && memory_poll_timeout + privdata->sms_memory_poll_interval < time(NULL)) { if (at2_read_sms_memory(privdata) == -1) { at2_close_device(privdata); reconnecting = 1; goto reconnect; } memory_poll_timeout = time(NULL); } if (gw_prioqueue_len(privdata->outgoing_queue) > 0) { at2_send_messages(privdata); idle_timeout = time(NULL); } } at2_close_device(privdata); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DISCONNECTED; mutex_unlock(conn->flow_mutex); /* maybe some cleanup here? */ at2_destroy_modem(privdata->modem); octstr_destroy(privdata->device); octstr_destroy(privdata->ilb); octstr_destroy(privdata->lines); octstr_destroy(privdata->pin); octstr_destroy(privdata->validityperiod); octstr_destroy(privdata->my_number); octstr_destroy(privdata->sms_center); octstr_destroy(privdata->name); octstr_destroy(privdata->configfile); octstr_destroy(privdata->username); octstr_destroy(privdata->password); octstr_destroy(privdata->rawtcp_host); gw_prioqueue_destroy(privdata->outgoing_queue, NULL); gwlist_destroy(privdata->pending_incoming_messages, octstr_destroy_item); load_destroy(privdata->load); gw_free(conn->data); conn->data = NULL; mutex_lock(conn->flow_mutex); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; conn->status = SMSCCONN_DEAD; mutex_unlock(conn->flow_mutex); bb_smscconn_killed(); } static int at2_shutdown_cb(SMSCConn *conn, int finish_sending) { PrivAT2data *privdata = conn->data; debug("bb.sms", 0, "AT2[%s]: Shutting down SMSCConn, %s", octstr_get_cstr(privdata->name), finish_sending ? "slow" : "instant"); /* * Documentation claims this would have been done by smscconn.c, * but isn't when this code is being written. */ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; privdata->shutdown = 1; /* * Separate from why_killed to avoid locking, as * why_killed may be changed from outside? */ if (finish_sending == 0) { Msg *msg; while ((msg = gw_prioqueue_remove(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } } gwthread_wakeup(privdata->device_thread); return 0; } static long at2_queued_cb(SMSCConn *conn) { PrivAT2data *privdata; privdata = conn->data; conn->load = (privdata ? (conn->status != SMSCCONN_DEAD ? gw_prioqueue_len(privdata->outgoing_queue) : 0) : 0); return conn->load; } static void at2_start_cb(SMSCConn *conn) { PrivAT2data *privdata; privdata = conn->data; if (conn->status == SMSCCONN_DISCONNECTED) conn->status = SMSCCONN_ACTIVE; /* in case there are messages in the buffer already */ gwthread_wakeup(privdata->device_thread); debug("smsc.at2", 0, "AT2[%s]: start called", octstr_get_cstr(privdata->name)); } static int at2_add_msg_cb(SMSCConn *conn, Msg *sms) { PrivAT2data *privdata; privdata = conn->data; gw_prioqueue_produce(privdata->outgoing_queue, msg_duplicate(sms)); gwthread_wakeup(privdata->device_thread); return 0; } int smsc_at2_create(SMSCConn *conn, CfgGroup *cfg) { PrivAT2data *privdata; Octstr *modem_type_string; long portno; /* has to be long because of cfg_get_integer */ privdata = gw_malloc(sizeof(PrivAT2data)); memset(privdata, 0, sizeof(PrivAT2data)); privdata->outgoing_queue = gw_prioqueue_create(sms_priority_compare); privdata->pending_incoming_messages = gwlist_create(); privdata->configfile = cfg_get_configfile(cfg); privdata->device = cfg_get(cfg, octstr_imm("device")); if (privdata->device == NULL) { error(0, "AT2[-]: 'device' missing in at2 configuration."); goto error; } if (octstr_str_compare(privdata->device, "rawtcp") == 0) { privdata->rawtcp_host = cfg_get(cfg, octstr_imm("host")); if (privdata->rawtcp_host == NULL) { error(0, "AT2[-]: 'host' missing in at2 rawtcp configuration."); goto error; } if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) { error(0, "AT2[-]: 'port' missing in at2 rawtcp configuration."); goto error; } privdata->rawtcp_port = portno; privdata->is_serial = 0; privdata->use_telnet = 0; } else if (octstr_str_compare(privdata->device, "telnet") == 0) { privdata->rawtcp_host = cfg_get(cfg, octstr_imm("host")); if (privdata->rawtcp_host == NULL) { error(0, "AT2[-]: 'host' missing in at2 telnet configuration."); goto error; } if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) { error(0, "AT2[-]: 'port' missing in at2 telnet configuration."); goto error; } privdata->rawtcp_port = portno; privdata->is_serial = 0; privdata->use_telnet = 1; } else { privdata->is_serial = 1; privdata->use_telnet = 0; } privdata->name = cfg_get(cfg, octstr_imm("smsc-id")); if (privdata->name == NULL) { privdata->name = octstr_duplicate(privdata->device); } privdata->speed = 0; cfg_get_integer(&privdata->speed, cfg, octstr_imm("speed")); privdata->keepalive = 0; cfg_get_integer(&privdata->keepalive, cfg, octstr_imm("keepalive")); cfg_get_bool(&privdata->sms_memory_poll_interval, cfg, octstr_imm("sim-buffering")); if (privdata->sms_memory_poll_interval) { if (privdata->keepalive) privdata->sms_memory_poll_interval = privdata->keepalive; else privdata->sms_memory_poll_interval = AT2_DEFAULT_SMS_POLL_INTERVAL; } privdata->my_number = cfg_get(cfg, octstr_imm("my-number")); privdata->sms_center = cfg_get(cfg, octstr_imm("sms-center")); privdata->username = cfg_get(cfg, octstr_imm("smsc-username")); privdata->password = cfg_get(cfg, octstr_imm("smsc-password")); privdata->login_prompt = cfg_get(cfg, octstr_imm("login-prompt")); privdata->password_prompt = cfg_get(cfg, octstr_imm("password-prompt")); modem_type_string = cfg_get(cfg, octstr_imm("modemtype")); privdata->modem = NULL; if (modem_type_string != NULL) { if (octstr_compare(modem_type_string, octstr_imm("auto")) == 0 || octstr_compare(modem_type_string, octstr_imm("autodetect")) == 0) O_DESTROY(modem_type_string); } if (octstr_len(modem_type_string) == 0) { info(0, "AT2[%s]: configuration doesn't show modemtype. will autodetect", octstr_get_cstr(privdata->name)); } else { info(0, "AT2[%s]: configuration shows modemtype <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(modem_type_string)); privdata->modem = at2_read_modems(privdata, privdata->configfile, modem_type_string, 0); if (privdata->modem == NULL) { info(0, "AT2[%s]: modemtype not found, revert to autodetect", octstr_get_cstr(privdata->name)); } else { info(0, "AT2[%s]: read modem definition for <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(privdata->modem->name)); } O_DESTROY(modem_type_string); } privdata->ilb = octstr_create(""); privdata->fd = -1; privdata->lines = NULL; privdata->pin = cfg_get(cfg, octstr_imm("pin")); privdata->pin_ready = 0; privdata->conn = conn; privdata->phase2plus = 0; privdata->validityperiod = cfg_get(cfg, octstr_imm("validityperiod")); if (cfg_get_integer((long *) &privdata->max_error_count, cfg, octstr_imm("max-error-count")) == -1) privdata->max_error_count = -1; privdata->load = load_create_real(0); load_add_interval(privdata->load, 1); conn->data = privdata; conn->name = octstr_format("AT2[%s]", octstr_get_cstr(privdata->name)); conn->status = SMSCCONN_CONNECTING; conn->connect_time = time(NULL); privdata->shutdown = 0; if ((privdata->device_thread = gwthread_create(at2_device_thread, conn)) == -1) { privdata->shutdown = 1; goto error; } conn->shutdown = at2_shutdown_cb; conn->queued = at2_queued_cb; conn->start_conn = at2_start_cb; conn->send_msg = at2_add_msg_cb; return 0; error: error(0, "AT2[%s]: Failed to create at2 smsc connection", octstr_len(privdata->name) ? octstr_get_cstr(privdata->name) : ""); if (privdata != NULL) { gw_prioqueue_destroy(privdata->outgoing_queue, NULL); } gw_free(privdata); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; info(0, "AT2[%s]: exiting", octstr_get_cstr(privdata->name)); return -1; } static int at2_pdu_extract(PrivAT2data *privdata, Octstr **pdu, Octstr *line, Octstr *smsc_number) { Octstr *buffer; long len = 0; int pos = 0; int tmp; Octstr *numtmp; Octstr *tmp2; buffer = octstr_duplicate(line); /* find the beginning of a message from the modem*/ if ((pos = octstr_search(buffer, octstr_imm("+CDS:"), 0)) != -1) pos += 5; else { if ((pos = octstr_search(buffer, octstr_imm("+CMT:"), 0)) != -1) pos += 5; else if ((pos = octstr_search(buffer, octstr_imm("+CMGR:"), 0)) != -1) { /* skip status field in +CMGR response */ if ((pos = octstr_search(buffer, octstr_imm(","), pos + 6)) != -1) pos++; else goto nomsg; } else goto nomsg; /* skip the next comma in CMGR and CMT responses */ tmp = octstr_search(buffer, octstr_imm(","), pos); if (!privdata->modem->broken && tmp == -1) goto nomsg; if (tmp != -1) pos = tmp + 1; } /* read the message length */ pos = octstr_parse_long(&len, buffer, pos, 10); if (pos == -1 || len == 0) goto nomsg; /* skip the spaces and line return */ while (isspace(octstr_get_char(buffer, pos))) pos++; octstr_truncate(smsc_number,0); /* skip the SMSC address on some modem types */ if (!privdata->modem->no_smsc) { tmp = at2_hexchar(octstr_get_char(buffer, pos)) * 16 + at2_hexchar(octstr_get_char(buffer, pos + 1)); if (tmp < 0) goto nomsg; numtmp = octstr_create_from_data(octstr_get_cstr(buffer)+pos+2,tmp * 2); /* we now have the hexchars of the SMSC in GSM encoding */ octstr_hex_to_binary(numtmp); tmp2 = gsm2number(numtmp); debug("bb.smsc.at2", 0, "AT2[%s]: received message from SMSC: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(tmp2)); octstr_destroy(numtmp); octstr_append(smsc_number,tmp2); octstr_destroy(tmp2); pos += 2 + tmp * 2; } /* check if the buffer is long enough to contain the full message */ if (!privdata->modem->broken && octstr_len(buffer) < len * 2 + pos) goto nomsg; if (privdata->modem->broken && octstr_len(buffer) < len * 2) goto nomsg; /* copy the PDU then remove it from the input buffer*/ *pdu = octstr_copy(buffer, pos, len * 2); octstr_destroy(buffer); return 1; nomsg: octstr_destroy(buffer); return 0; } static unsigned char nibble2hex(unsigned char b) { if(b < 0x0A) return '0'+ b; else return 'A'+ b - 0x0A; } static Octstr *gsm2number(Octstr *pdu) { Octstr *tmp = NULL; unsigned char c; unsigned char a; unsigned char b; int ton; int len; int pos; pos=0; len = octstr_len(pdu); if(len<= 0) return octstr_create(""); ton = octstr_get_char(pdu,pos++); ton = (ton >> 4) & 0x07; switch(ton) { case 0: /* unknown */ tmp = octstr_create(""); break; case 1: /* international */ tmp = octstr_create("+"); break; case 2: /* national */ tmp = octstr_create("0"); break; case 3: /* network-specific */ default: tmp = octstr_create(""); break; } while(--len > 0) { c = octstr_get_char(pdu,pos++); a = c & 0x0F; b = ((c & 0xF0) >> 4); if((b == 0x0F) && (len < 2)) { octstr_append_char(tmp, nibble2hex(a)); } else { octstr_append_char(tmp, nibble2hex(a)); octstr_append_char(tmp, nibble2hex(b)); } } return tmp; } static int at2_hexchar(int hexc) { hexc = toupper(hexc) - 48; return (hexc > 9) ? hexc - 7 : hexc; } static Msg *at2_pdu_decode(Octstr *data, PrivAT2data *privdata) { int type; Msg *msg = NULL; /* Get the PDU type */ type = octstr_get_char(data, 1) & 3; switch (type) { case AT_DELIVER_SM: msg = at2_pdu_decode_deliver_sm(data, privdata); break; case AT_STATUS_REPORT_SM: msg = at2_pdu_decode_report_sm(data, privdata); break; /* Add other message types here: */ } return msg; } static Msg *at2_pdu_decode_deliver_sm(Octstr *data, PrivAT2data *privdata) { int len, pos, i, ntype; int udhi, dcs, udhlen, pid; Octstr *origin = NULL; Octstr *udh = NULL; Octstr *text = NULL, *tmpstr; Octstr *pdu = NULL; Msg *message = NULL; struct universaltime mtime; /* time structure */ long stime; /* time in seconds */ int timezone; /* timezone in 15 minutes jumps from GMT */ /* * Note: some parts of the PDU are not decoded because they are * not needed for the Msg type. */ /* convert the pdu to binary format for ease of processing */ pdu = at2_convertpdu(data); /* UDH Indicator */ udhi = (octstr_get_char(pdu, 0) & 64) >> 6; /* originating address */ len = octstr_get_char(pdu, 1); if (len > 20) /* maximum valid number of semi-octets in Address-Value field */ goto msg_error; ntype = octstr_get_char(pdu, 2); pos = 3; if ((ntype & 0xD0) == 0xD0) { /* Alphanumeric sender */ origin = octstr_create(""); tmpstr = octstr_copy(pdu, 3, len); at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, origin, 0); octstr_destroy(tmpstr); debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric sender <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(origin)); pos += (len + 1) / 2; } else { origin = octstr_create(""); if ((ntype & 0x90) == 0x90) { /* International number */ octstr_append_char(origin, '+'); } for (i = 0; i < len; i += 2, pos++) { octstr_append_char(origin, (octstr_get_char(pdu, pos) & 15) + 48); if (i + 1 < len) octstr_append_char(origin, (octstr_get_char(pdu, pos) >> 4) + 48); } debug("bb.smsc.at2", 0, "AT2[%s]: Numeric sender %s <%s>", octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""), octstr_get_cstr(origin)); } if (pos > octstr_len(pdu)) goto msg_error; /* PID */ pid = octstr_get_char(pdu, pos); pos++; /* DCS */ dcs = octstr_get_char(pdu, pos); pos++; /* get the timestamp */ mtime.year = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.year += (mtime.year < 70 ? 2000 : 1900); mtime.month = swap_nibbles(octstr_get_char(pdu, pos)); mtime.month--; pos++; mtime.day = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.hour = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.minute = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.second = swap_nibbles(octstr_get_char(pdu, pos)); pos++; /* * time zone: * * time zone is "swapped nibble", with the MSB as the sign (1 is negative). */ timezone = swap_nibbles(octstr_get_char(pdu, pos)); pos++; timezone = ((timezone >> 7) ? -1 : 1) * (timezone & 127); /* * Ok, that was the time zone as read from the PDU. Now how to interpert it? * All the handsets I tested send the timestamp of their local time and the * timezone as GMT+0. I assume that the timestamp is the handset's local time, * so we need to apply the timezone in reverse to get GM time: */ /* * time in PDU is handset's local time and timezone is handset's time zone * difference from GMT */ mtime.hour -= timezone / 4; mtime.minute -= 15 * (timezone % 4); stime = date_convert_universal(&mtime); /* get data length * TODO: Is it allowed to have length = 0 ??? (alex) */ len = octstr_get_char(pdu, pos); pos++; debug("bb.smsc.at2", 0, "AT2[%s]: User data length read as (%d)", octstr_get_cstr(privdata->name), len); /* if there is a UDH */ udhlen = 0; if (udhi && len > 0) { udhlen = octstr_get_char(pdu, pos); pos++; if (udhlen + 1 > len) goto msg_error; udh = octstr_copy(pdu, pos-1, udhlen+1); pos += udhlen; len -= udhlen + 1; } else if (len <= 0) /* len < 0 is impossible, but sure is sure */ udhi = 0; debug("bb.smsc.at2", 0, "AT2[%s]: Udh decoding done len=%d udhi=%d udhlen=%d udh='%s'", octstr_get_cstr(privdata->name), len, udhi, udhlen, (udh ? octstr_get_cstr(udh) : "")); if (pos > octstr_len(pdu) || len < 0) goto msg_error; /* build the message */ message = msg_create(sms); if (!dcs_to_fields(&message, dcs)) { /* TODO Should we reject this message? */ error(0, "AT2[%s]: Invalid DCS (0x%02x)", octstr_get_cstr(privdata->name), dcs); dcs_to_fields(&message, 0); } message->sms.pid = pid; /* deal with the user data -- 7 or 8 bit encoded */ tmpstr = octstr_copy(pdu, pos, len); if (message->sms.coding == DC_8BIT || message->sms.coding == DC_UCS2) { text = octstr_duplicate(tmpstr); } else { int offset = 0; text = octstr_create(""); if (udhi && message->sms.coding == DC_7BIT) { int nbits; nbits = (udhlen + 1) * 8; /* fill bits for UDH to septet boundary */ offset = (((nbits / 7) + 1) * 7 - nbits) % 7; /* * Fix length because UDH data length is determined * in septets if we are in GSM coding, otherwise it's in octets. Adding 6 * will ensure that for an octet length of 0, we get septet length 0, * and for octet length 1 we get septet length 2. */ len = len + udhlen + 1 - (8 * (udhlen + 1) + 6) / 7; } at2_decode7bituncompressed(tmpstr, len, text, offset); } message->sms.sender = origin; if (octstr_len(privdata->my_number)) { message->sms.receiver = octstr_duplicate(privdata->my_number); } else { /* Put a dummy address in the receiver for now (SMSC requires one) */ message->sms.receiver = octstr_create_from_data("1234", 4); } if (udhi) { message->sms.udhdata = udh; } message->sms.msgdata = text; message->sms.time = stime; /* cleanup */ octstr_destroy(pdu); octstr_destroy(tmpstr); return message; msg_error: error(1, "AT2[%s]: Invalid DELIVER-SMS pdu!", octstr_get_cstr(privdata->name)); O_DESTROY(udh); O_DESTROY(origin); O_DESTROY(text); O_DESTROY(pdu); return NULL; } static Msg *at2_pdu_decode_report_sm(Octstr *data, PrivAT2data *privdata) { Msg *dlrmsg = NULL; Octstr *pdu, *msg_id, *tmpstr = NULL, *receiver = NULL; int type, tp_mr, len, ntype, pos; /* * parse the PDU. */ /* convert the pdu to binary format for ease of processing */ pdu = at2_convertpdu(data); /* Message reference */ tp_mr = octstr_get_char(pdu, 1); msg_id = octstr_format("%d", tp_mr); debug("bb.smsc.at2", 0, "AT2[%s]: got STATUS-REPORT for message <%d>:", octstr_get_cstr(privdata->name), tp_mr); /* reciver address */ len = octstr_get_char(pdu, 2); ntype = octstr_get_char(pdu, 3); pos = 4; if ((ntype & 0xD0) == 0xD0) { /* Alphanumeric sender */ receiver = octstr_create(""); tmpstr = octstr_copy(pdu, pos, (len + 1) / 2); at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, receiver, 0); octstr_destroy(tmpstr); debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric receiver <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(receiver)); pos += (len + 1) / 2; } else { int i; receiver = octstr_create(""); if ((ntype & 0x90) == 0x90) { /* International number */ octstr_append_char(receiver, '+'); } for (i = 0; i < len; i += 2, pos++) { octstr_append_char(receiver, (octstr_get_char(pdu, pos) & 15) + 48); if (i + 1 < len) octstr_append_char(receiver, (octstr_get_char(pdu, pos) >> 4) + 48); } debug("bb.smsc.at2", 0, "AT2[%s]: Numeric receiver %s <%s>", octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""), octstr_get_cstr(receiver)); } pos += 14; /* skip time stamps for now */ if ((type = octstr_get_char(pdu, pos)) == -1 ) { error(1, "AT2[%s]: STATUS-REPORT pdu too short to have TP-Status field !", octstr_get_cstr(privdata->name)); goto error; } /* Check DLR type: * 3GPP TS 23.040 defines this a bit mapped field with lots of options * most of which are not really intersting to us, as we are only interested * in one of three conditions : failed, held in SC for delivery later, or delivered successfuly * and here's how I suggest to test it (read the 3GPP reference for further detailes) - * we'll test the 6th and 5th bits (7th bit when set making all other values 'reseved' so I want to test it). */ type = type & 0xE0; /* filter out everything but the 7th, 6th and 5th bits */ switch (type) { case 0x00: /* 0 0 : success class */ type = DLR_SUCCESS; tmpstr = octstr_create("Success"); break; case 0x20: /* 0 1 : buffered class (temporary error) */ type = DLR_BUFFERED; tmpstr = octstr_create("Buffered"); break; case 0x40: case 0x60: default: /* 1 0 : failed class */ /* 1 1 : failed class (actually, temporary error but timed out) */ /* and any other value (can't think of any) is considered failure */ type = DLR_FAIL; tmpstr = octstr_create("Failed"); break; } /* Actually, the above implementation is not correct, as the reference * says that implementations should consider any "reserved" values to be * "failure", but most reserved values fall into one of the three * categories. It will catch "reserved" values where the first 3 MSBits * are not set as "Success" which may not be correct. */ if ((dlrmsg = dlr_find(privdata->conn->id, msg_id, receiver, type, 0)) == NULL) { debug("bb.smsc.at2", 1, "AT2[%s]: Received delivery notification but can't find that ID in the DLR storage", octstr_get_cstr(privdata->name)); goto error; } /* Beware DLR URL is now in msg->sms.dlr_url given by dlr_find() */ dlrmsg->sms.msgdata = octstr_duplicate(tmpstr); error: O_DESTROY(tmpstr); O_DESTROY(pdu); O_DESTROY(receiver); O_DESTROY(msg_id); return dlrmsg; } static Octstr *at2_convertpdu(Octstr *pdutext) { Octstr *pdu; int i; int len = octstr_len(pdutext); pdu = octstr_create(""); for (i = 0; i < len; i += 2) { octstr_append_char(pdu, at2_hexchar(octstr_get_char(pdutext, i)) * 16 + at2_hexchar(octstr_get_char(pdutext, i + 1))); } return pdu; } static int at2_rmask[8] = { 0, 1, 3, 7, 15, 31, 63, 127 }; static int at2_lmask[8] = { 0, 128, 192, 224, 240, 248, 252, 254 }; static void at2_decode7bituncompressed(Octstr *input, int len, Octstr *decoded, int offset) { unsigned char septet, octet, prevoctet; int i; int r = 1; int c = 7; int pos = 0; /* Shift the buffer offset bits to the left */ if (offset > 0) { unsigned char *ip; for (i = 0, ip = (unsigned char *)octstr_get_cstr(input); i < octstr_len(input); i++) { if (i == octstr_len(input) - 1) *ip = *ip >> offset; else *ip = (*ip >> offset) | (*(ip + 1) << (8 - offset)); ip++; } } octet = octstr_get_char(input, pos); prevoctet = 0; for (i = 0; i < len; i++) { septet = ((octet & at2_rmask[c]) << (r - 1)) + prevoctet; octstr_append_char(decoded, septet); prevoctet = (octet & at2_lmask[r]) >> c; /* When r=7 we have a full character in prevoctet */ if ((r == 7) && (i < len - 1)) { i++; octstr_append_char(decoded, prevoctet); prevoctet = 0; } r = (r > 6) ? 1 : r + 1; c = (c < 2) ? 7 : c - 1; pos++; octet = octstr_get_char(input, pos); } charset_gsm_to_utf8(decoded); } static void at2_send_messages(PrivAT2data *privdata) { Msg *msg; if (privdata->modem->enable_mms && gw_prioqueue_len(privdata->outgoing_queue) > 1) at2_send_modem_command(privdata, "AT+CMMS=2", 0, 0); if (privdata->conn->throughput > 0 && load_get(privdata->load, 0) >= privdata->conn->throughput) { debug("bb.sms.at2", 0, "AT2[%s]: throughput limit exceeded (load: %.02f, throughput: %.02f)", octstr_get_cstr(privdata->conn->id), load_get(privdata->load, 0), privdata->conn->throughput); } else { if ((msg = gw_prioqueue_remove(privdata->outgoing_queue))) { load_increase(privdata->load); at2_send_one_message(privdata, msg); } } } static void at2_send_one_message(PrivAT2data *privdata, Msg *msg) { char command[500]; int ret = -1; char sc[3]; if (octstr_len(privdata->my_number)) { octstr_destroy(msg->sms.sender); msg->sms.sender = octstr_duplicate(privdata->my_number); } /* * The standard says you should be prepending the PDU with 00 to indicate * to use the default SC. Some older modems dont expect this so it can be * disabled * NB: This extra padding is not counted in the CMGS byte count */ sc[0] = '\0'; if (!privdata->modem->no_smsc) strcpy(sc, "00"); if (msg_type(msg) == sms) { Octstr *pdu; int msg_id = -1; if ((pdu = at2_pdu_encode(msg, privdata)) == NULL) { error(2, "AT2[%s]: Error encoding PDU!",octstr_get_cstr(privdata->name)); return; } /* * send the initial command and then wait for > */ sprintf(command, "AT+CMGS=%ld", octstr_len(pdu) / 2); ret = at2_send_modem_command(privdata, command, 5, 1); debug("bb.smsc.at2", 0, "AT2[%s]: send command status: %d", octstr_get_cstr(privdata->name), ret); if (ret == 1) {/* > only! */ /* * Ok the > has been see now so we can send the PDU now and a * control Z but no CR or LF * * We will handle the 'nokiaphone' types a bit differently, since * they have a generic error in accepting PDUs that are "too big". * Which means, PDU that are longer then 18 bytes get truncated by * the phone modems. We'll buffer the PDU output in a loop. * All other types will get handled as used to be. */ if (octstr_compare(privdata->modem->id, octstr_imm("nokiaphone")) != 0) { sprintf(command, "%s%s", sc, octstr_get_cstr(pdu)); at2_write(privdata, command); at2_write_ctrlz(privdata); } else { /* include the CTRL-Z in the PDU string */ sprintf(command, "%s%s%c", sc, octstr_get_cstr(pdu), 0x1A); /* chop PDU into 18-byte-at-a-time pieces to prevent choking * of certain GSM Phones (e.g. Nokia 6310, 6230 etc.) */ if (strlen(command) > 18) { char chop[20]; int len = strlen(command); int pos = 0; int ret = 18; while (pos < len) { if (pos + ret > len) ret = len - pos; memcpy(chop, command + pos, ret); pos += ret; chop[ret] = '\0'; at2_write(privdata, chop); gwthread_sleep((double) 10/1000); } } else { at2_write(privdata, command); } } /* wait 20 secs for modem command */ ret = at2_wait_modem_command(privdata, 20, 0, &msg_id); debug("bb.smsc.at2", 0, "AT2[%s]: send command status: %d", octstr_get_cstr(privdata->name), ret); if (ret != 0) { bb_smscconn_send_failed(privdata->conn, msg, SMSCCONN_FAILED_TEMPORARILY, octstr_create("ERROR")); } else { /* store DLR message if needed for SMSC generated delivery reports */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) { if (msg_id == -1) error(0,"AT2[%s]: delivery notification requested, but I have no message ID!", octstr_get_cstr(privdata->name)); else { Octstr *dlrmsgid = octstr_format("%d", msg_id); dlr_add(privdata->conn->id, dlrmsgid, msg, 0); O_DESTROY(dlrmsgid); } } bb_smscconn_sent(privdata->conn, msg, NULL); } } else { error(0,"AT2[%s]: Error received, notifying failure, " "sender: %s receiver: %s msgdata: %s udhdata: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.msgdata), octstr_get_cstr(msg->sms.udhdata)); bb_smscconn_send_failed(privdata->conn, msg, SMSCCONN_FAILED_TEMPORARILY, octstr_create("ERROR")); } O_DESTROY(pdu); } } static Octstr *at2_pdu_encode(Msg *msg, PrivAT2data *privdata) { /* * Message coding is done as a binary octet string, * as per 3GPP TS 23.040 specification (GSM 03.40), */ Octstr *pdu = NULL, *temp = NULL, *buffer = octstr_create(""); int len, setvalidity = 0; /* * message type SUBMIT , bit mapped : * bit7 .. bit0 * TP-RP , TP-UDHI, TP-SRR, TP-VPF(4), TP-VPF(3), TP-RD, TP-MTI(1), TP-MTI(0) */ octstr_append_char(buffer, ((msg->sms.rpi > 0 ? 1 : 0) << 7) /* TP-RP */ | ((octstr_len(msg->sms.udhdata) ? 1 : 0) << 6) /* TP-UDHI */ | ((DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask) ? 1 : 0) << 5) /* TP-SRR */ | 16 /* TP-VP(Rel)*/ | 1 /* TP-MTI: SUBMIT_SM */ ); /* message reference (0 for now) */ octstr_append_char(buffer, 0); /* destination address */ if ((temp = at2_format_address_field(msg->sms.receiver)) == NULL) goto error; octstr_append(buffer, temp); O_DESTROY(temp); octstr_append_char(buffer, (msg->sms.pid == SMS_PARAM_UNDEFINED ? 0 : msg->sms.pid) ); /* protocol identifier */ octstr_append_char(buffer, fields_to_dcs(msg, /* data coding scheme */ (msg->sms.alt_dcs != SMS_PARAM_UNDEFINED ? msg->sms.alt_dcs : privdata->conn->alt_dcs))); /* * Validity-Period (TP-VP) * see GSM 03.40 section 9.2.3.12 * defaults to 24 hours = 167 if not set */ if (msg->sms.validity != MSG_PARAM_UNDEFINED) { long val = (msg->sms.validity - time(NULL)) / 60; if (val > 635040) setvalidity = 255; if (val >= 50400 && val <= 635040) setvalidity = (val - 1) / 7 / 24 / 60 + 192 + 1; if (val > 43200 && val < 50400) setvalidity = 197; if (val >= 2880 && val <= 43200) setvalidity = (val - 1) / 24 / 60 + 166 + 1; if (val > 1440 && val < 2880) setvalidity = 168; if (val >= 750 && val <= 1440) setvalidity = (val - 720 - 1) / 30 + 143 + 1; if (val > 720 && val < 750) setvalidity = 144; if (val >= 5 && val <= 720) setvalidity = (val - 1) / 5 - 1 + 1; if (val < 5) setvalidity = 0; } else setvalidity = (privdata->validityperiod != NULL ? atoi(octstr_get_cstr(privdata->validityperiod)) : 167); if (setvalidity >= 0 && setvalidity <= 143) debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d minutes", octstr_get_cstr(privdata->name), (setvalidity + 1)*5); else if (setvalidity >= 144 && setvalidity <= 167) debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %3.1f hours", octstr_get_cstr(privdata->name), ((float)(setvalidity - 143) / 2) + 12); else if (setvalidity >= 168 && setvalidity <= 196) debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d days", octstr_get_cstr(privdata->name), (setvalidity - 166)); else debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d weeks", octstr_get_cstr(privdata->name), (setvalidity - 192)); octstr_append_char(buffer, setvalidity); /* user data length - include length of UDH if it exists */ len = sms_msgdata_len(msg); if (octstr_len(msg->sms.udhdata)) { if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) { len += octstr_len(msg->sms.udhdata); if (len > SMS_8BIT_MAX_LEN) { /* truncate user data to allow UDH to fit */ octstr_delete(msg->sms.msgdata, SMS_8BIT_MAX_LEN - octstr_len(msg->sms.udhdata), 9999); len = SMS_8BIT_MAX_LEN; } } else { /* * The reason we branch here is because UDH data length is determined * in septets if we are in GSM coding, otherwise it's in octets. Adding 6 * will ensure that for an octet length of 0, we get septet length 0, * and for octet length 1 we get septet length 2. */ int temp_len; len += (temp_len = (((8 * octstr_len(msg->sms.udhdata)) + 6) / 7)); if (len > SMS_7BIT_MAX_LEN) { /* truncate user data to allow UDH to fit */ octstr_delete(msg->sms.msgdata, SMS_7BIT_MAX_LEN - temp_len, 9999); len = SMS_7BIT_MAX_LEN; } } } octstr_append_char(buffer,len); if (octstr_len(msg->sms.udhdata)) /* udh */ octstr_append(buffer, msg->sms.udhdata); /* user data */ if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) { octstr_append(buffer, msg->sms.msgdata); } else { int offset = 0; Octstr *msgdata; /* * calculate the number of fill bits needed to align * the 7bit encoded user data on septet boundry */ if (octstr_len(msg->sms.udhdata)) { /* Have UDH */ int nbits = octstr_len(msg->sms.udhdata) * 8; /* Includes UDH length byte */ offset = (((nbits / 7) + 1) * 7 - nbits) % 7; /* Fill bits */ } msgdata = octstr_duplicate(msg->sms.msgdata); charset_utf8_to_gsm(msgdata); if ((temp = at2_encode7bituncompressed(msgdata, offset)) != NULL) octstr_append(buffer, temp); O_DESTROY(temp); octstr_destroy(msgdata); } /* convert PDU to HEX representation suitable for the AT2 command set */ pdu = at2_encode8bituncompressed(buffer); O_DESTROY(buffer); return pdu; error: O_DESTROY(temp); O_DESTROY(buffer); O_DESTROY(pdu); return NULL; } static Octstr *at2_encode7bituncompressed(Octstr *source, int offset) { int LSBmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; int MSBmask[8] = { 0x00, 0x40, 0x60, 0x70, 0x78, 0x7C, 0x7E, 0x7F }; int destRemain = (int)ceil((octstr_len(source) * 7.0 + offset) / 8.0); int i = (offset?8-offset:7), iStore = offset; int posS; Octstr *target = octstr_create(""); int target_chr = 0, source_chr; /* start packing the septet stream into an octet stream */ for (posS = 0; (source_chr = octstr_get_char(source, posS++)) != -1;) { /* grab least significant bits from current septet and * store them packed to the right */ target_chr |= (source_chr & LSBmask[i]) << iStore; /* store current byte if last command filled it */ if (iStore != 0) { destRemain--; octstr_append_char(target, target_chr); target_chr = 0; } /* grab most significant bits from current septet and * store them packed to the left */ target_chr |= (source_chr & MSBmask[7 - i]) >> (8 - iStore) % 8; /* advance target bit index by 7 (modulo 8 addition ) */ iStore = (--iStore < 0 ? 7 : iStore); /* if just finished packing 8 septets (into 7 octets) don't advance mask index */ if (iStore != 0) i = (++i > 7 ? 1 : i); } /* don't forget to pack the leftovers ;-) */ if (destRemain > 0) octstr_append_char(target, target_chr); return target; } static Octstr *at2_encode8bituncompressed(Octstr *input) { int len, i; Octstr *out = octstr_create(""); len = octstr_len(input); for (i = 0; i < len; i++) { /* each character is encoded in its hex representation (2 chars) */ octstr_append_char(out, at2_numtext( (octstr_get_char(input, i) & 0xF0) >> 4)); octstr_append_char(out, at2_numtext( (octstr_get_char(input, i) & 0x0F))); } return out; } static int at2_numtext(int num) { return (num > 9) ? (num + 55) : (num + 48); } static int at2_detect_speed(PrivAT2data *privdata) { int i; int autospeeds[] = { #ifdef B115200 115200, #endif #ifdef B57600 57600, #endif 38400, 19200, 9600 }; debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem speed. ", octstr_get_cstr(privdata->name)); for (i = 0; i < (sizeof(autospeeds) / sizeof(int)) && !privdata->shutdown; i++) { if(at2_test_speed(privdata, autospeeds[i]) == 0) { privdata->speed = autospeeds[i]; break; } } if (privdata->speed == 0) { info(0, "AT2[%s]: cannot detect speed", octstr_get_cstr(privdata->name)); return -1; } info(0, "AT2[%s]: detect speed is %ld", octstr_get_cstr(privdata->name), privdata->speed); return 0; } static int at2_test_speed(PrivAT2data *privdata, long speed) { int res; if (at2_open_device(privdata) == -1) return -1; at2_read_buffer(privdata, 0); /* give telnet escape sequences a chance */ at2_set_speed(privdata, speed); /* send a return so the modem can detect the speed */ res = at2_send_modem_command(privdata, "", 1, 0); res = at2_send_modem_command(privdata, "AT", 0, 0); if (res != 0) res = at2_send_modem_command(privdata, "AT", 0, 0); if (res != 0) res = at2_send_modem_command(privdata, "AT", 0, 0); at2_close_device(privdata); return res; } static int at2_detect_modem_type(PrivAT2data *privdata) { int res; ModemDef *modem; int i; debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem type", octstr_get_cstr(privdata->name)); if (at2_open_device(privdata) == -1) return -1; at2_set_speed(privdata, privdata->speed); /* sleep 10 ms in order to get device some time to accept speed */ gwthread_sleep(0.1); /* reset the modem */ if (at2_send_modem_command(privdata, "ATZ", 0, 0) == -1) { error(0, "AT2[%s]: Wrong or no answer to ATZ", octstr_get_cstr(privdata->name)); at2_close_device(privdata); return -1; } /* check if the modem responded */ if (at2_send_modem_command(privdata, "AT", 0, 0) == -1) { error(0, "AT2[%s]: Wrong or no answer to AT. Trying again", octstr_get_cstr(privdata->name)); if (at2_send_modem_command(privdata, "AT", 0, 0) == -1) { error(0, "AT2[%s]: Second attempt to send AT failed", octstr_get_cstr(privdata->name)); at2_close_device(privdata); return -1; } } at2_flush_buffer(privdata); /* send a return so the modem can detect the speed */ res = at2_send_modem_command(privdata, "", 1, 0); res = at2_send_modem_command(privdata, "AT", 0, 0); if (at2_send_modem_command(privdata, "AT&F", 0, 0) == -1) { at2_close_device(privdata); return -1; } at2_flush_buffer(privdata); if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1) { at2_close_device(privdata); return -1; } at2_flush_buffer(privdata); if (at2_send_modem_command(privdata, "ATI", 0, 0) == -1) { at2_close_device(privdata); return -1; } /* we try to detect the modem automatically */ i = 1; while ((modem = at2_read_modems(privdata, privdata->configfile, NULL, i++)) != NULL) { if (octstr_len(modem->detect_string) == 0) { at2_destroy_modem(modem); continue; } /* debug("bb.smsc.at2",0,"AT2[%s]: searching for %s", octstr_get_cstr(privdata->name), octstr_get_cstr(modem->name)); */ if (octstr_search(privdata->lines, modem->detect_string, 0) != -1) { if (octstr_len(modem->detect_string2) == 0) { debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s>, using modem definition <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(modem->detect_string), octstr_get_cstr(modem->name)); privdata->modem = modem; break; } else { if (octstr_search(privdata->lines, modem->detect_string2, 0) != -1) { debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s> plus <%s>, using modem " "definition <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(modem->detect_string), octstr_get_cstr(modem->detect_string2), octstr_get_cstr(modem->name)); privdata->modem = modem; break; } } } else { /* Destroy modem */ at2_destroy_modem(modem); } } if (privdata->modem == NULL) { debug("bb.smsc.at2", 0, "AT2[%s]: Cannot detect modem, using generic", octstr_get_cstr(privdata->name)); if ((modem = at2_read_modems(privdata, privdata->configfile, octstr_imm("generic"), 0)) == NULL) { panic(0, "AT2[%s]: Cannot detect modem and generic not found", octstr_get_cstr(privdata->name)); } else { privdata->modem = modem; } } /* lets see if it supports GSM SMS 2+ mode */ res = at2_send_modem_command(privdata, "AT+CSMS=?", 0, 0); if (res != 0) /* if it doesnt even understand the command, I'm sure it won't support it */ privdata->phase2plus = 0; else { /* we have to take a part a string like +CSMS: (0,1,128) */ Octstr *ts; int i; List *vals; ts = privdata->lines; privdata->lines = NULL; i = octstr_search_char(ts, '(', 0); if (i > 0) { octstr_delete(ts, 0, i + 1); } i = octstr_search_char(ts, ')', 0); if (i > 0) { octstr_truncate(ts, i); } vals = octstr_split(ts, octstr_imm(",")); octstr_destroy(ts); ts = gwlist_search(vals, octstr_imm("1"), (void*) octstr_item_match); if (ts) privdata->phase2plus = 1; gwlist_destroy(vals, octstr_destroy_item); } if (privdata->phase2plus) info(0, "AT2[%s]: Phase 2+ is supported", octstr_get_cstr(privdata->name)); at2_close_device(privdata); return 0; } static ModemDef *at2_read_modems(PrivAT2data *privdata, Octstr *file, Octstr *id, int idnumber) { Cfg *cfg; List *grplist; CfgGroup *grp; Octstr *p; ModemDef *modem; int i = 1; /* * Use id and idnumber=0 or id=NULL and idnumber > 0 */ if (octstr_len(id) == 0 && idnumber == 0) return NULL; if (idnumber == 0) debug("bb.smsc.at2", 0, "AT2[%s]: Reading modem definitions from <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(file)); cfg = cfg_create(file); if (cfg_read(cfg) == -1) panic(0, "Cannot read modem definition file"); grplist = cfg_get_multi_group(cfg, octstr_imm("modems")); if (idnumber == 0) debug("bb.smsc.at2", 0, "AT2[%s]: Found <%ld> modems in config", octstr_get_cstr(privdata->name), gwlist_len(grplist)); if (grplist == NULL) panic(0, "Where are the modem definitions ?!?!"); grp = NULL; while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p == NULL) { info(0, "Modems group without id, bad"); continue; } /* Check by id */ if (octstr_len(id) != 0 && octstr_compare(p, id) == 0) { O_DESTROY(p); break; } /* Check by idnumber */ if (octstr_len(id) == 0 && idnumber == i) { O_DESTROY(p); break; } O_DESTROY(p); i++; grp = NULL; } if (grplist != NULL) gwlist_destroy(grplist, NULL); if (grp != NULL) { modem = gw_malloc(sizeof(ModemDef)); modem->id = cfg_get(grp, octstr_imm("id")); modem->name = cfg_get(grp, octstr_imm("name")); if (modem->name == NULL) modem->name = octstr_duplicate(modem->id); modem->detect_string = cfg_get(grp, octstr_imm("detect-string")); modem->detect_string2 = cfg_get(grp, octstr_imm("detect-string2")); modem->init_string = cfg_get(grp, octstr_imm("init-string")); if (modem->init_string == NULL) modem->init_string = octstr_create("AT+CNMI=1,2,0,1,0"); modem->reset_string = cfg_get(grp, octstr_imm("reset-string")); modem->speed = 9600; cfg_get_integer(&modem->speed, grp, octstr_imm("speed")); cfg_get_bool(&modem->need_sleep, grp, octstr_imm("need-sleep")); modem->enable_hwhs = cfg_get(grp, octstr_imm("enable-hwhs")); if (modem->enable_hwhs == NULL) modem->enable_hwhs = octstr_create("AT+IFC=2,2"); cfg_get_bool(&modem->no_pin, grp, octstr_imm("no-pin")); cfg_get_bool(&modem->no_smsc, grp, octstr_imm("no-smsc")); modem->sendline_sleep = 100; cfg_get_integer(&modem->sendline_sleep, grp, octstr_imm("sendline-sleep")); modem->keepalive_cmd = cfg_get(grp, octstr_imm("keepalive-cmd")); if (modem->keepalive_cmd == NULL) modem->keepalive_cmd = octstr_create("AT"); modem->message_storage = cfg_get(grp, octstr_imm("message-storage")); if (cfg_get_integer(&modem->message_start, grp, octstr_imm("message-start"))) modem->message_start = 1; cfg_get_bool(&modem->enable_mms, grp, octstr_imm("enable-mms")); modem->hardware_flow_control = 1; cfg_get_bool(&modem->hardware_flow_control, grp, octstr_imm("hardware-flow-control")); /* if (modem->message_storage == NULL) modem->message_storage = octstr_create("SM"); */ cfg_get_bool(&modem->broken, grp, octstr_imm("broken")); cfg_destroy(cfg); return modem; } else { cfg_destroy(cfg); return NULL; } } static void at2_destroy_modem(ModemDef *modem) { if (modem != NULL) { O_DESTROY(modem->id); O_DESTROY(modem->name); O_DESTROY(modem->detect_string); O_DESTROY(modem->detect_string2); O_DESTROY(modem->init_string); O_DESTROY(modem->enable_hwhs); O_DESTROY(modem->keepalive_cmd); O_DESTROY(modem->message_storage); O_DESTROY(modem->reset_string); gw_free(modem); } } static int swap_nibbles(unsigned char byte) { return ( ( byte & 15 ) * 10 ) + ( byte >> 4 ); } static Octstr *at2_format_address_field(Octstr *msisdn) { int ntype = PNT_UNKNOWN; Octstr *out = octstr_create(""); Octstr *temp = octstr_duplicate(msisdn); octstr_strip_blanks(temp); /* * Check for international numbers * number starting with '+' or '00' are international, * others are national. */ if (strncmp(octstr_get_cstr(msisdn), "+", 1) == 0) { octstr_delete(temp, 0, 1); ntype = PNT_INTER; /* international */ } else if (strncmp(octstr_get_cstr(msisdn), "00", 2) == 0) { octstr_delete(temp, 0, 2); ntype = PNT_INTER; /* international */ } /* address length */ octstr_append_char(out, octstr_len(temp)); /* Type of address : bit mapped values */ octstr_append_char(out, 0x80 /* Type-of-address prefix */ | 0x01 /* Numbering-plan: MSISDN */ | (ntype == PNT_INTER ? 0x10 : 0x00) /* Type-of-number: International or National */ ); /* grab the digits from the MSISDN and encode as swapped semi-octets */ while (out != NULL && octstr_len(temp) > 0) { int digit1, digit2; /* get the first two digit */ digit1 = octstr_get_char(temp,0) - 48; digit2 = octstr_get_char(temp,1) - '0'; if (digit2 < 0) digit2 = 0x0F; if(digit1 >= 0 && digit1 < 16 && digit2 < 16) { octstr_append_char(out, (digit2 << 4) | digit1); } else { O_DESTROY(out); out = NULL; } octstr_delete(temp, 0, 2); } O_DESTROY(temp); return out; } static int at2_set_message_storage(PrivAT2data *privdata, Octstr *memory_name) { Octstr *temp; int ret; if (!memory_name || !privdata) return -1; temp = octstr_format("AT+CPMS=\"%S\"", memory_name); ret = at2_send_modem_command(privdata, octstr_get_cstr(temp), 0, 0); octstr_destroy(temp); return !ret ? 0 : -1; } static const char *at2_error_string(int errcode) { /* * +CMS ERRORS * 0...127 from GSM 04.11 Annex E-2 values * 128...255 from GSM 03.40 subclause 9.2.3.22 * 300...511 from GSM 07.05 subclause 3.2.5 * 512+ are manufacturer specific according to GSM 07.05 subclause 3.2.5 * * +CME ERRORS * CME Error codes from GSM 07.07 section 9.2 * GPP TS 27.007 /2/ * GPRS-related errors - (GSM 04.08 cause codes) * */ switch (errcode) { case 0: /* * Default the code to 0 then when you extract the value from the * modem response message and no code is found, 0 will result. */ return "Modem returned ERROR but no error code - possibly unsupported or invalid command?"; case 1: /* * This cause indicates that the destination requested by the Mobile * Station cannot be reached because, although the number is in a * valid format, it is not currently assigned (allocated). */ return "Unassigned (unallocated) number (+CMS) or No connection to phone (+CME)"; case 2: return "Phone-adaptor link reserved"; case 3: /* * This can be a lot of things, depending upon the command, but in general * it relates to trying to do a command when no connection exists. */ return "Operation not allowed at this time (connection may be required)"; case 4: /* * This can be a lot of things, depending upon the command, but in general * it relates to invaid parameters being passed. */ return "Operation / Parameter(s) not supported"; case 5: return "PH-SIM PIN required"; case 8: /* * This cause indicates that the MS has tried to send a mobile originating * short message when the MS's network operator or service provider has * forbidden such transactions. */ return "Operator determined barring"; case 10: /* * This cause indicates that the outgoing call barred service applies to * the short message service for the called destination. */ return "Call barred (+CMS) or SIM not inserted or Card inserted is not a SIM (+CME)"; case 11: return "SIM PIN required"; case 12: return "SIM PUK required"; case 13: return "SIM failure"; case 14: return "SIM busy"; case 15: return "SIM wrong"; case 16: return "Incorrect password"; case 17: /* * This cause is sent to the MS if the MSC cannot service an MS generated * request because of PLMN failures, e.g. problems in MAP. */ return "Network failure (+CMS) or SIM PIN2 required (+CME)"; case 18: return "SIM PUK2 required"; case 20: return "Memory full"; case 21: /* * This cause indicates that the equipment sending this cause does not * wish to accept this short message, although it could have accepted * the short message since the equipment sending this cause is neither * busy nor incompatible. */ return "Short message transfer rejected (+CMS) or Invalid Index (+CME)"; case 22: /* * This cause is sent if the service request cannot be actioned because * of congestion (e.g. no channel, facility busy/congested etc.). Or * this cause indicates that the mobile station cannot store the * incoming short message due to lack of storage capacity. */ return "Congestion (+CMS) or Memory capacity exceeded (+CME)"; case 23: return "Memory failure"; case 24: return "Text string too long"; /* +CPBW, +CPIN, +CPIN2, +CLCK, +CPWD */ case 25: return "Invalid characters in text string"; case 26: return "Dial string too long"; /* +CPBW, ATD, +CCFC */ case 27: /* * This cause indicates that the destination indicated by the Mobile * Station cannot be reached because the interface to the destination * is not functioning correctly. The term "not functioning correctly" * indicates that a signalling message was unable to be delivered to * the remote user; e.g., a physical layer or data link layer failure * at the remote user, user equipment off-line, etc. * Also means "Invalid characters in dial string" for +CPBW. */ return "Destination out of service"; case 28: /* * This cause indicates that the subscriber is not registered in the PLMN * (i.e. IMSI not known). */ return "Unidentified subscriber"; case 29: /* * This cause indicates that the facility requested by the Mobile Station * is not supported by the PLMN. */ return "Facility rejected"; case 30: /* * This cause indicates that the subscriber is not registered in the HLR * (i.e. IMSI or directory number is not allocated to a subscriber). * Also means "No network service" for +VTS, +COPS=?, +CLCK, +CCFC, +CCWA, +CUSD */ return "Unknown subscriber (+CMS) or No network service (+CME)"; case 31: return "Network timeout"; case 32: return "Network not allowed - emergency calls only"; /* +COPS */ case 38: /* * This cause indicates that the network is not functioning correctly and * that the condition is likely to last a relatively long period of time; * e.g., immediately reattempting the short message transfer is not * likely to be successful. */ return "Network out of order"; case 40: return "Network personal PIN required (Network lock)"; case 41: /* * This cause indicates that the network is not functioning correctly and * that the condition is not likely to last a long period of time; e.g., * the Mobile Station may wish to try another short message transfer * attempt almost immediately. */ return "Temporary failure (+CMS) or Network personalization PUK required (+CME)"; case 42: /* * This cause indicates that the short message service cannot be serviced * because of high traffic. */ return "Congestion (+CMS) or Network subset personalization PIN required (+CME)"; case 43: return "Network subset personalization PUK required"; case 44: return "Service provider personalization PIN required"; case 45: return "Service provider personalization PUK required"; case 46: return "Corporate personalization PIN required"; case 47: /* * This cause is used to report a resource unavailable event only when no * other cause applies. */ return "Resources unavailable, unspecified (+CMS) or Corporate personalization PUK required (+CME)"; case 50: /* * This cause indicates that the requested short message service could not * be provided by the network because the user has not completed the * necessary administrative arrangements with its supporting networks. */ return "Requested facility not subscribed"; case 69: /* * This cause indicates that the network is unable to provide the * requested short message service. */ return "Requested facility not implemented"; case 81: /* * This cause indicates that the equipment sending this cause has received * a message with a short message reference which is not currently in use * on the MS-network interface. */ return "Invalid short message transfer reference value"; case 95: /* * This cause is used to report an invalid message event only when no * other cause in the invalid message class applies. */ return "Invalid message, unspecified"; case 96: /* * This cause indicates that the equipment sending this cause has received * a message where a mandatory information element is missing and/or has * a content error (the two cases are indistinguishable). */ return "Invalid mandatory information"; case 97: /* * This cause indicates that the equipment sending this cause has received * a message with a message type it does not recognize either because this * is a message not defined or defined but not implemented by the * equipment sending this cause. */ return "Message type non-existent or not implemented"; case 98: /* * This cause indicates that the equipment sending this cause has received * a message such that the procedures do not indicate that this is a * permissible message to receive while in the short message transfer * state. */ return "Message not compatible with short message protocol state"; case 99: /* * This cause indicates that the equipment sending this cause has received * a message which includes information elements not recognized because * the information element identifier is not defined or it is defined * but not implemented by the equipment sending the cause. However, the * information element is not required to be present in the message in * order for the equipment sending the cause to process the message. */ return "Information element non-existent or not implemented"; case 100: return "Unknown"; case 103: return "Illegal MS (#3)"; /* +CGATT */ case 106: return "Illegal ME (#6)"; /* +CGATT */ case 107: return "GPRS services not allowed (#7)"; /* +CGATT */ case 111: /* * This cause is used to report a protocol error event only when no other * cause applies. * Also means "PLMN not allowed (#11)" for +CGATT */ return "Protocol error, unspecified (+CMS) or PLMN not allowed (#11) (+CME)"; case 112: return "Location area not allowed (#12)"; /* +CGATT */ case 113: return "Roaming not allowed in this area (#13)"; /* +CGATT */ case 127: /* * This cause indicates that there has been interworking with a network * which does not provide causes for actions it takes; thus, the precise * cause for a message which is being send cannot be ascertained. */ return "Interworking, unspecified"; case 128: return "Telematic interworking not supported"; case 129: return "Short message Type 0 not supported"; case 130: return "Cannot replace short message"; case 132: return "Service option not supported (#32)"; /* +CGACT +CGDATA ATD*99 */ case 133: return "Requested service option not subscribed (#33)"; /* +CGACT +CGDATA ATD*99 */ case 134: return "Service option temporarily out of order (#34)"; /* +CGACT +CGDATA ATD*99 */ case 143: return "Unspecified TP-PID error"; case 144: return "Data coding scheme (alphabet) not supported"; case 145: return "Message class not supported"; case 148: return "Unspecified GPRS error"; case 149: return "PDP authentication failure"; /* +CGACT +CGDATA ATD*99 */ case 150: return "Invalid mobile class"; case 159: return "Unspecified TP-DCS error"; case 160: return "Command cannot be actioned"; case 161: return "Unsupported command"; case 175: return "Unspecified TP-Command error"; case 176: return "TPDU not supported"; case 192: return "SC busy"; case 193: return "No SC subscription"; case 194: return "SC system failure"; case 195: return "Invalid SME address"; case 196: return "Destination SME barred"; case 197: return "SM Rejected-Duplicate SM"; case 198: return "TP-VPF not supported"; case 199: return "TP-VP not supported"; case 208: return "DO SIM SMS storage full"; case 209: return "No SMS storage capability in SIM"; case 210: return "Error in MS"; case 211: return "SIM Memory Capacity Exceeded"; case 212: return "SIM Application Toolkit Busy"; case 213: return "SIM data download error"; case 255: return "Unspecified error cause"; case 300: /* * Mobile equipment refers to the mobile device that communicates with * the wireless network. Usually it is a mobile phone or GSM/GPRS modem. * The SIM card is defined as a separate entity and is not part of mobile equipment. */ return "Mobile equipment (ME) failure"; case 301: /* * See +CMS error code 300 for the meaning of mobile equipment. */ return "SMS service of mobile equipment (ME) is reserved"; case 302: return "The operation to be done by the AT command is not allowed"; case 303: return "The operation to be done by the AT command is not supported"; case 304: return "One or more parameter values assigned to the AT command are invalid"; case 305: return "One or more parameter values assigned to the AT command are invalid"; case 310: return "There is no SIM card"; case 311: /* * The AT command +CPIN (command name in text: Enter PIN) * can be used to send the PIN to the SIM card. */ return "The SIM card requires a PIN to operate"; case 312: /* * The AT command +CPIN (command name in text: Enter PIN) * can be used to send the PH-SIM PIN to the SIM card. */ return "The SIM card requires a PH-SIM PIN to operate"; case 313: return "SIM card failure"; case 314: return "The SIM card is busy"; case 315: return "The SIM card is wrong"; case 316: /* * The AT command +CPIN (command name in text: Enter PIN) * can be used to send the PUK to the SIM card. */ return "The SIM card requires a PUK to operate"; case 317: return "The SIM card requires a PIN2 to operate"; case 318: return "The SIM card requires a PUK2 to operate"; case 320: return "Memory/message storage failure"; case 321: return "The memory/message storage index assigned to the AT command is invalid"; case 322: return "The memory/message storage is out of space"; case 330: return "The SMS center (SMSC) address is unknown"; case 331: return "No network service is available"; case 332: return "Network timeout occurred"; case 340: return "There is no need to send message ack by the AT command +CNMA"; case 500: return "An unknown error occurred"; case 512: /* * Resulting from +CMGS, +CMSS */ return "User abort or MM establishment failure (SMS)"; case 513: /* * Resulting from +CMGS, +CMSS */ return "Lower layer falure (SMS)"; case 514: /* * Resulting from +CMGS, +CMSS */ return "CP error (SMS)"; case 515: return "Please wait, service not available, init or command in progress"; case 517: /* * Resulting from +STGI */ return "SIM ToolKit facility not supported"; case 518: /* * Resulting from +STGI */ return "SIM ToolKit indication not received"; case 519: /* * Resulting from +ECHO, +VIP */ return "Reset the product to activate or change a new echo cancellation algorithm"; case 520: /* * Resulting from +COPS=? */ return "Automatic abort about get plmn list for an incoming call"; case 526: /* * Resulting from +CLCK */ return "PIN deactivation forbidden with this SIM card"; case 527: /* * Resulting from +COPS */ return "Please wait, RR or MM is busy. Retry your selection later"; case 528: /* * Resulting from +COPS */ return "Location update failure. Emergency calls only"; case 529: /* * Resulting from +COPS */ return "PLMN selection failure. Emergency calls only"; case 531: /* * Resulting from +CMGS, +CMSS */ return "SMS not sent: the is not in FDN phonebook, and FDN lock is enabled"; case 532: /* * Resulting from +WOPEN */ return "The embedded application is activated so the objects flash are not erased"; case 533: /* * Resulting from +ATD*99,+GACT,+CGDATA */ return "Missing or unknown APN"; default: return "Error number unknown. Ask google and add it"; } } gateway-1.4.5/gw/smsc/smsc_p.h0000644000175000017500000001757013227613126014720 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_p.h - private interface to SMS center subsystem * * Lars Wirzenius * * New API by Kalle Marjola 1999 */ #ifndef SMSC_P_H #define SMSC_P_H #include #include #include #include #include "smsc.h" /* * List of SMS center types that we support. */ enum { SMSC_TYPE_DELETED, SMSC_TYPE_CIMD, SMSC_TYPE_EMI_X25, SMSC_TYPE_SEMA_X28, SMSC_TYPE_OIS, }; /* * The implementation of the SMSCenter object. */ #define DIAL_PREFIX_MAX_LEN 1024 struct SMSCenter { int type; int transport; char name[1024]; int id; /* Routing prefixes (based on phone number) */ char *preferred_prefix; char *allowed_prefix; char *denied_prefix; /* Alternative charset */ long alt_charset; /* For locking/unlocking. */ Mutex *mutex; /* for dying */ volatile sig_atomic_t killed; /* General IO device */ int socket; /* Maximum minutes idle time before ping is sent. 0 for no pings. */ int keepalive; /* TCP/IP */ char *hostname; int port; int receive_port; /* if used, with EMI 2.0/OIS 4.5 */ /* PSTN/ISDN */ char *phonenum; char *serialdevice; /* X.31 */ char *x31_phonenum; char *x31_serialdevice; /* Unix pipes */ char *pipe_command; /* CIMD */ char *cimd_hostname; int cimd_port; char *cimd_username; char *cimd_password; time_t cimd_last_spoke; int cimd_config_bits; /* EMI_X25 */ int emi_fd; FILE *emi_fp; char *emi_phonenum; char *emi_serialdevice; char *emi_hostname; int emi_port; char *emi_username; char *emi_password; int emi_current_msg_number; time_t emi_last_spoke; int emi_backup_fd; int emi_backup_port; /* different one! rename! */ char *emi_backup_allow_ip; int emi_our_port; /* port to bind us when connecting smsc */ int emi_secondary_fd; /* SEMA SMS2000 OIS 4.5 X28 */ char * sema_smscnua; char * sema_homenua; char * sema_serialdevice; struct sema_msglist *sema_mt, *sema_mo; int sema_fd; /* SEMA SMS2000 OIS 5.0 (TCP/IP to X.25 router) */ time_t ois_alive; time_t ois_alive2; void *ois_received_mo; int ois_ack_debt; int ois_flags; int ois_listening_socket; int ois_socket; char *ois_buffer; size_t ois_bufsize; size_t ois_buflen; Octstr *sender_prefix; /* For buffering input. */ char *buffer; size_t bufsize; size_t buflen; }; /* * Operations on an SMSCenter object. */ SMSCenter *smscenter_construct(void); void smscenter_destruct(SMSCenter *smsc); int smscenter_read_into_buffer(SMSCenter *); void smscenter_remove_from_buffer(SMSCenter *smsc, size_t n); /* Send an SMS message via an SMS center. Return -1 for error, 0 for OK. */ int smscenter_submit_msg(SMSCenter *smsc, Msg *msg); /* Receive an SMS message from an SMS center. Return -1 for error, 0 end of messages (other end closed their end of the connection), or 1 for a message was received. If a message was received, a pointer to it is returned via `*msg'. Note that this operation blocks until there is a message. */ int smscenter_receive_msg(SMSCenter *smsc, Msg **msg); /* Is there an SMS message pending from an SMS center? Return -1 for error, 0 for no, 1 for yes. This operation won't block, but may not be instantaneous, if it has to read a few characters to see if there is a message. Use smscenter_receive_smsmessage to actually receive the message. */ int smscenter_pending_smsmessage(SMSCenter *smsc); /* * Interface to Nokia SMS centers using CIMD. */ SMSCenter *cimd_open(char *hostname, int port, char *username, char *password); int cimd_reopen(SMSCenter *smsc); int cimd_close(SMSCenter *smsc); int cimd_pending_smsmessage(SMSCenter *smsc); int cimd_submit_msg(SMSCenter *smsc, Msg *msg); int cimd_receive_msg(SMSCenter *smsc, Msg **msg); /* * Interface to CMG SMS centers using EMI_X25. */ SMSCenter *emi_open(char *phonenum, char *serialdevice, char *username, char *password); int emi_reopen(SMSCenter *smsc); int emi_close(SMSCenter *smsc); SMSCenter *emi_open_ip(char *hostname, int port, char *username, char *password, int receive_port, char *allow_ip, int our_port); int emi_reopen_ip(SMSCenter *smsc); int emi_close_ip(SMSCenter *smsc); int emi_pending_smsmessage(SMSCenter *smsc); int emi_submit_msg(SMSCenter *smsc, Msg *msg); int emi_receive_msg(SMSCenter *smsc, Msg **msg); /* * Interface to Sema SMS centers using SM2000 */ SMSCenter *sema_open(char *smscnua, char *homenua, char* serialdevice, int waitreport); int sema_reopen(SMSCenter *smsc); int sema_close(SMSCenter *smsc); int sema_pending_smsmessage(SMSCenter *smsc); int sema_submit_msg(SMSCenter *smsc, Msg *msg); int sema_receive_msg(SMSCenter *smsc, Msg **msg); /* * Interface to Sema SMS centers using OIS 5.0. * Interface to Sema SMS centers using SM2000 */ SMSCenter *ois_open(int receiveport, const char *hostname, int port, int debug_level); int ois_reopen(SMSCenter *smsc); int ois_close(SMSCenter *smsc); int ois_pending_smsmessage(SMSCenter *smsc); int ois_submit_msg(SMSCenter *smsc, const Msg *msg); int ois_receive_msg(SMSCenter *smsc, Msg **msg); void ois_delete_queue(SMSCenter *smsc); #endif gateway-1.4.5/gw/smsc/smpp_pdu.h0000644000175000017500000002364413227613126015262 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smpp_pdu.h - declarations for SMPP PDUs * * Lars Wirzenius * Alexander Malysh : * Extended optional parameters implementation. */ #ifndef SMPP_PDU_H #define SMPP_PDU_H #include "gwlib/gwlib.h" #include "gwlib/dict.h" enum { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, max_len) #define TLV_NULTERMINATED(name, max_len) #define TLV_OCTETS(name, min_len, max_len) #define OPTIONAL_END #define INTEGER(name, octets) #define NULTERMINATED(name, max_octets) #define OCTETS(name, field_giving_octets) #define PDU(name, id, fields) name = id, #include "smpp_pdu.def" SMPP_PDU_DUMMY_TYPE }; typedef struct SMPP_PDU SMPP_PDU; struct SMPP_PDU { unsigned long type; const char *type_name; union { #define OPTIONAL_BEGIN #define TLV_INTEGER(name, octets) long name; #define TLV_NULTERMINATED(name, max_len) Octstr *name; #define TLV_OCTETS(name, min_len, max_len) Octstr *name; #define OPTIONAL_END Dict *tlv; #define INTEGER(name, octets) unsigned long name; #define NULTERMINATED(name, max_octets) Octstr *name; #define OCTETS(name, field_giving_octets) Octstr *name; #define PDU(name, id, fields) struct name { fields } name; #include "smpp_pdu.def" } u; }; /****************************************************************************** * Numbering Plan Indicator and Type of Number codes from * GSM 03.40 Version 5.3.0 Section 9.1.2.5. * http://www.etsi.org/ */ #define GSM_ADDR_TON_UNKNOWN 0x00000000 #define GSM_ADDR_TON_INTERNATIONAL 0x00000001 #define GSM_ADDR_TON_NATIONAL 0x00000002 #define GSM_ADDR_TON_NETWORKSPECIFIC 0x00000003 #define GSM_ADDR_TON_SUBSCRIBER 0x00000004 #define GSM_ADDR_TON_ALPHANUMERIC 0x00000005 /* GSM TS 03.38 */ #define GSM_ADDR_TON_ABBREVIATED 0x00000006 #define GSM_ADDR_TON_EXTENSION 0x00000007 /* Reserved */ #define GSM_ADDR_NPI_UNKNOWN 0x00000000 #define GSM_ADDR_NPI_E164 0x00000001 #define GSM_ADDR_NPI_X121 0x00000003 #define GSM_ADDR_NPI_TELEX 0x00000004 #define GSM_ADDR_NPI_NATIONAL 0x00000008 #define GSM_ADDR_NPI_PRIVATE 0x00000009 #define GSM_ADDR_NPI_ERMES 0x0000000A /* ETSI DE/PS 3 01-3 */ #define GSM_ADDR_NPI_INTERNET 0x0000000E /* SMPP v5.0, sec. 4.7.2, page 113 */ #define GSM_ADDR_NPI_EXTENSION 0x0000000F /* Reserved */ #define GSM_ADDR_NPI_WAP_CLIENT_ID 0x00000012 /* SMPP v5.0, sec. 4.7.2, page 113 */ /****************************************************************************** * esm_class parameters for both submit_sm and deliver_sm PDUs */ #define ESM_CLASS_SUBMIT_DEFAULT_SMSC_MODE 0x00000000 #define ESM_CLASS_SUBMIT_DATAGRAM_MODE 0x00000001 #define ESM_CLASS_SUBMIT_FORWARD_MODE 0x00000002 #define ESM_CLASS_SUBMIT_STORE_AND_FORWARD_MODE 0x00000003 #define ESM_CLASS_SUBMIT_DELIVERY_ACK 0x00000008 #define ESM_CLASS_SUBMIT_USER_ACK 0x00000010 #define ESM_CLASS_SUBMIT_UDH_INDICATOR 0x00000040 #define ESM_CLASS_SUBMIT_RPI 0x00000080 #define ESM_CLASS_SUBMIT_UDH_AND_RPI 0x000000C0 #define ESM_CLASS_DELIVER_DEFAULT_TYPE 0x00000000 #define ESM_CLASS_DELIVER_SMSC_DELIVER_ACK 0x00000004 #define ESM_CLASS_DELIVER_SME_DELIVER_ACK 0x00000008 #define ESM_CLASS_DELIVER_SME_MANULAL_ACK 0x00000010 #define ESM_CLASS_DELIVER_INTERM_DEL_NOTIFICATION 0x00000020 #define ESM_CLASS_DELIVER_UDH_INDICATOR 0x00000040 #define ESM_CLASS_DELIVER_RPI 0x00000080 #define ESM_CLASS_DELIVER_UDH_AND_RPI 0x000000C0 /* * Some SMPP error messages we come across */ enum SMPP_ERROR_MESSAGES { SMPP_ESME_ROK = 0x00000000, SMPP_ESME_RINVMSGLEN = 0x00000001, SMPP_ESME_RINVCMDLEN = 0x00000002, SMPP_ESME_RINVCMDID = 0x00000003, SMPP_ESME_RINVBNDSTS = 0x00000004, SMPP_ESME_RALYBND = 0x00000005, SMPP_ESME_RINVPRTFLG = 0x00000006, SMPP_ESME_RINVREGDLVFLG = 0x00000007, SMPP_ESME_RSYSERR = 0x00000008, SMPP_ESME_RINVSRCADR = 0x0000000A, SMPP_ESME_RINVDSTADR = 0x0000000B, SMPP_ESME_RINVMSGID = 0x0000000C, SMPP_ESME_RBINDFAIL = 0x0000000D, SMPP_ESME_RINVPASWD = 0x0000000E, SMPP_ESME_RINVSYSID = 0x0000000F, SMPP_ESME_RCANCELFAIL = 0x00000011, SMPP_ESME_RREPLACEFAIL = 0x00000013, SMPP_ESME_RMSGQFUL = 0x00000014, SMPP_ESME_RINVSERTYP = 0x00000015, SMPP_ESME_RINVNUMDESTS = 0x00000033, SMPP_ESME_RINVDLNAME = 0x00000034, SMPP_ESME_RINVDESTFLAG = 0x00000040, SMPP_ESME_RINVSUBREP = 0x00000042, SMPP_ESME_RINVESMCLASS = 0x00000043, SMPP_ESME_RCNTSUBDL = 0x00000044, SMPP_ESME_RSUBMITFAIL = 0x00000045, SMPP_ESME_RINVSRCTON = 0x00000048, SMPP_ESME_RINVSRCNPI = 0x00000049, SMPP_ESME_RINVDSTTON = 0x00000050, SMPP_ESME_RINVDSTNPI = 0x00000051, SMPP_ESME_RINVSYSTYP = 0x00000053, SMPP_ESME_RINVREPFLAG = 0x00000054, SMPP_ESME_RINVNUMMSGS = 0x00000055, SMPP_ESME_RTHROTTLED = 0x00000058, SMPP_ESME_RINVSCHED = 0x00000061, SMPP_ESME_RINVEXPIRY = 0x00000062, SMPP_ESME_RINVDFTMSGID = 0x00000063, SMPP_ESME_RX_T_APPN = 0x00000064, SMPP_ESME_RX_P_APPN = 0x00000065, SMPP_ESME_RX_R_APPN = 0x00000066, SMPP_ESME_RQUERYFAIL = 0x00000067, SMPP_ESME_RINVTLVSTREAM = 0x000000C0, SMPP_ESME_RTLVNOTALLWD = 0x000000C1, SMPP_ESME_RINVTLVLEN = 0x000000C2, SMPP_ESME_RMISSINGTLV = 0x000000C3, SMPP_ESME_RINVTLVVAL = 0x000000C4, SMPP_ESME_RDELIVERYFAILURE = 0x000000FE, SMPP_ESME_RUNKNOWNERR = 0x000000FF, SMPP_ESME_RSERTYPUNAUTH = 0x00000100, SMPP_ESME_RPROHIBITED = 0x00000101, SMPP_ESME_RSERTYPUNAVAIL = 0x00000102, SMPP_ESME_RSERTYPDENIED = 0x00000103, SMPP_ESME_RINVDCS = 0x00000104, SMPP_ESME_RINVSRCADDRSUBUNIT = 0x00000105, SMPP_ESME_RINVDSTADDRSUBUNIT = 0x00000106, SMPP_ESME_RINVBCASTFREQINT = 0x00000107, SMPP_ESME_RINVBCASTALIAS_NAME = 0x00000108, SMPP_ESME_RINVBCASTAREAFMT = 0x00000109, SMPP_ESME_RINVNUMBCAST_AREAS = 0x0000010A, SMPP_ESME_RINVBCASTCNTTYPE = 0x0000010B, SMPP_ESME_RINVBCASTMSGCLASS = 0x0000010C, SMPP_ESME_RBCASTFAIL = 0x0000010D, SMPP_ESME_RBCASTQUERYFAIL = 0x0000010E, SMPP_ESME_RBCASTCANCELFAIL = 0x0000010F, SMPP_ESME_RINVBCAST_REP = 0x00000110, SMPP_ESME_RINVBCASTSRVGRP = 0x00000111, SMPP_ESME_RINVBCASTCHANIND = 0x00000112, }; /* initialize SMPP PDU */ int smpp_pdu_init(Cfg *cfg); /* shutdown SMPP PDU */ int smpp_pdu_shutdown(void); SMPP_PDU *smpp_pdu_create(unsigned long type, unsigned long seq_no); void smpp_pdu_destroy(SMPP_PDU *pdu); int smpp_pdu_is_valid(SMPP_PDU *pdu); /* XXX */ Octstr *smpp_pdu_pack(Octstr *smsc_id, SMPP_PDU *pdu); SMPP_PDU *smpp_pdu_unpack(Octstr *smsc_id, Octstr *data_without_len); void smpp_pdu_dump(Octstr *smsc_id, SMPP_PDU *pdu); void smpp_pdu_dump_line(Octstr *smsc_id, SMPP_PDU *pdu); long smpp_pdu_read_len(Connection *conn); Octstr *smpp_pdu_read_data(Connection *conn, long len); /* * Return error string for given error code */ const char *smpp_error_to_string(enum SMPP_ERROR_MESSAGES error); /* add constant TLVs to TLV dictionary */ void smpp_tlv_add_constant(Octstr *smsc_id, Dict **tlvs); #endif gateway-1.4.5/gw/smsc/smsc.c0000644000175000017500000004156513227613126014375 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc.c - implement interface to SMS centers as defined by smsc.h * * Lars Wirzenius and Kalle Marjola for WapIT Ltd. */ /* NOTE: private functions (only for smsc_* use) are named smscenter_*, * public functions (used by gateway) are named smsc_* */ #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smsc.h" #include "smsc_p.h" #include "msg.h" /* * Maximum number of characters for read_into_buffer to read at a time. */ #define MAX_READ_INTO_BUFFER (1024) static void smscenter_lock(SMSCenter *smsc); static void smscenter_unlock(SMSCenter *smsc); /*-------------------------------------------------------------------- * TODO: WAP WDP functions! */ /*-------------------------------------------------------------------- * smscenter functions */ SMSCenter *smscenter_construct(void) { SMSCenter *smsc; static int next_id = 1; smsc = gw_malloc(sizeof(SMSCenter)); smsc->killed = 0; smsc->type = SMSC_TYPE_DELETED; smsc->preferred_prefix = NULL; smsc->allowed_prefix = NULL; smsc->denied_prefix = NULL; smsc->alt_charset = 0; smsc->keepalive = 0; smsc->mutex = mutex_create(); sprintf(smsc->name, "Unknown SMSC"); smsc->id = next_id++; /* FAKE */ smsc->hostname = NULL; smsc->port = -1; smsc->socket = -1; /* CIMD */ smsc->cimd_hostname = NULL; smsc->cimd_port = -1; smsc->cimd_username = NULL; smsc->cimd_password = NULL; /* EMI_X25 */ smsc->emi_phonenum = NULL; smsc->emi_serialdevice = NULL; smsc->emi_username = NULL; smsc->emi_password = NULL; /* SEMA SMS2000 */ smsc->sema_smscnua = NULL; smsc->sema_homenua = NULL; smsc->sema_serialdevice = NULL; smsc->sema_fd = -1; /* SEMA SMS2000 OIS X.25 */ smsc->ois_alive = 0; smsc->ois_alive2 = 0; smsc->ois_received_mo = NULL; smsc->ois_ack_debt = 0; smsc->ois_flags = 0; smsc->ois_listening_socket = -1; smsc->ois_socket = -1; smsc->ois_buflen = 0; smsc->ois_bufsize = 0; smsc->ois_buffer = 0; /* add new SMSCes here */ /* Memory */ smsc->buflen = 0; smsc->bufsize = 10*1024; smsc->buffer = gw_malloc(smsc->bufsize); memset(smsc->buffer, 0, smsc->bufsize); return smsc; } void smscenter_destruct(SMSCenter *smsc) { if (smsc == NULL) return; /* FAKE */ gw_free(smsc->hostname); /* CIMD */ gw_free(smsc->cimd_hostname); gw_free(smsc->cimd_username); gw_free(smsc->cimd_password); /* EMI_X25 */ gw_free(smsc->emi_phonenum); gw_free(smsc->emi_serialdevice); gw_free(smsc->emi_username); gw_free(smsc->emi_password); /* SEMA */ gw_free(smsc->sema_smscnua); gw_free(smsc->sema_homenua); gw_free(smsc->sema_serialdevice); /* OIS */ ois_delete_queue(smsc); gw_free(smsc->ois_buffer); /* add new SMSCes here */ /* Other fields */ mutex_destroy(smsc->mutex); /* Memory */ gw_free(smsc->buffer); gw_free(smsc); } int smscenter_submit_msg(SMSCenter *smsc, Msg *msg) { smscenter_lock(smsc); switch (smsc->type) { case SMSC_TYPE_CIMD: if (cimd_submit_msg(smsc, msg) == -1) goto error; break; case SMSC_TYPE_EMI_X25: if (emi_submit_msg(smsc, msg) == -1) goto error; break; case SMSC_TYPE_SEMA_X28: if (sema_submit_msg(smsc, msg) == -1) goto error; break; case SMSC_TYPE_OIS: if (ois_submit_msg(smsc, msg) == -1) goto error; break; /* add new SMSCes here */ default: goto error; } smscenter_unlock(smsc); return 0; error: smscenter_unlock(smsc); return -1; } int smscenter_receive_msg(SMSCenter *smsc, Msg **msg) { int ret; smscenter_lock(smsc); switch (smsc->type) { case SMSC_TYPE_CIMD: ret = cimd_receive_msg(smsc, msg); if (ret == -1) goto error; break; case SMSC_TYPE_EMI_X25: ret = emi_receive_msg(smsc, msg); if (ret == -1) goto error; break; case SMSC_TYPE_OIS: ret = ois_receive_msg(smsc, msg); if (ret == -1) goto error; break; case SMSC_TYPE_SEMA_X28: ret = sema_receive_msg(smsc, msg); if (ret == -1) goto error; break; default: goto error; } smscenter_unlock(smsc); /* If the SMSC didn't set the timestamp, set it here. */ if (ret == 1 && msg_type(*msg) == sms && (*msg)->sms.time == 0) time(&(*msg)->sms.time); return ret; error: smscenter_unlock(smsc); return -1; } int smscenter_pending_smsmessage(SMSCenter *smsc) { int ret; smscenter_lock(smsc); switch (smsc->type) { case SMSC_TYPE_CIMD: ret = cimd_pending_smsmessage(smsc); if (ret == -1) goto error; break; case SMSC_TYPE_EMI_X25: ret = emi_pending_smsmessage(smsc); if (ret == -1) goto error; break; case SMSC_TYPE_SEMA_X28: ret = sema_pending_smsmessage(smsc); if (ret == -1) goto error; break; case SMSC_TYPE_OIS: ret = ois_pending_smsmessage(smsc); if (ret == -1) goto error; break; default: goto error; } smscenter_unlock(smsc); return ret; error: error(0, "smscenter_pending_smsmessage is failing"); smscenter_unlock(smsc); return -1; } int smscenter_read_into_buffer(SMSCenter *smsc) { char *p; int ret; fd_set read_fd; struct timeval tv, tvinit; size_t bytes_read; tvinit.tv_sec = 0; tvinit.tv_usec = 1000; bytes_read = 0; for (;;) { FD_ZERO(&read_fd); FD_SET(smsc->socket, &read_fd); tv = tvinit; ret = select(smsc->socket + 1, &read_fd, NULL, NULL, &tv); if (ret == -1) { if (errno == EINTR) goto got_data; if (errno == EAGAIN) goto got_data; error(errno, "Error doing select for socket"); goto error; } else if (ret == 0) goto got_data; if (smsc->buflen == smsc->bufsize) { p = gw_realloc(smsc->buffer, smsc->bufsize * 2); smsc->buffer = p; smsc->bufsize *= 2; } ret = read(smsc->socket, smsc->buffer + smsc->buflen, 1); if (ret == -1) { error(errno, "Reading from `%s' port `%d' failed.", smsc->hostname, smsc->port); goto error; } if (ret == 0) goto eof; smsc->buflen += ret; bytes_read += ret; if (bytes_read >= MAX_READ_INTO_BUFFER) break; } eof: ret = 0; goto unblock; got_data: ret = 1; goto unblock; error: ret = -1; goto unblock; unblock: return ret; } void smscenter_remove_from_buffer(SMSCenter *smsc, size_t n) { memmove(smsc->buffer, smsc->buffer + n, smsc->buflen - n); smsc->buflen -= n; } /* * Lock an SMSCenter. Return -1 for error, 0 for OK. */ static void smscenter_lock(SMSCenter *smsc) { if (smsc->type == SMSC_TYPE_DELETED) error(0, "smscenter_lock called on DELETED SMSC."); mutex_lock(smsc->mutex); } /* * Unlock an SMSCenter. Return -1 for error, 0 for OK. */ static void smscenter_unlock(SMSCenter *smsc) { mutex_unlock(smsc->mutex); } /*------------------------------------------------------------------------ * Public SMSC functions */ SMSCenter *smsc_open(CfgGroup *grp) { SMSCenter *smsc; Octstr *type, *host, *username, *password, *phone, *device; Octstr *preferred_prefix, *allowed_prefix, *denied_prefix; Octstr *alt_chars, *allow_ip; Octstr *sema_smscnua, *sema_homenua, *sema_report; Octstr *sender_prefix; long iwaitreport; long port, receive_port, our_port; long keepalive; long ois_debug; long alt_dcs; int typeno; type = cfg_get(grp, octstr_imm("smsc")); if (type == NULL) { error(0, "Required field 'smsc' missing for smsc group."); return NULL; } if (octstr_compare(type, octstr_imm("cimd")) == 0) typeno = SMSC_TYPE_CIMD; else if (octstr_compare(type, octstr_imm("emi_x25")) == 0) typeno = SMSC_TYPE_EMI_X25; else if (octstr_compare(type, octstr_imm("sema")) == 0) typeno = SMSC_TYPE_SEMA_X28; else if (octstr_compare(type, octstr_imm("ois")) == 0) typeno = SMSC_TYPE_OIS; else { error(0, "Unknown SMSC type '%s'", octstr_get_cstr(type)); octstr_destroy(type); return NULL; } host = cfg_get(grp, octstr_imm("host")); if (cfg_get_integer(&port, grp, octstr_imm("port")) == -1) port = 0; if (cfg_get_integer(&receive_port, grp, octstr_imm("receive-port")) == -1) receive_port = 0; if (cfg_get_integer(&our_port, grp, octstr_imm("our-port")) == -1) our_port = 0; username = cfg_get(grp, octstr_imm("smsc-username")); password = cfg_get(grp, octstr_imm("smsc-password")); phone = cfg_get(grp, octstr_imm("phone")); device = cfg_get(grp, octstr_imm("device")); preferred_prefix = cfg_get(grp, octstr_imm("preferred-prefix")); allowed_prefix = cfg_get(grp, octstr_imm("allowed-prefix")); denied_prefix = cfg_get(grp, octstr_imm("denied-prefix")); alt_chars = cfg_get(grp, octstr_imm("alt-charset")); allow_ip = cfg_get(grp, octstr_imm("connect-allow-ip")); sema_smscnua = cfg_get(grp, octstr_imm("smsc_nua")); sema_homenua = cfg_get(grp, octstr_imm("home_nua")); sema_report = cfg_get(grp, octstr_imm("wait_report")); if (sema_report == NULL) iwaitreport = 1; else octstr_parse_long(&iwaitreport, sema_report, 0, 0); if (cfg_get_integer(&keepalive, grp, octstr_imm("keepalive")) == -1) keepalive = 0; if (cfg_get_integer(&alt_dcs, grp, octstr_imm("alt-dcs")) == -1) alt_dcs = 0; if (alt_dcs > 1) alt_dcs = 1; if (cfg_get_integer(&ois_debug, grp, octstr_imm("ois-debug-level")) == -1) ois_debug = 0; sender_prefix = cfg_get(grp, octstr_imm("sender-prefix")); if (sender_prefix == NULL) sender_prefix = octstr_create("never"); smsc = NULL; switch (typeno) { case SMSC_TYPE_CIMD: if (host == NULL || port == 0 || username == NULL || password == NULL) error(0, "Required field missing for CIMD center."); else smsc = cimd_open(octstr_get_cstr(host), port, octstr_get_cstr(username), octstr_get_cstr(password)); break; case SMSC_TYPE_EMI_X25: if (phone == NULL || device == NULL || username == NULL || password == NULL) error(0, "Required field missing for EMI_X25 center."); else smsc = emi_open(octstr_get_cstr(phone), octstr_get_cstr(device), octstr_get_cstr(username), octstr_get_cstr(password)); break; case SMSC_TYPE_SEMA_X28: if (device == NULL || sema_smscnua == NULL || sema_homenua == NULL) error(0, "Required field missing for SEMA center."); else smsc = sema_open(octstr_get_cstr(sema_smscnua), octstr_get_cstr(sema_homenua), octstr_get_cstr(device), iwaitreport); break; case SMSC_TYPE_OIS: if (host == NULL || port == 0 || receive_port == 0) error(0, "Required field missing for OIS center."); else smsc = ois_open(receive_port, octstr_get_cstr(host), port, ois_debug); break; /* add new SMSCes here */ default: /* Unknown SMSC type */ break; } if (smsc != NULL) { if (cfg_get_integer(&smsc->alt_charset, grp, octstr_imm("alt-charset")) == -1) smsc->alt_charset = 0; if (preferred_prefix == NULL) smsc->preferred_prefix = NULL; else smsc->preferred_prefix = gw_strdup(octstr_get_cstr(preferred_prefix)); if (allowed_prefix == NULL) smsc->allowed_prefix = NULL; else smsc->allowed_prefix = gw_strdup(octstr_get_cstr(allowed_prefix)); if (denied_prefix == NULL) smsc->denied_prefix = NULL; else smsc->denied_prefix = gw_strdup(octstr_get_cstr(denied_prefix)); } octstr_destroy(type); octstr_destroy(host); octstr_destroy(username); octstr_destroy(password); octstr_destroy(phone); octstr_destroy(device); octstr_destroy(preferred_prefix); octstr_destroy(denied_prefix); octstr_destroy(allowed_prefix); octstr_destroy(alt_chars); octstr_destroy(allow_ip); octstr_destroy(sema_smscnua); octstr_destroy(sema_homenua); octstr_destroy(sema_report); octstr_destroy(sender_prefix); return smsc; } int smsc_reopen(SMSCenter *smsc) { int ret; if (smsc->killed) return -2; smscenter_lock(smsc); switch (smsc->type) { case SMSC_TYPE_CIMD: ret = cimd_reopen(smsc); break; case SMSC_TYPE_EMI_X25: ret = emi_reopen(smsc); break; case SMSC_TYPE_SEMA_X28: ret = sema_reopen(smsc); break; case SMSC_TYPE_OIS: ret = ois_reopen(smsc); break; /* add new SMSCes here */ default: /* Unknown SMSC type */ ret = -2; /* no use */ } smscenter_unlock(smsc); return ret; } char *smsc_name(SMSCenter *smsc) { return smsc->name; } int smsc_close(SMSCenter *smsc) { int errors = 0; if (smsc == NULL) return 0; smscenter_lock(smsc); switch (smsc->type) { case SMSC_TYPE_CIMD: if (cimd_close(smsc) == -1) errors = 1; break; case SMSC_TYPE_EMI_X25: if (emi_close(smsc) == -1) errors = 1; break; case SMSC_TYPE_SEMA_X28: if (sema_close(smsc) == -1) errors = 1; break; case SMSC_TYPE_OIS: if (ois_close(smsc) == -1) errors = 1; break; /* add new SMSCes here */ default: /* Unknown SMSC type */ break; } /* smsc->type = SMSC_TYPE_DELETED; smscenter_unlock(smsc); */ if (errors) return -1; return 0; } gateway-1.4.5/gw/smsc/smsc_soap.c0000644000175000017500000030404313227613126015410 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_soap.c - Implementation of SOAP (XML over HTTP) as a Kannel module * * Oded Arbel, m-Wise inc (oded@m-wise.com) * Dima Milentiev, m-Wise inc (dima@m-wise.com) * * ChangeLog: * * 20/02/2002: started - copied smsc_mam.c for starting * 25/02/2002: implemented MT sending * 09/05/2002: fixed problem crash when HTTP connection fails. * send message back to bearerbox on HTTP failure instead of local queue * 19/05/2002: stripped leading + from international numbers * 20/05/2002: fixed previous change * changed Transaction Id returned to support 64 bit integers * 27/05/2002: changed DLR creation to store the transaction ID instead of timestamp * added parsing of human readable time in DLR * 28/05/2002: added multi thread sending support * 02/06/2002: changed validity computing to accept minutes instead of seconds * 04/06/2002: Changed callbacks to take into account that they might be called while the connection * is dead. * 04/06/2002: Started to implement generic parsing engine. * 09/06/2002: Removed hardcoded XML generation and parsing * 22/07/2002: Removed wrong assignment of charset_convert return code to msg->sms.coding * 30/07/2002: fixed wrong format for year in soap_write_date * additional debug and process for invalid charset conversion * 04/08/2002: forced chraset_conversion to/from UCS-2 to use big endianity * added curly bracing support to XML data tokens * 04/09/2002: Added some debugging info * 05/09/2002: Changed dlr_add and http_start_request calls to support current CVS * 26/09/2002: Added soap_fetch_xml_data * 29/09/2002: Changed Ack/Nack to process case when Ack not return msg ID, move declaration to fix worning * 01/10/2002: started to change MO general * 07/10/2002: MT generalization * * TODOs: * - add a configuration option to the max number of messages a client can send, and use * and implement KeepAlive in the clients. * - support XML generation through DTD * - support XML parsing through DTD * * * Usage: add the following to kannel.conf: * * group = smsc * smsc = soap * send-url = - URI to send SOAP bubbles at (mandatory) * receive-port = - port number to bind our server on (Default: disabled - MT only) * xml-files = "MT.xml;MO.xml;DLR.xml" - XML templates for generation of MT messages * and MO and DLR responses * xmlspec-files = "MT.spec;MO.spec;DLR.spec" - XML path spec files for parsing of MT Â¥ * response and MO and DLR submission * alt-charset = "character map" - charset in which a text message is received (default UTF-8) * */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "gwlib/http.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "msg.h" #include "sms.h" #include "dlr.h" /* libxml include */ #include #include /* Defines and defaults */ #define SOAP_SLEEP_TIME 0.01 #define SOAP_MAX_MESSAGE_PER_ROUND 1 #define SOAP_DEFAULT_SENDER_STRING "Kannel" #define SOAP_DEFAULT_VALIDITY 60 /* URIs for MOs and delivery reports */ #define SOAP_MO_URI "/mo" #define SOAP_DLR_URI "/dlr" /* default responses to HTTP queries */ #define SOAP_DEFAULT_MESSAGE "\r\nNo method by that name" #define SOAP_ERROR_NO_DLR_MESSAGE "\r\nSorry - no DLR for that MT" #define SOAP_ERROR_DLR_MESSAGE "\r\nFatal error while trying to parse delivery report" #define SOAP_ERROR_MO_MESSAGE "\r\nFatal error while trying to parse incoming MO" #define SOAP_ERROR_NO_DATA_MESSAGE "\r\nNo data received" #define SOAP_ERROR_MALFORMED_DATA_MESSAGE "\r\nMalformed data received" /* map HTTP status codes to SOAP HTTP reply codes */ #define SOAP_ERROR_NO_DLR_CODE HTTP_BAD_METHOD #define SOAP_DEFAULT_CODE HTTP_NOT_FOUND #define SOAP_ERROR_DLR_CODE HTTP_INTERNAL_SERVER_ERROR #define SOAP_ERROR_MO_CODE HTTP_INTERNAL_SERVER_ERROR #define SOAP_ERROR_NO_DATA_CODE HTTP_NOT_IMPLEMENTED #define SOAP_ERROR_MALFORMED_DATA_CODE HTTP_BAD_GATEWAY #define SOAP_QUERY_OK HTTP_OK /* compile time configuration defines */ #undef HUMAN_TIME #define MIN_SOAP_CLIENTS 5 #define MAX_SOAP_CLIENTS 50 #define CLIENT_BUSY_TIME 5 #define CLIENT_TEARDOWN_TIME 600 #define CLIENT_BUSY_LOAD 5 #define SPEC_DEFAULT "default" /* private data store for the SOAP module */ typedef struct privdata { List *outgoing_queue; /* queue to hold unsent messages */ long listener_thread; /* SOAP HTTP client and module managment */ long server_thread; /* SOAP HTTP server */ int shutdown; /* Internal signal to shut down */ int soap_server; /* internal signal to shut down the server */ long port; /* listener port */ int ssl; /* flag whether to use SSL for the server */ Octstr *uri; /* URI to send MTs on */ Octstr *allow_ip, *deny_ip; /* connection allowed mask */ List* soap_client; /* list to hold callers */ Octstr* name; /* connection name for use in private functions that want to do logging */ /* SOAP configurtion */ Octstr* form_variable; /* variable name used in post */ int form_urlencoded; /* whether to send the data urlencoded or multipart */ Octstr* alt_charset; /* alt-charset to use */ Octstr* mt_xml_file; Octstr* mt_spec_file; Octstr* mo_xml_file; Octstr* mo_spec_file; Octstr* dlr_xml_file; Octstr* dlr_spec_file; Octstr* mo_deps_file; } PrivData; /* struct to hold one HTTP client connection (I hope) */ typedef struct client_data { time_t last_access; unsigned long requests; HTTPCaller* caller; } ClientData; /* struct useful for the XML mapping routines */ typedef struct argument_map { Octstr* name; Octstr* path; Octstr* attribute; Octstr* sscan_type; void* store; } ArgumentMap; /* useful macros go here (some of these were ripped of other modules, so maybe its better to put them in a shared file) */ #define O_DESTROY(a) { if(a) octstr_destroy(a); a=NULL; } /* * SOAP module public API towards bearerbox */ /* module entry point - will also be defined in smscconn_p.h */ int smsc_soap_create(SMSCConn *conn, CfgGroup *cfg); /* callback for bearerbox to add messages to our queue */ static int soap_add_msg_cb(SMSCConn *conn, Msg *sms); /* callback for bearerbox to signal a shutdown */ static int soap_shutdown_cb(SMSCConn *conn, int finish_sending); /* callback for bearerbox to signal us to start the connection */ static void soap_start_cb(SMSCConn *conn); /* callback for bearerbox to signal us to drop the connection */ static void soap_stop_cb(SMSCConn *conn); /* callback for bearerbox to query on the number of messages in our queue */ static long soap_queued_cb(SMSCConn *conn); /* * SOAP module thread functions (created by smsc_soap_create()) */ /* SOAP module thread for launching HTTP clients. */ static void soap_listener(void *arg); /* SOAP HTTP server thread for incoming MO */ static void soap_server(void *arg); /* * SOAP module internal protocol implementation functions */ /* start the loop to send all messages in the queue */ static void soap_send_loop(SMSCConn *conn); /* function used to send a single MT message */ static void soap_send(PrivData *privdata, Octstr *xmlbuffer, Msg *msgid); /* called to retrieve HTTP responses from the HTTP library */ static void soap_read_response(SMSCConn *conn); /* format a messages structure as an XML buffer */ static Octstr *soap_format_xml(Octstr *xml_file, Msg *msg, PrivData *privdata); /* parse a response from the SOAP server to get the message ID */ static long long soap_parse_response(PrivData *privdata, Octstr *xmlResponse); /* parse an incoming MO xml */ static long soap_parse_mo(SMSCConn *conn, Octstr *request, Octstr **response); /* parse an incoming derlivery report */ static long soap_parse_dlr(SMSCConn *conn, Octstr *request, Octstr **response); /* * SOAP internal utility functions */ /* parse an integer out of a XML node */ int soap_xmlnode_get_long(xmlNodePtr cur, long *out); /* parse an int64 out of a XML node */ int soap_xmlnode_get_int64(xmlNodePtr cur, long long *out); /* parse a string out of a XML node */ int soap_xmlnode_get_octstr(xmlNodePtr cur, Octstr **out); /* convert a one2one date format to epoch time */ time_t soap_read_date(Octstr *dateString); /* convert a epoch time to one2one date format */ static Octstr *soap_write_date(time_t date); /* start the SOAP server */ int soap_server_start(SMSCConn *conn); /* stop the SOAP server */ static void soap_server_stop(PrivData *privdata); /* create a new SOAP client caller */ static ClientData *soap_create_client_data(); /* destroy a SOAP client caller */ static void soap_destroy_client_data(void *data); /* start an HTTP query */ static void soap_client_init_query(PrivData *privdata, List *headers, Octstr *data, Msg *msg); /* return a caller from the pool that has responses waiting */ static ClientData *soap_client_have_response(List *client_list); /* return data from a message according to its name */ static Octstr *soap_convert_token(Msg *msg, Octstr *name, PrivData *privdata); /* convert a XML parsing spec file and a list of recognized keywords to an argument map */ List *soap_create_map(Octstr* spec, long count, char* keywords[], char* types[], void* storage[]); /* destroy a map structure */ void soap_destroy_map(void *item); /* map content in a XML structure to a list of variable using a spec file */ int soap_map_xml_data(xmlNodePtr xml, List* maps); /* fetch content from the XML */ Octstr* soap_fetch_xml_data(xmlNodePtr xml, Octstr* path); /* MO */ /* search and release dependences for keys */ long soap_release_dependences(Octstr* deps, List* lstmaps, Msg* msg, PrivData *privdata); /* for appropriate call function referenced by key_func_ind */ int soap_process_deps(int key_index, int key_func_ind, Msg* msg, PrivData *privdata); /* s specific functions */ int soap_msgtype_deps(int key_func_index, Msg* msg); int soap_msgdata_deps(int key_func_index, Msg* msg, PrivData *privdata); /* MT */ /* return index of functions alias in array of function aliases */ int soap_lookup_function(Octstr* funcname); /* select function by index */ Octstr* soap_select_function(int index, Msg* msg, PrivData* privdata); Octstr* soap_bouyg_content_attribute(Msg* msg); Octstr* soap_mobitai_content_attribute(Msg* msg); Octstr* soap_o2o_msgdata_attribute(Msg* msg, PrivData *privdata); Octstr* soap_msgdata_attribute(Msg* msg, PrivData* privdata); Octstr* soap_o2o_validity30_attribute(Msg* msg); Octstr* soap_mobitai_validity_date_attribute(Msg* msg); Octstr* soap_bouyg_validity_attribute(Msg* msg); Octstr* soap_o2o_date_attribute(Msg* msg); Octstr* soap_mobitai_date_attribute(Msg* msg); Octstr* soap_rand_attribute(Msg* msg); Octstr* soap_o2o_dlrmask_smsc_yn_attribute(Msg* msg); Octstr* soap_o2o_dlrmask_success_01_attribute(Msg* msg); /* searching 'key' in 'where' and return index of element or -1 */ int soap_get_index(List* where, Octstr* key, int map_index); /************************************************************************************** * Implementation */ /* * function smsc_soap_create() * called to create and initalize the module's internal data. * if needed also will start the connection threads * Input: SMSCConn pointer to connection data, cfgGroup pointer to configuration data * Returns: status (0 = OK, -1 = failed) */ int smsc_soap_create(SMSCConn *conn, CfgGroup *cfg) { PrivData *privdata; Octstr* temp = NULL; List* filenames = NULL; /* allocate and init internat data structure */ privdata = gw_malloc(sizeof(PrivData)); privdata->outgoing_queue = gwlist_create(); /* privdata->pending_ack_queue = gwlist_create(); */ privdata->shutdown = 0; privdata->soap_client = NULL; privdata->soap_server = 0; /* read configuration data */ if (cfg_get_integer(&(privdata->port), cfg, octstr_imm("receive-port-ssl")) == -1) if (cfg_get_integer(&(privdata->port), cfg, octstr_imm("receive-port")) == -1) privdata->port = 0; else privdata->ssl = 0; else privdata->ssl = 1; privdata->uri = cfg_get(cfg, octstr_imm("send-url")); privdata->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip")); if (privdata->allow_ip) privdata->deny_ip = octstr_create("*.*.*.*"); else privdata->deny_ip = NULL; /* read XML configuration */ privdata->form_variable = cfg_get(cfg, octstr_imm("form-variable")); cfg_get_bool(&(privdata->form_urlencoded), cfg, octstr_imm("form-urlencoded")); privdata->alt_charset = cfg_get(cfg, octstr_imm("alt-charset")); if (!privdata->alt_charset) privdata->alt_charset = octstr_create("utf-8"); /* check validity of stuff */ if (privdata->port <= 0 || privdata->port > 65535) { error(0, "invalid port definition for SOAP server (%ld) - aborting", privdata->port); goto error; } if (!privdata->uri) { error(0, "invalid or missing send-url definition for SOAP - aborting."); goto error; } if (!privdata->form_variable) { error(0, "invalid or missing form variable name definition for SOAP - aborting."); goto error; } /* load XML templates and specs */ filenames = octstr_split(temp = cfg_get(cfg,octstr_imm("xml-files")), octstr_imm(";")); octstr_destroy(temp); if (gwlist_len(filenames) < 3) { error(0,"SOAP: Not enough template files for XML generation, you need 3 - aborting"); goto error; } if ( !(privdata->mt_xml_file = octstr_read_file( octstr_get_cstr(temp = gwlist_extract_first(filenames))))) { error(0,"SOAP: Can't load XML template for MT - aborting"); goto error; } octstr_destroy(temp); if ( !(privdata->mo_xml_file = octstr_read_file( octstr_get_cstr(temp = gwlist_extract_first(filenames))))) { error(0,"SOAP: Can't load XML template for MO - aborting"); goto error; } octstr_destroy(temp); if ( !(privdata->dlr_xml_file = octstr_read_file( octstr_get_cstr(temp = gwlist_extract_first(filenames))))) { error(0,"SOAP: Can't load XML template for DLR - aborting"); goto error; } octstr_destroy(temp); gwlist_destroy(filenames, octstr_destroy_item); filenames = octstr_split(temp = cfg_get(cfg,octstr_imm("xmlspec-files")), octstr_imm(";")); octstr_destroy(temp); if (gwlist_len(filenames) < 4) { error(0,"Not enough spec files for XML parsing, you need 4 - aborting"); goto error; } if ( !(privdata->mt_spec_file = octstr_read_file( octstr_get_cstr(temp = gwlist_extract_first(filenames))))) { error(0,"Can't load spec for MT parsing - aborting"); goto error; } octstr_destroy(temp); if ( !(privdata->mo_spec_file = octstr_read_file( octstr_get_cstr(temp = gwlist_extract_first(filenames))))) { error(0,"SOAP: Can't load spec for MO parsing - aborting"); goto error; } octstr_destroy(temp); if ( !(privdata->dlr_spec_file = octstr_read_file( octstr_get_cstr(temp = gwlist_extract_first(filenames))))) { error(0,"SOAP: Can't load spec for DLR parsing - aborting"); goto error; } octstr_destroy(temp); if ( !(privdata->mo_deps_file = octstr_read_file( octstr_get_cstr(temp = gwlist_extract_first(filenames))))) { error(0,"SOAP: Can't load 'deps' file for MO processing - aborting"); goto error; } octstr_destroy(temp); gwlist_destroy(filenames, octstr_destroy_item); debug("bb.soap.create",0,"Connecting to %s", octstr_get_cstr(privdata->uri)); /* store private data struct in connection data */ conn->data = privdata; /* state my name */ conn->name = octstr_format("SOAP: %s", octstr_get_cstr(privdata->uri) ); privdata->name = octstr_duplicate(conn->id); /* init status vars */ conn->status = SMSCCONN_CONNECTING; conn->connect_time = time(NULL); /* set up call backs for bearerbox */ conn->shutdown = soap_shutdown_cb; conn->queued = soap_queued_cb; conn->start_conn = soap_start_cb; conn->stop_conn = soap_stop_cb; conn->send_msg = soap_add_msg_cb; privdata->listener_thread = 0; privdata->server_thread = 0; /* check whether we can start right away */ if (!conn->is_stopped) /* yes, we can */ conn->status = SMSCCONN_CONNECTING; else conn->status = SMSCCONN_DISCONNECTED; /* any which way - start the connection thread */ if ((privdata->listener_thread = gwthread_create(soap_listener, conn)) == -1) { error(0, "SOAP: soap_create, failed to spawn thread - aborting"); goto error; } return 0; /* done - ok */ error: /* oh oh, problems */ error(0, "SOAP: Failed to create SOAP smsc connection"); /* release stuff */ if (privdata != NULL) { gwlist_destroy(privdata->outgoing_queue, NULL); /* gwlist_destroy(privdata->pending_ack_queue, NULL); */ O_DESTROY(privdata->uri); O_DESTROY(privdata->allow_ip); O_DESTROY(privdata->deny_ip); O_DESTROY(privdata->form_variable); O_DESTROY(privdata->alt_charset); O_DESTROY(privdata->name); O_DESTROY(privdata->mo_xml_file); O_DESTROY(privdata->dlr_xml_file); O_DESTROY(privdata->mt_xml_file); O_DESTROY(privdata->mo_spec_file); O_DESTROY(privdata->dlr_spec_file); O_DESTROY(privdata->mt_spec_file); O_DESTROY(privdata->mo_deps_file); } gw_free(privdata); octstr_destroy(temp); gwlist_destroy(filenames, octstr_destroy_item); /* notify bearerbox */ conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; info(0, "exiting"); return -1; /* I'm dead */ } /************************************************************************************** * Callbacks */ /* * function soap_add_msg_cb() * get a message and copy it to the queue. note that message must be copied * as I don't know what bearerbox wants to do with it after I return * Input: SMSCConn connection state data, Msg to send * Returns: status - 0 on success, -1 on fail. */ static int soap_add_msg_cb(SMSCConn *conn, Msg *sms) { PrivData *privdata = conn->data; Msg *copy; /* I'm dead and cannot take any calls at the moment, please don't leave a message */ if (conn->status == SMSCCONN_DEAD) return -1; copy = msg_duplicate(sms); /* copy the message */ gwlist_append(privdata->outgoing_queue, copy); /* put it in the queue */ debug("bb.soap.add_msg",0,"SOAP[%s]: got a new MT from %s, list has now %ld MTs", octstr_get_cstr(privdata->name), octstr_get_cstr(sms->sms.sender), gwlist_len(privdata->outgoing_queue)); gwthread_wakeup(privdata->listener_thread); return 0; } /* * function soap_shutdown_cb() * called by bearerbox to signal the module to shutdown. sets the shutdown flags, * wakes up the listener thread and exits (if we add more threads, we need to handle those too) * Input: SMSCConn connection state data, flag indicating whether we can finish sending messages * in the queue first. * Returns: status - 0 on success, -1 on fail. */ static int soap_shutdown_cb(SMSCConn *conn, int finish_sending) { PrivData *privdata = conn->data; long thread; /* I'm dead, there's really no point in killing me again, is it ? */ if (conn->status == SMSCCONN_DEAD) return -1; debug("bb.soap.cb", 0, "SOAP[%s]: Shutting down SMSCConn, %s", octstr_get_cstr(privdata->name), finish_sending ? "slow" : "instant"); /* Documentation claims this would have been done by smscconn.c, * but isn't when this code is being written.*/ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; /* Separate from why_killed to avoid locking, * as why_killed may be changed from outside? */ privdata->shutdown = 1; if (finish_sending == 0) { Msg *msg; while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } thread = privdata->listener_thread; gwthread_wakeup(thread); gwthread_join(thread); return 0; } /* * function soap_start_cb() * called by bearerbox when the module is allowed to start working * Input: SMSCConn connection state data * Returns: status - 0 on success, -1 on fail. */ static void soap_start_cb(SMSCConn *conn) { PrivData *privdata = conn->data; debug("smsc.soap.start", 0, "SOAP[%s]: start called", octstr_get_cstr(privdata->name)); /* set the status so that connection_thread will know what to do */ conn->status = SMSCCONN_CONNECTING; /* start connection_thread, in case its not started. */ if ((!privdata->listener_thread) && ((privdata->listener_thread = gwthread_create(soap_listener, conn)) == -1)) { error(0, "SOAP: soap_start, failed to spawn thread - aborting"); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; privdata->shutdown = 1; return; } /* gwthread_wakeup(privdata->listener_thread); */ debug("smsc.soap.start",0,"SOAP[%s]: starting OK", octstr_get_cstr(privdata->name)); } /* * function soap_stop_cb() * this function may be used to 'pause' the module. it should cause the connection * to logout, but not to be destroyed, so it will be restarted later. * Input: SMSCConn connection state data */ static void soap_stop_cb(SMSCConn *conn) { PrivData *privdata = conn->data; /* I'm dead, its really too late to take a break now */ if (conn->status == SMSCCONN_DEAD) return; debug("smsc.soap.stop", 0, "SOAP[%s]: stop called", octstr_get_cstr(privdata->name)); /* make connection thread disconnect */ conn->status = SMSCCONN_DISCONNECTED; } /* * function soap_queued_cb() * called by bearerbox to query the number of messages pending send. * the number returned includes the number of messages sent, but for which no ACK was yet received. * Input: SMSCConn connection state data * Returns: number of messages still waiting to be sent */ static long soap_queued_cb(SMSCConn *conn) { PrivData *privdata = conn->data; long ret; /* I'm dead, so I have no queues - well there ! */ if (conn->status == SMSCCONN_DEAD) return -1; ret = gwlist_len(privdata->outgoing_queue); /* + gwlist_len(privdata->pending_ack_queue); */ /* use internal queue as load, maybe something else later */ conn->load = ret; return ret; } /************************************************************************************** * SOAP module thread functions (created by smsc_soap_create()) */ /* * function soap_listener() * entry point to the listenr thread. this thread listenes on the MO port (if * needed, and is also reposnsible for invoking "MT threads" (HTTP clients) to * to send MTs. * Input: SMSCConn connection state data */ static void soap_listener(void *arg) { SMSCConn *conn = arg; PrivData *privdata = conn->data; Msg *msg = NULL; debug("bb.soap.listener",0,"SOAP[%s]: listener entering", octstr_get_cstr(privdata->name)); while (!privdata->shutdown) { /* check connection status */ switch (conn->status) { case SMSCCONN_RECONNECTING: case SMSCCONN_CONNECTING: if (privdata->soap_server) { soap_server_stop(privdata); } if (soap_server_start(conn)) { privdata->shutdown = 1; error(0, "SOAP[%s]: failed to start HTTP server!", octstr_get_cstr(privdata->name)); break; } mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); break; case SMSCCONN_DISCONNECTED: if (privdata->soap_server) soap_server_stop(privdata); break; case SMSCCONN_ACTIVE: if (!privdata->soap_server) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); break; } /* run the normal send/receive loop */ if (gwlist_len(privdata->outgoing_queue) > 0) { /* we have messages to send */ soap_send_loop(conn); /* send any messages in queue */ } break; case SMSCCONN_DEAD: /* this shouldn't happen here - * I'm the only one allowed to set SMSCCONN_DEAD */ default: break; } soap_read_response(conn); /* collect HTTP responses */ /* sleep for a while so I wont busy-loop */ gwthread_sleep(SOAP_SLEEP_TIME); } debug("bb.soap.connection",0,"SOAP[%s]: connection shutting down", octstr_get_cstr(privdata->name)); soap_server_stop(privdata); /* send all queued messages to bearerbox for recycling */ debug("bb.soap.connection",0,"SOAP[%s]: sending messages back to bearerbox", octstr_get_cstr(privdata->name)); while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); /* lock module public state data */ mutex_lock(conn->flow_mutex); debug("bb.soap.connection",0,"SOAP[%s]: playing dead", octstr_get_cstr(privdata->name)); conn->status = SMSCCONN_DEAD; /* set state */ /* destroy lists */ debug("bb.soap.connection",0,"SOAP[%s]: don't need the queue anymore", octstr_get_cstr(privdata->name)); gwlist_destroy(privdata->outgoing_queue, NULL); /* gwlist_destroy(privdata->pending_ack_queue, NULL); */ /* clear the soap client collection */ debug("bb.soap.connection",0,"SOAP[%s]: tell caller to stop", octstr_get_cstr(privdata->name)); if (privdata->soap_client) gwlist_destroy(privdata->soap_client, soap_destroy_client_data); /* destroy private data stores */ debug("bb.soap.connection",0,"SOAP[%s]: done with privdata", octstr_get_cstr(privdata->name)); O_DESTROY(privdata->uri); O_DESTROY(privdata->allow_ip); O_DESTROY(privdata->deny_ip); O_DESTROY(privdata->form_variable); O_DESTROY(privdata->alt_charset); O_DESTROY(privdata->name); O_DESTROY(privdata->mo_xml_file); O_DESTROY(privdata->dlr_xml_file); O_DESTROY(privdata->mt_xml_file); O_DESTROY(privdata->mo_spec_file); O_DESTROY(privdata->dlr_spec_file); O_DESTROY(privdata->mt_spec_file); O_DESTROY(privdata->mo_deps_file); gw_free(privdata); conn->data = NULL; mutex_unlock(conn->flow_mutex); debug("bb.soap.connection", 0, "SOAP: module has completed shutdown."); bb_smscconn_killed(); } /* * function soap_server() * server thread - accepts incoming MOs * Input: SMSCConn connection state data */ static void soap_server(void* arg) { SMSCConn* conn = (SMSCConn*)arg; PrivData* privdata = conn->data; /* PrivData* privdata = (PrivData*)arg; */ HTTPClient* remote_client = NULL; List *request_headers = NULL, *response_headers = NULL; List *cgivars = NULL; Octstr *client_ip = NULL, *request_uri = NULL, *request_body = NULL; Octstr *response_body = NULL; Octstr *timebuf = NULL; int http_response_status; debug("bb.soap.server",0,"SOAP[%s]: Server starting", octstr_get_cstr(privdata->name)); /* create basic headers */ response_headers = http_create_empty_headers(); http_header_add(response_headers, "Content-type","text/xml"); /* http_header_add(response_headers, "Content-type","application/x-www-form-urlencoded"); */ /* http_header_add(response_headers,"Connection", "Close"); */ http_header_add(response_headers, "Server","Kannel"); while (privdata->soap_server) { if ((remote_client = http_accept_request(privdata->port, &client_ip, &request_uri, &request_headers, &request_body, &cgivars))) { debug("bb.soap.server",0,"SOAP[%s]: server got a request for " "%s from %s, with body <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(request_uri),octstr_get_cstr(client_ip), request_body ? octstr_get_cstr(request_body) : ""); /* parse request */ if (!octstr_compare(request_uri,octstr_imm(SOAP_MO_URI))) { /* this is an incoming MO */ if ((http_response_status = soap_parse_mo(conn,request_body, &response_body)) == -1) { /* fatal error parsing MO */ error(0,"SOAP[%s]: fatal error parsing MO", octstr_get_cstr(privdata->name)); response_body = octstr_create(SOAP_ERROR_MO_MESSAGE); http_response_status = SOAP_ERROR_MO_CODE; } } else if (!octstr_compare(request_uri,octstr_imm(SOAP_DLR_URI))) { /* a delivery report */ if ((http_response_status = soap_parse_dlr(conn,request_body, &response_body)) == -1) { /* fatal error parsing MO */ error(0,"SOAP[%s]: fatal error parsing DLR", octstr_get_cstr(privdata->name)); response_body = octstr_create(SOAP_ERROR_DLR_MESSAGE); http_response_status = SOAP_ERROR_DLR_CODE; } } else { /* unknown command send default message */ response_body = octstr_create(SOAP_DEFAULT_MESSAGE); http_response_status = SOAP_DEFAULT_CODE; } /* create response */ /* response_body = octstr_create("\n" "\n" "\n" " 447951718145\n" " 22/01/2002:15:12\n" " 00\n" "\n"); */ /* encode date in headers */ timebuf = date_format_http(time(NULL)); /* http_header_add(response_headers, "Date", octstr_get_cstr(timebuf)); */ O_DESTROY(timebuf); /* http_header_dump(response_headers); */ /* send response back to client */ http_send_reply(remote_client,http_response_status,response_headers, response_body); /* destroy response data */ /* http_destroy_headers(response_headers); */ O_DESTROY(response_body); /* destroy request data */ O_DESTROY(request_uri); O_DESTROY(request_body); O_DESTROY(client_ip); http_destroy_headers(request_headers); gwlist_destroy(cgivars, NULL); } gwthread_sleep(SOAP_SLEEP_TIME); } debug("bb.soap.server",0,"SOAP[%s]: server going down", octstr_get_cstr(privdata->name)); /* privdata->server_thread = 0; */ } /************************************************************************************** * SOAP module internal protocol implementation functions */ /* * function soap_send_loop() * called when there are messages in the queue waiting to be sent * Input: SMSCConn connection state data */ static void soap_send_loop(SMSCConn* conn) { PrivData* privdata = conn->data; Msg *msg; Octstr* xmldata = NULL; int counter = 0; debug("bb.soap.client",0,"SOAP[%s]: client - entering", octstr_get_cstr(privdata->name)); while ((counter < SOAP_MAX_MESSAGE_PER_ROUND) && (msg = gwlist_extract_first(privdata->outgoing_queue))) { /* as long as we have some messages */ ++counter; if (uuid_is_null(msg->sms.id)) /* generate a message id */ uuid_generate(msg->sms.id); /* format the messages as a character buffer to send */ if (!(xmldata = soap_format_xml(privdata->mt_xml_file, msg, privdata))) { debug("bb.soap.client",0,"SOAP[%s]: client - failed to format message for sending", octstr_get_cstr(privdata->name)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED")); continue; } debug("bb.soap.client",0,"SOAP[%s]: client - Sending message <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(msg->sms.msgdata)); if (xmldata) debug("bb.soap.client",0,"SOAP[%s]: data dump: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(xmldata)); /* send to the server */ soap_send(privdata, xmldata, msg); /* store in the second queue so that soap_read_response will know what to do */ /* gwlist_append(privdata->pending_ack_queue,msg); */ /* don't need this anymore */ O_DESTROY(xmldata); } } /* * function soap_format_xml() * fill in the fields in a XML template with data from a message * Input: Octstr containing an XML template, Msg structure * Returns: Octstr xml formated data or NULL on error */ static Octstr *soap_format_xml(Octstr *xml_file, Msg *msg, PrivData *privdata) { Octstr *xml; long t; long start = -1; int curly_enclose = 0; xml = octstr_create(""); for (t = 0; t < octstr_len(xml_file); ++t) { unsigned char c; if ((c = octstr_get_char(xml_file,t)) == '%') { /* found start of token */ start = t+1; continue; } if (c == '{' && start == t) { /* the token is enclosed in curlys */ ++start; /* make sure the token is read from the next char */ curly_enclose=1; } if (start < 0) octstr_append_char(xml,c); else if ( (curly_enclose && (c == '}')) /* end of token in case of curly enclosure */ || (!curly_enclose && !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))) { /* found end of token */ Octstr *data, *token; token = octstr_copy(xml_file,start,(t-start)); if ((data = soap_convert_token(msg, token, privdata))) { octstr_append(xml, data); octstr_destroy(data); } else { error(0,"SOAP: format_xml - failed to format token %s using message", octstr_get_cstr(token)); octstr_destroy(token); octstr_destroy(xml); return NULL; } octstr_destroy(token); start = -1; if (!curly_enclose) /* I want to get that char again, to let the normal behaviour * deal with it - only if it's not the ending curly */ --t; else curly_enclose = 0; } } return xml; } /* * function soap_send() * send an XML buffer using POST to the SOAP server. * Input: PrivData connection state, Octstr XML formatted data buffer, * Message pointer to store with request */ static void soap_send(PrivData* privdata, Octstr* xmlbuffer, Msg* msg) { List *requestHeaders; Octstr* postdata; /* create request headers */ requestHeaders = http_create_empty_headers(); http_header_add(requestHeaders, "User-Agent", "Kannel " GW_VERSION); if (privdata->form_urlencoded) { http_header_add(requestHeaders, "Content-Type", "application/x-www-form-urlencoded"); postdata = octstr_format("%S=%E", privdata->form_variable, xmlbuffer); } else { http_header_add(requestHeaders, "Content-Type", "multipart/form-data, boundary=AaB03x"); postdata = octstr_format("--AaB03x\r\n" "content-disposition: form-data; name=\"%S\"\r\n\r\n%S", privdata->form_variable, xmlbuffer); } /* send the request along */ soap_client_init_query(privdata, requestHeaders, postdata, msg); O_DESTROY(postdata); /* done with that */ http_destroy_headers(requestHeaders); return; } /* * function soap_read_response() * check my HTTP caller for responses and act on them * Input: PrivData connection state **/ static void soap_read_response(SMSCConn *conn) { PrivData *privdata = conn->data; Msg* msg; Octstr *responseBody, *responseURL; List* responseHeaders; int responseStatus; long long msgID; ClientData* cd; /* don't get in here unless I have some callers */ /* (I shouldn't have one before I start sending messages) */ if (!gwlist_len(privdata->soap_client)) return; /* see if we have any responses pending */ if (!(cd = soap_client_have_response(privdata->soap_client))) return; cd->requests--; msg = http_receive_result(cd->caller, &responseStatus, &responseURL, &responseHeaders, &responseBody); if (!msg) /* no responses here */ { debug("bb.soap.read_response",0,"SOAP[%s]: sorry, no response", octstr_get_cstr(privdata->name)); return; } if (responseStatus == -1) { debug("bb.soap.read_response",0,"SOAP[%s]: HTTP connection failed - blame the server (requeing msg)", octstr_get_cstr(privdata->name)); bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED")); /* bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY); */ /* gwlist_append(privdata->outgoing_queue, msg); */ return; } debug("bb.soap.read_response",0,"SOAP[%s]: got a response %d= %s", octstr_get_cstr(privdata->name), responseStatus, responseBody?octstr_get_cstr(responseBody):octstr_get_cstr(octstr_imm("NULL"))); /* got a message from HTTP, parse it */ if ( (msgID = soap_parse_response(privdata, responseBody)) >= 0) { /* ack with msg ID */ char tmpid[30]; /* * XXX UUID is used, fix this. if (msgID == 0) msgID = msg->sms.id; */ sprintf(tmpid,"%lld",msgID); debug("bb.soap.read_response",0,"SOAP[%s]: ACK - id: %lld", octstr_get_cstr(privdata->name), msgID); dlr_add(conn->id, octstr_imm(tmpid), msg, 0); /* send msg back to bearerbox for recycling */ bb_smscconn_sent(conn, msg, NULL); } else { /* nack */ debug("bb.soap.read_response",0,"SOAP[%s]: NACK", octstr_get_cstr(privdata->name)); /* send msg back to bearerbox for recycling */ bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_create("MALFORMED")); } http_destroy_headers(responseHeaders); O_DESTROY(responseBody); O_DESTROY(responseURL); } /* * function soap_parse_response() * parse the response from the server to find the message ID * Input: Connection session data, Octstr xml buffer * Returns: message ID parsed or -1 if parsing failed (for example - a NACK received) * * Possible bug : I use gwlist_get() liberaly here, after checking that I have enough items, * but if gwlist_get() returns NULL for an empty item, things might break - and * not in a nice way. **/ static long long soap_parse_response(PrivData* privdata, Octstr* xmlResponse) { long long msgID = -1; long responseStatus = -1; xmlDocPtr responseDoc; xmlNodePtr root; List* maps; char* keywords[] = { "id", "result" }; char* sscans[] = { "%lld", "%ld" }; void* pointers[] = { &msgID, &responseStatus }; if (!xmlResponse) return -1; /* FIXME: do something here */ /* parse XML */ if ( !(responseDoc = xmlParseDoc((xmlChar *)octstr_get_cstr(xmlResponse))) ) { error(0,"SOAP[%s]: couldn't parse XML response [ %s ] in MT parsing", octstr_get_cstr(privdata->name), octstr_get_cstr(xmlResponse)); return -1; } /* get root element */ if ( ! (root = xmlDocGetRootElement(responseDoc)) ) { error(0,"SOAP[%s]: couldn't get XML root element in MT parsing", octstr_get_cstr(privdata->name)); xmlFreeDoc(responseDoc); return -1; } /* create the argument map */ maps = soap_create_map(privdata->mt_spec_file, 2, keywords, sscans, pointers); /* run the map and the xml through the parser */ if (soap_map_xml_data(root, maps) < 2) { error(0,"SOAP[%s]: failed to map all the arguments from the XML data", octstr_get_cstr(privdata->name)); } gwlist_destroy(maps, soap_destroy_map); /* done with the document */ xmlFreeDoc(responseDoc); if (msgID == -1) { if (responseStatus == 0) { /* success without msg ID */ warning(0, "SOAP[%s]: parse_response - the protocol does not support message ID", octstr_get_cstr(privdata->name)); return 0; } else { error(0,"SOAP[%s]: parse_response - response code isn't 0 ! (%ld)", octstr_get_cstr(privdata->name), responseStatus); return -1; /* Nack */ } } else return msgID; /* success with msg ID */ } /* * function soap_parse_mo() * parse an incoming MO xml request, build a message from it and sent it. * also generate the response text and status code * Input: module public state data, request body * Output: response body * Returns: HTTP status code on successful parse or -1 on failure **/ static long soap_parse_mo(SMSCConn *conn, Octstr *request, Octstr **response) { PrivData *privdata = conn->data; xmlDocPtr requestDoc; xmlNodePtr root; Msg* msg; int pos = 0; long res = -1; List* maps; char receiver[30], sender[30], msgtype[30], msgdata[255], date[30]; long long msgid = -1; char* keywords[] = { "receiver", "sender", "msgtype", "msgdata", "date", "id" }; char* sscans[] = { "%s", "%s", "%s", "%s", "%s", "%lld" }; void* pointers[] = { &receiver, &sender, &msgtype, &msgdata, &date, &msgid }; receiver[0] = sender[0] = msgtype[0] = msgdata[0] = date[0] = '\0'; if (!response) /* how am I supposed to return a response now ? */ return -1; if (!request) { *response = octstr_create(SOAP_ERROR_NO_DATA_MESSAGE); return SOAP_ERROR_NO_DATA_CODE; } /* find the POST parameter name */ if ( (pos = octstr_search_char(request,'=',0)) < 0) { /* didn't find it - */ *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } /* cut of the parameter name - I'm not really interested in it */ octstr_delete(request,0,pos+1); /* decode the URL encoded data */ if (octstr_url_decode(request) < 0) { /* probably not URL encoded */ *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } debug("bb.soap.parse_mo",0,"SOAP[%s]: parse_mo - MO request dump <%s>", octstr_get_cstr(privdata->name),octstr_get_cstr(request)); /* parse XML */ if ( !(requestDoc = xmlParseDoc((xmlChar *)octstr_get_cstr(request))) ) { error(0,"SOAP[%s]: parse_mo couldn't parse XML response", octstr_get_cstr(privdata->name)); return -1; } /* get root element */ if ( ! (root = xmlDocGetRootElement(requestDoc)) ) { error(0,"SOAP[%s]: parse_mo couldn't get XML root element for request", octstr_get_cstr(privdata->name)); xmlFreeDoc(requestDoc); return -1; } /* create the argument map */ maps = soap_create_map(privdata->mo_spec_file, 6, keywords, sscans, pointers); /* run the map and the xml through the parser */ if (soap_map_xml_data(root, maps) < gwlist_len(maps)) { error(0,"SOAP[%s]: parse_mo failed to map all the arguments from the XML data", octstr_get_cstr(privdata->name)); } /* done with the document */ xmlFreeDoc(requestDoc); if (strlen(receiver) == 0) { error(0,"SOAP: parse_mo - failed to get receiver"); *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } if (strlen(sender) == 0) { error(0,"SOAP: parse_mo - failed to get sender"); *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } if (strlen(msgdata) == 0) { error(0,"SOAP: parse_mo - failed to get message content"); *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } /* create me a message to store data in it */ msg = msg_create(sms); /* * XXX UUID is used, fix this. if (msgid == -1) { error(0,"SOAP: parse_mo - failed to get message ID, generate by itself"); msg->sms.id = gw_generate_id(); } */ /* fill in the fields from the parsed arguments */ msg->sms.sender = octstr_create(sender); msg->sms.receiver = octstr_create(receiver); /* * XXX UUID is used, fix this. msg->sms.id = msgid; */ msg->sms.msgdata = octstr_create(msgdata); /* special processing and refill appropriate fields */ if (privdata->mo_deps_file) { if ((res = soap_release_dependences(privdata->mo_deps_file, maps, msg, privdata))!=0) error(0,"SOAP: parse_mo - failed to release all dependences"); } gwlist_destroy(maps, soap_destroy_map); /* fill in the date */ if (strlen(date)) { struct universaltime tm; Octstr* temp = octstr_create(date); if (date_parse_iso(&tm, temp)) /* failed to parse the date */ msg->sms.time = time(NULL); else msg->sms.time = date_convert_universal(&tm); octstr_destroy(temp); } else msg->sms.time = time(NULL); /* / * check message data type - B stands for "base 64 encoded" in Team Mobile * / if (!strcmp(msgtype, "B")) { octstr_base64_to_binary(msg->sms.msgdata); msg->sms.coding = DC_8BIT; } else if (!strcmp(msgtype, "binary")) { octstr_hex_to_binary(msg->sms.msgdata); msg->sms.coding = DC_8BIT; } else { */ /* not gonna play this game - just convert from whatever alt_charset is set to, to UCS-2 / * scan message for unicode chars (UTF-8 encoded) * / pos = 0; while (pos < octstr_len(msg->sms.msgdata)) { if (octstr_get_char(msg->sms.msgdata,pos) & 128) break; ++pos; } if (pos < octstr_len(msg->sms.msgdata)) { / * message has some unicode - we need to convert to UCS-2 first * / Octstr* temp = msg->sms.msgdata; msg->sms.coding = DC_UCS2; if (charset_from_utf8(temp, &(msg->sms.msgdata), octstr_imm("UCS-2")) < 0) { error(0,"SOAP[%s]: parse_mo couldn't convert msg text from UTF-8 to UCS-2. leaving as is.", octstr_get_cstr(privdata->name)); O_DESTROY(msg->sms.msgdata); msg->sms.msgdata = octstr_duplicate(temp); / * set coding to 8bit and hope for the best * / msg->sms.coding = DC_8BIT; } octstr_destroy(temp); } else / * not unicode : 7bit * / msg->sms.coding = DC_7BIT; */ /* if it's not binary, then assume unicode and convert from alt_charset to UCS-2 */ /* msg->sms.coding = DC_UCS2; if (!octstr_case_compare(privdata->alt_charset, octstr_imm("UCS-2"))) { int ret = 0; debug("bb.soap.parse_mo",0,"SOAP[%s]: converting from %s to UCS-2BE", octstr_get_cstr(privdata->name), octstr_get_cstr(privdata->alt_charset)); ret = charset_convert(msg->sms.msgdata, octstr_get_cstr(privdata->alt_charset), "UCS-2BE"); if (ret == -1) { error(2,"SOAP[%s]: Error converting MO data from %s to unicode", octstr_get_cstr(privdata->name), octstr_get_cstr(privdata->alt_charset)); } else if (ret != 0) { debug("bb.soap.parse_mo",1,"SOAP[%s]: charset_convert made %d irreversable transformations", octstr_get_cstr(privdata->name), ret); } } msg->sms.charset = octstr_create("UCS-2"); } debug("bb.soap.parse_mo",0,"SOAP[%s]: message decoded -", octstr_get_cstr(privdata->name)); octstr_dump(msg->sms.msgdata,0); */ /* check that we have all the fields necessary */ if (!(msg->sms.sender) || !(msg->sms.msgdata)) { /* generate error message */ *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } /* setup defaults */ if (msg->sms.time <= 0) msg->sms.time = time(NULL); if (!msg->sms.receiver) msg->sms.receiver = octstr_create(SOAP_DEFAULT_SENDER_STRING); if (!msg->sms.smsc_id) msg->sms.smsc_id = octstr_duplicate(conn->id); *response = soap_format_xml(privdata->mo_xml_file,msg,privdata); if (*response) debug("bb.soap.response_dlr",0,"SOAP[%s]: data dump: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(*response)); bb_smscconn_receive(conn,msg); return SOAP_QUERY_OK; } /* * function soap_parse_dlr() * parse an incoming DLR xml request, build a message from it and sent it. * also generate the response text and status code * Input: module public state data, request body * Output: response body * Returns: HTTP status code on successful parse or -1 on failure **/ static long soap_parse_dlr(SMSCConn *conn, Octstr *request, Octstr **response) { PrivData *privdata = conn->data; xmlDocPtr requestDoc; xmlNodePtr root; Msg* dlrmsg = NULL; long dlrtype; int pos; List* maps; char receiver[30], soapdate[30], msgid[30]; long result = -1; char* keywords[] = { "receiver", "soapdate", "id", "result" }; char* sscans[] = { "%s", "%s", "%s", "%ld" }; void* pointers[] = { &receiver, &soapdate, &msgid, &result }; receiver[0] = soapdate[0] = msgid[0] = '\0'; if (!response) /* how am I supposed to return a response now ? */ return -1; if (!request) { *response = octstr_create(SOAP_ERROR_NO_DATA_MESSAGE); return SOAP_ERROR_NO_DATA_CODE; } /* find the POST parameter name */ if ( (pos = octstr_search_char(request,'=',0)) < 0) { /* didn't find it - */ *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } /* cut of the parameter name - I'm not really interested in it */ octstr_delete(request,0,pos+1); /* decode the URL encoded data */ if (octstr_url_decode(request) < 0) { /* probably not URL encoded */ *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } debug("bb.soap.parse_dlr",0,"SOAP[%s]: parse_dlr - DLR request dump <%s>", octstr_get_cstr(privdata->name),octstr_get_cstr(request)); /* parse XML */ if ( !(requestDoc = xmlParseDoc((xmlChar *)octstr_get_cstr(request))) ) { error(0,"SOAP[%s]: parse_dlr couldn't parse XML response", octstr_get_cstr(privdata->name)); return -1; } /* get root element */ if ( ! (root = xmlDocGetRootElement(requestDoc)) ) { error(0,"SOAP[%s]: parse_dlr couldn't get XML root element for request", octstr_get_cstr(privdata->name)); xmlFreeDoc(requestDoc); return -1; } /* create the argument map */ maps = soap_create_map(privdata->dlr_spec_file, 4, keywords, sscans, pointers); /* run the map and the xml through the parser */ if (soap_map_xml_data(root, maps) < 4) { error(0,"SOAP[%s]: parse_dlr failed to map all the arguments from the XML data", octstr_get_cstr(privdata->name)); } gwlist_destroy(maps, soap_destroy_map); /* done with the document */ xmlFreeDoc(requestDoc); if (strlen(msgid) == 0) { error(0,"SOAP: parse_dlr - failed to get message ID"); *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } if (result == -1) { error(0,"SOAP: parse_dlr - failed to get delivery code"); *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } /* we not need it because receiver now is constant string "receiver" if (strlen(receiver) == 0) { error(0,"SOAP: parse_dlr - failed to get receiver"); *response = octstr_create(SOAP_ERROR_MALFORMED_DATA_MESSAGE); return SOAP_ERROR_MALFORMED_DATA_CODE; } */ /* log the delivery code - this could be used to determine dlrtype (or so I hope) */ debug("bb.soap.parse_dlr",0,"SOAP[%s]: parse_dlr DELIVERY_CODE : %ld", octstr_get_cstr(privdata->name),result); if (result == 0) dlrtype = DLR_SUCCESS; else dlrtype = DLR_FAIL; /* fetch the DLR */ dlrmsg = dlr_find(conn->id, octstr_imm(msgid), octstr_imm("receiver"), /* destination */ dlrtype, 0); if (!dlrmsg) { error(0,"SOAP[%s]: parse_dlr invoked (%ld), but no DLR found for MsgID %s", octstr_get_cstr(privdata->name),dlrtype,msgid); *response = octstr_create(SOAP_ERROR_NO_DLR_MESSAGE); return SOAP_ERROR_NO_DLR_CODE; } debug("bb.soap.parse_dlr",0,"SOAP[%s]: parse_dlr found dlr", octstr_get_cstr(privdata->name)); octstr_destroy(dlrmsg->sms.msgdata); switch (dlrtype) { /* change message according to DLR type */ case DLR_SUCCESS: dlrmsg->sms.msgdata = octstr_create("Delivered"); break; case DLR_BUFFERED: dlrmsg->sms.msgdata = octstr_create("Buffered"); break; case DLR_FAIL: dlrmsg->sms.msgdata = octstr_create("Failed"); break; default: break; } /* if (dlrmsg->sms.receiver) { octstr_destroy(dlrmsg->sms.sender); dlrmsg->sms.sender = dlrmsg->sms.receiver; } dlrmsg->sms.receiver = octstr_create(receiver); dlrmsg->sms.id = strtol(msgid, NULL, 10); */ debug("bb.soap.parse_dlr",0,"SOAP[%s]: parse_dlr sent dlr <%s>", octstr_get_cstr(privdata->name),octstr_get_cstr(dlrmsg->sms.msgdata)); *response = soap_format_xml(privdata->dlr_xml_file, dlrmsg, privdata); if (*response) debug("bb.soap.response_dlr",0,"SOAP[%s]: data dump: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(*response)); /* send to bearerbox */ bb_smscconn_receive(conn, dlrmsg); return SOAP_QUERY_OK; } /* * SOAP internal utility functions **/ /* * function soap_xmlnode_get_long() * parse the content of an XML node and return it as an integer * Input: xmlNodePtr to node * Output: long parsed * Returns: 0 on success, -1 on failure **/ int soap_xmlnode_get_long(xmlNodePtr cur, long* out) { xmlChar* nodeContent; char* endPointer; if (!out) /* sanity check */ return -1; /* get content of tag */ if (!(nodeContent = xmlNodeGetContent(cur))) { error(0,"SOAP: get_long - xml Node has content !"); return -1; } /* read the content into output */ *out = strtol((char *)nodeContent,&endPointer,10); xmlFree(nodeContent); if (endPointer == (char*)nodeContent) { error(0,"SOAP: get_long - node has non-numeric content <%s>", nodeContent); return -1; } return 0; } /* * function soap_xmlnode_get_int64() * parse the content of an XML node and return it as an long long * Input: xmlNodePtr to node * Output: long parsed * Returns: 0 on success, -1 on failure **/ int soap_xmlnode_get_int64(xmlNodePtr cur, long long* out) { xmlChar* nodeContent; char* endPointer; if (!out) /* sanity check */ return -1; /* get content of tag */ if (!(nodeContent = xmlNodeGetContent(cur))) { error(0,"SOAP: get_long - xml Node has content !"); return -1; } /* read the content into output */ *out = strtoll((char *)nodeContent,&endPointer,10); xmlFree(nodeContent); if (endPointer == (char*)nodeContent) { error(0,"SOAP: get_long - node has non-numeric content <%s>", nodeContent); return -1; } return 0; } /* * function soap_xmlnode_get_octstr() * parse the content of an XML node and return it as an Octstr* * Input: xmlNodePtr to node * Output: Octstr to feel with data * Returns: 0 on success, -1 on failure **/ int soap_xmlnode_get_octstr(xmlNodePtr cur, Octstr **out) { xmlChar* nodeContent; if (!out) /* sanity check */ return -1; /* get content of tag */ if (!(nodeContent = xmlNodeGetContent(cur))) { error(0,"SOAP: get_octstr - xml Node has content !"); return -1; } /* store the content into output */ *out = octstr_create((char *)nodeContent); xmlFree(nodeContent); if (*out) return 0; else return -1; } /* * function soap_read_date() * convert a date string in one2one obiquis format (%Y/%M/%d:%h:%m) to epoch time * Input: Octstr date * Returns: epoch time on success or -1 on failure **/ time_t soap_read_date(Octstr* dateString) { int pos, count; struct universaltime stTime; long arTime[5]; if (!dateString) /* sanity check */ return -1; pos = count = 0; /* tricky control structures are my favourite among complicated expressions ;-) */ while (count < 5 && pos < octstr_len(dateString) && (pos = octstr_parse_long(&(arTime[count++]),dateString, pos,10)) && pos != -1) ++pos; if (count < 5) { /* error parsing the date */ debug("bb.soap.read_date",0,"read_date failed parsing the date value <%s>", octstr_get_cstr(dateString)); return -1; } stTime.day = arTime[0]; stTime.month = arTime[1]; stTime.year = arTime[2]; stTime.hour = arTime[3]; stTime.minute = arTime[4]; stTime.second = 0; return date_convert_universal(&stTime); } /* * function soap_write_date() * convert an epoch time value to a date string in one2one obiquis format (%Y/%M/%d:%h:%m) * Input: time_t epoch time * Returns: an Octstr containing the date - this must be freed by the caller **/ static Octstr* soap_write_date(time_t date) { struct tm date_parts; Octstr* out; if (date < 0) /* sanity check - I don't think it should ever happen, but I don't want to get support calls at 2am because some gateway in the UK went bananas. */ return octstr_create("ERROR"); /* split up epoch time to elements */ gmtime_r(&date, &date_parts); out = octstr_format("%d/%02d/%02d:%02d:%02d", date_parts.tm_year + 1900, date_parts.tm_mon + 1, date_parts.tm_mday, date_parts.tm_hour, date_parts.tm_min); /* again */ if (out) return out; else return octstr_create("ERROR"); /* assuming octstr_create never fails, unlike octstr_format. this is not the case currently (both cannot fail), but it may change */ } /* * function soap_server_start() * init and start the SOAP HTTP server * Input: Module public connection state data * Returns: 0 on success, -1 on failure **/ int soap_server_start(SMSCConn *conn) { PrivData* privdata = conn->data; debug("bb.soap.server_stop",0,"SOAP[%s]: Starting HTTP server", octstr_get_cstr(privdata->name)); /* start the HTTP server */ if (http_open_port(privdata->port,privdata->ssl)) { return -1; } /* raise server flag */ privdata->soap_server = 1; if ( (privdata->server_thread = gwthread_create(soap_server, conn)) == -1) { error(0, "SOAP[%s]: server_start failed to create server thread!", octstr_get_cstr(privdata->name)); http_close_port(privdata->port); return -1; } return 0; } /* * function soap_server_stop() * tears down and stops the SOAP HTTP server * Input: Module connection state data **/ static void soap_server_stop(PrivData* privdata) { /* time_t start = time(NULL); */ debug("bb.soap.server_stop",0,"SOAP[%s]: Stopping HTTP server", octstr_get_cstr(privdata->name)); /* signal the server thread to stop */ privdata->soap_server = 0; /* close the http server thread */ http_close_port(privdata->port); if (privdata->server_thread) { gwthread_wakeup(privdata->server_thread); gwthread_join(privdata->server_thread); privdata->server_thread = 0; } /* / * wait upto 5 minutes for our server thread to shutdown * / while (privdata->server_thread && (start + 300 > time(NULL))) gwthread_sleep(SOAP_SLEEP_TIME); if (privdata->server_thread) { error(0,"SOAP[%s]: our server refuses to die!", octstr_get_cstr(privdata->name)); privdata->server_thread = 0; / * dump it either way * / }*/ debug("bb.soap.server_stop",0,"SOAP[%s]: Done stopping HTTP server", octstr_get_cstr(privdata->name)); } /* * function soap_create_client_data() * creates a new SOAP client data structure and caller * Returns: an initialized client data structure with a live caller **/ static ClientData* soap_create_client_data() { ClientData *cd = gw_malloc(sizeof(ClientData)); cd->last_access = 0; cd->requests = 0; cd->caller = http_caller_create(); return cd; } /* * function soap_client_init_query() * start an HTTP query, load balance callers, and manage caller pool * Input: Module state, list of headers to send, data to send, message to store **/ static void soap_client_init_query(PrivData* privdata, List* headers, Octstr* data, Msg* msg) { ClientData *cur_client = NULL; long index; /* no list yet, generate one */ if (!privdata->soap_client) privdata->soap_client = gwlist_create(); /* I'm going to change the list, so lock it */ gwlist_lock(privdata->soap_client); /* find the next live caller */ for (index = gwlist_len(privdata->soap_client) - 1 ; index >= 0; --index) { cur_client = gwlist_get(privdata->soap_client, index); if ( cur_client->last_access + CLIENT_BUSY_TIME < time(NULL) && cur_client->requests < CLIENT_BUSY_LOAD ) { debug("bb.soap.init_query",0,"SOAP[%s]: init_query getting a client",octstr_get_cstr(privdata->name)); /* client is not busy - get it */ gwlist_delete(privdata->soap_client, index, 1); break; } cur_client = NULL; } if (!cur_client) { if (gwlist_len(privdata->soap_client) > MAX_SOAP_CLIENTS) { debug("bb.soap.init_query",0,"SOAP[%s]: init_query all clients are busy, getting the first client",octstr_get_cstr(privdata->name)); /* query not dispatched, and we have the max number of callers - grab the first caller (least used) from the list */ cur_client = gwlist_extract_first(privdata->soap_client); } else { /* query not dispatched, and we don't have enough callers - start a new one */ debug("bb.soap.init_query",0,"SOAP[%s]: init_query creates a new client",octstr_get_cstr(privdata->name)); cur_client = soap_create_client_data(); } } /* dispatch query to selected client */ http_start_request(cur_client->caller, HTTP_METHOD_POST, privdata->uri, headers, data, 1, msg, NULL); cur_client->requests++; cur_client->last_access = time(NULL); gwlist_append(privdata->soap_client, cur_client); gwlist_unlock(privdata->soap_client); } /* * function soap_destroy_client_data() * destroy a SOAP client caller * Input: pointer to a client data structure with a live caller **/ static void soap_destroy_client_data(void* data) { ClientData *cd = (ClientData*) data; /* signal the caller to stop and then kill it */ if (cd->caller) { http_caller_signal_shutdown(cd->caller); http_caller_destroy(cd->caller); } } /* * function soap_client_have_response() * return a caller from the pool that has responses waiting * Input: ClientData pool * Returns: a client data structure that has a caller with responses waiting, * or NULL if none are found **/ static ClientData* soap_client_have_response(List* client_list) { long index; ClientData* cd; if (!client_list) return NULL; /* lock the list so nobody removes or adds clients while I'm looping on the list */ gwlist_lock(client_list); for (index = gwlist_len(client_list) - 1; index >= 0; --index) { cd = gwlist_get(client_list,index); if (gwlist_len(cd->caller)) { gwlist_unlock(client_list); return gwlist_get(client_list, index); } } gwlist_unlock(client_list); return NULL; } /* * function soap_convert_token() * convert a member of the message structure and return it as octstr * Input: member name * Returns: an Octstr containing the content of the data member from the message structure * or NULL if an error occured. **/ static Octstr* soap_convert_token(Msg* msg, Octstr* name, PrivData* privdata) { char buf[20]; int index; if ( (index=soap_lookup_function(name)) >= 0 ) return soap_select_function(index, msg, privdata); #define INTEGER(fieldname) \ if (!octstr_str_compare(name, #fieldname)) { \ sprintf(buf,"%ld", p->fieldname); \ return octstr_create(buf); \ } #define INT64(fieldname) \ if (!octstr_str_compare(name, #fieldname)) { \ sprintf(buf,"%lld", p->fieldname); \ return octstr_create(buf); \ } #define OCTSTR(fieldname) \ if (!octstr_str_compare(name, #fieldname)) \ return octstr_duplicate(p->fieldname); #define UUID(fieldname) #define VOID(fieldname) #define MSG(type, stmt) \ case type: { struct type *p = &msg->type; stmt } break; switch (msg->type) { #include "msg-decl.h" default: error(0, "SOAP: Internal error: unknown message type %d", msg->type); return NULL; } error(0,"SOAP: soap_convert_token, can't find token named <%s>", octstr_get_cstr(name)); return NULL; } /* * function soap_create_map() * convert a XML parsing spec file and a list of recognized keywords to an argument map * Input: XML parsing spec buffer and lists of keywords, types and pointers * Returns: number of variables successfuly mapped **/ List* soap_create_map(Octstr* spec, long count, char* keywords[], char* types[], void* storage[]) { List *parse_items, *out; out = gwlist_create(); /* read the list of items from the spec file */ parse_items = octstr_split(spec, octstr_imm("\n")); while (gwlist_len(parse_items)) { ArgumentMap* map; int index; Octstr* temp = gwlist_extract_first(parse_items); List* item = octstr_split_words(temp); /* make sure we have at least two things in the item : a keyword and a path */ if (gwlist_len(item) < 2) { debug("bb.soap.parse_create_map",0,"SOAP: broken spec file line <%s> in soap_create_map", octstr_get_cstr(temp)); octstr_destroy(temp); gwlist_destroy(item, octstr_destroy_item); continue; } /* check that the keyword matches something in the list of keywords */ for (index = 0; index < count; ++index) { if (!octstr_str_compare(gwlist_get(item,0), keywords[index])) { /* allocate the structure */ map = gw_malloc(sizeof(ArgumentMap)); map->name = gwlist_extract_first(item); map->path = gwlist_extract_first(item); map->attribute = gwlist_extract_first(item); /* could be NULL, but that is ok */ map->sscan_type = octstr_create(types[index]); map->store = storage[index]; gwlist_append(out, map); break; } } /* destroy temporary variables; */ gwlist_destroy(item, octstr_destroy_item); octstr_destroy(temp); } gwlist_destroy(parse_items, octstr_destroy_item); return out; } /* * function soap_destroy_map() * destroy a map structure. used in gwlist_destroy(calls); * Input: pointer to a map structure; **/ void soap_destroy_map(void *item) { ArgumentMap* map = item; octstr_destroy(map->name); octstr_destroy(map->path); octstr_destroy(map->attribute); octstr_destroy(map->sscan_type); gw_free(map); } /* * function soap_fetch_xml_data() * return the value of an XML element. * Input: pointer to root of XML to search under, path specified in one of three forms * a) - will return the content of this tag * b) , - will return the value of this attribute * c) "" - will return the given value as it is * Returns: content if found or NULL **/ Octstr* soap_fetch_xml_data(xmlNodePtr xml, Octstr* path) { Octstr *temp, *xml_path, *attr_name = NULL; List* path_elements; unsigned char c; xmlNodePtr parent, node; int index; /* sanity check */ if (!octstr_len(path) || !xml) return NULL; /* stop here for case (c) */ if (((c = octstr_get_char(path, 0)) == '"' || c == '\'') && (octstr_get_char(path, octstr_len(path)-1) == c)) return octstr_copy(path, 1, octstr_len(path) - 2); /* split into XML path and attribute name */ path_elements = octstr_split(path, octstr_imm(",")); xml_path = gwlist_get(path_elements,0); if (gwlist_len(path_elements) > 1) /* case (b), we have an attribute */ attr_name = gwlist_get(path_elements,1); gwlist_destroy(path_elements, NULL); /* split path into parts */ path_elements = octstr_split(xml_path, octstr_imm("/")); /* walk the message tree down the path */ parent = NULL; node = xml; index = 0; while (index < gwlist_len(path_elements)) { int found = 0; /* get the next path element */ temp = gwlist_get(path_elements, index); do { if (!octstr_str_compare(temp,(char *)node->name)) { /* found what we're looking for */ if (!(node->xmlChildrenNode) && index < (gwlist_len(path_elements)-1)) { /* while this is indeed the item we are looking for, it's not the end * of the path, and this item has no children */ debug("bb.soap.fetch_xml_data",0,"SOAP: fetch_xml - error parsing XML, " "looking for <%s>, but element <%s> has no children", octstr_get_cstr(xml_path), octstr_get_cstr(temp)); } else { ++index; /* go down the path */ parent = node; /* remember where I came from */ node = node->xmlChildrenNode; /* trace into the node */ ++found; /* remember that I found it */ break; /* escape to the next level */ } } /* get the next node on this level - this runs if the current node is not in the path */ } while ((node = node->next)); if (!found) { /* didn't find anything - back track */ node = parent; parent = node->parent; if (--index < 0) /* I backtracked too much up the tree, nowhere to go to */ break; /* out of the main loop with nothing to show for it */ if (!(node = node->next)) /* after back tracking, go over to the next sibling of the node I just * finished searching under, or bail out if no more siblings */ break; } } /* coming here there are two options: * 1) we looped over all the tree, but did not succeed in traveling the * requested path - index not pointing past the list of path elements - */ if (index < gwlist_len(path_elements)) { /* didn't find the full path */ debug("bb.soap.map_xml_data",0,"SOAP: fetch_xml - path <%s> cannot be traveled in input XML", octstr_get_cstr(xml_path)); gwlist_destroy(path_elements, octstr_destroy_item); octstr_destroy(xml_path); octstr_destroy(attr_name); return NULL; } /* 2) index is pointing past the end of the path and the correct node * is stored in parent */ if (attr_name) { /* The caller wants to get an attribute */ xmlChar* content; content = xmlGetProp(parent, (xmlChar *)octstr_get_cstr(attr_name)); if (content) temp = octstr_create((char *)content); else /* dont treat an empty or non-existant attribute as an error right away */ temp = octstr_create(""); xmlFree(content); } else { /* the caller wants to get the content */ xmlChar* content; content = xmlNodeGetContent(parent); if (content) temp = octstr_create((char *)content); else /* don't treat an empty tag an error right away */ temp = octstr_create(""); xmlFree(content); } gwlist_destroy(path_elements, octstr_destroy_item); octstr_destroy(xml_path); octstr_destroy(attr_name); return temp; } /* * function soap_map_xml_data() * maps content of an XML structure to a list of variables using a map * Input: XML document and an argument map * Returns: number of variables successfuly mapped **/ int soap_map_xml_data(xmlNodePtr xml, List* maps) { int mapindex = 0, args = 0; xmlNodePtr node, parent; /* step through the items on the map */ while (mapindex < gwlist_len(maps)) { Octstr* temp; int index = 0; ArgumentMap* map = gwlist_get(maps,mapindex); /* split the path elements */ List* path_elements = octstr_split(map->path, octstr_imm("/")); /* walk the message tree down the path */ parent = NULL; node = xml; while (index < gwlist_len(path_elements)) { int found = 0; /* get the next path element */ temp = gwlist_get(path_elements, index); do { if (!octstr_str_compare(temp,(char *)node->name)) { /* found what we're looking for */ if (!(node->xmlChildrenNode) && index < (gwlist_len(path_elements)-1)) { /* while this is indeed the item we are looking for, it's not the end of the path, and this item has no children */ debug("bb.soap.map_xml_data",0,"SOAP: error parsing XML, looking for <%s>, but element <%s> has no children", octstr_get_cstr(map->path), octstr_get_cstr(temp)); } else { ++index; /* go down the path */ parent = node; /* remember where I came from */ node = node->xmlChildrenNode; /* trace into the node */ ++found; break; /* escape to the next level */ } } } while ((node = node->next)); if (!found) { /* didn't find anything - back track */ node = parent; if (parent==NULL) /* first tag not found, quickly go out ! */ return 0; parent = node->parent; if (--index < 0) /* I backtracked too much up the tree, nowhere to go to */ break; if (!(node = node->next)) /* no more childs under the main tree to look under, abort */ break; } } if (index < gwlist_len(path_elements)) { /* didn't find the full path */ debug("bb.soap.map_xml_data",0,"SOAP: didn't find element for keyword <%s> in XML data", octstr_get_cstr(map->name)); gwlist_destroy(path_elements, octstr_destroy_item); ++mapindex; continue; } /* found the correct node (it's stored in parent) */ if (map->attribute) { /* The user wants to get an attribute */ xmlChar* content; content = xmlGetProp(parent, (xmlChar *)octstr_get_cstr(map->attribute)); if (content) temp = octstr_create((char *)content); else /* dont treat an empty or non-existant attribute as an error right away */ temp = octstr_create(""); xmlFree(content); } else { /* the user wants to get the content */ xmlChar* content; content = xmlNodeGetContent(parent); if (content) temp = octstr_create((char *)content); else /* don't treat an empty tag an error right away */ temp = octstr_create(""); xmlFree(content); } /* parse the content using sscan_type from the map */ octstr_strip_blanks(temp); if (!octstr_str_compare(map->sscan_type,"%s")) { /* special processing of %s - this means the whole string, while sscanf stops at spaces */ strcpy(map->store,octstr_get_cstr(temp)); ++args; } else { if (!sscanf(octstr_get_cstr(temp), octstr_get_cstr(map->sscan_type), map->store)) { debug("bb.soap.map_xml_data",0,"SOAP: failed to scan content '%s' for '%s' in xml parsing", octstr_get_cstr(temp), octstr_get_cstr(map->sscan_type)); } else { ++args; } } /* done for this item */ octstr_destroy(temp); gwlist_destroy(path_elements, octstr_destroy_item); ++mapindex; } return args; } /* * function soap_release_dependences() * check for each key if we need specific convertation and do it * Input: specification of dependences to convert, map with all keys, msg structure to change values * Returns: error code or 0 on success **/ long soap_release_dependences(Octstr* file_deps, List* lstmaps, Msg* msg, PrivData *privdata) { List *issues; long i, j, key_index, key_deps_index, map_index; int res, k; List *issue_items, *header_item; int key_func_index; ArgumentMap* map; Octstr *header, *key, *key_deps; Octstr *func_alias = NULL, *block; /* follows keys and funcs identifiers must be * the same as in a 'deps' file **/ /* structure of file_deps; * * * * * ; */ /* ADD HERE: */ char* funcs[][5] = { /* functions aliasis used in mo.deps file */ {"text","binary","unicode","default"}, /* msgtype */ {"set_iso","64_binary","hex_binary","unicode","default"} /* msgdata */ }; issues = octstr_split(file_deps, octstr_imm(";")); /* get paragraphs */ if (gwlist_len(issues) == 0) { error(0, "SOAP: soap_release_dependences, empty or broken 'deps' file"); return -1; } for (i=0; i"); gwlist_destroy(issue_items, octstr_destroy_item); gwlist_destroy(issues, octstr_destroy_item); return -1; } header = gwlist_extract_first(issue_items); header_item = octstr_split_words(header); /* header content */ O_DESTROY(header); if (gwlist_len(header_item) < 2) { error(0, "SOAP: soap_release_dependences, broken 'deps' file in part"); gwlist_destroy(header_item, octstr_destroy_item); gwlist_destroy(issue_items, octstr_destroy_item); gwlist_destroy(issues, octstr_destroy_item); return -1; } key = gwlist_get(header_item, 0); key_deps = gwlist_get(header_item, 1); key_index = soap_get_index(lstmaps, key, 0); /* search key_index */ key_deps_index = soap_get_index(lstmaps, key_deps, 0); /* search key_deps_index, from what depends */ if (key_index == -1 || key_deps_index == -1) { gwlist_destroy(header_item, octstr_destroy_item); gwlist_destroy(issue_items, octstr_destroy_item); gwlist_destroy(issues, octstr_destroy_item); return -1; } map_index = soap_get_index(lstmaps, key_deps, 1); /* get index for map->name==key_deps */ map = gwlist_get(lstmaps, map_index); /* search and if not found try to set default */ for (j=0; j < gwlist_len(issue_items); ++j) { Octstr *tmp = gwlist_get(issue_items, j); List *row = octstr_split_words(tmp); if (!octstr_str_compare(gwlist_get(row, 0), map->store)) { func_alias = octstr_duplicate(gwlist_get(row, 1)); gwlist_destroy(row, octstr_destroy_item); break; } if (j==gwlist_len(issue_items)-1) { error(0, "SOAP: soap_release_dependences, \ can't find function_alias for <%s> in 'deps' file, set default", (char*)map->store); func_alias = octstr_create(SPEC_DEFAULT); } gwlist_destroy(row, octstr_destroy_item); } key_func_index = -1; /* searching index of function by its alias */ for (k=0; k < sizeof(funcs[key_index])/sizeof(funcs[key_index][0]); ++k) { if (!octstr_str_compare(func_alias, funcs[key_index][k])) { key_func_index = k; break; } } if (key_func_index==-1) error(0, "SOAP: soap_release_dependences, can't find function for alias <%s>", octstr_get_cstr(func_alias)); O_DESTROY(func_alias); gwlist_destroy(header_item, octstr_destroy_item); gwlist_destroy(issue_items, octstr_destroy_item); /* which field has deps, which func need be called, msg need be changed */ if ((res=soap_process_deps(key_index, key_func_index, msg, privdata)) < 0) error(0, "SOAP: soap_release_dependences, error processing dependent value"); } gwlist_destroy(issues, octstr_destroy_item); return 0; /* OK */ } /* * function soap_process_deps * select function for selected **/ int soap_process_deps(int key_index, int key_func_ind, Msg* msg, PrivData *privdata) { /* ADD HERE: MO 'key' functions */ switch (key_index) { case 0: return soap_msgtype_deps(key_func_ind, msg); case 1: return soap_msgdata_deps(key_func_ind, msg, privdata); default: return -1; } return -1; } /* * function soap_msgtype_deps * release dependences fot all types of specific coding **/ int soap_msgtype_deps(int key_func_index, Msg* msg) { /* {"text","binary","unicode","default"} msgtype */ /* ADD HERE: see order in funcs[][] */ switch (key_func_index) { case 0: /* "text" */ msg->sms.coding = DC_7BIT; break; case 1: /* "binary" */ msg->sms.coding = DC_8BIT; break; case 2: /* "unicode" */ case 3: /* "default" == unicode */ msg->sms.coding = DC_UCS2; break; default: /* out of range */ error(0, "SOAP: soap_msgtype_deps, unknown index %d", key_func_index); return -1; } return 0; } int soap_msgdata_deps(int key_func_index, Msg* msg, PrivData *privdata) { int ret = 0; /* {"set_iso","64_binary","hex_binary","unicode","default"} msgdata */ /* ADD HERE: */ switch (key_func_index) { case 0: /* "set_iso" */ msg->sms.charset = octstr_create("ISO-8859-1"); break; case 1: /* "64_binary" */ octstr_base64_to_binary(msg->sms.msgdata); break; case 2: /* "hex_binary" */ octstr_hex_to_binary(msg->sms.msgdata); break; case 3: /* "unicode" */ case 4: /* "default" */ if (!octstr_case_compare(privdata->alt_charset, octstr_imm("UCS-2"))) { debug("bb.soap.msgdata_deps",0,"SOAP[%s]: converting from %s to UCS-2BE", octstr_get_cstr(privdata->name), octstr_get_cstr(privdata->alt_charset)); ret = charset_convert(msg->sms.msgdata, octstr_get_cstr(privdata->alt_charset), "UCS-2BE"); if (ret == -1) { error(2,"SOAP[%s]: Error converting MO data from %s to unicode", octstr_get_cstr(privdata->name), octstr_get_cstr(privdata->alt_charset)); } } else if (ret != 0) { debug("bb.soap.parse_mo",1,"SOAP[%s]: charset_convert made %d irreversable transformations", octstr_get_cstr(privdata->name), ret); } msg->sms.charset = octstr_create("UCS-2"); debug("bb.soap.parse_mo",0,"SOAP[%s]: message decoded -", octstr_get_cstr(privdata->name)); octstr_dump(msg->sms.msgdata, 0); break; default: /* out of range */ error(0, "SOAP: soap_msgdata_deps, unknown index %d", key_func_index); return -1; } return 0; } /* MT spec processing */ /* return index of function alias in array of aliasis for functions * used in MT XML file to fill up specific parameters in XML doc */ int soap_lookup_function(Octstr* funcname) { int i; /* ADD HERE: XML functions aliasis */ char *aliasis[] = { "bouyg_content", "mobitai_content", "o2o_msgdata", "msgdata", "o2o_validity30", "mobitai_validity_date", "bouyg_validity", "o2o_date", "mobitai_date", "rand", "o2o_dlrmask_smsc_yn", "o2o_dlrmask_success_01" }; for (i=0; isms.coding == DC_8BIT) return octstr_create("D"); else return octstr_create("A"); } Octstr* soap_mobitai_content_attribute(Msg* msg) { if (msg->sms.coding == DC_8BIT) return octstr_create("binary"); else return octstr_create("text"); } Octstr* soap_o2o_msgdata_attribute(Msg* msg, PrivData *privdata) { Octstr *data, *res, *udhres; int ret; data = octstr_duplicate(msg->sms.msgdata); if (msg->sms.coding == DC_8BIT) { debug("bb.soap.o2o_msgdata_attribute",0,"SOAP: base 64 encoding"); octstr_binary_to_base64(data); res = octstr_format("%S", data); if (octstr_len(msg->sms.udhdata) > 0) { /* add UDH */ O_DESTROY(data); data = octstr_duplicate(msg->sms.udhdata); debug("bb.soap.o2o_msgdata_attribute",0,"SOAP: UDH base 64 encoding"); octstr_binary_to_base64(data); udhres = octstr_format("%S", data); octstr_append(res, udhres); O_DESTROY(udhres); } else { error(0, "SOAP: o2o_msgdata_attribute, UDH not defined"); udhres = octstr_create(""); octstr_append(res, udhres); O_DESTROY(udhres); } O_DESTROY(data); return res; } else if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) { /* convert message data to target encoding */ debug("bb.soap.o2o_msgdata_attribute", 0, "SOAP: converting from UTF-8 to %s", octstr_get_cstr(privdata->alt_charset)); ret = charset_convert(data, "UTF-8", octstr_get_cstr(privdata->alt_charset)); if (ret == -1) { error(0,"SOAP: soap_o2o_msgdata_attribute, charset_convert failed"); octstr_dump(msg->sms.msgdata, 0); O_DESTROY(data); return NULL; } debug("bb.soap.o2o_msgdata_attribute",0,"SOAP: converting to HTML entities"); octstr_convert_to_html_entities(data); res = octstr_format("%S", data); O_DESTROY(data); return res; } else if (msg->sms.coding == DC_UCS2) { /* convert message data to target encoding */ debug("bb.soap.o2o_msgdata_attribute", 0, "converting from USC-2 to %s", octstr_get_cstr(privdata->alt_charset)); ret = charset_convert(msg->sms.msgdata, "UCS-2BE", octstr_get_cstr(privdata->alt_charset)); if (ret == -1) { error(0,"SOAP: soap_o2o_msgdata_attribute, charset_convert failed"); octstr_dump(msg->sms.msgdata, 0); O_DESTROY(data); return NULL; } res = octstr_format("%s", data); O_DESTROY(data); return res; } else { error(0,"SOAP: soap_o2o_msgdata_attribute, unknown coding: %ld", msg->sms.coding); O_DESTROY(data); return NULL; } } /* mobitai/bouyg */ Octstr* soap_msgdata_attribute(Msg* msg, PrivData* privdata) { Octstr *data, *udhdata; int ret; data = octstr_duplicate(msg->sms.msgdata); if (msg->sms.coding == DC_8BIT) { udhdata = octstr_duplicate(msg->sms.udhdata); octstr_append(udhdata, data); octstr_binary_to_hex(udhdata, 1); O_DESTROY(data); return udhdata; } else if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) { /* convert message data to target encoding */ debug("bb.soap.msgdata_attribute", 0, "SOAP: converting from UTF-8 to %s", octstr_get_cstr(privdata->alt_charset)); ret = charset_convert(data, "UTF-8", octstr_get_cstr(privdata->alt_charset)); if (ret == -1) { error(0,"SOAP: soap_msgdata_attribute, charset_convert failed"); octstr_dump(msg->sms.msgdata, 0); O_DESTROY(data); return NULL; } debug("bb.soap.msgdata_attribute",0,"SOAP: converting to HTML entities"); octstr_convert_to_html_entities(data); return data; } else if (msg->sms.coding == DC_UCS2) { /* convert message data to target encoding */ debug("bb.soap.msgdata_attribute", 0, "converting from USC-2 to %s", octstr_get_cstr(privdata->alt_charset)); ret = charset_convert(data, "UCS-2BE", octstr_get_cstr(privdata->alt_charset)); if (ret == -1) { error(0,"SOAP: soap_msgdata_attribute, charset_convert failed"); octstr_dump(data, 0); O_DESTROY(data); return NULL; } return data; } else { error(0,"SOAP: soap_msgdata_attribute, unknown coding: %ld", msg->sms.coding); O_DESTROY(data); return NULL; } } /* validity in 30 minutes increment */ Octstr* soap_o2o_validity30_attribute(Msg* msg) { return octstr_format("%ld",(msg->sms.validity != SMS_PARAM_UNDEFINED ? (msg->sms.validity - time(NULL))/60 : SOAP_DEFAULT_VALIDITY) / 30); } /* date on which the message's validity expires */ Octstr* soap_mobitai_validity_date_attribute(Msg* msg) { return date_create_iso(msg->sms.validity); } /* validity in seconds */ Octstr* soap_bouyg_validity_attribute(Msg* msg) { return octstr_format("%d", msg->sms.validity - time(NULL)); } Octstr* soap_o2o_date_attribute(Msg* msg) { return soap_write_date(msg->sms.time); } /* TIMESTAMP */ Octstr* soap_mobitai_date_attribute(Msg* msg) { return date_create_iso(msg->sms.time); } Octstr* soap_rand_attribute(Msg* msg) { return octstr_format("%d",gw_rand()); } /* "Y" for any of the SMSC generated DLRs, "N" otherwise */ Octstr* soap_o2o_dlrmask_smsc_yn_attribute(Msg* msg) { return octstr_create(DLR_IS_ENABLED_SMSC(msg->sms.dlr_mask) ? "Y" : "N"); } /* "1" for any of the SMSC generated DLRs, "0" otherwise */ Octstr* soap_o2o_dlrmask_success_01_attribute(Msg* msg) { return octstr_create( DLR_IS_SUCCESS(msg->sms.dlr_mask) ? "0" : "1"); } /* * looking for key in the map names collection to find key_index * if map_index==1 i like to know index in the map 'where' for name 'key' */ int soap_get_index(List* where, Octstr* key, int map_index) { int i, j; ArgumentMap* map; /* ADD HERE: */ /* key and key_deps values as defined in mo.deps */ char* funcs_deps[] = { "msgtype", "msgdata" }; for (i=0; i < gwlist_len(where); ++i) { map = gwlist_get(where, i); if (!octstr_compare(map->name, key)) { if (map_index==1) /* return index from the list where found name */ return i; for (j=0; j < sizeof(funcs_deps)/sizeof(funcs_deps[0]); ++j) { if (!octstr_str_compare(map->name, funcs_deps[j])) return j; } } } error(0, "SOAP: soap_get_index, broken 'deps' file, can't find key <%s> ", octstr_get_cstr(key)); return -1; } gateway-1.4.5/gw/smsc/smsc_sema.h0000644000175000017500000002563513227613126015407 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef SMSC_SEMA_H #define SMSC_SEMA_H #include "gwlib/gwlib.h" #include "smsc.h" #include "smsc_p.h" #define SM_RESULT_SUCCESS 0 #define SM_RESULT_FAIL_ARGS 1 #define SM_RESLUT_FAIL_SMSC_DB 2 #define SM_RESULT_FAIL_SMSC_BUSY 3 #define SM_RESULT_FAIL_SM_NOTFOUND 4 #define SM_RESULT_FAIL_SM_DUPLICATE 5 #define SME_RESULT_SUCCESS 0 #define SME_RESULT_INVALIDDATA 1 #define SME_RESULT_DBFULL 2 #define SME_RESULT_SMEBUSY 3 #define SME_RESULT_NOTUSED 4 #define SME_RESULT_DUPLICATESM 5 #define SME_RESULT_DESTUNAVAILABLE 6 #define SME_RESULT_CALLBARREDUSER 7 #define SME_RESULT_TRANSMISSION 21 #define SME_RESULT_FACILITYNOTSUPPORT 22 #define SME_RESULT_ERRORINSME 23 #define SME_RESULT_UNKNOWNSUBSCRIBER 24 #define SME_RESULT_CALLBARREDOPERATOR 25 #define SME_RESULT_CUGVIOLATION 26 #define SME_RESULT_NETWORKFAIL 120 #define ENCODE_IA5 15 #define ENCODE_GSM 0 /*internal definition*/ #define LINE_ENCODE_IA5 1 #define LINE_ENCODE_HEX 2 #define LINE_ENCODE_BIN 3 #define X28_COMMAND_MODE 0 #define X28_MT_DATA_MODE 1 #define X28_MO_DATA_MODE 2 #define INTERNAL_DISCONNECT_TIMEVAL 3 #define INTERNAL_READFD_TIMEVAL 1 #define INTERNAL_CONNECT_TIMEVAL 5 #define INTERNAL_SESSION_MT_TIMEVAL 20 #define SESSION_MT_RECEIVE_ERR 0 #define SESSION_MT_RECEIVE_TIMEOUT 1 #define SESSION_MT_RECEIVE_SUCCESS 2 typedef struct msg_hash{ int key; Octstr* content; } msg_hash; typedef struct sema_msg{ unsigned char type; /*1 byte */ unsigned char continuebyte; /* 1 byte */ unsigned char optref[4]; /*4 byte int */ int encodetype; /* 1 byte ,0 is IA5, 1 is hex, 2 is bin */ time_t logtime; void *msgbody; /* the actual message structure */ struct sema_msg *prev, *next; } sema_msg; typedef struct sema_msglist{ int count; sema_msg* first; sema_msg* last; }sema_msglist; typedef struct sm_statusreport_result{ unsigned int smeresult; /*see spec*/ }sm_statusreport_result; typedef struct sm_statusreport_invoke{ unsigned int msisdnlen; /*1 byte*/ Octstr* msisdn; /* string */ unsigned int smetype; /* 1byte, 0-sme, 1-smsc */ unsigned char smerefnum[4]; /* 4 byte integer */ unsigned char smscrefnum[4]; /* 4 byte int */ char accepttime[14]; /*absolute format*/ unsigned int status; char completetime[14]; /*absolute format*/ char intermediatime[14]; /*absolute format*/ unsigned int failreason; /*see spec*/ unsigned int origaddlen; /*1 byte;*/ Octstr* origadd; /*1 byte; */ char invoketime[14]; /*absolute format */ }sm_statusreport_invoke; typedef struct sm_submit_result{ unsigned int smeresult; /*0- ok, 1-reject for rg problem, 2-db is full or db crash 3-fail for smsc busy, 4- sm is not in db. 5- fail for already there(smsc ref or {sme ref, msdnid */ unsigned char smscrefnum[4]; /* 4 byte int*/ char accepttime[14]; /*YYMMDDHHMMSSZZ*/ } sm_submit_result; typedef struct sm_submit_invoke{ unsigned int msisdnlen; /*1 byte*/ Octstr* msisdn; /* string */ unsigned int smereftype; /* 1btype 1 key, 0 not key */ unsigned char smerefnum[4]; /* 4 byte integer */ unsigned int priority; /* 1 byte, 0 means high, 2normal */ unsigned int origaddlen; /* 1 byte; */ Octstr* origadd; /* in X25 it will b overwritten by NUA, if user login, it will home NUA */ unsigned int validperiodtype; /* 0-none, 1-absolute, 2-relative */ char validperiodabs[14]; unsigned int validperiodrela; /*1 byte ,usage see sema spec.*/ unsigned int DCS; /* 1 byte */ unsigned int statusreportrequest; /* 1 byte, 0-failed(abondon), 1-expire, 2-delivered, 3-delete by sme, 4-delete by smsc operator 5 retry*/ unsigned int protocal; /*1 byte */ unsigned int replypath; /* 0 mean can not use sender smsc, 1 means can*/ unsigned int textsizeseptet; /*1byte, in gsm format, it's 7 bits*/ unsigned int textsizeoctect; /* 1 byte in 8 bits */ Octstr* shortmsg; unsigned char smscrefnum[4]; }sm_submit_invoke; typedef struct sm_deliver_result{ /* if ok, must return */ unsigned int smeresult; /* 0- ok, 1-reject for rg problem, 2-db is full or db crash*/ } sm_deliver_result; typedef struct sm_deliver_invoke{ unsigned int destaddlen; /*1 byte*/ Octstr* destadd; /*string*/ unsigned char smscrefnum[4]; /*4 byte integer*/ unsigned int origaddlen; /*1 byte*/ Octstr* origadd; /* note, in X25 it will b overwritten by NUA, if user login, it will home NUA*/ unsigned int DCS; /*1 byte*/ unsigned int protocal; /*1 byte*/ unsigned int replypath; /* 0 mean can not use sender smsc, 1 means can*/ unsigned int textsizeseptet; /* 1byte, in gsm format, it's 7 bits */ unsigned int textsizeoctect; /* 1 byte in 8 bits */ Octstr* shortmsg; char accepttime[14]; char invoketime[14]; /*note in X25 sublogical number is omit*/ }sm_deliver_invoke; /********************** unimplemted msg here typedef struct sm_login_result{ unsigned int result; } sm_login_result; typedef struct sm_login{ unsigned int homenualen; Octstr* homenua; unsigned char pim[2]; unsigned int result; } sm_login; typedef struct sm_delete_invoke_result{ unsigned int result; } sm_delete_invoke_result; typedef struct sm_delete_invoke{ unsigned int smtype; unsigned char smscrefnum[4]; unsigned char smerefnum[4]; unsigned int msisdnlen; Octstr* msisdn; unsigned int origaddlen; Octstr* origadd; }sm_delete_invoke; typedef struct sm_deleteall_invoke{ unsigned int msisdnlen; Octstr* msisdn; unsigned int origaddlen; Octstr* origadd; unsigned int nostatusreport; }sm_deleteall_invoke; typedef struct sm_replace_result{ unsigned int delete_result; unsigned int add_result; unsigned char smscrefnum[4]; char accepttime[14]; } sm_replace_result; typedef struct sm_replace_invoke{ unsigned int smtype; unsigned char smscrefnum[4]; unsigned char smerefnum[4]; unsigned int msisdnlen; Octstr* msisdn; unsigned int new_smereftype; unsigned char new_smerefnum[4]; unsigned int new_priority; unsigned int new_origaddlen; Octstr* new_origadd; unsigned int new_validperiodtype; unsigned char new_validperiodabs[14]; unsigned int new_validperiodrela; unsigned int new_DCS; unsigned int new_statusreportrequest; unsigned int new_protocal; unsigned int new_replypath; unsigned int new_textsizechar; unsigned int new_textsizebyte; Octstr* new_shortmsg; }sm_replace_invoke; typedef struct 2K_ENQUIRE_INVOKE{ int smtype; int smscrefnum; int smerefnum; int msisdnlen; Octstrr* msisdn; int origaddlen; Octstr* origadd; int enquiretype; }sm_enqire_invoke; typedef struct 2K_ENQUIRE_RESULT{ int result; int enquiretype; int status; char[15] completetime; int failreason; int priority; int origaddlen; char* origadd; char[15] accepttime; char[15] exipretime; int DCS; int statusreportrequest; int protocalid; int replypath; int textsizechar; int textsizebyte; char* shortmsg; }sm_enqire_result; other msg type ...****************************** */ /* function definition */ static int sema_submit_result(SMSCenter*, sema_msg*, int); static int X28_open_data_link(char*); static int X28_reopen_data_link(int,char*); static int X28_close_send_link(int); static int X28_open_send_link(int,char*); static int X28_data_read(int, char*); static int X28_data_send(int, char*, int); static int X28_msg_pop(char *, char *); static int sema_msg_session_mt(SMSCenter*, sema_msg*); static int sema_msg_session_mo(SMSCenter*, char*); static sema_msg* sema_msg_new(void); static int sema_msg_free(sema_msg *msg); static sema_msglist* sema_msglist_new(void); static void sema_msglist_free(sema_msglist*); static int sema_msglist_push(sema_msglist*, sema_msg*); static int sema_msglist_pop(sema_msglist*, sema_msg**); /* static int sema_msgbuffer_pop(Octstr *, Octstr **); */ static int sema_decode_msg(sema_msg**, char*); static int sema_encode_msg(sema_msg*, char*); static int line_append_hex_IA5(Octstr* , unsigned char*, int); static int line_scan_IA5_hex(char*, int, unsigned char*); static int line_scan_hex_GSM7(unsigned char*,int,int,unsigned char*); static int internal_char_IA5_to_hex(char *, unsigned char *); static int internal_char_hex_to_IA5(unsigned char, unsigned char *); static unsigned char internal_char_hex_to_gsm(unsigned char from); static int unpack_continous_byte(unsigned char, int *, int * , int *); static unsigned char pack_continous_byte(int, int, int); static void increment_counter(void); #endif gateway-1.4.5/gw/smsc/smsc_cgw.c0000644000175000017500000011313213227613126015223 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_cgw.c - Implements an interface to the Sonera ContentGateway software * * Anders Lindh, FlyerOne Ltd * * * Changelog: * * 22/02/2002: Preliminary support for the Euro character (req. ProviderServer 2.5.2) * 25/01/2002: Caught a potentially nasty bug * 16/01/2002: Some code cleanup * 10/01/2002: Fixed a bug in trn handling * 16/11/2001: Some minor fixes (Thanks to Tuomas Luttinen) * 12/11/2001: Delivery reports, better acking and numerous other small fixes * 05/11/2001: Initial release. Based heavily on smsc_emi2 and smsc_at2. * * * TO-DO: Do some real life testing * Squash bugs * * Usage: add the following to kannel.conf: * * group = smsc * smsc = cgw * host = x.x.x.x <- CGW server host * port = xxxx <- CGW server otp port (if omitted, defaults to 21772) * receive-port = xxxx <- our port for incoming messages * appname = xxxx <- Name of a "Send only" service. Defaults to "send". * All outgoing messages are routed through this service. * * Configure ContentGateway software to use the above port as text-port * (in provider.cnf). This is documented in their "Guide for Service * development 2.5", page 80. * * Add a new "Receive only" service (with the Remote Control tool), and set * the "Application for Incoming Message" to "text://kannelhost:receive-port". * * * Note: * * Do NOT define the service as a "Query/Reply" service, as it expects response * messages to have a matching session-id tag. Kannel does not store the * relation between a query and a reply, so the response message will not have * the session-id tag. Even though the messages are delivered successfully, * billing of premium priced services will fail. * * */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "msg.h" #include "sms.h" #include "dlr.h" #define CGW_DEFPORT 21772 #define CGW_EOL 0x0A #define CGW_TRN_MAX 500 /* Size of our internal message buffer. */ #define CGWOP_MAXARGS 10 /* max. number of name:value pairs in cgwop */ /* Valid CGW operations */ #define CGW_OP_NOP 0 /* this doesn't really exist.. */ #define CGW_OP_MSG 1 #define CGW_OP_OK 2 #define CGW_OP_ERR 3 #define CGW_OP_DELIVERY 4 #define CGW_OP_HELLO 5 #define CGW_OP_STATUS 6 struct cgwop { int op; /* one of above */ int num_fields; int trn; /* transaction number, used to ACK messages */ Octstr **name; /* for storing name/value pairs */ Octstr **value; }; static char *cgw_ops[6] = {"nop", "msg", "ok", "err", "delivery", "hello"}; typedef struct privdata { List *outgoing_queue; long receiver_thread; long sender_thread; int shutdown; /* Internal signal to shut down */ int listening_socket; /* File descriptor */ int send_socket; int port; /* SMSC port */ int rport; /* port for receiving messages*/ int our_port; /* Optional local port number in which to * bind our end of send connection */ Octstr *host; Octstr *allow_ip, *deny_ip; Octstr *appname; /* Application name as defined in Sonera Remote manager */ Msg *sendmsg[CGW_TRN_MAX]; time_t sendtime[CGW_TRN_MAX]; int dlr[CGW_TRN_MAX]; /* dlr = DLR_SMSC_SUCCESS || DLR_SMSC_FAIL */ int unacked; /* Sent messages not acked */ int waitack; /* Seconds to wait to ack */ int nexttrn; long check_time; /* last checked ack/nack status */ } PrivData; static int cgw_add_msg_cb(SMSCConn *conn, Msg *sms); static int cgw_shutdown_cb(SMSCConn *conn, int finish_sending); static void cgw_start_cb(SMSCConn *conn); static long cgw_queued_cb(SMSCConn *conn); static void cgw_sender(void *arg); static Connection *cgw_open_send_connection(SMSCConn *conn); static int cgw_send_loop(SMSCConn *conn, Connection *server); void cgw_check_acks(PrivData *privdata); int cgw_wait_command(PrivData *privdata, SMSCConn *conn, Connection *server, int timeout); static int cgw_open_listening_socket(SMSCConn *conn, PrivData *privdata); static void cgw_listener(void *arg); static void cgw_receiver(SMSCConn *conn, Connection *server); static int cgw_handle_op(SMSCConn *conn, Connection *server, struct cgwop *cgwop); struct cgwop *cgw_read_op(PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout); /****************************************************************************** * Functions for handling cgwop -structures */ static void cgwop_add(struct cgwop *cgwop, Octstr *name, Octstr *value) { if (cgwop->num_fields < CGWOP_MAXARGS) { cgwop->name[cgwop->num_fields] = octstr_duplicate(name); cgwop->value[cgwop->num_fields] = octstr_duplicate(value); cgwop->num_fields++; } else { info(0, "cgw: CGWOP_MAXARGS exceeded."); } } static struct cgwop *cgwop_create(int op, int trn) { struct cgwop *ret; Octstr *trnstr; ret = gw_malloc(sizeof(struct cgwop)); ret->op = op; ret->num_fields = 0; ret->trn = trn; ret->name = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *)); ret->value = gw_malloc(CGWOP_MAXARGS * sizeof(Octstr *)); if (trn != -1) { trnstr = octstr_create(""); octstr_append_decimal(trnstr, trn); cgwop_add(ret, octstr_imm("client-id"), trnstr); octstr_destroy(trnstr); } return ret; } static void cgwop_destroy(struct cgwop *cgwop) { int len; len = cgwop->num_fields; while (--len >= 0) { octstr_destroy(cgwop->name[len]); /* octstr_destroy(NULL) is ok */ octstr_destroy(cgwop->value[len]); } gw_free(cgwop->name); gw_free(cgwop->value); gw_free(cgwop); } static Octstr *cgwop_get(struct cgwop *cgwop, Octstr *name) { int len = cgwop->num_fields; while (--len >= 0) if (octstr_compare(name, cgwop->name[len]) == 0) return cgwop->value[len]; return NULL; } static Octstr *cgwop_tostr(struct cgwop *cgwop) { int len = cgwop->num_fields; Octstr *str; if (cgw_ops[cgwop->op] == NULL) return NULL; /* invalid operation */ str = octstr_create(""); octstr_append(str, octstr_imm("op:")); octstr_append(str, octstr_imm(cgw_ops[cgwop->op])); octstr_append_char(str, CGW_EOL); while (--len >= 0) { octstr_append(str, cgwop->name[len]); octstr_append_char(str, ':'); octstr_append(str, cgwop->value[len]); octstr_append_char(str, CGW_EOL); } octstr_append(str, octstr_imm("end:")); octstr_append(str, octstr_imm(cgw_ops[cgwop->op])); octstr_append_char(str, CGW_EOL); return str; } static int cgwop_send(Connection *conn, struct cgwop *cgwop) { Octstr *dta = cgwop_tostr(cgwop); if (dta == NULL) return -1; /* couldn't convert to string */ if (conn_write(conn, dta) == -1) { octstr_destroy(dta); return -1; } octstr_destroy(dta); return 1; } /****************************************************************************** * cgw_encode_msg - Encode a msg according to specifications */ static Octstr *cgw_encode_msg(Octstr* str) { int i; char esc = 27; char e = 'e'; /* Euro char (0x80) -> ESC + e. We do this conversion as long as the message length is under 160 chars (the checking could probably be done better) */ while ((i = octstr_search_char(str, 0x80, 0)) != -1) { octstr_delete(str, i, 1); /* delete Euro char */ if (octstr_len(str) < 160) { octstr_insert_data(str, i, &esc, 1); /* replace with ESC + e */ octstr_insert_data(str, i+1, &e, 1); } else { octstr_insert_data(str, i, &e, 1); /* no room for ESC + e, just replace with an e */ } } /* Escape backslash characters */ while ((i = octstr_search_char(str, '\\', 0)) != -1) { octstr_insert(str, octstr_imm("\\"), i); } /* Remove Line Feed characters */ while ((i = octstr_search_char(str, CGW_EOL, 0)) != -1) { octstr_delete(str, i, 1); /* delete EOL char */ octstr_insert(str, octstr_imm("\\n"), i); } /* Remove Carriage return characters */ while ((i = octstr_search_char(str, 13, 0)) != -1) { octstr_delete(str, i, 1); /* delete EOL char */ octstr_insert(str, octstr_imm("\\r"), i); } return str; } /****************************************************************************** * cgw_decode_msg - Decode an incoming msg */ static Octstr *cgw_decode_msg(Octstr* str) { int i; /* make \n -> linefeed */ while ((i = octstr_search(str, octstr_imm("\\n"), 0)) != -1) { octstr_delete(str, i, 2); /* delete "\n" str */ octstr_insert(str, octstr_imm("\n"), i); } /* make \r -> carriage return */ while ((i = octstr_search(str, octstr_imm("\\r"), 0)) != -1) { octstr_delete(str, i, 2); /* delete EOL char */ octstr_insert(str, octstr_imm("\r"), i); } /* remove double backslashes */ while ((i = octstr_search(str, octstr_imm("\\\\"), 0)) != -1) { octstr_delete(str, i, 1); } return str; } /****************************************************************************** * msg_to_cgwop - Create a send cgwop from a message */ static struct cgwop *msg_to_cgwop(PrivData *privdata, Msg *msg, int trn) { struct cgwop *cgwop; Octstr *sender, *udh, *dta; cgwop = cgwop_create(CGW_OP_MSG, trn); if (cgwop == NULL) return NULL; if (!octstr_check_range(msg->sms.sender, 0, octstr_len(msg->sms.sender), gw_isdigit)) { /* If alphanumeric, simply prefix sender with '$' char */ sender = octstr_create("$"); octstr_append(sender, msg->sms.sender); } else sender = octstr_duplicate(msg->sms.sender); cgwop_add(cgwop, octstr_imm("app"), privdata->appname); cgwop_add(cgwop, octstr_imm("from"), sender); cgwop_add(cgwop, octstr_imm("to"), msg->sms.receiver); /* If delivery reports are asked, ask for them by adding a nrq:anything field */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) cgwop_add(cgwop, octstr_imm("nrq"), octstr_imm("true")); octstr_destroy(sender); if (octstr_len(msg->sms.udhdata)) { udh = octstr_duplicate(msg->sms.udhdata); octstr_binary_to_hex(udh, 1); cgwop_add(cgwop, octstr_imm("udh"), udh); octstr_destroy(udh); dta = octstr_duplicate(msg->sms.msgdata); octstr_binary_to_hex(dta, 1); cgwop_add(cgwop, octstr_imm("msg"), dta); cgwop_add(cgwop, octstr_imm("type"), octstr_imm("bin")); octstr_destroy(dta); } else { cgwop_add(cgwop, octstr_imm("msg"), cgw_encode_msg(msg->sms.msgdata)); } return cgwop; } /****************************************************************************** * Called to create the SMSC. This is our entry point. */ int smsc_cgw_create(SMSCConn *conn, CfgGroup *cfg) { PrivData *privdata; Octstr *allow_ip, *deny_ip, *host, *appname; long portno, our_port, waitack; int i; privdata = gw_malloc(sizeof(PrivData)); privdata->outgoing_queue = gwlist_create(); privdata->listening_socket = -1; if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) portno = 0; privdata->port = portno; if (cfg_get_integer(&portno, cfg, octstr_imm("receive-port")) < 0) portno = 0; privdata->rport = portno; host = cfg_get(cfg, octstr_imm("host")); appname = cfg_get(cfg, octstr_imm("appname")); if (cfg_get_integer(&our_port, cfg, octstr_imm("our-port")) == -1) privdata->our_port = 0; /* 0 means use any port */ else privdata->our_port = our_port; allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip")); if (allow_ip) deny_ip = octstr_create("*.*.*.*"); else deny_ip = NULL; if (cfg_get_integer(&waitack, cfg, octstr_imm("wait-ack")) < 0) privdata->waitack = 60; else privdata->waitack = waitack; if (privdata->port <= 0 || privdata->port > 65535) { info(1, "No port defined for cgw -> using default (%d)", CGW_DEFPORT); privdata->port = CGW_DEFPORT; } if (host == NULL) { error(0, "'host' missing in cgw configuration."); goto error; } if (appname == NULL) appname = octstr_create("send"); privdata->allow_ip = allow_ip; privdata->deny_ip = deny_ip; privdata->host = host; privdata->appname = appname; privdata->nexttrn = 0; privdata->check_time = 0; for (i = 0; i < CGW_TRN_MAX; i++) { privdata->sendtime[i] = 0; privdata->dlr[i] = 0; } if (privdata->rport > 0 && cgw_open_listening_socket(conn,privdata) < 0) { gw_free(privdata); privdata = NULL; goto error; } conn->data = privdata; conn->name = octstr_format("CGW:%d", privdata->port); privdata->shutdown = 0; conn->status = SMSCCONN_CONNECTING; conn->connect_time = time(NULL); if (privdata->rport > 0 && (privdata->receiver_thread = gwthread_create(cgw_listener, conn)) == -1) goto error; if ((privdata->sender_thread = gwthread_create(cgw_sender, conn)) == -1) { privdata->shutdown = 1; goto error; } conn->shutdown = cgw_shutdown_cb; conn->queued = cgw_queued_cb; conn->start_conn = cgw_start_cb; conn->send_msg = cgw_add_msg_cb; return 0; error: error(0, "Failed to create CGW smsc connection"); if (privdata != NULL) gwlist_destroy(privdata->outgoing_queue, NULL); gw_free(privdata); octstr_destroy(host); octstr_destroy(allow_ip); octstr_destroy(deny_ip); octstr_destroy(appname); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; info(0, "exiting"); return -1; } /****************************************************************************** * Callbacks for startup, shutdown, incoming and outgoing messages */ static int cgw_add_msg_cb(SMSCConn *conn, Msg *sms) { PrivData *privdata = conn->data; Msg *copy; copy = msg_duplicate(sms); gwlist_produce(privdata->outgoing_queue, copy); gwthread_wakeup(privdata->sender_thread); return 0; } static int cgw_shutdown_cb(SMSCConn *conn, int finish_sending) { PrivData *privdata = conn->data; debug("bb.sms", 0, "Shutting down SMSCConn CGW, %s", finish_sending ? "slow" : "instant"); /* Documentation claims this would have been done by smscconn.c, but isn't when this code is being written. */ conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; privdata->shutdown = 1; /* Separate from why_killed to avoid locking, as * why_killed may be changed from outside? */ if (finish_sending == 0) { Msg *msg; while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } } if (privdata->rport > 0) gwthread_wakeup(privdata->receiver_thread); return 0; } static void cgw_start_cb(SMSCConn *conn) { PrivData *privdata = conn->data; /* in case there are messages in the buffer already */ if (privdata->rport > 0) gwthread_wakeup(privdata->receiver_thread); debug("smsc.cgw", 0, "smsc_cgw: start called"); } static long cgw_queued_cb(SMSCConn *conn) { PrivData *privdata = conn->data; long ret = gwlist_len(privdata->outgoing_queue); /* use internal queue as load, maybe something else later */ conn->load = ret; return ret; } /****************************************************************************** * This is the entry point for out sender thread. This function is responsible * for sending and acking messages in queue */ static void cgw_sender(void *arg) { SMSCConn *conn = arg; PrivData *privdata = conn->data; Msg *msg = NULL; Connection *server = NULL; int l = 0; int ret = 0; conn->status = SMSCCONN_CONNECTING; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (!privdata->shutdown) { /* check that connection is active */ if (conn->status != SMSCCONN_ACTIVE) { if ((server = cgw_open_send_connection(conn)) == NULL) { privdata->shutdown = 1; error(0, "Unable to connect to CGW server"); return ; } conn->status = SMSCCONN_ACTIVE; bb_smscconn_connected(conn); } else { ret = 0; l = gwlist_len(privdata->outgoing_queue); if (l > 0) ret = cgw_send_loop(conn, server); /* send any messages in queue */ if (ret != -1) ret = cgw_wait_command(privdata, conn, server, 1); /* read ack's and delivery reports */ if (ret != -1) cgw_check_acks(privdata); /* check un-acked messages */ if (ret == -1) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); } } } conn_destroy(server); while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; gwlist_destroy(privdata->outgoing_queue, NULL); octstr_destroy(privdata->host); octstr_destroy(privdata->allow_ip); octstr_destroy(privdata->deny_ip); gw_free(privdata); conn->data = NULL; mutex_unlock(conn->flow_mutex); debug("bb.sms", 0, "smsc_cgw connection has completed shutdown."); bb_smscconn_killed(); } static Connection *cgw_open_send_connection(SMSCConn *conn) { PrivData *privdata = conn->data; int wait; Connection *server; Msg *msg; wait = 0; while (!privdata->shutdown) { /* Change status only if the first attempt to form a * connection fails, as it's possible that the SMSC closed the * connection because of idle timeout and a new one will be * created quickly. */ if (wait) { if (conn->status == SMSCCONN_ACTIVE) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); } while ((msg = gwlist_extract_first(privdata->outgoing_queue))) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); info(0, "smsc_cgw: waiting for %d minutes before trying to connect again", wait); gwthread_sleep(wait * 60); wait = wait > 5 ? 10 : wait * 2; } else wait = 1; server = conn_open_tcp_with_port(privdata->host, privdata->port, privdata->our_port, conn->our_host); if (privdata->shutdown) { conn_destroy(server); return NULL; } if (server == NULL) { error(0, "smsc_cgw: opening TCP connection to %s failed", octstr_get_cstr(privdata->host)); continue; } if (conn->status != SMSCCONN_ACTIVE) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); mutex_unlock(conn->flow_mutex); bb_smscconn_connected(conn); } return server; } return NULL; } /****************************************************************************** * Send messages in queue. */ static int cgw_send_loop(SMSCConn *conn, Connection *server) { PrivData *privdata = conn->data; struct cgwop *cgwop; Msg *msg; int firsttrn; /* Send messages in queue */ while ((msg = gwlist_extract_first(privdata->outgoing_queue)) != NULL) { firsttrn = privdata->nexttrn; while (privdata->sendtime[privdata->nexttrn] != 0) { if (++privdata->nexttrn >= CGW_TRN_MAX) privdata->nexttrn = 0; if (privdata->nexttrn == firsttrn) { /* no available trn */ /* this happens too many messages are sent, and old messages * haven't been acked. In this case, increase size of * CGW_TRN_MAX */ info(0, "cgw: Saturated, increase size of CGW_TRN_MAX!"); gwlist_produce(privdata->outgoing_queue, msg); return 1; /* re-insert, and go check for acks */ } } cgwop = msg_to_cgwop(privdata, msg, privdata->nexttrn); if (cgwop == NULL) { info(0, "cgw: cgwop == NULL"); return 0; } privdata->sendmsg[privdata->nexttrn] = msg; privdata->sendtime[privdata->nexttrn] = time(NULL); if (cgwop_send(server, cgwop) == -1) { cgwop_destroy(cgwop); info(0, "cgw: Unable to send (cgwop_send() == -1)"); return -1; } privdata->unacked++; cgwop_destroy(cgwop); } return 0; } /* Check whether there are messages the server hasn't acked in a * reasonable time */ void cgw_check_acks(PrivData *privdata) { time_t current_time; int i; current_time = time(NULL); if (privdata->unacked && (current_time > privdata->check_time + 30)) { privdata->check_time = current_time; for (i = 0; i < CGW_TRN_MAX; i++) if (privdata->sendtime[i] && privdata->sendtime[i] < (current_time - privdata->waitack)) { privdata->sendtime[i] = 0; privdata->unacked--; warning(0, "smsc_cgw: received neither OK nor ERR for message %d " "in %d seconds, resending message", i, privdata->waitack); gwlist_produce(privdata->outgoing_queue, privdata->sendmsg[i]); } } } /****************************************************************************** * cgw_wait_command - Used by cgw_sender thread to read delivery reports */ int cgw_wait_command(PrivData *privdata, SMSCConn *conn, Connection *server, int timeout) { int ret; struct cgwop *cgwop; /* is there data to be read? */ ret = gwthread_pollfd(privdata->send_socket, POLLIN, 0.2); if (ret != -1) { /* read all waiting ops */ cgwop = cgw_read_op(privdata, conn, server, timeout); if (cgwop != NULL) { do { if (conn_eof(server)) { info(0, "cgw: Connection closed by SMSC"); conn->status = SMSCCONN_DISCONNECTED; if (cgwop != NULL) cgwop_destroy(cgwop); return -1; } if (conn_error(server)) { error(0, "cgw: Error trying to read ACKs from SMSC"); if (cgwop != NULL) cgwop_destroy(cgwop); return -1; } cgw_handle_op(conn, server, cgwop); cgwop_destroy(cgwop); } while ((cgwop = cgw_read_op(privdata, conn, server, timeout)) != NULL); } else conn_wait(server, 1); /* added because gwthread_pollfd seems to always return 1. This will keep the load on a reasonable level */ } return 0; } /****************************************************************************** * cgw_read_op - read an operation, and return it as a *cgwop structure * * This function will not lock and wait for data if none is available. It will * however lock until a whole op has been read. Timeout not implemented yet. */ struct cgwop *cgw_read_op(PrivData *privdata, SMSCConn *conn, Connection *server, time_t timeout) { Octstr *line, *name, *value; int finished = 0; int c = 0; struct cgwop *cgwop = NULL; int op = CGW_OP_NOP; if ((line = conn_read_line(server)) == NULL) return NULL; /* don't block */ do { while (line == NULL) line = conn_read_line(server); /* wait for more data */ c = octstr_search_char(line, ':', 0); if (c != -1) { name = octstr_copy(line, 0, c); value = octstr_copy(line, c + 1, octstr_len(line) - (c + 1)); if (octstr_compare(name, octstr_imm("hello")) == 0) { /* A connection is started by CGW by sending a * "hello: Provider Server..." line. */ cgwop = cgwop_create(CGW_OP_HELLO, 0); cgwop_add(cgwop, octstr_imm("hello"), value); octstr_destroy(name); octstr_destroy(value); octstr_destroy(line); return cgwop; } if (octstr_compare(name, octstr_imm("op")) == 0) { /* check different ops */ if (octstr_compare(value, octstr_imm("msg")) == 0) op = CGW_OP_MSG; else if (octstr_compare(value, octstr_imm("ok")) == 0) op = CGW_OP_OK; else if (octstr_compare(value, octstr_imm("delivery")) == 0) op = CGW_OP_DELIVERY; else if (octstr_compare(value, octstr_imm("err")) == 0) op = CGW_OP_ERR; else if (octstr_compare(value, octstr_imm("status")) == 0) op = CGW_OP_STATUS; else info(0, "CGW: Received unknown op: %s", octstr_get_cstr(value)); if (cgwop == NULL) cgwop = cgwop_create(op, 0); else info(0, "cgw: cgwop != null"); } if (op != CGW_OP_NOP) { /* All commands have to be inside an op:xx ... end:xx statement */ if (octstr_compare(name, octstr_imm("end")) == 0) { /* found end of op */ finished = 1; } else { /* store in name/value fields in cgwop */ if (cgwop != NULL) { cgwop_add(cgwop, name, value); } } } octstr_destroy(name); octstr_destroy(value); octstr_destroy(line); if (!finished) line = conn_read_line(server); } else { info(0, "cgw: Received invalid input: %s", octstr_get_cstr(line)); octstr_destroy(line); finished = 1; } } while (!finished); return cgwop; } static int cgw_open_listening_socket(SMSCConn *conn, PrivData *privdata) { int s; if ((s = make_server_socket(privdata->rport, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL))) == -1) { error(0, "smsc_cgw: could not create listening socket in port %d", privdata->rport); return -1; } if (socket_set_blocking(s, 0) == -1) { error(0, "smsc_cgw: couldn't make listening socket port %d non-blocking", privdata->rport); close(s); return -1; } privdata->listening_socket = s; return 0; } /****************************************************************************** * This is the entry point for our receiver thread. Listens for incoming * connections and handles operations. */ static void cgw_listener(void *arg) { SMSCConn *conn = arg; PrivData *privdata = conn->data; struct sockaddr_in server_addr; socklen_t server_addr_len; Octstr *ip; Connection *server; int s, ret; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (!privdata->shutdown) { server_addr_len = sizeof(server_addr); ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1); if (ret == -1) { if (errno == EINTR) continue; error(0, "Poll for cgw smsc connections failed, shutting down"); break; } if (privdata->shutdown) break; if (ret == 0) /* This thread was woken up from elsewhere, but * if we're not shutting down nothing to do here. */ continue; s = accept(privdata->listening_socket, (struct sockaddr *) & server_addr, &server_addr_len); if (s == -1) { warning(errno, "cgw_listener: accept() failed, retrying..."); continue; } ip = host_ip(server_addr); if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) { info(0, "CGW smsc connection tried from denied host <%s>, disconnected", octstr_get_cstr(ip)); octstr_destroy(ip); close(s); continue; } server = conn_wrap_fd(s, 0); if (server == NULL) { error(0, "cgw_listener: conn_wrap_fd failed on accept()ed fd"); octstr_destroy(ip); close(s); continue; } conn_claim(server); info(0, "cgw: smsc connected from %s", octstr_get_cstr(ip)); octstr_destroy(ip); cgw_receiver(conn, server); conn_destroy(server); } if (close(privdata->listening_socket) == -1) warning(errno, "smsc_cgw: couldn't close listening socket at shutdown"); gwthread_wakeup(privdata->sender_thread); } static void cgw_receiver(SMSCConn *conn, Connection *server) { PrivData *privdata = conn->data; struct cgwop *cgwop; while (1) { if (conn_eof(server)) { info(0, "cgw: receive connection closed by SMSC"); return ; } if (conn_error(server)) { error(0, "cgw: receive connection broken"); return ; } cgwop = cgw_read_op(conn->data, conn, server, 0); if (cgwop != NULL) { cgw_handle_op(conn, server, cgwop); cgwop_destroy(cgwop); } else conn_wait(server, -1); if (privdata->shutdown) break; } return ; } /****************************************************************************** * This function handles incoming operations. Used by both receiver and sender * threads (i.e. sender thread uses this function for delivery and ack * operations). * Returns 1 if successfull, otherwise 0 */ static int cgw_handle_op(SMSCConn *conn, Connection *server, struct cgwop *cgwop) { PrivData *privdata = conn->data; Msg *msg = NULL; Octstr *from, *sid, *to, *msgdata; /* for messages */ Octstr *msid, *status, *txt; /* delivery reports */ Octstr *clid; /* for acks */ struct cgwop *reply = NULL; long trn, stat; /* transaction number for ack */ Msg *dlrmsg = NULL, *origmsg = NULL; Octstr *ts; if (cgwop == NULL) return 0; from = cgwop_get(cgwop, octstr_imm("from")); sid = cgwop_get(cgwop, octstr_imm("session-id")); to = cgwop_get(cgwop, octstr_imm("to")); msgdata = cgwop_get(cgwop, octstr_imm("msg")); txt = cgwop_get(cgwop, octstr_imm("txt")); msid = cgwop_get(cgwop, octstr_imm("msid")); status = cgwop_get(cgwop, octstr_imm("status")); clid = cgwop_get(cgwop, octstr_imm("client-id")); if (clid != NULL) { octstr_parse_long(&trn, clid, 0, 10); if ((trn < 0) || (trn >= CGW_TRN_MAX)) { /* invalid transaction number */ info(0, "cgw: Invalid transaction number: %d", (int) trn); trn = -1; return 0; } } switch (cgwop->op) { case CGW_OP_MSG: msg = msg_create(sms); time(&msg->sms.time); msg->sms.msgdata = cgw_decode_msg(octstr_duplicate(msgdata)); msg->sms.sender = octstr_duplicate(from); msg->sms.receiver = octstr_duplicate(to); msg->sms.smsc_id = octstr_duplicate(conn->id); bb_smscconn_receive(conn, msg); reply = cgwop_create(CGW_OP_OK, -1); cgwop_add(reply, octstr_imm("session-id"), sid); cgwop_send(server, reply); /* send reply */ cgwop_destroy(reply); break; case CGW_OP_DELIVERY: if (privdata->dlr[trn]) { octstr_parse_long(&stat, status, 0, 10); origmsg = privdata->sendmsg[trn]; if (origmsg == NULL) break; ts = octstr_create(""); octstr_append(ts, conn->id); octstr_append_char(ts, '-'); octstr_append_decimal(ts, trn); switch (stat) { case 0: /* delivered */ dlrmsg = dlr_find(conn->id, ts, /* timestamp */ msid, /* destination */ DLR_SUCCESS, 0); break; case 1: /* buffered */ dlrmsg = dlr_find(conn->id, ts, /* timestamp */ msid, /* destination */ DLR_BUFFERED, 0); break; case 2: /* not delivered */ dlrmsg = dlr_find(conn->id, ts, /* timestamp */ msid, /* destination */ DLR_FAIL, 0); break; } octstr_destroy(ts); if (dlrmsg != NULL) { dlrmsg->sms.msgdata = octstr_duplicate(txt); bb_smscconn_receive(conn, dlrmsg); } } break; case CGW_OP_OK: if (trn == -1) break; /* invalid transaction number */ /* info(0, "cgw: Got ACK: %s", octstr_get_cstr(clid)); */ privdata->sendtime[trn] = 0; privdata->unacked--; /* add delivery notification request if wanted */ msg = privdata->sendmsg[trn]; if (msg && msg->sms.dlr_url && DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) { Octstr *ts; ts = octstr_create(""); octstr_append(ts, conn->id); octstr_append_char(ts, '-'); octstr_append_decimal(ts, trn); dlr_add(conn->id, ts, msg, 0); octstr_destroy(ts); privdata->dlr[trn] = 1; } else { privdata->dlr[trn] = 0; } /* mark as successfully sent */ bb_smscconn_sent(conn, msg, NULL); break; case CGW_OP_STATUS: info(0, "CGW: Warning: Got session status"); /* op:status messages are sent by ProviderServer to tell if there are problems with the session status. These are not wanted, and should never occur, as the delivery is cancelled, and no end-user billing is done. */ break; case CGW_OP_HELLO: info(0, "CGW: Server said: %s", octstr_get_cstr(cgwop_get(cgwop, octstr_imm("hello")))); break; case CGW_OP_ERR: if (trn == -1) break; /* invalid transaction number */ info(0, "CGW: Received error: %s", octstr_get_cstr(txt)); privdata->sendtime[trn] = 0; privdata->unacked--; bb_smscconn_send_failed(conn, privdata->sendmsg[trn], SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED")); break; default: info(0, "cgw: Unknown operation: %d", cgwop->op); return 0; } return 1; } gateway-1.4.5/gw/smsc/smsc_soap_parlayx.c0000644000175000017500000011042013227613126017142 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_soap_parlayx.c - Kannel SMSC module for ParlayX 2.1 * * Stipe Tolj */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "msg.h" #include "sms.h" #include "dlr.h" #include "urltrans.h" #ifdef HAVE_GSOAP #include "soapH.h" #include "SendSmsBinding.nsmap" #include "wsseapi.h" /* * Define DEBUG macro to also activate the DLR sending * thread, which allows us to self-inject DLRs. */ #undef DEBUG #define DEBUG 1 /* Default character encoding */ #define DEFAULT_CHARSET "UTF-8" typedef struct ConnData { HTTPCaller *http_ref; long receive_thread; long senders; /* number of concurrent sending threads */ int shutdown; int port; /* port for receiving SMS'es */ Octstr *allow_ip; Octstr *send_url; Octstr *dlr_url; long open_sends; Octstr *username; /* if needed */ Octstr *password; /* as said */ Octstr *alt_charset; /* alternative charset use */ gw_prioqueue_t *msgs_to_send; List *sender_threads; long dlr_thread; List *dlr_queue; /* callback functions */ void (*send_sms) (SMSCConn *conn, Msg *msg); void (*parse_reply) (SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body); void (*receive_sms) (SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars); void (*httpsmsc_sender) (void *arg); } ConnData; static void octstr_remove_crlfs(Octstr *ostr); static void soap_send_sms(struct soap *soap, SMSCConn *conn, Msg *sms); #ifdef DEBUG static void soap_send_dlr(struct soap *soap, SMSCConn *conn, Msg *sms); #endif /******************************************************************** * DLR state mapping * * See VMP spec v0.9, section 2.4.2, page 21 for the VMP specific * value details. */ static struct StateTable { unsigned int dlr_mask; enum pxSms__DeliveryStatus state; } state_table[] = { #define ENTRY(mask, state) { mask, state }, ENTRY(DLR_SUCCESS, pxSms__DeliveryStatus__DeliveredToTerminal) ENTRY(DLR_FAIL, pxSms__DeliveryStatus__DeliveryImpossible) ENTRY(DLR_BUFFERED, pxSms__DeliveryStatus__DeliveredToNetwork) ENTRY(DLR_SMSC_FAIL, pxSms__DeliveryStatus__DeliveryNotificationNotSupported) ENTRY(DLR_FAIL, pxSms__DeliveryStatus__DeliveryUncertain) ENTRY(DLR_BUFFERED, pxSms__DeliveryStatus__MessageWaiting) #undef ENTRY }; static int state_table_entries = sizeof(state_table) / sizeof(state_table[0]); /******************************************************************** * Internal threads */ /* * Each sender thread has it's own gSOAP IO context that is passed along * to the sending function in the consume loop. This ensures we maintain * the TCP connection, along with the HTTP/1.1 keep-alive state for the * HTTP transport layer. */ /* * The various ParlayX variants use separate thread logic that are * addressed via the corresponding function pointer callback in * conndata. * * The variants 'ericsson-sdp' and 'oneapi-v1' have the same ParlayX * SOAP XML PDUs, but differ in the authentication scheme they use, where * 'ericsson-sdp' uses WS-Security via wsse and 'oneapi-v1' uses plain * HTTP basic authentication. */ static void httpsmsc_sender_ercisson_sdp(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; Msg *msg; struct soap *soap; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* establish soap context */ soap = soap_new1(SOAP_XML_INDENT|SOAP_IO_KEEPALIVE); /* register wsse plugin */ soap_register_plugin(soap, soap_wsse); #ifdef WITH_OPENSSL /* setup the SSL context */ if (soap_ssl_client_context(soap, SOAP_SSL_NO_AUTHENTICATION, NULL, NULL, NULL, NULL, NULL)) { char buf[1024]; Octstr *os; soap_sprint_fault(soap, buf, 1024); os = octstr_create(buf); octstr_remove_crlfs(os); error(0, "SOAP[%s]: Could not assign gSOAP SSL context:", octstr_get_cstr(conn->id)); error(0, "SOAP[%s]: %s", octstr_get_cstr(conn->id), octstr_get_cstr(os)); octstr_destroy(os); goto done; } #endif /* main consume loop for the sender */ while ((msg = gw_prioqueue_consume(conndata->msgs_to_send)) != NULL) { /* message lifetime of 10 seconds */ soap_wsse_add_Timestamp(soap, "Time", 10); /* add user name with digest password */ soap_wsse_add_UsernameTokenDigest(soap, "User", octstr_get_cstr(conndata->username), octstr_get_cstr(conndata->password)); soap_send_sms(soap, conn, msg); conndata->open_sends--; /* clean up security header */ soap_wsse_delete_Security(soap); } done: /* destroy soap context */ soap_destroy(soap); soap_end(soap); soap_free(soap); } static void httpsmsc_sender_gsma_oneapi(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; Msg *msg; struct soap *soap; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* establish soap context */ soap = soap_new1(SOAP_XML_INDENT|SOAP_IO_KEEPALIVE); /* assign HTTP basic authentication tokens */ soap->userid = octstr_get_cstr(conndata->username); soap->passwd = octstr_get_cstr(conndata->password); #ifdef WITH_OPENSSL /* setup the SSL context */ if (soap_ssl_client_context(soap, SOAP_SSL_NO_AUTHENTICATION, NULL, NULL, NULL, NULL, NULL)) { char buf[1024]; Octstr *os; soap_sprint_fault(soap, buf, 1024); os = octstr_create(buf); octstr_remove_crlfs(os); error(0, "SOAP[%s]: Could not assign gSOAP SSL context:", octstr_get_cstr(conn->id)); error(0, "SOAP[%s]: %s", octstr_get_cstr(conn->id), octstr_get_cstr(os)); octstr_destroy(os); goto done; } #endif /* main consume loop for the sender */ while ((msg = gw_prioqueue_consume(conndata->msgs_to_send)) != NULL) { soap_send_sms(soap, conn, msg); conndata->open_sends--; } done: /* destroy soap context */ soap_destroy(soap); soap_end(soap); soap_free(soap); } /* * Thread to listen to HTTP requests from SMSC entity */ static void httpsmsc_receiver(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; HTTPClient *client; Octstr *ip, *url, *body; List *headers, *cgivars; ip = url = body = NULL; headers = cgivars = NULL; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (conndata->shutdown == 0) { /* XXX if conn->is_stopped, do not receive new messages.. */ client = http_accept_request(conndata->port, &ip, &url, &headers, &body, &cgivars); if (client == NULL) break; debug("smsc.soap", 0, "SOAP[%s]: Got HTTP request `%s'", octstr_get_cstr(conn->id), octstr_get_cstr(url)); if (connect_denied(conndata->allow_ip, ip)) { info(0, "SOAP[%s]: Connection `%s' tried from denied " "host %s, ignored", octstr_get_cstr(conn->id), octstr_get_cstr(url), octstr_get_cstr(ip)); http_close_client(client); } else conndata->receive_sms(conn, client, headers, body, cgivars); debug("smsc.soap", 0, "SOAP[%s]: Destroying client information", octstr_get_cstr(conn->id)); octstr_destroy(url); octstr_destroy(ip); octstr_destroy(body); http_destroy_headers(headers); http_destroy_cgiargs(cgivars); } debug("smsc.soap", 0, "SOAP[%s]: httpsmsc_receiver dying", octstr_get_cstr(conn->id)); conndata->shutdown = 1; http_close_port(conndata->port); /* unblock http_receive_result() if there are no open sends */ if (conndata->open_sends == 0) http_caller_signal_shutdown(conndata->http_ref); } #ifdef DEBUG static void dlr_sender(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; Msg *msg; struct soap *soap; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); /* establish soap context */ soap = soap_new1(SOAP_XML_INDENT|SOAP_IO_KEEPALIVE); #ifdef WITH_OPENSSL /* setup the SSL context */ if (soap_ssl_client_context(soap, SOAP_SSL_NO_AUTHENTICATION, NULL, NULL, NULL, NULL, NULL)) { char buf[1024]; Octstr *os; soap_sprint_fault(soap, buf, 1024); os = octstr_create(buf); octstr_remove_crlfs(os); error(0, "SOAP[%s]: Could not assign gSOAP SSL context:", octstr_get_cstr(conn->id)); error(0, "SOAP[%s]: %s", octstr_get_cstr(conn->id), octstr_get_cstr(os)); octstr_destroy(os); goto done; } #endif while ((msg = gwlist_consume(conndata->dlr_queue)) != NULL) { /* first we delay a bit to simulate the SMSC latency */ gwthread_sleep(1); soap_send_dlr(soap, conn, msg); msg_destroy(msg); } done: /* destroy soap context */ soap_destroy(soap); soap_end(soap); soap_free(soap); } #endif /*********************************************************************** * Helper functions */ #define octstr_cstr(os) \ (os ? octstr_get_cstr(os) : NULL) #define octstr(os) \ (os ? octstr_create(os) : NULL) static int iscrlf(unsigned char c) { return c == '\n' || c == '\r'; } static void octstr_remove_crlfs(Octstr *ostr) { int i, end; end = octstr_len(ostr); for (i = 0; i < end; i++) { if (iscrlf(octstr_get_char(ostr, i))) octstr_set_char(ostr, i, ' '); } } static void gw_free_wrapper(void *data) { gw_free(data); } /*********************************************************************** * gSOAP callbacks for internal XML transport */ typedef struct gBuffer { SMSCConn *conn; char *buffer; size_t size; size_t rlen, slen; } gBuffer; static gBuffer *gbuffer_create(SMSCConn *conn, size_t size) { gBuffer *buf; buf = gw_malloc(sizeof(gBuffer)); buf->conn = conn; buf->buffer = gw_malloc(size); buf->size = size; buf->rlen = buf->slen = 0; return buf; } static void gbuffer_destroy(gBuffer *buf) { if (buf == NULL) return; gw_free(buf->buffer); gw_free(buf); } /* * Callback function of gSOAP internals that sends response bytes * via this callback. We use it to intercept the response to the * own handled buffer. */ static int mysend(struct soap *soap, const char *s, size_t n) { gBuffer *buf = (gBuffer*) soap->user; if (buf->slen + n > buf->size) return SOAP_EOF; strcpy(buf->buffer + buf->slen, s); buf->slen += n; return SOAP_OK; } /* * Callback function of gSOAP internals to read the HTTP POST * body contents into the gSOAP processing. We inject the input * via our own mapped buffer here. */ static size_t myrecv(struct soap *soap, char *s, size_t n) { gBuffer *buf = (gBuffer*) soap->user; strncpy(s, buf->buffer + buf->rlen, n); buf->rlen += n; return n; } /* * Callback function of gSOAP's internal HTTP response headers. * We don't use them here and simply ensure that they are skipped. */ static int myheader(struct soap *soap, const char *key, const char *value) { return SOAP_OK; } /******************************************************************** * SOAP specific operations */ static void soap_send_sms(struct soap *soap, SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; struct pxSmsSend__sendSmsResponse resp; int ret; char tid[UUID_STR_LEN + 1]; Octstr *mid = NULL; Octstr *receiver; const char *receiv[1]; /* request parameters */ struct pxSmsSend__sendSms req; struct pxCommon__ChargingInformation charge; struct pxCommon__SimpleReference dlr; /* unparse our msg ID */ if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask) && !uuid_is_null(sms->sms.id)) { uuid_unparse(sms->sms.id, tid); mid = octstr_create(tid); } req.__sizeaddresses = 1; receiver = octstr_format("tel:%s", octstr_get_cstr(sms->sms.receiver)); receiv[0] = octstr_get_cstr(receiver); req.addresses = (char**)receiv; req.senderName = octstr_cstr(sms->sms.sender); req.message = octstr_get_cstr(sms->sms.msgdata); req.charging = NULL; req.receiptRequest = NULL; /* * If billing identifier is set then we will parse for the * ChargingInformation fields using the following notation: * * binfo = * * where is the delimiter character, defined as the FIRST * character of the binfo field. */ if (sms->sms.binfo) { Octstr *delim = octstr_copy(sms->sms.binfo, 0, 1); List *l = octstr_split(sms->sms.binfo, delim); if (gwlist_len(l) != 5) { error(0, "SOAP[%s]: Billing identifier <%s> has wrong format!", octstr_get_cstr(conn->id), octstr_get_cstr(sms->sms.binfo)); } else { charge.description = octstr_get_cstr(gwlist_get(l, 1)); charge.currency = octstr_get_cstr(gwlist_get(l, 2)); charge.amount = octstr_get_cstr(gwlist_get(l, 3)); charge.code = octstr_get_cstr(gwlist_get(l, 3)); req.charging = &charge; } gwlist_destroy(l, octstr_destroy_item); octstr_destroy(delim); gwlist_destroy(l, octstr_destroy_item); } /* * Define callback for DLR notification. */ if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask) && conndata->dlr_url) { dlr.endpoint = octstr_get_cstr(conndata->dlr_url); dlr.correlator = octstr_get_cstr(mid); dlr.interfaceName = NULL; req.receiptRequest = &dlr; } /* perform the SOAP call itself */ ret = soap_call___px1__sendSms( soap, octstr_get_cstr(conndata->send_url), "", &req, &resp); if (ret) { /* HTTP request failed, or any other SOAP fault raised. */ char buf[1024]; Octstr *os; soap_sprint_fault(soap, buf, 1024); os = octstr_create(buf); octstr_remove_crlfs(os); error(0, "SOAP[%s]: Sending HTTP request failed:", octstr_get_cstr(conn->id)); error(0, "SOAP[%s]: %s", octstr_get_cstr(conn->id), octstr_get_cstr(os)); /* * TODO: we may consider this also as temporary error, * or even better interpret the SOAP fault detail tags. */ bb_smscconn_send_failed(conn, sms, SMSCCONN_FAILED_MALFORMED, octstr_duplicate(os)); octstr_destroy(os); } else { /* * We got a corresponding SOAP/XML PDU response, * so this is considered a successful transaction. */ /* * The following code parts can be used to verify * for transaction time and authentication. * * They are NOT used in the ParlayX variants we * support, but we keep them here for reference * to any possible new variant. */ /* if (soap_wsse_verify_Timestamp(soap)) { error(0, "SOAP[%s]: Server response expired.", octstr_get_cstr(conn->id)); goto done; } username = soap_wsse_get_Username(soap); if (!username || octstr_str_compare(conndata->username, username) || soap_wsse_verify_Password(soap, octstr_get_cstr(conndata->password))) { error(0, "SOAP[%s]: Server authentication failed.", octstr_get_cstr(conn->id)); goto done; } */ /* * The sendSmsResponse result is defined to be a message identifier * for the transaction we did, so keep that as foreign ID. */ if (resp.result) { octstr_destroy(sms->sms.foreign_id); sms->sms.foreign_id = octstr_create(resp.result); } /* add to our own DLR storage */ if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask) && mid) { dlr_add(conn->id, mid, sms, 0); #ifdef DEBUG /* * Pass duplicate into DLR re-inject queue with the * msg ID that the SMSC gave us. * BEWARE: This works only for internal tests where * the msg ID returned is a UUID string. */ { Msg *msg = msg_duplicate(sms); uuid_clear(msg->sms.id); uuid_parse(octstr_get_cstr(mid), msg->sms.id); gwlist_produce(conndata->dlr_queue, msg); } #endif } bb_smscconn_sent(conn, sms, NULL); } octstr_destroy(mid); octstr_destroy(receiver); } static void soap_parse_reply(SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body) { if (status == HTTP_OK || status == HTTP_ACCEPTED) { /* add to our own DLR storage */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) { char id[UUID_STR_LEN + 1]; Octstr *mid; uuid_unparse(msg->sms.id, id); mid = octstr_create(id); dlr_add(conn->id, mid, msg, 0); octstr_destroy(mid); } bb_smscconn_sent(conn, msg, NULL); } else { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body)); } } static void soap_receive_sms(SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars) { List *reply_headers; struct soap *soap; gBuffer *buf; Octstr *response; /* * We expect a SOAP/XML element as POST body. If there is no * body, then return an error instantly. */ if (octstr_len(body) == 0) { http_send_reply(client, HTTP_BAD_METHOD, NULL, NULL); return; } /* dump the SOAP/XML we got */ octstr_dump(body, 0); /* move the XML into the buffer */ buf = gbuffer_create(conn, 32000); octstr_get_many_chars(buf->buffer, body, 0, octstr_len(body)); /* create gSOAP context and assign the buffer */ soap = soap_new(); soap->fsend = mysend; soap->frecv = myrecv; soap->fposthdr = myheader; soap->user = buf; /* perform the server operation */ soap_serve(soap); /* move response XML from buffer to octstr */ response = octstr_create(""); octstr_append_data(response, buf->buffer, buf->slen); /* destroy buffer */ gbuffer_destroy(buf); /* destroy context */ soap_destroy(soap); soap_end(soap); soap_free(soap); /* send the HTTP response */ reply_headers = gwlist_create(); http_header_add(reply_headers, "SOAPAction" , "\"\""); http_header_add(reply_headers, "Content-Type", "text/xml;charset=\"utf-8\""); debug("smsc.soap", 0, "SOAP[%s]: Sending HTTP response", octstr_get_cstr(conn->id)); octstr_dump(response, 0); http_send_reply(client, HTTP_OK, reply_headers, response); octstr_destroy(response); http_destroy_headers(reply_headers); } static void soap_send_sms_cb(SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; gw_prioqueue_produce(conndata->msgs_to_send, sms); } #ifdef DEBUG static void soap_send_dlr(struct soap *soap, SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; struct pxSmsNotification__notifySmsDeliveryReceiptResponse resp; int ret; char tid[UUID_STR_LEN + 1]; Octstr *mid = NULL; Octstr *receiver = octstr_format("tel:%s", sms->sms.receiver); /* request parameters */ struct pxSmsNotification__notifySmsDeliveryReceipt req; struct pxSms__DeliveryInformation deliveryStatus; /* get the message id */ if (!uuid_is_null(sms->sms.id)) { uuid_unparse(sms->sms.id, tid); mid = octstr_create(tid); } /* apply values from Kannel msg struct */ req.correlator = octstr_get_cstr(mid); deliveryStatus.address = octstr_get_cstr(receiver); deliveryStatus.deliveryStatus = pxSms__DeliveryStatus__DeliveredToTerminal; req.deliveryStatus = &deliveryStatus; /* no SOAP header set */ /* perform the SOAP call itself */ ret = soap_call___px2__notifySmsDeliveryReceipt( soap, octstr_get_cstr(conndata->send_url), "", &req, &resp); if (ret) { /* HTTP request failed */ char buf[1024]; Octstr *os; soap_sprint_fault(soap, buf, 1024); os = octstr_create(buf); octstr_remove_crlfs(os); error(0, "SOAP[%s]: Sending DLR HTTP request failed:", octstr_get_cstr(conn->id)); error(0, "SOAP[%s]: %s", octstr_get_cstr(conn->id), octstr_get_cstr(os)); octstr_destroy(os); } else { /* we got a corresponding SOAP/XML response */ debug("smsc.soap",0,"SOAP[%s] Received DLR HTTP response.", octstr_get_cstr(conn->id)); } octstr_destroy(receiver); octstr_destroy(mid); } #endif /******************************************************************** * Internal smscconn operations */ static void conndata_destroy(ConnData *conndata) { if (conndata == NULL) return; if (conndata->http_ref) http_caller_destroy(conndata->http_ref); gwlist_destroy(conndata->sender_threads, (void(*)(void *)) gw_free_wrapper); gw_prioqueue_destroy(conndata->msgs_to_send, msg_destroy_item); #ifdef DEBUG gwlist_destroy(conndata->dlr_queue, msg_destroy_item); #endif octstr_destroy(conndata->allow_ip); octstr_destroy(conndata->send_url); octstr_destroy(conndata->dlr_url); octstr_destroy(conndata->username); octstr_destroy(conndata->password); octstr_destroy(conndata->alt_charset); gw_free(conndata); } static int httpsmsc_send(SMSCConn *conn, Msg *msg) { ConnData *conndata = conn->data; Msg *sms = msg_duplicate(msg); double delay = 0; if (conn->throughput > 0) { delay = 1.0 / conn->throughput; } /* convert character encoding if required */ if (conndata->alt_charset && charset_convert(sms->sms.msgdata, DEFAULT_CHARSET, octstr_get_cstr(conndata->alt_charset)) != 0) error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.", DEFAULT_CHARSET, octstr_get_cstr(conndata->alt_charset)); conndata->open_sends++; conndata->send_sms(conn, sms); /* obey throughput speed limit, if any */ if (conn->throughput > 0) gwthread_sleep(delay); return 0; } static long httpsmsc_queued(SMSCConn *conn) { ConnData *conndata = conn->data; return (conndata ? (conn->status != SMSCCONN_DEAD ? conndata->open_sends : 0) : 0); } static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending) { ConnData *conndata = conn->data; long *id; debug("httpsmsc_shutdown", 0, "SOAP[%s]: Shutting down", octstr_get_cstr(conn->id)); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; conndata->shutdown = 1; #ifdef DEBUG /* stop DLR re-injection thread */ gwlist_remove_producer(conndata->dlr_queue); gwthread_join(conndata->dlr_thread); #endif /* stop receiver thread */ http_close_port(conndata->port); /* stop all sender threads */ gw_prioqueue_remove_producer(conndata->msgs_to_send); while ((id = gwlist_consume(conndata->sender_threads)) != NULL) { gwthread_join(*id); gw_free(id); } conn->data = NULL; conndata_destroy(conndata); conn->status = SMSCCONN_DEAD; bb_smscconn_killed(); return 0; } int smsc_soap_parlayx_create(SMSCConn *conn, CfgGroup *cfg) { ConnData *conndata = NULL; Octstr *type; long portno; /* has to be long because of cfg_get_integer */ int ssl = 0; /* indicate if SSL-enabled server should be used */ int i; if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) { error(0, "SOAP[%s]: 'port' invalid in 'smsc = parlayx' group.", octstr_get_cstr(conn->id)); return -1; } cfg_get_bool(&ssl, cfg, octstr_imm("use-ssl")); if ((type = cfg_get(cfg, octstr_imm("system-type"))) == NULL) { error(0, "SOAP[%s]: 'system-type' missing in 'smsc = parlayx' group.", octstr_get_cstr(conn->id)); octstr_destroy(type); return -1; } conndata = gw_malloc(sizeof(ConnData)); conndata->http_ref = NULL; conndata->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip")); conndata->send_url = cfg_get(cfg, octstr_imm("send-url")); conndata->dlr_url = cfg_get(cfg, octstr_imm("dlr-url")); conndata->username = cfg_get(cfg, octstr_imm("smsc-username")); conndata->password = cfg_get(cfg, octstr_imm("smsc-password")); conndata->alt_charset = cfg_get(cfg, octstr_imm("alt-charset")); if (cfg_get_integer(&(conndata->senders), cfg, octstr_imm("window")) == -1) { conndata->senders = 1; } else { info(0, "SOAP[%s]: Using %ld sender threads.", octstr_get_cstr(conn->id), conndata->senders); } if (conndata->send_url == NULL) panic(0, "SOAP[%s]: Sending not allowed. No 'send-url' specified.", octstr_get_cstr(conn->id)); if (conndata->dlr_url == NULL) warning(0, "SOAP[%s]: DLR requesting not allowed. No 'dlr-url' specified.", octstr_get_cstr(conn->id)); if (conndata->username == NULL || conndata->password == NULL) { error(0, "SOAP[%s]: 'username' and 'password' required for smsc", octstr_get_cstr(conn->id)); goto error; } if (octstr_case_compare(type, octstr_imm("ericsson-sdp")) == 0) { conndata->httpsmsc_sender = httpsmsc_sender_ercisson_sdp; } else if (octstr_case_compare(type, octstr_imm("oneapi-v1")) == 0) { conndata->httpsmsc_sender = httpsmsc_sender_gsma_oneapi; } /* * Add new ParlayX variants here */ else { error(0, "SOAP[%s]: system-type '%s' unknown in 'smsc = parlayx' group.", octstr_get_cstr(conn->id), octstr_get_cstr(type)); goto error; } #ifdef WITH_OPENSSL /* setup gSOAP SSL internals */ soap_ssl_init(); #endif /* setup MT queue */ conndata->msgs_to_send = gw_prioqueue_create(sms_priority_compare); /* assign our SOAP operations */ conndata->receive_sms = soap_receive_sms; conndata->send_sms = soap_send_sms_cb; conndata->parse_reply = soap_parse_reply; conndata->open_sends = 0; conndata->http_ref = http_caller_create(); conn->data = conndata; conn->name = octstr_create("SOAP"); conn->status = SMSCCONN_ACTIVE; conn->connect_time = time(NULL); conn->shutdown = httpsmsc_shutdown; conn->queued = httpsmsc_queued; conn->send_msg = httpsmsc_send; if (http_open_port_if(portno, ssl, conn->our_host) == -1) goto error; conndata->port = portno; conndata->shutdown = 0; /* receiver thread */ if ((conndata->receive_thread = gwthread_create(httpsmsc_receiver, conn)) == -1) goto error; #ifdef DEBUG /* DLR re-injection thread */ conndata->dlr_queue = gwlist_create(); gwlist_add_producer(conndata->dlr_queue); if ((conndata->dlr_thread = gwthread_create(dlr_sender, conn)) == -1) goto error; #else conndata->dlr_queue = NULL; conndata->dlr_thread = -1; #endif /* sender thread(s), keep record of the thread IDs in our * sender_threads list to ensure we join the right threads * at the shutdown sequence. */ conndata->sender_threads = gwlist_create(); gw_prioqueue_add_producer(conndata->msgs_to_send); for (i = 0; i < conndata->senders; i++) { long *id = gw_malloc(sizeof(long)); if ((*id = gwthread_create(conndata->httpsmsc_sender, conn)) == -1) { gw_free(id); goto error; } gwlist_produce(conndata->sender_threads, id); } info(0, "SOAP[%s]: Initiated and ready", octstr_get_cstr(conn->id)); octstr_destroy(type); return 0; error: error(0, "SOAP[%s]: Failed to create smsc connection", octstr_get_cstr(conn->id)); conn->data = NULL; conndata_destroy(conndata); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; octstr_destroy(type); return -1; } /******************************************************************** * SOAP specific methods */ /* * This operation is handled by the server side. We just implement it * here with hard-coded values to be able to test our own gSOAP sending * routines to our own HTTP end-point. */ int __px1__sendSms ( /* soap structure hook */ struct soap *soap, /* request struct */ struct pxSmsSend__sendSms *req, /* response struct */ struct pxSmsSend__sendSmsResponse *resp) { /* positive response */ resp->result = "100"; /* negative response */ /* resp->result = "300"; */ return SOAP_OK; } int __px2__notifySmsDeliveryReceipt ( /* soap structure hook */ struct soap *soap, /* request struct */ struct pxSmsNotification__notifySmsDeliveryReceipt *req, /* response struct */ struct pxSmsNotification__notifySmsDeliveryReceiptResponse *resp) { gBuffer *buf = soap->user; ConnData *conndata = buf->conn->data; Msg *dlrmsg; Octstr *id, *destination; int sm_status, state, i; destination = NULL; sm_status = -1; /* get corresponding values from the SOAP/XML request */ id = octstr(req->correlator); if (req->deliveryStatus) { destination = octstr(req->deliveryStatus->address); /* strip 'tel:' from address */ if (destination) octstr_delete_matching(destination, octstr_imm("tel:")); sm_status = req->deliveryStatus->deliveryStatus; } /* map the DLR state */ state = DLR_NOTHING; for (i = 0; sm_status != -1 && i < state_table_entries; ++i) { if (sm_status == state_table[i].state) { state = state_table[i].dlr_mask; break; } } /* resolve the DLR from the DLR temp storage */ dlrmsg = dlr_find(buf->conn->id, id, /* smsc message id */ destination, /* destination */ state, 0); if (dlrmsg != NULL) { dlrmsg->sms.sms_type = report_mo; dlrmsg->sms.account = octstr_duplicate(conndata->username); /* * There is no response values returned. */ /* passing DLR to upper layer */ bb_smscconn_receive(buf->conn, dlrmsg); } else { error(0,"SOAP[%s]: got DLR but could not find message or was not interested " "in it id<%s> dst<%s>, type<%d>", octstr_get_cstr(buf->conn->id), octstr_get_cstr(id), octstr_get_cstr(destination), state); } octstr_destroy(id); octstr_destroy(destination); return SOAP_OK; } int __px2__notifySmsReception ( /* soap structure hook */ struct soap *soap, /* request struct */ struct pxSmsNotification__notifySmsReception *req, /* response struct */ struct pxSmsNotification__notifySmsReceptionResponse *resp) { gBuffer *buf = soap->user; ConnData *conndata = buf->conn->data; Msg *msg; int ret; msg = msg_create(sms); msg->sms.sms_type = mo; msg->sms.sender = octstr(req->message->senderAddress); msg->sms.receiver = octstr(req->message->smsServiceActivationNumber); msg->sms.msgdata = octstr(req->message->message); msg->sms.foreign_id = octstr(req->correlator); msg->sms.smsc_id = octstr_duplicate(buf->conn->id); msg->sms.time = time(NULL); msg->sms.account = octstr_duplicate(conndata->username); ret = bb_smscconn_receive(buf->conn, msg); if (ret == SMSCCONN_SUCCESS) { /* no response is set */ } else { /* no response is set */ } return SOAP_OK; } /******************************************************************** * SOAP functions stubs that are not used. */ int __px1__sendSmsLogo( struct soap *soap, // request parameters: struct pxSmsSend__sendSmsLogo* pxSmsSend__sendSmsLogo, // response parameters: struct pxSmsSend__sendSmsLogoResponse* pxSmsSend__sendSmsLogoResponse ) { return SOAP_OK; } int __px1__sendSmsRingtone( struct soap *soap, // request parameters: struct pxSmsSend__sendSmsRingtone* pxSmsSend__sendSmsRingtone, // response parameters: struct pxSmsSend__sendSmsRingtoneResponse* pxSmsSend__sendSmsRingtoneResponse ) { return SOAP_OK; } int __px1__getSmsDeliveryStatus( struct soap *soap, // request parameters: struct pxSmsSend__getSmsDeliveryStatus* pxSmsSend__getSmsDeliveryStatus, // response parameters: struct pxSmsSend__getSmsDeliveryStatusResponse* pxSmsSend__getSmsDeliveryStatusResponse ) { return SOAP_OK; } int __px3__getReceivedSms( struct soap *soap, // request parameters: struct pxSmsReceive__getReceivedSms* pxSmsReceive__getReceivedSms, // response parameters: struct pxSmsReceive__getReceivedSmsResponse* pxSmsReceive__getReceivedSmsResponse ) { return SOAP_OK; } #endif /* HAVE_GSOAP */ gateway-1.4.5/gw/smsc/emimsg.c0000644000175000017500000002763613227613126014714 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * emimsg.c * * Functions for working with EMI messages * Uoti Urpala 2001 */ #include "emimsg.h" /* Return an error string corresponding to the number. */ static char *emi_strerror(int errnum) { switch (errnum) { case 1: return "Checksum error"; case 2: return "Syntax error"; case 3: return "Operation not supported by system"; case 4: return "Operation not allowed"; case 5: return "Call barring active"; case 6: return "AdC invalid"; case 7: return "Authentication failure"; case 8: return "Legitimisation code for all calls, failure"; case 9: return "GA not valid"; case 10: return "Repetition not allowed"; case 11: return "Legitimisation code for repetition, failure"; case 12: return "Priority call not allowed"; case 13: return "Legitimisation code for priority call, failure"; case 14: return "Urgent message not allowed"; case 15: return "Legitimisation code for urgent message, failure"; case 16: return "Reverse charging not allowed"; case 17: return "Legitimisation code for reverse charging, failure"; case 18: return "Deferred delivery not allowed"; case 19: return "New AC not valid"; case 20: return "New legitimisation code not valid"; case 21: return "Standard text not valid"; case 22: return "Time period not valid"; case 23: return "Message type not supported by system"; case 24: return "Message too long"; case 25: return "Requested standard text not valid"; case 26: return "Message type not valid for the pager type"; case 27: return "Message not found in smsc"; case 30: return "Subscriber hang-up"; case 31: return "Fax group not supported"; case 32: return "Fax message type not supported"; case 33: return "Address already in list (60 series)"; case 34: return "Address not in list (60 series)"; case 35: return "List full, cannot add address to list (60 series)"; case 36: return "RPID already in use"; case 37: return "Delivery in progress"; case 38: return "Message forwarded"; default: return "!UNRECOGNIZED ERROR CODE!"; } } static int field_count_op(int ot, Octstr *whoami) { switch (ot) { case 01: return SZ01; case 31: return 2; case 51: case 52: case 53: return SZ50; case 60: return SZ60; default: error(0, "EMI2[%s]: Unsupported EMI operation request type %d", octstr_get_cstr(whoami), ot); return -1; } } static int field_count_reply(int ot, int posit, Octstr *whoami) { switch(ot) { case 01: return posit ? 2 : 3; case 31: return posit ? 2 : 3; case 51: case 52: case 53: return 3; case 60: return posit ? 2 : 3; default: error(0, "EMI2[%s]: Unsupported EMI operation reply type %d", octstr_get_cstr(whoami), ot); return -1; } } static struct emimsg *emimsg_create_withlen(int len) { struct emimsg *ret; ret = gw_malloc(sizeof(struct emimsg)); ret->fields = gw_malloc(len * sizeof(Octstr *)); ret->num_fields = len; while (--len >= 0) ret->fields[len] = NULL; return ret; } struct emimsg *emimsg_create_op(int ot, int trn, Octstr *whoami) { int len; struct emimsg *ret; len = field_count_op(ot, whoami); if (len < 0) return NULL; ret = emimsg_create_withlen(len); ret->ot = ot; ret->or = 'O'; ret->trn = trn; return ret; } static struct emimsg *emimsg_create_reply_s(int ot, int trn, int positive, Octstr *whoami) { int len; struct emimsg *ret; len = field_count_reply(ot, positive, whoami); if (len < 0) return NULL; ret = emimsg_create_withlen(len); ret->ot = ot; ret->or = 'R'; ret->trn = trn; return ret; } struct emimsg *emimsg_create_reply(int ot, int trn, int positive, Octstr *whoami) { struct emimsg *ret; ret = emimsg_create_reply_s(ot, trn, positive, whoami); if (ret) { if (positive) ret->fields[0] = octstr_create("A"); else ret->fields[0] = octstr_create("N"); } return ret; } void emimsg_destroy(struct emimsg *emimsg) { int len; len = emimsg->num_fields; while (--len >= 0) { octstr_destroy(emimsg->fields[len]); /* octstr_destroy(NULL) is ok */ emimsg->fields[len] = NULL; } gw_free(emimsg->fields); gw_free(emimsg); } struct emimsg *emimsg_duplicate(struct emimsg *emimsg) { int len; struct emimsg *ret; len = emimsg->num_fields; if (len < 0) return NULL; ret = gw_malloc(sizeof(struct emimsg)); ret->fields = gw_malloc(len * sizeof(Octstr *)); ret->num_fields = len; while (--len >= 0) ret->fields[len] = octstr_duplicate(emimsg->fields[len]); ret->ot = emimsg->ot; ret->or = emimsg->or; ret->trn = emimsg->trn; return ret; } /* The argument can be either the whole message (with the stx/etx start/end characters), or miss the last 3 characters (checksum digits and etx) */ static int calculate_checksum(Octstr *message) { int end, i, checksum; end = octstr_len(message); if (octstr_get_char(message, end - 1) == 3) /* etx, whole message */ end -= 3; checksum = 0; for (i = 1; i < end; i++) checksum += octstr_get_char(message, i); return checksum & 0xff; } static Octstr *emimsg_tostring(struct emimsg *emimsg) { int i, checksum; Octstr *result, *data; char *hexits = "0123456789ABCDEF"; data = octstr_create(""); for (i = 0; i < emimsg->num_fields; i++) { if (emimsg->fields[i]) octstr_append(data, emimsg->fields[i]); octstr_append_char(data, '/'); } result = octstr_format("\02%02d/%05d/%c/%02d/%S", emimsg->trn, octstr_len(data) + 16, emimsg->or, emimsg->ot, data); checksum = calculate_checksum(result); octstr_append_char(result, hexits[checksum >> 4 & 15]); octstr_append_char(result, hexits[checksum & 15]); octstr_append_char(result, 3); octstr_destroy(data); return result; } /* Doesn't check that the string is strictly according to format */ struct emimsg *get_fields(Octstr *message, Octstr *whoami) { long trn, len, ot, checksum; /* because of Octstr_parse_long... */ char or, posit; long fieldno, pos, pos2; struct emimsg *result = NULL; debug("smsc.emi2", 0, "EMI2[%s]: emi2 parsing packet: <%s>", octstr_get_cstr(whoami), octstr_get_cstr(message)); if (octstr_get_char(message, 0) != 2 || octstr_get_char(message, octstr_len(message) - 1) != 3) goto error; if (octstr_parse_long(&trn, message, 1, 10) != 3) goto error; if (octstr_parse_long(&len, message, 4, 10) != 9) goto error; if (octstr_len(message) != len + 2) /* +2 for start/end markers */ goto error; if ( (or = octstr_get_char(message, 10)) != 'O' && or != 'R') goto error; if (octstr_parse_long(&ot, message, 12, 10) != 14) goto error; if (or == 'O') result = emimsg_create_op(ot, trn, whoami); else { posit = octstr_get_char(message, 15); if (posit == 'A') result = emimsg_create_reply_s(ot, trn, 1, whoami); else if (posit == 'N') result = emimsg_create_reply_s(ot, trn, 0, whoami); else goto error; } if (result == NULL) goto error; pos2 = 14; for (fieldno = 0; fieldno < result->num_fields; fieldno++) { pos = pos2 + 1; if ( (pos2 = octstr_search_char(message, '/', pos)) == -1) goto error; if (pos2 > pos) result->fields[fieldno] = octstr_copy(message, pos, pos2 - pos); } if (octstr_search_char(message, '/', pos2 + 1) != -1) { int extrafields = 0; pos = pos2; while ((pos = octstr_search_char(message, '/', pos + 1)) != -1) { extrafields++; pos2 = pos; } /* The extra fields are ignored */ warning(0, "get_fields: EMI message of type %d/%c has %d more fields " "than expected.", result->ot, result->or, extrafields); } if (octstr_parse_long(&checksum, message, pos2 + 1, 16) != octstr_len(message) - 1 || checksum != calculate_checksum(message)) goto error; if (result->or == 'R' && octstr_get_char(result->fields[0], 0) == 'N') { long errcode; if (!result->fields[1] || octstr_parse_long(&errcode, result->fields[1], 0, 10) != 2) goto error; error(0, "EMI2[%s]: Got negative ack. op:%d, trn:%d, error:%ld (%s), message:%s", octstr_get_cstr(whoami), result->ot, result->trn, errcode, emi_strerror(errcode), result->fields[2] ? octstr_get_cstr(result->fields[2]) : ""); } return result; error: error(0, "EMI2[%s]: Invalid EMI packet: %s", octstr_get_cstr(whoami), octstr_get_cstr(message)); if (result) emimsg_destroy(result); return NULL; } int emimsg_send(Connection *conn, struct emimsg *emimsg, Octstr *whoami) { Octstr *string; string = emimsg_tostring(emimsg); if (!string) { error(0, "EMI2[%s]: emimsg_send: conversion to string failed", octstr_get_cstr(whoami)); return -1; } if (emimsg->ot == 60) debug("smsc.emi2", 0, "EMI2[%s]: Sending operation type 60, message with " "password not shown in log file.", octstr_get_cstr(whoami)); else debug("smsc.emi2", 0, "EMI2[%s]: emi2 sending packet: <%s>", octstr_get_cstr(whoami), octstr_get_cstr(string)); if (conn_write(conn, string) == -1) { octstr_destroy(string); error(0, "EMI2[%s]: emimsg_send: write failed", octstr_get_cstr(whoami)); return -1; } octstr_destroy(string); return 1; } gateway-1.4.5/gw/smsc/smsc_smasi.c0000644000175000017500000011135113227613126015560 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Implementation of a SM/ASI SMSC module. * * Stipe Tolj * * This module connects to a CriticalPath InVoke SMS Center which * uses the SM/ASI protocol. * The module is heavily based on the SMPP module design. * * TODO: * 1. alt_dcs is not used. Instead, msg->sms.mclass is used as the SMASI * Class. * 2. Numbers are not handled correctly, I guess. SMASI allows only(?) * international numbers without leading double zero. How to ensure * this? * 3. Handling of npi and ton correct? * 4. SubmitMulti PDUs not supported. * 5. Replace PDUs not supported. * 6. Status PDUs not supported. * 7. Cancel PDUs not supported. * 8. UserRes PDUs not supported. * 9. Smsc PDUs not supported. * 10. EnquireLink PDUs not supported. */ #include "gwlib/gwlib.h" #include "msg.h" #include "smsc_p.h" #include "smasi_pdu.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "sms.h" #include "dlr.h" #define DEBUG 1 #ifndef DEBUG static void dump_pdu(const char *msg, Octstr *id, SMASI_PDU *pdu) { } #else static void dump_pdu(const char *msg, Octstr *id, SMASI_PDU *pdu) { debug("bb.sms.smasi", 0, "SMASI[%s]: %s", octstr_get_cstr(id), msg); smasi_pdu_dump(pdu); } #endif /************************************************************************/ /* DEFAULT SETTINGS */ /************************************************************************/ #define SMASI_DEFAULT_PORT 21500 #define SMASI_DEFAULT_PRIORITY 0 #define MAX_PENDING_SUBMITS 10 #define SMASI_THROTTLING_SLEEP_TIME 15 #define SMASI_ENQUIRE_LINK_INTERVAL 30.0 /************************************************************************/ /* OVERRIDE SETTINGS */ /************************************************************************/ /* Set these to -1 if no override desired. Values carried in message will * be used then. Or the defaults - if message has no values. * * Otherwise these values will be forced! */ #define SMASI_OVERRIDE_SOURCE_TON 1 #define SMASI_OVERRIDE_SOURCE_NPI -1 #define SMASI_OVERRIDE_DEST_TON -1 #define SMASI_OVERRIDE_DEST_NPI -1 /************************************************************************/ /* SMASI STRUCTURE AND RELATED FUNCTIONS */ /************************************************************************/ typedef struct { SMSCConn * conn; /* connection to the bearerbox */ int thread_handle; /* handle for the SMASI thread */ List *msgs_to_send; Dict *sent_msgs; /* hash table for send, but yet not confirmed */ List *received_msgs; /* list of received, but yet not processed */ Counter *message_id_counter; /* sequence number */ Octstr *host; /* host or IP of the SMASI server */ long port; /* port to connect to */ Octstr *username; Octstr * password; Octstr * my_number; long source_addr_ton; long source_addr_npi; long dest_addr_ton; long dest_addr_npi; long priority; time_t throttling_err_time; int quitting; long enquire_link_interval; int logged_off; } SMASI; static SMASI *smasi_create(SMSCConn *conn) { SMASI *smasi = gw_malloc(sizeof(SMASI)); smasi->conn = conn; smasi->thread_handle = -1; smasi->msgs_to_send = gwlist_create(); smasi->sent_msgs = dict_create(16, NULL); smasi->received_msgs = gwlist_create(); smasi->message_id_counter = counter_create(); smasi->host = NULL; smasi->username = NULL; smasi->password = NULL; smasi->source_addr_ton = -1; smasi->source_addr_npi = -1; smasi->dest_addr_ton = -1; smasi->dest_addr_npi = -1; smasi->my_number = NULL; smasi->port = 21500; smasi->quitting = 0; smasi->logged_off = 0; smasi->priority = 0; smasi->throttling_err_time = 0; smasi->enquire_link_interval = 30; gwlist_add_producer(smasi->msgs_to_send); return smasi; } static void smasi_destroy(SMASI *smasi) { if (smasi == NULL) return; gwlist_destroy(smasi->msgs_to_send, msg_destroy_item); dict_destroy(smasi->sent_msgs); gwlist_destroy(smasi->received_msgs, msg_destroy_item); counter_destroy(smasi->message_id_counter); octstr_destroy(smasi->host); octstr_destroy(smasi->username); octstr_destroy(smasi->password); gw_free(smasi); } /************************************************************************/ /* DATA ENCODING */ /************************************************************************/ /* These values will be initialized on module startup. They contain the * ASCII representation of the chars that need to be escaped in the message * body before transmission. Example: "," (comma) will be represented by * the octet string ":2c". */ static Octstr *colon = NULL; static Octstr *assign = NULL; static Octstr *comma = NULL; static Octstr *cr = NULL; static Octstr *lf = NULL; /* * Escapes outgoing message body data by replacing occurrences of "special" * chars inside the octet string. */ static void escape_data(Octstr *data) { long pos = 0; /* This one uses a different approach than the encode and decode * functions. Because it is assumed, that only a fraction of the * contained chars have to be escaped. */ while (pos < octstr_len(data)) { Octstr * escaped = NULL; int check = octstr_get_char(data, pos); if (check == ':') escaped = colon; else if (check == '=') escaped = assign; else if (check == ',') escaped = comma; else if (check == '\n') escaped = cr; else if (check == '\r') escaped = lf; if (escaped != NULL) { /* If the current char has to be escaped, delete the char from * the source string, replace it with the escape sequence, and * advance position until after the inserted sequence. */ octstr_delete(data, pos, 1); octstr_insert(data, escaped, pos); pos += octstr_len(escaped); } else { /* If not escaped, simply skip the current char. */ pos++; } } } /* * Unescapes incoming message body data by replacing occurrences of escaped * chars with their original character representation. */ static void unescape_data(Octstr *data) { long pos = 0; /* Again, an inplace transformation is used. Because, again, it is * assumed that only a fraction of chars has to be unescaped. */ while (pos < octstr_len(data)) { int check = octstr_get_char(data, pos); if (check == ':') { char byte = 0; int msb = octstr_get_char(data, pos + 1); int lsb = octstr_get_char(data, pos + 2); if (msb == '0') msb = 0; else if (msb >= '1' && msb <= '9') msb -= '1' + 1; else msb -= 'a' + 10; if (lsb == '0') lsb = 0; else if (lsb >= '1' && lsb <= '9') lsb -= '1' + 1; else lsb -= 'a' + 10; byte = msb << 4 | lsb; /* Do inplace unescaping. */ octstr_delete(data, pos, 3); octstr_insert_data(data, pos, &byte, 1); } pos++; } } /* * Will replace a binary data octet string (inplace) with a SMASI conform * ASCII representation of the data. */ static void encode_binary_data(Octstr *data) { Octstr *result = octstr_create(""); long pos = 0; while (pos < octstr_len(data)) { int encode = octstr_get_char(data, pos); int msb = (encode & 0xf0) >> 4; int lsb = (encode & 0x0f) >> 0; if (msb == 0) msb = '0'; else if (msb < 10) msb = '1' + msb - 1; else msb = 'a' + msb - 10; if (lsb == 0) lsb = '0'; else if (lsb < 10) lsb = '1' + lsb - 1; else lsb = 'a' + lsb - 10; octstr_append_char(result, ':'); octstr_append_char(result, msb); octstr_append_char(result, lsb); pos++; } /* Replace binary data octet string with ASCII representation. */ octstr_delete(data, 0, octstr_len(data)); octstr_append(data, result); octstr_destroy(result); } /* * Re-escape SMASI ASCII representation of binary data with the * original binary data octet string. * XXX this may be done by the internal parser routines too. */ static void decode_binary_data(Octstr *data) { long pos = 0; while (pos < octstr_len(data)) { int check = octstr_get_char(data, pos); if (check == ':') { Octstr *byte; int msb = octstr_get_char(data, pos + 1); int lsb = octstr_get_char(data, pos + 2); if (msb != -1 && lsb != -1) { byte = octstr_create(""); octstr_append_char(byte, msb); octstr_append_char(byte, lsb); if (octstr_hex_to_binary(byte) != -1) { /* Do inplace unescaping. */ octstr_delete(data, pos, 3); octstr_insert(data, byte, pos); } else { error(0, "Malformed binary encoded data."); } octstr_destroy(byte); } } pos++; } } /************************************************************************/ /* MESSAGE PROCESSING */ /************************************************************************/ static Octstr *get_ton_npi_value(int override, int message) { if (override != -1) { debug("bb.sms.smasi", 0, "SMASI: Manually forced ton or npi to `%d'", override); return (octstr_format("%ld", override)); } else { return (octstr_format("%ld", message)); } } /* * Gets the value to be used as source_addr_ton. Will use override values * if configured. Will use values from message otherwise. Or fall back to * defaults if nothing given. */ static Octstr *get_source_addr_ton(SMASI *smasi, Msg *msg) { return get_ton_npi_value(smasi->source_addr_ton, GSM_ADDR_TON_INTERNATIONAL); } /* * Gets the value to be used as source_addr_npi. Will use override values * if configured. Will use values from message otherwise. Or fall back to * defaults if nothing given. */ static Octstr *get_source_addr_npi(SMASI *smasi, Msg *msg) { return get_ton_npi_value(smasi->source_addr_npi, GSM_ADDR_NPI_E164); } /* * Gets the value to be used as dest_addr_ton. Will use override values * if configured. Will use values from message otherwise. Or fall back to * defaults if nothing given. */ static Octstr *get_dest_addr_ton(SMASI *smasi, Msg *msg) { return get_ton_npi_value(smasi->dest_addr_ton, GSM_ADDR_TON_INTERNATIONAL); } /* * Gets the value to be used as dest_addr_npi. Will use override values * if configured. Will use values from message otherwise. Or fall back to * defaults if nothing given. */ static Octstr *get_dest_addr_npi(SMASI *smasi, Msg *msg) { return get_ton_npi_value(smasi->dest_addr_npi, GSM_ADDR_NPI_E164); } /* * Determine the originator (sender number) type based on the number. Will * change the originator number if necessary. */ static Octstr *get_originator_type(SMASI *smasi, Octstr *originator) { /* International or alphanumeric sender? */ if (octstr_get_char(originator, 0) == '+') { if (!octstr_check_range(originator, 1, 256, gw_isdigit)) { return octstr_format("%ld", GSM_ADDR_TON_ALPHANUMERIC); } else { /* Numeric sender address with + in front: The + has to be * removed from this international number. */ octstr_delete(originator, 0, 1); return octstr_format("%ld", GSM_ADDR_TON_INTERNATIONAL); } } else if (!octstr_check_range(originator, 0, 256, gw_isdigit)) { return octstr_format("%ld", GSM_ADDR_TON_ALPHANUMERIC); } /* Return the default value. */ return octstr_format("%ld", GSM_ADDR_TON_INTERNATIONAL); } /* * Creates a SubmitReq PDU from an outgoing message. */ static SMASI_PDU *msg_to_pdu(SMASI *smasi, Msg *msg) { SMASI_PDU *pdu = smasi_pdu_create(SubmitReq); pdu->u.SubmitReq.Destination = octstr_duplicate(msg->sms.receiver); pdu->u.SubmitReq.Body = octstr_duplicate(msg->sms.msgdata); pdu->u.SubmitReq.Originator = octstr_duplicate(msg->sms.sender); pdu->u.SubmitReq.OriginatorType = get_originator_type(smasi, pdu->u.SubmitReq.Originator); pdu->u.SubmitReq.Sequence = octstr_format("%ld", counter_increase(smasi->message_id_counter)); /* If its a international number starting with +, lets remove the +. */ if (octstr_get_char(pdu->u.SubmitReq.Destination, 0) == '+') octstr_delete(pdu->u.SubmitReq.Destination, 0, 1); /* Do ton and npi override - if configured. Use values from message * otherwise. */ pdu->u.SubmitReq.OriginatorType = get_source_addr_ton(smasi, msg); pdu->u.SubmitReq.OriginatorPlan = get_source_addr_npi(smasi, msg); pdu->u.SubmitReq.DestinationType = get_dest_addr_ton(smasi, msg); pdu->u.SubmitReq.DestinationPlan = get_dest_addr_npi(smasi, msg); /* Set priority. */ if (smasi->priority >= 0 && smasi->priority <= 3) { pdu->u.SubmitReq.MqPriority = octstr_format("%ld", smasi->priority); } else { pdu->u.SubmitReq.MqPriority = octstr_format("%ld", 0); } /* Set encoding. */ if (msg->sms.coding != DC_UNDEF) { if (msg->sms.coding == DC_7BIT) pdu->u.SubmitReq.MsEncoding = octstr_create("7bit"); else if (msg->sms.coding == DC_8BIT) pdu->u.SubmitReq.MsEncoding = octstr_create("8bit"); else if (msg->sms.coding == DC_UCS2) pdu->u.SubmitReq.MsEncoding = octstr_create("16bit"); /* Everything else will default to 7bit. */ } /* Set messaging class - if within defined parameter range. */ if (msg->sms.mclass != MC_UNDEF) pdu->u.SubmitReq.Class = octstr_format("%ld", msg->sms.mclass); /* Set Protocol ID. */ pdu->u.SubmitReq.ProtocolID = octstr_format("%ld", (msg->sms.pid == SMS_PARAM_UNDEFINED ? 0 : msg->sms.pid)); /* Check if SMS is binary. */ if (msg->sms.udhdata && octstr_len(msg->sms.udhdata) > 0) { pdu->u.SubmitReq.UserDataHeader = octstr_duplicate(msg->sms.udhdata); pdu->u.SubmitReq.BodyEncoding = octstr_create("Data"); if (pdu->u.SubmitReq.MsEncoding) octstr_destroy(pdu->u.SubmitReq.MsEncoding); pdu->u.SubmitReq.MsEncoding = octstr_create("transparent"); /* Encode data. */ encode_binary_data(pdu->u.SubmitReq.UserDataHeader); encode_binary_data(pdu->u.SubmitReq.Body); } else { /* Otherwise do data escaping. */ escape_data(pdu->u.SubmitReq.Body); } return pdu; } /* * Create a message structure from an incoming DeliverReq PDU. */ static Msg *pdu_to_msg(SMASI_PDU *pdu) { Msg *msg = NULL; gw_assert(pdu->type == DeliverReq); gw_assert(pdu->u.DeliverReq.Originator); gw_assert(pdu->u.DeliverReq.Destination); gw_assert(pdu->u.DeliverReq.Body); msg = msg_create(sms); msg->sms.sender = octstr_duplicate(pdu->u.DeliverReq.Originator); msg->sms.receiver = octstr_duplicate(pdu->u.DeliverReq.Destination); msg->sms.msgdata = octstr_duplicate(pdu->u.DeliverReq.Body); /* Read priority. */ if (pdu->u.DeliverReq.ProtocolId) if (octstr_parse_long(&msg->sms.pid, pdu->u.DeliverReq.ProtocolId, 0, 10) == -1) msg->sms.pid = SMS_PARAM_UNDEFINED; /* Read Coding. */ if (pdu->u.DeliverReq.MsEncoding) { /* Use specified coding. */ if (octstr_str_compare(pdu->u.DeliverReq.MsEncoding, "7bit") == 0) msg->sms.coding = DC_7BIT; else if (octstr_str_compare(pdu->u.DeliverReq.MsEncoding, "8bit") == 0) msg->sms.coding = DC_8BIT; else if (octstr_str_compare(pdu->u.DeliverReq.MsEncoding, "UCS2") == 0) msg->sms.coding = DC_UCS2; else if (octstr_str_compare(pdu->u.DeliverReq.MsEncoding, "transparent") == 0) msg->sms.coding = DC_8BIT; } else { /* Determine specified coding according to udhdata presence. */ if (pdu->u.DeliverReq.UserDataHeader) msg->sms.coding = DC_8BIT; else msg->sms.coding = DC_7BIT; } /* Unescape (non-binary) or decode (binary) data. */ if (msg->sms.coding == DC_8BIT) { decode_binary_data(msg->sms.msgdata); if (pdu->u.DeliverReq.UserDataHeader && octstr_len(pdu->u.DeliverReq.UserDataHeader) > 0) { msg->sms.udhdata = octstr_duplicate(pdu->u.DeliverReq.UserDataHeader); decode_binary_data(msg->sms.udhdata); } } else { unescape_data(msg->sms.msgdata); } /* Read message class. */ if (pdu->u.DeliverReq.Class && octstr_parse_long(&msg->sms.mclass, pdu->u.DeliverReq.Class, 0, 10) == -1) msg->sms.mclass = MC_UNDEF; /* Set to unspecified. */ /* Read protocol ID. */ if (pdu->u.DeliverReq.ProtocolId && octstr_parse_long(&msg->sms.pid, pdu->u.DeliverReq.ProtocolId, 0, 10) == -1) msg->sms.pid = SMS_PARAM_UNDEFINED; return msg; } /************************************************************************/ /* PDU HANDLING */ /************************************************************************/ static void send_logoff(SMASI *smasi, Connection *conn) { SMASI_PDU *pdu = NULL; Octstr *os = NULL; counter_increase(smasi->message_id_counter); pdu = smasi_pdu_create(LogoffReq); pdu->u.LogoffReq.Reason = octstr_create("Client shutting down"); dump_pdu("Sending !LogoffReq:", smasi->conn->id, pdu); os = smasi_pdu_pack(pdu); conn_write(conn, os); octstr_destroy(os); smasi_pdu_destroy(pdu); } static void send_enquire_link(SMASI *smasi, Connection *conn, long *last_sent) { SMASI_PDU *pdu = NULL; Octstr *os = NULL; if (date_universal_now() - *last_sent < smasi->enquire_link_interval) return; *last_sent = date_universal_now(); pdu = smasi_pdu_create(EnquireLinkReq); dump_pdu("Sending EnquireLinkReq:", smasi->conn->id, pdu); os = smasi_pdu_pack(pdu); if (os) conn_write(conn, os); /* Write errors checked by caller. */ octstr_destroy(os); smasi_pdu_destroy(pdu); } static int send_pdu(Connection *conn, Octstr *id, SMASI_PDU *pdu) { Octstr * os = NULL; int ret = 0; dump_pdu("Sending PDU:", id, pdu); os = smasi_pdu_pack(pdu); if (os) ret = conn_write(conn, os); else ret = -1; octstr_destroy(os); return ret; } /* * Try to read a SMASI PDU from a connection. Return -1 for error (caller * should close the connection), 0 for no PDU ready yet, or 1 for PDU read * and unpacked. Return a pointer to the PDU in `*pdu'. */ static int read_pdu(SMASI *smasi, Connection *conn, SMASI_PDU **pdu) { Octstr *os; os = smasi_pdu_read(conn); if (os == NULL) { if (conn_eof(conn) || conn_error(conn)) return -1; return 0; } *pdu = smasi_pdu_unpack(os); if (*pdu == NULL) { error(0, "SMASI[%s]: PDU unpacking failed.", octstr_get_cstr(smasi->conn->id)); debug("bb.sms.smasi", 0, "SMASI[%s]: Failed PDU follows.", octstr_get_cstr(smasi->conn->id)); octstr_dump(os, 0); octstr_destroy(os); return -1; } octstr_destroy(os); return 1; } static void handle_pdu(SMASI *smasi, Connection *conn, SMASI_PDU *pdu, long *pending_submits) { SMASI_PDU *resp = NULL; Msg *msg = NULL; long reason; switch (pdu->type) { case DeliverReq: msg = pdu_to_msg(pdu); msg_dump(msg, 0); if (smasi->my_number && octstr_len(smasi->my_number)) { octstr_destroy(msg->sms.receiver); msg->sms.receiver = octstr_duplicate(smasi->my_number); } time(&msg->sms.time); msg->sms.smsc_id = octstr_duplicate(smasi->conn->id); bb_smscconn_receive(smasi->conn, msg); resp = smasi_pdu_create(DeliverConf); if (pdu->u.DeliverReq.Sequence) resp->u.DeliverConf.Sequence = octstr_duplicate(pdu->u.DeliverReq.Sequence); if (pdu->u.DeliverReq.MsgReference) resp->u.DeliverConf.MsgReference = octstr_duplicate(pdu->u.DeliverReq.MsgReference); break; case SubmitConf: if (pdu->u.SubmitConf.Sequence) { msg = dict_remove(smasi->sent_msgs, pdu->u.SubmitConf.Sequence); } else { msg = NULL; } if (msg == NULL) { warning(0, "SMASI[%s]: SMSC sent SubmitConf for unknown message.", octstr_get_cstr(smasi->conn->id)); } else { debug("bb.sms.smasi",0, "SMSC[%s]: SMSC confirmed msg seq <%s> ref <%s>", octstr_get_cstr(smasi->conn->id), octstr_get_cstr(pdu->u.SubmitConf.Sequence), octstr_get_cstr(pdu->u.SubmitConf.MsgReference)); bb_smscconn_sent(smasi->conn, msg, NULL); --(*pending_submits); } break; case SubmitRej: if (pdu->u.SubmitRej.Sequence) { msg = dict_remove(smasi->sent_msgs, pdu->u.SubmitRej.Sequence); } else { msg = NULL; } error(0, "SMASI[%s]: SMSC returned error code %s for " "message ref <%s>", octstr_get_cstr(smasi->conn->id), octstr_get_cstr(pdu->u.SubmitRej.RejectCode), octstr_get_cstr(pdu->u.SubmitRej.MsgReference)); if (msg == NULL) { warning(0, "SMASI[%s]: SMSC sent SubmitRej for unknown message.", octstr_get_cstr(smasi->conn->id)); } else { reason = SMSCCONN_FAILED_REJECTED; bb_smscconn_send_failed(smasi->conn, msg, reason, octstr_create("REJECTED")); --(*pending_submits); } break; case LogonConf: *pending_submits = 0; smasi->conn->status = SMSCCONN_ACTIVE; smasi->conn->connect_time = time(NULL); bb_smscconn_connected(smasi->conn); info(0, "SMASI[%s]: connection to SMSC established.", octstr_get_cstr(smasi->conn->id)); break; case LogonRej: if (octstr_len(pdu->u.LogonRej.Reason) > 0) { error(0, "SMASI[%s]: SMSC rejected login with reason <%s>", octstr_get_cstr(smasi->conn->id), octstr_get_cstr(pdu->u.LogonRej.Reason)); } else { error(0, "SMASI[%s]: SMSC rejected login without reason", octstr_get_cstr(smasi->conn->id)); } break; case LogoffConf: info(0, "SMASI[%s]: SMSC confirmed logoff.", octstr_get_cstr(smasi->conn->id)); smasi->logged_off = 1; break; default: warning(0, "SMASI[%s]: Unknown PDU type <%s>, ignored.", octstr_get_cstr(smasi->conn->id), pdu->type_name); break; } if (resp != NULL) { send_pdu(conn, smasi->conn->id, resp); smasi_pdu_destroy(resp); } } /************************************************************************/ /* SMASI CONNECTION HANDLING */ /************************************************************************/ /* * Open transmission connection to SMS center. Return NULL for error, * open connection for OK. Caller must set smasi->conn->status correctly * before calling this. */ static Connection *open_connection(SMASI *smasi) { Connection *conn = conn_open_tcp_with_port(smasi->host, smasi->port, 0, smasi->conn->our_host); if (conn == NULL) { error(0, "SMASI[%s]: Couldn't connect to server.", octstr_get_cstr(smasi->conn->id)); return NULL; } else { SMASI_PDU *logon = smasi_pdu_create(LogonReq); logon->u.LogonReq.Name = octstr_duplicate(smasi->username); logon->u.LogonReq.Password = octstr_duplicate(smasi->password); counter_increase(smasi->message_id_counter); send_pdu(conn, smasi->conn->id, logon); smasi_pdu_destroy(logon); } return conn; } static void send_messages(SMASI *smasi, Connection *conn, long *pending_submits) { double delay = 0; if (*pending_submits == -1) return; if (smasi->conn->throughput > 0) { delay = 1.0 / smasi->conn->throughput; } while (*pending_submits < MAX_PENDING_SUBMITS) { SMASI_PDU *pdu = NULL; /* Get next message, quit if none to be sent. */ Msg *msg = gwlist_extract_first(smasi->msgs_to_send); if (msg == NULL) break; /* Send PDU, record it as waiting for ack from SMSC. */ pdu = msg_to_pdu(smasi, msg); if (pdu->u.SubmitReq.Sequence) dict_put(smasi->sent_msgs, pdu->u.SubmitReq.Sequence, msg); send_pdu(conn, smasi->conn->id, pdu); smasi_pdu_destroy(pdu); /* obey throughput speed limit, if any */ if (smasi->conn->throughput > 0) gwthread_sleep(delay); ++(*pending_submits); } } /* * This is the main function for the background thread for doing I/O on * one SMASI connection (the one for transmitting or receiving messages). * It makes the initial connection to the SMASI server and re-connects * if there are I/O errors or other errors that require it. */ static void smasi_thread(void *arg) { long pending_submits; SMASI_PDU *pdu; SMASI *smasi; int logoff_already_sent = 0; int ret; Connection *conn; long last_enquire_sent; double timeout; smasi = arg; /* Make sure we log into our own log-file if defined */ log_thread_to(smasi->conn->log_idx); while (!smasi->quitting) { conn = open_connection(smasi); if (conn == NULL) { error(0, "SMASI[%s]: Could not connect to SMSC center " \ "(retrying in %ld seconds).", octstr_get_cstr(smasi->conn->id), smasi->conn->reconnect_delay); gwthread_sleep(smasi->conn->reconnect_delay); smasi->conn->status = SMSCCONN_RECONNECTING; continue; } last_enquire_sent = date_universal_now(); pending_submits = -1; for (;;) { timeout = last_enquire_sent + smasi->enquire_link_interval - date_universal_now(); /* wait for activity */ if (conn_wait(conn, timeout) == -1) { error(0, "SMASI[%s]: I/O error or other error. Re-connecting.", octstr_get_cstr(smasi->conn->id)); break; } /* Send logoff request if module is shutting down. */ if (smasi->quitting && !logoff_already_sent) { send_logoff(smasi, conn); logoff_already_sent = 1; } /* send an enquire link */ send_enquire_link(smasi, conn, &last_enquire_sent); /* Receive incoming PDUs. */ while ((ret = read_pdu(smasi, conn, &pdu)) == 1) { /* Deal with the PDU we just got */ dump_pdu("Got PDU:", smasi->conn->id, pdu); /* Process the received PDU. */ handle_pdu(smasi, conn, pdu, &pending_submits); smasi_pdu_destroy(pdu); /* Bail out if logoff confirmed. */ if (smasi->logged_off) break; /* Make sure we send even if we read a lot. */ if ((!smasi->throttling_err_time || ((time(NULL) - smasi->throttling_err_time) > SMASI_THROTTLING_SLEEP_TIME && !(smasi->throttling_err_time = 0)))) send_messages(smasi, conn, &pending_submits); } /* Check if connection broken. */ if (ret == -1) { error(0, "SMASI[%s]: I/O error or other error. Re-connecting.", octstr_get_cstr(smasi->conn->id)); break; } /* Bail out if logoff confirmed. */ if (smasi->logged_off) break; if ((!smasi->throttling_err_time || ((time(NULL) - smasi->throttling_err_time) > SMASI_THROTTLING_SLEEP_TIME && !(smasi->throttling_err_time = 0)))) send_messages(smasi, conn, &pending_submits); } conn_destroy(conn); conn = NULL; } } /************************************************************************/ /* SMSCCONN INTERFACE */ /************************************************************************/ static long queued_cb(SMSCConn *conn) { SMASI *smasi = conn->data; conn->load = (smasi ? (conn->status != SMSCCONN_DEAD ? gwlist_len(smasi->msgs_to_send) : 0) : 0); return conn->load; } static int send_msg_cb(SMSCConn *conn, Msg *msg) { SMASI *smasi = conn->data; gwlist_produce(smasi->msgs_to_send, msg_duplicate(msg)); gwthread_wakeup(smasi->thread_handle); return 0; } static int shutdown_cb(SMSCConn *conn, int finish_sending) { SMASI *smasi = NULL; debug("bb.sms.smasi", 0, "Shutting down SMSCConn %s (%s)", octstr_get_cstr(conn->name), finish_sending ? "slow" : "instant"); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; smasi = conn->data; smasi->quitting = 1; gwthread_wakeup(smasi->thread_handle); gwthread_join(smasi->thread_handle); smasi_destroy(smasi); debug("bb.sms.smasi", 0, "SMSCConn %s shut down.", octstr_get_cstr(conn->name)); conn->status = SMSCCONN_DEAD; bb_smscconn_killed(); /* Clean up. */ octstr_destroy(colon); octstr_destroy(assign); octstr_destroy(comma); octstr_destroy(cr); octstr_destroy(lf); return 0; } /* * Configures the SMASI structure according to the configuration. * * @return 0 on complete success. -1 if failed due to missing or invalid * configuration entry. */ static int init_configuration(SMASI *smasi, CfgGroup *config) { /* Read mandatory entries. */ smasi->host = cfg_get(config, octstr_imm("host")); smasi->username = cfg_get(config, octstr_imm("smsc-username")); smasi->password = cfg_get(config, octstr_imm("smsc-password")); /* Check configuration. */ if (smasi->host == NULL) { error(0,"SMASI: Configuration file doesn't specify host"); return -1; } if (smasi->username == NULL) { error(0, "SMASI: Configuration file doesn't specify username."); return -1; } if (smasi->password == NULL) { error(0, "SMASI: Configuration file doesn't specify password."); return -1; } /* Read optional entries. Set default values if not set. */ smasi->my_number = cfg_get(config, octstr_imm("my-number")); if (cfg_get_integer(&smasi->port, config, octstr_imm("port")) == -1) smasi->port = SMASI_DEFAULT_PORT; if (cfg_get_integer(&smasi->source_addr_ton, config, octstr_imm("source-addr-ton")) == -1) smasi->source_addr_ton = SMASI_OVERRIDE_SOURCE_TON; if (cfg_get_integer(&smasi->source_addr_npi, config, octstr_imm("source-addr-npi")) == -1) smasi->source_addr_npi = SMASI_OVERRIDE_SOURCE_NPI; if (cfg_get_integer(&smasi->dest_addr_ton, config, octstr_imm("dest-addr-ton")) == -1) smasi->dest_addr_ton = SMASI_OVERRIDE_DEST_TON; if (cfg_get_integer(&smasi->dest_addr_npi, config, octstr_imm("dest-addr-npi")) == -1) smasi->dest_addr_npi = SMASI_OVERRIDE_DEST_NPI; if (cfg_get_integer(&smasi->priority, config, octstr_imm("priority")) == -1) smasi->priority = SMASI_DEFAULT_PRIORITY; if (cfg_get_integer(&smasi->enquire_link_interval, config, octstr_imm("enquire-link-interval")) == -1) smasi->enquire_link_interval = SMASI_ENQUIRE_LINK_INTERVAL; /* Configure SMSC connection. */ smasi->conn->data = smasi; smasi->conn->name = octstr_format("SMASI:%S:%d:%S", smasi->host, smasi->port, smasi->username); smasi->conn->id = cfg_get(config, octstr_imm("smsc-id")); if (smasi->conn->id == NULL) smasi->conn->id = octstr_duplicate(smasi->conn->name); return 0; } int smsc_smasi_create(SMSCConn *conn, CfgGroup *config) { SMASI *smasi = NULL; /* Initialize data encoding subsystem. */ colon = octstr_create(":3a"); assign = octstr_create(":3d"); comma = octstr_create(":2c"); cr = octstr_create(":0a"); lf = octstr_create(":0d"); /* Create main SMASI structure and initialize it with configuration * settings. */ smasi = smasi_create(conn); if (init_configuration(smasi, config) != 0) panic(0, "SMASI SMSC module configuration invalid."); conn->status = SMSCCONN_CONNECTING; /* Port is always set to a configured value or defaults to 21500. * Therefore, threads are always started. */ smasi->thread_handle = gwthread_create(smasi_thread, smasi); if (smasi->thread_handle == -1) { error(0, "SMASI[%s]: Couldn't start SMASI thread.", octstr_get_cstr(smasi->conn->id)); smasi_destroy(conn->data); return -1; } /* Setup control function pointers. */ conn->shutdown = shutdown_cb; conn->queued = queued_cb; conn->send_msg = send_msg_cb; return 0; } gateway-1.4.5/gw/smsc/smsc_cimd.c0000644000175000017500000012302513227613126015361 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /***************************************************************************** * smsc_cimd.c - Nokia SMS Center (CIMD 1.3). * Mikael Gueck for WapIT Ltd. */ #include #include #include #include #include #include #include #include #include #include "smsc.h" #include "smsc_p.h" #include "gwlib/gwlib.h" #include "alt_charsets.h" /****************************************************************************** * Static functions */ /* do the handshake baby */ static int cimd_open_connection(SMSCenter *smsc); /* waits for an ACK message, returns the ACK command number or -1 for error */ static int expect_acknowledge(SMSCenter *smsc, int *cmd, int *err); /* sends a general ACK */ static int send_acknowledge(SMSCenter *smsc); /* Reconnect to a CIMD server, use an existing structure */ static int connect_tcpip(SMSCenter *smsc); static int parse_cimd_to_iso88591(char *from, char *to, int length); static int parse_iso88591_to_cimd( char *from, char *to, int length, int alt_charset); /****************************************************************************** * Open the connection and log in * * return 0 if ok, -1 on failure */ static int cimd_open_connection(SMSCenter *smsc) { char *tmpbuff = NULL; int ret = 0; int cmd = 0, err = 0; /* allocate some spare space */ tmpbuff = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); /* connect */ smsc->socket = tcpip_connect_to_server(smsc->cimd_hostname, smsc->cimd_port, NULL); /* XXX add interface_name if required */ if (smsc->socket == -1) goto error; /* receive protocol string "CIMD rel 1.37\n" */ for (;;) { ret = smscenter_read_into_buffer(smsc); if (strstr(smsc->buffer, "CIMD rel 1.37\n") != NULL) break; if (ret < 0) goto logout; } debug("bb.sms.cimd", 0, "got the server identification tag"); smscenter_remove_from_buffer(smsc, smsc->buflen); /* send login string */ sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%c", 0x02, "01", 0x09, smsc->cimd_username, 0x09, smsc->cimd_password, 0x09, "11", 0x03, 0x0A); ret = write_to_socket(smsc->socket, tmpbuff); if (ret < 0) goto logout; /* get an acknowledge message */ smsc->cimd_last_spoke = 0; if (expect_acknowledge(smsc, &cmd, &err) < 1) goto logout; debug("bb.sms.cimd", 0, "logged in"); gw_free(tmpbuff); return 0; logout: cimd_close(smsc); error: error(0, "cimd_open: could not open/handshake"); gw_free(tmpbuff); return -1; } /****************************************************************************** * Open the smscenter */ SMSCenter *cimd_open(char *hostname, int port, char *username, char *password) { SMSCenter *smsc = NULL; int ret = 0; /* create a SMSCenter structure */ smsc = smscenter_construct(); if (smsc == NULL) goto error; smsc->type = SMSC_TYPE_CIMD; smsc->cimd_hostname = gw_strdup(hostname); smsc->hostname = gw_strdup(hostname); /* Needed by read_into_buffer() */ smsc->cimd_port = port; smsc->cimd_username = gw_strdup(username); smsc->cimd_password = gw_strdup(password); ret = cimd_open_connection(smsc); if (ret < 0) goto error; sprintf(smsc->name, "CIMD:%s:%d:%s", smsc->cimd_hostname, smsc->cimd_port, smsc->cimd_username); return smsc; error: error(0, "cimd_open: could not open!"); smscenter_destruct(smsc); return NULL; } /****************************************************************************** * Re-open the connection and log in * * return -1 if failed */ int cimd_reopen(SMSCenter *smsc) { cimd_close(smsc); if (cimd_open_connection(smsc) < 0) { error(0, "Failed to re-open the connection!"); return -1; } return 0; } /****************************************************************************** * Log out and close the socket * */ int cimd_close(SMSCenter *smsc) { char *cbuff = NULL; int sum; int ret; if (smsc->socket == -1) { debug("bb.sms.cimd", 0, "Trying to close cimd while already closed!"); return 0; } cbuff = gw_malloc(2 * 1024); sprintf(cbuff, "%c%s%c%s%c%c", 0x02, "02", 0x09, "11", 0x03, 0x0A); sum = write_to_socket(smsc->socket, cbuff); if (sum < 0) goto error; /* this time we don't block waiting for acknowledge */ recv(smsc->socket, cbuff, 2*1024, 0); gw_free(cbuff); ret = close(smsc->socket); smsc->socket = -1; return ret; error: gw_free(cbuff); return -1; } /****************************************************************************** * Check for MO messages, returns as in smsc_submit_smsmessage in smsc.h */ int cimd_pending_smsmessage(SMSCenter *smsc) { char *tmpbuff = NULL, *newline = NULL; int ret = 0; time_t thetime = 0; /* check for input sanity */ if (smsc == NULL) goto error; /* we can only query every 5 seconds */ thetime = time(NULL); if ((smsc->cimd_last_spoke + 5) > thetime) goto no_messages; smsc->cimd_last_spoke = thetime; /* allocate some spare space */ tmpbuff = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); sprintf(tmpbuff, "%c%s%c%s%c%c", 0x02, /* stx */ "05", 0x09, /* request for message, tab */ "11", /* dummy chksum */ 0x03, 0x0A); /* etx, lf */ /* send the poll message to determine if we have messages in queue */ ret = write_to_socket(smsc->socket, tmpbuff); if (ret < 0) { debug("bb.sms.cimd", 0, "sending poll message failed"); goto error; } /* block while waiting for answer that dataset ends to a 0x0A */ for (;;) { newline = memchr(smsc->buffer, 0x0A, smsc->buflen); if (newline != NULL) break; newline = memchr(smsc->buffer, 0x03, smsc->buflen); if (newline != NULL) break; ret = smscenter_read_into_buffer(smsc); if (ret <= 0) { debug("bb.sms.cimd", 0, "read_into_buffer failed!, ret=%d", ret); goto error; } usleep(500); /* Reconnect if no results in 30 seconds */ if (time(NULL) > (thetime + 30)) { error(0, "timeout occurred, maybe the connection was broken?"); /* Reconnect if neccessary, this catches most of them */ /* XXX this is an ugly kludge, but then again, CIMD 1.3 is an ugly kludge. */ connect_tcpip(smsc); goto no_messages; } } /* if we got an nck, cut the message out and return 0 */ newline = memchr(smsc->buffer, 0x15, smsc->buflen); if (newline != NULL) { newline = memchr(smsc->buffer, 0x0A, smsc->buflen); if (newline == NULL) newline = memchr(smsc->buffer, 0x03, smsc->buflen); smscenter_remove_from_buffer(smsc, newline - smsc->buffer + 1); goto no_messages; } /* miracle of miracles, we got a message */ gw_free(tmpbuff); return 1; no_messages: gw_free(tmpbuff); return 0; error: debug("bb.sms.cimd", 0, "smscenter_pending_smsmessage: returning error"); gw_free(tmpbuff); return -1; } /****************************************************************************** * Send a MT message, returns as in smsc_submit_smsmessage in smsc.h */ int cimd_submit_msg(SMSCenter *smsc, Msg *msg) { char *tmpbuff = NULL, *tmptext = NULL; char msgtext[1024]; int ret; int cmd = 0, err = 0; /* Fix these by implementing a could-not-send-because- protocol-does-not-allow in smsc.c or smsgateway.c */ if (octstr_len(msg->sms.msgdata) + octstr_len(msg->sms.udhdata) < 1) { if (msg->sms.msgdata == NULL) msg->sms.msgdata = octstr_create(""); octstr_append_from_hex(msg->sms.msgdata, "20"); } if (octstr_len(msg->sms.sender) < 1) { warning(0, "cimd_submit_smsmessage: ignoring message with 0-length field"); goto okay; /* THIS IS NOT OKAY!!!! XXX */ } if (octstr_len(msg->sms.receiver) < 1) { warning(0, "cimd_submit_smsmessage: ignoring message with 0-length field"); goto okay; /* THIS IS NOT OKAY!!!! XXX */ } tmpbuff = gw_malloc(10 * 1024); tmptext = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); memset(tmptext, 0, 10*1024); memset(msgtext, 0, sizeof(msgtext)); if (octstr_len(msg->sms.udhdata)) { octstr_get_many_chars(msgtext, msg->sms.udhdata, 0, octstr_len(msg->sms.udhdata)); octstr_get_many_chars(msgtext + octstr_len(msg->sms.udhdata), msg->sms.msgdata, 0, 140 - octstr_len(msg->sms.udhdata)); } else { octstr_get_many_chars(msgtext, msg->sms.msgdata, 0, octstr_len(msg->sms.msgdata)); } /* XXX parse_iso88591_to_cimd should use Octstr * directly, or get a char* and a length, instead of using NUL * terminated strings. */ parse_iso88591_to_cimd(msgtext, tmptext, 10*1024, smsc->alt_charset); /* If messages has UDHs, add the magic number 31 to the right spot */ sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%s%c%s%c%s%c%c", 0x02, "03", 0x09, octstr_get_cstr(msg->sms.receiver), 0x09, tmptext, 0x09, "", 0x09, "", 0x09, (octstr_len(msg->sms.udhdata)) ? "31" : "", 0x09, "11", 0x03, 0x0A); ret = write_to_socket(smsc->socket, tmpbuff); if (ret < 0) { debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: socket write error"); goto error; } /* The Nokia SMSC MAY be configured to send delivery information, which we then will HAVE to acknowledge. Naturally the CIMD 1.3 protocol does not include any kind of negotiation mechanism. */ ret = expect_acknowledge(smsc, &cmd, &err); if (ret >= 1) { if (cmd == 4) { send_acknowledge(smsc); goto okay; } else if (cmd == 3) { goto okay; } } else if (ret == 0) { if (cmd == 4) { send_acknowledge(smsc); goto okay; /* FIXME XXX THIS IS BOGUS, FIX SMSGATEWAY.C */ goto error; } else if (cmd == 3) { goto okay; /* FIXME XXX THIS IS BOGUS, FIX SMSGATEWAY.C */ goto error; } else { error(0, "Unexpected behaviour from the CIMD server"); debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: acknowledge was <%i>", ret); debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: buffer==<%s>", smsc->buffer); goto error; } } okay: gw_free(tmpbuff); gw_free(tmptext); return 0; error: debug("bb.sms.cimd", 0, "cimd_submit_smsmessage: returning error"); gw_free(tmpbuff); gw_free(tmptext); return -1; } int cimd_receive_msg(SMSCenter *smsc, Msg **msg) { char *tmpbuff = NULL, *sender = NULL; char *receiver = NULL, *text = NULL, *scts = NULL; char *tmpchar = NULL; debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: starting"); /* the PENDING function has previously requested for the message and checked that it safely found its way into the memory buffer (smsc->buffer) */ /* we want to temporarily store some data */ tmpbuff = gw_malloc(10 * 1024); sender = gw_malloc(10 * 1024); receiver = gw_malloc(10 * 1024); text = gw_malloc(10 * 1024); scts = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10 * 1024); memset(sender, 0, 10 * 1024); memset(receiver, 0, 10 * 1024); memset(text, 0, 10 * 1024); memset(scts, 0, 10 * 1024); /* cut the raw message out from the message buffer */ tmpchar = memchr(smsc->buffer, 0x0A, smsc->buflen); if (tmpchar == NULL) { tmpchar = memchr(smsc->buffer, 0x03, smsc->buflen); if (tmpchar == NULL) goto error; } strncpy(tmpbuff, smsc->buffer, tmpchar - smsc->buffer); smscenter_remove_from_buffer(smsc, tmpchar - smsc->buffer + 1); /* Parse the raw message */ sscanf(tmpbuff, "\x02\x06\tC:05\t%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\t11\x03\x0A", receiver, sender, text, scts); sscanf(tmpbuff, "\x02\x06\tC:05\t%[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\t11\x03", receiver, sender, text, scts); /* Translate from the CIMD character set to iso8859-1 */ parse_cimd_to_iso88591(text, tmpbuff, 10*1024); strncpy(text, tmpbuff, 480); /* create a smsmessage structure out of the components */ *msg = msg_create(sms); if (*msg == NULL) return -1; (*msg)->sms.sender = octstr_create(sender); (*msg)->sms.receiver = octstr_create(receiver); (*msg)->sms.msgdata = octstr_create(text); /* Send acknowledge */ send_acknowledge(smsc); /* We got a message so we can instantly check for a new one. */ smsc->cimd_last_spoke -= 5; /* Free and Finish */ gw_free(tmpbuff); gw_free(sender); gw_free(receiver); gw_free(text); gw_free(scts); debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: return ok"); return 1; error: debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: failed"); gw_free(tmpbuff); gw_free(sender); gw_free(receiver); gw_free(text); gw_free(scts); debug("bb.sms.cimd", 0, "cimd_receive_smsmessage: return failed"); return -1; } /****************************************************************************** * In(f)ternal Functions */ static int connect_tcpip(SMSCenter *smsc) { char *tmpbuff = NULL; int ret = 0; int cmd = 0, err = 0; debug("bb.sms.cimd", 0, "reconnecting to <%s>", smsc->name); /* allocate some spare space */ tmpbuff = gw_malloc(10 * 1024); memset(tmpbuff, 0, 10*1024); /* Close connection */ close(smsc->socket); smsc->socket = -1; /* Be sure to open a socket. */ for (;;) { smsc->socket = tcpip_connect_to_server( smsc->cimd_hostname, smsc->cimd_port, NULL); /* XXX add interface_name if required */ if (smsc->socket != -1) break; usleep(1000); } /* Empty the buffer, there might be an evil ghost inside... */ memset(smsc->buffer, 0, smsc->bufsize); smsc->buflen = 0; /* Expect the protocol string "CIMD rel 1.37\n" */ for (;;) { ret = smscenter_read_into_buffer(smsc); if (ret < 0) goto logout; if (strstr(smsc->buffer, "CIMD rel 1.37\n") != NULL) break; usleep(1000); } smscenter_remove_from_buffer(smsc, smsc->buflen); /* send login string */ sprintf(tmpbuff, "%c%s%c%s%c%s%c%s%c%c", 0x02, "01", 0x09, smsc->cimd_username, 0x09, smsc->cimd_password, 0x09, "11", 0x03, 0x0A); ret = write_to_socket(smsc->socket, tmpbuff); if (ret < 0) goto logout; /* get an acknowledge message */ smsc->cimd_last_spoke = 0; if (expect_acknowledge(smsc, &cmd, &err) < 1) goto logout; debug("bb.sms.cimd", 0, "cimd_connect_tcpip: logged in"); gw_free(tmpbuff); return 1; logout: close(smsc->socket); gw_free(tmpbuff); return 0; } /****************************************************************************** * Yeah, we got the message! */ static int send_acknowledge(SMSCenter *smsc) { char tmpbuff[100]; int tmpint; if (tmpbuff == NULL) { error(0, "cimd_send_acknowledge: memory allocation failure"); goto error; } memset(tmpbuff, 0, sizeof(tmpbuff)); sprintf(tmpbuff, "\2\6\t11\3\n"); tmpint = write_to_socket(smsc->socket, tmpbuff); if (tmpint == -1) { error(0, "cimd_send_acknowledge: connection failure"); goto error; } return 0; error: debug("bb.sms.cimd", 0, "cimd_send_acknowledge: failed"); return -1; } /****************************************************************************** * Wait for the Nokia piece of *!%&%*^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H SMSC * to catch up with our swift operation, block until... (~1sec?) */ static int expect_acknowledge(SMSCenter *smsc, int *cmd, int *err) { char *end_of_dataset = NULL; char *ack = NULL, *nck = NULL; char *cmdspecifier = NULL, *errorspecifier = NULL; int ret = 0; #if 0 time_t thetime; time(&thetime); #endif if (smsc == NULL) goto error; /* Loop until we get an acknowledgement message. */ for (;;) { /* If the server is configured in to end a dataset with a \n */ end_of_dataset = memchr(smsc->buffer, '\n', smsc->buflen); if (end_of_dataset != NULL) break; /* If the server is configured in to end a dataset with a \3 */ end_of_dataset = memchr(smsc->buffer, 0x03, smsc->buflen); if (end_of_dataset != NULL) break; ret = smscenter_read_into_buffer(smsc); if (ret <= 0) { if (errno == EAGAIN) continue; if (errno == EINTR) continue; return -1; } usleep(500); #if 0 /* Abort if no results in 30 seconds */ if (time(NULL) > (thetime + 30)) { error(0, "timeout occurred, maybe the connection was broken?"); if (errno == EPIPE) { error(0, "broken pipe"); } /* if errno */ goto error; } /* if time */ #endif } /* Check if our request was answered or denied */ ack = memchr(smsc->buffer, 0x06, end_of_dataset - smsc->buffer); nck = memchr(smsc->buffer, 0x15, end_of_dataset - smsc->buffer); /* Get the command code from the acknowledge message */ cmdspecifier = strstr(smsc->buffer, "\tC:"); if (cmdspecifier != NULL) *cmd = strtol(cmdspecifier + 3, NULL, 10); else *cmd = 0; errorspecifier = strstr(smsc->buffer, "\tE:"); if (errorspecifier != NULL) *err = strtol(errorspecifier + 3, NULL, 10); else *err = 0; debug("bb.sms.cimd", 0, "cimd_pending_smsmessage: smsc->buffer == <%s>", smsc->buffer); /* Remove the acknowledge message from the incoming buffer. */ smscenter_remove_from_buffer(smsc, end_of_dataset - smsc->buffer + 1); /* if we got an acknowledge */ if (ack != NULL) { info(0, "cimd_pending_smsmessage: got ACK"); return 1; } /* if we got an NOT acknowledge */ if (nck != NULL) { info(0, "cimd_pending_smsmessage: got NCK"); return 0; } /* if we got an ERROR */ error: error(0, "cimd_expect_acknowledge failed"); return -1; } /****************************************************************************** * Convert a string from ISO-8859-1 to the CIMD character set */ static int parse_iso88591_to_cimd(char* from, char* to, int length, int alt_charset) { char *temp = to; if (from == NULL || to == NULL || length == 0) return -1; *to = '\0'; while ((*from != '\0') && ((int) strlen(temp) < (length - 2))) { switch (*from) { case '@': strcat(to, "_Oa"); to += 3; break; case '£': strcat(to, "_L-"); to += 3; break; case '$': if (alt_charset == CIMD_PLAIN_DOLLAR_SIGN) { strcat(to, "$"); to++; } else { strcat(to, "_$ "); to += 3; } break; case 'Å': strcat(to, "_A*"); to += 3; break; case 'å': strcat(to, "_a*"); to += 3; break; case 'ä': strcat(to, "_a\""); to += 3; break; case 'ö': strcat(to, "_o\""); to += 3; break; case 'Ä': strcat(to, "_A\""); to += 3; break; case 'Ö': strcat(to, "_O\""); to += 3; break; case '¥': strcat(to, "_Y-"); to += 3; break; case 'è': strcat(to, "_e`"); to += 3; break; case 'é': strcat(to, "_e´"); to += 3; break; case 'ù': strcat(to, "_u`"); to += 3; break; case 'ì': strcat(to, "_i`"); to += 3; break; case 'ò': strcat(to, "_o`"); to += 3; break; case 'Ç': strcat(to, "_C,"); to += 3; break; case 'Ø': strcat(to, "_O/"); to += 3; break; case 'ø': strcat(to, "_o/"); to += 3; break; case 'Æ': strcat(to, "_AE"); to += 3; break; case 'æ': strcat(to, "_ae"); to += 3; break; case 'ß': strcat(to, "_ss"); to += 3; break; case 'É': strcat(to, "_E´"); to += 3; break; case '¿': strcat(to, "_??"); to += 3; break; case 'Ü': strcat(to, "_U\""); to += 3; break; case 'ñ': strcat(to, "_n~"); to += 3; break; case 'ü': strcat(to, "_u\""); to += 3; break; case 'à': strcat(to, "_a`"); to += 3; break; case '¡': strcat(to, "_!!"); to += 3; break; case '_': strcat(to, "_--"); to += 3; break; case 'Ñ': strcat(to, "_N~"); to += 3; break; case '!': strcat(to, "!"); to++; break; case '"': strcat(to, "\""); to++; break; case '#': strcat(to, "#"); to++; break; case '¤': strcat(to, "¤"); to++; break; case '%': strcat(to, "%"); to++; break; case '&': strcat(to, "&"); to++; break; case '\'': strcat(to, "'"); to++; break; case '(': strcat(to, "("); to++; break; case ')': strcat(to, ")"); to++; break; case '*': strcat(to, "*"); to++; break; case '+': strcat(to, "+"); to++; break; case ',': strcat(to, ","); to++; break; case '-': strcat(to, "-"); to++; break; case '.': strcat(to, "."); to++; break; case '/': strcat(to, "/"); to++; break; case '0': strcat(to, "0"); to++; break; case '1': strcat(to, "1"); to++; break; case '2': strcat(to, "2"); to++; break; case '3': strcat(to, "3"); to++; break; case '4': strcat(to, "4"); to++; break; case '5': strcat(to, "5"); to++; break; case '6': strcat(to, "6"); to++; break; case '7': strcat(to, "7"); to++; break; case '8': strcat(to, "8"); to++; break; case '9': strcat(to, "9"); to++; break; case ':': strcat(to, ":"); to++; break; case ';': strcat(to, ";"); to++; break; case '<': strcat(to, "<"); to++; break; case '=': strcat(to, "="); to++; break; case '>': strcat(to, ">"); to++; break; case '?': strcat(to, "?"); to++; break; case 'A': strcat(to, "A"); to++; break; case 'B': strcat(to, "B"); to++; break; case 'C': strcat(to, "C"); to++; break; case 'D': strcat(to, "D"); to++; break; case 'E': strcat(to, "E"); to++; break; case 'F': strcat(to, "F"); to++; break; case 'G': strcat(to, "G"); to++; break; case 'H': strcat(to, "H"); to++; break; case 'I': strcat(to, "I"); to++; break; case 'J': strcat(to, "J"); to++; break; case 'K': strcat(to, "K"); to++; break; case 'L': strcat(to, "L"); to++; break; case 'M': strcat(to, "M"); to++; break; case 'N': strcat(to, "N"); to++; break; case 'O': strcat(to, "O"); to++; break; case 'P': strcat(to, "P"); to++; break; case 'Q': strcat(to, "Q"); to++; break; case 'R': strcat(to, "R"); to++; break; case 'S': strcat(to, "S"); to++; break; case 'T': strcat(to, "T"); to++; break; case 'U': strcat(to, "U"); to++; break; case 'V': strcat(to, "V"); to++; break; case 'W': strcat(to, "W"); to++; break; case 'X': strcat(to, "X"); to++; break; case 'Y': strcat(to, "Y"); to++; break; case 'Z': strcat(to, "Z"); to++; break; case 'a': strcat(to, "a"); to++; break; case 'b': strcat(to, "b"); to++; break; case 'c': strcat(to, "c"); to++; break; case 'd': strcat(to, "d"); to++; break; case 'e': strcat(to, "e"); to++; break; case 'f': strcat(to, "f"); to++; break; case 'g': strcat(to, "g"); to++; break; case 'h': strcat(to, "h"); to++; break; case 'i': strcat(to, "i"); to++; break; case 'j': strcat(to, "j"); to++; break; case 'k': strcat(to, "k"); to++; break; case 'l': strcat(to, "l"); to++; break; case 'm': strcat(to, "m"); to++; break; case 'n': strcat(to, "n"); to++; break; case 'o': strcat(to, "o"); to++; break; case 'p': strcat(to, "p"); to++; break; case 'q': strcat(to, "q"); to++; break; case 'r': strcat(to, "r"); to++; break; case 's': strcat(to, "s"); to++; break; case 't': strcat(to, "t"); to++; break; case 'u': strcat(to, "u"); to++; break; case 'v': strcat(to, "v"); to++; break; case 'w': strcat(to, "w"); to++; break; case 'x': strcat(to, "x"); to++; break; case 'y': strcat(to, "y"); to++; break; case 'z': strcat(to, "z"); to++; break; case ' ': strcat(to, " "); to++; break; case '\r': strcat(to, "\r"); to++; break; case '\n': strcat(to, "\n"); to++; break; default: strcat(to, "_??"); to += 3; break; } from++; } *to = '\0'; return strlen(temp); } /****************************************************************************** * Convert a string from the CIMD character set to ISO-8859-1 */ static int parse_cimd_to_iso88591(char* from, char* to, int length) { int my_int, temp_int; *to = '\0'; for (my_int = 0; my_int < (int)strlen(from) && (int)strlen(to) < length; ) { if (from[my_int] == '_' && from[my_int + 1] == 'a' && from[my_int + 2] == '"') { strcat(to, "ä"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'a' && from[my_int + 2] == '*') { strcat(to, "å"); my_int += 3; } /* argh, this drives me nu---uuutts */ else if (from[my_int] == '@') { strcat(to, "@"); my_int ++; } else if (from[my_int] == '_' && from[my_int + 1] == 'O' && from[my_int + 2] == 'a') { strcat(to, "@"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'L' && from[my_int + 2] == '-') { strcat(to, "£"); my_int += 3; } /* this following one is against specifications but what to do * when it works?!? (the other is NOT used) rpr 1.10. */ else if (from[my_int] == '$') { strcat(to, "$"); my_int ++; } else if (from[my_int] == '_' && from[my_int + 1] == '$' && from[my_int + 2] == ' ') { strcat(to, "$"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'A' && from[my_int + 2] == '*') { strcat(to, "Å"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'o' && from[my_int + 2] == '"') { strcat(to, "ö"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'A' && from[my_int + 2] == '"') { strcat(to, "Ä"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'O' && from[my_int + 2] == '"') { strcat(to, "Ö"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'Y' && from[my_int + 2] == '-') { strcat(to, "¥"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'e' && from[my_int + 2] == '`') { strcat(to, "è"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'e' && from[my_int + 2] == '´') { strcat(to, "é"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'u' && from[my_int + 2] == '`') { strcat(to, "ù"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'i' && from[my_int + 2] == '`') { strcat(to, "ì"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'o' && from[my_int + 2] == '`') { strcat(to, "ò"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'C' && from[my_int + 2] == ',') { strcat(to, "Ç"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'O' && from[my_int + 2] == '/') { strcat(to, "Ø"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'o' && from[my_int + 2] == '/') { strcat(to, "ø"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'A' && from[my_int + 2] == 'E') { strcat(to, "Æ"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'a' && from[my_int + 2] == 'e') { strcat(to, "æ"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 's' && from[my_int + 2] == 's') { strcat(to, "ß"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'E' && from[my_int + 2] == '´') { strcat(to, "É"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == '?' && from[my_int + 2] == '?') { strcat(to, "¿"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'U' && from[my_int + 2] == '"') { strcat(to, "Ü"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'n' && from[my_int + 2] == '~' ) { strcat(to, "ñ"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'u' && from[my_int + 2] == '"') { strcat(to, "ü"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'a' && from[my_int + 2] == '`') { strcat(to, "à"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == '!' && from[my_int + 2] == '!') { strcat(to, "¡"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == '-' && from[my_int + 2] == '-') { strcat(to, "_"); my_int += 3; } else if (from[my_int] == '_' && from[my_int + 1] == 'N' && from[my_int + 2] == '~') { strcat(to, "_"); my_int += 3; } /* I just LOVE the designers of this protocol -mg */ else if (from[my_int] == ']') { strcat(to, "Å"); my_int++; } else if (from[my_int] == '}') { strcat(to, "å"); my_int++; } else if (from[my_int] == '[') { strcat(to, "Ä"); my_int++; } else if (from[my_int] == '{') { strcat(to, "ä"); my_int++; } else if (from[my_int] == '\\') { strcat(to, "Ö"); my_int++; } else if (from[my_int] == '|') { strcat(to, "ö"); my_int++; } else if (from[my_int] == '!') { strcat(to, "!"); my_int++; } else if (from[my_int] == '"') { strcat(to, "\""); my_int++; } else if (from[my_int] == '#') { strcat(to, "#"); my_int++; } else if (from[my_int] == '¤') { strcat(to, "¤"); my_int++; } else if (from[my_int] == '%') { strcat(to, "%"); my_int++; } else if (from[my_int] == '&') { strcat(to, "&"); my_int++; } else if (from[my_int] == '\'') { strcat(to, "'"); my_int++; } else if (from[my_int] == '(') { strcat(to, "("); my_int++; } else if (from[my_int] == ')') { strcat(to, ")"); my_int++; } else if (from[my_int] == '*') { strcat(to, "*"); my_int++; } else if (from[my_int] == '+') { strcat(to, "+"); my_int++; } else if (from[my_int] == ',') { strcat(to, ","); my_int++; } else if (from[my_int] == '-') { strcat(to, "-"); my_int++; } else if (from[my_int] == '.') { strcat(to, "."); my_int++; } else if (from[my_int] == '/') { strcat(to, "/"); my_int++; } else if (from[my_int] == '0') { strcat(to, "0"); my_int++; } else if (from[my_int] == '1') { strcat(to, "1"); my_int++; } else if (from[my_int] == '2') { strcat(to, "2"); my_int++; } else if (from[my_int] == '3') { strcat(to, "3"); my_int++; } else if (from[my_int] == '4') { strcat(to, "4"); my_int++; } else if (from[my_int] == '5') { strcat(to, "5"); my_int++; } else if (from[my_int] == '6') { strcat(to, "6"); my_int++; } else if (from[my_int] == '7') { strcat(to, "7"); my_int++; } else if (from[my_int] == '8') { strcat(to, "8"); my_int++; } else if (from[my_int] == '9') { strcat(to, "9"); my_int++; } else if (from[my_int] == ':') { strcat(to, ":"); my_int++; } else if (from[my_int] == ';') { strcat(to, ";"); my_int++; } else if (from[my_int] == '<') { strcat(to, "<"); my_int++; } else if (from[my_int] == '=') { strcat(to, "="); my_int++; } else if (from[my_int] == '>') { strcat(to, ">"); my_int++; } else if (from[my_int] == '?') { strcat(to, "?"); my_int++; } else if (from[my_int] == 'A') { strcat(to, "A"); my_int++; } else if (from[my_int] == 'B') { strcat(to, "B"); my_int++; } else if (from[my_int] == 'C') { strcat(to, "C"); my_int++; } else if (from[my_int] == 'D') { strcat(to, "D"); my_int++; } else if (from[my_int] == 'E') { strcat(to, "E"); my_int++; } else if (from[my_int] == 'F') { strcat(to, "F"); my_int++; } else if (from[my_int] == 'G') { strcat(to, "G"); my_int++; } else if (from[my_int] == 'H') { strcat(to, "H"); my_int++; } else if (from[my_int] == 'I') { strcat(to, "I"); my_int++; } else if (from[my_int] == 'J') { strcat(to, "J"); my_int++; } else if (from[my_int] == 'K') { strcat(to, "K"); my_int++; } else if (from[my_int] == 'L') { strcat(to, "L"); my_int++; } else if (from[my_int] == 'M') { strcat(to, "M"); my_int++; } else if (from[my_int] == 'N') { strcat(to, "N"); my_int++; } else if (from[my_int] == 'O') { strcat(to, "O"); my_int++; } else if (from[my_int] == 'P') { strcat(to, "P"); my_int++; } else if (from[my_int] == 'Q') { strcat(to, "Q"); my_int++; } else if (from[my_int] == 'R') { strcat(to, "R"); my_int++; } else if (from[my_int] == 'S') { strcat(to, "S"); my_int++; } else if (from[my_int] == 'T') { strcat(to, "T"); my_int++; } else if (from[my_int] == 'U') { strcat(to, "U"); my_int++; } else if (from[my_int] == 'V') { strcat(to, "V"); my_int++; } else if (from[my_int] == 'W') { strcat(to, "W"); my_int++; } else if (from[my_int] == 'X') { strcat(to, "X"); my_int++; } else if (from[my_int] == 'Y') { strcat(to, "Y"); my_int++; } else if (from[my_int] == 'Z') { strcat(to, "Z"); my_int++; } else if (from[my_int] == 'a') { strcat(to, "a"); my_int++; } else if (from[my_int] == 'b') { strcat(to, "b"); my_int++; } else if (from[my_int] == 'c') { strcat(to, "c"); my_int++; } else if (from[my_int] == 'd') { strcat(to, "d"); my_int++; } else if (from[my_int] == 'e') { strcat(to, "e"); my_int++; } else if (from[my_int] == 'f') { strcat(to, "f"); my_int++; } else if (from[my_int] == 'g') { strcat(to, "g"); my_int++; } else if (from[my_int] == 'h') { strcat(to, "h"); my_int++; } else if (from[my_int] == 'i') { strcat(to, "i"); my_int++; } else if (from[my_int] == 'j') { strcat(to, "j"); my_int++; } else if (from[my_int] == 'k') { strcat(to, "k"); my_int++; } else if (from[my_int] == 'l') { strcat(to, "l"); my_int++; } else if (from[my_int] == 'm') { strcat(to, "m"); my_int++; } else if (from[my_int] == 'n') { strcat(to, "n"); my_int++; } else if (from[my_int] == 'o') { strcat(to, "o"); my_int++; } else if (from[my_int] == 'p') { strcat(to, "p"); my_int++; } else if (from[my_int] == 'q') { strcat(to, "q"); my_int++; } else if (from[my_int] == 'r') { strcat(to, "r"); my_int++; } else if (from[my_int] == 's') { strcat(to, "s"); my_int++; } else if (from[my_int] == 't') { strcat(to, "t"); my_int++; } else if (from[my_int] == 'u') { strcat(to, "u"); my_int++; } else if (from[my_int] == 'v') { strcat(to, "v"); my_int++; } else if (from[my_int] == 'w') { strcat(to, "w"); my_int++; } else if (from[my_int] == 'x') { strcat(to, "x"); my_int++; } else if (from[my_int] == 'y') { strcat(to, "y"); my_int++; } else if (from[my_int] == 'z') { strcat(to, "z"); my_int++; } else if (from[my_int] == ' ') { strcat(to, " "); my_int++; } else if (from[my_int] == '\r') { strcat(to, "\r"); my_int++; } else if (from[my_int] == '\n') { strcat(to, "\n"); my_int++; } else { /* of course it might be that nothing happened */ debug("bb.sms.cimd", 0, "parse: [%c:%02X %c:%02X %c:%02X]", from[my_int], from[my_int], from[my_int + 1], from[my_int + 1], from[my_int + 2], from[my_int + 2]); temp_int = strlen(to); to[temp_int] = 0xBF; /* '¿' */ to[temp_int + 1] = '\0'; my_int++; } } /* for */ return strlen(to); } gateway-1.4.5/gw/smsc/smsc_http.c0000644000175000017500000011216213227613126015424 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_http.c - interface to various HTTP based content/SMS gateways * * HTTP based "SMSC Connection" is meant for gateway connections, * and has following features: * * o Kannel listens to certain (HTTP server) port for MO SMS messages. * The exact format of these HTTP calls are defined by type of HTTP based * connection. Kannel replies to these messages as ACK, but does not * support immediate reply. Thus, if Kannel is linked to another Kannel, * only 'max-messages = 0' services are practically supported - any * replies must be done with SMS PUSH (sendsms) * * o For MT messages, Kannel does HTTP GET or POST to given address, in format * defined by type of HTTP based protocol * * The 'type' of requests and replies are defined by 'system-type' variable. * The only type of HTTP requests currently supported are basic Kannel. * If new support is added, smsc_http_create is modified accordingly and new * functions added. * * * KANNEL->KANNEL linking: (UDH not supported in MO messages) * ***** * FOR CLIENT/END-POINT KANNEL: * * group = smsc * smsc = http * system-type = kannel * port = NNN * smsc-username = XXX * smsc-password = YYY * send-url = "server.host:PORT" * ***** * FOR SERVER/RELAY KANNEL: * * group = smsbox * sendsms-port = PORT * ... * * group = sms-service * keyword = ... * url = "client.host:NNN/sms?user=XXX&pass=YYY&from=%p&to=%P&text=%a" * max-messages = 0 * * group = send-sms * username = XXX * password = YYY * * Kalle Marjola for Project Kannel 2001 * Stipe Tolj * Alexander Malysh * Tobias Weber */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smscconn.h" #include "smscconn_p.h" #include "bb_smscconn_cb.h" #include "msg.h" #include "sms.h" #include "dlr.h" #include "urltrans.h" #include "meta_data.h" #define DEFAULT_CHARSET "UTF-8" #define DEFAULT_UCS2_CHARSET "UTF-16BE" /* callback functions set by HTTP-SMSC type */ struct smsc_http_fn_callbacks { int (*init) (SMSCConn *conn, CfgGroup *cfg); void (*destroy) (SMSCConn *conn); int (*send_sms) (SMSCConn *conn, Msg *msg); void (*parse_reply) (SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body); void (*receive_sms) (SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars); }; typedef struct conndata { HTTPCaller *http_ref; long receive_thread; long send_cb_thread; long sender_thread; volatile int shutdown; long port; /* port for receiving SMS'es */ Octstr *allow_ip; Octstr *send_url; Octstr *dlr_url; Counter *open_sends; Semaphore *max_pending_sends; Octstr *username; /* if needed */ Octstr *password; /* as said */ Octstr *system_id; /* api id for clickatell */ int no_sender; /* ditto */ int no_coding; /* this, too */ int no_sep; /* not to mention this */ Octstr *proxy; /* proxy a constant string */ Octstr *alt_charset; /* alternative charset use */ List *msg_to_send; /* our send queue */ /* callback functions set by HTTP-SMSC type */ struct smsc_http_fn_callbacks *callbacks; /* submodule specific data */ void *data; } ConnData; static void conndata_destroy(ConnData *conndata) { if (conndata == NULL) return; if (conndata->http_ref) http_caller_destroy(conndata->http_ref); octstr_destroy(conndata->allow_ip); octstr_destroy(conndata->send_url); octstr_destroy(conndata->dlr_url); octstr_destroy(conndata->username); octstr_destroy(conndata->password); octstr_destroy(conndata->proxy); octstr_destroy(conndata->system_id); octstr_destroy(conndata->alt_charset); counter_destroy(conndata->open_sends); gwlist_destroy(conndata->msg_to_send, NULL); if (conndata->max_pending_sends) semaphore_destroy(conndata->max_pending_sends); gw_free(conndata); } /* * Thread to listen to HTTP requests from SMSC entity */ static void httpsmsc_receiver(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; HTTPClient *client; Octstr *ip, *url, *body; List *headers, *cgivars; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while (conndata->shutdown == 0) { /* reset */ ip = url = body = NULL; headers = cgivars = NULL; /* XXX if conn->is_stopped, do not receive new messages.. */ client = http_accept_request(conndata->port, &ip, &url, &headers, &body, &cgivars); if (client == NULL) break; if (cgivars != NULL) { octstr_append_char(url, '?'); http_cgivar_dump_into(cgivars, url); } debug("smsc.http", 0, "HTTP[%s]: Got request `%s'", octstr_get_cstr(conn->id), octstr_get_cstr(url)); if (connect_denied(conndata->allow_ip, ip)) { info(0, "HTTP[%s]: Connection `%s' tried from denied " "host %s, ignored", octstr_get_cstr(conn->id), octstr_get_cstr(url), octstr_get_cstr(ip)); http_close_client(client); } else conndata->callbacks->receive_sms(conn, client, headers, body, cgivars); debug("smsc.http", 0, "HTTP[%s]: Destroying client information", octstr_get_cstr(conn->id)); octstr_destroy(url); octstr_destroy(ip); octstr_destroy(body); http_destroy_headers(headers); http_destroy_cgiargs(cgivars); } debug("smsc.http", 0, "HTTP[%s]: httpsmsc_receiver dying", octstr_get_cstr(conn->id)); conndata->shutdown = 1; http_close_port(conndata->port); /* unblock http_receive_result() if there are no open sends */ if (counter_value(conndata->open_sends) == 0) http_caller_signal_shutdown(conndata->http_ref); if (conndata->sender_thread != -1) { gwthread_wakeup(conndata->sender_thread); gwthread_join(conndata->sender_thread); } if (conndata->send_cb_thread != -1) { gwthread_wakeup(conndata->send_cb_thread); gwthread_join(conndata->send_cb_thread); } mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; mutex_unlock(conn->flow_mutex); if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL) conndata->callbacks->destroy(conn); conn->data = NULL; conndata_destroy(conndata); bb_smscconn_killed(); } /* * Thread to send queued messages */ static void httpsmsc_sender(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; Msg *msg; double delay = 0; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); if (conn->throughput) { delay = 1.0 / conn->throughput; } while (conndata->shutdown == 0) { /* check if we can send ; otherwise block on semaphore */ if (conndata->max_pending_sends) semaphore_down(conndata->max_pending_sends); if (conndata->shutdown) { if (conndata->max_pending_sends) semaphore_up(conndata->max_pending_sends); break; } msg = gwlist_consume(conndata->msg_to_send); if (msg == NULL) break; /* obey throughput speed limit, if any */ if (conn->throughput > 0) { gwthread_sleep(delay); } counter_increase(conndata->open_sends); if (conndata->callbacks->send_sms(conn, msg) == -1) { counter_decrease(conndata->open_sends); if (conndata->max_pending_sends) semaphore_up(conndata->max_pending_sends); } } /* put outstanding sends back into global queue */ while((msg = gwlist_extract_first(conndata->msg_to_send))) bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); /* if there no receiver shutdown */ if (conndata->port <= 0) { /* unblock http_receive_result() if there are no open sends */ if (counter_value(conndata->open_sends) == 0) http_caller_signal_shutdown(conndata->http_ref); if (conndata->send_cb_thread != -1) { gwthread_wakeup(conndata->send_cb_thread); gwthread_join(conndata->send_cb_thread); } mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_DEAD; mutex_unlock(conn->flow_mutex); if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL) conndata->callbacks->destroy(conn); conn->data = NULL; conndata_destroy(conndata); bb_smscconn_killed(); } } /* * Thread to handle finished sendings */ static void httpsmsc_send_cb(void *arg) { SMSCConn *conn = arg; ConnData *conndata = conn->data; Msg *msg; int status; List *headers; Octstr *final_url, *body; /* Make sure we log into our own log-file if defined */ log_thread_to(conn->log_idx); while(conndata->shutdown == 0 || counter_value(conndata->open_sends)) { msg = http_receive_result(conndata->http_ref, &status, &final_url, &headers, &body); if (msg == NULL) break; /* they told us to die, by unlocking */ counter_decrease(conndata->open_sends); if (conndata->max_pending_sends) semaphore_up(conndata->max_pending_sends); /* Handle various states here. */ /* request failed and we are not in shutdown mode */ if (status == -1 && conndata->shutdown == 0) { error(0, "HTTP[%s]: Couldn't connect to SMS center." "(retrying in %ld seconds) %ld.", octstr_get_cstr(conn->id), conn->reconnect_delay, counter_value(conndata->open_sends)); mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_RECONNECTING; mutex_unlock(conn->flow_mutex); /* XXX how should we know whether it's temp. error ?? */ bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_TEMPORARILY, NULL); /* * Just sleep reconnect delay and set conn to ACTIVE again; * otherwise if no pending request are here, we leave conn in * RECONNECTING state for ever and no routing (trials) take place. */ if (counter_value(conndata->open_sends) == 0) { gwthread_sleep(conn->reconnect_delay); /* and now enable routing again */ mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; time(&conn->connect_time); mutex_unlock(conn->flow_mutex); /* tell bearerbox core that we are connected again */ bb_smscconn_connected(conn); } continue; } /* request failed and we *are* in shutdown mode, drop the message */ else if (status == -1 && conndata->shutdown == 1) { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL); } /* request succeeded */ else { /* we received a response, so this link is considered online again */ if (conn->status != SMSCCONN_ACTIVE) { mutex_lock(conn->flow_mutex); conn->status = SMSCCONN_ACTIVE; time(&conn->connect_time); mutex_unlock(conn->flow_mutex); /* tell bearerbox core that we are connected again */ bb_smscconn_connected(conn); } conndata->callbacks->parse_reply(conn, msg, status, headers, body); } http_destroy_headers(headers); octstr_destroy(final_url); octstr_destroy(body); } debug("smsc.http", 0, "HTTP[%s]: httpsmsc_send_cb dying", octstr_get_cstr(conn->id)); conndata->shutdown = 1; if (counter_value(conndata->open_sends)) { warning(0, "HTTP[%s]: Shutdown while <%ld> requests are pending.", octstr_get_cstr(conn->id), counter_value(conndata->open_sends)); } } /*---------------------------------------------------------------- * SMSC-type specific functions * * 3 functions are needed for each: * * 1) send SMS * 2) parse send SMS result * 3) receive SMS (and send reply) * * These functions do not return anything and do not destroy * arguments. They must handle everything that happens therein * and must call appropriate bb_smscconn functions */ /*---------------------------------------------------------------- * Kannel * * This type allows concatenation of Kannel instances, ie: * * ----HTTP-- * * Where MT messages are injected via the sendsms HTTP interface at smsbox1, * forwarded to bearerbo1 and routed via the SMSC HTTP type kannel to * sendsms HTTP interface of smsbox2 and further on. * * This allows chaining of Kannel instances for MO and MT traffic. * * DLR handling: * For DLR handling we have the usual effect that the "last" smsbox instance * of the chain is signaling the DLR-URL, since the last instance receives * the DLR from the upstream SMSC and the associated smsbox triggers the * DLR-URL. * For some considerations this is not what we want. If we want to transport * the orginal DLR-URL to the "first" smsbox instance of the calling chain * then we need to define a 'dlr-url' config directive in the smsc group. * This value defines the inbound MO/DLR port of our own smsc group and * maps arround the orginal DLR-URL. So the next smsbox does not signal the * orginal DLR-URL, but our own smsc group instance with the DLR, and we can * forward on to smsbox and possibly further on the chain to the first * instance. * * Example: (consider the 2 chain architecture from above) * A MT is put to smsbox1 with dlr-url=http://foobar/aaa as DLR-URL. The MT * is forwarded to bearerbox. * If no 'dlr-url' is given in the smsc HTTP for the next smsbox2, then we * simply pass the same value to smsbox2. Resulting that smsbox2 will call * the DLR-URL when we receive a DLR from the upstream SMSC connection of * bearerbox2. * If 'dlr-url = http://localhost:15015/' is given in the smsc HTTP for the * next smsbox2, then we map the orginal DLR-URL into this value, resulting * in a dlr-url=http://lcoalhost:15015/&dlr-url=http://foobar/aaa call to * smsbox2. So smsbox2 is not signaling http://foobar/aaa directly, but our * own bearerbox1's smsc HTTP port for MO/DLR receive. */ enum { HEX_NOT_UPPERCASE = 0 }; static int kannel_send_sms(SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; Octstr *url; List *headers; if (!conndata->no_sep) { url = octstr_format("%S?" "username=%E&password=%E&to=%E&text=%E", conndata->send_url, conndata->username, conndata->password, sms->sms.receiver, sms->sms.msgdata); } else { Octstr *msgdata = octstr_duplicate(sms->sms.msgdata); octstr_binary_to_hex(msgdata, HEX_NOT_UPPERCASE); url = octstr_format("%S?" "username=%E&password=%E&to=%E&text=%S", conndata->send_url, conndata->username, conndata->password, sms->sms.receiver, msgdata); octstr_destroy(msgdata); } if (octstr_len(sms->sms.udhdata)) { if (!conndata->no_sep) { octstr_format_append(url, "&udh=%E", sms->sms.udhdata); } else { Octstr *udhdata = octstr_duplicate(sms->sms.udhdata); octstr_binary_to_hex(udhdata, HEX_NOT_UPPERCASE); octstr_format_append(url, "&udh=%S", udhdata); octstr_destroy(udhdata); } } if (!conndata->no_sender) octstr_format_append(url, "&from=%E", sms->sms.sender); if (sms->sms.mclass != MC_UNDEF) octstr_format_append(url, "&mclass=%d", sms->sms.mclass); if (!conndata->no_coding && sms->sms.coding != DC_UNDEF) octstr_format_append(url, "&coding=%d", sms->sms.coding); /* Obey that smsbox's sendsms HTTP interface is still expecting * WINDOWS-1252 as default charset, while all other internal parts * use UTF-8 as internal encoding. This means, when we pass a SMS * into a next Kannel instance, we need to let the smsbox know which * charset we have in use. * XXX TODO: change smsbox interface to use UTF-8 as default * in next major release. */ if (sms->sms.coding == DC_7BIT) octstr_append_cstr(url, "&charset=UTF-8"); else if (sms->sms.coding == DC_UCS2) octstr_append_cstr(url, "&charset=UTF-16BE"); if (sms->sms.mwi != MWI_UNDEF) octstr_format_append(url, "&mwi=%d", sms->sms.mwi); if (sms->sms.account) /* prepend account with local username */ octstr_format_append(url, "&account=%E:%E", sms->sms.service, sms->sms.account); if (sms->sms.binfo) /* prepend billing info */ octstr_format_append(url, "&binfo=%S", sms->sms.binfo); if (sms->sms.smsc_id) /* proxy the smsc-id to the next instance */ octstr_format_append(url, "&smsc=%S", sms->sms.smsc_id); if (conndata->dlr_url) { char id[UUID_STR_LEN + 1]; Octstr *mid; /* create Octstr from UUID */ uuid_unparse(sms->sms.id, id); mid = octstr_create(id); octstr_format_append(url, "&dlr-url=%E", conndata->dlr_url); /* encapsulate the original DLR-URL, escape code for DLR mask * and message id */ octstr_format_append(url, "%E%E%E%E%E", octstr_imm("&dlr-url="), sms->sms.dlr_url != NULL ? sms->sms.dlr_url : octstr_imm(""), octstr_imm("&dlr-mask=%d"), octstr_imm("&dlr-mid="), mid); octstr_destroy(mid); } else if (sms->sms.dlr_url != NULL) octstr_format_append(url, "&dlr-url=%E", sms->sms.dlr_url); if (sms->sms.dlr_mask != DLR_UNDEFINED && sms->sms.dlr_mask != DLR_NOTHING) octstr_format_append(url, "&dlr-mask=%d", sms->sms.dlr_mask); if (sms->sms.validity != SMS_PARAM_UNDEFINED) octstr_format_append(url, "&validity=%ld", (sms->sms.validity - time(NULL)) / 60); if (sms->sms.deferred != SMS_PARAM_UNDEFINED) octstr_format_append(url, "&deferred=%ld", (sms->sms.deferred - time(NULL)) / 60); headers = gwlist_create(); debug("smsc.http.kannel", 0, "HTTP[%s]: Start request", octstr_get_cstr(conn->id)); http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, NULL, 0, sms, NULL); octstr_destroy(url); http_destroy_headers(headers); return 0; } static void kannel_parse_reply(SMSCConn *conn, Msg *msg, int status, List *headers, Octstr *body) { /* Test on three cases: * 1. an smsbox reply of an remote kannel instance * 2. an smsc_http response (if used for MT to MO looping) * 3. an smsbox reply of partly successful sendings */ if ((status == HTTP_OK || status == HTTP_ACCEPTED) && (octstr_case_compare(body, octstr_imm("0: Accepted for delivery")) == 0 || octstr_case_compare(body, octstr_imm("Sent.")) == 0 || octstr_case_compare(body, octstr_imm("Ok.")) == 0 || octstr_ncompare(body, octstr_imm("Result: OK"),10) == 0)) { char id[UUID_STR_LEN + 1]; Octstr *mid; /* create Octstr from UUID */ uuid_unparse(msg->sms.id, id); mid = octstr_create(id); /* add to our own DLR storage */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) dlr_add(conn->id, mid, msg, 0); octstr_destroy(mid); bb_smscconn_sent(conn, msg, NULL); } else { bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body)); } } static void kannel_receive_sms(SMSCConn *conn, HTTPClient *client, List *headers, Octstr *body, List *cgivars) { ConnData *conndata = conn->data; Octstr *user, *pass, *from, *to, *text, *udh, *account, *binfo, *charset; Octstr *dlrmid, *dlrerr; Octstr *tmp_string, *retmsg; int mclass, mwi, coding, validity, deferred, dlrmask; List *reply_headers; int ret; mclass = mwi = coding = validity = deferred = dlrmask = SMS_PARAM_UNDEFINED; user = http_cgi_variable(cgivars, "username"); pass = http_cgi_variable(cgivars, "password"); from = http_cgi_variable(cgivars, "from"); to = http_cgi_variable(cgivars, "to"); text = http_cgi_variable(cgivars, "text"); udh = http_cgi_variable(cgivars, "udh"); charset = http_cgi_variable(cgivars, "charset"); account = http_cgi_variable(cgivars, "account"); binfo = http_cgi_variable(cgivars, "binfo"); dlrmid = http_cgi_variable(cgivars, "dlr-mid"); tmp_string = http_cgi_variable(cgivars, "flash"); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%d", &mclass); } tmp_string = http_cgi_variable(cgivars, "mclass"); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%d", &mclass); } tmp_string = http_cgi_variable(cgivars, "mwi"); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%d", &mwi); } tmp_string = http_cgi_variable(cgivars, "coding"); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%d", &coding); } tmp_string = http_cgi_variable(cgivars, "validity"); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%d", &validity); } tmp_string = http_cgi_variable(cgivars, "deferred"); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%d", &deferred); } tmp_string = http_cgi_variable(cgivars, "dlr-mask"); if (tmp_string) { sscanf(octstr_get_cstr(tmp_string),"%d", &dlrmask); } dlrerr = http_cgi_variable(cgivars, "dlr-err"); debug("smsc.http.kannel", 0, "HTTP[%s]: Received an HTTP request", octstr_get_cstr(conn->id)); if (user == NULL || pass == NULL || octstr_compare(user, conndata->username) != 0 || octstr_compare(pass, conndata->password) != 0) { error(0, "HTTP[%s]: Authorization failure", octstr_get_cstr(conn->id)); retmsg = octstr_create("Authorization failed for sendsms"); } else if (dlrmask != 0 && dlrmid != NULL) { /* we got a DLR, and we don't require additional values */ Msg *dlrmsg; dlrmsg = dlr_find(conn->id, dlrmid, /* message id */ to, /* destination */ dlrmask, 0); if (dlrmsg != NULL) { dlrmsg->sms.sms_type = report_mo; dlrmsg->sms.msgdata = octstr_duplicate(text); dlrmsg->sms.account = octstr_duplicate(conndata->username); debug("smsc.http.kannel", 0, "HTTP[%s]: Received DLR for DLR-URL <%s>", octstr_get_cstr(conn->id), octstr_get_cstr(dlrmsg->sms.dlr_url)); if (dlrerr != NULL) { /* pass errorcode as is */ if (dlrmsg->sms.meta_data == NULL) dlrmsg->sms.meta_data = octstr_create(""); meta_data_set_value(dlrmsg->sms.meta_data, METADATA_DLR_GROUP, octstr_imm(METADATA_DLR_GROUP_ERRORCODE), dlrerr, 1); } ret = bb_smscconn_receive(conn, dlrmsg); if (ret == -1) retmsg = octstr_create("Not accepted"); else retmsg = octstr_create("Sent."); } else { error(0,"HTTP[%s]: Got DLR but could not find message or was not interested " "in it id<%s> dst<%s>, type<%d>", octstr_get_cstr(conn->id), octstr_get_cstr(dlrmid), octstr_get_cstr(to), dlrmask); retmsg = octstr_create("Unknown DLR, not accepted"); } } else if (from == NULL || to == NULL || text == NULL) { error(0, "HTTP[%s]: Insufficient args", octstr_get_cstr(conn->id)); retmsg = octstr_create("Insufficient args, rejected"); } else if (udh != NULL && (octstr_len(udh) != octstr_get_char(udh, 0) + 1)) { error(0, "HTTP[%s]: UDH field misformed, rejected", octstr_get_cstr(conn->id)); retmsg = octstr_create("UDH field misformed, rejected"); } else if (udh != NULL && octstr_len(udh) > MAX_SMS_OCTETS) { error(0, "HTTP[%s]: UDH field is too long, rejected", octstr_get_cstr(conn->id)); retmsg = octstr_create("UDH field is too long, rejected"); } else { /* we got a normal MO SMS */ Msg *msg; msg = msg_create(sms); debug("smsc.http.kannel", 0, "HTTP[%s]: Constructing new SMS", octstr_get_cstr(conn->id)); msg->sms.service = octstr_duplicate(user); msg->sms.sender = octstr_duplicate(from); msg->sms.receiver = octstr_duplicate(to); msg->sms.msgdata = octstr_duplicate(text); msg->sms.udhdata = octstr_duplicate(udh); msg->sms.smsc_id = octstr_duplicate(conn->id); msg->sms.time = time(NULL); msg->sms.mclass = mclass; msg->sms.mwi = mwi; msg->sms.coding = coding; msg->sms.validity = (validity == SMS_PARAM_UNDEFINED ? validity : time(NULL) + validity * 60); msg->sms.deferred = (deferred == SMS_PARAM_UNDEFINED ? deferred : time(NULL) + deferred * 60); msg->sms.account = octstr_duplicate(account); msg->sms.binfo = octstr_duplicate(binfo); /* re-encode content if necessary */ if (sms_charset_processing(charset, msg->sms.msgdata, msg->sms.coding) == -1) { error(0, "HTTP[%s]: Charset or body misformed, rejected", octstr_get_cstr(conn->id)); retmsg = octstr_create("Charset or body misformed, rejected"); } else { ret = bb_smscconn_receive(conn, msg); if (ret == -1) retmsg = octstr_create("Not accepted"); else retmsg = octstr_create("Sent."); } } reply_headers = gwlist_create(); http_header_add(reply_headers, "Content-Type", "text/plain"); debug("smsc.http.kannel", 0, "HTTP[%s]: Sending reply", octstr_get_cstr(conn->id)); http_send_reply(client, HTTP_ACCEPTED, reply_headers, retmsg); octstr_destroy(retmsg); http_destroy_headers(reply_headers); } struct smsc_http_fn_callbacks smsc_http_kannel_callback = { .send_sms = kannel_send_sms, .parse_reply = kannel_parse_reply, .receive_sms = kannel_receive_sms, }; /*----------------------------------------------------------------- * functions to implement various smscconn operations */ static int httpsmsc_send(SMSCConn *conn, Msg *msg) { ConnData *conndata = conn->data; Msg *sms; /* don't crash if no send_sms handle defined */ if (!conndata || !conndata->callbacks->send_sms) return -1; sms = msg_duplicate(msg); /* convert character encoding if required */ if (conndata->alt_charset) { /* * Converted now to the target character set based on the * one we got in the msg, which is either UTF-8 (our normal * inter-box encoding), but may also be UCS-2, so beware. * In addition, IF we convert to an "extra" encoding here * we also revert the .coding vaue to DC_UNDEF, in order * that all API specific code doesn't indicate an encoding * which is no longer inside the payload here. */ if (sms->sms.coding == DC_7BIT) { if (charset_convert(sms->sms.msgdata, DEFAULT_CHARSET, octstr_get_cstr(conndata->alt_charset)) == 0) { sms->sms.coding = DC_UNDEF; } else { error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.", DEFAULT_CHARSET, octstr_get_cstr(conndata->alt_charset)); } } else if (sms->sms.coding == DC_UCS2) { if (charset_convert(sms->sms.msgdata, DEFAULT_UCS2_CHARSET, octstr_get_cstr(conndata->alt_charset)) == 0) { sms->sms.coding = DC_UNDEF; } else { error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.", DEFAULT_UCS2_CHARSET, octstr_get_cstr(conndata->alt_charset)); } } } gwlist_produce(conndata->msg_to_send, sms); return 0; } static long httpsmsc_queued(SMSCConn *conn) { ConnData *conndata = conn->data; conn->load = (conndata ? (conn->status != SMSCCONN_DEAD ? gwlist_len(conndata->msg_to_send) : 0) : 0); return conn->load; } static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending) { ConnData *conndata = conn->data; if (conndata == NULL) return 0; debug("httpsmsc_shutdown", 0, "HTTP[%s]: Shutting down", octstr_get_cstr(conn->id)); mutex_lock(conn->flow_mutex); conn->why_killed = SMSCCONN_KILLED_SHUTDOWN; conndata->shutdown = 1; if (conndata->port > 0) http_close_port(conndata->port); gwlist_remove_producer(conndata->msg_to_send); if (conndata->receive_thread != -1) gwthread_wakeup(conndata->receive_thread); if (conndata->sender_thread != -1) gwthread_wakeup(conndata->sender_thread); mutex_unlock(conn->flow_mutex); return 0; } #include "http/generic.c" #include "http/brunet.c" #include "http/xidris.c" #include "http/clickatell.c" int smsc_http_create(SMSCConn *conn, CfgGroup *cfg) { ConnData *conndata = NULL; Octstr *type; int ssl = 0; /* indicate if SSL-enabled server should be used */ long max_ps; if ((type = cfg_get(cfg, octstr_imm("system-type"))) == NULL) { error(0, "HTTP[%s]: 'system-type' missing in smsc 'http' record.", octstr_get_cstr(conn->id)); octstr_destroy(type); return -1; } conndata = gw_malloc(sizeof(ConnData)); /* reset conndata */ memset(conndata, 0, sizeof(ConnData)); conn->data = conndata; conndata->http_ref = NULL; conndata->data = NULL; if (cfg_get_integer(&conndata->port, cfg, octstr_imm("port")) == -1) { warning(0, "HTTP[%s]: 'port' not set in smsc 'http' group.", octstr_get_cstr(conn->id)); conndata->port = -1; } conndata->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip")); conndata->send_url = cfg_get(cfg, octstr_imm("send-url")); conndata->username = cfg_get(cfg, octstr_imm("smsc-username")); conndata->password = cfg_get(cfg, octstr_imm("smsc-password")); conndata->system_id = cfg_get(cfg, octstr_imm("system-id")); cfg_get_bool(&conndata->no_sender, cfg, octstr_imm("no-sender")); cfg_get_bool(&conndata->no_coding, cfg, octstr_imm("no-coding")); cfg_get_bool(&conndata->no_sep, cfg, octstr_imm("no-sep")); conndata->proxy = cfg_get(cfg, octstr_imm("system-id")); cfg_get_bool(&ssl, cfg, octstr_imm("use-ssl")); conndata->dlr_url = cfg_get(cfg, octstr_imm("dlr-url")); conndata->alt_charset = cfg_get(cfg, octstr_imm("alt-charset")); if (cfg_get_integer(&max_ps, cfg, octstr_imm("max-pending-submits")) == -1 || max_ps < 1) max_ps = 10; conndata->max_pending_sends = semaphore_create(max_ps); if (conndata->port <= 0 && conndata->send_url == NULL) { error(0, "Sender and receiver disabled. Dummy SMSC not allowed."); goto error; } if (conndata->send_url == NULL) panic(0, "HTTP[%s]: Sending not allowed. No 'send-url' specified.", octstr_get_cstr(conn->id)); if (octstr_case_compare(type, octstr_imm("kannel")) == 0) { if (conndata->username == NULL || conndata->password == NULL) { error(0, "HTTP[%s]: 'username' and 'password' required for Kannel http smsc", octstr_get_cstr(conn->id)); goto error; } conndata->callbacks = &smsc_http_kannel_callback; } else if (octstr_case_compare(type, octstr_imm("brunet")) == 0) { conndata->callbacks = &smsc_http_brunet_callback; } else if (octstr_case_compare(type, octstr_imm("xidris")) == 0) { conndata->callbacks = &smsc_http_xidris_callback; } else if (octstr_case_compare(type, octstr_imm("generic")) == 0) { conndata->callbacks = &smsc_http_generic_callback; } else if (octstr_case_compare(type, octstr_imm("clickatell")) == 0) { conndata->callbacks = &smsc_http_clickatell_callback; } /* * ADD NEW HTTP SMSC TYPES HERE */ else { error(0, "HTTP[%s]: system-type '%s' unknown smsc 'http' record.", octstr_get_cstr(conn->id), octstr_get_cstr(type)); goto error; } if (conndata->callbacks != NULL && conndata->callbacks->init != NULL && conndata->callbacks->init(conn, cfg)) { error(0, "HTTP[%s]: submodule '%s' init failed.", octstr_get_cstr(conn->id), octstr_get_cstr(type)); goto error; } conndata->open_sends = counter_create(); conndata->msg_to_send = gwlist_create(); gwlist_add_producer(conndata->msg_to_send); conndata->http_ref = http_caller_create(); conn->name = octstr_format("HTTP%s:%S:%d", (ssl?"S":""), type, conndata->port); if (conndata->send_url != NULL) { conn->status = SMSCCONN_ACTIVE; } else { conn->status = SMSCCONN_ACTIVE_RECV; } conn->connect_time = time(NULL); conn->shutdown = httpsmsc_shutdown; conn->queued = httpsmsc_queued; conn->send_msg = httpsmsc_send; conndata->shutdown = 0; /* start receiver thread */ if (conndata->port > 0) { if (http_open_port(conndata->port, ssl) == -1) goto error; if ((conndata->receive_thread = gwthread_create(httpsmsc_receiver, conn)) == -1) goto error; } else conndata->receive_thread = -1; /* start sender threads */ if (conndata->send_url) { if ((conndata->send_cb_thread = gwthread_create(httpsmsc_send_cb, conn)) == -1) goto error; if ((conndata->sender_thread = gwthread_create(httpsmsc_sender, conn)) == -1) goto error; } else { conndata->send_cb_thread = conndata->sender_thread = -1; } info(0, "HTTP[%s]: Initiated and ready", octstr_get_cstr(conn->id)); octstr_destroy(type); return 0; error: error(0, "HTTP[%s]: Failed to create HTTP SMSC connection", octstr_get_cstr(conn->id)); if (conndata->callbacks != NULL && conndata->callbacks->destroy != NULL) conndata->callbacks->destroy(conn); conn->data = NULL; conndata_destroy(conndata); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; octstr_destroy(type); return -1; } gateway-1.4.5/gw/smsc/smasi_pdu.c0000644000175000017500000002173113227613126015405 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_smasi.c - parse and generate SMASI PDUs * * Stipe Tolj */ #include #include "smasi_pdu.h" static Octstr *decode_type(Octstr *os) { long p1, p2; Octstr *temp; if ((p2 = octstr_search_char(os, ':', 0)) == -1) return NULL; if ((p1 = octstr_search_char(os, '!', 0)) != -1 && p1 < p2) { p1++; } else { p1 = 0; } temp = octstr_copy(os, p1, p2 - p1); return temp; } static Octstr *copy_until_coma(Octstr *os, long *pos) { long nul; Octstr *data; nul = octstr_search_char(os, ',', *pos); if (nul == -1) { warning(0, "SMASI: Parameter without value or value not properly terminated: %s", octstr_get_cstr(os)); return NULL; } data = octstr_copy(os, *pos, nul - *pos); *pos = nul + 1; return data; } static Octstr *copy_until_assign(Octstr *os, long *pos) { long nul; Octstr *data; nul = octstr_search_char(os, '=', *pos); if (nul == -1 && (octstr_len(os) - *pos) > 1) { warning(0, "SMASI: Garbage at end of parameter list: %s", octstr_get_cstr(os)); *pos = octstr_len(os); return NULL; } data = octstr_copy(os, *pos, nul - *pos); *pos = nul + 1; return data; } static void skip_until_after_colon(Octstr *os, long *pos) { long colon = octstr_search_char(os, ':', *pos); if (colon == -1) warning(0, "SMASI: No colon after SMASI PDU name: %s", octstr_get_cstr(os)); *pos = colon + 1; } SMASI_PDU *smasi_pdu_create(unsigned long type) { SMASI_PDU *pdu; pdu = gw_malloc(sizeof(*pdu)); pdu->type = type; switch (type) { #define NONTERMINATED(name) p->name = NULL; #define COMATERMINATED(name) p->name = NULL; #define PDU(name, id, fields) \ case id: { \ struct name *p = &pdu->u.name; \ pdu->type_name = #name; \ pdu->needs_hyphen = (id < SMASI_HYPHEN_ID ? 1 : 0); \ fields \ } break; #include "smasi_pdu.def" default: warning(0, "Unknown SMASI_PDU type, internal error."); gw_free(pdu); return NULL; } return pdu; } void smasi_pdu_destroy(SMASI_PDU *pdu) { if (pdu == NULL) return; switch (pdu->type) { #define NONTERMINATED(name) octstr_destroy(p->name); #define COMATERMINATED(name) octstr_destroy(p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smasi_pdu.def" default: error(0, "Unknown SMASI_PDU type, internal error while destroying."); } gw_free(pdu); } Octstr *smasi_pdu_pack(SMASI_PDU *pdu) { Octstr *os; Octstr *temp; os = octstr_create(""); /* * Fix lengths of octet string fields. */ switch (pdu->type) { #define NONTERMINATED(name) p = *(&p); #define COMATERMINATED(name) p = *(&p); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smasi_pdu.def" default: error(0, "Unknown SMASI_PDU type, internal error while packing."); } switch (pdu->type) { #define NONTERMINATED(name) p = *(&p); #define COMATERMINATED(name) \ if (p->name != NULL) { octstr_append_cstr(os, #name); \ octstr_append_char(os, '='); \ octstr_append(os, p->name); \ octstr_append_char(os, ','); } #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smasi_pdu.def" default: error(0, "Unknown SMASI_PDU type, internal error while packing."); } octstr_append_char(os, '\n'); temp = pdu->needs_hyphen ? octstr_create("!") : octstr_create(""); octstr_append_cstr(temp, pdu->type_name); octstr_append_char(temp, ':'); octstr_insert(os, temp, 0); octstr_destroy(temp); return os; } SMASI_PDU *smasi_pdu_unpack(Octstr *data_without_len) { SMASI_PDU *pdu; char *type_name; Octstr *temp; long pos; unsigned long type = 0; /* extract the PDU type identifier */ temp = decode_type(data_without_len); type_name = (temp ? octstr_get_cstr(temp) : ""); if (strcmp(type_name, "dummy") == 0) type = 0; #define NONTERMINATED(name) p = *(&p); #define COMATERMINATED(name) p = *(&p); #define PDU(name, id, fields) \ else if (strcmp(type_name, #name) == 0) type = id; #include "smasi_pdu.def" else warning(0, "unknown SMASI PDU type"); pdu = smasi_pdu_create(type); if (pdu == NULL) return NULL; pos = 0; skip_until_after_colon(data_without_len, &pos); switch (type) { #define NONTERMINATED(name) p = *(&p); #define COMATERMINATED(name) \ if (octstr_str_compare(field_name, #name) == 0 && field_value != NULL) \ p->name = octstr_duplicate(field_value); #define PDU(name, id, fields) \ case id: { \ Octstr * field_name = NULL; \ Octstr * field_value = NULL; \ struct name *p = &pdu->u.name; \ while (pos < octstr_len(data_without_len)) { \ field_name = copy_until_assign(data_without_len, &pos); \ if (field_name == NULL) break; \ field_value = copy_until_coma(data_without_len, &pos); \ if (field_value == NULL) continue; \ fields \ octstr_destroy(field_name); \ octstr_destroy(field_value); \ } \ } break; #include "smasi_pdu.def" default: warning(0, "Unknown SMASI_PDU type, internal error while unpacking."); } octstr_destroy(temp); return pdu; } void smasi_pdu_dump(SMASI_PDU *pdu) { debug("sms.smasi", 0, "SMASI PDU %p dump:", (void *) pdu); debug("sms.smasi", 0, " type_name: %s", pdu->type_name); switch (pdu->type) { #define NONTERMINATED(name) p = *(&p); #define COMATERMINATED(name) \ octstr_dump_short(p->name, 2, #name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "smasi_pdu.def" default: warning(0, "Unknown SMASI_PDU type, internal error."); break; } debug("sms.smasi", 0, "SMASI PDU dump ends."); } Octstr *smasi_pdu_read(Connection *conn) { Octstr *line; line = conn_read_line(conn); /* read one line */ return line; } gateway-1.4.5/gw/smsc/smasi_pdu.h0000644000175000017500000001266213227613126015415 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smasi_pdu.h - declarations for SMASI PDUs * * Stipe Tolj */ #ifndef SMASI_PDU_H #define SMASI_PDU_H #include "gwlib/gwlib.h" /* * Any PDUs that are below this ID will be packed with a * prefixed hyphen. */ #define SMASI_HYPHEN_ID 0x00000010 enum { #define NONTERMINATED(name) #define COMATERMINATED(name) #define PDU(name, id, fields) name = id, #include "smasi_pdu.def" SMASI_PDU_DUMMY_TYPE }; typedef struct SMASI_PDU SMASI_PDU; struct SMASI_PDU { unsigned long type; const char *type_name; unsigned int needs_hyphen; union { #define NONTERMINATED(name) Octstr *name; #define COMATERMINATED(name) Octstr *name; #define PDU(name, id, fields) struct name { fields } name; #include "smasi_pdu.def" } u; }; /****************************************************************************** * Numering Plan Indicator and Type of Number codes from * GSM 03.40 Version 5.3.0 Section 9.1.2.5. * http://www.etsi.org/ */ #define GSM_ADDR_TON_UNKNOWN 0x00000000 #define GSM_ADDR_TON_INTERNATIONAL 0x00000001 #define GSM_ADDR_TON_NATIONAL 0x00000002 #define GSM_ADDR_TON_NETWORKSPECIFIC 0x00000003 #define GSM_ADDR_TON_SUBSCRIBER 0x00000004 #define GSM_ADDR_TON_ALPHANUMERIC 0x00000005 /* GSM TS 03.38 */ #define GSM_ADDR_TON_ABBREVIATED 0x00000006 #define GSM_ADDR_TON_EXTENSION 0x00000007 /* Reserved */ #define GSM_ADDR_NPI_UNKNOWN 0x00000000 #define GSM_ADDR_NPI_E164 0x00000001 #define GSM_ADDR_NPI_X121 0x00000003 #define GSM_ADDR_NPI_TELEX 0x00000004 #define GSM_ADDR_NPI_NATIONAL 0x00000008 #define GSM_ADDR_NPI_PRIVATE 0x00000009 #define GSM_ADDR_NPI_ERMES 0x0000000A /* ETSI DE/PS 3 01-3 */ #define GSM_ADDR_NPI_EXTENSION 0x0000000F /* Reserved */ /****************************************************************************** * esm_class parameters */ #define ESM_CLASS_DEFAULT_SMSC_MODE 0x00000000 #define ESM_CLASS_DATAGRAM_MODE 0x00000001 #define ESM_CLASS_FORWARD_MODE 0x00000002 #define ESM_CLASS_STORE_AND_FORWARD_MODE 0x00000003 #define ESM_CLASS_DELIVERY_ACK 0x00000008 #define ESM_CLASS_USER_ACK 0x00000010 #define ESM_CLASS_UDH_INDICATOR 0x00000040 #define ESM_CLASS_RPI 0x00000080 #define ESM_CLASS_UDH_AND_RPI 0x000000C0 SMASI_PDU *smasi_pdu_create(unsigned long type); void smasi_pdu_destroy(SMASI_PDU *pdu); int smasi_pdu_is_valid(SMASI_PDU *pdu); /* XXX */ Octstr *smasi_pdu_pack(SMASI_PDU *pdu); SMASI_PDU *smasi_pdu_unpack(Octstr *data_without_len); void smasi_pdu_dump(SMASI_PDU *pdu); Octstr *smasi_pdu_read(Connection *conn); #endif gateway-1.4.5/gw/smsc/smsc_sema.c0000644000175000017500000015035413227613126015377 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * smsc_sema.c - implement sms2000 protocal by using X25 access * the data communication layer is implemented by using X28 protocol * * Code implement submit invoke, status invoke, deliver invoke session * there is no internal db for storing delivered and undelivered message * * IA5 is most common line coding scheme. * smsc_sema support only IA5 encoding, hex and binary line encoding is not * supported. * * smsc_sema support IA5 and GSM Data Code Scheme for delivered invoke message * smsc_sema support only IA5 Data Code Scheme for submit invoke message * * Reference : SMS2000 Version 4.0 Open Interface Specification * Open Source WAP Gateway Architecture Design * ESTI GSM 03.40 * * Hao Shi 2000 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "smsc.h" #include "smsc_p.h" #include "alt_charsets.h" #include "smsc_sema.h" #include "sms.h" #ifndef CRTSCTS #define CRTSCTS 0 #endif static unsigned char sema_counter[4] = "0000"; static int sema_wait_report = 1; static int x28_data_mode = X28_COMMAND_MODE; SMSCenter * sema_open(char* smscnua, char* homenua, char* serialdevice, int waitreport) { SMSCenter *smsc; int nret = -1; smsc = smscenter_construct(); if(smsc == NULL) goto error; sprintf(smsc->name, "SEMA:X28:"); smsc->type = SMSC_TYPE_SEMA_X28; smsc->sema_smscnua = gw_strdup(smscnua); smsc->sema_homenua = gw_strdup(homenua); smsc->sema_serialdevice = gw_strdup(serialdevice); sema_wait_report = waitreport; smsc->sema_mt = sema_msglist_new(); if(smsc->sema_mt == NULL) goto error; smsc->sema_mo = sema_msglist_new(); if(smsc->sema_mo == NULL) goto error; /* Open the device properly. Remember to set the access codes correctly. */ debug("smsc.sema", 0, "sema_open: open datalink"); smsc->sema_fd = X28_open_data_link(smsc->sema_serialdevice); if(smsc->sema_fd == -1) goto error; /* test the outgoing callX28 to smsc center */ debug("smsc.sema", 0, "sema_open: test send link"); nret = X28_open_send_link(smsc->sema_fd, smsc->sema_smscnua); if(nret < 1){ sleep(2); nret = X28_open_send_link(smsc->sema_fd, smsc->sema_smscnua); if(nret < 1) goto error; } X28_close_send_link(smsc->sema_fd); return smsc; error: error(0, "sema_open: could not open"); smscenter_destruct(smsc); return NULL; } int sema_reopen(SMSCenter *smsc) { int nret = 0; debug("smsc.sema", 0, "reopening the connection"); /*deallocate*/ sema_msglist_free(smsc->sema_mt); sema_msglist_free(smsc->sema_mo); /*reallocate*/ smsc->sema_mt = sema_msglist_new(); if(smsc->sema_mt == NULL) goto error; smsc->sema_mo = sema_msglist_new(); if(smsc->sema_mo == NULL) goto error; memset(smsc->buffer,0,sizeof(smsc->buffer)); /* Open the device properly. Remember to set the access codes correctly. */ smsc->sema_fd = X28_reopen_data_link(smsc->sema_fd, smsc->sema_serialdevice); if(smsc->sema_fd == -1){ error(0,"sema_reopen_data_link: device file error"); goto error; } /*test outgoing call to the smsc */ nret = X28_open_send_link(smsc->sema_fd, smsc->sema_smscnua); if(nret < 1){ error(0,"test send data link failed"); goto error; } X28_close_send_link(smsc->sema_fd); return 0; error: error(0, "sema_reopen_data_link: failed"); return -1; } int sema_close(SMSCenter *smsc) { if(smsc->sema_fd > 0) close(smsc->sema_fd); /*deallocate*/ sema_msglist_free(smsc->sema_mt); sema_msglist_free(smsc->sema_mo); return 0; } int sema_submit_msg(SMSCenter *smsc, Msg *msg) { int nret = 0; struct sema_msg *lmsg = NULL; struct sm_submit_invoke *submit_sm = NULL; char x28sender[2] = "A3"; /* Validate msg */ if(smsc == NULL){ error(0,"sema_submit_msg: SMSC is empty"); goto error; } if(msg == NULL){ error(0, "sema_submit_msg: Msg is empty"); goto error; } if(msg_type(msg) != sms) { error(0, "sema_submit_sms: Msg is WRONG TYPE"); goto error; } /* user data header is not supported in sm2000 X25 access if(msg->sms.coding == DC_7BIT ...|| DC_UNDEF?){ error(0, "sema_submit_sms: submit invoke support in IA5 encoding(8 bits chars)"); goto error; } if(octstr_len(msg->sms.udhdata)){ error(0, "sema_submit_sms: submit invoke not support in IA5 encoding "); goto error; } */ lmsg = sema_msg_new(); submit_sm = gw_malloc(sizeof(struct sm_submit_invoke)); memset(submit_sm, 0, sizeof(struct sm_submit_invoke)); lmsg->type = 'S'; lmsg->encodetype = LINE_ENCODE_IA5; /* set operation reference */ increment_counter(); memcpy(lmsg->optref,sema_counter,4); /*set sme reference number*/ increment_counter(); memcpy(submit_sm->smerefnum, sema_counter, 4); /*we send as not key type*/ submit_sm->smereftype= 2; /*key type is 1*/ /*we set prority as normal*/ submit_sm->priority = 1; /*0 is high*/ /*set valid period type as relative*/ submit_sm->validperiodtype = 2; /* 1 is absolute */ /*time*/ submit_sm->validperiodrela = 1; /* from 0 to 143 , fomula is (V+1)*5 min*/ /*send msg without 00 header*/ submit_sm->msisdnlen= octstr_len(msg->sms.receiver); submit_sm->msisdn = octstr_copy(msg->sms.receiver,0,submit_sm->msisdnlen); /* X25 access will always append sender during data transfer */ submit_sm->origaddlen= 2; /* we need only to orignate address type */ submit_sm->origadd = octstr_create_from_data(x28sender,2); /*data encoding scheme ,support only IA5 in current version*/ submit_sm->DCS = 15; /*gsm is 0 ,IA5 is 15*/ /*protocal ,support only default value 0 in current version*/ submit_sm->protocal = 0; /*replypath*/ submit_sm->replypath= 0; /*gateway do not pay for reply*/ /*status report*/ if(sema_wait_report > 0) submit_sm->statusreportrequest =4; /* deliver success, in bin form 00000100*/ else submit_sm->statusreportrequest = 0;/* no report */ /* we support submit invoke only in IA5 line encoding*/ submit_sm->textsizeoctect = submit_sm->textsizeseptet = octstr_len(msg->sms.msgdata); /*copy msg buffer*/ submit_sm->shortmsg = octstr_copy(msg->sms.msgdata, 0, submit_sm->textsizeoctect); memset(submit_sm->smscrefnum,0,sizeof(submit_sm->smscrefnum)); /*pack the message body in 2kmsg*/ lmsg->msgbody = submit_sm; nret = sema_msg_session_mt(smsc, lmsg); gw_free(submit_sm); submit_sm = NULL; sema_msg_free(lmsg); lmsg = NULL; if(nret == SESSION_MT_RECEIVE_SUCCESS){ debug("smsc.sema", 0, "sema_submit_msg: message is successfully delivered"); return 1; /*success*/ } else if(nret == SESSION_MT_RECEIVE_TIMEOUT){ info(0, "sema_submit msg: session timed out without return"); return 0; } else if(nret == SESSION_MT_RECEIVE_ERR){ info(0, "sema_submit msg: smsc says submit failed!"); return 0; } return 1; error: if(submit_sm) gw_free(submit_sm); if(lmsg) sema_msg_free(lmsg); return -1; } int sema_receive_msg(SMSCenter *smsc, Msg **msg) { struct sema_msg *rmsg = NULL; struct sm_deliver_invoke *recieve_sm = NULL; while(sema_msglist_pop(smsc->sema_mo, &rmsg) == 1 ) { *msg = msg_create(sms); if(*msg==NULL) goto error; recieve_sm = (struct sm_deliver_invoke*) rmsg->msgbody; if(recieve_sm==NULL) goto error; /* as IA5(8 bit character) is the default line encoding used by X28 * and we do not support other line encoding scheme like binary or * hex encoding */ (*msg)->sms.coding = DC_8BIT; /* OIS in X28 implementation does not include udh field */ (*msg)->sms.sender = octstr_create_from_data( octstr_get_cstr(recieve_sm->origadd) +2, octstr_len(recieve_sm->origadd)-2); (*msg)->sms.receiver = octstr_create_from_data( octstr_get_cstr(recieve_sm->destadd) +2, octstr_len(recieve_sm->destadd)-2); (*msg)->sms.msgdata = octstr_duplicate(recieve_sm->shortmsg); (*msg)->sms.udhdata = octstr_create(""); gw_free(recieve_sm); sema_msg_free(rmsg); rmsg = NULL; } return 1; error: error(0, "sema_receive_msg: can not create Smart Msg"); return -1; } int sema_pending_smsmessage(SMSCenter *smsc) { char data[1024]; int ret = 0; char clrbuff[]="CLR\0"; char errbuff[]="ERR\0"; /* struct sema_msg* smsg = NULL;*/ /* Receive raw data */ ret = X28_data_read(smsc->sema_fd, smsc->buffer); if(ret == -1) { ret = X28_reopen_data_link(smsc->sema_fd, smsc->sema_serialdevice); if(ret == -1) goto error; return 0; } /* Interpret the raw data */ memset(data,0,sizeof(data)); while(X28_msg_pop(smsc->buffer, data) == 0 ) { if(strlen(data) > 0){ if(strstr(data,clrbuff) != NULL || strstr(data,errbuff) != NULL){ debug("smsc.sema", 0, "sema_pending_msg: Radio Pad Command line-%s",data); } else{ ret = sema_msg_session_mo(smsc, data); if(ret == -1) goto error; } memset(data,0,sizeof(data)); } } /* Signal that we got a MO message if mo list is not empty*/ if(smsc->sema_mo->first != NULL){ return 1; } return 0; error: error(0,"sema_pending message: device file error"); return -1; } static sema_msg* sema_msg_new(void) { struct sema_msg *msg = NULL; msg = gw_malloc(sizeof(struct sema_msg)); memset(msg, 0, sizeof(struct sema_msg)); return msg; } static int sema_msg_free(sema_msg *msg) { if(msg == NULL) return 0; gw_free(msg); return 1; } static sema_msglist* sema_msglist_new(void) { struct sema_msglist *mlist = NULL; mlist = gw_malloc(sizeof(struct sema_msglist)); memset(mlist, 0, sizeof(struct sema_msglist)); mlist->first = NULL; mlist->last = NULL; mlist->count = 0; return mlist; } static void sema_msglist_free(sema_msglist *mlist) { struct sema_msg *pmsg = NULL; if(mlist == NULL) return; while( sema_msglist_pop(mlist, &pmsg) == 1 ) { if(pmsg==NULL) break; sema_msg_free(pmsg); pmsg = NULL; } gw_free(mlist); mlist->count = 0; } static int sema_msglist_push(sema_msglist *plist, sema_msg *pmsg) { struct sema_msg * lmsg = NULL; if(plist == NULL) { info(0, "msglist_push: NULL msg list"); goto error; } if(pmsg == NULL) { info(0, "msglist_push: NULL input"); goto error; } /* If list is completely empty. */ if( plist->first == NULL ) { plist->last = pmsg; plist->first = pmsg; pmsg->prev = NULL; pmsg->next = NULL; } else{ lmsg=plist->last; lmsg->next=pmsg; pmsg->prev=lmsg; pmsg->next=NULL; plist->last=pmsg; } plist->count += 1; return 1; error: error(0, "msglist_push: error"); return 0; } static int sema_msglist_pop(sema_msglist *plist, sema_msg **msg) { if(plist == NULL) { info(0, "msglist_pop: NULL list"); goto no_msg; } if(plist->first == NULL) { goto no_msg; } *msg = plist->first; if(plist->last == *msg) { plist->first = NULL; (*msg)->prev = NULL; plist->last = NULL; } else { plist->first = (*msg)->next; plist->first->prev = NULL; if(plist->first->next == NULL) plist->last = plist->first; } plist->count -= 1; return 1; no_msg: return 0; } static int X28_open_data_link(char* device){ int fd = -1, iret; struct termios tios; info(0,"open serial device %s",device); fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY); if(fd==-1) { error(errno, "sema_open_data_link: error open(2)ing the character device <%s>", device); if(errno == EACCES) error(0, "sema_open_data_link: user has no right to access the serial device"); return -1; } tcgetattr(fd, &tios); cfsetospeed(&tios, B4800); /* check radio pad parameter*/ cfsetispeed(&tios, B4800); kannel_cfmakeraw(&tios); tios.c_iflag |= IGNBRK|IGNPAR|INPCK|ISTRIP; tios.c_cflag |= (CSIZE|HUPCL | CREAD | CRTSCTS); tios.c_cflag ^= PARODD; tios.c_cflag |=CS7; iret = tcsetattr(fd, TCSANOW, &tios); if(iret == -1){ error(errno,"sema_open_data_link: fail to set termios attribute"); goto error; } tcflush(fd, TCIOFLUSH); return fd; error: return -1; } static int X28_reopen_data_link(int oldpadfd ,char* device){ int nret = 0; if(oldpadfd > 0){ nret= close(oldpadfd); if(nret == -1){ error(errno,"sema_reopen_data_link: close device file failed!!"); } } sleep(1); return X28_open_data_link(device); } static int X28_close_send_link(int padfd) { char discnntbuff[5]; char readbuff[1024]; char finishconfirm[]="CLR CONF\0"; int nret = 0, readall = 0; time_t tstart; time(&tstart); sprintf(discnntbuff,"%cCLR\r",0x10); memset(readbuff,0,sizeof(readbuff)); /* what ever is the close return, data mode is unreliable now*/ x28_data_mode = X28_COMMAND_MODE; if(padfd <= 0) goto datalink_error; while((time(NULL) - tstart) < INTERNAL_DISCONNECT_TIMEVAL){ nret =write(padfd, discnntbuff, 5); if(nret == -1){ if(errno == EAGAIN || errno ==EINTR) continue; else{ goto datalink_error; } } sleep(1); /*wait 1 senconds for virtual link break*/ nret=read(padfd, readbuff+readall,128); if(nret == -1){ if(errno == EAGAIN || errno ==EINTR) continue; else{ goto datalink_error; } } if(nret >0){ readall += nret; if(strstr(readbuff,finishconfirm)) return 1; } } return 0; datalink_error: error(errno,"sema_close_send_link, device file error"); return -1; } static int X28_open_send_link(int padfd, char *nua) { char readbuff[1024]; char writebuff[129]; char smscbuff[129]; int readall = 0, readonce = 0, writeonce = 0, writeall = 0, i = 0; char X28prompt[]="*\r\n\0"; time_t timestart; debug("smsc.sema", 0, "sema_open send link: call smsc <%s> for <%i> seconds", nua, (int)INTERNAL_CONNECT_TIMEVAL); /* type few to invoke DTE */ writebuff[0] = '\r'; memset(readbuff,0,sizeof(readbuff)); for(i = 0; i <= 3; i++) { readonce = writeonce = -1; writeonce = write(padfd, writebuff, 1); if(writeonce < 1){ if(errno == EINTR || errno == EAGAIN) continue; else{ goto datalink_error; } } usleep(1000); /* wait for prompt */ readonce = read(padfd, &readbuff[readall],1024); if(readonce == -1){ if(errno == EINTR || errno == EAGAIN) continue; else{ goto datalink_error; } } else readall += readonce; } if(strstr(readbuff, X28prompt) == NULL){ warning(0,"X28_open_send_link: can not read command prompt, abort"); return 0; } /* second, connect to the smsc now */ memset(writebuff,0,sizeof(writebuff)); memset(readbuff,0,sizeof(readbuff)); writeall = readall = 0; sprintf(writebuff, "%s\r", nua); sprintf(smscbuff, "%s COM",nua); while((size_t) writeall < strlen(writebuff)){ writeonce = -1; writeonce = write(padfd, writebuff+writeall, strlen(writebuff)-writeall); if(writeonce == -1){ if(errno == EINTR || errno == EAGAIN) continue; else goto datalink_error; } if(writeonce > 0) writeall +=writeonce; } tcdrain(padfd); usleep(1000*1000);/* wait for smsc answer */ time(×tart); while(time(NULL) - timestart < INTERNAL_CONNECT_TIMEVAL){ if((size_t) readall >= sizeof(readbuff)) goto error_overflow; /* We read 1 char a time */ readonce = read(padfd, &readbuff[readall], 1); if(readonce == -1) { if(errno == EINTR || errno == EAGAIN) continue; else goto datalink_error; } if(readonce > 0) readall += readonce; /* Search for response line. */ if(readall > 2 && readbuff[readall-1] == '\n' && readbuff[readall-2] == '\r') { if(strstr(readbuff, smscbuff)) { debug("smsc.sema", 0, "sema_open send link: smsc responded, virtual link established"); x28_data_mode = X28_MT_DATA_MODE; return 1; } } usleep(1000); } info(0,"sema_open_send_link: connect timeout"); return 0; error_overflow: warning(0, "sema_open_send_link: command buffer overflow"); return 0; datalink_error: error(errno,"sema_open_send_link: device file error"); return -1; } static int X28_data_read(int padfd, char *cbuffer) { char *p = NULL; int ret, len; fd_set read_fd; struct timeval tv, tvinit; size_t readall; tvinit.tv_sec = 0; tvinit.tv_usec = 1000; readall = 0; for (;;) { FD_ZERO(&read_fd); FD_SET(padfd, &read_fd); tv = tvinit; ret = select(padfd + 1, &read_fd, NULL, NULL, &tv); if (ret == -1) { if(errno==EINTR) goto got_data; if(errno==EAGAIN) goto got_data; error(errno, "Error doing select for fad"); return -1; } else if (ret == 0) goto got_data; len = strlen(cbuffer); ret = read(padfd, cbuffer + len, 256); if (ret == -1) { error(errno," read device file"); return -1; } if (ret == 0) goto eof; readall += ret; if ((size_t) len > sizeof(cbuffer)- 256) { p = gw_realloc(cbuffer, sizeof(cbuffer) * 2); memset(p+len,0,sizeof(cbuffer)*2 - len); cbuffer = p; } if(readall > 0) break; } eof: if(readall > 0) ret = 1; goto unblock; got_data: ret = 0; goto unblock; unblock: return ret; } static int X28_data_send(int padfd, char *cbuffer,int sentonce) { int len = 0, pos = 0,writeonce = 0,writeall = 0; tcdrain(padfd); len = strlen(cbuffer); while(len > 0){ if(len < sentonce) { writeonce = write(padfd, cbuffer+pos, len); } else writeonce = write(padfd, cbuffer+pos, sentonce); if (writeonce == -1) { if(errno == EINTR || errno == EINTR) continue; else{ goto error; } } if(writeonce > 0){ len -= writeonce; pos += writeonce; writeall = pos; } } tcdrain(padfd); return writeall; error: error(errno,"sema_send data error: device file error"); return -1; } static int X28_msg_pop(char *from, char *to) { char* Rbuff =NULL; char* RRbuff = NULL; char mobuff[] ="COM\r\n\0"; char mobuffend[] = "\r\0"; char prompbuff[] = "*\r\0"; int len = 0, Llen= 0, Rlen = 0,RRlen = 0; len = strlen(from); if(len <=0) goto no_msg; /* trim off rabbish header */ while(*from == '\r' || *from == '\n'){ len = strlen(from); if(len > 1){ memmove(from, from +1, len-1); memset(from+(len-1), 0, 1); } else{ memset(from,0,len); return -1; } } len = strlen(from); /*all kinds of useful infomation contains \r*/ if((Rbuff=memchr(from,'\r',len)) == NULL) goto no_msg; /*check if it is a command prompt *\r\n */ if((Rbuff -from) > 0 && *(Rbuff -1) == '*'){ if(strlen(Rbuff) < 2) goto no_msg; /*\n is not coming yet*/ if(Rbuff -from > 4){ /* command info */ Rlen = Rbuff -1 -from; memcpy(to,from,Rlen); } x28_data_mode = X28_COMMAND_MODE; if(strlen(Rbuff+1) > 1){ Rlen = strlen(Rbuff +2); memmove(from, Rbuff +2, Rlen); memset(from+Rlen, 0, len-Rlen); } else memset(from, 0,len); }/* check mo msg , format X121address+COM\r\n+msg+\r*/ else if((Rbuff-from) > 3 && strstr(Rbuff-4,mobuff)!= NULL){ if(strlen(Rbuff) < 3 || (RRbuff = strstr(Rbuff + 2, mobuffend)) == NULL) goto no_msg; /*the msg+\r is still coming*/ RRlen = RRbuff - (Rbuff+2); if(RRlen > 4){ /* msg header is 4 byte always+msg content*/ memcpy(to, Rbuff +2 , RRlen); x28_data_mode = X28_MO_DATA_MODE; } if(strlen(RRbuff) > 1){ Rlen = strlen(RRbuff +1); memmove(from, RRbuff+1 ,Rlen); memset(from+Rlen,0,len -Rlen); } else memset(from,0,len); } else{/* it can be mt reply */ if(Rbuff - from > 0){ Llen = Rbuff - from; memcpy(to, from, Llen); } if(strlen(Rbuff) > 1){ Rlen = strlen(Rbuff+1); memmove(from,Rbuff+1,Rlen); memset(from+Rlen,0,len-Rlen); } else memset(from,0,len); } /* check rest of line for link state: command mode or data mode */ if(strstr(from,prompbuff) != NULL) x28_data_mode = X28_COMMAND_MODE; return 0; no_msg: return -1; } static int sema_submit_result(SMSCenter *smsc, sema_msg* srcmsg, int result) { char IA5buff[1024]; unsigned char oct1byte[1]; unsigned char ia5byte[2]; unsigned char cTr='t'; unsigned char cMr='m'; unsigned char ccontinuebyte = 'P', ccr = '\r'; int j = 0, iret; memset(IA5buff,0,sizeof(IA5buff)); switch(srcmsg->type) { case 'M': memcpy(IA5buff,&cMr,1);/*msg type*/ memcpy(IA5buff+1,&ccontinuebyte,1); /*continue bit*/ memcpy(IA5buff+2,srcmsg->optref,4); /*operation reference*/ write_variable_value(result,oct1byte); j=internal_char_hex_to_IA5(oct1byte[0],ia5byte); memcpy(IA5buff+6,ia5byte,j); memcpy(IA5buff+6+j,&ccr,1);/*result*/ iret = X28_data_send(smsc->sema_fd,IA5buff,strlen(IA5buff)); if(iret == -1) goto error; break; case 'T': memcpy(IA5buff,&cTr,1); memcpy(IA5buff+1,&ccontinuebyte,1); memcpy(IA5buff+2,srcmsg->optref,4); write_variable_value(result,oct1byte); j=internal_char_hex_to_IA5(oct1byte[0],ia5byte); memcpy(IA5buff+6,ia5byte,j); memcpy(IA5buff+6+j,&ccr,1); iret = X28_data_send(smsc->sema_fd,IA5buff,strlen(IA5buff)); if(iret == -1) goto error; break; default: return 0; /*unsupoorted result msg type*/ } return 1; error: error(0,"sk_submit_result: write to device file failed"); return -1; } static int sema_msg_session_mt(SMSCenter *smsc, sema_msg* pmsg){ struct msg_hash *segments = NULL; struct sema_msg* mtrmsg = NULL; struct sm_statusreport_invoke* report_invoke = NULL; struct sm_submit_result* submit_result = NULL; struct sm_submit_invoke* submit_invoke = NULL; struct sm_deliver_invoke* deliver_invoke = NULL; char data[1024], IA5buff[256], IA5chars[1024], mochars[10*1024]; unsigned char ccontinuebyte, ccr = '\r'; unsigned char cerr[] = "ERR\0",cclr[] = "CLR\0", tmp1[5] , tmp2[5]; int i, iseg = 0, ilen = 0,iret = 0, moret; int isrcved = 0, iTrcved = 0, decoderesult = 0; time_t tstart; submit_invoke = (struct sm_submit_invoke*) pmsg->msgbody; if(submit_invoke == NULL) goto error; /*encode first*/ memset(IA5chars,0,sizeof(IA5chars)); if(sema_encode_msg(pmsg, IA5chars) < 1) goto encode_error; /*divide segments, we send buffer no more than 128 byte once*/ iseg = strlen(IA5chars)/121 + 1; segments = gw_malloc(iseg * sizeof(struct msg_hash)); if(segments == NULL) goto error; /*first segments*/ if(strlen(IA5chars) < 121) ilen = strlen(IA5chars); else ilen = 121; segments[0].content = octstr_create_from_data((char *)&(pmsg->type), 1);/*msg type, in hex*/ ccontinuebyte = pack_continous_byte(pmsg->encodetype, 1, iseg -1); octstr_insert_data(segments[0].content, 1, (char *)&ccontinuebyte, 1); /*continue char, in hex*/ octstr_insert_data(segments[0].content, 2, (char *)pmsg->optref, 4); /*operation reference, in hex*/ octstr_insert_data(segments[0].content, 6, IA5chars, ilen); octstr_insert_data(segments[0].content, octstr_len(segments[0].content), (char *)&ccr, 1); /**/ /*rest segments*/ for( i = 1; i < iseg; i++){ if(strlen(IA5chars) - i*121 < 121) ilen = strlen(IA5chars) - i*121; else ilen =121; segments[i].content= octstr_create_from_data((char *)&(pmsg->type), 1); ccontinuebyte = pack_continous_byte(pmsg->encodetype, 0, iseg -i-1); octstr_insert_data(segments[i].content, 1, (char *)&ccontinuebyte, 1); octstr_insert_data(segments[i].content, 2, (char *)pmsg->optref, 4); octstr_insert_data(segments[i].content, 6, IA5chars + i*121, ilen); octstr_insert_data(segments[i].content, octstr_len(segments[i].content),(char *)&ccr, 1); } if(x28_data_mode != X28_MT_DATA_MODE){ /* do not trust any existing data mode*/ X28_close_send_link(smsc->sema_fd); /*open send link*/ if((iret = X28_open_send_link(smsc->sema_fd,smsc->sema_smscnua)) < 1){ if(iret == -1){ iret = X28_reopen_data_link(smsc->sema_fd, smsc->sema_serialdevice); if(iret == -1){ goto error; } } X28_close_send_link(smsc->sema_fd); sleep(1); iret = X28_open_send_link(smsc->sema_fd,smsc->sema_smscnua); if(iret < 1) goto sendlink_error; } } /*deliver buff*/ for(i = 0; i < iseg; i++){ memset(IA5buff,0,sizeof(IA5buff)); memcpy(IA5buff,octstr_get_cstr(segments[i].content), octstr_len(segments[i].content)); iret =X28_data_send(smsc->sema_fd,IA5buff,strlen(IA5buff)); if(iret == -1) goto error; octstr_destroy(segments[i].content); } gw_free(segments); /*wait result and report return*/ mtrmsg = sema_msg_new(); memset(mochars,0,sizeof(mochars)); time(&tstart); while(time(NULL) -tstart < INTERNAL_SESSION_MT_TIMEVAL){ iret = X28_data_read(smsc->sema_fd, smsc->buffer); if(iret == -1) goto error; /* Interpret the raw data */ memset(data,0,sizeof(data)); while(X28_msg_pop(smsc->buffer, data) == 0 ) { if(strlen(data) > 0){ if(strstr(data,(char *)cerr) != NULL || strstr(data,(char *)cclr) != NULL){ debug("smsc.sema", 0, "sema_mt_session: Radio Pad Command line-%s",data); goto sendlink_error; } /* decode msg*/ decoderesult = sema_decode_msg(&mtrmsg,data); if(decoderesult >= 0){ if(mtrmsg->type == 's'){ /*submit result*/ submit_result = (struct sm_submit_result*) mtrmsg->msgbody; if(submit_result == NULL) goto error; /* check result operation number is what we send */ memset(tmp1,0,5); memset(tmp2,0,5); memcpy(tmp1,mtrmsg->optref,4); memcpy(tmp2, pmsg->optref,4); if(strstr((char *)tmp1,(char *)tmp2) != NULL){ isrcved = 1; memcpy(submit_invoke->smscrefnum, submit_result->smscrefnum,4); } if(isrcved == 1 && submit_result->smeresult != 0){ gw_free(submit_result); goto smsc_say_fail; } gw_free(submit_result); } else if(mtrmsg->type == 'T'){ /*report invoke*/ report_invoke = (struct sm_statusreport_invoke*) mtrmsg->msgbody; if(report_invoke == NULL) goto error; /*check if report reference number is what we expect*/ memset(tmp1,0,sizeof(tmp1)); memset(tmp2,0,sizeof(tmp2)); memcpy(tmp1,report_invoke->smscrefnum,4); memcpy(tmp2,submit_invoke->smscrefnum,4); if(strstr((char *)tmp1,(char *)tmp2) != NULL){ iTrcved = 1; } decoderesult = 0; iret = sema_submit_result(smsc, mtrmsg, decoderesult); if(iret == -1) goto error; if(iTrcved == 1 && report_invoke->status != 3){ /*3 means msg delivered*/ info(0,"sema_mt_session: submit invoke failed with report value-%i",report_invoke->status); gw_free(report_invoke); goto smsc_say_fail; } gw_free(report_invoke); } else if(mtrmsg->type == 'M'){/* deliver invoke*/ /* we do not deal with deliver in mt session*/ decoderesult = 0; iret = sema_submit_result(smsc, mtrmsg, decoderesult); if(iret == -1) goto error; deliver_invoke = (struct sm_deliver_invoke*) mtrmsg->msgbody; if(deliver_invoke != NULL){ gw_free(deliver_invoke); /*append buffer back to smsc->buffer*/ ilen=strlen(mochars); memcpy(mochars+ilen,data,strlen(data)); ilen=strlen(mochars); memcpy(mochars+ilen,&ccr,1); } time(&tstart); } /* clean msg for next read*/ memset(mtrmsg,0,sizeof(struct sema_msg)); } /* clean buffer for next useful info*/ memset(data,0,sizeof(data)); if(sema_wait_report == 0 && isrcved == 1) { info(0,"sema_mt_session: submit invoke delivered successfully to smsc"); goto mo_success; } if(sema_wait_report > 0 && isrcved == 1 && iTrcved == 1) { info(0,"sema_mt_session: submit invoke delivered successfully to msisdn"); goto mo_success; } } } } /* mo_timeout: */ info(0,"sema_mt_session: timeout without receiving all expected returns"); moret = SESSION_MT_RECEIVE_TIMEOUT; goto mo_return; mo_success: moret = SESSION_MT_RECEIVE_SUCCESS; goto mo_return; smsc_say_fail: info(0,"sema_mt_session: smsc says message deliver failed!"); moret = SESSION_MT_RECEIVE_ERR; goto mo_return; mo_return: X28_close_send_link(smsc->sema_fd); /* we have to close here, otherwise smsc will wait for a long time untill it find out nothing is coming */ sema_msg_free(mtrmsg); ilen = strlen(mochars); i = strlen(smsc->buffer); if(ilen > 0){ memmove( smsc->buffer+ilen,smsc->buffer,i); memcpy(smsc->buffer, mochars,ilen); } return moret; sendlink_error: info(0,"sema_mt_session: X28 data link has broken"); if(mtrmsg != NULL) sema_msg_free(mtrmsg); return 0; encode_error: info(0,"sema_mt_session: Msg encode error"); return 0; error: error(0,"sema_mt session: memory allocation error or device file error"); return -1; } static int sema_msg_session_mo(SMSCenter *smsc, char* cbuff){ struct sema_msg *rmsg = NULL; int iret = 0, retresult = 0; struct sm_deliver_invoke* deliver_invoke = NULL; struct sm_statusreport_invoke* report_invoke = NULL; rmsg = sema_msg_new(); iret = sema_decode_msg(&rmsg,cbuff); if(iret == - 1) goto msg_error;/* decode error */ if(x28_data_mode == X28_COMMAND_MODE){ /* do not trust any existing data mode*/ /* XXX this should be fixed? -rpr */ X28_close_send_link(smsc->sema_fd); /*open send link*/ if(X28_open_send_link(smsc->sema_fd,smsc->sema_smscnua) < 1){ info(0,"sema_mo_session: can not establish send link"); return 0; } } if(rmsg->type == 'M'){ /* deliver invoke */ retresult = 0; /* deliver invoke */ iret = sema_submit_result(smsc, rmsg, retresult); if(iret == -1) goto error; deliver_invoke = (struct sm_deliver_invoke*) rmsg->msgbody; if(deliver_invoke == NULL) goto msg_error; sema_msglist_push(smsc->sema_mo, rmsg); return 1; } else if(rmsg->type == 'T'){ /* status report */ retresult = 0; /* let msg through */ sema_submit_result(smsc, rmsg, retresult); if(iret == -1) goto error; report_invoke = (struct sm_statusreport_invoke*) rmsg->msgbody; if(report_invoke != NULL) gw_free(report_invoke); } else{ /* add your additional support here*/ } sema_msg_free(rmsg); return 1; msg_error: sema_msg_free(rmsg); error(0,"sema_mo session: Msg decode failed"); return 0; error: error(0,"sema_mo session: device file error or memory allocation problem!"); return -1; } static int sema_decode_msg(sema_msg **desmsg, char* octsrc) { struct sm_deliver_invoke *receive_sm = NULL; struct sm_statusreport_invoke* receive_report = NULL; struct sm_submit_result* submit_result = NULL; unsigned char tmp[1024],tmpgsm[1024]; int octetlen, iret, iusedbyte; int imsgtopseg = 0, imsgfollownum = 0, imsgencodetype = 0; unsigned char cmsgtype, cmsgcontinuebyte; /* message type */ if(strlen(octsrc) <= 4) goto no_msg; /* check if we support this type */ cmsgtype = *octsrc; if(cmsgtype != 's' /* invoke reseult */ && cmsgtype != 'M' /* deliver invoke */ && cmsgtype != 'T'){ /* report invoke */ info(0,"sema_decode: msg type not supported"); goto error_msg; } /*check if continue bit is correct */ cmsgcontinuebyte = *(octsrc+1); iret = unpack_continous_byte(cmsgcontinuebyte, &imsgencodetype,&imsgtopseg, &imsgfollownum); if(iret == -1){ info(0,"sema_decode: msg continue bit can not be interpreted"); goto error_msg; } /*status report and submit result will always be 1 segments for deliver invoke, if smsc can not send all the data in one packet, text data will be truncated ,so it's also 1 packet*/ if(imsgtopseg == 0){ info(0, "sema_decode: can not interpret more than one segments msg"); goto error_msg; } (*desmsg)->type = cmsgtype; (*desmsg)->continuebyte = cmsgcontinuebyte; (*desmsg)->encodetype = imsgencodetype; /*operation reference*/ memcpy((*desmsg)->optref, octsrc +2, 4); octsrc += 6; iusedbyte = 0; switch(cmsgtype){ case 's': /* submit invoke result */ submit_result = gw_malloc(sizeof(struct sm_submit_result)); memset(submit_result,0,sizeof(struct sm_submit_result)); /* result */ iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp); if(iusedbyte < 1) goto error_submit; octetlen = 1; submit_result->smeresult = get_variable_value(tmp, &octetlen); if(submit_result->smeresult == SM_RESULT_SUCCESS) { /*smsc reference number*/ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 4,tmp); if(iusedbyte <1) goto error_submit; memcpy(submit_result->smscrefnum, tmp, 4); /*accept time*/ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 14,tmp); if(iusedbyte < 1) goto error_submit; memcpy(submit_result->accepttime, tmp, 4); } (*desmsg)->msgbody = submit_result; break; case 'M': /* deliver invoke*/ receive_sm = gw_malloc(sizeof(struct sm_deliver_invoke)); memset(receive_sm, 0, sizeof(struct sm_deliver_invoke)); /*deliver destination address length*/ iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp); if(iusedbyte < 1) goto error_deliver; octetlen = 1; receive_sm->destaddlen = get_variable_value(tmp, &octetlen); /*deliver destination address*/ octsrc +=iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc,receive_sm->destaddlen,tmp); if(iusedbyte < 1) goto error_deliver; receive_sm->destadd= octstr_create_from_data((char *)tmp, receive_sm->destaddlen); /*smsc reference number*/ octsrc +=iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 4,tmp); if(iusedbyte < 1) goto error_deliver; memcpy(receive_sm->smscrefnum, tmp, 4); /*originate address length*/ octsrc +=iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp); if(iusedbyte < 1) goto error_deliver; octetlen = 1; receive_sm->origaddlen = get_variable_value(tmp, &octetlen); /*originate address*/ octsrc +=iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, receive_sm->origaddlen, tmp); if(iusedbyte < 1) goto error_deliver; receive_sm->origadd= octstr_create_from_data((char *)tmp,receive_sm->origaddlen); /* data code scheme */ octsrc +=iusedbyte; if(iusedbyte < 1) goto error_deliver; iusedbyte = line_scan_IA5_hex(octsrc, 1,tmp); octetlen = 1; receive_sm->DCS = get_variable_value(tmp, &octetlen); if(receive_sm->DCS != ENCODE_IA5 && receive_sm->DCS !=ENCODE_GSM){ info(0, "sema_decode, Data encoding scheme not supported"); goto error_deliver; } /* protocol */ octsrc +=iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 1,tmp); if(iusedbyte < 1) goto error_deliver; octetlen = 1; receive_sm->protocal = get_variable_value(tmp, &octetlen); /* reply path */ octsrc +=iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 1,tmp); if(iusedbyte < 1) goto error_deliver; octetlen = 1; receive_sm->replypath = get_variable_value(tmp, &octetlen); /*text size in septect*/ octsrc +=iusedbyte; iusedbyte = internal_char_IA5_to_hex(octsrc, tmp); if(iusedbyte < 1) goto error_deliver; receive_sm->textsizeseptet = tmp[0]; /*text size in octects*/ octsrc +=iusedbyte; iusedbyte = internal_char_IA5_to_hex(octsrc, tmp); if(iusedbyte < 1) goto error_deliver; receive_sm->textsizeoctect = tmp[0]; octsrc+=iusedbyte; /*message text*/ iusedbyte = 0; memset(tmp,0,sizeof(tmp)); if(receive_sm->DCS == ENCODE_IA5 && receive_sm->textsizeoctect > 0) { iusedbyte = line_scan_IA5_hex(octsrc,receive_sm->textsizeoctect,tmp); if(iusedbyte < 1) goto error_deliver; receive_sm->shortmsg =octstr_create_from_data( (char *)tmp,receive_sm->textsizeoctect); } else if(receive_sm->DCS == ENCODE_GSM && receive_sm->textsizeseptet > 0) { memset(tmpgsm,0,sizeof(tmpgsm)); iusedbyte = line_scan_IA5_hex(octsrc,receive_sm->textsizeoctect,tmp); if(iusedbyte < 1) goto error_deliver; line_scan_hex_GSM7(tmp,receive_sm->textsizeoctect, receive_sm->textsizeseptet, tmpgsm); receive_sm->shortmsg = octstr_create_from_data((char *)tmpgsm, receive_sm->textsizeseptet); } else if(receive_sm->textsizeoctect <= 0) receive_sm->shortmsg = octstr_create(""); /*accepttime*/ octsrc +=iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc,14,tmp); if(iusedbyte < 1) goto error_deliver; memcpy(receive_sm->accepttime, tmp,14); /*valid time*/ octsrc +=iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc,14,tmp); if(iusedbyte < 1) goto error_deliver; memcpy(receive_sm->invoketime, tmp,14); (*desmsg)->msgbody = receive_sm; break; case 'T': /* status report invoke */ receive_report = gw_malloc(sizeof(struct sm_statusreport_invoke)); memset(receive_report,0,sizeof(struct sm_statusreport_invoke)); /*deliver msisdn address length*/ iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp); if(iusedbyte < 1) goto error_receive; octetlen = 1; receive_report->msisdnlen = get_variable_value(tmp, &octetlen); /*msisdn*/ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, receive_report->msisdnlen, tmp); if(iusedbyte < 1) goto error_receive; receive_report->msisdn = octstr_create_from_data( (char *)tmp,receive_report->msisdnlen); /*sme reference type*/ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp); if(iusedbyte < 1) goto error_receive; octetlen = 1; receive_report->smetype = get_variable_value(tmp, &octetlen); /*sme reference number */ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc,4, tmp); if(iusedbyte < 1) goto error_receive; memcpy(receive_report->smerefnum ,tmp, 4); /*smsc reference number */ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc,4, tmp); if(iusedbyte < 1) goto error_receive; memcpy(receive_report->smscrefnum ,tmp, 4); /*accepted time*/ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc,14, tmp); if(iusedbyte < 1) goto error_receive; memcpy(receive_report->accepttime ,tmp, 4); /*status*/ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp); if(iusedbyte < 1) goto error_receive; octetlen = 1; receive_report->status = get_variable_value(tmp, &octetlen); octsrc += iusedbyte; if(receive_report->status != 6) /*6 means unable to deliver , but retry*/ { iusedbyte = line_scan_IA5_hex(octsrc,14, tmp); if(iusedbyte < 1) goto error_receive; memcpy(receive_report->completetime ,tmp, 14); } else { iusedbyte = line_scan_IA5_hex(octsrc,14, tmp); if(iusedbyte < 1) goto error_receive; memcpy(receive_report->intermediatime ,tmp, 14); } if(receive_report->status == 6 || receive_report->status == 1) /*unable to deliver ,both case */ { octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp); if(iusedbyte < 1) goto error_receive; octetlen = 1; receive_report->failreason = get_variable_value(tmp, &octetlen); } /*deliver orignate address length*/ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp); if(iusedbyte < 1) goto error_receive; octetlen = 1; receive_report->origaddlen = get_variable_value(tmp, &octetlen); /*orignate address*/ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc, receive_report->origaddlen, tmp); if(iusedbyte < 1) goto error_receive; receive_report->origadd = octstr_create_from_data((char *)tmp, receive_report->msisdnlen); /* invoke time */ octsrc += iusedbyte; iusedbyte = line_scan_IA5_hex(octsrc,14, tmp); if(iusedbyte < 1){ goto error_receive; } memcpy(receive_report->invoketime ,tmp, 14); (*desmsg)->msgbody = receive_report; break; } return 1; no_msg: info(0,"sema_decode: msg is empty"); return 0; error_receive: gw_free(receive_report); goto error_msg; error_submit: gw_free(submit_result); goto error_msg; error_deliver: gw_free(receive_sm); goto error_msg; error_msg: info(0,"sema_decode:msg parameter is not recognized or unsupported"); return 0; } static int sema_encode_msg(sema_msg* pmsg, char* str) { struct sm_submit_invoke *submit_sm = NULL; Octstr *IA5msg = NULL; int tSize = 0; unsigned char oc1byte[10]; IA5msg = octstr_create(""); switch(pmsg->type) { case 'S': submit_sm = (struct sm_submit_invoke *) pmsg->msgbody; write_variable_value(submit_sm->msisdnlen, oc1byte); /*msisdn len*/ line_append_hex_IA5(IA5msg, oc1byte,1); line_append_hex_IA5(IA5msg, (unsigned char *)octstr_get_cstr(submit_sm->msisdn), octstr_len(submit_sm->msisdn)); /*msisdn*/ write_variable_value(submit_sm->smereftype, oc1byte);/*smetype*/ line_append_hex_IA5(IA5msg, oc1byte,1); line_append_hex_IA5(IA5msg, submit_sm->smerefnum,4);/*sme reference*/ write_variable_value(submit_sm->priority, oc1byte);/*priority*/ line_append_hex_IA5(IA5msg, oc1byte,1); write_variable_value(submit_sm->origaddlen, oc1byte); /*orignating address length*/ line_append_hex_IA5(IA5msg, oc1byte,1); line_append_hex_IA5(IA5msg, (unsigned char *)octstr_get_cstr(submit_sm->origadd), octstr_len(submit_sm->origadd)); /*orignating address*/ write_variable_value(submit_sm->validperiodtype, oc1byte); /*valid period type*/ line_append_hex_IA5(IA5msg, oc1byte,1); write_variable_value(submit_sm->validperiodrela, oc1byte); /*relative period*/ line_append_hex_IA5(IA5msg, oc1byte,1); write_variable_value(submit_sm->DCS, oc1byte);/*data code scheme*/ line_append_hex_IA5(IA5msg, oc1byte,1); write_variable_value(submit_sm->statusreportrequest, oc1byte);/*request report*/ line_append_hex_IA5(IA5msg, oc1byte,1); write_variable_value(submit_sm->protocal, oc1byte);/*protocal id*/ line_append_hex_IA5(IA5msg, oc1byte, 1); write_variable_value(submit_sm->replypath, oc1byte);/*use reply path*/ line_append_hex_IA5(IA5msg, oc1byte, 1); /*text size in 7 bits char*/ tSize = internal_char_hex_to_IA5(submit_sm->textsizeseptet,oc1byte); octstr_insert_data(IA5msg, octstr_len(IA5msg), (char *)oc1byte, tSize); /*text size in 8 bits char*/ tSize = internal_char_hex_to_IA5(submit_sm->textsizeoctect,oc1byte); octstr_insert_data(IA5msg, octstr_len(IA5msg),(char *) oc1byte, tSize); line_append_hex_IA5(IA5msg, (unsigned char *)octstr_get_cstr(submit_sm->shortmsg), submit_sm->textsizeoctect); /*msg text*/ memcpy(str,octstr_get_cstr(IA5msg),octstr_len(IA5msg)); octstr_destroy(IA5msg); return 1; } return 0; } static int line_scan_hex_GSM7(unsigned char* from, int octects ,int spetets, unsigned char* to) { char* cin2 =NULL; unsigned char c; char cin7[8]; int i, pos, value; int lenin2=octects*8; cin2 = gw_malloc(lenin2); memset(cin2,48,lenin2); /*make many zeros*/ /*tranverse the octects first, so ABC -> CBA(in bin form)*/ for(i = 0; i < octects; i ++) { c = *(from + i); if(c & 1) cin2[(octects-1-i)*8 +7] = 49; if(c & 2) cin2[(octects-1-i)*8 +6] = 49; if(c & 4) cin2[(octects-1-i)*8 +5] = 49; if(c & 8) cin2[(octects-1-i)*8 +4] = 49; if(c & 16) cin2[(octects-1-i)*8 +3] = 49; if(c & 32) cin2[(octects-1-i)*8 +2] = 49; if(c & 64) cin2[(octects-1-i)*8 +1] = 49; if(c & 128) cin2[(octects-1-i)*8] = 49; } i= 1; while( i <= spetets ){ pos=lenin2 -1 -(i*7 -1); memset(cin7,0,sizeof(cin7)); memcpy(cin7, cin2 + pos, 7); value = 0; if(cin7[6] == '1') value += 1; if(cin7[5] == '1') value += 2; if(cin7[4] == '1') value += 4; if(cin7[3] == '1') value += 8; if(cin7[2] == '1') value += 16; if(cin7[1] == '1') value += 32; if(cin7[0] == '1') value += 64; to[i-1]=internal_char_hex_to_gsm(value); i +=1; } return i; } /* check SMS2000 Version 4.0 B.4.2.3 */ static int line_append_hex_IA5(Octstr* des, unsigned char* src, int len) { unsigned char IA5char[3]; unsigned char tmp[1024]; int j=0; int i=0, iall=0; for(i=0; i0){ memcpy(tmp+iall,IA5char,j); iall += j; } } octstr_insert_data(des,octstr_len(des),(char *)tmp,iall); return iall; } /* check SMS2000 Version 4.0 B.4.2.3 */ static int line_scan_IA5_hex(char* from, int hexnum, unsigned char* to) { unsigned char cha[1]; int cn =0, cnall = 0, i = 0; char *tmpfrom = NULL; tmpfrom = from; for(i = 0; i< hexnum; i++) { cn=internal_char_IA5_to_hex(tmpfrom, cha); if(cn >0) { memcpy(to+i,cha,1); tmpfrom += cn; cnall += cn; } else return -1; } return cnall; } static unsigned char internal_char_hex_to_gsm(unsigned char from) { switch (from){ case 0x00: return '@'; case 0x01: return '£'; case 0x02: return '$'; case 0x03: return '¥'; case 0x04: return 'è'; case 0x05: return 'é'; case 0x06: return 'ù'; case 0x07: return 'ì'; case 0x08: return 'ò'; case 0x09: return 'Ç'; case 0x0A: return '\n'; case 0x0B: return 'Ø'; case 0x0C: return 'ø'; case 0x0D: return '\r'; case 0x0E: return 'Å'; case 0x0F: return 'å'; case 0x10: return 'D'; case 0x11: return ' '; case 0x12: return 'F'; case 0x13: return 'G'; case 0x14: return 'L'; case 0x15: return 'W'; case 0x16: return 'P'; case 0x17: return 'Y'; case 0x18: return 'S'; case 0x19: return 'Q'; case 0x1A: return 'X'; case 0x1B: return ' '; case 0x1C: return 'Æ'; case 0x1D: return 'æ'; case 0x1E: return 'b'; case 0x1F: return 'É'; case 0x5B: return 'Ä'; case 0x5C: return 'Ö'; case 0x5D: return 'Ñ'; case 0x5E: return 'Ü'; case 0x5F: return '§'; case 0x60: return '¿'; case 0x7B: return 'a'; case 0x7C: return 'ö'; case 0x7D: return 'ñ'; case 0x7E: return 'ü'; case 0x7F: return 'à'; default: return from; } } /* check SMS2000 Version 4.0 B.4.2.3 */ static int internal_char_hex_to_IA5(unsigned char from, unsigned char * to){ if(from <= 0x1F) { to[0] = '^'; to[1] = 0x40 + from; return 2; } else if(from ==0x5C) { to[0] = 0x5C; to[1] = 0x5C; return 2; } else if(from == 0x5E) { to[0] = 0x5C; to[1] = 0x5E; return 2; } else if(from == 0x60) { to[0] = 0x5C; to[1] = 0x60; return 2; } else if(from == 0x7E) { to[0] = 0x5C; to[1] = 0x7E; return 2; } else if(from >= 0x20 && from <= 0x7E) { to [0] = from; return 1; } else if(from == 0x7F) { to[0] = 0x5E; to[1] = 0x7E; return 2; } else if(from >= 0x80 && from <=0x9F) { to[0] = 0x7E; to[1] = from -0x40; return 2; } else if(from >= 0xA0 && from <=0xFE) { to[0] = 0x60; to[1] = from -0x80; return 2; } else if(from == 0xFF) { to[0] =to[1] = 0x7E; return 2; } else return -1; } static int internal_char_IA5_to_hex(char *from, unsigned char * to){ int ret = -1; int len = strlen(from); if(*from == '^' && len >= 2 && *(from +1) == '~') { *to = 0x7F; ret = 2; } else if(*from ==0x5C && len >= 2 && *(from +1) == 0x5C) { *to= 0x5C; ret = 2; } else if(*from == 0x5C && len >= 2 && *(from+1) == 0x5E) { *to= 0x5E; ret = 2; } else if(*from == 0x5C && len >= 2 && *(from+1) == 0x60) { *to= 0x60; ret = 2; } else if(*from == 0x5C && len >=2 && *(from+1) == 0x7E) { *to= 0x7E; ret = 2; } else if(*from == '^' && len >= 2 && (*(from +1) >= 0x40 && *(from +1) <= 0x5F)) { *to = *(from +1) -0x40; ret = 2; } else if(*from == '~' && len >= 2 && (*(from +1) >= 0x40 && *(from +1) <= 0x5F)) { *to = *(from +1) +0x40; ret = 2; } else if(*from == '`' && len >= 2 && (*(from+1) >= 0x20 && *(from +1) <= 0x7E)) { *to = *(from +1) +0x80; ret = 2; } else if(*from >=0x20 && *from <=0x7E) { *to= *from; ret = 1; } return ret; } static void increment_counter(void) { if(sema_counter[3] == 0x39) sema_counter[3] = 0x30; else { sema_counter[3] += 0x01; return; } if(sema_counter[2] == 0x39) sema_counter[2] = 0x30; else { sema_counter[2] += 0x01; return; } if(sema_counter[1] == 0x39) sema_counter[1] = 0x30; else { sema_counter[1] += 0x01; return; } if(sema_counter[0] == 0x39) sema_counter[0] = 0x30; else sema_counter[0] += 0x01; return; } /* check SMS2000 Version 4.0 B.4.2.2 */ static unsigned char pack_continous_byte(int encode, int isfirst, int follownum) { char bin[4]; int value; memset(bin, 0, 4); value = 0; if(isfirst == 1) strncpy(bin,"0101",4); else strncpy(bin,"0110",4); if(bin[3] == '1') value += 16; if(bin[2] == '1') value += 32; if(bin[1] == '1') value += 64; if(bin[0] == '1') /* although it's impossible */ value += 128; return (value+follownum); } /* check SMS2000 Version 4.0 B.4.2.2 */ static int unpack_continous_byte(unsigned char continueCount, int * encode, int * isfirst, int * follownum) { int rest = 0; int head = 0; if(continueCount & 1) rest +=1; if(continueCount & 2) rest +=2; if(continueCount & 4) rest += 4; if(continueCount & 8) rest += 8; *follownum = rest; if(continueCount & 16) head += 1; if(continueCount & 32) head += 2; if(continueCount & 64) head += 4; if(continueCount & 128) /* though not possible */ head += 8; *encode = *isfirst = -1; if(head == 5) { *encode =LINE_ENCODE_IA5; *isfirst = 1; } else if(head == 6) { *encode =LINE_ENCODE_IA5; *isfirst = 0; } else if(head == 4) { *encode =LINE_ENCODE_HEX; *isfirst = 1; } else if(head == 3) { *encode =LINE_ENCODE_HEX; *isfirst = 0; } else if(head == 7) { *encode =LINE_ENCODE_BIN; *isfirst = 1; } else if(head == 2) { *encode =LINE_ENCODE_BIN; *isfirst = 0; } if(*encode != -1 && *isfirst != -1) return 0; else return -1; } gateway-1.4.5/gw/smsc/smsc_at.h0000644000175000017500000002667313227613126015071 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/smsc_at.h * * New driver for serial connected AT based * devices. * 4.9.2001 * Andreas Fink * */ #ifndef SMSC_AT2_H #define SMSC_AT2_H #include "gwlib/gwlib.h" #include "load.h" /* maximum data to attempt to read in one go */ #define MAX_READ 1023 /* Message types defines */ #define AT_DELIVER_SM 0 #define AT_SUBMIT_SM 1 #define AT_STATUS_REPORT_SM 2 /* type of phone number defines */ #define PNT_UNKNOWN 0 #define PNT_INTER 1 #define PNT_NATIONAL 2 /* The number of times to attempt to write a line should writing fail */ #define RETRY_WRITE 3 /* * defines for use with the so-called "SIM buffering techinique": * once in how many seconds to poll the memory locations, * if keepalive is _not_ set (will use keepalive time if set) */ #define AT2_DEFAULT_SMS_POLL_INTERVAL 60 /* * Structures used in at2 */ typedef struct ModemDef { Octstr *id; Octstr *name; Octstr *detect_string; Octstr *detect_string2; Octstr *init_string; Octstr *reset_string; long speed; Octstr *enable_hwhs; int need_sleep; int no_pin; int no_smsc; long sendline_sleep; Octstr *keepalive_cmd; int broken; Octstr *message_storage; long message_start; int enable_mms; int hardware_flow_control; } ModemDef; typedef struct PrivAT2data { gw_prioqueue_t *outgoing_queue; ModemDef *modem; long device_thread; int shutdown; /* Internal signal to shut down */ Octstr *device; long speed; long keepalive; int fd; /* file descriptor */ Octstr *ilb; /* input line buffer */ Octstr *lines; /* the last few lines before OK was seen */ Octstr *pin; /* PIN code */ int pin_ready; SMSCConn *conn; int phase2plus; Octstr *validityperiod; int retry; Octstr *my_number; Octstr *sms_center; Octstr *name; Octstr *configfile; Octstr *username; Octstr *password; Octstr *login_prompt; Octstr *password_prompt; int sms_memory_poll_interval; int sms_memory_capacity; int sms_memory_usage; List *pending_incoming_messages; long max_error_count; Octstr *rawtcp_host; int rawtcp_port; int is_serial; /* false if device is rawtcp */ int use_telnet; /* use telnet escape sequences */ Load *load; } PrivAT2data; /* * Macro that is used inside smsc_at2.c in order to handle * octstr destruction more carefully. */ #define O_DESTROY(a) { if(a) octstr_destroy(a); a = NULL; } /* #define at2_write_ctrlz(a) at2_write(a,"\032") */ /* * open the specified device using the serial line */ static int at2_open_device(PrivAT2data *privdata); /* * close the specified device and hence disconnect from the serial line */ static void at2_close_device(PrivAT2data *privdata); /* * checks if there are any incoming bytes and adds them to the line buffer */ static void at2_read_buffer(PrivAT2data *privdata, double timeout); /* * Looks for a full line to be read from the buffer. * Returns the line and removes it from the buffer or if no full line * is yet received waits until the line is there or a timeout occurs. * If gt_flag is set, it is also looking for a line containing '>' even * there is no CR yet. */ static Octstr *at2_wait_line(PrivAT2data *privdata, time_t timeout, int gt_flag); /* * Looks for a full line to be read from the buffer. * Returns the line and removes it from the buffer or if no full line * is yet received returns NULL. If gt_flag is set, it is also looking for * a line containing > even there is no CR yet. */ static Octstr *at2_read_line(PrivAT2data *privdata, int gt_flag, double timeout); /* * Writes a line out to the device and adds a carriage return/linefeed to it. * Returns number of characters sent. */ static int at2_write_line(PrivAT2data *privdata, char *line); static int at2_write_ctrlz(PrivAT2data *privdata); static int at2_write(PrivAT2data *privdata, char *line); /* * Clears incoming buffer */ static void at2_flush_buffer(PrivAT2data *privdata); /* * Initializes the device after being opened, detects the modem type, * sets speed settings etc. * On failure returns -1. */ static int at2_init_device(PrivAT2data *privdata); /* * Sends an AT command to the modem and waits for a reply * Return values are: * 0 = OK * 1 = ERROR * 2 = SIM PIN * 3 = > * 4 = READY * 5 = CMGS * -1 = timeout occurred */ static int at2_send_modem_command(PrivAT2data *privdata, char *cmd, time_t timeout, int greaterflag); /* * Waits for the modem to send us something. */ static int at2_wait_modem_command(PrivAT2data *privdata, time_t timeout, int greaterflag, int *output); /* * Sets the serial port speed on the device */ static void at2_set_speed(PrivAT2data *privdata, int bps); /* * This is the main tread "sitting" on the device. * Its task is to initialize the modem then wait for messages * to arrive or to be sent */ static void at2_device_thread(void *arg); static int at2_shutdown_cb(SMSCConn *conn, int finish_sending); static long at2_queued_cb(SMSCConn *conn); static void at2_start_cb(SMSCConn *conn); static int at2_add_msg_cb(SMSCConn *conn, Msg *sms); /* * Starts the whole thing up */ int smsc_at2_create(SMSCConn *conn, CfgGroup *cfg); /* * Extracts the first PDU in the string */ static int at2_pdu_extract(PrivAT2data *privdata, Octstr **pdu, Octstr *line, Octstr *smsc_number); /* * Get the numeric value of the text hex */ static int at2_hexchar(int hexc); /* * Decode a raw PDU into a Msg */ static Msg *at2_pdu_decode(Octstr *data, PrivAT2data *privdata); /* * Decode a DELIVER PDU */ static Msg *at2_pdu_decode_deliver_sm(Octstr *data, PrivAT2data *privdata); /* * Decode a SUBMIT-REPORT PDU */ static Msg *at2_pdu_decode_report_sm(Octstr *data, PrivAT2data *privdata); /* * Converts the text representation of hexa to binary */ static Octstr *at2_convertpdu(Octstr *pdutext); /* * Decode 7bit uncompressed user data */ static void at2_decode7bituncompressed(Octstr *input, int len, Octstr *decoded, int offset); /* * Sends messages from the queue */ static void at2_send_messages(PrivAT2data *privdata); /* * Sends a single message. * After having it sent, the msg is no longe belonging to us */ static void at2_send_one_message(PrivAT2data *privdata, Msg *msg); /* * Encode a Msg into a PDU */ static Octstr *at2_pdu_encode(Msg *msg, PrivAT2data *privdata); /* * Encode 7bit uncompressed user data into an Octstr, prefixing with 0 bits */ static Octstr *at2_encode7bituncompressed(Octstr *input, int offset); /* * Encode 8bit uncompressed user data into an Octstr */ static Octstr *at2_encode8bituncompressed(Octstr *input); /* * Code a half-byte to its text hexa representation */ static int at2_numtext(int num); /* * Try to detect modem speeds */ static int at2_detect_speed(PrivAT2data *privdata); /* * Test modem speed */ static int at2_test_speed(PrivAT2data *privdata, long speed); /* * Try to detect modem type */ static int at2_detect_modem_type(PrivAT2data *privdata); /* * Read all defined modems from the included modem definition file */ static ModemDef *at2_read_modems(PrivAT2data *privdata, Octstr *file, Octstr *id, int idnumber); /* * Destroy the ModemDef structure components */ static void at2_destroy_modem(ModemDef *modem); /* * Checks whether any messages are buffered in message storage and extract them. */ static int at2_read_sms_memory(PrivAT2data *privdata); /* * Memory capacity and usage check */ static int at2_check_sms_memory(PrivAT2data *privdata); /* * This silly thing here will just translate a "swapped nibble" * pseodo Hex encoding (from PDU) into something that people can * actually understand. * Implementation completly ripped off Dennis Malmstrom timestamp * patches against 1.0.3. Thanks Dennis! */ static int swap_nibbles(unsigned char byte); /* * creates a buffer with a valid PDU address field as per [GSM 03.40] * from an MSISDN number */ static Octstr *at2_format_address_field(Octstr *msisdn); /* * Check the pending_incoming_messages queue for CMTI notifications. * Every notification is parsed and the messages are read (and deleted) * accordingly. */ static void at2_read_pending_incoming_messages(PrivAT2data *privdata); /* * Set the memory storage location of the modem by sending a +CPMS command */ static int at2_set_message_storage(PrivAT2data *privdata, Octstr *memory_name); /* * Reads a message from selected memory location and deletes it afterwards. * returns 0 on failure and 1 on success */ static int at2_read_delete_message(PrivAT2data *privdata, int message_number); /* * Return appropriate error string for the given error code. */ static const char *at2_error_string(int code); #endif /* SMSC_AT2_H */ gateway-1.4.5/gw/smsc/smpp_pdu_opt.def0000644000175000017500000001447113227613126016451 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * The SMPP supported TLVs and their associated Tag Values. * * Reference: * SMPP v5.0 Specification, section 4.8 'PDU TLV Definitions', page 135. */ #ifndef SMPP_PDU_OPT #define SMPP_PDU_OPT /* defined in SMP v3.4 */ #define SMPP_dest_addr_subunit 0x0005 #define SMPP_dest_network_type 0x0006 #define SMPP_dest_bearer_type 0x0007 #define SMPP_dest_telematics_id 0x0008 #define SMPP_source_addr_subunit 0x000D #define SMPP_source_network_type 0x000E #define SMPP_source_bearer_type 0x000F #define SMPP_source_telematics_id 0x0010 #define SMPP_qos_time_to_live 0x0017 #define SMPP_payload_type 0x0019 #define SMPP_additional_status_info_text 0x001D #define SMPP_receipted_message_id 0x001E #define SMPP_ms_msg_wait_facilities 0x0030 #define SMPP_privacy_indicator 0x0201 #define SMPP_source_subaddress 0x0202 #define SMPP_dest_subaddress 0x0203 #define SMPP_user_message_reference 0x0204 #define SMPP_user_response_code 0x0205 #define SMPP_source_port 0x020A #define SMPP_destination_port 0x020B #define SMPP_sar_msg_ref_num 0x020C #define SMPP_language_indicator 0x020D #define SMPP_sar_total_segments 0x020E #define SMPP_sar_segment_seqnum 0x020F #define SMPP_sc_interface_version 0x0210 #define SMPP_callback_num_pres_ind 0x0302 #define SMPP_callback_num_atag 0x0303 #define SMPP_number_of_messages 0x0304 #define SMPP_callback_num 0x0381 #define SMPP_dpf_result 0x0420 #define SMPP_set_dpf 0x0421 #define SMPP_ms_availability_status 0x0422 #define SMPP_network_error_code 0x0423 #define SMPP_message_payload 0x0424 #define SMPP_delivery_failure_reason 0x0425 #define SMPP_more_messages_to_send 0x0426 #define SMPP_message_state 0x0427 #define SMPP_congestion_state 0x0428 /* defined in SMPP v5.0 */ #define SMPP_ussd_service_op 0x0501 /* defined in SMPP v3.4 */ /* block 0x06xx defined in SMPP v5.0 */ #define SMPP_broadcast_channel_indicator 0x0600 #define SMPP_broadcast_content_type 0x0601 #define SMPP_broadcast_content_type_info 0x0602 #define SMPP_broadcast_message_class 0x0603 #define SMPP_broadcast_rep_num 0x0604 #define SMPP_broadcast_frequency_interval 0x0605 #define SMPP_broadcast_area_identifier 0x0606 #define SMPP_failed_broadcast_area_identifier 0x0606 /* see 4.8.4.4, page 138 */ #define SMPP_broadcast_error_status 0x0607 #define SMPP_broadcast_area_success 0x0608 #define SMPP_broadcast_end_time 0x0609 #define SMPP_broadcast_service_group 0x060A #define SMPP_billing_identification 0x060B #define SMPP_source_network_id 0x060D #define SMPP_dest_network_id 0x060E #define SMPP_source_node_id 0x060F #define SMPP_dest_node_id 0x0610 #define SMPP_dest_addr_np_resolution 0x0611 #define SMPP_dest_addr_np_information 0x0612 #define SMPP_dest_addr_np_country 0x0613 /* defined in SMPP v3.4 */ #define SMPP_display_time 0x1201 #define SMPP_sms_signal 0x1203 #define SMPP_ms_validity 0x1204 #define SMPP_alert_on_message_delivery 0x130C #define SMPP_its_reply_type 0x1380 #define SMPP_its_session_info 0x1383 #endif gateway-1.4.5/gw/dlr.h0000644000175000017500000001271513227613126013244 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/dlr.h * * Implementation of handling delivery reports (DLRs) * * Andreas Fink , 18.08.2001 * Stipe Tolj , 22.03.2002 * Alexander Malysh , 2016 */ #ifndef DLR_H #define DLR_H 1 #define DLR_UNDEFINED -1 #define DLR_NOTHING 0x00 #define DLR_SUCCESS 0x01 #define DLR_FAIL 0x02 #define DLR_BUFFERED 0x04 #define DLR_SMSC_SUCCESS 0x08 #define DLR_SMSC_FAIL 0x10 #define DLR_EXPIRED 0x20|DLR_FAIL #define DLR_UNKNOWN 0x40|DLR_FAIL #define DLR_IS_DEFINED(dlr) (dlr != DLR_UNDEFINED) #define DLR_IS_ENABLED(dlr) (DLR_IS_DEFINED(dlr) && (dlr & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED | DLR_SMSC_SUCCESS | DLR_SMSC_FAIL | DLR_EXPIRED | DLR_UNKNOWN))) #define DLR_IS_ENABLED_DEVICE(dlr) (DLR_IS_DEFINED(dlr) && (dlr & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED | DLR_EXPIRED | DLR_UNKNOWN))) #define DLR_IS_ENABLED_SMSC(dlr) (DLR_IS_DEFINED(dlr) && (dlr & (DLR_SMSC_SUCCESS | DLR_SMSC_FAIL))) #define DLR_IS_NOT_FINAL(dlr) (DLR_IS_DEFINED(dlr) && (dlr & (DLR_BUFFERED | DLR_SMSC_SUCCESS))) #define DLR_IS_SUCCESS_OR_FAIL(dlr) (DLR_IS_DEFINED(dlr) && (dlr & (DLR_SUCCESS | DLR_FAIL | DLR_EXPIRED | DLR_UNKNOWN))) #define DLR_IS_SUCCESS(dlr) (DLR_IS_DEFINED(dlr) && (dlr & DLR_SUCCESS)) #define DLR_IS_FAIL(dlr) (DLR_IS_DEFINED(dlr) && (dlr & (DLR_FAIL|DLR_EXPIRED|DLR_UNKNOWN))) #define DLR_IS_BUFFERED(dlr) (DLR_IS_DEFINED(dlr) && (dlr & DLR_BUFFERED)) #define DLR_IS_SMSC_SUCCESS(dlr) (DLR_IS_DEFINED(dlr) && (dlr & DLR_SMSC_SUCCESS)) #define DLR_IS_SMSC_FAIL(dlr) (DLR_IS_DEFINED(dlr) && (dlr & DLR_SMSC_FAIL)) /* DLR initialization routine (abstracted) */ void dlr_init(Cfg *cfg); /* DLR shutdown routine (abstracted) */ void dlr_shutdown(void); /* * Add a new entry to the list */ void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg, int use_dst); /* * Find an entry in the list. If there is one a message is returned and * the entry is removed from the list otherwhise the message returned is NULL */ Msg* dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int type, int use_dst); /* return the number of DLR messages in the current waiting queue */ long dlr_messages(void); /* * Flush all DLR messages in the current waiting queue. * Beware to take bearerbox to suspended state before doing this. */ void dlr_flush(void); /* * Return type of dlr storage */ const char* dlr_type(void); /* * Helper function, create DLR from given message */ Msg* create_dlr_from_msg(const Octstr *smsc, const Msg *msg, const Octstr *reply, long stat); /* * Yet not used functions. */ void dlr_save(const char *filename); void dlr_load(const char *filename); #endif /* DLR_H */ gateway-1.4.5/gw/wap_push_si_compiler.h0000644000175000017500000000620513227613126016673 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_si_compiler.h: The interface to si tokenizer * * By Aarno Syvänen for Wiral Ltd */ #ifndef WAP_PUSH_SI_COMPILER_H #define WAP_PUSH_SI_COMPILER_H #include "gwlib/gwlib.h" /* * Compiles a si document to si binary. Input textual form of a si document * and its charset (from http headers), output the document in a tokenised * form. */ int si_compile(Octstr *si_doc, Octstr *charset, Octstr **si_binary); #endif gateway-1.4.5/gw/bb_store_redis.c0000644000175000017500000005074213227613126015445 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /** * bb_store_redis.c - bearerbox box SMS storage/retrieval module using a redis database * * Author: Alejandro Guerrieri, 2015 * Adds: Stipe Tolj, 2015 */ #include "gw-config.h" #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "msg.h" #include "sms.h" #include "bearerbox.h" #include "bb_store.h" #ifdef HAVE_REDIS #include "gwlib/dbpool.h" /* * Define REDIS_TRACE to get DEBUG level output of the * Redis commands send to the server. */ /* #define REDIS_TRACE 1 */ static Counter *counter; static List *loaded; static DBPool *pool = NULL; struct store_db_fields { Octstr *table; Octstr *field_uuid; Octstr *field_message; }; static struct store_db_fields *fields = NULL; static int hash = 0; /* * Convert a Msg structure to a Dict hash. * This will assume we handle the msg->sms type only. */ /* static Dict *hash_msg_pack(Msg *msg) { Dict *h; gw_assert(msg->type == sms); h = dict_create(32, octstr_destroy_item); #define INTEGER(name) dict_put(h, octstr_imm(#name), octstr_format("%ld", p->name)); #define OCTSTR(name) dict_put(h, octstr_imm(#name), octstr_duplicate(p->name)); #define UUID(name) { \ char id[UUID_STR_LEN + 1]; \ uuid_unparse(p->name, id); \ dict_put(h, octstr_imm(#name), octstr_create(id)); \ } #define VOID(name) #define MSG(type, stmt) \ case type: { struct type *p = &msg->type; stmt } break; switch (msg->type) { #include "msg-decl.h" default: panic(0, "Internal error: unknown message type: %d", msg->type); } return h; } */ static Msg *hash_msg_unpack(Dict *hash) { Msg *msg; Octstr *os; if (hash == NULL) return NULL; msg = msg_create(sms); #define INTEGER(name) \ if ((os = dict_get(hash, octstr_imm(#name))) != NULL) \ p->name = atol(octstr_get_cstr(os)); #define OCTSTR(name) p->name = octstr_duplicate(dict_get(hash, octstr_imm(#name))); #define UUID(name) \ if ((os = dict_get(hash, octstr_imm(#name))) != NULL) \ uuid_parse(octstr_get_cstr(os), p->name); #define VOID(name) #define MSG(type, stmt) \ case type: { struct type *p = &msg->type; stmt } break; switch (msg->type) { #include "msg-decl.h" default: panic(0, "Internal error: unknown message type: %d", msg->type); } return msg; } static int store_redis_dump() { /* nothing to do */ return 0; } static long store_redis_messages() { return counter ? counter_value(counter) : -1; } static void redis_update(const Octstr *cmd, List *binds) { int res; DBPoolConn *pc; #if defined(REDIS_TRACE) debug("store.redis", 0, "redis cmd: %s", octstr_get_cstr(cmd)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "Database pool got no connection! Redis update failed!"); return; } res = dbpool_conn_update(pc, cmd, binds); if (res < 0) { error(0, "Store-Redis: Error while updating: command was `%s'", octstr_get_cstr(cmd)); } dbpool_conn_produce(pc); } static void store_redis_add(Octstr *id, Octstr *os) { Octstr *cmd; octstr_binary_to_base64(os); cmd = octstr_format("HSET %s %s %s", octstr_get_cstr(fields->table), octstr_get_cstr(id), octstr_get_cstr(os)); redis_update(cmd, NULL); octstr_destroy(cmd); } /* static void store_redis_add_hash(Octstr *id, Dict *hash) { List *l, *b; Octstr *cmd, *key, *val; cmd = octstr_create(""); b = gwlist_create(); gwlist_produce(b, octstr_create("HMSET")); gwlist_produce(b, octstr_duplicate(id)); l = dict_keys(hash); while ((key = gwlist_extract_first(l)) != NULL) { if ((val = dict_get(hash, key)) != NULL) { gwlist_produce(b, key); gwlist_produce(b, octstr_duplicate(val)); } } gwlist_destroy(l, NULL); redis_update(cmd, b); gwlist_destroy(b, octstr_destroy_item); octstr_destroy(cmd); } */ /* * In order to a) speed-up the processing of the bind list in the dbpool_redis.c * module and b) safe space in the redis-server memory, we will only store * values that are set. */ static void store_redis_add_msg(Octstr *id, Msg *msg) { List *b; Octstr *cmd; char uuid[UUID_STR_LEN + 1]; cmd = octstr_create(""); b = gwlist_create(); gwlist_produce(b, octstr_create("HMSET")); gwlist_produce(b, octstr_duplicate(id)); #define INTEGER(name) \ if (p->name != MSG_PARAM_UNDEFINED) { \ gwlist_produce(b, octstr_imm(#name)); \ gwlist_produce(b, octstr_format("%ld", p->name)); \ } #define OCTSTR(name) \ if (p->name != NULL) { \ gwlist_produce(b, octstr_imm(#name)); \ gwlist_produce(b, octstr_duplicate(p->name)); \ } #define UUID(name) \ gwlist_produce(b, octstr_imm(#name)); \ uuid_unparse(p->name, uuid); \ gwlist_produce(b, octstr_create(uuid)); #define VOID(name) #define MSG(type, stmt) \ case type: { struct type *p = &msg->type; stmt } break; switch (msg->type) { #include "msg-decl.h" default: panic(0, "Internal error: unknown message type: %d", msg->type); break; } redis_update(cmd, b); gwlist_destroy(b, octstr_destroy_item); octstr_destroy(cmd); } static void store_redis_delete(Octstr *id) { Octstr *cmd; cmd = octstr_format("HDEL %s %s", octstr_get_cstr(fields->table), octstr_get_cstr(id)); redis_update(cmd, NULL); octstr_destroy(cmd); } static void store_redis_delete_hash(Octstr *id) { Octstr *cmd; cmd = octstr_format("DEL %s", octstr_get_cstr(id)); redis_update(cmd, NULL); octstr_destroy(cmd); } static struct store_db_fields *store_db_fields_create(CfgGroup *grp) { struct store_db_fields *ret; ret = gw_malloc(sizeof(*ret)); gw_assert(ret != NULL); memset(ret, 0, sizeof(*ret)); if ((ret->table = cfg_get(grp, octstr_imm("table"))) == NULL) { grp_dump(grp); panic(0, "Directive 'table' is not specified in 'group = store-db' context!"); } return ret; } static void store_db_fields_destroy(struct store_db_fields *fields) { /* sanity check */ if (fields == NULL) return; octstr_destroy(fields->table); octstr_destroy(fields->field_uuid); octstr_destroy(fields->field_message); gw_free(fields); } static int store_redis_getall(int ignore_err, void(*cb)(Octstr*, void*), void *data) { DBPoolConn *pc; Octstr *cmd; Octstr *os, *key; List *result, *row; cmd = octstr_format("HGETALL %s", octstr_get_cstr(fields->table)); #if defined(REDIS_TRACE) debug("store.redis", 0, "redis cmd: %s", octstr_get_cstr(cmd)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "Database pool got no connection! Redis HGETALL failed!"); dbpool_conn_produce(pc); return -1; } if (dbpool_conn_select(pc, cmd, NULL, &result) != 0) { error(0, "Failed to fetch messages from redis with cmd `%s'", octstr_get_cstr(cmd)); octstr_destroy(cmd); dbpool_conn_produce(pc); return -1; } dbpool_conn_produce(pc); octstr_destroy(cmd); if (gwlist_len(result) == 1 && (row = gwlist_extract_first(result)) != NULL) { while (gwlist_len(row) > 0) { key = gwlist_extract_first(row); os = gwlist_extract_first(row); if (key && os) { debug("store.redis", 0, "Found entry for message ID <%s>", octstr_get_cstr(key)); octstr_base64_to_binary(os); if (os == NULL) { error(0, "Could not base64 decode message ID <%s>", octstr_get_cstr(key)); } else { cb(os, data); } } octstr_destroy(os); octstr_destroy(key); } gwlist_destroy(row, octstr_destroy_item); } else { debug("store.redis", 0, "No messages loaded from redis store"); } gwlist_destroy(result, NULL); return 0; } static int store_redis_getall_hash(int ignore_err, void(*cb)(Dict*, void*), void *data) { DBPoolConn *pc; Octstr *cmd; Octstr *os, *key, *id; List *result, *row, *result_key, *row_key; Dict *hash; cmd = octstr_create("KEYS *"); #if defined(REDIS_TRACE) debug("store.redis", 0, "redis cmd: %s", octstr_get_cstr(cmd)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "Database pool got no connection! Redis KEYS failed!"); dbpool_conn_produce(pc); return -1; } if (dbpool_conn_select(pc, cmd, NULL, &result) != 0) { error(0, "Failed to fetch messages from redis with cmd `%s'", octstr_get_cstr(cmd)); octstr_destroy(cmd); dbpool_conn_produce(pc); return -1; } octstr_destroy(cmd); if (gwlist_len(result) == 1 && ((row = gwlist_extract_first(result)) != NULL)) { while ((id = gwlist_extract_first(row)) != NULL) { cmd = octstr_format("HGETALL %s", octstr_get_cstr(id)); if (dbpool_conn_select(pc, cmd, NULL, &result_key) != 0) { error(0, "Failed to fetch messages from redis with cmd `%s'", octstr_get_cstr(cmd)); octstr_destroy(cmd); dbpool_conn_produce(pc); octstr_destroy(id); gwlist_destroy(result, octstr_destroy_item); return -1; } octstr_destroy(cmd); if (gwlist_len(result_key) == 1 && ((row_key = gwlist_extract_first(result_key)) != NULL)) { hash = dict_create(32, octstr_destroy_item); while (gwlist_len(row_key) > 0) { key = gwlist_extract_first(row_key); os = gwlist_extract_first(row_key); if (key && os) { dict_put(hash, key, os); } octstr_destroy(key); } cb(hash, data); dict_destroy(hash); gwlist_destroy(row_key, octstr_destroy_item); } gwlist_destroy(result_key, NULL); } gwlist_destroy(row, octstr_destroy_item); } else { debug("store.redis", 0, "No messages loaded from redis store"); } dbpool_conn_produce(pc); gwlist_destroy(result, NULL); return 0; } struct status { void(*callback_fn)(Msg* msg, void *data); void *data; }; static void status_cb(Octstr *msg_s, void *d) { struct status *data = d; Msg *msg; msg = store_msg_unpack(msg_s); if (msg == NULL) return; data->callback_fn(msg, data->data); msg_destroy(msg); } static void store_redis_for_each_message(void(*callback_fn)(Msg* msg, void *data), void *data) { struct status d; if (pool == NULL) return; d.callback_fn = callback_fn; d.data = data; /* ignore error because files may disappear */ store_redis_getall(1, status_cb, &d); } static void dispatch(Octstr *msg_s, void *data) { Msg *msg; void (*receive_msg)(Msg*) = data; if (msg_s == NULL) return; msg = store_msg_unpack(msg_s); if (msg != NULL) { receive_msg(msg); counter_increase(counter); } else { error(0, "Could not unpack message from redis store!"); } } static void dispatch_hash(Dict *msg_h, void *data) { Msg *msg; void (*receive_msg)(Msg*) = data; if (msg_h == NULL) return; msg = hash_msg_unpack(msg_h); if (msg != NULL) { receive_msg(msg); counter_increase(counter); } else { error(0, "Could not unpack message hash from redis store!"); } } static int store_redis_load(void(*receive_msg)(Msg*)) { int rc; /* check if we are active */ if (pool == NULL) return 0; /* sanity check */ if (receive_msg == NULL) return -1; /* * We will use a Dict as an intermediate data structure to re-construct the * Msg struct itself. This is faster, then using pre-processor magic and * then strcmp() on the msg field names. */ rc = hash ? store_redis_getall_hash(0, dispatch_hash, receive_msg) : store_redis_getall(0, dispatch, receive_msg); info(0, "Loaded %ld messages from store.", counter_value(counter)); /* allow using of storage */ gwlist_remove_producer(loaded); return rc; } static int store_redis_save(Msg *msg) { char id[UUID_STR_LEN + 1]; Octstr *id_s; /* always set msg id and timestamp */ if (msg_type(msg) == sms && uuid_is_null(msg->sms.id)) uuid_generate(msg->sms.id); if (msg_type(msg) == sms && msg->sms.time == MSG_PARAM_UNDEFINED) time(&msg->sms.time); if (pool == NULL) return 0; /* block here if store still not loaded */ gwlist_consume(loaded); switch (msg_type(msg)) { case sms: { uuid_unparse(msg->sms.id, id); id_s = octstr_create(id); /* XXX we could use function pointers to avoid iteration checks */ if (hash) { store_redis_add_msg(id_s, msg); } else { Octstr *os = store_msg_pack(msg); if (os == NULL) { error(0, "Could not pack message."); return -1; } store_redis_add(id_s, os); octstr_destroy(os); } octstr_destroy(id_s); counter_increase(counter); break; } case ack: { uuid_unparse(msg->ack.id, id); id_s = octstr_create(id); if (hash) store_redis_delete_hash(id_s); else store_redis_delete(id_s); octstr_destroy(id_s); counter_decrease(counter); break; } default: return -1; } return 0; } static int store_redis_save_ack(Msg *msg, ack_status_t status) { int ret; Msg *nack = msg_create(ack); nack->ack.nack = status; uuid_copy(nack->ack.id, msg->sms.id); nack->ack.time = msg->sms.time; ret = store_redis_save(nack); msg_destroy(nack); return ret; } static void store_redis_shutdown() { dbpool_destroy(pool); store_db_fields_destroy(fields); counter_destroy(counter); gwlist_destroy(loaded, NULL); } int store_redis_init(Cfg *cfg) { CfgGroup *grp; List *grplist; Octstr *redis_host, *redis_pass, *redis_id; long redis_port = 0, redis_database = -1, redis_idle_timeout = -1; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; /* * Check for all mandatory directives that specify the field names * of the used Redis key */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("store-db")))) panic(0, "Store-Redis: group 'store-db' is not specified!"); if (!(redis_id = cfg_get(grp, octstr_imm("id")))) panic(0, "Store-Redis: directive 'id' is not specified!"); cfg_get_bool(&hash, grp, octstr_imm("hash")); fields = store_db_fields_create(grp); gw_assert(fields != NULL); /* select corresponding functions */ store_messages = store_redis_messages; store_save = store_redis_save; store_save_ack = store_redis_save_ack; store_load = store_redis_load; store_dump = store_redis_dump; store_shutdown = store_redis_shutdown; store_for_each_message = store_redis_for_each_message; /* * Now grab the required information from the 'redis-connection' group * with the id we just obtained. * * We have to loop through all available Redis connection definitions * and search for the one we are looking for. */ grplist = cfg_get_multi_group(cfg, octstr_imm("redis-connection")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, redis_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "Connection settings for 'redis-connection' with id '%s' are not specified!", octstr_get_cstr(redis_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(redis_host = cfg_get(grp, octstr_imm("host")))) { grp_dump(grp); panic(0, "Directive 'host' is not specified in 'group = redis-connection' context!"); } if (cfg_get_integer(&redis_port, grp, octstr_imm("port")) == -1) { grp_dump(grp); panic(0, "Directive 'port' is not specified in 'group = redis-connection' context!"); } redis_pass = cfg_get(grp, octstr_imm("password")); cfg_get_integer(&redis_database, grp, octstr_imm("database")); cfg_get_integer(&redis_idle_timeout, grp, octstr_imm("idle-timeout")); /* * Ok, ready to connect to Redis */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->redis = gw_malloc(sizeof(RedisConf)); gw_assert(db_conf->redis != NULL); db_conf->redis->host = redis_host; db_conf->redis->port = redis_port; db_conf->redis->password = redis_pass; db_conf->redis->database = redis_database; db_conf->redis->idle_timeout = redis_idle_timeout; pool = dbpool_create(DBPOOL_REDIS, db_conf, pool_size); gw_assert(pool != NULL); /* * Panic on failure to connect. Should we just try to reconnect? */ if (dbpool_conn_count(pool) == 0) panic(0, "Redis database pool has no connections!"); loaded = gwlist_create(); gwlist_add_producer(loaded); counter = counter_create(); octstr_destroy(redis_id); return 0; } #endif gateway-1.4.5/gw/wap_push_ppg_pushuser.h0000644000175000017500000001432713227613126017116 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_ppg_pushuser.h: Header of the push user module. This means * currently authentication and smsc routing. * * Only WAP-165-PushArchOverview-19991108-a, an informal document, mentions * pi authentication. (See chapter 13.) So this is definitely left for * implementors. * Basic authentication is defined in rfc 2617. Note that https connections * are handled by our http module. * * By Aarno Syvänen for Wiral Ltd and Global Networks Inc */ #ifndef WAP_PUSH_PPG_PUSHUSER_H #define WAP_PUSH_PPG_PUSHUSER_H #include "gwlib/gwlib.h" /* * This function initializes the module and push users data stucture, contain- * ing user specific data for all push user accounts. This function MUST be * called before any other functions of this module. */ int wap_push_ppg_pushuser_list_add(List *l, long number_of_pushes, long number_of_users); /* * This function does clean up for module shutdown. This module MUST be called * when the caller of this module is shut down. */ void wap_push_ppg_pushuser_list_destroy(void); /* * This function does authentication possible before compiling the control * document. This means: * a) password authentication by url or by headers (it is, by basic * authentication response, see rfc 2617, chapter 2) * b) if this does not work, basic authentication by challenge - * response * c) enforcing various ip lists * * Check does ppg allows a connection from this at all, then try to find username * and password from headers, then from url. If both fails, try basic authentica- * tion. Then check does this user allow a push from this ip, then check the pass- * word. * * For protection against brute force and partial protection for denial of serv- * ice attacks, an exponential backup algorithm is used. Time when a specific ip * is allowed to reconnect, is stored in Dict next_try. If an ip tries to recon- * nect before this (three attemps are allowed, then exponential seconds are add- * ed to the limit) we make a new challenge. We do the corresponding check before * testing passwords; after all, it is an authorization failure that causes a new * challenge. * * Rfc 2617, chapter 1 states that if we do not accept credentials of an user's, * we must send a new challenge to the user. * * Output an authenticated username. * This function should be called only when there are a push users list; the * caller is responsible for this. */ int wap_push_ppg_pushuser_authenticate(HTTPClient *client, List *cgivars, Octstr *ip, List *headers, Octstr **username); /* * This function checks phone number for allowed prefixes, black lists and * white lists. Note that the phone number necessarily follows the interna- * tional format (this is checked by our pap compiler). */ int wap_push_ppg_pushuser_client_phone_number_acceptable(Octstr *username, Octstr *number); int wap_push_ppg_pushuser_search_ip_from_wildcarded_list(Octstr *haystack, Octstr *needle, Octstr *gwlist_sep, Octstr *ip_sep); /* * Returns smsc pushes by this user must use, or NULL when error. */ Octstr *wap_push_ppg_pushuser_smsc_id_get(Octstr *username); /* * Returns default dlr url for this user, or NULL when error. */ Octstr *wap_push_ppg_pushuser_dlr_url_get(Octstr *username); /* * Returns default dlr smsbox id for this user, or NULL when error. */ Octstr *wap_push_ppg_pushuser_smsbox_id_get(Octstr *username); #endif gateway-1.4.5/gw/wap_push_pap_compiler.c0000644000175000017500000020245213227613126017035 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_pap_compiler.c - implementation of wap_push_pap_compiler.h inter- * face (compiling pap documents to Kannel WAPEvents) * * This module implements PAP document DTD and status codes, defined in * WAP-164-PAP-19991108-a (called hereafter pap), chapter 9 and * PPG client addressing (it is. parsing client address of a pap document), * defined in * WAP-151-PPGService-19990816-a (ppg), chapter 7. * * In addition, Wapforum specification WAP-200-WDP-20001212-a (wdp) is re- * ferred. * * Compiler can be used by PI or PPG (it will handle all possible PAP DTD * elements). It checks that attribute values are legal and that an element * has only legal attributes, but does not otherwise validate PAP documents * against PAP DTD. (XML validation is quite another matter, of course.) * Client address is parsed out from the relevant PAP message attribute * containing lots of additional data, see ppg, 7.1. We do not yet support * user defined addresses. * * After compiling, some semantic analysing of the resulted event, and sett- * ing some defaults (however, relying on them is quite a bad policy). In * addition changing undefined values (any) to defined ones. * * By Aarno Syvänen for Wapit Ltd and for Wiral Ltd. */ #include #include #include #include #include #include #include #include #include "shared.h" #include "wap_push_pap_compiler.h" #include "wap_push_ppg.h" /**************************************************************************** * * Global data structures * * Table for pap elements. These are defined in PAP, Chapter 9. */ static char *pap_elements[] = { "pap", "push-message", "address", "quality-of-service", "push-response", "progress-note", "response-result", "cancel-message", "cancel-result", "cancel-response", "resultnotification-message", "resultnotification-response", "statusquery-message", "statusquery-response", "statusquery-result", "ccq-message", "ccq-response", "badmessage-response" }; #define NUM_ELEMENTS sizeof(pap_elements)/sizeof(pap_elements[0]) /* * Table for PAP attributes. These are defined in pap, Chapter 9. */ struct pap_attributes_t { char *name; char *value; }; typedef struct pap_attributes_t pap_attributes_t; static pap_attributes_t pap_attributes[] = { { "product-name", NULL }, { "push-id", NULL }, { "deliver-before-timestamp", NULL }, { "deliver-after-timestamp", NULL }, { "source-reference", NULL }, { "progress-notes-requested", "true" }, { "progress-notes-requested", "false" }, { "ppg-notify-requested-to", NULL }, { "address-value", NULL }, { "priority", "high" }, { "priority", "medium" }, { "priority", "low" }, { "delivery-method", "confirmed" }, { "delivery-method", "preferconfirmed" }, { "delivery-method", "unconfirmed" }, { "delivery-method", "notspecified" }, { "network", NULL }, { "network-required", "true" }, { "network-required", "false" }, { "bearer", NULL }, { "bearer-required", "true" }, { "bearer-required", "false" }, { "sender-address", NULL }, { "sender-name", NULL }, { "reply-time", NULL }, { "stage", NULL }, { "note", NULL }, { "time", NULL }, { "code", NULL }, { "desc", NULL }, { "received-time", NULL }, { "event-time", NULL }, { "message-state", NULL }, { "query-id", NULL }, { "app-id", NULL }, { "bad-message-fragment", NULL} }; #define NUM_ATTRIBUTES sizeof(pap_attributes)/sizeof(pap_attributes[0]) /* * Status codes are defined in pap, chapter 9.13. */ static int pap_codes[] = { PAP_ACCEPTED_FOR_PROCESSING, PAP_BAD_REQUEST, PAP_FORBIDDEN, PAP_ADDRESS_ERROR, PAP_CAPABILITIES_MISMATCH, PAP_DUPLICATE_PUSH_ID, PAP_TRANSFORMATION_FAILURE, PAP_REQUIRED_BEARER_NOT_AVAILABLE, PAP_ABORT_USERPND }; #define NUM_CODES sizeof(pap_codes)/sizeof(pap_codes[0]) /* * Possible bearer types. These are defined in wdp, appendix C. */ static char *pap_bearer_types[] = { "Any", "USSD", "SMS", "GUTS/R-Data", "CSD", "Packet Data", "GPRS", "CDPD", "FLEX", "SDS", "ReFLEX", "MPAK", "GHOST/R_DATA" }; #define NUM_BEARER_TYPES sizeof(pap_bearer_types)/sizeof(pap_bearer_types[0]) /* * Possible network types. These are defined in wdp, appendix C. */ static char *pap_network_types[] = { "Any", "GSM", "ANSI-136", "IS-95 CDMA", "AMPS", "PDC", "IDEN", "Paging network", "PHS", "TETRA", "Mobitex", }; #define NUM_NETWORK_TYPES sizeof(pap_network_types)/ \ sizeof(pap_network_types[0]) /**************************************************************************** * * Prototypes of internal functions. Note that suffix 'Ptr' means '*'. */ static int parse_document(xmlDocPtr doc_p, WAPEvent **e); static int parse_node(xmlNodePtr node, WAPEvent **e, long *type_of_address, int *is_any); static int parse_element(xmlNodePtr node, WAPEvent **e, long *type_of_address, int *is_any); static int parse_attribute(Octstr *element_name, xmlAttrPtr attribute, WAPEvent **e, long *type_of_address, int *is_any); static int parse_attr_value(Octstr *element_name, Octstr *attr_name, Octstr *attr_value, WAPEvent **e, long *type_of_address, int *is_any); static int set_attribute_value(Octstr *element_name, Octstr *attr_value, Octstr *attr_name, WAPEvent **e); static int return_flag(Octstr *ros); static void wap_event_accept_or_create(Octstr *element_name, WAPEvent **e); static int parse_pap_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e); static int parse_push_message_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e); static int parse_address_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e, long *type_of_address); static int parse_quality_of_service_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e, int *is_any); static int parse_push_response_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e); static int parse_progress_note_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e); static int parse_bad_message_response_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e); static int parse_response_result_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e); static int parse_code(Octstr *attr_value); static Octstr *parse_bearer(Octstr *attr_value); static Octstr *parse_network(Octstr *attr_value); static int parse_requirement(Octstr *attr_value); static int parse_priority(Octstr *attr_value); static int parse_delivery_method(Octstr *attr_value); static int parse_state(Octstr *attr_value); static long parse_wappush_client_address(Octstr **address, long pos, long *type_of_address); static long parse_ppg_specifier(Octstr **address, long pos); static long parse_client_specifier(Octstr **address, long pos, long *type_of_address); static long parse_constant(const char *field_name, Octstr **address, long pos); static long parse_dom_fragment(Octstr **address, long pos); static long drop_character(Octstr **address, long pos); static long parse_type(Octstr **address, Octstr **type_value, long pos); static long parse_ext_qualifiers(Octstr **address, long pos, Octstr *type_value); static long parse_global_phone_number(Octstr **address, long pos); static long parse_ipv4(Octstr **address, long pos); static long parse_ipv6(Octstr **address, long pos); static long parse_escaped_value(Octstr **address, long pos); static Octstr *prepend_char(Octstr *address, unsigned char c); static int qualifiers(Octstr *address, long pos, Octstr *type); static long parse_qualifier_value(Octstr **address, long pos); static long parse_qualifier_keyword(Octstr **address, long pos); static long parse_ipv4_fragment(Octstr **address, long pos); static long parse_ipv6_fragment(Octstr **address, long pos); static int wina_bearer_identifier(Octstr *type_value); static int create_peek_window(Octstr **address, long *pos); static long rest_unescaped(Octstr **address, long pos); static int issafe(Octstr **address, long pos); static long accept_safe(Octstr **address, long pos); static long accept_escaped(Octstr **address, long pos); static long handle_two_terminators (Octstr **address, long pos, unsigned char comma, unsigned char point, unsigned char c, long fragment_parsed, long fragment_length); static int uses_gsm_msisdn_address(long bearer_required, Octstr *bearer); static int uses_ipv4_address(long bearer_required, Octstr *bearer); static int uses_ipv6_address(long bearer_required, Octstr *bearer); static int event_semantically_valid(WAPEvent *e, long type_of_address); static char *address_type(long type_of_address); static void set_defaults(WAPEvent **e, long type_of_address); static void set_bearer_defaults(WAPEvent **e, long type_of_address); static void set_network_defaults(WAPEvent **e, long type_of_address); static int set_anys(WAPEvent **e, long type_of_address, int is_any); static void set_any_value(int *is_any, Octstr *attr_name, Octstr *attr_value); /* * Macro for creating an octet string from a node content. This has two * versions for different libxml node content implementation methods. */ #ifdef XML_USE_BUFFER_CONTENT #define create_octstr_from_node(node) (octstr_create(node->content->content)) #else #define create_octstr_from_node(node) (octstr_create(node->content)) #endif /**************************************************************************** * * Compile PAP control document to a corresponding Kannel event. Checks vali- * dity of the document. The caller must initialize wap event to NULL. In add- * ition, it must free memory allocated by this function. * * After compiling, some semantic analysing of the resulted event. * * Note that entities in the DTD are parameter entities and they can appear * only in DTD (See site http://www.w3.org/TR/REC-xml, Chapter 4.1). So we do * not need to worry about them in the document itself. * * Returns 0, when success * -1, when a non-implemented pap feature is asked for * -2, when error * In addition, returns a newly created wap event corresponding the pap * control message, if success, wap event NULL otherwise. */ int pap_compile(Octstr *pap_content, WAPEvent **e) { xmlDocPtr doc_p; size_t oslen; int ret; if (octstr_search_char(pap_content, '\0', 0) != -1) { warning(0, "PAP COMPILER: pap_compile: pap source contained a \\0" " character"); return -2; } octstr_strip_blanks(pap_content); oslen = octstr_len(pap_content); doc_p = xmlParseMemory(octstr_get_cstr(pap_content), oslen); if (doc_p == NULL) { goto error; } if ((ret = parse_document(doc_p, e)) < 0) { goto parserror; } xmlFreeDoc(doc_p); return 0; parserror: xmlFreeDoc(doc_p); wap_event_destroy(*e); *e = NULL; return ret; error: warning(0, "PAP COMPILER: pap_compile: parse error in pap source"); xmlFreeDoc(doc_p); wap_event_destroy(*e); *e = NULL; return -2; } /**************************************************************************** * * Implementation of internal functions * */ enum { NEITHER = 0, BEARER_ANY = 1, NETWORK_ANY = 2, EITHER = 3, ERROR_ANY = 4 }; /* * Parse the document node of libxml syntax tree. FIXME: Add parsing of pap * version. * After parsing, some semantic analysing of the resulted event. Then set * a default network and bearer deduced from address type, if the correspond- * ing pap attribute is missing. * * Returns 0, when success * -1, when a non-implemented pap feature is requested * -2, when error * In addition, return a newly created wap event corresponding the pap * control message, if success, or partially parsed pap document, if not. Set * a field containing address type. */ static int parse_document(xmlDocPtr doc_p, WAPEvent **e) { xmlNodePtr node; int ret, is_any; /* is bearer and/or network set any in qos attribute */ long type_of_address; gw_assert(doc_p); node = xmlDocGetRootElement(doc_p); is_any = NEITHER; if ((ret = parse_node(node, e, &type_of_address, &is_any)) < 0) return ret; (*e)->u.Push_Message.address_type = type_of_address; if ((ret= event_semantically_valid(*e, type_of_address)) == 0) { warning(0, "wrong type of address for requested bearer"); return -2; } else if (ret == -1) { info(0, "reverting to default bearer and network"); set_defaults(e, type_of_address); return 0; } if (!set_anys(e, type_of_address, is_any)) { warning(0, "unable to handle any values in qos"); return -2; } else { debug("wap.push.pap.compiler", 0, "using defaults instead of anys"); } wap_event_assert(*e); return 0; } static int set_anys(WAPEvent **e, long type_of_address, int is_any) { switch (is_any) { case NEITHER: return 1; case BEARER_ANY: set_bearer_defaults(e, type_of_address); return 1; case NETWORK_ANY: set_network_defaults(e, type_of_address); return 1; case EITHER: set_defaults(e, type_of_address); return 1; default: return 0; } } /* * We actually use address_type field of a wap event for controlling the bearer * selection. Bearer and network filed are used for debugging purposes. */ static void set_defaults(WAPEvent **e, long type_of_address) { set_bearer_defaults(e, type_of_address); set_network_defaults(e, type_of_address); } static void set_bearer_defaults(WAPEvent **e, long type_of_address) { gw_assert(type_of_address == ADDR_USER || type_of_address == ADDR_PLMN || type_of_address == ADDR_IPV4 || type_of_address == ADDR_IPV6 || type_of_address == ADDR_WINA); if ((*e)->type != Push_Message) return; (*e)->u.Push_Message.bearer_required = PAP_TRUE; octstr_destroy((*e)->u.Push_Message.bearer); switch (type_of_address) { case ADDR_PLMN: (*e)->u.Push_Message.bearer = octstr_format("%s", "SMS"); break; case ADDR_IPV4: (*e)->u.Push_Message.bearer = octstr_format("%s", "CSD"); break; case ADDR_IPV6: break; } } static void set_network_defaults(WAPEvent **e, long type_of_address) { gw_assert(type_of_address == ADDR_USER || type_of_address == ADDR_PLMN || type_of_address == ADDR_IPV4 || type_of_address == ADDR_IPV6 || type_of_address == ADDR_WINA); if ((*e)->type != Push_Message) return; (*e)->u.Push_Message.network_required = PAP_TRUE; octstr_destroy((*e)->u.Push_Message.network); switch (type_of_address) { case ADDR_PLMN: (*e)->u.Push_Message.network = octstr_format("%s", "GSM"); break; case ADDR_IPV4: (*e)->u.Push_Message.network = octstr_format("%s", "GSM"); break; case ADDR_IPV6: break; } } static char *address_type(long type_of_address) { switch(type_of_address) { case ADDR_USER: return "user defined address"; case ADDR_PLMN: return "a phone number"; case ADDR_IPV4: return "a IPv4 address"; case ADDR_IPV6: return "a IPv6 address"; case ADDR_WINA: return "a WINA accepted address"; default: return "unknown address"; } } /* * Do semantic analysis, when the event was Push_Message. Do not accept an IP * address, when a non-IP bearer is requested, and a phone number, when an IP * bearer is requested. * Return 0, when event is unacceptable * 1, when it is acceptable * -1, when there are no bearer or network specified */ static int event_semantically_valid(WAPEvent *e, long type_of_address) { int ret; debug("wap.push.pap.compiler", 0, "PAP COMPILER: doing semantic analysis" " for address type %s", address_type(type_of_address)); if (e->type != Push_Message) { return 1; } if (e->u.Push_Message.network_required != e->u.Push_Message.bearer_required) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: network-required and" " bearer-required must have same value"); return 0; } if (type_of_address == ADDR_PLMN) { if ((ret = uses_gsm_msisdn_address( e->u.Push_Message.bearer_required, e->u.Push_Message.bearer)) == 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: bearer does" " not accept PLMN address"); return 0; } else if (ret == -1) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: network or" "bearer missing, reverting to GSM+SMS"); return -1; } else return 1; } if (type_of_address == ADDR_IPV4) { if ((ret = uses_ipv4_address(e->u.Push_Message.bearer_required, e->u.Push_Message.bearer)) == 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: bearer does" " not accept IPv4 address"); return 0; } else if (ret == -1) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: network or" " bearer missing, reverting to GSM+CSD"); return -1; } else return 1; } if (type_of_address == ADDR_IPV6) { if ((ret = uses_ipv6_address(e->u.Push_Message.bearer_required, e->u.Push_Message.bearer)) == 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: network or" " bearer does not accept IPv6 address"); return 0; } else if (ret == -1) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: network or" " bearer missing, reverting Any+Any"); return -1; } else return 1; } return 0; } /* * Bearers accepting IP addresses. These are defined in wdp, appendix c. Note * that when ipv6 bearers begin to appear, they must be added to the following * table. Currently none are specified. */ static char *ip6_bearers[] = { "Any" }; #define NUMBER_OF_IP6_BEARERS sizeof(ip6_bearers)/sizeof(ip6_bearers[0]) static char *ip4_bearers[] = { "Any", "CSD", "Packet Data", "GPRS", "USSD" }; #define NUMBER_OF_IP4_BEARERS sizeof(ip4_bearers)/sizeof(ip4_bearers[0]) /* * Bearers accepting gsm msisdn addresses are defined in wdp, appendix c. We * add any, because Kannel PPG will change this to SMS. * Return -1, when there are no bearer defined * 0, when a bearer not accepting msisdn address is found * 1, when a bearer is accepting msisdn addresesses */ static int uses_gsm_msisdn_address(long bearer_required, Octstr *bearer) { if (!bearer_required) return -1; if (!bearer) return 1; return (octstr_case_compare(bearer, octstr_imm("SMS")) == 0 || octstr_case_compare(bearer, octstr_imm("GHOST/R_DATA")) == 0 || octstr_case_compare(bearer, octstr_imm("Any")) == 0); } /* * Bearers accepting ipv4 addresses are defined in wdp, appendix c. * Return -1, when there are no bearer defined * 0, when a bearer not accepting ipv4 address is found * 1, when a bearer is accepting ipv4 addresesses */ static int uses_ipv4_address(long bearer_required, Octstr *bearer) { long i; if (!bearer_required) { return -1; } if (!bearer) return -1; i = 0; while (i < NUMBER_OF_IP4_BEARERS) { if (octstr_case_compare(bearer, octstr_imm(ip4_bearers[i])) == 0) { return 1; } ++i; } return 0; } /* * Bearers accepting ipv6 addresses (currently *not* accepting) are defined in * wdp, appendix c. * Return -1, when there are no bearer defined * 0, when a bearer not accepting ipv6 address is found * 1, when a bearer is accepting ipv6 addresesses */ static int uses_ipv6_address(long bearer_required, Octstr *bearer) { long i; if (!bearer_required) return -1; if (!bearer) return -1; i = 0; while (i < NUMBER_OF_IP6_BEARERS) { if (octstr_case_compare(bearer, octstr_imm(ip6_bearers[i])) == 0) { return 1; } ++i; } return 0; } /* * Parse node of the syntax tree. DTD, as defined in pap, chapter 9, contains * only elements (entities are restricted to DTDs). * The caller must initialize the value of is_any to 0. * * Output: a) a newly created wap event containing attributes from pap * document node, if success; partially parsed node, if not. * b) the type of of the client address * c) is bearer and/or network any * Returns 0, when success * -1, when a non-implemented feature is requested * -2, when error */ static int parse_node(xmlNodePtr node, WAPEvent **e, long *type_of_address, int *is_any) { int ret; switch (node->type) { case XML_COMMENT_NODE: /* ignore text, comments and pi nodes */ case XML_PI_NODE: case XML_TEXT_NODE: break; case XML_ELEMENT_NODE: if ((ret = parse_element(node, e, type_of_address, is_any)) < 0) { return ret; } break; default: warning(0, "PAP COMPILER: parse_node: Unknown XML node in PAP source"); return -2; } if (node->children != NULL) if ((ret = parse_node(node->children, e, type_of_address, is_any)) < 0) { return ret; } if (node->next != NULL) if ((ret = parse_node(node->next, e, type_of_address, is_any)) < 0) { return ret; } return 0; } /* * Parse elements of a PAP source. * * Output: a) a newly created wap event containing attributes from the * element, if success; containing some unparsed attributes, if not. * b) the type of the client address * c) is bearer and/or network any * Returns 0, when success * -1, when a non-implemented feature is requested * -2, when error * In addition, return */ static int parse_element(xmlNodePtr node, WAPEvent **e, long *type_of_address, int *is_any) { Octstr *name; xmlAttrPtr attribute; size_t i; int ret; name = octstr_create((char *)node->name); if (octstr_len(name) == 0) { octstr_destroy(name); debug("wap.push.pap.compiler", 0, "PAP COMPILER: element name length" " zero"); return -2; } i = 0; while (i < NUM_ELEMENTS) { if (octstr_compare(name, octstr_imm(pap_elements[i])) == 0) break; ++i; } if (i == NUM_ELEMENTS) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown element:"); octstr_dump(name, 0); octstr_destroy(name); return -2; } if (node->properties != NULL) { attribute = node->properties; while (attribute != NULL) { if ((ret = parse_attribute(name, attribute, e, type_of_address, is_any)) < 0) { octstr_destroy(name); return ret; } attribute = attribute->next; } } octstr_destroy(name); return 0; /* If we reach this point, our node does not have any attributes left (or it had no attributes to start with). This is *not* an error. */ } /* * Parse attribute updates corresponding fields of the wap event. Check that * both attribute name and value are papwise legal. If value is enumerated, * legal values are stored in the attributes table. Otherwise, call a separate * parsing function. If an attribute value is empty, use value "erroneous". * * Output: a) a newly created wap event containing parsed attribute from pap * source, if successfull, an uncomplete wap event otherwise. * b) the type of the client address * c) is bearer and/or network set any * Returns 0, when success * -1, when a non-implemented feature is requested * -2, when error */ static int parse_attribute(Octstr *element_name, xmlAttrPtr attribute, WAPEvent **e, long *type_of_address, int *is_any) { Octstr *attr_name, *value, *nameos; size_t i; int ret; nameos = octstr_imm("erroneous"); attr_name = octstr_create((char *)attribute->name); if (attribute->children != NULL) value = create_octstr_from_node((char *)attribute->children); else value = octstr_imm("erroneous"); i = 0; while (i < NUM_ATTRIBUTES) { if (octstr_compare(attr_name, nameos = octstr_imm(pap_attributes[i].name)) == 0) break; ++i; } if (i == NUM_ATTRIBUTES) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown attribute `%s' " "within XML entity `%s'", octstr_get_cstr(attr_name), octstr_get_cstr(element_name)); goto error; } /* * Parse an attribute (it is, check cdata is has for a value) that is *not* an * enumeration. Legal values are defined in pap, chapter 9. */ if (pap_attributes[i].value == NULL) { ret = parse_attr_value(element_name, attr_name, value, e, type_of_address, is_any); if (ret == -2) { goto error; } else { goto parsed; } } while (octstr_compare(attr_name, nameos = octstr_imm(pap_attributes[i].name)) == 0) { if (octstr_compare(value, octstr_imm(pap_attributes[i].value)) == 0) break; ++i; } if (octstr_compare(attr_name, nameos) != 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown attribute " "value `%s' for attribute `%s' within XML entity `%s'", octstr_get_cstr(value), octstr_get_cstr(attr_name), octstr_get_cstr(element_name)); goto error; } /* * Check that the value of the attribute is one enumerated for this attribute * in pap, chapter 9. */ if (set_attribute_value(element_name, value, attr_name, e) == -1) goto error; octstr_destroy(attr_name); octstr_destroy(value); return 0; error: octstr_destroy(attr_name); octstr_destroy(value); return -2; parsed: octstr_destroy(attr_name); octstr_destroy(value); return ret; } /* * Attribute value parsing functions for the PAP element. * Defined in PAP, chapter 8.1. */ static int parse_pap_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e) { if (*e != NULL) wap_event_dump(*e); if (octstr_compare(attr_name, octstr_imm("product-name")) == 0) { /* * XXX This is a kludge. * We can't add the product-name value to the WAPEvent, because * the wap_event_create() is created in the deeper layer, which * means as soon as we see or . * But we would have to decide which WAPEvent to create while * being on the higher level. * How's this to be solved?! -- Stipe */ return 0; } debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown pap" " element attribute `%s'", octstr_get_cstr(attr_name)); return -2; } /* * Value parsing functions return the newly created wap event containing * attribute value from pap source, if successfull; NULL otherwise . Value * types of attributes are defined in pap, chapter 9. */ static int parse_push_message_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e) { Octstr *ros; ros = octstr_imm("erroneous"); if (octstr_compare(attr_name, octstr_imm("push-id")) == 0) { octstr_destroy((**e).u.Push_Message.pi_push_id); (**e).u.Push_Message.pi_push_id = octstr_duplicate(attr_value); return 0; } else if (octstr_compare(attr_name, octstr_imm("deliver-before-timestamp")) == 0) { (**e).u.Push_Message.deliver_before_timestamp = (ros = parse_date(attr_value)) ? octstr_duplicate(attr_value) : octstr_imm("erroneous"); return return_flag(ros); } else if (octstr_compare(attr_name, octstr_imm("deliver-after-timestamp")) == 0) { (**e).u.Push_Message.deliver_after_timestamp = (ros = parse_date(attr_value)) ? octstr_duplicate(attr_value) : octstr_imm("erroneous"); return return_flag(ros); } else if (octstr_compare(attr_name, octstr_imm("source-reference")) == 0) { (**e).u.Push_Message.source_reference = octstr_duplicate(attr_value); return 0; } else if (octstr_compare(attr_name, octstr_imm("ppg-notify-requested-to")) == 0) { (**e).u.Push_Message.ppg_notify_requested_to = octstr_duplicate(attr_value); return 0; } debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown push message" " element attribute"); return -2; } /* * When there is no legal address to be stored in field (either parsing was * unsuccessful or an unimplemented address format was requested by the push * initiator) we use value "erroneous". This is necessary, because this a * mandatory field. * * Output a) a newly created wap event * b) the type of the client address */ static int parse_address_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e, long *type_of_address) { int ret; ret = -2; if (octstr_compare(attr_name, octstr_imm("address-value")) == 0) { octstr_destroy((**e).u.Push_Message.address_value); (**e).u.Push_Message.address_value = (ret = parse_address(&attr_value, type_of_address)) > -1 ? octstr_duplicate(attr_value) : octstr_imm("erroneous"); return ret; } debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown address element" " attribute"); return -2; } static int parse_quality_of_service_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e, int *is_any) { Octstr *ros; ros = octstr_imm("erroneous"); if (octstr_compare(attr_name, octstr_imm("network")) == 0) { (**e).u.Push_Message.network = (ros = parse_network(attr_value)) ? octstr_duplicate(attr_value) : octstr_imm("erroneous"); set_any_value(is_any, attr_name, attr_value); return return_flag(ros); } if (octstr_compare(attr_name, octstr_imm("bearer")) == 0) { (**e).u.Push_Message.bearer = (ros = parse_bearer(attr_value)) ? octstr_duplicate(attr_value) : octstr_imm("erroneous"); set_any_value(is_any, attr_name, attr_value); return return_flag(ros); } debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown quality of" " service attribute"); return -2; } static void set_any_value(int *is_any, Octstr *attr_name, Octstr *attr_value) { switch (*is_any) { case NEITHER: if (octstr_compare(attr_name, octstr_imm("bearer")) == 0 && octstr_case_compare(attr_value, octstr_imm("any")) == 0) *is_any = BEARER_ANY; else if (octstr_compare(attr_name, octstr_imm("network")) == 0 && octstr_case_compare(attr_value, octstr_imm("any")) == 0) *is_any = NETWORK_ANY; return; case BEARER_ANY: if (octstr_compare(attr_name, octstr_imm("network")) == 0 && octstr_case_compare(attr_value, octstr_imm("any")) == 0) *is_any = EITHER; return; case NETWORK_ANY: if (octstr_compare(attr_name, octstr_imm("bearer")) == 0 && octstr_case_compare(attr_value, octstr_imm("any")) == 0) *is_any = EITHER; return; case EITHER: debug("wap.push.pap.compiler", 0, "PAP COMPILER: problems with" " setting any"); *is_any = ERROR_ANY; return; default: debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong any value"); *is_any = ERROR_ANY; return; } } static int parse_push_response_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e) { Octstr *ros; ros = octstr_imm("erroneous"); if (octstr_compare(attr_name, octstr_imm("push-id")) == 0) { octstr_destroy((**e).u.Push_Response.pi_push_id); (**e).u.Push_Response.pi_push_id = octstr_duplicate(attr_value); return 0; } else if (octstr_compare(attr_name, octstr_imm("sender-address")) == 0) { (**e).u.Push_Response.sender_address = octstr_duplicate(attr_value); return 0; } else if (octstr_compare(attr_name, octstr_imm("reply-time")) == 0) { (**e).u.Push_Response.reply_time = (ros = parse_date(attr_value)) ? octstr_duplicate(attr_value) : NULL; return return_flag(ros); } else if (octstr_compare(attr_name, octstr_imm("sender-name")) == 0) { (**e).u.Push_Response.sender_name = octstr_duplicate(attr_value); return 0; } debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown push response" " element attribute"); return -2; } static int parse_progress_note_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e) { Octstr *ros; int ret; ret = -2; ros = octstr_imm("erroneous"); if (octstr_compare(attr_name, octstr_imm("stage")) == 0) { (**e).u.Progress_Note.stage = (ret = parse_state(attr_value)) ? ret : 0; return ret; } else if (octstr_compare(attr_name, octstr_imm("note")) == 0) { (**e).u.Progress_Note.note = octstr_duplicate(attr_value); return 0; } else if (octstr_compare(attr_name, octstr_imm("time")) == 0) { (**e).u.Progress_Note.time = (ros = parse_date(attr_value)) ? octstr_duplicate(attr_value) : octstr_imm("erroneous"); return return_flag(ros); } debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown progress note" " element attribute"); return -2; } static int parse_bad_message_response_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e) { if (octstr_compare(attr_name, octstr_imm("code")) == 0) { (**e).u.Bad_Message_Response.code = parse_code(attr_value); return 0; } else if (octstr_compare(attr_name, octstr_imm("desc")) == 0) { (**e).u.Bad_Message_Response.desc = octstr_duplicate(attr_value); return 0; } else if (octstr_compare(attr_name, octstr_imm("bad-message-fragment")) == 0) { (**e).u.Bad_Message_Response.bad_message_fragment = octstr_duplicate(attr_value); return 0; } debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown bad message" " response element attribute"); return -2; } static int parse_response_result_value(Octstr *attr_name, Octstr *attr_value, WAPEvent **e) { if (octstr_compare(attr_name, octstr_imm("code")) == 0) { (**e).u.Push_Response.code = parse_code(attr_value); return 0; } else if (octstr_compare(attr_name, octstr_imm("desc")) == 0) { (**e).u.Push_Response.desc = octstr_duplicate(attr_value); return 0; } debug("wap.push.pap.compiler", 0, "PAP COMPILER: unknown response result" " attribute"); return -2; } /* * Do not create multiple events. If *e points to NULL, we have not yet creat- * ed a wap event. Create a wap event mandatory fields set to error values * (these will be latter overwritten). This hack will disappear when we have * PAP validation. */ static void wap_event_accept_or_create(Octstr *element_name, WAPEvent **e) { if (octstr_compare(element_name, octstr_imm("push-message")) == 0 && *e == NULL) { *e = wap_event_create(Push_Message); (**e).u.Push_Message.pi_push_id = octstr_format("%s", "erroneous"); (**e).u.Push_Message.address_value = octstr_format("%s", "erroneous"); } else if (octstr_compare(element_name, octstr_imm("push-response")) == 0 && *e == NULL) { *e = wap_event_create(Push_Response); (**e).u.Push_Response.pi_push_id = octstr_format("%s", "erroneous"); } else if (octstr_compare(element_name, octstr_imm("progress-note")) == 0 && *e == NULL) { *e = wap_event_create(Progress_Note); } else if (octstr_compare(element_name, octstr_imm("badmessage-response")) == 0 && *e == NULL) { *e = wap_event_create(Bad_Message_Response); } } static int return_flag(Octstr *ros) { if (ros) { return 0; } else { return -2; } } /* * Validates non-enumeration attributes and stores their value to a newly * created wap event e. (Even when attribute value parsing was not success- * full.) We do not accept NULL or empty attributes (if this kind of an * attribute is optional, we just drop it from the tokenised document). * * Output: a) a wap event, as created by subroutines * b) the type of the client address * c) is bearer or network set any * Returns 0, when success, * -1, when a non-implemented feature requested. * -2, when an error */ static int parse_attr_value(Octstr *element_name, Octstr *attr_name, Octstr *attr_value, WAPEvent **e, long *type_of_address, int *is_any) { if (octstr_compare(attr_value, octstr_imm("erroneous")) == 0) { debug("wap.push.pap.compiler", 0, "unknown value for an attribute"); return -2; } wap_event_accept_or_create(element_name, e); if (octstr_compare(element_name, octstr_imm("pap")) == 0) { return parse_pap_value(attr_name, attr_value, e); } else if (octstr_compare(element_name, octstr_imm("push-message")) == 0) { return parse_push_message_value(attr_name, attr_value, e); } else if (octstr_compare(element_name, octstr_imm("address")) == 0) { return parse_address_value(attr_name, attr_value, e, type_of_address); } else if (octstr_compare(element_name, octstr_imm("quality-of-service")) == 0) { return parse_quality_of_service_value(attr_name, attr_value, e, is_any); } else if (octstr_compare(element_name, octstr_imm("push-response")) == 0) { return parse_push_response_value(attr_name, attr_value, e); } else if (octstr_compare(element_name, octstr_imm("progress-note")) == 0) { return parse_progress_note_value(attr_name, attr_value, e); } else if (octstr_compare(element_name, octstr_imm("badmessage-response")) == 0) { return parse_bad_message_response_value(attr_name, attr_value, e); } else if (octstr_compare(element_name, octstr_imm("response-result")) == 0) { return parse_response_result_value(attr_name, attr_value, e); } return -2; } /* * Stores values of enumeration fields of a pap control message to wap event e. */ static int set_attribute_value(Octstr *element_name, Octstr *attr_value, Octstr *attr_name, WAPEvent **e) { int ret; ret = -2; if (octstr_compare(element_name, octstr_imm("push-message")) == 0) { if (*e == NULL) *e = wap_event_create(Push_Message); if (octstr_compare(attr_name, octstr_imm("progress-notes-requested")) == 0) (**e).u.Push_Message.progress_notes_requested = (ret = parse_requirement(attr_value)) >= 0 ? ret : 0; } else if (octstr_compare(element_name, octstr_imm("quality-of-service")) == 0) { if (*e == NULL) *e = wap_event_create(Push_Message); if (octstr_compare(attr_name, octstr_imm("priority")) == 0) (**e).u.Push_Message.priority = (ret = parse_priority(attr_value)) >= 0 ? ret : 0; else if (octstr_compare(attr_name, octstr_imm("delivery-method")) == 0) (**e).u.Push_Message.delivery_method = (ret = parse_delivery_method(attr_value)) >= 0 ? ret : 0; else if (octstr_compare(attr_name, octstr_imm("network-required")) == 0) (**e).u.Push_Message.network_required = (ret = parse_requirement(attr_value)) >= 0 ? ret : 0; else if (octstr_compare(attr_name, octstr_imm("bearer-required")) == 0) (**e).u.Push_Message.bearer_required = (ret = parse_requirement(attr_value)) >= 0 ? ret : 0; } return ret; } /* * We must recognize status class and treat unrecognized codes as a x000 code, * as required by pap, 9.13, p 27. */ static int parse_code(Octstr *attr_value) { long attr_as_number; size_t i; Octstr *ros; for (i = 0; i < NUM_CODES; i++) { ros = octstr_format("%d", pap_codes[i]); if (octstr_compare(attr_value, ros) == 0) { octstr_destroy(ros); return pap_codes[i]; } octstr_destroy(ros); } warning(0, "PAP COMPILER: parse_code: no such return code, reversing to" " x000 code"); octstr_parse_long(&attr_as_number, attr_value, 0, 10); if (attr_as_number >= PAP_OK && attr_as_number < PAP_BAD_REQUEST) { attr_as_number = PAP_OK; } else if (attr_as_number >= PAP_BAD_REQUEST && attr_as_number < PAP_INTERNAL_SERVER_ERROR) { attr_as_number = PAP_BAD_REQUEST; } else if (attr_as_number >= PAP_INTERNAL_SERVER_ERROR && attr_as_number < PAP_SERVICE_FAILURE) { attr_as_number = PAP_INTERNAL_SERVER_ERROR; } else if (attr_as_number >= PAP_SERVICE_FAILURE && attr_as_number < PAP_CLIENT_ABORTED) { attr_as_number = PAP_SERVICE_FAILURE; } else { attr_as_number = PAP_CLIENT_ABORTED; } return attr_as_number; } static Octstr *parse_bearer(Octstr *attr_value) { size_t i; Octstr *ros; for (i = 0; i < NUM_BEARER_TYPES; i++) { if (octstr_case_compare(attr_value, ros = octstr_imm(pap_bearer_types[i])) == 0) return ros; } warning(0, "no such bearer"); return NULL; } static Octstr *parse_network(Octstr *attr_value) { size_t i; Octstr *ros; for (i = 0; i < NUM_NETWORK_TYPES; i++) { if (octstr_case_compare(attr_value, ros = octstr_imm(pap_network_types[i])) == 0) { return ros; } } warning(0, "no such network"); return NULL; } /* * Used for attributes accepting logical values. */ static int parse_requirement(Octstr *attr_value) { long attr_as_number; attr_as_number = -2; if (octstr_case_compare(attr_value, octstr_imm("false")) == 0) attr_as_number = PAP_FALSE; else if (octstr_case_compare(attr_value, octstr_imm("true")) == 0) attr_as_number = PAP_TRUE; else warning(0, "in a requirement, value not a truth value"); return attr_as_number; } /* * Priority is defined in pap, chapter 9.2.2. */ static int parse_priority(Octstr *attr_value) { long attr_as_number; attr_as_number = -2; if (octstr_case_compare(attr_value, octstr_imm("high")) == 0) attr_as_number = PAP_HIGH; else if (octstr_case_compare(attr_value, octstr_imm("medium")) == 0) attr_as_number = PAP_MEDIUM; else if (octstr_case_compare(attr_value, octstr_imm("low")) == 0) attr_as_number = PAP_LOW; else warning(0, "illegal priority"); return attr_as_number; } /* * Delivery-method is defined in pap, chapter 9.2.2. */ static int parse_delivery_method(Octstr *attr_value) { long attr_as_number; attr_as_number = -2; if (octstr_case_compare(attr_value, octstr_imm("confirmed")) == 0) attr_as_number = PAP_CONFIRMED; else if (octstr_case_compare(attr_value, octstr_imm("preferconfirmed")) == 0) attr_as_number = PAP_PREFERCONFIRMED; else if (octstr_case_compare(attr_value, octstr_imm("unconfirmed")) == 0) attr_as_number = PAP_UNCONFIRMED; else if (octstr_case_compare(attr_value, octstr_imm("notspecified")) == 0) attr_as_number = PAP_NOT_SPECIFIED; else warning(0, "illegal delivery method"); return attr_as_number; } /* * PAP states are defined in ppg, chapter 6. */ static int parse_state(Octstr *attr_value) { long attr_as_number; attr_as_number = -2; if (octstr_case_compare(attr_value, octstr_imm("undeliverable")) == 0) attr_as_number = PAP_UNDELIVERABLE; else if (octstr_case_compare(attr_value, octstr_imm("pending")) == 0) attr_as_number = PAP_PENDING; else if (octstr_case_compare(attr_value, octstr_imm("expired")) == 0) attr_as_number = PAP_EXPIRED; else if (octstr_case_compare(attr_value, octstr_imm("delivered")) == 0) attr_as_number = PAP_DELIVERED; else if (octstr_case_compare(attr_value, octstr_imm("aborted")) == 0) attr_as_number = PAP_ABORTED; else if (octstr_case_compare(attr_value, octstr_imm("timeout")) == 0) attr_as_number = PAP_TIMEOUT; else if (octstr_case_compare(attr_value, octstr_imm("cancelled")) == 0) attr_as_number = PAP_CANCELLED; else warning(0, "illegal ppg state"); return attr_as_number; } /* * Check legality of pap client address attribute and transform it to the * client address usable in Kannel wap address tuple data type. The grammar * for client address is specified in ppg, chapter 7.1. * * Output: the address type of the client address * Returns: 0, when success * -1, a non-implemented pap feature requested by pi * -2, address parsing error */ int parse_address(Octstr **address, long *type_of_address) { long pos; Octstr *copy; pos = octstr_len(*address) - 1; /* * Delete first separator, if there is one. This will help our parsing later. */ if (octstr_get_char(*address, 0) == '/') octstr_delete(*address, 0, 1); /* * WAP-209, chapter 8 states that addresses with telephone numbers * should not have a ppg specifier. WAP-151 grammar, however, makes it * mandatory. Best way to solve this contradiction seems to be regarding * ppg specifier optional - MMSC is very important type of pi. */ if (octstr_search_char(*address, '@', 0) >= 0) { if ((pos = parse_ppg_specifier(address, pos)) < 0) return -2; } if ((pos = parse_wappush_client_address(address, pos, type_of_address)) == -2) { warning(0, "illegal client address"); return -2; } else if (pos == -1) { warning(0, "unimplemented feature"); return -1; } info(0, "client address was <%s>, accepted", octstr_get_cstr(copy = octstr_duplicate(*address))); octstr_destroy(copy); return pos; } /* * Output: the type of the client address */ static long parse_wappush_client_address(Octstr **address, long pos, long *type_of_address) { if ((pos = parse_client_specifier(address, pos, type_of_address)) < 0) { return pos; } pos = parse_constant("WAPPUSH", address, pos); return pos; } /* * We are not interested of ppg specifier, but we must check its format, * if we find it - it is optional. */ static long parse_ppg_specifier(Octstr **address, long pos) { if (pos >= 0) { pos = parse_dom_fragment(address, pos); } while (octstr_get_char(*address, pos) != '@' && pos >= 0) { if (octstr_get_char(*address, pos) == '.') { octstr_delete(*address, pos, 1); --pos; } else { return -2; } pos = parse_dom_fragment(address, pos); } pos = drop_character(address, pos); if (octstr_get_char(*address, pos) == '/' && pos >= 0) { octstr_delete(*address, pos, 1); if (pos > 0) --pos; } if (pos < 0) { return -2; } return pos; } /* * Output: the type of a client address. * Return a negative value, when error, positive (the position of the parsing * cursor) otherwise. */ static long parse_client_specifier(Octstr **address, long pos, long *type_of_address) { Octstr *type_value; type_value = octstr_create(""); if ((pos = parse_type(address, &type_value, pos)) < 0) { goto parse_error; } pos = drop_character(address, pos); if ((pos = parse_constant("/TYPE", address, pos)) < 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: constant TYPE" " missing from the client address"); goto parse_error; } if (octstr_case_compare(type_value, octstr_imm("USER")) == 0) { *type_of_address = ADDR_USER; goto not_implemented; } if ((pos = parse_ext_qualifiers(address, pos, type_value)) < 0) { goto parse_error; } if (octstr_case_compare(type_value, octstr_imm("PLMN")) == 0) { *type_of_address = ADDR_PLMN; pos = parse_global_phone_number(address, pos); } else if (octstr_case_compare(type_value, octstr_imm("IPv4")) == 0) { *type_of_address = ADDR_IPV4; pos = parse_ipv4(address, pos); } else if (octstr_case_compare(type_value, octstr_imm("IPv6")) == 0) { *type_of_address = ADDR_IPV6; pos = parse_ipv6(address, pos); } else if (wina_bearer_identifier(type_value)) { *type_of_address = ADDR_WINA; pos = parse_escaped_value(address, pos); } else { debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong address type" " in the client address"); goto parse_error; } octstr_destroy(type_value); return pos; not_implemented: octstr_destroy(type_value); return -1; parse_error: octstr_destroy(type_value); return -2; } /* * XXX We have a kludge here. WAP-249-PPGService-20010713-a defines in * section 6.1 the constant strings "WAPPUSH" and "TYPE" in upper-case. * But in the examples of section 6.2 they use lower-case too. Some PI * vendors (ie. Jatayuu's MMSC) have implemented lower-case in their PAP * documents. So we'll support this too for sake of operatibility -- st. */ static long parse_constant(const char *field_name, Octstr **address, long pos) { size_t i, size; Octstr *nameos; nameos = octstr_format("%s", field_name); size = octstr_len(nameos); i = 0; /* convert both to lower case, see above note */ octstr_convert_range(nameos, 0, octstr_len(nameos), tolower); octstr_convert_range(*address, 0, octstr_len(*address), tolower); while (octstr_get_char(*address, pos - i) == octstr_get_char(nameos, size-1 - i) && i < size) { ++i; } while ((octstr_len(*address) > 0) && octstr_get_char(*address, pos) != octstr_get_char(nameos, 0) && pos >= 0) { pos = drop_character(address, pos); } pos = drop_character(address, pos); if (pos < 0 || i != size) { debug("wap.push.pap.compiler", 0, "parse_constant: unparsable" " constant %s", field_name); octstr_destroy(nameos); return -2; } octstr_destroy(nameos); return pos; } static long parse_dom_fragment(Octstr **address, long pos) { unsigned char c; if (pos >= 0) { if (isalnum(octstr_get_char(*address, pos))) { pos = drop_character(address, pos); } else return -2; } while ((c = octstr_get_char(*address, pos)) != '@' && octstr_get_char(*address, pos) != '.' && pos >= 0) { if (isalnum(c) || c == '-') { pos = drop_character(address, pos); } else return -2; } return pos; } static long drop_character(Octstr **address, long pos) { if (pos >= 0) { octstr_delete(*address, pos, 1); if (pos > 0) --pos; } return pos; } static long parse_type(Octstr **address, Octstr **type_value, long pos) { unsigned char c; while ((c = octstr_get_char(*address, pos)) != '=' && pos >= 0) { *type_value = prepend_char(*type_value, c); pos = drop_character(address, pos); } if (pos < 0) return -2; return pos; } static long parse_ext_qualifiers(Octstr **address, long pos, Octstr *type) { int ret; while ((ret = qualifiers(*address, pos, type)) == 1) { if ((pos = parse_qualifier_value(address, pos)) < 0) return pos; if ((pos = parse_qualifier_keyword(address, pos)) < 0) return pos; } if (ret == 1) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: erroneous qualifiers" " in the client address"); return -2; } return pos; } /* * According to ppg, chapter 7.1, global phone number starts with +. Phone * number is here an unique identifier, so if it does not conform the inter- * national format, we return an error. (Is up to bearerbox to transform it * to an usable phone number) */ static long parse_global_phone_number(Octstr **address, long pos) { unsigned char c; while ((c = octstr_get_char(*address, pos)) != '+' && pos >= 0) { if (!isdigit(c) && c != '-' && c != '.') { debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong separator" " in a phone number (- and . allowed)"); return -2; } else { --pos; } } if (pos == 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER:a phone number must" " start with +"); return -2; } if (pos > 0) --pos; pos = drop_character(address, pos); return pos; } static long parse_ipv4(Octstr **address, long pos) { long i; if ((pos = parse_ipv4_fragment(address, pos)) < 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong separator in a" " ipv4 address"); return -2; } i = 1; while (i <= 3 && octstr_get_char(*address, pos) != '=' && pos >= 0) { pos = parse_ipv4_fragment(address, pos); ++i; } if (pos == 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: missing separator at" " beginning of a client address (=)"); return -2; } return pos; } static long parse_ipv6(Octstr **address, long pos) { long i; if ((pos = parse_ipv6_fragment(address, pos)) < 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: wrong separator in a" " ipv6 address"); return -2; } i = 1; while (i <= 7 && octstr_get_char(*address, pos) != '=' && pos >= 0) { pos = parse_ipv6_fragment(address, pos); ++i; } if (pos == 0) { debug("wap.push.pap.compiler", 0, "PAP COMPILER: missing separator at" " beginning of a client address (=)"); return -2; } return pos; } /* * WINA web page does not include address type identifiers. Following ones are * from wdp, Appendix C. */ static char *bearer_address[] = { "GSM_MSISDN", "ANSI_136_MSISDN", "IS_637_MSISDN", "iDEN_MSISDN", "FLEX_MSISDN", "PHS_MSISDN", "GSM_Service_Code", "TETRA_ITSI", "TETRA_MSISDN", "ReFLEX_MSIDDN", "MAN", }; static size_t bearer_address_size = sizeof(bearer_address) / sizeof(bearer_address[0]); static int wina_bearer_identifier(Octstr *type_value) { size_t i; i = 0; while (i < bearer_address_size) { if (octstr_case_compare(type_value, octstr_imm(bearer_address[i])) == 0) return 1; ++i; } debug("wap.push.pap.compiler", 0, "PAP COMPILER: a bearer not registered" " by wina"); return 0; } /* * Note that we parse backwards. First we create a window of three characters * (representing a possible escaped character). If the first character of the * window is not escape, we handle the last character and move the window one * character backwards; if it is, we handle escaped sequence and create a new * window. If we cannot create a window, rest of characters are unescaped. */ static long parse_escaped_value(Octstr **address, long pos) { int ret; if (create_peek_window(address, &pos) == 0) if ((pos = rest_unescaped(address, pos)) == -2) return -2; while (octstr_get_char(*address, pos) != '=' && pos >= 0) { if ((ret = issafe(address, pos)) == 1) { pos = accept_safe(address, pos); } else if (ret == 0) { if ((pos = accept_escaped(address, pos)) < 0) return -2; if (create_peek_window(address, &pos) == 0) if ((pos = rest_unescaped(address, pos)) == -2) return -2; } } pos = drop_character(address, pos); return pos; } static Octstr *prepend_char(Octstr *os, unsigned char c) { Octstr *tmp; tmp = octstr_format("%c", c); octstr_insert(os, tmp, 0); octstr_destroy(tmp); return os; } /* * Ext qualifiers contain /, ipv4 address contains . , ipv6 address contains :. * phone number contains + and escaped-value contain no specific tokens. Lastly * mentioned are for future extensions, but we must parse them. * Return 1, when qualifiers found * 0, when not * -1, when an error was found during the process */ static int qualifiers(Octstr *address, long pos, Octstr *type) { unsigned char term, c; long i; i = pos; c = 'E'; if (octstr_case_compare(type, octstr_imm("PLMN")) == 0) term = '+'; else if (octstr_case_compare(type, octstr_imm("IPv4")) == 0) term = '.'; else if (octstr_case_compare(type, octstr_imm("IPv6")) == 0) term = ':'; else term = 'N'; if (term != 'N') { while ((c = octstr_get_char(address, i)) != term && i != 0) { if (c == '/') return 1; --i; } if (i == 0) return 0; } if (term == 'N') { while (i != 0) { if (c == '/') return 1; --i; } } return 0; } static long parse_qualifier_value(Octstr **address, long pos) { unsigned char c; while ((c = octstr_get_char(*address, pos)) != '=' && pos >= 0) { if (c < 0x20 || (c > 0x2e && c < 0x30) || (c > 0x3c && c < 0x3e) || c > 0x7e) return -2; pos = drop_character(address, pos); } pos = drop_character(address, pos); return pos; } static long parse_qualifier_keyword(Octstr **address, long pos) { unsigned char c; while ((c = octstr_get_char(*address, pos)) != '/') { if (isalnum(c) || c == '-') { pos = drop_character(address, pos); } else return -2; } pos = drop_character(address, pos); return pos; } static long parse_ipv4_fragment(Octstr **address, long pos) { long i; unsigned char c; i = 0; c = '='; if (isdigit(c = octstr_get_char(*address, pos)) && pos >= 0) { --pos; ++i; } else { debug("wap.push.pap.compiler", 0, "non-digit found in ip address," " address unacceptable"); return -2; } while (i <= 3 && ((c = octstr_get_char(*address, pos)) != '.' && c != '=') && pos >= 0) { if (isdigit(c)) { --pos; ++i; } else { debug("wap.push.pap.compiler", 0, "parse_ipv4_fragment: non-digit" " in ipv4 address, address unacceptable"); return -2; } } pos = handle_two_terminators(address, pos, '.', '=', c, i, 3); return pos; } static long parse_ipv6_fragment(Octstr **address, long pos) { long i; unsigned char c; i = 0; if (isxdigit(octstr_get_char(*address, pos)) && pos >= 0) { --pos; ++i; } else { return -2; } c = '='; while (i <= 4 && ((c = octstr_get_char(*address, pos)) != ':' && c != '=') && pos >= 0) { if (isxdigit(c)) { --pos; ++i; } else { return -2; } } pos = handle_two_terminators(address, pos, ':', '=', c, i, 4); return pos; } /* * Return -1, it was impossible to create the window because of there is no * more enough characters left and 0 if OK. */ static int create_peek_window(Octstr **address, long *pos) { long i; unsigned char c; i = 0; c = '='; while (i < 2 && (c = octstr_get_char(*address, *pos)) != '=') { if (*pos > 0) --*pos; ++i; } if (c == '=') return 0; return 1; } static long rest_unescaped(Octstr **address, long pos) { long i, ret; for (i = 2; i > 0; i--) { if ((ret = accept_safe(address, pos)) == -2) return -2; else if (ret == -1) return pos; } return pos; } static int issafe(Octstr **address, long pos) { if (octstr_get_char(*address, pos) == '%') return 0; else return 1; } static long accept_safe(Octstr **address, long pos) { unsigned char c; c = octstr_get_char(*address, pos); if ((isalnum(c) || c == '+' || c == '-' || c == '.' || c == '_') && pos >= 0) --pos; else if (c == '=') return -1; else return -2; return pos; } static long accept_escaped(Octstr **address, long pos) { Octstr *temp; long i; unsigned char c; pos = drop_character(address, pos); temp = octstr_create(""); for (i = 2; i > 0; i--) { c = octstr_get_char(*address, pos + i); temp = prepend_char(temp, c); pos = drop_character(address, pos + i); if (pos > 0) --pos; } if (octstr_hex_to_binary(temp) < 0) { octstr_destroy(temp); return -2; } octstr_insert(*address, temp, pos + 2); /* To the end of the window */ octstr_destroy(temp); return pos + 1; /* The position preceding the inserted character */ } /* * Point ends the string to be parsed, comma separates its fragments. */ static long handle_two_terminators (Octstr **address, long pos, unsigned char comma, unsigned char point, unsigned char c, long fragment_parsed, long fragment_length) { if (fragment_parsed == fragment_length && c != comma && c != point) return -2; if (c == point) octstr_delete(*address, pos, 1); --pos; return pos; } gateway-1.4.5/gw/wap-appl.h0000644000175000017500000000774113227613126014207 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap-appl.h - interface to application layer */ #ifndef WAP_APPL_H #define WAP_APPL_H #include "wap/wap.h" void wap_appl_init(Cfg *cfg); void wap_appl_dispatch(WAPEvent *event); void wap_appl_shutdown(void); long wap_appl_get_load(void); /* configure an URL mapping (new version) */ void wsp_http_url_map(Octstr *name, Octstr *url, Octstr *map_url, Octstr *send_msisdn_query, Octstr *send_msisdn_header, Octstr *send_msisdn_format, int accept_cookies); /* configure an URL mapping; parses string on whitespace, uses left * part for the source URL, and right part for the destination URL */ void wsp_http_map_url_config(char *); /* configure an URL mapping from source DEVICE:home to given string */ void wsp_http_map_url_config_device_home(char *); /* show all configured URL mappings */ void wsp_http_map_url_config_info(void); /* Free URL mapping table. */ void wsp_http_map_destroy(void); /* configure an User mapping */ void wsp_http_user_map(Octstr *name, Octstr *user, Octstr *pass, Octstr *msisdn); /* show all configured User mappings */ void wsp_http_map_user_config_info(void); /* Free User mapping table. */ void wsp_http_map_user_destroy(void); #endif gateway-1.4.5/gw/cert.pem0000644000175000017500000000225007363702670013752 0ustar toljtolj-----BEGIN CERTIFICATE----- MIIDRDCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBqTELMAkGA1UEBhMCWFkx FTATBgNVBAgTDFNuYWtlIERlc2VydDETMBEGA1UEBxMKU25ha2UgVG93bjEXMBUG A1UEChMOU25ha2UgT2lsLCBMdGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhv cml0eTEVMBMGA1UEAxMMU25ha2UgT2lsIENBMR4wHAYJKoZIhvcNAQkBFg9jYUBz bmFrZW9pbC5kb20wHhcNOTkxMDIxMTgyMTQ2WhcNMDExMDIwMTgyMTQ2WjCBqTEL MAkGA1UEBhMCWFkxFTATBgNVBAgTDFNuYWtlIERlc2VydDETMBEGA1UEBxMKU25h a2UgVG93bjEXMBUGA1UEChMOU25ha2UgT2lsLCBMdGQxHjAcBgNVBAsTFUNlcnRp ZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMU25ha2UgT2lsIENBMR4wHAYJKoZI hvcNAQkBFg9jYUBzbmFrZW9pbC5kb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ AoGBANiTGAmWoiB2Qx3SbwFXwjbqU9ZwnfBE5Er1h1kNh487D782I8mcT/CzxmsH evK3heBKTEno+jB0y5p4+QShxryaMUUbRoOGfrlrVwc/dbwJQz7UNyqDlWnvnW4p TfdVd+8JlCpYFB23Z7bmpUV1Xy6VFKBahzIhzITaux1vvEPLAgMBAAGjejB4MBoG A1UdEQQTMBGBD2NhQHNuYWtlb2lsLmRvbTAPBgNVHRMECDAGAQH/AgEAMDYGCWCG SAGG+EIBDQQpFidtb2Rfc3NsIGdlbmVyYXRlZCBjdXN0b20gQ0EgY2VydGlmaWNh dGUwEQYJYIZIAYb4QgEBBAQDAgIEMA0GCSqGSIb3DQEBBAUAA4GBAImhzPY4PBRt PQbAQBAmHIBRcb69iTbFC+dghnVJQ3F549rZapY420kQDKQ6aCybPFmxJ/Rf27gY FuAuo+B8EEVX0lU8VUSEhYQedODnQ3skwcT02g4b33GkzH7ED2N9kaa6U65UUrcE KXJgz7tmAQHnTc9K1g2qIApIjnr3FrrJ -----END CERTIFICATE----- gateway-1.4.5/gw/bb_store_spool.c0000644000175000017500000002471713227613126015476 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /** * bb_store_spool.c - bearerbox box SMS storage/retrieval module using spool directory * * Author: Alexander Malysh, 2006 */ #include "gw-config.h" #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "msg.h" #include "sms.h" #include "bearerbox.h" #include "bb_store.h" /* how much subdirs allowed ? */ #define MAX_DIRS 100 static Octstr *spool; static Counter *counter; static List *loaded; static int store_spool_dump() { /* nothing todo */ return 0; } static long store_spool_messages() { return counter ? counter_value(counter) : -1; } static int for_each_file(const Octstr *dir_s, int ignore_err, void(*cb)(const Octstr*, void*), void *data) { DIR *dir; struct dirent *ent; struct stat stat; int ret = 0; if ((dir = opendir(octstr_get_cstr(dir_s))) == NULL) { error(errno, "Could not open directory `%s'", octstr_get_cstr(dir_s)); return -1; } while((ent = readdir(dir)) != NULL) { Octstr *filename; if (*(ent->d_name) == '.') /* skip hidden files */ continue; filename = octstr_format("%S/%s", dir_s, ent->d_name); if (lstat(octstr_get_cstr(filename), &stat) == -1) { if (!ignore_err) error(errno, "Could not get stat for `%s'", octstr_get_cstr(filename)); ret = -1; } else if (S_ISDIR(stat.st_mode) && for_each_file(filename, ignore_err, cb, data) == -1) { ret = -1; } else if (S_ISREG(stat.st_mode) && cb != NULL) cb(filename, data); octstr_destroy(filename); if (ret == -1 && ignore_err) ret = 0; else if (ret == -1) break; } closedir(dir); return ret; } struct status { void(*callback_fn)(Msg* msg, void *data); void *data; }; static void status_cb(const Octstr *filename, void *d) { struct status *data = d; Octstr *msg_s; Msg *msg; msg_s = octstr_read_file(octstr_get_cstr(filename)); msg = store_msg_unpack(msg_s); octstr_destroy(msg_s); if (msg == NULL) return; data->callback_fn(msg, data->data); msg_destroy(msg); } static void store_spool_for_each_message(void(*callback_fn)(Msg* msg, void *data), void *data) { struct status d; if (spool == NULL) return; d.callback_fn = callback_fn; d.data = data; /* ignore error because files may disappear */ for_each_file(spool, 1, status_cb, &d); } static void dispatch(const Octstr *filename, void *data) { Octstr *msg_s; Msg *msg; void(*receive_msg)(Msg*) = data; /* debug("", 0, "dispatch(%s,...) called", octstr_get_cstr(filename)); */ msg_s = octstr_read_file(octstr_get_cstr(filename)); if (msg_s == NULL) return; msg = store_msg_unpack(msg_s); octstr_destroy(msg_s); if (msg != NULL) { receive_msg(msg); counter_increase(counter); } else { error(0, "Could not unpack message `%s'", octstr_get_cstr(filename)); } } static int store_spool_load(void(*receive_msg)(Msg*)) { int rc; /* check if we are active */ if (spool == NULL) return 0; /* sanity check */ if (receive_msg == NULL) return -1; rc = for_each_file(spool, 0, dispatch, receive_msg); info(0, "Loaded %ld messages from store.", counter_value(counter)); /* allow using of storage */ gwlist_remove_producer(loaded); return rc; } static int store_spool_save(Msg *msg) { char id[UUID_STR_LEN + 1]; Octstr *id_s; /* always set msg id and timestamp */ if (msg_type(msg) == sms && uuid_is_null(msg->sms.id)) uuid_generate(msg->sms.id); if (msg_type(msg) == sms && msg->sms.time == MSG_PARAM_UNDEFINED) time(&msg->sms.time); if (spool == NULL) return 0; /* blocke here if store still not loaded */ gwlist_consume(loaded); switch(msg_type(msg)) { case sms: { Octstr *os = store_msg_pack(msg); Octstr *filename, *dir; int fd; size_t wrc; if (os == NULL) { error(0, "Could not pack message."); return -1; } uuid_unparse(msg->sms.id, id); id_s = octstr_create(id); dir = octstr_format("%S/%ld", spool, octstr_hash_key(id_s) % MAX_DIRS); octstr_destroy(id_s); if (mkdir(octstr_get_cstr(dir), S_IRUSR|S_IWUSR|S_IXUSR) == -1 && errno != EEXIST) { error(errno, "Could not create directory `%s'.", octstr_get_cstr(dir)); octstr_destroy(dir); octstr_destroy(os); return -1; } filename = octstr_format("%S/%s", dir, id); octstr_destroy(dir); if ((fd = open(octstr_get_cstr(filename), O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR)) == -1) { error(errno, "Could not open file `%s'.", octstr_get_cstr(filename)); octstr_destroy(filename); octstr_destroy(os); return -1; } for (wrc = 0; wrc < octstr_len(os); ) { size_t rc = write(fd, octstr_get_cstr(os) + wrc, octstr_len(os) - wrc); if (rc == -1) { /* remove file */ error(errno, "Could not write message to `%s'.", octstr_get_cstr(filename)); close(fd); if (unlink(octstr_get_cstr(filename)) == -1) error(errno, "Oops, Could not remove failed file `%s'.", octstr_get_cstr(filename)); octstr_destroy(os); octstr_destroy(filename); return -1; } wrc += rc; } close(fd); counter_increase(counter); octstr_destroy(filename); octstr_destroy(os); break; } case ack: { Octstr *filename; uuid_unparse(msg->ack.id, id); id_s = octstr_create(id); filename = octstr_format("%S/%ld/%s", spool, octstr_hash_key(id_s) % MAX_DIRS, id); octstr_destroy(id_s); if (unlink(octstr_get_cstr(filename)) == -1) { error(errno, "Could not unlink file `%s'.", octstr_get_cstr(filename)); octstr_destroy(filename); return -1; } counter_decrease(counter); octstr_destroy(filename); break; } default: return -1; } return 0; } static int store_spool_save_ack(Msg *msg, ack_status_t status) { int ret; Msg *nack = msg_create(ack); nack->ack.nack = status; uuid_copy(nack->ack.id, msg->sms.id); nack->ack.time = msg->sms.time; ret = store_spool_save(nack); msg_destroy(nack); return ret; } static void store_spool_shutdown() { if (spool == NULL) return; counter_destroy(counter); octstr_destroy(spool); gwlist_destroy(loaded, NULL); } int store_spool_init(const Octstr *store_dir) { DIR *dir; store_messages = store_spool_messages; store_save = store_spool_save; store_save_ack = store_spool_save_ack; store_load = store_spool_load; store_dump = store_spool_dump; store_shutdown = store_spool_shutdown; store_for_each_message = store_spool_for_each_message; if (store_dir == NULL) return 0; /* check if we can open directory */ if ((dir = opendir(octstr_get_cstr(store_dir))) == NULL) { error(errno, "Could not open directory `%s'", octstr_get_cstr(store_dir)); return -1; } closedir(dir); loaded = gwlist_create(); gwlist_add_producer(loaded); spool = octstr_duplicate(store_dir); counter = counter_create(); return 0; } gateway-1.4.5/gw/settings.dtd0000644000175000017500000000037707424243130014644 0ustar toljtolj gateway-1.4.5/gw/dlr_pgsql.c0000644000175000017500000003351713227613126014450 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dlr_pgsql.c * * Implementation of handling delivery reports (DLRs) * for PostgreSQL database * * modeled after dlr_mysql.c * * Alexander Malysh , cleanup 2004 */ #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #include "dlr_p.h" #ifdef HAVE_PGSQL #include /* * Our connection pool to pgsql. */ static DBPool *pool = NULL; /* * Database fields, which we are use. */ static struct dlr_db_fields *fields = NULL; static inline int pgsql_update(const Octstr *sql) { DBPoolConn *pc; int ret = 0; #if defined(DLR_TRACE) debug("dlr.pgsql", 0, "sql: %s", octstr_get_cstr(sql)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "PGSQL: Database pool got no connection! DB update failed!"); return -1; } if ((ret = dbpool_conn_update(pc, sql, NULL)) == -1) error(0, "PGSQL: DB update failed!"); dbpool_conn_produce(pc); return ret; } static inline List *pgsql_select(const Octstr *sql) { DBPoolConn *pc; List *ret = NULL; #if defined(DLR_TRACE) debug("dlr.pgsql", 0, "sql: %s", octstr_get_cstr(sql)); #endif pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "PGSQL: Database pool got no connection! DB operation failed!"); return NULL; } if (dbpool_conn_select(pc, sql, NULL, &ret) == -1) error(0, "PGSQL: Select failed!"); dbpool_conn_produce(pc); return ret; } static void dlr_pgsql_shutdown() { dbpool_destroy(pool); dlr_db_fields_destroy(fields); } static void dlr_pgsql_add(struct dlr_entry *entry) { Octstr *sql; sql = octstr_format("INSERT INTO \"%s\" (\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\") VALUES " "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d');", octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc), octstr_get_cstr(fields->field_ts), octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc), octstr_get_cstr(fields->field_status), octstr_get_cstr(entry->smsc), octstr_get_cstr(entry->timestamp), octstr_get_cstr(entry->source), octstr_get_cstr(entry->destination), octstr_get_cstr(entry->service), octstr_get_cstr(entry->url), entry->mask, octstr_get_cstr(entry->boxc_id), 0); if (!pgsql_update(sql)) warning(0, "DLR: PGSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination)); octstr_destroy(sql); dlr_entry_destroy(entry); } static struct dlr_entry *dlr_pgsql_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { struct dlr_entry *res = NULL; Octstr *sql, *like; List *result, *row; if (dst) like = octstr_format("AND \"%S\" LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("SELECT \"%S\", \"%S\", \"%S\", \"%S\", \"%S\", " "\"%S\" FROM \"%S\" WHERE \"%S\"='%S' AND \"%S\"='%S' %S LIMIT 1;", fields->field_mask, fields->field_serv, fields->field_url, fields->field_src, fields->field_dst, fields->field_boxc, fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like); result = pgsql_select(sql); octstr_destroy(sql); octstr_destroy(like); if (result == NULL || gwlist_len(result) < 1) { debug("dlr.pgsql", 0, "no rows found"); gwlist_destroy(result, NULL); return NULL; } row = gwlist_get(result, 0); debug("dlr.pgsql", 0, "Found entry, col1=%s, col2=%s, col3=%s, col4=%s, col5=%s col6=%s", octstr_get_cstr(gwlist_get(row, 0)), octstr_get_cstr(gwlist_get(row, 1)), octstr_get_cstr(gwlist_get(row, 2)), octstr_get_cstr(gwlist_get(row, 3)), octstr_get_cstr(gwlist_get(row, 4)), octstr_get_cstr(gwlist_get(row, 5)) ); res = dlr_entry_create(); gw_assert(res != NULL); res->mask = atoi(octstr_get_cstr(gwlist_get(row, 0))); res->service = octstr_duplicate(gwlist_get(row, 1)); res->url = octstr_duplicate(gwlist_get(row, 2)); res->source = octstr_duplicate(gwlist_get(row, 3)); res->destination = octstr_duplicate(gwlist_get(row, 4)); res->boxc_id = octstr_duplicate(gwlist_get(row, 5)); res->smsc = octstr_duplicate(smsc); while((row = gwlist_extract_first(result))) gwlist_destroy(row, octstr_destroy_item); gwlist_destroy(result, NULL); return res; } static void dlr_pgsql_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; debug("dlr.pgsql", 0, "removing DLR from database"); if (dst) like = octstr_format("AND \"%S\" LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("DELETE FROM \"%S\" WHERE oid = (SELECT oid FROM " "\"%S\" WHERE \"%S\"='%S' AND \"%S\"='%S' %S LIMIT 1);", fields->table, fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like); if (!pgsql_update(sql)) warning(0, "DLR: PGSQL: No dlr deleted for DST<%s>", octstr_get_cstr(dst)); octstr_destroy(sql); octstr_destroy(like); } static void dlr_pgsql_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status) { Octstr *sql, *like; debug("dlr.pgsql", 0, "updating DLR status in database"); if (dst) like = octstr_format("AND \"%S\" LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("UPDATE \"%S\" SET \"%S\"=%d WHERE oid = (SELECT " "oid FROM \"%S\" WHERE \"%S\"='%S' AND \"%S\"='%S' %S LIMIT 1);", fields->table, fields->field_status, status, fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like); if (!pgsql_update(sql)) warning(0, "DLR: PGSQL: No dlr updated for DST<%s> (status: %d)", octstr_get_cstr(dst), status); octstr_destroy(sql); octstr_destroy(like); } static long dlr_pgsql_messages(void) { Octstr *sql; long ret; List *res; sql = octstr_format("SELECT count(*) FROM \"%s\";", octstr_get_cstr(fields->table)); res = pgsql_select(sql); octstr_destroy(sql); if (res == NULL || gwlist_len(res) < 1) { error(0, "PGSQL: Could not get count of DLR table"); ret = -1; } else { ret = atol(octstr_get_cstr(gwlist_get(gwlist_get(res, 0), 0))); gwlist_destroy(gwlist_extract_first(res), octstr_destroy_item); } gwlist_destroy(res, NULL); return ret; } static void dlr_pgsql_flush(void) { Octstr *sql; sql = octstr_format("DELETE FROM \"%s\";", octstr_get_cstr(fields->table)); pgsql_update(sql); octstr_destroy(sql); } static struct dlr_storage handles = { .type = "pgsql", .dlr_add = dlr_pgsql_add, .dlr_get = dlr_pgsql_get, .dlr_update = dlr_pgsql_update, .dlr_remove = dlr_pgsql_remove, .dlr_shutdown = dlr_pgsql_shutdown, .dlr_messages = dlr_pgsql_messages, .dlr_flush = dlr_pgsql_flush }; struct dlr_storage *dlr_init_pgsql(Cfg *cfg) { CfgGroup *grp; List *grplist; Octstr *pgsql_host, *pgsql_user, *pgsql_pass, *pgsql_db, *pgsql_id; long pgsql_port = 0; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; /* * check for all mandatory directives that specify the field names * of the table used */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db")))) panic(0, "DLR: PgSQL: group 'dlr-db' is not specified!"); if (!(pgsql_id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: PgSQL: directive 'id' is not specified!"); fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); /* * Escaping special quotes for field/table names */ octstr_replace(fields->table, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_smsc, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_ts, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_src, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_dst, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_serv, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_url, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_mask, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_status, octstr_imm("\""), octstr_imm("\"\"")); octstr_replace(fields->field_boxc, octstr_imm("\""), octstr_imm("\"\"")); /* * now grap the required information from the 'pgsql-connection' group * with the pgsql-id we just obtained * * we have to loop through all available PostgreSQL connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("pgsql-connection")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, pgsql_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "DLR: PgSQL: connection settings for id '%s' are not specified!", octstr_get_cstr(pgsql_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(pgsql_host = cfg_get(grp, octstr_imm("host")))) panic(0, "DLR: PgSQL: directive 'host' is not specified!"); if (!(pgsql_user = cfg_get(grp, octstr_imm("username")))) panic(0, "DLR: PgSQL: directive 'username' is not specified!"); if (!(pgsql_pass = cfg_get(grp, octstr_imm("password")))) panic(0, "DLR: PgSQL: directive 'password' is not specified!"); if (!(pgsql_db = cfg_get(grp, octstr_imm("database")))) panic(0, "DLR: PgSQL: directive 'database' is not specified!"); cfg_get_integer(&pgsql_port, grp, octstr_imm("port")); /* optional */ /* * ok, ready to connect to the database */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->pgsql = gw_malloc(sizeof(PgSQLConf)); gw_assert(db_conf->pgsql != NULL); db_conf->pgsql->host = pgsql_host; db_conf->pgsql->port = pgsql_port; db_conf->pgsql->username = pgsql_user; db_conf->pgsql->password = pgsql_pass; db_conf->pgsql->database = pgsql_db; pool = dbpool_create(DBPOOL_PGSQL, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"DLR: PgSQL: database pool has no connections!"); octstr_destroy(pgsql_id); return &handles; } #else /* * Return NULL , so we point dlr-core that we were * not compiled in. */ struct dlr_storage *dlr_init_pgsql(Cfg* cfg) { return NULL; } #endif /* HAVE_PGSQL */ gateway-1.4.5/gw/wap_push_ota.c0000644000175000017500000005045213227613126015147 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Wap_push_ota.c: implementation of push related requests of OTA protocol * * This module implements requirement primitives of WAP-189-PushOTA-20000217-a * (hereafter called ota). * In addition, WAP-203-WSP-20000504-a (wsp) is referred. * * This module forwards push requests made by the wap_push_ppg module to * connected or connectionless session services. * Indications (for confirmed push, push abort and disconnect, e.g., in the * case of unability to create a session) of OTA protocol are done for wap_ * push_ppg module by a module common with pull, wap-appl. * * Note that push header encoding and decoding are divided into two parts: * first decoding and encoding numeric values and then packing these values * into WSP format and unpacking them from WSP format. This module contains * decoding part. * * By Aarno Syvänen for Wapit Ltd and Global Networks Inc. */ #include #include "wap_push_ota.h" #include "gwlib/gwlib.h" #include "wap/wsp.h" #include "wap/wsp_strings.h" #include "wap/wsp_pdu.h" /************************************************************************** * * Internal data structures */ /* * Give the status of the push ota module: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum {limbo, running, terminating} run_status = limbo; /* * Bearerbox address for the phone (it needs to know who it is talking with) */ struct BearerboxAddress { Octstr *address; Mutex *mutex; }; typedef struct BearerboxAddress BearerboxAddress; static BearerboxAddress *bearerbox = NULL; static List *ota_queue = NULL; wap_dispatch_func_t *dispatch_to_wsp; wap_dispatch_func_t *dispatch_to_wsp_unit; /************************************************************************** * * Prototypes of internal functions */ static void main_thread(void *arg); static void handle_ota_event(WAPEvent *e); static void make_session_request(WAPEvent *e); static void make_push_request(WAPEvent *e); static void make_confirmed_push_request(WAPEvent *e); static void make_unit_push_request(WAPEvent *e); static void abort_push(WAPEvent *e); /* * Add push flag into push headers. Push flag is defined in PushOTA, p. 17-18. */ static List *add_push_flag(WAPEvent *e); /* * When server is requesting a session with a client, content type and applic- * ation headers must be present (this behaviour is defined in PushOTA, p. 14). * We check headers for them and add them if they are not already present. */ static void check_session_request_headers(List *headers); /* * Contact points and application ids in the push initiator are packed into a * specific structure, being like WSP PDUs. */ static Octstr *pack_sia(List *headers); static void flags_assert(WAPEvent *e); static void reason_assert(long reason); static Octstr *pack_server_address(void); static Octstr *pack_appid_list(List *headers); /* * Returns bearerbox ip address. Resolve it, if the address is localhost. */ static Octstr *name(Octstr *os); static BearerboxAddress *bearerbox_address_create(void); static void bearerbox_address_destroy(BearerboxAddress *ba); /*************************************************************************** * * EXTERNAL FUNCTIONS */ void wap_push_ota_init(wap_dispatch_func_t *wsp_dispatch, wap_dispatch_func_t *wsp_unit_dispatch) { ota_queue = gwlist_create(); gwlist_add_producer(ota_queue); dispatch_to_wsp = wsp_dispatch; dispatch_to_wsp_unit = wsp_unit_dispatch; bearerbox = bearerbox_address_create(); gw_assert(run_status == limbo); run_status = running; gwthread_create(main_thread, NULL); } void wap_push_ota_shutdown(void) { gw_assert(run_status == running); run_status = terminating; gwlist_remove_producer(ota_queue); gwthread_join_every(main_thread); gwlist_destroy(ota_queue, wap_event_destroy_item); bearerbox_address_destroy(bearerbox); } void wap_push_ota_dispatch_event(WAPEvent *e) { gw_assert(run_status == running); gwlist_produce(ota_queue, e); } /* * Sets bearerbox address, used for push contact point. Resolve address local- * host before assignment. */ void wap_push_ota_bb_address_set(Octstr *in) { gw_assert(in); mutex_lock(bearerbox->mutex); bearerbox->address = name(in); mutex_unlock(bearerbox->mutex); } /************************************************************************** * * INTERNAL FUNCTIONS */ static void main_thread(void *arg) { WAPEvent *e; while (run_status == running && (e = gwlist_consume(ota_queue)) != NULL) { handle_ota_event(e); } } static void handle_ota_event(WAPEvent *e) { debug("wap.push.ota", 0, "OTA: event arrived"); switch (e->type) { case Pom_SessionRequest_Req: make_session_request(e); break; case Po_Push_Req: make_push_request(e); break; case Po_ConfirmedPush_Req: make_confirmed_push_request(e); break; case Po_Unit_Push_Req: make_unit_push_request(e); break; case Po_PushAbort_Req: abort_push(e); break; default: debug("wap.push.ota", 0, "OTA: unhandled event"); wap_event_dump(e); break; } wap_event_destroy(e); } static void make_session_request(WAPEvent *e) { WAPEvent *wsp_event; List *appid_headers, *push_headers; gw_assert(e->type == Pom_SessionRequest_Req); push_headers = e->u.Pom_SessionRequest_Req.push_headers; check_session_request_headers(push_headers); wsp_event = wap_event_create(S_Unit_Push_Req); wsp_event->u.S_Unit_Push_Req.address_type = e->u.Pom_SessionRequest_Req.address_type; if (e->u.Pom_SessionRequest_Req.smsc_id != NULL) wsp_event->u.S_Unit_Push_Req.smsc_id = octstr_duplicate(e->u.Pom_SessionRequest_Req.smsc_id); else wsp_event->u.S_Unit_Push_Req.smsc_id = NULL; if (e->u.Pom_SessionRequest_Req.dlr_url != NULL) wsp_event->u.S_Unit_Push_Req.dlr_url = octstr_duplicate(e->u.Pom_SessionRequest_Req.dlr_url); else wsp_event->u.S_Unit_Push_Req.dlr_url = NULL; wsp_event->u.S_Unit_Push_Req.dlr_mask = e->u.Pom_SessionRequest_Req.dlr_mask; if (e->u.Pom_SessionRequest_Req.smsbox_id != NULL) wsp_event->u.S_Unit_Push_Req.smsbox_id = octstr_duplicate(e->u.Pom_SessionRequest_Req.smsbox_id); else wsp_event->u.S_Unit_Push_Req.smsbox_id = NULL; wsp_event->u.S_Unit_Push_Req.service_name = octstr_duplicate(e->u.Pom_SessionRequest_Req.service_name); wsp_event->u.S_Unit_Push_Req.push_id = e->u.Pom_SessionRequest_Req.push_id; wsp_event->u.S_Unit_Push_Req.addr_tuple = wap_addr_tuple_duplicate(e->u.Pom_SessionRequest_Req.addr_tuple); wsp_event->u.S_Unit_Push_Req.push_headers = http_header_duplicate(push_headers); appid_headers = http_header_find_all(push_headers, "X-WAP-Application-Id"); wsp_event->u.S_Unit_Push_Req.push_body = pack_sia(appid_headers); debug("wap.push.ota", 0, "OTA: making a connectionless session request for" " creating a session"); dispatch_to_wsp_unit(wsp_event); } static void make_push_request(WAPEvent *e) { WAPEvent *wsp_event; List *push_headers; gw_assert(e->type == Po_Push_Req); push_headers = add_push_flag(e); wsp_event = wap_event_create(S_Push_Req); wsp_event->u.S_Push_Req.push_headers = push_headers; if (e->u.Po_Push_Req.push_body != NULL) wsp_event->u.S_Push_Req.push_body = octstr_duplicate(e->u.Po_Push_Req.push_body); else wsp_event->u.S_Push_Req.push_body = NULL; wsp_event->u.S_Push_Req.session_id = e->u.Po_Push_Req.session_handle; dispatch_to_wsp(wsp_event); } static void make_confirmed_push_request(WAPEvent *e) { WAPEvent *wsp_event; List *push_headers; gw_assert(e->type == Po_ConfirmedPush_Req); push_headers = add_push_flag(e); wsp_event = wap_event_create(S_ConfirmedPush_Req); wsp_event->u.S_ConfirmedPush_Req.server_push_id = e->u.Po_ConfirmedPush_Req.server_push_id; wsp_event->u.S_ConfirmedPush_Req.push_headers = push_headers; if (e->u.Po_ConfirmedPush_Req.push_body != NULL) wsp_event->u.S_ConfirmedPush_Req.push_body = octstr_duplicate(e->u.Po_ConfirmedPush_Req.push_body); else wsp_event->u.S_ConfirmedPush_Req.push_body = NULL; wsp_event->u.S_ConfirmedPush_Req.session_id = e->u.Po_ConfirmedPush_Req.session_handle; debug("wap.push.ota", 0, "OTA: making confirmed push request to wsp"); dispatch_to_wsp(wsp_event); } static void make_unit_push_request(WAPEvent *e) { WAPEvent *wsp_event; List *push_headers; Octstr *smsc_id; Octstr *dlr_url; Octstr *smsbox_id; Octstr *push_body; Octstr *service_name; gw_assert(e->type == Po_Unit_Push_Req); gw_assert(e->u.Po_Unit_Push_Req.addr_tuple); gw_assert(e->u.Po_Unit_Push_Req.service_name); smsc_id = octstr_duplicate(e->u.Po_Unit_Push_Req.smsc_id); dlr_url = octstr_duplicate(e->u.Po_Unit_Push_Req.dlr_url); smsbox_id = octstr_duplicate(e->u.Po_Unit_Push_Req.smsbox_id); push_body = octstr_duplicate(e->u.Po_Unit_Push_Req.push_body); service_name = octstr_duplicate(e->u.Po_Unit_Push_Req.service_name); push_headers = add_push_flag(e); wsp_event = wap_event_create(S_Unit_Push_Req); wsp_event->u.S_Unit_Push_Req.addr_tuple = wap_addr_tuple_duplicate(e->u.Po_Unit_Push_Req.addr_tuple); wsp_event->u.S_Unit_Push_Req.push_id = e->u.Po_Unit_Push_Req.push_id; wsp_event->u.S_Unit_Push_Req.push_headers = push_headers; wsp_event->u.S_Unit_Push_Req.address_type = e->u.Po_Unit_Push_Req.address_type; if (smsc_id != NULL) wsp_event->u.S_Unit_Push_Req.smsc_id = smsc_id; else wsp_event->u.S_Unit_Push_Req.smsc_id = NULL; if (dlr_url != NULL) wsp_event->u.S_Unit_Push_Req.dlr_url = dlr_url; else wsp_event->u.S_Unit_Push_Req.dlr_url = NULL; wsp_event->u.S_Unit_Push_Req.dlr_mask = e->u.Po_Unit_Push_Req.dlr_mask; if (smsbox_id != NULL) wsp_event->u.S_Unit_Push_Req.smsbox_id = smsbox_id; else wsp_event->u.S_Unit_Push_Req.smsbox_id = NULL; wsp_event->u.S_Unit_Push_Req.service_name = service_name; if (push_body != NULL) wsp_event->u.S_Unit_Push_Req.push_body = push_body; else wsp_event->u.S_Unit_Push_Req.push_body = NULL; dispatch_to_wsp_unit(wsp_event); debug("wap.push.ota", 0, "OTA: made connectionless session service" " request"); } static void abort_push(WAPEvent *e) { WAPEvent *wsp_event; long reason; reason = e->u.Po_PushAbort_Req.reason; gw_assert(e->type == Po_PushAbort_Req); reason_assert(reason); wsp_event = wap_event_create(S_PushAbort_Req); wsp_event->u.S_PushAbort_Req.push_id = e->u.Po_PushAbort_Req.push_id; wsp_event->u.S_PushAbort_Req.reason = reason; wsp_event->u.S_PushAbort_Req.session_handle = e->u.Po_PushAbort_Req.session_id; dispatch_to_wsp(wsp_event); } /* * Add push flag into push headers. Push flag is defined in ota, p. 17-18. * If there is no flags set, no Push-Flag header is added. */ static List *add_push_flag(WAPEvent *e) { int push_flag, trusted, authenticated, last; Octstr *buf; List *headers; flags_assert(e); if (e->type == Po_Unit_Push_Req) { trusted = e->u.Po_Unit_Push_Req.trusted << 1; authenticated = e->u.Po_Unit_Push_Req.authenticated; last = e->u.Po_Unit_Push_Req.last << 2; headers = http_header_duplicate(e->u.Po_Unit_Push_Req.push_headers); } else if (e->type == Po_Push_Req) { trusted = e->u.Po_Push_Req.trusted << 1; authenticated = e->u.Po_Push_Req.authenticated; last = e->u.Po_Push_Req.last << 2; headers = http_header_duplicate(e->u.Po_Push_Req.push_headers); } else if (e->type == Po_ConfirmedPush_Req) { trusted = e->u.Po_ConfirmedPush_Req.trusted << 1; authenticated = e->u.Po_ConfirmedPush_Req.authenticated; last = e->u.Po_ConfirmedPush_Req.last << 2; headers = http_header_duplicate( e->u.Po_ConfirmedPush_Req.push_headers); } else { debug("wap.ota", 0, "OTA: no push flag when the event is: \n"); wap_event_dump(e); return NULL; } push_flag = 0; push_flag = push_flag | authenticated | trusted | last; if (push_flag) { buf = octstr_format("%d", push_flag); http_header_add(headers, "Push-Flag", octstr_get_cstr(buf)); octstr_destroy(buf); } return headers; } static void flags_assert(WAPEvent *e) { if (e->type == Po_Unit_Push_Req) { gw_assert(e->u.Po_Unit_Push_Req.trusted == 0 || e->u.Po_Unit_Push_Req.trusted == 1); gw_assert(e->u.Po_Unit_Push_Req.authenticated == 0 || e->u.Po_Unit_Push_Req.authenticated == 1); gw_assert(e->u.Po_Unit_Push_Req.last == 0 || e->u.Po_Unit_Push_Req.last == 1); } else if (e->type == Po_Push_Req) { gw_assert(e->u.Po_Push_Req.trusted == 0 || e->u.Po_Push_Req.trusted == 1); gw_assert(e->u.Po_Push_Req.authenticated == 0 || e->u.Po_Push_Req.authenticated == 1); gw_assert(e->u.Po_Push_Req.last == 0 || e->u.Po_Push_Req.last == 1); } else if (e->type == Po_ConfirmedPush_Req) { gw_assert(e->u.Po_ConfirmedPush_Req.trusted == 0 || e->u.Po_ConfirmedPush_Req.trusted == 1); gw_assert(e->u.Po_ConfirmedPush_Req.authenticated == 0 || e->u.Po_ConfirmedPush_Req.authenticated == 1); gw_assert(e->u.Po_ConfirmedPush_Req.last == 0 || e->u.Po_ConfirmedPush_Req.last == 1); } } /* * Accepted reasons are defined in ota 6.3.3. */ static void reason_assert(long reason) { gw_assert(reason == WSP_ABORT_USERREQ || reason == WSP_ABORT_USERRFS || reason == WSP_ABORT_USERPND || reason == WSP_ABORT_USERDCR || reason == WSP_ABORT_USERDCU); } /* * When server is requesting a session with a client, content type and applic- * ation headers must be present (this behaviour is defined in ota, p. 14). * We check headers for them and add them if they are not already present. * X-WAP-Application-Id has been added by ppg module. */ static void check_session_request_headers(List *headers) { if (!http_type_accepted(headers, "application/wnd.wap.sia")) http_header_add(headers, "Content-Type", "application/vnd.wap.sia"); } /* * Pack contact points and application id list into sia content type. It is * defined in ota, p. 18. */ static Octstr *pack_sia(List *headers) { Octstr *sia_content; WSP_PDU *pdu; pdu = wsp_pdu_create(sia); pdu->u.sia.version = CURRENT_VERSION; pdu->u.sia.application_id_list = pack_appid_list(headers); pdu->u.sia.contactpoints = pack_server_address(); sia_content = wsp_pdu_pack(pdu); wsp_pdu_destroy(pdu); http_destroy_headers(headers); return sia_content; } /* * Input: List of headers containing only X-Wap-Application-Id headers, values * being numeric application id codes. (Ppg module does coding of the header * value part of the X-WAP-Application-Id header). * Output: Octstr containing them in a byte list (one id per byte). * * Returns: Octstr containing headers, if succesfull, otherwise an empty * octstr. */ static Octstr *pack_appid_list(List *headers) { Octstr *appid_os, *header_name, *header_value; long i; size_t len; i = 0; appid_os = octstr_create(""); len = (size_t) gwlist_len(headers); gw_assert(len); while (i < len) { http_header_get(headers, i, &header_name, &header_value); gw_assert(octstr_compare(header_name, octstr_imm("X-WAP-Application-Id")) == 0); octstr_format_append(appid_os, "%S", header_value); octstr_destroy(header_name); octstr_destroy(header_value); ++i; } return appid_os; } /* * NB: This data includes bearer information. We use IPv4 values. Address Type * is defined in wsp, table 16, p. 65 */ static Octstr *pack_server_address(void) { Octstr *address, *ip_address; unsigned char address_len; long port; int bearer_type; bearer_type = GSM_CSD_IPV4; port = CONNECTED_PORT; mutex_lock(bearerbox->mutex); ip_address = octstr_duplicate(bearerbox->address); address_len = octstr_len(bearerbox->address); mutex_unlock(bearerbox->mutex); address = octstr_create(""); octstr_append_char(address, address_len); octstr_set_bits(address, 0, 1, 1); /* bearer type included */ octstr_set_bits(address, 1, 1, 1); /* port number included */ octstr_append_char(address, bearer_type); octstr_append_decimal(address, port); octstr_append(address, ip_address); octstr_destroy(ip_address); return address; } /* * Returns bearerbox ip address. Resolve it, if the address is localhost. Do * not panic here. Even if we cannot do push, we still can do pull. */ static Octstr *name(Octstr *in) { if (octstr_compare(in, octstr_imm("localhost")) != 0) return octstr_duplicate(in); else return octstr_duplicate(get_official_ip()); } static BearerboxAddress *bearerbox_address_create(void) { BearerboxAddress *ba; ba = gw_malloc(sizeof(BearerboxAddress)); ba->mutex = mutex_create(); ba->address = NULL; return ba; } static void bearerbox_address_destroy(BearerboxAddress *ba) { if (ba == NULL) return; octstr_destroy(ba->address); mutex_destroy(ba->mutex); gw_free(ba); } gateway-1.4.5/gw/wap_push_ppg.c0000644000175000017500000032144213227613126015152 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_ppg.c: General logic of a push proxy gateway. * * This module implements following WAP Forum specifications: * WAP-151-PPGService-19990816-a (called afterwards PPG), * WAP-164-PAP-19991108-a (PAP), * WAP-164_100-PAP-20000218-a (PAP implementation note). * * We refer following WAP Forum specifications: * WAP-145-PushMessage-19990816-a (push message) * WAP-200-WDP-20001212-a (WDP) * WAP-203-WSP-20000504-a (WSP) * WAP-189-PushOTA-20000217-a (OTA). * * In addition, RFCs 1521 and 2045 are referred. * * By Aarno Syv�nen for Wapit Ltd, Wiral Ltd and Global Networks Inc. */ #include #include #include "wap_push_ppg.h" #include "wap/wap_events.h" #include "wap/wsp_caps.h" #include "wml_compiler.h" #include "wap-appl.h" #include "wap/wsp.h" #include "wap/wsp_strings.h" #include "wap_push_si_compiler.h" #include "wap_push_sl_compiler.h" #include "wap_push_pap_compiler.h" #include "wap_push_pap_mime.h" #include "wap_push_ppg_pushuser.h" enum { TIME_EXPIRED = 0, TIME_TOO_EARLY = 1, NO_CONSTRAINTS = 2 }; /* * Default values for configuration variables */ enum { DEFAULT_HTTP_PORT = 8080, NO_HTTPS_PORT = -1, DEFAULT_NUMBER_OF_PUSHES = 100, PI_TRUSTED = 1, SSL_CONNECTION_OFF = 0, DEFAULT_NUMBER_OF_USERS = 1024, USER_CONFIGURATION_NOT_ADDED = 0 }; enum { USER_CONFIGURATION_ADDED = 1 }; #define DEFAULT_PPG_URL "/wappush" /***************************************************************************** * * Internal data structures * * Give the status of the push ppg module: * * limbo * not running at all * running * operating normally * terminating * waiting for operations to terminate, returning to limbo */ static enum {limbo, running, terminating} run_status = limbo; /* * The external event queue for this module */ static List *ppg_queue = NULL; /* * The internal event queue for this module (allowing listening of many ports) */ static List *pap_queue = NULL; /* * List of ppg session machines (it is, of currently active sessions) */ static List *ppg_machines = NULL; /* * List of currently active unit pushes (we need a threadsafe storage for them, * because pushes can be cancelled and queried): */ static List *ppg_unit_pushes = NULL; /* * Counter to store our internal push id. */ static Counter *push_id_counter = NULL; /* * We need a mapping between HTTPClient structures, used by http library, and * push ids, used by ppg. */ static Dict *http_clients = NULL; /* * Mapping between urls used by pi and push ids used by ppg. */ static Dict *urls = NULL; /* * Push content packed for compilers (wml, si, sl, co). */ struct content { Octstr *body; Octstr *type; Octstr *charset; }; static wap_dispatch_func_t *dispatch_to_ota; static wap_dispatch_func_t *dispatch_to_appl; /* * Configurable variables of ppg core group (for general configuration of a * ppg), with some default values. */ static Octstr *ppg_url = NULL ; static long ppg_port = DEFAULT_HTTP_PORT; #ifdef HAVE_LIBSSL static long ppg_ssl_port = NO_HTTPS_PORT; #endif static long number_of_pushes = DEFAULT_NUMBER_OF_PUSHES; static int trusted_pi = PI_TRUSTED; static long number_of_users = DEFAULT_NUMBER_OF_USERS; static Octstr *ppg_deny_ip = NULL; static Octstr *ppg_allow_ip = NULL; static int user_configuration = USER_CONFIGURATION_NOT_ADDED; static Octstr *global_sender = NULL; static Octstr *ppg_default_smsc = NULL; #ifdef HAVE_LIBSSL static Octstr *ssl_server_cert_file = NULL; static Octstr *ssl_server_key_file = NULL; #endif static Octstr *ppg_dlr_url = NULL; static Octstr *ppg_smsbox_id = NULL; static Octstr *service_name = NULL; struct PAPEvent { HTTPClient *client; Octstr *ip; Octstr *url; List *push_headers; Octstr *mime_content; List *cgivars; }; typedef struct PAPEvent PAPEvent; /***************************************************************************** * * Prototypes of internal functions * * Event handling */ static void ota_read_thread(void *arg); static void http_read_thread(void *arg); #ifdef HAVE_LIBSSL static void https_read_thread(void *arg); #endif static void handle_internal_event(WAPEvent *e); static void pap_request_thread(void *arg); static int handle_push_message(HTTPClient **c, WAPEvent *ppg_event, int status); static PAPEvent *pap_event_create(Octstr *ip, Octstr *url, List *push_headers, Octstr *mime_content, List *cgivars, HTTPClient *client); static void pap_event_destroy(PAPEvent *p); static void pap_event_destroy_item(void *p); static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url, List **push_headers, Octstr **mime_content, List **cgivars, HTTPClient **client); /* * Constructors and destructors for machines. */ static PPGSessionMachine *session_machine_create(WAPAddrTuple *tuple, WAPEvent *e); static void session_machine_destroy(void *p); static PPGPushMachine *push_machine_create(WAPEvent *e, WAPAddrTuple *tuple); static void push_machine_destroy(void *pm); static void push_machines_list_destroy(List *pl); /* * Communicating other modules (ota and appl) */ static void create_session(WAPEvent *e, PPGPushMachine *pm); static void request_confirmed_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm); static void request_unit_push(long last, PPGPushMachine *pm); static void request_push(long last, PPGPushMachine *sm); static int response_push_connection(WAPEvent *e, PPGSessionMachine *sm); static HTTPClient *response_push_message(PPGPushMachine *pm, long code, int status); /* * Functions to find machines using various identifiers, and related help * functions. */ static PPGSessionMachine *session_find_using_pi_client_address(Octstr *addr); static PPGPushMachine *find_ppg_push_machine_using_pid(PPGSessionMachine *sm, long pid); static PPGPushMachine *find_ppg_push_machine_using_pi_push_id( PPGSessionMachine *sm, Octstr *pi_push_id); static PPGPushMachine *find_unit_ppg_push_machine_using_pi_push_id( Octstr *pi_push_id); static int push_has_pi_push_id(void *a, void *b); static int push_has_pid(void *a, void *b); static int session_has_pi_client_address(void *a, void *b); static int session_has_addr(void *a, void *b); static int session_has_sid(void *a, void *b); /* * Main logic of PPG. */ static int check_capabilities(List *requested, List *assumed); static int transform_message(WAPEvent **e, WAPAddrTuple **tuple, List *push_headers, int connected, Octstr **type); static long check_x_wap_application_id_header(List **push_headers); static int pap_convert_content(struct content *content); static int pap_get_content(struct content *content); static int select_bearer_network(WAPEvent **e); static int delivery_time_constraints(WAPEvent *e, PPGPushMachine *pm); static void deliver_confirmed_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm); static PPGPushMachine *deliver_unit_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm, int session_exists); static int store_push_data(PPGPushMachine **pm, PPGSessionMachine *sm, WAPEvent *e, WAPAddrTuple *tuple, int cless); static PPGPushMachine *update_push_data_with_attribute(PPGSessionMachine **sm, PPGPushMachine *pm, long reason, long status); static void remove_push_data(PPGSessionMachine *sm, PPGPushMachine *pm, int cless); static void remove_session_data(PPGSessionMachine *sm, int status); static void remove_pushless_session(PPGSessionMachine *sm); static PPGSessionMachine *store_session_data(PPGSessionMachine *sm, WAPEvent *e, WAPAddrTuple *tuple, int *session_exists); static PPGSessionMachine *update_session_data_with_headers( PPGSessionMachine *sm, PPGPushMachine *pm); static void deliver_pending_pushes(PPGSessionMachine *sm, int last); static PPGPushMachine *abort_delivery(PPGSessionMachine *sm, int status); static PPGSessionMachine *update_session_data(PPGSessionMachine *sm, long sid, long port, List *caps); static int confirmation_requested(WAPEvent *e); static int cless_accepted(WAPEvent *e, PPGSessionMachine *sm); /* * Header functions */ static int headers_acceptable(List *push_headers, Octstr **content_header); static int type_is(Octstr *content_header, char *required_type); static int get_mime_boundary(List *push_headers, Octstr *content_header, Octstr **boundary); static void change_header_value(List **push_headers, char *name, char *value); static void remove_mime_headers(List **push_headers); static void remove_link_headers(List **push_headers); static void remove_x_kannel_headers(List **push_headers); /* * Communicating with pi. */ static void send_bad_message_response(HTTPClient **c, Octstr *body_fragment, int code, int status); static HTTPClient *send_push_response(WAPEvent *e, int status); static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status); static void tell_fatal_error(HTTPClient **c, WAPEvent *e, Octstr *url, int status, int code); /* * PPG core authentication (not related to any particular user). */ static int read_ppg_config(Cfg *cfg); static int ip_allowed_by_ppg(Octstr *ip); /* * Interface to various compilers */ static Octstr *convert_wml_to_wmlc(struct content *content); static Octstr *convert_si_to_sic(struct content *content); static Octstr *convert_sl_to_slc(struct content *content); /* * Setting values for controlling sms level. (Pap control document enables * some control, but not enough.) */ static Octstr *set_smsc_id(List *headers, Octstr *username, int trusted_pi); static Octstr *set_dlr_url(List *headers, Octstr *username, int trusted_pi); static long set_dlr_mask(List *headers, Octstr *dlr_url); static Octstr *set_smsbox_id(List *headers, Octstr *username, int trusted_pi); static Octstr *set_service_name(void); /* * Various utility functions */ static Octstr *set_time(void); static int deliver_before_test_cleared(Octstr *before, struct tm now); static int deliver_after_test_cleared(Octstr *after, struct tm now); static void session_machine_assert(PPGSessionMachine *sm); static void push_machine_assert(PPGPushMachine *pm); static Octstr *tell_ppg_name(void); static Octstr *describe_code(long code); static long ota_abort_to_pap(long reason); static int content_transformable(List *push_headers); static WAPAddrTuple *set_addr_tuple(Octstr *address, long cliport, long servport, long address_type, List *push_headers); static WAPAddrTuple *addr_tuple_change_cliport(WAPAddrTuple *tuple, long port); static void initialize_time_item_array(long time_data[], struct tm now); static int date_item_compare(Octstr *before, long time_data, long pos); static long parse_appid_header(Octstr **assigned_code); static Octstr *escape_fragment(Octstr *fragment); static int coriented_deliverable(long code); static int is_phone_number(long type_of_address); static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos); /***************************************************************************** * * EXTERNAL FUNCTIONS */ enum { TYPE_HTTP = 0, TYPE_HTTPS = 1 }; void wap_push_ppg_init(wap_dispatch_func_t *ota_dispatch, wap_dispatch_func_t *appl_dispatch, Cfg *cfg) { user_configuration = read_ppg_config(cfg); if (user_configuration != USER_CONFIGURATION_NOT_ADDED) { ppg_queue = gwlist_create(); gwlist_add_producer(ppg_queue); pap_queue = gwlist_create(); gwlist_add_producer(pap_queue); push_id_counter = counter_create(); ppg_machines = gwlist_create(); ppg_unit_pushes = gwlist_create(); dispatch_to_ota = ota_dispatch; dispatch_to_appl = appl_dispatch; http_open_port(ppg_port, TYPE_HTTP); #ifdef HAVE_LIBSSL if (ppg_ssl_port != NO_HTTPS_PORT) http_open_port(ppg_ssl_port, TYPE_HTTPS); #endif http_clients = dict_create(number_of_pushes, NULL); urls = dict_create(number_of_pushes, NULL); gw_assert(run_status == limbo); run_status = running; gwthread_create(ota_read_thread, NULL); gwthread_create(http_read_thread, NULL); #ifdef HAVE_LIBSSL if (ppg_ssl_port != NO_HTTPS_PORT) gwthread_create(https_read_thread, NULL); #endif gwthread_create(pap_request_thread, NULL); } } void wap_push_ppg_shutdown(void) { if (user_configuration != USER_CONFIGURATION_NOT_ADDED) { gw_assert(run_status == running); run_status = terminating; gwlist_remove_producer(ppg_queue); gwlist_remove_producer(pap_queue); octstr_destroy(ppg_url); ppg_url = NULL; http_close_all_ports(); dict_destroy(http_clients); dict_destroy(urls); wap_push_ppg_pushuser_list_destroy(); octstr_destroy(ppg_deny_ip); octstr_destroy(ppg_allow_ip); octstr_destroy(global_sender); octstr_destroy(service_name); octstr_destroy(ppg_default_smsc); octstr_destroy(ppg_dlr_url); octstr_destroy(ppg_smsbox_id); gwthread_join_every(http_read_thread); #ifdef HAVE_LIBSSL if (ppg_ssl_port != NO_HTTPS_PORT) gwthread_join_every(https_read_thread); #endif gwthread_join_every(ota_read_thread); gwthread_join_every(pap_request_thread); gwlist_destroy(ppg_queue, wap_event_destroy_item); gwlist_destroy(pap_queue, pap_event_destroy_item); counter_destroy(push_id_counter); debug("wap.push.ppg", 0, "PPG: %ld push session machines left.", gwlist_len(ppg_machines)); gwlist_destroy(ppg_machines, session_machine_destroy); debug("wap_push_ppg", 0, "PPG: %ld unit pushes left", gwlist_len(ppg_unit_pushes)); gwlist_destroy(ppg_unit_pushes, push_machine_destroy); } } void wap_push_ppg_dispatch_event(WAPEvent *e) { gw_assert(run_status == running); gwlist_produce(ppg_queue, e); } /* * We cannot know port the client is using when it establish the connection. * However, we must link session creation with a pending push request. Only * data available is the client address, so we check it here. * Return non-NULL (pointer to the session machine found), if we have one. */ PPGSessionMachine *wap_push_ppg_have_push_session_for(WAPAddrTuple *tuple) { PPGSessionMachine *sm; gw_assert(tuple); sm = gwlist_search(ppg_machines, tuple->remote->address, session_has_addr); return sm; } /* * Now initiators are identified by their session id. Return non-NULL (pointer * to the session machine found), if we have one. This function are used after * wsp has indicated session establishment, giving us a session id. */ PPGSessionMachine *wap_push_ppg_have_push_session_for_sid(long sid) { PPGSessionMachine *sm; gw_assert(sid >= 0); sm = gwlist_search(ppg_machines, &sid, session_has_sid); return sm; } /***************************************************************************** * * INTERNAL FUNCTIONS * * Read general ppg configuration and configuration specific for users (to the * list 'users'). * Return 1 when an user ppg group is present, 0 otherwise (and panic * if we have not trusted ppg and no user groups). */ static int read_ppg_config(Cfg *cfg) { CfgGroup *grp; List *list; if (cfg == NULL) return USER_CONFIGURATION_NOT_ADDED; grp = cfg_get_single_group(cfg, octstr_imm("ppg")); if ((ppg_url = cfg_get(grp, octstr_imm("ppg-url"))) == NULL) ppg_url = octstr_imm("/wappush"); cfg_get_integer(&ppg_port, grp, octstr_imm("ppg-port")); cfg_get_integer(&number_of_pushes, grp, octstr_imm("concurrent-pushes")); cfg_get_bool(&trusted_pi, grp, octstr_imm("trusted-pi")); cfg_get_integer(&number_of_users, grp, octstr_imm("users")); ppg_deny_ip = cfg_get(grp, octstr_imm("ppg-deny-ip")); ppg_allow_ip = cfg_get(grp, octstr_imm("ppg-allow-ip")); if ((global_sender = cfg_get(grp, octstr_imm("global-sender"))) == NULL) global_sender = octstr_format("%s", "1234"); ppg_default_smsc = cfg_get(grp, octstr_imm("default-smsc")); ppg_dlr_url = cfg_get(grp, octstr_imm("default-dlr-url")); ppg_smsbox_id = cfg_get(grp, octstr_imm("ppg-smsbox-id")); if ((service_name = cfg_get(grp, octstr_imm("service-name"))) == NULL) service_name = octstr_format("%s", "ppg"); #ifdef HAVE_LIBSSL cfg_get_integer(&ppg_ssl_port, grp, octstr_imm("ppg-ssl-port")); ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file")); ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file")); if (ppg_ssl_port != NO_HTTPS_PORT) { if (ssl_server_cert_file == NULL || ssl_server_key_file == NULL) panic(0, "cannot continue without server cert and/or key files"); conn_use_global_server_certkey_file(ssl_server_cert_file, ssl_server_key_file); } octstr_destroy(ssl_server_cert_file); octstr_destroy(ssl_server_key_file); #endif /* If pi is trusted, ignore possible user groups. */ if (trusted_pi) { cfg_destroy(cfg); return USER_CONFIGURATION_ADDED; } /* But if it is not, we cannot continue without user groups.*/ if ((list = cfg_get_multi_group(cfg, octstr_imm("wap-push-user"))) == NULL) { panic(0, "No user group but ppg not trusted, stopping"); gwlist_destroy(list, NULL); cfg_destroy(cfg); return USER_CONFIGURATION_NOT_ADDED; } if (!wap_push_ppg_pushuser_list_add(list, number_of_pushes, number_of_users)) { panic(0, "unable to create users configuration list, exiting"); return USER_CONFIGURATION_NOT_ADDED; } cfg_destroy(cfg); return USER_CONFIGURATION_ADDED; } static int ip_allowed_by_ppg(Octstr *ip) { if (ip == NULL) return 0; if (trusted_pi) return 1; if (ppg_deny_ip == NULL && ppg_allow_ip == NULL) { warning(0, "Your ppg core configuration lacks allowed and denied" " ip lists"); return 1; } if (ppg_deny_ip) if (octstr_compare(ppg_deny_ip, octstr_imm("*.*.*.*")) == 0) { panic(0, "Your ppg core configuration deny all ips, exiting"); return 0; } if (ppg_allow_ip) if (octstr_compare(ppg_allow_ip, octstr_imm("*.*.*.*")) == 0) { warning(0, "Your ppg core configuration allow all ips"); return 1; } if (ppg_deny_ip) if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(ppg_deny_ip, ip, octstr_imm(";"), octstr_imm("."))) { error(0, "ip found from denied list"); return 0; } if (ppg_allow_ip) if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(ppg_allow_ip, ip, octstr_imm(";"), octstr_imm("."))) { debug("wap.push.ppg.pushuser", 0, "PPG: ip_allowed_by_ppg: ip found" " from allowed list"); return 1; } warning(0, "did not found ip from any of core lists, deny it"); return 0; } /* * Event handling functions */ static void ota_read_thread (void *arg) { WAPEvent *e; while (run_status == running && (e = gwlist_consume(ppg_queue)) != NULL) { handle_internal_event(e); } } /* * Pap event functions handle only copy pointers. They do not allocate memory. */ static PAPEvent *pap_event_create(Octstr *ip, Octstr *url, List *push_headers, Octstr *mime_content, List *cgivars, HTTPClient *client) { PAPEvent *p; p = gw_malloc(sizeof(PAPEvent)); p->ip = ip; p->url = url; p->push_headers = push_headers; p->mime_content = mime_content; p->cgivars = cgivars; p->client = client; return p; } static void pap_event_destroy(PAPEvent *p) { if (p == NULL) return; gw_free(p); } static void pap_event_destroy_item(void *p) { pap_event_destroy(p); } static void pap_event_unpack(PAPEvent *p, Octstr **ip, Octstr **url, List **push_headers, Octstr **mime_content, List **cgivars, HTTPClient **client) { *ip = p->ip; *url = p->url; *push_headers = p->push_headers; *mime_content = p->mime_content; *cgivars = p->cgivars; *client = p->client; } static void http_read_thread(void *arg) { PAPEvent *p; Octstr *ip; Octstr *url; List *push_headers; Octstr *mime_content; List *cgivars; HTTPClient *client; while (run_status == running) { client = http_accept_request(ppg_port, &ip, &url, &push_headers, &mime_content, &cgivars); if (client == NULL) break; p = pap_event_create(ip, url, push_headers, mime_content, cgivars, client); gwlist_produce(pap_queue, p); } } #ifdef HAVE_LIBSSL static void https_read_thread(void *arg) { PAPEvent *p; Octstr *ip; Octstr *url; List *push_headers; Octstr *mime_content; List *cgivars; HTTPClient *client; while (run_status == running) { client = http_accept_request(ppg_ssl_port, &ip, &url, &push_headers, &mime_content, &cgivars); if (client == NULL) break; p = pap_event_create(ip, url, push_headers, mime_content, cgivars, client); gwlist_produce(pap_queue, p); } } #endif /* * Authorization failure as such causes a challenge to the client (as required * by rfc 2617, chapter 1). * We store HTTPClient data structure corresponding a given push id, so that * we can send responses to the rigth address. * Pap chapter 14.4.1 states that we must return http status 202 after we have * accepted PAP message, even if it is unparsable. So only the non-existing * service error and some authorisation failures are handled at HTTP level. * When a phone number was unacceptable, we return a PAP level error, because * we cannot know this error before parsing the document. */ static void pap_request_thread(void *arg) { WAPEvent *ppg_event; PAPEvent *p; size_t push_len; Octstr *pap_content = NULL; Octstr *push_data = NULL; Octstr *rdf_content = NULL; Octstr *mime_content = NULL; Octstr *plos = NULL; /* a temporary variable*/ Octstr *boundary = NULL; Octstr *content_header = NULL; /* Content-Type MIME header */ Octstr *url = NULL; Octstr *ip = NULL; Octstr *not_found = NULL; Octstr *username = NULL; int compiler_status, http_status; List *push_headers, /* MIME headers themselves */ *content_headers, /* Headers from the content entity, see pap chapters 8.2, 13.1. Rfc 2045 grammar calls these MIME-part-hea- ders */ *cgivars; HTTPClient *client; Octstr *dlr_url; http_status = 0; url = ip = mime_content = username = NULL; while (run_status == running && (p = gwlist_consume(pap_queue)) != NULL) { http_status = HTTP_NOT_FOUND; pap_event_unpack(p, &ip, &url, &push_headers, &mime_content, &cgivars, &client); if (octstr_compare(url, ppg_url) != 0) { error(0, "Request <%s> from <%s>: service not found", octstr_get_cstr(url), octstr_get_cstr(ip)); debug("wap.push.ppg", 0, "your configuration uses %s", octstr_get_cstr(ppg_url)); not_found = octstr_imm("Service not specified\n"); http_send_reply(client, http_status, push_headers, not_found); goto ferror; } http_status = HTTP_UNAUTHORIZED; if (!ip_allowed_by_ppg(ip)) { error(0, "Request <%s> from <%s>: ip forbidden, closing the" " client", octstr_get_cstr(url), octstr_get_cstr(ip)); http_close_client(client); goto ferror; } if (!trusted_pi && user_configuration) { if (!wap_push_ppg_pushuser_authenticate(client, cgivars, ip, push_headers, &username)) { error(0, "Request <%s> from <%s>: authorisation failure", octstr_get_cstr(url), octstr_get_cstr(ip)); goto ferror; } } else { /* J�rg, this wont disappear again */ username = octstr_imm(""); } http_status = HTTP_ACCEPTED; info(0, "PPG: Accept request <%s> from <%s>", octstr_get_cstr(url), octstr_get_cstr(ip)); if (octstr_len(mime_content) == 0) { warning(0, "PPG: No MIME content received, the request" " unacceptable"); send_bad_message_response(&client, octstr_imm("No MIME content"), PAP_BAD_REQUEST, http_status); if (client == NULL) break; goto ferror; } if (!push_headers) { warning(0, "PPG: No push headers received , the request" " unacceptable"); send_bad_message_response(&client, octstr_imm("No push headers"), PAP_BAD_REQUEST, http_status); if (client == NULL) break; goto ferror; } octstr_destroy(ip); http_remove_hop_headers(push_headers); remove_mime_headers(&push_headers); remove_link_headers(&push_headers); if (!headers_acceptable(push_headers, &content_header)) { warning(0, "PPG: Unparsable push headers, the request" " unacceptable"); send_bad_message_response(&client, content_header, PAP_BAD_REQUEST, http_status); if (client == NULL) break; goto herror; } if (get_mime_boundary(push_headers, content_header, &boundary) == -1) { warning(0, "PPG: No MIME boundary, the request unacceptable"); send_bad_message_response(&client, content_header, PAP_BAD_REQUEST, http_status); if (client == NULL) break; goto berror; } gw_assert(mime_content); if (!mime_parse(boundary, mime_content, &pap_content, &push_data, &content_headers, &rdf_content)) { send_bad_message_response(&client, mime_content, PAP_BAD_REQUEST, http_status); if (client == NULL) break; warning(0, "PPG: unable to parse mime content, the request" " unacceptable"); goto clean; } else { debug("wap.push.ppg", 0, "PPG: http_read_thread: pap multipart" " accepted"); } push_len = octstr_len(push_data); http_header_remove_all(push_headers, "Content-Type"); http_append_headers(push_headers, content_headers); change_header_value(&push_headers, "Content-Length", octstr_get_cstr(plos = octstr_format("%d", push_len))); octstr_destroy(plos); octstr_destroy(content_header); http_destroy_headers(content_headers); ppg_event = NULL; if ((compiler_status = pap_compile(pap_content, &ppg_event)) == -2) { send_bad_message_response(&client, pap_content, PAP_BAD_REQUEST, http_status); if (client == NULL) break; warning(0, "PPG: pap control entity erroneous, the request" " unacceptable"); goto no_compile; } else if (compiler_status == -1) { send_bad_message_response(&client, pap_content, PAP_BAD_REQUEST, http_status); if (client == NULL) break; warning(0, "PPG: non implemented pap feature requested, the" " request unacceptable"); goto no_compile; } else { if (!dict_put_once(http_clients, ppg_event->u.Push_Message.pi_push_id, client)) { warning(0, "PPG: duplicate push id, the request unacceptable"); tell_fatal_error(&client, ppg_event, url, http_status, PAP_DUPLICATE_PUSH_ID); if (client == NULL) break; goto not_acceptable; } dict_put(urls, ppg_event->u.Push_Message.pi_push_id, url); if (is_phone_number(ppg_event->u.Push_Message.address_type)) { if (!trusted_pi && user_configuration && !wap_push_ppg_pushuser_client_phone_number_acceptable( username, ppg_event->u.Push_Message.address_value)) { tell_fatal_error(&client, ppg_event, url, http_status, PAP_FORBIDDEN); if (client == NULL) break; goto not_acceptable; } } debug("wap.push.ppg", 0, "PPG: http_read_thread: pap control" " entity compiled ok"); ppg_event->u.Push_Message.push_data = octstr_duplicate(push_data); ppg_event->u.Push_Message.smsc_id = set_smsc_id(push_headers, username, trusted_pi); dlr_url = set_dlr_url(push_headers, username, trusted_pi); ppg_event->u.Push_Message.dlr_url = dlr_url; ppg_event->u.Push_Message.dlr_mask = set_dlr_mask(push_headers, dlr_url); ppg_event->u.Push_Message.smsbox_id = set_smsbox_id(push_headers, username, trusted_pi); ppg_event->u.Push_Message.service_name = set_service_name(); remove_x_kannel_headers(&push_headers); ppg_event->u.Push_Message.push_headers = http_header_duplicate(push_headers); if (!handle_push_message(&client, ppg_event, http_status)) { if (client == NULL) break; goto no_transform; } } pap_event_destroy(p); http_destroy_headers(push_headers); http_destroy_cgiargs(cgivars); octstr_destroy(username); octstr_destroy(mime_content); octstr_destroy(pap_content); octstr_destroy(push_data); octstr_destroy(rdf_content); octstr_destroy(boundary); boundary = rdf_content = push_data = pap_content = mime_content = username = NULL; continue; no_transform: pap_event_destroy(p); http_destroy_headers(push_headers); http_destroy_cgiargs(cgivars); octstr_destroy(username); octstr_destroy(mime_content); octstr_destroy(pap_content); octstr_destroy(push_data); octstr_destroy(rdf_content); octstr_destroy(boundary); boundary = rdf_content = push_data = pap_content = mime_content = username = NULL; continue; no_compile: pap_event_destroy(p); http_destroy_headers(push_headers); http_destroy_cgiargs(cgivars); octstr_destroy(username); octstr_destroy(mime_content); octstr_destroy(push_data); octstr_destroy(rdf_content); octstr_destroy(boundary); octstr_destroy(url); url = boundary = rdf_content = push_data = mime_content = username = NULL; continue; not_acceptable: pap_event_destroy(p); http_destroy_headers(push_headers); http_destroy_cgiargs(cgivars); octstr_destroy(username); octstr_destroy(mime_content); octstr_destroy(pap_content); octstr_destroy(push_data); octstr_destroy(rdf_content); octstr_destroy(boundary); octstr_destroy(url); url = boundary = rdf_content = push_data = pap_content = mime_content = username = NULL; continue; clean: pap_event_destroy(p); http_destroy_headers(push_headers); http_destroy_headers(content_headers); octstr_destroy(pap_content); octstr_destroy(push_data); octstr_destroy(rdf_content); octstr_destroy(content_header); octstr_destroy(boundary); octstr_destroy(url); url = boundary = content_header = rdf_content = push_data = pap_content = NULL; continue; ferror: pap_event_destroy(p); http_destroy_headers(push_headers); http_destroy_cgiargs(cgivars); octstr_destroy(username); octstr_destroy(url); octstr_destroy(ip); octstr_destroy(mime_content); mime_content = ip = url = username = NULL; continue; herror: pap_event_destroy(p); http_destroy_headers(push_headers); http_destroy_cgiargs(cgivars); octstr_destroy(username); octstr_destroy(url); url = username = NULL; continue; berror: pap_event_destroy(p); http_destroy_headers(push_headers); http_destroy_cgiargs(cgivars); octstr_destroy(username); octstr_destroy(mime_content); octstr_destroy(content_header); octstr_destroy(boundary); octstr_destroy(url); url = boundary = content_header = mime_content = username = NULL; continue; } } /* * Operations needed when push proxy gateway receives a new push message are * defined in ppg Chapter 6. We create machines when error, too, because we * must then have a reportable message error state. * Output: current HTTP Client state. * Return 1 if the push content was OK, 0 if it was not transformable. */ static int handle_push_message(HTTPClient **c, WAPEvent *e, int status) { int cless, session_exists, bearer_supported, dummy, constraints, message_transformable, coriented_possible; long coded_appid_value; PPGPushMachine *pm; PPGSessionMachine *sm; WAPAddrTuple *tuple=NULL; Octstr *cliaddr=NULL; Octstr *type=NULL; List *push_headers; push_headers = e->u.Push_Message.push_headers; cliaddr = e->u.Push_Message.address_value; session_exists = 0; sm = session_find_using_pi_client_address(cliaddr); coded_appid_value = check_x_wap_application_id_header(&push_headers); cless = cless_accepted(e, sm); message_transformable = transform_message(&e, &tuple, push_headers, cless, &type); if (!sm && !cless) { sm = store_session_data(sm, e, tuple, &session_exists); } if (!store_push_data(&pm, sm, e, tuple, cless)) { warning(0, "PPG: handle_push_message: duplicate push id"); *c = response_push_message(pm, PAP_DUPLICATE_PUSH_ID, status); goto no_start; } if (!message_transformable) { pm = update_push_data_with_attribute(&sm, pm, PAP_TRANSFORMATION_FAILURE, PAP_UNDELIVERABLE1); if (tuple != NULL) *c = response_push_message(pm, PAP_TRANSFORMATION_FAILURE, status); else *c = response_push_message(pm, PAP_ADDRESS_ERROR, status); goto no_transformation; } dummy = 0; pm = update_push_data_with_attribute(&sm, pm, dummy, PAP_PENDING); bearer_supported = select_bearer_network(&e); if (!bearer_supported) { pm = update_push_data_with_attribute(&sm, pm, dummy, PAP_UNDELIVERABLE2); *c = response_push_message(pm, PAP_REQUIRED_BEARER_NOT_AVAILABLE, status); goto no_start; } if ((constraints = delivery_time_constraints(e, pm)) == TIME_EXPIRED) { pm = update_push_data_with_attribute(&sm, pm, PAP_FORBIDDEN, PAP_EXPIRED); *c = response_push_message(pm, PAP_FORBIDDEN, status); goto no_start; } /* * If time is to early for delivering the push message, we do not remove push * data. We response PI here, so that "accepted for processing" means "no * error messages to come". */ *c = response_push_message(pm, PAP_ACCEPTED_FOR_PROCESSING, status); info(0, "PPG: handle_push_message: push message accepted for processing"); if (constraints == TIME_TOO_EARLY) goto store_push; if (constraints == NO_CONSTRAINTS) { http_header_mark_transformation(pm->push_headers, pm->push_data, type); if (sm) sm = update_session_data_with_headers(sm, pm); if (!confirmation_requested(e)) { pm = deliver_unit_push(NOT_LAST, pm, sm, session_exists); goto unit_push_delivered; } if (session_exists) { deliver_confirmed_push(NOT_LAST, pm, sm); } else { coriented_possible = coriented_deliverable(coded_appid_value); http_header_remove_all(e->u.Push_Message.push_headers, "Content-Type"); if (coriented_possible) { create_session(e, pm); } else { warning(0, "PPG: handle_push_message: wrong app id for confirmed" " push session creation"); *c = response_push_message(pm, PAP_BAD_REQUEST, status); } } } wap_addr_tuple_destroy(tuple); octstr_destroy(type); wap_event_destroy(e); return 1; unit_push_delivered: wap_addr_tuple_destroy(tuple); remove_push_data(sm, pm, cless); octstr_destroy(type); wap_event_destroy(e); return 1; store_push: wap_addr_tuple_destroy(tuple); octstr_destroy(type); wap_event_destroy(e); return 1; no_transformation: wap_addr_tuple_destroy(tuple); remove_push_data(sm, pm, cless); if (sm) remove_pushless_session(sm); wap_event_destroy(e); return 0; no_start: wap_addr_tuple_destroy(tuple); octstr_destroy(type); remove_push_data(sm, pm, cless); if (sm) remove_pushless_session(sm); wap_event_destroy(e); return 1; } /* * These events come from OTA layer */ static void handle_internal_event(WAPEvent *e) { long sid, pid, reason, port; int http_status; PPGPushMachine *pm; PPGSessionMachine *sm; WAPAddrTuple *tuple; List *caps; http_status = HTTP_OK; switch (e->type) { /* * Pap, Chapter 11.1.3 states that if client is incapable, we should abort the * push and inform PI. We do this here. * In addition, we store session id used as an alias for address tuple and do * all pushes pending for this initiator (or abort them). */ case Pom_Connect_Ind: debug("wap.push.ppg", 0, "PPG: handle_internal_event: connect" " indication from OTA"); sid = e->u.Pom_Connect_Ind.session_id; tuple = e->u.Pom_Connect_Ind.addr_tuple; port = tuple->remote->port; caps = e->u.Pom_Connect_Ind.requested_capabilities; sm = wap_push_ppg_have_push_session_for(tuple); sm = update_session_data(sm, sid, port, caps); if (!response_push_connection(e, sm)) { pm = abort_delivery(sm, http_status); wap_event_destroy(e); return; } /* * hard-coded until we have bearer control implemented */ deliver_pending_pushes(sm, NOT_LAST); wap_event_destroy(e); break; case Pom_Disconnect_Ind: debug("wap.push.ppg", 0, "PPG: handle_internal_event: disconnect" " indication from OTA"); sm = wap_push_ppg_have_push_session_for_sid( e->u.Pom_Disconnect_Ind.session_handle); remove_session_data(sm, http_status); wap_event_destroy(e); break; /* * Only the client can close a session. So we leave session open, even when * there are no active pushes. Note that we do not store PAP attribute very * long time. Point is that result notification message, if asked, will rep- * ort this fact to PI, after which there is no need to store it any more. */ case Po_ConfirmedPush_Cnf: debug("wap.push.ppg", 0, "PPG: handle_internal_event: push" " confirmation from OTA"); sid = e->u.Po_ConfirmedPush_Cnf.session_handle; pid = e->u.Po_ConfirmedPush_Cnf.server_push_id; sm = wap_push_ppg_have_push_session_for_sid(sid); pm = find_ppg_push_machine_using_pid(sm, pid); pm = update_push_data_with_attribute(&sm, pm, PAP_CONFIRMED, PAP_DELIVERED2); wap_event_destroy(e); remove_push_data(sm, pm, 0); break; /* * Again, PAP attribute will be reported to PI by using result notification. */ case Po_PushAbort_Ind: debug("wap.push.ppg", 0, "PPG: handle_internal_event: abort" " indication from OTA"); sid = e->u.Po_PushAbort_Ind.session_handle; pid = e->u.Po_PushAbort_Ind.push_id; sm = wap_push_ppg_have_push_session_for_sid(sid); pm = find_ppg_push_machine_using_pid(sm, pid); session_machine_assert(sm); push_machine_assert(pm); reason = e->u.Po_PushAbort_Ind.reason; pm = update_push_data_with_attribute(&sm, pm, reason, PAP_ABORTED); remove_session_data(sm, http_status); wap_event_destroy(e); break; /* * FIXME TRU: Add timeout (a mandatory feature!) */ default: debug("wap.ppg", 0, "PPG: handle_internal_event: an unhandled event"); wap_event_dump(e); wap_event_destroy(e); break; } } /* * Functions related to various ppg machine types. * * We do not set session id here: it is told to us by wsp. */ static PPGSessionMachine *session_machine_create(WAPAddrTuple *tuple, WAPEvent *e) { PPGSessionMachine *m; gw_assert(e->type == Push_Message); m = gw_malloc(sizeof(PPGSessionMachine)); #define INTEGER(name) m->name = 0; #define OCTSTR(name) m->name = NULL; #define ADDRTUPLE(name) m->name = NULL; #define PUSHMACHINES(name) m->name = gwlist_create(); #define CAPABILITIES(name) m->name = NULL; #define MACHINE(fields) fields #include "wap_ppg_session_machine.def" m->pi_client_address = octstr_duplicate(e->u.Push_Message.address_value); m->addr_tuple = wap_addr_tuple_duplicate(tuple); m->assumed_capabilities = wsp_cap_duplicate_list(e->u.Push_Message.pi_capabilities); m->preferconfirmed_value = PAP_CONFIRMED; gwlist_append(ppg_machines, m); debug("wap.push.ppg", 0, "PPG: Created PPGSessionMachine %ld", m->session_id); return m; } static void session_machine_destroy(void *p) { PPGSessionMachine *sm; if (p == NULL) return; sm = p; debug("wap.push.ppg", 0, "PPG: destroying PPGSEssionMachine %ld", sm->session_id); #define OCTSTR(name) octstr_destroy(sm->name); #define ADDRTUPLE(name) wap_addr_tuple_destroy(sm->name); #define INTEGER(name) sm->name = 0; #define PUSHMACHINES(name) push_machines_list_destroy(sm->name); #define CAPABILITIES(name) wsp_cap_destroy_list(sm->name); #define MACHINE(fields) fields #include "wap_ppg_session_machine.def" gw_free(sm); } /* * FIXME: PPG's trust policy (flags authenticated and trusted). * We return pointer to the created push machine and push id it uses. */ static PPGPushMachine *push_machine_create(WAPEvent *e, WAPAddrTuple *tuple) { PPGPushMachine *m; m = gw_malloc(sizeof(PPGPushMachine)); #define INTEGER(name) m->name = 0; #define OCTSTR(name) m->name = NULL; #define OPTIONAL_OCTSTR(name) m->name = NULL; #define ADDRTUPLE(name) m->name = NULL; #define CAPABILITIES m->name = NULL; #define HTTPHEADER(name) m->name = NULL; #define MACHINE(fields) fields #include "wap_ppg_push_machine.def" m->addr_tuple = wap_addr_tuple_duplicate(tuple); m->pi_push_id = octstr_duplicate(e->u.Push_Message.pi_push_id); m->push_id = counter_increase(push_id_counter); m->delivery_method = e->u.Push_Message.delivery_method; m->deliver_after_timestamp = octstr_duplicate(e->u.Push_Message.deliver_after_timestamp); m->priority = e->u.Push_Message.priority; m->push_headers = http_header_duplicate(e->u.Push_Message.push_headers); m->push_data = octstr_duplicate(e->u.Push_Message.push_data); m->address_type = e->u.Push_Message.address_type; if (e->u.Push_Message.smsc_id != NULL) m->smsc_id = octstr_duplicate(e->u.Push_Message.smsc_id); else m->smsc_id = NULL; if (e->u.Push_Message.dlr_url != NULL) m->dlr_url = octstr_duplicate(e->u.Push_Message.dlr_url); else m->dlr_url = NULL; m->dlr_mask = e->u.Push_Message.dlr_mask; if (e->u.Push_Message.smsbox_id != NULL) m->smsbox_id = octstr_duplicate(e->u.Push_Message.smsbox_id); else m->smsbox_id = NULL; m->service_name = octstr_duplicate(e->u.Push_Message.service_name); m->progress_notes_requested = e->u.Push_Message.progress_notes_requested; if (e->u.Push_Message.progress_notes_requested) m->ppg_notify_requested_to = octstr_duplicate(e->u.Push_Message.ppg_notify_requested_to); debug("wap.push.ppg", 0, "PPG: push machine %ld created", m->push_id); return m; } /* * Contrary to the normal Kannel style, we do not remove from a list here. * That is because we now have two different push lists. */ static void push_machine_destroy(void *p) { PPGPushMachine *pm; if (p == NULL) return; pm = p; debug("wap.push.ppg", 0, "PPG: destroying push machine %ld", pm->push_id); #define OCTSTR(name) octstr_destroy(pm->name); #define OPTIONAL_OCTSTR(name) octstr_destroy(pm->name); #define INTEGER(name) #define ADDRTUPLE(name) wap_addr_tuple_destroy(pm->name); #define CAPABILITIES(name) wap_cap_destroy_list(pm->name); #define HTTPHEADER(name) http_destroy_headers(pm->name); #define MACHINE(fields) fields #include "wap_ppg_push_machine.def" gw_free(p); } static void push_machines_list_destroy(List *machines) { if (machines == NULL) return; gwlist_destroy(machines, push_machine_destroy); } static int session_has_addr(void *a, void *b) { Octstr *cliaddr; PPGSessionMachine *sm; cliaddr = b; sm = a; return octstr_compare(sm->addr_tuple->remote->address, cliaddr) == 0; } static int session_has_sid(void *a, void *b) { PPGSessionMachine *sm; long *sid; sid = b; sm = a; return *sid == sm->session_id; } /* * Here session machine address tuples have connection-oriented ports, because * these are used when establishing the connection an doing pushes. But session * creation request must be to the the connectionless push port of the client. * So we change ports here. */ static void create_session(WAPEvent *e, PPGPushMachine *pm) { WAPEvent *ota_event; List *push_headers; Octstr *smsc_id; Octstr *dlr_url; Octstr *smsbox_id; Octstr *service_name; gw_assert(e->type == Push_Message); push_machine_assert(pm); push_headers = http_header_duplicate(e->u.Push_Message.push_headers); smsc_id = octstr_duplicate(e->u.Push_Message.smsc_id); dlr_url = octstr_duplicate(e->u.Push_Message.dlr_url); smsbox_id = octstr_duplicate(e->u.Push_Message.smsbox_id); service_name = octstr_duplicate(e->u.Push_Message.service_name); ota_event = wap_event_create(Pom_SessionRequest_Req); ota_event->u.Pom_SessionRequest_Req.addr_tuple = addr_tuple_change_cliport(pm->addr_tuple, CONNECTIONLESS_PUSH_CLIPORT); ota_event->u.Pom_SessionRequest_Req.push_headers = push_headers; ota_event->u.Pom_SessionRequest_Req.push_id = pm->push_id; ota_event->u.Pom_SessionRequest_Req.address_type = pm->address_type; if (smsc_id != NULL) ota_event->u.Pom_SessionRequest_Req.smsc_id = smsc_id; else ota_event->u.Pom_SessionRequest_Req.smsc_id = NULL; if (dlr_url != NULL) ota_event->u.Pom_SessionRequest_Req.dlr_url = dlr_url; else ota_event->u.Pom_SessionRequest_Req.dlr_url = NULL; ota_event->u.Pom_SessionRequest_Req.dlr_mask = e->u.Push_Message.dlr_mask; if (smsbox_id != NULL) ota_event->u.Pom_SessionRequest_Req.smsbox_id = smsbox_id; else ota_event->u.Pom_SessionRequest_Req.smsbox_id = NULL; ota_event->u.Pom_SessionRequest_Req.service_name = service_name; dispatch_to_ota(ota_event); } /* * We store data to push machine, because it is possible that we do not have * a session when push request happens. */ static void request_confirmed_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm) { WAPEvent *ota_event; List *push_headers; gw_assert(last == 0 || last == 1); push_machine_assert(pm); session_machine_assert(sm); push_headers = http_header_duplicate(pm->push_headers); ota_event = wap_event_create(Po_ConfirmedPush_Req); ota_event->u.Po_ConfirmedPush_Req.server_push_id = pm->push_id; ota_event->u.Po_ConfirmedPush_Req.push_headers = push_headers; ota_event->u.Po_ConfirmedPush_Req.authenticated = pm->authenticated; ota_event->u.Po_ConfirmedPush_Req.trusted = pm->trusted; ota_event->u.Po_ConfirmedPush_Req.last = last; if (pm->push_data != NULL) ota_event->u.Po_ConfirmedPush_Req.push_body = octstr_duplicate(pm->push_data); else ota_event->u.Po_ConfirmedPush_Req.push_body = NULL; ota_event->u.Po_ConfirmedPush_Req.session_handle = sm->session_id; debug("wap.push.ota", 0, "PPG: confirmed push request to OTA"); dispatch_to_ota(ota_event); } /* * There is to types of unit push requests: requesting ip services and sms * services. Address type tells the difference. */ static void request_unit_push(long last, PPGPushMachine *pm) { WAPEvent *ota_event; List *push_headers; gw_assert(last == 0 || last == 1); push_machine_assert(pm); push_headers = http_header_duplicate(pm->push_headers); ota_event = wap_event_create(Po_Unit_Push_Req); ota_event->u.Po_Unit_Push_Req.addr_tuple = wap_addr_tuple_duplicate(pm->addr_tuple); ota_event->u.Po_Unit_Push_Req.push_id = pm->push_id; ota_event->u.Po_Unit_Push_Req.push_headers = push_headers; ota_event->u.Po_Unit_Push_Req.authenticated = pm->authenticated; ota_event->u.Po_Unit_Push_Req.trusted = pm->trusted; ota_event->u.Po_Unit_Push_Req.last = last; ota_event->u.Po_Unit_Push_Req.address_type = pm->address_type; if (pm->smsc_id != NULL) ota_event->u.Po_Unit_Push_Req.smsc_id = octstr_duplicate(pm->smsc_id); else ota_event->u.Po_Unit_Push_Req.smsc_id = NULL; if (pm->dlr_url != NULL) ota_event->u.Po_Unit_Push_Req.dlr_url = octstr_duplicate(pm->dlr_url); else ota_event->u.Po_Unit_Push_Req.dlr_url = NULL; ota_event->u.Po_Unit_Push_Req.dlr_mask = pm->dlr_mask; if (pm->smsbox_id != NULL) ota_event->u.Po_Unit_Push_Req.smsbox_id = octstr_duplicate(pm->smsbox_id); else ota_event->u.Po_Unit_Push_Req.smsbox_id = NULL; if (pm->service_name != NULL) ota_event->u.Po_Unit_Push_Req.service_name = octstr_duplicate(pm->service_name); ota_event->u.Po_Unit_Push_Req.push_body = octstr_duplicate(pm->push_data); dispatch_to_ota(ota_event); debug("wap.push.ppg", 0, "PPG: OTA request for unit push"); } static void request_push(long last, PPGPushMachine *pm) { WAPEvent *ota_event; List *push_headers; gw_assert(last == 0 || last == 1); push_machine_assert(pm); push_headers = http_header_duplicate(pm->push_headers); ota_event = wap_event_create(Po_Push_Req); ota_event->u.Po_Push_Req.push_headers = push_headers; ota_event->u.Po_Push_Req.authenticated = pm->authenticated; ota_event->u.Po_Push_Req.trusted = pm->trusted; ota_event->u.Po_Push_Req.last = last; if (pm->push_data != NULL) ota_event->u.Po_Push_Req.push_body = octstr_duplicate(pm->push_data); else ota_event->u.Po_Push_Req.push_body = NULL; ota_event->u.Po_Push_Req.session_handle = pm->session_id; debug("wap.push.ppg", 0, "PPG: OTA request for push"); dispatch_to_ota(ota_event); } /* * According to pap, Chapter 11, capabilities can be * * a) queried by PI * b) told to PI when a client is subscribing * c) assumed * * In case c) we got capabilities from third part of the push message (other * cases PI knows what it is doing), and we check is the client capable to * handle the message. * Requested capabilities are client capabilities, assumed capabilities are * PI capabilities. If there is no assumed capabilities, PI knows client capab- * ilities by method a) or method b). * Returns 1, if the client is capable, 0 when it is not. */ static int response_push_connection(WAPEvent *e, PPGSessionMachine *sm) { WAPEvent *appl_event; gw_assert(e->type == Pom_Connect_Ind); if (sm->assumed_capabilities != NULL && check_capabilities( e->u.Pom_Connect_Ind.requested_capabilities, sm->assumed_capabilities) == 0) return 0; appl_event = wap_event_create(Pom_Connect_Res); appl_event->u.Pom_Connect_Res.negotiated_capabilities = wsp_cap_duplicate_list(e->u.Pom_Connect_Ind.requested_capabilities); appl_event->u.Pom_Connect_Res.session_id = e->u.Pom_Connect_Ind.session_id; dispatch_to_appl(appl_event); return 1; } /* * Push response, from pap, Chapter 9.3. * Inputs error code, in PAP format. * Return the current value of HTTPClient. */ static HTTPClient *response_push_message(PPGPushMachine *pm, long code, int status) { WAPEvent *e; HTTPClient *c; push_machine_assert(pm); e = wap_event_create(Push_Response); e->u.Push_Response.pi_push_id = octstr_duplicate(pm->pi_push_id); e->u.Push_Response.sender_name = tell_ppg_name(); e->u.Push_Response.reply_time = set_time(); e->u.Push_Response.code = code; e->u.Push_Response.desc = describe_code(code); c = send_push_response(e, status); return c; } static int check_capabilities(List *requested, List *assumed) { int is_capable; is_capable = 1; return is_capable; } /* * Time of creation of the response (pap, chapter 9.3). We convert UNIX time * to ISO8601, it is, YYYY-MM-DDThh:mm:ssZ, T and Z being literal strings (we * use gw_gmtime to turn UNIX time to broken time). */ static Octstr *set_time(void) { Octstr *current_time; struct tm now; now = gw_gmtime(time(NULL)); 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; } static void session_machine_assert(PPGSessionMachine *sm) { gw_assert(sm); gw_assert(sm->session_id >= 0); gw_assert(sm->addr_tuple); gw_assert(sm->pi_client_address); } static void push_machine_assert(PPGPushMachine *pm) { gw_assert(pm); gw_assert(pm->pi_push_id); gw_assert(pm->push_id >= 0); gw_assert(pm->session_id >= 0); gw_assert(pm->addr_tuple); gw_assert(pm->trusted == 1 || pm->trusted == 0); gw_assert(pm->authenticated == 1 || pm->authenticated == 0); } /* * Message transformations performed by PPG are defined in ppg, 6.1.2.1. Ppg, * chapter 6.1.1, states that we MUST reject a push having an erroneous PAP * push message element. So we must validate it even when we do not compile * it. * If message content was not si or sl, we pass it without modifications. * We do not do any (formally optional, but phones may disagree) header * conversions to the binary format here, these are responsibility of our OTA * module (gw/wap_push_ota.c). * FIXME: Remove all headers which default values are known to the client. * * Return * a) message, either transformed or not (if there is no-transform cache * directive, wml code is erroneous or content was not si or sl.) * b) The transformed gw address. Use here global-sender, when the bearer * is SMS (some SMS centers would require this). * c) the transformed message content type * * Returned flag tells was the transformation (if any) successful or not. Error * flag is returned when there is no push headers, there is no Content-Type header * or push content does not compile. We should have checked existence of push * headers earlier, but let us be careful. */ static int transform_message(WAPEvent **e, WAPAddrTuple **tuple, List *push_headers, int cless_accepted, Octstr **type) { int message_deliverable; struct content content; Octstr *cliaddr; long cliport, servport, address_type; gw_assert((**e).type == Push_Message); if ((**e).u.Push_Message.push_headers == NULL) goto herror; cliaddr = (**e).u.Push_Message.address_value; push_headers = (**e).u.Push_Message.push_headers; if (!cless_accepted) { cliport = CONNECTED_CLIPORT; servport = CONNECTED_SERVPORT; } else { cliport = CONNECTIONLESS_PUSH_CLIPORT; servport = CONNECTIONLESS_SERVPORT; } address_type = (**e).u.Push_Message.address_type; *tuple = set_addr_tuple(cliaddr, cliport, servport, address_type, push_headers); if (!content_transformable(push_headers)) goto no_transform; content.charset = NULL; content.type = NULL; content.body = (**e).u.Push_Message.push_data; if (content.body == NULL) goto no_transform; content.type = http_header_find_first(push_headers, "Content-Transfer-Encoding"); if (content.type) { octstr_strip_blanks(content.type); debug("wap.push.ppg", 0, "PPG: Content-Transfer-Encoding is \"%s\"", octstr_get_cstr (content.type)); message_deliverable = pap_get_content(&content); if (message_deliverable) { change_header_value(&push_headers, "Content-Transfer-Encoding", "binary"); } else { goto error; } } octstr_destroy(content.type); http_header_get_content_type(push_headers, &content.type, &content.charset); message_deliverable = pap_convert_content(&content); if (content.type == NULL) goto error; if (message_deliverable) { *type = content.type; } else { goto error; } (**e).u.Push_Message.push_data = content.body; octstr_destroy(content.charset); debug("wap.push.ppg", 0, "PPG: transform_message: push message content" " and headers valid"); return 1; herror: warning(0, "PPG: transform_message: no push headers, cannot accept"); octstr_destroy(content.type); return 0; error: warning(0, "PPG: transform_message: push content erroneous, cannot" " accept"); octstr_destroy(content.type); octstr_destroy(content.charset); return 0; no_transform: warning(0, "PPG: transform_message: push content non transformable"); return 1; } /* * Transform X-WAP-Application headers as per ppg 6.1.2.1. Note that missing * header means that wml.ua is assumed. * Return coded value (starting with 0), when the id was not wml.ua * -1, when id was wml.ua (or no application id was present) * -2, when error */ static long check_x_wap_application_id_header(List **push_headers) { Octstr *appid_content; long coded_value; Octstr *cos; if (*push_headers == NULL) return -2; appid_content = http_header_find_first(*push_headers, "X-WAP-Application-Id"); if (appid_content == NULL) { octstr_destroy(appid_content); return -1; } if ((coded_value = parse_appid_header(&appid_content)) < 0) { octstr_destroy(appid_content); return -2; } if (coded_value == 2) { octstr_destroy(appid_content); http_header_remove_all(*push_headers, "X-WAP-Application-Id"); return -1; } cos = octstr_format("%ld", coded_value); http_header_remove_all(*push_headers, "X-WAP-Application-Id"); http_header_add(*push_headers, "X-WAP-Application-Id", octstr_get_cstr(cos)); octstr_destroy(appid_content); octstr_destroy(cos); return coded_value; } /* * Check do we have a no-transform cache directive amongst the headers. */ static int content_transformable(List *push_headers) { List *cache_directives; long i; Octstr *header_name, *header_value; gw_assert(push_headers); cache_directives = http_header_find_all(push_headers, "Cache-Control"); if (gwlist_len(cache_directives) == 0) { http_destroy_headers(cache_directives); return 1; } i = 0; while (i < gwlist_len(cache_directives)) { http_header_get(cache_directives, i, &header_name, &header_value); if (octstr_compare(header_value, octstr_imm("no-transform")) == 0) { http_destroy_headers(cache_directives); octstr_destroy(header_name); octstr_destroy(header_value); return 0; } ++i; } http_destroy_headers(cache_directives); octstr_destroy(header_name); octstr_destroy(header_value); return 1; } /* * Convert push content to compact binary format (this can be wmlc, sic, slc * or coc). Current status wml, sl and si compiled, others passed. */ static Octstr *convert_wml_to_wmlc(struct content *content) { Octstr *wmlc; if (wml_compile(content->body, content->charset, &wmlc, NULL) == 0) return wmlc; warning(0, "PPG: wml compilation failed"); return NULL; } static Octstr *convert_si_to_sic(struct content *content) { Octstr *sic; if (si_compile(content->body, content->charset, &sic) == 0) return sic; warning(0, "PPG: si compilation failed"); return NULL; } static Octstr *convert_sl_to_slc(struct content *content) { Octstr *slc; if (sl_compile(content->body, content->charset, &slc) == 0) return slc; warning(0, "PPG: sl compilation failed"); return NULL; } static Octstr *extract_base64(struct content *content) { Octstr *orig = octstr_duplicate(content->body); octstr_base64_to_binary(orig); return orig; } static struct { char *type; char *result_type; Octstr *(*convert) (struct content *); } converters[] = { { "text/vnd.wap.wml", "application/vnd.wap.wmlc", convert_wml_to_wmlc }, { "text/vnd.wap.si", "application/vnd.wap.sic", convert_si_to_sic }, { "text/vnd.wap.sl", "application/vnd.wap.slc", convert_sl_to_slc} }; #define NUM_CONVERTERS ((long) (sizeof(converters) / sizeof(converters[0]))) static struct { char *transfer_encoding; Octstr *(*extract) (struct content *); } extractors[] = { { "base64", extract_base64 } }; #define NUM_EXTRACTORS ((long) (sizeof(extractors) / sizeof(extractors[0]))) /* * Compile wap defined contents, accept others without modifications. Push * message 6.3 states that push content can be any MIME accepted content type. */ static int pap_convert_content(struct content *content) { long i; Octstr *new_body; for (i = 0; i < NUM_CONVERTERS; i++) { if (octstr_compare(content->type, octstr_imm(converters[i].type)) == 0) { new_body = converters[i].convert(content); if (new_body == NULL) return 0; octstr_destroy(content->body); content->body = new_body; octstr_destroy(content->type); content->type = octstr_create(converters[i].result_type); return 1; } } return 1; } /* * MIME specifies a number of content transfer encodings. * This function tries to get the original version of the * content. */ static int pap_get_content(struct content *content) { long i; Octstr *new_body; for (i = 0; i < NUM_EXTRACTORS; i++) { if (octstr_case_compare(content->type, octstr_imm(extractors[i].transfer_encoding)) == 0) { new_body = extractors[i].extract(content); if (new_body == NULL) return 0; octstr_destroy(content->body); content->body = new_body; octstr_destroy(content->type); content->type = NULL; return 1; } } return 1; } /* * Bearer and network types are defined in wdp, Appendix C. Any means any net- * work supporting IPv4 or IPv6. */ static char *bearers[] = { "Any", "SMS", "CSD", "GPRS", "Packet Data", "CDPD" }; #define NUMBER_OF_BEARERS sizeof(bearers)/sizeof(bearers[0]) static char *networks[] = { "Any", "GSM", "IS-95 CDMA", "ANSI-136", "AMPS", "PDC", "IDEN", "PHS", "TETRA" }; #define NUMBER_OF_NETWORKS sizeof(networks)/sizeof(networks[0]) /* * We support networks using IP as a bearer and GSM using SMS as bearer, so we * must reject others. Default bearer is IP, it is (currently) not-SMS. After * the check we change meaning of the bearer_required-attribute: it will tell * do we use WAP over SMS. */ int select_bearer_network(WAPEvent **e) { Octstr *bearer, *network; int bearer_required, network_required; size_t i, j; gw_assert((**e).type == Push_Message); bearer_required = (**e).u.Push_Message.bearer_required; network_required = (**e).u.Push_Message.network_required; bearer = octstr_imm("Any"); network = octstr_imm("Any"); if (!bearer_required || !network_required) return 1; if (bearer_required) bearer = (**e).u.Push_Message.bearer; if (network_required) network = (**e).u.Push_Message.network; for (i = 0; i < NUMBER_OF_NETWORKS ; ++i) { if (octstr_case_compare(network, octstr_imm(networks[i])) == 0) break; } for (j = 0; j < NUMBER_OF_BEARERS ; ++j) { if (octstr_case_compare(bearer, octstr_imm(bearers[j])) == 0) break; } if (i == NUMBER_OF_NETWORKS || j == NUMBER_OF_BEARERS) return 0; return 1; } static int session_has_pi_client_address(void *a, void *b) { Octstr *caddr; PPGSessionMachine *sm; caddr = b; sm = a; return octstr_compare(caddr, sm->pi_client_address) == 0; } /* * PI client address is composed of a client specifier and a PPG specifier (see * ppg, chapter 7). So it is equivalent with gw address quadruplet. */ PPGSessionMachine *session_find_using_pi_client_address(Octstr *caddr) { PPGSessionMachine *sm; sm = gwlist_search(ppg_machines, caddr, session_has_pi_client_address); return sm; } /* * Give PPG a human readable name. */ static Octstr *tell_ppg_name(void) { return octstr_format("%S; WAP/1.3 (" GW_NAME "/%s)", get_official_name(), GW_VERSION); } /* * Delivery time constraints are a) deliver before and b) deliver after. It is * possible that service required is after some time and before other. So we * test first condition a). Note that 'now' satisfy both constraints. * Returns: 0 delivery time expired * 1 too early to send the message * 2 no constraints */ static int delivery_time_constraints(WAPEvent *e, PPGPushMachine *pm) { Octstr *before, *after; struct tm now; gw_assert(e->type == Push_Message); before = e->u.Push_Message.deliver_before_timestamp; after = pm->deliver_after_timestamp; now = gw_gmtime(time(NULL)); if (!deliver_before_test_cleared(before, now)) { info(0, "PPG: delivery deadline expired, dropping the push message"); return 0; } if (!deliver_after_test_cleared(after, now)) { debug("wap.push.ppg", 0, "PPG: too early to push the message," " waiting"); return 1; } return 2; } /* * Give verbose description of the result code. Conversion table for descrip- * tion. */ struct description_t { long reason; char *description; }; typedef struct description_t description_t; static description_t pap_desc[] = { { PAP_OK, "The request succeeded"}, { PAP_ACCEPTED_FOR_PROCESSING, "The request has been accepted for" " processing"}, { PAP_BAD_REQUEST, "Not understood due to malformed syntax"}, { PAP_FORBIDDEN, "Request was refused"}, { PAP_ADDRESS_ERROR, "The client specified not recognised"}, { PAP_CAPABILITIES_MISMATCH, "Capabilities assumed by PI were not" " acceptable for the client specified"}, { PAP_DUPLICATE_PUSH_ID, "Push id supplied was not unique"}, { PAP_INTERNAL_SERVER_ERROR, "Server could not fulfill the request due" " to an internal error"}, { PAP_TRANSFORMATION_FAILURE, "PPG was unable to perform a transformation" " of the message"}, { PAP_REQUIRED_BEARER_NOT_AVAILABLE, "Required bearer not available"}, { PAP_SERVICE_FAILURE, "The service failed. The client may re-attempt" " the operation"}, { PAP_CLIENT_ABORTED, "The client aborted the operation. No reason given"}, { WSP_ABORT_USERREQ, "Wsp requested abort"}, { WSP_ABORT_USERRFS, "Wsp refused push message. Do not try again"}, { WSP_ABORT_USERPND, "Push message cannot be delivered to intended" " destination by the wsp"}, { WSP_ABORT_USERDCR, "Push message discarded due to resource shortage in" " wsp"}, { WSP_ABORT_USERDCU, "Content type of the push message cannot be" " processed by the wsp"} }; static size_t desc_tab_size = sizeof(pap_desc) / sizeof(pap_desc[0]); static Octstr *describe_code(long code) { Octstr *desc; size_t i; for (i = 0; i < desc_tab_size; i++) { if (pap_desc[i].reason == code) { desc = octstr_create(pap_desc[i].description); return desc; } } return octstr_imm("unknown PAP code"); } /* * Remove push data from the list of connectionless pushes, if cless is true, * otherwise from the list of pushes belonging to session machine sm. */ static void remove_push_data(PPGSessionMachine *sm, PPGPushMachine *pm, int cless) { push_machine_assert(pm); if (cless) { gwlist_delete_equal(ppg_unit_pushes, pm); } else { session_machine_assert(sm); gwlist_delete_equal(sm->push_machines, pm); } push_machine_destroy(pm); } /* * If cless is true, store push to the list connectionless pushes, otherwise * in the push list of the session machine sm. * We must create a push machine even when an error occurred, because this is * used for storing the relevant pap error state and other data for this push. * There should not be any duplicate push ids here (this is tested by http_ * read_thread), but let us be carefull. * Return a pointer the push machine newly created and a flag telling was the * push id duplicate. */ static int store_push_data(PPGPushMachine **pm, PPGSessionMachine *sm, WAPEvent *e, WAPAddrTuple *tuple, int cless) { Octstr *pi_push_id; int duplicate_push_id; gw_assert(e->type == Push_Message); pi_push_id = e->u.Push_Message.pi_push_id; duplicate_push_id = 0; if (((!cless) && (find_ppg_push_machine_using_pi_push_id(sm, pi_push_id) != NULL)) || ((cless) && (find_unit_ppg_push_machine_using_pi_push_id(pi_push_id) != NULL))) duplicate_push_id = 1; *pm = push_machine_create(e, tuple); if (duplicate_push_id) return !duplicate_push_id; if (!cless) { gwlist_append(sm->push_machines, *pm); debug("wap.push.ppg", 0, "PPG: store_push_data: push machine %ld" " appended to push list of sm machine %ld", (*pm)->push_id, sm->session_id); } else { gwlist_append(ppg_unit_pushes, *pm); debug("wap.push.ppg", 0, "PPG: store_push_data: push machine %ld" " appended to unit push list", (*pm)->push_id); } return !duplicate_push_id; } /* * Deliver confirmed push. Note that if push is confirmed, PAP attribute is up- * dated only after an additional event (confirmation, abort or time-out). */ static void deliver_confirmed_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm) { request_confirmed_push(last, pm, sm); } /* * Ppg, chapter 6.1.2.2 , subchapter delivery, says that if push is unconform- * ed, we can use either Po-Unit-Push.req or Po-Push.req primitive. We use Po- * Push.req, if have an already established session (other words, sm != NULL). * In addition, update PAP attribute. Return pointer to the updated push mach- * ine. */ static PPGPushMachine *deliver_unit_push(long last, PPGPushMachine *pm, PPGSessionMachine *sm, int session_exists) { push_machine_assert(pm); if (!session_exists) request_unit_push(last, pm); else request_push(last, pm); pm = update_push_data_with_attribute(&sm, pm, PAP_UNCONFIRMED, PAP_DELIVERED1); info(0, "PPG: unconfirmed push delivered to OTA"); return pm; } /* * Deliver all pushes queued by session machine sm (it is, make a relevant OTA * request). Update PAP attribute, if push is unconfirmed. */ static void deliver_pending_pushes(PPGSessionMachine *sm, int last) { PPGPushMachine *pm; long i; session_machine_assert(sm); gw_assert(gwlist_len(sm->push_machines) > 0); i = 0; while (i < gwlist_len(sm->push_machines)) { pm = gwlist_get(sm->push_machines, i); push_machine_assert(pm); if (pm->delivery_method == PAP_UNCONFIRMED) { request_push(last, pm); pm = update_push_data_with_attribute(&sm, pm, PAP_UNCONFIRMED, PAP_DELIVERED1); remove_push_data(sm, pm, sm == NULL); } else { request_confirmed_push(last, pm, sm); ++i; } } } /* * Abort all pushes queued by session machine sm. In addition, update PAP * attribute and notify PI. */ static PPGPushMachine *abort_delivery(PPGSessionMachine *sm, int status) { PPGPushMachine *pm; long reason, code; session_machine_assert(sm); pm = NULL; reason = PAP_ABORT_USERPND; code = PAP_CAPABILITIES_MISMATCH; while (gwlist_len(sm->push_machines) > 0) { pm = gwlist_get(sm->push_machines, 0); push_machine_assert(pm); pm = update_push_data_with_attribute(&sm, pm, reason, PAP_ABORTED); response_push_message(pm, code, status); remove_push_data(sm, pm, sm == NULL); } return pm; } /* * Remove a session, even if it have active pushes. These are aborted, and we * must inform PI about this. Client abort codes are defined in pap, 9.14.5, * which refers to wsp, Appendix A, table 35. */ static void remove_session_data(PPGSessionMachine *sm, int status) { long code; PPGPushMachine *pm; session_machine_assert(sm); code = PAP_ABORT_USERPND; while (gwlist_len(sm->push_machines) > 0) { pm = gwlist_get(sm->push_machines, 0); response_push_message(pm, code, status); remove_push_data(sm, pm, sm == NULL); } gwlist_delete_equal(ppg_machines, sm); session_machine_destroy(sm); } /* * Remove session, if it has no active pushes. */ static void remove_pushless_session(PPGSessionMachine *sm) { session_machine_assert(sm); if (gwlist_len(sm->push_machines) == 0) { gwlist_delete_equal(ppg_machines, sm); session_machine_destroy(sm); } } /* * If session machine not exist, create a session machine and store session * data. If session exists, ignore. * Return pointer to the session machine, and a flag did we have a session * before executing this function. (Session data is needed to implement the * PAP attribute. It does not mean that a session exists.) */ static PPGSessionMachine *store_session_data(PPGSessionMachine *sm, WAPEvent *e, WAPAddrTuple *tuple, int *session_exists) { gw_assert(e->type == Push_Message); if (sm == NULL) { sm = session_machine_create(tuple, e); *session_exists = 0; } else *session_exists = 1; return sm; } static PPGSessionMachine *update_session_data_with_headers( PPGSessionMachine *sm, PPGPushMachine *pm) { gwlist_delete_matching(sm->push_machines, &pm->push_id, push_has_pid); gwlist_append(sm->push_machines, pm); return sm; } /* * Ppg 6.1.2.2, subchapter delivery, states that if the delivery method is not * confirmed or unconfirmed, PPG may select an implementation specific type of * the primitive. We use an unconfirmed push, if QoS is notspecified, and * confirmed one, when it is preferconfirmed (we do support confirmed push). */ static int confirmation_requested(WAPEvent *e) { gw_assert(e->type == Push_Message); return e->u.Push_Message.delivery_method == PAP_CONFIRMED || e->u.Push_Message.delivery_method == PAP_PREFERCONFIRMED; } static int push_has_pid(void *a, void *b) { long *pid; PPGPushMachine *pm; pid = b; pm = a; return *pid == pm->push_id; } static PPGPushMachine *find_ppg_push_machine_using_pid(PPGSessionMachine *sm, long pid) { PPGPushMachine *pm; gw_assert(pid >= 0); session_machine_assert(sm); pm = gwlist_search(sm->push_machines, &pid, push_has_pid); return pm; } static int push_has_pi_push_id(void *a, void *b) { Octstr *pi_push_id; PPGPushMachine *pm; pi_push_id = b; pm = a; return octstr_compare(pm->pi_push_id, pi_push_id) == 0; } static PPGPushMachine *find_ppg_push_machine_using_pi_push_id( PPGSessionMachine *sm, Octstr *pi_push_id) { PPGPushMachine *pm; gw_assert(pi_push_id); session_machine_assert(sm); pm = gwlist_search(sm->push_machines, pi_push_id, push_has_pi_push_id); return pm; } static PPGPushMachine *find_unit_ppg_push_machine_using_pi_push_id( Octstr *pi_push_id) { PPGPushMachine *pm; gw_assert(pi_push_id); pm = gwlist_search(ppg_unit_pushes, pi_push_id, push_has_pi_push_id); return pm; } /* * Store a new value of the push attribute into a push machine. It is to be * found from the list of unit pushes, if connectionless push was asked * (sm == NULL), otherwise from the the push list of the session machine sm. * Returns updated push machine and session machine (this one has an updated * push machines list). */ static PPGPushMachine *update_push_data_with_attribute(PPGSessionMachine **sm, PPGPushMachine *qm, long reason, long status) { push_machine_assert(qm); switch (status) { case PAP_UNDELIVERABLE1: qm->message_state = PAP_UNDELIVERABLE; qm->code = PAP_BAD_REQUEST; break; case PAP_UNDELIVERABLE2: qm->code = reason; qm->message_state = PAP_UNDELIVERABLE; qm->desc = describe_code(reason); break; case PAP_ABORTED: qm->message_state = status; qm->code = ota_abort_to_pap(reason); qm->event_time = set_time(); qm->desc = describe_code(reason); break; case PAP_DELIVERED1: qm->message_state = PAP_DELIVERED; qm->delivery_method = PAP_UNCONFIRMED; qm->event_time = set_time(); break; case PAP_DELIVERED2: qm->message_state = PAP_DELIVERED; qm->delivery_method = PAP_CONFIRMED; qm->event_time = set_time(); break; case PAP_EXPIRED: qm->message_state = PAP_EXPIRED; qm->event_time = set_time(); qm->desc = describe_code(reason); break; case PAP_PENDING: qm->message_state = PAP_PENDING; break; default: error(0, "WAP_PUSH_PPG: update_push_data_with_attribute: Non" " existing push machine status: %ld", status); break; } if (*sm != NULL){ gwlist_delete_matching((**sm).push_machines, &qm->push_id, push_has_pid); gwlist_append((**sm).push_machines, qm); gwlist_delete_equal(ppg_machines, *sm); gwlist_append(ppg_machines, *sm); } else { gwlist_delete_matching(ppg_unit_pushes, &qm->push_id, push_has_pid); gwlist_append(ppg_unit_pushes, qm); } return qm; } /* * Store session id, client port and caps list received from application layer. */ static PPGSessionMachine *update_session_data(PPGSessionMachine *m, long sid, long port, List *caps) { session_machine_assert(m); gw_assert(sid >= 0); m->session_id = sid; m->addr_tuple->remote->port = port; m->client_capabilities = wsp_cap_duplicate_list(caps); gwlist_delete_equal(ppg_machines, m); gwlist_append(ppg_machines, m); return m; } /* * Convert OTA abort codes (ota 6.3.3) to corresponding PAP status codes. These * are defined in pap 9.14.5. */ static long ota_abort_to_pap(long reason) { long offset; offset = reason - 0xEA; reason = 5026 + offset; return reason; } /* * Accept connectionless push when PI wants connectionless push and there is * no sessions open. */ static int cless_accepted(WAPEvent *e, PPGSessionMachine *sm) { gw_assert(e->type == Push_Message); return (e->u.Push_Message.delivery_method == PAP_UNCONFIRMED || e->u.Push_Message.delivery_method == PAP_NOT_SPECIFIED) && (sm == NULL); } /* * Application ids start with 0 and -1 means that default (wml.ua) was used. */ static int coriented_deliverable(long appid_code) { return appid_code > -1; } /* * Compare PAP message timestamp, in PAP message format, and stored in octstr, * to gm (UTC) broken time. Return true, if before is after now, or if the * service in question was not requested by PI. PAP time format is defined in * pap, chapter 9.2. */ static void initialize_time_item_array(long time_data[], struct tm now) { time_data[0] = now.tm_year + 1900; time_data[1] = now.tm_mon + 1; time_data[2] = now.tm_mday; time_data[3] = now.tm_hour; time_data[4] = now.tm_min; time_data[5] = now.tm_sec; } static int date_item_compare(Octstr *condition, long time_data, long pos) { long data; if (octstr_parse_long(&data, condition, pos, 10) < 0) { return 0; } if (data < time_data) { return -1; } if (data > time_data) { return 1; } return 0; } /* * We do not accept timestamps equalling now. Return true, if the service was * not requested. */ static int deliver_before_test_cleared(Octstr *before, struct tm now) { long time_data[6]; long j; if (before == NULL) return 1; initialize_time_item_array(time_data, now); if (date_item_compare(before, time_data[0], 0) == 1) return 1; if (date_item_compare(before, time_data[0], 0) == -1) return 0; for (j = 5; j < octstr_len(before); j += 3) { if (date_item_compare(before, time_data[(j-5)/3 + 1], j) == 1) return 1; if (date_item_compare(before, time_data[(j-5)/3 + 1], j) == -1) return 0; } return 0; } /* * Ditto. Return true, if after is before now (or the service was not request- * ed). Do not accept timestamps equalling now. */ static int deliver_after_test_cleared(Octstr *after, struct tm now) { long time_data[6]; long j; if (after == NULL) return 1; initialize_time_item_array(time_data, now); if (date_item_compare(after, time_data[0], 0) == -1) return 1; if (date_item_compare(after, time_data[0], 0) == 1) return 0; for (j = 5; j < octstr_len(after); j += 3) { if (date_item_compare(after, time_data[(j-5)/3 + 1], j) == -1) return 1; if (date_item_compare(after, time_data[(j-5)/3 + 1], j) == 1) return 0; } return 0; } /* * We exchange here server and client addresses and ports, because our WDP, * written for pull, exchange them, too. Similarly server address INADDR_ANY is * used for compability reasons, when the bearer is ip. When it is SMS, the * server address is global-sender. */ static WAPAddrTuple *set_addr_tuple(Octstr *address, long cliport, long servport, long address_type, List *push_headers) { Octstr *cliaddr; Octstr *from = NULL; WAPAddrTuple *tuple; gw_assert(address); if (address_type == ADDR_PLMN) { from = http_header_value(push_headers, octstr_imm("X-Kannel-From")); cliaddr = from ? from : global_sender; } else { cliaddr = octstr_imm("0.0.0.0"); } tuple = wap_addr_tuple_create(address, cliport, cliaddr, servport); octstr_destroy(from); http_header_remove_all(push_headers, "X-Kannel-From"); return tuple; } /* * We are not interested about parsing URI fully - we check only does it cont- * ain application id reserved by WINA or the part containing assigned code. * Otherwise (regardless of it being an URI or assigned code) we simply pass * it forward. * These are defined by WINA at http://www.openmobilealliance.org/tech/ * omna/omna-push-app-id.htm. We recognize both well-known and registered * values. X-wap-application is not added, it is considired a default. */ static char *wina_uri[] = { "*", "push.sia", "wml.ua", "wta.ua", "mms.ua", "push.syncml", "loc.ua", "syncml.dm", "drm.ua", "emn.ua", "wv.ua", "x-wap-microsoft:localcontent.ua", "x-wap-microsoft:IMclient.ua", "x-wap-docomo:imode.mail.ua", "x-wap-docomo:imode.mr.ua", "x-wap-docomo:imode.mf.ua", "x-motorola:location.ua", "x-motorola:now.ua", "x-motorola:otaprov.ua", "x-motorola:browser.ua", "x-motorola:splash.ua", "x-wap-nai:mvsw.command", "x-wap-openwave:iota.ua", "x-wap-docomo:imode.mail2.ua", "x-oma-nec:otaprov.ua", "x-oma-nokia:call.ua" }; #define NUMBER_OF_WINA_URIS sizeof(wina_uri)/sizeof(wina_uri[0]) /* * X-Wap-Application-Id header is defined in Push Message, chapter 6.2.2.1. * First check do we a header with an app-encoding field and a coded value. * If not, try to find push application id from table of wina approved values. * Return coded value value of application id in question, or an error code: * -1, no coded value (but defaults may be applied) * 0, * (meaning any application acceptable) * greater or equal as 1: code for this application id */ static long parse_appid_header(Octstr **appid_content) { long pos, coded_value; size_t i; if ((pos = octstr_search(*appid_content, octstr_imm(";"), 0)) >= 0) { octstr_delete(*appid_content, pos, octstr_len(octstr_imm(";app-encoding="))); octstr_delete(*appid_content, 0, pos); /* the URI part */ return -1; } i = 0; while (i < NUMBER_OF_WINA_URIS) { if ((pos = octstr_case_search(*appid_content, octstr_imm(wina_uri[i]), 0)) >= 0) break; ++i; } if (i == NUMBER_OF_WINA_URIS) { octstr_destroy(*appid_content); *appid_content = octstr_format("%ld", 2); /* assigned number */ return -1; /* for wml ua */ } octstr_delete(*appid_content, 0, pos); /* again the URI */ if ((coded_value = wsp_string_to_application_id(*appid_content)) >= 0) { octstr_destroy(*appid_content); *appid_content = octstr_format("%ld", coded_value); return coded_value; } return -1; } static WAPAddrTuple *addr_tuple_change_cliport(WAPAddrTuple *tuple, long port) { WAPAddrTuple *dubble; if (tuple == NULL) return NULL; dubble = wap_addr_tuple_create(tuple->remote->address, port, tuple->local->address, tuple->local->port); return dubble; } /* * Pi uses multipart/related content type when communicating with ppg. (see * pap, Chapter 8) and subtype application/xml. * Check if push headers are acceptable according this rule. In addition, * return the field value of Content-Type header, if any and error string if * none (this string is used by send_bad_message_response). */ static int headers_acceptable(List *push_headers, Octstr **content_header) { gw_assert(push_headers); *content_header = http_header_find_first(push_headers, "Content-Type"); if (*content_header == NULL) { *content_header = octstr_format("%s", "no content type header found"); goto error; } if (!type_is(*content_header, "multipart/related")) { goto error; } if (!type_is(*content_header, "application/xml")) { goto error; } return 1; error: warning(0, "PPG: headers_acceptable: got unacceptable push headers"); return 0; } /* * Content-Type header field is defined in rfc 1521, chapter 4. We are looking * after type multipart/related or "multipart/related" and parameter * type=application/xml or type="application/xml", as required by pap, chapter * 8. */ static int type_is(Octstr *content_header, char *name) { Octstr *quoted_type, *osname; osname = octstr_imm(name); if (octstr_case_search(content_header, osname, 0) >= 0) return 1; quoted_type = octstr_format("\"%S\"", osname); if (octstr_case_search(content_header, quoted_type, 0) >= 0) { octstr_destroy(quoted_type); return 1; } octstr_destroy(quoted_type); return 0; } /* * Again looking after a parameter, this time of type boundary=XXX or boundary= * "XXX". */ static int get_mime_boundary(List *push_headers, Octstr *content_header, Octstr **boundary) { long pos; Octstr *bos; int c, quoted = 0; long bstart; pos = 0; if ((pos = octstr_case_search(content_header, bos = octstr_imm("boundary="), 0)) < 0) { warning(0, "PPG: get_mime_boundary: no boundary specified"); return -1; } pos += octstr_len(bos); if (octstr_get_char(content_header, pos) == '"') { ++pos; quoted = 1; } bstart = pos; while ((c = octstr_get_char(content_header, pos)) != -1) { if (c == ';' || (quoted && c == '"') || (!quoted && c == ' ')) break; ++pos; } *boundary = octstr_copy(content_header, bstart, pos - bstart); return 0; } static void change_header_value(List **push_headers, char *name, char *value) { http_header_remove_all(*push_headers, name); http_header_add(*push_headers, name, value); } /* * Some application level protocols may use MIME headers. This may cause problems * to them. (MIME version is a mandatory header). */ static void remove_mime_headers(List **push_headers) { http_header_remove_all(*push_headers, "MIME-Version"); } /* * There are headers used only for HTTP POST pi->ppg. (For debugging, mainly.) */ static void remove_link_headers(List **push_headers) { http_header_remove_all(*push_headers, "Host"); } /* * X-Kannel headers are used to control Kannel ppg. */ static void remove_x_kannel_headers(List **push_headers) { http_header_remove_all(*push_headers, "X-Kannel-SMSC"); http_header_remove_all(*push_headers, "X-Kannel-DLR-Url"); http_header_remove_all(*push_headers, "X-Kannel-DLR-Mask"); http_header_remove_all(*push_headers, "X-Kannel-Smsbox-Id"); } /* * Badmessage-response element is redefined in pap, implementation note, * chapter 5. Do not add to the document a fragment being NULL or empty. * Return current status of HTTPClient. */ static void send_bad_message_response(HTTPClient **c, Octstr *fragment, int code, int status) { Octstr *reply_body; reply_body = octstr_format("%s", "" "" "" "" "" ""); debug("wap.push.ppg", 0, "PPG: send_bad_message_response: telling pi"); send_to_pi(c, reply_body, status); octstr_destroy(fragment); } /* * Push response is defined in pap, chapter 9.3. Mapping between push ids and * http clients is done by using http_clients. We remove (push id, http client) * pair from the dictionary after the mapping has been done. * Return current status of HTTPClient. */ static HTTPClient *send_push_response(WAPEvent *e, int status) { Octstr *reply_body, *url; HTTPClient *c; gw_assert(e->type == Push_Response); url = dict_get(urls, e->u.Push_Response.pi_push_id); dict_remove(urls, e->u.Push_Response.pi_push_id); reply_body = octstr_format("%s", "" "" "" "u.Push_Response.pi_push_id); octstr_format_append(reply_body, "%s", "\""); if (e->u.Push_Response.sender_name != NULL) { octstr_format_append(reply_body, "%s", " sender-name=\""); octstr_format_append(reply_body, "%S", e->u.Push_Response.sender_name); octstr_format_append(reply_body, "%s", "\""); } if (e->u.Push_Response.reply_time != NULL) { octstr_format_append(reply_body, "%s", " reply-time=\""); octstr_format_append(reply_body, "%S", e->u.Push_Response.reply_time); octstr_format_append(reply_body, "%s", "\""); } if (url != NULL) { octstr_format_append(reply_body, "%s", " sender-address=\""); octstr_format_append(reply_body, "%S", url); octstr_format_append(reply_body, "%s", "\""); } octstr_format_append(reply_body, "%s", ">" "u.Push_Response.code); octstr_format_append(reply_body, "%s", "\""); if (e->u.Push_Response.desc != NULL) { octstr_format_append(reply_body, "%s", " desc=\""); octstr_format_append(reply_body, "%S", e->u.Push_Response.desc); octstr_format_append(reply_body, "\""); } octstr_format_append(reply_body, "%s", ">" "" "" ""); octstr_destroy(url); c = dict_get(http_clients, e->u.Push_Response.pi_push_id); dict_remove(http_clients, e->u.Push_Response.pi_push_id); debug("wap.push.ppg", 0, "PPG: send_push_response: telling pi"); send_to_pi(&c, reply_body, status); wap_event_destroy(e); return c; } /* * Ppg notifies pi about duplicate push id by sending a push response document * to it. Note that we never put the push id to the dict in this case. * Return current c value. */ static void tell_fatal_error(HTTPClient **c, WAPEvent *e, Octstr *url, int status, int code) { Octstr *reply_body, *dos, /* temporaries */ *tos, *sos; gw_assert(e->type == Push_Message); reply_body = octstr_format("%s", "" "" "" "u.Push_Message.pi_push_id); octstr_format_append(reply_body, "%s", "\""); octstr_format_append(reply_body, "%s", " sender-name=\""); octstr_format_append(reply_body, "%S", tos = tell_ppg_name()); octstr_format_append(reply_body, "%s", "\""); octstr_format_append(reply_body, "%s", " reply-time=\""); octstr_format_append(reply_body, "%S", sos = set_time()); octstr_format_append(reply_body, "%s", "\""); octstr_format_append(reply_body, "%s", " sender-address=\""); octstr_format_append(reply_body, "%S", url); octstr_format_append(reply_body, "%s", "\""); octstr_format_append(reply_body, "%s", ">" "" "" "" ""); debug("wap.push.ppg", 0, "PPG: tell_fatal_error: %s", octstr_get_cstr(dos)); send_to_pi(c, reply_body, status); octstr_destroy(dos); octstr_destroy(tos); octstr_destroy(sos); wap_event_destroy(e); } /* * Does the HTTP reply to pi. Test has HTTPClient disappeared. * Return current c value. */ static void send_to_pi(HTTPClient **c, Octstr *reply_body, int status) { List *reply_headers; reply_headers = http_create_empty_headers(); http_header_add(reply_headers, "Content-Type", "application/xml"); if (*c != NULL) http_send_reply(*c, status, reply_headers, reply_body); octstr_destroy(reply_body); http_destroy_headers(reply_headers); } /* * Escape characters not allowed in the value of an attribute. Pap does not * define escape sequences for message fragments; try common xml ones. */ static Octstr *escape_fragment(Octstr *fragment) { long i; int c; i = 0; while (i < octstr_len(fragment)) { if ((c = octstr_get_char(fragment, i)) == '"') { replace_octstr_char(fragment, octstr_imm("""), &i); } else if (c == '<') { replace_octstr_char(fragment, octstr_imm("<"), &i); } else if (c == '>') { replace_octstr_char(fragment, octstr_imm(">"), &i); } else if (c == '&') { replace_octstr_char(fragment, octstr_imm("&"), &i); } ++i; } return fragment; } static int is_phone_number(long address_type) { return address_type == ADDR_PLMN; } static void replace_octstr_char(Octstr *os1, Octstr *os2, long *pos) { octstr_delete(os1, *pos, 1); octstr_insert(os1, os2, *pos); *pos += octstr_len(os2) - 1; } /* * Check if we have an explicit routing information * a) first check x-kannel header * b) then ppg user specific routing (if there is any groups; we have none, * if pi is trusted) * c) then global ppg routing * d) if all these failed, return NULL */ static Octstr *set_smsc_id(List *headers, Octstr *username, int trusted_pi) { Octstr *smsc_id = NULL; smsc_id = http_header_value(headers, octstr_imm("X-Kannel-SMSC")); if (smsc_id) { return smsc_id; } if (!trusted_pi) smsc_id = wap_push_ppg_pushuser_smsc_id_get(username); smsc_id = smsc_id ? smsc_id : (ppg_default_smsc ? octstr_duplicate(ppg_default_smsc) : NULL); return smsc_id; } /* * Checking for dlr url, using following order: * a) first check X-Kannel header * b) then ppg user specific dlr url (if there is any user group; if pi is * trusted, there are none.) * c) then global ppg dlr url * d) if all these failed, return NULL */ static Octstr *set_dlr_url(List *headers, Octstr *username, int trusted_pi) { Octstr *dlr_url = NULL; dlr_url = http_header_value(headers, octstr_imm("X-Kannel-DLR-Url")); if (dlr_url) { return dlr_url; } if (!trusted_pi) dlr_url = wap_push_ppg_pushuser_dlr_url_get(username); dlr_url = dlr_url ? dlr_url : (ppg_dlr_url ? octstr_duplicate(ppg_dlr_url) : NULL); return dlr_url; } /* * Checking for dlr mask. Mask without dlr url is of course useless. * We reject (some) non-meaningfull values of dlr_mask. Value indic- * ating rejection is 0. */ static long set_dlr_mask(List *headers, Octstr *dlr_url) { Octstr *dlrmaskos; long dlr_mask; long masklen; dlrmaskos = http_header_value(headers, octstr_imm("X-Kannel-DLR-Mask")); if (dlrmaskos == NULL) { return 0; } if ((masklen = octstr_parse_long(&dlr_mask, dlrmaskos, 0, 10)) != -1 && masklen == octstr_len(dlrmaskos) && dlr_mask >= -1 && dlr_mask <= 31) { octstr_destroy(dlrmaskos); return dlr_mask; } warning(0, "unparsable dlr mask, rejected"); octstr_destroy(dlrmaskos); return 0; } /* * Checking for dlr smsbox id, using following order: * a) first check X-Kannel header * b) then ppg user specific smsbox id, if there is any group; if pi * is trusted, there are none * c) then global ppg smsbox id * d) if all these failed, return NULL */ static Octstr *set_smsbox_id(List *headers, Octstr *username, int trusted_pi) { Octstr *smsbox_id = NULL; smsbox_id = http_header_value(headers, octstr_imm("X-Kannel-Smsbox-Id")); if (smsbox_id != NULL) { return smsbox_id; } if (!trusted_pi) smsbox_id = wap_push_ppg_pushuser_smsbox_id_get(username); smsbox_id = smsbox_id ? smsbox_id : (ppg_smsbox_id ? octstr_duplicate(ppg_smsbox_id) : NULL); return smsbox_id; } /* * Service is ppg core group only configuration variable */ static Octstr *set_service_name(void) { return octstr_duplicate(service_name); } gateway-1.4.5/gw/dlr_cass.c0000644000175000017500000003222013254732660014246 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dlr_cass.c * * Implementation of handling delivery reports (DLRs) * for Cassandra NoSQL database * * Stipe Tolj table, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status); os_mask = octstr_format("%d", entry->mask); gwlist_append(binds, entry->smsc); gwlist_append(binds, entry->timestamp); gwlist_append(binds, entry->source); gwlist_append(binds, entry->destination); gwlist_append(binds, entry->service); gwlist_append(binds, entry->url); gwlist_append(binds, os_mask); gwlist_append(binds, entry->boxc_id); /* add TTL value */ if (fields->ttl) { octstr_format_append(sql, "USING TTL %ld;", fields->ttl); } else { /* final semicolon */ octstr_append_char(sql, ';'); } #if defined(DLR_TRACE) debug("dlr.cass", 0, "cql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: Cassandra: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination)); dbpool_conn_produce(pconn); octstr_destroy(sql); gwlist_destroy(binds, NULL); octstr_destroy(os_mask); dlr_entry_destroy(entry); } static struct dlr_entry* dlr_cass_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql; DBPoolConn *pconn; List *result = NULL, *row; struct dlr_entry *res = NULL; List *binds = gwlist_create(); pconn = dbpool_conn_consume(pool); if (pconn == NULL) /* sanity check */ return NULL; sql = octstr_format("SELECT %S, %S, %S, %S, %S, %S FROM %S WHERE %S=? AND %S=? LIMIT 1;", fields->field_mask, fields->field_serv, fields->field_url, fields->field_src, fields->field_dst, fields->field_boxc, fields->table, fields->field_smsc, fields->field_ts); gwlist_append(binds, (Octstr*) smsc); gwlist_append(binds, (Octstr*) ts); #if defined(DLR_TRACE) debug("dlr.cass", 0, "cql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(pconn, sql, binds, &result) != 0) { octstr_destroy(sql); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); return NULL; } octstr_destroy(sql); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); #define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i)) if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); res = dlr_entry_create(); gw_assert(res != NULL); res->mask = atoi(LO2CSTR(row,0)); res->service = octstr_create(LO2CSTR(row, 1)); res->url = octstr_create(LO2CSTR(row,2)); res->source = octstr_create(LO2CSTR(row, 3)); res->destination = octstr_create(LO2CSTR(row, 4)); res->boxc_id = octstr_create(LO2CSTR(row, 5)); gwlist_destroy(row, octstr_destroy_item); res->smsc = octstr_duplicate(smsc); } gwlist_destroy(result, NULL); #undef LO2CSTR return res; } static void dlr_cass_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.cass", 0, "removing DLR from database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; sql = octstr_format("DELETE FROM %S WHERE %S=? AND %S=?;", fields->table, fields->field_smsc, fields->field_ts); gwlist_append(binds, (Octstr*) smsc); gwlist_append(binds, (Octstr*) ts); #if defined(DLR_TRACE) debug("dlr.cass", 0, "cql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: Cassandra: Error while removing dlr entry for DST<%s>", octstr_get_cstr(dst)); dbpool_conn_produce(pconn); gwlist_destroy(binds, NULL); octstr_destroy(sql); } static void dlr_cass_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status) { Octstr *sql, *os_status; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.cass", 0, "updating DLR status in database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; sql = octstr_format("UPDATE %S SET %S=? WHERE %S=? AND %S=? LIMIT 1;", fields->table, fields->field_status, fields->field_smsc, fields->field_ts); os_status = octstr_format("%d", status); gwlist_append(binds, (Octstr*) os_status); gwlist_append(binds, (Octstr*) smsc); gwlist_append(binds, (Octstr*) ts); #if defined(DLR_TRACE) debug("dlr.cass", 0, "cql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: Cassandra: Error while updating dlr entry for DST<%s>", octstr_get_cstr(dst)); dbpool_conn_produce(pconn); gwlist_destroy(binds, NULL); octstr_destroy(os_status); octstr_destroy(sql); } static long dlr_cass_messages(void) { List *result, *row; Octstr *sql; DBPoolConn *conn; long msgs = -1; conn = dbpool_conn_consume(pool); if (conn == NULL) return -1; sql = octstr_format("SELECT count(*) FROM %s", octstr_get_cstr(fields->table)); #if defined(DLR_TRACE) debug("dlr.cass", 0, "cql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(conn, sql, NULL, &result) != 0) { octstr_destroy(sql); dbpool_conn_produce(conn); return -1; } dbpool_conn_produce(conn); octstr_destroy(sql); if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); msgs = strtol(octstr_get_cstr(gwlist_get(row,0)), NULL, 10); gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(result, NULL); return msgs; } static void dlr_cass_flush(void) { Octstr *sql; DBPoolConn *pconn; int rows; pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; sql = octstr_format("DELETE FROM %S", fields->table); #if defined(DLR_TRACE) debug("dlr.mysql", 0, "cql: %s", octstr_get_cstr(sql)); #endif rows = dbpool_conn_update(pconn, sql, NULL); if (rows == -1) error(0, "DLR: Cassandra: Error while flushing dlr entries from database"); dbpool_conn_produce(pconn); octstr_destroy(sql); } static struct dlr_storage handles = { .type = "cassandra", .dlr_add = dlr_cass_add, .dlr_get = dlr_cass_get, .dlr_update = dlr_cass_update, .dlr_remove = dlr_cass_remove, .dlr_shutdown = dlr_cass_shutdown, .dlr_messages = dlr_cass_messages, .dlr_flush = dlr_cass_flush }; struct dlr_storage *dlr_init_cass(Cfg *cfg) { CfgGroup *grp; List *grplist; Octstr *host, *user, *pass, *db, *id; long port = 0; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; /* * check for all mandatory directives that specify the field names * of the used Cassandra table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db")))) panic(0, "DLR: Cassandra: group 'dlr-db' is not specified!"); if (!(id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: Cassandra: directive 'id' is not specified!"); fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); /* * now grap the required information from the 'cassandra-connection' group * with the id we just obtained * * we have to loop through all available Cassandra connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("cassandra-connection")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "DLR: Cassandra: connection settings for id '%s' are not specified!", octstr_get_cstr(id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(host = cfg_get(grp, octstr_imm("host")))) panic(0, "DLR: Cassandra: directive 'host' is not specified!"); /* optional(s) */ user = cfg_get(grp, octstr_imm("username")); pass = cfg_get(grp, octstr_imm("password")); db = cfg_get(grp, octstr_imm("database")); cfg_get_integer(&port, grp, octstr_imm("port")); /* * ok, ready to connect to Cassandra */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->cass = gw_malloc(sizeof(CassConf)); gw_assert(db_conf->cass != NULL); db_conf->cass->host = host; db_conf->cass->port = port; db_conf->cass->username = user; db_conf->cass->password = pass; db_conf->cass->database = db; pool = dbpool_create(DBPOOL_CASS, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"DLR: Cassandra: database pool has no connections!"); octstr_destroy(id); return &handles; } #else /* * Return NULL , so we point dlr-core that we were * not compiled in. */ struct dlr_storage *dlr_init_cass(Cfg* cfg) { return NULL; } #endif /* HAVE_CASS */ gateway-1.4.5/gw/key.pem0000644000175000017500000000156707363702670013617 0ustar toljtolj-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDYkxgJlqIgdkMd0m8BV8I26lPWcJ3wRORK9YdZDYePOw+/NiPJ nE/ws8ZrB3ryt4XgSkxJ6PowdMuaePkEoca8mjFFG0aDhn65a1cHP3W8CUM+1Dcq g5Vp751uKU33VXfvCZQqWBQdt2e25qVFdV8ulRSgWocyIcyE2rsdb7xDywIDAQAB AoGAEIvUZ08h3dcLM6kTIAgjZ2ypsRVzi5rH0k5F4/DbrX62qkYpn8qYdOxXOXAd 3ZNV4BftEiyBiNgzgf7CD6+IblZUqkc1dUc96AJH16CUXM/favAHhIoSdyhrnAH8 O9UN1KxlzUpvLDOelbOdL4/4sQ0XXqd9DJcZkeKc4zCi35kCQQD43SlsTDBeO7ae Ig5qnJ/g2V2V4bPh1xTH7LjxthsksOqPUEt3DgRmRVq+qeDyyxN49V9uFYf8oXDl 1FchPranAkEA3sjny2sxBNIBGtPVLGFl+aukBRkNOdmssVcBudsnigOEL0lbd4Wu 07ok0zeCuAu+yHRYJKY4eqWVGQJ/DtUSPQJBAIqxVuCQJXSe+stuV3J7D28UNN/P BZ0bbO1utDOhNcdhAZgVO7mCClmk1UnlCwTEwHls5l5HiZ31qyGrEVPpy4kCQDfR VmIdBTcT9rrmAC8SaB5Z5spwMGQiKaZ1CjWqtwlZQDEozAXyNI9PwBI7gkDikHZg 0AS+sL/p5KVTfsoUkHECQQDWCSgpZ8k7EajS1RWIGH/GcFT/GaKX8yiMIP2S3Atc nl7yMj8yw+1N503FF0aRwimryXQt/VHVYjtYsSAgNU/i -----END RSA PRIVATE KEY----- gateway-1.4.5/gw/pushkannel.conf0000644000175000017500000000406111144324076015323 0ustar toljtolj# # SAMPLE CONFIGURATION FOR KANNEL PPG (PUSH OVER SMS) # # It is run like this: # # 1% gw/bearerbox gw/pushkannel.conf # 2% gw/wapbox gw/pushkannel.conf # # Boys and girls: use more complex passwords when setting up real services, # this is an *example* file ! # # Aarno Syvänen in August 2001, for Wiral Ltd # BEARERBOX SETUP, for Kannel core operations group = core admin-port = 13000 smsbox-port = 13001 wapbox-port = 13002 admin-password = bar #status-password = foo #admin-deny-ip = "" #admin-allow-ip = "" #wdp-interface-name = "*" #log-file = "/tmp/bearerbox.log" #log-level = 0 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" #unified-prefix = "+358,00358,0;+,00" #access-log = "/tmp/access.log" #store-file = "/tmp/kannel.store" #ssl-server-cert-file = "cert.pem" #ssl-server-key-file = "key.pem" #ssl-certkey-file = "mycertandprivkeyfile.pem" # WAPBOX SETUP, for pushing and for pulling (fetching) the wap data group = wapbox bearerbox-host = 127.0.0.1 #log-file = "/tmp/wapbox.log" #log-level = 0 syslog-level = none # PPG CORE SETUP, for defining the push request interface group = ppg ppg-url = /cgi-bin/wap-push.cgi ppg-port = 18080 #ppg-ssl-port = 18081 concurrent-pushes = 100 trusted-pi = false users = 1024 #ppg-deny-ip = "*.*.*.*" ppg-allow-ip = "*.*.*.*" #ssl-server-cert-file = "cert.pem" #ssl-server-key-file = "key.pem" # PPG USER SETUP, for authorizing a specific push user group = wap-push-user wap-push-user = foo ppg-username = foo ppg-password = bar #country-prefix = +358 #allowed-prefix = "40;60;70" #denied-prefix = 50 #white-list = http://localhost:8082/whitelist #black-list = http://localhost:8082/blacklist #deny-ip = "*.*.*.*" #allow-ip = "127.0.0.1" # SMSC CONNECTIONS, for pushing SI, SL, MMS notifications or whatever over SMS group = smsc smsc = fake smsc-id = FAKE port = 10010 connect-allow-ip = 127.0.0.1 # SMSBOX SETUP (a kludge!) group = smsbox bearerbox-host = 127.0.0.1 #sendsms-port = 13013 #global-sender = 13013 #sendsms-chars = "0123456789 +-" #log-file = "/tmp/smsbox.log" #log-level = 0 #access-log = "/tmp/access.log" gateway-1.4.5/gw/wapkannel.conf0000644000175000017500000000223111144324076015130 0ustar toljtolj# # THIS IS A SAMPLE CONFIGURATION FOR WAP KANNEL # # It is run like this: # # 1% gw/bearerbox gw/wapkannel.conf # 2% gw/wapbox gw/wapkannel.conf # # ..as both commands in separate shells (or screen sessions) # # After that you can use your 7110 to test this out. Or use # fakewap from test directory, or some SDK. # # For any guidelines to set up your SDK or 7110, see Kannel FAQ # on Kannel WWW pages at http://www.kannel.org/ # # For any modifications to this file, see Kannel User Guide # If that does not help, send email to users@kannel.org # # Kalle Marjola May 2000 # group = core admin-port = 13000 wapbox-port = 13002 admin-password = bar #status-password = foo #admin-deny-ip = "" #admin-allow-ip = "" wdp-interface-name = "127.0.0.1" #log-file = "/tmp/bearerbox.log" #log-level = 0 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" #access-log = "/tmp/access.log" #store-file = "/tmp/kannel.store" #ssl-server-cert-file = "cert.pem" #ssl-server-key-file = "key.pem" #ssl-certkey-file = "mycertandprivkeyfile.pem" group = wapbox bearerbox-host = 127.0.0.1 #log-file = "/tmp/wapbox.log" #log-level = 0 syslog-level = none #access-log = "/tmp/wapaccess.log" gateway-1.4.5/gw/wap_ppg_session_machine.def0000644000175000017500000000775513227613126017666 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_ppg_session_machine.def: Macro call to store data about push sessions. * See documentation for details how to use and updata this. * * By Aarno Syvänen for Wapit Ltd */ #if !defined(MACHINE) #error "Macro MACHINE is missing" #elif !defined(ADDRTUPLE) #error "Macro ADDRTUPLE is missing" #elif !defined(INTEGER) #error "Macro INTEGER is missing" #elif !defined(PUSHMACHINES) #error "Macro PUSHMACHINES not defined" #elif !defined(CAPABILITIES) #error "Macro CAPABILITIES not defined" #endif MACHINE( OCTSTR(pi_client_address) /* client address in PAP format */ OCTSTR(sender_address) /* PPG's address */ ADDRTUPLE(addr_tuple) /* addresses using gw format */ INTEGER(session_id) PUSHMACHINES(push_machines) /* pushes belonging to this session */ CAPABILITIES(client_capabilities) /* Client capabilities. These can be queried by PI */ CAPABILITIES(assumed_capabilities) /* capabilities assumed by PI */ INTEGER(preferconfirmed_value) /* previously stored value of the delivery method attribute */ ) #undef MACHINE #undef ADDRTUPLE #undef INTEGER #undef PUSHMACHINES #undef CAPABILITIES #undef OCTSTR gateway-1.4.5/gw/wml_compiler.h0000644000175000017500000001113513227613126015147 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wml_compiler.h - compiling WML to WML binary * * This is a header for WML compiler for compiling the WML text * format to WML binary format, which is used for transmitting the * decks to the mobile terminal to decrease the use of the bandwidth. * * See comments below for explanations on individual functions. * * Tuomas Luttinen for Wapit Ltd. */ #ifndef WML_COMPILER_H #define WML_COMPILER_H /* * wml_compile - the interface to wml_compiler * * This function compiles the WML to WML binary. The arguments are * the following: * wml_text: the WML text to be compiled * charset: the character set as HTTP headers declare it * wml_binary: buffer for the compiled WML binary * version: max wbxml version supported by device, or NULL for default * * The wml_text and charset are allocated by the caller and should also be * freed by the caller. The function takes care for memory allocation for * the wml_binary. The caller is responsible for freeing this space. * * Return: 0 for ok, -1 for an error * * Errors are logged with a little explanation and error number. */ int wml_compile(Octstr *wml_text, Octstr *charset, Octstr **wml_binary, Octstr *version); /* * A function to initialize the wml compiler for use. Allocates memory * for the tables wml compiler uses. * * The passed boolean defines if our internal wml_compiler will be forcing * libxml2 parser to be strict, hence not to recover from XML parsing * errors, or if we let the parset be relax and recover from errors. * * Beware that a related XML parsing mode is considered to be a vulnerability * to your wapbox if huge WML/XML bogus is injected and the wml_compiler * runs all his string sorting/matching things on this. */ void wml_init(int wml_xml_strict); /* * A function for shutting down the wml_compiler. Frees the memory used * by the wml compiler. */ void wml_shutdown(void); #endif gateway-1.4.5/gw/dlr_redis.c0000644000175000017500000004472113227613126014427 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dlr_redis.c * * Implementation of handling delivery reports (DLRs) * for the Redis keystore * * Toby Phipps , 2011-08-23 * Stipe Tolj , 2013-12-12 */ #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #include "dlr_p.h" #ifdef HAVE_REDIS /* * Some SMSCs (such as the Logica SMPP simulator when bound multiple times * under high load) erroneously return duplicate message IDs. Before writing * the DLR, check to ensure that an existing DLR with the same message ID * doesn't already exist (HMSET of an existing key overwrites it silently * and we want the first message to win, not the erroneous one). * We issue a HSETNX first to ensure that the key doesn't already exist. * Only if it succeeds do we proceed to update it with full DLR info. * Define the following macro in case you want this extra handling. */ /* #define REDIS_PRECHECK 1 */ /* * Our connection pool to redis. */ static DBPool *pool = NULL; /* * Database-centric DLR definition (common across all engines) */ static struct dlr_db_fields *fields = NULL; static void dlr_redis_shutdown() { dbpool_destroy(pool); dlr_db_fields_destroy(fields); } static void dlr_redis_add(struct dlr_entry *entry) { Octstr *key, *sql, *os; DBPoolConn *pconn; List *binds; int res, len; debug("dlr.redis", 0, "Adding DLR into keystore"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { error(0, "DLR: REDIS: No connection available - dropping DLR"); dlr_entry_destroy(entry); return; } if (entry->use_dst && entry->destination) { Octstr *dst_min; /* keep a shorten version for the key part */ dst_min = octstr_duplicate(entry->destination); len = octstr_len(dst_min); if (len > MIN_DST_LEN) octstr_delete(dst_min, 0, len - MIN_DST_LEN); key = octstr_format("%S:%S:%S:%S", fields->table, entry->smsc, entry->timestamp, dst_min); octstr_destroy(dst_min); } else { key = octstr_format("%S:%S:%S", fields->table, entry->smsc, entry->timestamp); } #ifdef REDIS_PRECHECK binds = gwlist_create(); sql = octstr_format("HSETNX %S %S ?", key, fields->field_smsc); if (dbpool_conn_update(pconn, sql, binds) != 1) { error(0, "DLR: REDIS: DLR for %s already exists! Duplicate Message ID?", octstr_get_cstr(key)); octstr_destroy(sql); octstr_destroy(key); octstr_destroy(tsclean); octstr_destroy(dstclean); octstr_destroy(srcclean); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); return; } octstr_destroy(sql); gwlist_destroy(binds, NULL); #endif binds = gwlist_create(); sql = octstr_create(""); gwlist_append(binds, octstr_imm("HMSET")); gwlist_append(binds, key); gwlist_append(binds, fields->field_smsc); gwlist_append(binds, entry->smsc); gwlist_append(binds, fields->field_ts); gwlist_append(binds, entry->timestamp); gwlist_append(binds, fields->field_src); gwlist_append(binds, entry->source); gwlist_append(binds, fields->field_dst); gwlist_append(binds, entry->destination); gwlist_append(binds, fields->field_serv); gwlist_append(binds, entry->service); gwlist_append(binds, fields->field_url); octstr_url_encode(entry->url); gwlist_append(binds, entry->url); gwlist_append(binds, fields->field_mask); os = octstr_format("%d", entry->mask); gwlist_append(binds, os); gwlist_append(binds, fields->field_boxc); gwlist_append(binds, entry->boxc_id); res = dbpool_conn_update(pconn, sql, binds); if (res == -1) { error(0, "DLR: REDIS: Error while adding dlr entry %s", octstr_get_cstr(key)); } else { /* HMSET returned OK. Set EXPIRE if applicable and then * increment the DLR counter */ if (fields->ttl) { gwlist_destroy(binds, NULL); binds = gwlist_create(); gwlist_append(binds, octstr_imm("EXPIRE")); gwlist_append(binds, key); octstr_destroy(os); os = octstr_format("%ld", fields->ttl); gwlist_append(binds, os); res = dbpool_conn_update(pconn, sql, binds); } /* We are not performing an 'INCR :Count' * operation here, since we can't be accurate due * to TTL'ed expiration. Rather use 'DBSIZE' based * on seperated databases in redis. */ } dbpool_conn_produce(pconn); octstr_destroy(sql); octstr_destroy(key); octstr_destroy(os); gwlist_destroy(binds, NULL); dlr_entry_destroy(entry); } static inline void get_octstr_value(Octstr **os, const List *r, const int i) { *os = octstr_duplicate(gwlist_get((List*)r, i)); if (octstr_str_compare(*os, "_NULL_") == 0) { octstr_destroy(*os); *os = NULL; } } static struct dlr_entry *dlr_redis_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *key, *sql; DBPoolConn *pconn; List *binds = gwlist_create(); List *result = NULL, *row; struct dlr_entry *res = NULL; pconn = dbpool_conn_consume(pool); if (pconn == NULL) { error(0, "DLR: REDIS: No connection available"); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); return NULL; } /* If the destination address is not NULL, then * it has been shortened by the abstractive layer. */ if (dst) key = octstr_format("%S:%S:%S:%S", fields->table, (Octstr*) smsc, (Octstr*) ts, (Octstr*) dst); else key = octstr_format("%S:%S:%S", fields->table, (Octstr*) smsc, (Octstr*) ts); sql = octstr_create(""); gwlist_append(binds, octstr_imm("HMGET")); gwlist_append(binds, key); gwlist_append(binds, fields->field_mask); gwlist_append(binds, fields->field_serv); gwlist_append(binds, fields->field_url); gwlist_append(binds, fields->field_src); gwlist_append(binds, fields->field_dst); gwlist_append(binds, fields->field_boxc); if (dbpool_conn_select(pconn, sql, binds, &result) != 0) { error(0, "DLR: REDIS: Failed to fetch DLR for %s", octstr_get_cstr(key)); octstr_destroy(sql); octstr_destroy(key); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); return NULL; } dbpool_conn_produce(pconn); octstr_destroy(sql); octstr_destroy(key); gwlist_destroy(binds, NULL); #define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i)) if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); /* * If we get an empty set back from redis, this is * still an array with "" values, representing (nil). * If the mask is empty then this can't be a valid * set, therefore bail out. */ if (octstr_len(gwlist_get(row, 0)) > 0) { res = dlr_entry_create(); gw_assert(res != NULL); res->mask = atoi(octstr_get_cstr(gwlist_get(row, 0))); get_octstr_value(&res->service, row, 1); get_octstr_value(&res->url, row, 2); octstr_url_decode(res->url); get_octstr_value(&res->source, row, 3); get_octstr_value(&res->destination, row, 4); get_octstr_value(&res->boxc_id, row, 5); res->smsc = octstr_duplicate(smsc); } gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(result, NULL); #undef LO2CSTR return res; } static void dlr_redis_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *key, *sql; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.redis", 0, "Removing DLR from keystore"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { error(0, "DLR: REDIS: No connection available"); gwlist_destroy(binds, NULL); return; } if (dst) key = octstr_format("%S:%S:%S:%S", fields->table, (Octstr*) smsc, (Octstr*) ts, (Octstr*) dst); else key = octstr_format("%S:%S:%S", fields->table, (Octstr*) smsc, (Octstr*) ts); sql = octstr_create(""); gwlist_append(binds, octstr_imm("DEL")); gwlist_append(binds, key); res = dbpool_conn_update(pconn, sql, binds); /* * Redis DEL returns the number of keys deleted */ if (res != 1) { /* * We may fail to delete a DLR that was successfully retrieved * just above due to race conditions when duplicate message IDs * are received. This happens frequently when testing via the * Logica SMPP emulator due to its duplicate message ID bugs. */ error(0, "DLR: REDIS: Error while removing dlr entry for %s", octstr_get_cstr(key)); } /* We don't perform 'DECR
:Count', since we have TTL'ed * expirations, which can't be handled with manual counters. */ dbpool_conn_produce(pconn); octstr_destroy(sql); octstr_destroy(key); gwlist_destroy(binds, NULL); } static void dlr_redis_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status) { Octstr *key, *sql, *os_status; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.redis", 0, "Updating DLR status in keystore"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { error(0, "DLR: REDIS: No connection available"); gwlist_destroy(binds, NULL); return; } os_status = octstr_format("%d", status); key = octstr_format((dst ? "%S:?:?:?" : "%S:?:?"), fields->table); sql = octstr_format("HSET %S %S ?", key, fields->field_status); gwlist_append(binds, (Octstr*)smsc); gwlist_append(binds, (Octstr*)ts); if (dst != NULL) gwlist_append(binds, (Octstr*)dst); gwlist_append(binds, os_status); if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) { error(0, "DLR: REDIS: Error while updating dlr entry for %s", octstr_get_cstr(key)); } else if (!res) { warning(0, "DLR: REDIS: No dlr found to update for %s", octstr_get_cstr(key)); } dbpool_conn_produce(pconn); octstr_destroy(os_status); octstr_destroy(key); octstr_destroy(sql); gwlist_destroy(binds, NULL); } static long dlr_redis_messages(void) { List *result, *row; DBPoolConn *conn; long msgs = -1; conn = dbpool_conn_consume(pool); if (conn == NULL) return -1; if (dbpool_conn_select(conn, octstr_imm("DBSIZE"), NULL, &result) != 0) { dbpool_conn_produce(conn); return 0; } dbpool_conn_produce(conn); if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); msgs = atol(octstr_get_cstr(gwlist_get(row, 0))); gwlist_destroy(row, octstr_destroy_item); while ((row = gwlist_extract_first(result)) != NULL) gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(result, NULL); return msgs; } static void dlr_redis_flush(void) { Octstr *sql; DBPoolConn *pconn; int rows; pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { error(0, "DLR: REDIS: No connection available"); return; } sql = octstr_imm("FLUSHDB"); rows = dbpool_conn_update(pconn, sql, NULL); if (rows == -1) error(0, "DLR: REDIS: Error while flushing dlr entries from database"); else debug("dlr.redis", 0, "Flushed %d DLR entries from database", rows); dbpool_conn_produce(pconn); octstr_destroy(sql); } static struct dlr_storage handles = { .type = "redis", .dlr_add = dlr_redis_add, .dlr_get = dlr_redis_get, .dlr_update = dlr_redis_update, .dlr_remove = dlr_redis_remove, .dlr_shutdown = dlr_redis_shutdown, .dlr_messages = dlr_redis_messages, .dlr_flush = dlr_redis_flush }; struct dlr_storage *dlr_init_redis(Cfg *cfg) { CfgGroup *grp; List *grplist; Octstr *redis_host, *redis_pass, *redis_id; long redis_port = 0, redis_database = -1, redis_idle_timeout = -1; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; /* * Check for all mandatory directives that specify the field names * of the used Redis key */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db")))) panic(0, "DLR: Redis: group 'dlr-db' is not specified!"); if (!(redis_id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: Redis: directive 'id' is not specified!"); fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); /* * Escaping special quotes for field/table names */ octstr_replace(fields->table, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_smsc, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_ts, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_src, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_dst, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_serv, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_url, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_mask, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_status, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_boxc, octstr_imm("`"), octstr_imm("``")); /* * Now grab the required information from the 'redis-connection' group * with the redis-id we just obtained. * * We have to loop through all available Redis connection definitions * and search for the one we are looking for. */ grplist = cfg_get_multi_group(cfg, octstr_imm("redis-connection")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, redis_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "DLR: Redis: connection settings for id '%s' are not specified!", octstr_get_cstr(redis_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(redis_host = cfg_get(grp, octstr_imm("host")))) panic(0, "DLR: Redis: directive 'host' is not specified!"); if (cfg_get_integer(&redis_port, grp, octstr_imm("port")) == -1) panic(0, "DLR: Redis: directive 'port' is not specified!"); redis_pass = cfg_get(grp, octstr_imm("password")); cfg_get_integer(&redis_database, grp, octstr_imm("database")); cfg_get_integer(&redis_idle_timeout, grp, octstr_imm("idle-timeout")); /* * Ok, ready to connect to Redis */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->redis = gw_malloc(sizeof(RedisConf)); gw_assert(db_conf->redis != NULL); db_conf->redis->host = redis_host; db_conf->redis->port = redis_port; db_conf->redis->password = redis_pass; db_conf->redis->database = redis_database; db_conf->redis->idle_timeout = redis_idle_timeout; pool = dbpool_create(DBPOOL_REDIS, db_conf, pool_size); gw_assert(pool != NULL); /* * Panic on failure to connect. Should we just try to reconnect? */ if (dbpool_conn_count(pool) == 0) panic(0,"DLR: Redis: database pool has no connections!"); octstr_destroy(redis_id); return &handles; } #else /* * Return NULL, so we point dlr-core that we were * not compiled in. */ struct dlr_storage *dlr_init_redis(Cfg* cfg) { return NULL; } #endif /* HAVE_REDIS */ gateway-1.4.5/gw/dlr_sdb.c0000644000175000017500000003463513227613126014074 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dlr_sdb.c * * Implementation of handling delivery reports (DLRs) * for LibSDB. * * Andreas Fink , 18.08.2001 * Stipe Tolj , 22.03.2002 * Alexander Malysh 2003 * Guillaume Cottenceau 2004 (dbpool support) */ #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #include "dlr_p.h" #ifdef HAVE_SDB #include /* * Our connection pool to sdb. */ static DBPool *pool = NULL; /* * Database fields, which we use. */ static struct dlr_db_fields *fields = NULL; enum { SDB_ORACLE, SDB_MYSQL, SDB_POSTGRES, SDB_OTHER }; static long sdb_conn_type = SDB_OTHER; static const char* sdb_get_limit_str() { switch (sdb_conn_type) { case SDB_ORACLE: return "AND ROWNUM < 2"; case SDB_MYSQL: case SDB_POSTGRES: return "LIMIT 1"; case SDB_OTHER: default: return ""; } } static void dlr_sdb_shutdown() { dbpool_destroy(pool); dlr_db_fields_destroy(fields); } static int gw_sdb_query(char *query, int (*callback)(int, char **, void *), void *closure) { DBPoolConn *pc; int rows; pc = dbpool_conn_consume(pool); if (pc == NULL) { error(0, "SDB: Database pool got no connection!"); return -1; } rows = sdb_query(pc->conn, query, callback, closure); dbpool_conn_produce(pc); return rows; } static void dlr_sdb_add(struct dlr_entry *dlr) { Octstr *sql; int state; sql = octstr_format("INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES " "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d')", octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc), octstr_get_cstr(fields->field_ts), octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc), octstr_get_cstr(fields->field_status), octstr_get_cstr(dlr->smsc), octstr_get_cstr(dlr->timestamp), octstr_get_cstr(dlr->source), octstr_get_cstr(dlr->destination), octstr_get_cstr(dlr->service), octstr_get_cstr(dlr->url), dlr->mask, octstr_get_cstr(dlr->boxc_id), 0); #if defined(DLR_TRACE) debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL); if (state == -1) error(0, "SDB: error in inserting DLR for DST <%s>", octstr_get_cstr(dlr->destination)); else if (!state) warning(0, "SDB: No dlr inserted for DST <%s>", octstr_get_cstr(dlr->destination)); octstr_destroy(sql); dlr_entry_destroy(dlr); } static int sdb_callback_add(int n, char **p, void *data) { struct dlr_entry *res = (struct dlr_entry *) data; if (n != 6) { debug("dlr.sdb", 0, "SDB: Result has incorrect number of columns: %d", n); return 0; } #if defined(DLR_TRACE) debug("dlr.sdb", 0, "row=%s,%s,%s,%s,%s,%s",p[0],p[1],p[2],p[3],p[4],p[5]); #endif if (res->destination != NULL) { debug("dlr.sdb", 0, "SDB: Row already stored."); return 0; } res->mask = atoi(p[0]); res->service = octstr_create(p[1]); res->url = octstr_create(p[2]); res->source = octstr_create(p[3]); res->destination = octstr_create(p[4]); res->boxc_id = octstr_create(p[5]); return 0; } static int sdb_callback_msgs(int n, char **p, void *data) { long *count = (long *) data; if (n != 1) { debug("dlr.sdb", 0, "SDB: Result has incorrect number of columns: %d", n); return 0; } #if defined(DLR_TRACE) debug("dlr.sdb", 0, "SDB: messages=%s",p[0]); #endif *count = atol(p[0]); return 0; } static struct dlr_entry* dlr_sdb_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; int state; struct dlr_entry *res = dlr_entry_create(); gw_assert(res != NULL); if (dst) like = octstr_format("AND %S LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("SELECT %S, %S, %S, %S, %S, %S FROM %S WHERE %S='%S' " "AND %S='%S' %S %s", fields->field_mask, fields->field_serv, fields->field_url, fields->field_src, fields->field_dst, fields->field_boxc, fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like, sdb_get_limit_str()); #if defined(DLR_TRACE) debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), sdb_callback_add, res); octstr_destroy(sql); octstr_destroy(like); if (state == -1) { error(0, "SDB: error in finding DLR"); goto notfound; } else if (state == 0) { debug("dlr.sdb", 0, "SDB: no entry found for DST <%s>.", octstr_get_cstr(dst)); goto notfound; } res->smsc = octstr_duplicate(smsc); return res; notfound: dlr_entry_destroy(res); return NULL; } static void dlr_sdb_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status) { Octstr *sql, *like; int state; debug("dlr.sdb", 0, "SDB: updating DLR status in database"); if (dst) like = octstr_format("AND %S LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("UPDATE %S SET %S=%d WHERE %S='%S' AND %S='%S' %S %s", fields->table, fields->field_status, status, fields->field_smsc, smsc, fields->field_ts, ts, like, sdb_get_limit_str()); #if defined(DLR_TRACE) debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL); octstr_destroy(sql); octstr_destroy(like); if (state == -1) error(0, "SDB: error in updating DLR"); else if (!state) warning(0, "SDB: No dlr to update for DST<%s> (status %d)", octstr_get_cstr(dst), status); } static void dlr_sdb_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; int state; debug("dlr.sdb", 0, "removing DLR from database"); if (sdb_conn_type == SDB_POSTGRES) { /* * Postgres doesn't support limiting delete/update queries, * thus we need to use a select subquery. * - notice that for uniqueness use of `oid', postgres suggests * to do vacuum regularly, even if it's virtually impossible * to hit duplicates since oid's are given in a row */ if (dst) like = octstr_format("AND %S LIKE '%%%S')", fields->field_dst, dst); else like = octstr_imm("LIMIT 1)"); sql = octstr_format("DELETE FROM %S WHERE oid = (SELECT oid FROM %S " "WHERE %S='%S' AND %S='%S' %S LIMIT 1", fields->table, fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like); } else { if (dst) like = octstr_format("AND %S LIKE '%%%S'", fields->field_dst, dst); else like = octstr_imm(""); sql = octstr_format("DELETE FROM %S WHERE %S='%S' AND %S='%S' %S %s", fields->table, fields->field_smsc, smsc, fields->field_ts, ts, like, sdb_get_limit_str()); } #if defined(DLR_TRACE) debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL); octstr_destroy(sql); octstr_destroy(like); if (state == -1) error(0, "SDB: error in deleting DLR"); else if (!state) warning(0, "SDB: No dlr deleted for DST<%s>", octstr_get_cstr(dst)); } static long dlr_sdb_messages(void) { Octstr *sql; int state; long res = 0; sql = octstr_format("SELECT count(*) FROM %s", octstr_get_cstr(fields->table)); #if defined(DLR_TRACE) debug("dlr.sdb", 0, "sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), sdb_callback_msgs, &res); octstr_destroy(sql); if (state == -1) { error(0, "SDB: error in selecting ammount of waiting DLRs"); return -1; } return res; } static void dlr_sdb_flush(void) { Octstr *sql; int state; sql = octstr_format("DELETE FROM %s", octstr_get_cstr(fields->table)); #if defined(DLR_TRACE) debug("dlr.sdb", 0, "sql: %s", octstr_get_cstr(sql)); #endif state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL); octstr_destroy(sql); if (state == -1) { error(0, "SDB: error in flusing DLR table"); } } static struct dlr_storage handles = { .type = "sdb", .dlr_add = dlr_sdb_add, .dlr_get = dlr_sdb_get, .dlr_update = dlr_sdb_update, .dlr_remove = dlr_sdb_remove, .dlr_shutdown = dlr_sdb_shutdown, .dlr_messages = dlr_sdb_messages, .dlr_flush = dlr_sdb_flush }; struct dlr_storage *dlr_init_sdb(Cfg* cfg) { CfgGroup *grp; List *grplist; Octstr *sdb_url, *sdb_id; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; /* * check for all mandatory directives that specify the field names * of the used table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db")))) panic(0, "DLR: SDB: group 'dlr-db' is not specified!"); if (!(sdb_id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: SDB: directive 'id' is not specified!"); fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); /* * now grap the required information from the 'mysql-connection' group * with the sdb-id we just obtained * * we have to loop through all available SDB connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("sdb-connection")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, sdb_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "DLR: SDB: connection settings for id '%s' are not specified!", octstr_get_cstr(sdb_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(sdb_url = cfg_get(grp, octstr_imm("url")))) panic(0, "DLR: SDB: directive 'url' is not specified!"); if (octstr_search(sdb_url, octstr_imm("oracle:"), 0) == 0) sdb_conn_type = SDB_ORACLE; else if (octstr_search(sdb_url, octstr_imm("mysql:"), 0) == 0) { warning(0, "DLR[sdb]: Please use native MySQL support, instead of libsdb."); sdb_conn_type = SDB_MYSQL; } else if (octstr_search(sdb_url, octstr_imm("postgres:"), 0) == 0) { sdb_conn_type = SDB_POSTGRES; } else sdb_conn_type = SDB_OTHER; /* * ok, ready to connect */ info(0,"Connecting to sdb resource <%s>.", octstr_get_cstr(sdb_url)); db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->sdb = gw_malloc(sizeof(SDBConf)); gw_assert(db_conf->sdb != NULL); db_conf->sdb->url = sdb_url; pool = dbpool_create(DBPOOL_SDB, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"DLR: SDB: database pool has no connections!"); return &handles; } #else /* * Return NULL , so we point dlr-core that we were * not compiled in. */ struct dlr_storage *dlr_init_sdb(Cfg* cfg) { return NULL; } #endif /* HAVE_SDB */ gateway-1.4.5/gw/heartbeat.h0000644000175000017500000000723013227613126014416 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * heartbeat.h - thread for sending heartbeat Msgs to bearerbox */ #ifndef HEARTBEAT_H #define HEARTBEAT_H #include "gwlib/gwlib.h" #include "msg.h" #define DEFAULT_HEARTBEAT 30 #define ALL_HEARTBEATS -1 /* * Signature for a function that returns the current load value. */ typedef long hb_load_func_t(void); /* * Signature for a function that takes the heartbeat msg and does * something with it. */ typedef void hb_send_func_t(Msg *hb); /* * Start a thread that produces Msgs of type heartbeat on the msgs list. * The speed is approximately one per freq seconds. * The function load_func will be called to determine what should be * filled in for the load parameter. * Return the thread number. Return -1 if the operation failed. */ long heartbeat_start(hb_send_func_t *send_func, double freq, hb_load_func_t *load_func); /* * Stop the indicated heartbeat thread. */ void heartbeat_stop(long hb_thread); #endif gateway-1.4.5/gw/wap_push_pap_mime.c0000644000175000017500000007027213227613126016155 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * Implementation of a gateway oriented mime parser for pap module. This * parser follows proxy rules stated in Push Message, chapter 7. * * By Aarno Syvänen for Wiral Ltd and Global Networks Inc. */ #include "wap_push_pap_mime.h" /***************************************************************************** * * Prototypes for internal functions */ static int is_cr(int c); static int is_lf(int c); static int islwspchar(int c); static long octstr_drop_leading_blanks(Octstr **header_value); static void drop_separator(Octstr **header_value, long *pos); static int parse_preamble(Octstr **mime_content, Octstr *boundary); static long parse_transport_padding(Octstr *mime_content, long pos); static long parse_terminator(Octstr *mime_content, long pos); static int parse_body_part(Octstr **multipart, Octstr *boundary, Octstr **body_part); static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, Octstr **push_data, List **content_headers, Octstr **rdf_content); static int check_control_headers(Octstr **body_part); static int check_control_content_type_header(Octstr **body_part, Octstr *boundary); static int drop_optional_header(Octstr **body_part, char *name, Octstr *boundary); static int drop_header_true(Octstr **body_part, long content_pos); static int drop_extension_headers(Octstr **mime_content, Octstr *boundary); static long parse_field_value(Octstr *pap_content, long pos); static long parse_field_name(Octstr *pap_content, long pos); static void octstr_split_by_pos(Octstr **mime_content, Octstr **pap_content, long boundary_pos); static Octstr *make_close_delimiter(Octstr *boundary); static Octstr *make_part_delimiter(Octstr *boundary); static Octstr *make_start_delimiter(Octstr *dash_boundary); static int pass_data_headers(Octstr **body_part, List **data_headers); static int check_data_x_wap_application_id_header(Octstr **body_part, List **data_headers, Octstr *boundary); static int check_data_content_type_header(Octstr **body_part, List **data_headers, Octstr *boundary); static int pass_optional_header(Octstr **body_part, char *name, List **content_headers, Octstr *boundary); static int pass_extension_headers(Octstr **body_part, List **data_headers, Octstr *boundary); static long pass_field_name(Octstr **body_part, Octstr **content_header, long pos); static long pass_field_value(Octstr **body_part, Octstr **content_header, long pos); static int parse_epilogue(Octstr **mime_content); static int parse_tail(Octstr **multipart, Octstr *part_delimiter, long boundary_pos, long *next_part_pos); /***************************************************************************** * * Implementation of the external function, PAP uses MIME type multipart/ * related to communicate a push message and related control information from * pi to ppg. Mime_parse separates parts of message and in addition returns * MIME-part-headers of the content entity. Preamble and epilogue of are dis- * carded from control messages, but not from a multipart content entity. * Already parsed parts of mime content are removed. * Multipart/related content type is defined in rfc 2046, chapters 5.1, 5.1.1, * and 5.1.7. Grammar is capitulated in rfc 2046 appendix A and in rfc 822, * appendix D. PAP, chapter 8 defines how MIME multipart message is used by PAP * protocol. Functions called by mime_parse remove parsed parts from the mime * content. * Input: pointer to mime boundary and mime content * Output: Pointer to pap control document and push data, if parsable, NULL * otherwise. If there is a capabilities document, pointer to this is return- * ed, too. If there is none, pointer to NULL instead. Neither prologue nor * epilogue is returned. * In addition, return 1 if parsing was succesfull, 0 otherwise. */ int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, Octstr **push_data, List **content_headers, Octstr **rdf_content) { int ret; *pap_content = NULL; *push_data = NULL; *content_headers = NULL; *rdf_content = NULL; if (parse_preamble(&mime_content, boundary) < 0) { warning(0, "erroneous preamble"); return 0; } if (parse_body_part(&mime_content, boundary, pap_content) <= 0) { warning(0, "erroneous control entity"); return 0; } if (check_control_headers(pap_content) == 0) { warning(0, "erroneous control headers"); return 0; } ret = -1; if ((ret = parse_encapsulation(&mime_content, boundary, push_data, content_headers, rdf_content)) < 0) { warning(0, "erroneous content entity (push message)"); return 0; } else if (ret == 0) { gw_assert(*rdf_content == NULL); if (octstr_len(mime_content) != 0) parse_epilogue(&mime_content); return 1; } if (check_control_headers(rdf_content) == 0) { warning(0, "erroneous capacity (rdf) headers"); return 0; } if (octstr_len(mime_content) != 0) parse_epilogue(&mime_content); gw_assert(octstr_len(mime_content) == 0); return 1; } /***************************************************************************** * * Implementation of internal functions */ static int is_cr(int c) { return c == '\r'; } static int is_lf(int c) { return c == '\n'; } /* * Lwspchar is defined in rfc 822, appendix D. */ static int islwspchar(int c) { return c == '\t' || c == ' '; } /* These thingies we after normally have after delimiters. */ static int parse_tail(Octstr **multipart, Octstr *delimiter, long boundary_pos, long *next_part_pos) { *next_part_pos = parse_transport_padding(*multipart, boundary_pos + octstr_len(delimiter)); if ((*next_part_pos = parse_terminator(*multipart, *next_part_pos)) < 0) return -1; return 0; } /* * Boundary misses crlf here. This is intentional: Kannel header parsing pro- * cess drops this terminator. */ static int parse_preamble(Octstr **mime_content, Octstr *boundary) { long boundary_pos, next_part_pos; Octstr *dash_boundary; boundary_pos = next_part_pos = -1; dash_boundary = make_start_delimiter(boundary); if ((boundary_pos = octstr_search(*mime_content, dash_boundary, 0)) < 0) goto error; if (parse_tail(mime_content, dash_boundary, boundary_pos, &next_part_pos) < 0) goto error; octstr_delete(*mime_content, 0, next_part_pos); octstr_destroy(dash_boundary); return 0; error: octstr_destroy(dash_boundary); return -1; } static long parse_terminator(Octstr *mime_content, long pos) { if (is_cr(octstr_get_char(mime_content, pos))) ++pos; else return -1; if (is_lf(octstr_get_char(mime_content, pos))) ++pos; else return -1; return pos; } static long parse_transport_padding(Octstr *mime_content, long pos) { while (islwspchar(octstr_get_char(mime_content, pos))) ++pos; return pos; } static long parse_close_delimiter(Octstr *close_delimiter, Octstr *mime_content, long pos) { if (octstr_ncompare(close_delimiter, mime_content, octstr_len(close_delimiter)) != 0) return -1; pos += octstr_len(close_delimiter); return pos; } /* * Splits the first body part away from the multipart message. A body part end with * either with another body or with a close delimiter. We first split the body and * then remove the separating stuff from the remainder. If we have the last body * part, we must parse all closing stuff. * Returns 1, there is still another body part in the multipart message * 0, if there is none * -1, when parsing error. */ static int parse_body_part (Octstr **multipart, Octstr *boundary, Octstr **body_part) { Octstr *part_delimiter, *close_delimiter; long boundary_pos, /* start of the boundary */ close_delimiter_pos, /* start of the close delimiter */ next_part_pos, /* start of the next part */ epilogue_pos; /* start of the epilogue */ part_delimiter = make_part_delimiter(boundary); close_delimiter = make_close_delimiter(boundary); if ((close_delimiter_pos = octstr_search(*multipart, close_delimiter, 0)) < 0) goto error; boundary_pos = octstr_search(*multipart, part_delimiter, 0); if (boundary_pos == close_delimiter_pos) { octstr_split_by_pos(multipart, body_part, close_delimiter_pos); if ((epilogue_pos = parse_close_delimiter(close_delimiter, *multipart, 0)) < 0) goto error; epilogue_pos = parse_transport_padding(*multipart, epilogue_pos); octstr_delete(*multipart, 0, epilogue_pos); goto last_part; } octstr_split_by_pos(multipart, body_part, boundary_pos); if (parse_tail(multipart, part_delimiter, 0, &next_part_pos) < 0) { goto error; } octstr_delete(*multipart, 0, next_part_pos); octstr_destroy(part_delimiter); octstr_destroy(close_delimiter); return 1; error: octstr_destroy(part_delimiter); octstr_destroy(close_delimiter); return -1; last_part: octstr_destroy(part_delimiter); octstr_destroy(close_delimiter); return 0; } /* * PAP, Chapter 8 states that PAP multipart message MUST have at least two * parts, control entity (containing the pap control message) and content * entity (containing the push message). So we must have at least one body * part here, and at most two (MIME grammar in rfc 2046, appendix A sets no * limitations here). * Input: mime content, part boundary * Output: Push content, rdf content if present, content headers. In addi- * tion, modified mime content (without parsed parts). * Returns 1, if rdf content was present * 0, if it was absent * -1, when error */ static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, Octstr **push_data, List **content_headers, Octstr **rdf_content) { int ret; ret = -1; if ((ret = parse_body_part(mime_content, boundary, push_data)) < 0) return -1; if (pass_data_headers(push_data, content_headers) == 0) return -1; if (ret == 0) { *rdf_content = NULL; return 0; } if ((ret = parse_body_part(mime_content, boundary, rdf_content)) < 0 || ret > 0) return -1; else if (ret == 0) return 1; return 1; } /* * Split os2 from os1, boundary being boundary_pos. */ static void octstr_split_by_pos(Octstr **os1, Octstr **os2, long boundary_pos) { *os2 = octstr_copy(*os1, 0, boundary_pos); octstr_delete(*os1, 0, boundary_pos); } static Octstr *make_close_delimiter(Octstr *boundary) { Octstr *close_delimiter; close_delimiter = make_part_delimiter(boundary); octstr_format_append(close_delimiter, "%s", "--"); return close_delimiter; } static Octstr *make_part_delimiter(Octstr *dash_boundary) { Octstr *part_delimiter; part_delimiter = octstr_create("\r\n--"); octstr_append(part_delimiter, dash_boundary); return part_delimiter; } static Octstr *make_start_delimiter(Octstr *dash_boundary) { Octstr *start_delimiter; start_delimiter = octstr_create("--"); octstr_append(start_delimiter, dash_boundary); return start_delimiter; } /* * Control entity headers must contain Content-Type: application/xml headers. * Rfc 2045, Appendix A does not specify the order of entity headers and states * that all rfc 822 headers having a string "Content" in their field-name must * be accepted. Rfc 822 grammar is capitulated in appendix D. * Message starts after the first null line, so only something after it can be * an extension header (or any header). */ static int check_control_headers(Octstr **body_part) { if (check_control_content_type_header(body_part, octstr_imm("\r\n\r\n")) == 0) return 0; if (drop_optional_header(body_part, "Content-Transfer-Encoding:", octstr_imm("\r\n\r\n")) == 0) return 0; if (drop_optional_header(body_part, "Content-ID:", octstr_imm("\r\n\r\n")) == 0) return 0; if (drop_optional_header(body_part, "Content-Description:", octstr_imm("\r\n\r\n")) == 0) return 0; if (drop_extension_headers(body_part, octstr_imm("\r\n\r\n")) == 0) return 0; return 1; } static int check_control_content_type_header(Octstr **body_part, Octstr *boundary) { long content_pos; long message_start_pos; message_start_pos = octstr_search(*body_part, boundary, 0); if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm("Content-Type:"), 0, message_start_pos)) < 0 || octstr_case_search(*body_part, octstr_imm("application/xml"), 0) < 0) { return 0; } if (drop_header_true(body_part, content_pos) < 0) return 0; return 1; } /* * This function actually removes a header (deletes corresponding part from * the octet string body_part), in addition of all stuff prepending it. So * deleting start from the octet 0. Content_pos tells where the header starts. */ static int drop_header_true(Octstr **body_part, long content_pos) { long next_header_pos; next_header_pos = -1; if ((next_header_pos = parse_field_value(*body_part, content_pos)) == 0) return 0; if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) == 0) return 0; octstr_delete(*body_part, 0, next_header_pos); return 1; } static int drop_optional_header(Octstr **body_part, char *name, Octstr *boundary) { long content_pos; long message_start_pos; content_pos = -1; message_start_pos = octstr_search(*body_part, boundary, 0); if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm(name), 0, message_start_pos)) < 0) return 1; if (drop_header_true(body_part, content_pos) < 0) return 0; return 1; } /* * Extension headers are defined in rfc 822, Appendix D, as fields. We must * parse all rfc 822 headers containing a string "Content". These headers * are optional, too. For general definition of message parts see chapter 4.1. * Specifically: "everything after first null line is message body". */ static int drop_extension_headers(Octstr **body_part, Octstr *boundary) { long content_pos, next_header_pos; long next_content_part_pos; next_content_part_pos = octstr_case_search(*body_part, boundary, 0); do { if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm("Content"), 0, next_content_part_pos)) < 0) return 1; if ((next_header_pos = parse_field_name(*body_part, content_pos)) < 0) return 0; if ((next_header_pos = parse_field_value(*body_part, next_header_pos)) < 0) return 0; if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) == 0) return 0; } while (islwspchar(octstr_get_char(*body_part, next_header_pos))); octstr_delete(*body_part, content_pos, next_header_pos - content_pos); return 1; } static long parse_field_value(Octstr *pap_content, long pos) { int c; while (!is_cr(c = octstr_get_char(pap_content, pos)) && pos < octstr_len(pap_content)) { ++pos; } if (is_lf(c)) { if (is_lf(octstr_get_char(pap_content, pos))) { ++pos; } else { return -1; } } if (pos == octstr_len(pap_content)) { return -1; } return pos; } static long parse_field_name(Octstr *content, long pos) { while (octstr_get_char(content, pos) != ':' && pos < octstr_len(content)) ++pos; if (pos == octstr_len(content)) return -1; return pos; } /* * Transfer entity headers of a body part (it is, from the content entity) * to a header list. Push Message, chapter 6.2.1.10 states that Content-Type * header is mandatory. * Message proper starts after first empty line. We search only to it, and * remove the line here. * Return 0 when error, 1 otherwise. In addition, return the modified body * part and content headers. */ static int pass_data_headers(Octstr **body_part, List **data_headers) { *data_headers = http_create_empty_headers(); /* Transform X-WAP-Application headers as per PPG 6.1.2.1. * Note that missing header means that wml.ua is assumed. */ if (check_data_x_wap_application_id_header(body_part, data_headers, octstr_imm("\r\n\r\n")) == 0) { warning(0, "MIME: %s: X-Wap-Application-Id header missing, assuming 'wml.ua'", __func__); gwlist_append(*data_headers, octstr_create("X-Wap-Application-Id: wml.ua")); } if (check_data_content_type_header(body_part, data_headers, octstr_imm("\r\n\r\n")) == 0) { warning(0, "MIME: %s: Content-Type header missing", __func__); return 0; } if (pass_optional_header(body_part, "Content-Transfer-Encoding", data_headers, octstr_imm("\r\n\r\n")) < 0) goto operror; if (pass_optional_header(body_part, "Content-ID", data_headers, octstr_imm("\r\n\r\n")) < 0) goto operror; if (pass_optional_header(body_part, "Content-Description", data_headers, octstr_imm("\r\n\r\n")) < 0) goto operror; if (pass_extension_headers(body_part, data_headers, octstr_imm("\r\n\r\n")) == 0) goto operror; /* * XXX: TODO: This assumes that there are no further headers prefixing * the MIME body. Which MAY not be the case. We SHOULD rather move all * headers to the data_headers and ensure by this that there are no * left overs. */ octstr_delete(*body_part, 0, octstr_len(octstr_imm("\r\n"))); return 1; operror: warning(0, "MIME: pass_data_headers: an unparseable optional header"); return 0; } /* * Checks if body_part contains a X-Wap-Application-Id header. Transfers this header to * a list content_headers. * Return 1, when X-Wap-Application-Id header was found, 0 otherwise */ static int check_data_x_wap_application_id_header(Octstr **body_part, List **content_headers, Octstr *boundary) { long header_pos, next_header_pos; Octstr *content_header; long message_start_pos; header_pos = next_header_pos = -1; content_header = octstr_create("X-Wap-Application-Id"); message_start_pos = octstr_search(*body_part, boundary, 0); if ((header_pos = octstr_case_nsearch(*body_part, content_header, 0, message_start_pos)) < 0) { goto error; } if ((next_header_pos = pass_field_value(body_part, &content_header, header_pos + octstr_len(content_header))) < 0) { goto error; } if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) < 0) { goto error; } octstr_delete(*body_part, header_pos, next_header_pos - header_pos); gwlist_append(*content_headers, octstr_duplicate(content_header)); octstr_destroy(content_header); return 1; error: octstr_destroy(content_header); return 0; } /* * Checks if body_part contains a Content-Type header. Transfers this header to * a list content_headers. (Only part before 'boundary'). * Return 1, when Content-Type headers was found, 0 otherwise */ static int check_data_content_type_header(Octstr **body_part, List **content_headers, Octstr *boundary) { long header_pos, next_header_pos; Octstr *content_header; long message_start_pos; header_pos = next_header_pos = -1; content_header = octstr_create("Content-Type"); message_start_pos = octstr_search(*body_part, boundary, 0); if ((header_pos = octstr_case_nsearch(*body_part, content_header, 0, message_start_pos)) < 0) { goto error; } if ((next_header_pos = pass_field_value(body_part, &content_header, header_pos + octstr_len(content_header))) < 0) { goto error; } if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) < 0) { goto error; } octstr_delete(*body_part, header_pos, next_header_pos - header_pos); gwlist_append(*content_headers, octstr_duplicate(content_header)); octstr_destroy(content_header); return 1; error: octstr_destroy(content_header); return 0; } /* * We try to find an optional header, so a failure to find one is not an * error. Return -1 when error, 0 when header name not found, 1 otherwise. * Search only until 'boundary'. */ static int pass_optional_header(Octstr **body_part, char *name, List **content_headers, Octstr *boundary) { long content_pos, next_header_pos; Octstr *osname, *osvalue; long message_start_pos; content_pos = next_header_pos = -1; osname = octstr_create(name); osvalue = octstr_create(""); message_start_pos = octstr_search(*body_part, boundary, 0); if ((content_pos = octstr_case_nsearch(*body_part, osname, 0, message_start_pos)) < 0) goto noheader; if ((next_header_pos = pass_field_value(body_part, &osvalue, content_pos + octstr_len(osname))) < 0) goto error; if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) == 0) goto error; drop_separator(&osvalue, &next_header_pos); http_header_add(*content_headers, name, octstr_get_cstr(osvalue)); octstr_delete(*body_part, content_pos, next_header_pos - content_pos); octstr_destroy(osname); octstr_destroy(osvalue); return 1; error: octstr_destroy(osvalue); octstr_destroy(osname); return -1; noheader: octstr_destroy(osvalue); octstr_destroy(osname); return 0; } /* * Remove ':' plus spaces from the header value */ static void drop_separator(Octstr **header_value, long *pos) { long count; octstr_delete(*header_value, 0, 1); /* remove :*/ count = octstr_drop_leading_blanks(header_value); pos = pos - 1 - count; } /* * Return number of spaces dropped. */ static long octstr_drop_leading_blanks(Octstr **header_value) { long count; count = 0; while (octstr_get_char(*header_value, 0) == ' ') { octstr_delete(*header_value, 0, 1); ++count; } return count; } /* * Extension headers are optional, see Push Message, chapter 6.2. Field struc- * ture is defined in rfc 822, chapter 3.2. Extension headers are defined in * rfc 2045, chapter 9, grammar in appendix A. (Only to the next null line). * Return 0 when error, 1 otherwise. */ static int pass_extension_headers(Octstr **body_part, List **content_headers, Octstr *boundary) { long next_field_part_pos; Octstr *header_name, *header_value; long next_content_part_pos; header_name = octstr_create(""); header_value = octstr_create(""); next_field_part_pos = 0; next_content_part_pos = octstr_search(*body_part, boundary, 0); do { if ((octstr_case_nsearch(*body_part, octstr_imm("Content"), 0, next_content_part_pos)) < 0) goto end; if ((next_field_part_pos = pass_field_name(body_part, &header_name, next_field_part_pos)) < 0) goto error; if ((next_field_part_pos = pass_field_value(body_part, &header_value, next_field_part_pos)) < 0) goto error; if ((next_field_part_pos = parse_terminator(*body_part, next_field_part_pos)) == 0) goto error; drop_separator(&header_value, &next_field_part_pos); http_header_add(*content_headers, octstr_get_cstr(header_name), octstr_get_cstr(header_value)); } while (islwspchar(octstr_get_char(*body_part, next_field_part_pos))); octstr_delete(*body_part, 0, next_field_part_pos); /* * An intentional fall-through. We must eventually use a function for memory * cleaning. */ end: octstr_destroy(header_name); octstr_destroy(header_value); return 1; error: octstr_destroy(header_name); octstr_destroy(header_value); return 0; } static long pass_field_value(Octstr **body_part, Octstr **header, long pos) { int c; long start; Octstr *field = NULL; start = pos; while (!is_cr(c = octstr_get_char(*body_part, pos)) && pos < octstr_len(*body_part)) { ++pos; } if (pos == octstr_len(*body_part)) { return -1; } field = octstr_copy(*body_part, start, pos - start); octstr_append(*header, field); octstr_destroy(field); return pos; } static long pass_field_name(Octstr **body_part, Octstr **field_part, long pos) { int c; long start; Octstr *name = NULL; start = pos; while (((c = octstr_get_char(*body_part, pos)) != ':') && pos < octstr_len(*body_part)) { ++pos; } if (pos == octstr_len(*body_part)) { return -1; } name = octstr_copy(*body_part, start, pos - start); octstr_append(*field_part, name); octstr_destroy(name); return pos; } /* This is actually CRLF epilogue. */ static int parse_epilogue(Octstr **mime_content) { long pos; if (octstr_len(*mime_content) == 0) return 0; if ((pos = parse_terminator(*mime_content, 0)) < 0) return -1; octstr_delete(*mime_content, 0, octstr_len(*mime_content)); return 0; } gateway-1.4.5/gw/smscconn.h0000644000175000017500000002035313227613126014303 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef SMSCCONN_H #define SMSCCONN_H /* * SMSC Connection * * Interface for main bearerbox to SMS center connection modules * * At first stage a simple wrapper for old ugly smsc module * * Kalle Marjola 2000 */ #include "gwlib/gwlib.h" #include "gw/msg.h" /* * Structure hierarchy: * * Bearerbox keeps list of pointers to SMSCConn structures, which * include all data needed by connection, including routing data. * If any extra data not linked to that SMSC Connection is needed, * that is held in bearerbox * * SMSCConn is internal structure for smscconn module. It has a list * of common variables like number of sent/received messages and * and pointers to appropriate lists, and then it has a void pointer * to appropriate smsc structure defined and used by corresponding smsc * connection type module (like CIMD2, SMPP etc al) * * Concurrency notes: * * bearerbox is responsible for not calling cleanup at the same time * as it calls other functions, but must call it after it has noticed that * status == KILLED */ typedef struct smscconn SMSCConn; typedef enum { SMSCCONN_CONNECTING, SMSCCONN_ACTIVE, SMSCCONN_ACTIVE_RECV, SMSCCONN_RECONNECTING, SMSCCONN_DISCONNECTED, SMSCCONN_DEAD /* ready to be cleaned */ } smscconn_status_t; typedef enum { SMSCCONN_ALIVE = 0, SMSCCONN_KILLED_WRONG_PASSWORD = 1, SMSCCONN_KILLED_CANNOT_CONNECT = 2, SMSCCONN_KILLED_SHUTDOWN = 3 } smscconn_killed_t; typedef struct smsc_state { smscconn_status_t status; /* see enumeration, below */ smscconn_killed_t killed; /* if we are killed, why */ int is_stopped; /* is connection currently in stopped state? */ unsigned long received; /* total number */ unsigned long received_dlr; /* total number */ unsigned long sent; /* total number */ unsigned long sent_dlr; /* total number */ unsigned long failed; /* total number */ long queued; /* set our internal outgoing queue length */ long online; /* in seconds */ int load; /* subjective value 'how loaded we are' for * routing purposes, similar to sms/wapbox load */ } StatusInfo; /* create new SMS center connection from given configuration group, * or return NULL if failed. * * The new connection does its work in its own privacy, and calls * callback functions at bb_smscconn_cb module. It calls function * bb_smscconn_ready when it has put everything up. * * NOTE: this function starts one or more threads to * handle traffic with SMSC, and caller does not need to * care about it afterwards. */ SMSCConn *smscconn_create(CfgGroup *cfg, int start_as_stopped); /* shutdown/destroy smscc. Stop receiving messages and accepting * new message to-be-sent. Die when any internal queues are empty, * if finish_sending != 0, or if set to 0, kill connection ASAP and * call send_failed -callback for all messages still in queue */ void smscconn_shutdown(SMSCConn *smscconn, int finish_sending); /* this is final function to cleanup all memory still held by * SMSC Connection after it has been killed (for synchronization * problems it cannot be cleaned automatically) * Call this after send returns problems or otherwise notice that * status is KILLED. Returns 0 if OK, -1 if it cannot be (yet) destroyed. */ int smscconn_destroy(SMSCConn *smscconn); /* stop smscc. A stopped smscc does not receive any messages, but can * still send messages, so that internal queue can be emptied. The caller * is responsible for not to add new messages into queue if the caller wants * the list to empty at some point */ int smscconn_stop(SMSCConn *smscconn); /* start stopped smscc. Return -1 if failed, 0 otherwise */ void smscconn_start(SMSCConn *smscconn); /* Return name of the SMSC, as reference - caller may not free it! */ const Octstr *smscconn_name(SMSCConn *smscconn); /* Return ID of the SMSC, as reference - caller may not free it! */ const Octstr *smscconn_id(SMSCConn *conn); /* Return Admin ID of the SMSC, as reference - caller may not free it! */ const Octstr *smscconn_admin_id(SMSCConn *conn); /* Check if this SMSC Connection is usable as sender for given * message. The bearerbox must then select the good SMSC for sending * according to load levels and connected/disconnected status, this * function only checks preferred/denied strings and overall status * * Return -1 if not (denied or permanently down), 0 if okay, * 1 if preferred one. */ int smscconn_usable(SMSCConn *conn, Msg *msg); /* Call SMSC specific function to handle sending of 'msg' * Returns immediately, with 0 if successful and -1 if failed. * In any case the caller is still responsible for 'msg' after this * call * Note that return value does NOT mean that message has been send * or send has failed, but SMSC Connection calls appropriate callback * function later */ int smscconn_send(SMSCConn *smsccconn, Msg *msg); /* Return just status as defined below */ int smscconn_status(SMSCConn *smscconn); /* return current status of the SMSC connection, filled to infotable. * For unknown numbers, put -1. Return -1 if either argument was NULL. */ int smscconn_info(SMSCConn *smscconn, StatusInfo *infotable); /* Determine if the specific SMS center group will be started * with multiple instances. * Return the number of multiple instances that should be started. * If no multiple indicator is set in the config group, then 1 * is returned. */ unsigned int smscconn_instances(CfgGroup *grp); /* Reconfigure the running SMSC for any routing relevant * information from the configuration group. */ void smscconn_reconfig(SMSCConn *conn, CfgGroup *grp); #endif gateway-1.4.5/gw/wap_push_si_compiler.c0000644000175000017500000004376413227613126016701 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_si_compiler.c: Tokenizes a SI document. SI DTD is defined in * Wapforum specification WAP-167-ServiceInd-20010731-a (hereafter called si), * chapter 8.2. * * By Aarno Syvänen for Wiral Ltd */ #include #include #include #include #include #include #include "shared.h" #include "xml_shared.h" #include "wap_push_si_compiler.h" /**************************************************************************** * * Global variables * * Two token table types, one and two token fields */ struct si_2table_t { char *name; unsigned char token; }; typedef struct si_2table_t si_2table_t; /* * Value part can mean part or whole of the value. It can be NULL, too, which * means that no part of the value will be tokenised. See si, chapter 9.3.2. */ struct si_3table_t { char *name; char *value_part; unsigned char token; }; typedef struct si_3table_t si_3table_t; /* * Elements from tag code page zero. These are defined in si, chapter 9.3.1. */ static si_2table_t si_elements[] = { { "si", 0x05 }, { "indication", 0x06 }, { "info", 0x07 }, { "item", 0x08 } }; #define NUMBER_OF_ELEMENTS sizeof(si_elements)/sizeof(si_elements[0]) /* * Attributes (and start or whole value of ) from attribute code page zero. * These are defined in si, chapter 9.3.2. */ static si_3table_t si_attributes[] = { { "action", "signal-none", 0x05 }, { "action", "signal-low", 0x06 }, { "action", "signal-medium", 0x07 }, { "action", "signal-high", 0x08 }, { "action", "delete", 0x09 }, { "created", NULL, 0x0a }, { "href", "https://www.", 0x0f }, { "href", "http://www.", 0x0d }, { "href", "https://", 0x0e }, { "href", "http://", 0x0c }, { "href", NULL, 0x0b }, { "si-expires", NULL, 0x10 }, { "si-id", NULL, 0x11 }, { "class", NULL, 0x12 } }; #define NUMBER_OF_ATTRIBUTES sizeof(si_attributes)/sizeof(si_attributes[0]) /* * Attribute value tokes (URL value codes), from si, chapter 9.3.3. */ static si_2table_t si_URL_values[] = { { ".com/", 0x85 }, { ".edu/", 0x86 }, { ".net/", 0x87 }, { ".org/", 0x88 } }; #define NUMBER_OF_URL_VALUES sizeof(si_URL_values)/sizeof(si_URL_values[0]) #include "xml_definitions.h" /**************************************************************************** * * Prototypes of internal functions. Note that 'Ptr' means here '*'. */ static int parse_document(xmlDocPtr document, Octstr *charset, simple_binary_t **si_binary); static int parse_node(xmlNodePtr node, simple_binary_t **sibxml); static int parse_element(xmlNodePtr node, simple_binary_t **sibxml); static int parse_text(xmlNodePtr node, simple_binary_t **sibxml); static int parse_cdata(xmlNodePtr node, simple_binary_t **sibxml); static int parse_attribute(xmlAttrPtr attr, simple_binary_t **sibxml); static int url(int hex); static int action(int hex); static int date(int hex); static Octstr *tokenize_date(Octstr *date); static void octstr_drop_trailing_zeros(Octstr **date_token); static void flag_date_length(Octstr **token); static void parse_url_value(Octstr *value, simple_binary_t **sibxml); /**************************************************************************** * * Implementation of the external function */ int si_compile(Octstr *si_doc, Octstr *charset, Octstr **si_binary) { simple_binary_t *sibxml; int ret; xmlDocPtr pDoc; size_t size; char *si_c_text; *si_binary = octstr_create(""); sibxml = simple_binary_create(); octstr_strip_blanks(si_doc); set_charset(si_doc, charset); size = octstr_len(si_doc); si_c_text = octstr_get_cstr(si_doc); pDoc = xmlParseMemory(si_c_text, size); ret = 0; if (pDoc) { ret = parse_document(pDoc, charset, &sibxml); simple_binary_output(*si_binary, sibxml); xmlFreeDoc(pDoc); } else { xmlFreeDoc(pDoc); octstr_destroy(*si_binary); simple_binary_destroy(sibxml); error(0, "SI: No document to parse. Probably an error in SI source"); return -1; } simple_binary_destroy(sibxml); return ret; } /**************************************************************************** * * Implementation of internal functions * * Parse document node. Store si version number, public identifier and char- * acter set into the start of the document. FIXME: Add parse_prologue! */ static int parse_document(xmlDocPtr document, Octstr *charset, simple_binary_t **sibxml) { xmlNodePtr node; (*sibxml)->wbxml_version = 0x02; /* WBXML Version number 1.2 */ (*sibxml)->public_id = 0x05; /* SI 1.0 Public ID */ charset = octstr_create("UTF-8"); (*sibxml)->charset = parse_charset(charset); octstr_destroy(charset); node = xmlDocGetRootElement(document); return parse_node(node, sibxml); } /* * Parse an element node. Check if there is a token for an element tag; if not * output the element as a string, else ouput the token. After that, call * attribute parsing functions * Returns: 1, add an end tag (element node has no children) * 0, do not add an end tag (it has children) * -1, an error occurred */ static int parse_element(xmlNodePtr node, simple_binary_t **sibxml) { Octstr *name, *outos; size_t i; unsigned char status_bits, si_hex; int add_end_tag; xmlAttrPtr attribute; name = octstr_create((char *)node->name); outos = NULL; if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } i = 0; while (i < NUMBER_OF_ELEMENTS) { if (octstr_compare(name, octstr_imm(si_elements[i].name)) == 0) break; ++i; } status_bits = 0x00; si_hex = 0x00; add_end_tag = 0; if (i != NUMBER_OF_ELEMENTS) { si_hex = si_elements[i].token; if ((status_bits = element_check_content(node)) > 0) { si_hex = si_hex | status_bits; if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) add_end_tag = 1; } output_char(si_hex, sibxml); } else { warning(0, "unknown tag %s in SI source", octstr_get_cstr(name)); si_hex = WBXML_LITERAL; if ((status_bits = element_check_content(node)) > 0) { si_hex = si_hex | status_bits; /* If this node has children, the end tag must be added after them. */ if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) add_end_tag = 1; } output_char(si_hex, sibxml); output_octet_string(outos = octstr_duplicate(name), sibxml); } if (node->properties != NULL) { attribute = node->properties; while (attribute != NULL) { parse_attribute(attribute, sibxml); attribute = attribute->next; } parse_end(sibxml); } octstr_destroy(outos); octstr_destroy(name); return add_end_tag; } /* * Parse a text node of a si document. Ignore empty text nodes (space addi- * tions to certain points will produce these). Si codes text nodes as an * inline string. */ static int parse_text(xmlNodePtr node, simple_binary_t **sibxml) { Octstr *temp; temp = create_octstr_from_node((char *)node); octstr_shrink_blanks(temp); octstr_strip_blanks(temp); if (octstr_len(temp) == 0) { octstr_destroy(temp); return 0; } parse_inline_string(temp, sibxml); octstr_destroy(temp); return 0; } /* * Tokenises an attribute, and in most cases, the start of its value (some- * times whole of it). Tokenisation is based on tables in si, chapters 9.3.2 * and 9.3.3. * Returns 0 when success, -1 when error. */ static int parse_attribute(xmlAttrPtr attr, simple_binary_t **sibxml) { Octstr *name, *value, *valueos, *tokenized_date; unsigned char si_hex; size_t i, value_len; name = octstr_create((char *)attr->name); if (attr->children != NULL) value = create_octstr_from_node((char *)attr->children); else value = NULL; if (value == NULL) goto error; i = 0; valueos = NULL; while (i < NUMBER_OF_ATTRIBUTES) { if (octstr_compare(name, octstr_imm(si_attributes[i].name)) == 0) { if (si_attributes[i].value_part == NULL) { break; } else { value_len = octstr_len(valueos = octstr_imm(si_attributes[i].value_part)); if (octstr_ncompare(value, valueos, value_len) == 0) { break; } } } ++i; } if (i == NUMBER_OF_ATTRIBUTES) goto error; tokenized_date = NULL; si_hex = si_attributes[i].token; if (action(si_hex)) { output_char(si_hex, sibxml); } else if (url(si_hex)) { output_char(si_hex, sibxml); octstr_delete(value, 0, octstr_len(valueos)); parse_url_value(value, sibxml); } else if (date(si_hex)) { if ((tokenized_date = tokenize_date(value)) == NULL) goto error; output_char(si_hex, sibxml); output_octet_string(tokenized_date, sibxml); } else { output_char(si_hex, sibxml); parse_inline_string(value, sibxml); } octstr_destroy(tokenized_date); octstr_destroy(name); octstr_destroy(value); return 0; error: octstr_destroy(name); octstr_destroy(value); return -1; } /* * checks whether a si attribute value is an URL or some other kind of value. * Returns 1 for an URL and 0 otherwise. */ static int url(int hex) { switch ((unsigned char) hex) { case 0x0b: /* href */ case 0x0c: case 0x0e: /* href http://, href https:// */ case 0x0d: case 0x0f: /* href http://www., href https://www. */ return 1; } return 0; } /* * checks whether a si attribute value is an action attribute or some other * kind of value. * Returns 1 for an action attribute and 0 otherwise. */ static int action(int hex) { switch ((unsigned char) hex) { case 0x05: case 0x06: /* action signal-none, action signal-low */ case 0x07: case 0x08: /* action signal-medium, action signal-high */ case 0x09: /* action delete */ return 1; } return 0; } /* * checks whether a si attribute value is an OSI date or some other kind of * value. * Returns 1 for an action attribute and 0 otherwise. */ static int date(int hex) { switch ((unsigned char) hex) { case 0x0a: case 0x10: /* created, si-expires */ return 1; } return 0; } /* * Tokenises an OSI date. Procedure is defined in si, chapter 9.2.2. Validate * OSI date as specified in 9.2.1.1. Returns NULL when error, a tokenised date * string otherwise. */ static Octstr *tokenize_date(Octstr *date) { Octstr *date_token; long j; size_t i, date_len; unsigned char c; if (!parse_date(date)) { return NULL; } date_token = octstr_create(""); octstr_append_char(date_token, WBXML_OPAQUE); i = 0; j = 0; date_len = octstr_len(date); while (i < date_len) { c = octstr_get_char(date, i); if (c != 'T' && c != 'Z' && c != '-' && c != ':') { if (isdigit(c)) { octstr_set_bits(date_token, 4*j + 8, 4, c & 0x0f); ++j; } else { octstr_destroy(date_token); return NULL; } } ++i; } octstr_drop_trailing_zeros(&date_token); flag_date_length(&date_token); return date_token; } static void octstr_drop_trailing_zeros(Octstr **date_token) { while (1) { if (octstr_get_char(*date_token, octstr_len(*date_token) - 1) == '\0') octstr_delete(*date_token, octstr_len(*date_token) - 1, 1); else return; } } static void flag_date_length(Octstr **token) { Octstr *lenos; lenos = octstr_format("%c", octstr_len(*token) - 1); octstr_insert(*token, lenos, 1); octstr_destroy(lenos); } /* * The recursive parsing function for the parsing tree. Function checks the * type of the node, calls for the right parse function for the type, then * calls itself for the first child of the current node if there's one and * after that calls itself for the next child on the list. */ static int parse_node(xmlNodePtr node, simple_binary_t **sibxml) { int status = 0; /* Call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_element(node, sibxml); break; case XML_TEXT_NODE: status = parse_text(node, sibxml); break; case XML_CDATA_SECTION_NODE: status = parse_cdata(node, sibxml); break; case XML_COMMENT_NODE: case XML_PI_NODE: /* Comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * SI. Therefore they are assumed to be an error. */ default: error(0, "SI compiler: Unknown XML node in the SI source."); return -1; break; } /* * If node is an element with content, it will need an end tag after it's * children. The status for it is returned by parse_element. */ switch (status) { case 0: if (node->children != NULL) if (parse_node(node->children, sibxml) == -1) return -1; break; case 1: if (node->children != NULL) if (parse_node(node->children, sibxml) == -1) return -1; parse_end(sibxml); break; case -1: /* Something went wrong in the parsing. */ return -1; default: warning(0,"SI compiler: undefined return value in a parse function."); return -1; break; } if (node->next != NULL) if (parse_node(node->next, sibxml) == -1) return -1; return 0; } /* * Cdata section parsing function. Output this "as it is" */ static int parse_cdata(xmlNodePtr node, simple_binary_t **sibxml) { int ret = 0; Octstr *temp; temp = create_octstr_from_node((char *)node); parse_octet_string(temp, sibxml); octstr_destroy(temp); return ret; } /* * In the case of SI documents, only attribute values to be tokenized are * parts of urls (see si, chapter 9.3.3). The caller romoves the start of an * url. Check whether we can find parts in the value. If not, parse value a an * inline string, otherwise parse parts before and after tokenizable parts as * inline strings. */ void parse_url_value(Octstr *value, simple_binary_t **sibxml) { size_t i; long pos; Octstr *urlos, *first_part, *last_part; size_t first_part_len; i = 0; first_part_len = 0; first_part = NULL; last_part = NULL; while (i < NUMBER_OF_URL_VALUES) { pos = octstr_search(value, urlos = octstr_imm(si_URL_values[i].name), 0); if (pos >= 0) { first_part = octstr_duplicate(value); octstr_delete(first_part, pos, octstr_len(first_part) - pos); first_part_len = octstr_len(first_part); parse_inline_string(first_part, sibxml); output_char(si_URL_values[i].token, sibxml); last_part = octstr_duplicate(value); octstr_delete(last_part, 0, first_part_len + octstr_len(urlos)); parse_inline_string(last_part, sibxml); octstr_destroy(first_part); octstr_destroy(last_part); break; } octstr_destroy(urlos); ++i; } if (pos < 0) parse_inline_string(value, sibxml); } gateway-1.4.5/gw/kannel.80000644000175000017500000000214607166363552013662 0ustar toljtolj.\" Hey, Emacs! This is an -*- nroff -*- source file. .TH KANNEL 8 "3rd October 2000" "Kannel Project" "Kannel Project" .SH NAME bearerbox, wapbox, smsbox \- Parts of Kannel, the WAP and SMS gateway .SH SYNOPSIS .B bearerbox .IR "" [ options ... "] [" conffile ] .PP .B wapbox .IR "" [ options ... "] [" conffile ] .PP .B smsbox .IR "" [ options ... "] [" conffile ] .SH DESCRIPTION .I Kannel is an WAP and SMS gateway. WAP is short for Wireless Application Protocol, and is used to implement hypertext based services on mobile phones. SMS is short for Short Message Service, and is used to send and recive short (up to 160 characters) text messages with mobile phones. SMS can also be used to implement simple text based services on mobile phones. .PP Kannel consists of three programs, usually run as daemons: .BR bearerbox , .BR wapbox , and .BR smsbox . They implement the connection to the phone (SMS or UDP), the WAP protocol stack, and the SMS based services, respectively. .PP For more information, see .B http://www.kannel.org or .BR file://usr/doc/kannel/ . .SH "SEE ALSO" .BR run_kannel_box (8), .BR seewbmp (1). gateway-1.4.5/gw/dlr_spool.c0000644000175000017500000004217513245353052014455 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/dlr_spool.c * * Implementation of handling delivery reports (DLRs) in a spool directory. * This ensures we have disk persistence of the temporary DLR data, but also * doesn't force users to use third party RDMS systems for the storage. * * Stipe Tolj */ #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "dlr_p.h" #include "sms.h" #include "bb_store.h" #ifdef HAVE_NFTW #include #endif /* some standard constant for the hash functions */ #define MD5_DIGEST_LEN 32 #define SHA1_DIGEST_LEN 40 #ifdef HAVE_LIBSSL # define OUR_DIGEST_LEN SHA1_DIGEST_LEN #else # define OUR_DIGEST_LEN MD5_DIGEST_LEN #endif /* how much sub-directories will we allow? */ #define MAX_DIRS 100 /* * Define this macro in order to get verified counter * values while start-up. This will decrease start-up performance, * especially for large scale DLR spools */ /* #define VERIFIED 1 */ /* * Our DLR spool location. */ static Octstr *spool_dir = NULL; /* * Internal counter keeping track of how many items we have. */ static Counter *counter; /******************************************************************** * Hashing functions. */ /* * Calculates a SHA1 hash digest, if openssl library was available * on the system, or a less secure MD5 hash digest. */ static Octstr *our_hash_func(Octstr *os) { #ifdef HAVE_LIBSSL /* use openssl's SHA1 */ unsigned char hash[20]; Octstr *ret; memset(hash, 0, sizeof(hash)); SHA1((const unsigned char *)octstr_get_cstr(os), octstr_len(os), hash); ret = octstr_create_from_data((const char*)hash, sizeof(hash)); octstr_binary_to_hex(ret, 0); return ret; #else /* fallback to our own MD5 if we don't have openssl available */ return md5digest(os); #endif } /******************************************************************** * Disk IO operations. */ /* * This callback function for use with for_each_file() will really * try to load the DLR message file from the DLR spool and try to * unpack it. This ensures we get a real accurate counter value at * startup time. */ #ifdef VERIFIED #ifdef HAVE_NFTW static int verified_file(const char *filename, const struct stat *sb, int tflag, struct FTW *ftwbuf) { Octstr *os; Msg *msg; /* we need to check here if we have a regular file. */ if (tflag != FTW_F) return 0; #else static int verified_file(const char *filename, const struct stat *sb, int tflag, void *ftwbuf) { Octstr *os; Msg *msg; #endif if ((os = octstr_read_file(filename)) == NULL) { return -1; } if ((msg = store_msg_unpack(os)) == NULL) { error(0, "Could not unpack DLR message `%s'", filename); octstr_destroy(os); return -1; } /* we could load and unpack, so this is verified */ counter_increase(counter); octstr_destroy(os); msg_destroy(msg); return 0; } #endif /* * This callback function for use with for_each_file() will be more * optimistic and simply account and file occurrences, without trying * to load and unpack the DLR message. This is less accurate, but * faster for very large DLR spools. */ #ifdef HAVE_NFTW static int non_verified_file(const char *filename, const struct stat *sb, int tflag, struct FTW *ftwbuf) { /* we need to check here if we have a regular file. */ if (tflag != FTW_F) return 0; #else static int non_verified_file(const char *filename, const struct stat *sb, int tflag, void *ftwbuf) { #endif counter_increase(counter); return 0; } /* * This callback function for use with for_each_file() will unlink * the file, and hence removing all regular files within the DLR spool. */ #ifdef HAVE_NFTW static int unlink_file(const char *filename, const struct stat *sb, int tflag, struct FTW *ftwbuf) { /* we need to check here if we have a regular file. */ if (tflag != FTW_F) return 0; #else static int unlink_file(const char *filename, const struct stat *sb, int tflag, void *ftwbuf) { #endif /* remove the file from the file system */ if (unlink(filename) == -1) { error(errno, "Could not unlink file `%s'.", filename); } return 0; } /* * The function traverses a directory structure and calls a callback * function for each regular file within that directory structure. */ #ifdef HAVE_NFTW static int for_each_file(const Octstr *dir_s, int ignore_err, int(*cb)(const char *, const struct stat *, int, struct FTW *)) { int ret; ret = nftw(octstr_get_cstr(dir_s), cb, 20, FTW_PHYS); return ret; } #else static int for_each_file(const Octstr *dir_s, int ignore_err, int(*cb)(const char *, const struct stat *, int, void *)) { DIR *dir; struct dirent *ent; int ret = 0; #ifndef _DIRENT_HAVE_D_TYPE struct stat stat; #endif if ((dir = opendir(octstr_get_cstr(dir_s))) == NULL) { error(errno, "Could not open directory `%s'", octstr_get_cstr(dir_s)); return -1; } while ((ent = readdir(dir)) != NULL) { Octstr *filename; if (!(strcmp((char*)ent->d_name, "." ) != 0 && strcmp((char*)ent->d_name, ".." ) != 0)) continue; filename = octstr_format("%S/%s", dir_s, ent->d_name); #ifdef _DIRENT_HAVE_D_TYPE if (ent->d_type == DT_DIR && for_each_file(filename, ignore_err, cb) == -1) { ret = -1; } else if (ent->d_type == DT_REG && cb != NULL) { cb(octstr_get_cstr(filename), NULL, 0, NULL); } #else if (lstat(octstr_get_cstr(filename), &stat) == -1) { if (!ignore_err) error(errno, "Could not get stat for `%s'", octstr_get_cstr(filename)); ret = -1; } else if (S_ISDIR(stat.st_mode) && for_each_file(filename, ignore_err, cb) == -1) { ret = -1; } else if (S_ISREG(stat.st_mode) && cb != NULL) cb(octstr_get_cstr(filename), &stat, 0, NULL); #endif octstr_destroy(filename); if (ret == -1 && ignore_err) ret = 0; else if (ret == -1) break; } closedir(dir); return ret; } #endif static Octstr *get_msg_filename(const Octstr *dir_s, const Octstr *hash, const Octstr *dst) { Octstr *ret; DIR *dir; struct dirent *ent; if ((dir = opendir(octstr_get_cstr(dir_s))) == NULL) { error(errno, "Could not open directory `%s'", octstr_get_cstr(dir_s)); return NULL; } while ((ent = readdir(dir)) != NULL) { Octstr *fname = octstr_create((char*)ent->d_name); if (octstr_ncompare(fname, hash, OUR_DIGEST_LEN) == 0) { Octstr *addr; long addr_len, pos; /* this is a candidate */ if (dst == NULL) goto found; /* check for the destination address suffix part */ if ((addr_len = (octstr_len(fname) - OUR_DIGEST_LEN)) < 0 || (pos = (addr_len - octstr_len(dst))) < 0) { octstr_destroy(fname); continue; } addr = octstr_copy(fname, OUR_DIGEST_LEN, addr_len); /* if not found, then bail out*/ if (octstr_search(addr, dst, pos) == -1) { octstr_destroy(addr); octstr_destroy(fname); continue; } octstr_destroy(addr); found: /* found it */ closedir(dir); ret = octstr_format("%S/%S", dir_s, fname); octstr_destroy(fname); return ret; } octstr_destroy(fname); } closedir(dir); return NULL; } static Octstr *get_msg_surrogate(const Octstr *dir_s, const Octstr *hash, const Octstr *dst, Octstr **filename) { /* get our msg filename */ if ((*filename = get_msg_filename(dir_s, hash, dst)) == NULL) return NULL; return octstr_read_file(octstr_get_cstr(*filename)); } /******************************************************************** * Implementation of the DLR handle functions. */ /* * Adds a struct dlr_entry to the spool directory. */ static void dlr_spool_add(struct dlr_entry *dlr) { Msg *msg; Octstr *os, *hash, *dir, *filename; int fd; size_t wrc; #define MAP(to, from) \ to = from; \ from = NULL; /* create a common message structure to contain our values */ msg = msg_create(sms); msg->sms.sms_type = report_mt; MAP(msg->sms.smsc_id, dlr->smsc); MAP(msg->sms.foreign_id, dlr->timestamp); MAP(msg->sms.sender, dlr->source); MAP(msg->sms.receiver, dlr->destination); MAP(msg->sms.service, dlr->service); MAP(msg->sms.dlr_url, dlr->url); MAP(msg->sms.boxc_id, dlr->boxc_id); msg->sms.dlr_mask = dlr->mask; /* we got all values, destroy the structure now */ dlr_entry_destroy(dlr); /* create hash value */ os = octstr_duplicate(msg->sms.smsc_id); octstr_append(os, msg->sms.foreign_id); hash = our_hash_func(os); octstr_destroy(os); /* target directory */ dir = octstr_format("%S/%ld", spool_dir, octstr_hash_key(hash) % MAX_DIRS); if (mkdir(octstr_get_cstr(dir), S_IRUSR|S_IWUSR|S_IXUSR) == -1 && errno != EEXIST) { error(errno, "Could not create directory `%s'.", octstr_get_cstr(dir)); octstr_destroy(dir); octstr_destroy(hash); return; } /* * Now also add the hex value of the destination. * This will be the part we look later into while * DLR resolving. */ os = octstr_duplicate(msg->sms.receiver); octstr_binary_to_hex(os, 0); octstr_append(hash, os); octstr_destroy(os); /* target file */ filename = octstr_format("%S/%S", dir, hash); octstr_destroy(dir); octstr_destroy(hash); if ((fd = open(octstr_get_cstr(filename), O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR)) == -1) { error(errno, "Could not open file `%s'.", octstr_get_cstr(filename)); octstr_destroy(filename); return; } /* pack and write content to file */ os = store_msg_pack(msg); msg_destroy(msg); for (wrc = 0; wrc < octstr_len(os); ) { size_t rc = write(fd, octstr_get_cstr(os) + wrc, octstr_len(os) - wrc); if (rc == -1) { /* remove file */ error(errno, "Could not write DLR message to `%s'.", octstr_get_cstr(filename)); close(fd); if (unlink(octstr_get_cstr(filename)) == -1) error(errno, "Oops, Could not remove failed file `%s'.", octstr_get_cstr(filename)); octstr_destroy(os); octstr_destroy(filename); return; } wrc += rc; } close(fd); counter_increase(counter); octstr_destroy(filename); octstr_destroy(os); } /* * Find matching entry in our spool and return the dlr_entry. */ static struct dlr_entry *dlr_spool_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { struct dlr_entry *ret = NULL; Octstr *os, *hash, *dir, *filename = NULL; Msg *msg; /* determine target dir and filename via hash */ os = octstr_duplicate(smsc); octstr_append(os, ts); hash = our_hash_func(os); octstr_destroy(os); /* determine target dir */ dir = octstr_format("%S/%ld", spool_dir, octstr_hash_key(hash) % MAX_DIRS); /* get content of msg surrogate */ os = get_msg_surrogate(dir, hash, dst, &filename); octstr_destroy(dir); octstr_destroy(hash); /* if there was no content */ if (os == NULL) { octstr_destroy(filename); return NULL; } /* unpack */ if ((msg = store_msg_unpack(os)) == NULL) { octstr_destroy(os); error(0, "Could not unpack DLR message `%s'", octstr_get_cstr(filename)); octstr_destroy(filename); return ret; } octstr_destroy(os); octstr_destroy(filename); #define MAP(to, from) \ to = from; \ from = NULL; /* map values to a struct dlr_entry */ ret = dlr_entry_create(); MAP(ret->smsc, msg->sms.smsc_id); MAP(ret->timestamp, msg->sms.foreign_id); MAP(ret->source, msg->sms.sender); MAP(ret->destination, msg->sms.receiver); MAP(ret->service, msg->sms.service); MAP(ret->url, msg->sms.dlr_url); MAP(ret->boxc_id, msg->sms.boxc_id); ret->mask = msg->sms.dlr_mask; msg_destroy(msg); return ret; } /* * Remove matching entry from the spool. */ static void dlr_spool_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *os, *hash, *dir, *filename; /* determine target dir and filename via hash */ os = octstr_duplicate(smsc); octstr_append(os, ts); hash = our_hash_func(os); octstr_destroy(os); /* determine target dir */ dir = octstr_format("%S/%ld", spool_dir, octstr_hash_key(hash) % MAX_DIRS); /* get msg surrogate filename */ filename = get_msg_filename(dir, hash, dst); octstr_destroy(dir); octstr_destroy(hash); /* if there was no filename, then we didn't find it */ if (filename == NULL) { return; } /* remove the file from the file system */ if (unlink(octstr_get_cstr(filename)) == -1) { error(errno, "Could not unlink file `%s'.", octstr_get_cstr(filename)); octstr_destroy(filename); return; } counter_decrease(counter); octstr_destroy(filename); } /* * Destroy data structures of the module. */ static void dlr_spool_shutdown() { counter_destroy(counter); octstr_destroy(spool_dir); } /* * Get count of DLR messages within the spool. */ static long dlr_spool_messages(void) { return counter_value(counter); } /* * Flush all DLR messages out of the spool, removing all. */ static void dlr_spool_flush(void) { for_each_file(spool_dir, 1, unlink_file); counter_set(counter, 0); } /******************************************************************** * DLR storage handle definition and init function. */ static struct dlr_storage handles = { .type = "spool", .dlr_add = dlr_spool_add, .dlr_get = dlr_spool_get, .dlr_remove = dlr_spool_remove, .dlr_shutdown = dlr_spool_shutdown, .dlr_messages = dlr_spool_messages, .dlr_flush = dlr_spool_flush }; /* * Initialize dlr_waiting_list and return out storage handles. */ struct dlr_storage *dlr_init_spool(Cfg *cfg) { CfgGroup *grp; if (!(grp = cfg_get_single_group(cfg, octstr_imm("core")))) panic(0, "DLR: spool: group 'core' is not specified!"); if (!(spool_dir = cfg_get(grp, octstr_imm("dlr-spool")))) panic(0, "DLR: spool: directive 'dlr-spool' is not specified!"); #ifdef HAVE_LIBSSL OpenSSL_add_all_digests(); #endif counter = counter_create(); /* we need to traverse the DLR spool to determine how * many entries we have. */ #ifdef VERIFIED for_each_file(spool_dir, 1, verified_file); #else for_each_file(spool_dir, 1, non_verified_file); #endif return &handles; } gateway-1.4.5/gw/smscconn_p.h0000644000175000017500000002774713227613126014640 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef SMSCCONN_P_H #define SMSCCONN_P_H /* SMSC Connection private header * * Defines internal private structure * * Kalle Marjola 2000 for project Kannel * ADDING AND WORKING OF NEW SMS CENTER CONNECTIONS: These are guidelines and rules for adding new SMSC Connections to Kannel. See file bb_smscconn_cb.h for callback function prototypes. An SMSC Connection handler is free-formed module which only has the following rules: 1) Each new SMSC Connection MUST implement function smsc_xxx_create(SMSCConn *conn, CfgGrp *cfg), which: a) SHOULD NOT block (XXX) b) MUST warn about any configuration group variables it does not support (XXX) c) MUST set up send_msg dynamic function to handle messages to-be-sent. This function MAY NOT block. This function MAY NOT destroy or alter the supplied message, but instead copy it if need to be stored d) CAN set up private shutdown function, which MAY NOT block e) SHOULD set private function to return number of queued messages to-be-sent inside the driver f) MUST set SMSCConn->name 2) Each SMSC Connection MUST call certain BB callback functions when certain things occur: a) Each SMSC Connection MUST call callback function bb_smscconn_killed when it dies because it was put down earlier with bb_smscconn_shutdown or it simply cannot keep the connection up (wrong password etc. When killed, SMSC Connection MUST release all memory it has taken EXCEPT for the basic SMSCConn struct, which is laterwards released by the bearerbox. b) When SMSC Connection receives a message from SMSC, it must create a new Msg from it and call bb_smscconn_received c) When SMSC Connection has sent a message to SMSC, it MUST call callback function bb_smscconn_sent. The msg-parameter must be identical to msg supplied with smscconn_send, but it can be a duplicate of it d) When SMSC Connection has failed to send a message to SMSC, it MUST call callback function bb_smscconn_send_failed with appropriate reason. The message supplied as with bb_smscconn_send e) When SMSC Connection changes to SMSCCONN_ACTIVE, connection MUST call bb_smscconn_connected 3) SMSC Connection MUST fill up SMSCConn structure as needed to, and is responsible for any concurrency timings. SMSCConn->status MAY NOT be set to SMSCCONN_DEAD until the connection is really that. Use why_killed to make internally dead, supplied with reason. If the connection is disconnected temporarily, the connection SHOULD call bb_smscconn_send_failed for each message in its internal list 4) When SMSC Connection shuts down (shutdown called), it MUST try to send all messages so-far relied to it to be sent if 'finish_sending' is set to non-zero. If set to 0, it MUST call bb_smscconn_send_failed for each message not yet sent. After everything is ready (it can happen in different thread), before calling callback function bb_smscconn_killed it MUST release all memory it has taken except for basic SMSCConn structure, and set status to SMSCCONN_DEAD so it can be finally deleted. 5) Callback bb_smscconn_ready is automatically called by main smscconn_create. New implementation MAY NOT call it directly 6) SMSC Connection driver must obey is_stopped/stopped variable to suspend receiving (it can still send/re-connect), or must set appropriate function calls. When connection is stopped, it is not allowed to receive any new messages */ #include #include "gwlib/gwlib.h" #include "gwlib/regex.h" #include "smscconn.h" #include "load.h" struct smscconn { /* variables set by appropriate SMSCConn driver */ smscconn_status_t status; /* see smscconn.h */ int load; /* load factor, 0 = no load */ smscconn_killed_t why_killed; /* time to die with reason, set when * shutdown called */ time_t connect_time; /* When connection to SMSC was established */ Mutex *flow_mutex; /* used to lock SMSCConn structure (both * in smscconn.c and specific driver) */ /* connection specific counters (created in smscconn.c, updated * by callback functions in bb_smscconn.c, NOT used by specific driver) */ Counter *received; Counter *received_dlr; Counter *sent; Counter *sent_dlr; Counter *failed; /* SMSCConn variables set in smscconn.c */ volatile sig_atomic_t is_stopped; Octstr *chksum; /* MD5 hash of the whole configuration */ Octstr *chksum_conn; /* MD5 hash minus the routing configuration */ Octstr *name; /* Descriptive name filled from connection info */ Octstr *id; /* Abstract name specified in configuration and used for logging and routing */ Octstr *admin_id; List *allowed_smsc_id; List *denied_smsc_id; List *preferred_smsc_id; regex_t *allowed_smsc_id_regex; regex_t *denied_smsc_id_regex; regex_t *preferred_smsc_id_regex; Octstr *allowed_prefix; regex_t *allowed_prefix_regex; Octstr *denied_prefix; regex_t *denied_prefix_regex; Octstr *preferred_prefix; regex_t *preferred_prefix_regex; Octstr *unified_prefix; Octstr *our_host; /* local device IP to bind for TCP communication */ /* Our smsc specific log-file data */ Octstr *log_file; long log_level; int log_idx; /* index position within the global logfiles[] array in gwlib/log.c */ long reconnect_delay; /* delay in seconds while re-connect attempts */ int alt_dcs; /* use alternate DCS 0xFX */ double throughput; /* message thoughput per sec. to be delivered to SMSC */ /* Stores rerouting information for this specific smsc-id */ int reroute; /* simply turn MO into MT and process internally */ Dict *reroute_by_receiver; /* reroute receiver numbers to specific smsc-ids */ Octstr *reroute_to_smsc; /* define a smsc-id to reroute to */ int reroute_dlr; /* should DLR's are rereouted too? */ int dead_start; /* don't connect this SMSC at startup time */ long max_sms_octets; /* max allowed octets for this SMSC */ Load *outgoing_sms_load; Load *incoming_sms_load; Load *incoming_dlr_load; Load *outgoing_dlr_load; /* XXX: move rest global data from Smsc here */ /* pointers set by specific driver, but initiated to NULL by smscconn. * Note that flow_mutex is always locked before these functions are * called, and released after execution returns from them */ /* pointer to function called when smscconn_shutdown called. * Note that this function is not needed always. If set, this * function MUST set why_killed */ int (*shutdown) (SMSCConn *conn, int finish_sending); /* pointer to function called when a new message is needed to be sent. * MAY NOT block. Connection MAY NOT use msg directly after it has * returned from this function, but must instead duplicate it if need to. */ int (*send_msg) (SMSCConn *conn, Msg *msg); /* pointer to function which returns current number of queued * messages to-be-sent. The function CAN also set load factor directly * to SMSCConn structure (above) */ long (*queued) (SMSCConn *conn); /* pointers to functions called when connection started/stopped * (suspend/resume), if not NULL */ void (*start_conn) (SMSCConn *conn); void (*stop_conn) (SMSCConn *conn); void *data; /* SMSC specific stuff */ }; /* * Initializers for various SMSC connection implementations, * each should take same arguments and return an int, * which is 0 for okay and -1 for error. * * Each function is responsible for setting up all dynamic * function pointers at SMSCConn structure and starting up any * threads it might need. * * If conn->is_stopped is set (!= 0), create function MUST set * its internal state as stopped, so that laterwards called * smscconn_start works fine (and until it is called, no messages * are received) */ /* generic wrapper for old SMSC implementations (uses old smsc.h). * Responsible file: smsc/smsc_wrapper.c */ int smsc_wrapper_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_fake.c */ int smsc_fake_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_cimd2.c */ int smsc_cimd2_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_emi.c */ int smsc_emi2_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_http.c */ int smsc_http_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_smpp.c */ int smsc_smpp_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_cgw.c */ int smsc_cgw_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_at.c. */ int smsc_at2_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_smasi.c */ int smsc_smasi_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_oisd.c */ int smsc_oisd_create(SMSCConn *conn, CfgGroup *cfg); /* Responsible file: smsc/smsc_loopback.c */ int smsc_loopback_create(SMSCConn *conn, CfgGroup *cfg); #ifdef HAVE_GSOAP /* Responsible file: smsc/smsc_soap_parlayx.c */ int smsc_soap_parlayx_create(SMSCConn *conn, CfgGroup *cfg); #endif /* ADD NEW CREATE FUNCTIONS HERE * * int smsc_xxx_create(SMSCConn *conn, CfgGroup *cfg); */ #endif gateway-1.4.5/gw/shared.h0000644000175000017500000001117213227613126013725 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * shared.h - utility functions shared by Kannel boxes * * The functions declared here are not part of any box in particular, but * are quite specific to Kannel, so they are not suitable for gwlib, either. * * Lars Wirzenius */ #ifndef SHARED_H #define SHARED_H #include "gwlib/gwlib.h" #include "msg.h" #define INFINITE_TIME -1 /* * Program status. Set this to shutting_down to make read_from_bearerbox * return even if the bearerbox hasn't closed the connection yet. */ extern volatile enum program_status { starting_up, running, shutting_down } program_status; /* * Open a connection to the bearerbox. */ Connection *connect_to_bearerbox_real(Octstr *host, int port, int ssl, Octstr *our_host); void connect_to_bearerbox(Octstr *host, int port, int ssl, Octstr *our_host); /* * Close connection to the bearerbox. */ void close_connection_to_bearerbox_real(Connection *conn); void close_connection_to_bearerbox(void); /* * Receive and store Msg from bearerbox into msg. Unblock the call when * the given timeout for conn_wait() is reached. Use a negative value, * ie. -1 for an infinite blocking, hence no timeout applies. * Return 0 if Msg received ; -1 if error occurs; 1 if timedout. */ int read_from_bearerbox_real(Connection *conn, Msg **msg, double seconds); int read_from_bearerbox(Msg **msg, double seconds); /* * Send an Msg to the bearerbox, and destroy the Msg. */ void write_to_bearerbox_real(Connection *conn, Msg *pmsg); void write_to_bearerbox(Msg *msg); /* * Delivers a SMS to the bearerbox and returns an error code: 0 if * successfull. -1 if transfer failed. * * Note: Message is only destroyed if successfully delivered! */ int deliver_to_bearerbox_real(Connection *conn, Msg *msg); int deliver_to_bearerbox(Msg *msg); /* * Validates an OSI date. */ Octstr *parse_date(Octstr *date); /* * Restarts process with a given params */ int restart_box(char **argv); #endif gateway-1.4.5/gw/xml_shared.c0000644000175000017500000002435413227613126014606 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * xml_shared.c: Common functions of xml compilers (mainly charset handling * and operations with wbxml binary not using a string table) * * By Tuomas Luttinen & Aarno Syvänen (for Wiral Ltd) */ #include #include "xml_shared.h" #include "xml_definitions.h" #include struct charset_t { char *charset; char *nro; unsigned int MIBenum; }; charset_t character_sets[] = { { "ISO", "8859-1", 4 }, { "ISO", "8859-2", 5 }, { "ISO", "8859-3", 6 }, { "ISO", "8859-4", 7 }, { "ISO", "8859-5", 8 }, { "ISO", "8859-6", 9 }, { "ISO", "8859-7", 10 }, { "ISO", "8859-8", 11 }, { "ISO", "8859-9", 12 }, { "WINDOWS", "1250", 2250 }, { "WINDOWS", "1251", 2251 }, { "WINDOWS", "1252", 2252 }, { "WINDOWS", "1253", 2253 }, { "WINDOWS", "1254", 2254 }, { "WINDOWS", "1255", 2255 }, { "WINDOWS", "1256", 2256 }, { "WINDOWS", "1257", 2257 }, { "WINDOWS", "1258", 2258 }, { "UTF", "8", 106 }, { NULL } }; /**************************************************************************** * * Implementation of external functions */ /* * set_charset - if xml doesn't have an , * converts body from argument charset to UTF-8 */ void set_charset(Octstr *document, Octstr *charset) { long gt = 0, enc = 0; Octstr *encoding = NULL, *text = NULL, *temp = NULL; if (octstr_len(charset) == 0) return; encoding = octstr_create(" encoding"); enc = octstr_search(document, encoding, 0); gt = octstr_search_char(document, '>', 0); if (enc < 0 || enc > gt) { gt++; text = octstr_copy(document, gt, octstr_len(document) - gt); if (charset_to_utf8(text, &temp, charset) >= 0) { octstr_delete(document, gt, octstr_len(document) - gt); octstr_append_data(document, octstr_get_cstr(temp), octstr_len(temp)); } octstr_destroy(temp); octstr_destroy(text); } octstr_destroy(encoding); } /* * find_charset_encoding -- parses for a encoding argument within * the xml preabmle, ie. */ Octstr *find_charset_encoding(Octstr *document) { long gt = 0, enc = 0; Octstr *encoding = NULL, *temp = NULL; enc = octstr_search(document, octstr_imm(" encoding="), 0); gt = octstr_search(document, octstr_imm("?>"), 0); /* in case there is no encoding argument, assume always UTF-8 */ if (enc < 0 || enc + 10 > gt) return NULL; temp = octstr_copy(document, enc + 10, gt - (enc + 10)); octstr_strip_blanks(temp); encoding = octstr_copy(temp, 1, octstr_len(temp) - 2); octstr_destroy(temp); return encoding; } /* * only_blanks - checks if a text node contains only white space, when it can * be left out as a element content. */ int only_blanks(const char *text) { int blank = 1; int j=0; int len = strlen(text); while ((j 0) { number = octstr_copy(charset, cut + 1, (octstr_len(charset) - (cut + 1))); octstr_truncate(charset, cut); } else if ((cut = octstr_search_char(charset, '-', 0)) > 0) { number = octstr_copy(charset, cut + 1, (octstr_len(charset) - (cut + 1))); octstr_truncate(charset, cut); } /* And table search. */ for (i = 0; character_sets[i].charset != NULL; i++) if (octstr_str_compare(charset, character_sets[i].charset) == 0) { for (j = i; octstr_str_compare(charset, character_sets[j].charset) == 0; j++) if (octstr_str_compare(number, character_sets[j].nro) == 0) { ret = character_sets[j].MIBenum; break; } break; } /* UTF-8 is the default value */ if (character_sets[i].charset == NULL) ret = character_sets[i-1].MIBenum; octstr_destroy(number); octstr_destroy(charset); return ret; } /* * element_check_content - a helper function for parse_element for checking * if an element has content or attributes. Returns status bit for attributes * (0x80) and another for content (0x40) added into one octet. */ unsigned char element_check_content(xmlNodePtr node) { unsigned char status_bits = 0x00; if ((node->children != NULL) && !((node->children->next == NULL) && (node->children->type == XML_TEXT_NODE) && (only_blanks((char *)node->children->content)))) status_bits = WBXML_CONTENT_BIT; if (node->properties != NULL) status_bits = status_bits | WBXML_ATTR_BIT; return status_bits; } /* * Return the character sets supported by the WML compiler, as a List * of Octstrs, where each string is the MIME identifier for one charset. */ List *wml_charsets(void) { int i; List *result; Octstr *charset; result = gwlist_create(); for (i = 0; character_sets[i].charset != NULL; i++) { charset = octstr_create(character_sets[i].charset); octstr_append_char(charset, '-'); octstr_append(charset, octstr_imm(character_sets[i].nro)); gwlist_append(result, charset); } return result; } /* * Functions working with simple binary data type (no string table). No * variables are present either. */ simple_binary_t *simple_binary_create(void) { simple_binary_t *binary; binary = gw_malloc(sizeof(simple_binary_t)); binary->wbxml_version = 0x00; binary->public_id = 0x00; binary->charset = 0x00; binary->binary = octstr_create(""); return binary; } void simple_binary_destroy(simple_binary_t *binary) { if (binary == NULL) return; octstr_destroy(binary->binary); gw_free(binary); } /* * Output the wbxml content field after field into octet string os. We add * string table length 0 (meaning no string table) before the content. */ void simple_binary_output(Octstr *os, simple_binary_t *binary) { gw_assert(octstr_len(os) == 0); octstr_format_append(os, "%c", binary->wbxml_version); octstr_format_append(os, "%c", binary->public_id); octstr_append_uintvar(os, binary->charset); octstr_format_append(os, "%c", 0x00); octstr_format_append(os, "%S", binary->binary); } void parse_end(simple_binary_t **binary) { output_char(WBXML_END, binary); } void output_char(int byte, simple_binary_t **binary) { octstr_append_char((**binary).binary, byte); } void parse_octet_string(Octstr *os, simple_binary_t **binary) { output_octet_string(os, binary); } /* * Add global tokens to the start and to the end of an inline string. */ void parse_inline_string(Octstr *temp, simple_binary_t **binary) { Octstr *startos; octstr_insert(temp, startos = octstr_format("%c", WBXML_STR_I), 0); octstr_destroy(startos); octstr_format_append(temp, "%c", WBXML_STR_END); parse_octet_string(temp, binary); } void output_octet_string(Octstr *os, simple_binary_t **sibxml) { octstr_insert((*sibxml)->binary, os, octstr_len((*sibxml)->binary)); } gateway-1.4.5/gw/wml_definitions.h0000644000175000017500000001663713227613126015664 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wml_definitions.h - definitions unique to WML compiler * * This file contains fefinitions for global tokens and structures containing * element and attribute tokens for the code page 1. * * * Tuomas Luttinen for Wapit Ltd. */ /*********************************************************************** * Declarations of global variables. */ /* * Elements as defined by tag code page 0. */ static wml_table_t wml_elements[] = { { "wml", 0x3F }, { "card", 0x27 }, { "do", 0x28 }, { "onevent", 0x33 }, { "head", 0x2C }, { "template", 0x3B }, { "access", 0x23 }, { "meta", 0x30 }, { "go", 0x2B }, { "prev", 0x32 }, { "refresh", 0x36 }, { "noop", 0x31 }, { "postfield", 0x21 }, { "setvar", 0x3E }, { "select", 0x37 }, { "optgroup", 0x34 }, { "option", 0x35 }, { "input", 0x2F }, { "fieldset", 0x2A }, { "timer", 0x3C }, { "img", 0x2E }, { "anchor", 0x22 }, { "a", 0x1C }, { "table", 0x1F }, { "tr", 0x1E }, { "td", 0x1D }, { "em", 0x29 }, { "strong", 0x39 }, { "b", 0x24 }, { "i", 0x2D }, { "u", 0x3D }, { "big", 0x25 }, { "small", 0x38 }, { "p", 0x20 }, { "br", 0x26 }, { NULL } }; /* * Attributes as defined by WAP-191-WML-20000219a * section 14.3.3 Attribute Start Tokens */ static wml_table3_t wml_attributes[] = { { "accept-charset", NULL, 0x05 }, { "accesskey", NULL, 0x5E }, { "align", NULL, 0x52 }, { "align", "bottom", 0x06 }, { "align", "center", 0x07 }, { "align", "left", 0x08 }, { "align", "middle", 0x09 }, { "align", "right", 0x0A }, { "align", "top", 0x0B }, { "alt", NULL, 0x0C }, { "cache-control", "no-cache", 0x64 }, { "class", NULL, 0x54 }, { "columns", NULL, 0x53 }, { "content", NULL, 0x0D }, { "content", "application/vnd.wap.wmlc;charset=", 0x5C }, { "domain", NULL, 0x0F }, { "emptyok", "false", 0x10 }, { "emptyok", "true", 0x11 }, { "enctype", NULL, 0x5F }, { "enctype", "application/x-www-form-urlencoded", 0x60 }, { "enctype", "multipart/form-data", 0x61 }, { "format", NULL, 0x12 }, { "forua", "false", 0x56 }, { "forua", "true", 0x57 }, { "height", NULL, 0x13 }, { "href", NULL, 0x4A }, { "href", "http://", 0x4B }, { "href", "https://", 0x4C }, { "hspace", NULL, 0x14 }, { "http-equiv", NULL, 0x5A }, { "http-equiv", "Content-Type", 0x5B }, { "http-equiv", "Expires", 0x5D }, { "id", NULL, 0x55 }, { "ivalue", NULL, 0x15 }, { "iname", NULL, 0x16 }, { "label", NULL, 0x18 }, { "localsrc", NULL, 0x19 }, { "maxlength", NULL, 0x1A }, { "method", "get", 0x1B }, { "method", "post", 0x1C }, { "mode", "nowrap", 0x1D }, { "mode", "wrap", 0x1E }, { "multiple", "false", 0x1F }, { "multiple", "true", 0x20 }, { "name", NULL, 0x21 }, { "newcontext", "false", 0x22 }, { "newcontext", "true", 0x23 }, { "onenterbackward", NULL, 0x25 }, { "onenterforward", NULL, 0x26 }, { "onpick", NULL, 0x24 }, { "ontimer", NULL, 0x27 }, { "optional", "false", 0x28 }, { "optional", "true", 0x29 }, { "path", NULL, 0x2A }, { "scheme", NULL, 0x2E }, { "sendreferer", "false", 0x2F }, { "sendreferer", "true", 0x30 }, { "size", NULL, 0x31 }, { "src", NULL, 0x32 }, { "src", "http://", 0x58 }, { "src", "https://", 0x59 }, { "ordered", "true", 0x33 }, { "ordered", "false", 0x34 }, { "tabindex", NULL, 0x35 }, { "title", NULL, 0x36 }, { "type", NULL, 0x37 }, { "type", "accept", 0x38 }, { "type", "delete", 0x39 }, { "type", "help", 0x3A }, { "type", "password", 0x3B }, { "type", "onpick", 0x3C }, { "type", "onenterbackward", 0x3D }, { "type", "onenterforward", 0x3E }, { "type", "ontimer", 0x3F }, { "type", "options", 0x45 }, { "type", "prev", 0x46 }, { "type", "reset", 0x47 }, { "type", "text", 0x48 }, { "type", "vnd.", 0x49 }, { "value", NULL, 0x4D }, { "vspace", NULL, 0x4E }, { "width", NULL, 0x4F }, { "xml:lang", NULL, 0x50 }, { "xml:space", "preserve", 0x62 }, { "xml:space", "default", 0x63 }, { NULL } }; /* * Attribute value codes. */ static wml_table_t wml_attribute_values[] = { { "accept", 0x89 }, { "bottom", 0x8A }, { "clear", 0x8B }, { "delete", 0x8C }, { "help", 0x8D }, { "middle", 0x93 }, { "nowrap", 0x94 }, { "onenterbackward", 0x96 }, { "onenterforward", 0x97 }, { "onpick", 0x95 }, { "ontimer", 0x98 }, { "options", 0x99 }, { "password", 0x9A }, { "reset", 0x9B }, { "text", 0x9D }, { "top", 0x9E }, { "unknown", 0x9F }, { "wrap", 0xA0 }, { NULL } }; /* * URL value codes. */ static wml_table_t wml_URL_values[] = { { "www.", 0xA1 }, { ".com/", 0x85 }, { ".edu/", 0x86 }, { ".net/", 0x87 }, { ".org/", 0x88 }, { "http://", 0x8E }, { "http://www.", 0x8F }, { "https://", 0x90 }, { "https://www.", 0x91 }, { "Www.", 0xA1 }, { NULL } }; gateway-1.4.5/gw/wap_push_sl_compiler.c0000644000175000017500000003476213227613126016702 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_sl_compiler.c: Tokenizes a SL document. SL DTD is defined in * Wapforum specification WAP-168-ServiceLoad-20010731-a (hereafter called sl), * chapter 9.2. * * By Aarno Syvänen for Wiral Ltd */ #include #include #include #include #include #include #include "xml_shared.h" #include "wap_push_sl_compiler.h" /****************************************************************************** * * Following global variables are unique to SL compiler. See sl, chapter 10.3. * * Two token table types, with one and two token fields. */ struct sl_2table_t { char *name; unsigned char token; }; typedef struct sl_2table_t sl_2table_t; /* * Value part can mean whole or part of the value. It can be NULL, too; then * no part of the value will be tokenized, see sl, chapter 10.3.2. */ struct sl_3table_t { char *name; char *value_part; unsigned char token; }; typedef struct sl_3table_t sl_3table_t; /* * Element from tag code page zero. It is defined in sl, chapter 10.3.1. */ static sl_2table_t sl_elements[] = { { "sl", 0x05 } }; #define NUMBER_OF_ELEMENTS sizeof(sl_elements)/sizeof(sl_elements[0]) /* * Attributes (and sometimes start or whole of their value) from code page * zero. These are defined in sl, chapter 10.3.2. */ static sl_3table_t sl_attributes[] = { { "action", "execute-low", 0x05 }, { "action", "execute-high", 0x06 }, { "action", "cache", 0x07 }, { "href", "http://", 0x09 }, { "href", "http://www.", 0x0a }, { "href", "https://", 0x0b }, { "href", "https://www.", 0x0c }, { "href", NULL, 0x08 } }; #define NUMBER_OF_ATTRIBUTES sizeof(sl_attributes)/sizeof(sl_attributes[0]) /* * URL value codes from code page zero. These are defined in sl, chapter * 10.3.3. */ static sl_2table_t sl_url_values[] = { { ".com/", 0x85 }, { ".edu/", 0x86 }, { ".net/", 0x87 }, { ".org/", 0x88 }, }; #define NUMBER_OF_URL_VALUES sizeof(sl_url_values)/sizeof(sl_url_values[0]) #include "xml_definitions.h" /**************************************************************************** * * Prototypes of internal functions. Note that 'Ptr' means here '*'. */ static int parse_document(xmlDocPtr document, Octstr *charset, simple_binary_t **slbxml); static int parse_node(xmlNodePtr node, simple_binary_t **slbxml); static int parse_element(xmlNodePtr node, simple_binary_t **slbxml); static int parse_attribute(xmlAttrPtr attr, simple_binary_t **slbxml); static int url(int hex); static int action(int hex); static void parse_url_value(Octstr *value, simple_binary_t **slbxml); /**************************************************************************** * * Implementation of the external function */ int sl_compile(Octstr *sl_doc, Octstr *charset, Octstr **sl_binary) { simple_binary_t *slbxml; int ret; xmlDocPtr pDoc; size_t size; char *sl_c_text; *sl_binary = octstr_create(""); slbxml = simple_binary_create(); octstr_strip_blanks(sl_doc); set_charset(sl_doc, charset); size = octstr_len(sl_doc); sl_c_text = octstr_get_cstr(sl_doc); pDoc = xmlParseMemory(sl_c_text, size); ret = 0; if (pDoc) { ret = parse_document(pDoc, charset, &slbxml); simple_binary_output(*sl_binary, slbxml); xmlFreeDoc(pDoc); } else { xmlFreeDoc(pDoc); octstr_destroy(*sl_binary); simple_binary_destroy(slbxml); error(0, "SL: No document to parse. Probably an error in SL source"); return -1; } simple_binary_destroy(slbxml); return ret; } /**************************************************************************** * * Implementation of internal functions * * Parse document node. Store sl version number, public identifier and * character set at the start of the document */ static int parse_document(xmlDocPtr document, Octstr *charset, simple_binary_t **slbxml) { xmlNodePtr node; (**slbxml).wbxml_version = 0x02; /* WBXML Version number 1.2 */ (**slbxml).public_id = 0x06; /* SL 1.0 Public ID */ charset = octstr_create("UTF-8"); (**slbxml).charset = parse_charset(charset); octstr_destroy(charset); node = xmlDocGetRootElement(document); return parse_node(node, slbxml); } /* * The recursive parsing function for the parsing tree. Function checks the * type of the node, calls for the right parse function for the type, then * calls itself for the first child of the current node if there's one and * after that calls itself for the next child on the list. We parse whole * tree, even though SL DTD defines only one node (see sl, chapter 9.2); this * allows us throw an error message when an unknown element is found. */ static int parse_node(xmlNodePtr node, simple_binary_t **slbxml) { int status = 0; /* Call for the parser function of the node type. */ switch (node->type) { case XML_ELEMENT_NODE: status = parse_element(node, slbxml); break; case XML_TEXT_NODE: case XML_COMMENT_NODE: case XML_PI_NODE: /* Text nodes, comments and PIs are ignored. */ break; /* * XML has also many other node types, these are not needed with * SL. Therefore they are assumed to be an error. */ default: error(0, "SL COMPILER: Unknown XML node in the SL source."); return -1; break; } /* * If node is an element with content, it will need an end tag after it's * children. The status for it is returned by parse_element. */ switch (status) { case 0: if (node->children != NULL) if (parse_node(node->children, slbxml) == -1) return -1; break; case 1: if (node->children != NULL) if (parse_node(node->children, slbxml) == -1) return -1; parse_end(slbxml); break; case -1: /* Something went wrong in the parsing. */ return -1; default: warning(0,"SL compiler: undefined return value in a parse function."); return -1; break; } if (node->next != NULL) if (parse_node(node->next, slbxml) == -1) return -1; return 0; } /* * Parse an element node. Check if there is a token for an element tag; if not * output the element as a string, else ouput the token. After that, call * attribute parsing functions. Note that we take advantage of the fact that * sl documents have only one element (see sl, chapter 6.2). * Returns: 1, add an end tag (element node has no children) * 0, do not add an end tag (it has children) * -1, an error occurred */ static int parse_element(xmlNodePtr node, simple_binary_t **slbxml) { Octstr *name, *nameos; unsigned char status_bits, sl_hex; int add_end_tag; xmlAttrPtr attribute; name = octstr_create((char *)node->name); if (octstr_len(name) == 0) { octstr_destroy(name); return -1; } status_bits = 0x00; sl_hex = 0x00; add_end_tag = 0; if (octstr_compare(name, octstr_imm(sl_elements[0].name)) != 0) { warning(0, "unknown tag %s in SL source", octstr_get_cstr(name)); sl_hex = WBXML_LITERAL; if ((status_bits = element_check_content(node)) > 0) { sl_hex = sl_hex | status_bits; /* If this node has children, the end tag must be added after them. */ if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) add_end_tag = 1; } output_char(sl_hex, slbxml); output_octet_string(nameos = octstr_duplicate(name), slbxml); octstr_destroy(nameos); } else { sl_hex = sl_elements[0].token; if ((status_bits = element_check_content(node)) > 0) { sl_hex = sl_hex | status_bits; if ((status_bits & WBXML_CONTENT_BIT) == WBXML_CONTENT_BIT) { add_end_tag = 1; } output_char(sl_hex, slbxml); } } if (node->properties != NULL) { attribute = node->properties; while (attribute != NULL) { parse_attribute(attribute, slbxml); attribute = attribute->next; } parse_end(slbxml); } octstr_destroy(name); return add_end_tag; } static int parse_attribute(xmlAttrPtr attr, simple_binary_t **slbxml) { Octstr *name, *value, *valueos; unsigned char sl_hex; size_t i, value_len; name = octstr_create((char *)attr->name); if (attr->children != NULL) value = create_octstr_from_node((char *)attr->children); else value = NULL; if (value == NULL) goto error; i = 0; valueos = NULL; while (i < NUMBER_OF_ATTRIBUTES) { if (octstr_compare(name, octstr_imm(sl_attributes[i].name)) == 0) { if (sl_attributes[i].value_part == NULL) { debug("wap.push.sl.compiler", 0, "value part was NULL"); break; } else { value_len = octstr_len(valueos = octstr_imm(sl_attributes[i].value_part)); if (octstr_ncompare(value, valueos, value_len) == 0) { break; } } } ++i; } if (i == NUMBER_OF_ATTRIBUTES) { warning(0, "unknown attribute in SL source"); goto error; } sl_hex = sl_attributes[i].token; if (action(sl_hex)) { output_char(sl_hex, slbxml); } else if (url(sl_hex)) { output_char(sl_hex, slbxml); octstr_delete(value, 0, octstr_len(valueos)); parse_url_value(value, slbxml); } else { output_char(sl_hex, slbxml); parse_inline_string(value, slbxml); } octstr_destroy(name); octstr_destroy(value); return 0; error: octstr_destroy(name); octstr_destroy(value); return -1; } /* * checks whether a sl attribute value is an URL or some other kind of value. * Returns 1 for an URL and 0 otherwise. */ static int url(int hex) { switch ((unsigned char) hex) { case 0x08: /* href */ case 0x09: case 0x0b: /* href http://, href https:// */ case 0x0a: case 0x0c: /* href http://www., href https://www. */ return 1; } return 0; } /* * checks whether a sl attribute value is an action attribute or some other * kind of value. * Returns 1 for an action attribute and 0 otherwise. */ static int action(int hex) { switch ((unsigned char) hex) { case 0x05: case 0x06: /* action execute-low, action execute-high */ case 0x07: /* action cache */ return 1; } return 0; } /* * In the case of SL document, only attribute values to be tokenised are parts * of urls. See sl, chapter 10.3.3. The caller removes the start of the url. * Check whether we can find one of tokenisable values in value. If not, parse * value as a inline string, else parse parts before and after the tokenisable * url value as a inline string. */ static void parse_url_value(Octstr *value, simple_binary_t **slbxml) { size_t i; long pos; Octstr *urlos, *first_part, *last_part; size_t first_part_len; i = 0; first_part_len = 0; first_part = NULL; last_part = NULL; while (i < NUMBER_OF_URL_VALUES) { pos = octstr_search(value, urlos = octstr_imm(sl_url_values[i].name), 0); if (pos >= 0) { first_part = octstr_duplicate(value); octstr_delete(first_part, pos, octstr_len(first_part) - pos); first_part_len = octstr_len(first_part); parse_inline_string(first_part, slbxml); output_char(sl_url_values[i].token, slbxml); last_part = octstr_duplicate(value); octstr_delete(last_part, 0, first_part_len + octstr_len(urlos)); parse_inline_string(last_part, slbxml); octstr_destroy(first_part); octstr_destroy(last_part); break; } octstr_destroy(urlos); ++i; } if (pos < 0) parse_inline_string(value, slbxml); } gateway-1.4.5/gw/xml_shared.h0000644000175000017500000001340313227613126014604 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * xml_shared.h - Common xml tokenizer interface * This file contains mainly character set functions and binary manipulating * functions used with a binary without a string table. * * Tuomas Luttinen for Wapit Ltd and Aarno Syvänen for Wiral Ltd. */ #ifndef XML_SHARED_H #define XML_SHARED_H /* * Charset type is used by WML, SI and SL. */ typedef struct charset_t charset_t; /* * XML binary type not containing a string table. This is used for SI and SL. */ typedef struct simple_binary_t simple_binary_t; #include "gwlib/gwlib.h" /* * XML binary type not containing a string table. This is used for SI and SL. */ struct simple_binary_t { unsigned char wbxml_version; unsigned char public_id; unsigned long charset; Octstr *binary; int code_page; }; /* * Prototypes of common functions. First functions common with wml, si and sl * compilers. * * set_charset - set the charset of the http headers into the document, if * it has no encoding set. */ void set_charset(Octstr *document, Octstr *charset); /* * find_charset_encoding -- parses for a encoding argument within * the xml preabmle, ie. */ Octstr *find_charset_encoding(Octstr *document); /* * element_check_content - a helper function for checking if an element has * content or attributes. Returns status bit for attributes (0x80) and another * for content (0x40) added into one octet. */ unsigned char element_check_content(xmlNodePtr node); /* * only_blanks - checks if a text node contains only white space, when it can * be left out as a element content. */ int only_blanks(const char *text); /* * Parses the character set of the document given as Octstr. Returns the * MIBenum value. If the charset is not found, we default to UTF-8 value. */ int parse_charset(Octstr *os); /* * Return the character sets supported by the WML compiler, as a List * of Octstrs, where each string is the MIME identifier for one charset. */ List *wml_charsets(void); /* * Macro for creating an octet string from a node content. This has two * versions for different libxml node content implementation methods. */ #ifdef XML_USE_BUFFER_CONTENT #define create_octstr_from_node(node) (octstr_create(node->content->content)) #else #define create_octstr_from_node(node) (octstr_create(node->content)) #endif #endif /* * Functions working with simple binary type (no string table) */ simple_binary_t *simple_binary_create(void); void simple_binary_destroy(simple_binary_t *bxml); /* * Output the sibxml content field after field into octet string os. We add * string table length 0 (no string table) before the content. */ void simple_binary_output(Octstr *os, simple_binary_t *bxml); void parse_end(simple_binary_t **bxml); void output_char(int byte, simple_binary_t **bxml); void parse_octet_string(Octstr *os, simple_binary_t **bxml); /* * Add global tokens to the start and to the end of an inline string. */ void parse_inline_string(Octstr *temp, simple_binary_t **bxml); void output_octet_string(Octstr *os, simple_binary_t **bxml); gateway-1.4.5/gw/wap_push_ppg_pushuser.c0000644000175000017500000007753013227613126017116 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_ppg_pushuser.c: Implementation of wap_push_ppg_pushuser.h header. * * By Aarno Syvänen for Wiral Ltd and Global Networks Inc. */ #include "wap_push_ppg_pushuser.h" #include "numhash.h" #include "gwlib/regex.h" /*************************************************************************** * * Global data structures * * Hold user specific data for one ppg user */ struct WAPPushUser { Octstr *name; /* the name of the user */ Octstr *username; /* the username of this ppg user */ Octstr *password; /* and password */ Octstr *country_prefix; Octstr *allowed_prefix; /* phone number prefixes allowed by this user when pushing*/ regex_t *allowed_prefix_regex; Octstr *denied_prefix; /* and denied ones */ regex_t *denied_prefix_regex; Numhash *white_list; /* phone numbers of this user, used for push*/ regex_t *white_list_regex; Numhash *black_list; /* numbers should not be used for push*/ regex_t *black_list_regex; Octstr *user_deny_ip; /* this user allows pushes from these IPs*/ Octstr *user_allow_ip; /* and denies them from these*/ Octstr *smsc_id; /* force push SMs to this smsc */ Octstr *default_smsc_id; /* use this smsc as a default for push SMs */ Octstr *dlr_url; /* default dlr url from this user */ Octstr *smsbox_id; /* use this smsbox for sending dlrs back*/ }; typedef struct WAPPushUser WAPPushUser; /* * Hold user specific data of all ppg users */ struct WAPPushUserList { List *list; Dict *names; }; typedef struct WAPPushUserList WAPPushUserList; static WAPPushUserList *users = NULL; /* * This hash table stores time when a specific ip is allowed to try next time. */ static Dict *next_try = NULL; /*********************************************************************************** * * Prototypes of internal functions */ static void destroy_users_list(void *l); static WAPPushUserList *pushusers_create(long number_of_users); static WAPPushUser *create_oneuser(CfgGroup *grp); static void destroy_oneuser(void *p); static int oneuser_add(CfgGroup *cfg); static void oneuser_dump(WAPPushUser *u); static WAPPushUser *user_find_by_username(Octstr *username); static int password_matches(WAPPushUser *u, Octstr *password); static int ip_allowed_by_user(WAPPushUser *u, Octstr *ip); static int prefix_allowed(WAPPushUser *u, Octstr *number); static int whitelisted(WAPPushUser *u, Octstr *number); static int blacklisted(WAPPushUser *u, Octstr *number); static int wildcarded_ip_found(Octstr *ip, Octstr *needle, Octstr *ip_sep); static int response(List *push_headers, Octstr **username, Octstr **password); static void challenge(HTTPClient *c, List *push_headers); static void reply(HTTPClient *c, List *push_headers); static int parse_cgivars_for_username(List *cgivars, Octstr **username); static int parse_cgivars_for_password(List *cgivars, Octstr **password); static int compare_octstr_sequence(Octstr *os1, Octstr *os2, long start); static Octstr *forced_smsc(WAPPushUser *u); static Octstr *default_smsc(WAPPushUser *u); /**************************************************************************** * * Implementation of external functions */ /* * Initialize the whole module and fill the push users list. */ int wap_push_ppg_pushuser_list_add(List *list, long number_of_pushes, long number_of_users) { CfgGroup *grp; next_try = dict_create(number_of_pushes, octstr_destroy_item); users = pushusers_create(number_of_users); gw_assert(list); while (list && (grp = gwlist_extract_first(list))) { if (oneuser_add(grp) == -1) { gwlist_destroy(list, NULL); return 0; } } gwlist_destroy(list, NULL); return 1; } void wap_push_ppg_pushuser_list_destroy(void) { dict_destroy(next_try); if (users == NULL) return; gwlist_destroy(users->list, destroy_oneuser); dict_destroy(users->names); gw_free(users); } enum { NO_USERNAME = -1, NO_PASSWORD = 0, HEADER_AUTHENTICATION = 1 }; #define ADDITION 0.1 /* * This function does authentication possible before compiling the control * document. This means: * a) password authentication by url or by headers (it is, by basic * authentication response, see rfc 2617, chapter 2) * b) if this does not work, basic authentication by challenge - * response * c) enforcing various ip lists * * Check does ppg allows a connection from this at all, then try to find username * and password from headers, then from url. If both fails, try basic authentica- * tion. Then check does this user allow a push from this ip, then check the pass- * word. * * For protection against brute force and partial protection for denial of serv- * ice attacks, an exponential backup algorithm is used. Time when a specific ip * is allowed to reconnect, is stored in Dict next_try. If an ip tries to recon- * nect before this (three attemps are allowed, then exponential seconds are add- * ed to the limit) we make a new challenge. We do the corresponding check before * testing passwords; after all, it is an authorization failure that causes a new * challenge. * * Rfc 2617, chapter 1 states that if we do not accept credentials of an user's, * we must send a new challenge to the user. * * Output an authenticated username. * This function should be called only when there are a push users list; the * caller is responsible for this. */ int wap_push_ppg_pushuser_authenticate(HTTPClient *c, List *cgivars, Octstr *ip, List *push_headers, Octstr **username) { time_t now; static long next = 0L; /* used only in this thread (and this function) */ long next_time; Octstr *next_time_os; static long multiplier = 1L; /* ditto */ WAPPushUser *u; Octstr *copy, *password; int ret; copy = octstr_duplicate(ip); time(&now); next_time_os = NULL; if ((ret = response(push_headers, username, &password)) == NO_USERNAME) { if (!parse_cgivars_for_username(cgivars, username)) { error(0, "no user specified, challenging regardless"); goto listed; } } if (password == NULL) parse_cgivars_for_password(cgivars, &password); u = user_find_by_username(*username); if (!ip_allowed_by_user(u, ip)) { goto not_listed; } next = 0; if ((next_time_os = dict_get(next_try, ip)) != NULL) { octstr_parse_long(&next_time, next_time_os, 0, 10); if (difftime(now, (time_t) next_time) < 0) { error(0, "another try from %s, not much time used", octstr_get_cstr(copy)); goto listed; } } if (u == NULL) { error(0, "user %s is not allowed by users list, challenging", octstr_get_cstr(*username)); goto listed; } if (!password_matches(u, password)) { error(0, "wrong or missing password in request from %s, challenging" , octstr_get_cstr(copy)); goto listed; } dict_remove(next_try, ip); /* no restrictions after authentica- tion */ octstr_destroy(password); octstr_destroy(copy); octstr_destroy(next_time_os); return 1; not_listed: octstr_destroy(password); octstr_destroy(copy); reply(c, push_headers); octstr_destroy(next_time_os); return 0; listed: challenge(c, push_headers); multiplier <<= 1; next = next + multiplier * ADDITION; next += now; next_time_os = octstr_format("%ld", next); dict_put(next_try, ip, next_time_os); octstr_destroy(copy); octstr_destroy(password); return 0; } /* * This function checks phone number for allowed prefixes, black lists and white * lists. Note that the phone number necessarily follows the international format * (a requirement by our pap compiler). */ int wap_push_ppg_pushuser_client_phone_number_acceptable(Octstr *username, Octstr *number) { WAPPushUser *u; u = user_find_by_username(username); if (!prefix_allowed(u, number)) { error(0, "Number %s not allowed by user %s (wrong prefix)", octstr_get_cstr(number), octstr_get_cstr(username)); return 0; } if (blacklisted(u, number)) { error(0, "Number %s not allowed by user %s (blacklisted)", octstr_get_cstr(number), octstr_get_cstr(username) ); return 0; } if (!whitelisted(u, number)) { error(0, "Number %s not allowed by user %s (not whitelisted)", octstr_get_cstr(number), octstr_get_cstr(username) ); return 0; } return 1; } int wap_push_ppg_pushuser_search_ip_from_wildcarded_list(Octstr *haystack, Octstr *needle, Octstr *gwlist_sep, Octstr *ip_sep) { List *ips; long i; Octstr *configured_ip; gw_assert(haystack); gw_assert(gwlist_sep); gw_assert(ip_sep); /*There are no wildcards in the list*/ if (octstr_search_char(haystack, '*', 0) < 0) { if (octstr_search(haystack, needle, 0) >= 0) { return 1; } else { return 0; } } /*There are wildcards in the list*/ configured_ip = NULL; ips = octstr_split(haystack, gwlist_sep); for (i = 0; i < gwlist_len(ips); ++i) { configured_ip = gwlist_get(ips, i); if (wildcarded_ip_found(configured_ip, needle, ip_sep)) goto found; } gwlist_destroy(ips, octstr_destroy_item); return 0; found: gwlist_destroy(ips, octstr_destroy_item); return 1; } /* * Returns smsc-id that pushes by this user must use, * NULL when there was an error. */ Octstr *wap_push_ppg_pushuser_smsc_id_get(Octstr *username) { WAPPushUser *u; Octstr *smsc_id; if ((u = user_find_by_username(username)) == NULL) { /* no user found with this username */ return NULL; } if ((smsc_id = forced_smsc(u)) != NULL) return octstr_duplicate(smsc_id); smsc_id = default_smsc(u); return octstr_duplicate(smsc_id); } /* * Returns default dlr url for this user. */ Octstr *wap_push_ppg_pushuser_dlr_url_get(Octstr *username) { WAPPushUser *u; Octstr *dlr_url; u = user_find_by_username(username); dlr_url = u->dlr_url; return octstr_duplicate(dlr_url); } /* * Returns default dlr smsbox id for this user. */ Octstr *wap_push_ppg_pushuser_smsbox_id_get(Octstr *username) { WAPPushUser *u; Octstr *smsbox_id; u = user_find_by_username(username); smsbox_id = u->smsbox_id; return octstr_duplicate(smsbox_id); } /*************************************************************************** * * Implementation of internal functions */ static void destroy_users_list(void *l) { gwlist_destroy(l, NULL); } static WAPPushUserList *pushusers_create(long number_of_users) { users = gw_malloc(sizeof(WAPPushUserList)); users->list = gwlist_create(); users->names = dict_create(number_of_users, destroy_users_list); return users; } /* * Allocate memory for one push user and read configuration data to it. We initial- * ize all fields to NULL, because the value NULL means that the configuration did * not have this variable. * Return NULL when failure, a pointer to the data structure otherwise. */ static WAPPushUser *create_oneuser(CfgGroup *grp) { WAPPushUser *u; Octstr *grpname, *os; grpname = cfg_get(grp, octstr_imm("wap-push-user")); if (grpname == NULL) { error(0, "all users group (wap-push-user) are missing"); goto no_grpname; } u = gw_malloc(sizeof(WAPPushUser)); u->name = NULL; u->username = NULL; u->allowed_prefix = NULL; u->allowed_prefix_regex = NULL; u->denied_prefix = NULL; u->denied_prefix_regex = NULL; u->white_list = NULL; u->white_list_regex = NULL; u->black_list = NULL; u->black_list_regex = NULL; u->user_deny_ip = NULL; u->user_allow_ip = NULL; u->smsc_id = NULL; u->default_smsc_id = NULL; u->name = cfg_get(grp, octstr_imm("wap-push-user")); if (u->name == NULL) { warning(0, "user name missing, dump follows"); oneuser_dump(u); goto error; } u->username = cfg_get(grp, octstr_imm("ppg-username")); u->password = cfg_get(grp, octstr_imm("ppg-password")); if (u->username == NULL) { warning(0, "login name for user %s missing, dump follows", octstr_get_cstr(u->name)); oneuser_dump(u); goto error; } if (u->password == NULL) { warning(0, "password for user %s missing, dump follows", octstr_get_cstr(u->name)); oneuser_dump(u); goto error; } u->user_deny_ip = cfg_get(grp, octstr_imm("deny-ip")); u->user_allow_ip = cfg_get(grp, octstr_imm("allow-ip")); u->country_prefix = cfg_get(grp, octstr_imm("country-prefix")); u->allowed_prefix = cfg_get(grp, octstr_imm("allowed-prefix")); u->denied_prefix = cfg_get(grp, octstr_imm("denied-prefix")); u->smsc_id = cfg_get(grp, octstr_imm("forced-smsc")); u->default_smsc_id = cfg_get(grp, octstr_imm("default-smsc")); u->dlr_url = cfg_get(grp, octstr_imm("dlr-url")); u->smsbox_id = cfg_get(grp, octstr_imm("smsbox-id")); os = cfg_get(grp, octstr_imm("white-list")); if (os != NULL) { u->white_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } os = cfg_get(grp, octstr_imm("black-list")); if (os != NULL) { u->black_list = numhash_create(octstr_get_cstr(os)); octstr_destroy(os); } if ((os = cfg_get(grp, octstr_imm("allowed-prefix-regex"))) != NULL) { if ((u->allowed_prefix_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); }; if ((os = cfg_get(grp, octstr_imm("denied-prefix-regex"))) != NULL) { if ((u->denied_prefix_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); }; if ((os = cfg_get(grp, octstr_imm("white-list-regex"))) != NULL) { if ((u->white_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); }; if ((os = cfg_get(grp, octstr_imm("black-list-regex"))) != NULL) { if ((u->black_list_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL) panic(0, "Could not compile pattern '%s'", octstr_get_cstr(os)); octstr_destroy(os); }; octstr_destroy(grpname); return u; no_grpname: octstr_destroy(grpname); return NULL; error: octstr_destroy(grpname); destroy_oneuser(u); return NULL; } static void destroy_oneuser(void *p) { WAPPushUser *u; u = p; if (u == NULL) return; octstr_destroy(u->name); octstr_destroy(u->username); octstr_destroy(u->password); octstr_destroy(u->country_prefix); octstr_destroy(u->allowed_prefix); octstr_destroy(u->denied_prefix); numhash_destroy(u->white_list); numhash_destroy(u->black_list); octstr_destroy(u->user_deny_ip); octstr_destroy(u->user_allow_ip); octstr_destroy(u->smsc_id); octstr_destroy(u->default_smsc_id); if (u->black_list_regex != NULL) gw_regex_destroy(u->black_list_regex); if (u->white_list_regex != NULL) gw_regex_destroy(u->white_list_regex); if (u->denied_prefix_regex != NULL) gw_regex_destroy(u->denied_prefix_regex); if (u->allowed_prefix_regex != NULL) gw_regex_destroy(u->allowed_prefix_regex); gw_free(u); } static void oneuser_dump(WAPPushUser *u) { if (u == NULL) { debug("wap.push.ppg.pushuser", 0, "no user found"); return; } debug("wap.push.ppg.pushuser", 0, "Dumping user data: Name of the user:"); octstr_dump(u->name, 0); debug("wap.push.ppg.pushuser", 0, "username:"); octstr_dump(u->username, 0); debug("wap.push.ppg.pushuser", 0, "omitting password"); debug("wap-push.ppg.pushuser", 0, "country prefix"); octstr_dump(u->country_prefix, 0); debug("wap.push.ppg.pushuser", 0, "allowed prefix list:"); octstr_dump(u->allowed_prefix, 0); debug("wap.push.ppg.pushuser", 0, "denied prefix list:"); octstr_dump(u->denied_prefix, 0); debug("wap.push.ppg.pushuser", 0, "denied ip list:"); octstr_dump(u->user_deny_ip, 0); debug("wap.push.ppg.pushuser", 0, "allowed ip list:"); octstr_dump(u->user_allow_ip, 0); debug("wap.push.ppg.pushuser", 0, "send via smsc-id:"); octstr_dump(u->smsc_id, 0); debug("wap.push.ppg.pushuser", 0, "use default smsc:"); octstr_dump(u->default_smsc_id, 0); debug("wap.push.ppg.pushuser", 0, "end of the dump"); } /* * Add an user to the push users list */ static int oneuser_add(CfgGroup *grp) { WAPPushUser *u; List *list; u = create_oneuser(grp); if (u == NULL) return -1; gwlist_append(users->list, u); list = dict_get(users->names, u->username); if (list == NULL) { list = gwlist_create(); dict_put(users->names, u->username, list); } return 0; } static WAPPushUser *user_find_by_username(Octstr *username) { WAPPushUser *u; long i; List *list; if (username == NULL) return NULL; if ((list = dict_get(users->names, username)) == NULL) return NULL; for (i = 0; i < gwlist_len(users->list); ++i) { u = gwlist_get(users->list, i); if (octstr_compare(u->username, username) == 0) return u; } return NULL; } static int password_matches(WAPPushUser *u, Octstr *password) { if (password == NULL) return 0; return octstr_compare(u->password, password) == 0; } static int wildcarded_ip_found(Octstr *ip, Octstr *needle, Octstr *ip_sep) { List *ip_fragments, *needle_fragments; long i; Octstr *ip_fragment, *needle_fragment; ip_fragments = octstr_split(ip, ip_sep); needle_fragments = octstr_split(needle, ip_sep); gw_assert(gwlist_len(ip_fragments) == gwlist_len(needle_fragments)); for (i = 0; i < gwlist_len(ip_fragments); ++i) { ip_fragment = gwlist_get(ip_fragments, i); needle_fragment = gwlist_get(needle_fragments, i); if (octstr_compare(ip_fragment, needle_fragment) != 0 && octstr_compare(ip_fragment, octstr_imm("*")) != 0) goto not_found; } gwlist_destroy(ip_fragments, octstr_destroy_item); gwlist_destroy(needle_fragments, octstr_destroy_item); return 1; not_found: gwlist_destroy(ip_fragments, octstr_destroy_item); gwlist_destroy(needle_fragments, octstr_destroy_item); return 0; } /* * Deny_ip = '*.*.*.*' is here taken literally: no ips allowed by this user * (definitely strange, but not a fatal error). */ static int ip_allowed_by_user(WAPPushUser *u, Octstr *ip) { Octstr *copy, *ip_copy; if (u == NULL) { warning(0, "user not found from the users list"); goto no_user; } copy = octstr_duplicate(u->username); if (u->user_deny_ip == NULL && u->user_allow_ip == NULL) goto allowed; if (u->user_deny_ip) { if (octstr_compare(u->user_deny_ip, octstr_imm("*.*.*.*")) == 0) { warning(0, "no ips allowed for %s", octstr_get_cstr(copy)); goto denied; } } if (u->user_allow_ip) if (octstr_compare(u->user_allow_ip, octstr_imm("*.*.*.*")) == 0) goto allowed; if (u->user_deny_ip) { if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(u->user_deny_ip, ip, octstr_imm(";"), octstr_imm("."))) { goto denied; } } if (u->user_allow_ip) { if (wap_push_ppg_pushuser_search_ip_from_wildcarded_list(u->user_allow_ip, ip, octstr_imm(";"), octstr_imm("."))) { goto allowed; } } octstr_destroy(copy); warning(0, "ip not found from either ip list, deny it"); return 0; allowed: octstr_destroy(copy); return 1; denied: ip_copy = octstr_duplicate(ip); warning(0, "%s denied by user %s", octstr_get_cstr(ip_copy), octstr_get_cstr(copy)); octstr_destroy(copy); octstr_destroy(ip_copy); return 0; no_user: return 0; } /* * HTTP basic authentication server response is defined in rfc 2617, chapter 2. * Return 1, when we found username and password from headers, 0, when there were * no password and -1 when there were no username (or no Authorization header at * all, or an unparsable one). Username and password value 'NULL' means no user- * name or password supplied. */ static int response(List *push_headers, Octstr **username, Octstr **password) { Octstr *header_value, *basic; size_t basic_len; List *auth_list; *username = NULL; *password = NULL; if ((header_value = http_header_find_first(push_headers, "Authorization")) == NULL) goto no_response3; octstr_strip_blanks(header_value); basic = octstr_imm("Basic"); basic_len = octstr_len(basic); if (octstr_ncompare(header_value, basic, basic_len) != 0) goto no_response1; octstr_delete(header_value, 0, basic_len); octstr_strip_blanks(header_value); octstr_base64_to_binary(header_value); auth_list = octstr_split(header_value, octstr_imm(":")); if (gwlist_len(auth_list) != 2) goto no_response2; *username = octstr_duplicate(gwlist_get(auth_list, 0)); *password = octstr_duplicate(gwlist_get(auth_list, 1)); if (username == NULL) { goto no_response2; } if (password == NULL) { goto no_response4; } debug("wap.push.ppg.pushuser", 0, "we have an username and a password in" " authorization header"); gwlist_destroy(auth_list, octstr_destroy_item); octstr_destroy(header_value); http_header_remove_all(push_headers, "Authorization"); return HEADER_AUTHENTICATION; no_response1: octstr_destroy(header_value); return NO_USERNAME; no_response2: gwlist_destroy(auth_list, octstr_destroy_item); octstr_destroy(header_value); return NO_USERNAME; no_response3: return NO_USERNAME; no_response4: gwlist_destroy(auth_list, octstr_destroy_item); octstr_destroy(header_value); return NO_PASSWORD; } /* * HTTP basic authentication server challenge is defined in rfc 2617, chapter 2. * Only WWW-Authenticate header is required here by specs. This function does not * release memory used by push headers, the caller must do this. */ static void challenge(HTTPClient *c, List *push_headers) { Octstr *challenge, *realm; int http_status; List *reply_headers; realm = octstr_format("%s", "Basic realm="); octstr_append(realm, get_official_name()); octstr_format_append(realm, "%s", "\"wappush\""); reply_headers = http_create_empty_headers(); http_header_add(reply_headers, "WWW-Authenticate", octstr_get_cstr(realm)); http_status = HTTP_UNAUTHORIZED; challenge = octstr_imm("You must show your credentials.\n"); http_send_reply(c, http_status, reply_headers, challenge); octstr_destroy(realm); http_destroy_headers(reply_headers); } /* * This function does not release memory used by push headers, the caller must do this. */ static void reply(HTTPClient *c, List *push_headers) { int http_status; Octstr *denied; List *reply_headers; reply_headers = http_create_empty_headers(); http_status = HTTP_FORBIDDEN; denied = octstr_imm("You are not allowed to use this service. Do not retry.\n"); http_send_reply(c, http_status, push_headers, denied); http_destroy_headers(reply_headers); } /* * Note that the phone number necessarily follows the international format (a requi- * rement by our pap compiler). So we add country prefix to listed prefixes, if one * is configured. */ static int prefix_allowed(WAPPushUser *u, Octstr *number) { List *allowed, *denied; long i; Octstr *listed_prefix; allowed = NULL; denied = NULL; if (u == NULL) goto no_user; if ( u->allowed_prefix == NULL && u->denied_prefix == NULL && u->allowed_prefix_regex == NULL && u->denied_prefix_regex == NULL) goto no_configuration; if (u->denied_prefix != NULL) { denied = octstr_split(u->denied_prefix, octstr_imm(";")); for (i = 0; i < gwlist_len(denied); ++i) { listed_prefix = gwlist_get(denied, i); if (u->country_prefix != NULL) octstr_insert(listed_prefix, u->country_prefix, 0); if (compare_octstr_sequence(number, listed_prefix, 0) == 0) { goto denied; } } } /* note: country-prefix _must_be included in the pattern */ if (u->denied_prefix_regex != NULL) if (gw_regex_match_pre(u->denied_prefix_regex, number) == 1) goto denied; if (u->allowed_prefix_regex == NULL && u->allowed_prefix == NULL) goto no_allowed_config; if (u->allowed_prefix != NULL) { allowed = octstr_split(u->allowed_prefix, octstr_imm(";")); for (i = 0; i < gwlist_len(allowed); ++i) { listed_prefix = gwlist_get(allowed, i); if (u->country_prefix != NULL) octstr_insert(listed_prefix, u->country_prefix, 0); if (compare_octstr_sequence(number, listed_prefix, 0) == 0) { goto allowed; } } } /* note: country-prefix _must_ be included in the pattern */ if (u->allowed_prefix_regex != NULL) if (gw_regex_match_pre(u->allowed_prefix_regex, number) == 1) goto allowed; /* * Here we have an intentional fall-through. It will removed when memory cleaning * functions are implemented. */ denied: gwlist_destroy(allowed, octstr_destroy_item); gwlist_destroy(denied, octstr_destroy_item); return 0; allowed: gwlist_destroy(allowed, octstr_destroy_item); gwlist_destroy(denied, octstr_destroy_item); return 1; no_configuration: return 1; no_user: return 0; no_allowed_config: gwlist_destroy(denied, octstr_destroy_item); return 1; } static int whitelisted(WAPPushUser *u, Octstr *number) { int result = 1; if (u->white_list != NULL) result = numhash_find_number(u->white_list, number); if ((result == 0) && (u->white_list_regex != NULL)) result = gw_regex_match_pre(u->white_list_regex, number); return result; } static int blacklisted(WAPPushUser *u, Octstr *number) { int result = 0; if (u->black_list != NULL) result = numhash_find_number(u->black_list, number); if ((result == 0) && (u->black_list_regex != NULL)) result = gw_regex_match_pre(u->black_list_regex, number); return result; } /* * 'NULL' means here 'no value found'. * Return 1 when we found username, 0 when we did not. */ static int parse_cgivars_for_username(List *cgivars, Octstr **username) { *username = NULL; *username = octstr_duplicate(http_cgi_variable(cgivars, "username")); if (*username == NULL) { return 0; } return 1; } static int parse_cgivars_for_password(List *cgivars, Octstr **password) { *password = NULL; *password = octstr_duplicate(http_cgi_variable(cgivars, "password")); if (*password == NULL) { return 0; } return 1; } /* * Compare an octet string os2 with a sequence of an octet string os1. The sequence * starts with a position start. */ static int compare_octstr_sequence(Octstr *os1, Octstr *os2, long start) { int ret; unsigned char *prefix; long end; if (octstr_len(os2) == 0) return 1; if (octstr_len(os1) == 0) return -1; prefix = NULL; if (start != 0) { prefix = gw_malloc(start); octstr_get_many_chars((char *)prefix, os1, 0, start); octstr_delete(os1, 0, start); } end = start + octstr_len(os2); ret = octstr_ncompare(os1, os2, end - start); if (start != 0) { octstr_insert_data(os1, 0, (char *)prefix, start); gw_free(prefix); } return ret; } static Octstr *forced_smsc(WAPPushUser *u) { return u->smsc_id; } static Octstr *default_smsc(WAPPushUser *u) { return u->default_smsc_id; } gateway-1.4.5/gw/load.c0000644000175000017500000001427613227613126013401 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /** * load.c * * Alexander Malysh 2008 for project Kannel */ #include "gwlib/gwlib.h" #include "load.h" struct load_entry { float prev; float curr; double last; int interval; int dirty; }; struct load { struct load_entry **entries; int len; int heuristic; RWLock *lock; }; static double microtime(double *p) { struct timeval tv; double result; gettimeofday(&tv, NULL); result = tv.tv_sec + (1e-6 * tv.tv_usec); if(p != NULL) { *p = result; } return result; } Load* load_create_real(int heuristic) { struct load *load; load = gw_malloc(sizeof(*load)); load->len = 0; load->entries = NULL; load->heuristic = heuristic; load->lock = gw_rwlock_create(); return load; } int load_add_interval(Load *load, int interval) { int i; struct load_entry *entry; if (load == NULL) return -1; gw_rwlock_wrlock(load->lock); /* first look if we have equal interval added already */ for (i = 0; i < load->len; i++) { if (load->entries[i]->interval == interval) { gw_rwlock_unlock(load->lock); return -1; } } /* so no equal interval there, add new one */ entry = gw_malloc(sizeof(struct load_entry)); entry->prev = entry->curr = 0.0; entry->interval = interval; entry->dirty = 1; microtime(&entry->last); load->entries = gw_realloc(load->entries, sizeof(struct load*) * (load->len + 1)); load->entries[load->len] = entry; load->len++; gw_rwlock_unlock(load->lock); return 0; } void load_destroy(Load *load) { int i; if (load == NULL) return; for (i = 0; i < load->len; i++) { gw_free(load->entries[i]); } gw_free(load->entries); gw_rwlock_destroy(load->lock); gw_free(load); } void load_increase_with(Load *load, unsigned long value) { double now; int i; if (load == NULL) return; gw_rwlock_wrlock(load->lock); microtime(&now); for (i = 0; i < load->len; i++) { struct load_entry *entry = load->entries[i]; /* check for special case, load over whole live time */ if((entry->interval != -1 && now >= entry->last + entry->interval)) { /* rotate */ entry->curr /= entry->interval; if (entry->prev > 0) entry->prev = (2*entry->curr + entry->prev)/3; else entry->prev = entry->curr; entry->last = now; entry->curr = 0.0; entry->dirty = 0; } entry->curr += value; } gw_rwlock_unlock(load->lock); } double load_get(Load *load, int pos) { double ret; double now; struct load_entry *entry; if (load == NULL || pos >= load->len) { return -1.0; } /* first maybe rotate load */ load_increase_with(load, 0); microtime(&now); gw_rwlock_rdlock(load->lock); entry = load->entries[pos]; if (load->heuristic && !entry->dirty) { ret = entry->prev; } else { double diff = (now - entry->last); if (diff == 0) diff = 1; ret = entry->curr/diff; ret = (ret > entry->curr ? entry->curr : ret); } gw_rwlock_unlock(load->lock); return ret; } int load_len(Load *load) { int ret; if (load == NULL) return 0; gw_rwlock_rdlock(load->lock); ret = load->len; gw_rwlock_unlock(load->lock); return ret; } gateway-1.4.5/gw/meta_data.c0000644000175000017500000003304213227613126014371 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * meta_data.c * * Meta Data manipulation. * * Alexander Malysh , 2007-2009 */ #include "gwlib/gwlib.h" #include "meta_data.h" struct meta_data { Octstr *group; Dict *values; struct meta_data *next; }; static struct meta_data *meta_data_create(void) { struct meta_data *ret; ret = gw_malloc(sizeof(*ret)); ret->group = NULL; ret->values = NULL; ret->next = NULL; return ret; } static void meta_data_destroy(struct meta_data *meta) { struct meta_data *next; if (meta == NULL) return; do { next = meta->next; octstr_destroy(meta->group); dict_destroy(meta->values); gw_free(meta); meta = next; } while(meta != NULL); } /* format: ?group-name?key=value&key=value?group?... group, key, value are urlencoded */ static struct meta_data *meta_data_unpack(const Octstr *data) { struct meta_data *ret = NULL, *curr = NULL; const char *str; long pos; Octstr *key = NULL; int type, next_type; long start, end; start = end = -1; type = next_type = -1; for (pos = 0, str = octstr_get_cstr(data); pos <= octstr_len(data); str++, pos++) { switch(*str) { case '?': if (start == -1) { /* start of str */ start = pos; type = 0; } else if (type == 0) { /* end of group */ end = pos; next_type = 1; } else if (type == 2 && key != NULL) { /* end of value */ end = pos; next_type = 0; } else if (key == NULL) { /* start of next group without key and value */ start = pos; type = 0; } else { /* FAILED */ error(0, "MDATA: Found '?' but not expected it end=%ld start=%ld type=%d.", end, start, type); meta_data_destroy(ret); octstr_destroy(key); return NULL; } break; case '=': if (type == 1 && curr != NULL && key == NULL) { /* end of key */ end = pos; next_type = 2; } else { /* FAILED */ error(0, "MDATA: Found '=' but not expected it end=%ld start=%ld type=%d.", end, start, type); meta_data_destroy(ret); octstr_destroy(key); return NULL; } break; case '&': if (type == 2 && curr != NULL && key != NULL) { /* end of value */ end = pos; next_type = 1; } else if (type == 1 && key == NULL) { /* just & skip it */ start = pos; } else { /* FAILED */ error(0, "MDATA: Found '&' but not expected it end=%ld start=%ld type=%d.", end, start, type); meta_data_destroy(ret); octstr_destroy(key); return NULL; } break; case '\0': if (type == 2) /* end of value */ end = pos; break; } if (start >= 0 && end >= 0) { Octstr *tmp; if (end - start - 1 == 0) tmp = octstr_create(""); else tmp = octstr_create_from_data(str - end + start + 1, end - start - 1); octstr_url_decode(tmp); switch(type) { case 0: /* group */ if (curr == NULL) { curr = gw_malloc(sizeof(*curr)); } else { curr->next = gw_malloc(sizeof(*curr)); curr = curr->next; } curr->group = tmp; tmp = NULL; curr->values = dict_create(1024, octstr_destroy_item); curr->next = NULL; if (ret == NULL) ret = curr; debug("meta_data", 0, "new group created `%s'", octstr_get_cstr(curr->group)); break; case 1: /* key */ key = tmp; tmp = NULL; break; case 2: /* value */ debug("meta_data", 0, "group=`%s' key=`%s' value=`%s'", octstr_get_cstr(curr->group), octstr_get_cstr(key), octstr_get_cstr(tmp)); dict_put(curr->values, key, tmp); tmp = NULL; octstr_destroy(key); key = NULL; break; } octstr_destroy(tmp); type = next_type; next_type = -1; start = end; end = -1; } } octstr_destroy(key); return ret; } static int meta_data_pack(struct meta_data *mdata, Octstr *data) { List *l; Octstr *tmp; if (mdata == NULL || data == NULL) return -1; /* clear data */ octstr_delete(data, 0, octstr_len(data)); do { octstr_format_append(data, "?%E?", mdata->group); l = dict_keys(mdata->values); while(l != NULL && (tmp = gwlist_extract_first(l)) != NULL) { octstr_format_append(data, "%E=%E&", tmp, dict_get(mdata->values, tmp)); octstr_destroy(tmp); } gwlist_destroy(l, octstr_destroy_item); mdata = mdata->next; } while(mdata != NULL); return 0; } Dict *meta_data_get_values(const Octstr *data, const char *group) { struct meta_data *mdata, *curr; Dict *ret = NULL; if (data == NULL || group == NULL) return NULL; mdata = meta_data_unpack(data); if (mdata == NULL) return NULL; for (curr = mdata; curr != NULL; curr = curr->next) { if (octstr_str_case_compare(curr->group, group) == 0) { ret = curr->values; curr->values = NULL; break; } } meta_data_destroy(mdata); return ret; } int meta_data_set_values(Octstr *data, const Dict *dict, const char *group, int replace) { struct meta_data *mdata, *curr; int i; List *keys; Octstr *key; if (data == NULL || group == NULL) return -1; mdata = meta_data_unpack(data); for (curr = mdata; curr != NULL; curr = curr->next) { if (octstr_str_case_compare(curr->group, group) == 0) { /* * If we don't replace the values, copy the old Dict values to the new Dict */ if (replace == 0) { keys = dict_keys(curr->values); while((key = gwlist_extract_first(keys)) != NULL) { dict_put_once((Dict*)dict, key, octstr_duplicate(dict_get(curr->values, key))); octstr_destroy(key); } gwlist_destroy(keys, octstr_destroy_item); } dict_destroy(curr->values); curr->values = (Dict*)dict; break; } } if (curr == NULL) { curr = meta_data_create(); curr->group = octstr_create(group); curr->values = (Dict*)dict; curr->next = NULL; if (mdata == NULL) { mdata = curr; } else { curr->next = mdata->next; mdata->next = curr; } } i = meta_data_pack(mdata, data); curr->values = NULL; meta_data_destroy(mdata); return i; } int meta_data_set_value(Octstr *data, const char *group, const Octstr *key, const Octstr *value, int replace) { struct meta_data *mdata, *curr; int ret = 0; if (data == NULL || group == NULL || value == NULL) return -1; mdata = meta_data_unpack(data); for (curr = mdata; curr != NULL; curr = curr->next) { if (octstr_str_case_compare(curr->group, group) == 0) break; } if (curr == NULL) { /* group doesn't exists */ curr = meta_data_create(); curr->group = octstr_create(group); curr->values = dict_create(10, octstr_destroy_item); if (mdata != NULL) { curr->next = mdata->next; mdata->next = curr; } else { mdata = curr; } } if (replace) { /* delete old value if any */ dict_put(curr->values, (Octstr *) key, NULL); /* put new value */ dict_put(curr->values, (Octstr *) key, octstr_duplicate(value)); } else if (dict_get(curr->values, (Octstr *) key) == NULL) { /* put new value */ dict_put(curr->values, (Octstr *) key, octstr_duplicate(value)); } /* pack it */ ret = meta_data_pack(mdata, data); meta_data_destroy(mdata); return ret; } Octstr *meta_data_get_value(Octstr *data, const char *group, const Octstr *key) { struct meta_data *mdata, *curr; Octstr *ret = NULL; if (data == NULL || group == NULL || key == NULL) return NULL; mdata = meta_data_unpack(data); if (mdata == NULL) return NULL; for (curr = mdata; curr != NULL; curr = curr->next) { if (octstr_str_case_compare(curr->group, group) == 0) { ret = dict_remove(curr->values, (Octstr *) key); break; } } meta_data_destroy(mdata); return ret; } Octstr *meta_data_merge(const Octstr *data, const Octstr *new_data, int replace) { Octstr *ret = NULL; struct meta_data *mdata, *new_mdata, *new_curr, *curr; if (octstr_len(data) < 1) return octstr_duplicate(new_data); if (octstr_len(new_data) < 1) return octstr_duplicate(data); mdata = meta_data_unpack(data); if (mdata == NULL) { error(0, "meta_data_merge: Unable to parse data `%s'", octstr_get_cstr(data)); return octstr_duplicate(new_data); } new_mdata = meta_data_unpack(new_data); if (new_mdata == NULL) { meta_data_destroy(mdata); error(0, "meta_data_merge: Unable to parse data `%s'", octstr_get_cstr(new_data)); return octstr_duplicate(data); } for (new_curr = new_mdata; new_curr != NULL; new_curr = new_curr->next) { for (curr = mdata; curr != NULL; curr = curr->next) { /* check group name */ if (octstr_compare(curr->group, new_curr->group) == 0) { /* match */ List *keys; Octstr *key; keys = dict_keys(new_curr->values); while((key = gwlist_consume(keys)) != NULL) { if (replace == 0) { dict_put_once(curr->values, key, octstr_duplicate(dict_get(new_curr->values, key))); } else { /* remove if any */ dict_put(curr->values, key, NULL); dict_put(curr->values, key, octstr_duplicate(dict_get(new_curr->values, key))); } octstr_destroy(key); } gwlist_destroy(keys, octstr_destroy_item); break; /* we found mdata group */ } else if (curr->next == NULL) { /* do not match and this is last value -> add group */ curr->next = meta_data_create(); curr->next->group = octstr_duplicate(new_curr->group); curr->next->values = dict_create(10, octstr_destroy_item); } } } ret = octstr_create(""); if (meta_data_pack(mdata, ret) == -1) { octstr_destroy(ret); ret = NULL; } meta_data_destroy(new_mdata); meta_data_destroy(mdata); return ret; } gateway-1.4.5/gw/wap_push_pap_compiler.h0000644000175000017500000000770013227613126017041 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wap_push_pap_compiler.h - compiling PAP control document to a Kannel event. * * By Aarno Syvänen for Wapit Ltd. */ #ifndef WAP_PUSH_PAP_COMPILER_H #define WAP_PUSH_PAP_COMPILER_H #include "wap/wap_events.h" #include "gwlib/gwlib.h" /* * Possible address types */ enum { ADDR_IPV4 = 0, ADDR_PLMN = 1, ADDR_USER = 2, ADDR_IPV6 = 3, ADDR_WINA = 4 }; /* *Compile PAP control document to a corresponding Kannel event. Checks vali- * dity of the document. The caller must initialize wap event to NULL. In add- * ition, it must free memory allocated by this function. * * After compiling, some semantic analysing of the resulted event. * * Note that entities in the DTD are parameter entities and they can appear * only in DTD (See site http://www.w3.org/TR/REC-xml, Chapter 4.1). So we do * not need to worry about them in the document itself. * * Returns 0, when success * -1, when a non-implemented pap feature is asked for * -2, when error * In addition, returns a newly created wap event corresponding the pap * control message, if success, wap event NULL otherwise. */ int pap_compile(Octstr *pap_content, WAPEvent **e); int parse_address(Octstr **attr_value, long *type_of_address); #endif gateway-1.4.5/gw/wap-maps.h0000644000175000017500000001123113227613126014200 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * gw/wap-maps.h - URL mapping * * Bruno Rodrigues */ /* * Adds a mapping entry to map an url into an (all optional) * - an description name * - new url * - a query-string parameter name to send msisdn, if available * - an header name to send msisdn, if available * - msisdn header format * - accept cookies (1), not accept (0) or use global settings (-1) */ void wap_map_add_url(Octstr *name, Octstr *url, Octstr *map_url, Octstr *send_msisdn_query, Octstr *send_msisdn_header, Octstr *send_msisdn_format, int accept_cookies); /* * Adds a mapping entry to map user/pass into a description * name and a msisdn */ void wap_map_add_user(Octstr *name, Octstr *user, Octstr *pass, Octstr *msisdn); /* * Destruction routines */ void wap_map_destroy(void); void wap_map_user_destroy(void); /* * Maybe rewrite URL, if there is a mapping. This is where the runtime * lookup comes in (called from further down this file, wsp_http.c) */ void wap_map_url(Octstr **osp, Octstr **send_msisdn_query, Octstr **send_msisdn_header, Octstr **send_msisdn_format, int *accept_cookies); /* * Provides a mapping facility for resolving user and pass to an * predefined MSISDN. * Returns 1, if mapping has been found, 0 otherwise. */ int wap_map_user(Octstr **msisdn, Octstr *user, Octstr *pass); /* * Called during configuration read, this adds a mapping for the source URL * "DEVICE:home", to the given destination. The mapping is configured * as an in/out prefix mapping. */ void wap_map_url_config_device_home(char *to); /* * Called during configuration read, once for each "map-url" statement. * Interprets parameter value as a space-separated two-tuple of src and dst. */ void wap_map_url_config(char *s); gateway-1.4.5/gw/numhash.h0000644000175000017500000001176113227613126014126 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * numhash.h - (telephone) number storing/hashing system * * Kalle Marjola 2000 for project Kannel * * !!! NOTE NOTE NOTE !!! * * Phone number precision is limited according to sizeof(long long) * in host machine. that is usually either 32 or 64 bits. In a * case of 32 bit longs, only last 19 digits are checked, otherwise * last 38 digits. This means that in some places several numbers * might map to same hash entry, and thus some caution is needed * specially with telephone number black lists * * USAGE: * the system is not very dynamic; if you want to resize the table * or hash, you must first nuke all old data and then recreate it * * MEMORY NEEDED: (approximated) * * 2* (sizeof(long long)+sizeof(void *)) bytes per number */ #ifndef NUMHASH_H #define NUMHASH_H #include /* number hashing/seeking functions * all return -1 on error and write to general Kannel log * * these 2 first are only required if you want to add the numbers * by hand - otherwise use the last function instead * * use prime_hash if you want an automatically generated hash size */ typedef struct numhash_table Numhash; /* get numbers from 'url' and create a new database out of them * Return NULL if cannot open database or other error, error is logged * * Numbers to datafile are saved as follows: * - one number per line * - number might have white spaces, '+' and '-' signs * - number is ended with ':' or end-of-line * - there can be additional comment after ':' * * For example, all following ones are valid lines: * 040 1234 * +358 40 1234 * +358 40-1234 : Kalle Marjola */ Numhash *numhash_create(const char *url); /* destroy hash and all numbers in it */ void numhash_destroy(Numhash *table); /* check if the number is in database, return 1 if found, 0 if not, * -1 on error */ int numhash_find_number(Numhash *table, Octstr *nro); /* if we already have the key */ int numhash_find_key(Numhash *table, long long key); /* if we want to know the key */ long long numhash_get_key(Octstr *nro); long long numhash_get_char_key(char *nro); /* Return hash fill percent. If 'longest' != NULL, set as longest * trail in hash */ double numhash_hash_fill(Numhash *table, int *longest); /* return number of numbers in hash */ int numhash_size(Numhash *table); #endif gateway-1.4.5/gw/mime_decompiler.c0000644000175000017500000001441613227613126015610 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * mime_decompiler.c - decompiling application/vnd.wap.multipart.* * to multipart/ * * * This is a header for Mime decompiler for decompiling binary mime * format to text mime format, which is used for transmitting POST * data from mobile terminal to decrease the use of the bandwidth. * * See comments below for explanations on individual functions. * * Bruno Rodrigues */ #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "wap/wsp.h" #include "wap/wsp_headers.h" #include "wap/wsp_strings.h" #include "mime_decompiler.h" /*********************************************************************** * Declarations of data types. */ int mime_decompile(Octstr *binary_mime, Octstr **mime) { char *boundary = "kannel_boundary"; ParseContext *context; long mime_parts; long i, j; unsigned long headers_len, data_len; i = mime_parts = headers_len = data_len = 0; debug("wap.wsp.multipart.form.data", 0, "MIMEDEC: begining decoding"); if(binary_mime == NULL || octstr_len(binary_mime) < 1) { warning(0, "MIMEDEC: invalid mime, ending"); return -1; } *mime = octstr_create(""); /* already dumped in deconvert_content debug("mime", 0, "MMSDEC: binary mime dump:"); octstr_dump(binary_mime, 0); */ context = parse_context_create(binary_mime); debug("mime", 0, "MIMEDEC: context created"); mime_parts = parse_get_uintvar(context); debug("mime", 0, "MIMEDEC: mime has %ld multipart entities", mime_parts); if(mime_parts == 0) { debug("mime", 0, "MIMEDEC: mime has none multipart entities, ending"); return 0; } while(parse_octets_left(context) > 0) { Octstr *headers, *data; List *gwlist_headers; i++; octstr_append(*mime, octstr_imm("--")); octstr_append(*mime, octstr_imm(boundary)); octstr_append(*mime, octstr_imm("\n")); headers_len = parse_get_uintvar(context); data_len = parse_get_uintvar(context); debug("mime", 0, "MIMEDEC[%ld]: headers length <0x%02lx>, " "data length <0x%02lx>", i, headers_len, data_len); if((headers = parse_get_octets(context, headers_len)) != NULL) { gwlist_headers = wsp_headers_unpack(headers, 1); for(j=0; j. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * ota_prov.h: OTA settings and bookmarks provisioning routines * * This module contains routines for the SMS OTA (auto configuration) message * creation and manipulation for the sendota HTTP interface. * * Official Nokia and Ericsson WAP OTA configuration settings coded * by Stipe Tolj , Wapme Systems AG. * * Officual OMA ProvCont OTA provisioning coded * by Paul Bagyenda, digital solutions Ltd. * * XML compiler by Aarno Syvänen , Wiral Ltd. */ #ifndef OTA_PROV_H #define OTA_PROV_H #include "gwlib/gwlib.h" /* * Our WSP data: a compiled OTA document * Return -2 when header error, -1 when compile error, 0 when no error */ int ota_pack_message(Msg **msg, Octstr *ota_doc, Octstr *doc_type, Octstr *from, Octstr *phone_number, Octstr *sec, Octstr *pin); /* * Tokenizes a given 'ota-setting' group (without using the xml compiler) to * a binary message and returns the whole message including sender and * receiver numbers. */ Msg *ota_tokenize_settings(CfgGroup *grp, Octstr *from, Octstr *receiver); /* * Tokenizes a given 'ota-bookmark' group (without using the xml compiler) to * a binary message and returns the whole message including sender and * receiver numbers. */ Msg *ota_tokenize_bookmarks(CfgGroup *grp, Octstr *from, Octstr *receiver); #endif /* OTA_PROV_H */ gateway-1.4.5/gw/load.h0000644000175000017500000000743113227613126013401 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /** * load.h * * Alexander Malysh 2008 for project Kannel */ #ifndef LOAD_H #define LOAD_H 1 #include /** * Anonymos Load typedef. */ typedef struct load Load; /** * Create new Load object. * @heuristic - 0 disable heuristic (means get always current load); 1 enable */ Load* load_create_real(int heuristic); #define load_create() load_create_real(1) /** * Add load measure interval. * @load - load object * @interval - measure interval in seconds * @return -1 if error occurs (e.g. interval already exists); 0 if all was fine */ int load_add_interval(Load *load, int interval); /** * Increase load values with @value. * @load - load object * @valu - how much to increase */ void load_increase_with(Load *load, unsigned long value); #define load_increase(load) load_increase_with(load, 1) /** * Destroy load object. * @load - load object */ void load_destroy(Load *load); /** * Get measured load value at position @pos. */ double load_get(Load *load, int pos); /** * Get length of intervals. */ int load_len(Load *load); #endif gateway-1.4.5/gw/bearerbox.h0000644000175000017500000001672513227613126014441 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * bearerbox.h * * General typedefs and functions for bearerbox */ #include "gwlib/gwlib.h" #include "msg.h" #include "smscconn.h" #include "bb_store.h" /* Default outgoing queue length */ #define DEFAULT_OUTGOING_SMS_QLENGTH 1000000 /* general bearerbox state */ enum { BB_RUNNING = 0, BB_ISOLATED = 1, /* do not receive new messgaes from UDP/SMSC */ BB_SUSPENDED = 2, /* do not transfer any messages */ BB_SHUTDOWN = 3, BB_DEAD = 4, BB_FULL = 5 /* message queue too long, do not accept new messages */ }; /* type of output given by various status functions */ enum { BBSTATUS_HTML = 0, BBSTATUS_TEXT = 1, BBSTATUS_WML = 2, BBSTATUS_XML = 3 }; /*--------------------------------------------------------------- * Module interface to core bearerbox * * Modules implement one or more of the following interfaces: * * XXX_start(Cfg *config) - start the module * XXX_restart(Cfg *config) - restart the module, according to new config * XXX_shutdown() - start the avalanche - started from UDP/SMSC * XXX_die() - final cleanup * * XXX_addwdp() - only for SMSC/UDP: add a new WDP message to outgoing system */ /*--------------- * bb_boxc.c (SMS and WAPBOX connections) */ int smsbox_start(Cfg *config); int smsbox_restart(Cfg *config); int wapbox_start(Cfg *config); Octstr *boxc_status(int status_type); /* tell total number of messages in separate wapbox incoming queues */ int boxc_incoming_wdp_queue(void); /* Clean up after box connections have died. */ void boxc_cleanup(void); /* * Route the incoming message to one of the following input queues: * a specific smsbox conn * a random smsbox conn if no shortcut routing and msg->sms.boxc_id match. * @return -1 if incoming queue full; 0 otherwise. */ int route_incoming_to_boxc(Msg *msg); /*--------------- * bb_udp.c (UDP receiver/sender) */ int udp_start(Cfg *config); /* int udp_restart(Cfg *config); */ int udp_shutdown(void); int udp_die(void); /* called when router dies */ /* add outgoing WDP. If fails, return -1 and msg is untouched, so * caller must think of new uses for it */ int udp_addwdp(Msg *msg); /* tell total number of messages in separate UDP outgoing port queues */ int udp_outgoing_queue(void); /*--------------- * bb_smscconn.c (SMS Center connections) */ int smsc2_start(Cfg *config); int smsc2_restart(Cfg *config); int smsc2_graceful_restart(void); void smsc2_suspend(void); /* suspend (can still send but not receive) */ void smsc2_resume(int is_init); /* resume */ int smsc2_shutdown(void); void smsc2_cleanup(void); /* final clean-up */ Octstr *smsc2_status(int status_type); /* function to route outgoing SMS'es * * If finds a good one, puts into it and returns SMSCCONN_SUCCESS * If finds only bad ones, but acceptable, queues and * returns SMSCCONN_QUEUED (like all acceptable currently disconnected) * if message acceptable but queues full returns SMSCCONN_FAILED_QFULL and * message is not destroyed. * If cannot find nothing at all, returns SMSCCONN_FAILED_DISCARDED and * message is NOT destroyed (otherwise it is) */ long smsc2_rout(Msg *msg, int resend); int smsc2_stop_smsc(Octstr *id); /* shutdown a specific smsc */ int smsc2_restart_smsc(Octstr *id); /* re-start a specific smsc */ int smsc2_add_smsc(Octstr *id); /* add a new smsc */ int smsc2_remove_smsc(Octstr *id); /* remove a specific smsc */ int smsc2_reload_lists(void); /* reload blacklists */ /*--------------- * bb_http.c (HTTP Admin) */ int httpadmin_start(Cfg *config); /* int http_restart(Cfg *config); */ void httpadmin_stop(void); /*----------------- * bb_alog.c (Custom access-log format handling) */ /* passes the access-log-format string from config to the module */ void bb_alog_init(const Octstr *format); /* cleanup for internal things */ void bb_alog_shutdown(void); /* called from bb_smscconn.c to log the various access-log events */ void bb_alog_sms(SMSCConn *conn, Msg *sms, const char *message); /*---------------------------------------------------------------- * Core bearerbox public functions; * used only via HTTP adminstration */ int bb_shutdown(void); int bb_isolate(void); int bb_suspend(void); int bb_resume(void); int bb_restart(void); int bb_graceful_restart(void); int bb_flush_dlr(void); int bb_stop_smsc(Octstr *id); int bb_add_smsc(Octstr *id); int bb_remove_smsc(Octstr *id); int bb_restart_smsc(Octstr *id); int bb_remove_message(Octstr *id); int bb_reload_lists(void); int bb_reload_smsc_groups(void); /* return string of current status */ Octstr *bb_print_status(int status_type); /*---------------------------------------------------------------- * common function to all (in bearerbox.c) */ /* return linebreak for given output format, or NULL if format * not supported */ char *bb_status_linebreak(int status_type); gateway-1.4.5/gw/smskannel.conf0000644000175000017500000000663511144324076015157 0ustar toljtolj# # THIS IS A SAMPLE CONFIGURATION FOR SMS KANNEL # # This basic version is used for system testing. It expects 'fakesmsc' to # send messages which are replied with simple fixed text message. # It is run like this: # # 1% gw/bearerbox gw/smskannel.conf # 2% gw/smsbox gw/smskannel.conf # 3% test/fakesmsc -i 0.1 -m 100 "123 345 text nop" # # ..all 3 commands in separate shells (or screen sessions) # Note that you can run them in different machines but have to # add certain command line argument and configuration variables then # # # For any modifications to this file, see Kannel User Guide # If that does not help, see Kannel web page (http://www.kannel.org) and # various online help and mailing list archives # # Notes on those who base their configuration on this: # 1) check security issues! (allowed IPs, passwords and ports) # 2) groups cannot have empty rows inside them! # 3) read the user guide # # Kalle Marjola for Kannel project 2001, 2004 #--------------------------------------------- # CORE # # There is only one core group and it sets all basic settings # of the bearerbox (and system). You should take extra notes on # configuration variables like 'store-file' (or 'store-dir'), # 'admin-allow-ip' and 'access.log' group = core admin-port = 13000 smsbox-port = 13001 admin-password = bar #status-password = foo #admin-deny-ip = "" #admin-allow-ip = "" #log-file = "/tmp/kannel.log" #log-level = 0 box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" #unified-prefix = "+358,00358,0;+,00" #access-log = "/tmp/access.log" #store-file = "kannel.store" #ssl-server-cert-file = "cert.pem" #ssl-server-key-file = "key.pem" #ssl-certkey-file = "mycertandprivkeyfile.pem" #--------------------------------------------- # SMSC CONNECTIONS # # SMSC connections are created in bearerbox and they handle SMSC specific # protocol and message relying. You need these to actually receive and send # messages to handset, but can use GSM modems as virtual SMSCs # This is a fake smsc connection, _only_ used to test the system and services. # It really cannot relay messages to actual handsets! group = smsc smsc = fake smsc-id = FAKE port = 20000 connect-allow-ip = 127.0.0.1 #--------------------------------------------- # SMSBOX SETUP # # Smsbox(es) do higher-level SMS handling after they have been received from # SMS centers by bearerbox, or before they are given to bearerbox for delivery group = smsbox bearerbox-host = 127.0.0.1 sendsms-port = 13013 global-sender = 13013 #sendsms-chars = "0123456789 +-" #log-file = "/tmp/smsbox.log" #log-level = 0 #access-log = "/tmp/access.log" #--------------------------------------------- # SEND-SMS USERS # # These users are used when Kannel smsbox sendsms interface is used to # send PUSH sms messages, i.e. calling URL like # http://kannel.machine:13013/cgi-bin/sendsms?username=tester&password=foobar... group = sendsms-user username = tester password = foobar #user-deny-ip = "" #user-allow-ip = "" #--------------------------------------------- # SERVICES # # These are 'responses' to sms PULL messages, i.e. messages arriving from # handsets. The response is based on message content. Only one sms-service is # applied, using the first one to match. group = sms-service keyword = nop text = "You asked nothing and I did it!" # There should be always a 'default' service. This service is used when no # other 'sms-service' is applied. group = sms-service keyword = default text = "No service specified" gateway-1.4.5/gw/numhash.c0000644000175000017500000002406113227613126014116 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * numhash.c * * NUMBER HASH functions * * functions to add a number to database/hash * and functions to retrieve them * * notes: read header file * * Kalle Marjola for project Kannel 1999-2000 */ #include #include #include #include #include "gwlib/gwlib.h" #include "numhash.h" #define NUMHASH_AUTO_HASH -1 /* set of pre-calculated prime numbers for hash generation... */ static int primes[] = { 101, 503, 1009, 2003, 3001, 5003, 7001, 10007, 20011, 30011, 40009, 50021, 60013, 70001, 80021, 90001, 100003, 150001, 200003, 300007, 400009, 500009, 600011, 700001, 800011, 900001, 1000003, 1100009, 1200007, 1300021, 1400017, 1500007, 1600033, 1700021, 1800017, 1900009, 2000003, 3000017, 4000037, 5000111, 6000101, 7000127, 8000051, -1 }; struct numhash_table { struct numhash_number *numbers; long number_total; long table_size; struct numhash_number **hash; long hash_size; }; /* Numhash */ struct numhash_number { long long key; /* (hopefully) unique key */ struct numhash_number *next; /* next in hash table, if any */ }; struct nh_entry { Numhash *hash; struct nh_entry *next; }; struct numhashes { struct nh_entry *first; struct nh_entry *last; }; /* Multitable */ static int precision = 19; /* the precision (last numbers) used */ /* * add new item (number) to hash table */ static int add_item(Numhash *table, struct numhash_number *nro) { if (table->hash[nro->key % table->hash_size]) { /* conflict */ struct numhash_number *ptr = table->hash[nro->key % table->hash_size]; if (ptr->key == nro->key) goto duplicate; while(ptr->next) { ptr = ptr->next; if (ptr->key == nro->key) goto duplicate; } ptr->next = nro; /* put as last of the linkage */ } else table->hash[nro->key % table->hash_size] = nro; return 0; duplicate: warning(0, "Duplicate number %lld!", nro->key); return -1; } /* Add a new number to number list and hash * Return 0 if all went ok, -1 if out of room */ static int numhash_add_number(Numhash *table, char *nro) { struct numhash_number *newnro; if (table->number_total == table->table_size) { error(0, "Table limit %ld reached, cannot add %s!", table->table_size, nro); return -1; } newnro = &table->numbers[table->number_total++]; /* take the next free */ newnro->key = numhash_get_char_key(nro); newnro->next = NULL; add_item(table, newnro); return 0; } /* Init the number table and hash table with given sizes */ static Numhash *numhash_init(int max_numbers, int hash_size) { Numhash *ntable = NULL; ntable = gw_malloc(sizeof(Numhash)); if (hash_size > 0) ntable->hash_size = hash_size; else if (hash_size == NUMHASH_AUTO_HASH) { int i; for(i=0 ; primes[i] > 0; i++) { ntable->hash_size = primes[i]; if (ntable->hash_size > max_numbers) break; } } else { gw_free(ntable); return NULL; } ntable->hash = gw_malloc(ntable->hash_size * sizeof(struct numhash_number *)); memset(ntable->hash, 0, sizeof(struct numhash_number *) * ntable->hash_size); ntable->table_size = max_numbers; ntable->numbers = gw_malloc(ntable->table_size * sizeof(struct numhash_number)); ntable->number_total = 0; /* set our accuracy according to the size of long int * Ok, we call this many times if we use multiple tables, but * that is not a problem... */ if (sizeof(long long) >= 16) precision = 38; else if (sizeof(long long) >= 8) precision = 19; return ntable; } /*------------------------------------------------------ * PUBLIC FUNCTIONS */ int numhash_find_number(Numhash *table, Octstr *nro) { long long key = numhash_get_key(nro); if (key < 0) return key; return numhash_find_key(table, key); } int numhash_find_key(Numhash *table, long long key) { struct numhash_number *ptr; ptr = table->hash[key % table->hash_size]; while (ptr) { if (ptr->key == key) return 1; ptr = ptr->next; } return 0; /* not found */ } long long numhash_get_key(Octstr *nro) { long long key; if (!nro) return -1; if (octstr_len(nro) > precision) key = strtoll(octstr_get_cstr(nro) + octstr_len(nro) - precision, (char**) NULL, 10); else key = strtoll(octstr_get_cstr(nro), (char**) NULL, 10); return key; } long long numhash_get_char_key(char *nro) { int len; long long key; if (!nro) return -1; len = strlen(nro); if (len > precision) key = strtoll(nro + len - precision, (char**) NULL, 10); else key = strtoll(nro, (char**) NULL, 10); return key; } void numhash_destroy(Numhash *table) { if (table == NULL) return; gw_free(table->numbers); gw_free(table->hash); gw_free(table); } double numhash_hash_fill(Numhash *table, int *longest) { int i, l, max = 0, tot = 0; struct numhash_number *ptr; for (i=0; i < table->hash_size; i++) if (table->hash[i]) { tot++; ptr = table->hash[i]; for (l=0; ptr->next; ptr = ptr->next) l++; if (l > max) max = l; } if (longest != NULL) *longest = max; return (double)(tot*100.0/(table->hash_size)); } int numhash_size(Numhash *table) { return table->number_total; } Numhash *numhash_create(const char *seek_url) { int loc, lines = 0; List *request_headers, *reply_headers; Octstr *url, *final_url, *reply_body; Octstr *type, *charset; char *data, *ptr, numbuf[100]; int status; Numhash *table; url = octstr_create(seek_url); request_headers = http_create_empty_headers(); status = http_get_real(HTTP_METHOD_GET, url, request_headers, &final_url, &reply_headers, &reply_body); octstr_destroy(url); octstr_destroy(final_url); http_destroy_headers(request_headers); if (status != HTTP_OK) { http_destroy_headers(reply_headers); octstr_destroy(reply_body); error(0, "Cannot load numhash!"); return NULL; } http_header_get_content_type(reply_headers, &type, &charset); octstr_destroy(charset); http_destroy_headers(reply_headers); if (octstr_str_compare(type, "text/plain") != 0) { octstr_destroy(reply_body); error(0, "Strange content type <%s> for numhash - expecting 'text/plain'" ", operatiom fails", octstr_get_cstr(type)); octstr_destroy(type); return NULL; } octstr_destroy(type); ptr = data = octstr_get_cstr(reply_body); while(*ptr) { if (*ptr == '\n') lines++; ptr++; } debug("numhash", 0, "Total %d lines in %s", lines, seek_url); table = numhash_init(lines+10, NUMHASH_AUTO_HASH); /* automatic hash */ /* now, parse the number information */ lines = 0; while((ptr = strchr(data, '\n'))) { /* each line is ended with linefeed */ *ptr = '\0'; while(*data != '\0' && isspace(*data)) data++; if (*data != '#') { loc = 0; while (*data != '\0') { if (isdigit(*data)) numbuf[loc++] = *data; else if (*data == ' ' || *data == '+' || *data == '-') ; else break; data++; } if (loc) { numbuf[loc] = '\0'; numhash_add_number(table, numbuf); lines++; } else warning(0, "Corrupted line '%s'", data); } data = ptr+1; /* next row... */ } octstr_destroy(reply_body); info(0, "Read from <%s> total of %ld numbers", seek_url, table->number_total); return table; } gateway-1.4.5/gw/dlr_sqlite3.c0000644000175000017500000003337513227613126014710 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dlr_sqlite3.c - sqlite3 dlr storage implementation. * * Author: David Butler * * Based on dlr_oracle.c * * Copyright: See COPYING file that comes with this distribution */ #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #include "dlr_p.h" #ifdef HAVE_SQLITE3 /* * Our connection pool to sqlite3. */ static DBPool *pool = NULL; /* * Database fields, which we are use. */ static struct dlr_db_fields *fields = NULL; static long dlr_messages_sqlite3() { List *result, *row; Octstr *sql; DBPoolConn *conn; long msgs = -1; conn = dbpool_conn_consume(pool); if (conn == NULL) return -1; sql = octstr_format("SELECT count(*) FROM %S", fields->table); #if defined(DLR_TRACE) debug("dlr.sqlite3", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(conn, sql, NULL, &result) != 0) { octstr_destroy(sql); dbpool_conn_produce(conn); return -1; } dbpool_conn_produce(conn); octstr_destroy(sql); if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); msgs = strtol(octstr_get_cstr(gwlist_get(row, 0)), NULL, 10); gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(result, NULL); return msgs; } static void dlr_shutdown_sqlite3() { dbpool_destroy(pool); dlr_db_fields_destroy(fields); } static void dlr_add_sqlite3(struct dlr_entry *entry) { Octstr *sql, *os_mask; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.sqlite3", 0, "adding DLR entry into database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { dlr_entry_destroy(entry); return; } sql = octstr_format("INSERT INTO %S (%S, %S, %S, %S, %S, %S, %S, %S, %S) VALUES " "(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, 0)", fields->table, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status); os_mask = octstr_format("%d", entry->mask); gwlist_append(binds, entry->smsc); /* ?1 */ gwlist_append(binds, entry->timestamp); /* ?2 */ gwlist_append(binds, entry->source); /* ?3 */ gwlist_append(binds, entry->destination); /* ?4 */ gwlist_append(binds, entry->service); /* ?5 */ gwlist_append(binds, entry->url); /* ?6 */ gwlist_append(binds, os_mask); /* ?7 */ gwlist_append(binds, entry->boxc_id); /* ?8 */ #if defined(DLR_TRACE) debug("dlr.sqlite3", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: SQLite3: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination)); else if (!res) warning(0, "DLR: SQLite3: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination)); dbpool_conn_produce(pconn); octstr_destroy(sql); gwlist_destroy(binds, NULL); octstr_destroy(os_mask); dlr_entry_destroy(entry); } static void dlr_remove_sqlite3(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.sqlite3", 0, "removing DLR from database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; if (dst) like = octstr_format("AND %S LIKE '%?3'", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("DELETE FROM %S WHERE ROWID IN (SELECT ROWID FROM %S WHERE %S=?1 AND %S=?2 %S LIMIT 1)", fields->table, fields->table, fields->field_smsc, fields->field_ts, like); gwlist_append(binds, (Octstr *)smsc); /* ?1 */ gwlist_append(binds, (Octstr *)ts); /* ?2 */ if (dst) gwlist_append(binds, (Octstr *)dst); /* ?3 */ #if defined(DLR_TRACE) debug("dlr.sqlite3", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: SQLite3: Error while removing dlr entry for DST<%s>", octstr_get_cstr(dst)); else if (!res) warning(0, "DLR: SQLite3: No dlr deleted for DST<%s>", octstr_get_cstr(dst)); dbpool_conn_produce(pconn); gwlist_destroy(binds, NULL); octstr_destroy(sql); octstr_destroy(like); } static struct dlr_entry* dlr_get_sqlite3(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; DBPoolConn *pconn; List *result = NULL, *row; struct dlr_entry *res = NULL; List *binds = gwlist_create(); pconn = dbpool_conn_consume(pool); if (pconn == NULL) /* should not happens, but sure is sure */ return NULL; if (dst) like = octstr_format("AND %S LIKE '%?3'", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("SELECT %S, %S, %S, %S, %S, %S FROM %S WHERE %S=?1 AND %S=?2 %S LIMIT 1", fields->field_mask, fields->field_serv, fields->field_url, fields->field_src, fields->field_dst, fields->field_boxc, fields->table, fields->field_smsc, fields->field_ts, like); gwlist_append(binds, (Octstr *)smsc); /* ?1 */ gwlist_append(binds, (Octstr *)ts); /* ?2 */ if (dst) gwlist_append(binds, (Octstr *)dst); /* ?3 */ #if defined(DLR_TRACE) debug("dlr.sqlite3", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(pconn, sql, binds, &result) != 0) { octstr_destroy(sql); dbpool_conn_produce(pconn); return NULL; } octstr_destroy(sql); octstr_destroy(like); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); #define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i)) if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); res = dlr_entry_create(); gw_assert(res != NULL); res->mask = atoi(LO2CSTR(row,0)); res->service = octstr_create(LO2CSTR(row, 1)); res->url = octstr_create(LO2CSTR(row,2)); res->source = octstr_create(LO2CSTR(row, 3)); res->destination = octstr_create(LO2CSTR(row, 4)); res->boxc_id = octstr_create(LO2CSTR(row, 5)); gwlist_destroy(row, octstr_destroy_item); res->smsc = octstr_duplicate(smsc); } gwlist_destroy(result, NULL); #undef LO2CSTR return res; } static void dlr_update_sqlite3(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status) { Octstr *sql, *os_status, *like; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.sqlite3", 0, "updating DLR status in database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; if (dst) like = octstr_format("AND %S LIKE '%?4'", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("UPDATE %S SET %S=?1 WHERE ROWID IN (SELECT ROWID FROM %S WHERE %S=?2 AND %S=?3 %S LIMIT 1)", fields->table, fields->field_status, fields->table, fields->field_smsc, fields->field_ts, like); os_status = octstr_format("%d", status); gwlist_append(binds, (Octstr *)os_status); /* ?1 */ gwlist_append(binds, (Octstr *)smsc); /* ?2 */ gwlist_append(binds, (Octstr *)ts); /* ?3 */ if (dst) gwlist_append(binds, (Octstr *)dst); /* ?4 */ #if defined(DLR_TRACE) debug("dlr.sqlite3", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: SQLite3: Error while updating dlr entry for DST<%s>", octstr_get_cstr(dst)); else if (!res) warning(0, "DLR: SQLite3: No dlr found to update for DST<%s> (status: %d)", octstr_get_cstr(dst), status); dbpool_conn_produce(pconn); gwlist_destroy(binds, NULL); octstr_destroy(os_status); octstr_destroy(sql); octstr_destroy(like); } static void dlr_flush_sqlite3 (void) { Octstr *sql; DBPoolConn *pconn; int rows; pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; sql = octstr_format("DELETE FROM %S", fields->table); #if defined(DLR_TRACE) debug("dlr.sqlite3", 0, "sql: %s", octstr_get_cstr(sql)); #endif rows = dbpool_conn_update(pconn, sql, NULL); if (rows == -1) error(0, "DLR: SQLite3: Error while flushing dlr entries from database"); else debug("dlr.sqlite3", 0, "Flushing %d DLR entries from database", rows); dbpool_conn_produce(pconn); octstr_destroy(sql); } static struct dlr_storage handles = { .type = "sqlite3", .dlr_messages = dlr_messages_sqlite3, .dlr_shutdown = dlr_shutdown_sqlite3, .dlr_add = dlr_add_sqlite3, .dlr_get = dlr_get_sqlite3, .dlr_remove = dlr_remove_sqlite3, .dlr_update = dlr_update_sqlite3, .dlr_flush = dlr_flush_sqlite3 }; struct dlr_storage *dlr_init_sqlite3(Cfg *cfg) { CfgGroup *grp; List *grplist; long pool_size; DBConf *db_conf = NULL; Octstr *id, *file; int found; if ((grp = cfg_get_single_group(cfg, octstr_imm("dlr-db"))) == NULL) panic(0, "DLR: SQLite3: group 'dlr-db' is not specified!"); if (!(id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: SQLite3: directive 'id' is not specified!"); /* initialize database fields */ fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); grplist = cfg_get_multi_group(cfg, octstr_imm("sqlite3-connection")); found = 0; while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { Octstr *p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, id) == 0) { found = 1; } if (p != NULL) octstr_destroy(p); if (found == 1) break; } gwlist_destroy(grplist, NULL); if (found == 0) panic(0, "DLR: SQLite3: connection settings for id '%s' are not specified!", octstr_get_cstr(id)); file = cfg_get(grp, octstr_imm("database")); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1) pool_size = 1; if (file == NULL) panic(0, "DLR: SQLite3: connection settings missing for id '%s', please" " check you configuration.",octstr_get_cstr(id)); /* ok we are ready to create dbpool */ db_conf = gw_malloc(sizeof(*db_conf)); db_conf->sqlite3 = gw_malloc(sizeof(SQLite3Conf)); db_conf->sqlite3->file = file; pool = dbpool_create(DBPOOL_SQLITE3, db_conf, pool_size); gw_assert(pool != NULL); if (dbpool_conn_count(pool) == 0) panic(0, "DLR: SQLite3: Could not establish sqlite3 connection(s)."); octstr_destroy(id); return &handles; } #else /* no sqlite3 support build in */ struct dlr_storage *dlr_init_sqlite3(Cfg *cfg) { return NULL; } #endif /* HAVE_SQLITE3 */ gateway-1.4.5/gw/xml_definitions.h0000644000175000017500000000737013227613126015657 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * xml_definitions.h - definitions common to XML compilers * * This file contains definitions for global tokens * * Tuomas Luttinen for Wapit Ltd. */ /*********************************************************************** * Declarations of global tokens. */ #define WBXML_SWITCH_PAGE 0x00 #define WBXML_END 0x01 #define WBXML_ENTITY 0x02 #define WBXML_STR_I 0x03 #define WBXML_LITERAL 0x04 #define WBXML_EXT_I_0 0x40 #define WBXML_EXT_I_1 0x41 #define WBXML_EXT_I_2 0x42 #define WBXML_PI 0x43 #define WBXML_LITERAL_C 0x44 #define WBXML_EXT_T_0 0x80 #define WBXML_EXT_T_1 0x81 #define WBXML_EXT_T_2 0x82 #define WBXML_STR_T 0x83 #define WBXML_LITERAL_A 0x84 #define WBXML_EXT_0 0xC0 #define WBXML_EXT_1 0xC1 #define WBXML_EXT_2 0xC2 #define WBXML_OPAQUE 0xC3 #define WBXML_LITERAL_AC 0xC4 #define WBXML_STR_END 0x00 #define WBXML_CONTENT_BIT 0x40 #define WBXML_ATTR_BIT 0x80 #define WBXML_STRING_TABLE_MIN 4 #define WBXML_START_NUM 100 gateway-1.4.5/gw/bb_store_file.c0000644000175000017500000003516213227613126015255 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * bb_store.c : bearerbox box SMS storage/retrieval module * * Kalle Marjola 2001 for project Kannel * * Updated Oct 2004 * * New features: * - uses dict to save messages, for faster retrieval * - acks are no longer saved (to memory), they simply delete * messages from dict * - better choice when dump done; configurable frequency */ #include #include #include #include #include #include #include #include #include #include #include "gwlib/gwlib.h" #include "msg.h" #include "bearerbox.h" #include "sms.h" static FILE *file = NULL; static Octstr *filename = NULL; static Octstr *newfile = NULL; static Octstr *bakfile = NULL; static Mutex *file_mutex = NULL; static long cleanup_thread = -1; static long dump_frequency = 0; static Dict *sms_dict = NULL; static int active = 1; static time_t last_dict_mod = 0; static List *loaded; static void write_msg(Msg *msg) { Octstr *pack; unsigned char buf[4]; pack = store_msg_pack(msg); encode_network_long(buf, octstr_len(pack)); octstr_insert_data(pack, 0, (char*)buf, 4); octstr_print(file, pack); fflush(file); octstr_destroy(pack); } static int read_msg(Msg **msg, Octstr *os, long *off) { unsigned char buf[4]; long i; Octstr *pack; gw_assert(*off >= 0); if (*off + 4 > octstr_len(os)) { error(0, "Packet too short while unpacking Msg."); return -1; } octstr_get_many_chars((char*)buf, os, *off, 4); i = decode_network_long(buf); *off += 4; pack = octstr_copy(os, *off, i); *off += octstr_len(pack); *msg = store_msg_unpack(pack); octstr_destroy(pack); if (!*msg) return -1; return 0; } static int open_file(Octstr *name) { file = fopen(octstr_get_cstr(name), "w"); if (file == NULL) { error(errno, "Failed to open '%s' for writing, cannot create store-file", octstr_get_cstr(name)); return -1; } return 0; } static int rename_store(void) { if (rename(octstr_get_cstr(filename), octstr_get_cstr(bakfile)) == -1) { if (errno != ENOENT) { error(errno, "Failed to rename old store '%s' as '%s'", octstr_get_cstr(filename), octstr_get_cstr(bakfile)); return -1; } } if (rename(octstr_get_cstr(newfile), octstr_get_cstr(filename)) == -1) { error(errno, "Failed to rename new store '%s' as '%s'", octstr_get_cstr(newfile), octstr_get_cstr(filename)); return -1; } return 0; } static int do_dump(void) { Octstr *key; Msg *msg; List *sms_list; long l; if (filename == NULL) return 0; /* create a new store-file and save all non-acknowledged * messages into it */ if (open_file(newfile)==-1) return -1; sms_list = dict_keys(sms_dict); for (l=0; l < gwlist_len(sms_list); l++) { key = gwlist_get(sms_list, l); msg = dict_get(sms_dict, key); if (msg != NULL) write_msg(msg); } fflush(file); gwlist_destroy(sms_list, octstr_destroy_item); /* rename old storefile as .bak, and then new as regular file * without .new ending */ return rename_store(); } /* * thread to write current store to file now and then, to prevent * it from becoming far too big (slows startup) */ static void store_dumper(void *arg) { time_t now; int busy = 0; while (active) { now = time(NULL); /* * write store to file up to each N. second, providing * that something happened or if we are constantly busy. */ if (now - last_dict_mod > dump_frequency || busy) { store_dump(); /* * make sure that no new dump is done for a while unless * something happens. This moves the trigger in the future * and allows the if statement to pass if nothing happened * in the mean time while sleeping. The busy flag is needed * to garantee we do dump in case we are constantly busy * and hence the difference between now and last dict * operation is less then dump frequency, otherwise we * would never dump. This is for constant high load. */ last_dict_mod = time(NULL) + 3600*24; busy = 0; } else { busy = (now - last_dict_mod) > 0; } gwthread_sleep(dump_frequency); } store_dump(); if (file != NULL) fclose(file); octstr_destroy(filename); octstr_destroy(newfile); octstr_destroy(bakfile); mutex_destroy(file_mutex); dict_destroy(sms_dict); /* set all vars to NULL */ filename = newfile = bakfile = NULL; file_mutex = NULL; sms_dict = NULL; } /*------------------------------------------------------*/ static void store_file_for_each_message(void(*callback_fn)(Msg* msg, void *data), void *data) { List *keys; long l; Msg *msg; Octstr *key; /* if there is no store-file, then don't loop in sms_store */ if (filename == NULL) return; mutex_lock(file_mutex); keys = dict_keys(sms_dict); for (l = 0; l < gwlist_len(keys); l++) { key = gwlist_get(keys, l); msg = dict_get(sms_dict, key); if (msg == NULL) continue; callback_fn(msg, data); } mutex_unlock(file_mutex); gwlist_destroy(keys, octstr_destroy_item); } static long store_file_messages(void) { return (sms_dict ? dict_key_count(sms_dict) : -1); } static int store_to_dict(Msg *msg) { Msg *copy; Octstr *uuid_os; char id[UUID_STR_LEN + 1]; /* always set msg id and timestamp */ if (msg_type(msg) == sms && uuid_is_null(msg->sms.id)) uuid_generate(msg->sms.id); if (msg_type(msg) == sms && msg->sms.time == MSG_PARAM_UNDEFINED) time(&msg->sms.time); if (msg_type(msg) == sms) { copy = msg_duplicate(msg); uuid_unparse(copy->sms.id, id); uuid_os = octstr_create(id); dict_put(sms_dict, uuid_os, copy); octstr_destroy(uuid_os); last_dict_mod = time(NULL); } else if (msg_type(msg) == ack) { uuid_unparse(msg->ack.id, id); uuid_os = octstr_create(id); copy = dict_remove(sms_dict, uuid_os); octstr_destroy(uuid_os); if (copy == NULL) { warning(0, "bb_store: get ACK of message not found " "from store, strange?"); } else { msg_destroy(copy); last_dict_mod = time(NULL); } } else return -1; return 0; } static int store_file_save(Msg *msg) { if (filename == NULL) return 0; /* block here until store not loaded */ gwlist_consume(loaded); /* lock file_mutex in order to have dict and file in sync */ mutex_lock(file_mutex); if (store_to_dict(msg) == -1) { mutex_unlock(file_mutex); return -1; } /* write to file, too */ write_msg(msg); fflush(file); mutex_unlock(file_mutex); return 0; } static int store_file_save_ack(Msg *msg, ack_status_t status) { Msg *mack; int ret; /* only sms are handled */ if (!msg || msg_type(msg) != sms) return -1; if (filename == NULL) return 0; mack = msg_create(ack); if (!mack) return -1; mack->ack.time = msg->sms.time; uuid_copy(mack->ack.id, msg->sms.id); mack->ack.nack = status; ret = store_save(mack); msg_destroy(mack); return ret; } static int store_file_load(void(*receive_msg)(Msg*)) { List *keys; Octstr *store_file, *key; Msg *msg; int retval, msgs; long end, pos; if (filename == NULL) return 0; mutex_lock(file_mutex); if (file != NULL) { fclose(file); file = NULL; } store_file = octstr_read_file(octstr_get_cstr(filename)); if (store_file != NULL) info(0, "Loading store file `%s'", octstr_get_cstr(filename)); else { store_file = octstr_read_file(octstr_get_cstr(newfile)); if (store_file != NULL) info(0, "Loading store file `%s'", octstr_get_cstr(newfile)); else { store_file = octstr_read_file(octstr_get_cstr(bakfile)); if (store_file != NULL) info(0, "Loading store file `%s'", octstr_get_cstr(bakfile)); else { info(0, "Cannot open any store file, starting a new one"); retval = open_file(filename); goto end; } } } info(0, "Store-file size %ld, starting to unpack%s", octstr_len(store_file), octstr_len(store_file) > 10000 ? " (may take awhile)" : ""); pos = 0; msgs = 0; end = octstr_len(store_file); while (pos < end) { if (read_msg(&msg, store_file, &pos) == -1) { error(0, "Garbage at store-file, skipped."); continue; } if (msg_type(msg) == sms) { store_to_dict(msg); msgs++; } else if (msg_type(msg) == ack) { store_to_dict(msg); } else { warning(0, "Strange message in store-file, discarded, " "dump follows:"); msg_dump(msg, 0); } msg_destroy(msg); } octstr_destroy(store_file); info(0, "Retrieved %d messages, non-acknowledged messages: %ld", msgs, dict_key_count(sms_dict)); /* now create a new sms_store out of messages left */ keys = dict_keys(sms_dict); while ((key = gwlist_extract_first(keys)) != NULL) { msg = dict_remove(sms_dict, key); if (store_to_dict(msg) != -1) { receive_msg(msg); } else { error(0, "Found unknown message type in store file."); msg_dump(msg, 0); msg_destroy(msg); } octstr_destroy(key); } gwlist_destroy(keys, octstr_destroy_item); /* Finally, generate new store file out of left messages */ retval = do_dump(); end: mutex_unlock(file_mutex); /* allow using of store */ gwlist_remove_producer(loaded); /* start dumper thread */ if ((cleanup_thread = gwthread_create(store_dumper, NULL))==-1) panic(0, "Failed to create a cleanup thread!"); return retval; } static int store_file_dump(void) { int retval; debug("bb.store", 0, "Dumping %ld messages to store", dict_key_count(sms_dict)); mutex_lock(file_mutex); if (file != NULL) { fclose(file); file = NULL; } retval = do_dump(); mutex_unlock(file_mutex); return retval; } static void store_file_shutdown(void) { if (filename == NULL) return; active = 0; gwthread_wakeup(cleanup_thread); /* wait for cleanup thread */ if (cleanup_thread != -1) gwthread_join(cleanup_thread); gwlist_destroy(loaded, NULL); } int store_file_init(const Octstr *fname, long dump_freq) { /* Initialize function pointers */ store_messages = store_file_messages; store_save = store_file_save; store_save_ack = store_file_save_ack; store_load = store_file_load; store_dump = store_file_dump; store_shutdown = store_file_shutdown; store_for_each_message = store_file_for_each_message; if (fname == NULL) return 0; /* we are done */ if (octstr_len(fname) > (FILENAME_MAX-5)) panic(0, "Store file filename too long: `%s', failed to init.", octstr_get_cstr(fname)); filename = octstr_duplicate(fname); newfile = octstr_format("%s.new", octstr_get_cstr(filename)); bakfile = octstr_format("%s.bak", octstr_get_cstr(filename)); sms_dict = dict_create(1024, msg_destroy_item); if (dump_freq > 0) dump_frequency = dump_freq; else dump_frequency = BB_STORE_DEFAULT_DUMP_FREQ; file_mutex = mutex_create(); active = 1; loaded = gwlist_create(); gwlist_add_producer(loaded); return 0; } gateway-1.4.5/gw/dlr_mysql.c0000644000175000017500000003660313227613126014466 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * dlr_mysql.c * * Implementation of handling delivery reports (DLRs) * for MySql database * * Andreas Fink , 18.08.2001 * Stipe Tolj , 22.03.2002 * Alexander Malysh 2003 */ #include "gwlib/gwlib.h" #include "gwlib/dbpool.h" #include "dlr_p.h" #ifdef HAVE_MYSQL /* * Our connection pool to mysql. */ static DBPool *pool = NULL; /* * Database fields, which we are use. */ static struct dlr_db_fields *fields = NULL; static void dlr_mysql_shutdown() { dbpool_destroy(pool); dlr_db_fields_destroy(fields); } static void dlr_mysql_add(struct dlr_entry *entry) { Octstr *sql, *os_mask; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.mysql", 0, "adding DLR entry into database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) { dlr_entry_destroy(entry); return; } sql = octstr_format("INSERT INTO `%S` (`%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`) VALUES " "(?, ?, ?, ?, ?, ?, ?, ?, 0)", fields->table, fields->field_smsc, fields->field_ts, fields->field_src, fields->field_dst, fields->field_serv, fields->field_url, fields->field_mask, fields->field_boxc, fields->field_status); os_mask = octstr_format("%d", entry->mask); gwlist_append(binds, entry->smsc); gwlist_append(binds, entry->timestamp); gwlist_append(binds, entry->source); gwlist_append(binds, entry->destination); gwlist_append(binds, entry->service); gwlist_append(binds, entry->url); gwlist_append(binds, os_mask); gwlist_append(binds, entry->boxc_id); #if defined(DLR_TRACE) debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: MYSQL: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination)); else if (!res) warning(0, "DLR: MYSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination)); dbpool_conn_produce(pconn); octstr_destroy(sql); gwlist_destroy(binds, NULL); octstr_destroy(os_mask); dlr_entry_destroy(entry); } static struct dlr_entry* dlr_mysql_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; DBPoolConn *pconn; List *result = NULL, *row; struct dlr_entry *res = NULL; List *binds = gwlist_create(); pconn = dbpool_conn_consume(pool); if (pconn == NULL) /* should not happens, but sure is sure */ return NULL; if (dst) like = octstr_format("AND `%S` LIKE CONCAT('%%', ?)", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("SELECT `%S`, `%S`, `%S`, `%S`, `%S`, `%S` FROM `%S` WHERE `%S`=? AND `%S`=? %S LIMIT 1", fields->field_mask, fields->field_serv, fields->field_url, fields->field_src, fields->field_dst, fields->field_boxc, fields->table, fields->field_smsc, fields->field_ts, like); gwlist_append(binds, (Octstr *)smsc); gwlist_append(binds, (Octstr *)ts); if (dst) gwlist_append(binds, (Octstr *)dst); #if defined(DLR_TRACE) debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(pconn, sql, binds, &result) != 0) { octstr_destroy(sql); octstr_destroy(like); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); return NULL; } octstr_destroy(sql); octstr_destroy(like); gwlist_destroy(binds, NULL); dbpool_conn_produce(pconn); #define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i)) if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); res = dlr_entry_create(); gw_assert(res != NULL); res->mask = atoi(LO2CSTR(row,0)); res->service = octstr_create(LO2CSTR(row, 1)); res->url = octstr_create(LO2CSTR(row,2)); res->source = octstr_create(LO2CSTR(row, 3)); res->destination = octstr_create(LO2CSTR(row, 4)); res->boxc_id = octstr_create(LO2CSTR(row, 5)); gwlist_destroy(row, octstr_destroy_item); res->smsc = octstr_duplicate(smsc); } gwlist_destroy(result, NULL); #undef LO2CSTR return res; } static void dlr_mysql_remove(const Octstr *smsc, const Octstr *ts, const Octstr *dst) { Octstr *sql, *like; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.mysql", 0, "removing DLR from database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; if (dst) like = octstr_format("AND `%S` LIKE CONCAT('%%', ?)", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("DELETE FROM `%S` WHERE `%S`=? AND `%S`=? %S LIMIT 1", fields->table, fields->field_smsc, fields->field_ts, like); gwlist_append(binds, (Octstr *)smsc); gwlist_append(binds, (Octstr *)ts); if (dst) gwlist_append(binds, (Octstr *)dst); #if defined(DLR_TRACE) debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: MYSQL: Error while removing dlr entry for DST<%s>", octstr_get_cstr(dst)); else if (!res) warning(0, "DLR: MYSQL: No dlr deleted for DST<%s>", octstr_get_cstr(dst)); dbpool_conn_produce(pconn); gwlist_destroy(binds, NULL); octstr_destroy(sql); octstr_destroy(like); } static void dlr_mysql_update(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int status) { Octstr *sql, *os_status, *like; DBPoolConn *pconn; List *binds = gwlist_create(); int res; debug("dlr.mysql", 0, "updating DLR status in database"); pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; if (dst) like = octstr_format("AND `%S` LIKE CONCAT('%%', ?)", fields->field_dst); else like = octstr_imm(""); sql = octstr_format("UPDATE `%S` SET `%S`=? WHERE `%S`=? AND `%S`=? %S LIMIT 1", fields->table, fields->field_status, fields->field_smsc, fields->field_ts, like); os_status = octstr_format("%d", status); gwlist_append(binds, (Octstr *)os_status); gwlist_append(binds, (Octstr *)smsc); gwlist_append(binds, (Octstr *)ts); if (dst) gwlist_append(binds, (Octstr *)dst); #if defined(DLR_TRACE) debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if ((res = dbpool_conn_update(pconn, sql, binds)) == -1) error(0, "DLR: MYSQL: Error while updating dlr entry for DST<%s>", octstr_get_cstr(dst)); else if (!res) warning(0, "DLR: MYSQL: No dlr found to update for DST<%s>, (status %d)", octstr_get_cstr(dst), status); dbpool_conn_produce(pconn); gwlist_destroy(binds, NULL); octstr_destroy(os_status); octstr_destroy(sql); octstr_destroy(like); } static long dlr_mysql_messages(void) { List *result, *row; Octstr *sql; DBPoolConn *conn; long msgs = -1; conn = dbpool_conn_consume(pool); if (conn == NULL) return -1; sql = octstr_format("SELECT count(*) FROM `%S`", fields->table); #if defined(DLR_TRACE) debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql)); #endif if (dbpool_conn_select(conn, sql, NULL, &result) != 0) { octstr_destroy(sql); dbpool_conn_produce(conn); return -1; } dbpool_conn_produce(conn); octstr_destroy(sql); if (gwlist_len(result) > 0) { row = gwlist_extract_first(result); msgs = strtol(octstr_get_cstr(gwlist_get(row,0)), NULL, 10); gwlist_destroy(row, octstr_destroy_item); } gwlist_destroy(result, NULL); return msgs; } static void dlr_mysql_flush(void) { Octstr *sql; DBPoolConn *pconn; int rows; pconn = dbpool_conn_consume(pool); /* just for sure */ if (pconn == NULL) return; sql = octstr_format("DELETE FROM `%S`", fields->table); #if defined(DLR_TRACE) debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql)); #endif rows = dbpool_conn_update(pconn, sql, NULL); if (rows == -1) error(0, "DLR: MYSQL: Error while flushing dlr entries from database"); else debug("dlr.mysql", 0, "Flushing %d DLR entries from database", rows); dbpool_conn_produce(pconn); octstr_destroy(sql); } static struct dlr_storage handles = { .type = "mysql", .dlr_add = dlr_mysql_add, .dlr_get = dlr_mysql_get, .dlr_update = dlr_mysql_update, .dlr_remove = dlr_mysql_remove, .dlr_shutdown = dlr_mysql_shutdown, .dlr_messages = dlr_mysql_messages, .dlr_flush = dlr_mysql_flush }; struct dlr_storage *dlr_init_mysql(Cfg *cfg) { CfgGroup *grp; List *grplist; Octstr *mysql_host, *mysql_user, *mysql_pass, *mysql_db, *mysql_id; long mysql_port = 0; Octstr *p = NULL; long pool_size; DBConf *db_conf = NULL; /* * check for all mandatory directives that specify the field names * of the used MySQL table */ if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db")))) panic(0, "DLR: MySQL: group 'dlr-db' is not specified!"); if (!(mysql_id = cfg_get(grp, octstr_imm("id")))) panic(0, "DLR: MySQL: directive 'id' is not specified!"); fields = dlr_db_fields_create(grp); gw_assert(fields != NULL); /* * Escaping special quotes for field/table names */ octstr_replace(fields->table, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_smsc, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_ts, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_src, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_dst, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_serv, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_url, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_mask, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_status, octstr_imm("`"), octstr_imm("``")); octstr_replace(fields->field_boxc, octstr_imm("`"), octstr_imm("``")); /* * now grap the required information from the 'mysql-connection' group * with the mysql-id we just obtained * * we have to loop through all available MySQL connection definitions * and search for the one we are looking for */ grplist = cfg_get_multi_group(cfg, octstr_imm("mysql-connection")); while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) { p = cfg_get(grp, octstr_imm("id")); if (p != NULL && octstr_compare(p, mysql_id) == 0) { goto found; } if (p != NULL) octstr_destroy(p); } panic(0, "DLR: MySQL: connection settings for id '%s' are not specified!", octstr_get_cstr(mysql_id)); found: octstr_destroy(p); gwlist_destroy(grplist, NULL); if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0) pool_size = 1; if (!(mysql_host = cfg_get(grp, octstr_imm("host")))) panic(0, "DLR: MySQL: directive 'host' is not specified!"); if (!(mysql_user = cfg_get(grp, octstr_imm("username")))) panic(0, "DLR: MySQL: directive 'username' is not specified!"); if (!(mysql_pass = cfg_get(grp, octstr_imm("password")))) panic(0, "DLR: MySQL: directive 'password' is not specified!"); if (!(mysql_db = cfg_get(grp, octstr_imm("database")))) panic(0, "DLR: MySQL: directive 'database' is not specified!"); cfg_get_integer(&mysql_port, grp, octstr_imm("port")); /* optional */ /* * ok, ready to connect to MySQL */ db_conf = gw_malloc(sizeof(DBConf)); gw_assert(db_conf != NULL); db_conf->mysql = gw_malloc(sizeof(MySQLConf)); gw_assert(db_conf->mysql != NULL); db_conf->mysql->host = mysql_host; db_conf->mysql->port = mysql_port; db_conf->mysql->username = mysql_user; db_conf->mysql->password = mysql_pass; db_conf->mysql->database = mysql_db; pool = dbpool_create(DBPOOL_MYSQL, db_conf, pool_size); gw_assert(pool != NULL); /* * XXX should a failing connect throw panic?! */ if (dbpool_conn_count(pool) == 0) panic(0,"DLR: MySQL: database pool has no connections!"); octstr_destroy(mysql_id); return &handles; } #else /* * Return NULL , so we point dlr-core that we were * not compiled in. */ struct dlr_storage *dlr_init_mysql(Cfg* cfg) { return NULL; } #endif /* HAVE_MYSQL */ gateway-1.4.5/gw/msg.c0000644000175000017500000002266013227613126013244 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * msg.c - manipulate messages * * This file contains implementations of the functions that create, destroy, * pack, and unpack messages. * * Lars Wirzenius */ #include #include #include #include #include "msg.h" #include "gwlib/gwlib.h" /********************************************************************** * Prototypes for private functions. */ static void append_integer(Octstr *os, long i); static void append_string(Octstr *os, Octstr *field); static void append_uuid(Octstr *os, uuid_t id); static int parse_integer(long *i, Octstr *packed, int *off); static int parse_string(Octstr **os, Octstr *packed, int *off); static int parse_uuid(uuid_t id, Octstr *packed, int *off); static char *type_as_str(Msg *msg); /********************************************************************** * Implementations of the exported functions. */ Msg *msg_create_real(enum msg_type type, const char *file, long line, const char *func) { Msg *msg; msg = gw_malloc_trace(sizeof(Msg), file, line, func); msg->type = type; #define INTEGER(name) p->name = MSG_PARAM_UNDEFINED; #define OCTSTR(name) p->name = NULL; #define UUID(name) uuid_generate(p->name); #define VOID(name) p->name = NULL; #define MSG(type, stmt) { struct type *p = &msg->type; stmt } #include "msg-decl.h" return msg; } Msg *msg_duplicate(Msg *msg) { Msg *new; new = msg_create(msg->type); #define INTEGER(name) p->name = q->name; #define OCTSTR(name) \ if (q->name == NULL) p->name = NULL; \ else p->name = octstr_duplicate(q->name); #define UUID(name) uuid_copy(p->name, q->name); #define VOID(name) p->name = q->name; #define MSG(type, stmt) { \ struct type *p = &new->type; \ struct type *q = &msg->type; \ stmt } #include "msg-decl.h" return new; } void msg_destroy(Msg *msg) { if (msg == NULL) return; #define INTEGER(name) p->name = 0; #define OCTSTR(name) octstr_destroy(p->name); #define UUID(name) uuid_clear(p->name); #define VOID(name) #define MSG(type, stmt) { struct type *p = &msg->type; stmt } #include "msg-decl.h" gw_free(msg); } void msg_destroy_item(void *msg) { msg_destroy(msg); } void msg_dump(Msg *msg, int level) { char buf[UUID_STR_LEN + 1]; debug("gw.msg", 0, "%*sMsg object at %p:", level, "", (void *) msg); debug("gw.msg", 0, "%*s type: %s", level, "", type_as_str(msg)); #define INTEGER(name) \ debug("gw.msg", 0, "%*s %s.%s: %ld", level, "", t, #name, (long) p->name); #define OCTSTR(name) \ debug("gw.msg", 0, "%*s %s.%s:", level, "", t, #name); \ octstr_dump(p->name, level + 1); #define UUID(name) \ uuid_unparse(p->name, buf); \ debug("gw.msg", 0 , "%*s %s.%s: %s", level, "", t, #name, buf); #define VOID(name) \ debug("gw.msg", 0, "%*s %s.%s: %p", level, "", t, #name, p->name); #define MSG(tt, stmt) \ if (tt == msg->type) \ { char *t = #tt; struct tt *p = &msg->tt; stmt } #include "msg-decl.h" debug("gw.msg", 0, "Msg object ends."); } enum msg_type msg_type(Msg *msg) { return msg->type; } Octstr *msg_pack(Msg *msg) { Octstr *os; os = octstr_create(""); append_integer(os, msg->type); #define INTEGER(name) append_integer(os, p->name); #define OCTSTR(name) append_string(os, p->name); #define UUID(name) append_uuid(os, p->name); #define VOID(name) #define MSG(type, stmt) \ case type: { struct type *p = &msg->type; stmt } break; switch (msg->type) { #include "msg-decl.h" default: panic(0, "Internal error: unknown message type: %d", msg->type); } return os; } Msg *msg_unpack_real(Octstr *os, const char *file, long line, const char *func) { Msg *msg; int off; long i; msg = msg_create_real(0, file, line, func); if (msg == NULL) goto error; off = 0; if (parse_integer(&i, os, &off) == -1) goto error; msg->type = i; #define INTEGER(name) \ if (parse_integer(&(p->name), os, &off) == -1) goto error; #define OCTSTR(name) \ if (parse_string(&(p->name), os, &off) == -1) goto error; #define UUID(name) \ if (parse_uuid(p->name, os, &off) == -1) goto error; #define VOID(name) #define MSG(type, stmt) \ case type: { struct type *p = &(msg->type); stmt } break; switch (msg->type) { #include "msg-decl.h" default: error(0, "Internal error: unknown message type: %d", msg->type); msg->type = 0; msg_destroy(msg); return NULL; } return msg; error: if (msg != NULL) msg_destroy(msg); error(0, "Msg packet was invalid."); return NULL; } /* * Wrapper function needed for function pointer forwarding to storage * subsystem. We can't pass the msg_unpack() pre-processor macro, so we * need to wrapp a function arround it. */ inline Msg *msg_unpack_wrapper(Octstr *os) { return msg_unpack(os); } /********************************************************************** * Implementations of private functions. */ static void append_integer(Octstr *os, long i) { unsigned char buf[4]; encode_network_long(buf, i); octstr_append_data(os, (char *)buf, 4); } static void append_string(Octstr *os, Octstr *field) { if (field == NULL) append_integer(os, -1); else { append_integer(os, octstr_len(field)); octstr_insert(os, field, octstr_len(os)); } } static void append_uuid(Octstr *os, uuid_t id) { char buf[UUID_STR_LEN + 1]; uuid_unparse(id, buf); append_integer(os, UUID_STR_LEN); octstr_append_cstr(os, buf); } static int parse_integer(long *i, Octstr *packed, int *off) { unsigned char buf[4]; gw_assert(*off >= 0); if (*off + 4 > octstr_len(packed)) { error(0, "Packet too short while unpacking Msg."); return -1; } octstr_get_many_chars((char *)buf, packed, *off, 4); *i = decode_network_long(buf); *off += 4; return 0; } static int parse_string(Octstr **os, Octstr *packed, int *off) { long len; if (parse_integer(&len, packed, off) == -1) return -1; if (len == -1) { *os = NULL; return 0; } /* XXX check that len is ok */ *os = octstr_copy(packed, *off, len); if (*os == NULL) return -1; *off += len; return 0; } static int parse_uuid(uuid_t id, Octstr *packed, int *off) { Octstr *tmp = NULL; if (parse_string(&tmp, packed, off) == -1) { octstr_destroy(tmp); return -1; } if (uuid_parse(octstr_get_cstr(tmp), id) == -1) { octstr_destroy(tmp); return -1; } octstr_destroy(tmp); return 0; } static char *type_as_str(Msg *msg) { switch (msg->type) { #define MSG(t, stmt) case t: return #t; #include "msg-decl.h" default: return "unknown type"; } } gateway-1.4.5/gw/wapbox.c0000644000175000017500000007054413227613126013762 0ustar toljtolj/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see . * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * wapbox.c - main program for wapbox * * This module contains the main program for the WAP box of the WAP gateway. * See the architecture documentation for details. */ #include #include #include #include #include "gwlib/gwlib.h" #include "shared.h" #include "wml_compiler.h" #include "heartbeat.h" #include "wap/wap.h" #include "wap-appl.h" #include "wap-maps.h" #include "wap_push_ota.h" #include "wap_push_ppg.h" #include "gw/msg.h" #include "bb.h" #include "sms.h" #ifdef HAVE_WTLS_OPENSSL #include #include "wap/wtls.h" #include "gwlib/pki.h" #endif #include "radius/radius_acct.h" static void config_reload(int reload); static long logfilelevel=-1; enum { CONNECTIONLESS_PORT = 9200, CONNECTION_ORIENTED_PORT = 9201, WTLS_CONNECTIONLESS_PORT = 9202, WTLS_CONNECTION_ORIENTED_PORT = 9203 }; enum { DEFAULT_TIMER_FREQ = 1}; static Octstr *bearerbox_host; static long bearerbox_port = BB_DEFAULT_WAPBOX_PORT; static int bearerbox_ssl = 0; static Counter *sequence_counter = NULL; static long timer_freq = DEFAULT_TIMER_FREQ; static Octstr *config_filename; /* use strict XML parsing or relaxed */ static int wml_xml_strict = 1; /* smart error messaging related globals */ int wsp_smart_errors = 0; Octstr *device_home = NULL; /* Controlling segmentation of sms messages sent by wapbox (push related).*/ int concatenation = 1; long max_messages = 10; #ifdef HAVE_WTLS_OPENSSL extern RSA* private_key; extern X509* x509_cert; extern void wtls_secmgr_init(); #endif static Cfg *init_wapbox(Cfg *cfg) { CfgGroup *grp; Octstr *s; Octstr *logfile; int lf, m; long value; lf = m = 1; cfg_dump(cfg); /* * Extract info from the core group. */ grp = cfg_get_single_group(cfg, octstr_imm("core")); if (grp == NULL) panic(0, "No 'core' group in configuration."); if (cfg_get_integer(&bearerbox_port,grp,octstr_imm("wapbox-port")) == -1) panic(0, "No 'wapbox-port' in core group"); #ifdef HAVE_LIBSSL cfg_get_bool(&bearerbox_ssl, grp, octstr_imm("wapbox-port-ssl")); #endif /* HAVE_LIBSSL */ /* load parameters that could be later reloaded */ config_reload(0); conn_config_ssl(grp); /* * And the rest of the pull info comes from the wapbox group. */ grp = cfg_get_single_group(cfg, octstr_imm("wapbox")); if (grp == NULL) panic(0, "No 'wapbox' group in configuration."); bearerbox_host = cfg_get(grp, octstr_imm("bearerbox-host")); if (cfg_get_integer(&timer_freq, grp, octstr_imm("timer-freq")) == -1) timer_freq = DEFAULT_TIMER_FREQ; logfile = cfg_get(grp, octstr_imm("log-file")); if (logfile != NULL) { log_open(octstr_get_cstr(logfile), logfilelevel, GW_NON_EXCL); info(0, "Starting to log to file %s level %ld", octstr_get_cstr(logfile), logfilelevel); } octstr_destroy(logfile); if ((s = cfg_get(grp, octstr_imm("syslog-level"))) != NULL) { long level; Octstr *facility; if ((facility = cfg_get(grp, octstr_imm("syslog-facility"))) != NULL) { log_set_syslog_facility(octstr_get_cstr(facility)); octstr_destroy(facility); } if (octstr_compare(s, octstr_imm("none")) == 0) { log_set_syslog(NULL, 0); debug("wap", 0, "syslog parameter is none"); } else if (octstr_parse_long(&level, s, 0, 10) > 0) { log_set_syslog("wapbox", level); debug("wap", 0, "syslog parameter is %ld", level); } octstr_destroy(s); } else { log_set_syslog(NULL, 0); debug("wap", 0, "no syslog parameter"); } /* determine which timezone we use for access logging */ if ((s = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) { lf = (octstr_case_compare(s, octstr_imm("gmt")) == 0) ? 0 : 1; octstr_destroy(s); } /* should predefined markers be used, ie. prefixing timestamp */ cfg_get_bool(&m, grp, octstr_imm("access-log-clean")); /* open access-log file */ if ((s = cfg_get(grp, octstr_imm("access-log"))) != NULL) { info(0, "Logging accesses to '%s'.", octstr_get_cstr(s)); alog_open(octstr_get_cstr(s), lf, m ? 0 : 1); octstr_destroy(s); } if (cfg_get_integer(&value, grp, octstr_imm("http-timeout")) == 0) http_set_client_timeout(value); /* configure the 'wtls' group */ #if (HAVE_WTLS_OPENSSL) /* Load up the necessary keys */ grp = cfg_get_single_group(cfg, octstr_imm("wtls")); if (grp != NULL) { if ((s = cfg_get(grp, octstr_imm("certificate-file"))) != NULL) { if (octstr_compare(s, octstr_imm("none")) == 0) { debug("bbox", 0, "certificate file not set"); } else { /* Load the certificate into the necessary parameter */ get_cert_from_file(s, &x509_cert); gw_assert(x509_cert != NULL); debug("bbox", 0, "certificate parameter is %s", octstr_get_cstr(s)); } octstr_destroy(s); } else panic(0, "No 'certificate-file' in wtls group"); if ((s = cfg_get(grp, octstr_imm("privatekey-file"))) != NULL) { Octstr *password; password = cfg_get(grp, octstr_imm("privatekey-password")); if (octstr_compare(s, octstr_imm("none")) == 0) { debug("bbox", 0, "privatekey-file not set"); } else { /* Load the private key into the necessary parameter */ get_privkey_from_file(s, &private_key, password); gw_assert(private_key != NULL); debug("bbox", 0, "certificate parameter is %s", octstr_get_cstr(s)); } if (password != NULL) octstr_destroy(password); octstr_destroy(s); } else panic(0, "No 'privatekey-file' in wtls group"); } #endif /* * Check if we have a 'radius-acct' proxy group and start the * corresponding thread for the proxy. */ grp = cfg_get_single_group(cfg, octstr_imm("radius-acct")); if (grp) { radius_acct_init(grp); } /* * We pass ppg configuration groups to the ppg module. */ grp = cfg_get_single_group(cfg, octstr_imm("ppg")); if (grp == NULL) { cfg_destroy(cfg); return NULL; } return cfg; } static void signal_handler(int signum) { /* * On some implementations (i.e. linuxthreads), signals are delivered * to all threads. We only want to handle each signal once for the * entire box, and we let the gwthread wrapper take care of choosing * one. */ if (!gwthread_shouldhandlesignal(signum)) return; switch (signum) { case SIGINT: case SIGTERM: if (program_status != shutting_down) { error(0, "SIGINT or SIGTERM received, let's die."); program_status = shutting_down; break; } break; case SIGHUP: warning(0, "SIGHUP received, catching and re-opening logs"); config_reload(1); log_reopen(); alog_reopen(); break; /* * It would be more proper to use SIGUSR1 for this, but on some * platforms that's reserved by the pthread support. */ case SIGQUIT: warning(0, "SIGQUIT received, reporting memory usage."); gw_check_leaks(); break; } } static void setup_signal_handlers(void) { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGPIPE, &act, NULL); } /* * We create wdp_datagram for IP traffic and sms for SMS traffic. */ static Msg *pack_ip_datagram(WAPEvent *dgram) { Msg *msg; WAPAddrTuple *tuple; msg = msg_create(wdp_datagram); tuple = dgram->u.T_DUnitdata_Req.addr_tuple; msg->wdp_datagram.source_address = octstr_duplicate(tuple->local->address); msg->wdp_datagram.source_port = dgram->u.T_DUnitdata_Req.addr_tuple->local->port; msg->wdp_datagram.destination_address = octstr_duplicate(tuple->remote->address); msg->wdp_datagram.destination_port = dgram->u.T_DUnitdata_Req.addr_tuple->remote->port; msg->wdp_datagram.user_data = octstr_duplicate(dgram->u.T_DUnitdata_Req.user_data); return msg; } /* * Format for port UDH is defined in wdp, appendix A. It is %06%05%04 * %dest port high hex%dest port low%hex source port high hex%source port low * hex. (Unsecure) push client port itself is 2948. */ static Octstr *pack_udhdata(WAPAddrTuple *tuple) { int source_port, dest_port; Octstr *udh; source_port = tuple->local->port; dest_port = tuple->remote->port; udh = octstr_create(""); octstr_format_append(udh, "%c", 6); octstr_format_append(udh, "%c", 5); octstr_format_append(udh, "%c", 4); octstr_format_append(udh, "%c", (dest_port >> 8) & 0xff); octstr_format_append(udh, "%c", dest_port & 0xff); octstr_format_append(udh, "%c", (source_port >> 8) & 0xff); octstr_format_append(udh, "%c", source_port & 0xff); return udh; } /* * We send a normal 8-bit unconcatenated binary message with an udh. Caller * must do segmentation before calling this function. * * Note: we have hardcoded validity period here. We must eventually use push * control document to fill this field. */ static Msg *pack_sms_datagram(WAPEvent *dgram) { Msg *msg; WAPAddrTuple *tuple; msg = msg_create(sms); tuple = dgram->u.T_DUnitdata_Req.addr_tuple; msg->sms.sender = octstr_duplicate(tuple->local->address); msg->sms.receiver = octstr_duplicate(tuple->remote->address); msg->sms.udhdata = pack_udhdata(tuple); msg->sms.msgdata = octstr_duplicate(dgram->u.T_DUnitdata_Req.user_data); msg->sms.time = time(NULL); if (dgram->u.T_DUnitdata_Req.smsc_id != NULL) msg->sms.smsc_id = octstr_duplicate(dgram->u.T_DUnitdata_Req.smsc_id); else msg->sms.smsc_id = NULL; msg->sms.dlr_mask = dgram->u.T_DUnitdata_Req.dlr_mask; if (dgram->u.T_DUnitdata_Req.smsbox_id != NULL) msg->sms.boxc_id = octstr_duplicate(dgram->u.T_DUnitdata_Req.smsbox_id); else msg->sms.boxc_id = NULL; if (dgram->u.T_DUnitdata_Req.dlr_url != NULL) msg->sms.dlr_url = octstr_duplicate(dgram->u.T_DUnitdata_Req.dlr_url); else msg->sms.dlr_url = NULL; msg->sms.sms_type = mt_push; msg->sms.mwi = MWI_UNDEF; msg->sms.coding = DC_8BIT; msg->sms.mclass = MC_UNDEF; msg->sms.validity = time(NULL) + 1440; msg->sms.deferred = SMS_PARAM_UNDEFINED; if (dgram->u.T_DUnitdata_Req.service_name != NULL) msg->sms.service = octstr_duplicate(dgram->u.T_DUnitdata_Req.service_name); return msg; } /* * Possible address types */ enum { ADDR_IPV4 = 0, ADDR_PLMN = 1, ADDR_USER = 2, ADDR_IPV6 = 3, ADDR_WINA = 4 }; /* * Send IP datagram as it is, segment SMS datagram if necessary. */ static void dispatch_datagram(WAPEvent *dgram) { Msg *msg, *part; List *sms_datagrams; static unsigned long msg_sequence = 0L; /* Used only by this function */ msg = part = NULL; sms_datagrams = NULL; if (dgram == NULL) { error(0, "WDP: dispatch_datagram received empty datagram, ignoring."); } else if (dgram->type != T_DUnitdata_Req) { warning(0, "WDP: dispatch_datagram received event of unexpected type."); wap_event_dump(dgram); } else if (dgram->u.T_DUnitdata_Req.address_type == ADDR_IPV4) { #ifdef HAVE_WTLS_OPENSSL if (dgram->u.T_DUnitdata_Req.addr_tuple->local->port >= WTLS_CONNECTIONLESS_PORT) wtls_dispatch_resp(dgram); else #endif /* HAVE_WTLS_OPENSSL */ { msg = pack_ip_datagram(dgram); write_to_bearerbox(msg); } } else { msg_sequence = counter_increase(sequence_counter) & 0xff; msg = pack_sms_datagram(dgram); sms_datagrams = sms_split(msg, NULL, NULL, NULL, NULL, concatenation, msg_sequence, max_messages, MAX_SMS_OCTETS); debug("wap",0,"WDP (wapbox): delivering %ld segments to bearerbox", gwlist_len(sms_datagrams)); while ((part = gwlist_extract_first(sms_datagrams)) != NULL) { write_to_bearerbox(part); } gwlist_destroy(sms_datagrams, NULL); msg_destroy(msg); } wap_event_destroy(dgram); } /* * Reloading functions */ static void reload_int(int reload, Octstr *desc, long *o, long *n) { if (reload && *o != *n) { info(0, "Reloading int '%s' from %ld to %ld", octstr_get_cstr(desc), *o, *n); *o = *n; } } static void reload_bool(int reload, Octstr *desc, int *o, int *n) { if (reload && *o != *n) { info(0, "Reloading bool '%s' from %s to %s", octstr_get_cstr(desc), (*o ? "yes" : "no"), (*n ? "yes" : "no")); *o = *n; } } /* * Read all reloadable configuration directives */ static void config_reload(int reload) { Cfg *cfg; CfgGroup *grp; List *groups; long map_url_max; Octstr *s; long i; long new_value; int new_bool; Octstr *http_proxy_host; Octstr *http_interface_name; long http_proxy_port; int http_proxy_ssl = 0; List *http_proxy_exceptions; Octstr *http_proxy_username; Octstr *http_proxy_password; Octstr *http_proxy_exceptions_regex; int warn_map_url = 0; /* XXX TO-DO: if(reload) implement wapbox.suspend/mutex.lock */ if (reload) debug("config_reload", 0, "Reloading configuration"); /* * NOTE: we could lstat config file and only reload if it was modified, * but as we have a include directive, we don't know every file's * timestamp at this point */ cfg = cfg_create(config_filename); if (cfg_read(cfg) == -1) { warning(0, "Couldn't %sload configuration from `%s'.", (reload ? "re" : ""), octstr_get_cstr(config_filename)); return; } grp = cfg_get_single_group(cfg, octstr_imm("core")); http_proxy_host = cfg_get(grp, octstr_imm("http-proxy-host")); http_proxy_port = -1; cfg_get_integer(&http_proxy_port, grp, octstr_imm("http-proxy-port")); #ifdef HAVE_LIBSSL cfg_get_bool(&http_proxy_ssl, grp, octstr_imm("http-proxy-ssl")); #endif /* HAVE_LIBSSL */ http_proxy_username = cfg_get(grp, octstr_imm("http-proxy-username")); http_proxy_password = cfg_get(grp, octstr_imm("http-proxy-password")); http_proxy_exceptions = cfg_get_list(grp, octstr_imm("http-proxy-exceptions")); http_proxy_exceptions_regex = cfg_get(grp, octstr_imm("http-proxy-exceptions-regex")); if (http_proxy_host != NULL && http_proxy_port > 0) { http_use_proxy(http_proxy_host, http_proxy_port, http_proxy_ssl, http_proxy_exceptions, http_proxy_username, http_proxy_password, http_proxy_exceptions_regex); } octstr_destroy(http_proxy_host); octstr_destroy(http_proxy_username); octstr_destroy(http_proxy_password); octstr_destroy(http_proxy_exceptions_regex); gwlist_destroy(http_proxy_exceptions, octstr_destroy_item); grp = cfg_get_single_group(cfg, octstr_imm("wapbox")); if (grp == NULL) { warning(0, "No 'wapbox' group in configuration."); return; } if (cfg_get_integer(&new_value, grp, octstr_imm("log-level")) != -1) { reload_int(reload, octstr_imm("log level"), &logfilelevel, &new_value); logfilelevel = new_value; log_set_log_level(new_value); } /* Configure interface name for http requests */ http_interface_name = cfg_get(grp, octstr_imm("http-interface-name")); if (http_interface_name != NULL) { http_set_interface(http_interface_name); octstr_destroy(http_interface_name); } /* * users may define 'smart-errors' to have WML decks returned with * error information instead of signaling using the HTTP reply codes */ cfg_get_bool(&new_bool, grp, octstr_imm("smart-errors")); reload_bool(reload, octstr_imm("smart error messaging"), &wsp_smart_errors, &new_bool); /* decide if our XML parser within WML compiler is strict or relaxed */ cfg_get_bool(&new_bool, grp, octstr_imm("wml-strict")); reload_bool(reload, octstr_imm("XML within WML has to be strict"), &wml_xml_strict, &new_bool); if (!wml_xml_strict) warning(0, "'wml-strict' config directive has been set to no, " "this may make you vulnerable against XML bogus input."); if (cfg_get_bool(&new_bool, grp, octstr_imm("concatenation")) == 1) reload_bool(reload, octstr_imm("concatenation"), &concatenation, &new_bool); else concatenation = 1; if (cfg_get_integer(&new_value, grp, octstr_imm("max-messages")) != -1) { max_messages = new_value; reload_int(reload, octstr_imm("max messages"), &max_messages, &new_value); } /* configure URL mappings */ map_url_max = -1; cfg_get_integer(&map_url_max, grp, octstr_imm("map-url-max")); if (map_url_max > 0) warn_map_url = 1; if (reload) { /* clear old map */ wap_map_destroy(); wap_map_user_destroy(); } if ((device_home = cfg_get(grp, octstr_imm("device-home"))) != NULL) { wap_map_url_config_device_home(octstr_get_cstr(device_home)); } if ((s = cfg_get(grp, octstr_imm("map-url"))) != NULL) { warn_map_url = 1; wap_map_url_config(octstr_get_cstr(s)); octstr_destroy(s); } debug("wap", 0, "map_url_max = %ld", map_url_max); for (i = 0; i <= map_url_max; i++) { Octstr *name; name = octstr_format("map-url-%d", i); if ((s = cfg_get(grp, name)) != NULL) wap_map_url_config(octstr_get_cstr(s)); octstr_destroy(name); } /* warn the user that he/she should use the new wap-url-map groups */ if (warn_map_url) warning(0, "'map-url' config directive and related are deprecated, " "please use wap-url-map group"); /* configure wap-url-map */ groups = cfg_get_multi_group(cfg, octstr_imm("wap-url-map")); while (groups && (grp = gwlist_extract_first(groups)) != NULL) { Octstr *name, *url, *map_url, *send_msisdn_query; Octstr *send_msisdn_header, *send_msisdn_format; int accept_cookies; name = cfg_get(grp, octstr_imm("name")); url = cfg_get(grp, octstr_imm("url")); map_url = cfg_get(grp, octstr_imm("map-url")); send_msisdn_query = cfg_get(grp, octstr_imm("send-msisdn-query")); send_msisdn_header = cfg_get(grp, octstr_imm("send-msisdn-header")); send_msisdn_format = cfg_get(grp, octstr_imm("send-msisdn-format")); accept_cookies = -1; cfg_get_bool(&accept_cookies, grp, octstr_imm("accept-cookies")); wap_map_add_url(name, url, map_url, send_msisdn_query, send_msisdn_header, send_msisdn_format, accept_cookies); info(0, "Added wap-url-map <%s> with url <%s>, map-url <%s>, " "send-msisdn-query <%s>, send-msisdn-header <%s>, " "send-msisdn-format <%s>, accept-cookies <%s>", octstr_get_cstr(name), octstr_get_cstr(url), octstr_get_cstr(map_url), octstr_get_cstr(send_msisdn_query), octstr_get_cstr(send_msisdn_header), octstr_get_cstr(send_msisdn_format), (accept_cookies ? "yes" : "no")); } gwlist_destroy(groups, NULL); /* configure wap-user-map */ groups = cfg_get_multi_group(cfg, octstr_imm("wap-user-map")); while (groups && (grp = gwlist_extract_first(groups)) != NULL) { Octstr *name, *user, *pass, *msisdn; name = cfg_get(grp, octstr_imm("name")); user = cfg_get(grp, octstr_imm("user")); pass = cfg_get(grp, octstr_imm("pass")); msisdn = cfg_get(grp, octstr_imm("msisdn")); wap_map_add_user(name, user, pass, msisdn); info(0,"Added wap-user-map <%s> with credentials <%s:%s> " "and MSISDN <%s>", octstr_get_cstr(name), octstr_get_cstr(user), octstr_get_cstr(pass), octstr_get_cstr(msisdn)); } gwlist_destroy(groups, NULL); cfg_destroy(cfg); /* XXX TO-DO: if(reload) implement wapbox.resume/mutex.unlock */ } int main(int argc, char **argv) { int cf_index; int restart = 0; Msg *msg; Cfg *cfg; double heartbeat_freq = DEFAULT_HEARTBEAT; gwlib_init(); cf_index = get_and_set_debugs(argc, argv, NULL); setup_signal_handlers(); if (argv[cf_index] == NULL) config_filename = octstr_create("kannel.conf"); else config_filename = octstr_create(argv[cf_index]); cfg = cfg_create(config_filename); if (cfg_read(cfg) == -1) panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(config_filename)); report_versions("wapbox"); cfg = init_wapbox(cfg); info(0, "------------------------------------------------------------"); info(0, GW_NAME " wapbox version %s starting up.", GW_VERSION); sequence_counter = counter_create(); wsp_session_init(&wtp_resp_dispatch_event, &wtp_initiator_dispatch_event, &wap_appl_dispatch, &wap_push_ppg_dispatch_event); wsp_unit_init(&dispatch_datagram, &wap_appl_dispatch); wsp_push_client_init(&wsp_push_client_dispatch_event, &wtp_resp_dispatch_event); if (cfg) wtp_initiator_init(&dispatch_datagram, &wsp_session_dispatch_event, timer_freq); wtp_resp_init(&dispatch_datagram, &wsp_session_dispatch_event, &wsp_push_client_dispatch_event, timer_freq); wap_appl_init(cfg); #if (HAVE_WTLS_OPENSSL) wtls_secmgr_init(); wtls_init(&write_to_bearerbox); #endif if (cfg) { wap_push_ota_init(&wsp_session_dispatch_event, &wsp_unit_dispatch_event); wap_push_ppg_init(&wap_push_ota_dispatch_event, &wap_appl_dispatch, cfg); } wml_init(wml_xml_strict); if (bearerbox_host == NULL) bearerbox_host = octstr_create(BB_DEFAULT_HOST); connect_to_bearerbox(bearerbox_host, bearerbox_port, bearerbox_ssl, NULL /* bearerbox_our_port */); if (cfg) wap_push_ota_bb_address_set(bearerbox_host); program_status = running; if (0 > heartbeat_start(write_to_bearerbox, heartbeat_freq, wap_appl_get_load)) { info(0, GW_NAME "Could not start heartbeat."); } while (program_status != shutting_down) { WAPEvent *dgram; int ret; /* block infinite for reading messages */ ret = read_from_bearerbox(&msg, INFINITE_TIME); if (ret == -1) { error(0, "Bearerbox is gone, restarting"); program_status = shutting_down; restart = 1; break; } else if (ret == 1) /* timeout */ continue; else if (msg == NULL) /* just to be sure, may not happens */ break; if (msg_type(msg) == admin) { if (msg->admin.command == cmd_shutdown) { info(0, "Bearerbox told us to die"); program_status = shutting_down; } else if (msg->admin.command == cmd_restart) { info(0, "Bearerbox told us to restart"); restart = 1; program_status = shutting_down; } /* * XXXX here should be suspend/resume, add RSN */ } else if (msg_type(msg) == wdp_datagram) { switch (msg->wdp_datagram.destination_port) { case CONNECTIONLESS_PORT: case CONNECTION_ORIENTED_PORT: dgram = wap_event_create(T_DUnitdata_Ind); dgram->u.T_DUnitdata_Ind.addr_tuple = wap_addr_tuple_create( msg->wdp_datagram.source_address, msg->wdp_datagram.source_port, msg->wdp_datagram.destination_address, msg->wdp_datagram.destination_port); dgram->u.T_DUnitdata_Ind.user_data = msg->wdp_datagram.user_data; msg->wdp_datagram.user_data = NULL; wap_dispatch_datagram(dgram); break; case WTLS_CONNECTIONLESS_PORT: case WTLS_CONNECTION_ORIENTED_PORT: #if (HAVE_WTLS_OPENSSL) dgram = wtls_unpack_wdp_datagram(msg); if (dgram != NULL) wtls_dispatch_event(dgram); #endif break; default: panic(0,"Bad packet received! This shouldn't happen!"); break; } } else { warning(0, "Received other message than wdp/admin, ignoring!"); } msg_destroy(msg); } info(0, GW_NAME " wapbox terminating."); program_status = shutting_down; heartbeat_stop(ALL_HEARTBEATS); counter_destroy(sequence_counter); if (cfg) wtp_initiator_shutdown(); wtp_resp_shutdown(); wsp_push_client_shutdown(); wsp_unit_shutdown(); wsp_session_shutdown(); wap_appl_shutdown(); radius_acct_shutdown(); if (cfg) { wap_push_ota_shutdown(); wap_push_ppg_shutdown(); } wml_shutdown(); close_connection_to_bearerbox(); alog_close(); wap_map_destroy(); wap_map_user_destroy(); octstr_destroy(device_home); octstr_destroy(bearerbox_host); octstr_destroy(config_filename); /* * Just sleep for a while to get bearerbox chance to restart. * Otherwise we will fail while trying to connect to bearerbox! */ if (restart) { gwthread_sleep(10.0); /* now really restart */ restart_box(argv); } log_close_all(); gwlib_shutdown(); return 0; } gateway-1.4.5/contrib/0000755000175000017500000000000013312227714013326 5ustar toljtoljgateway-1.4.5/contrib/kannel-monitor/0000755000175000017500000000000013312227714016263 5ustar toljtoljgateway-1.4.5/contrib/kannel-monitor/kannel.css0000644000175000017500000000515011302742315020242 0ustar toljtoljbody { background-color: #ffffff; color: #000000; font-size: 8pt; font-family: Verdana,Arial,sans-serif; } #desc { color: black; font: 11px; z-index: 10; position: absolute; top: 0px; left: 0px; width: 220px; visibility: hidden; border: 1px solid #a0a0a0; background: #fafafa; padding: 4px; text-align: left; } .bold { font-weight: bold } .text { color: #000033; font-family: Verdana,Arial,sans-serif; font-size: 8pt; font-weight: normal; } .green { color: green; font-family: Verdana,Arial,sans-serif; font-size: 8pt; font-weight: bold; text-decoration: none; } .red { color: red; font-family: Verdana,Arial,sans-serif; font-size: 8pt; font-weight: bold; } .sum td { background-color: #FFFF99; font-weight: bold; } .sep { border-top: 3px solid #000088; } a.link:link { font-family: Verdana,Arial,sans-serif; color: #a0a0a0; font-size: 8pt; font-weight: normal; text-decoration: none; } a.link:visited { font-family: Verdana,Arial,sans-serif; color: #000033; font-size: 9pt; font-weight: normal; text-decoration: underline; } a.link:active { font-family: Verdana,Arial,sans-serif; color: #000033; font-size: 9pt; font-weight: normal; text-decoration: underline; } a.link:hover { font-family: Verdana,Arial,sans-serif; color: #FF6600; font-size: 8pt; font-weight: normal; text-decoration: underline; } a.href:link { font-family: Verdana,Arial,sans-serif; color: #000033; font-size: 8pt; font-weight: normal; text-decoration: none; } a.href:visited { font-family: Verdana,Arial,sans-serif; color: #000033; font-size: 8pt; font-weight: normal; text-decoration: none; } a.href:active { font-family: Verdana,Arial,sans-serif; color: #000033; font-size: 8pt; font-weight: normal; text-decoration: none; } a.href:hover { font-family: Verdana,Arial,sans-serif; color:green; font-size: 8pt; font-weight: normal; text-decoration: underline; } #bord { border-width: 1px; border-style: solid; border-color: back; padding: 2px; background-color: #f0f0f0; } #overall table { border: 1px solid black; } #overall td, th { padding: 4px; border: 1px solid black; text-align: center; } #overall th { background-color: #000088; color: white; border-right: 1px solid #CCC; } table { border-collapse: collapse; } #overall tr:nth-child(even) { background: #EEE } #overall tr:nth-child(odd) { background: #FFF }gateway-1.4.5/contrib/kannel-monitor/xmltoarray.php0000644000175000017500000000625011725743670021213 0ustar toljtolj, * Moderator, phpResource (LINK1http://groups.yahoo.com/group/phpresource/LINK1) * URL: LINK2http://www.rupom.infoLINK2 * @version : 1.0 * @date 06/05/2006 * Purpose : Creating Hierarchical Array from XML Data * Released : Under GPL */ class XmlToArray { var $xml=''; /** * Default Constructor * @param $xml = xml data * @return none */ function XmlToArray($xml) { $this->xml = $xml; } /** * _struct_to_array($values, &$i) * * This is adds the contents of the return xml into the array for easier processing. * Recursive, Static * * @access private * @param array $values this is the xml data in an array * @param int $i this is the current location in the array * @return Array */ function _struct_to_array($values, &$i) { $child = array(); if (isset($values[$i]['value'])) array_push($child, $values[$i]['value']); while ($i++ < count($values)) { switch ($values[$i]['type']) { case 'cdata': array_push($child, $values[$i]['value']); break; case 'complete': $name = $values[$i]['tag']; if(!empty($name)){ $child[$name]= ($values[$i]['value'])?($values[$i]['value']):''; if(isset($values[$i]['attributes'])) { $child[$name] = $values[$i]['attributes']; } } break; case 'open': $name = $values[$i]['tag']; $size = isset($child[$name]) ? sizeof($child[$name]) : 0; $child[$name][$size] = $this->_struct_to_array($values, $i); break; case 'close': return $child; break; } } return $child; }//_struct_to_array /** * createArray($data) * * This is adds the contents of the return xml into the array for easier processing. * * @access public * @param string $data this is the string of the xml data * @return Array */ function createArray() { $xml = $this->xml; $values = array(); $index = array(); $array = array(); $parser = xml_parser_create(); xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); xml_parse_into_struct($parser, $xml, $values, $index); xml_parser_free($parser); $i = 0; $name = $values[$i]['tag']; $array[$name] = isset($values[$i]['attributes']) ? $values[$i]['attributes'] : ''; $array[$name] = $this->_struct_to_array($values, $i); return $array; }//createArray }//XmlToArray ?> gateway-1.4.5/contrib/kannel-monitor/config.php0000644000175000017500000000126411302742315020240 0ustar toljtolj "http://kannel.yourdomain.com:23000", "status_passwd" => "foobar", "admin_passwd" => "", "name" => "Kannel 1" ), array( "base_url" => "http://kannel.yourdomain.com:33000", "status_passwd" => "foobar", "admin_passwd" => "", "name" => "Kannel 2" ) ); /* some constants */ define('MAX_QUEUE', 100); /* Maximum size of queues before displaying it in red */ define('DEFAULT_REFRESH', 60); /* Default refresh time for the web interface */ ?> gateway-1.4.5/contrib/kannel-monitor/index.php0000644000175000017500000003267313044340032020105 0ustar toljtolj * * Rewrite/Makeover to update the interface and add dlr support * Alejandro Guerrieri * * Copyright (c) 2003-2009 Kannel Group. * */ require_once("config.php"); require_once("xmlfunc.php"); require_once("xmltoarray.php"); $depth = array(); $status = array(); /* set php internal error reporting level */ error_reporting(0); /* Refresh variables */ $timeout = get_timeout(); $t_down = ceil($timeout / 2); $t_up = ceil($timeout * 2); $purl = parse_url($_SERVER['REQUEST_URI']); $base_uri = $purl[path]; ?> Kannel Status

Kannel Status Monitor

Current date and time:
Refresh rate:
s | s | s
\n"; } else { return "\n"; } } /* * Create the admin link to change bearerbox status */ function admin_link($mode) { global $config; return "".$mode.""; } /* * Cleanup the whole array */ function cleanup_array($arr) { if (is_array($arr) && is_array($arr['gateway'])) { $arr = $arr['gateway']; clean_branch($arr, 'wdp'); clean_branch($arr, 'sms'); clean_branch($arr, 'dlr'); $arr['boxes'] = $arr['boxes'][0]['box']; $arr['smscs'] = $arr['smscs'][0]['smsc']; } return $arr; } /* * Cleanup the branches to fold unnecessary levels */ function clean_branch(&$arr, $tag='') { $fields = array('received', 'sent'); if ($tag) { $arr[$tag] = array_shift($arr[$tag]); } foreach ($fields as $key) { if ($tag) { if (is_array($arr[$tag][$key])) { $arr[$tag][$key] = array_shift($arr[$tag][$key]); } } else { if (is_array($arr[$key])) { $arr[$key] = array_shift($arr[$key]); } } } } /* * Get a path/of/xml/nodes from an array */ function get_path($arr, $path) { $parts = explode("/", $path); if (!is_array($arr) || !is_array($parts)) { return $arr; } foreach($parts as $part) { $arr = $arr[$part]; } return $arr; } ?>gateway-1.4.5/contrib/kannel-monitor/kannel.js0000644000175000017500000000210407752661156020103 0ustar toljtolj function admin_url(command, url, passwd) { if (passwd == "") { passwd = prompt("Please enter admin password for this Kannel instance:", "(enter admin password here)"); } check = confirm("Are you sure you want to '"+command+"' bearerbox from this Kannel instance?"); if (check == true) { admin_window = window.open("","newWin","width=350,height=150,left=0,top=0"); admin_window.location.href = url + "?password=" + passwd; } location.reload(); self.focus(); } function admin_smsc_url(command, url, smsc, passwd) { if (passwd == "") { passwd = prompt("Please enter admin password for this Kannel instance:", "(enter admin password here)"); } check = confirm("Are you sure you want to '"+command+"' the smsc-id '"+smsc+"' on the Kannel instance?"); if (check == true) { admin_window = window.open("","newWin","width=350,height=150,left=0,top=0"); admin_window.location.href = url + "&password=" + passwd; } location.reload(); self.focus(); } function do_alert(text) { alert(text); } gateway-1.4.5/contrib/smstomail.cgi0000755000175000017500000000117207213750456016035 0ustar toljtolj#!/usr/bin/python MAIL_SENDER = "liw" MAIL_RECEIVER = "liw" import cgi, os, string class Vars: def __init__(self): self._dict = cgi.FieldStorage() def __getitem__(self, key): return self._dict[key].value def smstomail(): print "Content-Type: text/plain" print "" v = Vars() f = os.popen("/usr/sbin/sendmail -oi %s" % MAIL_RECEIVER, "w") f.write("From: %s\nTo: %s\nSubject: SMS message from %s\n\n%s:\n%s\n" % (MAIL_SENDER, MAIL_RECEIVER, v["from"], v["to"], v["text"])) f.close() print "Sent via mail to receiver." if __name__ == "__main__": smstomail() gateway-1.4.5/contrib/mon/0000755000175000017500000000000013312227714014117 5ustar toljtoljgateway-1.4.5/contrib/mon/kannel.monitor0000644000175000017500000002617707663717126017032 0ustar toljtolj#!/usr/bin/perl # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA # # # Revision $Id: kannel.monitor,v 1.4 2003-05-24 16:31:18 davi Exp $ # # Ingo Brombach #use warnings; use LWP::UserAgent; use XML::Parser; use Sys::Hostname; use Getopt::Std; getopts('P:s:p:f:n:ivhS',\%opts); my $p = new XML::Parser(ErrorContext => 2, Namespaces => 1, ParseParamEnt => 1, Handlers => {Start => \&sthndl, Char => \&chrhndl } ); local $scount=0; # SMS-Level - Counter local $bcount=0; # Box-Level - Counter local $kannel_status; local $status_file='/tmp/kannel_monitor.status'; local $qlimit=1; # Maximum Number of queued messages per minute local $port = ($opts{p}) ? $opts{p} : "13000"; local $statussheet = ($opts{s}) ? $opts{s} : "status.xml"; local $password = ($opts{P}) ? $opts{P} : ""; local $http = ($opts{S}) ? "https" : "http"; local @failures; &usage if ($opts{h}|| !($opts{f} || @ARGV)); if ($opts{f}){ my $file=$opts{f}; die "Can´t find '$file' : $!\n" unless -f $file; $p->parsefile ($file); &show if $opts{i}; @failures=@{&analyze()}; } else{ foreach $host (@ARGV){ $url=$http."://".$host.":".$port."/".$statussheet."?password=".$password; &info("# GET URL $url ... \n"); my $ua = LWP::UserAgent->new(env_proxy => 1, keep_alive => 1, timeout => 10, ); my $response=$ua->get($url)|| do { &err($host);&info("GET request to $host failed \n");next}; &info("OK\n"); if ((${$response}{'_content'})){ my $doc=${$response}{'_content'}; $p->parse($doc); } # end if else{do { &err($host);&info("GET request to $host failed \n");next}} &show if $opts{i}; push @failures, @{&analyze()}; } } # end else if (@failures == 0) { exit 0; } print "@failures\n" unless $opts{v}; exit 1; ################ ## End main ################ sub usage{ $0 =~ s,.*/,,g; my $program=$0; printf("\n"); print <<"EOU"; $program -- Kannel monitoring module for 'mon' This Perl script is a custom monitoring module for mon, the system monitoring tool, see http://www.kernel.org/pub/software/admin/mon/. The module watchs for availibility of the Kannel SMS gateway, basicaly it checks the state of the connected SMSC links. In case of an error it will returns the affected SMSC IDs of the links. 2002-07-31 Ingo Brombach, USAGE: $program [options] hosts... where options can be any of: -h this help message -n "smsc-ids..." a list of smsc-ids that should be ignored by the test -s URI the URI on the hosts containing the status-document (default: $statussheet) -p port the port to connect to (default: $port) -S use https:// scheme to access the URI (via SSLv3) (default: http://) -P password the status-password (default: $password) -f file local XML file to read (mainly for testing) -v verbose output -i info mode, displays the whole information to stdout Examples: $program -i -v -n "smpp_foo smpp_bar" kannel.foobar.com Checks out the status page status.xml (default) on kannel.foobar.com, port 13000 (default) without password. It lookes for the general status as well as for the status of the smsc-connections but ignores error on the smsc-ids smpp_foo and smpp_bar. The whole status is displayed. The failure messages are verbose. $program -i -v -f status.xml -n "smpp_foo smpp_bar" The same as above, but reading from a local status.xml file $program -p 13001 -P secret kannel.foobar.com Looking for status on port 13001 with password "secret". Only failing smsc-ids are displayed. EOU exit 1; } sub info { print STDERR @_ if $opts{v}; } # Output Verbose-Modus sub err { my $host=$_[0]; push @failures, $host; } sub pushall{ my @failures; for ($count=1;$count>=0;$count++){ last unless (exists ${"smsc".$count}{id}); push @failures, ${"smsc".$count}{id}; } # end for return \@failures; } sub analyze{ my @failures; # Bearerbox does not run: #============================== if (! $kannel_status || (split /,/,$kannel_status)[0] ne 'running'){ info "bearerbox is not running\n"; return &pushall; } # end if (Bearerbox) # SMS-or WAPBox does not run: #============================== for ($count=1;$count>=0;$count++){ if ($count==1 && ! ${"box".$count}{'status'}){ info "No SMS- or WAP-Box is running!!\n"; push @failures, "No SMS- or WAP-Box is running!!\n"; } #end if elsif ((${"box".$count}{'status'} &&(split /\s+/,${"box".$count}{'status'})[0] ne 'on-line')){ info ${"box".$count}{'type'}." is not running!!\n"; push @failures, hostname().": ".${"box".$count}{'type'}." is not running!!\n"; } # end elsif last unless (${"box".$count}{'type'} &&((${"box".$count}{'type'} eq 'smsbox') || (${"box".$count}{'type'} eq 'wapbox'))); } # end for count (SMS-Box) # SMSC does not run: #============================== for ($count=1;$count>=0;$count++){ last unless (exists ${"smsc".$count}{id}); if (${"smsc".$count}{id}){ $exists{${"smsc".$count}{id}}=1; if ((split /\s+/,${"smsc".$count}{status})[0] ne 'online'){ local $smsc_not; if ($opts{n}){ foreach $smsc (split /\s+/, $opts{n}){ $smsc_not=1 if $smsc eq ${"smsc".$count}{id}; } # end foreach smsc } # end if $opts{n} unless ($smsc_not){ info "SMSC ".${"smsc".$count}{id}. " is in status \"". (split /\s+/,${"smsc".$count}{status})[0]."\"\n"; push @failures, ${"smsc".$count}{id}; } #end unless $smsc_not } # end if split } # end if smsc } # end for count # SMSC does not exist: #============================== if ($opts{n}){ foreach $arg (split /\s+/, $opts{n}){ unless (exists $exists{$arg}){ info "$arg does not exist\n"; push @failures, $arg; } #end unless } # end foreaceh } # end of $opts{n} # Kannel is queueing: #============================== open (STATUSFILE,"<$status_file") or push @failures, hostname().": Could not open $status_file: $!"; local $warncount=0; while (){ my ($field,$value,$time,$diffmin); ($field,$value,$time)=split /\|/, $_,3; $diffmin=(time - $time)/60; if ((${"sms"}{$field} - $value)/$diffmin >= $qlimit){ $warncount+=1; } # end if } # end while STATUSFILE if ($warncount){ info "Kannel is queueing - please take a look\n"; return &pushall; } close(STATUSFILE); open (STATUSFILE,">$status_file") or push @failures, hostname().": Could not open $status_file: $!"; foreach $field (keys %{"sms"}){ if ((split /_/,$field)[1] &&(split /_/,$field)[1] eq 'queued'){ printf(STATUSFILE "%s|%s|%d\n", $field,${"sms"}{$field},time); } # end if } # end foreach close(STATUSFILE); return \@failures; } sub show{ my $count=1; my $bcount=1; if ($kannel_status){ printf("============== Status ===================\n"); printf("%s\n", $kannel_status); printf("=========================================\n"); } # end elsif printf("============SMS Overall==================\n"); foreach $field (keys %{"sms"}){ printf("%s -> %s\n", $field,${"sms"}{$field}); } printf("=========================================\n"); printf("=================BOXES===================\n") if (exists ${"box".$bcount}{type}); while (exists ${"box".$bcount}{type}){ foreach $field (keys %{"box".$bcount}){ printf("%s -> %s\n", $field,${"box".$bcount}{$field}); } # end foreach ++$bcount; printf("=========================================\n"); } # end while if (exists ${"smsc".$count}{id}){ printf("\n================SMSC´s===================\n"); printf("=========================================\n") ; } while (exists ${"smsc".$count}{id}){ foreach $field (keys %{"smsc".$count}){ printf("%s -> %s\n", $field,${"smsc".$count}{$field}); } # end foreach printf("=========================================\n"); ++$count; } # end while } # End show sub sthndl { my $xp = shift; my $el = shift; my $nm = $xp->namespace($el) ? "n1:$el" : $el; $parent{$nm}=$xp->current_element; } # End sthndl sub chrhndl { my ($xp, $data) = @_; my (@level); my $value= sprintf("%s\n",$xp->xml_escape($data, '>', "\xD")); my $level = $xp->current_element; chomp $value; if ($value!~/^\s+$/){ while($level=$parent{$level}){ unshift @level, $level; } push @level, $xp->current_element; if (($level[0] eq 'gateway') && ($level[1] eq 'smscs') && ($level[2] eq 'smsc')&& ($level[3])){ ++$scount if $level[3] eq 'name'; ${"smsc".$scount}{$level[3]}=$value; } # end if elsif (($level[0] eq 'gateway') && ($level[1] eq 'status')){ $kannel_status=$value; } # end elsif elsif (($level[0] eq 'gateway') && ($level[1] eq 'boxes') && ($level[2] eq 'box')&& ($level[3])){ ++$bcount if $level[3] eq 'type'; ${"box".$bcount}{$level[3]}=$value; } # end elsif elsif (($level[0] eq 'gateway') && ($level[1] eq 'sms')){ if (($level[2] eq 'sent'||$level[2] eq 'received') && $level[3]){ ${'sms'}{$level[2].'_'.$level[3]}=$value; } # end if else{ ${'sms'}{$level[2]}=$value; } # end else } # end elsif } } # End chrhndl # Tell emacs that this is really a perl script #Local Variables: #Mode: perl #End: gateway-1.4.5/contrib/mon/README0000644000175000017500000000444007523050322014775 0ustar toljtoljKannel monitoring module for 'mon' ================================== This Perl script is a custom monitoring module for mon, the system monitoring tool, see http://www.kernel.org/pub/software/admin/mon/. The module watchs for availibility of the Kannel SMS gateway, basicaly it checks the state of the connected SMSC links. In case of an error it will returns the affected SMSC IDs of the links. 2002-07-31 Ingo Brombach, USAGE: $program [options] hosts... where options can be any of: -h this help message -n "smsc-ids..." a list of smsc-ids that should be ignored by the test -s URI the URI on the hosts containing the status-document (default: status.xml) -p port the port to connect to (default: 13000) -S use https:// scheme to access the URI (via SSLv3) (default: http://) -P password the status-password (default: ) -f file local XML file to read (mainly for testing) -v verbose output -i info mode, displays the whole information to stdout Examples: ./kannel.monitor -i -v -n "smpp_foo smpp_bar" kannel.foobar.com Checks out the status page status.xml (default) on kannel.foobar.com, port 13000 (default) without password. It lookes for the general status as well as for the status of the smsc-connections but ignores error on the smsc-ids smpp_foo and smpp_bar. The whole status is displayed. The failure messages are verbose. ./kannel.monitor -i -v -f status.xml -n "smpp_foo smpp_bar" The same as above, but reading from a local status.xml file ./kannel.monitor -p 13001 -P secret kannel.foobar.com Looking for status on port 13001 with password "secret". Only failing smsc-ids are displayed. Installation ============ You need the following Perl modules installed in order to run kannel.monitor on your system: URI.pm HTML/Tagset.pm HTML/Parser.pm LWP/UserAgent.pm XML/Parser They may be found on a CPAN mirror close to you, see http://www.cpan.org. Disclaimer ========== THIS SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. gateway-1.4.5/contrib/php-admin/0000755000175000017500000000000013312227714015203 5ustar toljtoljgateway-1.4.5/contrib/php-admin/functions.inc0000644000175000017500000000147707211717164017723 0ustar toljtolj$error_description ($error_number)
\n"; echo "The SMS message was NOT sent!

\n"; } else { socket_set_blocking($connection, false); fputs($connection, "GET $URL HTTP/1.0\r\n\r\n"); while (!feof($connection)) { $myline = fgets($connection, 128); switch($myline) { case (strstr($myline, 'Content-')): break; case (strstr($myline, 'HTTP/1')): break; case "": break; case "\r\n": break; default: echo "

".$myline."

"; } } fclose ($connection); } } function octstr_append_cstr($mystring) { for($pos=0;$posgateway-1.4.5/contrib/php-admin/config.inc0000644000175000017500000000061207211717164017146 0ustar toljtolj gateway-1.4.5/contrib/php-admin/sendvcard.php0000644000175000017500000000324407211717164017674 0ustar toljtolj vCard SMS Sender \"$text\" to the phone $to...
\n"; $URL = "/cgi-bin/sendsms?username=".USERNAME."&password=".PASSWORD."&from=".GLOBAL_SENDER."&to=$to&udh=%06%05%04%23%F4%00%00&text=".urlencode($text); // echo "URL: $URL
\n"; http_send($URL,SENDSMS_PORT); echo "
Back to Send vCard SMS
\n"; } else { ?>

vCard SMS Sender

">

Telephone number to send the SMS to:

vCard:

Configured instances

$config) { //echo "
Name Status Started Uptime SMS (MO) DLR (MO) SMS (MT) DLR (MT) Commands
\n"; /* get the status.xml URL of one config */ $url = $config["base_url"]."/status.xml?password=".$config["status_passwd"]; $xml_data = ""; /* open the file description to the URL */ if (($fp = fopen($url, "r"))) { $bgcolor = 'green'; /* read the XML input */ while (!feof($fp)) { $xml_data .= fread($fp, 200000); } fclose($fp); $xml_obj = new XmlToArray($xml_data); $status[$inst] = cleanup_array($xml_obj->createArray()); for ($i=0;$i < sizeof($status[$inst]['smscs']); $i++) { clean_branch($status[$inst]['smscs'][$i], ''); } /* get the status of this bearerbox */ list ($st, $started, $uptime) = parse_uptime($status[$inst]['status']); /* get the info of this bearerbox into a button, to save some screen real-estate*/ $ver = preg_replace("/\n+/", '\\n', $status[$inst]['version']); $ver = preg_replace("/[\'\`]/", "\'", $ver); $ver = 'Url: '.$config["base_url"].'\n\n'.$ver; $boxstatus = array ( 'name' => ''.$config['name'].'', 'bgcolor' => 'green', 'status' => $st, 'started' => $started, 'uptime' => $uptime, ); } else { $boxstatus = array ( 'name' => $config['name'], 'bgcolor' => 'red', 'status' => 'error', 'started' => '-', 'uptime' => '-', ); } ?>
"; ?>

Overall SMS traffic

$config) { $cols = array( get_path($status[$inst], 'sms/received/total'), get_path($status[$inst], 'dlr/received/total'), get_path($status[$inst], 'sms/inbound'), get_path($status[$inst], 'dlr/inbound'), get_path($status[$inst], 'sms/sent/total'), get_path($status[$inst], 'dlr/sent/total'), get_path($status[$inst], 'sms/outbound'), get_path($status[$inst], 'dlr/outbound'), get_path($status[$inst], 'sms/received/queued'), get_path($status[$inst], 'sms/sent/queued'), ); for ($i=0;$i<10;$i++) { $sums[$i] += $cols[$i]; } ?>
Instance Received (MO) Received (DLR) Inbound (MO) Inbound (DLR) Sent (MT) Sent (DLR) Outbound (MT) Outbound (DLR) Queued (MO) Queued (MT)
Total

Box connections

$config) { /* drop an error in case we have no boxes connected */ if (!is_array($status[$inst]['boxes']) || sizeof($status[$inst]['boxes']) < 0) { ?> 0) ? " class=\"sep\"":''; /* loop the boxes */ foreach ($status[$inst]['boxes'] as $box) { list ($st, $started, $uptime) = parse_uptime($box['status']); ?> >
Instance Type ID IP Queued (MO) Started Uptime SSL
No boxes connected to this bearerbox!
msgs

SMSC connections

$config) { $smsc_status = count_smsc_status($status[$inst]['smscs']); $cols = array( array_sum($smsc_status), $smsc_status['online'], $smsc_status['disconnected'], $smsc_status['connecting'], $smsc_status['re-connecting'], $smsc_status['dead'], $smsc_status['unknown'], ); for ($i=0;$i<7;$i++) { $sums[$i] += $cols[$i]; } ?>
Instance Links Online Disconnected Connecting Re-Connecting Dead Unknown
Total

SMSC connection details

$config) { $sep = ($inst > 0) ? " class=\"sep\"":''; foreach ($status[$inst]['smscs'] as $smsc) { list ($st, $uptime) = explode(" ", $smsc['status']); $uptime = ($uptime) ? get_uptime($uptime):'-'; ?> >
Instance SMSC-ID Status Uptime Received (MO) Received (DLR) Sent (MT) Sent (DLR) Failed (MT) Queued (MT) Admins
[]
/stop-smsc?smsc=', '', ''); return false;">stop | /start-smsc?smsc=', '', ''); return false;">start
/remove-smsc?smsc=', '', ''); return false;">remove | /add-smsc?smsc=', '', ''); return false;">add
0) { echo "&details=1"; } else { echo "?details=1"; } echo "\">SMSC connection details\n"; } ?> gateway-1.4.5/contrib/kannel-monitor/xmlfunc.php0000644000175000017500000001203111302742315020441 0ustar toljtolj 0) ? $refresh : DEFAULT_REFRESH; } function get_uptime($sec) { $d = floor($sec/(24*3600)); $sec -= ($d*24*3600); $h = floor($sec/3600); $sec -= ($h*3600); $m = floor($sec/60); $sec -= ($m*60); return sprintf("%dd %dh %dm %ds", $d, $h, $m, $sec); } function count_smsc_status($smscs) { $stats = array( 'online' => 0, 'disconnected' => 0, 'connecting' => 0, 're-connecting' => 0, 'dead' => 0, 'unknown' => 0 ); foreach ($smscs as $smsc) { foreach ($stats as $st => $i) { if (substr($smsc['status'], 0, strlen($st)) == $st) { $stats[$st]++; } } } return $stats; } function get_smscids($status, $smscs) { /* loop the smsc */ $n = ""; foreach ($smscs as $smsc) { if (substr($smsc['status'], 0, strlen($status)) == $status) { $n .= $smsc['admin-id']." "; } } return $n; } function format_status($st) { $span = 'text'; switch ($st) { case "online": $span = 'green'; break; case "disconnected": case "connecting": case "re-connecting": $span = 'red'; break; } return "$st"; } /* * Parse start date, uptime and status from the status text */ function parse_uptime($str) { $regs = array(); if (ereg("(.*), uptime (.*)d (.*)h (.*)m (.*)s", $str, $regs) || ereg("(.*) (.*)d (.*)h (.*)m (.*)s", $str, $regs)) { $ts = ($regs[2]*24*60*60) + ($regs[3]*60*60) + ($regs[4]*60) + $regs[5]; $bb_time[$inst] = mktime()-$ts; $started = date("Y-m-d H:i:s", mktime()-$ts); $uptime = sprintf("%dd %02d:%02d:%02d", $regs[2], $regs[3], $regs[4], $regs[5]); $status = $regs[1]; } else { $started = '-'; $uptime = '-'; $status = '-'; } return array($status, $started, $uptime); } /* * Create a link for the SMSC status with a detail popup */ function make_link($smsc_status, $state, $mode='red') { global $status, $inst; if ($state == 'total') { return ($smsc_status > 0) ? "$smsc_status links":"none"; } elseif ($smsc_status[$state] == 0) { return "none"; } else { switch ($mode) { case 'red': return "". $smsc_status[$state]. " links"; break; case 'green': return "". $smsc_status[$state]. " links"; break; } } } /* * Split the load text into 3

*/ function split_load($str) { if (!$str) { return "---".implode("", explode(",", $str))."
First name (ie. John)
Last name (ie. Doe)
Telephone (ie. 4512345678)



Back to admin
Visit the Kannel homepage at www.kannel.org.
gateway-1.4.5/contrib/php-admin/sendota.php0000644000175000017500000000743607211717164017367 0ustar toljtolj SMS OTA Message Sender \"$text\" (length: ".strlen($text).") to the phone $to...
\n"; http_send($URL,SENDSMS_PORT); echo "
Back to Send OTA SMS Message
\n"; } else { ?>

OTA SMS Message Sender

">

Telephone number:

Configuration:
Location: (ie. http://wap.yoursite.com)
Service Name: (ie. You Wapsite)
IP address: (ie. 192.168.1.1)
Phone number: (ie. 4512345678)
Bearer type: (ie. data)
Connection type: (ie. temp)
Call type: (ie. ISDN)
Speed: (ie. 9600)
PPP security: (ie. Off)
Authentication: (ie. Normal)
Login: (ie. login)
Password: (ie. secret)



Back to admin
Visit the Kannel homepage at www.kannel.org.
gateway-1.4.5/contrib/php-admin/index.html0000644000175000017500000000266307211717164017213 0ustar toljtolj Administration

Administration

 

Usage

gateway-1.4.5/contrib/php-admin/README0000644000175000017500000000030607211717164016066 0ustar toljtolj Edit the config.inc so it matches your kannel.conf Depending on your PHP setup you might have to set the: "allow_call_time_pass_reference = on" in your php.ini to get rid of the annoing warning. gateway-1.4.5/contrib/php-admin/sendsms.php0000644000175000017500000000222407211717164017374 0ustar toljtolj SMS Message Sender \"$text\" to the phone $to...
\n"; $URL = "/cgi-bin/sendsms?username=".USERNAME."&password=".PASSWORD."&from=".GLOBAL_SENDER."&to=$to&text=".urlencode($text); http_send($URL,SENDSMS_PORT); echo "
Back to Send SMS
\n"; } else { ?>

SMS Message Sender

">

Telephone number:

Message:



Back to admin
Visit the Kannel homepage at www.kannel.org.
gateway-1.4.5/contrib/php-admin/admin.php0000644000175000017500000000221107211717164017004 0ustar toljtolj Kannel Administration \n"; } echo "

Reload page

\n"; ?>


Back to admin
Visit the Kannel homepage at www.kannel.org.
gateway-1.4.5/contrib/fortune.cgi0000755000175000017500000000064107213750456015507 0ustar toljtolj#!/usr/bin/python FORTUNE_MAX_TRIES = 10 SMS_MAX = 160 import os, string, sys def fortune(): for i in range(FORTUNE_MAX_TRIES): f = os.popen("/usr/games/fortune", "r") data = f.read() f.close() data = string.join(string.split(data)) if len(data) <= SMS_MAX: break sys.stdout.write("Content-Type: text/plain\r\n\r\n") sys.stdout.write(data[:SMS_MAX]) if __name__ == "__main__": fortune() gateway-1.4.5/contrib/webalizer/0000755000175000017500000000000013312227714015312 5ustar toljtoljgateway-1.4.5/contrib/webalizer/split.pl0000755000175000017500000000122507462343074017014 0ustar toljtolj#!/usr/bin/perl -w # This script reads access.log (pass it through multi-line first!) and # split them by SMSC or Service # Just define your service and smsc names as: # # SMSC: (smsc-id in smsc groups) # - # # Service: (name in sms-service and sendsms-user) # -- # SVC = for user, MT or USER # for service, MO or SERVICE $dir = shift || "/tmp"; foreach $line (<>) { $line =~ /^.{19} (.+) \[SMSC:(.*?)\] \[SVC:(.*?)\].*$/; $status= $1; $smsc= $2; $service= $3; if( $status =~ /Receive/) { open(X, ">>$dir/$smsc.log"); } else { open(X, ">>$dir/$service.log"); } print X $line; close(X); } gateway-1.4.5/contrib/webalizer/ReadMe0000644000175000017500000000206707462343074016406 0ustar toljtoljScripts to generate webalizer pages from kannel access.log format. * smsc-id name have only one slash in it example: KannelClient-P12345 First field is client name and second field is short number, "P" for production SMSC * sendsms-user and service name have at least two slashes in it example: KannelClient-MT-Logos or KannelClient-MO-ReplyLogo First field is client name, second is MT for sendsms-users (web generated MT messages) and MO for services (even if it is a MT message, it's a reply to an MO). Could be something like USER and SERVICE. Third field is the service name. * scripts have some hard-coded directories and filenames. I have a user kannel, in directory /home/kannel, inside a bin, etc and var/log. Just check and adjust them. * stats.sh could be run in crontab when everything is working ok * scripts uses to create a directory and the rest for the webalizer directory. This way, we could have different directories for different clients connected to kannel (c) 2001,2002 Bruno Rodrigues Under GPL Licence gateway-1.4.5/contrib/webalizer/converte.pl0000755000175000017500000000275607462343074017520 0ustar toljtolj#!/usr/bin/perl $exchange = shift; $exchange = "" if $exchange =~ /-/; $|=1; @months = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); %results = ( "Sent" => "200", "Receive" => "200", "FAILED Send" => 403, "DISCARDED" => "404"); while ($line = ) { chop($line); # Lines to ignore # --------------- next if $line =~ /Log begins/; next if $line =~ /Log ends/; $line =~ /^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) (.+?) SMS \[SMSC:(.*?)\] \[SVC:(.*?)\] \[from:(.*?)\] \[to:(.*?)\] \[flags:(.):(.):(.):(.):(.)\] \[msg:([0-9]+):(.*?)\] \[udh:([0-9]+):(.*?)\]$/i; ($year, $month, $day, $hour, $minute, $second, $result, $smsc, $svc, $from, $to, $f1, $f2, $f3, $f4, $f5, $msglen, $msg, $udhlen, $udh) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20); $msg =~ s/[^a-zA-Z0-9]//g; $msg = substr($msg, 0, 60); $msg =~ tr/a-z/A-Z/; if($exchange ne "") { $to = $from; } $to .= ".pt" if $to =~ /^91/; $to .= ".fr" if $to =~ /^93/; $to .= ".es" if $to =~ /^96/; $to .= ".uk" if $to =~ /^95/; $string = $to; $string .= " - - [". $day; $string .= "/". $months[$month-1]; $string .= "/". $year; $string .= ":". $hour; $string .= ":". $minute; $string .= ":". $second; $string .= " +0100] ". '"GET /'. $msg; $string .= ' HTTP/1.0" '. $results{$result}; $string .= " ". ($msglen+$udhlen); $string .= ' "'. $f1. ",". $f2. ",". $f3. ",". $f4. ",". $f5 . '" -'."\n"; print $string; } gateway-1.4.5/contrib/webalizer/stats.sh0000755000175000017500000000153507462343074017022 0ustar toljtolj#!/bin/bash logdir="var/tmp" http="public_html/web/stats" cd /home/kannel || exit 1 old="" rm -f $logdir/*.log cat var/log/bearerbox_access.log$old | bin/multi-line.pl | bin/split.pl "$logdir/" # This block checks reads access.log from other machine #if [ "`/sbin/ifconfig | grep 100.204`" = "" ] ; then # other=204 #else # other=205 #fi #ssh .$other "cat var/log/bearerbox_access.log$old" | bin/multi-line.pl | bin/split.pl "$logdir/" for i in `(cd $logdir ; ls -1 *.log)` ; do dir=${i%%-*} file=${i#*-} ; file=${file%.log} echo "**$dir**$file**" if [ ! -d "$http/$dir" ] ; then mkdir -p "$http/$dir" fi if [ ! -d "$http/$dir/$file" ] ; then mkdir -p "$http/$dir/$file/" fi cat $logdir/$i | sort | bin/converte.pl $file | /usr/bin/webalizer -q -c etc/webalizer.conf -o $http/$dir/$file -t "$file" - done rm -f $logdir/*.log gateway-1.4.5/contrib/webalizer/webalizer.conf0000644000175000017500000005661510106446071020157 0ustar toljtolj# # Sample Webalizer configuration file # Copyright 1997-2000 by Bradford L. Barrett (brad@mrunix.net) # # Distributed under the GNU General Public License. See the # files "Copyright" and "COPYING" provided with the webalizer # distribution for additional information. # # This is a sample configuration file for the Webalizer (ver 2.01) # Lines starting with pound signs '#' are comment lines and are # ignored. Blank lines are skipped as well. Other lines are considered # as configuration lines, and have the form "ConfigOption Value" where # ConfigOption is a valid configuration keyword, and Value is the value # to assign that configuration option. Invalid keyword/values are # ignored, with appropriate warnings being displayed. There must be # at least one space or tab between the keyword and its value. # # As of version 0.98, The Webalizer will look for a 'default' configuration # file named "webalizer.conf" in the current directory, and if not found # there, will look for "/etc/webalizer.conf". # LogFile defines the web server log file to use. If not specified # here or on on the command line, input will default to STDIN. If # the log filename ends in '.gz' (ie: a gzip compressed file), it will # be decompressed on the fly as it is being read. #LogFile /var/lib/httpd/logs/access_log # LogType defines the log type being processed. Normally, the Webalizer # expects a CLF or Combined web server log as input. Using this option, # you can process ftp logs as well (xferlog as produced by wu-ftp and # others), or Squid native logs. Values can be 'clf', 'ftp' or 'squid', # with 'clf' the default. #LogType clf # OutputDir is where you want to put the output files. This should # should be a full path name, however relative ones might work as well. # If no output directory is specified, the current directory will be used. #OutputDir /var/lib/httpd/htdocs/usage # HistoryName allows you to specify the name of the history file produced # by the Webalizer. The history file keeps the data for up to 12 months # worth of logs, used for generating the main HTML page (index.html). # The default is a file named "webalizer.hist", stored in the specified # output directory. If you specify just the filename (without a path), # it will be kept in the specified output directory. Otherwise, the path # is relative to the output directory, unless absolute (leading /). HistoryName webalizer.hist # Incremental processing allows multiple partial log files to be used # instead of one huge one. Useful for large sites that have to rotate # their log files more than once a month. The Webalizer will save its # internal state before exiting, and restore it the next time run, in # order to continue processing where it left off. This mode also causes # The Webalizer to scan for and ignore duplicate records (records already # processed by a previous run). See the README file for additional # information. The value may be 'yes' or 'no', with a default of 'no'. # The file 'webalizer.current' is used to store the current state data, # and is located in the output directory of the program (unless changed # with the IncrementalName option below). Please read at least the section # on Incremental processing in the README file before you enable this option. Incremental yes # IncrementalName allows you to specify the filename for saving the # incremental data in. It is similar to the HistoryName option where the # name is relative to the specified output directory, unless an absolute # filename is specified. The default is a file named "webalizer.current" # kept in the normal output directory. If you don't specify "Incremental" # as 'yes' then this option has no meaning. IncrementalName webalizer.current # ReportTitle is the text to display as the title. The hostname # (unless blank) is appended to the end of this string (separated with # a space) to generate the final full title string. # Default is (for english) "Usage Statistics for". #ReportTitle Usage Statistics for # HostName defines the hostname for the report. This is used in # the title, and is prepended to the URL table items. This allows # clicking on URL's in the report to go to the proper location in # the event you are running the report on a 'virtual' web server, # or for a server different than the one the report resides on. # If not specified here, or on the command line, webalizer will # try to get the hostname via a uname system call. If that fails, # it will default to "localhost". #HostName localhost # HTMLExtension allows you to specify the filename extension to use # for generated HTML pages. Normally, this defaults to "html", but # can be changed for sites who need it (like for PHP embeded pages). #HTMLExtension html # PageType lets you tell the Webalizer what types of URL's you # consider a 'page'. Most people consider html and cgi documents # as pages, while not images and audio files. If no types are # specified, defaults will be used ('htm*', 'cgi' and HTMLExtension # if different for web logs, 'txt' for ftp logs). PageType * #PageType htm* #PageType cgi #PageType phtml #PageType php3 #PageType pl # UseHTTPS should be used if the analysis is being run on a # secure server, and links to urls should use 'https://' instead # of the default 'http://'. If you need this, set it to 'yes'. # Default is 'no'. This only changes the behaviour of the 'Top # URL's' table. #UseHTTPS no # DNSCache specifies the DNS cache filename to use for reverse DNS lookups. # This file must be specified if you wish to perform name lookups on any IP # addresses found in the log file. If an absolute path is not given as # part of the filename (ie: starts with a leading '/'), then the name is # relative to the default output directory. See the DNS.README file for # additional information. #DNSCache dns_cache.db # DNSChildren allows you to specify how many "children" processes are # run to perform DNS lookups to create or update the DNS cache file. # If a number is specified, the DNS cache file will be created/updated # each time the Webalizer is run, immediately prior to normal processing, # by running the specified number of "children" processes to perform # DNS lookups. If used, the DNS cache filename MUST be specified as # well. The default value is zero (0), which disables DNS cache file # creation/updates at run time. The number of children processes to # run may be anywhere from 1 to 100, however a large number may effect # normal system operations. Reasonable values should be between 5 and # 20. See the DNS.README file for additional information. #DNSChildren 0 # HTMLPre defines HTML code to insert at the very beginning of the # file. Default is the DOCTYPE line shown below. Max line length # is 80 characters, so use multiple HTMLPre lines if you need more. #HTMLPre # HTMLHead defines HTML code to insert within the # block, immediately after the line. Maximum line length # is 80 characters, so use multiple lines if needed. #HTMLHead <META NAME="author" CONTENT="The Webalizer"> # HTMLBody defined the HTML code to be inserted, starting with the # <BODY> tag. If not specified, the default is shown below. If # used, you MUST include your own <BODY> tag as the first line. # Maximum line length is 80 char, use multiple lines if needed. HTMLBody <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF0000" VLINK="#A00000"> # HTMLPost defines the HTML code to insert immediately before the # first <HR> on the document, which is just after the title and # "summary period"-"Generated on:" lines. If anything, this should # be used to clean up in case an image was inserted with HTMLBody. # As with HTMLHead, you can define as many of these as you want and # they will be inserted in the output stream in order of apperance. # Max string size is 80 characters. Use multiple lines if you need to. #HTMLPost <BR CLEAR="all"> # HTMLTail defines the HTML code to insert at the bottom of each # HTML document, usually to include a link back to your home # page or insert a small graphic. It is inserted as a table # data element (ie: <TD> your code here </TD>) and is right # alligned with the page. Max string size is 80 characters. #HTMLTail <IMG SRC="msfree.png" ALT="100% Micro$oft free!"> # HTMLEnd defines the HTML code to add at the very end of the # generated files. It defaults to what is shown below. If # used, you MUST specify the </BODY> and </HTML> closing tags # as the last lines. Max string length is 80 characters. #HTMLEnd </BODY></HTML> # The Quiet option suppresses output messages... Useful when run # as a cron job to prevent bogus e-mails. Values can be either # "yes" or "no". Default is "no". Note: this does not suppress # warnings and errors (which are printed to stderr). #Quiet no # ReallyQuiet will supress all messages including errors and # warnings. Values can be 'yes' or 'no' with 'no' being the # default. If 'yes' is used here, it cannot be overriden from # the command line, so use with caution. A value of 'no' has # no effect. #ReallyQuiet no # TimeMe allows you to force the display of timing information # at the end of processing. A value of 'yes' will force the # timing information to be displayed. A value of 'no' has no # effect. #TimeMe no # GMTTime allows reports to show GMT (UTC) time instead of local # time. Default is to display the time the report was generated # in the timezone of the local machine, such as EDT or PST. This # keyword allows you to have times displayed in UTC instead. Use # only if you really have a good reason, since it will probably # screw up the reporting periods by however many hours your local # time zone is off of GMT. #GMTTime no # Debug prints additional information for error messages. This # will cause webalizer to dump bad records/fields instead of just # telling you it found a bad one. As usual, the value can be # either "yes" or "no". The default is "no". It shouldn't be # needed unless you start getting a lot of Warning or Error # messages and want to see why. (Note: warning and error messages # are printed to stderr, not stdout like normal messages). #Debug no # FoldSeqErr forces the Webalizer to ignore sequence errors. # This is useful for Netscape and other web servers that cache # the writing of log records and do not guarentee that they # will be in chronological order. The use of the FoldSeqErr # option will cause out of sequence log records to be treated # as if they had the same time stamp as the last valid record. # Default is to ignore out of sequence log records. FoldSeqErr yes # VisitTimeout allows you to set the default timeout for a visit # (sometimes called a 'session'). The default is 30 minutes, # which should be fine for most sites. # Visits are determined by looking at the time of the current # request, and the time of the last request from the site. If # the time difference is greater than the VisitTimeout value, it # is considered a new visit, and visit totals are incremented. # Value is the number of seconds to timeout (default=1800=30min) #VisitTimeout 1800 # IgnoreHist shouldn't be used in a config file, but it is here # just because it might be useful in certain situations. If the # history file is ignored, the main "index.html" file will only # report on the current log files contents. Usefull only when you # want to reproduce the reports from scratch. USE WITH CAUTION! # Valid values are "yes" or "no". Default is "no". #IgnoreHist no # Country Graph allows the usage by country graph to be disabled. # Values can be 'yes' or 'no', default is 'yes'. #CountryGraph yes # DailyGraph and DailyStats allows the daily statistics graph # and statistics table to be disabled (not displayed). Values # may be "yes" or "no". Default is "yes". #DailyGraph yes #DailyStats yes # HourlyGraph and HourlyStats allows the hourly statistics graph # and statistics table to be disabled (not displayed). Values # may be "yes" or "no". Default is "yes". #HourlyGraph yes #HourlyStats yes # GraphLegend allows the color coded legends to be turned on or off # in the graphs. The default is for them to be displayed. This only # toggles the color coded legends, the other legends are not changed. # If you think they are hideous and ugly, say 'no' here :) #GraphLegend yes # GraphLines allows you to have index lines drawn behind the graphs. # I personally am not crazy about them, but a lot of people requested # them and they weren't a big deal to add. The number represents the # number of lines you want displayed. Default is 2, you can disable # the lines by using a value of zero ('0'). [max is 20] # Note, due to rounding errors, some values don't work quite right. # The lower the better, with 1,2,3,4,6 and 10 producing nice results. #GraphLines 2 # The "Top" options below define the number of entries for each table. # Defaults are Sites=30, URL's=30, Referrers=30 and Agents=15, and # Countries=30. TopKSites and TopKURLs (by KByte tables) both default # to 10, as do the top entry/exit tables (TopEntry/TopExit). The top # search strings and usernames default to 20. Tables may be disabled # by using zero (0) for the value. TopSites 10 TopKSites 10 TopURLs 10 TopKURLs 10 TopReferrers 10 TopAgents 10 TopCountries 10 TopEntry 0 TopExit 0 TopSearch 10 TopUsers 10 # The All* keywords allow the display of all URL's, Sites, Referrers # User Agents, Search Strings and Usernames. If enabled, a separate # HTML page will be created, and a link will be added to the bottom # of the appropriate "Top" table. There are a couple of conditions # for this to occur.. First, there must be more items than will fit # in the "Top" table (otherwise it would just be duplicating what is # already displayed). Second, the listing will only show those items # that are normally visable, which means it will not show any hidden # items. Grouped entries will be listed first, followed by individual # items. The value for these keywords can be either 'yes' or 'no', # with the default being 'no'. Please be aware that these pages can # be quite large in size, particularly the sites page, and separate # pages are generated for each month, which can consume quite a lot # of disk space depending on the traffic to your site. AllSites yes AllURLs yes AllReferrers yes AllAgents yes AllSearchStr yes AllUsers yes # The Webalizer normally strips the string 'index.' off the end of # URL's in order to consolidate URL totals. For example, the URL # /somedir/index.html is turned into /somedir/ which is really the # same URL. This option allows you to specify additional strings # to treat in the same way. You don't need to specify 'index.' as # it is always scanned for by The Webalizer, this option is just to # specify _additional_ strings if needed. If you don't need any, # don't specify any as each string will be scanned for in EVERY # log record... A bunch of them will degrade performance. Also, # the string is scanned for anywhere in the URL, so a string of # 'home' would turn the URL /somedir/homepages/brad/home.html into # just /somedir/ which is probably not what was intended. #IndexAlias home.htm #IndexAlias homepage.htm # The Hide*, Group* and Ignore* and Include* keywords allow you to # change the way Sites, URL's, Referrers, User Agents and Usernames # are manipulated. The Ignore* keywords will cause The Webalizer to # completely ignore records as if they didn't exist (and thus not # counted in the main site totals). The Hide* keywords will prevent # things from being displayed in the 'Top' tables, but will still be # counted in the main totals. The Group* keywords allow grouping # similar objects as if they were one. Grouped records are displayed # in the 'Top' tables and can optionally be displayed in BOLD and/or # shaded. Groups cannot be hidden, and are not counted in the main # totals. The Group* options do not, by default, hide all the items # that it matches. If you want to hide the records that match (so just # the grouping record is displayed), follow with an identical Hide* # keyword with the same value. (see example below) In addition, # Group* keywords may have an optional label which will be displayed # instead of the keywords value. The label should be separated from # the value by at least one 'white-space' character, such as a space # or tab. # # The value can have either a leading or trailing '*' wildcard # character. If no wildcard is found, a match can occur anywhere # in the string. Given a string "www.yourmama.com", the values "your", # "*mama.com" and "www.your*" will all match. # Your own site should be hidden #HideSite *mrunix.net #HideSite localhost # Your own site gives most referrals #HideReferrer mrunix.net/ # This one hides non-referrers ("-" Direct requests) HideReferrer Direct Request # Usually you want to hide these #HideURL *.gif #HideURL *.GIF #HideURL *.jpg #HideURL *.JPG #HideURL *.png #HideURL *.PNG #HideURL *.ra # Hiding agents is kind of futile #HideAgent RealPlayer # You can also hide based on authenticated username #HideUser root #HideUser admin # Grouping options #GroupURL /cgi-bin/* CGI Scripts #GroupURL /images/* Images #GroupSite *.aol.com #GroupSite *.compuserve.com #GroupReferrer yahoo.com/ Yahoo! #GroupReferrer excite.com/ Excite #GroupReferrer infoseek.com/ InfoSeek #GroupReferrer webcrawler.com/ WebCrawler #GroupUser root Admin users #GroupUser admin Admin users #GroupUser wheel Admin users # The following is a great way to get an overall total # for browsers, and not display all the detail records. # (You should use MangleAgent to refine further...) #GroupAgent MSIE Micro$oft Internet Exploder #HideAgent MSIE #GroupAgent Mozilla Netscape #HideAgent Mozilla #GroupAgent Lynx* Lynx #HideAgent Lynx* # HideAllSites allows forcing individual sites to be hidden in the # report. This is particularly useful when used in conjunction # with the "GroupDomain" feature, but could be useful in other # situations as well, such as when you only want to display grouped # sites (with the GroupSite keywords...). The value for this # keyword can be either 'yes' or 'no', with 'no' the default, # allowing individual sites to be displayed. #HideAllSites no # The GroupDomains keyword allows you to group individual hostnames # into their respective domains. The value specifies the level of # grouping to perform, and can be thought of as 'the number of dots' # that will be displayed. For example, if a visiting host is named # cust1.tnt.mia.uu.net, a domain grouping of 1 will result in just # "uu.net" being displayed, while a 2 will result in "mia.uu.net". # The default value of zero disable this feature. Domains will only # be grouped if they do not match any existing "GroupSite" records, # which allows overriding this feature with your own if desired. #GroupDomains 0 # The GroupShading allows grouped rows to be shaded in the report. # Useful if you have lots of groups and individual records that # intermingle in the report, and you want to diferentiate the group # records a little more. Value can be 'yes' or 'no', with 'yes' # being the default. #GroupShading yes # GroupHighlight allows the group record to be displayed in BOLD. # Can be either 'yes' or 'no' with the default 'yes'. #GroupHighlight yes # The Ignore* keywords allow you to completely ignore log records based # on hostname, URL, user agent, referrer or username. I hessitated in # adding these, since the Webalizer was designed to generate _accurate_ # statistics about a web servers performance. By choosing to ignore # records, the accuracy of reports become skewed, negating why I wrote # this program in the first place. However, due to popular demand, here # they are. Use the same as the Hide* keywords, where the value can have # a leading or trailing wildcard '*'. Use at your own risk ;) #IgnoreSite bad.site.net #IgnoreURL /test* #IgnoreReferrer file:/* #IgnoreAgent RealPlayer #IgnoreUser root # The Include* keywords allow you to force the inclusion of log records # based on hostname, URL, user agent, referrer or username. They take # precidence over the Ignore* keywords. Note: Using Ignore/Include # combinations to selectivly process parts of a web site is _extremely # inefficent_!!! Avoid doing so if possible (ie: grep the records to a # separate file if you really want that kind of report). # Example: Only show stats on Joe User's pages... #IgnoreURL * #IncludeURL ~joeuser* # Or based on an authenticated username #IgnoreUser * #IncludeUser someuser # The MangleAgents allows you to specify how much, if any, The Webalizer # should mangle user agent names. This allows several levels of detail # to be produced when reporting user agent statistics. There are six # levels that can be specified, which define different levels of detail # supression. Level 5 shows only the browser name (MSIE or Mozilla) # and the major version number. Level 4 adds the minor version number # (single decimal place). Level 3 displays the minor version to two # decimal places. Level 2 will add any sub-level designation (such # as Mozilla/3.01Gold or MSIE 3.0b). Level 1 will attempt to also add # the system type if it is specified. The default Level 0 displays the # full user agent field without modification and produces the greatest # amount of detail. User agent names that can't be mangled will be # left unmodified. #MangleAgents 0 # The SearchEngine keywords allow specification of search engines and # their query strings on the URL. These are used to locate and report # what search strings are used to find your site. The first word is # a substring to match in the referrer field that identifies the search # engine, and the second is the URL variable used by that search engine # to define it's search terms. #SearchEngine yahoo.com p= #SearchEngine altavista.com q= #SearchEngine google.com q= #SearchEngine eureka.com q= #SearchEngine lycos.com query= #SearchEngine hotbot.com MT= #SearchEngine msn.com MT= #SearchEngine infoseek.com qt= #SearchEngine webcrawler searchText= #SearchEngine excite search= #SearchEngine netscape.com search= #SearchEngine mamma.com query= #SearchEngine alltheweb.com query= #SearchEngine northernlight.com qr= # The Dump* keywords allow the dumping of Sites, URL's, Referrers # User Agents, Usernames and Search strings to separate tab delimited # text files, suitable for import into most database or spreadsheet # programs. # DumpPath specifies the path to dump the files. If not specified, # it will default to the current output directory. Do not use a # trailing slash ('/'). #DumpPath /var/lib/httpd/logs # The DumpHeader keyword specifies if a header record should be # written to the file. A header record is the first record of the # file, and contains the labels for each field written. Normally, # files that are intended to be imported into a database system # will not need a header record, while spreadsheets usually do. # Value can be either 'yes' or 'no', with 'no' being the default. #DumpHeader no # DumpExtension allow you to specify the dump filename extension # to use. The default is "tab", but some programs are pickey about # the filenames they use, so you may change it here (for example, # some people may prefer to use "csv"). #DumpExtension tab # These control the dumping of each individual table. The value # can be either 'yes' or 'no'.. the default is 'no'. #DumpSites no #DumpURLs no #DumpReferrers no #DumpAgents no #DumpUsers no #DumpSearchStr no # End of configuration file... Have a nice day! �������������������������������������������������������������������������������������������������������������������gateway-1.4.5/contrib/webalizer/multi-line.pl�������������������������������������������������������0000755�0001750�0001750�00000001373�07462343074�017744� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl -w # This script joins multi-line entries from access.log # cat bearerbox_access.log | multi-line.pl $|=1; $linenum=0; $result=""; while($line = <STDIN>) { $linenum++; chop($line); next if $line =~ /Log begins/; next if $line =~ /Log ends/; if ( $result ne "" && $line =~ /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} .+? .+? \[SMSC:.*?\] \[SVC:.*?\] \[from:.*?\] \[to:.*?\] \[flags:.:.:.:.:.+?\] \[msg:.+?:.*$/) { $result = ""; print STDERR "$linenum:$line\n"; } $result .= $line; if($result =~ /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} .+? .+? \[SMSC:.*?\] \[SVC:.*?\] \[from:.*?\] \[to:.*?\] \[flags:.:.:.:.:.+?\] \[msg:.+?:.*?\] \[udh:.+?:.*?\]$/i) { print $result."\n"; $result=""; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/contrib/html2wml.pl�������������������������������������������������������������������0000644�0001750�0001750�00000014271�07104013153�015426� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/perl require HTML::TokeParser; # html2wml 0.1 13/01/2000 # Taneli Leppa <rosmo@SEKTORI.COM> # License: public domain $error_cardstart = "<card id=\"error\" title=\"Error\" newcontext=\"true\">\n"; $error_cardend = "</card>\n"; $error_filenotfound = $error_cardstart . "<p>The file was not found.</p>\n" . $error_cardend; $HTML_HEAD = 0x0001; $HTML_UL = 0x0002; $HTML_NL = 0x0004; # Print default headers # $wml = q{<?xml version="1.0"?> <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> <wml> }; # Read in the HTML # if (!($p = HTML::TokeParser->new($ARGV[0]))) { $wml .= $error_filenotfound; goto "FINISH"; } $p->get_tag("title"); $title = $p->get_text; $wml .= "<card id=\"foo\" title=\"$title\">\n"; if (!($p = HTML::TokeParser->new($ARGV[0]))) { $wml .= $error_filenotfound; goto "FINISH"; } $hide_text = 0; $current_place = 0; while ($token = $p->get_token) { $_ = $token->[0]; TAGTYPE: { /S/ && do { $wmlbit = start_tag($token->[1], $token->[2]); last TAGTYPE; }; /E/ && do { $wmlbit = end_tag($token->[1]); last TAGTYPE; }; /T/ && do { $wmlbit = $token->[1]; chomp $wmlbit; last TAGTYPE; }; # /D/ && do { $text = $token->[0]; last TAGTYPE; }; # /PI/ && do { $text = $token->[0]; last TAGTYPE; }; } if (!$hide_text) { $wml .= $wmlbit; } } close(F); FINISH: $wml .= "\n</card>\n</wml>"; print length($wml), "\n"; print $wml; sub start_tag { local($tag, $attrs) = @_; my $s; if (uc($tag) eq "LI") { if ($current_place & $HTML_UL) { if ($list_index > 1) { $s = "<BR/>"; } $s .= "* "; } if ($current_place & $HTML_OL) { if ($list_index > 1) { $s = "<BR/>"; } $s .= " " . $list_index . ". "; } $list_index++; } if (uc($tag) eq "BR") { $s = "<BR/>"; } if (uc($tag) eq "UL") { $list_index = 1; $current_place |= $HTML_UL; $s = "<BR/>"; } if (uc($tag) eq "NL") { $list_index = 1; $current_place |= $HTML_NL; $s = "<BR/>"; } if (uc($tag) eq "H1" || uc($tag) eq "H2") { $s = "<STRONG>"; } if (uc($tag) eq "H3" || uc($tag) eq "H4") { $s = "<EM>"; } if (uc($tag) eq "H5" || uc($tag) eq "H6") { $s = "<B>"; } if (uc($tag) eq "HEAD") { $current_place |= $HTML_HEAD; $hide_text = 1; } if (uc($tag) eq "IMG") { if ($attrs->{"alt"} ne "") { $s = $attrs->{"alt"}; } } if (uc($tag) eq "TEXTAREA") { $s = "<INPUT type=\"text\" name=\"" . $attrs->{"name"} . "\""; if ($attrs->{"size"} ne "") { $s .= " size=\"" . $attrs->{"size"} . "\""; } $s .= " value=\""; push @form_dynamic_vars, $attrs->{"name"}; } if (uc($tag) eq "INPUT") { if (uc($attrs->{"type"}) eq "TEXT") { $s = "<INPUT type=\"text\" name=\"" . $attrs->{"name"} . "\" value=\"" . $attrs->{"value"} . "\""; if ($attrs->{"size"} ne "") { $s .= " size=\"" . $attrs->{"size"} . "\""; } $s .= "/>\n"; push @form_dynamic_vars, $attrs->{"name"}; } if (uc($attrs->{"type"}) eq "SUBMIT") { $form_submit_label = $attrs->{"value"}; } if (uc($attrs->{"type"}) eq "PASSWORD") { $s = "<INPUT type=\"text\" name=\"" . $attrs->{"name"} . "\""; if ($attrs->{"size"} ne "") { $s .= " size=\"" . $attrs->{"size"} . "\""; } $s .= "/>"; push @form_dynamic_vars, $attrs->{"name"}; } if (uc($attrs->{"type"}) eq "HIDDEN") { push @form_static_vars, ($attrs->{"name"}, $attrs->{"value"}); } } if (uc($tag) eq "FORM") { reset(@form_dynamic_vars); reset(@form_static_vars); reset $form_submit_label; $form_method = $attrs->{"method"}; $form_action = $attrs->{"action"}; } if (uc($tag) eq "A") { $s = "<A href=\"" . $attrs->{"href"} . "\">"; } if (uc($tag) eq "B") { $s = "<EM>"; } if (uc($tag) eq "I" || uc($tag) eq "U") { $s = "<" . uc($tag) . ">"; } if (uc($tag) eq "P") { $s = "<P/>"; } return $s; } sub end_tag { local($tag) = @_; my $s; if (uc($tag) eq "UL") { $current_place ^= $HTML_UL; $s = "<BR/>"; } if (uc($tag) eq "NL") { $current_place ^= $HTML_NL; $s = "<BR/>"; } if (uc($tag) eq "H1" || uc($tag) eq "H2") { $s = "</STRONG><BR/>"; } if (uc($tag) eq "H3" || uc($tag) eq "H4") { $s = "</EM><BR/>"; } if (uc($tag) eq "H5" || uc($tag) eq "H6") { $s = "</B><BR/>"; } if (uc($tag) eq "HEAD") { $current_place ^= $HTML_HEAD; $hide_text = 0; } if (uc($tag) eq "STYLE") { if ($current_place & $HTML_HEAD) { $hide_text = 0; } } if (uc($tag) eq "TEXTAREA") { $s = "\"/>"; } if (uc($tag) eq "FORM") { $s = "\n<DO type=\"accept\" label=\"$form_submit_label\">\n"; if (uc($form_method) eq "") { $form_method = "GET"; } if (uc($form_method) eq "POST") { $s .= "\t<GO method=\"POST\" href=\"$form_action\">\n"; $z = pop @form_static_vars; while (defined($z)) { $x = pop @form_static_vars; $s .= "\t\t" . "<POSTFIELD name=\"$z\" value=\"$x\">\n"; $z = pop @form_static_vars; } foreach $z (@form_dynamic_vars) { $s .= "\t\t" . "<POSTFIELD name=\"$z\" value=\"\${$z}\">\n"; } $s .= "\n\t</GO>\n"; } if (uc($form_method) eq "GET") { $s .= "\t<GO href=\"$form_action?"; $z = pop @form_static_vars; $i = 0; while (defined($z)) { if ($i++ > 0) { $s .= "&"; } $s .= $z; $z = pop @form_static_vars; if (defined($z)) { $s .= "=" . $z; $z = pop @form_static_vars; } } $z = pop @form_dynamic_vars; while (defined($z)) { if ($i++ > 0) { $s .= "&"; } $s .= $z . "=\${" . $z . "}"; $z = pop @form_dynamic_vars; } $s .= "\"/>\t</GO>\n"; } $s .= "</DO>\n"; } if (uc($tag) eq "A") { $s = "</A>"; } if (uc($tag) eq "B") { $s = "</EM>"; } if (uc($tag) eq "I" || uc($tag) eq "U") { $s = "</" . uc($tag) . ">"; } return $s; } exit 0; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/contrib/ping.cgi����������������������������������������������������������������������0000755�0001750�0001750�00000001506�07213750456�014763� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/python """PING cgi. Gets the name or IP number of a host as CGI argument. Returns as plain text the output of the ping command for that host. Lars Wirzenius <liw@wapit.com> """ import os, cgi, string def ping(host): if len(string.split(host, "'")) != 1: return "Invalid host name." f = os.popen("ping -q -c 4 '%s'" % host) lines = f.readlines() f.close() lines = map(lambda line: line[:-1], lines) lines = filter(lambda line: line and line[:4] != "--- ", lines) return string.join(string.split(string.join(lines, " ")), " ") def do_cgi(): print "Content-type: text/plain" print "" form = cgi.FieldStorage() if not form.has_key("host"): print "CGI argument `host' missing." else: host = form["host"].value print ping(host) if __name__ == "__main__": do_cgi() ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/contrib/web/��������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13312227714�014103� 5����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/contrib/web/form.php������������������������������������������������������������������0000644�0001750�0001750�00000037726�10334365535�015603� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html> <body bgcolor=white text=black link=blue vlink=navy alink=red> <script> function help(texto) { document.all.help.innerHTML = texto; } </script> <base target="envia"> <?php function help($fields) { return "<h1>Help</h1><h2>".$fields[0]."</h2><p><i>".$fields[2]."</i></p>"; } $aModes = array ( "TEXT", "LOGO", "GROUP", "PICTURE", "TUNE", "PROFILE", "VCARD", "VCAL", "MWI", "WAPCONFIG", "BOOKMARK", "RAW"); $aFields = array ( "from" => array ( "From", "<input size=16 name=from>", "Numeric (16chars) or alphanumeric (11chars)", ), "to" => array ( "To", "<input size=16 name=to>", "Numeric (16 chars)", ), "text" => array ( "Text", "<textarea name=text rows=4 cols=40></textarea>", "Text message (for UNICODE messages, see <i>charset</i>", ), "charset" => array ( "Charset", "<input size=16 name=charset>", "(Optional) Charset (ex: ISO-8859-1, UTF-16BE, UTF-8, etc). Defaults to ISO-8859-1 or UTF-16BE with UNICODE", ), "udh" => array ( "User Data Header", "<textarea name=udh rows=2 cols=40></textarea>", "Encode as 001122AAFF", ), "mclass" => array ( "Message Class", '<select name="mclass"> <option value="0">Undefined</option> <option value="1">Visor</option> <option value="2">Mobile</option> <option value="3">SIM</option> <option value="4">SIM Toolkit</option> </select>', "aaa", ), "coding" => array ( "Data Coding", '<select name="coding"> <option value="0">Undefined</option> <option value="0">Texto</option> <option value="2">UNICODE</option> </select>', "A opção <i>Texto</i> é o normal, onde o texto é convertido para o alfabeto GSM e cada mensagem leva no máximo 160 caracteres.<br>No caso de UNICODE, a mensagem vai até 70 caracteres mas o texto não é convertido e suporta todo o alfabeto UNICODE, desde que o telefone também suporte", ), "mwi" => array ( "Message Waiting Indicator", '<select name="mwi"> <option value="0">Voice Mail, active</option> <option value="1">Fax, active</option> <option value="2">E-Mail, active</option> <option value="3">Other, active</option> <option value="4">Voice Mail, inactive</option> <option value="5">Fax, inactive</option> <option value="6">E-Mail, inactive</option> <option value="7">Other, inactive</option> </select>', "aaa", ), "mwi_messages" => array ( "Messages", "<input size=2 name=mwi_messages>", "Number of messages", ), "validity" => array ( "Validity", "<input size=8 name=validity>", "Message will be retried on SMSC for this many minutes", ), "deferred" => array ( "Deferred", "<input size=8 name=deferred>", "Message will be deferred on SMSC for this many minutes", ), "country" => array ( "Country", "<input size=8 name=country>", "Contry code", ), "operator" => array ( "Operator", "<input size=8 name=operator>", "Operator Code", ), "image" => array ( "Image", 'Hex Image: <table><tr><td><table background="Nokia.jpg" width="151" height="143"> <tr><td align=center> <applet code=GSMViewer.class name=GSMViewer width=72 height=14 VIEWASTEXT> <param name=ActiveColor value="000000"> <param name=InactiveColor value="7FBF6F"> <param name=BackColor value="7FBF6F"> <param name=Rows value=28> <param name=Cols value=72> </applet> </td></tr></table> </td>'. '<td><applet code="GSM.class" name=GSM width=362 height=72 VIEWASTEXT> <param name=ActiveColor value="000000"> <param name=InactiveColor value="7FBF6F"> <param name=BorderColor value="808080"> <param name=BackColor value="7FBF6F"> <param name=Rows value=28> <param name=Cols value=72> <param name=CellHeight value=5> <param name=Viewer value ="GSMViewer"> </applet> <br>'. ' <input type="button" onclick="GSM.FClear()" value="Ini"> <input type="button" onclick="GSM.FInvert()" value="Inv"> <input type="button" onclick="GSM.FHorizontalFlip()" value="H"> <input type="button" on click="GSM.FVerticalFlip();" value="V"> <input type="button" onclick="GSM.FUp()" value="/\"> <input type="button" onclick="GSM.FDown()" value="\/"> <input type="button" onclick="GSM.FLeft()" value="<"> <input type="button" onclick="GSM.FRight()" value=">"> </td></tr></table> <script> function update_java() { ; heximage = send.image.value; binimage=""; for(i=0;i<504;i++) { ; x="1"+heximage.substr(i,1); y=parseInt(x,16); z=y.toString(2); z=z.substr(1,4); binimage +=z; }; GSM.FSetValues(binimage); } ; function update_image() { ; nokiaimage = GSM.FGetValues(); heximage=""; for(i=0;i<504;i++) { ; x=nokiaimage.substr(i*4, 4); y=parseInt(x,2); heximage += y.toString(16); }; send.image.value = heximage; } </script><input type="text" name=image onChange="update_java();"><br><input type=submit value="Update Hex Image field" onClick="update_image(); return false;";>', "Enviar encoded 001122AAFF", 'update_image();', ), "imagesize" => array ( "Image Size", '<script> function change_image_size() { GSM.height = send.imagesize.value * 5 + 2; GSMViewer.height = send.imagesize.value; GSM.Rows = send.imagesize.value; GSMViewer.Rows = send.imagesize.value; } </script><select name="imagesize" onChange="change_image_size();"><option value=14>14</option><option value=28>28</option></select>', 'hexencoded tone', ), "tune" => array ( "Ringing Tone", '<input type=text name="tune"><br><APPLET CODE="composer.RingRing.class" WIDTH="300" HEIGHT="40" ARCHIVE="ringring/classes.zip" MAYSCRIPT> </APPLET>', 'hexencoded tone', ), "name" => array ( "Name", '<input type=text name="name">', 'Nome URL', ), "url" => array ( "URL", '<input type=text name="url">', 'URL', ), "urlpush" => array ( "URL", '<input type=text name="url">', 'URL; wtai://wp/mc;phone, wtai://wp/ap;phone;name', ), "bearer" => array ("Wap Bearer", '<select name=bearer><option value=45>GSM/CSD<option value=46>GSM/SMS<option value=47>GSM/USSD<option value=48>IS-i36/CSD<option value=49>GPRS</select>', 'Bearer to connect to wap', ), "ppp_authtype" => array ("Authentication Type <br><font size=-3>GSM/CSD, IS-I36/CSD, GPRS</font>", '<select name=ppp_authtype><option value=0>Select...<option value=70>PAP<option value=71>CHAP<option value=78>MS_CHAP</select>', 'PPP Authentication Type. GSM/CSD, IS-i36/CSD and GPRS', ), "ppp_authname" => array ("PPP Authentication Name (username)<br><font size=-3>GSM/CSD, IS-I36/CSD, GPRS</font>", '<input size=32 maxlength=32 type=text name=ppp_authname>', 'PPP Authentication Name. GSM/CSD, IS-i36/CSD and GPRS', ), "ppp_authsecret" => array ("PPP Authentication Secret (password)<br><font size=-3>GSM/CSD, IS-I36/CSD, GPRS</font>", '<input size=20 maxlength=20 type=text name=ppp_authsecret>', 'PPP Authentication Secret. GSM/CSD, IS-i36/CSD and GPRS', ), "ppp_logintype" => array ("PPP Login Type<br><font size=-3>GSM/CSD, IS-I36/CSD, GPRS</font>", '<select name=ppp_logintype><option value=0>Select...<option value=64>Automatic<option value=65>Manual</select>', 'PPP Login Type. GSM/CSD, IS-i36/CSD and GPRS', ), "proxy" => array ("Proxy<br><font size=-3>Required</font>", '<input size=21 maxlength=21 type=text name=proxy>', 'Required. GSM/CSD (wap gateway), GSM/SMS (SMSC MSISDN), GSM/USSD (IP or MSISDN), IS-i36/CSD and GPRS', ), "proxy_type" => array ("Proxy Type<br><font size=-3>GSM/USSD</font>", '<select name=proxy_type><option value=0>Select...<option value=76>MSISDN (default)<option value=77>IPV4</select>', 'Proxy Type. GSM/USSD, required.', ), "proxy_authname" => array ("Proxy Auth Name<br><font size=-3>GSM/CSD, IS-I36/CSD, GPRS</font>", '<input size=32 maxlength=32 type=text name=proxy_authname>', 'Proxy Auth Name. GSM/CSD, IS-i36/CSD, GPRS.', ), "proxy_authsecret" => array ("Proxy Auth Secret<br><font size=-3>GSM/CSD, IS-I36/CSD, GPRS</font>", '<input size=20 maxlength=20 type=text name=proxy_authsecret>', 'Proxy Auth Secret. GSM/CSD, IS-i36/CSD, GPRS.', ), "proxy_logintype" => array ("Proxy Login Type<br><font size=-3>GSM/CSD, IS-I36/CSD, GPRS</font>", '<select name=ppp_logintype><option value=0>Select...<option value=64>Automatic<option value=65>Manual</select>', 'Proxy Login Type. GSM/CSD, IS-i36/CSD, GPRS.', ), "port" => array ("Wap Port", '<select name=port><option value=0>Select...<option value=60>9200<option value=61>9201<option value=62>9202<option value=63>9203</select>', 'Wap Port. 9200 (connectionless), 9201 (connection oriented) or 9202/9203 (wtls equivalents). All.', ), "csd_dialstring" => array ("CSD Dialstring<br><font size=-3>Required; GSM/CSD, IS-I36/CSD</font>", '<input size=21 maxlength=21 type=text name=csd_dialstring>', 'CSD Dial string. GSM/CSD (required), IS-i36/CSD (required)', ), "csd_calltype" => array ("CSD Call Type<br><font size=-3>GSM/CSD</font>", '<select name=csd_calltype><option value=0>Select...<option value=72>Analogue<option value=73>ISDN</select>', 'CSD Call Type. GSM/CSD', ), "csd_callspeed" => array ("CSD Call Speed<br><font size=-3>GSM/CSD</font>", '<select name=csd_callspeed><option value=0>Select...<option value="6A">AUTO<option value=6B>9600<option value="6C">14400<option value="6D">19200<option value="6E">28800<option value="6F">38400<option value="74">43200<option value="75">57600</select>', 'CSD Call Type. GSM/CSD', ), "isp_name" => array ("ISP Name<br><font size=-3>GSM/CSD, IS-I36/CSD, GPRS</font>", '<input size=20 maxlength=20 type=text name=isp_name>', 'ISP Name.', ), "sms_smsc_address" => array ("SMSC Address<br><font size=-3>Required; GSM/SMS</font>", '<input size=21 maxlength=21 type=text name=sms_smsc_address>', 'SMSC Address.', ), "ussd_service_code" => array ("USSD Service Code<br><font size=-3>Required; USSD</font>", '<input size=10 maxlength=10 type=text name=ussd_service_code>', 'USSD Service Code.', ), "gprs_accesspointname" => array ("GPRS Access Point Name<br><font size=-3>Required; GPRS</font>", '<input size=32 maxlength=100 type=text name=gprs_accesspointname>', 'GPRS Access Point Name. GPRS (required)', ), "mmc_file_type" => array ("File Type", '<select name=mmc_file_type><option value=0>Select...<option value="mid">Midi<option value="bmp">Bitmap<option value="lng">Language<option value="mp3">Mp3<option value="jar">Jar<option value="jad">Jad</select>', 'File Type', ), "mmc_file_name" => array ("File Name", '<input type=text name=mmc_file_name>', 'File Name (use "path/filename" for example with jad/jar files', ), "mmc_file_raw" => array ("File", '<input type=file name=mmc_file_raw>', 'File', ), "tele_pref" => array ("Telefone (Predefinido)", '<input type=text name=tele_pref>', 'Default phone', ), "tele_cell" => array ("Telemóvel", '<input type=text name=tele_cell>', 'Cell phone', ), "tele_home" => array ("Telefone Casa", '<input type=text name=tele_home>', 'Home phone', ), "tele_work" => array ("Telefone Trabalho", '<input type=text name=tele_work>', 'Work phone', ), "tele_fax" => array ("Fax", '<input type=text name=tele_fax>', 'Fax', ), "email" => array ("Email", '<input type=text name=email>', 'email', ), "label" => array ("Morada", '<input type=text name=label>', 'Address', ), "note" => array ("Nota", '<input type=text name=note>', 'Note', ), "vcard" => array ("VCard", '<textarea rows=8 name=vcard></textarea><input type=submit value="Update" onClick=\'vcard.value="BEGIN: VCARD\nVERSION:2.1\n"; if(send.name.value != "") { vcard.value += "N: "+send.name.value+"\n"; } ; if(send.tele_pref.value != "") { vcard.value += "TEL;PREF: "+send.tele_pref.value+"\n"; } ; if(send.tele_cell.value != "") { vcard.value += "TEL;CELL: "+send.tele_cell.value+"\n"; } ; if(send.tele_home.value != "") { vcard.value += "TEL;HOME: "+send.tele_home.value+"\n"; } ; if(send.tele_work.value != "") { vcard.value += "TEL;WORK: "+send.tele_work.value+"\n"; } ; if(send.tele_fax.value != "") { vcard.value += "TEL;FAX: "+send.tele_fax.value+"\n"; } ; if(send.email.value != "") { vcard.value += "EMAIL: "+send.email.value+"\n"; } ; if(send.label.value != "") { vcard.value += "LABEL: "+send.label.value+"\n"; } ; if(send.note.value != "") { vcard.value += "NOTE: "+send.note.value+"\n"; } ; vcard.value +="END:VCARD"; return false;\'>', 'Vcard', ), "date" => array ("Date (yyyymmddThhmmss)", '<input type=text name=date>', 'Date', ), "vcal_name" => array ("Name", '<input type=text name=vcal_name>', 'Examples: <br>Birthday:<br>Name: YYYY Name<br>Categories: Birthday<br>Rule: YD1 #0<br><br>Call:<br>Name: phone name<br><br>Weekly meeting:<br>Rule: W1 #0', ), "categories" => array ("Categories", '<select name=categories><option value="">Select...<option value="SPECIAL OCCASION">Birthday<option value="PHONE CALL">Call<option value="MEETING">Meeting</select>', 'Categories', ), "rule" => array ("Rule", '<input type=text name=rule>', 'Examples:<br>Repeat week: "W1 #0"<br>Repeat daily: "D1 #0"<br>Repeat yearly: "YD1 #0"', ), "alarm" => array ("Alarm (yyyymmddThhmmss)", '<input type=text name=alarm>', 'Date', ), "vcal" => array ("VCal", '<textarea rows=8 name=vcal></textarea><input type=submit value="Update" onClick=\'vcal.value="BEGIN: VCALENDAR\nVERSION:1.0\nBEGIN:VEVENT\n"; if(send.vcal_name.value != "") { vcal.value += "DESCRIPTION: "+send.vcal_name.value+"\nSUMMARY: "+send.vcal_name.value+"\n"; } ; if(send.date.value != "") { vcal.value += "DTSTART: "+send.date.value+"\n"; } ; if(send.categories.value != "") { vcal.value += "CATEGORIES: "+send.categories.value+"\n"; } ; if(send.rule.value != "") { vcal.value += "RULES: "+send.rule.value+"\n"; } ; if(send.alarm.value != "") { vcal.value += "DALARM: "+send.alarm.value+"\nAALARM: "+send.alarm.value+"\n"; } ; vcal.value +="END:VEVENT\nEND:VCARD"; return false;\'>', 'VCalendar', ), "incompleto" => array ( "INCOMPLETO", '<h2>Este formulario ainda está incompleto</h2>', 'URL', ), ); ?> <?php $aModeFields = array ( "ALL" => array ("from", "to", "validity", "deferred"), "TEXT" => array ("text", "charset", "mclass", "coding"), "LOGO" => array ("country", "operator", "image"), "GROUP" => array ("image"), "PICTURE" => array ("image", "imagesize", "text"), "TUNE" => array ("tune"), "PROFILE" => array ("image","text", "incompleto"), "VCARD" => array ("name", "tele_pref", "tele_cell", "tele_home", "tele_work", "tele_fax", "email", "label", "note", "vcard"), "VCAL" => array ("vcal_name", "date", "categories", "rule", "alarm", "vcal"), "MWI" => array ("mwi", "mwi_messages", "text", "charset", "coding"), "WAPCONFIG" => array ("name", "url", "bearer", "ppp_authtype", "ppp_authname", "ppp_authsecret", "ppp_logintype", "proxy", "proxy_type", "proxy_authname", "proxy_authsecret", "proxy_logintype", "port", "csd_dialstring", "csd_calltype", "csd_callspeed", "isp_name", "sms_smsc_address", "ussd_service_code", "gprs_accesspointname"), "BOOKMARK" => array ( "name", "url"), "WAPPUSHSI" => array ( "name", "urlpush"), "WAPPUSHSL" => array ( "url"), "SIEMENS" => array ( "mmc_file_type", "mmc_file_name", "mmc_file_raw"), "RAW" => array("udh", "incompleto"), ); ?> <h1>Sendsms <?=$mode?></h1> <table width=100%> <tr><td valign=top> <form enctype="multipart/form-data" name=send method=POST action="sendsms.php"> <table> <?php $submit_string=""; while (list ($k, $field) = each ($aModeFields["ALL"])) { $a = $aFields[$field]; $submit_string .= $a[3]; ?> <tr><td>[<a href="" onClick='help("<?=help($a)?>"); return false;'>?</a>]<td><?=$a[0]?>:</td><td><?=$a[1]?></td></tr> <?php } ?> </table> <hr width=90%> <table> <?php while (list ($k, $field) = each ($aModeFields[$mode])) { $a = $aFields[$field]; $submit_string .= $a[3]; ?> <tr><td>[<a href="" onClick='help("<?=escapeshellcmd(help($a))?>"); return false;'>?</a>]<td><?=$a[0]?>:</td><td><?=$a[1]?></td></tr> <?php } ?> </table> <hr width=90%> <input type=hidden name=mode value=<?=$mode?>> <!--<input type=text name=debug value=1>--> <input type=submit value="Enviar" onClick='<?=$submit_string?>'> <input type=reset value="Limpar Valores"> </form> </td><td width=25% valign=top><div id="help"><h1>Help</h1></div> </td></tr></table> </body> </html> ������������������������������������������gateway-1.4.5/contrib/web/menu.html�����������������������������������������������������������������0000755�0001750�0001750�00000002074�07436550451�015752� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html> <body bgcolor="#FFFFFF" text="#000000"> <base target="dados"> <h2>Message Type </h2><p> <a href="form.php?mode=TEXT">Text</a><p> <a href="form.php?mode=LOGO">Nokia Smart Messaging - Logo</a><p> <a href="form.php?mode=GROUP">Nokia Smart Messaging - Group</a><p> <a href="form.php?mode=PICTURE">Nokia Smart Messaging - Picture</a><p> <a href="form.php?mode=TUNE">Nokia Smart Messaging - Tune</a><p> <a href="form.php?mode=VCARD">Nokia Smart Messaging - vCard</a><p> <a href="form.php?mode=VCAL">Nokia Smart Messaging - vCal</a><p> <a href="form.php?mode=PROFILE">Nokia Smart Messaging - Profile</a><p> <a href="form.php?mode=MWI">Message Waiting Indicator</a><p> <a href="form.php?mode=WAPCONFIG">Wap OTA - Wap Config</a><p> <a href="form.php?mode=BOOKMARK">Wap OTA - Wap Bookmark</a><p> <a href="form.php?mode=WAPPUSHSI">Wap OTA - Wap Push SI</a><p> <a href="form.php?mode=WAPPUSHSL">Wap OTA - Wap Push SL</a><p> <a href="form.php?mode=SIEMENS">Siemens - MMC</a><p> <a href="form.php?mode=RAW">RAW</a><p> </body> </html> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/contrib/web/index.html����������������������������������������������������������������0000755�0001750�0001750�00000000415�07436550451�016112� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html> <frameset cols="300,*" frameborder=0> <frame src="menu.html"> <frameset rows="*,100" frameborder=0> <frame src="form.php?mode=TEXT" name="dados"> <frame src="javascript:document.write('Please submit data!');" name="envia"> </frameset> </frameset> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/contrib/web/sendsms.php���������������������������������������������������������������0000644�0001750�0001750�00000036035�11463521267�016304� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html> <font size=-2> <? $kannel = array ( host => "localhost", port => "13013", user => "user", pass => "pass"); $string=""; while(list($k,$v) = each($_GET)) { if ( $v != "" ) { $fields[$k]= "$v"; } } while(list($k,$v) = each($_POST)) { if ( $v != "" ) { $fields[$k]= "$v"; } } if ( $fields['debug'] + 0 != "0" ) { $debug = 1; } else $debug=0; $fields['debug'] = ""; if ( $fields['text'] != "" ) { if ( ! preg_match("/%/", $fields['text'])) { $fields['text'] = urlencode($fields['text']); } } if ( $fields['image'] != "" ) $fields['image'] = preg_replace("/(..)/", "%$1", $fields['image']); if ( $fields['tune'] != "" ) $fields['tune'] = preg_replace("/(..)/", "%$1", $fields['tune']); if ( $mode == "LOGO") { if ($fields['country'] == "" ) $fields['country']="268"; if ($fields['operator'] == "" ) $fields['operator']="01"; $fields['image'] = substr($fields['image'], 0, 72*14*3/8); $fields['udh'] = "%06%05%04%15%82%00%00"; $fields['text'] = "%" .substr($fields['country'],1,1) .substr($fields['country'],0,1) ."%F" . substr($fields['country'],2,1) . "%". substr($fields['operator'],1,1) . substr($fields['operator'],0,1) . "%00%48%0E%01".$fields['image']; $fields['image'] = ""; $fields['country'] = ""; $fields['operator'] = ""; sendsms(); } else if ( $mode == "VCARD") { $fields['udh'] = "%06%05%04%23%F4%00%00"; $fields['vcard'] = ""; $fields['text'] = "BEGIN:VCARD%0D%0AVERSION:2.1%0D%0A"; if ( $fields['name'] != "") { $fields['text'] .= "N:".urlencode($fields['name']) . "%0D%0A"; $fields['name']=""; } if ( $fields['tele_pref'] != "") { $fields['text'] .= "TEL;PREF:".urlencode($fields['tele_pref']) . "%0D%0A"; $fields['tele_pref']=""; } if ( $fields['tele_cell'] != "") { $fields['text'] .= "TEL;CELL:".urlencode($fields['tele_cell']) . "%0D%0A"; $fields['tele_cell']=""; } if ( $fields['tele_home'] != "") { $fields['text'] .= "TEL;HOME:".urlencode($fields['tele_home']) . "%0D%0A"; $fields['tele_home']=""; } if ( $fields['tele_work'] != "") { $fields['text'] .= "TEL;WORK:".urlencode($fields['tele_work']) . "%0D%0A"; $fields['tele_work']=""; } if ( $fields['tele_fax'] != "") { $fields['text'] .= "TEL:FAX:".urlencode($fields['tele_fax']) . "%0D%0A"; $fields['tele_fax']=""; } if ( $fields['email'] != "") { $fields['text'] .= "EMAIL:".urlencode($fields['email']) . "%0D%0A"; $fields['email']=""; } if ( $fields['label'] != "") { $fields['text'] .= "LABEL:".urlencode($fields['label']) . "%0D%0A"; $fields['label']=""; } if ( $fields['note'] != "") { $fields['text'] .= "NOTE:".urlencode($fields['note']) . "%0D%0A"; $fields['note']=""; } $fields['text'] .= "END:VCARD%0D%0A"; sendsms(); } else if ( $mode == "VCAL") { $fields['udh'] = "%06%05%04%23%F5%00%00"; $fields['vcal'] = ""; $fields['text'] = "BEGIN:VCALENDAR%0D%0AVERSION:1.0%0D%0ABEGIN:VEVENT%0D%0A"; if ( $fields['vcal_name'] != "") { $fields['text'] .= "DESCRIPTION:".urlencode($fields['vcal_name']) . "%0D%0ASUMMARY:".urlencode($fields['vcal_name'])."%0D%0A"; $fields['vcal_name']=""; } if ( $fields['date'] != "") { $fields['text'] .= "DTSTART:".urlencode($fields['date']) . "%0D%0A"; $fields['date']=""; } if ( $fields['categories'] != "") { $fields['text'] .= "CATEGORIES:".urlencode($fields['categories']) . "%0D%0A"; $fields['categories']=""; } if ( $fields['rule'] != "") { $fields['text'] .= "RULES:".urlencode($fields['rule']) . "%0D%0A"; $fields['rule']=""; } if ( $fields['alarm'] != "") { $fields['text'] .= "DALARM:".urlencode($fields['alarm']) . ";;;%0D%0AAALARM:".urlencode($fields['alarm']).";;;%0D%0A"; $fields['alarm']=""; } $fields['text'] .= "END:VEVENT%0D%0AEND:VCALENDAR%0D%0A"; sendsms(); } else if ( $mode == "GROUP") { $fields['image'] = substr($fields['image'], 0, 72*14*3/8); $fields['udh'] = "%06%05%04%15%83%00%00"; $fields['text'] = "%00%48%0E%01".$fields['image']; $fields['image'] = ""; sendsms(); } else if ( $mode == "TUNE") { $fields['udh'] = "%06%05%04%15%81%00%00"; $fields['text'] = $fields['tune']; $fields['tune'] = ""; sendsms(); } else if ( $mode == "PICTURE") { print "PICTURE<br>"; $fields['image'] = substr($fields['image'], 0, 72*$fields['imagesize']*3/8); $fields['udh'] = "%06%05%04%15%8A%00%00"; $fields['text'] = "%30%00" . "%00". "%" . sprintf("%02X", strlen($fields['text'])).$fields['text']. "%02" . ($fields['imagesize'] == "14" ? "%00%82" : "%01%00") . "%00%48%".($fields['imagesize'] == "14" ? "0E" : "1C"). "%01".$fields['image']; $fields['image'] = ""; $fields['imagesize'] = ""; sendsms(); } else if ( $mode == "MWI") { if ( $fields['mwi'] > 4) { $fields['text'] = ""; $fields['charset'] = ""; $fields['mwi_messages'] = ""; $fields['coding'] = ""; } if ( $fields['mwi_messages'] != "" ) { $fields['udh'] = "%04%01%02%".($fields['text'] == "" ? '0' : 'C'). ($mwi-1). "%". sprintf("%02X", $fields['mwi_messages']); if($fields['coding'] == 0) { $fields['coding'] = 1; } $fields['mwi_messages'] = ""; } sendsms(); } else if ( $mode == "BOOKMARK") { $fields['udh'] = "%06%05%04%C3%4F%00%00"; $fields['name'] = urlencode($fields['name']); $fields['url'] = urlencode($fields['url']); $fields['text'] = "%01%06%2D%1F%2B%61%70%70%6C%69%63%61%74%69%6F%6E%2F%78%2D%77%61%70%2D%70%72%6F%76%2E%62%72%6F%77%73%65%72%2D%62%6F%6F%6B%6D%61%72%6B%73%00%81%EA%00%01%00%45%C6%7F%01%87%15%11%03". $fields['name']. "%00%01%87%17%11%03". $fields['url']. "%00%01%01%01"; $fields['name'] = ""; $fields['url'] = ""; sendsms(); } else if ( $mode == "WAPCONFIG") { $fields['udh'] = "%06%05%04%C3%4F%00%00"; $fields['name'] = urlencode($fields['name']); $fields['url'] = urlencode($fields['url']); $fields['text'] = ""; $fields['text'] .= "%01"; # Transaction ID / Push ID $fields['text'] .= "%06"; # PDU Type (Push) $fields['text'] .= "%2C"; # Headers Lenght (content-type + headers) $fields['text'] .= "%1F"; # ? Length $fields['text'] .= "%2A" . urlencode("application/x-wap-prov.browser-settings") . "%00" ; # Content-Type $fields['text'] .= "%81%EA"; # charset = UTF-8 $fields['text'] .= "%01"; # Version WBXML 1.1 $fields['text'] .= "%01"; # Unknown Public Identifier $fields['text'] .= "%6A"; # Charset UTF-8 $fields['text'] .= "%00"; # String table length $params = array ( "bearer" => "12", "proxy" => "13", "port" => "14", "name" => "15", "proxy_type" => "16", "url" => "17", "proxy_authname" => "18", "proxy_authsecret" => "19", "sms_smsc_address" => "1A", "ussd_service_code" => "1B", "gprs_accesspointname" => "1C", "ppp_logintype" => "1D", "proxy_logintype" => "1E", "csd_dialstring" => "21", "csd_calltype" => "28", "csd_callspeed" => "29", "ppp_authtype" => "22", "ppp_authname" => "23", "ppp_authsecret" => "24" ); $params_with_attr = array ( "bearer", "port", "proxy_type", "ppp_logintype", "proxy_logintype", "csd_calltype", "csd_callspeed", "ppp_authtype"); #$otadebug=1; $fields['text'] .= "%45"; # <CHARACTERISTIC_LIST> if ( $fields['name'] != "" ) { $fields['text'] .= "%C6%08%01"; # <CHARACTERISTIC TYPE="NAME"> $fields['text'] .= "%87%15%11"; # <PARM NAME="NAME" VALUE=... $fields['text'] .= "%03" . $fields['name'] ."%00"; # ..."$name"... $fields['text'] .= "%01"; # .../> $fields['text'] .= "%01"; # </CHARACTERISTIC> } if ( $fields['url'] != "" ) { $fields['text'] .= "%86%07%11"; # <CHARACTERISTIC TYPE="URL" VALUE=... $fields['text'] .= "%03" . plusencode($fields['url']) ."%00"; # ..."$name"... $fields['text'] .= "%01"; # </CHARACTERISTIC> } if ($fields['name'] != "" && $fields['url'] != "") { $fields['text'] .= "%C6%7F%01"; # <CHARACTERISTIC TYPE="BOOKMARK"> $fields['text'] .= "%87%15%11"; # <PARM NAME="NAME" VALUE=... $fields['text'] .= "%03" . $fields['name'] ."%00"; # ..."$name"... $fields['text'] .= "%01"; # .../> $fields['text'] .= "%87%17%11"; # <PARM NAME="URL" VALUE=... $fields['text'] .= "%03" . $fields['url'] ."%00"; # ..."$name"... $fields['text'] .= "%01"; # .../> $fields['text'] .= "%01"; # .../> } $fields['name'] = ""; $fields['url'] = ""; $fields['text'] .= "%C6%06%01"; # <CHARACTERISTIC TYPE="ADDRESS"> while(list($key, $val) = each($params)) { if ( $fields[$key] != "" && $fields[$key] != "0" ) { if ($otadebug == 1) { $fields['text'].="<parm name=$key ($val)>"; } $fields['text'] .= "%87"; # <PARM> with attributes $fields['text'] .= "%".$val; # NAME= if ( in_array($key, $params_with_attr) ) { if ($otadebug == 1) { $fields['text'].="<value key=$key val=".$fields[$key].">"; } $fields['text'] .= "%" . $fields[$key]; # VALUE=CODE } else { if ($otadebug == 1) { $fields['text'].="<value key=$key val=".$fields[$key].">"; } $fields['text'] .= "%11"; # VALUE= $fields['text'] .= "%03". plusencode($fields[$key]) . "%00"; # STRING } $fields['text'] .= "%01"; # </PARM> } $fields[$key] = ""; } $fields['text'] .= "%01"; # </CHARACTERISTIC> $fields['text'] .= "%01"; # </CHARACTERISTIC_LIST> sendsms(); } else if ( $mode == "WAPPUSHSI") { $fields['text'] = ""; $fields['udh'] = "%06%05%04%0B%84%23%F0"; $MIME=urlencode("application/vnd.wap.sic"); $fields['text'] .= "%01"; # Transaction ID $fields['text'] .= "%06"; # PDU Type (push) $fields['text'] .= "%04"; # Headers Length (content-type + headers) $fields['text'] .= "%03"; # Length of content type $fields['text'] .= "%AE"; # Content-Type: application/vnd.wap.sic $fields['text'] .= "%81"; # Charset $fields['text'] .= "%EA"; # UTF-8 # End Headers # see si_binary_output $fields['text'] .= "%02"; # Version number (wbxml_version) $fields['text'] .= "%05"; # Unknown Public Identifier (si_public_id) $fields['text'] .= "%6A"; # charset= (sibxml->charset) $fields['text'] .= "%00"; # String table length $fields['text'] .= "%45"; # <si> $fields['text'] .= "%C6"; # <indication... $fields['text'] .= "%0b" . "%03" . $fields['url'] . "%00"; # href=$url $fields['text'] .= "%11" . "%03" . rand(1,9)."@vodafone.pt" . "%00"; # si-id= $fields['text'] .= "%08"; # action="signal-high" #$fields['text'] .= "%0A" . "%C3%07%20%01%10%21%20%02%23"; # created= #$fields['text'] .= "%10" . "%C3%04%20%02%06%30"; # valid= $fields['text'] .= "%01"; # end indication params $fields['text'] .= "%03" . urlencode($fields['name']). "%00"; $fields['text'] .= "%01"; # </indication> $fields['text'] .= "%01"; # </si> $fields['name']=""; $fields['url']=""; sendsms(); } else if ( $mode == "WAPPUSHSL") { $fields['text'] = ""; $fields['udh'] = "%06%05%04%0B%84%23%F0"; $MIME=urlencode("application/vnd.wap.slc"); #$fields['text'] .= "%01"; # Transaction ID #$fields['text'] .= "%06"; # PDU Type (push) #$fields['text'] .= "%04"; # Headers Length (content-type + headers) #$fields['text'] .= "%03"; # length of content type #$fields['text'] .= "%B0"; # Content-Type: application/vnd.wap.slc #$fields['text'] .= "%81"; # Charset #$fields['text'] .= "%EA"; # UTF-8 $fields['text'] .= "%01"; # Transaction ID $fields['text'] .= "%06"; # PDU Type (push) $fields['text'] .= "%1B"; # Headers Length (content-type + headers) $fields['text'] .= "%1A"; # length of content type $fields['text'] .= $MIME."%00"; # Content-Type: application/vnd.wap.slc $fields['text'] .= "%81"; # Charset $fields['text'] .= "%EA"; # UTF-8 # End Headers # see si_binary_output $fields['text'] .= "%02"; # Version number (wbxml_version) $fields['text'] .= "%06"; # Unknown Public Identifier (si_public_id) $fields['text'] .= "%6A"; # charset= (sibxml->charset) $fields['text'] .= "%00"; # String table length $fields['text'] .= "%85"; # <sl> $fields['text'] .= "%0b"; # action="signal-high" $fields['text'] .= "%08" . "%03" . $fields['url'] . "%00"; # href=$url $fields['text'] .= "%01"; # </si> $fields['name']=""; $fields['url']=""; sendsms(); } else if ( $mode == "SIEMENS") { $fields['coding'] = "1"; #print_r($mmc_file_raw);exit; #move_uploaded_file($mmc_file_raw, "/tmp/siemens.tmp"); $h=fopen($mmc_file_raw, "rb"); $file = fread($h, filesize($mmc_file_raw)); fclose($h); $file_size = strlen($file); #$file = join("", file($mmc_file_raw)); #print strlen($file); exit; $file = join("", unpack("H*", $file)); $file = preg_replace("/(..)/", "%$1", $file); $max_size = 140 - 22 - 3 - strlen($mmc_file_name); $file_type = $fields['mmc_file_type']; $file_name = $fields['mmc_file_name']; $fields['mmc_file'] = ""; $fields['mmc_file_type'] = ""; $fields['mmc_file_name'] = ""; $count = 0; $max = ceil( $file_size / $max_size); $packet_size = $max_size; $object_size = sprintf("%08X", $file_size); $object_size = "%". substr($object_size, 6, 2). "%". substr($object_size, 4, 2). "%". substr($object_size, 2, 2). "%". substr($object_size, 0, 2); print "max=$max, packetsize=$packet_size, objectsize=$object_size; file_size: ".$file_size."<p>"; while ($count < $max) { if ( $count == $max - 1 ) { # Last Packet $packet_size = $file_size % $max_size; } $fields['text'] = ""; $fields['text'] .= "//SEO"; $fields['text'] .= "%01"; # Version 1 $fields['text'] .= "%". sprintf("%02X", $packet_size % 256). "%". sprintf("%02X", floor($packet_size / 256)); # Data Size on this message $fields['text'] .= "%00%00%00%00"; # Reference $fields['text'] .= "%". sprintf("%02X", ($count+1) % 256). "%". sprintf("%02X", floor(($count+1) / 256)); # Packet Number $fields['text'] .= "%". sprintf("%02X", $max % 256). "%". sprintf("%02X", floor($max / 256)); # Max Packets $fields['text'] .= $object_size; # Object Size $fields['text'] .= "%". sprintf("%02X", strlen($mmc_file_type)). $mmc_file_type; # Object Type $fields['text'] .= "%". sprintf("%02X", strlen($mmc_file_name)). $mmc_file_name; # Object File Name $fields['text'] .= substr($file, $count * $max_size * 3, $packet_size * 3); #print $fields['text']. "<br>"; #$debug = 1; sendsms(); $count++; } } else { sendsms(); } function sendsms (){ global $fields, $debug, $kannel; $fields['mode'] = ""; reset($fields); while(list($k,$v) = each($fields)) { if ( $v != "" ) { $string .= "&$k=$v"; } } print ($debug ? "[DEBUG]" : "" )."Getting $string<br>"; if ( !$debug ) { $result = @file("http://".$kannel['host'].":".$kannel['port']."/sendsms?user=".$kannel['user']."&pass=".$kannel['pass']."&".$string); } print_r( $result); } function plusencode($string) { return preg_replace("/\+/", "%2B", $string); } ?> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/contrib/sendsms�����������������������������������������������������������������������0000755�0001750�0001750�00000002040�07213750456�014733� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/python import os, string, sys, urllib HOST = "localhost" PORT = 13013 USERNAME = "tester" PASSWORD = "foobar" NUMBERS = "~/.sendsms.dat" def is_a_phone_number(str): if not str: return 0 for c in str: if not c in "0123456789+- ": return 0 return 1 def recipient(arg): if is_a_phone_number(arg): return arg f = open(os.path.expanduser(NUMBERS), "r") arg = string.lower(arg) number = None for line in f.readlines(): parts = string.split(line) if len(parts) == 2 and string.lower(parts[0]) == arg: number = parts[1] break f.close() if number: return number print "Unknown recipient", arg sys.exit(1) def sendsms(): to = urllib.quote_plus(recipient(sys.argv[1])) text = urllib.quote_plus(string.join(sys.argv[2:], " ")) url="http://%s:%d/cgi-bin/sendsms?username=%s&password=%s&to=%s&text=%s" \ % (HOST, PORT, USERNAME, PASSWORD, to, text) f = urllib.urlopen(url) print f.read() f.close() if __name__ == "__main__": sendsms() ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/configure.in��������������������������������������������������������������������������0000644�0001750�0001750�00000136427�13312154361�014211� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl /* ==================================================================== dnl * The Kannel Software License, Version 1.0 dnl * dnl * Copyright (c) 2001-2018 Kannel Group dnl * Copyright (c) 1998-2001 WapIT Ltd. dnl * All rights reserved. dnl * dnl * Redistribution and use in source and binary forms, with or without dnl * modification, are permitted provided that the following conditions dnl * are met: dnl * dnl * 1. Redistributions of source code must retain the above copyright dnl * notice, this list of conditions and the following disclaimer. dnl * dnl * 2. Redistributions in binary form must reproduce the above copyright dnl * notice, this list of conditions and the following disclaimer in dnl * the documentation and/or other materials provided with the dnl * distribution. dnl * dnl * 3. The end-user documentation included with the redistribution, dnl * if any, must include the following acknowledgment: dnl * "This product includes software developed by the dnl * Kannel Group (http://www.kannel.org/)." dnl * Alternately, this acknowledgment may appear in the software itself, dnl * if and wherever such third-party acknowledgments normally appear. dnl * dnl * 4. The names "Kannel" and "Kannel Group" must not be used to dnl * endorse or promote products derived from this software without dnl * prior written permission. For written permission, please dnl * contact org@kannel.org. dnl * dnl * 5. Products derived from this software may not be called "Kannel", dnl * nor may "Kannel" appear in their name, without prior written dnl * permission of the Kannel Group. dnl * dnl * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED dnl * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES dnl * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE dnl * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS dnl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, dnl * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT dnl * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR dnl * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, dnl * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE dnl * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, dnl * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. dnl * ==================================================================== dnl * dnl * This software consists of voluntary contributions made by many dnl * individuals on behalf of the Kannel Group. For more information on dnl * the Kannel Group, please see <http://www.kannel.org/>. dnl * dnl * Portions of this software are based upon software originally written at dnl * WapIT Ltd., Helsinki, Finland for the Kannel project. dnl */ dnl dnl configure.in -- main autoconf macro definition file dnl dnl Process this file with autoconf to produce a configure script. dnl dnl initialization AC_PREREQ(2.5) AC_INIT(gw/alt_charsets.h) AC_CONFIG_HEADER(gw-config.h) AC_SUBST(SHELL) AC_CONFIG_AUX_DIR(.) AC_SET_TERMINAL_SEQUENCES() AC_CONFIG_NICE(config.nice) dnl Check gateway version number. VERSION=`head -n 1 VERSION` if test "x$VERSION" = "xsvn"; then AC_MSG_CHECKING([svn checkout revision]) AC_SVN_REVISION(SVN_REVISION) AC_MSG_RESULT([$SVN_REVISION]) VERSION="$VERSION-r$SVN_REVISION" fi AC_DEFINE_UNQUOTED(GW_NAME, "Kannel") AC_DEFINE_UNQUOTED(GW_VERSION, "$VERSION") AC_DEFINE_UNQUOTED(VERSION, "$VERSION") AC_SUBST(GW_VERSION) AC_SUBST(VERSION) AC_CONFIG_SECTION([Configuring for Kannel gateway version $VERSION]) AM_INIT_AUTOMAKE(Kannel,$VERSION) AC_LANG_C AC_DISABLE_STATIC AC_PROG_LIBTOOL dnl AC_SUBST(LIBTOOL_DEPS) dnl Solaris pkgadd support definitions PKGADD_PKG="KANNELgateway" PKGADD_NAME="Kannel - WAP and SMS gateway" PKGADD_VENDOR="www.kannel.org" AC_SUBST(PKGADD_PKG) AC_SUBST(PKGADD_NAME) AC_SUBST(PKGADD_VENDOR) dnl Target installation directory for documentation AC_SUBST(docdir) docdir='${prefix}/share/doc/kannel' dnl Checks system type. AC_CONFIG_SECTION([Running system checks]) AC_CANONICAL_HOST dnl Checks for programs. AC_PROG_CC AC_PROG_CC_C99 if test "$ac_cv_prog_cc_c99" = "no"; then AC_MSG_ERROR(["Kannel requires a C compiler that supports ISO C99."]) fi AC_PROG_INSTALL AC_PROG_RANLIB AC_PROG_YACC AC_PROG_LEX AC_CHECK_TOOL(AR, ar) AC_PATH_PROG(CONVERT, convert) AC_PATH_PROG(PERL, perl) dnl Apply system specific rules. dnl Executable extension for systems that need one, i.e. Cygwin dnl Set the LIBTOOL to be used to create libs EXE_EXT="" OLD_LIBTOOL="$AR rc" case "$host" in *-sun-solaris*) CFLAGS="$CFLAGS -DSunOS=1" ;; *-cygwin*) EXE_EXT=".exe" LDFLAGS="$LDFLAGS -Wl,--enable-auto-import" ;; *apple-darwin*) # MacOS X # Lets try to find the newest installed SDK for compilation # so we know how to link against it. # If we find a SDK, we use that rather then the standard /usr # location libs and includes. found=0 SDK="" for loc in "MacOSX10.7.sdk" "MacOSX10.6.sdk" "MacOSX10.5.sdk" "MacOSX10.4u.sdk" "MacOSX10.4.0.sdk" "MacOSX10.3.9.sdk" \ "MacOSX10.3.0.sdk" "MacOSX10.2.8.sdk" "MacOSX10.1.5.sdk" do if test "$found" = "0" ; then if test -d "/Developer/SDKs/${E}" ; then found="1" SDK="${loc}" fi fi done if test "$SDK" != "" ; then CFLAGS="$CFLAGS -DDARWIN=1 -L/Developer/SDKs/${SDK}/usr/lib -I/Developer/SDKs/${SDK}/usr/include" else CFLAGS="$CFLAGS -DDARWIN=1" fi OLD_LIBTOOL="libtool -static -o" ;; *-linux-*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -D_DEFAULT_SOURCE" LDFLAGS="$LDFLAGS -rdynamic" ;; *-*-openbsd* | *-*-freebsd*) CFLAGS="$CFLAGS -pthread" AC_CHECK_LIB(pthread, pthread_exit, [LIBS="$LIBS -lpthread"; pthread="yes"], [AC_CHECK_LIB(c_r, pthread_exit, [LIBS="$LIBS -lc_r"; pthread="yes"])] ) ;; *-interix3*) INSTALL="./install-sh" ;; esac AC_SUBST(EXE_EXT) AC_SUBST(OLD_LIBTOOL) AC_ARG_WITH(cflags, [ --with-cflags=FLAGS use FLAGS for CFLAGS], CFLAGS="$CFLAGS $withval") AC_ARG_WITH(libs, [ --with-libs=FLAGS use FLAGS for extra libraries], LIBS="$LIBS $withval") dnl Check whether compiler supports inline AC_C_INLINE dnl Check for how to do large files AC_SYS_LARGEFILE(CFLAGS) if test "${ac_cv_sys_file_offset_bits}" != no ; then CFLAGS="$CFLAGS -D_FILE_OFFSET_BITS=${ac_cv_sys_file_offset_bits}" fi if test "${ac_cv_sys_large_files}" != no ; then CFLAGS="$CFLAGS -D_LARGE_FILES=${ac_cv_sys_large_files}" fi dnl Check for word sizes. AC_CHECK_SIZEOF(short, 2) AC_CHECK_SIZEOF(int, 4) AC_CHECK_SIZEOF(long, 4) AC_CHECK_SIZEOF(long long, 8) SIZEOF_SHORT=$ac_cv_sizeof_short SIZEOF_INT=$ac_cv_sizeof_int SIZEOF_LONG=$ac_cv_sizeof_long SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long AC_SUBST(SIZEOF_SHORT) AC_SUBST(SIZEOF_INT) AC_SUBST(SIZEOF_LONG) AC_SUBST(SIZEOF_LONG_LONG) dnl Checks for libraries. AC_CHECK_LIB(m, log) AC_CHECK_LIB(socket, accept) AC_CHECK_LIB(nsl, inet_ntoa) AC_CHECK_LIB(resolv, inet_ntop) AC_CHECK_LIB(bind, inet_ntop) if test -z "$pthread"; then AC_CHECK_LIB(pthread, pthread_exit, [LIBS="$LIBS -lpthread"]) fi AC_CHECK_LIB(iconv, libiconv, [LIBS="$LIBS -liconv"]) dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(sys/ioctl.h sys/time.h sys/types.h unistd.h sys/poll.h) AC_CHECK_HEADERS(pthread.h getopt.h syslog.h zlib.h execinfo.h stdlib.h) AC_CHECK_HEADERS([sys/socket.h sys/sockio.h netinet/in.h]) AC_CHECK_HEADERS([net/if.h], [], [], [#include <stdio.h> #if STDC_HEADERS # include <stdlib.h> # include <stddef.h> #else #if HAVE_STDLIB_H # include <stdlib.h> # endif #endif #if HAVE_SYS_SOCKET_H # include <sys/socket.h> #endif ]) AC_CHECK_HEADERS([sys/ucontext.h], [AC_DEFINE(HAVE_UCONTEXT)], [AC_MSG_WARN(System lacks ucontext.h - user context support)] ) dnl Checks for typedefs, structures, and compiler characteristics. AC_TRY_COMPILE(, [char *func = __FUNCTION__;], AC_DEFINE(HAVE___FUNCTION__)) AC_TRY_COMPILE(, [char *func = __func__;], AC_DEFINE(HAVE___FUNC__)) dnl check for iconv AM_ICONV dnl Checks for library functions. AC_CHECK_FUNCS(gettimeofday select socket strdup getopt_long localtime_r gmtime_r backtrace srandom initgroups strtoll strtoq) AC_CHECK_FUNC(getopt, [], [AC_LIBOBJ([utils/attgetopt])]) dnl Check if we have reentrant gethostbyname and which one AC_CHECK_FUNC(gethostbyname_r, [ AC_FUNC_WHICH_GETHOSTBYNAME_R ], [ AC_CHECK_FUNC(gethostbyname,[], [ AC_MSG_ERROR([Couldnot find gethostbyname_r nor gethostbyname functions])])] ) dnl Extra feature checks dnl GW_HAVE_TYPE_FROM(HDRNAME, TYPE, HAVENAME, DESCRIPTION) AC_DEFUN([GW_HAVE_TYPE_FROM], [ AC_CACHE_CHECK([for $2 in <$1>], gw_cv_type_$3, AC_TRY_COMPILE([#ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif #include <$1> ], [$2 foo;], gw_cv_type_$3=yes, gw_cv_type_$3=no)) if test $gw_cv_type_$3 = yes; then AC_DEFINE($3, 1, $4) fi ]) dnl GW_HAVE_FUNC_FROM(HDRNAME, FUNC, HAVENAME, DESCRIPTION) AC_DEFUN([GW_HAVE_FUNC_FROM], [ AC_CACHE_CHECK([for $2 in <$1>], gw_cv_func_$3, AC_TRY_COMPILE([#include <$1>], [void *foo = $2;], gw_cv_func_$3=yes, gw_cv_func_$3=no)) if test $gw_cv_func_$3 = yes; then AC_DEFINE($3, 1, $4) fi ]) GW_HAVE_TYPE_FROM(sys/socket.h, socklen_t, HAVE_SOCKLEN_T, [Defined if there is a socklen_t in <sys/socket.h>]) GW_HAVE_FUNC_FROM(stdio.h, getopt, HAVE_GETOPT_IN_STDIO_H, [Does <stdio.h> declare getopt()?]) GW_HAVE_FUNC_FROM(unistd.h, getopt, HAVE_GETOPT_IN_UNISTD_H, [Does <unistd.h> declare getopt()?]) dnl POSIX nftw() AC_CHECK_HEADERS(ftw.h, [ AC_CHECK_FUNC(nftw, [ AC_DEFINE(HAVE_NFTW) ]) ]) dnl POSIX regular expression check AC_CHECK_HEADERS(regex.h, [ AC_CHECK_FUNC(regcomp, [ AC_DEFINE(HAVE_REGEX) has_posix_regex=1 ]) ]) dnl Misc feature checks AC_CONFIG_SECTION([Checking for POSIX threads support]) AC_MSG_CHECKING(for working pthreads) AC_TRY_RUN([#include <pthread.h> #include <unistd.h> int pid; void testpid(void* foo); int main(void){ pthread_t child; pid=getpid(); pthread_create(&child,NULL,(void*)testpid,NULL); pthread_join(child,NULL); return 0; } void testpid(void* foo){ int mypid=getpid(); if(mypid!=pid){ /* Pthreads states that all threads should have the same PID * we dont! */ exit(1); }else{ exit(0); } } ],echo yes , echo no ;CFLAGS="$CFLAGS -DBROKEN_PTHREADS=1", echo Cross compiling - assuming they work) dnl dnl Checking pthread_spin support dnl AC_MSG_CHECKING([for pthread_spinlock support]) AC_TRY_COMPILE([#include <pthread.h>], [ #ifdef __INTERIX /* * interix has experimental spinlock support and this doesn't work very well * therefore disable it for now */ pthread_spinlock_t_failed lock; #else pthread_spinlock_t lock; #endif pthread_spin_init(&lock, 0); pthread_spin_lock(&lock); pthread_spin_unlock(&lock); pthread_spin_destroy(&lock); ], [AC_MSG_RESULT(yes); AC_DEFINE(HAVE_PTHREAD_SPINLOCK_T)], AC_MSG_RESULT(no)) dnl checking pthread_rwlock support AC_MSG_CHECKING([for pthread_rwlock support]) AC_TRY_COMPILE([#include <pthread.h>], [ pthread_rwlock_t lock; pthread_rwlock_init(&lock, NULL); pthread_rwlock_rdlock(&lock); pthread_rwlock_unlock(&lock); pthread_rwlock_wrlock(&lock); pthread_rwlock_unlock(&lock); pthread_rwlock_destroy(&lock); ], [AC_MSG_RESULT(yes); AC_DEFINE(HAVE_PTHREAD_RWLOCK)], AC_MSG_RESULT(no), [ AC_MSG_RESULT(Cross compiling - assuming suuported) ; AC_DEFINE(HAVE_PTHREAD_RWLOCK)]) dnl checking for native semaphore support dnl Solaris & HP-UX needs librt. AC_CHECK_LIB(rt, sem_init) AC_MSG_CHECKING([for semaphore support]) AC_TRY_RUN([#include <semaphore.h> int main(void) { sem_t s; int val; /* DARWNIN doesn't implement native sem_init */ if (sem_init(&s, 0, 1) != 0) return 1; sem_wait(&s); sem_post(&s); sem_getvalue(&s, &val); sem_destroy(&s); return 0; } ], [AC_MSG_RESULT(yes); AC_DEFINE(HAVE_SEMAPHORE)], AC_MSG_RESULT(no), [ AC_MSG_RESULT(Cross compiling - assuming suuported) ; AC_DEFINE(HAVE_SEMAPHORE)]) dnl Check if we have libxml2 installed and which version it is. dnl Kannel requires currently at least version 2.6.0 of libxml2. AC_CONFIG_SECTION([Checking for libxml2 support]) xml_ver_required="2.6.0" AC_PATH_PROGS(XML_CONFIG, xml2-config xml-config, no) if test "$XML_CONFIG" = "no"; then AC_MSG_ERROR([You MUST have the libxml2 (aka gnome-xml) library installed]) else AC_MSG_CHECKING([libxml version]) xml_version=`$XML_CONFIG --version` AC_MSG_RESULT([$xml_version]) AC_CHECK_VERSION($xml_version, $xml_ver_required, [ LIBS="$LIBS `$XML_CONFIG --libs`" CFLAGS="$CFLAGS `$XML_CONFIG --cflags`" ],[ AC_MSG_ERROR([libxml2 version $xml_version is too old. You need at least $xml_ver_required]) ]) fi dnl Implement the --enable-pcre option. This will set HAVE_PCRE in gw-config.h dnl accordingly and enable the usage of Perl compatible regular expressions. dnl As POSIX regex is a subset of PCRE, we map the posixpcre API calls, so dnl HAVE_REGEX has to be undefined. AC_CONFIG_SECTION([Configuring for PCRE support]) AC_MSG_CHECKING([whether to compile with PCRE support]) AC_ARG_ENABLE(pcre, [ --enable-pcre enable PCRE regex support @<:@disabled@:>@], [ if test "$enableval" != yes; then AC_MSG_RESULT(disabled) else AC_MSG_RESULT(searching) AC_PATH_PROGS(PCRE_CONFIG, pcre-config, no) if test "$PCRE_CONFIG" = "no"; then AC_MSG_ERROR(Unable to find pcre-config in path for PCRE support) else AC_MSG_CHECKING([PCRE version]) pcre_version=`$PCRE_CONFIG --version` AC_MSG_RESULT([$pcre_version]) LIBS="$LIBS `$PCRE_CONFIG --libs-posix`" CFLAGS="$CFLAGS `$PCRE_CONFIG --cflags-posix`" AC_MSG_CHECKING([for POSIX regex provider]) AC_MSG_RESULT([PCRE library]) AC_CHECK_HEADERS(pcreposix.h) AC_CHECK_LIB(pcreposix, regcomp) AC_CHECK_HEADERS(pcre.h) AC_CHECK_FUNCS(pcre_compile) AC_DEFINE(HAVE_PCRE) AC_DEFINE_UNQUOTED(LIBPCRE_VERSION, "$pcre_version") PCRE="yes" fi fi ],[ AC_MSG_RESULT(disabled) ]) dnl DocBook stuff AC_CONFIG_SECTION([Configuring DocBook support]) AC_CHECK_PROGS(JADE, [jade openjade], no) AC_CHECK_PROG(JADETEX, jadetex, jadetex, no) AC_CHECK_PROG(PDFJADETEX, pdfjadetex, pdfjadetex, no) AC_CHECK_PROG(DVIPS, dvips, dvips, no) AC_CHECK_PROG(FIG2DEV, fig2dev, fig2dev, no) AC_CHECK_PROG(CONVERT, convert, convert, no) AC_SUBST(HTML_DSL) found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/html/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/html/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/html/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/html/docbook.dsl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/html/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/html/docbook.dsl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,HTML_DSL=$file; found=1) fi done fi done AC_SUBST(TEX_DSL) found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/print/docbook.dsl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/print/docbook.dsl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/print/docbook.dsl \ ${loc}/share/sgml/docbook/dsssl/modular/print/docbook.dsl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/print/docbook.dsl \ ${loc}/share/dsssl/docbook-dsssl/print/docbook.dsl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,TEX_DSL=$file; found=1) fi done fi done AC_SUBST(XML_DCL) found="" for loc in /usr /usr/local /sw /opt/local; do if test "x$found" = "x" ; then for file in ${loc}/lib/sgml/stylesheet/dsssl/docbook/nwalsh/dtds/decls/xml.dcl \ ${loc}/lib/sgml/stylesheets/nwalsh-modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets-1.*/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl-stylesheets/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/stylesheet/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/docbook/dsssl/modular/dtds/decls/xml.dcl \ ${loc}/share/sgml/declaration/xml.dcl \ ${loc}/share/sgml/dsssl/docbook-dsssl-nwalsh/dtds/decls/xml.dcl \ ${loc}/share/dsssl/docbook-dsssl/dtds/decls/xml.dcl ; do if test "x$found" = "x" ; then AC_CHECK_FILE($file,XML_DCL=$file; found=1) fi done fi done dnl Implement --enable-warnings option. AC_ARG_ENABLE(warnings, [ --enable-warnings enable compilation warnings @<:@disabled@:>@], [ echo enabling compilation warnings if test -n "$GCC"; then CFLAGS="$CFLAGS -Wall" CFLAGS="$CFLAGS -Wmissing-prototypes" CFLAGS="$CFLAGS -Wmissing-declarations" CFLAGS="$CFLAGS -Wnested-externs" CFLAGS="$CFLAGS -Winline" CFLAGS="$CFLAGS -Wformat -Wformat-security -Wmissing-format-attribute" #CFLAGS="$CFLAGS -Wstrict-prototypes" #CFLAGS="$CFLAGS -Wredundant-decls" #CFLAGS="$CFLAGS -Wconversion" fi ]) dnl Implement --enable-docs option. AC_SUBST(DOCSTARGET) AC_ARG_ENABLE(docs, [ --enable-docs enable building of documentation @<:@enabled@:>@], [ if test "$enableval" = "yes" then DOCSTARGET="docs" else DOCSTARGET="no-docs" fi ]) if test "x$HTML_DSL" = "x" -o "x$TEX_DSL" = "x" \ || test "$JADE" = "no" \ || test "$JADETEX" = "no" \ || test "$PDFJADETEX" = "no" \ || test "$DVIPS" = "no" \ || test "$FIG2DEV" = "no" \ || test "$CONVERT" = "no" \ || test "$DOCSTARGET" = "no-docs" then DOCSTARGET="no-docs" else DOCSTARGET="docs" fi case "$DOCSTARGET" in no-docs) AC_MSG_RESULT(Not building documentation.) ;; docs) AC_MSG_RESULT(Documentation will be built as well.) ;; esac dnl Implement --enable-drafts option. AC_SUBST(DOCDRAFTS) DOCDRAFTS="IGNORE" AC_ARG_ENABLE(drafts, [ --enable-drafts enable building of documentation drafts @<:@disabled@:>@], [ if test "$enableval" = "yes" then DOCDRAFTS="INCLUDE" else DOCDRAFTS="IGNORE" fi ]) if test "x$DOCSTARGET" = "xdocs" then case "$DOCDRAFTS" in INCLUDE) AC_MSG_RESULT(Documentation will include drafts.) ;; esac fi AC_CONFIG_SECTION([Configuring parameters]) dnl Implement --with-suffix=version option. SUFFIX="" AC_ARG_WITH(suffix, [ --with-suffix=VERSION set suffix for binaries @<:@foobox-VERSION@:>@], [ if test "x$withval" != "x" ; then SUFFIX=$withval fi ]) dnl Implement --enable-suffix option. AC_ARG_ENABLE(suffix, [ --enable-suffix enable suffix for binaries @<:@disabled@:>@], [ if test "$enableval" = "yes" ; then SUFFIX="-$VERSION" else SUFFIX="" fi ]) if test "x$SUFFIX" != "x" ; then AC_MSG_CHECKING(whether to append suffix to binary) AC_MSG_RESULT($SUFFIX) fi AC_DEFINE_UNQUOTED(SUFFIX, "$SUFFIX") AC_SUBST(SUFFIX) dnl Implement --with-defaults=speed/debug option. AC_ARG_WITH(defaults, [ --with-defaults=OPTION set default configure options: speed/debug @<:@speed@:>@ this will set assertion checking and malloc wrapper accordingly speed = native malloc + no assertions debug = checking malloc + assertions], [ case "$withval" in speed) assertiondefault=no mallocdefault=native ;; debug) assertiondefault=yes mallocdefault=check ;; *) echo "unknown --with-defaults parameter $withval" exit 1 ;; esac ], [ dnl defaults to native malloc but with assertions assertiondefault=yes mallocdefault=native ]) dnl Implement --with-malloc=[native|check|slow] option. AC_MSG_CHECKING(which malloc to use) AC_ARG_WITH(malloc, [ --with-malloc=OPTION select malloc wrapper to use: native/check/slow @<:@native@:>@], [ case "$withval" in native) AC_DEFINE(USE_GWMEM_NATIVE) AC_MSG_RESULT(native malloc) ;; check) AC_DEFINE(USE_GWMEM_CHECK) AC_MSG_RESULT(checking malloc) ;; slow) AC_DEFINE(USE_GWMEM_SLOW) AC_MSG_RESULT(slow malloc) ;; *) echo "Unknown malloc wrapper $withval. Oops."; exit 1 ;; esac ], [ case "$mallocdefault" in check) AC_DEFINE(USE_GWMEM_CHECK) AC_MSG_RESULT(checking malloc) ;; slow) AC_DEFINE(USE_GWMEM_SLOW) AC_MSG_RESULT(slow malloc) ;; *) AC_DEFINE(USE_GWMEM_NATIVE) AC_MSG_RESULT(native malloc) ;; esac ]) dnl Implement --disable-assertions option. AC_ARG_ENABLE(assertions, [ --disable-assertions turn off assertion checking], [ if test "$enableval" = "no" then echo disabling assertion checking AC_DEFINE(NO_GWASSERT) fi ], [ if test "$assertiondefault" = "no" then echo disabling assertion checking AC_DEFINE(NO_GWASSERT) fi ]) dnl Implement the --enable-pam option. AC_ARG_ENABLE(pam, [ --enable-pam enable PAM authentication @<:@disabled@:>@], [ if test "$enableval" = "yes" then AC_CHECK_LIB(pam, pam_end) AC_CHECK_LIB(dl,main) AC_CHECK_HEADERS(security/pam_appl.h) PAMTARGET="pam" else PAMTARGET="no-pam" fi ]) case "$PAMTARGET" in no-pam) echo PAM authentication is disabled. ;; pam) echo PAM authentication is enabled. ;; esac dnl Implement --enable-debug option. AC_ARG_ENABLE(debug, [ --enable-debug enable non-reentrant debugging for wmls compiler @<:@disabled@:>@], [ echo enabling WMLScript compiler debugging if test -n "$GCC"; then CFLAGS="$CFLAGS -Wall" fi AC_DEFINE(WS_DEBUG) ]) dnl Implement --enable-localtime option. AC_ARG_ENABLE(localtime, [ --enable-localtime log file time stamps in local time, not GMT @<:@enabled@:>@], [ if test "$enableval" = yes; then echo enabling local time AC_DEFINE(LOG_TIMESTAMP_LOCALTIME) fi ],[ echo enabling local time AC_DEFINE(LOG_TIMESTAMP_LOCALTIME) ]) dnl --enable-mutex-stats option. AC_ARG_ENABLE(mutex-stats, [ --enable-mutex-stats produce information about lock contention], [ if test "$enableval" = yes; then AC_DEFINE(MUTEX_STATS) fi ]) dnl --disable-cookies option. AC_ARG_ENABLE(cookies, [ --disable-cookies disable cookie support for WSP @<:@enabled@:>@], [ if test "$enableval" = yes; then echo enabling cookies AC_DEFINE(ENABLE_COOKIES) else echo disabling cookies fi ],[ echo enabling cookies AC_DEFINE(ENABLE_COOKIES) ]) dnl --disable-keepalive option. AC_ARG_ENABLE(keepalive, [ --disable-keepalive disable HTTP/1.1 keep-alive support @<:@enabled@:>@], [ if test "$enableval" = yes; then echo enabling HTTP/1.1 keep-alive AC_DEFINE(USE_KEEPALIVE) else echo disabling HTTP/1.1 keep-alive fi ],[ echo enabling HTTP/1.1 keep-alive AC_DEFINE(USE_KEEPALIVE) ]) dnl --enable-start-stop-daemon option. AC_MSG_CHECKING([whether to compile start-stop-daemon]) AC_ARG_ENABLE(start-stop-daemon, [ --enable-start-stop-daemon compile/install the start-stop-daemon program @<:@disabled@:>@], [ case "${enableval}" in yes) buildbin=true AC_MSG_RESULT(enabled) ;; no) buildbin=false AC_MSG_RESULT(disabled) ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-start-stop-daemon) ;; esac ],[ buildbin=false ; AC_MSG_RESULT(disabled)]) AM_CONDITIONAL(BUILD_STARTSTOPDAEMON, test x$buildbin = xtrue) dnl Implement --disable-wap and --disable-sms options. AC_ARG_ENABLE(wap, [ --disable-wap disables WAP gateway parts in bearerbox], [ if test "$enableval" = "no" then echo disabling WAP gateway parts in bearerbox AC_DEFINE(NO_WAP) fi ]) AC_ARG_ENABLE(sms, [ --disable-sms disables SMS gateway parts in bearerbox], [ if test "$enableval" = "no" then echo disabling SMS gateway parts in bearerbox AC_DEFINE(NO_SMS) fi ]) dnl Implement the --with-ssl option. AC_CONFIG_SECTION([Configuring OpenSSL support]) AC_ARG_WITH(ssl, [ --with-ssl[=DIR] where to look for OpenSSL libs and header files DIR points to the installation @<:@/usr/local/ssl@:>@], [ if test -d "$withval"; then ssllib="$withval/lib"; sslinc="$withval/include" else AC_MSG_ERROR(Unable to find OpenSSL libs and/or directories at $withval) fi ]) dnl Implement --enable-ssl option. AC_MSG_CHECKING([whether to compile with SSL support]) AC_ARG_ENABLE(ssl, [ --enable-ssl enable SSL client and server support @<:@enabled@:>@], [ if test "$enableval" = no ; then AC_MSG_RESULT(disabled) ssl=no else ssl=yes fi ],[ ssl=yes ]) if test "$ssl" = "yes" ; then dnl test only if --with-ssl has not been used if test "x$ssllib" = "x" && test "x$sslinc" = "x"; then for loc in /usr/lib /usr/lib64 /usr/local/ssl/lib /usr/local/openssl/lib; do if test -f "$loc/libssl.a" -o -f "$loc/libssl.so" -o -f "$loc/libssl.dylib" ; then ssllib="$loc" fi done if test "x$sslib" = "x" && test -n "$GCC"; then for lib in libssl.a libssl.so libssl.dylib; do name=`$CC -print-file-name=$lib` if test -f "$name"; then ssllib=`dirname $name` fi done fi for loc in /usr/include/ssl /usr/include/openssl /usr/local/ssl/include \ /usr/local/openssl/include; do if test -d "$loc"; then sslinc="$loc" fi done fi AC_MSG_RESULT(trying $ssllib $sslinc) fi dnl Implement the SSL library checking routine. dnl This will define HAVE_LIBSSL in gw-config.h if test "x$ssllib" != "x" && test "x$sslinc" != "x"; then CFLAGS="$CFLAGS -I$sslinc" LIBS="$LIBS -L$ssllib" AC_PATH_PROG(OPENSSL, openssl, no) if test "$OPENSSL" != "no"; then AC_MSG_CHECKING([openssl version]) openssl_version=`$OPENSSL version | awk '{print $2}'` openssl_ver=`echo $openssl_version | sed 's/[[a-zA-Z]]//g'` AC_MSG_RESULT([$openssl_version]) fi AC_CHECK_VERSION($openssl_ver, "1.1.0", [ CRYPTO_CHECK=HMAC_Update SSL_CHECK=OPENSSL_init_ssl ],[ CRYPTO_CHECK=CRYPTO_lock SSL_CHECK=SSL_library_init ]) AC_CHECK_LIB(crypto, $CRYPTO_CHECK, [ LIBS="$LIBS -lcrypto" AC_CHECK_LIB(ssl, $SSL_CHECK, [ AC_CHECK_LIB(ssl, SSL_connect) AC_CHECK_HEADERS(openssl/x509.h openssl/rsa.h openssl/crypto.h \ openssl/pem.h openssl/ssl.h openssl/err.h \ openssl/hmac.h) AC_MSG_CHECKING(whether the OpenSSL library is multithread-enabled) AC_TRY_RUN([ #define OPENSSL_THREAD_DEFINES #include <openssl/opensslconf.h> int main(void) { #if defined(THREADS) exit(0); #elif defined(OPENSSL_THREADS) exit(0); #else exit(1); #endif } ], [ AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LIBSSL) LIBS="$LIBS -lssl" AC_MSG_CHECKING([whether to compile with SSL support]) AC_MSG_RESULT(yes) ], [ AC_ARG_ENABLE(ssl-thread-test, [ --disable-ssl-thread-test disable the multithread test for the OpenSSL library this will force to continue even if the test fails], [ if test "$enableval" = no ; then AC_MSG_RESULT([no, continue forced]) fi ], [ AC_MSG_RESULT(no) AC_MSG_ERROR(Either get a multithread-enabled SSL or configure with --disable-ssl) ]) ], echo "Cross-compiling; make sure your SSL library is multithread-enabled" ) ]) ]) fi AC_CONFIG_SECTION([Configuring DB support]) dnl Implement the --with-mysql option. This will set HAVE_MYSQL in gw-config.h dnl accordingly and enable the usage of the libmysqlclient routines. AC_MSG_CHECKING([whether to compile with MySQL support]) AC_ARG_WITH(mysql, [ --with-mysql enable MySQL storage @<:@disabled@:>@], [ if test "$withval" != yes ; then AC_MSG_RESULT(disabled) else dnl Implement the --with-mysql-dir option. AC_ARG_WITH(mysql-dir, [ --with-mysql-dir=DIR where to look for MySQL libs and header files DIR points to the installation @<:@/usr/local/mysql@:>@], [ mysqlloc="" if test -d "$withval" ; then mysqlloc="$withval" fi ]) AC_MSG_RESULT(searching) AC_PATH_PROG(MYSQL_CONFIG, mysql_config, no, [$PATH:$mysqlloc/bin:$mysqlloc]) dnl check for MySQL 4.x style mysql_config information if test "$MYSQL_CONFIG" = "no"; then found="" for loc in $mysqlloc /usr /usr/local ; do if test "x$found" = "x" ; then AC_MSG_CHECKING([for MySQL client support in]) AC_MSG_RESULT($loc) AC_CHECK_FILE("$loc/include/mysql/mysql.h", [CFLAGS="$CFLAGS -I$loc/include/mysql"; LIBS="$LIBS -L$loc/lib/mysql -lmysqlclient"]; found=1, [AC_CHECK_FILE("$loc/include/mysql.h", [CFLAGS="$CFLAGS -I$loc/include"; LIBS="$LIBS -L$loc/lib -lmysqlclient"]; found=1 )] ) fi done if test "x$found" != "x1" ; then AC_MSG_ERROR([Unable to find mysql.h, please provide a --with-mysql-dir=<dir> location]) fi else dnl mysql_config found AC_MSG_CHECKING([mysql version]) mysql_version=`$MYSQL_CONFIG --version` AC_MSG_RESULT([$mysql_version]) dnl mysql-4.x style MYSQL_LIBS="" if $MYSQL_CONFIG --libs_r &>/dev/null ; then MYSQL_LIBS=`$MYSQL_CONFIG --libs_r` AC_MSG_CHECKING([mysql reentrant libs]) AC_MSG_RESULT([$MYSQL_LIBS]) AC_CHECK_LIB(mysqlclient_r, mysql_init, [ LIBS="$LIBS $MYSQL_LIBS" ], [ MYSQL_LIBS="" ], [ $MYSQL_LIBS ]) fi if test -z "$MYSQL_LIBS" ; then MYSQL_LIBS=`$MYSQL_CONFIG --libs` AC_MSG_CHECKING([mysql libs]) AC_MSG_RESULT([$MYSQL_LIBS]) AC_CHECK_LIB(mysqlclient, mysql_init, [ LIBS="$LIBS $MYSQL_LIBS" ], [AC_MSG_ERROR([Unable to find MySQL client libraries])], [ $MYSQL_LIBS ]) fi AC_MSG_CHECKING([mysql includes]) dnl mysql-4.x style if $MYSQL_CONFIG --include &>/dev/null ; then MYSQL_CFLAGS=`$MYSQL_CONFIG --include` else MYSQL_CFLAGS=`$MYSQL_CONFIG --cflags` fi CFLAGS="$CFLAGS $MYSQL_CFLAGS" AC_MSG_RESULT([$MYSQL_CFLAGS]) fi AC_CHECK_HEADERS(mysql/mysql.h mysql/mysql_version.h) AC_CHECK_LIB(mysqlclient_r, mysql_stmt_init, [], AC_CHECK_LIB(mysqlclient, mysql_stmt_init, [], [AC_MSG_ERROR([Unable to find MySQL client libraries version >= 4.1])]) ) AC_DEFINE(HAVE_MYSQL) AC_MSG_CHECKING([whether to compile with MySQL support]) AC_MSG_RESULT(yes) MYSQL="yes" fi ],[ AC_MSG_RESULT(disabled) ]) dnl Implement the --with-sdb option. This will set HAVE_SDB in gw-config.h dnl accordingly and enable the usage of the libsdb routines. AC_MSG_CHECKING([whether to compile with LibSDB support]) AC_ARG_WITH(sdb, [ --with-sdb enable LibSDB storage @<:@disabled@:>@], [ if test "$withval" != yes; then AC_MSG_RESULT(disabled) else AC_MSG_RESULT(searching) AC_PATH_PROGS(SDB_CONFIG, sdb-config, no) if test "$SDB_CONFIG" = "no"; then AC_MSG_ERROR(Unable to find sdb-config in path for SDB support) else AC_MSG_CHECKING([sdb version]) sdb_version=`$SDB_CONFIG --version` AC_MSG_RESULT([$sdb_version]) CFLAGS="$CFLAGS `$SDB_CONFIG --cflags`" AC_CHECK_HEADERS(sdb.h) LIBS="$LIBS `$SDB_CONFIG --libs`" AC_CHECK_LIB(sdb, sdb_init, [LIBS="$LIBS -lsdb" AC_DEFINE(HAVE_SDB) AC_DEFINE_UNQUOTED(LIBSDB_VERSION, "$sdb_version") SDB="yes"], [AC_MSG_ERROR([Unable to find libSDB client libraries])] ) fi fi ],[ AC_MSG_RESULT(disabled) ]) dnl Implement the --with-sqlite2 option. This will set HAVE_SQLITE in gw-config.h dnl accordingly and enable the usage of the libsqlite routines. AC_MSG_CHECKING([whether to compile with SQLite2 support]) AC_ARG_WITH(sqlite2, [ --with-sqlite2 enable SQLite2 storage @<:@disabled@:>@], [ if test "$withval" != yes; then AC_MSG_RESULT(disabled) else AC_MSG_RESULT(searching) AC_CHECK_HEADERS(sqlite.h) LIBS="$LIBS -L/usr/local/lib" AC_CHECK_LIB(sqlite, sqlite_open, [LIBS="$LIBS -lsqlite" AC_DEFINE(HAVE_SQLITE) SQLITE="yes"], [AC_MSG_ERROR([Unable to find SQLite2 client libraries])] ) AC_PATH_PROGS(SQLITE, sqlite, no) if test "$SQLITE" = "no"; then AC_MSG_WARN([Unable to find sqlite in path for SQLite2 support]) else AC_MSG_CHECKING([sqlite version]) sqlite_version=`$SQLITE -version` AC_MSG_RESULT([$sqlite_version]) fi fi ],[ AC_MSG_RESULT(disabled) ]) dnl Implement the --with-sqlite3 option. This will set HAVE_SQLITE3 in gw-config.h dnl accordingly and enable the usage of the libsqlite3 routines. AC_MSG_CHECKING([whether to compile with SQLite3 support]) AC_ARG_WITH(sqlite3, [ --with-sqlite3 enable SQLite3 storage @<:@disabled@:>@], [ if test "$withval" != yes; then AC_MSG_RESULT(disabled) else AC_MSG_RESULT(searching) AC_CHECK_HEADERS(sqlite3.h) LIBS="$LIBS -L/usr/local/lib" AC_CHECK_LIB(sqlite3, sqlite3_open, [LIBS="$LIBS -lsqlite3" AC_DEFINE(HAVE_SQLITE3) SQLITE3="yes"], [AC_MSG_ERROR([Unable to find SQLite3 client libraries])] ) AC_PATH_PROGS(SQLITE3, sqlite3, no) if test "$SQLITE3" = "no"; then AC_MSG_WARN([Unable to find sqlite3 in path for SQLite3 support]) else AC_MSG_CHECKING([sqlite3 version]) sqlite3_version=`$SQLITE3 -version | awk '{print $1}'` AC_MSG_RESULT([$sqlite3_version]) fi fi ],[ AC_MSG_RESULT(disabled) ]) dnl Implement the --with-oracle option. This will set HAVE_ORACLE in gw-config.h dnl accordingly and enable the usage of the OCI routines. AC_MSG_CHECKING([whether to compile with Oracle support]) AC_ARG_WITH(oracle, [ --with-oracle enable ORACLE storage @<:@disabled@:>@], [ if test "$withval" != yes ; then AC_MSG_RESULT(disabled) else AC_MSG_RESULT(searching) AC_ARG_WITH( oracle-includes, [ --with-oracle-includes=DIR adds oracle include paths], [ ORACLE_INCLUDE_PATH="$withval" ], [ ORACLE_INCLUDE_PATH="$ORACLE_HOME/rdbms/demo $ORACLE_HOME/rdbms/public" ] ) for a in $ORACLE_INCLUDE_PATH do CPPFLAGS="$CPPFLAGS -I$a" done AC_MSG_CHECKING([for oci.h ]) AC_TRY_CPP([#include <oci.h>],AC_MSG_RESULT(yes), AC_MSG_ERROR([oci.h not found])) CFLAGS="$CFLAGS $CPPFLAGS" AC_ARG_WITH( oracle-libs, [ --with-oracle-libs=DIR adds oracle library path], [ ORACLE_LIB_PATH="$withval" ], [ ORACLE_LIB_PATH="$ORACLE_HOME/lib" ] ) for a in $ORACLE_LIB_PATH do LIBS="$LIBS -L$a" done dnl Check for Oracle 10g instant client AC_CHECK_LIB(clntsh,OCIEnvCreate,[ LIBS="$LIBS -lclntsh" ], AC_CHECK_LIB(clntsh,OCIEnvCreate,[ LIBS="$LIBS -lclntsh -lnnz10" ],exit) ) dnl Beware that Oracle 10g doesn't use anymore the libwtcX.so libs, dnl so we don't break hard in case they are not present. AC_CHECK_LIB(wtc8,wtcstu,[ LIBS="$LIBS -lwtc8" ], AC_CHECK_LIB(wtc9,wtcstu,[ LIBS="$LIBS -lwtc9" ], true) ) AC_CHECK_FUNC(OCIPing, [AC_DEFINE(HAVE_OCIPING, 1, [Do we have OCIPing])]) AC_DEFINE(HAVE_ORACLE, 1, [Do we have Oracle]) AC_MSG_CHECKING([whether to compile with Oracle support]) AC_MSG_RESULT(yes) fi ], [AC_MSG_RESULT(disabled)]) dnl Implement the --with-pgsql option. This will set HAVE_PGSQL in gw-config.h dnl accordingly and enable the usage of the libpq routines. AC_MSG_CHECKING([whether to compile with PostgresSQL support]) AC_ARG_WITH(pgsql, [ --with-pgsql enable PostgreSQL storage @<:@disabled@:>@], [ if test "$withval" != yes ; then AC_MSG_RESULT(disabled) else dnl Implement the --with-pgsql-dir option. AC_ARG_WITH(pgsql-dir, [ --with-pgsql-dir=DIR where to look for PostgreSQL libs and header files DIR points to the installation @<:@/usr/local/pgsql@:>@], [ pgsqlloc="" if test -d "$withval" ; then pgsqlloc="$withval" fi ]) AC_MSG_RESULT(searching) AC_PATH_PROG(PGSQL_CONFIG, pg_config, no, [$PATH:$pgsqlloc/bin:$pgsqlloc:/usr/lib/postgresql/bin]) dnl check for PgSQL >= 7.2 style pg_config information if test "$PGSQL_CONFIG" = "no"; then found="" for loc in $pgsqlloc /usr /usr/local ; do if test "x$found" = "x" ; then AC_MSG_CHECKING([for PostgresSQL include files in]) AC_MSG_RESULT($loc) AC_CHECK_FILE("$loc/include/postgresql/libpq-fe.h", [CFLAGS="$CFLAGS -I$loc/include/postgresql"; LIBS="$LIBS -L$loc/lib/postgresql -lpq"]; found=1, [AC_CHECK_FILE("$loc/include/pgsql/libpq-fe.h", [CFLAGS="$CFLAGS -I$loc/include/pgsql"; LIBS="$LIBS -L$loc/lib/pgsql -lpq"]; found=1, [AC_CHECK_FILE("$loc/pgsql/include/libpq-fe.h", [CFLAGS="$CFLAGS -I$loc/pgsql/include"; LIBS="$LIBS -L$loc/pgsql/lib -lpq"]; found=1, )] )]) fi done if test "x$found" != "x1" ; then AC_MSG_ERROR([Unable to find libpq-fe.h, please provide a --with-pgsql-dir=<dir> location]) fi else dnl pg_config found AC_MSG_CHECKING([PostgreSQL version]) pgsql_version=`$PGSQL_CONFIG --version | awk '{print $2}'` AC_MSG_RESULT([$pgsql_version]) AC_MSG_CHECKING([PostgreSQL libdir]) if $PGSQL_CONFIG --libdir &>/dev/null ; then LIBS="$LIBS -L`$PGSQL_CONFIG --libdir`" pg_libdir=`$PGSQL_CONFIG --libdir` AC_MSG_RESULT([$pg_libdir]) fi AC_MSG_CHECKING([PostgreSQL includes]) if $PGSQL_CONFIG --includedir &>/dev/null ; then CFLAGS="$CFLAGS -I`$PGSQL_CONFIG --includedir`" CPPFLAGS="$CPPFLAGS -I`$PGSQL_CONFIG --includedir`" pg_incdir=`$PGSQL_CONFIG --includedir` AC_MSG_RESULT([$pg_incdir]) fi fi AC_CHECK_HEADERS(libpq-fe.h) AC_CHECK_LIB(pq, PQconnectdb, []) AC_DEFINE(HAVE_PGSQL) AC_MSG_CHECKING([whether to compile with PostgreSQL support]) AC_MSG_RESULT(yes) PGSQL="yes" fi ],[ AC_MSG_RESULT(disabled) ]) dnl Implement the --with-redis option. This will set HAVE_REDIS in gw-config.h dnl accordingly and enable the usage of the hiredis routines. AC_MSG_CHECKING([whether to compile with Redis support]) AC_ARG_WITH(redis, [ --with-redis enable Redis storage @<:@disabled@:>@], [ if test "$withval" != yes ; then AC_MSG_RESULT(disabled) else dnl Implement the --with-redis-dir option. AC_ARG_WITH(redis-dir, [ --with-redis-dir=DIR where to look for Redis libs and header files DIR points to the installation @<:@/usr/local/redis@:>@], [ redisloc="" if test -d "$withval" ; then redisloc="$withval" fi ]) AC_MSG_RESULT(searching) AC_PATH_PROG(REDIS_CONFIG, redis_config, no, [$PATH:$redisloc/bin:$redisloc]) if test "$REDIS_CONFIG" = "no"; then found="" for loc in $redisloc /usr /usr/local ; do if test "x$found" = "x" ; then AC_MSG_CHECKING([for Redis include files in]) AC_MSG_RESULT($loc) AC_CHECK_FILE("$loc/hiredis.h", [CFLAGS="$CFLAGS -I$loc"; LIBS="$LIBS -L$loc -lhiredis"]; found=1, [AC_CHECK_FILE("$loc/include/hiredis/hiredis.h", [CFLAGS="$CFLAGS -I$loc/include/hiredis"; LIBS="$LIBS -L$loc/lib -lhiredis"]; found=1 )] ) fi done if test "x$found" != "x1" ; then AC_MSG_ERROR([Unable to find hiredis.h, please provide a --with-redis-dir=<dir> location]) fi else dnl redis_config found REDIS_LIBS="" if test -z "$REDIS_LIBS" ; then REDIS_LIBS=`$REDIS_CONFIG --libs` AC_MSG_CHECKING([redis libs]) AC_MSG_RESULT([$REDIS_LIBS]) AC_CHECK_LIB(hiredis, [ LIBS="$LIBS $REDIS_LIBS" ], [AC_MSG_ERROR([Unable to find Redis client libraries])], [ $REDIS_LIBS ]) fi AC_MSG_CHECKING([redis includes]) if $REDIS_CONFIG --include &>/dev/null ; then REDIS_CFLAGS=`$REDIS_CONFIG --include` else REDIS_CFLAGS=`$REDIS_CONFIG --cflags` fi CFLAGS="$CFLAGS $REDIS_CFLAGS" AC_MSG_RESULT([$REDIS_CFLAGS]) fi AC_CHECK_HEADERS(hiredis/hiredis.h) AC_DEFINE(HAVE_REDIS) AC_MSG_CHECKING([whether to compile with Redis support]) AC_MSG_RESULT(yes) REDIS="yes" fi ],[ AC_MSG_RESULT(disabled) ]) dnl Checking for FreeTDS Ct-Lib support AC_MSG_CHECKING([whether to compile with FreeTDS Ct-Lib support]) AC_ARG_WITH(mssql, [ --with-mssql[=DIR] enable FreeTDS Ct-Lib storage support @<:@disabled@:>@ DIR points to the installation @<:@/usr/local@:>@], [ if test "$withval" = "yes"; then withval=/usr/local fi if test "$withval" != "no"; then if test -f $withval/include/ctpublic.h; then MSSQL_INCDIR=$withval/include MSSQL_LIBDIR=$withval/lib else if test -f $withval/include/freetds/ctpublic.h; then MSSQL_INCDIR=$withval/include/freetds MSSQL_LIBDIR=$withval/lib else AC_MSG_RESULT(no) AC_MSG_ERROR(Invalid FreeTDS directory - unable to find ctpublic.h) fi fi LIBS="$LIBS -L$MSSQL_LIBDIR -lct" CFLAGS="$CFLAGS -I$MSSQL_INCDIR" AC_DEFINE(HAVE_MSSQL, 1, [Defined to 1]) AC_MSG_RESULT(yes) MSSQL="yes" dnl AC_CHECK_FUNC(dlopen, , AC_CHECK_LIB(dl, dlopen, MSSQL_LFLAGS="$MSSQL_LFLAGS -ldl")) fi ],[ AC_MSG_RESULT(disabled) ]) dnl Implement the --with-cassandra option. This will set HAVE_CASS in gw-config.h AC_MSG_CHECKING([whether to compile with Cassandra support]) AC_ARG_WITH(cassandra, [ --with-cassandra enable Cassandra storage @<:@disabled@:>@], [ if test "$withval" != yes ; then AC_MSG_RESULT(disabled) else dnl Implement the --with-cassandra-dir option. AC_ARG_WITH(cassandra-dir, [ --with-cassandra-dir=DIR where to look for Cassandra libs and header files DIR points to the installation @<:@/usr/local@:>@], [ cassloc="" if test -d "$withval" ; then cassloc="$withval" fi ]) AC_MSG_RESULT(searching) found="" for loc in $cassloc /usr /usr/local ; do if test "x$found" = "x" ; then AC_MSG_CHECKING([for Cassandra include files in]) AC_MSG_RESULT($loc) AC_CHECK_FILE("$loc/include/cassandra.h", [CFLAGS="$CFLAGS -I$loc/include"; LIBS="$LIBS -L$loc/lib -lcassandra"]; found=1 ) fi done if test "x$found" != "x1" ; then AC_MSG_ERROR([Unable to find cassandra.h, please provide a --with-cassandra-dir=<dir> location]) fi AC_CHECK_HEADERS(cassandra.h) AC_DEFINE(HAVE_CASS) AC_MSG_CHECKING([whether to compile with Cassandra support]) AC_MSG_RESULT(yes) CASS="yes" fi ],[ AC_MSG_RESULT(disabled) ]) dnl Implement the --with-wtls option. dnl Check to see if we should include WTLS support, and which library to use. AC_ARG_WITH(wtls, [ --with-wtls@<:@=TYPE@:>@ select WTLS version to use: @<:@openssl|baltimore@:>@], [ AC_CONFIG_SECTION([Configuring WTLS support]) AC_MSG_CHECKING([for WTLS library]) AC_MSG_RESULT($withval) case "$withval" in openssl) AC_CHECK_LIB(crypto, RSA_new, [ AC_CHECK_HEADERS(openssl/objects.h openssl/rc5.h, AC_DEFINE(HAVE_WTLS_OPENSSL), AC_MSG_WARN(OpenSSL installation seems to lack RC5 algorithm!) ) ]) ;; baltimore) AC_MSG_ERROR(This WTLS library is yet not supported!) ;; *) AC_MSG_ERROR(Unknown WTLS libary support!) exit 1 ;; esac ]) AC_CONFIG_SECTION([Configuring for gSOAP support]) AC_MSG_CHECKING([whether to compile with SOAP support]) AC_ARG_WITH(gsoap, [ --with-gsoap@<:@=DIR@:>@ enable gSOAP web services SMSC module support @<:@disabled@:>@ DIR points to the gSOAP share directory @<:@/usr/share/gsoap@:>@], [ if test "x$withval" = "xyes"; then for loc in /usr/share/gsoap /usr/local/share/gsoap; do if test -d "$loc/import" && test -d "$loc/plugin"; then GSOAP_SHARE=$loc AC_MSG_RESULT($GSOAP_SHARE) fi done if test "x$GSOAP_SHARE" = "x"; then AC_MSG_RESULT(not found) AC_MSG_ERROR(Unable to find gSOAP's import and/or plugin directory) fi else if test -d "$withval/import" && test -d "$withval/plugin"; then GSOAP_SHARE="$withval" AC_MSG_RESULT($withval) else AC_MSG_RESULT(not found) AC_MSG_ERROR(Unable to find gSOAP's import at $withval/import and/or plugin at $withval/plugin) fi fi gsoap_ver_required="2.8.4" AC_PATH_PROGS(WSDL2H, wsdl2h, no) if test "$WSDL2H" = "no"; then AC_MSG_ERROR([Unable to find gSOAP's wsdl2h in path for SOAP support]) fi AC_PATH_PROGS(SOAPCPP, soapcpp2, no) if test "$SOAPCPP" = "no"; then AC_MSG_ERROR([Unable to find gSOAP's soapcpp2 in path for SOAP support]) fi AC_MSG_CHECKING([gSOAP version]) gsoap_version=`$SOAPCPP -v &> /tmp/gsoap.tmp && cat /tmp/gsoap.tmp | grep "C and C++" | awk '{print $NF}'` AC_MSG_RESULT([$gsoap_version]) gsoap_version_str=`echo $gsoap_version | grep -e "^[[0-9]]*\.[[0-9]]*\.[[0-9]]*$"` if test "$gsoap_version_str" = ""; then AC_MSG_WARN([gSOAP version $gsoap_version contains alphanumeric characters. Version MAYBE too old!]) else AC_CHECK_VERSION($gsoap_version, $gsoap_ver_required, [], [ AC_MSG_ERROR([gSOAP version $gsoap_version is too old. You MUST have at least $gsoap_ver_required]) ]) fi SOAP_INCLUDE="include soap/Makefile" AC_DEFINE(HAVE_GSOAP) AC_SUBST(WSDL2H) AC_SUBST(SOAPCPP) AC_SUBST(SOAP_INCLUDE) AC_SUBST(GSOAP_SHARE) ],[ AC_MSG_RESULT(disabled) ]) dnl Final Output AC_CONFIG_SECTION([Generating output files]) AC_OUTPUT([ gwlib/gw_uuid_types.h Makefile soap/Makefile utils/Makefile ]) dnl LICENSE notice AC_CONFIG_SECTION([License information]) cat <<X +--------------------------------------------------------------------+ | License: | | This software is subject to the Kannel Software License, available | | in this distribution in the file LICENSE. By continuing this | | installation process, you are bound by the terms of this license | | agreement. If you do not agree with the terms of this license, you | | must abort the installation process at this point. | | | | The Kannel Group <http://www.kannel.org/> | +--------------------------------------------------------------------+ Thank you for using Kannel. X �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/radius/�������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13312227713�013154� 5����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/radius/radius_pdu.c�������������������������������������������������������������������0000644�0001750�0001750�00000042252�13227613126�015466� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * radius_pdu.c - parse and generate RADIUS Accounting PDUs * * Taken from gw/smsc/smpp_pdu.c writen by Lars Wirzenius. * This makes heavy use of C pre-processor macro magic. * * References: RFC2866 - RADIUS Accounting * * Stipe Tolj <stolj@wapme.de> */ #include <string.h> #include "radius_pdu.h" #define MIN_RADIUS_PDU_LEN 20 #define MAX_RADIUS_PDU_LEN 4095 static unsigned long decode_integer(Octstr *os, long pos, int octets) { unsigned long u; int i; gw_assert(octstr_len(os) >= pos + octets); u = 0; for (i = 0; i < octets; ++i) u = (u << 8) | octstr_get_char(os, pos + i); return u; } static void append_encoded_integer(Octstr *os, unsigned long u, long octets) { long i; for (i = 0; i < octets; ++i) octstr_append_char(os, (u >> ((octets - i - 1) * 8)) & 0xFF); } /* static void *get_header_element(RADIUS_PDU *pdu, unsigned char *e) { switch (pdu->type) { #define INTEGER(name, octets) \ if (strcmp(#name, e) == 0) return (void*) *(&p->name); #define NULTERMINATED(name, max_octets) #define OCTETS(name, field_giving_octets) \ if (strcmp(#name, e) == 0) return (void*) p->name; #define PDU(name, id, fields) \ case id: { \ struct name *p = &pdu->u.name; \ } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error."); gw_free(pdu); return NULL; } } */ RADIUS_PDU *radius_pdu_create(int type, RADIUS_PDU *req) { RADIUS_PDU *pdu; pdu = gw_malloc(sizeof(*pdu)); pdu->type = type; switch (type) { #define INTEGER(name, octets) \ if (strcmp(#name, "code") == 0) p->name = type; \ else p->name = 0; #define OCTETS(name, field_giving_octets) p->name = NULL; #define PDU(name, id, fields) \ case id: { \ struct name *p = &pdu->u.name; \ pdu->type_name = #name; \ fields \ } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error."); gw_free(pdu); return NULL; } #define ATTR(attr, type, string, min, max) #define UNASSIGNED(attr) #define ATTRIBUTES(fields) \ pdu->attr = dict_create(20, (void (*)(void *))octstr_destroy); #include "radius_attributes.def" return pdu; } void radius_pdu_destroy(RADIUS_PDU *pdu) { if (pdu == NULL) return; switch (pdu->type) { #define INTEGER(name, octets) p->name = 0; #define OCTETS(name, field_giving_octets) octstr_destroy(p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error while destroying."); } #define ATTR(attr, type, string, min, max) #define UNASSIGNED(attr) #define ATTRIBUTES(fields) dict_destroy(pdu->attr); #include "radius_attributes.def" gw_free(pdu); } /* static void radius_type_append(Octstr **os, int type, int pmin, int pmax, Octstr *value) { long l; switch (type) { case t_int: octstr_parse_long(&l, value, 0, 10); append_encoded_integer(*os, l, pmin); break; case t_string: octstr_append(*os, value); break; case t_ipaddr: ret = octstr_create(""); for (i = 0; i < 4; i++) { int c = octstr_get_char(value, i); Octstr *b = octstr_format("%d", c); octstr_append(ret, b); i < 3 ? octstr_append_cstr(ret, ".") : NULL; octstr_destroy(b); } break; default: panic(0, "RADIUS: Attribute type %d does not exist.", type); break; } } */ static Octstr *radius_attr_pack(RADIUS_PDU *pdu) { Octstr *os; os = octstr_create(""); gw_assert(pdu != NULL); #define ATTR(atype, type, string, pmin, pmax) \ { \ Octstr *attr_strg = octstr_create(string); \ Octstr *attr_val = dict_get(p->attr, attr_str); \ if (attr_str != NULL) { \ int attr_len = octstr_len(attr_val) + 2; \ octstr_format_append(os, "%02X", atype); \ octstr_append_data(os, (char*) &attr_len, 2); \ radius_type_append(&os, type, pmin, pmax, attr_val); \ } \ octstr_destroy(attr_str); \ } #define UNASSIGNED(attr) #define ATTRIBUTES(fields) #include "radius_attributes.def" return os; } Octstr *radius_pdu_pack(RADIUS_PDU *pdu) { Octstr *os,*oos; Octstr *temp; os = octstr_create(""); gw_assert(pdu != NULL); /* switch (pdu->type) { #define INTEGER(name, octets) p = *(&p); #define NULTERMINATED(name, max_octets) p = *(&p); #define OCTETS(name, field_giving_octets) \ p->field_giving_octets = octstr_len(p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error while packing."); } */ switch (pdu->type) { #define INTEGER(name, octets) \ append_encoded_integer(os, p->name, octets); #define OCTETS(name, field_giving_octets) \ octstr_append(os, p->name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields; oos = radius_attr_pack(pdu); \ octstr_append(os, oos);octstr_destroy(oos); } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error while packing."); } /* now set PDU length */ temp = octstr_create(""); append_encoded_integer(temp, octstr_len(os), 2); octstr_delete(os, 2, 2); octstr_insert(os, temp, 2); octstr_destroy(temp); return os; } static Octstr *radius_type_convert(int type, Octstr *value) { Octstr *ret = NULL; int i; switch (type) { case t_int: ret = octstr_format("%ld", decode_integer(value, 0, 4)); break; case t_string: ret = octstr_format("%s", octstr_get_cstr(value)); break; case t_ipaddr: ret = octstr_create(""); for (i = 0; i < 4; i++) { int c = octstr_get_char(value, i); Octstr *b = octstr_format("%d", c); octstr_append(ret, b); if (i < 3) octstr_append_cstr(ret, "."); octstr_destroy(b); } break; default: panic(0, "RADIUS: Attribute type %d does not exist.", type); break; } return ret; } static void radius_attr_unpack(ParseContext **context, RADIUS_PDU **pdu) { #define ATTR(atype, type, string, pmin, pmax) \ if (atype == attr_type) { \ Octstr *tmp, *value; \ if ((attr_len-2) < pmin || (attr_len-2) > pmax) { \ error(0, "RADIUS: Attribute (%d) `%s' has invalid len %d, droppped.", \ attr_type, string, (attr_len-2)); \ continue; \ } \ attr_val = parse_get_octets(*context, attr_len - 2); \ tmp = octstr_format("RADIUS: Attribute (%d) `%s', len %d", \ attr_type, string, attr_len - 2); \ value = radius_type_convert(type, attr_val); \ octstr_destroy(attr_val); \ octstr_dump_short(value, 0, octstr_get_cstr(tmp)); \ octstr_destroy(tmp); \ attr_str = octstr_create(string); \ dict_put((*pdu)->attr, attr_str, value); \ octstr_destroy(attr_str); \ value = NULL; \ } else #define UNASSIGNED(attr) \ if (attr == attr_type) { \ error(0, "RADIUS: Attribute (%d) is unassigned and should not be used.", \ attr_type); \ continue; \ } else #define ATTRIBUTES(fields) \ while (parse_octets_left(*context) > 0 && !parse_error(*context)) { \ int attr_type, attr_len; \ Octstr *attr_val = NULL; \ Octstr *attr_str = NULL; \ attr_type = parse_get_char(*context); \ attr_len = parse_get_char(*context); \ fields \ { \ debug("radius.unpack", 0, "RADIUS: Unknown attribute type (0x%03lx) " \ "len %d in PDU `%s'.", \ (long unsigned int)attr_type, attr_len, (*pdu)->type_name); \ parse_skip(*context, attr_len - 2); \ } \ } #include "radius_attributes.def" } RADIUS_PDU *radius_pdu_unpack(Octstr *data_without_len) { RADIUS_PDU *pdu; int type; long len, pos; ParseContext *context; Octstr *authenticator; len = octstr_len(data_without_len); if (len < 20) { error(0, "RADIUS: PDU was too short (%ld bytes).", octstr_len(data_without_len)); return NULL; } context = parse_context_create(data_without_len); type = parse_get_char(context); parse_get_char(context); pdu = radius_pdu_create(type, NULL); if (pdu == NULL) return NULL; len = decode_integer(data_without_len, 2, 2) - 19; parse_skip(context, 2); debug("radius", 0, "RADIUS: Attributes len is %ld", len); authenticator = parse_get_octets(context, 16); octstr_dump_short(authenticator, 0, "RADIUS: Authenticator (md5) is:"); /* skipping back to context start for macro magic */ parse_context_destroy(context); context = parse_context_create(data_without_len); switch (type) { #define INTEGER(name, octets) \ pos = octstr_len(data_without_len) - parse_octets_left(context); \ p->name = decode_integer(data_without_len, pos, octets); \ parse_skip(context, octets); #define OCTETS(name, field_giving_octets) \ p->name = parse_get_octets(context, field_giving_octets); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields; \ radius_attr_unpack(&context, &pdu); } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error while unpacking."); } parse_context_destroy(context); octstr_destroy(authenticator); return pdu; } int radius_authenticate_pdu(RADIUS_PDU *pdu, Octstr **data, Octstr *secret) { int rc = 0; Octstr *stream; Octstr *attributes; Octstr *digest; stream = attributes = digest = NULL; /* first extract attributes from raw data, where * the first 20 octets are code, idendifier, length * and authenticator value as described in RFC2866, sec. 3 */ if (octstr_len(*data) > 20) attributes = octstr_copy(*data, 20, octstr_len(*data)-20); switch (pdu->type) { case 0x04: /* Accounting-Request, see RFC2866, page 6 */ stream = octstr_copy(*data, 0, 4); octstr_append_data(stream, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16); octstr_append(stream, attributes); octstr_append(stream, secret); digest = md5(stream); rc = octstr_compare(pdu->u.Accounting_Request.authenticator, digest) == 0 ? 1 : 0; break; case 0x05: /* Accounting-Response, create Response authenticator */ stream = octstr_duplicate(*data); octstr_append(stream, secret); digest = md5(stream); octstr_delete(*data, 4, 16); octstr_insert(*data, digest, 4); break; default: break; } octstr_destroy(attributes); octstr_destroy(stream); octstr_destroy(digest); return rc; } static void radius_attr_dump(RADIUS_PDU *pdu) { #define UNASSIGNED(attr) #define ATTR(atype, type, string, pmin, pmax) \ id = atype; \ key = octstr_create(string); \ val = dict_get(pdu->attr, key); \ if (val != NULL) \ octstr_dump_short(val, 2, #atype); \ octstr_destroy(key); #define ATTRIBUTES(fields) \ if (pdu->attr != NULL) { \ Octstr *key = NULL, *val = NULL; \ int id; \ fields \ } #include "radius_attributes.def" } void radius_pdu_dump(RADIUS_PDU *pdu) { debug("radius", 0, "RADIUS PDU %p dump:", (void *) pdu); debug("radius", 0, " type_name: %s", pdu->type_name); switch (pdu->type) { #define INTEGER(name, octets) \ debug("radius", 0, " %s: %lu = 0x%08lx", #name, p->name, p->name); #define OCTETS(name, field_giving_octets) \ octstr_dump_short(p->name, 2, #name); #define PDU(name, id, fields) \ case id: { struct name *p = &pdu->u.name; fields; \ radius_attr_dump(pdu); } break; #include "radius_pdu.def" default: error(0, "Unknown RADIUS_PDU type, internal error."); break; } debug("radius", 0, "RADIUS PDU dump ends."); } Octstr *radius_get_attribute(RADIUS_PDU *pdu, Octstr *attribute) { gw_assert(pdu != NULL); if (pdu->attr == NULL) return NULL; return dict_get(pdu->attr, attribute); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/radius/radius_pdu.def�����������������������������������������������������������������0000644�0001750�0001750�00000010600�13227613126�015772� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * radius_pdu.def - definitions of RADIUS Accounting PDU structure * * We implement a RADIUS accounting proxy to overcome the gap in the WAP * stack that no MSISDN numbers are transported. Basically this is needed * to map client IPs of the remote WAP/MMS clients to their MSISDN for various * purposes. Ie. for WAP application a special HTTP header is added to identify * the WAP client via it's MSISDN and to allow personalization of mobile content. * For Kannel's MMSC we need mapping of client IP to MSISDN numbers to replace * MMS "From:" header to the originator MSISDN. * * References: * RFC2865 "Remote Authentication Dial In User Service (RADIUS)" * RFC2866 "RADIUS Accounting" * * Stipe Tolj <stolj@wapme.de> */ #ifndef PDU #error Macro PDU not defined. #endif #ifndef INTEGER #error Macro INTEGER not defined. #endif #ifndef OCTETS #error Macro OCTETS not defined. #endif /* * All RADIUS PDUs have a common header consisting of 20 octets: * * Code: 1 octet (identifies PDU type) * Identifier: 1 octet (sort of sequence number) * Length: 2 octets (full length of the PDU) * Authenticator: 16 octets containing the MD5 hash * * (see RFC2866, page 5) */ #ifdef HEADER #error Macro HEADER was already defined. #endif #define HEADER \ INTEGER(code, 1) \ INTEGER(identifier, 1) \ INTEGER(length, 2) \ OCTETS(authenticator, 16) /* * Note: Remember that we only add attibutes that interest us for our RADIUS * accounting proxy. If you need more, then add them to the corresponding PDUs. */ PDU(Accounting_Request, 0x04, HEADER ) PDU(Accounting_Response, 0x05, HEADER ) #undef PDU #undef INTEGER #undef OCTETS #undef HEADER ��������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/radius/radius_pdu.h�������������������������������������������������������������������0000644�0001750�0001750�00000010513�13227613126�015466� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * radius_pdu.h - declarations for RADIUS Accounting PDUs * * Stipe Tolj <stolj@wapme.de> */ #ifndef RADIUS_PDU_H #define RADIUS_PDU_H #include "gwlib/gwlib.h" #include "gwlib/dict.h" /* attribute types */ enum { t_int, t_string, t_ipaddr }; enum { #define ATTR(attr, type, string, min, max) #define UNASSIGNED(attr) #define ATTRIBUTES(fields) #include "radius_attributes.def" #define INTEGER(name, octets) #define OCTETS(name, field_giving_octets) #define PDU(name, id, fields) name = id, #include "radius_pdu.def" RADIUS_PDU_DUMMY_TYPE }; typedef struct RADIUS_PDU RADIUS_PDU; struct RADIUS_PDU { int type; const char *type_name; Dict *attr; union { #define ATTR(attr, type, string, min, max) #define UNASSIGNED(attr) #define ATTRIBUTES(fields) #include "radius_attributes.def" #define INTEGER(name, octets) unsigned long name; #define NULTERMINATED(name, max_octets) Octstr *name; #define OCTETS(name, field_giving_octets) Octstr *name; #define PDU(name, id, fields) struct name { fields } name; #include "radius_pdu.def" } u; }; RADIUS_PDU *radius_pdu_create(int type, RADIUS_PDU *req); void radius_pdu_destroy(RADIUS_PDU *pdu); int radius_authenticate_pdu(RADIUS_PDU *pdu, Octstr **data, Octstr *secret); Octstr *radius_pdu_pack(RADIUS_PDU *pdu); RADIUS_PDU *radius_pdu_unpack(Octstr *data_without_len); void radius_pdu_dump(RADIUS_PDU *pdu); /* * Returns the value of an RADIUS attribute inside a PDU as Octstr. * If the attribute was not present in the PDU, it returns NULL. */ Octstr *radius_get_attribute(RADIUS_PDU *pdu, Octstr *attribute); #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/radius/radius_acct.h������������������������������������������������������������������0000644�0001750�0001750�00000006607�13227613126�015621� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * radius_acct.h - RADIUS accounting proxy thread declarations * * Stipe Tolj <stolj@wapme.de> */ #ifndef RADIUS_ACCT_H #define RADIUS_ACCT_H /* * Start the RADIUS accounting proxy accoding to the given configuration * group provided by the caller. */ void radius_acct_init(CfgGroup *grp); /* * Stop the RADIUS accounting proxy and destroy all depended structures * and hash tables. */ void radius_acct_shutdown(void); /* * Provides the mapping from client IP to client MSISDN from inside the * RADIUS accounting mapping tables. If the client IP is not found or NULL * has been given as argument, returns NULL. */ Octstr *radius_acct_get_msisdn(Octstr *client_ip); #endif �������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/radius/radius_acct.c������������������������������������������������������������������0000644�0001750�0001750�00000041177�13227613126�015615� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * radius_acct.c - RADIUS accounting proxy thread * * Stipe Tolj <stolj@kannel.org> */ #include <string.h> #include <fcntl.h> #include <errno.h> #include "gwlib/gwlib.h" #include "radius/radius_acct.h" #include "radius/radius_pdu.h" static Dict *radius_table = NULL; /* maps client ip -> msisdn */ static Dict *session_table = NULL; /* maps session id -> client ip */ static Dict *client_table = NULL; /* maps client ip -> session id */ /* we will initialize hash tables in the size of our NAS ports */ #define RADIUS_NAS_PORTS 30 static Mutex *radius_mutex = NULL; static int run_thread = 0; /* * Beware that the official UDP port for RADIUS accounting packets * is 1813 (according to RFC2866). The previously used port 1646 has * been conflicting with an other protocol and "should" not be used. */ static Octstr *our_host = NULL; static long our_port = 1813; static Octstr *remote_host = NULL; static long remote_port = 1813; /* the shared secrets for NAS and remote RADIUS communication */ static Octstr *secret_nas = NULL; static Octstr *secret_radius = NULL; /* the global unified-prefix list */ static Octstr *unified_prefix = NULL; /* timeout in msec for the remote RADIUS responses */ static long remote_timeout = 40000; /************************************************************************* * */ /* * Updates the internal RADIUS mapping tables. Returns 1 if the * mapping has been processes and the PDU should be proxied to the * remote RADIUS server, otherwise if it is a duplicate returns 0. */ static int update_tables(RADIUS_PDU *pdu) { Octstr *client_ip, *msisdn; Octstr *type, *session_id; int ret = 0; Octstr *rm_item; client_ip = msisdn = type = session_id = NULL; /* only add if we have a Accounting-Request PDU */ if (pdu->type == 0x04) { /* check if we have a START or STOP event */ type = dict_get(pdu->attr, octstr_imm("Acct-Status-Type")); /* get the sesion id */ session_id = dict_get(pdu->attr, octstr_imm("Acct-Session-Id")); /* grep the needed data */ client_ip = dict_get(pdu->attr, octstr_imm("Framed-IP-Address")); msisdn = dict_get(pdu->attr, octstr_imm("Calling-Station-Id")); /* we can't add mapping without both components */ if (client_ip == NULL || msisdn == NULL) { warning(0, "RADIUS: NAS did either not send 'Framed-IP-Address' or/and " "'Calling-Station-Id', dropping mapping but will forward."); /* anyway forward the packet to remote RADIUS server */ return 1; } if (octstr_compare(type, octstr_imm("1")) == 0 && session_id && msisdn) { /* session START */ if (dict_get(radius_table, client_ip) == NULL && dict_get(session_table, session_id) == NULL) { Octstr *put_msisdn = octstr_duplicate(msisdn); Octstr *put_client_ip = octstr_duplicate(client_ip); Octstr *put_session_id = octstr_duplicate(session_id); Octstr *old_session_id, *old_client_ip; /* ok, this is a new session. If it contains an IP that is still * in the session/client tables then remove the old session from the * two tables session/client */ if ((old_session_id = dict_get(client_table, client_ip)) != NULL && (old_client_ip = dict_get(session_table, old_session_id)) != NULL && octstr_compare(old_session_id, session_id) != 0) { rm_item = dict_remove(client_table, client_ip); octstr_destroy(rm_item); rm_item = dict_remove(session_table, old_session_id); octstr_destroy(rm_item); octstr_destroy(old_session_id); octstr_destroy(old_client_ip); } /* insert both, new client IP and session to mapping tables */ dict_put(radius_table, client_ip, put_msisdn); dict_put(session_table, session_id, put_client_ip); dict_put(client_table, client_ip, put_session_id); info(0, "RADIUS: Mapping `%s <-> %s' for session id <%s> added.", octstr_get_cstr(client_ip), octstr_get_cstr(msisdn), octstr_get_cstr(session_id)); ret = 1; } else { warning(0, "RADIUS: Duplicate mapping `%s <-> %s' for session " "id <%s> received, ignoring.", octstr_get_cstr(client_ip), octstr_get_cstr(msisdn), octstr_get_cstr(session_id)); } } else if (octstr_compare(type, octstr_imm("2")) == 0) { /* session STOP */ Octstr *comp_client_ip; if ((msisdn = dict_get(radius_table, client_ip)) != NULL && (comp_client_ip = dict_get(session_table, session_id)) != NULL && octstr_compare(client_ip, comp_client_ip) == 0) { dict_remove(radius_table, client_ip); rm_item = dict_remove(client_table, client_ip); octstr_destroy(rm_item); dict_remove(session_table, session_id); info(0, "RADIUS: Mapping `%s <-> %s' for session id <%s> removed.", octstr_get_cstr(client_ip), octstr_get_cstr(msisdn), octstr_get_cstr(session_id)); octstr_destroy(msisdn); octstr_destroy(comp_client_ip); ret = 1; } else { warning(0, "RADIUS: Could not find mapping for `%s' session " "id <%s>, ignoring.", octstr_get_cstr(client_ip), octstr_get_cstr(session_id)); } } else { error(0, "RADIUS: unknown Acct-Status-Type `%s' received, ignoring.", octstr_get_cstr(type)); } } return ret; } /************************************************************************* * The main proxy thread. */ static void proxy_thread(void *arg) { int ss, cs; /* server and client sockets */ int fl; /* socket flags */ Octstr *addr = NULL; int forward; Octstr *tmp; run_thread = 1; ss = cs = -1; /* create client binding, only if we have a remote server * and make the client socet non-blocking */ if (remote_host != NULL) { cs = udp_client_socket(); fl = fcntl(cs, F_GETFL); fcntl(cs, F_SETFL, fl | O_NONBLOCK); addr = udp_create_address(remote_host, remote_port); } /* create server binding */ ss = udp_bind(our_port, octstr_get_cstr(our_host)); /* make the server socket non-blocking */ fl = fcntl(ss, F_GETFL); fcntl(ss, F_SETFL, fl | O_NONBLOCK); if (ss == -1) panic(0, "RADIUS: Couldn't set up server socket for port %ld.", our_port); while (run_thread) { RADIUS_PDU *pdu, *r; Octstr *data, *rdata; Octstr *from_nas, *from_radius; pdu = r = NULL; data = rdata = from_nas = from_radius = NULL; if (read_available(ss, 100000) < 1) continue; /* get request from NAS */ if (udp_recvfrom(ss, &data, &from_nas) == -1) { if (errno == EAGAIN) /* No datagram available, don't block. */ continue; error(0, "RADIUS: Couldn't receive request data from NAS"); continue; } tmp = udp_get_ip(from_nas); info(0, "RADIUS: Got data from NAS <%s:%d>", octstr_get_cstr(tmp), udp_get_port(from_nas)); octstr_destroy(tmp); octstr_dump(data, 0); /* unpacking the RADIUS PDU */ if ((pdu = radius_pdu_unpack(data)) == NULL) { warning(0, "RADIUS: Couldn't unpack PDU from NAS, ignoring."); goto error; } info(0, "RADIUS: from NAS: PDU type: %s", pdu->type_name); /* authenticate the Accounting-Request packet */ if (radius_authenticate_pdu(pdu, &data, secret_nas) == 0) { warning(0, "RADIUS: Authentication failed for PDU from NAS, ignoring."); goto error; } /* store to hash table if not present yet */ mutex_lock(radius_mutex); forward = update_tables(pdu); mutex_unlock(radius_mutex); /* create response PDU for NAS */ r = radius_pdu_create(0x05, pdu); /* * create response authenticator * code+identifier(req)+length+authenticator(req)+(attributes)+secret */ r->u.Accounting_Response.identifier = pdu->u.Accounting_Request.identifier; r->u.Accounting_Response.authenticator = octstr_duplicate(pdu->u.Accounting_Request.authenticator); /* pack response for NAS */ rdata = radius_pdu_pack(r); /* creates response autenticator in encoded PDU */ radius_authenticate_pdu(r, &rdata, secret_nas); /* * forward request to remote RADIUS server only if updated * and if we have a configured remote RADIUS server */ if ((remote_host != NULL) && forward) { if (udp_sendto(cs, data, addr) == -1) { error(0, "RADIUS: Couldn't send to remote RADIUS <%s:%ld>.", octstr_get_cstr(remote_host), remote_port); } else if (read_available(cs, remote_timeout) < 1) { error(0, "RADIUS: Timeout for response from remote RADIUS <%s:%ld>.", octstr_get_cstr(remote_host), remote_port); } else if (udp_recvfrom(cs, &data, &from_radius) == -1) { error(0, "RADIUS: Couldn't receive from remote RADIUS <%s:%ld>.", octstr_get_cstr(remote_host), remote_port); } else { info(0, "RADIUS: Got data from remote RADIUS <%s:%d>.", octstr_get_cstr(udp_get_ip(from_radius)), udp_get_port(from_radius)); octstr_dump(data, 0); /* XXX unpack the response PDU and check if the response * authenticator is valid */ } } /* send response to NAS */ if (udp_sendto(ss, rdata, from_nas) == -1) error(0, "RADIUS: Couldn't send response data to NAS <%s:%d>.", octstr_get_cstr(udp_get_ip(from_nas)), udp_get_port(from_nas)); error: radius_pdu_destroy(pdu); radius_pdu_destroy(r); octstr_destroy(rdata); octstr_destroy(data); octstr_destroy(from_nas); debug("radius.proxy", 0, "RADIUS: Mapping table contains %ld elements", dict_key_count(radius_table)); debug("radius.proxy", 0, "RADIUS: Session table contains %ld elements", dict_key_count(session_table)); debug("radius.proxy", 0, "RADIUS: Client table contains %ld elements", dict_key_count(client_table)); } octstr_destroy(addr); } /************************************************************************* * Public functions: init, shutdown, mapping. */ Octstr *radius_acct_get_msisdn(Octstr *client_ip) { Octstr *m, *r; char *uf; /* if no proxy thread is running, then pass NULL as result */ if (radius_table == NULL || client_ip == NULL) return NULL; mutex_lock(radius_mutex); m = dict_get(radius_table, client_ip); mutex_unlock(radius_mutex); r = m ? octstr_duplicate(m) : NULL; /* apply number normalization */ uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL; normalize_number(uf, &r); return r; } void radius_acct_init(CfgGroup *grp) { long nas_ports = 0; /* get configured parameters */ if ((our_host = cfg_get(grp, octstr_imm("our-host"))) == NULL) { our_host = octstr_create("0.0.0.0"); } if ((remote_host = cfg_get(grp, octstr_imm("remote-host"))) != NULL) { cfg_get_integer(&remote_port, grp, octstr_imm("remote-port")); if ((secret_radius = cfg_get(grp, octstr_imm("secret-radius"))) == NULL) { panic(0, "RADIUS: No shared secret `secret-radius' for remote RADIUS in `radius-acct' provided."); } } cfg_get_integer(&our_port, grp, octstr_imm("our-port")); cfg_get_integer(&remote_timeout, grp, octstr_imm("remote-timeout")); if ((cfg_get_integer(&nas_ports, grp, octstr_imm("nas-ports"))) == -1) { nas_ports = RADIUS_NAS_PORTS; } if ((secret_nas = cfg_get(grp, octstr_imm("secret-nas"))) == NULL) { panic(0, "RADIUS: No shared secret `secret-nas' for NAS in `radius-acct' provided."); } unified_prefix = cfg_get(grp, octstr_imm("unified-prefix")); info(0, "RADIUS: local RADIUS accounting proxy at <%s:%ld>", octstr_get_cstr(our_host), our_port); if (remote_host == NULL) { info(0, "RADIUS: remote RADIUS accounting server is absent"); } else { info(0, "RADIUS: remote RADIUS accounting server at <%s:%ld>", octstr_get_cstr(remote_host), remote_port); } info(0, "RADIUS: initializing internal hash tables with %ld buckets.", nas_ports); radius_mutex = mutex_create(); /* init hash tables */ radius_table = dict_create(nas_ports, (void (*)(void *))octstr_destroy); session_table = dict_create(nas_ports, (void (*)(void *))octstr_destroy); client_table = dict_create(nas_ports, (void (*)(void *))octstr_destroy); gwthread_create(proxy_thread, NULL); } void radius_acct_shutdown(void) { if (radius_mutex == NULL) /* haven't init'ed at all */ return ; mutex_lock(radius_mutex); run_thread = 0; mutex_unlock(radius_mutex); gwthread_join_every(proxy_thread); dict_destroy(radius_table); dict_destroy(session_table); dict_destroy(client_table); mutex_destroy(radius_mutex); octstr_destroy(our_host); octstr_destroy(remote_host); octstr_destroy(secret_nas); octstr_destroy(secret_radius); octstr_destroy(unified_prefix); info(0, "RADIUS: accounting proxy stopped."); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/radius/radius_attributes.def����������������������������������������������������������0000644�0001750�0001750�00000012767�13227613126�017410� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ /* * RADIUS Attributes as defined by RFC2865, page 23 and RFC2866 */ #ifndef ATTRIBUTES #error Macro ATTRIBUTES not defined. #endif #ifndef ATTR #error Macro ATTR not defined. #endif #ifndef UNASSIGNED #error Macro UNASSIGNED not defined. #endif /* define the length of the undistinguised octets length */ #define UMAX 128 /* define type mappings for attribute types */ #define ATTR_INT(attr, string) \ ATTR(attr, t_int, string, 4, 4) #define ATTR_IPADDR(attr, string) \ ATTR(attr, t_ipaddr, string, 4, 4) #define ATTR_STR(attr, string, min, max) \ ATTR(attr, t_string, string, min, max) /* * defines the Attribute type, (see RFC2865, page 25 and on) * syntax: ATTR(<attribute>, <value-type>, <description string>, <min len>, <max len>) */ ATTRIBUTES( ATTR_STR(1, "User-Name", 1, 64) ATTR_STR(2, "User-Password", 16, UMAX) ATTR_STR(3, "CHAP-Password", 16, 16) ATTR_IPADDR(4, "NAS-IP-Address") ATTR_INT(5, "NAS-Port") ATTR_INT(6, "Service-Type") ATTR_INT(7, "Framed-Protocol") ATTR_IPADDR(8, "Framed-IP-Address") ATTR_IPADDR(9, "Framed-IP-Netmask") ATTR_INT(10, "Framed-Routing") ATTR_STR(11, "Filter-Id", 1, UMAX) ATTR_INT(12, "Framed-MTU") ATTR_INT(13, "Framed-Compression") ATTR_IPADDR(14, "Login-IP-Host") ATTR_INT(15, "Login-Service") ATTR_INT(16, "Login-TCP-Port") UNASSIGNED(17) ATTR_STR(18, "Reply-Message", 1, UMAX) ATTR_STR(19, "Callback-Number", 1, UMAX) ATTR_STR(20, "Callback-Id", 1, UMAX) UNASSIGNED(21) ATTR_STR(22, "Framed-Route", 1, UMAX) ATTR_IPADDR(23, "Framed-IPX-Network") ATTR_STR(24, "State", 1, UMAX) ATTR_STR(25, "Class", 1, UMAX) ATTR_STR(26, "Vendor-Specific", 5, 256) ATTR_INT(27, "Session-Timeout") ATTR_INT(28, "Idle-Timeout") ATTR_INT(29, "Termination-Action") ATTR_STR(30, "Called-Station-Id", 1, UMAX) ATTR_STR(31, "Calling-Station-Id", 1, UMAX) ATTR_STR(32, "NAS-Identifier", 1, UMAX) ATTR_STR(33, "Proxy-State", 1, UMAX) ATTR_STR(34, "Login-LAT-Service", 1, UMAX) ATTR_STR(35, "Login-LAT-Node", 1, UMAX) ATTR_STR(36, "Login-LAT-Group", 32, 32) ATTR_INT(37, "Framed-AppleTalk-Link") ATTR_INT(38, "Framed-AppleTalk-Network") ATTR_STR(39, "Framed-AppleTalk-Zone", 1, UMAX) /* accounting types (RFC2866, page 10) */ ATTR_INT(40, "Acct-Status-Type") ATTR_INT(41, "Acct-Delay-Time") ATTR_INT(42, "Acct-Input-Octets") ATTR_INT(43, "Acct-Output-Octets") ATTR_STR(44, "Acct-Session-Id", 1, UMAX) ATTR_INT(45, "Acct-Authentic") ATTR_INT(46, "Acct-Session-Time") ATTR_INT(47, "Acct-Input-Packets") ATTR_INT(48, "Acct-Output-Packets") ATTR_INT(49, "Acct-Terminate-Cause") ATTR_STR(50, "Acct-Multi-Session-Id", 1, UMAX) ATTR_INT(51, "Acct-Link-Count") ATTR_STR(60, "CHAP-Challenge", 5, UMAX) ATTR_INT(61, "NAS-Port-Type") ATTR_INT(62, "Port-Limit") ATTR_STR(63, "Login-LAT-Port", 1, UMAX) ) #undef UMAX #undef ATTR_INT #undef ATTR_IPADDR #undef ATTR_STR #undef ATTR #undef UNASSIGNED #undef ATTRIBUTES ���������gateway-1.4.5/acinclude.m4��������������������������������������������������������������������������0000644�0001750�0001750�00000012067�11721412114�014055� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl acinclude.m4 -- local include for for autoconf dnl dnl This file is processed while autoconf generates configure. dnl This file is part of the Kannel WAP and SMS gateway project. dnl Check if installed version string is equal or higher then required. dnl This is used in a couple of tests to ensure we have a valid version dnl of a software package installed. The basic idea is to split the dnl version sequences into three parts and then test against eachother dnl in a whole complex if statement. dnl dnl AC_CHECK_VERSION(installed, required, [do-if-success], [do-if-tail]) dnl dnl Written by Stipe Tolj <stolj@kannel.org> <st@tolj.org> AC_DEFUN([AC_CHECK_VERSION], [ dnl split installed version string ac_inst_ver_maj=`echo $1 | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_inst_ver_mid=`echo $1 | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_inst_ver_min=`echo $1 | sed -e 's/^.*\..*\.\(.*\)$/\1/'` dnl split required version string ac_req_ver_maj=`echo $2 | sed -e 's/^\(.*\)\..*\..*$/\1/'` ac_req_ver_mid=`echo $2 | sed -e 's/^.*\.\(.*\)\..*$/\1/'` ac_req_ver_min=`echo $2 | sed -e 's/^.*\..*\.\(.*\)$/\1/'` dnl now perform the test if test "$ac_inst_ver_maj" -lt "$ac_req_ver_maj" || \ ( test "$ac_inst_ver_maj" -eq "$ac_req_ver_maj" && \ test "$ac_inst_ver_mid" -lt "$ac_req_ver_mid" ) || \ ( test "$ac_inst_ver_mid" -eq "$ac_req_ver_mid" && \ test "$ac_inst_ver_min" -lt "$ac_req_ver_min" ) then ac_ver_fail=yes else ac_ver_fail=no fi dnl now see if we have to do something ifelse([$3],,, [if test $ac_ver_fail = no; then $3 fi]) ifelse([$4],,, [if test $ac_ver_fail = yes; then $4 fi]) ]) dnl Some optional terminal sequences for configure dnl Taken from the mod_ssl package by Ralf S. Engelschall. AC_DEFUN([AC_SET_TERMINAL_SEQUENCES], [ case $TERM in xterm|xterm*|vt220|vt220*|cygwin) T_MD=`echo dummy | awk '{ printf("%c%c%c%c", 27, 91, 49, 109); }'` T_ME=`echo dummy | awk '{ printf("%c%c%c", 27, 91, 109); }'` ;; vt100|vt100*) T_MD=`echo dummy | awk '{ printf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0); }'` T_ME=`echo dummy | awk '{ printf("%c%c%c%c%c", 27, 91, 109, 0, 0); }'` ;; default) T_MD='' T_ME='' ;; esac ]) dnl Display configure section name in bold white letters dnl if available on the terminal AC_DEFUN([AC_CONFIG_SECTION], [ nl=' ' echo "${nl}${T_MD}$1 ...${T_ME}" ]) dnl Check which SVN revision is and apply dnl the value to the given variable AC_DEFUN([AC_SVN_REVISION], [ if test -d ".svn" then revision=`svnversion .` test -z "$revision" && revision="unknown" $1="$revision" elif test -d ".git" then sha1=$(git rev-parse --short HEAD) mod=$(git status | grep "modified:\|added:\|deleted:" -q && echo "M") $1="$sha1$mod" fi ]) dnl Available from the GNU Autoconf Macro Archive at: dnl http://www.gnu.org/software/ac-archive/htmldoc/ac_caolan_func_which_gethostbyname_r.html dnl Modified by Alexander Malysh for Kannel Project. AC_DEFUN([AC_FUNC_WHICH_GETHOSTBYNAME_R], [AC_CACHE_CHECK(for which type of gethostbyname_r, ac_cv_func_which_gethostname_r, [ AC_TRY_COMPILE([ #include <netdb.h> ], [ char *name; struct hostent *he; struct hostent_data data; (void) gethostbyname_r(name, he, &data); ], ac_cv_func_which_gethostname_r=3, [ AC_TRY_COMPILE([ #include <netdb.h> ], [ char *name; struct hostent *he, *res; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop); ], ac_cv_func_which_gethostname_r=6, [ AC_TRY_COMPILE([ #include <netdb.h> ], [ char *name; struct hostent *he; char buffer[2048]; int buflen = 2048; int h_errnop; (void) gethostbyname_r(name, he, buffer, buflen, &h_errnop); ], ac_cv_func_which_gethostname_r=5 , ac_cv_func_which_gethostname_r=0)] )] )]) if test $ac_cv_func_which_gethostname_r -eq 6; then AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_6) elif test $ac_cv_func_which_gethostname_r -eq 5; then AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_5) elif test $ac_cv_func_which_gethostname_r -eq 3; then AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_3) elif test $ac_cv_func_which_gethostname_r -eq 0; then ac_cv_func_which_gethostname_r = no fi ]) dnl Creates a config.nice shell script that contains all given configure dnl options to the orginal configure call. Can be used to add further options dnl in additional re-configure calls. This is perfect while handling with a dnl large number of configure option switches. dnl This macro is taken from PHP5 aclocal.m4, Stipe Tolj. AC_DEFUN([AC_CONFIG_NICE], [ test -f $1 && mv $1 $1.old rm -f $1.old cat >$1<<EOF #! /bin/sh # # Created by configure EOF for var in CFLAGS CXXFLAGS CPPFLAGS LDFLAGS LIBS CC CXX; do eval val=\$$var if test -n "$val"; then echo "$var='$val' \\" >> $1 fi done for arg in [$]0 "[$]@"; do echo "'[$]arg' \\" >> $1 done echo '"[$]@"' >> $1 chmod +x $1 ]) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/INSTALL�������������������������������������������������������������������������������0000644�0001750�0001750�00000017357�07211537602�012735� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Basic Installation ================== These are generic installation instructions. For platform specific instructions please see the files in the doc/platforms directory. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). 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 diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. 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. Running `configure' takes awhile. 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. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== 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 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 `..'. If you have to use a `make' that does not supports 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. 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=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' 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. 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 `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 `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually 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. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM 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 host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. 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'. `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. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/ChangeLog�����������������������������������������������������������������������������0000644�0001750�0001750�00000001227�13312226107�013435� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������2018-06-19 Stipe Tolj <stolj at kannel.org> * Making stable release 1.4.5. 2018-06-19 Stipe Tolj <stolj at kannel.org> * README: update documentation build package dependencies. 2018-06-19 Stipe Tolj <stolj at kannel.org> * bootstrap.sh: re-order GNU auto-tools calls, NLC. * Makefile.in: provide phony 'am--refresh' to cope with bootstrapped source packages on different environments. 2018-06-19 Stipe Tolj <stolj at kannel.org> * doc/*/[alligata|arch|userguide|wtls].xml: update DOCTYPE URL reference to new official URL location to fix 'make docs' processing. * configure.in: adding Debian 8 location for xml.dcl.�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/gw-config.h.in������������������������������������������������������������������������0000644�0001750�0001750�00000022371�13227613126�014332� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ==================================================================== * The Kannel Software License, Version 1.0 * * Copyright (c) 2001-2018 Kannel Group * Copyright (c) 1998-2001 WapIT Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Kannel Group (http://www.kannel.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Kannel" and "Kannel Group" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please * contact org@kannel.org. * * 5. Products derived from this software may not be called "Kannel", * nor may "Kannel" appear in their name, without prior written * permission of the Kannel Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Kannel Group. For more information on * the Kannel Group, please see <http://www.kannel.org/>. * * Portions of this software are based upon software originally written at * WapIT Ltd., Helsinki, Finland for the Kannel project. */ #ifndef CONFIG_H #define CONFIG_H /* Define one of these depending on which malloc wrapper you want to use. */ #undef USE_GWMEM_NATIVE #undef USE_GWMEM_CHECK #undef USE_GWMEM_SLOW /* Define if you want information about lock collisions to be collected. * These are useful for finding performance bottlenecks. */ #undef MUTEX_STATS /* Define if you want log file timestamps in localtime instead of GMT. */ #undef LOG_TIMESTAMP_LOCALTIME /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define if your compiler supports the __func__ magic symbol. This is part of C99. */ #undef HAVE___FUNC__ /* Define if your compiler supports the __FUNCTION__ magic symbol. */ #undef HAVE___FUNCTION__ /* Make sure __func__ does something useful. */ #if defined(HAVE___FUNC__) /* Nothing to do. Life is so wonderful. */ #elif defined(HAVE___FUNCTION__) #define __func__ __FUNCTION__ #else #define __func__ "unknown" #endif /* Define if you have getopt.h. */ #undef HAVE_GETOPT_H /* Define if you have getopt(3). */ #undef HAVE_GETOPT /* Define if you have a declaration for getopt(3) in <stdio.h>. */ #undef HAVE_GETOPT_IN_STDIO_H /* Define if you have a declaration for getopt(3) in <unistd.h>. */ #undef HAVE_GETOPT_IN_UNISTD_H /* Define if you have getopt_long(3). */ #undef HAVE_GETOPT_LONG /* Define gateway name */ #undef GW_NAME /* Define which version we use */ #undef GW_VERSION /* WMLScript debugging. */ #undef WS_DEBUG /* Define if you have the gettimeofday function. */ #undef HAVE_GETTIMEOFDAY /* Define if you have the select function. */ #undef HAVE_SELECT /* Define if you have the socket function. */ #undef HAVE_SOCKET /* Define if you have the localtime_r function. */ #undef HAVE_LOCALTIME_R /* Define if you have the gmtime_r function. */ #undef HAVE_GMTIME_R /* Define if you have the backtrace function. */ #undef HAVE_BACKTRACE /* Define if you have the user context functions. */ #undef HAVE_UCONTEXT /* Define if you have the srandom function. */ #undef HAVE_SRANDOM /* Define if you have the initgroups function. */ #undef HAVE_INITGROUPS /* Define if you have the strtoll function. */ #undef HAVE_STRTOLL /* Define if you have the strtoq function. */ #undef HAVE_STRTOQ /* Define if you have the <fcntl.h> header file. */ #undef HAVE_FCNTL_H /* Define if you have the <pthread.h> header file. */ #undef HAVE_PTHREAD_H /* Define if you have the <sys/ioctl.h> header file. */ #undef HAVE_SYS_IOCTL_H /* Define if you have the <sys/types.h> header file. */ #undef HAVE_SYS_TYPES_H /* Define if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H /* Define if you have the <sys/poll.h> header file. */ #undef HAVE_SYS_POLL_H /* Define if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H /* Define if you have the <sys/socket.h> header file. */ #undef HAVE_SYS_SOCKET_H /* Define if you have the <sys/sockio.h> header file. */ #undef HAVE_SYS_SOCKIO_H /* Define if you have the <net/if.h> header file. */ #undef HAVE_NET_IF_H /* Define if you have the <netinet/in.h> header file. */ #undef HAVE_NETINET_IN_H /* Define if you have the m library (-lm). */ #undef HAVE_LIBM /* Define if you have the nsl library (-lnsl). */ #undef HAVE_LIBNSL /* Define if you have the pthread library (-lpthread). */ #undef HAVE_LIBPTHREAD /* Define if you have the socket library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define if you have the xml library (-lxml). */ #undef HAVE_LIBXML /* Define if you have the z library (-lz). */ #undef HAVE_LIBZ /* Define if there is a socklen_t in <sys/socket.h> */ #undef HAVE_SOCKLEN_T /* Define if the PAM headers are on the local machine */ #undef HAVE_SECURITY_PAM_APPL_H /* Define if you want to turn off assertion checking */ #undef NO_GWASSERT /* Define if you have <syslog.h>. */ #undef HAVE_SYSLOG_H /* Defines for iconv. */ #define HAVE_ICONV 0 #define ICONV_CONST const /* Define if you have <execinfo.h>. */ #undef HAVE_EXECINFO_H /* Define if you have and want to use the ssl library (-lssl) */ #undef HAVE_LIBSSL /* Defined if we're using OpenSSL WTLS */ #undef HAVE_WTLS_OPENSSL /* Define if you have and want to use the FreeTDS ct-lib */ #undef HAVE_MSSQL /* Define if you have and want to use the MySQL client library (-lmysqlclient) */ #undef HAVE_MYSQL /* Define if you have and want to use the sdb client library (-lsdb) */ #undef HAVE_SDB /* Define if you have and want to use the OCI library */ #undef HAVE_ORACLE /* Define if you have and want to use the OCIPing function */ #undef HAVE_OCIPING /* Define if you have and want to use the SQLite database library (-lsqlite) */ #undef HAVE_SQLITE /* Define if you have and want to use the SQLite3 database library (-lsqlite3) */ #undef HAVE_SQLITE3 /* Define version of used libSDB */ #undef LIBSDB_VERSION /* Define if you have and want to use the PostgreSQL dlr routines (-lpq) */ #undef HAVE_PGSQL /* Define if you have and want to use the Redis client library (-lhiredis) */ #undef HAVE_REDIS /* Define if you have and want to use the Cassandra client library (-lcassandra) */ #undef HAVE_CASS /* Define if you want to have cookie support for the WSP */ #undef ENABLE_COOKIES /* Define if you want to have HTTP/1.1 keep-alive support */ #undef USE_KEEPALIVE /* Define not to include the WAP gateway parts */ #undef NO_WAP /* Define not to include the SMS gateway parts */ #undef NO_SMS /* Define for various gethostbyname_r functions */ #undef HAVE_FUNC_GETHOSTBYNAME_R_6 #undef HAVE_FUNC_GETHOSTBYNAME_R_5 #undef HAVE_FUNC_GETHOSTBYNAME_R_3 /* Define if you have and want to use POSIX regular expressions */ #undef HAVE_REGEX /* Define if you have and want to use POSIX nftw function */ #undef HAVE_NFTW /* Define if you have and want to use PCRE (Perl compatible regular expressions) */ #undef HAVE_PCRE /* Define version of used libpcre */ #undef LIBPCRE_VERSION /* Define if you have pthread_spinlock_t type and spinlock support. */ #undef HAVE_PTHREAD_SPINLOCK_T /* Define if you have pthread_rwlock_t type and reader/writer lock support. */ #undef HAVE_PTHREAD_RWLOCK /* Define if you have working semaphore (sem_t). */ #undef HAVE_SEMAPHORE /* Define if you have and want to use gSOAP compiler */ #undef HAVE_GSOAP /* If we're using GCC, we can get it to check format function arguments. */ #ifdef __GNUC__ #define PRINTFLIKE(a,b) __attribute__((format(printf, a, b))) #else #define PRINTFLIKE(a, b) #endif /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/STATUS��������������������������������������������������������������������������������0000644�0001750�0001750�00000003035�12366730005�012635� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������KANNEL 1.x STATUS: Last modified at 2014-08-01 by Stipe Tolj Release: 1.4.4: update to stable, released Aug 01, 2014. 1.5.0: development version, released Oct 20, 2010. 1.4.3: update to stable, released Feb 04, 2009. 1.4.2: update to stable, released Jan 12, 2009. 1.4.1: update to stable, released Sep 25, 2006. 1.4.0: update to stable, released Nov 23, 2004. 1.3.2: development version, released Jul 14, 2004. 1.3.1: development version, released Feb 17, 2003. 1.3.0: development version, released Jan 06, 2003. 1.2.1: update to stable, released Nov 02, 2002. 1.2.0: update to stable, released Jul 04, 2002. 1.1.6: development version, released Mar 28, 2002. 1.1.5: development version, released May 31, 2001. 1.1.4: development version, released May 07, 2001. 1.0.3: update to stable, released Mar 27, 2001. 1.1.3: development version, released Mar 20, 2001. 1.0.2: received WAP 1.1 certification, Mar 07, 2001. 1.1.2: development version, released Feb 28, 2001. 1.0.2: update to stable, released Feb 26, 2001. 1.0.1: update to stable, released Feb 13, 2001. 1.1.1: development version, released Feb 01, 2001. 1.1: development version, released Jan 22, 2001. 1.0: update to stable, released Jan 08, 2001. 0.12.4: update to stable, released Dec 21, 2000. 0.13.1: development version, released Dec 13, 2000. 0.12.3: update to stable, released Dec 08, 2000. (see ChangeLog for details in directory doc/) Bugs: (see https://redmine.kannel.org/) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/���������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13312227714�012630� 5����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/plugin/��������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13312227713�014125� 5����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/Makefile.in����������������������������������������������������������������������0000644�0001750�0001750�00000007133�12500256312�014673� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # soap/Makefile.in - extending Makefile.in for SOAP web services # # This file is included from main Makefile, and contains various # targets and definitions to build the SOAP related object files # and libraries. # # This file is currently maintained manually. There is currently # no generation out of automake. This will change as soon as we # switch to our new autoconf/configure build process. # # Stipe Tolj <stolj at kannel.org> # # NOTE: At this time we CAN NOT build several gSOAP plugin # implementations using this build framework. The problem # arises from namespace clashes and the way gSOAP deals with # the individual soap_serve() functions internally while linking, # especially if WS-Security is used. # # If you need an additional gSOAP based implementation, then # change the build process to build ONLY ONE. # SOAPCPP = @SOAPCPP@ WSDL2H = @WSDL2H@ GSOAP_SHARE = @GSOAP_SHARE@ GSOAP_IMPORT = $(GSOAP_SHARE)/import GSOAP_PLUGIN = $(GSOAP_SHARE)/plugin LIBS=-lgsoapssl -lgsoap @LIBS@ @LIBICONV@ CFLAGS=-D_REENTRANT=1 -I. -Igw @CFLAGS@ -I$(GSOAP_IMPORT) -I$(GSOAP_PLUGIN) -DWITH_OPENSSL \ -Isoap/service/parlayx # # gSOAP plugin library, i.e. required for WS-Security # gsoap_plugin_srcs = $(GSOAP_PLUGIN)/wsseapi.c \ $(GSOAP_PLUGIN)/smdevp.c \ $(GSOAP_PLUGIN)/mecevp.c soap_plugin_srcs = soap/plugin/wsseapi.c \ soap/plugin/smdevp.c \ soap/plugin/mecevp.c soap_plugin_objs = $(soap_plugin_srcs:.c=.o) soap/plugin/wsseapi.c: $(GSOAP_PLUGIN)/wsseapi.c ln -sf $(GSOAP_PLUGIN)/wsseapi.c soap/plugin/wsseapi.c soap/plugin/smdevp.c: $(GSOAP_PLUGIN)/smdevp.c ln -sf $(GSOAP_PLUGIN)/smdevp.c soap/plugin/smdevp.c soap/plugin/mecevp.c: $(GSOAP_PLUGIN)/mecevp.c ln -sf $(GSOAP_PLUGIN)/mecevp.c soap/plugin/mecevp.c libsoap_plugin.a: $(soap_plugin_objs) @OLD_LIBTOOL@ libsoap_plugin.a $(soap_plugin_objs) $(RANLIB) libsoap_plugin.a # # Service implementation: Parlay X v2.1 # soap_parlayx_wsdls = soap/service/parlayx/wsdl/parlayx_sms_send_service_2_1.wsdl \ soap/service/parlayx/wsdl/parlayx_sms_notification_service_2_1.wsdl \ soap/service/parlayx/wsdl/parlayx_sms_receive_service_2_1.wsdl soap_parlayx_cppsrc = soap/service/parlayx/parlayx_sms_send_service_2_1.h soap_parlayx_cppwrap = soap/service/parlayx/parlayx_sms_send_service_2_1_wrapper.h soap_parlayx_cpphdr = soap/service/parlayx/soapH.h soap_parlayx_srcs = $(wildcard soap/service/parlayx/*.c) soap_parlayx_objs = $(soap_parlayx_srcs:.c=.o) $(soap_parlayx_cppsrc): $(soap_parlayx_wsdls) $(WSDL2H) -c -W -npx -t soap/service/parlayx/typemap.dat -o $(soap_parlayx_cppsrc) -I soap/service/parlayx/wsdl $(soap_parlayx_wsdls) sed -i -e '/^\/\/gsoapopt/d' $(soap_parlayx_cppsrc) $(soap_parlayx_cpphdr): $(soap_parlayx_cppwrap) $(soap_parlayx_cppsrc) $(SOAPCPP) -d `dirname $(soap_parlayx_cpphdr)` -I $(GSOAP_IMPORT) -I soap/service/parlayx -cLxw $(soap_parlayx_cppwrap) libsoap_parlayx.a: $(soap_parlayx_cpphdr) $(soap_parlayx_plugin_srcs) $(soap_parlayx_objs) @OLD_LIBTOOL@ libsoap_parlayx.a $(soap_parlayx_objs) $(RANLIB) libsoap_parlayx.a # # Define all soapcpp2 header inputs # Add $(soap_SERVICE_cpphdr) for new implementation. # gsoap_cpp_hdrs = $(soap_parlayx_cpphdr) # Add libsoap_SERVICE.a for new implementation. libs = libgw.a libwmlscript.a libwap.a libgwlib.a libsoap_plugin.a \ libsoap_parlayx.a # Add soap/service/SERVICE for new implementation. srcdirs = gw gw/smsc gwlib test utils wmlscript checks wap radius soap/service/plugin \ soap/service/parlayx soap_depend = $(gsoap_cpp_hdrs) soap_clean: find soap -name "*.o" -o -name "*.i" -o -name "*.c" \ -o -name "soap*.h" -o -name "*.nsmap" | xargs rm -f find . -name "libsoap_*.a" | xargs rm -f �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/�������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13312227713�014267� 5����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/�����������������������������������������������������������������0000755�0001750�0001750�00000000000�13312227713�015747� 5����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/typemap.dat������������������������������������������������������0000644�0001750�0001750�00000000712�12036105365�020120� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������px1 = "(default)" pxSmsSend = "http://www.csapi.org/schema/parlayx/sms/send/v2_1/local" px3 = "" pxCommon = "http://www.csapi.org/schema/parlayx/common/v2_1" pxSms = "http://www.csapi.org/schema/parlayx/sms/v2_1" pxSmsNotification = "http://www.csapi.org/schema/parlayx/sms/notification/v2_1/local" pxSmsReceive = "http://www.csapi.org/schema/parlayx/sms/receive/v2_1/local" ������������������������������������������������������gateway-1.4.5/soap/service/parlayx/parlayx_sms_send_service_2_1_wrapper.h���������������������������0000644�0001750�0001750�00000002651�12366463220�025423� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� /******************************************************************************\ * * * Import * * * \******************************************************************************/ #import "wsse.h" // wsse = <http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd> #import "parlayx_sms_send_service_2_1.h" // created by wsdl2h /******************************************************************************\ * * * SOAP Header * * * \******************************************************************************/ /** The SOAP Header is part of the gSOAP context and its content is accessed through the soap.header variable. You may have to set the soap.actor variable to serialize SOAP Headers with SOAP-ENV:actor or SOAP-ENV:role attributes. */ struct SOAP_ENV__Header { mustUnderstand // must be understood by receiver _wsse__Security *wsse__Security ; ///< TODO: Check element type (imported type) }; ���������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/������������������������������������������������������������0000755�0001750�0001750�00000000000�13312227714�016721� 5����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_sms_send_service_2_1.wsdl���������������������������0000644�0001750�0001750�00000006633�12036105365�025357� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <wsdl:definitions name="parlayx_sms_send_service" targetNamespace="http://www.csapi.org/wsdl/parlayx/sms/send/v2_1/service" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.csapi.org/wsdl/parlayx/sms/send/v2_1/service" xmlns:interface="http://www.csapi.org/wsdl/parlayx/sms/send/v2_1/interface"> <wsdl:import namespace="http://www.csapi.org/wsdl/parlayx/sms/send/v2_1/interface" location="parlayx_sms_send_interface_2_1.wsdl"/> <wsdl:binding name="SendSmsBinding" type="interface:SendSms"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="sendSms"> <soap:operation soapAction="" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal"/> </wsdl:fault> <wsdl:fault name="PolicyException"> <soap:fault name="PolicyException" use="literal"/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="sendSmsLogo"> <soap:operation soapAction="" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal"/> </wsdl:fault> <wsdl:fault name="PolicyException"> <soap:fault name="PolicyException" use="literal"/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="sendSmsRingtone"> <soap:operation soapAction="" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal"/> </wsdl:fault> <wsdl:fault name="PolicyException"> <soap:fault name="PolicyException" use="literal"/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="getSmsDeliveryStatus"> <soap:operation soapAction="" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal"/> </wsdl:fault> <wsdl:fault name="PolicyException"> <soap:fault name="PolicyException" use="literal"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:service name="SendSmsService"> <wsdl:port name="SendSms" binding="tns:SendSmsBinding"> <soap:address location="http://localhost:9080/ParlayXSms/services/SendSms"/> </wsdl:port> </wsdl:service> </wsdl:definitions> �����������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_common_types_2_1.xsd��������������������������������0000644�0001750�0001750�00000005407�12036105365�024363� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <xsd:schema targetNamespace="http://www.csapi.org/schema/parlayx/common/v2_1" xmlns:parlayx_common_xsd="http://www.csapi.org/schema/parlayx/common/v2_1" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:complexType name="TimeMetric"> <xsd:sequence> <xsd:element name="metric" type="parlayx_common_xsd:TimeMetrics"/> <xsd:element name="units" type="xsd:int"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="ChargingInformation"> <xsd:sequence> <xsd:element name="description" type="xsd:string"/> <xsd:element name="currency" type="xsd:string" minOccurs="0" maxOccurs="1"/> <xsd:element name="amount" type="xsd:decimal" minOccurs="0" maxOccurs="1"/> <xsd:element name="code" type="xsd:string" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="SimpleReference"> <xsd:sequence> <xsd:element name="endpoint" type="xsd:anyURI"/> <xsd:element name="interfaceName" type="xsd:string"/> <xsd:element name="correlator" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="ServiceError"> <xsd:sequence> <xsd:element name="messageId" type="xsd:string"/> <xsd:element name="text" type="xsd:string"/> <xsd:element name="variables" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <xsd:simpleType name="TimeMetrics"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="Millisecond"/> <xsd:enumeration value="Second"/> <xsd:enumeration value="Minute"/> <xsd:enumeration value="Hour"/> <xsd:enumeration value="Day"/> <xsd:enumeration value="Week"/> <xsd:enumeration value="Month"/> <xsd:enumeration value="Year"/> </xsd:restriction> </xsd:simpleType> <xsd:element name="ServiceException" type="parlayx_common_xsd:ServiceException"/> <xsd:complexType name="ServiceException"> <xsd:sequence> <xsd:element name="messageId" type="xsd:string"/> <xsd:element name="text" type="xsd:string"/> <xsd:element name="variables" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> <xsd:element name="PolicyException" type="parlayx_common_xsd:PolicyException"/> <xsd:complexType name="PolicyException"> <xsd:sequence> <xsd:element name="messageId" type="xsd:string"/> <xsd:element name="text" type="xsd:string"/> <xsd:element name="variables" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:schema> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_sms_notification_service_2_1.wsdl�������������������0000644�0001750�0001750�00000003470�12036105365�027110� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <wsdl:definitions name="parlayx_sms_notification_service" targetNamespace="http://www.csapi.org/wsdl/parlayx/sms/notification/v2_1/service" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.csapi.org/wsdl/parlayx/sms/notification/v2_1/service" xmlns:interface="http://www.csapi.org/wsdl/parlayx/sms/notification/v2_1/interface"> <wsdl:import namespace="http://www.csapi.org/wsdl/parlayx/sms/notification/v2_1/interface" location="parlayx_sms_notification_interface_2_1.wsdl"/> <wsdl:binding name="SmsNotificationBinding" type="interface:SmsNotification"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="notifySmsReception"> <soap:operation soapAction="" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> <wsdl:operation name="notifySmsDeliveryReceipt"> <soap:operation soapAction="" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="SmsNotificationService"> <wsdl:port name="SmsNotification" binding="tns:SmsNotificationBinding"> <soap:address location="http://localhost:9080/SmsNotificationService/services/SmsNotification"/> </wsdl:port> </wsdl:service> </wsdl:definitions> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_sms_types_2_1.xsd�����������������������������������0000644�0001750�0001750�00000002757�12036105365�023702� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <xsd:schema targetNamespace="http://www.csapi.org/schema/parlayx/sms/v2_1" xmlns:parlayx_sms_xsd="http://www.csapi.org/schema/parlayx/sms/v2_1" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:complexType name="DeliveryInformation"> <xsd:sequence> <xsd:element name="address" type="xsd:anyURI"/> <xsd:element name="deliveryStatus" type="parlayx_sms_xsd:DeliveryStatus"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="SmsMessage"> <xsd:sequence> <xsd:element name="message" type="xsd:string"/> <xsd:element name="senderAddress" type="xsd:anyURI"/> <xsd:element name="smsServiceActivationNumber" type="xsd:anyURI"/> </xsd:sequence> </xsd:complexType> <xsd:simpleType name="DeliveryStatus"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="DeliveredToNetwork"/> <xsd:enumeration value="DeliveryUncertain"/> <xsd:enumeration value="DeliveryImpossible"/> <xsd:enumeration value="MessageWaiting"/> <xsd:enumeration value="DeliveredToTerminal"/> <xsd:enumeration value="DeliveryNotificationNotSupported"/> </xsd:restriction> </xsd:simpleType> <xsd:simpleType name="SmsFormat"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="Ems"/> <xsd:enumeration value="SmartMessaging"/> </xsd:restriction> </xsd:simpleType> </xsd:schema> �����������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_common_faults_2_0.wsdl������������������������������0000644�0001750�0001750�00000001666�12036105365�024672� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <wsdl:definitions name="common_faults" targetNamespace="http://www.csapi.org/wsdl/parlayx/common/v2_0/faults" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:parlayx_common_xsd="http://www.csapi.org/schema/parlayx/common/v2_1"> <wsdl:types> <xsd:schema elementFormDefault="qualified"> <xsd:import namespace="http://www.csapi.org/schema/parlayx/common/v2_1" schemaLocation="parlayx_common_types_2_1.xsd"/> </xsd:schema> </wsdl:types> <wsdl:message name="ServiceException"> <wsdl:part name="ServiceException" element="parlayx_common_xsd:ServiceException"/> </wsdl:message> <wsdl:message name="PolicyException"> <wsdl:part name="PolicyException" element="parlayx_common_xsd:PolicyException"/> </wsdl:message> </wsdl:definitions> ��������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_sms_receive_interface_2_1.wsdl����������������������0000644�0001750�0001750�00000005536�12036105365�026351� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <wsdl:definitions name="parlayx_sms_receive_interface" targetNamespace="http://www.csapi.org/wsdl/parlayx/sms/receive/v2_1/interface" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:parlayx_sms_receive="http://www.csapi.org/wsdl/parlayx/sms/receive/v2_1/interface" xmlns:parlayx_common_faults="http://www.csapi.org/wsdl/parlayx/common/v2_0/faults" xmlns:parlayx_sms_xsd="http://www.csapi.org/schema/parlayx/sms/v2_1" xmlns:parlayx_common_xsd="http://www.csapi.org/schema/parlayx/common/v2_1" xmlns:parlayx_sms_receive_local_xsd="http://www.csapi.org/schema/parlayx/sms/receive/v2_1/local"> <wsdl:import namespace="http://www.csapi.org/wsdl/parlayx/common/v2_0/faults" location="parlayx_common_faults_2_0.wsdl"/> <wsdl:types> <xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.csapi.org/schema/parlayx/sms/receive/v2_1/local"> <xsd:import namespace="http://www.csapi.org/schema/parlayx/sms/v2_1" schemaLocation="parlayx_sms_types_2_1.xsd"/> <xsd:import namespace="http://www.csapi.org/schema/parlayx/common/v2_1" schemaLocation="parlayx_common_types_2_1.xsd"/> <xsd:element name="getReceivedSms" type="parlayx_sms_receive_local_xsd:getReceivedSms"/> <xsd:complexType name="getReceivedSms"> <xsd:sequence> <xsd:element name="registrationIdentifier" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:element name="getReceivedSmsResponse" type="parlayx_sms_receive_local_xsd:getReceivedSmsResponse"/> <xsd:complexType name="getReceivedSmsResponse"> <xsd:sequence> <xsd:element name="result" type="parlayx_sms_xsd:SmsMessage" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:schema> </wsdl:types> <wsdl:message name="ReceiveSms_getReceivedSmsRequest"> <wsdl:part name="parameters" element="parlayx_sms_receive_local_xsd:getReceivedSms"/> </wsdl:message> <wsdl:message name="ReceiveSms_getReceivedSmsResponse"> <wsdl:part name="result" element="parlayx_sms_receive_local_xsd:getReceivedSmsResponse"/> </wsdl:message> <wsdl:portType name="ReceiveSms"> <wsdl:operation name="getReceivedSms"> <wsdl:input message="parlayx_sms_receive:ReceiveSms_getReceivedSmsRequest"/> <wsdl:output message="parlayx_sms_receive:ReceiveSms_getReceivedSmsResponse"/> <wsdl:fault name="ServiceException" message="parlayx_common_faults:ServiceException"/> <wsdl:fault name="PolicyException" message="parlayx_common_faults:PolicyException"/> </wsdl:operation> </wsdl:portType> </wsdl:definitions> ������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_sms_receive_service_2_1.wsdl������������������������0000644�0001750�0001750�00000003307�12036105365�026043� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <wsdl:definitions name="parlayx_sms_receive_service" targetNamespace="http://www.csapi.org/wsdl/parlayx/sms/receive/v2_1/service" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.csapi.org/wsdl/parlayx/sms/receive/v2_1/service" xmlns:interface="http://www.csapi.org/wsdl/parlayx/sms/receive/v2_1/interface"> <wsdl:import namespace="http://www.csapi.org/wsdl/parlayx/sms/receive/v2_1/interface" location="parlayx_sms_receive_interface_2_1.wsdl"/> <wsdl:binding name="ReceiveSmsBinding" type="interface:ReceiveSms"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getReceivedSms"> <soap:operation soapAction="" style="document"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> <wsdl:fault name="ServiceException"> <soap:fault name="ServiceException" use="literal"/> </wsdl:fault> <wsdl:fault name="PolicyException"> <soap:fault name="PolicyException" use="literal"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:service name="ReceiveSmsService"> <wsdl:port name="ReceiveSms" binding="tns:ReceiveSmsBinding"> <soap:address location="http://localhost:9080/ReceiveSmsService/services/ReceiveSms"/> </wsdl:port> </wsdl:service> </wsdl:definitions> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_sms_send_interface_2_1.wsdl�������������������������0000644�0001750�0001750�00000020271�12036105365�025651� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <wsdl:definitions name="parlayx_sms_send_interface" targetNamespace="http://www.csapi.org/wsdl/parlayx/sms/send/v2_1/interface" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:parlayx_sms_send="http://www.csapi.org/wsdl/parlayx/sms/send/v2_1/interface" xmlns:parlayx_common_faults="http://www.csapi.org/wsdl/parlayx/common/v2_0/faults" xmlns:parlayx_sms_xsd="http://www.csapi.org/schema/parlayx/sms/v2_1" xmlns:parlayx_common_xsd="http://www.csapi.org/schema/parlayx/common/v2_1" xmlns:parlayx_sms_send_local_xsd="http://www.csapi.org/schema/parlayx/sms/send/v2_1/local"> <wsdl:import namespace="http://www.csapi.org/wsdl/parlayx/common/v2_0/faults" location="parlayx_common_faults_2_0.wsdl"/> <wsdl:types> <xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.csapi.org/schema/parlayx/sms/send/v2_1/local"> <xsd:import namespace="http://www.csapi.org/schema/parlayx/sms/v2_1" schemaLocation="parlayx_sms_types_2_1.xsd"/> <xsd:import namespace="http://www.csapi.org/schema/parlayx/common/v2_1" schemaLocation="parlayx_common_types_2_1.xsd"/> <xsd:element name="sendSms" type="parlayx_sms_send_local_xsd:sendSms"/> <xsd:complexType name="sendSms"> <xsd:sequence> <xsd:element name="addresses" type="xsd:anyURI" minOccurs="1" maxOccurs="unbounded"/> <xsd:element name="senderName" type="xsd:string" minOccurs="0" maxOccurs="1"/> <xsd:element name="charging" type="parlayx_common_xsd:ChargingInformation" minOccurs="0" maxOccurs="1"/> <xsd:element name="message" type="xsd:string"/> <xsd:element name="receiptRequest" type="parlayx_common_xsd:SimpleReference" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <xsd:element name="sendSmsResponse" type="parlayx_sms_send_local_xsd:sendSmsResponse"/> <xsd:complexType name="sendSmsResponse"> <xsd:sequence> <xsd:element name="result" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:element name="sendSmsLogo" type="parlayx_sms_send_local_xsd:sendSmsLogo"/> <xsd:complexType name="sendSmsLogo"> <xsd:sequence> <xsd:element name="addresses" type="xsd:anyURI" minOccurs="1" maxOccurs="unbounded"/> <xsd:element name="senderName" type="xsd:string" minOccurs="0" maxOccurs="1"/> <xsd:element name="charging" type="parlayx_common_xsd:ChargingInformation" minOccurs="0" maxOccurs="1"/> <xsd:element name="image" type="xsd:base64Binary"/> <xsd:element name="smsFormat" type="parlayx_sms_xsd:SmsFormat"/> <xsd:element name="receiptRequest" type="parlayx_common_xsd:SimpleReference" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <xsd:element name="sendSmsLogoResponse" type="parlayx_sms_send_local_xsd:sendSmsLogoResponse"/> <xsd:complexType name="sendSmsLogoResponse"> <xsd:sequence> <xsd:element name="result" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:element name="sendSmsRingtone" type="parlayx_sms_send_local_xsd:sendSmsRingtone"/> <xsd:complexType name="sendSmsRingtone"> <xsd:sequence> <xsd:element name="addresses" type="xsd:anyURI" minOccurs="1" maxOccurs="unbounded"/> <xsd:element name="senderName" type="xsd:string" minOccurs="0" maxOccurs="1"/> <xsd:element name="charging" type="parlayx_common_xsd:ChargingInformation" minOccurs="0" maxOccurs="1"/> <xsd:element name="ringtone" type="xsd:string"/> <xsd:element name="smsFormat" type="parlayx_sms_xsd:SmsFormat"/> <xsd:element name="receiptRequest" type="parlayx_common_xsd:SimpleReference" minOccurs="0" maxOccurs="1"/> </xsd:sequence> </xsd:complexType> <xsd:element name="sendSmsRingtoneResponse" type="parlayx_sms_send_local_xsd:sendSmsRingtoneResponse"/> <xsd:complexType name="sendSmsRingtoneResponse"> <xsd:sequence> <xsd:element name="result" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:element name="getSmsDeliveryStatus" type="parlayx_sms_send_local_xsd:getSmsDeliveryStatus"/> <xsd:complexType name="getSmsDeliveryStatus"> <xsd:sequence> <xsd:element name="requestIdentifier" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:element name="getSmsDeliveryStatusResponse" type="parlayx_sms_send_local_xsd:getSmsDeliveryStatusResponse"/> <xsd:complexType name="getSmsDeliveryStatusResponse"> <xsd:sequence> <xsd:element name="result" type="parlayx_sms_xsd:DeliveryInformation" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:schema> </wsdl:types> <wsdl:message name="SendSms_sendSmsRequest"> <wsdl:part name="parameters" element="parlayx_sms_send_local_xsd:sendSms"/> </wsdl:message> <wsdl:message name="SendSms_sendSmsResponse"> <wsdl:part name="result" element="parlayx_sms_send_local_xsd:sendSmsResponse"/> </wsdl:message> <wsdl:message name="SendSms_sendSmsLogoRequest"> <wsdl:part name="parameters" element="parlayx_sms_send_local_xsd:sendSmsLogo"/> </wsdl:message> <wsdl:message name="SendSms_sendSmsLogoResponse"> <wsdl:part name="result" element="parlayx_sms_send_local_xsd:sendSmsLogoResponse"/> </wsdl:message> <wsdl:message name="SendSms_sendSmsRingtoneRequest"> <wsdl:part name="parameters" element="parlayx_sms_send_local_xsd:sendSmsRingtone"/> </wsdl:message> <wsdl:message name="SendSms_sendSmsRingtoneResponse"> <wsdl:part name="result" element="parlayx_sms_send_local_xsd:sendSmsRingtoneResponse"/> </wsdl:message> <wsdl:message name="SendSms_getSmsDeliveryStatusRequest"> <wsdl:part name="parameters" element="parlayx_sms_send_local_xsd:getSmsDeliveryStatus"/> </wsdl:message> <wsdl:message name="SendSms_getSmsDeliveryStatusResponse"> <wsdl:part name="result" element="parlayx_sms_send_local_xsd:getSmsDeliveryStatusResponse"/> </wsdl:message> <wsdl:portType name="SendSms"> <wsdl:operation name="sendSms"> <wsdl:input message="parlayx_sms_send:SendSms_sendSmsRequest"/> <wsdl:output message="parlayx_sms_send:SendSms_sendSmsResponse"/> <wsdl:fault name="ServiceException" message="parlayx_common_faults:ServiceException"/> <wsdl:fault name="PolicyException" message="parlayx_common_faults:PolicyException"/> </wsdl:operation> <wsdl:operation name="sendSmsLogo"> <wsdl:input message="parlayx_sms_send:SendSms_sendSmsLogoRequest"/> <wsdl:output message="parlayx_sms_send:SendSms_sendSmsLogoResponse"/> <wsdl:fault name="ServiceException" message="parlayx_common_faults:ServiceException"/> <wsdl:fault name="PolicyException" message="parlayx_common_faults:PolicyException"/> </wsdl:operation> <wsdl:operation name="sendSmsRingtone"> <wsdl:input message="parlayx_sms_send:SendSms_sendSmsRingtoneRequest"/> <wsdl:output message="parlayx_sms_send:SendSms_sendSmsRingtoneResponse"/> <wsdl:fault name="ServiceException" message="parlayx_common_faults:ServiceException"/> <wsdl:fault name="PolicyException" message="parlayx_common_faults:PolicyException"/> </wsdl:operation> <wsdl:operation name="getSmsDeliveryStatus"> <wsdl:input message="parlayx_sms_send:SendSms_getSmsDeliveryStatusRequest"/> <wsdl:output message="parlayx_sms_send:SendSms_getSmsDeliveryStatusResponse"/> <wsdl:fault name="ServiceException" message="parlayx_common_faults:ServiceException"/> <wsdl:fault name="PolicyException" message="parlayx_common_faults:PolicyException"/> </wsdl:operation> </wsdl:portType> </wsdl:definitions> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/soap/service/parlayx/wsdl/parlayx_sms_notification_interface_2_1.wsdl�����������������0000644�0001750�0001750�00000007575�12036105365�027422� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!-- June 11, 2005 --> <wsdl:definitions name="parlayx_sms_notification_interface" targetNamespace="http://www.csapi.org/wsdl/parlayx/sms/notification/v2_1/interface" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:parlayx_sms_notification="http://www.csapi.org/wsdl/parlayx/sms/notification/v2_1/interface" xmlns:parlayx_sms_xsd="http://www.csapi.org/schema/parlayx/sms/v2_1" xmlns:parlayx_common_xsd="http://www.csapi.org/schema/parlayx/common/v2_1" xmlns:parlayx_sms_notification_local_xsd="http://www.csapi.org/schema/parlayx/sms/notification/v2_1/local"> <wsdl:types> <xsd:schema elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.csapi.org/schema/parlayx/sms/notification/v2_1/local"> <xsd:import namespace="http://www.csapi.org/schema/parlayx/sms/v2_1" schemaLocation="parlayx_sms_types_2_1.xsd"/> <xsd:import namespace="http://www.csapi.org/schema/parlayx/common/v2_1" schemaLocation="parlayx_common_types_2_1.xsd"/> <xsd:element name="notifySmsReception" type="parlayx_sms_notification_local_xsd:notifySmsReception"/> <xsd:complexType name="notifySmsReception"> <xsd:sequence> <xsd:element name="correlator" type="xsd:string"/> <xsd:element name="message" type="parlayx_sms_xsd:SmsMessage"/> </xsd:sequence> </xsd:complexType> <xsd:element name="notifySmsReceptionResponse" type="parlayx_sms_notification_local_xsd:notifySmsReceptionResponse"/> <xsd:complexType name="notifySmsReceptionResponse"> <xsd:sequence/> </xsd:complexType> <xsd:element name="notifySmsDeliveryReceipt" type="parlayx_sms_notification_local_xsd:notifySmsDeliveryReceipt"/> <xsd:complexType name="notifySmsDeliveryReceipt"> <xsd:sequence> <xsd:element name="correlator" type="xsd:string"/> <xsd:element name="deliveryStatus" type="parlayx_sms_xsd:DeliveryInformation"/> </xsd:sequence> </xsd:complexType> <xsd:element name="notifySmsDeliveryReceiptResponse" type="parlayx_sms_notification_local_xsd:notifySmsDeliveryReceiptResponse"/> <xsd:complexType name="notifySmsDeliveryReceiptResponse"> <xsd:sequence/> </xsd:complexType> </xsd:schema> </wsdl:types> <wsdl:message name="SmsNotification_notifySmsReceptionRequest"> <wsdl:part name="parameters" element="parlayx_sms_notification_local_xsd:notifySmsReception"/> </wsdl:message> <wsdl:message name="SmsNotification_notifySmsReceptionResponse"> <wsdl:part name="result" element="parlayx_sms_notification_local_xsd:notifySmsReceptionResponse"/> </wsdl:message> <wsdl:message name="SmsNotification_notifySmsDeliveryReceiptRequest"> <wsdl:part name="parameters" element="parlayx_sms_notification_local_xsd:notifySmsDeliveryReceipt"/> </wsdl:message> <wsdl:message name="SmsNotification_notifySmsDeliveryReceiptResponse"> <wsdl:part name="result" element="parlayx_sms_notification_local_xsd:notifySmsDeliveryReceiptResponse"/> </wsdl:message> <wsdl:portType name="SmsNotification"> <wsdl:operation name="notifySmsReception"> <wsdl:input message="parlayx_sms_notification:SmsNotification_notifySmsReceptionRequest"/> <wsdl:output message="parlayx_sms_notification:SmsNotification_notifySmsReceptionResponse"/> </wsdl:operation> <wsdl:operation name="notifySmsDeliveryReceipt"> <wsdl:input message="parlayx_sms_notification:SmsNotification_notifySmsDeliveryReceiptRequest"/> <wsdl:output message="parlayx_sms_notification:SmsNotification_notifySmsDeliveryReceiptResponse"/> </wsdl:operation> </wsdl:portType> </wsdl:definitions> �����������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/missing�������������������������������������������������������������������������������0000755�0001750�0001750�00000015330�13312227404�013263� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to <bug-automake@gnu.org>." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/benchmarks/���������������������������������������������������������������������������0000755�0001750�0001750�00000000000�13312227714�014003� 5����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/benchmarks/functions.inc��������������������������������������������������������������0000644�0001750�0001750�00000001433�07253444127�016515� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������function check_for_errors { if grep 'WARNING:|ERROR:|PANIC:' "$@" >/dev/null then echo "$0 failed" 1>&2 echo "See bench_sms*.log for info" 1>&2 exit 1 fi } function plot_commands { echo "set terminal $1" echo "set xlabel \"$2\"" echo "set ylabel \"$3\"" if [ "$5" = "" ] then echo -n "plot \"$4\" notitle with lines" else echo -n "plot \"$4\" title \"$5\" with lines" fi shift 5 while [ "$2" != "" ] do if [ "$2" == "" ] then echo -n ", \"$1\" notitle with lines" else echo -n ", \"$1\" title \"$2\" with lines" fi shift 2 done echo "" } function plot { base="$1" shift plot_commands png "$@" | gnuplot > "$base.png" plot_commands "postscript eps" "$@" | gnuplot > "$base.ps" } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gateway-1.4.5/benchmarks/bench_http.txt�������������������������������������������������������������0000644�0001750�0001750�00000000622�07250775005�016667� 0����������������������������������������������������������������������������������������������������ustar �tolj����������������������������tolj�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<sect1> <title>HTTP client and server benchmark This benchmark makes #TIMES# HTTP requests using the Kannel HTTP client and server code, specifically, the test_http client and the test_http_server server.
HTTP requests per second during benchmark
gateway-1.4.5/benchmarks/bench_sms.sh0000755000175000017500000000263607253456277016331 0ustar toljtolj#!/bin/sh # # Use `test/test_smsc' to test SMS speed. set -e case "$1" in --fast) times=1000; shift ;; *) times=100000 ;; esac . benchmarks/functions.inc function gather_data { rm -f bench_sms_*.log test/test_smsc -m "$1" -r $times 2> bench_sms_smsc.log & sleep 1 gw/bearerbox -v 4 benchmarks/bench_sms.conf & sleep 1 gw/smsbox -v 4 benchmarks/bench_sms.conf & wait check_for_errors bench_sms_*.log } function analyze_logs { for type in submit # deliver deliver_ack http_request do awk "/INFO: Event .*, type $type,/ { print \$NF, \$(NF-2) }" \ bench_sms_smsc.log | uniq -c | awk ' NR == 1 { first = $2 } { print $2 - first, $1 } ' > bench_sms-$type.dat done awk '/DEBUG: RTT / { print ++n, $NF }' bench_sms_smsc.log \ > bench_sms-rtt.dat } function make_graphs { plot benchmarks/bench_sms_"$1" \ "time (s)" "requests/s (Hz)" \ "bench_sms-submit.dat" "submit" # "bench_sms-deliver.dat" "deliver" \ # "bench_sms-deliver_ack.dat" "deliver_ack" \ # "bench_sms-http_request.dat" "http_request" \ plot benchmarks/bench_sms_rtt_"$1" \ "received message number" "average round trip time (s)" \ "bench_sms-rtt.dat" "" } function run { gather_data "$1" analyze_logs make_graphs "$1" } run n_messages # run sustained_level sed "s/#TIMES#/$times/g" benchmarks/bench_sms.txt rm -f bench_sms*.log rm -f bench_sms*.dat gateway-1.4.5/benchmarks/bench_sms.txt0000644000175000017500000000246607253444127016523 0ustar toljtolj SMS SMPP benchmark: #TIMES# messages This benchmark sends #TIMES# SMS requests using the SMPP protocol. Each SMS request results in one HTTP request, and one SMS response message. shows the number of completed requests during each second of the benchmark. shows the round trip time of each completed request, that is, the time from when the message was sent to the time the reply message was received.
Requests per second during benchmark
SMPP request average round trip time
gateway-1.4.5/benchmarks/run-benchmarks0000755000175000017500000000070107253444127016654 0ustar toljtolj#!/bin/sh BEGIN=benchmarks/report-begin.txt END=benchmarks/report-end.txt OUT=benchmarks/report.xml rm -f $OUT sed "s/#DATE#/`date +%Y-%m-%d`/g" < $BEGIN | sed "s/#UNAME#/`uname -a`/g" > $OUT case "$1" in --fast) fast="--fast"; shift ;; *) fast="" ;; esac for bench in "$@" do echo -n "Running benchmark $bench..." if $bench $fast >> $OUT then echo " OK." else echo " FAILURE!" exit 1 fi done cat < $END >>$OUT gateway-1.4.5/benchmarks/report-begin.txt0000644000175000017500000000211407253444127017145 0ustar toljtolj ]>
Benchmark results for Kannel &version; Kannel Project Automated Kannel benchmarks The goal of the automated Kannel benchmarks (known as make bench) is to make it easy to regularly measure the speed at which Kannel performs. This is important so that the developers have a way to check that the changes they make don't make Kannel slower without the developers knowing it. Also, when optimizing Kannel (i.e., when trying to make it run faster), they can see that their changes really do have that effect. The benchmarks will also produce numbers that will make marketing people make funny sounds. System information This benchmark was run on ×tamp; a system identified as #UNAME#. gateway-1.4.5/benchmarks/bench_http.sh0000755000175000017500000000132107253444127016463 0ustar toljtolj#!/bin/sh # # Run a simple HTTP benchmark. # # Lars Wirzenius set -e case "$1" in --fast) times=1000; shift ;; *) times=100000 ;; esac port=8080 . benchmarks/functions.inc rm -f bench_http.log test/test_http_server -v 4 -l bench_http.log -p $port & sleep 1 test/test_http -q -v 2 -r $times http://localhost:$port/foo test/test_http -q -v 2 http://localhost:$port/quit wait awk '/DEBUG: Request for/ { print $1, $2 }' bench_http.log | test/timestamp | uniq -c | awk ' NR == 1 { first = $2 } { print $2 - first, $1 } ' > bench_http.dat plot benchmarks/bench_http "time (s)" "requests/s (Hz)" "bench_http.dat" "" sed "s/#TIMES#/$times/g" benchmarks/bench_http.txt rm -f bench_http.log rm -f bench_http.dat gateway-1.4.5/benchmarks/report-end.txt0000644000175000017500000000001307247470041016620 0ustar toljtolj
gateway-1.4.5/benchmarks/bench_sms.conf0000644000175000017500000000145507277747361016642 0ustar toljtolj# # THIS IS THE CONFIGURATION FOR bench_sms.sh # group = core admin-port = 13000 smsbox-port = 13001 admin-password = bar admin-deny-ip = "*.*.*.*" admin-allow-ip = "127.0.0.1" log-file = "bench_sms_bb.log" box-deny-ip = "*.*.*.*" box-allow-ip = "127.0.0.1" group = smsc smsc = smpp smsc-id = smpp host = 127.0.0.1 port = 2345 receive-port = 2345 smsc-username = xyzzy smsc-password = xyzzy system-type = "VMA" address-range = "" group = smsbox bearerbox-host = localhost sendsms-port = 13013 global-sender = 123 log-file = "bench_sms_sb.log" group = sms-service keyword = nop text = "You asked nothing and I did it!" group = sms-service keyword = default url = "http://localhost:8080/foo?arg=%a" group = sendsms-user username = tester password = foobar user-deny-ip = "*.*.*.*" user-allow-ip = "127.0.0.1"